diff options
Diffstat (limited to 'mi')
-rw-r--r-- | mi/Makefile.am | 64 | ||||
-rw-r--r-- | mi/Makefile.in | 848 | ||||
-rw-r--r-- | mi/mi.h | 599 | ||||
-rw-r--r-- | mi/miarc.c | 3586 | ||||
-rw-r--r-- | mi/mibitblt.c | 825 | ||||
-rw-r--r-- | mi/mibstore.h | 23 | ||||
-rw-r--r-- | mi/micmap.c | 670 | ||||
-rw-r--r-- | mi/micmap.h | 63 | ||||
-rw-r--r-- | mi/micoord.h | 69 | ||||
-rw-r--r-- | mi/micopy.c | 350 | ||||
-rw-r--r-- | mi/micursor.c | 69 | ||||
-rw-r--r-- | mi/midash.c | 91 | ||||
-rw-r--r-- | mi/midispcur.c | 584 | ||||
-rw-r--r-- | mi/mieq.c | 495 | ||||
-rw-r--r-- | mi/miexpose.c | 697 | ||||
-rw-r--r-- | mi/mifillarc.c | 798 | ||||
-rw-r--r-- | mi/mifillarc.h | 190 | ||||
-rw-r--r-- | mi/mifillrct.c | 143 | ||||
-rw-r--r-- | mi/mifpoly.h | 102 | ||||
-rw-r--r-- | mi/mifpolycon.c | 280 | ||||
-rw-r--r-- | mi/migc.c | 249 | ||||
-rw-r--r-- | mi/migc.h | 64 | ||||
-rw-r--r-- | mi/miglblt.c | 256 | ||||
-rw-r--r-- | mi/miinitext.c | 544 | ||||
-rw-r--r-- | mi/miline.h | 173 | ||||
-rw-r--r-- | mi/mioverlay.c | 1946 | ||||
-rw-r--r-- | mi/mioverlay.h | 32 | ||||
-rw-r--r-- | mi/mipointer.c | 589 | ||||
-rw-r--r-- | mi/mipointer.h | 153 | ||||
-rw-r--r-- | mi/mipointrst.h | 56 | ||||
-rw-r--r-- | mi/mipoly.c | 124 | ||||
-rw-r--r-- | mi/mipoly.h | 207 | ||||
-rw-r--r-- | mi/mipolycon.c | 247 | ||||
-rw-r--r-- | mi/mipolygen.c | 230 | ||||
-rw-r--r-- | mi/mipolypnt.c | 125 | ||||
-rw-r--r-- | mi/mipolyrect.c | 187 | ||||
-rw-r--r-- | mi/mipolyseg.c | 79 | ||||
-rw-r--r-- | mi/mipolytext.c | 130 | ||||
-rw-r--r-- | mi/mipolyutil.c | 385 | ||||
-rw-r--r-- | mi/mipushpxl.c | 271 | ||||
-rw-r--r-- | mi/miscanfill.h | 147 | ||||
-rw-r--r-- | mi/miscrinit.c | 296 | ||||
-rw-r--r-- | mi/mispans.c | 527 | ||||
-rw-r--r-- | mi/mispans.h | 92 | ||||
-rw-r--r-- | mi/misprite.c | 1045 | ||||
-rw-r--r-- | mi/misprite.h | 50 | ||||
-rw-r--r-- | mi/mistruct.h | 63 | ||||
-rw-r--r-- | mi/mivalidate.h | 51 | ||||
-rw-r--r-- | mi/mivaltree.c | 813 | ||||
-rw-r--r-- | mi/miwideline.c | 2193 | ||||
-rw-r--r-- | mi/miwideline.h | 120 | ||||
-rw-r--r-- | mi/miwindow.c | 824 | ||||
-rw-r--r-- | mi/mizerarc.c | 848 | ||||
-rw-r--r-- | mi/mizerarc.h | 126 | ||||
-rw-r--r-- | mi/mizerclip.c | 630 | ||||
-rw-r--r-- | mi/mizerline.c | 381 |
56 files changed, 24799 insertions, 0 deletions
diff --git a/mi/Makefile.am b/mi/Makefile.am new file mode 100644 index 0000000..96ceeaa --- /dev/null +++ b/mi/Makefile.am @@ -0,0 +1,64 @@ +noinst_LTLIBRARIES = libmi.la + +if XORG +sdk_HEADERS = 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 mioverlay.h +endif + +AM_CFLAGS = $(DIX_CFLAGS) + +libmi_la_SOURCES = \ + mi.h \ + miarc.c \ + mibitblt.c \ + mibstore.h \ + micmap.c \ + micmap.h \ + micoord.h \ + micopy.c \ + 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 \ + miscanfill.h \ + miscrinit.c \ + mispans.c \ + mispans.h \ + misprite.c \ + misprite.h \ + mistruct.h \ + mivaltree.c \ + mivalidate.h \ + miwideline.c \ + miwideline.h \ + miwindow.c \ + mizerarc.c \ + mizerarc.h \ + mizerclip.c \ + mizerline.c diff --git a/mi/Makefile.in b/mi/Makefile.in new file mode 100644 index 0000000..9feec22 --- /dev/null +++ b/mi/Makefile.in @@ -0,0 +1,848 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 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@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@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)/m4/ac_define_dir.m4 \ + $(top_srcdir)/m4/ax_tls.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/xorg-config.h \ + $(top_builddir)/include/xkb-config.h \ + $(top_builddir)/include/xwin-config.h \ + $(top_builddir)/include/kdrive-config.h \ + $(top_builddir)/include/version-config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libmi_la_LIBADD = +am_libmi_la_OBJECTS = miarc.lo mibitblt.lo micmap.lo micopy.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 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) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libmi_la_SOURCES) +DIST_SOURCES = $(libmi_la_SOURCES) +am__sdk_HEADERS_DIST = 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 mioverlay.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 = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(sdkdir)" +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@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APPLE_APPLICATIONS_DIR = @APPLE_APPLICATIONS_DIR@ +APPLE_APPLICATION_NAME = @APPLE_APPLICATION_NAME@ +APP_MAN_DIR = @APP_MAN_DIR@ +APP_MAN_SUFFIX = @APP_MAN_SUFFIX@ +AR = @AR@ +ARM_BACKTRACE_CFLAGS = @ARM_BACKTRACE_CFLAGS@ +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@ +CHANGELOG_CMD = @CHANGELOG_CMD@ +COMPILEDDEFAULTFONTPATH = @COMPILEDDEFAULTFONTPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CWARNFLAGS = @CWARNFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DARWIN_LIBS = @DARWIN_LIBS@ +DBUS_CFLAGS = @DBUS_CFLAGS@ +DBUS_LIBS = @DBUS_LIBS@ +DEFAULT_LIBRARY_PATH = @DEFAULT_LIBRARY_PATH@ +DEFAULT_LOGDIR = @DEFAULT_LOGDIR@ +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@ +DIX_LIB = @DIX_LIB@ +DLLTOOL = @DLLTOOL@ +DLOPEN_LIBS = @DLOPEN_LIBS@ +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@ +DOXYGEN = @DOXYGEN@ +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_CFLAGS = @DRI_CFLAGS@ +DRI_DRIVER_PATH = @DRI_DRIVER_PATH@ +DRI_LIBS = @DRI_LIBS@ +DSYMUTIL = @DSYMUTIL@ +DTRACE = @DTRACE@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILE_MAN_DIR = @FILE_MAN_DIR@ +FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ +FONT100DPIDIR = @FONT100DPIDIR@ +FONT75DPIDIR = @FONT75DPIDIR@ +FONTMISCDIR = @FONTMISCDIR@ +FONTOTFDIR = @FONTOTFDIR@ +FONTROOTDIR = @FONTROOTDIR@ +FONTTTFDIR = @FONTTTFDIR@ +FONTTYPE1DIR = @FONTTYPE1DIR@ +FOP = @FOP@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GLX_ARCH_DEFINES = @GLX_ARCH_DEFINES@ +GLX_DEFINES = @GLX_DEFINES@ +GLX_TLS = @GLX_TLS@ +GL_CFLAGS = @GL_CFLAGS@ +GL_LIBS = @GL_LIBS@ +GREP = @GREP@ +HAL_CFLAGS = @HAL_CFLAGS@ +HAL_LIBS = @HAL_LIBS@ +INSTALL = @INSTALL@ +INSTALL_CMD = @INSTALL_CMD@ +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_ID_PREFIX = @LAUNCHD_ID_PREFIX@ +LD = @LD@ +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@ +LIBSHA1_CFLAGS = @LIBSHA1_CFLAGS@ +LIBSHA1_LIBS = @LIBSHA1_LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MAN_DIR = @LIB_MAN_DIR@ +LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAIN_LIB = @MAIN_LIB@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAN_SUBSTS = @MAN_SUBSTS@ +MISC_MAN_DIR = @MISC_MAN_DIR@ +MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCCLD = @OBJCCLD@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJCLINK = @OBJCLINK@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_CFLAGS = @OPENSSL_CFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OS_LIB = @OS_LIB@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +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@ +PIXMAN_CFLAGS = @PIXMAN_CFLAGS@ +PIXMAN_LIBS = @PIXMAN_LIBS@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PROJECTROOT = @PROJECTROOT@ +RANLIB = @RANLIB@ +RAWCPP = @RAWCPP@ +RAWCPPFLAGS = @RAWCPPFLAGS@ +RELEASE_DATE = @RELEASE_DATE@ +SDK_REQUIRED_MODULES = @SDK_REQUIRED_MODULES@ +SED = @SED@ +SELINUX_CFLAGS = @SELINUX_CFLAGS@ +SELINUX_LIBS = @SELINUX_LIBS@ +SERVER_MISC_CONFIG_PATH = @SERVER_MISC_CONFIG_PATH@ +SET_MAKE = @SET_MAKE@ +SHA1_CFLAGS = @SHA1_CFLAGS@ +SHA1_LIBS = @SHA1_LIBS@ +SHELL = @SHELL@ +SOLARIS_ASM_CFLAGS = @SOLARIS_ASM_CFLAGS@ +SOLARIS_INOUT_ARCH = @SOLARIS_INOUT_ARCH@ +STRIP = @STRIP@ +STYLESHEET_SRCDIR = @STYLESHEET_SRCDIR@ +SYSCONFDIR = @SYSCONFDIR@ +TSLIB_CFLAGS = @TSLIB_CFLAGS@ +TSLIB_LIBS = @TSLIB_LIBS@ +UDEV_CFLAGS = @UDEV_CFLAGS@ +UDEV_LIBS = @UDEV_LIBS@ +UTILS_SYS_LIBS = @UTILS_SYS_LIBS@ +VENDOR_NAME_SHORT = @VENDOR_NAME_SHORT@ +VERSION = @VERSION@ +WINDOWSWM_CFLAGS = @WINDOWSWM_CFLAGS@ +WINDOWSWM_LIBS = @WINDOWSWM_LIBS@ +WINDRES = @WINDRES@ +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@ +XEPHYR_CFLAGS = @XEPHYR_CFLAGS@ +XEPHYR_INCS = @XEPHYR_INCS@ +XEPHYR_LIBS = @XEPHYR_LIBS@ +XF86CONFIGDIR = @XF86CONFIGDIR@ +XF86CONFIGFILE = @XF86CONFIGFILE@ +XF86VIDMODE_CFLAGS = @XF86VIDMODE_CFLAGS@ +XF86VIDMODE_LIBS = @XF86VIDMODE_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@ +XMLTO = @XMLTO@ +XNESTMODULES_CFLAGS = @XNESTMODULES_CFLAGS@ +XNESTMODULES_LIBS = @XNESTMODULES_LIBS@ +XNEST_LIBS = @XNEST_LIBS@ +XNEST_SYS_LIBS = @XNEST_SYS_LIBS@ +XORG_CFLAGS = @XORG_CFLAGS@ +XORG_INCS = @XORG_INCS@ +XORG_LIBS = @XORG_LIBS@ +XORG_MAN_PAGE = @XORG_MAN_PAGE@ +XORG_MODULES_CFLAGS = @XORG_MODULES_CFLAGS@ +XORG_MODULES_LIBS = @XORG_MODULES_LIBS@ +XORG_OS = @XORG_OS@ +XORG_OS_SUBDIR = @XORG_OS_SUBDIR@ +XORG_SGML_PATH = @XORG_SGML_PATH@ +XORG_SYS_LIBS = @XORG_SYS_LIBS@ +XPBPROXY_CFLAGS = @XPBPROXY_CFLAGS@ +XPBPROXY_LIBS = @XPBPROXY_LIBS@ +XQUARTZ_SPARKLE = @XQUARTZ_SPARKLE@ +XRESEXAMPLES_DEP_CFLAGS = @XRESEXAMPLES_DEP_CFLAGS@ +XRESEXAMPLES_DEP_LIBS = @XRESEXAMPLES_DEP_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@ +XSL_STYLESHEET = @XSL_STYLESHEET@ +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@ +__XCONFIGDIR__ = @__XCONFIGDIR__@ +__XCONFIGFILE__ = @__XCONFIGFILE__@ +abi_ansic = @abi_ansic@ +abi_extension = @abi_extension@ +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_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +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@ +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@ +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@ +symbol_visibility = @symbol_visibility@ +sysconfdir = @sysconfdir@ +sysconfigdir = @sysconfigdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = libmi.la +@XORG_TRUE@sdk_HEADERS = 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 mioverlay.h + +AM_CFLAGS = $(DIX_CFLAGS) +libmi_la_SOURCES = \ + mi.h \ + miarc.c \ + mibitblt.c \ + mibstore.h \ + micmap.c \ + micmap.h \ + micoord.h \ + micopy.c \ + 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 \ + miscanfill.h \ + miscrinit.c \ + mispans.c \ + mispans.h \ + misprite.c \ + misprite.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 ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign mi/Makefile'; \ + $(am__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 +$(am__aclocal_m4_deps): + +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) + $(AM_V_CCLD)$(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)/mibitblt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/micmap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/micopy.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)/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@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@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@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@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@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@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)'; test -n "$(sdkdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(sdkdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(sdkdir)" || exit $$?; \ + done + +uninstall-sdkHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(sdk_HEADERS)'; test -n "$(sdkdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(sdkdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(sdkdir)" && rm -f $$files + +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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + 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; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + 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)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__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 "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$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) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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 + +html-am: + +info: info-am + +info-am: + +install-data-am: install-sdkHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +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: @@ -0,0 +1,599 @@ +/*********************************************************** + +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" +#include "colormap.h" +#include "events.h" + +#define MiBits CARD32 + +typedef struct _miDash *miDashPtr; +#define EVEN_DASH 0 +#define ODD_DASH ~0 + +/* miarc.c */ + +extern _X_EXPORT void miPolyArc( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*narcs*/, + xArc * /*parcs*/ +); + +/* mibitblt.c */ + +extern _X_EXPORT RegionPtr miCopyArea( + DrawablePtr /*pSrcDrawable*/, + DrawablePtr /*pDstDrawable*/, + GCPtr /*pGC*/, + int /*xIn*/, + int /*yIn*/, + int /*widthSrc*/, + int /*heightSrc*/, + int /*xOut*/, + int /*yOut*/ +); + +extern _X_EXPORT RegionPtr miCopyPlane( + DrawablePtr /*pSrcDrawable*/, + DrawablePtr /*pDstDrawable*/, + GCPtr /*pGC*/, + int /*srcx*/, + int /*srcy*/, + int /*width*/, + int /*height*/, + int /*dstx*/, + int /*dsty*/, + unsigned long /*bitPlane*/ +); + +extern _X_EXPORT void miGetImage( + DrawablePtr /*pDraw*/, + int /*sx*/, + int /*sy*/, + int /*w*/, + int /*h*/, + unsigned int /*format*/, + unsigned long /*planeMask*/, + char * /*pdstLine*/ +); + +extern _X_EXPORT void miPutImage( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*depth*/, + int /*x*/, + int /*y*/, + int /*w*/, + int /*h*/, + int /*leftPad*/, + int /*format*/, + char * /*pImage*/ +); + +/* micopy.c */ + +#define miGetCompositeClip(pGC) ((pGC)->pCompositeClip) + +typedef void (*miCopyProc) (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + BoxPtr pDstBox, + int nbox, + int dx, + int dy, + Bool reverse, + Bool upsidedown, + Pixel bitplane, + void *closure); + +extern _X_EXPORT void +miCopyRegion (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + RegionPtr pDstRegion, + int dx, + int dy, + miCopyProc copyProc, + Pixel bitPlane, + void *closure); + +extern _X_EXPORT RegionPtr +miDoCopy (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + int xIn, + int yIn, + int widthSrc, + int heightSrc, + int xOut, + int yOut, + miCopyProc copyProc, + Pixel bitplane, + void *closure); + +/* micursor.c */ + +extern _X_EXPORT void miRecolorCursor( + DeviceIntPtr /* pDev */, + ScreenPtr /*pScr*/, + CursorPtr /*pCurs*/, + Bool /*displayed*/ +); + +/* midash.c */ + +extern _X_EXPORT void miStepDash( + int /*dist*/, + int * /*pDashIndex*/, + unsigned char * /*pDash*/, + int /*numInDashList*/, + int * /*pDashOffset*/ +); + +/* mieq.c */ + + +#ifndef INPUT_H +typedef struct _DeviceRec *DevicePtr; +#endif + +extern _X_EXPORT Bool mieqInit( + void +); + +extern _X_EXPORT void mieqFini(void); + +extern _X_EXPORT void mieqEnqueue( + DeviceIntPtr /*pDev*/, + InternalEvent* /*e*/ +); + +extern _X_EXPORT void mieqSwitchScreen( + DeviceIntPtr /* pDev */, + ScreenPtr /*pScreen*/, + Bool /*fromDIX*/ +); + +extern _X_EXPORT void mieqProcessDeviceEvent( + DeviceIntPtr /* dev*/, + InternalEvent* /* event */, + ScreenPtr /* screen*/ +); + +extern _X_EXPORT void mieqProcessInputEvents( + void +); + +extern DeviceIntPtr CopyGetMasterEvent( + DeviceIntPtr /* sdev */, + InternalEvent* /* original */, + InternalEvent* /* copy */ +); + +/** + * Custom input event handler. If you need to process input events in some + * other way than the default path, register an input event handler for the + * given internal event type. + */ +typedef void (*mieqHandler)(int screen, InternalEvent* event, DeviceIntPtr dev); +void _X_EXPORT mieqSetHandler(int event, mieqHandler handler); + +/* miexpose.c */ + +extern _X_EXPORT RegionPtr miHandleExposures( + DrawablePtr /*pSrcDrawable*/, + DrawablePtr /*pDstDrawable*/, + GCPtr /*pGC*/, + int /*srcx*/, + int /*srcy*/, + int /*width*/, + int /*height*/, + int /*dstx*/, + int /*dsty*/, + unsigned long /*plane*/ +); + +extern _X_EXPORT void miSendGraphicsExpose( + ClientPtr /*client*/, + RegionPtr /*pRgn*/, + XID /*drawable*/, + int /*major*/, + int /*minor*/ +); + +extern _X_EXPORT void miSendExposures( + WindowPtr /*pWin*/, + RegionPtr /*pRgn*/, + int /*dx*/, + int /*dy*/ +); + +extern _X_EXPORT void miWindowExposures( + WindowPtr /*pWin*/, + RegionPtr /*prgn*/, + RegionPtr /*other_exposed*/ +); + +extern _X_EXPORT void miPaintWindow( + WindowPtr /*pWin*/, + RegionPtr /*prgn*/, + int /*what*/ +); + +extern _X_EXPORT void miClearDrawable( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/ +); + +/* mifillrct.c */ + +extern _X_EXPORT void miPolyFillRect( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*nrectFill*/, + xRectangle * /*prectInit*/ +); + +/* miglblt.c */ + +extern _X_EXPORT void miPolyGlyphBlt( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + unsigned int /*nglyph*/, + CharInfoPtr * /*ppci*/, + pointer /*pglyphBase*/ +); + +extern _X_EXPORT void miImageGlyphBlt( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + unsigned int /*nglyph*/, + CharInfoPtr * /*ppci*/, + pointer /*pglyphBase*/ +); + +/* mipoly.c */ + +extern _X_EXPORT void miFillPolygon( + DrawablePtr /*dst*/, + GCPtr /*pgc*/, + int /*shape*/, + int /*mode*/, + int /*count*/, + DDXPointPtr /*pPts*/ +); + +/* mipolycon.c */ + +extern _X_EXPORT Bool miFillConvexPoly( + DrawablePtr /*dst*/, + GCPtr /*pgc*/, + int /*count*/, + DDXPointPtr /*ptsIn*/ +); + +/* mipolygen.c */ + +extern _X_EXPORT Bool miFillGeneralPoly( + DrawablePtr /*dst*/, + GCPtr /*pgc*/, + int /*count*/, + DDXPointPtr /*ptsIn*/ +); + +/* mipolypnt.c */ + +extern _X_EXPORT void miPolyPoint( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*mode*/, + int /*npt*/, + xPoint * /*pptInit*/ +); + +/* mipolyrect.c */ + +extern _X_EXPORT void miPolyRectangle( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*nrects*/, + xRectangle * /*pRects*/ +); + +/* mipolyseg.c */ + +extern _X_EXPORT void miPolySegment( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*nseg*/, + xSegment * /*pSegs*/ +); + +/* mipolytext.c */ + +extern _X_EXPORT int miPolyText8( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + int /*count*/, + char * /*chars*/ +); + +extern _X_EXPORT int miPolyText16( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + int /*count*/, + unsigned short * /*chars*/ +); + +extern _X_EXPORT void miImageText8( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + int /*count*/, + char * /*chars*/ +); + +extern _X_EXPORT void miImageText16( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + int /*count*/, + unsigned short * /*chars*/ +); + +/* mipushpxl.c */ + +extern _X_EXPORT void miPushPixels( + GCPtr /*pGC*/, + PixmapPtr /*pBitMap*/, + DrawablePtr /*pDrawable*/, + int /*dx*/, + int /*dy*/, + int /*xOrg*/, + int /*yOrg*/ +); + +/* miscrinit.c */ + +extern _X_EXPORT Bool miModifyPixmapHeader( + PixmapPtr /*pPixmap*/, + int /*width*/, + int /*height*/, + int /*depth*/, + int /*bitsPerPixel*/, + int /*devKind*/, + pointer /*pPixData*/ +); + +extern _X_EXPORT Bool miCreateScreenResources( + ScreenPtr /*pScreen*/ +); + +extern _X_EXPORT Bool miScreenDevPrivateInit( + ScreenPtr /*pScreen*/, + int /*width*/, + pointer /*pbits*/ +); + +extern _X_EXPORT 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*/ +); + +/* mivaltree.c */ + +extern _X_EXPORT int miShapedWindowIn( + RegionPtr /*universe*/, + RegionPtr /*bounding*/, + BoxPtr /*rect*/, + int /*x*/, + int /*y*/ +); + +typedef void +(*SetRedirectBorderClipProcPtr) (WindowPtr pWindow, RegionPtr pRegion); + +typedef RegionPtr +(*GetRedirectBorderClipProcPtr) (WindowPtr pWindow); + +extern _X_EXPORT void +miRegisterRedirectBorderClipProc (SetRedirectBorderClipProcPtr setBorderClip, + GetRedirectBorderClipProcPtr getBorderClip); + +extern _X_EXPORT int miValidateTree( + WindowPtr /*pParent*/, + WindowPtr /*pChild*/, + VTKind /*kind*/ +); + +extern _X_EXPORT void miWideLine( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*mode*/, + int /*npt*/, + DDXPointPtr /*pPts*/ +); + +extern _X_EXPORT void miWideDash( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*mode*/, + int /*npt*/, + DDXPointPtr /*pPts*/ +); + +/* miwindow.c */ + +extern _X_EXPORT void miClearToBackground( + WindowPtr /*pWin*/, + int /*x*/, + int /*y*/, + int /*w*/, + int /*h*/, + Bool /*generateExposures*/ +); + +extern _X_EXPORT void miMarkWindow( + WindowPtr /*pWin*/ +); + +extern _X_EXPORT Bool miMarkOverlappedWindows( + WindowPtr /*pWin*/, + WindowPtr /*pFirst*/, + WindowPtr * /*ppLayerWin*/ +); + +extern _X_EXPORT void miHandleValidateExposures( + WindowPtr /*pWin*/ +); + +extern _X_EXPORT void miMoveWindow( + WindowPtr /*pWin*/, + int /*x*/, + int /*y*/, + WindowPtr /*pNextSib*/, + VTKind /*kind*/ +); + +extern _X_EXPORT void miSlideAndSizeWindow( + WindowPtr /*pWin*/, + int /*x*/, + int /*y*/, + unsigned int /*w*/, + unsigned int /*h*/, + WindowPtr /*pSib*/ +); + +extern _X_EXPORT WindowPtr miGetLayerWindow( + WindowPtr /*pWin*/ +); + +extern _X_EXPORT void miSetShape( + WindowPtr /*pWin*/, + int /*kind*/ +); + +extern _X_EXPORT void miChangeBorderWidth( + WindowPtr /*pWin*/, + unsigned int /*width*/ +); + +extern _X_EXPORT void miMarkUnrealizedWindow( + WindowPtr /*pChild*/, + WindowPtr /*pWin*/, + Bool /*fromConfigure*/ +); + +extern _X_EXPORT void miSegregateChildren(WindowPtr pWin, RegionPtr pReg, int depth); + +/* mizerarc.c */ + +extern _X_EXPORT void miZeroPolyArc( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*narcs*/, + xArc * /*parcs*/ +); + +/* mizerline.c */ + +extern _X_EXPORT void miZeroLine( + DrawablePtr /*dst*/, + GCPtr /*pgc*/, + int /*mode*/, + int /*nptInit*/, + DDXPointRec * /*pptInit*/ +); + +extern _X_EXPORT void miZeroDashLine( + DrawablePtr /*dst*/, + GCPtr /*pgc*/, + int /*mode*/, + int /*nptInit*/, + DDXPointRec * /*pptInit*/ +); + +extern _X_EXPORT void miPolyFillArc( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*narcs*/, + xArc * /*parcs*/ +); + +#endif /* MI_H */ diff --git a/mi/miarc.c b/mi/miarc.c new file mode 100644 index 0000000..881e0db --- /dev/null +++ b/mi/miarc.c @@ -0,0 +1,3586 @@ +/*********************************************************** + +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; + +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; + +static void drawQuadrant(struct arc_def *def, struct accelerators *acc, + int a0, int a1, int mask, miArcFacePtr right, + miArcFacePtr left, miArcSpanData *spdata); + +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) +{ + miArcSpanData *spdata = NULL; + int k; + + if (!lw) + lw = 1; + k = (parc->height >> 1) + ((lw - 1) >> 1); + spdata = malloc(sizeof(miArcSpanData) + sizeof(miArcSpan) * (k + 2)); + if (!spdata) + return NULL; + spdata->spans = (miArcSpan *)(spdata + 1); + spdata->k = k; + spdata->top = !(lw & 1) && !(parc->width & 1); + spdata->bot = !(parc->height & 1); + 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; + miArcSpan *span; + int xorg, yorgu, yorgl; + int n; + + yorgu = parc->height + pGC->lineWidth; + n = (sizeof(int) * 2) * yorgu; + widths = malloc(n + (sizeof(DDXPointRec) * 2) * yorgu); + if (!widths) + return; + points = (DDXPointPtr)((char *)widths + n); + spdata = miComputeWideEllipse((int)pGC->lineWidth, parc); + if (!spdata) + { + free(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; + } + } + free(spdata); + (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); + + free(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.) + */ + +void +miPolyArc(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; + { + ChangeGCVal gcvals[6]; + gcvals[0].val = GXcopy; + gcvals[1].val = 1; + gcvals[2].val = 0; + gcvals[3].val = pGC->lineWidth; + gcvals[4].val = pGC->capStyle; + gcvals[5].val = pGC->joinStyle; + ChangeGC(NullClient, pGCTo, GCFunction | + GCForeground | GCBackground | GCLineWidth | + GCCapStyle | GCJoinStyle, gcvals); + } + + /* 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--) + { + ChangeGCVal gcval; + if (iphase == 1) { + gcval.val = bg; + ChangeGC (NullClient, pGC, GCForeground, &gcval); + ValidateGC (pDraw, pGC); + } else if (pGC->lineStyle == LineDoubleDash) { + gcval.val = fg; + ChangeGC (NullClient, pGC, GCForeground, &gcval); + 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 = malloc(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); + } + free(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); + } + free(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 malloc()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 realloc() 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) realloc((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) realloc(*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) realloc(*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) realloc(*arcsp, + newsize * sizeof (**arcsp)); + if (!arc) + return 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) + free(arcs[iphase].arcs); + if (arcs[iphase].njoins > 0) + free(arcs[iphase].joins); + if (arcs[iphase].ncaps > 0) + free(arcs[iphase].caps); + } + free(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 = 0; + 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 = malloc(narcs * sizeof (struct arcData)); + if (!data) + return NULL; + arcs = malloc(sizeof (*arcs) * (isDoubleDash ? 2 : 1)); + if (!arcs) + { + free(data); + return 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; + } + free(data); + return arcs; +arcfail: + miFreeArcs(arcs, pGC); + free(data); + return 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 = malloc(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; + free(chunk); + } + chunks = 0; + freeFinalSpans = 0; + free(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 = malloc(nspans * sizeof (DDXPointRec)); + xWidth = xWidths = malloc(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 (); + free(xSpans); + free(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 = malloc(newSize * sizeof (struct finalSpan *)); + if (!newSpans) + return 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 *)); + free(finalSpans); + } + if ((i = finalMiny - newMiny) > 0) + memset((char *)newSpans, 0, i * sizeof (struct finalSpan *)); + if ((i = newMaxy - finalMaxy) > 0) + memset((char *)(newSpans + newSize - i), 0, + 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; + + spdata = miComputeWideEllipse(l, tarc); + 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; + } + } + free(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/mi/mibitblt.c b/mi/mibitblt.c new file mode 100644 index 0000000..49e17bd --- /dev/null +++ b/mi/mibitblt.c @@ -0,0 +1,825 @@ +/*********************************************************** + +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. + */ +RegionPtr +miCopyArea(DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + int xIn, + int yIn, + int widthSrc, + int heightSrc, + int xOut, + int 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 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 = RegionCreate(&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 = malloc(heightSrc * sizeof(DDXPointRec)); + pwidthFirst = pwidth = malloc(heightSrc * sizeof(unsigned int)); + numRects = RegionNumRects(prgnSrcClip); + boxes = RegionRects(prgnSrcClip); + ordering = malloc(numRects * sizeof(unsigned int)); + if(!pptFirst || !pwidthFirst || !ordering) + { + free(ordering); + free(pwidthFirst); + free(pptFirst); + return 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 = malloc(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); + free(pbits); + } + } + prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn, + widthSrc, heightSrc, xOut, yOut, (unsigned long)0); + if(realSrcClip) + RegionDestroy(prgnSrcClip); + + free(ordering); + free(pwidthFirst); + free(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 = calloc(h, widthInBytes); + if (!result) + return NULL; + bitsPerPixel = pDraw->bitsPerPixel; + 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; + ChangeGC(NullClient, pGCT, GCBackground, gcv); + ValidateGC((DrawablePtr)pPixmap, pGCT); + miClearDrawable((DrawablePtr)pPixmap, pGCT); + ppt = pptFirst = malloc(h * sizeof(DDXPointRec)); + pwidth = pwidthFirst = malloc(h * sizeof(int)); + if(!pptFirst || !pwidthFirst) + { + free(pwidthFirst); + free(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 = RegionCreate(NULL, 0); + RegionCopy(prgnSrcClip, prgnSrc); + RegionTranslate(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); + free(pwidthFirst); + free(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; + + ChangeGC(NullClient, pGC, + GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin, + 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; + ChangeGC(NullClient, pGCT, GCFunction, 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; + ChangeGC(NullClient, pGC, GCForeground | GCBackground | GCStipple, 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; + ChangeGC(NullClient, pGC, + GCForeground | GCBackground | GCFillStyle | GCStipple | + GCTileStipXOrigin | GCTileStipYOrigin, 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 + */ +RegionPtr +miCopyPlane( DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + int srcx, + int srcy, + int width, + int height, + int dstx, + int 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 = RegionCreate(&box, 1); + + if (pSrcDrawable->type != DRAWABLE_PIXMAP) { + /* clip to visible drawable */ + + if (pGC->subWindowMode == IncludeInferiors) + { + RegionPtr clipList = NotClippedByChildren ((WindowPtr) pSrcDrawable); + RegionIntersect(prgnSrc, prgnSrc, clipList); + RegionDestroy(clipList); + } else + RegionIntersect(prgnSrc, prgnSrc, + &((WindowPtr)pSrcDrawable)->clipList); + } + + box = *RegionExtents(prgnSrc); + RegionTranslate(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); + free(ptile); + } + } + prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, + width, height, dstx, dsty, bitPlane); + RegionDestroy(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 + */ +void +miGetImage( DrawablePtr pDraw, int sx, int sy, int w, int h, + unsigned int format, unsigned long planeMask, char *pDst) +{ + unsigned char depth; + int i, linelength, width, srcx, srcy; + DDXPointRec pt = {0, 0}; + PixmapPtr pPixmap = NULL; + GCPtr pGC = NULL; + + depth = pDraw->depth; + if(format == ZPixmap) + { + if ( (((1<<depth)-1)&planeMask) != (1<<depth)-1 ) + { + ChangeGCVal gcv; + 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.val = (XID)planeMask; + ChangeGC(NullClient, pGC, GCPlaneMask, &gcv); + 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 + */ +void +miPutImage( DrawablePtr pDraw, GCPtr pGC, int depth, + int x, int y, int w, int h, + int leftPad, int format, char *pImage) +{ + DDXPointPtr pptFirst, ppt; + int *pwidthFirst, *pwidth; + RegionPtr prgnSrc; + BoxRec box; + unsigned long oldFg, oldBg; + ChangeGCVal 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 = RegionCreate(&box, 1); + + miOpqStipDrawable(pDraw, pGC, prgnSrc, (MiBits *) pImage, + leftPad, w, h, x, y); + RegionDestroy(prgnSrc); + break; + + case XYPixmap: + depth = pGC->depth; + oldPlanemask = pGC->planemask; + oldFg = pGC->fgPixel; + oldBg = pGC->bgPixel; + gcv[0].val = (XID)~0; + gcv[1].val = (XID)0; + ChangeGC(NullClient, pGC, GCForeground | GCBackground, gcv); + bytesPer = (long)h * BitmapBytePad(w + leftPad); + + for (i = 1 << (depth-1); i != 0; i >>= 1, pImage += bytesPer) + { + if (i & oldPlanemask) + { + gcv[0].val = (XID)i; + ChangeGC(NullClient, pGC, GCPlaneMask, gcv); + ValidateGC(pDraw, pGC); + (*pGC->ops->PutImage)(pDraw, pGC, 1, x, y, w, h, leftPad, + XYBitmap, (char *)pImage); + } + } + gcv[0].val = (XID)oldPlanemask; + gcv[1].val = (XID)oldFg; + gcv[2].val = (XID)oldBg; + ChangeGC(NullClient, pGC, GCPlaneMask | GCForeground | GCBackground, gcv); + ValidateGC(pDraw, pGC); + break; + + case ZPixmap: + ppt = pptFirst = malloc(h * sizeof(DDXPointRec)); + pwidth = pwidthFirst = malloc(h * sizeof(int)); + if(!pptFirst || !pwidthFirst) + { + free(pwidthFirst); + free(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); + free(pwidthFirst); + free(pptFirst); + break; + } +} diff --git a/mi/mibstore.h b/mi/mibstore.h new file mode 100644 index 0000000..c23caac --- /dev/null +++ b/mi/mibstore.h @@ -0,0 +1,23 @@ +/*- + * 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" + +#define miInitializeBackingStore(x) do {} while (0) + +#endif /* _MIBSTORE_H */ diff --git a/mi/micmap.c b/mi/micmap.c new file mode 100644 index 0000000..7448ef8 --- /dev/null +++ b/mi/micmap.c @@ -0,0 +1,670 @@ +/* + * Copyright (c) 1987, Oracle and/or its affiliates. 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 (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* + * 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" + +DevPrivateKeyRec micmapScrPrivateKeyRec; + +int +miListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps) +{ + if (GetInstalledmiColormap(pScreen)) { + *pmaps = GetInstalledmiColormap(pScreen)->mid; + return 1; + } + return 0; +} + +void +miInstallColormap(ColormapPtr pmap) +{ + ColormapPtr oldpmap = GetInstalledmiColormap(pmap->pScreen); + + 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 */ + SetInstalledmiColormap(pmap->pScreen, pmap); + WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid); + + } +} + +void +miUninstallColormap(ColormapPtr pmap) +{ + ColormapPtr curpmap = GetInstalledmiColormap(pmap->pScreen); + + if(pmap == curpmap) + { + if (pmap->mid != pmap->pScreen->defColormap) + { + dixLookupResourceByType((pointer *)&curpmap, + pmap->pScreen->defColormap, + RT_COLORMAP, serverClient, + DixUseAccess); + (*pmap->pScreen->InstallColormap)(curpmap); + } + } +} + +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; + } +} + +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; \ +} + +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; +} + +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; + + if (!dixRegisterPrivateKey(&micmapScrPrivateKeyRec, PRIVATE_SCREEN, 0)) + return FALSE; + + 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; + +void +miClearVisualTypes(void) +{ + miVisualsPtr v; + + while ((v = miVisuals)) { + miVisuals = v->next; + free(v); + } +} + + +Bool +miSetVisualTypesAndMasks(int depth, int visuals, int bitsPerRGB, + int preferredCVC, + Pixel redMask, Pixel greenMask, Pixel blueMask) +{ + miVisualsPtr new, *prev, v; + int count; + + new = malloc(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; +} + +Bool +miSetVisualTypes(int depth, int visuals, int bitsPerRGB, int preferredCVC) +{ + return miSetVisualTypesAndMasks (depth, visuals, bitsPerRGB, + preferredCVC, 0, 0, 0); +} + +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; +} + +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; +} + +/* + * 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. + */ + +Bool +miInitVisuals(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 = malloc(ndepth * sizeof (DepthRec)); + visual = malloc(nvisual * sizeof (VisualRec)); + preferredCVCs = malloc(ndepth * sizeof(int)); + if (!depth || !visual || !preferredCVCs) + { + free(depth); + free(visual); + free(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 = malloc(nvtype * sizeof (VisualID)); + if (!vid) { + free(depth); + free(visual); + free(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++; + } + free(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]; + free(preferredCVCs); + + return TRUE; +} diff --git a/mi/micmap.h b/mi/micmap.h new file mode 100644 index 0000000..c67710c --- /dev/null +++ b/mi/micmap.h @@ -0,0 +1,63 @@ + +#include "colormapst.h" + +#ifndef _MICMAP_H_ +#define _MICMAP_H_ + +#define GetInstalledmiColormap(s) \ + ((ColormapPtr) dixLookupPrivate(&(s)->devPrivates, micmapScrPrivateKey)) +#define SetInstalledmiColormap(s,c) \ + (dixSetPrivate(&(s)->devPrivates, micmapScrPrivateKey, c)) + +extern _X_EXPORT DevPrivateKeyRec micmapScrPrivateKeyRec; +#define micmapScrPrivateKey (&micmapScrPrivateKeyRec) + +typedef Bool (* miInitVisualsProcPtr)(VisualPtr *, DepthPtr *, int *, int *, + int *, VisualID *, unsigned long, int, + int); + +extern _X_EXPORT int miListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps); +extern _X_EXPORT void miInstallColormap(ColormapPtr pmap); +extern _X_EXPORT void miUninstallColormap(ColormapPtr pmap); + +extern _X_EXPORT void miResolveColor(unsigned short *, unsigned short *, unsigned short *, + VisualPtr); +extern _X_EXPORT Bool miInitializeColormap(ColormapPtr); +extern _X_EXPORT int miExpandDirectColors(ColormapPtr, int, xColorItem *, xColorItem *); +extern _X_EXPORT Bool miCreateDefColormap(ScreenPtr); +extern _X_EXPORT void miClearVisualTypes(void); +extern _X_EXPORT Bool miSetVisualTypes(int, int, int, int); +extern _X_EXPORT Bool miSetPixmapDepths(void); +extern _X_EXPORT Bool miSetVisualTypesAndMasks(int depth, int visuals, int bitsPerRGB, + int preferredCVC, + Pixel redMask, Pixel greenMask, Pixel blueMask); +extern _X_EXPORT int miGetDefaultVisualMask(int); +extern _X_EXPORT Bool miInitVisuals(VisualPtr *, DepthPtr *, int *, int *, int *, VisualID *, + unsigned long, int, int); + +#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/mi/micoord.h b/mi/micoord.h new file mode 100644 index 0000000..e6d814f --- /dev/null +++ b/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(sparc) || defined(__sparc64__) || \ + defined(__alpha) || defined(__alpha__) || \ + defined(__i386__) || defined(__i386) || defined(__ia64__) || \ + defined(__s390x__) || defined(__s390__) || \ + defined(__amd64__) || defined(amd64) || defined(__amd64) +#define GetHighWord(x) (((int) (x)) >> 16) +#else +#define GetHighWord(x) (((int) (x)) / 65536) +#endif + +#if IMAGE_BYTE_ORDER == MSBFirst +#define intToCoord(i,x,y) (((x) = GetHighWord(i)), ((y) = (int) ((short) (i)))) +#define coordToInt(x,y) (((x) << 16) | ((y) & 0xffff)) +#define intToX(i) (GetHighWord(i)) +#define intToY(i) ((int) ((short) i)) +#else +#define intToCoord(i,x,y) (((x) = (int) ((short) (i))), ((y) = GetHighWord(i))) +#define coordToInt(x,y) (((y) << 16) | ((x) & 0xffff)) +#define intToX(i) ((int) ((short) (i))) +#define intToY(i) (GetHighWord(i)) +#endif + +#endif /* _MICOORD_H_ */ diff --git a/mi/micopy.c b/mi/micopy.c new file mode 100644 index 0000000..652c620 --- /dev/null +++ b/mi/micopy.c @@ -0,0 +1,350 @@ +/* + * Copyright © 1998 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "mi.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmap.h" +#include "pixmapstr.h" +#include "windowstr.h" + +void +miCopyRegion (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + RegionPtr pDstRegion, + int dx, + int dy, + miCopyProc copyProc, + Pixel bitPlane, + void *closure) +{ + int careful; + Bool reverse; + Bool upsidedown; + BoxPtr pbox; + int nbox; + BoxPtr pboxNew1, pboxNew2, pboxBase, pboxNext, pboxTmp; + + pbox = RegionRects(pDstRegion); + nbox = RegionNumRects(pDstRegion); + + /* XXX we have to err on the side of safety when both are windows, + * because we don't know if IncludeInferiors is being used. + */ + careful = ((pSrcDrawable == pDstDrawable) || + ((pSrcDrawable->type == DRAWABLE_WINDOW) && + (pDstDrawable->type == DRAWABLE_WINDOW))); + + pboxNew1 = NULL; + pboxNew2 = NULL; + if (careful && dy < 0) + { + upsidedown = TRUE; + + if (nbox > 1) + { + /* keep ordering in each band, reverse order of bands */ + pboxNew1 = (BoxPtr)malloc(sizeof(BoxRec) * nbox); + if(!pboxNew1) + return; + pboxBase = pboxNext = pbox+nbox-1; + while (pboxBase >= pbox) + { + while ((pboxNext >= pbox) && + (pboxBase->y1 == pboxNext->y1)) + pboxNext--; + pboxTmp = pboxNext+1; + while (pboxTmp <= pboxBase) + { + *pboxNew1++ = *pboxTmp++; + } + pboxBase = pboxNext; + } + pboxNew1 -= nbox; + pbox = pboxNew1; + } + } + else + { + /* walk source top to bottom */ + upsidedown = FALSE; + } + + if (careful && dx < 0) + { + /* walk source right to left */ + if (dy <= 0) + reverse = TRUE; + else + reverse = FALSE; + + if (nbox > 1) + { + /* reverse order of rects in each band */ + pboxNew2 = (BoxPtr)malloc(sizeof(BoxRec) * nbox); + if(!pboxNew2) + { + free(pboxNew1); + return; + } + pboxBase = pboxNext = pbox; + while (pboxBase < pbox+nbox) + { + while ((pboxNext < pbox+nbox) && + (pboxNext->y1 == pboxBase->y1)) + pboxNext++; + pboxTmp = pboxNext; + while (pboxTmp != pboxBase) + { + *pboxNew2++ = *--pboxTmp; + } + pboxBase = pboxNext; + } + pboxNew2 -= nbox; + pbox = pboxNew2; + } + } + else + { + /* walk source left to right */ + reverse = FALSE; + } + + (*copyProc) (pSrcDrawable, + pDstDrawable, + pGC, + pbox, + nbox, + dx, dy, + reverse, upsidedown, bitPlane, closure); + + free(pboxNew1); + free(pboxNew2); +} + +RegionPtr +miDoCopy (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + int xIn, + int yIn, + int widthSrc, + int heightSrc, + int xOut, + int yOut, + miCopyProc copyProc, + Pixel bitPlane, + void *closure) +{ + RegionPtr prgnSrcClip = NULL; /* may be a new region, or just a copy */ + Bool freeSrcClip = FALSE; + RegionPtr prgnExposed = NULL; + RegionRec rgnDst; + int dx; + int dy; + int numRects; + int box_x1; + int box_y1; + int box_x2; + int box_y2; + Bool fastSrc = FALSE; /* for fast clipping with pixmap source */ + Bool fastDst = FALSE; /* for fast clipping with one rect dest */ + Bool fastExpose = FALSE; /* for fast exposures with pixmap source */ + + /* Short cut for unmapped windows */ + + if (pDstDrawable->type == DRAWABLE_WINDOW && + !((WindowPtr)pDstDrawable)->realized) + { + return NULL; + } + + if (pSrcDrawable->pScreen->SourceValidate) + { + (*pSrcDrawable->pScreen->SourceValidate) (pSrcDrawable, xIn, yIn, widthSrc, heightSrc, + pGC->subWindowMode); + } + + /* Compute source clip region */ + if (pSrcDrawable->type == DRAWABLE_PIXMAP) + { + if ((pSrcDrawable == pDstDrawable) && (pGC->clientClipType == CT_NONE)) + prgnSrcClip = miGetCompositeClip(pGC); + else + fastSrc = TRUE; + } + else + { + if (pGC->subWindowMode == IncludeInferiors) + { + /* + * XFree86 DDX empties the border clip when the + * VT is inactive, make sure the region isn't empty + */ + if (!((WindowPtr) pSrcDrawable)->parent && + RegionNotEmpty(&((WindowPtr) pSrcDrawable)->borderClip)) + { + /* + * special case bitblt from root window in + * IncludeInferiors mode; just like from a pixmap + */ + fastSrc = TRUE; + } + else if ((pSrcDrawable == pDstDrawable) && + (pGC->clientClipType == CT_NONE)) + { + prgnSrcClip = miGetCompositeClip(pGC); + } + else + { + prgnSrcClip = NotClippedByChildren((WindowPtr)pSrcDrawable); + freeSrcClip = TRUE; + } + } + else + { + prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList; + } + } + + xIn += pSrcDrawable->x; + yIn += pSrcDrawable->y; + + xOut += pDstDrawable->x; + yOut += pDstDrawable->y; + + box_x1 = xIn; + box_y1 = yIn; + box_x2 = xIn + widthSrc; + box_y2 = yIn + heightSrc; + + dx = xIn - xOut; + dy = yIn - yOut; + + /* Don't create a source region if we are doing a fast clip */ + if (fastSrc) + { + RegionPtr cclip; + + fastExpose = TRUE; + /* + * clip the source; if regions extend beyond the source size, + * make sure exposure events get sent + */ + if (box_x1 < pSrcDrawable->x) + { + box_x1 = pSrcDrawable->x; + fastExpose = FALSE; + } + if (box_y1 < pSrcDrawable->y) + { + box_y1 = pSrcDrawable->y; + fastExpose = FALSE; + } + if (box_x2 > pSrcDrawable->x + (int) pSrcDrawable->width) + { + box_x2 = pSrcDrawable->x + (int) pSrcDrawable->width; + fastExpose = FALSE; + } + if (box_y2 > pSrcDrawable->y + (int) pSrcDrawable->height) + { + box_y2 = pSrcDrawable->y + (int) pSrcDrawable->height; + fastExpose = FALSE; + } + + /* Translate and clip the dst to the destination composite clip */ + box_x1 -= dx; + box_x2 -= dx; + box_y1 -= dy; + box_y2 -= dy; + + /* If the destination composite clip is one rectangle we can + do the clip directly. Otherwise we have to create a full + blown region and call intersect */ + + cclip = miGetCompositeClip(pGC); + if (RegionNumRects(cclip) == 1) + { + BoxPtr pBox = RegionRects(cclip); + + if (box_x1 < pBox->x1) box_x1 = pBox->x1; + if (box_x2 > pBox->x2) box_x2 = pBox->x2; + if (box_y1 < pBox->y1) box_y1 = pBox->y1; + if (box_y2 > pBox->y2) box_y2 = pBox->y2; + fastDst = TRUE; + } + } + + /* Check to see if the region is empty */ + if (box_x1 >= box_x2 || box_y1 >= box_y2) + { + RegionNull(&rgnDst); + } + else + { + BoxRec box; + box.x1 = box_x1; + box.y1 = box_y1; + box.x2 = box_x2; + box.y2 = box_y2; + RegionInit(&rgnDst, &box, 1); + } + + /* Clip against complex source if needed */ + if (!fastSrc) + { + RegionIntersect(&rgnDst, &rgnDst, prgnSrcClip); + RegionTranslate(&rgnDst, -dx, -dy); + } + + /* Clip against complex dest if needed */ + if (!fastDst) + { + RegionIntersect(&rgnDst, &rgnDst, + miGetCompositeClip(pGC)); + } + + /* Do bit blitting */ + numRects = RegionNumRects(&rgnDst); + if (numRects && widthSrc && heightSrc) + miCopyRegion (pSrcDrawable, pDstDrawable, pGC, + &rgnDst, dx, dy, copyProc, bitPlane, closure); + + /* Pixmap sources generate a NoExposed (we return NULL to do this) */ + if (!fastExpose && pGC->fExpose) + prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, + xIn - pSrcDrawable->x, + yIn - pSrcDrawable->y, + widthSrc, heightSrc, + xOut - pDstDrawable->x, + yOut - pDstDrawable->y, + (unsigned long) bitPlane); + RegionUninit(&rgnDst); + if (freeSrcClip) + RegionDestroy(prgnSrcClip); + return prgnExposed; +} diff --git a/mi/micursor.c b/mi/micursor.c new file mode 100644 index 0000000..f6ae8f4 --- /dev/null +++ b/mi/micursor.c @@ -0,0 +1,69 @@ +/*********************************************************** + +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" +#include "inputstr.h" + +void +miRecolorCursor(DeviceIntPtr pDev, 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(pDev, pScr, pCurs); + pScr->RealizeCursor(pDev, pScr, pCurs); + if (displayed) + pScr->DisplayCursor(pDev, pScr, pCurs); +} diff --git a/mi/midash.c b/mi/midash.c new file mode 100644 index 0000000..ba64d35 --- /dev/null +++ b/mi/midash.c @@ -0,0 +1,91 @@ +/*********************************************************** + +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" + +void +miStepDash ( + 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/mi/midispcur.c b/mi/midispcur.c new file mode 100644 index 0000000..5a87fa2 --- /dev/null +++ b/mi/midispcur.c @@ -0,0 +1,584 @@ +/* + * 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 + +# 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 + +# include "inputstr.h" + +/* per-screen private data */ +static DevPrivateKeyRec miDCScreenKeyRec; +#define miDCScreenKey (&miDCScreenKeyRec) +static DevScreenPrivateKeyRec miDCCursorBitsKeyRec; +#define miDCCursorBitsKey (&miDCCursorBitsKeyRec) +static DevScreenPrivateKeyRec miDCDeviceKeyRec; +#define miDCDeviceKey (&miDCDeviceKeyRec) + +static Bool miDCCloseScreen(int index, ScreenPtr pScreen); + +/* per device private data */ +typedef struct { + GCPtr pSourceGC, pMaskGC; + GCPtr pSaveGC, pRestoreGC; + PixmapPtr pSave; +#ifdef ARGB_CURSOR + PicturePtr pRootPicture; +#endif +} miDCBufferRec, *miDCBufferPtr; + +#define miGetDCDevice(dev, screen) \ + ((DevHasCursor(dev)) ? \ + (miDCBufferPtr)dixLookupScreenPrivate(&dev->devPrivates, miDCDeviceKey, screen) : \ + (miDCBufferPtr)dixLookupScreenPrivate(&dev->u.master->devPrivates, miDCDeviceKey, screen)) + +/* + * The core pointer buffer will point to the index of the virtual core pointer + * in the pCursorBuffers array. + */ +typedef struct { + CloseScreenProcPtr CloseScreen; +} miDCScreenRec, *miDCScreenPtr; + +#define miGetDCScreen(s) ((miDCScreenPtr)(dixLookupPrivate(&(s)->devPrivates, miDCScreenKey))) + +/* per-cursor per-screen private data */ +typedef struct { + PixmapPtr sourceBits; /* source bits */ + PixmapPtr maskBits; /* mask bits */ +#ifdef ARGB_CURSOR + PicturePtr pPicture; +#endif +} miDCCursorRec, *miDCCursorPtr; + +Bool +miDCInitialize (ScreenPtr pScreen, miPointerScreenFuncPtr screenFuncs) +{ + miDCScreenPtr pScreenPriv; + + if (!dixRegisterPrivateKey(&miDCScreenKeyRec, PRIVATE_SCREEN, 0) || + !dixRegisterScreenPrivateKey(&miDCCursorBitsKeyRec, pScreen, PRIVATE_CURSOR_BITS, 0) || + !dixRegisterScreenPrivateKey(&miDCDeviceKeyRec, pScreen, PRIVATE_DEVICE, 0)) + return FALSE; + + pScreenPriv = malloc(sizeof (miDCScreenRec)); + if (!pScreenPriv) + return FALSE; + + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = miDCCloseScreen; + + dixSetPrivate(&pScreen->devPrivates, miDCScreenKey, pScreenPriv); + + if (!miSpriteInitialize (pScreen, screenFuncs)) + { + free((pointer) pScreenPriv); + return FALSE; + } + return TRUE; +} + +static Bool +miDCCloseScreen (int index, ScreenPtr pScreen) +{ + miDCScreenPtr pScreenPriv; + + pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, + miDCScreenKey); + pScreen->CloseScreen = pScreenPriv->CloseScreen; + free((pointer) pScreenPriv); + return (*pScreen->CloseScreen) (index, pScreen); +} + +Bool +miDCRealizeCursor (ScreenPtr pScreen, CursorPtr pCursor) +{ + if (pCursor->bits->refcnt <= 1) + dixSetScreenPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey, 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; + ChangeGCVal gcvals; + + pPriv = malloc(sizeof (miDCCursorRec)); + if (!pPriv) + return NULL; +#ifdef ARGB_CURSOR + if (pCursor->bits->argb) + { + PixmapPtr pPixmap; + PictFormatPtr pFormat; + int error; + + pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); + if (!pFormat) + { + free((pointer) pPriv); + return NULL; + } + + pPriv->sourceBits = 0; + pPriv->maskBits = 0; + pPixmap = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, + pCursor->bits->height, 32, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pPixmap) + { + free((pointer) pPriv); + return NULL; + } + pGC = GetScratchGC (32, pScreen); + if (!pGC) + { + (*pScreen->DestroyPixmap) (pPixmap); + free((pointer) pPriv); + return 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) + { + free((pointer) pPriv); + return NULL; + } + dixSetScreenPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey, pScreen, pPriv); + return pPriv; + } + pPriv->pPicture = 0; +#endif + pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0); + if (!pPriv->sourceBits) + { + free((pointer) pPriv); + return NULL; + } + pPriv->maskBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0); + if (!pPriv->maskBits) + { + (*pScreen->DestroyPixmap) (pPriv->sourceBits); + free((pointer) pPriv); + return NULL; + } + dixSetScreenPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey, pScreen, pPriv); + + /* create the two sets of bits, clipping as appropriate */ + + pGC = GetScratchGC (1, pScreen); + if (!pGC) + { + (void) miDCUnrealizeCursor (pScreen, pCursor); + return 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.val = GXand; + ChangeGC (NullClient, 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.val = GXcopy; + ChangeGC (NullClient, 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.val = GXandInverted; + ChangeGC (NullClient, 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; +} + +Bool +miDCUnrealizeCursor (ScreenPtr pScreen, CursorPtr pCursor) +{ + miDCCursorPtr pPriv; + + pPriv = (miDCCursorPtr)dixLookupScreenPrivate(&pCursor->bits->devPrivates, + miDCCursorBitsKey, 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 + free((pointer) pPriv); + dixSetScreenPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey, 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) +{ + ChangeGCVal gcval; + int x, y; + + if (sourceGC->fgPixel != source) + { + gcval.val = source; + ChangeGC (NullClient, sourceGC, GCForeground, &gcval); + } + 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) + { + gcval.val = mask; + ChangeGC (NullClient, maskGC, GCForeground, &gcval); + } + 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); +} + +static GCPtr +miDCMakeGC(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); + return pGC; +} + + +Bool +miDCPutUpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, + int x, int y, unsigned long source, unsigned long mask) +{ + miDCCursorPtr pPriv; + miDCBufferPtr pBuffer; + WindowPtr pWin; + + pPriv = (miDCCursorPtr)dixLookupScreenPrivate(&pCursor->bits->devPrivates, + miDCCursorBitsKey, pScreen); + if (!pPriv) + { + pPriv = miDCRealize(pScreen, pCursor); + if (!pPriv) + return FALSE; + } + + pWin = pScreen->root; + pBuffer = miGetDCDevice(pDev, pScreen); + +#ifdef ARGB_CURSOR + if (pPriv->pPicture) + { + if (!EnsurePicture(pBuffer->pRootPicture, &pWin->drawable, pWin)) + return FALSE; + CompositePicture (PictOpOver, + pPriv->pPicture, + NULL, + pBuffer->pRootPicture, + 0, 0, 0, 0, + x, y, + pCursor->bits->width, + pCursor->bits->height); + } + else +#endif + { + miDCPutBits ((DrawablePtr)pWin, pPriv, + pBuffer->pSourceGC, pBuffer->pMaskGC, + x, y, pCursor->bits->width, pCursor->bits->height, + source, mask); + } + return TRUE; +} + +Bool +miDCSaveUnderCursor (DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y, int w, int h) +{ + miDCBufferPtr pBuffer; + PixmapPtr pSave; + WindowPtr pWin; + GCPtr pGC; + + pBuffer = miGetDCDevice(pDev, pScreen); + + pSave = pBuffer->pSave; + pWin = pScreen->root; + if (!pSave || pSave->drawable.width < w || pSave->drawable.height < h) + { + if (pSave) + (*pScreen->DestroyPixmap) (pSave); + pBuffer->pSave = pSave = + (*pScreen->CreatePixmap) (pScreen, w, h, pScreen->rootDepth, 0); + if (!pSave) + return FALSE; + } + + pGC = pBuffer->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; +} + +Bool +miDCRestoreUnderCursor (DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y, int w, int h) +{ + miDCBufferPtr pBuffer; + PixmapPtr pSave; + WindowPtr pWin; + GCPtr pGC; + + pBuffer = miGetDCDevice(pDev, pScreen); + pSave = pBuffer->pSave; + + pWin = pScreen->root; + if (!pSave) + return FALSE; + + pGC = pBuffer->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; +} + +Bool +miDCDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miDCBufferPtr pBuffer; + WindowPtr pWin; + int i; + + if (!DevHasCursor(pDev)) + return TRUE; + + for (i = 0; i < screenInfo.numScreens; i++) + { + pScreen = screenInfo.screens[i]; + + pBuffer = calloc(1, sizeof(miDCBufferRec)); + if (!pBuffer) + goto failure; + + dixSetScreenPrivate(&pDev->devPrivates, miDCDeviceKey, pScreen, pBuffer); + pWin = pScreen->root; + + pBuffer->pSourceGC = miDCMakeGC(pWin); + if (!pBuffer->pSourceGC) + goto failure; + + pBuffer->pMaskGC = miDCMakeGC(pWin); + if (!pBuffer->pMaskGC) + goto failure; + + pBuffer->pSaveGC = miDCMakeGC(pWin); + if (!pBuffer->pSaveGC) + goto failure; + + pBuffer->pRestoreGC = miDCMakeGC(pWin); + if (!pBuffer->pRestoreGC) + goto failure; + +#ifdef ARGB_CURSOR + pBuffer->pRootPicture = NULL; +#endif + + /* (re)allocated lazily depending on the cursor size */ + pBuffer->pSave = NULL; + } + + return TRUE; + +failure: + + miDCDeviceCleanup(pDev, pScreen); + + return FALSE; +} + +void +miDCDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miDCBufferPtr pBuffer; + int i; + + if (DevHasCursor(pDev)) + { + for (i = 0; i < screenInfo.numScreens; i++) + { + pScreen = screenInfo.screens[i]; + + pBuffer = miGetDCDevice(pDev, pScreen); + + if (pBuffer) + { + if (pBuffer->pSourceGC) FreeGC(pBuffer->pSourceGC, (GContext) 0); + if (pBuffer->pMaskGC) FreeGC(pBuffer->pMaskGC, (GContext) 0); + if (pBuffer->pSaveGC) FreeGC(pBuffer->pSaveGC, (GContext) 0); + if (pBuffer->pRestoreGC) FreeGC(pBuffer->pRestoreGC, (GContext) 0); + +#ifdef ARGB_CURSOR + /* If a pRootPicture was allocated for a root window, it + * is freed when that root window is destroyed, so don't + * free it again here. */ +#endif + + if (pBuffer->pSave) (*pScreen->DestroyPixmap)(pBuffer->pSave); + + free(pBuffer); + dixSetScreenPrivate(&pDev->devPrivates, miDCDeviceKey, pScreen, NULL); + } + } + } +} diff --git a/mi/mieq.c b/mi/mieq.c new file mode 100644 index 0000000..cd1e47f --- /dev/null +++ b/mi/mieq.c @@ -0,0 +1,495 @@ +/* + * +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 + +# 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 <X11/extensions/geproto.h> +# include "extinit.h" +# include "exglobals.h" +# include "eventstr.h" + +#ifdef DPMSExtension +# include "dpmsproc.h" +# include <X11/extensions/dpmsconst.h> +#endif + +#define QUEUE_SIZE 512 + +#define EnqueueScreen(dev) dev->spriteInfo->sprite->pEnqueueScreen +#define DequeueScreen(dev) dev->spriteInfo->sprite->pDequeueScreen + +typedef struct _Event { + EventListPtr events; + 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 */ + mieqHandler handlers[128]; /* custom event handler */ +} EventQueueRec, *EventQueuePtr; + +static EventQueueRec miEventQueue; + +#ifdef XQUARTZ +#include <pthread.h> +static pthread_mutex_t miEventQueueMutex = PTHREAD_MUTEX_INITIALIZER; + +extern BOOL serverRunning; +extern pthread_mutex_t serverRunningMutex; +extern pthread_cond_t serverRunningCond; + +static inline void wait_for_server_init(void) { + /* If the server hasn't finished initializing, wait for it... */ + if(!serverRunning) { + pthread_mutex_lock(&serverRunningMutex); + while(!serverRunning) + pthread_cond_wait(&serverRunningCond, &serverRunningMutex); + pthread_mutex_unlock(&serverRunningMutex); + } +} +#endif + +Bool +mieqInit(void) +{ + int i; + + miEventQueue.head = miEventQueue.tail = 0; + miEventQueue.lastEventTime = GetTimeInMillis (); + miEventQueue.lastMotion = FALSE; + for (i = 0; i < 128; i++) + miEventQueue.handlers[i] = NULL; + for (i = 0; i < QUEUE_SIZE; i++) + { + if (miEventQueue.events[i].events == NULL) { + EventListPtr evlist = InitEventList(1); + if (!evlist) + FatalError("Could not allocate event queue.\n"); + miEventQueue.events[i].events = evlist; + } + } + + SetInputCheck(&miEventQueue.head, &miEventQueue.tail); + return TRUE; +} + +void +mieqFini(void) +{ + int i; + for (i = 0; i < QUEUE_SIZE; i++) + { + if (miEventQueue.events[i].events != NULL) { + FreeEventList(miEventQueue.events[i].events, 1); + miEventQueue.events[i].events = NULL; + } + } +} + +/* + * 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, InternalEvent *e) +{ + unsigned int oldtail = miEventQueue.tail; + EventListPtr evt; + int isMotion = 0; + int evlen; + Time time; + +#ifdef XQUARTZ + wait_for_server_init(); + pthread_mutex_lock(&miEventQueueMutex); +#endif + + CHECKEVENT(e); + + /* avoid merging events from different devices */ + if (e->any.type == ET_Motion) + isMotion = pDev->id; + + if (isMotion && isMotion == miEventQueue.lastMotion && + oldtail != miEventQueue.head) { + oldtail = (oldtail - 1) % QUEUE_SIZE; + } + else { + static int stuck = 0; + /* 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 (((oldtail + 1) % QUEUE_SIZE) == miEventQueue.head) { + if (!stuck) { + ErrorF("[mi] EQ overflowing. The server is probably stuck " + "in an infinite loop.\n"); + xorg_backtrace(); + stuck = 1; + } +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif + return; + } + stuck = 0; + } + + evlen = e->any.length; + evt = miEventQueue.events[oldtail].events; + if (evt->evlen < evlen) + { + evt->evlen = evlen; + evt->event = realloc(evt->event, evt->evlen); + if (!evt->event) + { + ErrorF("[mi] Running out of memory. Tossing event.\n"); +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif + return; + } + } + + memcpy(evt->event, e, evlen); + + time = e->any.time; + /* Make sure that event times don't go backwards - this + * is "unnecessary", but very useful. */ + if (time < miEventQueue.lastEventTime && + miEventQueue.lastEventTime - time < 10000) + e->any.time = miEventQueue.lastEventTime; + + miEventQueue.lastEventTime = ((InternalEvent*)evt->event)->any.time; + miEventQueue.events[oldtail].pScreen = pDev ? EnqueueScreen(pDev) : NULL; + miEventQueue.events[oldtail].pDev = pDev; + + miEventQueue.lastMotion = isMotion; + miEventQueue.tail = (oldtail + 1) % QUEUE_SIZE; +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif +} + +void +mieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool fromDIX) +{ +#ifdef XQUARTZ + pthread_mutex_lock(&miEventQueueMutex); +#endif + EnqueueScreen(pDev) = pScreen; + if (fromDIX) + DequeueScreen(pDev) = pScreen; +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif +} + +void +mieqSetHandler(int event, mieqHandler handler) +{ +#ifdef XQUARTZ + pthread_mutex_lock(&miEventQueueMutex); +#endif + if (handler && miEventQueue.handlers[event]) + ErrorF("[mi] mieq: warning: overriding existing handler %p with %p for " + "event %d\n", miEventQueue.handlers[event], handler, event); + + miEventQueue.handlers[event] = handler; +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif +} + +/** + * Change the device id of the given event to the given device's id. + */ +static void +ChangeDeviceID(DeviceIntPtr dev, InternalEvent* event) +{ + switch(event->any.type) + { + case ET_Motion: + case ET_KeyPress: + case ET_KeyRelease: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_ProximityIn: + case ET_ProximityOut: + case ET_Hierarchy: + case ET_DeviceChanged: + event->device_event.deviceid = dev->id; + break; +#if XFreeXDGA + case ET_DGAEvent: + break; +#endif + case ET_RawKeyPress: + case ET_RawKeyRelease: + case ET_RawButtonPress: + case ET_RawButtonRelease: + case ET_RawMotion: + event->raw_event.deviceid = dev->id; + break; + default: + ErrorF("[mi] Unknown event type (%d), cannot change id.\n", + event->any.type); + } +} + +static void +FixUpEventForMaster(DeviceIntPtr mdev, DeviceIntPtr sdev, + InternalEvent* original, InternalEvent *master) +{ + CHECKEVENT(original); + CHECKEVENT(master); + /* Ensure chained button mappings, i.e. that the detail field is the + * value of the mapped button on the SD, not the physical button */ + if (original->any.type == ET_ButtonPress || + original->any.type == ET_ButtonRelease) + { + int btn = original->device_event.detail.button; + if (!sdev->button) + return; /* Should never happen */ + + master->device_event.detail.button = sdev->button->map[btn]; + } +} + +/** + * Copy the given event into master. + * @param sdev The slave device the original event comes from + * @param original The event as it came from the EQ + * @param copy The event after being copied + * @return The master device or NULL if the device is a floating slave. + */ +DeviceIntPtr +CopyGetMasterEvent(DeviceIntPtr sdev, + InternalEvent* original, InternalEvent *copy) +{ + DeviceIntPtr mdev; + int len = original->any.length; + int type = original->any.type; + + CHECKEVENT(original); + + /* ET_XQuartz has sdev == NULL */ + if (!sdev || !sdev->u.master) + return NULL; + +#if XFreeXDGA + if (type == ET_DGAEvent) + type = original->dga_event.subtype; +#endif + + switch(type) + { + case ET_KeyPress: + case ET_KeyRelease: + mdev = GetMaster(sdev, MASTER_KEYBOARD); + break; + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_Motion: + case ET_ProximityIn: + case ET_ProximityOut: + mdev = GetMaster(sdev, MASTER_POINTER); + break; + default: + mdev = sdev->u.master; + break; + } + + memcpy(copy, original, len); + ChangeDeviceID(mdev, copy); + FixUpEventForMaster(mdev, sdev, original, copy); + + return mdev; +} + + +/** + * Post the given @event through the device hierarchy, as appropriate. + * Use this function if an event must be posted for a given device during the + * usual event processing cycle. + */ +void +mieqProcessDeviceEvent(DeviceIntPtr dev, + InternalEvent *event, + ScreenPtr screen) +{ + mieqHandler handler; + int x = 0, y = 0; + DeviceIntPtr master; + InternalEvent mevent; /* master event */ + + CHECKEVENT(event); + + /* Custom event handler */ + handler = miEventQueue.handlers[event->any.type]; + + switch (event->any.type) { + /* Catch events that include valuator information and check if they + * are changing the screen */ + case ET_Motion: + case ET_KeyPress: + case ET_KeyRelease: + case ET_ButtonPress: + case ET_ButtonRelease: + if (dev && screen && screen != DequeueScreen(dev) && !handler) { + DequeueScreen(dev) = screen; + x = event->device_event.root_x; + y = event->device_event.root_y; + NewCurrentScreen (dev, DequeueScreen(dev), x, y); + } + break; + default: + break; + } + master = CopyGetMasterEvent(dev, event, &mevent); + + if (master) + master->u.lastSlave = dev; + + /* If someone's registered a custom event handler, let them + * steal it. */ + if (handler) + { + int screenNum = dev && DequeueScreen(dev) ? DequeueScreen(dev)->myNum : (screen ? screen->myNum : 0); + handler(screenNum, event, dev); + /* Check for the SD's master in case the device got detached + * during event processing */ + if (master && dev->u.master) + handler(screenNum, &mevent, master); + } else + { + /* process slave first, then master */ + dev->public.processInputProc(event, dev); + + /* Check for the SD's master in case the device got detached + * during event processing */ + if (master && dev->u.master) + master->public.processInputProc(&mevent, master); + } +} + +/* Call this from ProcessInputEvents(). */ +void +mieqProcessInputEvents(void) +{ + EventRec *e = NULL; + int evlen; + ScreenPtr screen; + static InternalEvent *event = NULL; + static size_t event_size = 0; + DeviceIntPtr dev = NULL, + master = NULL; + +#ifdef XQUARTZ + pthread_mutex_lock(&miEventQueueMutex); +#endif + + while (miEventQueue.head != miEventQueue.tail) { + e = &miEventQueue.events[miEventQueue.head]; + + evlen = e->events->evlen; + if(evlen > event_size) + { + event = realloc(event, evlen); + event_size = evlen; + } + + + if (!event) + FatalError("[mi] No memory left for event processing.\n"); + + memcpy(event, e->events->event, evlen); + + + dev = e->pDev; + screen = e->pScreen; + + miEventQueue.head = (miEventQueue.head + 1) % QUEUE_SIZE; + +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif + + master = (dev && !IsMaster(dev) && dev->u.master) ? dev->u.master : NULL; + + 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 + + mieqProcessDeviceEvent(dev, event, screen); + + /* Update the sprite now. Next event may be from different device. */ + if (event->any.type == ET_Motion && master) + miPointerUpdateSprite(dev); + +#ifdef XQUARTZ + pthread_mutex_lock(&miEventQueueMutex); +#endif + } +#ifdef XQUARTZ + pthread_mutex_unlock(&miEventQueueMutex); +#endif +} + diff --git a/mi/miexpose.c b/mi/miexpose.c new file mode 100644 index 0000000..94258b8 --- /dev/null +++ b/mi/miexpose.c @@ -0,0 +1,697 @@ +/*********************************************************** + +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> +#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. + +*/ + +RegionPtr +miHandleExposures(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, + GCPtr pGC, int srcx, int srcy, int width, int height, + int dstx, int dsty, unsigned long plane) +{ + 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; + + /* 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 ((RegionContainsRect(prgnSrcClip, &TsrcBox)) == rgnIN) + { + RegionDestroy(prgnSrcClip); + return NULL; + } + } + else + { + if ((RegionContainsRect(&pSrcWin->clipList, &TsrcBox)) == rgnIN) + return NULL; + prgnSrcClip = &rgnSrcRec; + RegionNull(prgnSrcClip); + RegionCopy(prgnSrcClip, &pSrcWin->clipList); + } + RegionTranslate(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; + RegionInit(prgnSrcClip, &box, 1); + pSrcWin = NULL; + } + + if (pDstDrawable == pSrcDrawable) + { + prgnDstClip = prgnSrcClip; + } + else if (pDstDrawable->type != DRAWABLE_PIXMAP) + { + if (pGC->subWindowMode == IncludeInferiors) + { + prgnDstClip = NotClippedByChildren((WindowPtr)pDstDrawable); + } + else + { + prgnDstClip = &rgnDstRec; + RegionNull(prgnDstClip); + RegionCopy(prgnDstClip, + &((WindowPtr)pDstDrawable)->clipList); + } + RegionTranslate(prgnDstClip, + -pDstDrawable->x, -pDstDrawable->y); + } + else + { + BoxRec box; + + box.x1 = 0; + box.y1 = 0; + box.x2 = pDstDrawable->width; + box.y2 = pDstDrawable->height; + prgnDstClip = &rgnDstRec; + RegionInit(prgnDstClip, &box, 1); + } + + /* drawable-relative source region */ + RegionInit(&rgnExposed, &srcBox, 1); + + /* now get the hidden parts of the source box*/ + RegionSubtract(&rgnExposed, &rgnExposed, prgnSrcClip); + + /* move them over the destination */ + RegionTranslate(&rgnExposed, dstx-srcx, dsty-srcy); + + /* intersect with visible areas of dest */ + RegionIntersect(&rgnExposed, &rgnExposed, prgnDstClip); + + /* intersect with client clip region. */ + if (pGC->clientClipType == CT_REGION) + RegionIntersect(&rgnExposed, &rgnExposed, pGC->clientClip); + + /* + * 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 && + (RegionNumRects(&rgnExposed) > RECTLIMIT) && + (pDstDrawable->type != DRAWABLE_PIXMAP); + 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 && + (RegionContainsRect(region, &srcBox) != rgnIN)) + extents = FALSE; + } + if (extents) + { + expBox = *RegionExtents(&rgnExposed); + RegionReset(&rgnExposed, &expBox); + } + if ((pDstDrawable->type != DRAWABLE_PIXMAP) && + (((WindowPtr)pDstDrawable)->backgroundState != None)) + { + WindowPtr pWin = (WindowPtr)pDstDrawable; + + /* make the exposed area screen-relative */ + RegionTranslate(&rgnExposed, + pDstDrawable->x, pDstDrawable->y); + + if (extents) + { + /* miPaintWindow doesn't clip, so we have to */ + RegionIntersect(&rgnExposed, &rgnExposed, &pWin->clipList); + } + miPaintWindow((WindowPtr)pDstDrawable, &rgnExposed, PW_BACKGROUND); + + if (extents) + { + RegionReset(&rgnExposed, &expBox); + } + else + RegionTranslate(&rgnExposed, + -pDstDrawable->x, -pDstDrawable->y); + } + if (prgnDstClip == &rgnDstRec) + { + RegionUninit(prgnDstClip); + } + else if (prgnDstClip != prgnSrcClip) + { + RegionDestroy(prgnDstClip); + } + + if (prgnSrcClip == &rgnSrcRec) + { + RegionUninit(prgnSrcClip); + } + else + { + RegionDestroy(prgnSrcClip); + } + + if (pGC->graphicsExposures) + { + /* don't look */ + RegionPtr exposed = RegionCreate(NullBox, 0); + *exposed = rgnExposed; + return exposed; + } + else + { + RegionUninit(&rgnExposed); + return NULL; + } +} + +/* send GraphicsExpose events, or a NoExpose event, based on the region */ + +void +miSendGraphicsExpose (ClientPtr client, RegionPtr pRgn, XID drawable, + int major, int minor) +{ + if (pRgn && !RegionNil(pRgn)) + { + xEvent *pEvent; + xEvent *pe; + BoxPtr pBox; + int i; + int numRects; + + numRects = RegionNumRects(pRgn); + pBox = RegionRects(pRgn); + if(!(pEvent = malloc(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; + } + /* GraphicsExpose is a "critical event", which TryClientEvents + * handles specially. */ + TryClientEvents(client, NULL, pEvent, numRects, + (Mask)0, NoEventMask, NullGrab); + free(pEvent); + } + else + { + xEvent event; + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = NoExpose; + event.u.noExposure.drawable = drawable; + event.u.noExposure.majorEvent = major; + event.u.noExposure.minorEvent = minor; + WriteEventsToClient(client, 1, &event); + } +} + + +void +miSendExposures( WindowPtr pWin, RegionPtr pRgn, int dx, int dy) +{ + BoxPtr pBox; + int numRects; + xEvent *pEvent, *pe; + int i; + + pBox = RegionRects(pRgn); + numRects = RegionNumRects(pRgn); + if(!(pEvent = calloc(1, 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 = screenInfo.screens[scrnum]->x; + y = screenInfo.screens[scrnum]->y; + pWin = screenInfo.screens[0]->root; + realWin = pWin->drawable.id; + } else if (scrnum) { + PanoramiXRes *win; + win = PanoramiXFindIDByScrnum(XRT_WINDOW, + pWin->drawable.id, scrnum); + if(!win) { + free(pEvent); + return; + } + realWin = win->info[0].id; + dixLookupWindow(&pWin, realWin, serverClient, DixSendAccess); + } + 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); + + free(pEvent); +} + +void +miWindowExposures( WindowPtr pWin, RegionPtr prgn, RegionPtr other_exposed) +{ + RegionPtr exposures = prgn; + if ((prgn && !RegionNil(prgn)) || + (exposures && !RegionNil(exposures)) || other_exposed) + { + RegionRec expRec; + int clientInterested; + + /* + * Restore from backing-store FIRST. + */ + clientInterested = (pWin->eventMask|wOtherEventMasks(pWin)) & ExposureMask; + if (other_exposed) + { + if (exposures) + { + RegionUnion(other_exposed, + exposures, + other_exposed); + if (exposures != prgn) + RegionDestroy(exposures); + } + exposures = other_exposed; + } + if (clientInterested && exposures && (RegionNumRects(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 = *RegionExtents(exposures); + if (exposures == prgn) { + exposures = &expRec; + RegionInit(exposures, &box, 1); + RegionReset(prgn, &box); + } else { + RegionReset(exposures, &box); + RegionUnion(prgn, prgn, exposures); + } + /* miPaintWindow doesn't clip, so we have to */ + RegionIntersect(prgn, prgn, &pWin->clipList); + } + if (prgn && !RegionNil(prgn)) + miPaintWindow(pWin, prgn, PW_BACKGROUND); + if (clientInterested && exposures && !RegionNil(exposures)) + miSendExposures(pWin, exposures, + pWin->drawable.x, pWin->drawable.y); + if (exposures == &expRec) + { + RegionUninit(exposures); + } + else if (exposures && exposures != prgn && exposures != other_exposed) + RegionDestroy(exposures); + if (prgn) + RegionEmpty(prgn); + } + else if (exposures && exposures != prgn) + RegionDestroy(exposures); +} + +#ifdef ROOTLESS +/* Ugly, ugly, but we lost our hooks into miPaintWindow... =/ */ +void RootlessSetPixmapOfAncestors(WindowPtr pWin); +void RootlessStartDrawing(WindowPtr pWin); +void RootlessDamageRegion(WindowPtr pWin, RegionPtr prgn); +Bool IsFramedWindow(WindowPtr pWin); +#endif + +void +miPaintWindow(WindowPtr pWin, RegionPtr prgn, int what) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + ChangeGCVal gcval[6]; + 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; + +#ifdef ROOTLESS + if(!drawable || drawable->type == UNDRAWABLE_WINDOW) + return; + + if(IsFramedWindow(pWin)) { + RootlessStartDrawing(pWin); + RootlessDamageRegion(pWin, prgn); + + if(pWin->backgroundState == ParentRelative) { + if((what == PW_BACKGROUND) || + (what == PW_BORDER && !pWin->borderIsPixel)) + RootlessSetPixmapOfAncestors(pWin); + } + } +#endif + + 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; + +#ifdef ROOTLESS_SAFEALPHA +/* Bit mask for alpha channel with a particular number of bits per + * pixel. Note that we only care for 32bpp data. Mac OS X uses planar + * alpha for 16bpp. + */ +#define RootlessAlphaMask(bpp) ((bpp) == 32 ? 0xFF000000 : 0) +#endif + + if (solid) + { +#ifdef ROOTLESS_SAFEALPHA + gcval[1].val = fill.pixel | RootlessAlphaMask(pWin->drawable.bitsPerPixel); +#else + gcval[1].val = fill.pixel; +#endif + gcval[2].val = FillSolid; + gcmask |= GCForeground | GCFillStyle; + } + else + { + int c=1; +#ifdef ROOTLESS_SAFEALPHA + gcval[c++].val = ((CARD32)-1) & ~RootlessAlphaMask(pWin->drawable.bitsPerPixel); + gcmask |= GCPlaneMask; +#endif + gcval[c++].val = FillTiled; + gcval[c++].ptr = (pointer)fill.pixmap; + gcval[c++].val = tile_x_off; + gcval[c++].val = tile_y_off; + gcmask |= GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin; + } + + prect = malloc(RegionNumRects(prgn) * sizeof(xRectangle)); + if (!prect) + return; + + pGC = GetScratchGC(drawable->depth, drawable->pScreen); + if (!pGC) + { + free(prect); + return; + } + + ChangeGC (NullClient, pGC, gcmask, gcval); + ValidateGC (drawable, pGC); + + numRects = RegionNumRects(prgn); + pbox = RegionRects(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); + free(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. */ +void +miClearDrawable(DrawablePtr pDraw, GCPtr pGC) +{ + ChangeGCVal fg, bg; + xRectangle rect; + + fg.val = pGC->fgPixel; + bg.val = pGC->bgPixel; + rect.x = 0; + rect.y = 0; + rect.width = pDraw->width; + rect.height = pDraw->height; + ChangeGC(NullClient, pGC, GCForeground, &bg); + ValidateGC(pDraw, pGC); + (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect); + ChangeGC(NullClient, pGC, GCForeground, &fg); + ValidateGC(pDraw, pGC); +} diff --git a/mi/mifillarc.c b/mi/mifillarc.c new file mode 100644 index 0000000..6e13e68 --- /dev/null +++ b/mi/mifillarc.c @@ -0,0 +1,798 @@ +/************************************************************ + +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)) + +void +miFillArcSetup(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); +} + +void +miFillArcSliceSetup(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 = malloc(sizeof(DDXPointRec) * arc->height); + if (!points) + return; + widths = malloc(sizeof(int) * arc->height); + if (!widths) + { + free(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); + free(widths); + free(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 = malloc(sizeof(DDXPointRec) * arc->height); + if (!points) + return; + widths = malloc(sizeof(int) * arc->height); + if (!widths) + { + free(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); + free(widths); + free(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 = malloc(sizeof(DDXPointRec) * slw); + if (!points) + return; + widths = malloc(sizeof(int) * slw); + if (!widths) + { + free(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); + free(widths); + free(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 = malloc(sizeof(DDXPointRec) * slw); + if (!points) + return; + widths = malloc(sizeof(int) * slw); + if (!widths) + { + free(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); + free(widths); + free(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. + */ +void +miPolyFillArc(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/mi/mifillarc.h b/mi/mifillarc.h new file mode 100644 index 0000000..1158754 --- /dev/null +++ b/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 _X_EXPORT void miFillArcSetup( + xArc * /*arc*/, + miFillArcRec * /*info*/ +); + +extern _X_EXPORT void miFillArcSliceSetup( + xArc * /*arc*/, + miArcSliceRec * /*slice*/, + GCPtr /*pGC*/ +); + +#endif /* __MIFILLARC_H__ */ diff --git a/mi/mifillrct.c b/mi/mifillrct.c new file mode 100644 index 0000000..1c63a35 --- /dev/null +++ b/mi/mifillrct.c @@ -0,0 +1,143 @@ +/*********************************************************** + +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 + */ +void +miPolyFillRect( + 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 = malloc(maxheight * sizeof(DDXPointRec)); + pwFirst = malloc(maxheight * sizeof(int)); + if(!pptFirst || !pwFirst) + { + free(pwFirst); + free(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++; + } + free(pwFirst); + free(pptFirst); +} diff --git a/mi/mifpoly.h b/mi/mifpoly.h new file mode 100644 index 0000000..ffd19a3 --- /dev/null +++ b/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 _X_EXPORT void miFillSppPoly( + DrawablePtr /*dst*/, + GCPtr /*pgc*/, + int /*count*/, + SppPointPtr /*ptsIn*/, + int /*xTrans*/, + int /*yTrans*/, + double /*xFtrans*/, + double /*yFtrans*/ +); + +#endif /* __MIFPOLY_H__ */ diff --git a/mi/mifpolycon.c b/mi/mifpolycon.c new file mode 100644 index 0000000..e48686a --- /dev/null +++ b/mi/mifpolycon.c @@ -0,0 +1,280 @@ +/*********************************************************** + +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( + DrawablePtr dst, + GCPtr pgc, + int count, /* number of points */ + SppPointPtr ptsIn, /* the points */ + int xTrans, int yTrans, /* Translate each point by this */ + double xFtrans, + double 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 = malloc(sizeof(DDXPointRec) * y); + width = FirstWidth = malloc(sizeof(int) * y); + Marked = malloc(sizeof(int) * count); + + if(!ptsOut || !width || !Marked) + { + free(Marked); + free(width); + free(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); + free(Marked); + free(FirstWidth); + free(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/mi/migc.c b/mi/migc.c new file mode 100644 index 0000000..6d734e1 --- /dev/null +++ b/mi/migc.c @@ -0,0 +1,249 @@ +/* + +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 */ +void +miChangeGC(GCPtr pGC, unsigned long mask) +{ + return; +} + +void +miDestroyGC(GCPtr pGC) +{ + if (pGC->pRotatedPixmap) + (*pGC->pScreen->DestroyPixmap) (pGC->pRotatedPixmap); + if (pGC->freeCompClip) + RegionDestroy(pGC->pCompositeClip); +} + +void +miDestroyClip(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 + */ + RegionDestroy(pGC->clientClip); + } + pGC->clientClip = NULL; + pGC->clientClipType = CT_NONE; +} + +void +miChangeClip( 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) BitmapToRegion(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) RegionFromRects(nrects, + (xRectangle *) pvalue, + type); + free(pvalue); + } + pGC->clientClipType = (type != CT_NONE && pGC->clientClip) ? CT_REGION : CT_NONE; + pGC->stateChanges |= GCClipMask; +} + +void +miCopyClip(GCPtr pgcDst, GCPtr 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 = RegionCreate(NULL, 1); + RegionCopy(prgnNew, (RegionPtr) (pgcSrc->clientClip)); + (*pgcDst->funcs->ChangeClip) (pgcDst, CT_REGION, (pointer) prgnNew, 0); + break; + } +} + +/* ARGSUSED */ +void +miCopyGC(GCPtr pGCSrc, unsigned long changes, GCPtr pGCDst) +{ + return; +} + +void +miComputeCompositeClip( GCPtr pGC, DrawablePtr pDrawable) +{ + 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) + RegionDestroy(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. + */ + + RegionTranslate(pGC->clientClip, + pDrawable->x + pGC->clipOrg.x, + pDrawable->y + pGC->clipOrg.y); + + if (freeCompClip) + { + RegionIntersect(pGC->pCompositeClip, + pregWin, pGC->clientClip); + if (freeTmpClip) + RegionDestroy(pregWin); + } + else if (freeTmpClip) + { + RegionIntersect(pregWin, pregWin, pGC->clientClip); + pGC->pCompositeClip = pregWin; + } + else + { + pGC->pCompositeClip = RegionCreate(NullBox, 0); + RegionIntersect(pGC->pCompositeClip, + pregWin, pGC->clientClip); + } + pGC->freeCompClip = TRUE; + RegionTranslate(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) + { + RegionReset(pGC->pCompositeClip, &pixbounds); + } + else + { + pGC->freeCompClip = TRUE; + pGC->pCompositeClip = RegionCreate(&pixbounds, 1); + } + + if (pGC->clientClipType == CT_REGION) + { + if(pDrawable->x || pDrawable->y) { + RegionTranslate(pGC->clientClip, + pDrawable->x + pGC->clipOrg.x, + pDrawable->y + pGC->clipOrg.y); + RegionIntersect(pGC->pCompositeClip, + pGC->pCompositeClip, pGC->clientClip); + RegionTranslate(pGC->clientClip, + -(pDrawable->x + pGC->clipOrg.x), + -(pDrawable->y + pGC->clipOrg.y)); + } else { + RegionTranslate(pGC->pCompositeClip, + -pGC->clipOrg.x, -pGC->clipOrg.y); + RegionIntersect(pGC->pCompositeClip, + pGC->pCompositeClip, pGC->clientClip); + RegionTranslate(pGC->pCompositeClip, + pGC->clipOrg.x, pGC->clipOrg.y); + } + } + } /* end of composite clip for pixmap */ +} /* end miComputeCompositeClip */ diff --git a/mi/migc.h b/mi/migc.h new file mode 100644 index 0000000..df5805f --- /dev/null +++ b/mi/migc.h @@ -0,0 +1,64 @@ +/* + +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 _X_EXPORT void miChangeGC( + GCPtr /*pGC*/, + unsigned long /*mask*/ +); + +extern _X_EXPORT void miDestroyGC( + GCPtr /*pGC*/ +); + +extern _X_EXPORT void miDestroyClip( + GCPtr /*pGC*/ +); + +extern _X_EXPORT void miChangeClip( + GCPtr /*pGC*/, + int /*type*/, + pointer /*pvalue*/, + int /*nrects*/ +); + +extern _X_EXPORT void miCopyClip( + GCPtr /*pgcDst*/, + GCPtr /*pgcSrc*/ +); + +extern _X_EXPORT void miCopyGC( + GCPtr /*pGCSrc*/, + unsigned long /*changes*/, + GCPtr /*pGCDst*/ +); + +extern _X_EXPORT void miComputeCompositeClip( + GCPtr /*pGC*/, + DrawablePtr /*pDrawable*/ +); diff --git a/mi/miglblt.c b/mi/miglblt.c new file mode 100644 index 0000000..9edb500 --- /dev/null +++ b/mi/miglblt.c @@ -0,0 +1,256 @@ +/*********************************************************** + +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 +*/ + +void +miPolyGlyphBlt( + DrawablePtr pDrawable, + GC *pGC, + int x, + int 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 */ + + ChangeGCVal 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].val = GXcopy; + gcvals[1].val = 1; + gcvals[2].val = 0; + + ChangeGC(NullClient, pGCtmp, GCFunction|GCForeground|GCBackground, gcvals); + + nbyLine = BitmapBytePad(width); + pbits = malloc(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); + + (*pGC->ops->PushPixels)(pGC, pPixmap, pDrawable, + gWidth, gHeight, + x + pci->metrics.leftSideBearing, + y - pci->metrics.ascent); + } + x += pci->metrics.characterWidth; + } + (*pDrawable->pScreen->DestroyPixmap)(pPixmap); + free(pbits); + FreeScratchGC(pGCtmp); +} + + +void +miImageGlyphBlt( + DrawablePtr pDrawable, + GC *pGC, + int x, + int y, + unsigned int nglyph, + CharInfoPtr *ppci, /* array of character info */ + pointer pglyphBase /* start of array of glyphs */ + ) +{ + ExtentInfoRec info; /* used by QueryGlyphExtents() */ + ChangeGCVal 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].val = GXcopy; + gcvals[1].val = pGC->bgPixel; + gcvals[2].val = FillSolid; + ChangeGC(NullClient, pGC, GCFunction|GCForeground|GCFillStyle, gcvals); + ValidateGC(pDrawable, pGC); + (*pGC->ops->PolyFillRect)(pDrawable, pGC, 1, &backrect); + + /* put down the glyphs */ + gcvals[0].val = oldFG; + ChangeGC(NullClient, pGC, GCForeground, gcvals); + ValidateGC(pDrawable, pGC); + (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, nglyph, ppci, + pglyphBase); + + /* put all the toys away when done playing */ + gcvals[0].val = oldAlu; + gcvals[1].val = oldFG; + gcvals[2].val = oldFS; + ChangeGC(NullClient, pGC, GCFunction|GCForeground|GCFillStyle, gcvals); + ValidateGC(pDrawable, pGC); + +} diff --git a/mi/miinitext.c b/mi/miinitext.c new file mode 100644 index 0000000..4499f37 --- /dev/null +++ b/mi/miinitext.c @@ -0,0 +1,544 @@ +/*********************************************************** + +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> +#undef XV +#undef DBE +#undef XF86VIDMODE +#undef XFreeXDGA +#undef XF86DRI +#undef SCREENSAVER +#undef RANDR +#undef XFIXES +#undef DAMAGE +#undef COMPOSITE +#undef MITSHM +#endif + +#ifdef HAVE_XNEST_CONFIG_H +#include <xnest-config.h> +#undef COMPOSITE +#undef DPMSExtension +#endif + +#ifdef HAVE_KDRIVE_CONFIG_H +#include <kdrive-config.h> +/* there must be a better way... */ +#undef XFreeXDGA +#undef XF86DRI +#undef XF86VIDMODE +#endif + +#ifdef HAVE_XGL_CONFIG_H +#include <xgl-config.h> +#undef XFreeXDGA +#undef XF86DRI +#undef XF86VIDMODE +#endif + +#include "misc.h" +#include "extension.h" +#include "micmap.h" +#include "globals.h" + + +extern Bool noTestExtensions; + +#ifdef COMPOSITE +extern Bool noCompositeExtension; +#endif +#ifdef DBE +extern Bool noDbeExtension; +#endif +#ifdef DPMSExtension +extern Bool noDPMSExtension; +#endif +#ifdef GLXEXT +extern Bool noGlxExtension; +#endif +#ifdef SCREENSAVER +extern Bool noScreenSaverExtension; +#endif +#ifdef MITSHM +extern Bool noMITShmExtension; +#endif +#ifdef RANDR +extern Bool noRRExtension; +#endif +extern Bool noRenderExtension; +#ifdef XCSECURITY +extern Bool noSecurityExtension; +#endif +#ifdef RES +extern Bool noResExtension; +#endif +#ifdef XF86BIGFONT +extern Bool noXFree86BigfontExtension; +#endif +#ifdef XFreeXDGA +extern Bool noXFree86DGAExtension; +#endif +#ifdef XF86DRI +extern Bool noXFree86DRIExtension; +#endif +#ifdef XF86VIDMODE +extern Bool noXFree86VidModeExtension; +#endif +#ifdef XFIXES +extern Bool noXFixesExtension; +#endif +#ifdef PANORAMIX +extern Bool noPanoramiXExtension; +#endif +#ifdef INXQUARTZ +extern Bool noPseudoramiXExtension; +#endif +#ifdef XSELINUX +extern Bool noSELinuxExtension; +#endif +#ifdef XV +extern Bool noXvExtension; +#endif +extern Bool noGEExtension; + +#ifndef XFree86LOADER +#define INITARGS void +typedef void (*InitExtension)(INITARGS); +#else /* XFree86Loader */ +#include "loaderProcs.h" +#endif + +#ifdef MITSHM +#include <X11/extensions/shm.h> +#endif +#ifdef XTEST +#include <X11/extensions/xtestconst.h> +#endif +#include <X11/extensions/XKB.h> +#ifdef XCSECURITY +#include "securitysrv.h" +#include <X11/extensions/secur.h> +#endif +#ifdef XSELINUX +#include "xselinux.h" +#endif +#ifdef PANORAMIX +#include <X11/extensions/panoramiXproto.h> +#endif +#ifdef XF86BIGFONT +#include <X11/extensions/xf86bigfproto.h> +#endif +#ifdef RES +#include <X11/extensions/XResproto.h> +#endif + +/* FIXME: this whole block of externs should be from the appropriate headers */ +#ifdef MITSHM +extern void ShmExtensionInit(INITARGS); +#endif +#ifdef PANORAMIX +extern void PanoramiXExtensionInit(INITARGS); +#endif +#ifdef INXQUARTZ +extern void PseudoramiXExtensionInit(INITARGS); +#endif +extern void XInputExtensionInit(INITARGS); +#ifdef XTEST +extern void XTestExtensionInit(INITARGS); +#endif +extern void BigReqExtensionInit(INITARGS); +#ifdef SCREENSAVER +extern void ScreenSaverExtensionInit (INITARGS); +#endif +#ifdef XV +extern void XvExtensionInit(INITARGS); +extern void XvMCExtensionInit(INITARGS); +#endif +extern void SyncExtensionInit(INITARGS); +extern void XkbExtensionInit(INITARGS); +extern void XCMiscExtensionInit(INITARGS); +#ifdef XRECORD +extern void RecordExtensionInit(INITARGS); +#endif +#ifdef DBE +extern void DbeExtensionInit(INITARGS); +#endif +#ifdef XCSECURITY +extern void SecurityExtensionInit(INITARGS); +#endif +#ifdef XSELINUX +extern void SELinuxExtensionInit(INITARGS); +#endif +#ifdef XF86BIGFONT +extern void XFree86BigfontExtensionInit(INITARGS); +#endif +#ifdef XF86VIDMODE +extern void XFree86VidModeExtensionInit(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 DPMSExtension +extern void DPMSExtensionInit(INITARGS); +#endif +extern void RenderExtensionInit(INITARGS); +#ifdef RANDR +extern void RRExtensionInit(INITARGS); +#endif +#ifdef RES +extern void ResExtensionInit(INITARGS); +#endif +#ifdef DMXEXT +extern void DMXExtensionInit(INITARGS); +#endif +#ifdef XFIXES +extern void XFixesExtensionInit(INITARGS); +#endif +#ifdef DAMAGE +extern void DamageExtensionInit(INITARGS); +#endif +#ifdef COMPOSITE +extern void CompositeExtensionInit(INITARGS); +#endif +extern void GEExtensionInit(INITARGS); + +/* 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 */ + { "Generic Events", &noGEExtension }, +#ifdef COMPOSITE + { "Composite", &noCompositeExtension }, +#endif +#ifdef DAMAGE + { "DAMAGE", &noDamageExtension }, +#endif +#ifdef DBE + { "DOUBLE-BUFFER", &noDbeExtension }, +#endif +#ifdef DPMSExtension + { "DPMS", &noDPMSExtension }, +#endif +#ifdef GLXEXT + { "GLX", &noGlxExtension }, +#endif +#ifdef SCREENSAVER + { "MIT-SCREEN-SAVER", &noScreenSaverExtension }, +#endif +#ifdef MITSHM + { SHMNAME, &noMITShmExtension }, +#endif +#ifdef RANDR + { "RANDR", &noRRExtension }, +#endif + { "RENDER", &noRenderExtension }, +#ifdef XCSECURITY + { "SECURITY", &noSecurityExtension }, +#endif +#ifdef RES + { "X-Resource", &noResExtension }, +#endif +#ifdef XF86BIGFONT + { "XFree86-Bigfont", &noXFree86BigfontExtension }, +#endif +#ifdef XFreeXDGA + { "XFree86-DGA", &noXFree86DGAExtension }, +#endif +#ifdef XF86DRI + { "XFree86-DRI", &noXFree86DRIExtension }, +#endif +#ifdef XF86VIDMODE + { "XFree86-VidModeExtension", &noXFree86VidModeExtension }, +#endif +#ifdef XFIXES + { "XFIXES", &noXFixesExtension }, +#endif +#ifdef PANORAMIX + { "XINERAMA", &noPanoramiXExtension }, +#endif + { "XInputExtension", NULL }, + { "XKEYBOARD", NULL }, +#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) { + if (ext->disablePtr != NULL) { + *ext->disablePtr = !enable; + return TRUE; + } else { + /* Extension is always on, impossible to disable */ + return enable; /* okay if they wanted to enable, + fail if they tried to disable */ + } + } + } + + return FALSE; +} + +void EnableDisableExtensionError(char *name, Bool enable) +{ + ExtensionToggle *ext = &ExtensionToggleList[0]; + Bool found = FALSE; + + for (ext = &ExtensionToggleList[0]; ext->name != NULL; ext++) { + if ((strcmp(name, ext->name) == 0) && (ext->disablePtr == NULL)) { + ErrorF("[mi] Extension \"%s\" can not be disabled\n", name); + found = TRUE; + break; + } + } + if (found == FALSE) + ErrorF("[mi] Extension \"%s\" is not recognized\n", name); + ErrorF("[mi] Only the following extensions can be run-time %s:\n", + enable ? "enabled" : "disabled"); + for (ext = &ExtensionToggleList[0]; ext->name != NULL; ext++) { + if (ext->disablePtr != NULL) { + ErrorF("[mi] %s\n", ext->name); + } + } +} + +#ifndef XFree86LOADER + +/*ARGSUSED*/ +void +InitExtensions(int argc, char *argv[]) +{ + if (!noGEExtension) GEExtensionInit(); + +#ifdef PANORAMIX + if (!noPanoramiXExtension) PanoramiXExtensionInit(); +#endif +#ifdef INXQUARTZ + if(!noPseudoramiXExtension) PseudoramiXExtensionInit(); +#endif + ShapeExtensionInit(); +#ifdef MITSHM + if (!noMITShmExtension) ShmExtensionInit(); +#endif + XInputExtensionInit(); +#ifdef XTEST + if (!noTestExtensions) XTestExtensionInit(); +#endif + BigReqExtensionInit(); +#if defined(SCREENSAVER) + if (!noScreenSaverExtension) ScreenSaverExtensionInit (); +#endif +#ifdef XV + if (!noXvExtension) { + XvExtensionInit(); + XvMCExtensionInit(); + } +#endif + SyncExtensionInit(); + XkbExtensionInit(); + XCMiscExtensionInit(); +#ifdef XRECORD + if (!noTestExtensions) RecordExtensionInit(); +#endif +#ifdef DBE + if (!noDbeExtension) DbeExtensionInit(); +#endif +#ifdef XCSECURITY + if (!noSecurityExtension) SecurityExtensionInit(); +#endif +#ifdef XSELINUX + if (!noSELinuxExtension) SELinuxExtensionInit(); +#endif +#if defined(DPMSExtension) && !defined(NO_HW_ONLY_EXTS) + if (!noDPMSExtension) DPMSExtensionInit(); +#endif +#ifdef XF86BIGFONT + if (!noXFree86BigfontExtension) XFree86BigfontExtensionInit(); +#endif +#if !defined(NO_HW_ONLY_EXTS) +#if defined(XF86VIDMODE) + if (!noXFree86VidModeExtension) XFree86VidModeExtensionInit(); +#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 + if (!noRenderExtension) RenderExtensionInit(); +#ifdef RANDR + if (!noRRExtension) RRExtensionInit(); +#endif +#ifdef RES + if (!noResExtension) ResExtensionInit(); +#endif +#ifdef DMXEXT + DMXExtensionInit(); /* server-specific extension, cannot be disabled */ +#endif +#ifdef COMPOSITE + if (!noCompositeExtension) CompositeExtensionInit(); +#endif +#ifdef DAMAGE + if (!noDamageExtension) DamageExtensionInit(); +#endif + +#ifdef GLXEXT + if (serverGeneration == 1) + GlxPushProvider(&__glXDRISWRastProvider); + if (!noGlxExtension) GlxExtensionInit(); +#endif +} + +#else /* XFree86LOADER */ +/* List of built-in (statically linked) extensions */ +static ExtensionModule staticExtensions[] = { + { GEExtensionInit, "Generic Event Extension", &noGEExtension, NULL, NULL}, + { ShapeExtensionInit, "SHAPE", NULL, NULL, NULL }, +#ifdef MITSHM + { ShmExtensionInit, SHMNAME, &noMITShmExtension, NULL, NULL }, +#endif + { XInputExtensionInit, "XInputExtension", NULL, NULL, NULL }, +#ifdef XTEST + { XTestExtensionInit, XTestExtensionName, &noTestExtensions, NULL, NULL }, +#endif + { BigReqExtensionInit, "BIG-REQUESTS", NULL, NULL, NULL }, + { SyncExtensionInit, "SYNC", NULL, NULL, NULL }, + { XkbExtensionInit, XkbName, NULL, NULL, NULL }, + { XCMiscExtensionInit, "XC-MISC", NULL, NULL, NULL }, +#ifdef XCSECURITY + { SecurityExtensionInit, SECURITY_EXTENSION_NAME, &noSecurityExtension, 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 + { RenderExtensionInit, "RENDER", &noRenderExtension, NULL, NULL }, +#ifdef RANDR + { RRExtensionInit, "RANDR", &noRRExtension, NULL, NULL }, +#endif +#ifdef COMPOSITE + { CompositeExtensionInit, "COMPOSITE", &noCompositeExtension, NULL }, +#endif +#ifdef DAMAGE + { DamageExtensionInit, "DAMAGE", &noDamageExtension, NULL }, +#endif + { NULL, NULL, NULL, NULL, NULL } +}; + +/*ARGSUSED*/ +void +InitExtensions(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)) { + (ext->initFunc)(); + } + } +} + +#endif /* XFree86LOADER */ diff --git a/mi/miline.h b/mi/miline.h new file mode 100644 index 0000000..ae9d113 --- /dev/null +++ b/mi/miline.h @@ -0,0 +1,173 @@ + +/* + +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 _X_EXPORT 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) (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 _X_EXPORT DevPrivateKeyRec miZeroLineScreenKeyRec; +#define miZeroLineScreenKey (&miZeroLineScreenKeyRec) + +extern _X_EXPORT 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/mi/mioverlay.c b/mi/mioverlay.c new file mode 100644 index 0000000..766c5e7 --- /dev/null +++ b/mi/mioverlay.c @@ -0,0 +1,1946 @@ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include "scrnintstr.h" +#include <X11/extensions/shapeproto.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 DevPrivateKeyRec miOverlayWindowKeyRec; +#define miOverlayWindowKey (&miOverlayWindowKeyRec) +static DevPrivateKeyRec miOverlayScreenKeyRec; +#define miOverlayScreenKey (&miOverlayScreenKeyRec) + +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); + +static void miOverlaySetShape(WindowPtr, int); +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) + +Bool +miInitOverlay( + ScreenPtr pScreen, + miOverlayInOverlayFunc inOverlayFunc, + miOverlayTransFunc transFunc +){ + miOverlayScreenPtr pScreenPriv; + + if(!inOverlayFunc || !transFunc) return FALSE; + + if(!dixRegisterPrivateKey(&miOverlayWindowKeyRec, PRIVATE_WINDOW, sizeof(miOverlayWindowRec))) + return FALSE; + + if(!dixRegisterPrivateKey(&miOverlayScreenKeyRec, PRIVATE_SCREEN, 0)) + return FALSE; + + if(!(pScreenPriv = malloc(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; + pScreen->SetShape = miOverlaySetShape; + 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; + + free(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)calloc(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) { + RegionNull(&(pTree->borderClip)); + RegionNull(&(pTree->clipList)); + RebuildTree(pWin); + } else { + BoxRec fullBox; + fullBox.x1 = 0; + fullBox.y1 = 0; + fullBox.x2 = pScreen->width; + fullBox.y2 = pScreen->height; + RegionInit(&(pTree->borderClip), &fullBox, 1); + RegionInit(&(pTree->clipList), &fullBox, 1); + } + } else free(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; + + RegionUninit(&(pTree->borderClip)); + RegionUninit(&(pTree->clipList)); + free(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(pWin->drawable.pScreen->root->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 +){ + 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 = RegionExtents(&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 (RegionBroken(&pChild->winSize)) + SetWinSize (pChild); + if (RegionBroken(&pChild->borderSize)) + SetBorderSize (pChild); + + if (markAll || + RegionContainsRect(&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 (RegionBroken(&tChild->pWin->winSize)) + SetWinSize (tChild->pWin); + if (RegionBroken(&tChild->pWin->borderSize)) + SetBorderSize (tChild->pWin); + + if(RegionContainsRect(&(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) { + ScreenPtr pScreen = pWin->drawable.pScreen; + 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 (RegionContainsRect(universe, &borderSize)) { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnPART: + newVis = VisibilityPartiallyObscured; + { + RegionPtr pBounding; + + if ((pBounding = wBoundingShape (pParent))) { + switch (miShapedWindowIn (universe, pBounding, + &borderSize, + pParent->drawable.x, + pParent->drawable.y)) + { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnOUT: + newVis = VisibilityFullyObscured; + break; + } + } + } + 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) { + RegionTranslate(&tChild->borderClip, dx, dy); + RegionTranslate(&tChild->clipList, dx, dy); + + tChild->pWin->drawable.serialNumber = + NEXT_SERIAL_NUMBER; + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (tChild->pWin, dx, dy); + } + if (tChild->valdata) { + RegionNull(&tChild->valdata->borderExposed); + if (HasParentRelativeBorder(tChild->pWin)){ + RegionSubtract(&tChild->valdata->borderExposed, + &tChild->borderClip, + &tChild->pWin->winSize); + } + RegionNull(&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) { + RegionTranslate(&tParent->borderClip, dx, dy); + RegionTranslate(&tParent->clipList, dx, dy); + } + break; + case VTBroken: + RegionEmpty(&tParent->borderClip); + RegionEmpty(&tParent->clipList); + break; + } + + borderVisible = tParent->valdata->borderVisible; + RegionNull(&tParent->valdata->borderExposed); + RegionNull(&tParent->valdata->exposed); + + if (HasBorder (pParent)) { + if (borderVisible) { + RegionSubtract(exposed, universe, borderVisible); + RegionDestroy(borderVisible); + } else + RegionSubtract(exposed, universe, &tParent->borderClip); + + if (HasParentRelativeBorder(pParent) && (dx || dy)) + RegionSubtract(&tParent->valdata->borderExposed, + universe, &pParent->winSize); + else + RegionSubtract(&tParent->valdata->borderExposed, + exposed, &pParent->winSize); + + RegionCopy(&tParent->borderClip, universe); + RegionIntersect(universe, universe, &pParent->winSize); + } + else + RegionCopy(&tParent->borderClip, universe); + + if ((tChild = tParent->firstChild) && pParent->mapped) { + RegionNull(&childUniverse); + RegionNull(&childUnion); + + for (; tChild; tChild = tChild->nextSib) { + if (tChild->pWin->viewable) + RegionAppend(&childUnion, &tChild->pWin->borderSize); + } + + RegionValidate(&childUnion, &overlap); + + for (tChild = tParent->firstChild; + tChild; + tChild = tChild->nextSib) + { + if (tChild->pWin->viewable) { + if (tChild->valdata) { + RegionIntersect(&childUniverse, universe, + &tChild->pWin->borderSize); + miOverlayComputeClips (tChild->pWin, &childUniverse, + kind, exposed); + } + if (overlap) + RegionSubtract(universe, universe, + &tChild->pWin->borderSize); + } + } + if (!overlap) + RegionSubtract(universe, universe, &childUnion); + RegionUninit(&childUnion); + RegionUninit(&childUniverse); + } + + if (oldVis == VisibilityFullyObscured || + oldVis == VisibilityNotViewable) + { + RegionCopy(&tParent->valdata->exposed, universe); + } + else if (newVis != VisibilityFullyObscured && + newVis != VisibilityNotViewable) + { + RegionSubtract(&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; + + RegionEmpty(&pChild->clipList); + if (pChild->drawable.pScreen->ClipNotify) + (* pChild->drawable.pScreen->ClipNotify)(pChild, 0, 0); + RegionEmpty(&pChild->borderClip); + if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) { + if(pTree->valdata != (miOverlayValDataPtr)UnmapValData) { + RegionEmpty(&pTree->clipList); + RegionEmpty(&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; + + RegionNull(&totalClip); + RegionNull(&childClip); + RegionNull(&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 (RegionBroken(&tParent->clipList) && + !RegionBroken(&tParent->borderClip)) + { + kind = VTBroken; + RegionCopy(&totalClip, &tParent->borderClip); + RegionIntersect(&totalClip, &totalClip, + &tParent->pWin->winSize); + + for (tWin = tParent->firstChild; tWin != tChild; tWin = tWin->nextSib) { + if (tWin->pWin->viewable) + RegionSubtract(&totalClip, &totalClip, + &tWin->pWin->borderSize); + } + RegionEmpty(&tParent->clipList); + } else { + for(tWin = tChild; tWin; tWin = tWin->nextSib) { + if(tWin->valdata) + RegionAppend(&totalClip, &tWin->borderClip); + } + RegionValidate(&totalClip, &overlap); + } + + if(kind != VTStack) + RegionUnion(&totalClip, &totalClip, &tParent->clipList); + + for(tWin = tChild; tWin; tWin = tWin->nextSib) { + if(tWin->valdata) { + if(tWin->pWin->viewable) { + RegionIntersect(&childClip, &totalClip, + &tWin->pWin->borderSize); + miOverlayComputeClips(tWin->pWin, &childClip, kind, &exposed); + RegionSubtract(&totalClip, &totalClip, + &tWin->pWin->borderSize); + } else { /* Means we are unmapping */ + RegionEmpty(&tWin->clipList); + RegionEmpty(&tWin->borderClip); + tWin->valdata = NULL; + } + } + } + + RegionUninit(&childClip); + + if(!((*pPriv->InOverlay)(newParent))) { + RegionNull(&tParent->valdata->exposed); + RegionNull(&tParent->valdata->borderExposed); + } + + switch (kind) { + case VTStack: + break; + default: + if(!((*pPriv->InOverlay)(newParent))) + RegionSubtract(&tParent->valdata->exposed, &totalClip, + &tParent->clipList); + /* fall through */ + case VTMap: + RegionCopy(&tParent->clipList, &totalClip); + if(!((*pPriv->InOverlay)(newParent))) + newParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; + break; + } + + RegionUninit(&totalClip); + RegionUninit(&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 (RegionNotEmpty(&mival->borderExposed)) { + miPaintWindow(pTree->pWin, &mival->borderExposed, + PW_BORDER); + } + RegionUninit(&mival->borderExposed); + + (*WindowExposures)(pTree->pWin,&mival->exposed,NullRegion); + RegionUninit(&mival->exposed); + } + free(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))) { + RegionUnion(&val->after.exposed, &val->after.exposed, + &val->after.borderExposed); + + if (RegionNotEmpty(&val->after.exposed)) { + (*(MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent))( + pScreen, + RegionNumRects(&val->after.exposed), + RegionRects(&val->after.exposed)); + } + } else { + if (RegionNotEmpty(&val->after.borderExposed)) { + miPaintWindow(pChild, &val->after.borderExposed, + PW_BORDER); + } + (*WindowExposures)(pChild, &val->after.exposed, NullRegion); + } + RegionUninit(&val->after.borderExposed); + RegionUninit(&val->after.exposed); + free(val); + pChild->valdata = 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; + + if (!(pParent = pWin->parent)) + return ; + bw = wBorderWidth (pWin); + + oldpt.x = pWin->drawable.x; + oldpt.y = pWin->drawable.y; + if (WasViewable) { + RegionNull(&overReg); + RegionNull(&underReg); + if(pTree) { + RegionCopy(&overReg, &pWin->borderClip); + RegionCopy(&underReg, &pTree->borderClip); + } else { + RegionCopy(&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); + + + (*pScreen->ValidateTree)(pWin->parent, NullWindow, kind); + if(RegionNotEmpty(&underReg)) { + pPriv->copyUnderlay = TRUE; + (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, &underReg); + } + RegionUninit(&underReg); + if(RegionNotEmpty(&overReg)) { + pPriv->copyUnderlay = FALSE; + (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, &overReg); + } + RegionUninit(&overReg); + (*pScreen->HandleExposures)(pWin->parent); + + 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; + + if ((prgn && !RegionNil(prgn)) || + (exposures && !RegionNil(exposures)) || other_exposed) + { + RegionRec expRec; + int clientInterested; + + clientInterested = (pWin->eventMask|wOtherEventMasks(pWin)) & + ExposureMask; + if (other_exposed) { + if (exposures) { + RegionUnion(other_exposed, exposures, other_exposed); + if (exposures != prgn) + RegionDestroy(exposures); + } + exposures = other_exposed; + } + if (clientInterested && exposures && + (RegionNumRects(exposures) > RECTLIMIT)) + { + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + BoxRec box; + + box = *RegionExtents(exposures); + if (exposures == prgn) { + exposures = &expRec; + RegionInit(exposures, &box, 1); + RegionReset(prgn, &box); + } else { + RegionReset(exposures, &box); + RegionUnion(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); + RegionIntersect(prgn, prgn, &pTree->clipList); + } else + RegionIntersect(prgn, prgn, &pWin->clipList); + } + if (prgn && !RegionNil(prgn)) + miPaintWindow(pWin, prgn, PW_BACKGROUND); + if (clientInterested && exposures && !RegionNil(exposures)) + miSendExposures(pWin, exposures, + pWin->drawable.x, pWin->drawable.y); + if (exposures == &expRec) { + RegionUninit(exposures); + } + else if (exposures && exposures != prgn && exposures != other_exposed) + RegionDestroy(exposures); + if (prgn) + RegionEmpty(prgn); + } + else if (exposures && exposures != prgn) + RegionDestroy(exposures); +} + + +typedef struct { + RegionPtr over; + RegionPtr under; +} miOverlayTwoRegions; + +static int +miOverlayRecomputeExposures ( + WindowPtr pWin, + pointer value +){ + miOverlayTwoRegions *pValid = (miOverlayTwoRegions*)value; + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + if (pWin->valdata) { + /* + * compute exposed regions of this window + */ + RegionSubtract(&pWin->valdata->after.exposed, + &pWin->clipList, pValid->over); + /* + * compute exposed regions of the border + */ + RegionSubtract(&pWin->valdata->after.borderExposed, + &pWin->borderClip, &pWin->winSize); + RegionSubtract(&pWin->valdata->after.borderExposed, + &pWin->valdata->after.borderExposed, pValid->over); + } + + if(pTree && pTree->valdata) { + RegionSubtract(&pTree->valdata->exposed, + &pTree->clipList, pValid->under); + RegionSubtract(&pTree->valdata->borderExposed, + &pTree->borderClip, &pWin->winSize); + RegionSubtract(&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 */ + 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 = RegionCreate(NullBox, 1); + RegionCopy(oldRegion, &pWin->winSize); + if(doUnderlay) { + oldRegion2 = RegionCreate(NullBox, 1); + RegionCopy(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] = RegionCreate(NullBox, 1); + RegionUnion(gravitate[g], + gravitate[g], &pChild->borderClip); + + if(doUnderlay) { + if (!gravitate2[g]) + gravitate2[g] = RegionCreate(NullBox, 0); + + if((tChild = MIOVERLAY_GET_WINDOW_TREE(pChild))) { + RegionUnion(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 = RegionCreate(NullBox, 1); + RegionCopy(oldWinClip, &pWin->clipList); + if(pTree) { + oldWinClip2 = RegionCreate(NullBox, 1); + RegionCopy(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 = RegionCreate(NullBox, 1); + if(pTree) + borderVisible2 = RegionCreate(NullBox, 1); + /* for tiled borders, we punt and draw the whole thing */ + if (pWin->borderIsPixel || !moved) + { + if (shrunk || moved) + RegionSubtract(borderVisible, + &pWin->borderClip, + &pWin->winSize); + else + RegionCopy(borderVisible, + &pWin->borderClip); + if(pTree) { + if (shrunk || moved) + RegionSubtract(borderVisible, + &pTree->borderClip, + &pWin->winSize); + else + RegionCopy(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 = RegionCreate(NullBox, 1); + + (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, NULL); + + pWin->valdata->before.resized = TRUE; + pWin->valdata->before.borderVisible = borderVisible; + if(pTree) + pTree->valdata->borderVisible = borderVisible2; + + + (*pScreen->ValidateTree)(pWin->parent, pFirstChange, VTOther); + /* + * the entire window is trashed unless bitGravity + * recovers portions of it + */ + RegionCopy(&pWin->valdata->after.exposed, &pWin->clipList); + if(pTree) + RegionCopy(&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) { + RegionTranslate(&pWin->winSize, dx, dy); + offx += dx; + offy += dy; + } + if(gravitate[g]) + RegionIntersect(gravitate[g], gravitate[g], + &pWin->winSize); + if(gravitate2[g]) + RegionIntersect(gravitate2[g], gravitate2[g], + &pWin->winSize); + } + /* get winSize back where it belongs */ + if (offx || offy) + RegionTranslate(&pWin->winSize, -offx, -offy); + } + /* + * add screen bits to the appropriate bucket + */ + + if (oldWinClip2) + { + RegionCopy(pRegion, oldWinClip2); + RegionTranslate(pRegion, nx - oldx, ny - oldy); + RegionIntersect(oldWinClip2, pRegion, &pTree->clipList); + + for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) { + if (gravitate2[g]) + RegionSubtract(oldWinClip2, oldWinClip2, + gravitate2[g]); + } + RegionTranslate(oldWinClip2, oldx - nx, oldy - ny); + g = pWin->bitGravity; + if (!gravitate2[g]) + gravitate2[g] = oldWinClip2; + else { + RegionUnion(gravitate2[g],gravitate2[g],oldWinClip2); + RegionDestroy(oldWinClip2); + } + } + + if (oldWinClip) + { + /* + * clip to new clipList + */ + RegionCopy(pRegion, oldWinClip); + RegionTranslate(pRegion, nx - oldx, ny - oldy); + RegionIntersect(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]) + RegionSubtract(oldWinClip, oldWinClip, + gravitate[g]); + } + RegionTranslate(oldWinClip, oldx - nx, oldy - ny); + g = pWin->bitGravity; + if (!gravitate[g]) + gravitate[g] = oldWinClip; + else { + RegionUnion(gravitate[g], gravitate[g], oldWinClip); + RegionDestroy(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]) + RegionIntersect(gravitate[g], + gravitate[g], oldRegion); + if(gravitate2[g]) + RegionIntersect(gravitate2[g], + gravitate2[g], oldRegion2); + + /* clip to not overwrite already copied areas */ + + if (destClip && gravitate[g]) { + RegionTranslate(destClip, oldpt.x - x, oldpt.y - y); + RegionSubtract(gravitate[g], gravitate[g], destClip); + RegionTranslate(destClip, x - oldpt.x, y - oldpt.y); + } + if (destClip2 && gravitate2[g]) { + RegionTranslate(destClip2, oldpt.x - x, oldpt.y - y); + RegionSubtract(gravitate2[g],gravitate2[g],destClip2); + RegionTranslate(destClip2, x - oldpt.x, y - oldpt.y); + } + + /* and move those bits */ + + if (oldpt.x != x || oldpt.y != y) { + if(gravitate2[g]) { + pPriv->copyUnderlay = TRUE; + (*pScreen->CopyWindow)(pWin, oldpt, gravitate2[g]); + } + if(gravitate[g]) { + pPriv->copyUnderlay = FALSE; + (*pScreen->CopyWindow)(pWin, oldpt, gravitate[g]); + } + } + + /* remove any overwritten bits from the remaining useful bits */ + + if(gravitate[g]) + RegionSubtract(oldRegion, oldRegion, gravitate[g]); + if(gravitate2[g]) + RegionSubtract(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]) + RegionSubtract(&pWin->valdata->after.exposed, + &pWin->valdata->after.exposed, gravitate[g]); + if(gravitate2[g] && pTree) + RegionSubtract(&pTree->valdata->exposed, + &pTree->valdata->exposed, gravitate2[g]); + } + if(gravitate[g]) { + if (!destClip) + destClip = gravitate[g]; + else { + RegionUnion(destClip, destClip, gravitate[g]); + RegionDestroy(gravitate[g]); + } + } + if(gravitate2[g]) { + if (!destClip2) + destClip2 = gravitate2[g]; + else { + RegionUnion(destClip2, destClip2, gravitate2[g]); + RegionDestroy(gravitate2[g]); + } + } + } + + RegionDestroy(pRegion); + RegionDestroy(oldRegion); + if(doUnderlay) + RegionDestroy(oldRegion2); + if (destClip) + RegionDestroy(destClip); + if (destClip2) + RegionDestroy(destClip2); + (*pScreen->HandleExposures)(pWin->parent); + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin->parent, pFirstChange, VTOther); + } + if (pWin->realized) + WindowsRestructured (); +} + + +static void +miOverlaySetShape(WindowPtr pWin, int kind) +{ + Bool WasViewable = (Bool)(pWin->viewable); + ScreenPtr pScreen = pWin->drawable.pScreen; + + if (kind != ShapeInput) { + if (WasViewable) { + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + + if (HasBorder (pWin)) { + RegionPtr borderVisible; + + borderVisible = RegionCreate(NullBox, 1); + RegionSubtract(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 = RegionCreate(NULL, 1); + RegionSubtract(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); + + + (*pScreen->ValidateTree)(pWin->parent, NullWindow, VTOther); + } + + if (WasViewable) { + (*pScreen->HandleExposures)(pWin->parent); + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin->parent, NullWindow, VTOther); + } + } + if (pWin->realized) + WindowsRestructured (); + CheckCursorConfinement(pWin); +} + + + +static void +miOverlayChangeBorderWidth( + WindowPtr pWin, + unsigned int width +){ + int oldwidth; + ScreenPtr pScreen; + Bool WasViewable = (Bool)(pWin->viewable); + Bool HadBorder; + + 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 = RegionCreate(NULL, 1); + RegionSubtract(borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + if(IN_UNDERLAY(pWin)) { + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + RegionPtr borderVisible2; + + borderVisible2 = RegionCreate(NULL, 1); + RegionSubtract(borderVisible2, + &pTree->borderClip, &pWin->winSize); + pTree->valdata->borderVisible = borderVisible2; + } + } + } + (*pScreen->ValidateTree)(pWin->parent, pWin, VTOther); + (*pScreen->HandleExposures)(pWin->parent); + + 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. */ + +void +miOverlaySetRootClip(ScreenPtr pScreen, Bool enable) +{ + WindowPtr pRoot = pScreen->root; + 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; + + RegionReset(&pTree->borderClip, &box); + } else + RegionEmpty(&pTree->borderClip); + + RegionBreak(&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 = RegionExtents(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; + + RegionInit(®, &box, 1); + + RegionIntersect(®, ®, clipList); + if (generateExposures) + (*pScreen->WindowExposures)(pWin, ®, pBSReg); + else if (pWin->backgroundState != None) + miPaintWindow(pWin, ®, PW_BACKGROUND); + RegionUninit(®); + if (pBSReg) + RegionDestroy(pBSReg); +} + + +/****************************************************************/ + +/* not used */ +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; +} + +void +miOverlaySetTransFunction ( + ScreenPtr pScreen, + miOverlayTransFunc transFunc +){ + MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent = transFunc; +} + +Bool +miOverlayCopyUnderlay(ScreenPtr pScreen) +{ + return MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->copyUnderlay; +} + +void +miOverlayComputeCompositeClip(GCPtr pGC, WindowPtr pWin) +{ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + RegionPtr pregWin; + Bool freeTmpClip, freeCompClip; + + if(!pTree) { + miComputeCompositeClip(pGC, &pWin->drawable); + return; + } + + if (pGC->subWindowMode == IncludeInferiors) { + pregWin = RegionCreate(NullBox, 1); + freeTmpClip = TRUE; + if (pWin->parent || (screenIsSaved != SCREEN_SAVER_ON) || + !HasSaverWindow (pGC->pScreen)) + { + RegionIntersect(pregWin,&pTree->borderClip,&pWin->winSize); + } + } else { + pregWin = &pTree->clipList; + freeTmpClip = FALSE; + } + freeCompClip = pGC->freeCompClip; + if (pGC->clientClipType == CT_NONE) { + if (freeCompClip) + RegionDestroy(pGC->pCompositeClip); + pGC->pCompositeClip = pregWin; + pGC->freeCompClip = freeTmpClip; + } else { + RegionTranslate(pGC->clientClip, + pWin->drawable.x + pGC->clipOrg.x, + pWin->drawable.y + pGC->clipOrg.y); + + if (freeCompClip) { + RegionIntersect(pGC->pCompositeClip, + pregWin, pGC->clientClip); + if (freeTmpClip) + RegionDestroy(pregWin); + } else if (freeTmpClip) { + RegionIntersect(pregWin, pregWin, pGC->clientClip); + pGC->pCompositeClip = pregWin; + } else { + pGC->pCompositeClip = RegionCreate(NullBox, 0); + RegionIntersect(pGC->pCompositeClip, + pregWin, pGC->clientClip); + } + pGC->freeCompClip = TRUE; + RegionTranslate(pGC->clientClip, + -(pWin->drawable.x + pGC->clipOrg.x), + -(pWin->drawable.y + pGC->clipOrg.y)); + } +} + +Bool +miOverlayCollectUnderlayRegions( + WindowPtr pWin, + RegionPtr *region +){ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + if(pTree) { + *region = &pTree->borderClip; + return FALSE; + } + + *region = RegionCreate(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))) { + RegionAppend(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; + RegionValidate(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/mi/mioverlay.h b/mi/mioverlay.h new file mode 100644 index 0000000..dca65ad --- /dev/null +++ b/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); + +extern _X_EXPORT Bool +miInitOverlay( + ScreenPtr pScreen, + miOverlayInOverlayFunc inOverlay, + miOverlayTransFunc trans +); + +extern _X_EXPORT Bool +miOverlayGetPrivateClips( + WindowPtr pWin, + RegionPtr *borderClip, + RegionPtr *clipList +); + +extern _X_EXPORT Bool miOverlayCollectUnderlayRegions(WindowPtr, RegionPtr*); +extern _X_EXPORT void miOverlayComputeCompositeClip(GCPtr, WindowPtr); +extern _X_EXPORT Bool miOverlayCopyUnderlay(ScreenPtr); +extern _X_EXPORT void miOverlaySetTransFunction(ScreenPtr, miOverlayTransFunc); +extern _X_EXPORT void miOverlaySetRootClip(ScreenPtr, Bool); + +#endif /* __MIOVERLAY_H */ diff --git a/mi/mipointer.c b/mi/mipointer.c new file mode 100644 index 0000000..ca0bae5 --- /dev/null +++ b/mi/mipointer.c @@ -0,0 +1,589 @@ +/* + +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/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" +# include "inpututils.h" + +DevPrivateKeyRec miPointerScreenKeyRec; + +#define GetScreenPrivate(s) ((miPointerScreenPtr) \ + dixLookupPrivate(&(s)->devPrivates, miPointerScreenKey)) +#define SetupScreen(s) miPointerScreenPtr pScreenPriv = GetScreenPrivate(s) + +DevPrivateKeyRec miPointerPrivKeyRec; + +#define MIPOINTER(dev) \ + ((!IsMaster(dev) && !dev->u.master) ? \ + (miPointerPtr)dixLookupPrivate(&(dev)->devPrivates, miPointerPrivKey): \ + (miPointerPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miPointerPrivKey)) + +static Bool miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor); +static Bool miPointerUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor); +static Bool miPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor); +static void miPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + BoxPtr pBox); +static void miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor, BoxPtr pHotBox, + BoxPtr pTopLeftBox); +static Bool miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y, + Bool generateEvent); +static Bool miPointerCloseScreen(int index, ScreenPtr pScreen); +static void miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y); +static Bool miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen); +static void miPointerDeviceCleanup(DeviceIntPtr pDev, + ScreenPtr pScreen); +static void miPointerMoveNoEvent (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y); + +static EventList* events; /* for WarpPointer MotionNotifies */ + +Bool +miPointerInitialize (ScreenPtr pScreen, + miPointerSpriteFuncPtr spriteFuncs, + miPointerScreenFuncPtr screenFuncs, + Bool waitForUpdate) +{ + miPointerScreenPtr pScreenPriv; + + if (!dixRegisterPrivateKey(&miPointerScreenKeyRec, PRIVATE_SCREEN, 0)) + return FALSE; + + if (!dixRegisterPrivateKey(&miPointerPrivKeyRec, PRIVATE_DEVICE, 0)) + return FALSE; + + pScreenPriv = malloc(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->DeviceCursorInitialize = miPointerDeviceInitialize; + pScreen->DeviceCursorCleanup = miPointerDeviceCleanup; + + events = NULL; + return TRUE; +} + +static Bool +miPointerCloseScreen (int index, ScreenPtr pScreen) +{ +#if 0 + miPointerPtr pPointer; + DeviceIntPtr pDev; +#endif + + SetupScreen(pScreen); + +#if 0 + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pPointer = MIPOINTER(pDev); + + if (pScreen == pPointer->pScreen) + pPointer->pScreen = 0; + if (pScreen == pPointer->pSpriteScreen) + pPointer->pSpriteScreen = 0; + } + } + + if (MIPOINTER(inputInfo.pointer)->pScreen == pScreen) + MIPOINTER(inputInfo.pointer)->pScreen = 0; + if (MIPOINTER(inputInfo.pointer)->pSpriteScreen == pScreen) + MIPOINTER(inputInfo.pointer)->pSpriteScreen = 0; +#endif + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + free((pointer) pScreenPriv); + FreeEventList(events, GetMaximumEventsNum()); + events = NULL; + return (*pScreen->CloseScreen) (index, pScreen); +} + +/* + * DIX/DDX interface routines + */ + +static Bool +miPointerRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + SetupScreen(pScreen); + return (*pScreenPriv->spriteFuncs->RealizeCursor) (pDev, pScreen, pCursor); +} + +static Bool +miPointerUnrealizeCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor) +{ + SetupScreen(pScreen); + return (*pScreenPriv->spriteFuncs->UnrealizeCursor) (pDev, pScreen, pCursor); +} + +static Bool +miPointerDisplayCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + miPointerPtr pPointer; + + /* return for keyboards */ + if ((IsMaster(pDev) && !DevHasCursor(pDev)) || + (!IsMaster(pDev) && pDev->u.master && !DevHasCursor(pDev->u.master))) + return FALSE; + + pPointer = MIPOINTER(pDev); + + pPointer->pCursor = pCursor; + pPointer->pScreen = pScreen; + miPointerUpdateSprite(pDev); + return TRUE; +} + +static void +miPointerConstrainCursor (DeviceIntPtr pDev, ScreenPtr pScreen, BoxPtr pBox) +{ + miPointerPtr pPointer; + + pPointer = MIPOINTER(pDev); + + pPointer->limits = *pBox; + pPointer->confined = PointerConfinedToScreen(pDev); +} + +/*ARGSUSED*/ +static void +miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, + BoxPtr pHotBox, BoxPtr pTopLeftBox) +{ + *pTopLeftBox = *pHotBox; +} + +static Bool GenerateEvent; + +static Bool +miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y, Bool generateEvent) +{ + SetupScreen (pScreen); + + GenerateEvent = generateEvent; + /* device dependent - must pend signal and call miPointerWarpCursor */ + (*pScreenPriv->screenFuncs->WarpCursor) (pDev, pScreen, x, y); + if (!generateEvent) + miPointerUpdateSprite(pDev); + return TRUE; +} + +/* Set up sprite information for the device. + This function will be called once for each device after it is initialized + in the DIX. + */ +static Bool +miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miPointerPtr pPointer; + SetupScreen (pScreen); + + pPointer = malloc(sizeof(miPointerRec)); + if (!pPointer) + return FALSE; + + pPointer->pScreen = NULL; + pPointer->pSpriteScreen = NULL; + pPointer->pCursor = NULL; + pPointer->pSpriteCursor = NULL; + pPointer->limits.x1 = 0; + pPointer->limits.x2 = 32767; + pPointer->limits.y1 = 0; + pPointer->limits.y2 = 32767; + pPointer->confined = FALSE; + pPointer->x = 0; + pPointer->y = 0; + + if (!((*pScreenPriv->spriteFuncs->DeviceCursorInitialize)(pDev, pScreen))) + { + free(pPointer); + return FALSE; + } + + dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, pPointer); + return TRUE; +} + +/* Clean up after device. + This function will be called once before the device is freed in the DIX + */ +static void +miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + SetupScreen(pScreen); + + if (!IsMaster(pDev) && pDev->u.master) + return; + + (*pScreenPriv->spriteFuncs->DeviceCursorCleanup)(pDev, pScreen); + free(dixLookupPrivate(&pDev->devPrivates, miPointerPrivKey)); + dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, NULL); +} + + +/* Once signals are ignored, the WarpCursor function can call this */ + +void +miPointerWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + miPointerPtr pPointer; + BOOL changedScreen = FALSE; + + SetupScreen (pScreen); + pPointer = MIPOINTER(pDev); + + if (pPointer->pScreen != pScreen) + { + (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, TRUE); + changedScreen = TRUE; + } + + if (GenerateEvent) + miPointerMove (pDev, pScreen, x, y); + else + miPointerMoveNoEvent(pDev, pScreen, x, y); + + /* Don't call USFS if we use Xinerama, otherwise the root window is + * updated to the second screen, and we never receive any events. + * (FDO bug #18668) */ + if (changedScreen +#ifdef PANORAMIX + && noPanoramiXExtension +#endif + ) + UpdateSpriteForScreen (pDev, pScreen) ; +} + +/* + * Pointer/CursorDisplay interface routines + */ + +/* + * miPointerUpdateSprite + * + * Syncronize the sprite with the cursor - called from ProcessInputEvents + */ + +void +miPointerUpdateSprite (DeviceIntPtr pDev) +{ + ScreenPtr pScreen; + miPointerScreenPtr pScreenPriv; + CursorPtr pCursor; + int x, y, devx, devy; + miPointerPtr pPointer; + + if (!pDev || !pDev->coreEvents) + return; + + pPointer = MIPOINTER(pDev); + + if (!pPointer) + return; + + pScreen = pPointer->pScreen; + if (!pScreen) + return; + + x = pPointer->x; + y = pPointer->y; + devx = pPointer->devx; + devy = pPointer->devy; + + pScreenPriv = GetScreenPrivate (pScreen); + /* + * if the cursor has switched screens, disable the sprite + * on the old screen + */ + if (pScreen != pPointer->pSpriteScreen) + { + if (pPointer->pSpriteScreen) + { + miPointerScreenPtr pOldPriv; + + pOldPriv = GetScreenPrivate (pPointer->pSpriteScreen); + if (pPointer->pCursor) + { + (*pOldPriv->spriteFuncs->SetCursor) + (pDev, pPointer->pSpriteScreen, NullCursor, 0, 0); + } + (*pOldPriv->screenFuncs->CrossScreen) (pPointer->pSpriteScreen, FALSE); + } + (*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE); + (*pScreenPriv->spriteFuncs->SetCursor) + (pDev, pScreen, pPointer->pCursor, x, y); + pPointer->devx = x; + pPointer->devy = y; + pPointer->pSpriteCursor = pPointer->pCursor; + pPointer->pSpriteScreen = pScreen; + } + /* + * if the cursor has changed, display the new one + */ + else if (pPointer->pCursor != pPointer->pSpriteCursor) + { + pCursor = pPointer->pCursor; + if (!pCursor || (pCursor->bits->emptyMask && !pScreenPriv->showTransparent)) + pCursor = NullCursor; + (*pScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, pCursor, x, y); + + pPointer->devx = x; + pPointer->devy = y; + pPointer->pSpriteCursor = pPointer->pCursor; + } + else if (x != devx || y != devy) + { + pPointer->devx = x; + pPointer->devy = y; + if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) + (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); + } +} + +void +miPointerSetScreen(DeviceIntPtr pDev, int screen_no, int x, int y) +{ + miPointerScreenPtr pScreenPriv; + ScreenPtr pScreen; + miPointerPtr pPointer; + + pPointer = MIPOINTER(pDev); + + pScreen = screenInfo.screens[screen_no]; + pScreenPriv = GetScreenPrivate (pScreen); + (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, FALSE); + NewCurrentScreen (pDev, pScreen, x, y); + + pPointer->limits.x2 = pScreen->width; + pPointer->limits.y2 = pScreen->height; +} + +ScreenPtr +miPointerCurrentScreen (void) +{ + return miPointerGetScreen(inputInfo.pointer); +} + +ScreenPtr +miPointerGetScreen(DeviceIntPtr pDev) +{ + miPointerPtr pPointer = MIPOINTER(pDev); + return (pPointer) ? pPointer->pScreen : NULL; +} + +/* Controls whether the cursor image should be updated immediately when + moved (FALSE) or if something else will be responsible for updating + it later (TRUE). Returns current setting. + Caller is responsible for calling OsBlockSignal first. +*/ +Bool +miPointerSetWaitForUpdate(ScreenPtr pScreen, Bool wait) +{ + SetupScreen(pScreen); + Bool prevWait = pScreenPriv->waitForUpdate; + + pScreenPriv->waitForUpdate = wait; + return prevWait; +} + + +/* Move the pointer on the current screen, and update the sprite. */ +static void +miPointerMoveNoEvent (DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y) +{ + miPointerPtr pPointer; + SetupScreen(pScreen); + + pPointer = MIPOINTER(pDev); + + /* Hack: We mustn't call into ->MoveCursor for anything but the + * VCP, as this may cause a non-HW rendered cursor to be rendered during + * SIGIO. This again leads to allocs during SIGIO which leads to SIGABRT. + */ + if ((pDev == inputInfo.pointer || (!IsMaster(pDev) && pDev->u.master == inputInfo.pointer)) + && !pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen) + { + pPointer->devx = x; + pPointer->devy = y; + if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) + (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); + } + + pPointer->x = x; + pPointer->y = y; + pPointer->pScreen = pScreen; +} + +void +miPointerSetPosition(DeviceIntPtr pDev, int *x, int *y) +{ + miPointerScreenPtr pScreenPriv; + ScreenPtr pScreen; + ScreenPtr newScreen; + + miPointerPtr pPointer; + + if (!pDev || !pDev->coreEvents) + return; + + pPointer = MIPOINTER(pDev); + pScreen = pPointer->pScreen; + if (!pScreen) + return; /* called before ready */ + + if (*x < 0 || *x >= pScreen->width || *y < 0 || *y >= pScreen->height) + { + pScreenPriv = GetScreenPrivate (pScreen); + if (!pPointer->confined) + { + newScreen = pScreen; + (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, x, y); + if (newScreen != pScreen) + { + pScreen = newScreen; + (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, + FALSE); + /* Smash the confine to the new screen */ + pPointer->limits.x2 = pScreen->width; + pPointer->limits.y2 = pScreen->height; + } + } + } + /* Constrain the sprite to the current limits. */ + if (*x < pPointer->limits.x1) + *x = pPointer->limits.x1; + if (*x >= pPointer->limits.x2) + *x = pPointer->limits.x2 - 1; + if (*y < pPointer->limits.y1) + *y = pPointer->limits.y1; + if (*y >= pPointer->limits.y2) + *y = pPointer->limits.y2 - 1; + + if (pPointer->x == *x && pPointer->y == *y && + pPointer->pScreen == pScreen) + return; + + miPointerMoveNoEvent(pDev, pScreen, *x, *y); +} + +void +miPointerGetPosition(DeviceIntPtr pDev, int *x, int *y) +{ + *x = MIPOINTER(pDev)->x; + *y = MIPOINTER(pDev)->y; +} + +#ifdef XQUARTZ +#include <pthread.h> +void darwinEvents_lock(void); +void darwinEvents_unlock(void); +#endif + +void +miPointerMove (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + int i, nevents; + int valuators[2]; + ValuatorMask mask; + + miPointerMoveNoEvent(pDev, pScreen, x, y); + + /* generate motion notify */ + valuators[0] = x; + valuators[1] = y; + + if (!events) + { + events = InitEventList(GetMaximumEventsNum()); + + if (!events) + { + FatalError("Could not allocate event store.\n"); + return; + } + } + + valuator_mask_set_range(&mask, 0, 2, valuators); + nevents = GetPointerEvents(events, pDev, MotionNotify, 0, + POINTER_SCREEN | POINTER_ABSOLUTE, &mask); + + OsBlockSignals(); +#ifdef XQUARTZ + darwinEvents_lock(); +#endif + for (i = 0; i < nevents; i++) + mieqEnqueue(pDev, (InternalEvent*)events[i].event); +#ifdef XQUARTZ + darwinEvents_unlock(); +#endif + OsReleaseSignals(); +} diff --git a/mi/mipointer.h b/mi/mipointer.h new file mode 100644 index 0000000..3c86110 --- /dev/null +++ b/mi/mipointer.h @@ -0,0 +1,153 @@ +/* + +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)( + DeviceIntPtr /* pDev */, + ScreenPtr /* pScr */, + CursorPtr /* pCurs */ + ); + Bool (*UnrealizeCursor)( + DeviceIntPtr /* pDev */, + ScreenPtr /* pScr */, + CursorPtr /* pCurs */ + ); + void (*SetCursor)( + DeviceIntPtr /* pDev */, + ScreenPtr /* pScr */, + CursorPtr /* pCurs */, + int /* x */, + int /* y */ + ); + void (*MoveCursor)( + DeviceIntPtr /* pDev */, + ScreenPtr /* pScr */, + int /* x */, + int /* y */ + ); + Bool (*DeviceCursorInitialize)( + DeviceIntPtr /* pDev */, + ScreenPtr /* pScr */ + ); + void (*DeviceCursorCleanup)( + DeviceIntPtr /* pDev */, + ScreenPtr /* pScr */ + ); +} miPointerSpriteFuncRec, *miPointerSpriteFuncPtr; + +typedef struct _miPointerScreenFuncRec { + Bool (*CursorOffScreen)( + ScreenPtr* /* ppScr */, + int* /* px */, + int* /* py */ + ); + void (*CrossScreen)( + ScreenPtr /* pScr */, + int /* entering */ + ); + void (*WarpCursor)( + DeviceIntPtr /*pDev*/, + ScreenPtr /* pScr */, + int /* x */, + int /* y */ + ); + void (*EnqueueEvent)( + DeviceIntPtr /* pDev */, + InternalEvent* /* event */ + ); + void (*NewEventScreen)( + DeviceIntPtr /* pDev */, + ScreenPtr /* pScr */, + Bool /* fromDIX */ + ); +} miPointerScreenFuncRec, *miPointerScreenFuncPtr; + +extern _X_EXPORT Bool miDCInitialize( + ScreenPtr /*pScreen*/, + miPointerScreenFuncPtr /*screenFuncs*/ +); + +extern _X_EXPORT Bool miPointerInitialize( + ScreenPtr /*pScreen*/, + miPointerSpriteFuncPtr /*spriteFuncs*/, + miPointerScreenFuncPtr /*screenFuncs*/, + Bool /*waitForUpdate*/ +); + +extern _X_EXPORT void miPointerWarpCursor( + DeviceIntPtr /*pDev*/, + ScreenPtr /*pScreen*/, + int /*x*/, + int /*y*/ +); + +/* Deprecated in favour of miPointerGetScreen. */ +extern _X_EXPORT ScreenPtr miPointerCurrentScreen( + void +) _X_DEPRECATED; + +extern _X_EXPORT ScreenPtr miPointerGetScreen( + DeviceIntPtr pDev); +extern _X_EXPORT void miPointerSetScreen( + DeviceIntPtr pDev, + int screen_num, + int x, + int y); + +/* Returns the current cursor position. */ +extern _X_EXPORT 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 _X_EXPORT void miPointerSetPosition( + DeviceIntPtr pDev, + int *x, + int *y); + +extern _X_EXPORT void miPointerUpdateSprite( + DeviceIntPtr pDev); + +/* Sets whether the sprite should be updated immediately on pointer moves */ +extern _X_EXPORT Bool miPointerSetWaitForUpdate( + ScreenPtr pScreen, + Bool wait); + +extern _X_EXPORT DevPrivateKeyRec miPointerPrivKeyRec; +#define miPointerPrivKey (&miPointerPrivKeyRec) + +extern _X_EXPORT DevPrivateKeyRec miPointerScreenKeyRec; +#define miPointerScreenKey (&miPointerScreenKeyRec) + +#endif /* MIPOINTER_H */ diff --git a/mi/mipointrst.h b/mi/mipointrst.h new file mode 100644 index 0000000..bd9c24a --- /dev/null +++ b/mi/mipointrst.h @@ -0,0 +1,56 @@ +/* + * 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. +*/ + +#ifndef MIPOINTRST_H +#define MIPOINTRST_H + +#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; +#endif /* MIPOINTRST_H */ diff --git a/mi/mipoly.c b/mi/mipoly.c new file mode 100644 index 0000000..b3e2c2f --- /dev/null +++ b/mi/mipoly.c @@ -0,0 +1,124 @@ +/*********************************************************** + +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" + + +void +miFillPolygon( DrawablePtr dst, GCPtr pgc, + int shape, int 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/mi/mipoly.h b/mi/mipoly.h new file mode 100644 index 0000000..d94796e --- /dev/null +++ b/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 _X_EXPORT Bool miCreateETandAET( + int /*count*/, + DDXPointPtr /*pts*/, + EdgeTable * /*ET*/, + EdgeTableEntry * /*AET*/, + EdgeTableEntry * /*pETEs*/, + ScanLineListBlock * /*pSLLBlock*/ +); + +extern _X_EXPORT void miloadAET( + EdgeTableEntry * /*AET*/, + EdgeTableEntry * /*ETEs*/ +); + +extern _X_EXPORT void micomputeWAET( + EdgeTableEntry * /*AET*/ +); + +extern _X_EXPORT int miInsertionSort( + EdgeTableEntry * /*AET*/ +); + +extern _X_EXPORT void miFreeStorage( + ScanLineListBlock * /*pSLLBlock*/ +); diff --git a/mi/mipolycon.c b/mi/mipolycon.c new file mode 100644 index 0000000..c201e39 --- /dev/null +++ b/mi/mipolycon.c @@ -0,0 +1,247 @@ +/*********************************************************** + +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. + */ +Bool +miFillConvexPoly( + 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 = malloc(sizeof(DDXPointRec)*dy); + width = FirstWidth = malloc(sizeof(int) * dy); + if(!FirstPoint || !FirstWidth) + { + free(FirstWidth); + free(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) + { + free(FirstWidth); + free(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); + free(FirstWidth); + free(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/mi/mipolygen.c b/mi/mipolygen.c new file mode 100644 index 0000000..7c7c593 --- /dev/null +++ b/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( + 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 = malloc(sizeof(EdgeTableEntry) * count))) + return FALSE; + ptsOut = FirstPoint; + width = FirstWidth; + if (!miCreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock)) + { + free(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); + free(pETEs); + miFreeStorage(SLLBlock.next); + return TRUE; +} diff --git a/mi/mipolypnt.c b/mi/mipolypnt.c new file mode 100644 index 0000000..3e43a52 --- /dev/null +++ b/mi/mipolypnt.c @@ -0,0 +1,125 @@ +/*********************************************************** + +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" + +void +miPolyPoint( + DrawablePtr pDrawable, + GCPtr pGC, + int mode, /* Origin or Previous */ + int npt, + xPoint *pptInit + ) +{ + + int xorg; + int yorg; + int nptTmp; + ChangeGCVal fsOld, fsNew; + int *pwidthInit, *pwidth; + int i; + xPoint *ppt; + + if(!(pwidthInit = malloc(npt * sizeof(int)))) + return; + + /* 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.val = pGC->fillStyle; + fsNew.val = FillSolid; + if(pGC->fillStyle != FillSolid) + { + ChangeGC(NullClient, pGC, GCFillStyle, &fsNew); + ValidateGC(pDrawable, pGC); + } + pwidth = pwidthInit; + for(i = 0; i < npt; i++) + *pwidth++ = 1; + (*pGC->ops->FillSpans)(pDrawable, pGC, npt, pptInit, pwidthInit, FALSE); + + if(fsOld.val != FillSolid) + { + ChangeGC(NullClient, pGC, GCFillStyle, &fsOld); + ValidateGC(pDrawable, pGC); + } + free(pwidthInit); +} + diff --git a/mi/mipolyrect.c b/mi/mipolyrect.c new file mode 100644 index 0000000..9b0edc1 --- /dev/null +++ b/mi/mipolyrect.c @@ -0,0 +1,187 @@ +/*********************************************************** + +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" + +void +miPolyRectangle(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 = malloc(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); + free((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/mi/mipolyseg.c b/mi/mipolyseg.c new file mode 100644 index 0000000..bf7f0f9 --- /dev/null +++ b/mi/mipolyseg.c @@ -0,0 +1,79 @@ +/*********************************************************** + +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. + * + *****************************************************************/ + + +void +miPolySegment(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/mi/mipolytext.c b/mi/mipolytext.c new file mode 100644 index 0000000..508e0ff --- /dev/null +++ b/mi/mipolytext.c @@ -0,0 +1,130 @@ +/******************************************************************* + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +************************************************************************/ +/* + * mipolytext.c - text routines + * + * Author: haynes + * Digital Equipment Corporation + * Western Software Laboratory + * Date: Thu Feb 5 1987 + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xmd.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "gcstruct.h" +#include <X11/fonts/fontstruct.h> +#include "dixfontstr.h" +#include "mi.h" + +int +miPolyText8(DrawablePtr pDraw, GCPtr pGC, int x, int 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; +} + +int +miPolyText16(DrawablePtr pDraw, GCPtr pGC, int x, int 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; +} + +void +miImageText8(DrawablePtr pDraw, GCPtr pGC, int x, int 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)); +} + +void +miImageText16(DrawablePtr pDraw, GCPtr pGC, int x, int 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/mi/mipolyutil.c b/mi/mipolyutil.c new file mode 100644 index 0000000..d978ee8 --- /dev/null +++ b/mi/mipolyutil.c @@ -0,0 +1,385 @@ +/*********************************************************** + +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 = malloc(sizeof(ScanLineListBlock)); + if (!tmpSLLBlock) + return FALSE; + (*SLLBlock)->next = tmpSLLBlock; + tmpSLLBlock->next = NULL; + *SLLBlock = tmpSLLBlock; + *iSLLBlock = 0; + } + pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]); + + pSLL->next = pPrevSLL->next; + pSLL->edgelist = NULL; + pPrevSLL->next = pSLL; + } + pSLL->scanline = scanline; + + /* + * now insert the edge in the right bucket + */ + prev = 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(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 = NULL; + AET->back = NULL; + AET->nextWETE = NULL; + AET->bres.minor = MININT; + + /* + * initialize the Edge Table. + */ + ET->scanlines.next = NULL; + ET->ymax = MININT; + ET->ymin = MAXINT; + pSLLBlock->next = 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(EdgeTableEntry *AET, EdgeTableEntry *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(EdgeTableEntry *AET) +{ + EdgeTableEntry *pWETE; + int inside = 1; + int isInside = 0; + + AET->nextWETE = 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 = NULL; +} + +/* + * InsertionSort + * + * Just a simple insertion sort using + * pointers and back pointers to sort the Active + * Edge Table. + * + */ + +int +miInsertionSort(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(ScanLineListBlock *pSLLBlock) +{ + ScanLineListBlock *tmpSLLBlock; + + while (pSLLBlock) + { + tmpSLLBlock = pSLLBlock->next; + free(pSLLBlock); + pSLLBlock = tmpSLLBlock; + } +} diff --git a/mi/mipushpxl.c b/mi/mipushpxl.c new file mode 100644 index 0000000..9f04298 --- /dev/null +++ b/mi/mipushpxl.c @@ -0,0 +1,271 @@ +/*********************************************************** + +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 + */ +void +miPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDrawable, + int dx, int dy, int xOrg, int 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 = malloc(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; + } + } + } + free(pwLineStart); + /* Flush any remaining spans */ + if (ipt) + { + (*pGC->ops->FillSpans)(pDrawable, pGC, ipt, pt, width, TRUE); + } +} diff --git a/mi/miscanfill.h b/mi/miscanfill.h new file mode 100644 index 0000000..e318c45 --- /dev/null +++ b/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/mi/miscrinit.c b/mi/miscrinit.c new file mode 100644 index 0000000..fb01c68 --- /dev/null +++ b/mi/miscrinit.c @@ -0,0 +1,296 @@ +/* + +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 +#include <X11/extensions/shm.h> +#include "shmint.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 */ +Bool +miModifyPixmapHeader(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.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; + } + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + 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. + */ +Bool +miCreateScreenResources(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; + } + free(pScreen->devPrivate); /* freeing miScreenInitParmsRec */ + pScreen->devPrivate = value; /* pPixmap or pbits */ + return TRUE; +} + +Bool +miScreenDevPrivateInit(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 = malloc(sizeof(miScreenInitParmsRec)); + if (!pScrInitParms) + return FALSE; + pScrInitParms->pbits = pbits; + pScrInitParms->width = width; + pScreen->devPrivate = (pointer)pScrInitParms; + return TRUE; +} + +static PixmapPtr +miGetScreenPixmap(ScreenPtr pScreen) +{ + return (PixmapPtr)(pScreen->devPrivate); +} + +static void +miSetScreenPixmap(PixmapPtr pPix) +{ + if (pPix) + pPix->drawable.pScreen->devPrivate = (pointer)pPix; +} + +Bool +miScreenInit( + ScreenPtr pScreen, + pointer pbits, /* pointer to screen bits */ + int xsize, int ysize, /* in pixels */ + int dpix, int 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->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->MoveWindow = miMoveWindow; + pScreen->ResizeWindow = miSlideAndSizeWindow; + pScreen->GetLayerWindow = miGetLayerWindow; + pScreen->HandleExposures = miHandleValidateExposures; + pScreen->ReparentWindow = (ReparentWindowProcPtr) 0; + pScreen->ChangeBorderWidth = miChangeBorderWidth; + pScreen->SetShape = miSetShape; + pScreen->MarkUnrealizedWindow = miMarkUnrealizedWindow; + + miSetZeroLineBias(pScreen, DEFAULTZEROLINEBIAS); + + return miScreenDevPrivateInit(pScreen, width, pbits); +} + +DevPrivateKeyRec miZeroLineScreenKeyRec; + +void +miSetZeroLineBias(ScreenPtr pScreen, unsigned int bias) +{ + if (!dixRegisterPrivateKey(&miZeroLineScreenKeyRec, PRIVATE_SCREEN, 0)) + return; + + dixSetPrivate(&pScreen->devPrivates, miZeroLineScreenKey, + (unsigned long *)(unsigned long)bias); +} diff --git a/mi/mispans.c b/mi/mispans.c new file mode 100644 index 0000000..21ba4da --- /dev/null +++ b/mi/mispans.c @@ -0,0 +1,527 @@ +/*********************************************************** + +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->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) realloc(spans->points, (spans->count + EXTRA) * sizeof (DDXPointRec)); + if (!newPt) + break; + spansPt = newPt + (spansPt - spans->points); + spans->points = newPt; + newwid = (int *) realloc(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 *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 *) + realloc(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 + { + free(spans->points); + free(spans->widths); + } +} /* AppendSpans */ + +void miFreeSpanGroup(SpanGroup *spanGroup) +{ + free(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; + free(spans->points); + free(spans->widths); + } +} + +void miFillUniqueSpanGroup(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); + free(spans->points); + free(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 = malloc(ylength * sizeof(Spans)); + ysizes = malloc(ylength * sizeof (int)); + + if (!yspans || !ysizes) + { + free(yspans); + free(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) realloc( + newspans->points, + ysizes[index] * sizeof(DDXPointRec)); + newwidths = (int *) realloc( + newspans->widths, + ysizes[index] * sizeof(int)); + if (!newpoints || !newwidths) + { + int i; + + for (i = 0; i < ylength; i++) + { + free(yspans[i].points); + free(yspans[i].widths); + } + free(yspans); + free(ysizes); + free(newpoints); + free(newwidths); + 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; + free(spans->points); + spans->points = NULL; + free(spans->widths); + spans->widths = NULL; + } /* for i thorough Spans */ + + /* Now sort by x and uniquify each bucket into the final array */ + points = malloc(count * sizeof(DDXPointRec)); + widths = malloc(count * sizeof(int)); + if (!points || !widths) + { + int i; + + for (i = 0; i < ylength; i++) + { + free(yspans[i].points); + free(yspans[i].widths); + } + free(yspans); + free(ysizes); + free(points); + free(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++; + } + free(yspans[i].points); + free(yspans[i].widths); + } + } + + (*pGC->ops->FillSpans) (pDraw, pGC, count, points, widths, TRUE); + free(points); + free(widths); + free(yspans); + free(ysizes); /* use (DE)xalloc for these? */ + } + + spanGroup->count = 0; + spanGroup->ymin = MAXSHORT; + spanGroup->ymax = MINSHORT; +} diff --git a/mi/mispans.h b/mi/mispans.h new file mode 100644 index 0000000..c3a3e67 --- /dev/null +++ b/mi/mispans.h @@ -0,0 +1,92 @@ +/*********************************************************** + +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. + +******************************************************************/ + +#ifndef MISPANS_H +#define MISPANS_H + +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 _X_EXPORT void miInitSpanGroup( + SpanGroup * /*spanGroup*/ +); + +/* Add a Spans to a SpanGroup. The spans MUST BE in y-sorted order */ +extern _X_EXPORT void miAppendSpans( + SpanGroup * /*spanGroup*/, + SpanGroup * /*otherGroup*/, + Spans * /*spans*/ +); + +/* Paint a span group, insuring that each pixel is painted at most once */ +extern _X_EXPORT 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 _X_EXPORT void miFreeSpanGroup( + SpanGroup * /*spanGroup*/ +); + +/* Rops which must use span groups */ +#define miSpansCarefulRop(rop) (((rop) & 0xc) == 0x8 || ((rop) & 0x3) == 0x2) +#define miSpansEasyRop(rop) (!miSpansCarefulRop(rop)) + +#endif /* MISPANS_H */ diff --git a/mi/misprite.c b/mi/misprite.c new file mode 100644 index 0000000..770951e --- /dev/null +++ b/mi/misprite.c @@ -0,0 +1,1045 @@ +/* + * 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 "misprite.h" +#include "dixfontstr.h" +#include <X11/fonts/fontstruct.h> +#include "inputstr.h" +#include "damage.h" + +typedef struct { + 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 */ + ScreenPtr pScreen; +} miCursorInfoRec, *miCursorInfoPtr; + +/* + * 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; + + /* device cursor procedures */ + DeviceCursorInitializeProcPtr DeviceCursorInitialize; + DeviceCursorCleanupProcPtr DeviceCursorCleanup; + + xColorItem colors[2]; + ColormapPtr pInstalledMap; + ColormapPtr pColormap; + VisualPtr pVisual; + DamagePtr pDamage; /* damage tracking structure */ + Bool damageRegistered; + int numberOfCursors; +} miSpriteScreenRec, *miSpriteScreenPtr; + +#define SOURCE_COLOR 0 +#define MASK_COLOR 1 + +/* + * 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)) + + +#define SPRITE_DEBUG_ENABLE 0 +#if SPRITE_DEBUG_ENABLE +#define SPRITE_DEBUG(x) ErrorF x +#else +#define SPRITE_DEBUG(x) +#endif + +#define MISPRITE(dev) \ + ((!IsMaster(dev) && !dev->u.master) ? \ + (miCursorInfoPtr)dixLookupPrivate(&dev->devPrivates, miSpriteDevPrivatesKey) : \ + (miCursorInfoPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miSpriteDevPrivatesKey)) + +static void +miSpriteDisableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv) +{ + if (pScreenPriv->damageRegistered) { + DamageUnregister (&(pScreen->GetScreenPixmap(pScreen)->drawable), + pScreenPriv->pDamage); + pScreenPriv->damageRegistered = 0; + } +} + +static void +miSpriteEnableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv) +{ + if (!pScreenPriv->damageRegistered) { + pScreenPriv->damageRegistered = 1; + DamageRegister (&(pScreen->GetScreenPixmap(pScreen)->drawable), + pScreenPriv->pDamage); + } +} + +static void +miSpriteIsUp(miCursorInfoPtr pDevCursor) +{ + pDevCursor->isUp = TRUE; +} + +static void +miSpriteIsDown(miCursorInfoPtr pDevCursor) +{ + pDevCursor->isUp = FALSE; +} + +/* + * screen wrappers + */ + +static DevPrivateKeyRec miSpriteScreenKeyRec; +#define miSpriteScreenKey (&miSpriteScreenKeyRec) +#define GetSpriteScreen(pScreen) \ + (dixLookupPrivate(&(pScreen)->devPrivates, miSpriteScreenKey)) +static DevPrivateKeyRec miSpriteDevPrivatesKeyRec; +#define miSpriteDevPrivatesKey (&miSpriteDevPrivatesKeyRec) + +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, + unsigned int subWindowMode); +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(DeviceIntPtr pDev, + ScreenPtr pScreen); + +static Bool miSpriteDeviceCursorInitialize(DeviceIntPtr pDev, + ScreenPtr pScreen); +static void miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, + ScreenPtr pScreen); + +#define SCREEN_PROLOGUE(pPriv, pScreen, field) ((pScreen)->field = \ + (pPriv)->field) +#define SCREEN_EPILOGUE(pPriv, pScreen, field)\ + ((pPriv)->field = (pScreen)->field, (pScreen)->field = miSprite##field) + +/* + * pointer-sprite method table + */ + +static Bool miSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor); +static Bool miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor); +static void miSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor, int x, int y); +static void miSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y); + +miPointerSpriteFuncRec miSpritePointerFuncs = { + miSpriteRealizeCursor, + miSpriteUnrealizeCursor, + miSpriteSetCursor, + miSpriteMoveCursor, + miSpriteDeviceCursorInitialize, + miSpriteDeviceCursorCleanup, +}; + +/* + * other misc functions + */ + +static void miSpriteRemoveCursor(DeviceIntPtr pDev, + ScreenPtr pScreen); +static void miSpriteSaveUnderCursor(DeviceIntPtr pDev, + ScreenPtr pScreen); +static void miSpriteRestoreCursor(DeviceIntPtr pDev, + ScreenPtr pScreen); + +static void +miSpriteRegisterBlockHandler(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv) +{ + if (!pScreenPriv->BlockHandler) { + pScreenPriv->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = miSpriteBlockHandler; + } +} + +static void +miSpriteReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure) +{ + ScreenPtr pScreen = closure; + miCursorInfoPtr pCursorInfo; + DeviceIntPtr pDev; + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + + if (pCursorInfo->isUp && + pCursorInfo->pScreen == pScreen && + RegionContainsRect(pRegion, &pCursorInfo->saved) != rgnOUT) + { + SPRITE_DEBUG(("Damage remove\n")); + miSpriteRemoveCursor (pDev, pScreen); + } + } + } +} + +/* + * miSpriteInitialize -- called from device-dependent screen + * initialization proc after all of the function pointers have + * been stored in the screen structure. + */ + +Bool +miSpriteInitialize (ScreenPtr pScreen, + miPointerScreenFuncPtr screenFuncs) +{ + miSpriteScreenPtr pScreenPriv; + VisualPtr pVisual; + + if (!DamageSetup (pScreen)) + return FALSE; + + if (!dixRegisterPrivateKey(&miSpriteScreenKeyRec, PRIVATE_SCREEN, 0)) + return FALSE; + + if (!dixRegisterPrivateKey(&miSpriteDevPrivatesKeyRec, PRIVATE_DEVICE, 0)) + return FALSE; + + pScreenPriv = malloc(sizeof (miSpriteScreenRec)); + if (!pScreenPriv) + return FALSE; + + pScreenPriv->pDamage = DamageCreate (miSpriteReportDamage, + NULL, + DamageReportRawRegion, + TRUE, + pScreen, + pScreen); + + if (!miPointerInitialize (pScreen, &miSpritePointerFuncs, screenFuncs,TRUE)) + { + free(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 = NULL; + + pScreenPriv->DeviceCursorInitialize = pScreen->DeviceCursorInitialize; + pScreenPriv->DeviceCursorCleanup = pScreen->DeviceCursorCleanup; + + pScreenPriv->pInstalledMap = NULL; + pScreenPriv->pColormap = NULL; + 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; + pScreenPriv->damageRegistered = 0; + pScreenPriv->numberOfCursors = 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; + + return TRUE; +} + +/* + * Screen wrappers + */ + +/* + * CloseScreen wrapper -- unwrap everything, free the private data + * and call the wrapped function + */ + +static Bool +miSpriteCloseScreen (int i, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv = GetSpriteScreen(pScreen); + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + pScreen->GetImage = pScreenPriv->GetImage; + pScreen->GetSpans = pScreenPriv->GetSpans; + pScreen->SourceValidate = pScreenPriv->SourceValidate; + pScreen->InstallColormap = pScreenPriv->InstallColormap; + pScreen->StoreColors = pScreenPriv->StoreColors; + + DamageDestroy (pScreenPriv->pDamage); + + free(pScreenPriv); + + return (*pScreen->CloseScreen) (i, pScreen); +} + +static void +miSpriteGetImage (DrawablePtr pDrawable, int sx, int sy, int w, int h, + unsigned int format, unsigned long planemask, + char *pdstLine) +{ + ScreenPtr pScreen = pDrawable->pScreen; + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); + + SCREEN_PROLOGUE (pPriv, pScreen, GetImage); + + if (pDrawable->type == DRAWABLE_WINDOW) + { + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen && + ORG_OVERLAP(&pCursorInfo->saved,pDrawable->x,pDrawable->y, + sx, sy, w, h)) + { + SPRITE_DEBUG (("GetImage remove\n")); + miSpriteRemoveCursor (pDev, pScreen); + } + } + } + } + + (*pScreen->GetImage) (pDrawable, sx, sy, w, h, + format, planemask, pdstLine); + + SCREEN_EPILOGUE (pPriv, pScreen, GetImage); +} + +static void +miSpriteGetSpans (DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, + int *pwidth, int nspans, char *pdstStart) +{ + ScreenPtr pScreen = pDrawable->pScreen; + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); + + SCREEN_PROLOGUE (pPriv, pScreen, GetSpans); + + if (pDrawable->type == DRAWABLE_WINDOW) + { + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) + { + 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(&pCursorInfo->saved,pts->y+yorg, + pts->x+xorg,*widths)) + { + SPRITE_DEBUG (("GetSpans remove\n")); + miSpriteRemoveCursor (pDev, pScreen); + break; + } + } + } + } + } + } + + (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); + + SCREEN_EPILOGUE (pPriv, pScreen, GetSpans); +} + +static void +miSpriteSourceValidate (DrawablePtr pDrawable, int x, int y, int width, + int height, unsigned int subWindowMode) +{ + ScreenPtr pScreen = pDrawable->pScreen; + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); + + SCREEN_PROLOGUE (pPriv, pScreen, SourceValidate); + + if (pDrawable->type == DRAWABLE_WINDOW) + { + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen && + ORG_OVERLAP(&pCursorInfo->saved, pDrawable->x, pDrawable->y, + x, y, width, height)) + { + SPRITE_DEBUG (("SourceValidate remove\n")); + miSpriteRemoveCursor (pDev, pScreen); + } + } + } + } + + if (pScreen->SourceValidate) + (*pScreen->SourceValidate) (pDrawable, x, y, width, height, subWindowMode); + + SCREEN_EPILOGUE (pPriv, pScreen, SourceValidate); +} + +static void +miSpriteCopyWindow (WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); + + SCREEN_PROLOGUE (pPriv, pScreen, CopyWindow); + + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + /* + * Damage will take care of destination check + */ + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen && + RegionContainsRect(prgnSrc, &pCursorInfo->saved) != rgnOUT) + { + SPRITE_DEBUG (("CopyWindow remove\n")); + miSpriteRemoveCursor (pDev, pScreen); + } + } + } + + (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc); + SCREEN_EPILOGUE (pPriv, pScreen, CopyWindow); +} + +static void +miSpriteBlockHandler (int i, pointer blockData, pointer pTimeout, + pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + Bool WorkToDo = FALSE; + + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + if (pCursorInfo && !pCursorInfo->isUp + && pCursorInfo->pScreen == pScreen + && pCursorInfo->shouldBeUp) + { + SPRITE_DEBUG (("BlockHandler save")); + miSpriteSaveUnderCursor (pDev, pScreen); + } + } + } + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + if (pCursorInfo && !pCursorInfo->isUp && + pCursorInfo->pScreen == pScreen && + pCursorInfo->shouldBeUp) + { + SPRITE_DEBUG (("BlockHandler restore\n")); + miSpriteRestoreCursor (pDev, pScreen); + if (!pCursorInfo->isUp) + WorkToDo = TRUE; + } + } + } + + SCREEN_PROLOGUE(pPriv, pScreen, BlockHandler); + + (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); + + if (WorkToDo) + SCREEN_EPILOGUE(pPriv, pScreen, BlockHandler); + else + pPriv->BlockHandler = NULL; +} + +static void +miSpriteInstallColormap (ColormapPtr pMap) +{ + ScreenPtr pScreen = pMap->pScreen; + miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); + + SCREEN_PROLOGUE(pPriv, pScreen, InstallColormap); + + (*pScreen->InstallColormap) (pMap); + + SCREEN_EPILOGUE(pPriv, pScreen, InstallColormap); + + /* InstallColormap can be called before devices are initialized. */ + pPriv->pInstalledMap = pMap; + if (pPriv->pColormap != pMap) + { + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + pCursorInfo->checkPixels = TRUE; + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) + miSpriteRemoveCursor(pDev, pScreen); + } + } + + } +} + +static void +miSpriteStoreColors (ColormapPtr pMap, int ndef, xColorItem *pdef) +{ + ScreenPtr pScreen = pMap->pScreen; + miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); + int i; + int updated; + VisualPtr pVisual; + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + + SCREEN_PROLOGUE(pPriv, pScreen, StoreColors); + + (*pScreen->StoreColors) (pMap, ndef, pdef); + + SCREEN_EPILOGUE(pPriv, 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(dev, plane,dac,mask) {\ + if (MaskMatch (dev->colors[plane].pixel,pdef[i].pixel,mask)) {\ + dev->colors[plane].dac = pdef[i].dac; \ + updated = 1; \ + } \ +} + +#define CheckDirect(dev, plane) \ + UpdateDAC(dev, plane,red,redMask) \ + UpdateDAC(dev, plane,green,greenMask) \ + UpdateDAC(dev, plane,blue,blueMask) + + for (i = 0; i < ndef; i++) + { + CheckDirect (pPriv, SOURCE_COLOR) + CheckDirect (pPriv, 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) + { + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + pCursorInfo->checkPixels = TRUE; + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) + miSpriteRemoveCursor (pDev, pScreen); + } + } + } + } +} + +static void +miSpriteFindColors (miCursorInfoPtr pDevCursor, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv = GetSpriteScreen(pScreen); + CursorPtr pCursor; + xColorItem *sourceColor, *maskColor; + + pCursor = pDevCursor->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); + } + + pDevCursor->checkPixels = FALSE; + +} + +/* + * miPointer interface routines + */ + +#define SPRITE_PAD 8 + +static Bool +miSpriteRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + miCursorInfoPtr pCursorInfo; + + if (!IsMaster(pDev) && !pDev->u.master) + return FALSE; + + pCursorInfo = MISPRITE(pDev); + + if (pCursor == pCursorInfo->pCursor) + pCursorInfo->checkPixels = TRUE; + + return miDCRealizeCursor(pScreen, pCursor); +} + +static Bool +miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + return miDCUnrealizeCursor(pScreen, pCursor); +} + +static void +miSpriteSetCursor (DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor, int x, int y) +{ + miCursorInfoPtr pPointer; + miSpriteScreenPtr pScreenPriv; + + if (!IsMaster(pDev) && !pDev->u.master) + return; + + pPointer = MISPRITE(pDev); + pScreenPriv = GetSpriteScreen(pScreen); + + if (!pCursor) + { + if (pPointer->shouldBeUp) + --pScreenPriv->numberOfCursors; + pPointer->shouldBeUp = FALSE; + if (pPointer->isUp) + miSpriteRemoveCursor (pDev, pScreen); + if (pScreenPriv->numberOfCursors == 0) + miSpriteDisableDamage(pScreen, pScreenPriv); + pPointer->pCursor = 0; + return; + } + if (!pPointer->shouldBeUp) + pScreenPriv->numberOfCursors++; + pPointer->shouldBeUp = TRUE; + if (!pPointer->isUp) + miSpriteRegisterBlockHandler(pScreen, pScreenPriv); + if (pPointer->x == x && + pPointer->y == y && + pPointer->pCursor == pCursor && + !pPointer->checkPixels) + { + return; + } + pPointer->x = x; + pPointer->y = y; + pPointer->pCacheWin = NullWindow; + if (pPointer->checkPixels || pPointer->pCursor != pCursor) + { + pPointer->pCursor = pCursor; + miSpriteFindColors (pPointer, pScreen); + } + if (pPointer->isUp) { + /* TODO: reimplement flicker-free MoveCursor */ + SPRITE_DEBUG (("SetCursor remove %d\n", pDev->id)); + miSpriteRemoveCursor (pDev, pScreen); + } + + if (!pPointer->isUp && pPointer->pCursor) + { + SPRITE_DEBUG (("SetCursor restore %d\n", pDev->id)); + miSpriteSaveUnderCursor(pDev, pScreen); + miSpriteRestoreCursor (pDev, pScreen); + } + +} + +static void +miSpriteMoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + CursorPtr pCursor; + + if (!IsMaster(pDev) && !pDev->u.master) + return; + + pCursor = MISPRITE(pDev)->pCursor; + + miSpriteSetCursor (pDev, pScreen, pCursor, x, y); +} + + +static Bool +miSpriteDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miCursorInfoPtr pCursorInfo; + int ret = FALSE; + + pCursorInfo = malloc(sizeof(miCursorInfoRec)); + if (!pCursorInfo) + return FALSE; + + pCursorInfo->pCursor = NULL; + pCursorInfo->x = 0; + pCursorInfo->y = 0; + pCursorInfo->isUp = FALSE; + pCursorInfo->shouldBeUp = FALSE; + pCursorInfo->pCacheWin = NullWindow; + pCursorInfo->isInCacheWin = FALSE; + pCursorInfo->checkPixels = TRUE; + pCursorInfo->pScreen = FALSE; + + ret = miDCDeviceInitialize(pDev, pScreen); + if (!ret) + { + free(pCursorInfo); + pCursorInfo = NULL; + } + dixSetPrivate(&pDev->devPrivates, miSpriteDevPrivatesKey, pCursorInfo); + return ret; +} + +static void +miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + if (DevHasCursor(pDev)) + miDCDeviceCleanup(pDev, pScreen); +} + +/* + * undraw/draw cursor + */ + +static void +miSpriteRemoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv; + miCursorInfoPtr pCursorInfo; + + + if (!IsMaster(pDev) && !pDev->u.master) + return; + + DamageDrawInternal (pScreen, TRUE); + pScreenPriv = GetSpriteScreen(pScreen); + pCursorInfo = MISPRITE(pDev); + + miSpriteIsDown(pCursorInfo); + miSpriteRegisterBlockHandler(pScreen, pScreenPriv); + pCursorInfo->pCacheWin = NullWindow; + miSpriteDisableDamage(pScreen, pScreenPriv); + if (!miDCRestoreUnderCursor(pDev, + pScreen, + pCursorInfo->saved.x1, + pCursorInfo->saved.y1, + pCursorInfo->saved.x2 - + pCursorInfo->saved.x1, + pCursorInfo->saved.y2 - + pCursorInfo->saved.y1)) + { + miSpriteIsUp(pCursorInfo); + } + miSpriteEnableDamage(pScreen, pScreenPriv); + DamageDrawInternal (pScreen, FALSE); +} + +/* + * Called from the block handler, saves area under cursor + * before waiting for something to do. + */ + +static void +miSpriteSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv; + int x, y; + CursorPtr pCursor; + miCursorInfoPtr pCursorInfo; + + if (!IsMaster(pDev) && !pDev->u.master) + return; + + DamageDrawInternal (pScreen, TRUE); + pScreenPriv = GetSpriteScreen(pScreen); + pCursorInfo = MISPRITE(pDev); + + miSpriteComputeSaved (pDev, pScreen); + pCursor = pCursorInfo->pCursor; + + x = pCursorInfo->x - (int)pCursor->bits->xhot; + y = pCursorInfo->y - (int)pCursor->bits->yhot; + miSpriteDisableDamage(pScreen, pScreenPriv); + + miDCSaveUnderCursor(pDev, + pScreen, + pCursorInfo->saved.x1, + pCursorInfo->saved.y1, + pCursorInfo->saved.x2 - + pCursorInfo->saved.x1, + pCursorInfo->saved.y2 - + pCursorInfo->saved.y1); + SPRITE_DEBUG(("SaveUnderCursor %d\n", pDev->id)); + miSpriteEnableDamage(pScreen, pScreenPriv); + DamageDrawInternal (pScreen, FALSE); +} + + +/* + * Called from the block handler, restores the cursor + * before waiting for something to do. + */ + +static void +miSpriteRestoreCursor (DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv; + int x, y; + CursorPtr pCursor; + miCursorInfoPtr pCursorInfo; + + if (!IsMaster(pDev) && !pDev->u.master) + return; + + DamageDrawInternal (pScreen, TRUE); + pScreenPriv = GetSpriteScreen(pScreen); + pCursorInfo = MISPRITE(pDev); + + miSpriteComputeSaved (pDev, pScreen); + pCursor = pCursorInfo->pCursor; + + x = pCursorInfo->x - (int)pCursor->bits->xhot; + y = pCursorInfo->y - (int)pCursor->bits->yhot; + miSpriteDisableDamage(pScreen, pScreenPriv); + SPRITE_DEBUG(("RestoreCursor %d\n", pDev->id)); + if (pCursorInfo->checkPixels) + miSpriteFindColors (pCursorInfo, pScreen); + if (miDCPutUpCursor(pDev, pScreen, + pCursor, x, y, + pScreenPriv->colors[SOURCE_COLOR].pixel, + pScreenPriv->colors[MASK_COLOR].pixel)) + { + miSpriteIsUp(pCursorInfo); + pCursorInfo->pScreen = pScreen; + } + miSpriteEnableDamage(pScreen, pScreenPriv); + DamageDrawInternal (pScreen, FALSE); +} + +/* + * compute the desired area of the screen to save + */ + +static void +miSpriteComputeSaved (DeviceIntPtr pDev, ScreenPtr pScreen) +{ + int x, y, w, h; + int wpad, hpad; + CursorPtr pCursor; + miCursorInfoPtr pCursorInfo; + + if (!IsMaster(pDev) && !pDev->u.master) + return; + + pCursorInfo = MISPRITE(pDev); + + pCursor = pCursorInfo->pCursor; + x = pCursorInfo->x - (int)pCursor->bits->xhot; + y = pCursorInfo->y - (int)pCursor->bits->yhot; + w = pCursor->bits->width; + h = pCursor->bits->height; + wpad = SPRITE_PAD; + hpad = SPRITE_PAD; + pCursorInfo->saved.x1 = x - wpad; + pCursorInfo->saved.y1 = y - hpad; + pCursorInfo->saved.x2 = pCursorInfo->saved.x1 + w + wpad * 2; + pCursorInfo->saved.y2 = pCursorInfo->saved.y1 + h + hpad * 2; +} + diff --git a/mi/misprite.h b/mi/misprite.h new file mode 100644 index 0000000..632d207 --- /dev/null +++ b/mi/misprite.h @@ -0,0 +1,50 @@ +/* + * 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. +*/ + +extern Bool miSpriteInitialize( + ScreenPtr /*pScreen*/, + miPointerScreenFuncPtr /*screenFuncs*/ +); + +extern Bool miDCRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); +extern Bool miDCUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); +extern Bool miDCPutUpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor, int x, int y, + unsigned long source, unsigned long mask); +extern Bool miDCSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y, int w, int h); +extern Bool miDCRestoreUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y, int w, int h); +extern Bool miDCDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen); +extern void miDCDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen); diff --git a/mi/mistruct.h b/mi/mistruct.h new file mode 100644 index 0000000..e9cfed5 --- /dev/null +++ b/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/mi/mivalidate.h b/mi/mivalidate.h new file mode 100644 index 0000000..18700ac --- /dev/null +++ b/mi/mivalidate.h @@ -0,0 +1,51 @@ +/* + +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 */ + } before; + struct AfterValidate { + RegionRec exposed; /* exposed regions, absolute pos */ + RegionRec borderExposed; + } after; +} ValidateRec; + +#endif /* MIVALIDATE_H */ diff --git a/mi/mivaltree.c b/mi/mivaltree.c new file mode 100644 index 0000000..0e00c2f --- /dev/null +++ b/mi/mivaltree.c @@ -0,0 +1,813 @@ +/* + * 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" + +/* + * Compute the visibility of a shaped window + */ +int +miShapedWindowIn (RegionPtr universe, RegionPtr bounding, + BoxPtr rect, int x, int y) +{ + BoxRec box; + BoxPtr boundBox; + int nbox; + Bool someIn, someOut; + int t, x1, y1, x2, y2; + + nbox = RegionNumRects (bounding); + boundBox = RegionRects (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 (RegionContainsRect(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; +} + +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)) + RegionEmpty(universe); + (*miSetRedirectBorderClipProc) (pParent, universe); + } + RegionCopy(universe, &pParent->borderSize); + } +#endif + + oldVis = pParent->visibility; + switch (RegionContainsRect(universe, &borderSize)) + { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnPART: + newVis = VisibilityPartiallyObscured; + { + RegionPtr pBounding; + + if ((pBounding = wBoundingShape (pParent))) + { + switch (miShapedWindowIn (universe, pBounding, + &borderSize, + pParent->drawable.x, + pParent->drawable.y)) + { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnOUT: + newVis = VisibilityFullyObscured; + break; + } + } + } + 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) + { + RegionTranslate(&pChild->borderClip, + dx, dy); + RegionTranslate(&pChild->clipList, + dx, dy); + pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER; + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pChild, dx, dy); + + } + if (pChild->valdata) + { + RegionNull(&pChild->valdata->after.borderExposed); + if (HasParentRelativeBorder(pChild)) + { + RegionSubtract(&pChild->valdata->after.borderExposed, + &pChild->borderClip, + &pChild->winSize); + } + RegionNull(&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. + */ + RegionTranslate(&pParent->borderClip, dx, dy); + RegionTranslate(&pParent->clipList, dx, dy); + } + break; + case VTBroken: + RegionEmpty(&pParent->borderClip); + RegionEmpty(&pParent->clipList); + break; + } + + borderVisible = pParent->valdata->before.borderVisible; + resized = pParent->valdata->before.resized; + RegionNull(&pParent->valdata->after.borderExposed); + RegionNull(&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 + */ + RegionSubtract(exposed, universe, borderVisible); + RegionDestroy(borderVisible); + } + else + { + RegionSubtract(exposed, universe, &pParent->borderClip); + } + if (HasParentRelativeBorder(pParent) && (dx || dy)) + RegionSubtract(&pParent->valdata->after.borderExposed, + universe, + &pParent->winSize); + else + RegionSubtract(&pParent->valdata->after.borderExposed, + exposed, &pParent->winSize); + + RegionCopy(&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. + */ + + RegionIntersect(universe, universe, &pParent->winSize); + } + else + RegionCopy(&pParent->borderClip, universe); + + if ((pChild = pParent->firstChild) && pParent->mapped) + { + RegionNull(&childUniverse); + RegionNull(&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)) + RegionAppend(&childUnion, &pChild->borderSize); + } + } + else + { + for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib) + { + if (pChild->viewable && !TreatAsTransparent(pChild)) + RegionAppend(&childUnion, &pChild->borderSize); + } + } + RegionValidate(&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. + */ + RegionIntersect(&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)) + RegionSubtract(universe, universe, + &pChild->borderSize); + } + } + if (!overlap) + RegionSubtract(universe, universe, &childUnion); + RegionUninit(&childUnion); + RegionUninit(&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) + { + RegionCopy(&pParent->valdata->after.exposed, universe); + } + else if (newVis != VisibilityFullyObscured && + newVis != VisibilityNotViewable) + { + RegionSubtract(&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 + RegionCopy(&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 ( + 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; + + RegionNull(&childClip); + RegionNull(&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. + */ + RegionNull(&totalClip); + viewvals = 0; + if (RegionBroken(&pParent->clipList) && + !RegionBroken(&pParent->borderClip)) + { + kind = VTBroken; + /* + * When rebuilding clip lists after out of memory, + * assume everything is busted. + */ + forward = TRUE; + RegionCopy(&totalClip, &pParent->borderClip); + RegionIntersect(&totalClip, &totalClip, &pParent->winSize); + + for (pWin = pParent->firstChild; pWin != pChild; pWin = pWin->nextSib) + { + if (pWin->viewable && !TreatAsTransparent (pWin)) + RegionSubtract(&totalClip, &totalClip, &pWin->borderSize); + } + for (pWin = pChild; pWin; pWin = pWin->nextSib) + if (pWin->valdata && pWin->viewable) + viewvals++; + + RegionEmpty(&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 + RegionAppend(&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 + RegionAppend(&totalClip, pBorderClip ); + if (pWin->viewable) + viewvals++; + } + if (pWin == pChild) + break; + pWin = pWin->prevSib; + } + } + RegionValidate(&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) + { + RegionUnion(&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. + */ + RegionNull(&childUnion); + if (forward) + { + for (pWin = pChild; pWin; pWin = pWin->nextSib) + if (pWin->valdata && pWin->viewable && !TreatAsTransparent (pWin)) + RegionAppend(&childUnion, + &pWin->borderSize); + } + else + { + pWin = pParent->lastChild; + while (1) + { + if (pWin->valdata && pWin->viewable && !TreatAsTransparent (pWin)) + RegionAppend(&childUnion, + &pWin->borderSize); + if (pWin == pChild) + break; + pWin = pWin->prevSib; + } + } + RegionValidate(&childUnion, &overlap); + if (overlap) + RegionUninit(&childUnion); + } + } + + for (pWin = pChild; + pWin != NullWindow; + pWin = pWin->nextSib) + { + if (pWin->viewable) { + if (pWin->valdata) { + RegionIntersect(&childClip, + &totalClip, + &pWin->borderSize); + miComputeClips (pWin, pScreen, &childClip, kind, &exposed); + if (overlap && !TreatAsTransparent (pWin)) + { + RegionSubtract(&totalClip, + &totalClip, + &pWin->borderSize); + } + } else if (pWin->visibility == VisibilityNotViewable) { + miTreeObscured(pWin); + } + } else { + if (pWin->valdata) { + RegionEmpty(&pWin->clipList); + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pWin, 0, 0); + RegionEmpty(&pWin->borderClip); + pWin->valdata = NULL; + } + } + } + + RegionUninit(&childClip); + if (!overlap) + { + RegionSubtract(&totalClip, &totalClip, &childUnion); + RegionUninit(&childUnion); + } + + RegionNull(&pParent->valdata->after.exposed); + RegionNull(&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. + */ + RegionSubtract(&pParent->valdata->after.exposed, + &totalClip, &pParent->clipList); + /* fall through */ + case VTMap: + RegionCopy(&pParent->clipList, &totalClip); + pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; + break; + } + + RegionUninit(&totalClip); + RegionUninit(&exposed); + if (pScreen->ClipNotify) + (*pScreen->ClipNotify) (pParent, 0, 0); + return 1; +} diff --git a/mi/miwideline.c b/mi/miwideline.c new file mode 100644 index 0000000..bc5ee74 --- /dev/null +++ b/mi/miwideline.c @@ -0,0 +1,2193 @@ +/* + +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 Bool +InitSpans(Spans *spans, size_t nspans) +{ + spans->points = malloc(nspans * sizeof (*spans->points)); + if (!spans->points) + return FALSE; + spans->widths = malloc(nspans * sizeof (*spans->widths)); + if (!spans->widths) + { + free(spans->points); + return FALSE; + } + return TRUE; +} + +/* + * interface data to span-merging polygon filler + */ + +typedef struct _SpanData { + SpanGroup fgGroup, bgGroup; +} SpanDataRec, *SpanDataPtr; + +static void +AppendSpanGroup(GCPtr pGC, unsigned long pixel, Spans *spanPtr, SpanDataPtr 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); +} + + +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 +fillSpans(DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel, Spans *spans, SpanDataPtr spanData) +{ + if (!spanData) + { + ChangeGCVal oldPixel, tmpPixel; + oldPixel.val = pGC->fgPixel; + if (pixel != oldPixel.val) + { + tmpPixel.val = (XID)pixel; + ChangeGC (NullClient, pGC, GCForeground, &tmpPixel); + ValidateGC (pDrawable, pGC); + } + (*pGC->ops->FillSpans) (pDrawable, pGC, spans->count, spans->points, spans->widths, TRUE); + free(spans->widths); + free(spans->points); + if (pixel != oldPixel.val) + { + ChangeGC (NullClient, pGC, GCForeground, &oldPixel); + ValidateGC (pDrawable, pGC); + } + } + else + AppendSpanGroup (pGC, pixel, spans, spanData); +} + +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; + int *pwidth; + int xorg; + Spans spanRec; + + if (!InitSpans(&spanRec, overall_height)) + 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)) + { + 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; + } + + 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; + } + + 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++; + + left_x += left_stepx; + left_e += left_dx; + if (left_e > 0) + { + left_x += left_signdx; + left_e -= left_dy; + } + + right_x += right_stepx; + right_e += right_dx; + if (right_e > 0) + { + right_x += right_signdx; + right_e -= right_dy; + } + } + } + spanRec.count = ppt - spanRec.points; + fillSpans (pDrawable, 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; + ChangeGCVal oldPixel, tmpPixel; + Spans spanRec; + xRectangle rect; + + if (!spanData) + { + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + oldPixel.val = pGC->fgPixel; + if (pixel != oldPixel.val) + { + tmpPixel.val = (XID)pixel; + ChangeGC (NullClient, pGC, GCForeground, &tmpPixel); + ValidateGC (pDrawable, pGC); + } + (*pGC->ops->PolyFillRect) (pDrawable, pGC, 1, &rect); + if (pixel != oldPixel.val) + { + ChangeGC (NullClient, pGC, GCForeground, &oldPixel); + ValidateGC (pDrawable, pGC); + } + } + else + { + if (!InitSpans(&spanRec, h)) + 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); + } +} + +/* static */ int +miPolyBuildEdge ( + double x0, + double y0, + double k, /* x0 * dy - y0 * dx */ + int dx, + int dy, + int xi, + int 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))) + +/* static */ int +miPolyBuildPoly ( + PolyVertexPtr vertices, + PolySlopePtr slopes, + int count, + int xi, + int yi, + PolyEdgePtr left, + PolyEdgePtr right, + int *pnleft, + int *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 ((int64_t)slopes[j].dy * slopes[i].dx > (int64_t)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; +} + +void +miRoundJoinClip (LineFacePtr pLeft, LineFacePtr pRight, + PolyEdgePtr edge1, PolyEdgePtr edge2, + int *y1, int *y2, Bool *left1, Bool *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); +} + +int +miRoundCapClip (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) +{ + int xorgi = 0, yorgi = 0; + 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 (!InitSpans(&spanRec, pGC->lineWidth)) + return; + if (isInt) + n = miLineArcI(pDraw, pGC, xorgi, yorgi, spanRec.points, spanRec.widths); + else + n = miLineArcD(pDraw, pGC, xorg, yorg, spanRec.points, spanRec.widths, + &edge1, edgey1, edgeleft1, + &edge2, edgey2, edgeleft2); + spanRec.count = n; + fillSpans (pDraw, 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) + { + ChangeGCVal oldPixel, pixel; + pixel.val = pGC->bgPixel; + oldPixel.val = pGC->fgPixel; + if (pixel.val != oldPixel.val) + { + ChangeGC (NullClient, pGC, GCForeground, &pixel); + ValidateGC (pDrawable, pGC); + } + miFillUniqueSpanGroup (pDrawable, pGC, &spanData->bgGroup); + miFreeSpanGroup (&spanData->bgGroup); + if (pixel.val != oldPixel.val) + { + ChangeGC (NullClient, pGC, GCForeground, &oldPixel); + ValidateGC (pDrawable, pGC); + } + } + miFillUniqueSpanGroup (pDrawable, pGC, &spanData->fgGroup); + miFreeSpanGroup (&spanData->fgGroup); +} + +void +miWideLine (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; +} + +void +miWideDash (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/mi/miwideline.h b/mi/miwideline.h new file mode 100644 index 0000000..e08aa68 --- /dev/null +++ b/mi/miwideline.h @@ -0,0 +1,120 @@ +/* + +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 */ + +/* + * 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 MILINESETPIXEL(pDrawable, pGC, pixel, oldPixel) { \ + oldPixel = pGC->fgPixel; \ + if (pixel != oldPixel) { \ + ChangeGCVal gcval; \ + gcval.val = pixel; \ + ChangeGC (NullClient, pGC, GCForeground, &gcval); \ + ValidateGC (pDrawable, pGC); \ + } \ +} +#define MILINERESETPIXEL(pDrawable, pGC, pixel, oldPixel) { \ + if (pixel != oldPixel) { \ + ChangeGCVal gcval; \ + gcval.val = oldPixel; \ + ChangeGC (NullClient, pGC, GCForeground, &gcval); \ + ValidateGC (pDrawable, pGC); \ + } \ +} + +extern _X_EXPORT void miRoundJoinClip( + LineFacePtr /*pLeft*/, + LineFacePtr /*pRight*/, + PolyEdgePtr /*edge1*/, + PolyEdgePtr /*edge2*/, + int * /*y1*/, + int * /*y2*/, + Bool * /*left1*/, + Bool * /*left2*/ +); + +extern _X_EXPORT int miRoundCapClip( + LineFacePtr /*face*/, + Bool /*isInt*/, + PolyEdgePtr /*edge*/, + Bool * /*leftEdge*/ +); + +extern _X_EXPORT int miPolyBuildEdge(double x0, double y0, double k, int dx, int dy, + int xi, int yi, int left, PolyEdgePtr edge); +extern _X_EXPORT 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/mi/miwindow.c b/mi/miwindow.c new file mode 100644 index 0000000..dc5d21a --- /dev/null +++ b/mi/miwindow.c @@ -0,0 +1,824 @@ + +/*********************************************************** + +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/extensions/shapeconst.h> +#include "regionstr.h" +#include "region.h" +#include "mi.h" +#include "windowstr.h" +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "mivalidate.h" + +void +miClearToBackground(WindowPtr pWin, + int x, int y, int w, int h, + Bool generateExposures) +{ + BoxRec box; + RegionRec reg; + 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; + + RegionInit(®, &box, 1); + + RegionIntersect(®, ®, &pWin->clipList); + if (generateExposures) + (*pWin->drawable.pScreen->WindowExposures)(pWin, ®, NULL); + else if (pWin->backgroundState != None) + miPaintWindow(pWin, ®, PW_BACKGROUND); + RegionUninit(®); +} + +void +miMarkWindow(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(WindowPtr pWin, WindowPtr pFirst, WindowPtr *ppLayerWin) +{ + BoxPtr box; + WindowPtr pChild, pLast; + Bool anyMarked = FALSE; + MarkWindowProcPtr MarkWindow = pWin->drawable.pScreen->MarkWindow; + + /* 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 (RegionBroken(&pChild->winSize)) + SetWinSize (pChild); + if (RegionBroken(&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 = RegionExtents(&pWin->borderSize); + pLast = pChild->parent->lastChild; + while (1) + { + if (pChild->viewable) + { + if (RegionBroken(&pChild->winSize)) + SetWinSize (pChild); + if (RegionBroken(&pChild->borderSize)) + SetBorderSize (pChild); + if (RegionContainsRect(&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 + *****/ +void +miHandleValidateExposures(WindowPtr pWin) +{ + WindowPtr pChild; + ValidatePtr val; + WindowExposuresProcPtr WindowExposures; + + pChild = pWin; + WindowExposures = pChild->drawable.pScreen->WindowExposures; + while (1) + { + if ( (val = pChild->valdata) ) + { + if (RegionNotEmpty(&val->after.borderExposed)) + miPaintWindow(pChild, &val->after.borderExposed, PW_BORDER); + RegionUninit(&val->after.borderExposed); + (*WindowExposures)(pChild, &val->after.exposed, NullRegion); + RegionUninit(&val->after.exposed); + free(val); + pChild->valdata = 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(WindowPtr pWin, int x, int 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; + 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 = RegionCreate(NullBox, 1); + RegionCopy(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, NULL); + else + anyMarked |= (*pScreen->MarkOverlappedWindows) + (pWin, pLayerWin, NULL); + + + if (anyMarked) + { + (*pScreen->ValidateTree)(pLayerWin->parent, NullWindow, kind); + (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, oldRegion); + RegionDestroy(oldRegion); + /* XXX need to retile border if ParentRelative origin */ + (*pScreen->HandleExposures)(pLayerWin->parent); + } + 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 */ +{ + RegionPtr pValid = (RegionPtr)value; + + if (pWin->valdata) + { +#ifdef COMPOSITE + /* + * Redirected windows are not affected by parent window + * gravity manipulations, so don't recompute their + * exposed areas here. + */ + if (pWin->redirectDraw != RedirectDrawNone) + return WT_DONTWALKCHILDREN; +#endif + /* + * compute exposed regions of this window + */ + RegionSubtract(&pWin->valdata->after.exposed, + &pWin->clipList, pValid); + /* + * compute exposed regions of the border + */ + RegionSubtract(&pWin->valdata->after.borderExposed, + &pWin->borderClip, &pWin->winSize); + RegionSubtract(&pWin->valdata->after.borderExposed, + &pWin->valdata->after.borderExposed, pValid); + return WT_WALKCHILDREN; + } + return WT_NOMATCH; +} + +void +miSlideAndSizeWindow(WindowPtr pWin, + int x, int y, + unsigned int w, unsigned int 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 */ + 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 = RegionCreate(NullBox, 1); + RegionCopy(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] = RegionCreate(NullBox, 1); + RegionUnion(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 = RegionCreate(NullBox, 1); + RegionCopy(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 = RegionCreate(NullBox, 1); + /* for tiled borders, we punt and draw the whole thing */ + if (pWin->borderIsPixel || !moved) + { + if (shrunk || moved) + RegionSubtract(borderVisible, + &pWin->borderClip, + &pWin->winSize); + else + RegionCopy(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 = RegionCreate(NullBox, 1); + + if (pLayerWin == pWin) + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, + NULL); + else + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pLayerWin, + NULL); + + if (pWin->valdata) + { + pWin->valdata->before.resized = TRUE; + pWin->valdata->before.borderVisible = borderVisible; + } + + + if (anyMarked) + (*pScreen->ValidateTree)(pLayerWin->parent, pFirstChange, VTOther); + /* + * the entire window is trashed unless bitGravity + * recovers portions of it + */ + RegionCopy(&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) + { + RegionTranslate(&pWin->winSize, dx, dy); + offx += dx; + offy += dy; + } + RegionIntersect(gravitate[g], gravitate[g], + &pWin->winSize); + } + /* get winSize back where it belongs */ + if (offx || offy) + RegionTranslate(&pWin->winSize, -offx, -offy); + } + /* + * add screen bits to the appropriate bucket + */ + + if (oldWinClip) + { + /* + * clip to new clipList + */ + RegionCopy(pRegion, oldWinClip); + RegionTranslate(pRegion, nx - oldx, ny - oldy); + RegionIntersect(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]) + RegionSubtract(oldWinClip, oldWinClip, + gravitate[g]); + } + RegionTranslate(oldWinClip, oldx - nx, oldy - ny); + g = pWin->bitGravity; + if (!gravitate[g]) + gravitate[g] = oldWinClip; + else + { + RegionUnion(gravitate[g], gravitate[g], oldWinClip); + RegionDestroy(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 */ + + RegionIntersect(gravitate[g], gravitate[g], oldRegion); + + /* clip to not overwrite already copied areas */ + + if (destClip) { + RegionTranslate(destClip, oldpt.x - x, oldpt.y - y); + RegionSubtract(gravitate[g], gravitate[g], destClip); + RegionTranslate(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 */ + + RegionSubtract(oldRegion, oldRegion, gravitate[g]); + + /* + * recompute exposed regions of child windows + */ + + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + if (pChild->winGravity != g) + continue; + RegionIntersect(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) + RegionSubtract(&pWin->valdata->after.exposed, + &pWin->valdata->after.exposed, gravitate[g]); + if (!destClip) + destClip = gravitate[g]; + else + { + RegionUnion(destClip, destClip, gravitate[g]); + RegionDestroy(gravitate[g]); + } + } + + RegionDestroy(oldRegion); + RegionDestroy(pRegion); + if (destClip) + RegionDestroy(destClip); + if (anyMarked) + (*pScreen->HandleExposures)(pLayerWin->parent); + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstChange, + VTOther); + } + if (pWin->realized) + WindowsRestructured (); +} + +WindowPtr +miGetLayerWindow(WindowPtr pWin) +{ + return pWin->firstChild; +} + +/****** + * + * miSetShape + * The border/window shape has changed. Recompute winSize/borderSize + * and send appropriate exposure events + */ + +void +miSetShape(WindowPtr pWin, int kind) +{ + Bool WasViewable = (Bool)(pWin->viewable); + ScreenPtr pScreen = pWin->drawable.pScreen; + Bool anyMarked = FALSE; + WindowPtr pLayerWin; + + if (kind != ShapeInput) { + if (WasViewable) + { + anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, + &pLayerWin); + if (pWin->valdata) + { + if (HasBorder (pWin)) + { + RegionPtr borderVisible; + + borderVisible = RegionCreate(NullBox, 1); + RegionSubtract(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, + NULL); + + if (anyMarked) + (*pScreen->ValidateTree)(pLayerWin->parent, NullWindow, + VTOther); + } + + if (WasViewable) + { + if (anyMarked) + (*pScreen->HandleExposures)(pLayerWin->parent); + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, NullWindow, + VTOther); + } + } + if (pWin->realized) + WindowsRestructured (); + CheckCursorConfinement(pWin); +} + +/* Keeps the same inside(!) origin */ + +void +miChangeBorderWidth(WindowPtr pWin, unsigned int width) +{ + int oldwidth; + Bool anyMarked = FALSE; + ScreenPtr pScreen; + Bool WasViewable = (Bool)(pWin->viewable); + Bool HadBorder; + 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 = RegionCreate(NULL, 1); + RegionSubtract(borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + } + } + + if (anyMarked) + { + (*pScreen->ValidateTree)(pLayerWin->parent, pLayerWin, VTOther); + (*pScreen->HandleExposures)(pLayerWin->parent); + } + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pLayerWin, + VTOther); + } + if (pWin->realized) + WindowsRestructured (); +} + +void +miMarkUnrealizedWindow(WindowPtr pChild, WindowPtr pWin, Bool fromConfigure) +{ + if ((pChild != pWin) || fromConfigure) + { + RegionEmpty(&pChild->clipList); + if (pChild->drawable.pScreen->ClipNotify) + (* pChild->drawable.pScreen->ClipNotify)(pChild, 0, 0); + RegionEmpty(&pChild->borderClip); + } +} + +void +miSegregateChildren(WindowPtr pWin, RegionPtr pReg, int depth) +{ + WindowPtr pChild; + + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + if (pChild->drawable.depth == depth) + RegionUnion(pReg, pReg, &pChild->borderClip); + + if (pChild->firstChild) + miSegregateChildren(pChild, pReg, depth); + } +} diff --git a/mi/mizerarc.c b/mi/mizerarc.c new file mode 100644 index 0000000..5adf3dd --- /dev/null +++ b/mi/mizerarc.c @@ -0,0 +1,848 @@ +/************************************************************ + +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) + * + */ + +Bool +miZeroArcSetup(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; +} + +void +miZeroPolyArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs) +{ + int maxPts = 0; + int n, maxw = 0; + xArc *arc; + int i; + DDXPointPtr points, pts, oddPts = NULL; + 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 = malloc(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 = malloc(sizeof(DDXPointRec) * numPts); + if (!points) + { + if (dospans) + { + free(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)) + { + ChangeGCVal gcval; + gcval.val = pGC->bgPixel; + ChangeGC(NullClient, pGC, GCForeground, &gcval); + 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)) + { + ChangeGCVal gcval; + gcval.val = fgPixel; + ChangeGC(NullClient, pGC, GCForeground, &gcval); + ValidateGC(pDraw, pGC); + } + } + } + free(points); + if (dospans) + { + free(widths); + } +} diff --git a/mi/mizerarc.h b/mi/mizerarc.h new file mode 100644 index 0000000..1612a52 --- /dev/null +++ b/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 _X_EXPORT Bool miZeroArcSetup( + xArc * /*arc*/, + miZeroArcRec * /*info*/, + Bool /*ok360*/ +); diff --git a/mi/mizerclip.c b/mi/mizerclip.c new file mode 100644 index 0000000..fb1e25f --- /dev/null +++ b/mi/mizerclip.c @@ -0,0 +1,630 @@ +/*********************************************************** + +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 + * + */ +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) +{ + 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/mi/mizerline.c b/mi/mizerline.c new file mode 100644 index 0000000..7077b51 --- /dev/null +++ b/mi/mizerline.c @@ -0,0 +1,381 @@ +/*********************************************************** + +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;\ + }\ +} + +void +miZeroLine( + 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 = malloc(list_len * sizeof(DDXPointRec)); + pwidthInit = malloc(list_len * sizeof(int)); + if (!pspanInit || !pwidthInit) { + free(pspanInit); + free(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); + + free(pwidthInit); + free(pspanInit); +} + +void +miZeroDashLine( + 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; +} |