diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2006-11-26 18:19:47 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2006-11-26 18:19:47 +0000 |
commit | 04f51aaa1f5b0cac419d2891812446c790b9c581 (patch) | |
tree | 7d104a653aff8d7488bc039ba435118115c18807 /xserver/mi | |
parent | 4a168ba45f33263ee86fc398ff32f108cffb1330 (diff) |
Importing xserver from X.Org 7.2RC2
Diffstat (limited to 'xserver/mi')
62 files changed, 35510 insertions, 0 deletions
diff --git a/xserver/mi/Makefile.am b/xserver/mi/Makefile.am new file mode 100644 index 000000000..42f75ae73 --- /dev/null +++ b/xserver/mi/Makefile.am @@ -0,0 +1,75 @@ +noinst_LTLIBRARIES = libminimi.la libmi.la + +if XORG +sdk_HEADERS = mibank.h micmap.h miline.h mipointer.h mi.h mibstore.h \ + migc.h mipointrst.h mizerarc.h micoord.h mifillarc.h \ + mispans.h miwideline.h mistruct.h mifpoly.h +endif + +AM_CFLAGS = $(DIX_CFLAGS) + +# libminimi is for dmx - it has different defines for miinitext.c +libminimi_la_SOURCES = \ + cbrt.c \ + mi.h \ + miarc.c \ + mibank.c \ + mibank.h \ + mibitblt.c \ + mibstore.c \ + mibstore.h \ + mibstorest.h \ + micmap.c \ + micmap.h \ + micoord.h \ + micursor.c \ + midash.c \ + midispcur.c \ + mieq.c \ + miexpose.c \ + mifillarc.c \ + mifillarc.h \ + mifillrct.c \ + mifpolycon.c \ + mifpoly.h \ + migc.c \ + migc.h \ + miglblt.c \ + miline.h \ + mioverlay.c \ + mioverlay.h \ + mipointer.c \ + mipointer.h \ + mipointrst.h \ + mipoly.c \ + mipoly.h \ + mipolycon.c \ + mipolygen.c \ + mipolypnt.c \ + mipolyrect.c \ + mipolyseg.c \ + mipolytext.c \ + mipolyutil.c \ + mipushpxl.c \ + miregion.c \ + miscanfill.h \ + miscrinit.c \ + mispans.c \ + mispans.h \ + misprite.c \ + misprite.h \ + mispritest.h \ + mistruct.h \ + mivaltree.c \ + mivalidate.h \ + miwideline.c \ + miwideline.h \ + miwindow.c \ + mizerarc.c \ + mizerarc.h \ + mizerclip.c \ + mizerline.c + +libmi_la_SOURCES = $(libminimi_la_SOURCES) + +INCLUDES = -I$(top_srcdir)/mfb diff --git a/xserver/mi/Makefile.in b/xserver/mi/Makefile.in new file mode 100644 index 000000000..1779a625e --- /dev/null +++ b/xserver/mi/Makefile.in @@ -0,0 +1,943 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = mi +DIST_COMMON = $(am__sdk_HEADERS_DIST) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/do-not-use-config.h \ + $(top_builddir)/include/xorg-server.h \ + $(top_builddir)/include/dix-config.h \ + $(top_builddir)/include/xgl-config.h \ + $(top_builddir)/include/xorg-config.h \ + $(top_builddir)/include/xkb-config.h \ + $(top_builddir)/include/xwin-config.h \ + $(top_builddir)/include/kdrive-config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libmi_la_LIBADD = +am__objects_1 = cbrt.lo miarc.lo mibank.lo mibitblt.lo mibstore.lo \ + micmap.lo micursor.lo midash.lo midispcur.lo mieq.lo \ + miexpose.lo mifillarc.lo mifillrct.lo mifpolycon.lo migc.lo \ + miglblt.lo mioverlay.lo mipointer.lo mipoly.lo mipolycon.lo \ + mipolygen.lo mipolypnt.lo mipolyrect.lo mipolyseg.lo \ + mipolytext.lo mipolyutil.lo mipushpxl.lo miregion.lo \ + miscrinit.lo mispans.lo misprite.lo mivaltree.lo miwideline.lo \ + miwindow.lo mizerarc.lo mizerclip.lo mizerline.lo +am_libmi_la_OBJECTS = $(am__objects_1) +libmi_la_OBJECTS = $(am_libmi_la_OBJECTS) +libminimi_la_LIBADD = +am_libminimi_la_OBJECTS = cbrt.lo miarc.lo mibank.lo mibitblt.lo \ + mibstore.lo micmap.lo micursor.lo midash.lo midispcur.lo \ + mieq.lo miexpose.lo mifillarc.lo mifillrct.lo mifpolycon.lo \ + migc.lo miglblt.lo mioverlay.lo mipointer.lo mipoly.lo \ + mipolycon.lo mipolygen.lo mipolypnt.lo mipolyrect.lo \ + mipolyseg.lo mipolytext.lo mipolyutil.lo mipushpxl.lo \ + miregion.lo miscrinit.lo mispans.lo misprite.lo mivaltree.lo \ + miwideline.lo miwindow.lo mizerarc.lo mizerclip.lo \ + mizerline.lo +libminimi_la_OBJECTS = $(am_libminimi_la_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libmi_la_SOURCES) $(libminimi_la_SOURCES) +DIST_SOURCES = $(libmi_la_SOURCES) $(libminimi_la_SOURCES) +am__sdk_HEADERS_DIST = mibank.h micmap.h miline.h mipointer.h mi.h \ + mibstore.h migc.h mipointrst.h mizerarc.h micoord.h \ + mifillarc.h mispans.h miwideline.h mistruct.h mifpoly.h +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(sdkdir)" +sdkHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(sdk_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ADMIN_MAN_DIR = @ADMIN_MAN_DIR@ +ADMIN_MAN_SUFFIX = @ADMIN_MAN_SUFFIX@ +AFB_FALSE = @AFB_FALSE@ +AFB_TRUE = @AFB_TRUE@ +AGP_FALSE = @AGP_FALSE@ +AGP_TRUE = @AGP_TRUE@ +AIGLX_FALSE = @AIGLX_FALSE@ +AIGLX_TRUE = @AIGLX_TRUE@ +ALLOCA = @ALLOCA@ +ALPHA_VIDEO_FALSE = @ALPHA_VIDEO_FALSE@ +ALPHA_VIDEO_TRUE = @ALPHA_VIDEO_TRUE@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +APPDEFAULTDIR = @APPDEFAULTDIR@ +APPGROUP_FALSE = @APPGROUP_FALSE@ +APPGROUP_TRUE = @APPGROUP_TRUE@ +APP_MAN_DIR = @APP_MAN_DIR@ +APP_MAN_SUFFIX = @APP_MAN_SUFFIX@ +AR = @AR@ +ARM_VIDEO_FALSE = @ARM_VIDEO_FALSE@ +ARM_VIDEO_TRUE = @ARM_VIDEO_TRUE@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASE_FONT_PATH = @BASE_FONT_PATH@ +BSD_KBD_MODE_FALSE = @BSD_KBD_MODE_FALSE@ +BSD_KBD_MODE_TRUE = @BSD_KBD_MODE_TRUE@ +BUILDDOCS_FALSE = @BUILDDOCS_FALSE@ +BUILDDOCS_TRUE = @BUILDDOCS_TRUE@ +BUILD_DATE = @BUILD_DATE@ +BUILD_KBD_MODE_FALSE = @BUILD_KBD_MODE_FALSE@ +BUILD_KBD_MODE_TRUE = @BUILD_KBD_MODE_TRUE@ +BUILD_LINUXDOC_FALSE = @BUILD_LINUXDOC_FALSE@ +BUILD_LINUXDOC_TRUE = @BUILD_LINUXDOC_TRUE@ +BUILD_PDFDOC_FALSE = @BUILD_PDFDOC_FALSE@ +BUILD_PDFDOC_TRUE = @BUILD_PDFDOC_TRUE@ +BUILD_XORGCFG_FALSE = @BUILD_XORGCFG_FALSE@ +BUILD_XORGCFG_TRUE = @BUILD_XORGCFG_TRUE@ +CC = @CC@ +CCAS = @CCAS@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFB_FALSE = @CFB_FALSE@ +CFB_TRUE = @CFB_TRUE@ +CFLAGS = @CFLAGS@ +COMPILEDDEFAULTFONTPATH = @COMPILEDDEFAULTFONTPATH@ +COMPOSITE_FALSE = @COMPOSITE_FALSE@ +COMPOSITE_TRUE = @COMPOSITE_TRUE@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CUP_FALSE = @CUP_FALSE@ +CUP_TRUE = @CUP_TRUE@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DBE_FALSE = @DBE_FALSE@ +DBE_TRUE = @DBE_TRUE@ +DEBUG_FALSE = @DEBUG_FALSE@ +DEBUG_TRUE = @DEBUG_TRUE@ +DEFAULT_LOGPREFIX = @DEFAULT_LOGPREFIX@ +DEFAULT_MODULE_PATH = @DEFAULT_MODULE_PATH@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DGA_FALSE = @DGA_FALSE@ +DGA_TRUE = @DGA_TRUE@ +DIX_CFLAGS = @DIX_CFLAGS@ +DLLTOOL = @DLLTOOL@ +DMXEXAMPLES_DEP_CFLAGS = @DMXEXAMPLES_DEP_CFLAGS@ +DMXEXAMPLES_DEP_LIBS = @DMXEXAMPLES_DEP_LIBS@ +DMXMODULES_CFLAGS = @DMXMODULES_CFLAGS@ +DMXMODULES_LIBS = @DMXMODULES_LIBS@ +DMXXIEXAMPLES_DEP_CFLAGS = @DMXXIEXAMPLES_DEP_CFLAGS@ +DMXXIEXAMPLES_DEP_LIBS = @DMXXIEXAMPLES_DEP_LIBS@ +DMXXMUEXAMPLES_DEP_CFLAGS = @DMXXMUEXAMPLES_DEP_CFLAGS@ +DMXXMUEXAMPLES_DEP_LIBS = @DMXXMUEXAMPLES_DEP_LIBS@ +DMX_BUILD_LNX_FALSE = @DMX_BUILD_LNX_FALSE@ +DMX_BUILD_LNX_TRUE = @DMX_BUILD_LNX_TRUE@ +DMX_BUILD_USB_FALSE = @DMX_BUILD_USB_FALSE@ +DMX_BUILD_USB_TRUE = @DMX_BUILD_USB_TRUE@ +DMX_FALSE = @DMX_FALSE@ +DMX_TRUE = @DMX_TRUE@ +DPMSExtension_FALSE = @DPMSExtension_FALSE@ +DPMSExtension_TRUE = @DPMSExtension_TRUE@ +DRIPROTO_CFLAGS = @DRIPROTO_CFLAGS@ +DRIPROTO_LIBS = @DRIPROTO_LIBS@ +DRIVER_MAN_DIR = @DRIVER_MAN_DIR@ +DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@ +DRI_DRIVER_PATH = @DRI_DRIVER_PATH@ +DRI_FALSE = @DRI_FALSE@ +DRI_TRUE = @DRI_TRUE@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EVI_FALSE = @EVI_FALSE@ +EVI_TRUE = @EVI_TRUE@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FBDEVHW_FALSE = @FBDEVHW_FALSE@ +FBDEVHW_TRUE = @FBDEVHW_TRUE@ +FFLAGS = @FFLAGS@ +FILE_MAN_DIR = @FILE_MAN_DIR@ +FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ +FONTCACHE_FALSE = @FONTCACHE_FALSE@ +FONTCACHE_TRUE = @FONTCACHE_TRUE@ +FREEBSD_KLDLOAD_FALSE = @FREEBSD_KLDLOAD_FALSE@ +FREEBSD_KLDLOAD_TRUE = @FREEBSD_KLDLOAD_TRUE@ +FREETYPE_CFLAGS = @FREETYPE_CFLAGS@ +FREETYPE_LIBS = @FREETYPE_LIBS@ +FREETYPE_REQUIRES = @FREETYPE_REQUIRES@ +GLX_DEFINES = @GLX_DEFINES@ +GLX_FALSE = @GLX_FALSE@ +GLX_TRUE = @GLX_TRUE@ +GL_CFLAGS = @GL_CFLAGS@ +GL_LIBS = @GL_LIBS@ +H3600_TS_FALSE = @H3600_TS_FALSE@ +H3600_TS_TRUE = @H3600_TS_TRUE@ +I386_VIDEO_FALSE = @I386_VIDEO_FALSE@ +I386_VIDEO_TRUE = @I386_VIDEO_TRUE@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_LIBXF86CONFIG_FALSE = @INSTALL_LIBXF86CONFIG_FALSE@ +INSTALL_LIBXF86CONFIG_TRUE = @INSTALL_LIBXF86CONFIG_TRUE@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_SETUID_FALSE = @INSTALL_SETUID_FALSE@ +INSTALL_SETUID_TRUE = @INSTALL_SETUID_TRUE@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INT10_STUB_FALSE = @INT10_STUB_FALSE@ +INT10_STUB_TRUE = @INT10_STUB_TRUE@ +INT10_VM86_FALSE = @INT10_VM86_FALSE@ +INT10_VM86_TRUE = @INT10_VM86_TRUE@ +INT10_X86EMU_FALSE = @INT10_X86EMU_FALSE@ +INT10_X86EMU_TRUE = @INT10_X86EMU_TRUE@ +KDRIVEFBDEV_FALSE = @KDRIVEFBDEV_FALSE@ +KDRIVEFBDEV_TRUE = @KDRIVEFBDEV_TRUE@ +KDRIVEVESA_FALSE = @KDRIVEVESA_FALSE@ +KDRIVEVESA_TRUE = @KDRIVEVESA_TRUE@ +KDRIVE_CFLAGS = @KDRIVE_CFLAGS@ +KDRIVE_FALSE = @KDRIVE_FALSE@ +KDRIVE_HW_FALSE = @KDRIVE_HW_FALSE@ +KDRIVE_HW_TRUE = @KDRIVE_HW_TRUE@ +KDRIVE_INCS = @KDRIVE_INCS@ +KDRIVE_LIBS = @KDRIVE_LIBS@ +KDRIVE_PURE_INCS = @KDRIVE_PURE_INCS@ +KDRIVE_PURE_LIBS = @KDRIVE_PURE_LIBS@ +KDRIVE_TRUE = @KDRIVE_TRUE@ +LDFLAGS = @LDFLAGS@ +LD_EXPORT_SYMBOLS_FLAG = @LD_EXPORT_SYMBOLS_FLAG@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBDRM_CFLAGS = @LIBDRM_CFLAGS@ +LIBDRM_LIBS = @LIBDRM_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MAN_DIR = @LIB_MAN_DIR@ +LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@ +LINUXDOC = @LINUXDOC@ +LINUX_ALPHA_FALSE = @LINUX_ALPHA_FALSE@ +LINUX_ALPHA_TRUE = @LINUX_ALPHA_TRUE@ +LINUX_IA64_FALSE = @LINUX_IA64_FALSE@ +LINUX_IA64_TRUE = @LINUX_IA64_TRUE@ +LNXACPI_FALSE = @LNXACPI_FALSE@ +LNXACPI_TRUE = @LNXACPI_TRUE@ +LNXAPM_FALSE = @LNXAPM_FALSE@ +LNXAPM_TRUE = @LNXAPM_TRUE@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +MAKE_HTML = @MAKE_HTML@ +MAKE_PDF = @MAKE_PDF@ +MAKE_PS = @MAKE_PS@ +MAKE_TEXT = @MAKE_TEXT@ +MESA_SOURCE = @MESA_SOURCE@ +MFB_FALSE = @MFB_FALSE@ +MFB_TRUE = @MFB_TRUE@ +MISC_MAN_DIR = @MISC_MAN_DIR@ +MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@ +MITSHM_FALSE = @MITSHM_FALSE@ +MITSHM_TRUE = @MITSHM_TRUE@ +MKFONTDIR = @MKFONTDIR@ +MKFONTSCALE = @MKFONTSCALE@ +MMX_CAPABLE_FALSE = @MMX_CAPABLE_FALSE@ +MMX_CAPABLE_TRUE = @MMX_CAPABLE_TRUE@ +MULTIBUFFER_FALSE = @MULTIBUFFER_FALSE@ +MULTIBUFFER_TRUE = @MULTIBUFFER_TRUE@ +NEED_STRLCAT_FALSE = @NEED_STRLCAT_FALSE@ +NEED_STRLCAT_TRUE = @NEED_STRLCAT_TRUE@ +NEED_VSNPRINTF_FALSE = @NEED_VSNPRINTF_FALSE@ +NEED_VSNPRINTF_TRUE = @NEED_VSNPRINTF_TRUE@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PPC_VIDEO_FALSE = @PPC_VIDEO_FALSE@ +PPC_VIDEO_TRUE = @PPC_VIDEO_TRUE@ +PROJECTROOT = @PROJECTROOT@ +PS2PDF = @PS2PDF@ +RANLIB = @RANLIB@ +RAWCPP = @RAWCPP@ +RAWCPPFLAGS = @RAWCPPFLAGS@ +RECORD_FALSE = @RECORD_FALSE@ +RECORD_TRUE = @RECORD_TRUE@ +RES_FALSE = @RES_FALSE@ +RES_TRUE = @RES_TRUE@ +RGB_DB = @RGB_DB@ +SCREENSAVER_FALSE = @SCREENSAVER_FALSE@ +SCREENSAVER_TRUE = @SCREENSAVER_TRUE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOLARIS_ASM_CFLAGS = @SOLARIS_ASM_CFLAGS@ +SOLARIS_ASM_INLINE_FALSE = @SOLARIS_ASM_INLINE_FALSE@ +SOLARIS_ASM_INLINE_TRUE = @SOLARIS_ASM_INLINE_TRUE@ +SOLARIS_INOUT_ARCH = @SOLARIS_INOUT_ARCH@ +SOLARIS_USL_CONSOLE_FALSE = @SOLARIS_USL_CONSOLE_FALSE@ +SOLARIS_USL_CONSOLE_TRUE = @SOLARIS_USL_CONSOLE_TRUE@ +SPARC64_VIDEO_FALSE = @SPARC64_VIDEO_FALSE@ +SPARC64_VIDEO_TRUE = @SPARC64_VIDEO_TRUE@ +STRIP = @STRIP@ +SUN_KBD_MODE_FALSE = @SUN_KBD_MODE_FALSE@ +SUN_KBD_MODE_TRUE = @SUN_KBD_MODE_TRUE@ +SYS_LIBS = @SYS_LIBS@ +TSLIB_CFLAGS = @TSLIB_CFLAGS@ +TSLIB_FALSE = @TSLIB_FALSE@ +TSLIB_LIBS = @TSLIB_LIBS@ +TSLIB_TRUE = @TSLIB_TRUE@ +USE_CURSES_FALSE = @USE_CURSES_FALSE@ +USE_CURSES_TRUE = @USE_CURSES_TRUE@ +USE_RGB_BUILTIN_FALSE = @USE_RGB_BUILTIN_FALSE@ +USE_RGB_BUILTIN_TRUE = @USE_RGB_BUILTIN_TRUE@ +VENDOR_MAN_VERSION = @VENDOR_MAN_VERSION@ +VENDOR_RELEASE = @VENDOR_RELEASE@ +VENDOR_STRING = @VENDOR_STRING@ +VENDOR_STRING_SHORT = @VENDOR_STRING_SHORT@ +VERSION = @VERSION@ +X11EXAMPLES_DEP_CFLAGS = @X11EXAMPLES_DEP_CFLAGS@ +X11EXAMPLES_DEP_LIBS = @X11EXAMPLES_DEP_LIBS@ +XACE_FALSE = @XACE_FALSE@ +XACE_TRUE = @XACE_TRUE@ +XCALIBRATE_FALSE = @XCALIBRATE_FALSE@ +XCALIBRATE_TRUE = @XCALIBRATE_TRUE@ +XCSECURITY_FALSE = @XCSECURITY_FALSE@ +XCSECURITY_TRUE = @XCSECURITY_TRUE@ +XDMAUTH_FALSE = @XDMAUTH_FALSE@ +XDMAUTH_TRUE = @XDMAUTH_TRUE@ +XDMCP_CFLAGS = @XDMCP_CFLAGS@ +XDMCP_FALSE = @XDMCP_FALSE@ +XDMCP_LIBS = @XDMCP_LIBS@ +XDMCP_TRUE = @XDMCP_TRUE@ +XDMXCONFIG_DEP_CFLAGS = @XDMXCONFIG_DEP_CFLAGS@ +XDMXCONFIG_DEP_LIBS = @XDMXCONFIG_DEP_LIBS@ +XDMX_LIBS = @XDMX_LIBS@ +XEGLMODULES_CFLAGS = @XEGLMODULES_CFLAGS@ +XEGLMODULES_LIBS = @XEGLMODULES_LIBS@ +XEGL_FALSE = @XEGL_FALSE@ +XEGL_LIBS = @XEGL_LIBS@ +XEGL_TRUE = @XEGL_TRUE@ +XEPHYR_CFLAGS = @XEPHYR_CFLAGS@ +XEPHYR_FALSE = @XEPHYR_FALSE@ +XEPHYR_INCS = @XEPHYR_INCS@ +XEPHYR_LIBS = @XEPHYR_LIBS@ +XEPHYR_TRUE = @XEPHYR_TRUE@ +XEVIE_FALSE = @XEVIE_FALSE@ +XEVIE_TRUE = @XEVIE_TRUE@ +XF86BIGFONT_FALSE = @XF86BIGFONT_FALSE@ +XF86BIGFONT_TRUE = @XF86BIGFONT_TRUE@ +XF86CONFIGFILE = @XF86CONFIGFILE@ +XF86UTILS_FALSE = @XF86UTILS_FALSE@ +XF86UTILS_TRUE = @XF86UTILS_TRUE@ +XGLMODULES_CFLAGS = @XGLMODULES_CFLAGS@ +XGLMODULES_LIBS = @XGLMODULES_LIBS@ +XGLXMODULES_CFLAGS = @XGLXMODULES_CFLAGS@ +XGLXMODULES_LIBS = @XGLXMODULES_LIBS@ +XGLX_FALSE = @XGLX_FALSE@ +XGLX_LIBS = @XGLX_LIBS@ +XGLX_TRUE = @XGLX_TRUE@ +XGL_FALSE = @XGL_FALSE@ +XGL_LIBS = @XGL_LIBS@ +XGL_MODULE_PATH = @XGL_MODULE_PATH@ +XGL_TRUE = @XGL_TRUE@ +XINERAMA_FALSE = @XINERAMA_FALSE@ +XINERAMA_TRUE = @XINERAMA_TRUE@ +XINPUT_FALSE = @XINPUT_FALSE@ +XINPUT_TRUE = @XINPUT_TRUE@ +XKB_BASE_DIRECTORY = @XKB_BASE_DIRECTORY@ +XKB_BIN_DIRECTORY = @XKB_BIN_DIRECTORY@ +XKB_COMPILED_DIR = @XKB_COMPILED_DIR@ +XKM_OUTPUT_DIR = @XKM_OUTPUT_DIR@ +XLIB_CFLAGS = @XLIB_CFLAGS@ +XLIB_LIBS = @XLIB_LIBS@ +XNESTMODULES_CFLAGS = @XNESTMODULES_CFLAGS@ +XNESTMODULES_LIBS = @XNESTMODULES_LIBS@ +XNEST_FALSE = @XNEST_FALSE@ +XNEST_LIBS = @XNEST_LIBS@ +XNEST_TRUE = @XNEST_TRUE@ +XORGCFG_DEP_CFLAGS = @XORGCFG_DEP_CFLAGS@ +XORGCFG_DEP_LIBS = @XORGCFG_DEP_LIBS@ +XORGCONFIG_DEP_CFLAGS = @XORGCONFIG_DEP_CFLAGS@ +XORGCONFIG_DEP_LIBS = @XORGCONFIG_DEP_LIBS@ +XORG_BUS_FREEBSDPCI_FALSE = @XORG_BUS_FREEBSDPCI_FALSE@ +XORG_BUS_FREEBSDPCI_TRUE = @XORG_BUS_FREEBSDPCI_TRUE@ +XORG_BUS_IX86PCI_FALSE = @XORG_BUS_IX86PCI_FALSE@ +XORG_BUS_IX86PCI_TRUE = @XORG_BUS_IX86PCI_TRUE@ +XORG_BUS_LINUXPCI_FALSE = @XORG_BUS_LINUXPCI_FALSE@ +XORG_BUS_LINUXPCI_TRUE = @XORG_BUS_LINUXPCI_TRUE@ +XORG_BUS_NETBSDPCI_FALSE = @XORG_BUS_NETBSDPCI_FALSE@ +XORG_BUS_NETBSDPCI_TRUE = @XORG_BUS_NETBSDPCI_TRUE@ +XORG_BUS_PPCPCI_FALSE = @XORG_BUS_PPCPCI_FALSE@ +XORG_BUS_PPCPCI_TRUE = @XORG_BUS_PPCPCI_TRUE@ +XORG_BUS_SPARCPCI_FALSE = @XORG_BUS_SPARCPCI_FALSE@ +XORG_BUS_SPARCPCI_TRUE = @XORG_BUS_SPARCPCI_TRUE@ +XORG_BUS_SPARC_FALSE = @XORG_BUS_SPARC_FALSE@ +XORG_BUS_SPARC_TRUE = @XORG_BUS_SPARC_TRUE@ +XORG_CFLAGS = @XORG_CFLAGS@ +XORG_CORE_LIBS = @XORG_CORE_LIBS@ +XORG_FALSE = @XORG_FALSE@ +XORG_INCS = @XORG_INCS@ +XORG_LIBS = @XORG_LIBS@ +XORG_LOADER_SPARC_FALSE = @XORG_LOADER_SPARC_FALSE@ +XORG_LOADER_SPARC_TRUE = @XORG_LOADER_SPARC_TRUE@ +XORG_OS = @XORG_OS@ +XORG_OS_KBD = @XORG_OS_KBD@ +XORG_OS_SUBDIR = @XORG_OS_SUBDIR@ +XORG_TRUE = @XORG_TRUE@ +XPRINTPROTO_CFLAGS = @XPRINTPROTO_CFLAGS@ +XPRINTPROTO_LIBS = @XPRINTPROTO_LIBS@ +XPRINT_CFLAGS = @XPRINT_CFLAGS@ +XPRINT_FALSE = @XPRINT_FALSE@ +XPRINT_LIBS = @XPRINT_LIBS@ +XPRINT_TRUE = @XPRINT_TRUE@ +XP_USE_FREETYPE_FALSE = @XP_USE_FREETYPE_FALSE@ +XP_USE_FREETYPE_TRUE = @XP_USE_FREETYPE_TRUE@ +XRESEXAMPLES_DEP_CFLAGS = @XRESEXAMPLES_DEP_CFLAGS@ +XRESEXAMPLES_DEP_LIBS = @XRESEXAMPLES_DEP_LIBS@ +XSDLSERVER_FALSE = @XSDLSERVER_FALSE@ +XSDLSERVER_TRUE = @XSDLSERVER_TRUE@ +XSDL_INCS = @XSDL_INCS@ +XSDL_LIBS = @XSDL_LIBS@ +XSERVERCFLAGS_CFLAGS = @XSERVERCFLAGS_CFLAGS@ +XSERVERCFLAGS_LIBS = @XSERVERCFLAGS_LIBS@ +XSERVERLIBS_CFLAGS = @XSERVERLIBS_CFLAGS@ +XSERVERLIBS_LIBS = @XSERVERLIBS_LIBS@ +XSERVER_LIBS = @XSERVER_LIBS@ +XTRAP_FALSE = @XTRAP_FALSE@ +XTRAP_TRUE = @XTRAP_TRUE@ +XTSTEXAMPLES_DEP_CFLAGS = @XTSTEXAMPLES_DEP_CFLAGS@ +XTSTEXAMPLES_DEP_LIBS = @XTSTEXAMPLES_DEP_LIBS@ +XVFB_FALSE = @XVFB_FALSE@ +XVFB_LIBS = @XVFB_LIBS@ +XVFB_TRUE = @XVFB_TRUE@ +XVMC_FALSE = @XVMC_FALSE@ +XVMC_TRUE = @XVMC_TRUE@ +XV_FALSE = @XV_FALSE@ +XV_TRUE = @XV_TRUE@ +XWINMODULES_CFLAGS = @XWINMODULES_CFLAGS@ +XWINMODULES_LIBS = @XWINMODULES_LIBS@ +XWIN_CLIPBOARD_FALSE = @XWIN_CLIPBOARD_FALSE@ +XWIN_CLIPBOARD_TRUE = @XWIN_CLIPBOARD_TRUE@ +XWIN_FALSE = @XWIN_FALSE@ +XWIN_GLX_WINDOWS_FALSE = @XWIN_GLX_WINDOWS_FALSE@ +XWIN_GLX_WINDOWS_TRUE = @XWIN_GLX_WINDOWS_TRUE@ +XWIN_LIBS = @XWIN_LIBS@ +XWIN_MULTIWINDOWEXTWM_FALSE = @XWIN_MULTIWINDOWEXTWM_FALSE@ +XWIN_MULTIWINDOWEXTWM_TRUE = @XWIN_MULTIWINDOWEXTWM_TRUE@ +XWIN_MULTIWINDOW_FALSE = @XWIN_MULTIWINDOW_FALSE@ +XWIN_MULTIWINDOW_TRUE = @XWIN_MULTIWINDOW_TRUE@ +XWIN_NATIVEGDI_FALSE = @XWIN_NATIVEGDI_FALSE@ +XWIN_NATIVEGDI_TRUE = @XWIN_NATIVEGDI_TRUE@ +XWIN_PRIMARYFB_FALSE = @XWIN_PRIMARYFB_FALSE@ +XWIN_PRIMARYFB_TRUE = @XWIN_PRIMARYFB_TRUE@ +XWIN_RANDR_FALSE = @XWIN_RANDR_FALSE@ +XWIN_RANDR_TRUE = @XWIN_RANDR_TRUE@ +XWIN_SERVER_NAME = @XWIN_SERVER_NAME@ +XWIN_SYSTEM_LIBS = @XWIN_SYSTEM_LIBS@ +XWIN_TRUE = @XWIN_TRUE@ +XWIN_XV_FALSE = @XWIN_XV_FALSE@ +XWIN_XV_TRUE = @XWIN_XV_TRUE@ +YACC = @YACC@ +__XCONFIGFILE__ = @__XCONFIGFILE__@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_AS = @ac_ct_AS@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +ac_pt_PKG_CONFIG = @ac_pt_PKG_CONFIG@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +driverdir = @driverdir@ +exec_prefix = @exec_prefix@ +extdir = @extdir@ +ft_config = @ft_config@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sdkdir = @sdkdir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +xglmoduledir = @xglmoduledir@ +xpconfigdir = @xpconfigdir@ +noinst_LTLIBRARIES = libminimi.la libmi.la +@XORG_TRUE@sdk_HEADERS = mibank.h micmap.h miline.h mipointer.h mi.h mibstore.h \ +@XORG_TRUE@ migc.h mipointrst.h mizerarc.h micoord.h mifillarc.h \ +@XORG_TRUE@ mispans.h miwideline.h mistruct.h mifpoly.h + +AM_CFLAGS = $(DIX_CFLAGS) + +# libminimi is for dmx - it has different defines for miinitext.c +libminimi_la_SOURCES = \ + cbrt.c \ + mi.h \ + miarc.c \ + mibank.c \ + mibank.h \ + mibitblt.c \ + mibstore.c \ + mibstore.h \ + mibstorest.h \ + micmap.c \ + micmap.h \ + micoord.h \ + micursor.c \ + midash.c \ + midispcur.c \ + mieq.c \ + miexpose.c \ + mifillarc.c \ + mifillarc.h \ + mifillrct.c \ + mifpolycon.c \ + mifpoly.h \ + migc.c \ + migc.h \ + miglblt.c \ + miline.h \ + mioverlay.c \ + mioverlay.h \ + mipointer.c \ + mipointer.h \ + mipointrst.h \ + mipoly.c \ + mipoly.h \ + mipolycon.c \ + mipolygen.c \ + mipolypnt.c \ + mipolyrect.c \ + mipolyseg.c \ + mipolytext.c \ + mipolyutil.c \ + mipushpxl.c \ + miregion.c \ + miscanfill.h \ + miscrinit.c \ + mispans.c \ + mispans.h \ + misprite.c \ + misprite.h \ + mispritest.h \ + mistruct.h \ + mivaltree.c \ + mivalidate.h \ + miwideline.c \ + miwideline.h \ + miwindow.c \ + mizerarc.c \ + mizerarc.h \ + mizerclip.c \ + mizerline.c + +libmi_la_SOURCES = $(libminimi_la_SOURCES) +INCLUDES = -I$(top_srcdir)/mfb +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign mi/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign mi/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libmi.la: $(libmi_la_OBJECTS) $(libmi_la_DEPENDENCIES) + $(LINK) $(libmi_la_LDFLAGS) $(libmi_la_OBJECTS) $(libmi_la_LIBADD) $(LIBS) +libminimi.la: $(libminimi_la_OBJECTS) $(libminimi_la_DEPENDENCIES) + $(LINK) $(libminimi_la_LDFLAGS) $(libminimi_la_OBJECTS) $(libminimi_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cbrt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/miarc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mibank.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mibitblt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mibstore.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/micmap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/micursor.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/midash.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/midispcur.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mieq.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/miexpose.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mifillarc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mifillrct.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mifpolycon.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/migc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/miglblt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mioverlay.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipointer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipoly.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipolycon.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipolygen.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipolypnt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipolyrect.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipolyseg.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipolytext.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipolyutil.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mipushpxl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/miregion.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/miscrinit.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mispans.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misprite.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mivaltree.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/miwideline.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/miwindow.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mizerarc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mizerclip.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mizerline.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +install-sdkHEADERS: $(sdk_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(sdkdir)" || $(mkdir_p) "$(DESTDIR)$(sdkdir)" + @list='$(sdk_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(sdkHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(sdkdir)/$$f'"; \ + $(sdkHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(sdkdir)/$$f"; \ + done + +uninstall-sdkHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(sdk_HEADERS)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(sdkdir)/$$f'"; \ + rm -f "$(DESTDIR)$(sdkdir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(sdkdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-sdkHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-sdkHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-sdkHEADERS install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am uninstall-sdkHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/xserver/mi/cbrt.c b/xserver/mi/cbrt.c new file mode 100644 index 000000000..c703fd9d2 --- /dev/null +++ b/xserver/mi/cbrt.c @@ -0,0 +1,46 @@ +/* + +Copyright 1990, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* simple cbrt, in case your math library doesn't have a good one */ + +/* + * Would normally include <math.h> for this, but for the sake of compiler + * warnings, we don't want to get duplicate declarations for cbrt(). + */ + +double pow(double, double); +double cbrt(double); + +double +cbrt(double x) +{ + if (x > 0.0) + return pow(x, 1.0/3.0); + else + return -pow(-x, 1.0/3.0); +} diff --git a/xserver/mi/mi.h b/xserver/mi/mi.h new file mode 100644 index 000000000..97e1b6f3a --- /dev/null +++ b/xserver/mi/mi.h @@ -0,0 +1,625 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#ifndef MI_H +#define MI_H +#include <X11/X.h> +#include "region.h" +#include "validate.h" +#include "window.h" +#include "gc.h" +#include <X11/fonts/font.h> +#include "input.h" +#include "cursor.h" + +#define MiBits CARD32 + +typedef struct _miDash *miDashPtr; +#define EVEN_DASH 0 +#define ODD_DASH ~0 + +/* miarc.c */ + +extern void miPolyArc( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*narcs*/, + xArc * /*parcs*/ +); + +/* mibitblt.c */ + +extern RegionPtr miCopyArea( + DrawablePtr /*pSrcDrawable*/, + DrawablePtr /*pDstDrawable*/, + GCPtr /*pGC*/, + int /*xIn*/, + int /*yIn*/, + int /*widthSrc*/, + int /*heightSrc*/, + int /*xOut*/, + int /*yOut*/ +); + +extern void miOpqStipDrawable( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + RegionPtr /*prgnSrc*/, + MiBits * /*pbits*/, + int /*srcx*/, + int /*w*/, + int /*h*/, + int /*dstx*/, + int /*dsty*/ +); + +extern RegionPtr miCopyPlane( + DrawablePtr /*pSrcDrawable*/, + DrawablePtr /*pDstDrawable*/, + GCPtr /*pGC*/, + int /*srcx*/, + int /*srcy*/, + int /*width*/, + int /*height*/, + int /*dstx*/, + int /*dsty*/, + unsigned long /*bitPlane*/ +); + +extern void miGetImage( + DrawablePtr /*pDraw*/, + int /*sx*/, + int /*sy*/, + int /*w*/, + int /*h*/, + unsigned int /*format*/, + unsigned long /*planeMask*/, + char * /*pdstLine*/ +); + +extern void miPutImage( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*depth*/, + int /*x*/, + int /*y*/, + int /*w*/, + int /*h*/, + int /*leftPad*/, + int /*format*/, + char * /*pImage*/ +); + +/* micursor.c */ + +extern void miRecolorCursor( + ScreenPtr /*pScr*/, + CursorPtr /*pCurs*/, + Bool /*displayed*/ +); + +/* midash.c */ + +extern miDashPtr miDashLine( + int /*npt*/, + DDXPointPtr /*ppt*/, + unsigned int /*nDash*/, + unsigned char * /*pDash*/, + unsigned int /*offset*/, + int * /*pnseg*/ +); + +extern void miStepDash( + int /*dist*/, + int * /*pDashIndex*/, + unsigned char * /*pDash*/, + int /*numInDashList*/, + int * /*pDashOffset*/ +); + +/* mieq.c */ + + +#ifndef INPUT_H +typedef struct _DeviceRec *DevicePtr; +#endif + +extern Bool mieqInit( + DevicePtr /*pKbd*/, + DevicePtr /*pPtr*/ +); + +extern void mieqEnqueue( + xEventPtr /*e*/ +); + +extern void mieqSwitchScreen( + ScreenPtr /*pScreen*/, + Bool /*fromDIX*/ +); + +extern void mieqProcessInputEvents( + void +); + +/* miexpose.c */ + +extern RegionPtr miHandleExposures( + DrawablePtr /*pSrcDrawable*/, + DrawablePtr /*pDstDrawable*/, + GCPtr /*pGC*/, + int /*srcx*/, + int /*srcy*/, + int /*width*/, + int /*height*/, + int /*dstx*/, + int /*dsty*/, + unsigned long /*plane*/ +); + +extern void miSendGraphicsExpose( + ClientPtr /*client*/, + RegionPtr /*pRgn*/, + XID /*drawable*/, + int /*major*/, + int /*minor*/ +); + +extern void miSendExposures( + WindowPtr /*pWin*/, + RegionPtr /*pRgn*/, + int /*dx*/, + int /*dy*/ +); + +extern void miWindowExposures( + WindowPtr /*pWin*/, + RegionPtr /*prgn*/, + RegionPtr /*other_exposed*/ +); + +extern void miPaintWindow( + WindowPtr /*pWin*/, + RegionPtr /*prgn*/, + int /*what*/ +); + +extern void miClearDrawable( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/ +); + +/* mifillrct.c */ + +extern void miPolyFillRect( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*nrectFill*/, + xRectangle * /*prectInit*/ +); + +/* miglblt.c */ + +extern void miPolyGlyphBlt( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + unsigned int /*nglyph*/, + CharInfoPtr * /*ppci*/, + pointer /*pglyphBase*/ +); + +extern void miImageGlyphBlt( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + unsigned int /*nglyph*/, + CharInfoPtr * /*ppci*/, + pointer /*pglyphBase*/ +); + +/* mipoly.c */ + +extern void miFillPolygon( + DrawablePtr /*dst*/, + GCPtr /*pgc*/, + int /*shape*/, + int /*mode*/, + int /*count*/, + DDXPointPtr /*pPts*/ +); + +/* mipolycon.c */ + +extern Bool miFillConvexPoly( + DrawablePtr /*dst*/, + GCPtr /*pgc*/, + int /*count*/, + DDXPointPtr /*ptsIn*/ +); + +/* mipolygen.c */ + +extern Bool miFillGeneralPoly( + DrawablePtr /*dst*/, + GCPtr /*pgc*/, + int /*count*/, + DDXPointPtr /*ptsIn*/ +); + +/* mipolypnt.c */ + +extern void miPolyPoint( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*mode*/, + int /*npt*/, + xPoint * /*pptInit*/ +); + +/* mipolyrect.c */ + +extern void miPolyRectangle( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*nrects*/, + xRectangle * /*pRects*/ +); + +/* mipolyseg.c */ + +extern void miPolySegment( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*nseg*/, + xSegment * /*pSegs*/ +); + +/* mipolytext.c */ + +extern int miPolyText( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + int /*count*/, + char * /*chars*/, + FontEncoding /*fontEncoding*/ +); + +extern int miPolyText8( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + int /*count*/, + char * /*chars*/ +); + +extern int miPolyText16( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + int /*count*/, + unsigned short * /*chars*/ +); + +extern int miImageText( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + int /*count*/, + char * /*chars*/, + FontEncoding /*fontEncoding*/ +); + +extern void miImageText8( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + int /*count*/, + char * /*chars*/ +); + +extern void miImageText16( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*x*/, + int /*y*/, + int /*count*/, + unsigned short * /*chars*/ +); + +/* mipushpxl.c */ + +extern void miPushPixels( + GCPtr /*pGC*/, + PixmapPtr /*pBitMap*/, + DrawablePtr /*pDrawable*/, + int /*dx*/, + int /*dy*/, + int /*xOrg*/, + int /*yOrg*/ +); + +/* miregion.c */ + +/* see also region.h */ + +extern Bool miRectAlloc( + RegionPtr /*pRgn*/, + int /*n*/ +); + +extern void miSetExtents( + RegionPtr /*pReg*/ +); + +extern int miFindMaxBand( + RegionPtr /*prgn*/ +); + +#ifdef DEBUG +extern Bool miValidRegion( + RegionPtr /*prgn*/ +); +#endif + +extern Bool miRegionDataCopy(RegionPtr dst, RegionPtr src); +extern Bool miRegionBroken(RegionPtr pReg); + +/* miscrinit.c */ + +extern Bool miModifyPixmapHeader( + PixmapPtr /*pPixmap*/, + int /*width*/, + int /*height*/, + int /*depth*/, + int /*bitsPerPixel*/, + int /*devKind*/, + pointer /*pPixData*/ +); + +extern Bool miCloseScreen( + int /*index*/, + ScreenPtr /*pScreen*/ +); + +extern Bool miCreateScreenResources( + ScreenPtr /*pScreen*/ +); + +extern Bool miScreenDevPrivateInit( + ScreenPtr /*pScreen*/, + int /*width*/, + pointer /*pbits*/ +); + +extern Bool miScreenInit( + ScreenPtr /*pScreen*/, + pointer /*pbits*/, + int /*xsize*/, + int /*ysize*/, + int /*dpix*/, + int /*dpiy*/, + int /*width*/, + int /*rootDepth*/, + int /*numDepths*/, + DepthPtr /*depths*/, + VisualID /*rootVisual*/, + int /*numVisuals*/, + VisualPtr /*visuals*/ +); + +extern int miAllocateGCPrivateIndex( + void +); + +extern PixmapPtr miGetScreenPixmap( + ScreenPtr pScreen +); + +extern void miSetScreenPixmap( + PixmapPtr pPix +); + +/* mivaltree.c */ + +extern int miShapedWindowIn( + ScreenPtr /*pScreen*/, + RegionPtr /*universe*/, + RegionPtr /*bounding*/, + BoxPtr /*rect*/, + int /*x*/, + int /*y*/ +); + +typedef void +(*SetRedirectBorderClipProcPtr) (WindowPtr pWindow, RegionPtr pRegion); + +typedef RegionPtr +(*GetRedirectBorderClipProcPtr) (WindowPtr pWindow); + +void +miRegisterRedirectBorderClipProc (SetRedirectBorderClipProcPtr setBorderClip, + GetRedirectBorderClipProcPtr getBorderClip); + +extern int miValidateTree( + WindowPtr /*pParent*/, + WindowPtr /*pChild*/, + VTKind /*kind*/ +); + +extern void miWideLine( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*mode*/, + int /*npt*/, + DDXPointPtr /*pPts*/ +); + +extern void miWideDash( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + int /*mode*/, + int /*npt*/, + DDXPointPtr /*pPts*/ +); + +/* miwindow.c */ + +extern void miClearToBackground( + WindowPtr /*pWin*/, + int /*x*/, + int /*y*/, + int /*w*/, + int /*h*/, + Bool /*generateExposures*/ +); + +extern Bool miChangeSaveUnder( + WindowPtr /*pWin*/, + WindowPtr /*first*/ +); + +extern void miPostChangeSaveUnder( + WindowPtr /*pWin*/, + WindowPtr /*pFirst*/ +); + +extern void miMarkWindow( + WindowPtr /*pWin*/ +); + +extern Bool miMarkOverlappedWindows( + WindowPtr /*pWin*/, + WindowPtr /*pFirst*/, + WindowPtr * /*ppLayerWin*/ +); + +extern void miHandleValidateExposures( + WindowPtr /*pWin*/ +); + +extern void miMoveWindow( + WindowPtr /*pWin*/, + int /*x*/, + int /*y*/, + WindowPtr /*pNextSib*/, + VTKind /*kind*/ +); + +extern void miSlideAndSizeWindow( + WindowPtr /*pWin*/, + int /*x*/, + int /*y*/, + unsigned int /*w*/, + unsigned int /*h*/, + WindowPtr /*pSib*/ +); + +extern WindowPtr miGetLayerWindow( + WindowPtr /*pWin*/ +); + +extern void miSetShape( + WindowPtr /*pWin*/ +); + +extern void miChangeBorderWidth( + WindowPtr /*pWin*/, + unsigned int /*width*/ +); + +extern void miMarkUnrealizedWindow( + WindowPtr /*pChild*/, + WindowPtr /*pWin*/, + Bool /*fromConfigure*/ +); + +extern void miSegregateChildren(WindowPtr pWin, RegionPtr pReg, int depth); + +/* mizerarc.c */ + +extern void miZeroPolyArc( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*narcs*/, + xArc * /*parcs*/ +); + +/* mizerline.c */ + +extern void miZeroLine( + DrawablePtr /*dst*/, + GCPtr /*pgc*/, + int /*mode*/, + int /*nptInit*/, + DDXPointRec * /*pptInit*/ +); + +extern void miZeroDashLine( + DrawablePtr /*dst*/, + GCPtr /*pgc*/, + int /*mode*/, + int /*nptInit*/, + DDXPointRec * /*pptInit*/ +); + +extern void miPolyFillArc( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + int /*narcs*/, + xArc * /*parcs*/ +); + +#endif /* MI_H */ diff --git a/xserver/mi/miarc.c b/xserver/mi/miarc.c new file mode 100644 index 000000000..2b3a0cbbc --- /dev/null +++ b/xserver/mi/miarc.c @@ -0,0 +1,3720 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +/* Author: Keith Packard and Bob Scheifler */ +/* Warning: this code is toxic, do not dally very long here. */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#if defined(_XOPEN_SOURCE) || defined(__QNXNTO__) \ + || (defined(sun) && defined(__SVR4)) +#include <math.h> +#else +#define _XOPEN_SOURCE /* to get prototype for hypot on some systems */ +#include <math.h> +#undef _XOPEN_SOURCE +#endif +#include <X11/X.h> +#include <X11/Xprotostr.h> +#include "misc.h" +#include "gcstruct.h" +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "mifpoly.h" +#include "mi.h" +#include "mifillarc.h" +#include <X11/Xfuncproto.h> + +static double miDsin(double a); +static double miDcos(double a); +static double miDasin(double v); +static double miDatan2(double dy, double dx); +double cbrt(double); + +#ifdef ICEILTEMPDECL +ICEILTEMPDECL +#endif + +/* + * some interesting sematic interpretation of the protocol: + * + * Self intersecting arcs (i.e. those spanning 360 degrees) + * never join with other arcs, and are drawn without caps + * (unless on/off dashed, in which case each dash segment + * is capped, except when the last segment meets the + * first segment, when no caps are drawn) + * + * double dash arcs are drawn in two parts, first the + * odd dashes (drawn in background) then the even dashes + * (drawn in foreground). This means that overlapping + * sections of foreground/background are drawn twice, + * first in background then in foreground. The double-draw + * occurs even when the function uses the destination values + * (e.g. xor mode). This is the same way the wide-line + * code works and should be "fixed". + * + */ + +#undef max +#undef min + +#if defined (__GNUC__) && !defined (__STRICT_ANSI__) +#define USE_INLINE +#endif + +#ifdef USE_INLINE +inline static int max (const int x, const int y) +{ + return x>y? x:y; +} + +inline static int min (const int x, const int y) +{ + return x<y? x:y; +} + +#else + +static int +max (int x, int y) +{ + return x>y? x:y; +} + +static int +min (int x, int y) +{ + return x<y? x:y; +} + +#endif + +struct bound { + double min, max; +}; + +struct ibound { + int min, max; +}; + +#define boundedLe(value, bounds)\ + ((bounds).min <= (value) && (value) <= (bounds).max) + +struct line { + double m, b; + int valid; +}; + +#define intersectLine(y,line) (line.m * (y) + line.b) + +/* + * these are all y value bounds + */ + +struct arc_bound { + struct bound ellipse; + struct bound inner; + struct bound outer; + struct bound right; + struct bound left; + struct ibound inneri; + struct ibound outeri; +}; + +struct accelerators { + double tail_y; + double h2; + double w2; + double h4; + double w4; + double h2mw2; + double h2l; + double w2l; + double fromIntX; + double fromIntY; + struct line left, right; + int yorgu; + int yorgl; + int xorg; +}; + +struct arc_def { + double w, h, l; + double a0, a1; +}; + +# define todeg(xAngle) (((double) (xAngle)) / 64.0) + +# define RIGHT_END 0 +# define LEFT_END 1 + +typedef struct _miArcJoin { + int arcIndex0, arcIndex1; + int phase0, phase1; + int end0, end1; +} miArcJoinRec, *miArcJoinPtr; + +typedef struct _miArcCap { + int arcIndex; + int end; +} miArcCapRec, *miArcCapPtr; + +typedef struct _miArcFace { + SppPointRec clock; + SppPointRec center; + SppPointRec counterClock; +} miArcFaceRec, *miArcFacePtr; + +typedef struct _miArcData { + xArc arc; + int render; /* non-zero means render after drawing */ + int join; /* related join */ + int cap; /* related cap */ + int selfJoin; /* final dash meets first dash */ + miArcFaceRec bounds[2]; + double x0, y0, x1, y1; +} miArcDataRec, *miArcDataPtr; + +/* + * This is an entire sequence of arcs, computed and categorized according + * to operation. miDashArcs generates either one or two of these. + */ + +typedef struct _miPolyArc { + int narcs; + miArcDataPtr arcs; + int ncaps; + miArcCapPtr caps; + int njoins; + miArcJoinPtr joins; +} miPolyArcRec, *miPolyArcPtr; + +#define GCValsFunction 0 +#define GCValsForeground 1 +#define GCValsBackground 2 +#define GCValsLineWidth 3 +#define GCValsCapStyle 4 +#define GCValsJoinStyle 5 +#define GCValsMask (GCFunction | GCForeground | GCBackground | \ + GCLineWidth | GCCapStyle | GCJoinStyle) +static CARD32 gcvals[6]; + +static void fillSpans(DrawablePtr pDrawable, GCPtr pGC); +static void newFinalSpan(int y, register int xmin, register int xmax); +static void drawArc(xArc *tarc, int l, int a0, int a1, miArcFacePtr right, + miArcFacePtr left); +static void drawZeroArc(DrawablePtr pDraw, GCPtr pGC, xArc *tarc, int lw, + miArcFacePtr left, miArcFacePtr right); +static void miArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft, + miArcFacePtr pRight, int xOrgLeft, int yOrgLeft, + double xFtransLeft, double yFtransLeft, + int xOrgRight, int yOrgRight, + double xFtransRight, double yFtransRight); +static void miArcCap(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pFace, + int end, int xOrg, int yOrg, double xFtrans, + double yFtrans); +static void miRoundCap(DrawablePtr pDraw, GCPtr pGC, SppPointRec pCenter, + SppPointRec pEnd, SppPointRec pCorner, + SppPointRec pOtherCorner, int fLineEnd, + int xOrg, int yOrg, double xFtrans, double yFtrans); +static void miFreeArcs(miPolyArcPtr arcs, GCPtr pGC); +static miPolyArcPtr miComputeArcs(xArc *parcs, int narcs, GCPtr pGC); +static int miGetArcPts(SppArcPtr parc, int cpt, SppPointPtr *ppPts); + +# define CUBED_ROOT_2 1.2599210498948732038115849718451499938964 +# define CUBED_ROOT_4 1.5874010519681993173435330390930175781250 + +/* + * draw one segment of the arc using the arc spans generation routines + */ + +static void +miArcSegment( + DrawablePtr pDraw, + GCPtr pGC, + xArc tarc, + miArcFacePtr right, + miArcFacePtr left) +{ + int l = pGC->lineWidth; + int a0, a1, startAngle, endAngle; + miArcFacePtr temp; + + if (!l) + l = 1; + + if (tarc.width == 0 || tarc.height == 0) { + drawZeroArc (pDraw, pGC, &tarc, l, left, right); + return; + } + + if (pGC->miTranslate) { + tarc.x += pDraw->x; + tarc.y += pDraw->y; + } + + a0 = tarc.angle1; + a1 = tarc.angle2; + if (a1 > FULLCIRCLE) + a1 = FULLCIRCLE; + else if (a1 < -FULLCIRCLE) + a1 = -FULLCIRCLE; + if (a1 < 0) { + startAngle = a0 + a1; + endAngle = a0; + temp = right; + right = left; + left = temp; + } else { + startAngle = a0; + endAngle = a0 + a1; + } + /* + * bounds check the two angles + */ + if (startAngle < 0) + startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE; + if (startAngle >= FULLCIRCLE) + startAngle = startAngle % FULLCIRCLE; + if (endAngle < 0) + endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE; + if (endAngle > FULLCIRCLE) + endAngle = (endAngle-1) % FULLCIRCLE + 1; + if ((startAngle == endAngle) && a1) { + startAngle = 0; + endAngle = FULLCIRCLE; + } + + drawArc (&tarc, l, startAngle, endAngle, right, left); +} + +/* + +Three equations combine to describe the boundaries of the arc + +x^2/w^2 + y^2/h^2 = 1 ellipse itself +(X-x)^2 + (Y-y)^2 = r^2 circle at (x, y) on the ellipse +(Y-y) = (X-x)*w^2*y/(h^2*x) normal at (x, y) on the ellipse + +These lead to a quartic relating Y and y + +y^4 - (2Y)y^3 + (Y^2 + (h^4 - w^2*r^2)/(w^2 - h^2))y^2 + - (2Y*h^4/(w^2 - h^2))y + (Y^2*h^4)/(w^2 - h^2) = 0 + +The reducible cubic obtained from this quartic is + +z^3 - (3N)z^2 - 2V = 0 + +where + +N = (Y^2 + (h^4 - w^2*r^2/(w^2 - h^2)))/6 +V = w^2*r^2*Y^2*h^4/(4 *(w^2 - h^2)^2) + +Let + +t = z - N +p = -N^2 +q = -N^3 - V + +Then we get + +t^3 + 3pt + 2q = 0 + +The discriminant of this cubic is + +D = q^2 + p^3 + +When D > 0, a real root is obtained as + +z = N + cbrt(-q+sqrt(D)) + cbrt(-q-sqrt(D)) + +When D < 0, a real root is obtained as + +z = N - 2m*cos(acos(-q/m^3)/3) + +where + +m = sqrt(|p|) * sign(q) + +Given a real root Z of the cubic, the roots of the quartic are the roots +of the two quadratics + +y^2 + ((b+A)/2)y + (Z + (bZ - d)/A) = 0 + +where + +A = +/- sqrt(8Z + b^2 - 4c) +b, c, d are the cubic, quadratic, and linear coefficients of the quartic + +Some experimentation is then required to determine which solutions +correspond to the inner and outer boundaries. + +*/ + +typedef struct { + short lx, lw, rx, rw; +} miArcSpan; + +typedef struct { + miArcSpan *spans; + int count1, count2, k; + char top, bot, hole; +} miArcSpanData; + +typedef struct { + unsigned long lrustamp; + unsigned short lw; + unsigned short width, height; + miArcSpanData *spdata; +} arcCacheRec; + +#define CACHESIZE 25 + +static void drawQuadrant(struct arc_def *def, struct accelerators *acc, + int a0, int a1, int mask, miArcFacePtr right, + miArcFacePtr left, miArcSpanData *spdata); + +static arcCacheRec arcCache[CACHESIZE]; +static unsigned long lrustamp; +static arcCacheRec *lastCacheHit = &arcCache[0]; +static RESTYPE cacheType; + +/* + * External so it can be called when low on memory. + * Call with a zero ID in that case. + */ +/*ARGSUSED*/ +int +miFreeArcCache (data, id) + pointer data; + XID id; +{ + int k; + arcCacheRec *cent; + + if (id) + cacheType = 0; + + for (k = CACHESIZE, cent = &arcCache[0]; --k >= 0; cent++) + { + if (cent->spdata) + { + cent->lrustamp = 0; + cent->lw = 0; + xfree(cent->spdata); + cent->spdata = NULL; + } + } + lrustamp = 0; + return Success; +} + +static void +miComputeCircleSpans( + int lw, + xArc *parc, + miArcSpanData *spdata) +{ + register miArcSpan *span; + int doinner; + register int x, y, e; + int xk, yk, xm, ym, dx, dy; + register int slw, inslw; + int inx = 0, iny, ine = 0; + int inxk = 0, inyk = 0, inxm = 0, inym = 0; + + doinner = -lw; + slw = parc->width - doinner; + y = parc->height >> 1; + dy = parc->height & 1; + dx = 1 - dy; + MIWIDEARCSETUP(x, y, dy, slw, e, xk, xm, yk, ym); + inslw = parc->width + doinner; + if (inslw > 0) + { + spdata->hole = spdata->top; + MIWIDEARCSETUP(inx, iny, dy, inslw, ine, inxk, inxm, inyk, inym); + } + else + { + spdata->hole = FALSE; + doinner = -y; + } + spdata->count1 = -doinner - spdata->top; + spdata->count2 = y + doinner; + span = spdata->spans; + while (y) + { + MIFILLARCSTEP(slw); + span->lx = dy - x; + if (++doinner <= 0) + { + span->lw = slw; + span->rx = 0; + span->rw = span->lx + slw; + } + else + { + MIFILLINARCSTEP(inslw); + span->lw = x - inx; + span->rx = dy - inx + inslw; + span->rw = inx - x + slw - inslw; + } + span++; + } + if (spdata->bot) + { + if (spdata->count2) + spdata->count2--; + else + { + if (lw > (int)parc->height) + span[-1].rx = span[-1].rw = -((lw - (int)parc->height) >> 1); + else + span[-1].rw = 0; + spdata->count1--; + } + } +} + +static void +miComputeEllipseSpans( + int lw, + xArc *parc, + miArcSpanData *spdata) +{ + register miArcSpan *span; + double w, h, r, xorg; + double Hs, Hf, WH, K, Vk, Nk, Fk, Vr, N, Nc, Z, rs; + double A, T, b, d, x, y, t, inx, outx = 0.0, hepp, hepm; + int flip, solution; + + w = (double)parc->width / 2.0; + h = (double)parc->height / 2.0; + r = lw / 2.0; + rs = r * r; + Hs = h * h; + WH = w * w - Hs; + Nk = w * r; + Vk = (Nk * Hs) / (WH + WH); + Hf = Hs * Hs; + Nk = (Hf - Nk * Nk) / WH; + Fk = Hf / WH; + hepp = h + EPSILON; + hepm = h - EPSILON; + K = h + ((lw - 1) >> 1); + span = spdata->spans; + if (parc->width & 1) + xorg = .5; + else + xorg = 0.0; + if (spdata->top) + { + span->lx = 0; + span->lw = 1; + span++; + } + spdata->count1 = 0; + spdata->count2 = 0; + spdata->hole = (spdata->top && + (int)parc->height * lw <= (int)(parc->width * parc->width) && + lw < (int)parc->height); + for (; K > 0.0; K -= 1.0) + { + N = (K * K + Nk) / 6.0; + Nc = N * N * N; + Vr = Vk * K; + t = Nc + Vr * Vr; + d = Nc + t; + if (d < 0.0) { + d = Nc; + b = N; + if ( (b < 0.0) == (t < 0.0) ) + { + b = -b; + d = -d; + } + Z = N - 2.0 * b * cos(acos(-t / d) / 3.0); + if ( (Z < 0.0) == (Vr < 0.0) ) + flip = 2; + else + flip = 1; + } + else + { + d = Vr * sqrt(d); + Z = N + cbrt(t + d) + cbrt(t - d); + flip = 0; + } + A = sqrt((Z + Z) - Nk); + T = (Fk - Z) * K / A; + inx = 0.0; + solution = FALSE; + b = -A + K; + d = b * b - 4 * (Z + T); + if (d >= 0) + { + d = sqrt(d); + y = (b + d) / 2; + if ((y >= 0.0) && (y < hepp)) + { + solution = TRUE; + if (y > hepm) + y = h; + t = y / h; + x = w * sqrt(1 - (t * t)); + t = K - y; + if (rs - (t * t) >= 0) + t = sqrt(rs - (t * t)); + else + t = 0; + if (flip == 2) + inx = x - t; + else + outx = x + t; + } + } + b = A + K; + d = b * b - 4 * (Z - T); + /* Because of the large magnitudes involved, we lose enough precision + * that sometimes we end up with a negative value near the axis, when + * it should be positive. This is a workaround. + */ + if (d < 0 && !solution) + d = 0.0; + if (d >= 0) { + d = sqrt(d); + y = (b + d) / 2; + if (y < hepp) + { + if (y > hepm) + y = h; + t = y / h; + x = w * sqrt(1 - (t * t)); + t = K - y; + if (rs - (t * t) >= 0) + inx = x - sqrt(rs - (t * t)); + else + inx = x; + } + y = (b - d) / 2; + if (y >= 0.0) + { + if (y > hepm) + y = h; + t = y / h; + x = w * sqrt(1 - (t * t)); + t = K - y; + if (rs - (t * t) >= 0) + t = sqrt(rs - (t * t)); + else + t = 0; + if (flip == 1) + inx = x - t; + else + outx = x + t; + } + } + span->lx = ICEIL(xorg - outx); + if (inx <= 0.0) + { + spdata->count1++; + span->lw = ICEIL(xorg + outx) - span->lx; + span->rx = ICEIL(xorg + inx); + span->rw = -ICEIL(xorg - inx); + } + else + { + spdata->count2++; + span->lw = ICEIL(xorg - inx) - span->lx; + span->rx = ICEIL(xorg + inx); + span->rw = ICEIL(xorg + outx) - span->rx; + } + span++; + } + if (spdata->bot) + { + outx = w + r; + if (r >= h && r <= w) + inx = 0.0; + else if (Nk < 0.0 && -Nk < Hs) + { + inx = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk); + if (inx > w - r) + inx = w - r; + } + else + inx = w - r; + span->lx = ICEIL(xorg - outx); + if (inx <= 0.0) + { + span->lw = ICEIL(xorg + outx) - span->lx; + span->rx = ICEIL(xorg + inx); + span->rw = -ICEIL(xorg - inx); + } + else + { + span->lw = ICEIL(xorg - inx) - span->lx; + span->rx = ICEIL(xorg + inx); + span->rw = ICEIL(xorg + outx) - span->rx; + } + } + if (spdata->hole) + { + span = &spdata->spans[spdata->count1]; + span->lw = -span->lx; + span->rx = 1; + span->rw = span->lw; + spdata->count1--; + spdata->count2++; + } +} + +static double +tailX( + double K, + struct arc_def *def, + struct arc_bound *bounds, + struct accelerators *acc) +{ + double w, h, r; + double Hs, Hf, WH, Vk, Nk, Fk, Vr, N, Nc, Z, rs; + double A, T, b, d, x, y, t, hepp, hepm; + int flip, solution; + double xs[2]; + double *xp; + + w = def->w; + h = def->h; + r = def->l; + rs = r * r; + Hs = acc->h2; + WH = -acc->h2mw2; + Nk = def->w * r; + Vk = (Nk * Hs) / (WH + WH); + Hf = acc->h4; + Nk = (Hf - Nk * Nk) / WH; + if (K == 0.0) { + if (Nk < 0.0 && -Nk < Hs) { + xs[0] = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk); + xs[1] = w - r; + if (acc->left.valid && boundedLe(K, bounds->left) && + !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0) + return xs[1]; + if (acc->right.valid && boundedLe(K, bounds->right) && + !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0) + return xs[1]; + return xs[0]; + } + return w - r; + } + Fk = Hf / WH; + hepp = h + EPSILON; + hepm = h - EPSILON; + N = (K * K + Nk) / 6.0; + Nc = N * N * N; + Vr = Vk * K; + xp = xs; + xs[0] = 0.0; + t = Nc + Vr * Vr; + d = Nc + t; + if (d < 0.0) { + d = Nc; + b = N; + if ( (b < 0.0) == (t < 0.0) ) + { + b = -b; + d = -d; + } + Z = N - 2.0 * b * cos(acos(-t / d) / 3.0); + if ( (Z < 0.0) == (Vr < 0.0) ) + flip = 2; + else + flip = 1; + } + else + { + d = Vr * sqrt(d); + Z = N + cbrt(t + d) + cbrt(t - d); + flip = 0; + } + A = sqrt((Z + Z) - Nk); + T = (Fk - Z) * K / A; + solution = FALSE; + b = -A + K; + d = b * b - 4 * (Z + T); + if (d >= 0 && flip == 2) + { + d = sqrt(d); + y = (b + d) / 2; + if ((y >= 0.0) && (y < hepp)) + { + solution = TRUE; + if (y > hepm) + y = h; + t = y / h; + x = w * sqrt(1 - (t * t)); + t = K - y; + if (rs - (t * t) >= 0) + t = sqrt(rs - (t * t)); + else + t = 0; + *xp++ = x - t; + } + } + b = A + K; + d = b * b - 4 * (Z - T); + /* Because of the large magnitudes involved, we lose enough precision + * that sometimes we end up with a negative value near the axis, when + * it should be positive. This is a workaround. + */ + if (d < 0 && !solution) + d = 0.0; + if (d >= 0) { + d = sqrt(d); + y = (b + d) / 2; + if (y < hepp) + { + if (y > hepm) + y = h; + t = y / h; + x = w * sqrt(1 - (t * t)); + t = K - y; + if (rs - (t * t) >= 0) + *xp++ = x - sqrt(rs - (t * t)); + else + *xp++ = x; + } + y = (b - d) / 2; + if (y >= 0.0 && flip == 1) + { + if (y > hepm) + y = h; + t = y / h; + x = w * sqrt(1 - (t * t)); + t = K - y; + if (rs - (t * t) >= 0) + t = sqrt(rs - (t * t)); + else + t = 0; + *xp++ = x - t; + } + } + if (xp > &xs[1]) { + if (acc->left.valid && boundedLe(K, bounds->left) && + !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0) + return xs[1]; + if (acc->right.valid && boundedLe(K, bounds->right) && + !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0) + return xs[1]; + } + return xs[0]; +} + +static miArcSpanData * +miComputeWideEllipse( + int lw, + register xArc *parc, + Bool *mustFree) +{ + register miArcSpanData *spdata; + register arcCacheRec *cent, *lruent; + register int k; + arcCacheRec fakeent; + + if (!lw) + lw = 1; + if (parc->height <= 1500) + { + *mustFree = FALSE; + cent = lastCacheHit; + if (cent->lw == lw && + cent->width == parc->width && cent->height == parc->height) + { + cent->lrustamp = ++lrustamp; + return cent->spdata; + } + lruent = &arcCache[0]; + for (k = CACHESIZE, cent = lruent; --k >= 0; cent++) + { + if (cent->lw == lw && + cent->width == parc->width && cent->height == parc->height) + { + cent->lrustamp = ++lrustamp; + lastCacheHit = cent; + return cent->spdata; + } + if (cent->lrustamp < lruent->lrustamp) + lruent = cent; + } + if (!cacheType) + { + cacheType = CreateNewResourceType(miFreeArcCache); + (void) AddResource(FakeClientID(0), cacheType, NULL); + } + } else { + lruent = &fakeent; + lruent->spdata = NULL; + *mustFree = TRUE; + } + k = (parc->height >> 1) + ((lw - 1) >> 1); + spdata = lruent->spdata; + if (!spdata || spdata->k != k) + { + if (spdata) + xfree(spdata); + spdata = (miArcSpanData *)xalloc(sizeof(miArcSpanData) + + sizeof(miArcSpan) * (k + 2)); + lruent->spdata = spdata; + if (!spdata) + { + lruent->lrustamp = 0; + lruent->lw = 0; + return spdata; + } + spdata->spans = (miArcSpan *)(spdata + 1); + spdata->k = k; + } + spdata->top = !(lw & 1) && !(parc->width & 1); + spdata->bot = !(parc->height & 1); + lruent->lrustamp = ++lrustamp; + lruent->lw = lw; + lruent->width = parc->width; + lruent->height = parc->height; + if (lruent != &fakeent) + lastCacheHit = lruent; + if (parc->width == parc->height) + miComputeCircleSpans(lw, parc, spdata); + else + miComputeEllipseSpans(lw, parc, spdata); + return spdata; +} + +static void +miFillWideEllipse( + DrawablePtr pDraw, + GCPtr pGC, + xArc *parc) +{ + DDXPointPtr points; + register DDXPointPtr pts; + int *widths; + register int *wids; + miArcSpanData *spdata; + Bool mustFree; + register miArcSpan *span; + register int xorg, yorgu, yorgl; + register int n; + + yorgu = parc->height + pGC->lineWidth; + n = (sizeof(int) * 2) * yorgu; + widths = (int *)ALLOCATE_LOCAL(n + (sizeof(DDXPointRec) * 2) * yorgu); + if (!widths) + return; + points = (DDXPointPtr)((char *)widths + n); + spdata = miComputeWideEllipse((int)pGC->lineWidth, parc, &mustFree); + if (!spdata) + { + DEALLOCATE_LOCAL(widths); + return; + } + pts = points; + wids = widths; + span = spdata->spans; + xorg = parc->x + (parc->width >> 1); + yorgu = parc->y + (parc->height >> 1); + yorgl = yorgu + (parc->height & 1); + if (pGC->miTranslate) + { + xorg += pDraw->x; + yorgu += pDraw->y; + yorgl += pDraw->y; + } + yorgu -= spdata->k; + yorgl += spdata->k; + if (spdata->top) + { + pts->x = xorg; + pts->y = yorgu - 1; + pts++; + *wids++ = 1; + span++; + } + for (n = spdata->count1; --n >= 0; ) + { + pts[0].x = xorg + span->lx; + pts[0].y = yorgu; + wids[0] = span->lw; + pts[1].x = pts[0].x; + pts[1].y = yorgl; + wids[1] = wids[0]; + yorgu++; + yorgl--; + pts += 2; + wids += 2; + span++; + } + if (spdata->hole) + { + pts[0].x = xorg; + pts[0].y = yorgl; + wids[0] = 1; + pts++; + wids++; + } + for (n = spdata->count2; --n >= 0; ) + { + pts[0].x = xorg + span->lx; + pts[0].y = yorgu; + wids[0] = span->lw; + pts[1].x = xorg + span->rx; + pts[1].y = pts[0].y; + wids[1] = span->rw; + pts[2].x = pts[0].x; + pts[2].y = yorgl; + wids[2] = wids[0]; + pts[3].x = pts[1].x; + pts[3].y = pts[2].y; + wids[3] = wids[1]; + yorgu++; + yorgl--; + pts += 4; + wids += 4; + span++; + } + if (spdata->bot) + { + if (span->rw <= 0) + { + pts[0].x = xorg + span->lx; + pts[0].y = yorgu; + wids[0] = span->lw; + pts++; + wids++; + } + else + { + pts[0].x = xorg + span->lx; + pts[0].y = yorgu; + wids[0] = span->lw; + pts[1].x = xorg + span->rx; + pts[1].y = pts[0].y; + wids[1] = span->rw; + pts += 2; + wids += 2; + } + } + if (mustFree) + xfree(spdata); + (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); + + DEALLOCATE_LOCAL(widths); +} + +/* + * miPolyArc strategy: + * + * If arc is zero width and solid, we don't have to worry about the rasterop + * or join styles. For wide solid circles, we use a fast integer algorithm. + * For wide solid ellipses, we use special case floating point code. + * Otherwise, we set up pDrawTo and pGCTo according to the rasterop, then + * draw using pGCTo and pDrawTo. If the raster-op was "tricky," that is, + * if it involves the destination, then we use PushPixels to move the bits + * from the scratch drawable to pDraw. (See the wide line code for a + * fuller explanation of this.) + */ + +_X_EXPORT void +miPolyArc(pDraw, pGC, narcs, parcs) + DrawablePtr pDraw; + GCPtr pGC; + int narcs; + xArc *parcs; +{ + register int i; + xArc *parc; + int xMin, xMax, yMin, yMax; + int pixmapWidth = 0, pixmapHeight = 0; + int xOrg = 0, yOrg = 0; + int width; + Bool fTricky; + DrawablePtr pDrawTo; + CARD32 fg, bg; + GCPtr pGCTo; + miPolyArcPtr polyArcs; + int cap[2], join[2]; + int iphase; + int halfWidth; + + width = pGC->lineWidth; + if(width == 0 && pGC->lineStyle == LineSolid) + { + for(i = narcs, parc = parcs; --i >= 0; parc++) + miArcSegment( pDraw, pGC, *parc, + (miArcFacePtr) 0, (miArcFacePtr) 0 ); + fillSpans (pDraw, pGC); + } + else + { + if ((pGC->lineStyle == LineSolid) && narcs) + { + while (parcs->width && parcs->height && + (parcs->angle2 >= FULLCIRCLE || + parcs->angle2 <= -FULLCIRCLE)) + { + miFillWideEllipse(pDraw, pGC, parcs); + if (!--narcs) + return; + parcs++; + } + } + + /* Set up pDrawTo and pGCTo based on the rasterop */ + switch(pGC->alu) + { + case GXclear: /* 0 */ + case GXcopy: /* src */ + case GXcopyInverted: /* NOT src */ + case GXset: /* 1 */ + fTricky = FALSE; + pDrawTo = pDraw; + pGCTo = pGC; + break; + default: + fTricky = TRUE; + + /* find bounding box around arcs */ + xMin = yMin = MAXSHORT; + xMax = yMax = MINSHORT; + + for(i = narcs, parc = parcs; --i >= 0; parc++) + { + xMin = min (xMin, parc->x); + yMin = min (yMin, parc->y); + xMax = max (xMax, (parc->x + (int) parc->width)); + yMax = max (yMax, (parc->y + (int) parc->height)); + } + + /* expand box to deal with line widths */ + halfWidth = (width + 1)/2; + xMin -= halfWidth; + yMin -= halfWidth; + xMax += halfWidth; + yMax += halfWidth; + + /* compute pixmap size; limit it to size of drawable */ + xOrg = max(xMin, 0); + yOrg = max(yMin, 0); + pixmapWidth = min(xMax, pDraw->width) - xOrg; + pixmapHeight = min(yMax, pDraw->height) - yOrg; + + /* if nothing left, return */ + if ( (pixmapWidth <= 0) || (pixmapHeight <= 0) ) return; + + for(i = narcs, parc = parcs; --i >= 0; parc++) + { + parc->x -= xOrg; + parc->y -= yOrg; + } + if (pGC->miTranslate) + { + xOrg += pDraw->x; + yOrg += pDraw->y; + } + + /* set up scratch GC */ + + pGCTo = GetScratchGC(1, pDraw->pScreen); + if (!pGCTo) + return; + gcvals[GCValsFunction] = GXcopy; + gcvals[GCValsForeground] = 1; + gcvals[GCValsBackground] = 0; + gcvals[GCValsLineWidth] = pGC->lineWidth; + gcvals[GCValsCapStyle] = pGC->capStyle; + gcvals[GCValsJoinStyle] = pGC->joinStyle; + dixChangeGC(NullClient, pGCTo, GCValsMask, gcvals, NULL); + + /* allocate a 1 bit deep pixmap of the appropriate size, and + * validate it */ + pDrawTo = (DrawablePtr)(*pDraw->pScreen->CreatePixmap) + (pDraw->pScreen, pixmapWidth, pixmapHeight, 1); + if (!pDrawTo) + { + FreeScratchGC(pGCTo); + return; + } + ValidateGC(pDrawTo, pGCTo); + miClearDrawable(pDrawTo, pGCTo); + } + + fg = pGC->fgPixel; + bg = pGC->bgPixel; + if ((pGC->fillStyle == FillTiled) || + (pGC->fillStyle == FillOpaqueStippled)) + bg = fg; /* the protocol sez these don't cause color changes */ + + polyArcs = miComputeArcs (parcs, narcs, pGC); + + if (!polyArcs) + { + if (fTricky) { + (*pDraw->pScreen->DestroyPixmap) ((PixmapPtr)pDrawTo); + FreeScratchGC (pGCTo); + } + return; + } + + cap[0] = cap[1] = 0; + join[0] = join[1] = 0; + for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0); + iphase >= 0; + iphase--) + { + if (iphase == 1) { + dixChangeGC (NullClient, pGC, GCForeground, &bg, NULL); + ValidateGC (pDraw, pGC); + } else if (pGC->lineStyle == LineDoubleDash) { + dixChangeGC (NullClient, pGC, GCForeground, &fg, NULL); + ValidateGC (pDraw, pGC); + } + for (i = 0; i < polyArcs[iphase].narcs; i++) { + miArcDataPtr arcData; + + arcData = &polyArcs[iphase].arcs[i]; + miArcSegment(pDrawTo, pGCTo, arcData->arc, + &arcData->bounds[RIGHT_END], + &arcData->bounds[LEFT_END]); + if (polyArcs[iphase].arcs[i].render) { + fillSpans (pDrawTo, pGCTo); + /* + * don't cap self-joining arcs + */ + if (polyArcs[iphase].arcs[i].selfJoin && + cap[iphase] < polyArcs[iphase].arcs[i].cap) + cap[iphase]++; + while (cap[iphase] < polyArcs[iphase].arcs[i].cap) { + int arcIndex, end; + miArcDataPtr arcData0; + + arcIndex = polyArcs[iphase].caps[cap[iphase]].arcIndex; + end = polyArcs[iphase].caps[cap[iphase]].end; + arcData0 = &polyArcs[iphase].arcs[arcIndex]; + miArcCap (pDrawTo, pGCTo, + &arcData0->bounds[end], end, + arcData0->arc.x, arcData0->arc.y, + (double) arcData0->arc.width / 2.0, + (double) arcData0->arc.height / 2.0); + ++cap[iphase]; + } + while (join[iphase] < polyArcs[iphase].arcs[i].join) { + int arcIndex0, arcIndex1, end0, end1; + int phase0, phase1; + miArcDataPtr arcData0, arcData1; + miArcJoinPtr joinp; + + joinp = &polyArcs[iphase].joins[join[iphase]]; + arcIndex0 = joinp->arcIndex0; + end0 = joinp->end0; + arcIndex1 = joinp->arcIndex1; + end1 = joinp->end1; + phase0 = joinp->phase0; + phase1 = joinp->phase1; + arcData0 = &polyArcs[phase0].arcs[arcIndex0]; + arcData1 = &polyArcs[phase1].arcs[arcIndex1]; + miArcJoin (pDrawTo, pGCTo, + &arcData0->bounds[end0], + &arcData1->bounds[end1], + arcData0->arc.x, arcData0->arc.y, + (double) arcData0->arc.width / 2.0, + (double) arcData0->arc.height / 2.0, + arcData1->arc.x, arcData1->arc.y, + (double) arcData1->arc.width / 2.0, + (double) arcData1->arc.height / 2.0); + ++join[iphase]; + } + if (fTricky) { + if (pGC->serialNumber != pDraw->serialNumber) + ValidateGC (pDraw, pGC); + (*pGC->ops->PushPixels) (pGC, (PixmapPtr)pDrawTo, + pDraw, pixmapWidth, pixmapHeight, xOrg, yOrg); + miClearDrawable ((DrawablePtr) pDrawTo, pGCTo); + } + } + } + } + miFreeArcs(polyArcs, pGC); + + if(fTricky) + { + (*pGCTo->pScreen->DestroyPixmap)((PixmapPtr)pDrawTo); + FreeScratchGC(pGCTo); + } + } +} + +static double +angleBetween (SppPointRec center, SppPointRec point1, SppPointRec point2) +{ + double a1, a2, a; + + /* + * reflect from X coordinates back to ellipse + * coordinates -- y increasing upwards + */ + a1 = miDatan2 (- (point1.y - center.y), point1.x - center.x); + a2 = miDatan2 (- (point2.y - center.y), point2.x - center.x); + a = a2 - a1; + if (a <= -180.0) + a += 360.0; + else if (a > 180.0) + a -= 360.0; + return a; +} + +static void +translateBounds ( + miArcFacePtr b, + int x, + int y, + double fx, + double fy) +{ + fx += x; + fy += y; + b->clock.x -= fx; + b->clock.y -= fy; + b->center.x -= fx; + b->center.y -= fy; + b->counterClock.x -= fx; + b->counterClock.y -= fy; +} + +static void +miArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft, + miArcFacePtr pRight, int xOrgLeft, int yOrgLeft, + double xFtransLeft, double yFtransLeft, + int xOrgRight, int yOrgRight, + double xFtransRight, double yFtransRight) +{ + SppPointRec center, corner, otherCorner; + SppPointRec poly[5], e; + SppPointPtr pArcPts; + int cpt; + SppArcRec arc; + miArcFaceRec Right, Left; + int polyLen = 0; + int xOrg, yOrg; + double xFtrans, yFtrans; + double a; + double ae, ac2, ec2, bc2, de; + double width; + + xOrg = (xOrgRight + xOrgLeft) / 2; + yOrg = (yOrgRight + yOrgLeft) / 2; + xFtrans = (xFtransLeft + xFtransRight) / 2; + yFtrans = (yFtransLeft + yFtransRight) / 2; + Right = *pRight; + translateBounds (&Right, xOrg - xOrgRight, yOrg - yOrgRight, + xFtrans - xFtransRight, yFtrans - yFtransRight); + Left = *pLeft; + translateBounds (&Left, xOrg - xOrgLeft, yOrg - yOrgLeft, + xFtrans - xFtransLeft, yFtrans - yFtransLeft); + pRight = &Right; + pLeft = &Left; + + if (pRight->clock.x == pLeft->counterClock.x && + pRight->clock.y == pLeft->counterClock.y) + return; + center = pRight->center; + if (0 <= (a = angleBetween (center, pRight->clock, pLeft->counterClock)) + && a <= 180.0) + { + corner = pRight->clock; + otherCorner = pLeft->counterClock; + } else { + a = angleBetween (center, pLeft->clock, pRight->counterClock); + corner = pLeft->clock; + otherCorner = pRight->counterClock; + } + switch (pGC->joinStyle) { + case JoinRound: + width = (pGC->lineWidth ? (double)pGC->lineWidth : (double)1); + + arc.x = center.x - width/2; + arc.y = center.y - width/2; + arc.width = width; + arc.height = width; + arc.angle1 = -miDatan2 (corner.y - center.y, corner.x - center.x); + arc.angle2 = a; + pArcPts = (SppPointPtr) xalloc (3 * sizeof (SppPointRec)); + if (!pArcPts) + return; + pArcPts[0].x = otherCorner.x; + pArcPts[0].y = otherCorner.y; + pArcPts[1].x = center.x; + pArcPts[1].y = center.y; + pArcPts[2].x = corner.x; + pArcPts[2].y = corner.y; + if( (cpt = miGetArcPts(&arc, 3, &pArcPts)) ) + { + /* by drawing with miFillSppPoly and setting the endpoints of the arc + * to be the corners, we assure that the cap will meet up with the + * rest of the line */ + miFillSppPoly(pDraw, pGC, cpt, pArcPts, xOrg, yOrg, xFtrans, yFtrans); + } + xfree(pArcPts); + return; + case JoinMiter: + /* + * don't miter arcs with less than 11 degrees between them + */ + if (a < 169.0) { + poly[0] = corner; + poly[1] = center; + poly[2] = otherCorner; + bc2 = (corner.x - otherCorner.x) * (corner.x - otherCorner.x) + + (corner.y - otherCorner.y) * (corner.y - otherCorner.y); + ec2 = bc2 / 4; + ac2 = (corner.x - center.x) * (corner.x - center.x) + + (corner.y - center.y) * (corner.y - center.y); + ae = sqrt (ac2 - ec2); + de = ec2 / ae; + e.x = (corner.x + otherCorner.x) / 2; + e.y = (corner.y + otherCorner.y) / 2; + poly[3].x = e.x + de * (e.x - center.x) / ae; + poly[3].y = e.y + de * (e.y - center.y) / ae; + poly[4] = corner; + polyLen = 5; + break; + } + case JoinBevel: + poly[0] = corner; + poly[1] = center; + poly[2] = otherCorner; + poly[3] = corner; + polyLen = 4; + break; + } + miFillSppPoly (pDraw, pGC, polyLen, poly, xOrg, yOrg, xFtrans, yFtrans); +} + +/*ARGSUSED*/ +static void +miArcCap ( + DrawablePtr pDraw, + GCPtr pGC, + miArcFacePtr pFace, + int end, + int xOrg, + int yOrg, + double xFtrans, + double yFtrans) +{ + SppPointRec corner, otherCorner, center, endPoint, poly[5]; + + corner = pFace->clock; + otherCorner = pFace->counterClock; + center = pFace->center; + switch (pGC->capStyle) { + case CapProjecting: + poly[0].x = otherCorner.x; + poly[0].y = otherCorner.y; + poly[1].x = corner.x; + poly[1].y = corner.y; + poly[2].x = corner.x - + (center.y - corner.y); + poly[2].y = corner.y + + (center.x - corner.x); + poly[3].x = otherCorner.x - + (otherCorner.y - center.y); + poly[3].y = otherCorner.y + + (otherCorner.x - center.x); + poly[4].x = otherCorner.x; + poly[4].y = otherCorner.y; + miFillSppPoly (pDraw, pGC, 5, poly, xOrg, yOrg, xFtrans, yFtrans); + break; + case CapRound: + /* + * miRoundCap just needs these to be unequal. + */ + endPoint = center; + endPoint.x = endPoint.x + 100; + miRoundCap (pDraw, pGC, center, endPoint, corner, otherCorner, 0, + -xOrg, -yOrg, xFtrans, yFtrans); + break; + } +} + +/* MIROUNDCAP -- a private helper function + * Put Rounded cap on end. pCenter is the center of this end of the line + * pEnd is the center of the other end of the line. pCorner is one of the + * two corners at this end of the line. + * NOTE: pOtherCorner must be counter-clockwise from pCorner. + */ +/*ARGSUSED*/ +static void +miRoundCap( + DrawablePtr pDraw, + GCPtr pGC, + SppPointRec pCenter, + SppPointRec pEnd, + SppPointRec pCorner, + SppPointRec pOtherCorner, + int fLineEnd, + int xOrg, + int yOrg, + double xFtrans, + double yFtrans) +{ + int cpt; + double width; + SppArcRec arc; + SppPointPtr pArcPts; + + width = (pGC->lineWidth ? (double)pGC->lineWidth : (double)1); + + arc.x = pCenter.x - width/2; + arc.y = pCenter.y - width/2; + arc.width = width; + arc.height = width; + arc.angle1 = -miDatan2 (pCorner.y - pCenter.y, pCorner.x - pCenter.x); + if(PTISEQUAL(pCenter, pEnd)) + arc.angle2 = - 180.0; + else { + arc.angle2 = -miDatan2 (pOtherCorner.y - pCenter.y, pOtherCorner.x - pCenter.x) - arc.angle1; + if (arc.angle2 < 0) + arc.angle2 += 360.0; + } + pArcPts = (SppPointPtr) NULL; + if( (cpt = miGetArcPts(&arc, 0, &pArcPts)) ) + { + /* by drawing with miFillSppPoly and setting the endpoints of the arc + * to be the corners, we assure that the cap will meet up with the + * rest of the line */ + miFillSppPoly(pDraw, pGC, cpt, pArcPts, -xOrg, -yOrg, xFtrans, yFtrans); + } + xfree(pArcPts); +} + +/* + * To avoid inaccuracy at the cardinal points, use trig functions + * which are exact for those angles + */ + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 +#endif + +# define Dsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0))) +# define Dcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0))) +# define mod(a,b) ((a) >= 0 ? (a) % (b) : (b) - (-a) % (b)) + +static double +miDcos (double a) +{ + int i; + + if (floor (a/90) == a/90) { + i = (int) (a/90.0); + switch (mod (i, 4)) { + case 0: return 1; + case 1: return 0; + case 2: return -1; + case 3: return 0; + } + } + return cos (a * M_PI / 180.0); +} + +static double +miDsin (double a) +{ + int i; + + if (floor (a/90) == a/90) { + i = (int) (a/90.0); + switch (mod (i, 4)) { + case 0: return 0; + case 1: return 1; + case 2: return 0; + case 3: return -1; + } + } + return sin (a * M_PI / 180.0); +} + +static double +miDasin (double v) +{ + if (v == 0) + return 0.0; + if (v == 1.0) + return 90.0; + if (v == -1.0) + return -90.0; + return asin(v) * (180.0 / M_PI); +} + +static double +miDatan2 (double dy, double dx) +{ + if (dy == 0) { + if (dx >= 0) + return 0.0; + return 180.0; + } else if (dx == 0) { + if (dy > 0) + return 90.0; + return -90.0; + } else if (Fabs (dy) == Fabs (dx)) { + if (dy > 0) { + if (dx > 0) + return 45.0; + return 135.0; + } else { + if (dx > 0) + return 315.0; + return 225.0; + } + } else { + return atan2 (dy, dx) * (180.0 / M_PI); + } +} + +/* MIGETARCPTS -- Converts an arc into a set of line segments -- a helper + * routine for filled arc and line (round cap) code. + * Returns the number of points in the arc. Note that it takes a pointer + * to a pointer to where it should put the points and an index (cpt). + * This procedure allocates the space necessary to fit the arc points. + * Sometimes it's convenient for those points to be at the end of an existing + * array. (For example, if we want to leave a spare point to make sectors + * instead of segments.) So we pass in the xalloc()ed chunk that contains the + * array and an index saying where we should start stashing the points. + * If there isn't an array already, we just pass in a null pointer and + * count on xrealloc() to handle the null pointer correctly. + */ +static int +miGetArcPts( + SppArcPtr parc, /* points to an arc */ + int cpt, /* number of points already in arc list */ + SppPointPtr *ppPts) /* pointer to pointer to arc-list -- modified */ +{ + double st, /* Start Theta, start angle */ + et, /* End Theta, offset from start theta */ + dt, /* Delta Theta, angle to sweep ellipse */ + cdt, /* Cos Delta Theta, actually 2 cos(dt) */ + x0, y0, /* the recurrence formula needs two points to start */ + x1, y1, + x2, y2, /* this will be the new point generated */ + xc, yc; /* the center point */ + int count, i; + SppPointPtr poly; + + /* The spec says that positive angles indicate counterclockwise motion. + * Given our coordinate system (with 0,0 in the upper left corner), + * the screen appears flipped in Y. The easiest fix is to negate the + * angles given */ + + st = - parc->angle1; + + et = - parc->angle2; + + /* Try to get a delta theta that is within 1/2 pixel. Then adjust it + * so that it divides evenly into the total. + * I'm just using cdt 'cause I'm lazy. + */ + cdt = parc->width; + if (parc->height > cdt) + cdt = parc->height; + cdt /= 2.0; + if(cdt <= 0) + return 0; + if (cdt < 1.0) + cdt = 1.0; + dt = miDasin ( 1.0 / cdt ); /* minimum step necessary */ + count = et/dt; + count = abs(count) + 1; + dt = et/count; + count++; + + cdt = 2 * miDcos(dt); + if (!(poly = (SppPointPtr) xrealloc((pointer)*ppPts, + (cpt + count) * sizeof(SppPointRec)))) + return(0); + *ppPts = poly; + + xc = parc->width/2.0; /* store half width and half height */ + yc = parc->height/2.0; + + x0 = xc * miDcos(st); + y0 = yc * miDsin(st); + x1 = xc * miDcos(st + dt); + y1 = yc * miDsin(st + dt); + xc += parc->x; /* by adding initial point, these become */ + yc += parc->y; /* the center point */ + + poly[cpt].x = (xc + x0); + poly[cpt].y = (yc + y0); + poly[cpt + 1].x = (xc + x1); + poly[cpt + 1].y = (yc + y1); + + for(i = 2; i < count; i++) + { + x2 = cdt * x1 - x0; + y2 = cdt * y1 - y0; + + poly[cpt + i].x = (xc + x2); + poly[cpt + i].y = (yc + y2); + + x0 = x1; y0 = y1; + x1 = x2; y1 = y2; + } + /* adjust the last point */ + if (abs(parc->angle2) >= 360.0) + poly[cpt +i -1] = poly[0]; + else { + poly[cpt +i -1].x = (miDcos(st + et) * parc->width/2.0 + xc); + poly[cpt +i -1].y = (miDsin(st + et) * parc->height/2.0 + yc); + } + + return(count); +} + +struct arcData { + double x0, y0, x1, y1; + int selfJoin; +}; + +# define ADD_REALLOC_STEP 20 + +static void +addCap ( + miArcCapPtr *capsp, + int *ncapsp, + int *sizep, + int end, + int arcIndex) +{ + int newsize; + miArcCapPtr cap; + + if (*ncapsp == *sizep) + { + newsize = *sizep + ADD_REALLOC_STEP; + cap = (miArcCapPtr) xrealloc (*capsp, + newsize * sizeof (**capsp)); + if (!cap) + return; + *sizep = newsize; + *capsp = cap; + } + cap = &(*capsp)[*ncapsp]; + cap->end = end; + cap->arcIndex = arcIndex; + ++*ncapsp; +} + +static void +addJoin ( + miArcJoinPtr *joinsp, + int *njoinsp, + int *sizep, + int end0, + int index0, + int phase0, + int end1, + int index1, + int phase1) +{ + int newsize; + miArcJoinPtr join; + + if (*njoinsp == *sizep) + { + newsize = *sizep + ADD_REALLOC_STEP; + join = (miArcJoinPtr) xrealloc (*joinsp, + newsize * sizeof (**joinsp)); + if (!join) + return; + *sizep = newsize; + *joinsp = join; + } + join = &(*joinsp)[*njoinsp]; + join->end0 = end0; + join->arcIndex0 = index0; + join->phase0 = phase0; + join->end1 = end1; + join->arcIndex1 = index1; + join->phase1 = phase1; + ++*njoinsp; +} + +static miArcDataPtr +addArc ( + miArcDataPtr *arcsp, + int *narcsp, + int *sizep, + xArc *xarc) +{ + int newsize; + miArcDataPtr arc; + + if (*narcsp == *sizep) + { + newsize = *sizep + ADD_REALLOC_STEP; + arc = (miArcDataPtr) xrealloc (*arcsp, + newsize * sizeof (**arcsp)); + if (!arc) + return (miArcDataPtr)NULL; + *sizep = newsize; + *arcsp = arc; + } + arc = &(*arcsp)[*narcsp]; + arc->arc = *xarc; + ++*narcsp; + return arc; +} + +static void +miFreeArcs( + miPolyArcPtr arcs, + GCPtr pGC) +{ + int iphase; + + for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0); + iphase >= 0; + iphase--) + { + if (arcs[iphase].narcs > 0) + xfree(arcs[iphase].arcs); + if (arcs[iphase].njoins > 0) + xfree(arcs[iphase].joins); + if (arcs[iphase].ncaps > 0) + xfree(arcs[iphase].caps); + } + xfree(arcs); +} + +/* + * map angles to radial distance. This only deals with the first quadrant + */ + +/* + * a polygonal approximation to the arc for computing arc lengths + */ + +# define DASH_MAP_SIZE 91 + +# define dashIndexToAngle(di) ((((double) (di)) * 90.0) / ((double) DASH_MAP_SIZE - 1)) +# define xAngleToDashIndex(xa) ((((long) (xa)) * (DASH_MAP_SIZE - 1)) / (90 * 64)) +# define dashIndexToXAngle(di) ((((long) (di)) * (90 * 64)) / (DASH_MAP_SIZE - 1)) +# define dashXAngleStep (((double) (90 * 64)) / ((double) (DASH_MAP_SIZE - 1))) + +typedef struct { + double map[DASH_MAP_SIZE]; +} dashMap; + +static int computeAngleFromPath(int startAngle, int endAngle, dashMap *map, + int *lenp, int backwards); + +static void +computeDashMap ( + xArc *arcp, + dashMap *map) +{ + int di; + double a, x, y, prevx = 0.0, prevy = 0.0, dist; + + for (di = 0; di < DASH_MAP_SIZE; di++) { + a = dashIndexToAngle (di); + x = ((double) arcp->width / 2.0) * miDcos (a); + y = ((double) arcp->height / 2.0) * miDsin (a); + if (di == 0) { + map->map[di] = 0.0; + } else { + dist = hypot (x - prevx, y - prevy); + map->map[di] = map->map[di - 1] + dist; + } + prevx = x; + prevy = y; + } +} + +typedef enum {HORIZONTAL, VERTICAL, OTHER} arcTypes; + +/* this routine is a bit gory */ + +static miPolyArcPtr +miComputeArcs ( + xArc *parcs, + int narcs, + GCPtr pGC) +{ + int isDashed, isDoubleDash; + int dashOffset; + miPolyArcPtr arcs; + int start, i, j, k = 0, nexti, nextk = 0; + int joinSize[2]; + int capSize[2]; + int arcSize[2]; + int angle2; + double a0, a1; + struct arcData *data; + miArcDataPtr arc; + xArc xarc; + int iphase, prevphase = 0, joinphase; + int arcsJoin; + int selfJoin; + + int iDash = 0, dashRemaining; + int iDashStart = 0, dashRemainingStart = 0, iphaseStart; + int startAngle, spanAngle, endAngle, backwards = 0; + int prevDashAngle, dashAngle; + dashMap map; + + isDashed = !(pGC->lineStyle == LineSolid); + isDoubleDash = (pGC->lineStyle == LineDoubleDash); + dashOffset = pGC->dashOffset; + + data = (struct arcData *) ALLOCATE_LOCAL (narcs * sizeof (struct arcData)); + if (!data) + return (miPolyArcPtr)NULL; + arcs = (miPolyArcPtr) xalloc (sizeof (*arcs) * (isDoubleDash ? 2 : 1)); + if (!arcs) + { + DEALLOCATE_LOCAL(data); + return (miPolyArcPtr)NULL; + } + for (i = 0; i < narcs; i++) { + a0 = todeg (parcs[i].angle1); + angle2 = parcs[i].angle2; + if (angle2 > FULLCIRCLE) + angle2 = FULLCIRCLE; + else if (angle2 < -FULLCIRCLE) + angle2 = -FULLCIRCLE; + data[i].selfJoin = angle2 == FULLCIRCLE || angle2 == -FULLCIRCLE; + a1 = todeg (parcs[i].angle1 + angle2); + data[i].x0 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a0)); + data[i].y0 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a0)); + data[i].x1 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a1)); + data[i].y1 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a1)); + } + + for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) { + arcs[iphase].njoins = 0; + arcs[iphase].joins = 0; + joinSize[iphase] = 0; + + arcs[iphase].ncaps = 0; + arcs[iphase].caps = 0; + capSize[iphase] = 0; + + arcs[iphase].narcs = 0; + arcs[iphase].arcs = 0; + arcSize[iphase] = 0; + } + + iphase = 0; + if (isDashed) { + iDash = 0; + dashRemaining = pGC->dash[0]; + while (dashOffset > 0) { + if (dashOffset >= dashRemaining) { + dashOffset -= dashRemaining; + iphase = iphase ? 0 : 1; + iDash++; + if (iDash == pGC->numInDashList) + iDash = 0; + dashRemaining = pGC->dash[iDash]; + } else { + dashRemaining -= dashOffset; + dashOffset = 0; + } + } + iDashStart = iDash; + dashRemainingStart = dashRemaining; + } + iphaseStart = iphase; + + for (i = narcs - 1; i >= 0; i--) { + j = i + 1; + if (j == narcs) + j = 0; + if (data[i].selfJoin || i == j || + (UNEQUAL (data[i].x1, data[j].x0) || + UNEQUAL (data[i].y1, data[j].y0))) + { + if (iphase == 0 || isDoubleDash) + addCap (&arcs[iphase].caps, &arcs[iphase].ncaps, + &capSize[iphase], RIGHT_END, 0); + break; + } + } + start = i + 1; + if (start == narcs) + start = 0; + i = start; + for (;;) { + j = i + 1; + if (j == narcs) + j = 0; + nexti = i+1; + if (nexti == narcs) + nexti = 0; + if (isDashed) { + /* + ** deal with dashed arcs. Use special rules for certain 0 area arcs. + ** Presumably, the other 0 area arcs still aren't done right. + */ + arcTypes arcType = OTHER; + CARD16 thisLength; + + if (parcs[i].height == 0 + && (parcs[i].angle1 % FULLCIRCLE) == 0x2d00 + && parcs[i].angle2 == 0x2d00) + arcType = HORIZONTAL; + else if (parcs[i].width == 0 + && (parcs[i].angle1 % FULLCIRCLE) == 0x1680 + && parcs[i].angle2 == 0x2d00) + arcType = VERTICAL; + if (arcType == OTHER) { + /* + * precompute an approximation map + */ + computeDashMap (&parcs[i], &map); + /* + * compute each individual dash segment using the path + * length function + */ + startAngle = parcs[i].angle1; + spanAngle = parcs[i].angle2; + if (spanAngle > FULLCIRCLE) + spanAngle = FULLCIRCLE; + else if (spanAngle < -FULLCIRCLE) + spanAngle = -FULLCIRCLE; + if (startAngle < 0) + startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE; + if (startAngle >= FULLCIRCLE) + startAngle = startAngle % FULLCIRCLE; + endAngle = startAngle + spanAngle; + backwards = spanAngle < 0; + } else { + xarc = parcs[i]; + if (arcType == VERTICAL) { + xarc.angle1 = 0x1680; + startAngle = parcs[i].y; + endAngle = startAngle + parcs[i].height; + } else { + xarc.angle1 = 0x2d00; + startAngle = parcs[i].x; + endAngle = startAngle + parcs[i].width; + } + } + dashAngle = startAngle; + selfJoin = data[i].selfJoin && + (iphase == 0 || isDoubleDash); + /* + * add dashed arcs to each bucket + */ + arc = 0; + while (dashAngle != endAngle) { + prevDashAngle = dashAngle; + if (arcType == OTHER) { + dashAngle = computeAngleFromPath (prevDashAngle, endAngle, + &map, &dashRemaining, backwards); + /* avoid troubles with huge arcs and small dashes */ + if (dashAngle == prevDashAngle) { + if (backwards) + dashAngle--; + else + dashAngle++; + } + } else { + thisLength = (dashAngle + dashRemaining <= endAngle) ? + dashRemaining : endAngle - dashAngle; + if (arcType == VERTICAL) { + xarc.y = dashAngle; + xarc.height = thisLength; + } else { + xarc.x = dashAngle; + xarc.width = thisLength; + } + dashAngle += thisLength; + dashRemaining -= thisLength; + } + if (iphase == 0 || isDoubleDash) { + if (arcType == OTHER) { + xarc = parcs[i]; + spanAngle = prevDashAngle; + if (spanAngle < 0) + spanAngle = FULLCIRCLE - (-spanAngle) % FULLCIRCLE; + if (spanAngle >= FULLCIRCLE) + spanAngle = spanAngle % FULLCIRCLE; + xarc.angle1 = spanAngle; + spanAngle = dashAngle - prevDashAngle; + if (backwards) { + if (dashAngle > prevDashAngle) + spanAngle = - FULLCIRCLE + spanAngle; + } else { + if (dashAngle < prevDashAngle) + spanAngle = FULLCIRCLE + spanAngle; + } + if (spanAngle > FULLCIRCLE) + spanAngle = FULLCIRCLE; + if (spanAngle < -FULLCIRCLE) + spanAngle = -FULLCIRCLE; + xarc.angle2 = spanAngle; + } + arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs, + &arcSize[iphase], &xarc); + if (!arc) + goto arcfail; + /* + * cap each end of an on/off dash + */ + if (!isDoubleDash) { + if (prevDashAngle != startAngle) { + addCap (&arcs[iphase].caps, + &arcs[iphase].ncaps, + &capSize[iphase], RIGHT_END, + arc - arcs[iphase].arcs); + + } + if (dashAngle != endAngle) { + addCap (&arcs[iphase].caps, + &arcs[iphase].ncaps, + &capSize[iphase], LEFT_END, + arc - arcs[iphase].arcs); + } + } + arc->cap = arcs[iphase].ncaps; + arc->join = arcs[iphase].njoins; + arc->render = 0; + arc->selfJoin = 0; + if (dashAngle == endAngle) + arc->selfJoin = selfJoin; + } + prevphase = iphase; + if (dashRemaining <= 0) { + ++iDash; + if (iDash == pGC->numInDashList) + iDash = 0; + iphase = iphase ? 0:1; + dashRemaining = pGC->dash[iDash]; + } + } + /* + * make sure a place exists for the position data when + * drawing a zero-length arc + */ + if (startAngle == endAngle) { + prevphase = iphase; + if (!isDoubleDash && iphase == 1) + prevphase = 0; + arc = addArc (&arcs[prevphase].arcs, &arcs[prevphase].narcs, + &arcSize[prevphase], &parcs[i]); + if (!arc) + goto arcfail; + arc->join = arcs[prevphase].njoins; + arc->cap = arcs[prevphase].ncaps; + arc->selfJoin = data[i].selfJoin; + } + } else { + arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs, + &arcSize[iphase], &parcs[i]); + if (!arc) + goto arcfail; + arc->join = arcs[iphase].njoins; + arc->cap = arcs[iphase].ncaps; + arc->selfJoin = data[i].selfJoin; + prevphase = iphase; + } + if (prevphase == 0 || isDoubleDash) + k = arcs[prevphase].narcs - 1; + if (iphase == 0 || isDoubleDash) + nextk = arcs[iphase].narcs; + if (nexti == start) { + nextk = 0; + if (isDashed) { + iDash = iDashStart; + iphase = iphaseStart; + dashRemaining = dashRemainingStart; + } + } + arcsJoin = narcs > 1 && i != j && + ISEQUAL (data[i].x1, data[j].x0) && + ISEQUAL (data[i].y1, data[j].y0) && + !data[i].selfJoin && !data[j].selfJoin; + if (arc) + { + if (arcsJoin) + arc->render = 0; + else + arc->render = 1; + } + if (arcsJoin && + (prevphase == 0 || isDoubleDash) && + (iphase == 0 || isDoubleDash)) + { + joinphase = iphase; + if (isDoubleDash) { + if (nexti == start) + joinphase = iphaseStart; + /* + * if the join is right at the dash, + * draw the join in foreground + * This is because the foreground + * arcs are computed second, the results + * of which are needed to draw the join + */ + if (joinphase != prevphase) + joinphase = 0; + } + if (joinphase == 0 || isDoubleDash) { + addJoin (&arcs[joinphase].joins, + &arcs[joinphase].njoins, + &joinSize[joinphase], + LEFT_END, k, prevphase, + RIGHT_END, nextk, iphase); + arc->join = arcs[prevphase].njoins; + } + } else { + /* + * cap the left end of this arc + * unless it joins itself + */ + if ((prevphase == 0 || isDoubleDash) && + !arc->selfJoin) + { + addCap (&arcs[prevphase].caps, &arcs[prevphase].ncaps, + &capSize[prevphase], LEFT_END, k); + arc->cap = arcs[prevphase].ncaps; + } + if (isDashed && !arcsJoin) { + iDash = iDashStart; + iphase = iphaseStart; + dashRemaining = dashRemainingStart; + } + nextk = arcs[iphase].narcs; + if (nexti == start) { + nextk = 0; + iDash = iDashStart; + iphase = iphaseStart; + dashRemaining = dashRemainingStart; + } + /* + * cap the right end of the next arc. If the + * next arc is actually the first arc, only + * cap it if it joins with this arc. This + * case will occur when the final dash segment + * of an on/off dash is off. Of course, this + * cap will be drawn at a strange time, but that + * hardly matters... + */ + if ((iphase == 0 || isDoubleDash) && + (nexti != start || (arcsJoin && isDashed))) + addCap (&arcs[iphase].caps, &arcs[iphase].ncaps, + &capSize[iphase], RIGHT_END, nextk); + } + i = nexti; + if (i == start) + break; + } + /* + * make sure the last section is rendered + */ + for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) + if (arcs[iphase].narcs > 0) { + arcs[iphase].arcs[arcs[iphase].narcs-1].render = 1; + arcs[iphase].arcs[arcs[iphase].narcs-1].join = + arcs[iphase].njoins; + arcs[iphase].arcs[arcs[iphase].narcs-1].cap = + arcs[iphase].ncaps; + } + DEALLOCATE_LOCAL(data); + return arcs; +arcfail: + miFreeArcs(arcs, pGC); + DEALLOCATE_LOCAL(data); + return (miPolyArcPtr)NULL; +} + +static double +angleToLength ( + int angle, + dashMap *map) +{ + double len, excesslen, sidelen = map->map[DASH_MAP_SIZE - 1], totallen; + int di; + int excess; + Bool oddSide = FALSE; + + totallen = 0; + if (angle >= 0) { + while (angle >= 90 * 64) { + angle -= 90 * 64; + totallen += sidelen; + oddSide = !oddSide; + } + } else { + while (angle < 0) { + angle += 90 * 64; + totallen -= sidelen; + oddSide = !oddSide; + } + } + if (oddSide) + angle = 90 * 64 - angle; + + di = xAngleToDashIndex (angle); + excess = angle - dashIndexToXAngle (di); + + len = map->map[di]; + /* + * linearly interpolate between this point and the next + */ + if (excess > 0) { + excesslen = (map->map[di + 1] - map->map[di]) * + ((double) excess) / dashXAngleStep; + len += excesslen; + } + if (oddSide) + totallen += (sidelen - len); + else + totallen += len; + return totallen; +} + +/* + * len is along the arc, but may be more than one rotation + */ + +static int +lengthToAngle ( + double len, + dashMap *map) +{ + double sidelen = map->map[DASH_MAP_SIZE - 1]; + int angle, angleexcess; + Bool oddSide = FALSE; + int a0, a1, a; + + angle = 0; + /* + * step around the ellipse, subtracting sidelens and + * adding 90 degrees. oddSide will tell if the + * map should be interpolated in reverse + */ + if (len >= 0) { + if (sidelen == 0) + return 2 * FULLCIRCLE; /* infinity */ + while (len >= sidelen) { + angle += 90 * 64; + len -= sidelen; + oddSide = !oddSide; + } + } else { + if (sidelen == 0) + return -2 * FULLCIRCLE; /* infinity */ + while (len < 0) { + angle -= 90 * 64; + len += sidelen; + oddSide = !oddSide; + } + } + if (oddSide) + len = sidelen - len; + a0 = 0; + a1 = DASH_MAP_SIZE - 1; + /* + * binary search for the closest pre-computed length + */ + while (a1 - a0 > 1) { + a = (a0 + a1) / 2; + if (len > map->map[a]) + a0 = a; + else + a1 = a; + } + angleexcess = dashIndexToXAngle (a0); + /* + * linearly interpolate to the next point + */ + angleexcess += (len - map->map[a0]) / + (map->map[a0+1] - map->map[a0]) * dashXAngleStep; + if (oddSide) + angle += (90 * 64) - angleexcess; + else + angle += angleexcess; + return angle; +} + +/* + * compute the angle of an ellipse which cooresponds to + * the given path length. Note that the correct solution + * to this problem is an eliptic integral, we'll punt and + * approximate (it's only for dashes anyway). This + * approximation uses a polygon. + * + * The remaining portion of len is stored in *lenp - + * this will be negative if the arc extends beyond + * len and positive if len extends beyond the arc. + */ + +static int +computeAngleFromPath ( + int startAngle, + int endAngle, /* normalized absolute angles in *64 degrees */ + dashMap *map, + int *lenp, + int backwards) +{ + int a0, a1, a; + double len0; + int len; + + a0 = startAngle; + a1 = endAngle; + len = *lenp; + if (backwards) { + /* + * flip the problem around to always be + * forwards + */ + a0 = FULLCIRCLE - a0; + a1 = FULLCIRCLE - a1; + } + if (a1 < a0) + a1 += FULLCIRCLE; + len0 = angleToLength (a0, map); + a = lengthToAngle (len0 + len, map); + if (a > a1) { + a = a1; + len -= angleToLength (a1, map) - len0; + } else + len = 0; + if (backwards) + a = FULLCIRCLE - a; + *lenp = len; + return a; +} + +/* + * scan convert wide arcs. + */ + +/* + * draw zero width/height arcs + */ + +static void +drawZeroArc ( + DrawablePtr pDraw, + GCPtr pGC, + xArc *tarc, + int lw, + miArcFacePtr left, + miArcFacePtr right) +{ + double x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0, w, h, x, y; + double xmax, ymax, xmin, ymin; + int a0, a1; + double a, startAngle, endAngle; + double l, lx, ly; + + l = lw / 2.0; + a0 = tarc->angle1; + a1 = tarc->angle2; + if (a1 > FULLCIRCLE) + a1 = FULLCIRCLE; + else if (a1 < -FULLCIRCLE) + a1 = -FULLCIRCLE; + w = (double)tarc->width / 2.0; + h = (double)tarc->height / 2.0; + /* + * play in X coordinates right away + */ + startAngle = - ((double) a0 / 64.0); + endAngle = - ((double) (a0 + a1) / 64.0); + + xmax = -w; + xmin = w; + ymax = -h; + ymin = h; + a = startAngle; + for (;;) + { + x = w * miDcos(a); + y = h * miDsin(a); + if (a == startAngle) + { + x0 = x; + y0 = y; + } + if (a == endAngle) + { + x1 = x; + y1 = y; + } + if (x > xmax) + xmax = x; + if (x < xmin) + xmin = x; + if (y > ymax) + ymax = y; + if (y < ymin) + ymin = y; + if (a == endAngle) + break; + if (a1 < 0) /* clockwise */ + { + if (floor (a / 90.0) == floor (endAngle / 90.0)) + a = endAngle; + else + a = 90 * (floor (a/90.0) + 1); + } + else + { + if (ceil (a / 90.0) == ceil (endAngle / 90.0)) + a = endAngle; + else + a = 90 * (ceil (a/90.0) - 1); + } + } + lx = ly = l; + if ((x1 - x0) + (y1 - y0) < 0) + lx = ly = -l; + if (h) + { + ly = 0.0; + lx = -lx; + } + else + lx = 0.0; + if (right) + { + right->center.x = x0; + right->center.y = y0; + right->clock.x = x0 - lx; + right->clock.y = y0 - ly; + right->counterClock.x = x0 + lx; + right->counterClock.y = y0 + ly; + } + if (left) + { + left->center.x = x1; + left->center.y = y1; + left->clock.x = x1 + lx; + left->clock.y = y1 + ly; + left->counterClock.x = x1 - lx; + left->counterClock.y = y1 - ly; + } + + x0 = xmin; + x1 = xmax; + y0 = ymin; + y1 = ymax; + if (ymin != y1) { + xmin = -l; + xmax = l; + } else { + ymin = -l; + ymax = l; + } + if (xmax != xmin && ymax != ymin) { + int minx, maxx, miny, maxy; + xRectangle rect; + + minx = ICEIL (xmin + w) + tarc->x; + maxx = ICEIL (xmax + w) + tarc->x; + miny = ICEIL (ymin + h) + tarc->y; + maxy = ICEIL (ymax + h) + tarc->y; + rect.x = minx; + rect.y = miny; + rect.width = maxx - minx; + rect.height = maxy - miny; + (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect); + } +} + +/* + * this computes the ellipse y value associated with the + * bottom of the tail. + */ + +static void +tailEllipseY ( + struct arc_def *def, + struct accelerators *acc) +{ + double t; + + acc->tail_y = 0.0; + if (def->w == def->h) + return; + t = def->l * def->w; + if (def->w > def->h) { + if (t < acc->h2) + return; + } else { + if (t > acc->h2) + return; + } + t = 2.0 * def->h * t; + t = (CUBED_ROOT_4 * acc->h2 - cbrt(t * t)) / acc->h2mw2; + if (t > 0.0) + acc->tail_y = def->h / CUBED_ROOT_2 * sqrt(t); +} + +/* + * inverse functions -- compute edge coordinates + * from the ellipse + */ + +static double +outerXfromXY ( + double x, + double y, + struct arc_def *def, + struct accelerators *acc) +{ + return x + (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); +} + +static double +outerYfromXY ( + double x, + double y, + struct arc_def *def, + struct accelerators *acc) +{ + return y + (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); +} + +static double +innerXfromXY ( + double x, + double y, + struct arc_def *def, + struct accelerators *acc) +{ + return x - (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); +} + +static double +innerYfromXY ( + double x, + double y, + struct arc_def *def, + struct accelerators *acc) +{ + return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); +} + +static double +innerYfromY ( + double y, + struct arc_def *def, + struct accelerators *acc) +{ + double x; + + x = (def->w / def->h) * sqrt (acc->h2 - y*y); + + return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); +} + +static void +computeLine ( + double x1, + double y1, + double x2, + double y2, + struct line *line) +{ + if (y1 == y2) + line->valid = 0; + else { + line->m = (x1 - x2) / (y1 - y2); + line->b = x1 - y1 * line->m; + line->valid = 1; + } +} + +/* + * compute various accelerators for an ellipse. These + * are simply values that are used repeatedly in + * the computations + */ + +static void +computeAcc ( + xArc *tarc, + int lw, + struct arc_def *def, + struct accelerators *acc) +{ + def->w = ((double) tarc->width) / 2.0; + def->h = ((double) tarc->height) / 2.0; + def->l = ((double) lw) / 2.0; + acc->h2 = def->h * def->h; + acc->w2 = def->w * def->w; + acc->h4 = acc->h2 * acc->h2; + acc->w4 = acc->w2 * acc->w2; + acc->h2l = acc->h2 * def->l; + acc->w2l = acc->w2 * def->l; + acc->h2mw2 = acc->h2 - acc->w2; + acc->fromIntX = (tarc->width & 1) ? 0.5 : 0.0; + acc->fromIntY = (tarc->height & 1) ? 0.5 : 0.0; + acc->xorg = tarc->x + (tarc->width >> 1); + acc->yorgu = tarc->y + (tarc->height >> 1); + acc->yorgl = acc->yorgu + (tarc->height & 1); + tailEllipseY (def, acc); +} + +/* + * compute y value bounds of various portions of the arc, + * the outer edge, the ellipse and the inner edge. + */ + +static void +computeBound ( + struct arc_def *def, + struct arc_bound *bound, + struct accelerators *acc, + miArcFacePtr right, + miArcFacePtr left) +{ + double t; + double innerTaily; + double tail_y; + struct bound innerx, outerx; + struct bound ellipsex; + + bound->ellipse.min = Dsin (def->a0) * def->h; + bound->ellipse.max = Dsin (def->a1) * def->h; + if (def->a0 == 45 && def->w == def->h) + ellipsex.min = bound->ellipse.min; + else + ellipsex.min = Dcos (def->a0) * def->w; + if (def->a1 == 45 && def->w == def->h) + ellipsex.max = bound->ellipse.max; + else + ellipsex.max = Dcos (def->a1) * def->w; + bound->outer.min = outerYfromXY (ellipsex.min, bound->ellipse.min, def, acc); + bound->outer.max = outerYfromXY (ellipsex.max, bound->ellipse.max, def, acc); + bound->inner.min = innerYfromXY (ellipsex.min, bound->ellipse.min, def, acc); + bound->inner.max = innerYfromXY (ellipsex.max, bound->ellipse.max, def, acc); + + outerx.min = outerXfromXY (ellipsex.min, bound->ellipse.min, def, acc); + outerx.max = outerXfromXY (ellipsex.max, bound->ellipse.max, def, acc); + innerx.min = innerXfromXY (ellipsex.min, bound->ellipse.min, def, acc); + innerx.max = innerXfromXY (ellipsex.max, bound->ellipse.max, def, acc); + + /* + * save the line end points for the + * cap code to use. Careful here, these are + * in cartesean coordinates (y increasing upwards) + * while the cap code uses inverted coordinates + * (y increasing downwards) + */ + + if (right) { + right->counterClock.y = bound->outer.min; + right->counterClock.x = outerx.min; + right->center.y = bound->ellipse.min; + right->center.x = ellipsex.min; + right->clock.y = bound->inner.min; + right->clock.x = innerx.min; + } + + if (left) { + left->clock.y = bound->outer.max; + left->clock.x = outerx.max; + left->center.y = bound->ellipse.max; + left->center.x = ellipsex.max; + left->counterClock.y = bound->inner.max; + left->counterClock.x = innerx.max; + } + + bound->left.min = bound->inner.max; + bound->left.max = bound->outer.max; + bound->right.min = bound->inner.min; + bound->right.max = bound->outer.min; + + computeLine (innerx.min, bound->inner.min, outerx.min, bound->outer.min, + &acc->right); + computeLine (innerx.max, bound->inner.max, outerx.max, bound->outer.max, + &acc->left); + + if (bound->inner.min > bound->inner.max) { + t = bound->inner.min; + bound->inner.min = bound->inner.max; + bound->inner.max = t; + } + tail_y = acc->tail_y; + if (tail_y > bound->ellipse.max) + tail_y = bound->ellipse.max; + else if (tail_y < bound->ellipse.min) + tail_y = bound->ellipse.min; + innerTaily = innerYfromY (tail_y, def, acc); + if (bound->inner.min > innerTaily) + bound->inner.min = innerTaily; + if (bound->inner.max < innerTaily) + bound->inner.max = innerTaily; + bound->inneri.min = ICEIL(bound->inner.min - acc->fromIntY); + bound->inneri.max = floor(bound->inner.max - acc->fromIntY); + bound->outeri.min = ICEIL(bound->outer.min - acc->fromIntY); + bound->outeri.max = floor(bound->outer.max - acc->fromIntY); +} + +/* + * this section computes the x value of the span at y + * intersected with the specified face of the ellipse. + * + * this is the min/max X value over the set of normal + * lines to the entire ellipse, the equation of the + * normal lines is: + * + * ellipse_x h^2 h^2 + * x = ------------ y + ellipse_x (1 - --- ) + * ellipse_y w^2 w^2 + * + * compute the derivative with-respect-to ellipse_y and solve + * for zero: + * + * (w^2 - h^2) ellipse_y^3 + h^4 y + * 0 = - ---------------------------------- + * h w ellipse_y^2 sqrt (h^2 - ellipse_y^2) + * + * ( h^4 y ) + * ellipse_y = ( ---------- ) ^ (1/3) + * ( (h^2 - w^2) ) + * + * The other two solutions to the equation are imaginary. + * + * This gives the position on the ellipse which generates + * the normal with the largest/smallest x intersection point. + * + * Now compute the second derivative to check whether + * the intersection is a minimum or maximum: + * + * h (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2)) + * - ------------------------------------------- + * w y0^3 (sqrt (h^2 - y^2)) ^ 3 + * + * as we only care about the sign, + * + * - (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2)) + * + * or (to use accelerators), + * + * y0^3 (h^2 - w^2) - h^2 y (3y0^2 - 2h^2) + * + */ + +/* + * computes the position on the ellipse whose normal line + * intersects the given scan line maximally + */ + +static double +hookEllipseY ( + double scan_y, + struct arc_bound *bound, + struct accelerators *acc, + int left) +{ + double ret; + + if (acc->h2mw2 == 0) { + if ( (scan_y > 0 && !left) || (scan_y < 0 && left) ) + return bound->ellipse.min; + return bound->ellipse.max; + } + ret = (acc->h4 * scan_y) / (acc->h2mw2); + if (ret >= 0) + return cbrt (ret); + else + return -cbrt (-ret); +} + +/* + * computes the X value of the intersection of the + * given scan line with the right side of the lower hook + */ + +static double +hookX ( + double scan_y, + struct arc_def *def, + struct arc_bound *bound, + struct accelerators *acc, + int left) +{ + double ellipse_y, x; + double maxMin; + + if (def->w != def->h) { + ellipse_y = hookEllipseY (scan_y, bound, acc, left); + if (boundedLe (ellipse_y, bound->ellipse)) { + /* + * compute the value of the second + * derivative + */ + maxMin = ellipse_y*ellipse_y*ellipse_y * acc->h2mw2 - + acc->h2 * scan_y * (3 * ellipse_y*ellipse_y - 2*acc->h2); + if ((left && maxMin > 0) || (!left && maxMin < 0)) { + if (ellipse_y == 0) + return def->w + left ? -def->l : def->l; + x = (acc->h2 * scan_y - ellipse_y * acc->h2mw2) * + sqrt (acc->h2 - ellipse_y * ellipse_y) / + (def->h * def->w * ellipse_y); + return x; + } + } + } + if (left) { + if (acc->left.valid && boundedLe (scan_y, bound->left)) { + x = intersectLine (scan_y, acc->left); + } else { + if (acc->right.valid) + x = intersectLine (scan_y, acc->right); + else + x = def->w - def->l; + } + } else { + if (acc->right.valid && boundedLe (scan_y, bound->right)) { + x = intersectLine (scan_y, acc->right); + } else { + if (acc->left.valid) + x = intersectLine (scan_y, acc->left); + else + x = def->w - def->l; + } + } + return x; +} + +/* + * generate the set of spans with + * the given y coordinate + */ + +static void +arcSpan ( + int y, + int lx, + int lw, + int rx, + int rw, + struct arc_def *def, + struct arc_bound *bounds, + struct accelerators *acc, + int mask) +{ + int linx, loutx, rinx, routx; + double x, altx; + + if (boundedLe (y, bounds->inneri)) { + linx = -(lx + lw); + rinx = rx; + } else { + /* + * intersection with left face + */ + x = hookX (y + acc->fromIntY, def, bounds, acc, 1); + if (acc->right.valid && + boundedLe (y + acc->fromIntY, bounds->right)) + { + altx = intersectLine (y + acc->fromIntY, acc->right); + if (altx < x) + x = altx; + } + linx = -ICEIL(acc->fromIntX - x); + rinx = ICEIL(acc->fromIntX + x); + } + if (boundedLe (y, bounds->outeri)) { + loutx = -lx; + routx = rx + rw; + } else { + /* + * intersection with right face + */ + x = hookX (y + acc->fromIntY, def, bounds, acc, 0); + if (acc->left.valid && + boundedLe (y + acc->fromIntY, bounds->left)) + { + altx = x; + x = intersectLine (y + acc->fromIntY, acc->left); + if (x < altx) + x = altx; + } + loutx = -ICEIL(acc->fromIntX - x); + routx = ICEIL(acc->fromIntX + x); + } + if (routx > rinx) { + if (mask & 1) + newFinalSpan (acc->yorgu - y, + acc->xorg + rinx, acc->xorg + routx); + if (mask & 8) + newFinalSpan (acc->yorgl + y, + acc->xorg + rinx, acc->xorg + routx); + } + if (loutx > linx) { + if (mask & 2) + newFinalSpan (acc->yorgu - y, + acc->xorg - loutx, acc->xorg - linx); + if (mask & 4) + newFinalSpan (acc->yorgl + y, + acc->xorg - loutx, acc->xorg - linx); + } +} + +static void +arcSpan0 ( + int lx, + int lw, + int rx, + int rw, + struct arc_def *def, + struct arc_bound *bounds, + struct accelerators *acc, + int mask) +{ + double x; + + if (boundedLe (0, bounds->inneri) && + acc->left.valid && boundedLe (0, bounds->left) && + acc->left.b > 0) + { + x = def->w - def->l; + if (acc->left.b < x) + x = acc->left.b; + lw = ICEIL(acc->fromIntX - x) - lx; + rw += rx; + rx = ICEIL(acc->fromIntX + x); + rw -= rx; + } + arcSpan (0, lx, lw, rx, rw, def, bounds, acc, mask); +} + +static void +tailSpan ( + int y, + int lw, + int rw, + struct arc_def *def, + struct arc_bound *bounds, + struct accelerators *acc, + int mask) +{ + double yy, xalt, x, lx, rx; + int n; + + if (boundedLe(y, bounds->outeri)) + arcSpan (y, 0, lw, -rw, rw, def, bounds, acc, mask); + else if (def->w != def->h) { + yy = y + acc->fromIntY; + x = tailX(yy, def, bounds, acc); + if (yy == 0.0 && x == -rw - acc->fromIntX) + return; + if (acc->right.valid && boundedLe (yy, bounds->right)) { + rx = x; + lx = -x; + xalt = intersectLine (yy, acc->right); + if (xalt >= -rw - acc->fromIntX && xalt <= rx) + rx = xalt; + n = ICEIL(acc->fromIntX + lx); + if (lw > n) { + if (mask & 2) + newFinalSpan (acc->yorgu - y, + acc->xorg + n, acc->xorg + lw); + if (mask & 4) + newFinalSpan (acc->yorgl + y, + acc->xorg + n, acc->xorg + lw); + } + n = ICEIL(acc->fromIntX + rx); + if (n > -rw) { + if (mask & 1) + newFinalSpan (acc->yorgu - y, + acc->xorg - rw, acc->xorg + n); + if (mask & 8) + newFinalSpan (acc->yorgl + y, + acc->xorg - rw, acc->xorg + n); + } + } + arcSpan (y, + ICEIL(acc->fromIntX - x), 0, + ICEIL(acc->fromIntX + x), 0, + def, bounds, acc, mask); + } +} + +/* + * create whole arcs out of pieces. This code is + * very bad. + */ + +static struct finalSpan **finalSpans = NULL; +static int finalMiny = 0, finalMaxy = -1; +static int finalSize = 0; + +static int nspans = 0; /* total spans, not just y coords */ + +struct finalSpan { + struct finalSpan *next; + int min, max; /* x values */ +}; + +static struct finalSpan *freeFinalSpans, *tmpFinalSpan; + +# define allocFinalSpan() (freeFinalSpans ?\ + ((tmpFinalSpan = freeFinalSpans), \ + (freeFinalSpans = freeFinalSpans->next), \ + (tmpFinalSpan->next = 0), \ + tmpFinalSpan) : \ + realAllocSpan ()) + +# define SPAN_CHUNK_SIZE 128 + +struct finalSpanChunk { + struct finalSpan data[SPAN_CHUNK_SIZE]; + struct finalSpanChunk *next; +}; + +static struct finalSpanChunk *chunks; + +struct finalSpan * +realAllocSpan () +{ + register struct finalSpanChunk *newChunk; + register struct finalSpan *span; + register int i; + + newChunk = (struct finalSpanChunk *) xalloc (sizeof (struct finalSpanChunk)); + if (!newChunk) + return (struct finalSpan *) NULL; + newChunk->next = chunks; + chunks = newChunk; + freeFinalSpans = span = newChunk->data + 1; + for (i = 1; i < SPAN_CHUNK_SIZE-1; i++) { + span->next = span+1; + span++; + } + span->next = 0; + span = newChunk->data; + span->next = 0; + return span; +} + +static void +disposeFinalSpans (void) +{ + struct finalSpanChunk *chunk, *next; + + for (chunk = chunks; chunk; chunk = next) { + next = chunk->next; + xfree (chunk); + } + chunks = 0; + freeFinalSpans = 0; + xfree(finalSpans); + finalSpans = 0; +} + +static void +fillSpans ( + DrawablePtr pDrawable, + GCPtr pGC) +{ + register struct finalSpan *span; + register DDXPointPtr xSpan; + register int *xWidth; + register int i; + register struct finalSpan **f; + register int spany; + DDXPointPtr xSpans; + int *xWidths; + + if (nspans == 0) + return; + xSpan = xSpans = (DDXPointPtr) ALLOCATE_LOCAL (nspans * sizeof (DDXPointRec)); + xWidth = xWidths = (int *) ALLOCATE_LOCAL (nspans * sizeof (int)); + if (xSpans && xWidths) + { + i = 0; + f = finalSpans; + for (spany = finalMiny; spany <= finalMaxy; spany++, f++) { + for (span = *f; span; span=span->next) { + if (span->max <= span->min) + continue; + xSpan->x = span->min; + xSpan->y = spany; + ++xSpan; + *xWidth++ = span->max - span->min; + ++i; + } + } + (*pGC->ops->FillSpans) (pDrawable, pGC, i, xSpans, xWidths, TRUE); + } + disposeFinalSpans (); + if (xSpans) + DEALLOCATE_LOCAL (xSpans); + if (xWidths) + DEALLOCATE_LOCAL (xWidths); + finalMiny = 0; + finalMaxy = -1; + finalSize = 0; + nspans = 0; +} + +# define SPAN_REALLOC 100 + +# define findSpan(y) ((finalMiny <= (y) && (y) <= finalMaxy) ? \ + &finalSpans[(y) - finalMiny] : \ + realFindSpan (y)) + +static struct finalSpan ** +realFindSpan (int y) +{ + struct finalSpan **newSpans; + int newSize, newMiny, newMaxy; + int change; + int i; + + if (y < finalMiny || y > finalMaxy) { + if (!finalSize) { + finalMiny = y; + finalMaxy = y - 1; + } + if (y < finalMiny) + change = finalMiny - y; + else + change = y - finalMaxy; + if (change >= SPAN_REALLOC) + change += SPAN_REALLOC; + else + change = SPAN_REALLOC; + newSize = finalSize + change; + newSpans = (struct finalSpan **) xalloc + (newSize * sizeof (struct finalSpan *)); + if (!newSpans) + return (struct finalSpan **)NULL; + newMiny = finalMiny; + newMaxy = finalMaxy; + if (y < finalMiny) + newMiny = finalMiny - change; + else + newMaxy = finalMaxy + change; + if (finalSpans) { + memmove(((char *) newSpans) + (finalMiny-newMiny) * sizeof (struct finalSpan *), + (char *) finalSpans, + finalSize * sizeof (struct finalSpan *)); + xfree (finalSpans); + } + if ((i = finalMiny - newMiny) > 0) + bzero ((char *)newSpans, i * sizeof (struct finalSpan *)); + if ((i = newMaxy - finalMaxy) > 0) + bzero ((char *)(newSpans + newSize - i), + i * sizeof (struct finalSpan *)); + finalSpans = newSpans; + finalMaxy = newMaxy; + finalMiny = newMiny; + finalSize = newSize; + } + return &finalSpans[y - finalMiny]; +} + +static void +newFinalSpan ( + int y, + register int xmin, + register int xmax) +{ + register struct finalSpan *x; + register struct finalSpan **f; + struct finalSpan *oldx; + struct finalSpan *prev; + + f = findSpan (y); + if (!f) + return; + oldx = 0; + for (;;) { + prev = 0; + for (x = *f; x; x=x->next) { + if (x == oldx) { + prev = x; + continue; + } + if (x->min <= xmax && xmin <= x->max) { + if (oldx) { + oldx->min = min (x->min, xmin); + oldx->max = max (x->max, xmax); + if (prev) + prev->next = x->next; + else + *f = x->next; + --nspans; + } else { + x->min = min (x->min, xmin); + x->max = max (x->max, xmax); + oldx = x; + } + xmin = oldx->min; + xmax = oldx->max; + break; + } + prev = x; + } + if (!x) + break; + } + if (!oldx) { + x = allocFinalSpan (); + if (x) + { + x->min = xmin; + x->max = xmax; + x->next = *f; + *f = x; + ++nspans; + } + } +} + +static void +mirrorSppPoint ( + int quadrant, + SppPointPtr sppPoint) +{ + switch (quadrant) { + case 0: + break; + case 1: + sppPoint->x = -sppPoint->x; + break; + case 2: + sppPoint->x = -sppPoint->x; + sppPoint->y = -sppPoint->y; + break; + case 3: + sppPoint->y = -sppPoint->y; + break; + } + /* + * and translate to X coordinate system + */ + sppPoint->y = -sppPoint->y; +} + +/* + * split an arc into pieces which are scan-converted + * in the first-quadrant and mirrored into position. + * This is necessary as the scan-conversion code can + * only deal with arcs completely contained in the + * first quadrant. + */ + +static void +drawArc ( + xArc *tarc, + int l, + int a0, + int a1, + miArcFacePtr right, + miArcFacePtr left) /* save end line points */ +{ + struct arc_def def; + struct accelerators acc; + int startq, endq, curq; + int rightq, leftq = 0, righta = 0, lefta = 0; + miArcFacePtr passRight, passLeft; + int q0 = 0, q1 = 0, mask; + struct band { + int a0, a1; + int mask; + } band[5], sweep[20]; + int bandno, sweepno; + int i, j; + int flipRight = 0, flipLeft = 0; + int copyEnd = 0; + miArcSpanData *spdata; + Bool mustFree; + + spdata = miComputeWideEllipse(l, tarc, &mustFree); + if (!spdata) + return; + + if (a1 < a0) + a1 += 360 * 64; + startq = a0 / (90 * 64); + if (a0 == a1) + endq = startq; + else + endq = (a1-1) / (90 * 64); + bandno = 0; + curq = startq; + rightq = -1; + for (;;) { + switch (curq) { + case 0: + if (a0 > 90 * 64) + q0 = 0; + else + q0 = a0; + if (a1 < 360 * 64) + q1 = min (a1, 90 * 64); + else + q1 = 90 * 64; + if (curq == startq && a0 == q0 && rightq < 0) { + righta = q0; + rightq = curq; + } + if (curq == endq && a1 == q1) { + lefta = q1; + leftq = curq; + } + break; + case 1: + if (a1 < 90 * 64) + q0 = 0; + else + q0 = 180 * 64 - min (a1, 180 * 64); + if (a0 > 180 * 64) + q1 = 90 * 64; + else + q1 = 180 * 64 - max (a0, 90 * 64); + if (curq == startq && 180 * 64 - a0 == q1) { + righta = q1; + rightq = curq; + } + if (curq == endq && 180 * 64 - a1 == q0) { + lefta = q0; + leftq = curq; + } + break; + case 2: + if (a0 > 270 * 64) + q0 = 0; + else + q0 = max (a0, 180 * 64) - 180 * 64; + if (a1 < 180 * 64) + q1 = 90 * 64; + else + q1 = min (a1, 270 * 64) - 180 * 64; + if (curq == startq && a0 - 180*64 == q0) { + righta = q0; + rightq = curq; + } + if (curq == endq && a1 - 180 * 64 == q1) { + lefta = q1; + leftq = curq; + } + break; + case 3: + if (a1 < 270 * 64) + q0 = 0; + else + q0 = 360 * 64 - min (a1, 360 * 64); + q1 = 360 * 64 - max (a0, 270 * 64); + if (curq == startq && 360 * 64 - a0 == q1) { + righta = q1; + rightq = curq; + } + if (curq == endq && 360 * 64 - a1 == q0) { + lefta = q0; + leftq = curq; + } + break; + } + band[bandno].a0 = q0; + band[bandno].a1 = q1; + band[bandno].mask = 1 << curq; + bandno++; + if (curq == endq) + break; + curq++; + if (curq == 4) { + a0 = 0; + a1 -= 360 * 64; + curq = 0; + endq -= 4; + } + } + sweepno = 0; + for (;;) { + q0 = 90 * 64; + mask = 0; + /* + * find left-most point + */ + for (i = 0; i < bandno; i++) + if (band[i].a0 <= q0) { + q0 = band[i].a0; + q1 = band[i].a1; + mask = band[i].mask; + } + if (!mask) + break; + /* + * locate next point of change + */ + for (i = 0; i < bandno; i++) + if (!(mask & band[i].mask)) { + if (band[i].a0 == q0) { + if (band[i].a1 < q1) + q1 = band[i].a1; + mask |= band[i].mask; + } else if (band[i].a0 < q1) + q1 = band[i].a0; + } + /* + * create a new sweep + */ + sweep[sweepno].a0 = q0; + sweep[sweepno].a1 = q1; + sweep[sweepno].mask = mask; + sweepno++; + /* + * subtract the sweep from the affected bands + */ + for (i = 0; i < bandno; i++) + if (band[i].a0 == q0) { + band[i].a0 = q1; + /* + * check if this band is empty + */ + if (band[i].a0 == band[i].a1) + band[i].a1 = band[i].a0 = 90 * 64 + 1; + } + } + computeAcc (tarc, l, &def, &acc); + for (j = 0; j < sweepno; j++) { + mask = sweep[j].mask; + passRight = passLeft = 0; + if (mask & (1 << rightq)) { + if (sweep[j].a0 == righta) + passRight = right; + else if (sweep[j].a1 == righta) { + passLeft = right; + flipRight = 1; + } + } + if (mask & (1 << leftq)) { + if (sweep[j].a1 == lefta) + { + if (passLeft) + copyEnd = 1; + passLeft = left; + } + else if (sweep[j].a0 == lefta) { + if (passRight) + copyEnd = 1; + passRight = left; + flipLeft = 1; + } + } + drawQuadrant (&def, &acc, sweep[j].a0, sweep[j].a1, mask, + passRight, passLeft, spdata); + } + /* + * when copyEnd is set, both ends of the arc were computed + * at the same time; drawQuadrant only takes one end though, + * so the left end will be the only one holding the data. Copy + * it from there. + */ + if (copyEnd) + *right = *left; + /* + * mirror the coordinates generated for the + * faces of the arc + */ + if (right) { + mirrorSppPoint (rightq, &right->clock); + mirrorSppPoint (rightq, &right->center); + mirrorSppPoint (rightq, &right->counterClock); + if (flipRight) { + SppPointRec temp; + + temp = right->clock; + right->clock = right->counterClock; + right->counterClock = temp; + } + } + if (left) { + mirrorSppPoint (leftq, &left->counterClock); + mirrorSppPoint (leftq, &left->center); + mirrorSppPoint (leftq, &left->clock); + if (flipLeft) { + SppPointRec temp; + + temp = left->clock; + left->clock = left->counterClock; + left->counterClock = temp; + } + } + if (mustFree) + xfree(spdata); +} + +static void +drawQuadrant ( + struct arc_def *def, + struct accelerators *acc, + int a0, + int a1, + int mask, + miArcFacePtr right, + miArcFacePtr left, + miArcSpanData *spdata) +{ + struct arc_bound bound; + double yy, x, xalt; + int y, miny, maxy; + int n; + miArcSpan *span; + + def->a0 = ((double) a0) / 64.0; + def->a1 = ((double) a1) / 64.0; + computeBound (def, &bound, acc, right, left); + yy = bound.inner.min; + if (bound.outer.min < yy) + yy = bound.outer.min; + miny = ICEIL(yy - acc->fromIntY); + yy = bound.inner.max; + if (bound.outer.max > yy) + yy = bound.outer.max; + maxy = floor(yy - acc->fromIntY); + y = spdata->k; + span = spdata->spans; + if (spdata->top) + { + if (a1 == 90 * 64 && (mask & 1)) + newFinalSpan (acc->yorgu - y - 1, acc->xorg, acc->xorg + 1); + span++; + } + for (n = spdata->count1; --n >= 0; ) + { + if (y < miny) + return; + if (y <= maxy) { + arcSpan (y, + span->lx, -span->lx, 0, span->lx + span->lw, + def, &bound, acc, mask); + if (span->rw + span->rx) + tailSpan (y, -span->rw, -span->rx, def, &bound, acc, mask); + } + y--; + span++; + } + if (y < miny) + return; + if (spdata->hole) + { + if (y <= maxy) + arcSpan (y, 0, 0, 0, 1, def, &bound, acc, mask & 0xc); + } + for (n = spdata->count2; --n >= 0; ) + { + if (y < miny) + return; + if (y <= maxy) + arcSpan (y, span->lx, span->lw, span->rx, span->rw, + def, &bound, acc, mask); + y--; + span++; + } + if (spdata->bot && miny <= y && y <= maxy) + { + n = mask; + if (y == miny) + n &= 0xc; + if (span->rw <= 0) { + arcSpan0 (span->lx, -span->lx, 0, span->lx + span->lw, + def, &bound, acc, n); + if (span->rw + span->rx) + tailSpan (y, -span->rw, -span->rx, def, &bound, acc, n); + } + else + arcSpan0 (span->lx, span->lw, span->rx, span->rw, + def, &bound, acc, n); + y--; + } + while (y >= miny) { + yy = y + acc->fromIntY; + if (def->w == def->h) { + xalt = def->w - def->l; + x = -sqrt(xalt * xalt - yy * yy); + } else { + x = tailX(yy, def, &bound, acc); + if (acc->left.valid && boundedLe (yy, bound.left)) { + xalt = intersectLine (yy, acc->left); + if (xalt < x) + x = xalt; + } + if (acc->right.valid && boundedLe (yy, bound.right)) { + xalt = intersectLine (yy, acc->right); + if (xalt < x) + x = xalt; + } + } + arcSpan (y, + ICEIL(acc->fromIntX - x), 0, + ICEIL(acc->fromIntX + x), 0, + def, &bound, acc, mask); + y--; + } +} diff --git a/xserver/mi/mibank.c b/xserver/mi/mibank.c new file mode 100644 index 000000000..32e963fab --- /dev/null +++ b/xserver/mi/mibank.c @@ -0,0 +1,2573 @@ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Copyright 1990,91,92,93 by Thomas Roell, Germany. + * Copyright 1991,92,93 by SGCS (Snitily Graphics Consulting Services), USA. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of Thomas Roell nor + * SGCS be used in advertising or publicity pertaining to distribution + * of the software without specific, written prior permission. + * Thomas Roell nor SGCS makes no representations about the suitability + * of this software for any purpose. It is provided "as is" without + * express or implied warranty. + * + * THOMAS ROELL AND SGCS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR SGCS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +/* + * This thing originated from an idea of Edwin Goei and his bank switching + * code for the DEC TX board. + */ + +/* + * Heavily modified for the XFree86 Project to turn this into an mi wrapper. + * --- Marc Aurele La France (tsi@xfree86.org) + */ + +/* + * "Heavily modified", indeed! By the time this is finalized, there probably + * won't be much left of Roell's code... + * + * Miscellaneous notes: + * - Pixels with imbedded bank boundaries are required to be off-screen. There + * >might< be a way to fool the underlying framebuffer into dealing with + * partial pixels. + * - Plans to generalise this to do (hardware) colour plane switching have been + * dropped due to colour flashing concerns. + * + * TODO: + * - Allow miModifyBanking() to change BankSize and nBankDepth. + * - Re-instate shared and double banking for framebuffers whose pixmap formats + * don't describe how the server "sees" the screen. + * - Remove remaining assumptions that a pixmap's devPrivate field points + * directly to its pixel data. + */ + +/* #define NO_ALLOCA 1 */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "servermd.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "mi.h" +#include "mibank.h" + +#define BANK_SINGLE 0 +#define BANK_SHARED 1 +#define BANK_DOUBLE 2 +#define BANK_NOBANK 3 + +typedef struct _miBankScreen +{ + miBankInfoRec BankInfo; + unsigned int nBankBPP; + unsigned int type; + + unsigned long nBitsPerBank; + unsigned long nBitsPerScanline; + unsigned long nPixelsPerScanlinePadUnit; + + PixmapPtr pScreenPixmap; + PixmapPtr pBankPixmap; + GCPtr pBankGC; + + int nBanks, maxRects; + RegionPtr *pBanks; + + pointer pbits; + + /* + * Screen Wrappers + */ + CreateScreenResourcesProcPtr CreateScreenResources; + ModifyPixmapHeaderProcPtr ModifyPixmapHeader; + CloseScreenProcPtr CloseScreen; + GetImageProcPtr GetImage; + GetSpansProcPtr GetSpans; + CreateGCProcPtr CreateGC; + PaintWindowBackgroundProcPtr PaintWindowBackground; + PaintWindowBorderProcPtr PaintWindowBorder; + CopyWindowProcPtr CopyWindow; + BSFuncRec BackingStoreFuncs; +} miBankScreenRec, *miBankScreenPtr; + +typedef struct _miBankGC +{ + GCOps *wrappedOps, *unwrappedOps; + GCFuncs *wrappedFuncs, *unwrappedFuncs; + + Bool fastCopy, fastPlane; + + RegionPtr pBankedClips[1]; +} miBankGCRec, *miBankGCPtr; + +typedef struct _miBankQueue +{ + Bool fastBlit; + unsigned short srcBankNo; + unsigned short dstBankNo; + short x; + short y; + short w; + short h; +} miBankQueue; + +/* + * CAVEAT: This banking scheme requires that the DDX store Pixmap data in the + * server's address space. + */ + +#define ModifyPixmap(_pPix, _width, _devKind, _pbits) \ + (*pScreen->ModifyPixmapHeader)((_pPix), \ + (_width), -1, -1, -1, (_devKind), (_pbits)) + +#define SET_SINGLE_BANK(_pPix, _width, _devKind, _no) \ + ModifyPixmap(_pPix, _width, _devKind, \ + (char *)pScreenPriv->BankInfo.pBankA + \ + (*pScreenPriv->BankInfo.SetSourceAndDestinationBanks)(pScreen, (_no)) - \ + (pScreenPriv->BankInfo.BankSize * (_no))) + +#define SET_SOURCE_BANK(_pPix, _width, _devKind, _no) \ + ModifyPixmap(_pPix, _width, _devKind, \ + (char *)pScreenPriv->BankInfo.pBankA + \ + (*pScreenPriv->BankInfo.SetSourceBank)(pScreen, (_no)) - \ + (pScreenPriv->BankInfo.BankSize * (_no))) + +#define SET_DESTINATION_BANK(_pPix, _width, _devKind, _no) \ + ModifyPixmap(_pPix, _width, _devKind, \ + (char *)pScreenPriv->BankInfo.pBankB + \ + (*pScreenPriv->BankInfo.SetDestinationBank)(pScreen, (_no)) - \ + (pScreenPriv->BankInfo.BankSize * (_no))) + +#define ALLOCATE_LOCAL_ARRAY(atype, ntype) \ + (atype *)ALLOCATE_LOCAL((ntype) * sizeof(atype)) + +static int miBankScreenIndex; +static int miBankGCIndex; +static unsigned long miBankGeneration = 0; + +#define BANK_SCRPRIVLVAL pScreen->devPrivates[miBankScreenIndex].ptr + +#define BANK_SCRPRIVATE ((miBankScreenPtr)(BANK_SCRPRIVLVAL)) + +#define BANK_GCPRIVLVAL(pGC) (pGC)->devPrivates[miBankGCIndex].ptr + +#define BANK_GCPRIVATE(pGC) ((miBankGCPtr)(BANK_GCPRIVLVAL(pGC))) + +#define PIXMAP_STATUS(_pPix) \ + pointer pbits = (_pPix)->devPrivate.ptr + +#define PIXMAP_SAVE(_pPix) \ + PIXMAP_STATUS(_pPix); \ + if (pbits == (pointer)pScreenPriv) \ + (_pPix)->devPrivate.ptr = pScreenPriv->pbits + +#define PIXMAP_RESTORE(_pPix) \ + (_pPix)->devPrivate.ptr = pbits + +#define BANK_SAVE \ + int width = pScreenPriv->pBankPixmap->drawable.width; \ + int devKind = pScreenPriv->pBankPixmap->devKind; \ + PIXMAP_SAVE(pScreenPriv->pBankPixmap) + +#define BANK_RESTORE \ + pScreenPriv->pBankPixmap->drawable.width = width; \ + pScreenPriv->pBankPixmap->devKind = devKind; \ + PIXMAP_RESTORE(pScreenPriv->pBankPixmap) + +#define SCREEN_STATUS \ + PIXMAP_STATUS(pScreenPriv->pScreenPixmap) + +#define SCREEN_SAVE \ + PIXMAP_SAVE(pScreenPriv->pScreenPixmap) + +#define SCREEN_RESTORE \ + PIXMAP_RESTORE(pScreenPriv->pScreenPixmap) + +#define SCREEN_INIT \ + miBankScreenPtr pScreenPriv = BANK_SCRPRIVATE + +#define SCREEN_UNWRAP(field) \ + pScreen->field = pScreenPriv->field + +#define SCREEN_WRAP(field, wrapper) \ + pScreenPriv->field = pScreen->field; \ + pScreen->field = wrapper + +#define GC_INIT(pGC) \ + miBankGCPtr pGCPriv = BANK_GCPRIVATE(pGC) + +#define GC_UNWRAP(pGC) \ + pGCPriv->unwrappedOps = (pGC)->ops; \ + pGCPriv->unwrappedFuncs = (pGC)->funcs; \ + (pGC)->ops = pGCPriv->wrappedOps; \ + (pGC)->funcs = pGCPriv->wrappedFuncs + +#define GC_WRAP(pGC) \ + pGCPriv->wrappedOps = (pGC)->ops; \ + pGCPriv->wrappedFuncs = (pGC)->funcs; \ + (pGC)->ops = pGCPriv->unwrappedOps; \ + (pGC)->funcs = pGCPriv->unwrappedFuncs + +#define IS_BANKED(pDrawable) \ + ((pbits == (pointer)pScreenPriv) && \ + (((DrawablePtr)(pDrawable))->type == DRAWABLE_WINDOW)) + +#define CLIP_SAVE \ + RegionPtr pOrigCompositeClip = pGC->pCompositeClip + +#define CLIP_RESTORE \ + pGC->pCompositeClip = pOrigCompositeClip + +#define GCOP_INIT \ + ScreenPtr pScreen = pGC->pScreen; \ + SCREEN_INIT; \ + GC_INIT(pGC) + +#define GCOP_UNWRAP \ + GC_UNWRAP(pGC) + +#define GCOP_WRAP \ + GC_WRAP(pGC) + +#define GCOP_TOP_PART \ + for (i = 0; i < pScreenPriv->nBanks; i++) \ + { \ + if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i])) \ + continue; \ + GCOP_UNWRAP; \ + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i) + +#define GCOP_BOTTOM_PART \ + GCOP_WRAP; \ + } + +#define GCOP_SIMPLE(statement) \ + if (nArray > 0) \ + { \ + GCOP_INIT; \ + SCREEN_SAVE; \ + if (!IS_BANKED(pDrawable)) \ + { \ + GCOP_UNWRAP; \ + statement; \ + GCOP_WRAP; \ + } \ + else \ + { \ + int i; \ + CLIP_SAVE; \ + GCOP_TOP_PART; \ + statement; \ + GCOP_BOTTOM_PART; \ + CLIP_RESTORE; \ + } \ + SCREEN_RESTORE; \ + } + +#define GCOP_0D_ARGS mode, +#define GCOP_1D_ARGS +#define GCOP_2D_ARGS shape, mode, + +#define GCOP_COMPLEX(aop, atype) \ + if (nArray > 0) \ + { \ + GCOP_INIT; \ + SCREEN_SAVE; \ + if (!IS_BANKED(pDrawable)) \ + { \ + GCOP_UNWRAP; \ + (*pGC->ops->aop)(pDrawable, pGC, GCOP_ARGS nArray, pArray); \ + GCOP_WRAP; \ + } \ + else \ + { \ + atype *aarg = pArray, *acopy; \ + int i; \ + CLIP_SAVE; \ + if ((acopy = ALLOCATE_LOCAL_ARRAY(atype, nArray))) \ + aarg = acopy; \ + GCOP_TOP_PART; \ + if (acopy) \ + memcpy(acopy, pArray, nArray * sizeof(atype)); \ + (*pGC->ops->aop)(pDrawable, pGC, GCOP_ARGS nArray, aarg); \ + GCOP_BOTTOM_PART; \ + DEALLOCATE_LOCAL(acopy); \ + CLIP_RESTORE; \ + } \ + SCREEN_RESTORE; \ + } + +/********************* + * Utility functions * + *********************/ + +static int +miBankOf( + miBankScreenPtr pScreenPriv, + int x, + int y +) +{ + int iBank = ((x * (int)pScreenPriv->nBankBPP) + + (y * (long)pScreenPriv->nBitsPerScanline)) / + (long)pScreenPriv->nBitsPerBank; + + if (iBank < 0) + iBank = 0; + else if (iBank >= pScreenPriv->nBanks) + iBank = pScreenPriv->nBanks - 1; + + return iBank; +} + +#define FirstBankOf(_x, _y) miBankOf(pScreenPriv, (_x), (_y)) +#define LastBankOf(_x, _y) miBankOf(pScreenPriv, (_x) - 1, (_y)) + +/* Determine banking type from the BankInfoRec */ +static unsigned int +miBankDeriveType( + ScreenPtr pScreen, + miBankInfoPtr pBankInfo +) +{ + unsigned int type; + + if (pBankInfo->pBankA == pBankInfo->pBankB) + { + if (pBankInfo->SetSourceBank == pBankInfo->SetDestinationBank) + { + if (pBankInfo->SetSourceAndDestinationBanks != + pBankInfo->SetSourceBank) + return BANK_NOBANK; + + type = BANK_SINGLE; + } + else + { + if (pBankInfo->SetSourceAndDestinationBanks == + pBankInfo->SetDestinationBank) + return BANK_NOBANK; + if (pBankInfo->SetSourceAndDestinationBanks == + pBankInfo->SetSourceBank) + return BANK_NOBANK; + + type = BANK_SHARED; + } + } + else + { + if ((unsigned long)abs((char *)pBankInfo->pBankA - + (char *)pBankInfo->pBankB) < pBankInfo->BankSize) + return BANK_NOBANK; + + if (pBankInfo->SetSourceBank == pBankInfo->SetDestinationBank) + { + if (pBankInfo->SetSourceAndDestinationBanks != + pBankInfo->SetSourceBank) + return BANK_NOBANK; + } + else + { + if (pBankInfo->SetSourceAndDestinationBanks == + pBankInfo->SetDestinationBank) + return BANK_NOBANK; + } + + type = BANK_DOUBLE; + } + + /* + * Internal limitation: Currently, only single banking is supported when + * the pixmap format and the screen's pixel format are different. The + * following test is only partially successful at detecting this condition. + */ + if (pBankInfo->nBankDepth != pScreen->rootDepth) + type = BANK_SINGLE; + + return type; +} + +/* Least common multiple */ +static unsigned int +miLCM( + unsigned int x, + unsigned int y +) +{ + unsigned int m = x, n = y, o; + + while ((o = m % n)) + { + m = n; + n = o; + } + + return (x / n) * y; +} + +/****************** + * GCOps wrappers * + ******************/ + +static void +miBankFillSpans( + DrawablePtr pDrawable, + GCPtr pGC, + int nArray, + DDXPointPtr pptInit, + int *pwidthInit, + int fSorted +) +{ + GCOP_SIMPLE((*pGC->ops->FillSpans)(pDrawable, pGC, + nArray, pptInit, pwidthInit, fSorted)); +} + +static void +miBankSetSpans( + DrawablePtr pDrawable, + GCPtr pGC, + char *psrc, + DDXPointPtr ppt, + int *pwidth, + int nArray, + int fSorted +) +{ + GCOP_SIMPLE((*pGC->ops->SetSpans)(pDrawable, pGC, psrc, + ppt, pwidth, nArray, fSorted)); +} + +static void +miBankPutImage( + DrawablePtr pDrawable, + GCPtr pGC, + int depth, + int x, + int y, + int w, + int h, + int leftPad, + int format, + char *pImage +) +{ + if ((w > 0) && (h > 0)) + { + GCOP_INIT; + SCREEN_SAVE; + + if (!IS_BANKED(pDrawable)) + { + GCOP_UNWRAP; + + (*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h, + leftPad, format, pImage); + + GCOP_WRAP; + } + else + { + int i, j; + + CLIP_SAVE; + + i = FirstBankOf(x + pDrawable->x, y + pDrawable->y); + j = LastBankOf(x + pDrawable->x + w, y + pDrawable->y + h); + for (; i <= j; i++) + { + if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i])) + continue; + + GCOP_UNWRAP; + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i); + + (*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h, + leftPad, format, pImage); + + GCOP_WRAP; + } + + CLIP_RESTORE; + } + + SCREEN_RESTORE; + } +} + +/* + * Here the CopyArea/CopyPlane wrappers. First off, we have to clip against + * the source in order to make the minimal number of copies in case of slow + * systems. Also the exposure handling is quite tricky. Special attention + * is to be given to the way the copies are sequenced. The list of boxes after + * the source clip is used to build a workqueue, that contains the atomic + * copies (i.e. only from one bank to one bank). Doing so produces a minimal + * list of things to do. + */ +static RegionPtr +miBankCopy( + DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + int srcx, + int srcy, + int w, + int h, + int dstx, + int dsty, + unsigned long plane, + Bool SinglePlane +) +{ + int cx1, cy1, cx2, cy2; + int ns, nd, nse, nde, dx, dy, xorg = 0, yorg = 0; + int maxWidth = 0, maxHeight = 0, paddedWidth = 0; + int nBox, nBoxClipSrc, nBoxClipDst, nQueue; + BoxPtr pBox, pBoxClipSrc, pBoxClipDst; + BoxRec fastBox, ccBox; + RegionPtr ret = NULL, prgnSrcClip = NULL; + RegionRec rgnDst; + char *pImage = NULL; + miBankQueue *pQueue, *pQueueNew, *Queue; + miBankQueue *pQueueTmp, *pQueueNext, *pQueueBase; + Bool fastBlit, freeSrcClip, fastClip; + Bool fExpose = FALSE, fastExpose = FALSE; + + GCOP_INIT; + SCREEN_SAVE; + + if (!IS_BANKED(pSrc) && !IS_BANKED(pDst)) + { + GCOP_UNWRAP; + + if (SinglePlane) + ret = (*pGC->ops->CopyPlane)(pSrc, pDst, pGC, + srcx, srcy, w, h, dstx, dsty, plane); + else + ret = (*pGC->ops->CopyArea)(pSrc, pDst, pGC, + srcx, srcy, w, h, dstx, dsty); + + GCOP_WRAP; + } + else if (!IS_BANKED(pDst)) + { + fExpose = pGC->fExpose; + pGC->fExpose = FALSE; + + xorg = pSrc->x; + yorg = pSrc->y; + dx = dstx - srcx; + dy = dsty - srcy; + srcx += xorg; + srcy += yorg; + + ns = FirstBankOf(srcx, srcy); + nse = LastBankOf(srcx + w, srcy + h); + for (; ns <= nse; ns++) + { + if (!pScreenPriv->pBanks[ns]) + continue; + + nBox = REGION_NUM_RECTS(pScreenPriv->pBanks[ns]); + pBox = REGION_RECTS(pScreenPriv->pBanks[ns]); + + for (; nBox--; pBox++) + { + cx1 = max(pBox->x1, srcx); + cy1 = max(pBox->y1, srcy); + cx2 = min(pBox->x2, srcx + w); + cy2 = min(pBox->y2, srcy + h); + + if ((cx1 >= cx2) || (cy1 >= cy2)) + continue; + + GCOP_UNWRAP; + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, ns); + + if (SinglePlane) + (*pGC->ops->CopyPlane)(pSrc, pDst, pGC, + cx1 - xorg, cy1 - yorg, + cx2 - cx1, cy2 - cy1, + cx1 + dx - xorg, cy1 + dy - yorg, plane); + else + (*pGC->ops->CopyArea)(pSrc, pDst, pGC, + cx1 - xorg, cy1 - yorg, + cx2 - cx1, cy2 - cy1, + cx1 + dx - xorg, cy1 + dy - yorg); + + GCOP_WRAP; + } + } + + pGC->fExpose = fExpose; + srcx -= xorg; + srcy -= yorg; + } + else if (!IS_BANKED(pSrc)) + { + CLIP_SAVE; + + if (pGC->miTranslate) + { + xorg = pDst->x; + yorg = pDst->y; + } + dx = srcx - dstx; + dy = srcy - dsty; + dstx += xorg; + dsty += yorg; + + nd = FirstBankOf(dstx, dsty); + nde = LastBankOf(dstx + w, dsty + h); + for (; nd <= nde; nd++) + { + if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[nd])) + continue; + + /* + * It's faster to let the lower-level CopyArea do the clipping + * within each bank. + */ + nBox = REGION_NUM_RECTS(pScreenPriv->pBanks[nd]); + pBox = REGION_RECTS(pScreenPriv->pBanks[nd]); + + for (; nBox--; pBox++) + { + cx1 = max(pBox->x1, dstx); + cy1 = max(pBox->y1, dsty); + cx2 = min(pBox->x2, dstx + w); + cy2 = min(pBox->y2, dsty + h); + + if ((cx1 >= cx2) || (cy1 >= cy2)) + continue; + + GCOP_UNWRAP; + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, nd); + + if (SinglePlane) + (*pGC->ops->CopyPlane)(pSrc, pDst, pGC, + cx1 + dx - xorg, cy1 + dy - yorg, + cx2 - cx1, cy2 - cy1, + cx1 - xorg, cy1 - yorg, plane); + else + (*pGC->ops->CopyArea)(pSrc, pDst, pGC, + cx1 + dx - xorg, cy1 + dy - yorg, + cx2 - cx1, cy2 - cy1, + cx1 - xorg, cy1 - yorg); + + GCOP_WRAP; + } + } + + CLIP_RESTORE; + } + else /* IS_BANKED(pSrc) && IS_BANKED(pDst) */ + { + CLIP_SAVE; + + fExpose = pGC->fExpose; + + fastBox.x1 = srcx + pSrc->x; + fastBox.y1 = srcy + pSrc->y; + fastBox.x2 = fastBox.x1 + w; + fastBox.y2 = fastBox.y1 + h; + + dx = dstx - fastBox.x1; + dy = dsty - fastBox.y1; + if (pGC->miTranslate) + { + xorg = pDst->x; + yorg = pDst->y; + } + + /* + * Clip against the source. Otherwise we will blit too much for SINGLE + * and SHARED banked systems. + */ + freeSrcClip = FALSE; + fastClip = FALSE; + fastExpose = FALSE; + + if (pGC->subWindowMode != IncludeInferiors) + prgnSrcClip = &((WindowPtr)pSrc)->clipList; + else if (!((WindowPtr)pSrc)->parent) + fastClip = TRUE; + else if ((pSrc == pDst) && (pGC->clientClipType == CT_NONE)) + prgnSrcClip = pGC->pCompositeClip; + else + { + prgnSrcClip = NotClippedByChildren((WindowPtr)pSrc); + freeSrcClip = TRUE; + } + + if (fastClip) + { + fastExpose = TRUE; + + /* + * Clip the source. If regions extend beyond the source size, make + * sure exposure events get sent. + */ + if (fastBox.x1 < pSrc->x) + { + fastBox.x1 = pSrc->x; + fastExpose = FALSE; + } + if (fastBox.y1 < pSrc->y) + { + fastBox.y1 = pSrc->y; + fastExpose = FALSE; + } + if (fastBox.x2 > pSrc->x + (int) pSrc->width) + { + fastBox.x2 = pSrc->x + (int) pSrc->width; + fastExpose = FALSE; + } + if (fastBox.y2 > pSrc->y + (int) pSrc->height) + { + fastBox.y2 = pSrc->y + (int) pSrc->height; + fastExpose = FALSE; + } + + nBox = 1; + pBox = &fastBox; + } + else + { + REGION_INIT(pScreen, &rgnDst, &fastBox, 1); + REGION_INTERSECT(pScreen, &rgnDst, &rgnDst, prgnSrcClip); + pBox = REGION_RECTS(&rgnDst); + nBox = REGION_NUM_RECTS(&rgnDst); + } + + /* + * fastBlit can only be TRUE if we don't need to worry about attempts + * to read partial pixels through the destination bank. + */ + if (SinglePlane) + fastBlit = pGCPriv->fastPlane; + else + fastBlit = pGCPriv->fastCopy; + + nQueue = nBox * pScreenPriv->maxRects * 2; + pQueue = Queue = ALLOCATE_LOCAL_ARRAY(miBankQueue, nQueue); + + if (Queue) + { + for (; nBox--; pBox++) + { + ns = FirstBankOf(pBox->x1, pBox->y1); + nse = LastBankOf(pBox->x2, pBox->y2); + for (; ns <= nse; ns++) + { + if (!pScreenPriv->pBanks[ns]) + continue; + + nBoxClipSrc = REGION_NUM_RECTS(pScreenPriv->pBanks[ns]); + pBoxClipSrc = REGION_RECTS(pScreenPriv->pBanks[ns]); + + for (; nBoxClipSrc--; pBoxClipSrc++) + { + cx1 = max(pBox->x1, pBoxClipSrc->x1); + cy1 = max(pBox->y1, pBoxClipSrc->y1); + cx2 = min(pBox->x2, pBoxClipSrc->x2); + cy2 = min(pBox->y2, pBoxClipSrc->y2); + + /* Check to see if the region is empty */ + if ((cx1 >= cx2) || (cy1 >= cy2)) + continue; + + /* Translate c[xy]* to destination coordinates */ + cx1 += dx + xorg; + cy1 += dy + yorg; + cx2 += dx + xorg; + cy2 += dy + yorg; + + nd = FirstBankOf(cx1, cy1); + nde = LastBankOf(cx2, cy2); + for (; nd <= nde; nd++) + { + if (!pGCPriv->pBankedClips[nd]) + continue; + + /* + * Clients can send quite large clip descriptions, + * so use the bank clips here instead. + */ + nBoxClipDst = + REGION_NUM_RECTS(pScreenPriv->pBanks[nd]); + pBoxClipDst = + REGION_RECTS(pScreenPriv->pBanks[nd]); + + for (; nBoxClipDst--; pBoxClipDst++) + { + ccBox.x1 = max(cx1, pBoxClipDst->x1); + ccBox.y1 = max(cy1, pBoxClipDst->y1); + ccBox.x2 = min(cx2, pBoxClipDst->x2); + ccBox.y2 = min(cy2, pBoxClipDst->y2); + + /* Check to see if the region is empty */ + if ((ccBox.x1 >= ccBox.x2) || + (ccBox.y1 >= ccBox.y2)) + continue; + + pQueue->srcBankNo = ns; + pQueue->dstBankNo = nd; + pQueue->x = ccBox.x1 - xorg; + pQueue->y = ccBox.y1 - yorg; + pQueue->w = ccBox.x2 - ccBox.x1; + pQueue->h = ccBox.y2 - ccBox.y1; + + if (maxWidth < pQueue->w) + maxWidth = pQueue->w; + if (maxHeight < pQueue->h) + maxHeight = pQueue->h; + + /* + * When shared banking is used and the source + * and destination banks differ, prevent + * attempts to fetch partial scanline pad units + * through the destination bank. + */ + pQueue->fastBlit = fastBlit; + if (fastBlit && + (pScreenPriv->type == BANK_SHARED) && + (ns != nd) && + ((ccBox.x1 % + pScreenPriv->nPixelsPerScanlinePadUnit) || + (ccBox.x2 % + pScreenPriv->nPixelsPerScanlinePadUnit) || + (RECT_IN_REGION(pScreen, + pGCPriv->pBankedClips[nd], &ccBox) != + rgnIN))) + pQueue->fastBlit = FALSE; + pQueue++; + } + } + } + } + } + } + + if (!fastClip) + { + REGION_UNINIT(pScreen, &rgnDst); + if (freeSrcClip) + REGION_DESTROY(pScreen, prgnSrcClip); + } + + pQueueNew = pQueue; + nQueue = pQueue - Queue; + + if (nQueue > 0) + { + BANK_SAVE; + + pQueue = Queue; + + if ((nQueue > 1) && + ((pSrc == pDst) || (pGC->subWindowMode == IncludeInferiors))) + { + if ((srcy + pSrc->y) < (dsty + yorg)) + { + /* Sort from bottom to top */ + pQueueBase = pQueueNext = pQueue + nQueue - 1; + + while (pQueueBase >= pQueue) + { + while ((pQueueNext >= pQueue) && + (pQueueBase->y == pQueueNext->y)) + pQueueNext--; + + pQueueTmp = pQueueNext + 1; + while (pQueueTmp <= pQueueBase) + *pQueueNew++ = *pQueueTmp++; + + pQueueBase = pQueueNext; + } + + pQueueNew -= nQueue; + pQueue = pQueueNew; + pQueueNew = Queue; + } + + if ((srcx + pSrc->x) < (dstx + xorg)) + { + /* Sort from right to left */ + pQueueBase = pQueueNext = pQueue; + + while (pQueueBase < pQueue + nQueue) + { + while ((pQueueNext < pQueue + nQueue) && + (pQueueNext->y == pQueueBase->y)) + pQueueNext++; + + pQueueTmp = pQueueNext; + while (pQueueTmp != pQueueBase) + *pQueueNew++ = *--pQueueTmp; + + pQueueBase = pQueueNext; + } + + pQueueNew -= nQueue; + pQueue = pQueueNew; + } + } + + paddedWidth = PixmapBytePad(maxWidth, + pScreenPriv->pScreenPixmap->drawable.depth); + pImage = (char *)ALLOCATE_LOCAL(paddedWidth * maxHeight); + + pGC->fExpose = FALSE; + + while (nQueue--) + { + pGC->pCompositeClip = pGCPriv->pBankedClips[pQueue->dstBankNo]; + + GCOP_UNWRAP; + + if (pQueue->srcBankNo == pQueue->dstBankNo) + { + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, + -1, -1, pQueue->srcBankNo); + + if (SinglePlane) + (*pGC->ops->CopyPlane)(pSrc, pDst, pGC, + pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y, + pQueue->w, pQueue->h, pQueue->x, pQueue->y, plane); + else + (*pGC->ops->CopyArea)(pSrc, pDst, pGC, + pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y, + pQueue->w, pQueue->h, pQueue->x, pQueue->y); + } + else if (pQueue->fastBlit) + { + SET_SOURCE_BANK (pScreenPriv->pBankPixmap, + pScreenPriv->pScreenPixmap->drawable.width, + pScreenPriv->pScreenPixmap->devKind, + pQueue->srcBankNo); + SET_DESTINATION_BANK(pScreenPriv->pScreenPixmap, + -1, -1, pQueue->dstBankNo); + + if (SinglePlane) + (*pGC->ops->CopyPlane)( + (DrawablePtr)pScreenPriv->pBankPixmap, pDst, pGC, + pQueue->x - dx, pQueue->y - dy, + pQueue->w, pQueue->h, pQueue->x, pQueue->y, plane); + else + (*pGC->ops->CopyArea)( + (DrawablePtr)pScreenPriv->pBankPixmap, pDst, pGC, + pQueue->x - dx, pQueue->y - dy, + pQueue->w, pQueue->h, pQueue->x, pQueue->y); + } + else if (pImage) + { + ModifyPixmap(pScreenPriv->pBankPixmap, + maxWidth, paddedWidth, pImage); + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, + -1, -1, pQueue->srcBankNo); + + (*pScreenPriv->pBankGC->ops->CopyArea)( + pSrc, (DrawablePtr)pScreenPriv->pBankPixmap, + pScreenPriv->pBankGC, + pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y, + pQueue->w, pQueue->h, 0, 0); + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, + -1, -1, pQueue->dstBankNo); + + if (SinglePlane) + (*pGC->ops->CopyPlane)( + (DrawablePtr)pScreenPriv->pBankPixmap, + pDst, pGC, 0, 0, pQueue->w, pQueue->h, + pQueue->x, pQueue->y, plane); + else + (*pGC->ops->CopyArea)( + (DrawablePtr)pScreenPriv->pBankPixmap, + pDst, pGC, 0, 0, pQueue->w, pQueue->h, + pQueue->x, pQueue->y); + } + + GCOP_WRAP; + + pQueue++; + } + + DEALLOCATE_LOCAL(pImage); + + BANK_RESTORE; + } + + CLIP_RESTORE; + + pGC->fExpose = fExpose; + + DEALLOCATE_LOCAL(Queue); + } + + SCREEN_RESTORE; + + if (!fExpose || fastExpose) + return ret; + + return miHandleExposures(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, 0); +} + +static RegionPtr +miBankCopyArea( + DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + int srcx, + int srcy, + int w, + int h, + int dstx, + int dsty +) +{ + return miBankCopy(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, 0, FALSE); +} + +static RegionPtr +miBankCopyPlane( + DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + int srcx, + int srcy, + int w, + int h, + int dstx, + int dsty, + unsigned long plane +) +{ + return + miBankCopy(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane, TRUE); +} + +static void +miBankPolyPoint( + DrawablePtr pDrawable, + GCPtr pGC, + int mode, + int nArray, + xPoint *pArray +) +{ +# define GCOP_ARGS GCOP_0D_ARGS + GCOP_COMPLEX(PolyPoint, xPoint); +# undef GCOP_ARGS +} + +static void +miBankPolylines( + DrawablePtr pDrawable, + GCPtr pGC, + int mode, + int nArray, + DDXPointPtr pArray +) +{ +# define GCOP_ARGS GCOP_0D_ARGS + GCOP_COMPLEX(Polylines, DDXPointRec); +# undef GCOP_ARGS +} + +static void +miBankPolySegment( + DrawablePtr pDrawable, + GCPtr pGC, + int nArray, + xSegment *pArray +) +{ +# define GCOP_ARGS GCOP_1D_ARGS + GCOP_COMPLEX(PolySegment, xSegment); +# undef GCOP_ARGS +} + +static void +miBankPolyRectangle( + DrawablePtr pDrawable, + GCPtr pGC, + int nArray, + xRectangle *pArray +) +{ +# define GCOP_ARGS GCOP_1D_ARGS + GCOP_COMPLEX(PolyRectangle, xRectangle); +# undef GCOP_ARGS +} + +static void +miBankPolyArc( + DrawablePtr pDrawable, + GCPtr pGC, + int nArray, + xArc *pArray +) +{ +# define GCOP_ARGS GCOP_1D_ARGS + GCOP_COMPLEX(PolyArc, xArc); +# undef GCOP_ARGS +} + +static void +miBankFillPolygon( + DrawablePtr pDrawable, + GCPtr pGC, + int shape, + int mode, + int nArray, + DDXPointRec *pArray +) +{ +# define GCOP_ARGS GCOP_2D_ARGS + GCOP_COMPLEX(FillPolygon, DDXPointRec); +# undef GCOP_ARGS +} + +static void +miBankPolyFillRect( + DrawablePtr pDrawable, + GCPtr pGC, + int nArray, + xRectangle *pArray +) +{ +# define GCOP_ARGS GCOP_1D_ARGS + GCOP_COMPLEX(PolyFillRect, xRectangle); +# undef GCOP_ARGS +} + +static void +miBankPolyFillArc( + DrawablePtr pDrawable, + GCPtr pGC, + int nArray, + xArc *pArray +) +{ +# define GCOP_ARGS GCOP_1D_ARGS + GCOP_COMPLEX(PolyFillArc, xArc); +# undef GCOP_ARGS +} + +static int +miBankPolyText8( + DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int nArray, + char *pchar +) +{ + int retval = x; + + GCOP_SIMPLE(retval = + (*pGC->ops->PolyText8)(pDrawable, pGC, x, y, nArray, pchar)); + + return retval; +} + +static int +miBankPolyText16( + DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int nArray, + unsigned short *pchar +) +{ + int retval = x; + + GCOP_SIMPLE(retval = + (*pGC->ops->PolyText16)(pDrawable, pGC, x, y, nArray, pchar)); + + return retval; +} + +static void +miBankImageText8( + DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int nArray, + char *pchar +) +{ + GCOP_SIMPLE((*pGC->ops->ImageText8)(pDrawable, pGC, x, y, nArray, pchar)); +} + +static void +miBankImageText16( + DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int nArray, + unsigned short *pchar +) +{ + GCOP_SIMPLE((*pGC->ops->ImageText16)(pDrawable, pGC, x, y, nArray, pchar)); +} + +static void +miBankImageGlyphBlt( + DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + unsigned int nArray, + CharInfoPtr *ppci, + pointer pglyphBase +) +{ + GCOP_SIMPLE((*pGC->ops->ImageGlyphBlt)(pDrawable, pGC, + x, y, nArray, ppci, pglyphBase)); +} + +static void +miBankPolyGlyphBlt( + DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + unsigned int nArray, + CharInfoPtr *ppci, + pointer pglyphBase +) +{ + GCOP_SIMPLE((*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, + x, y, nArray, ppci, pglyphBase)); +} + +static void +miBankPushPixels( + GCPtr pGC, + PixmapPtr pBitmap, + DrawablePtr pDrawable, + int w, + int h, + int x, + int y +) +{ + if ((w > 0) && (h > 0)) + { + GCOP_INIT; + SCREEN_SAVE; + + if (!IS_BANKED(pDrawable)) + { + GCOP_UNWRAP; + + (*pGC->ops->PushPixels)(pGC, pBitmap, pDrawable, w, h, x, y); + + GCOP_WRAP; + } + else + { + int i, j; + + CLIP_SAVE; + + i = FirstBankOf(x, y); + j = LastBankOf(x + w, y + h); + for (; i <= j; i++) + { + if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i])) + continue; + + GCOP_UNWRAP; + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i); + + (*pGC->ops->PushPixels)(pGC, pBitmap, pDrawable, w, h, x, y); + + GCOP_WRAP; + } + + CLIP_RESTORE; + } + + SCREEN_RESTORE; + } +} + +static GCOps miBankGCOps = +{ + miBankFillSpans, + miBankSetSpans, + miBankPutImage, + miBankCopyArea, + miBankCopyPlane, + miBankPolyPoint, + miBankPolylines, + miBankPolySegment, + miBankPolyRectangle, + miBankPolyArc, + miBankFillPolygon, + miBankPolyFillRect, + miBankPolyFillArc, + miBankPolyText8, + miBankPolyText16, + miBankImageText8, + miBankImageText16, + miBankImageGlyphBlt, + miBankPolyGlyphBlt, + miBankPushPixels, + {NULL} /* devPrivate */ +}; + +/******************** + * GCFuncs wrappers * + ********************/ + +static void +miBankValidateGC( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDrawable +) +{ + GC_INIT(pGC); + GC_UNWRAP(pGC); + + (*pGC->funcs->ValidateGC)(pGC, changes, pDrawable); + + if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)) || + (pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS))) + { + ScreenPtr pScreen = pGC->pScreen; + RegionPtr prgnClip; + unsigned long planemask; + int i; + + SCREEN_INIT; + SCREEN_SAVE; + + if (IS_BANKED(pDrawable)) + { + for (i = 0; i < pScreenPriv->nBanks; i++) + { + if (!pScreenPriv->pBanks[i]) + continue; + + if (!(prgnClip = pGCPriv->pBankedClips[i])) + prgnClip = REGION_CREATE(pScreen, NULL, 1); + + REGION_INTERSECT(pScreen, prgnClip, + pScreenPriv->pBanks[i], pGC->pCompositeClip); + + if ((REGION_NUM_RECTS(prgnClip) <= 1) && + ((prgnClip->extents.x1 == prgnClip->extents.x2) || + (prgnClip->extents.y1 == prgnClip->extents.y2))) + { + REGION_DESTROY(pScreen, prgnClip); + pGCPriv->pBankedClips[i] = NULL; + } + else + pGCPriv->pBankedClips[i] = prgnClip; + } + + /* + * fastCopy and fastPlane can only be TRUE if we don't need to + * worry about attempts to read partial pixels through the + * destination bank. + */ + switch (pScreenPriv->type) + { + case BANK_SHARED: + pGCPriv->fastCopy = pGCPriv->fastPlane = FALSE; + + if ((pGC->alu != GXclear) && (pGC->alu != GXcopy) && + (pGC->alu != GXcopyInverted) && (pGC->alu != GXset)) + break; + + if (pScreen->rootDepth == 1) + pGCPriv->fastPlane = TRUE; + + /* This is probably paranoia */ + if ((pDrawable->depth != pScreen->rootDepth) || + (pDrawable->depth != pGC->depth)) + break; + + planemask = (1 << pGC->depth) - 1; + if ((pGC->planemask & planemask) == planemask) + pGCPriv->fastCopy = TRUE; + + break; + + case BANK_DOUBLE: + pGCPriv->fastCopy = pGCPriv->fastPlane = TRUE; + break; + + default: + pGCPriv->fastCopy = pGCPriv->fastPlane = FALSE; + break; + } + } + else + { + /* + * Here we are on a pixmap and don't need all that special clipping + * stuff, hence free it. + */ + for (i = 0; i < pScreenPriv->nBanks; i++) + { + if (!pGCPriv->pBankedClips[i]) + continue; + + REGION_DESTROY(pScreen, pGCPriv->pBankedClips[i]); + pGCPriv->pBankedClips[i] = NULL; + } + } + + SCREEN_RESTORE; + } + + GC_WRAP(pGC); +} + +static void +miBankChangeGC( + GCPtr pGC, + unsigned long mask +) +{ + GC_INIT(pGC); + GC_UNWRAP(pGC); + + (*pGC->funcs->ChangeGC)(pGC, mask); + + GC_WRAP(pGC); +} + +static void +miBankCopyGC( + GCPtr pGCSrc, + unsigned long mask, + GCPtr pGCDst +) +{ + GC_INIT(pGCDst); + GC_UNWRAP(pGCDst); + + (*pGCDst->funcs->CopyGC)(pGCSrc, mask, pGCDst); + + GC_WRAP(pGCDst); +} + +static void +miBankDestroyGC( + GCPtr pGC +) +{ + ScreenPtr pScreen = pGC->pScreen; + int i; + + SCREEN_INIT; + GC_INIT(pGC); + GC_UNWRAP(pGC); + + (*pGC->funcs->DestroyGC)(pGC); + + for (i = 0; i < pScreenPriv->nBanks; i++) + { + if (!pGCPriv->pBankedClips[i]) + continue; + + REGION_DESTROY(pScreen, pGCPriv->pBankedClips[i]); + pGCPriv->pBankedClips[i] = NULL; + } + + GC_WRAP(pGC); +} + +static void +miBankChangeClip( + GCPtr pGC, + int type, + pointer pvalue, + int nrects +) +{ + GC_INIT(pGC); + GC_UNWRAP(pGC); + + (*pGC->funcs->ChangeClip)(pGC, type, pvalue, nrects); + + GC_WRAP(pGC); +} + +static void +miBankDestroyClip( + GCPtr pGC +) +{ + GC_INIT(pGC); + GC_UNWRAP(pGC); + + (*pGC->funcs->DestroyClip)(pGC); + + GC_WRAP(pGC); +} + +static void +miBankCopyClip( + GCPtr pGCDst, + GCPtr pGCSrc +) +{ + GC_INIT(pGCDst); + GC_UNWRAP(pGCDst); + + (*pGCDst->funcs->CopyClip)(pGCDst, pGCSrc); + + GC_WRAP(pGCDst); +} + +static GCFuncs miBankGCFuncs = +{ + miBankValidateGC, + miBankChangeGC, + miBankCopyGC, + miBankDestroyGC, + miBankChangeClip, + miBankDestroyClip, + miBankCopyClip +}; + +/******************* + * Screen Wrappers * + *******************/ + +static Bool +miBankCreateScreenResources( + ScreenPtr pScreen +) +{ + Bool retval; + + SCREEN_INIT; + SCREEN_UNWRAP(CreateScreenResources); + + if ((retval = (*pScreen->CreateScreenResources)(pScreen))) + { + /* Set screen buffer address to something recognizable */ + pScreenPriv->pScreenPixmap = (*pScreen->GetScreenPixmap)(pScreen); + pScreenPriv->pbits = pScreenPriv->pScreenPixmap->devPrivate.ptr; + pScreenPriv->pScreenPixmap->devPrivate.ptr = (pointer)pScreenPriv; + + /* Get shadow pixmap; width & height of 0 means no pixmap data */ + pScreenPriv->pBankPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, + pScreenPriv->pScreenPixmap->drawable.depth); + if (!pScreenPriv->pBankPixmap) + retval = FALSE; + } + + /* Shadow the screen */ + if (retval) + retval = (*pScreen->ModifyPixmapHeader)(pScreenPriv->pBankPixmap, + pScreenPriv->pScreenPixmap->drawable.width, + pScreenPriv->pScreenPixmap->drawable.height, + pScreenPriv->pScreenPixmap->drawable.depth, + pScreenPriv->pScreenPixmap->drawable.bitsPerPixel, + pScreenPriv->pScreenPixmap->devKind, NULL); + + /* Create shadow GC */ + if (retval) + { + pScreenPriv->pBankGC = CreateScratchGC(pScreen, + pScreenPriv->pBankPixmap->drawable.depth); + if (!pScreenPriv->pBankGC) + retval = FALSE; + } + + /* Validate shadow GC */ + if (retval) + { + pScreenPriv->pBankGC->graphicsExposures = FALSE; + pScreenPriv->pBankGC->subWindowMode = IncludeInferiors; + ValidateGC((DrawablePtr)pScreenPriv->pBankPixmap, + pScreenPriv->pBankGC); + } + + SCREEN_WRAP(CreateScreenResources, miBankCreateScreenResources); + + return retval; +} + +static Bool +miBankModifyPixmapHeader( + PixmapPtr pPixmap, + int width, + int height, + int depth, + int bitsPerPixel, + int devKind, + pointer pPixData +) +{ + Bool retval = FALSE; + + if (pPixmap) + { + ScreenPtr pScreen = pPixmap->drawable.pScreen; + + SCREEN_INIT; + PIXMAP_SAVE(pPixmap); + SCREEN_UNWRAP(ModifyPixmapHeader); + + retval = (*pScreen->ModifyPixmapHeader)(pPixmap, width, height, + depth, bitsPerPixel, devKind, pPixData); + + SCREEN_WRAP(ModifyPixmapHeader, miBankModifyPixmapHeader); + + if (pbits == (pointer)pScreenPriv) + { + pScreenPriv->pbits = pPixmap->devPrivate.ptr; + pPixmap->devPrivate.ptr = pbits; + } + } + + return retval; +} + +static Bool +miBankCloseScreen( + int nIndex, + ScreenPtr pScreen +) +{ + int i; + + SCREEN_INIT; + + /* Free shadow GC */ + FreeScratchGC(pScreenPriv->pBankGC); + + /* Free shadow pixmap */ + (*pScreen->DestroyPixmap)(pScreenPriv->pBankPixmap); + + /* Restore screen pixmap devPrivate pointer */ + pScreenPriv->pScreenPixmap->devPrivate.ptr = pScreenPriv->pbits; + + /* Delete bank clips */ + for (i = 0; i < pScreenPriv->nBanks; i++) + if (pScreenPriv->pBanks[i]) + REGION_DESTROY(pScreen, pScreenPriv->pBanks[i]); + + Xfree(pScreenPriv->pBanks); + + SCREEN_UNWRAP(CreateScreenResources); + SCREEN_UNWRAP(ModifyPixmapHeader); + SCREEN_UNWRAP(CloseScreen); + SCREEN_UNWRAP(GetImage); + SCREEN_UNWRAP(GetSpans); + SCREEN_UNWRAP(CreateGC); + SCREEN_UNWRAP(PaintWindowBackground); + SCREEN_UNWRAP(PaintWindowBorder); + SCREEN_UNWRAP(CopyWindow); + SCREEN_UNWRAP(BackingStoreFuncs); + + Xfree(pScreenPriv); + return (*pScreen->CloseScreen)(nIndex, pScreen); +} + +static void +miBankGetImage( + DrawablePtr pDrawable, + int sx, + int sy, + int w, + int h, + unsigned int format, + unsigned long planemask, + char *pImage +) +{ + if ((w > 0) && (h > 0)) + { + ScreenPtr pScreen = pDrawable->pScreen; + + SCREEN_INIT; + SCREEN_STATUS; + SCREEN_UNWRAP(GetImage); + + if (!IS_BANKED(pDrawable)) + { + (*pScreen->GetImage)(pDrawable, sx, sy, w, h, + format, planemask, pImage); + } + else + { + int paddedWidth; + char *pBankImage; + + paddedWidth = PixmapBytePad(w, + pScreenPriv->pScreenPixmap->drawable.depth); + pBankImage = (char *)ALLOCATE_LOCAL(paddedWidth * h); + + if (pBankImage) + { + BANK_SAVE; + + ModifyPixmap(pScreenPriv->pBankPixmap, w, paddedWidth, + pBankImage); + + (*pScreenPriv->pBankGC->ops->CopyArea)( + (DrawablePtr)WindowTable[pScreen->myNum], + (DrawablePtr)pScreenPriv->pBankPixmap, + pScreenPriv->pBankGC, + sx + pDrawable->x, sy + pDrawable->y, w, h, 0, 0); + + (*pScreen->GetImage)((DrawablePtr)pScreenPriv->pBankPixmap, + 0, 0, w, h, format, planemask, pImage); + + BANK_RESTORE; + + DEALLOCATE_LOCAL(pBankImage); + } + } + + SCREEN_WRAP(GetImage, miBankGetImage); + } +} + +static void +miBankGetSpans( + DrawablePtr pDrawable, + int wMax, + DDXPointPtr ppt, + int *pwidth, + int nspans, + char *pImage +) +{ + if (nspans > 0) + { + ScreenPtr pScreen = pDrawable->pScreen; + + SCREEN_INIT; + SCREEN_STATUS; + SCREEN_UNWRAP(GetSpans); + + if (!IS_BANKED(pDrawable)) + { + (*pScreen->GetSpans)(pDrawable, wMax, ppt, pwidth, nspans, pImage); + } + else + { + char *pBankImage; + int paddedWidth; + DDXPointRec pt; + + pt.x = pt.y = 0; + + paddedWidth = + PixmapBytePad(pScreenPriv->pScreenPixmap->drawable.width, + pScreenPriv->pScreenPixmap->drawable.depth); + pBankImage = (char *)ALLOCATE_LOCAL(paddedWidth); + + if (pBankImage) + { + BANK_SAVE; + + ModifyPixmap(pScreenPriv->pBankPixmap, + pScreenPriv->pScreenPixmap->drawable.width, + paddedWidth, pBankImage); + + for (; nspans--; ppt++, pwidth++) + { + if (*pwidth <= 0) + continue; + + (*pScreenPriv->pBankGC->ops->CopyArea)( + (DrawablePtr)WindowTable[pScreen->myNum], + (DrawablePtr)pScreenPriv->pBankPixmap, + pScreenPriv->pBankGC, + ppt->x, ppt->y, *pwidth, 1, 0, 0); + + (*pScreen->GetSpans)((DrawablePtr)pScreenPriv->pBankPixmap, + wMax, &pt, pwidth, 1, pImage); + + pImage = pImage + PixmapBytePad(*pwidth, pDrawable->depth); + } + + BANK_RESTORE; + + DEALLOCATE_LOCAL(pBankImage); + } + } + + SCREEN_WRAP(GetSpans, miBankGetSpans); + } +} + +static Bool +miBankCreateGC( + GCPtr pGC +) +{ + ScreenPtr pScreen = pGC->pScreen; + miBankGCPtr pGCPriv = BANK_GCPRIVATE(pGC); + Bool ret; + + SCREEN_INIT; + SCREEN_UNWRAP(CreateGC); + + if ((ret = (*pScreen->CreateGC)(pGC))) + { + pGCPriv->unwrappedOps = &miBankGCOps; + pGCPriv->unwrappedFuncs = &miBankGCFuncs; + GC_WRAP(pGC); + + memset(&pGCPriv->pBankedClips, 0, + pScreenPriv->nBanks * sizeof(pGCPriv->pBankedClips)); + } + + SCREEN_WRAP(CreateGC, miBankCreateGC); + + return ret; +} + +static void +miBankPaintWindow( + WindowPtr pWin, + RegionPtr pRegion, + int what +) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RegionRec tmpReg; + int i; + PaintWindowProcPtr PaintWindow; + + SCREEN_INIT; + SCREEN_SAVE; + + if (what == PW_BORDER) + { + SCREEN_UNWRAP(PaintWindowBorder); + PaintWindow = pScreen->PaintWindowBorder; + } + else + { + SCREEN_UNWRAP(PaintWindowBackground); + PaintWindow = pScreen->PaintWindowBackground; + } + + if (!IS_BANKED(pWin)) + { + (*PaintWindow)(pWin, pRegion, what); + } + else + { + REGION_NULL(pScreen, &tmpReg); + + for (i = 0; i < pScreenPriv->nBanks; i++) + { + if (!pScreenPriv->pBanks[i]) + continue; + + REGION_INTERSECT(pScreen, &tmpReg, pRegion, + pScreenPriv->pBanks[i]); + + if (REGION_NIL(&tmpReg)) + continue; + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i); + + (*PaintWindow)(pWin, &tmpReg, what); + } + + REGION_UNINIT(pScreen, &tmpReg); + } + + if (what == PW_BORDER) + { + SCREEN_WRAP(PaintWindowBorder, miBankPaintWindow); + } + else + { + SCREEN_WRAP(PaintWindowBackground, miBankPaintWindow); + } + + SCREEN_RESTORE; +} + +static void +miBankCopyWindow( + WindowPtr pWindow, + DDXPointRec ptOldOrg, + RegionPtr pRgnSrc +) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + GCPtr pGC; + int dx, dy, nBox; + DrawablePtr pDrawable = (DrawablePtr)WindowTable[pScreen->myNum]; + RegionPtr pRgnDst; + BoxPtr pBox, pBoxTmp, pBoxNext, pBoxBase, pBoxNew1, pBoxNew2; + XID subWindowMode = IncludeInferiors; + + pGC = GetScratchGC(pDrawable->depth, pScreen); + + ChangeGC(pGC, GCSubwindowMode, &subWindowMode); + ValidateGC(pDrawable, pGC); + + pRgnDst = REGION_CREATE(pScreen, NULL, 1); + + dx = ptOldOrg.x - pWindow->drawable.x; + dy = ptOldOrg.y - pWindow->drawable.y; + REGION_TRANSLATE(pScreen, pRgnSrc, -dx, -dy); + REGION_INTERSECT(pScreen, pRgnDst, &pWindow->borderClip, pRgnSrc); + + pBox = REGION_RECTS(pRgnDst); + nBox = REGION_NUM_RECTS(pRgnDst); + + pBoxNew1 = NULL; + pBoxNew2 = NULL; + + if (nBox > 1) + { + if (dy < 0) + { + /* Sort boxes from bottom to top */ + pBoxNew1 = ALLOCATE_LOCAL_ARRAY(BoxRec, nBox); + + if (pBoxNew1) + { + pBoxBase = pBoxNext = pBox + nBox - 1; + + while (pBoxBase >= pBox) + { + while ((pBoxNext >= pBox) && + (pBoxBase->y1 == pBoxNext->y1)) + pBoxNext--; + + pBoxTmp = pBoxNext + 1; + + while (pBoxTmp <= pBoxBase) + *pBoxNew1++ = *pBoxTmp++; + + pBoxBase = pBoxNext; + } + + pBoxNew1 -= nBox; + pBox = pBoxNew1; + } + } + + if (dx < 0) + { + /* Sort boxes from right to left */ + pBoxNew2 = ALLOCATE_LOCAL_ARRAY(BoxRec, nBox); + + if (pBoxNew2) + { + pBoxBase = pBoxNext = pBox; + + while (pBoxBase < pBox + nBox) + { + while ((pBoxNext < pBox + nBox) && + (pBoxNext->y1 == pBoxBase->y1)) + pBoxNext++; + + pBoxTmp = pBoxNext; + + while (pBoxTmp != pBoxBase) + *pBoxNew2++ = *--pBoxTmp; + + pBoxBase = pBoxNext; + } + + pBoxNew2 -= nBox; + pBox = pBoxNew2; + } + } + } + + while (nBox--) + { + (*pGC->ops->CopyArea)(pDrawable, pDrawable, pGC, + pBox->x1 + dx, pBox->y1 + dy, + pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, + pBox->x1, pBox->y1); + + pBox++; + } + + FreeScratchGC(pGC); + + REGION_DESTROY(pScreen, pRgnDst); + + DEALLOCATE_LOCAL(pBoxNew2); + DEALLOCATE_LOCAL(pBoxNew1); +} + +/************************** + * Backing store wrappers * + **************************/ + +static void +miBankSaveAreas( + PixmapPtr pPixmap, + RegionPtr prgnSave, + int xorg, + int yorg, + WindowPtr pWin +) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + RegionRec rgnClipped; + int i; + + SCREEN_INIT; + SCREEN_SAVE; + SCREEN_UNWRAP(BackingStoreFuncs.SaveAreas); + + if (!IS_BANKED(pWin)) + { + (*pScreen->BackingStoreFuncs.SaveAreas)(pPixmap, prgnSave, xorg, yorg, + pWin); + } + else + { + REGION_NULL(pScreen, &rgnClipped); + REGION_TRANSLATE(pScreen, prgnSave, xorg, yorg); + + for (i = 0; i < pScreenPriv->nBanks; i++) + { + if (!pScreenPriv->pBanks[i]) + continue; + + REGION_INTERSECT(pScreen, &rgnClipped, + prgnSave, pScreenPriv->pBanks[i]); + + if (REGION_NIL(&rgnClipped)) + continue; + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i); + + REGION_TRANSLATE(pScreen, &rgnClipped, -xorg, -yorg); + + (*pScreen->BackingStoreFuncs.SaveAreas)(pPixmap, &rgnClipped, + xorg, yorg, pWin); + } + + REGION_TRANSLATE(pScreen, prgnSave, -xorg, -yorg); + REGION_UNINIT(pScreen, &rgnClipped); + } + + SCREEN_WRAP(BackingStoreFuncs.SaveAreas, miBankSaveAreas); + SCREEN_RESTORE; +} + +static void +miBankRestoreAreas( + PixmapPtr pPixmap, + RegionPtr prgnRestore, + int xorg, + int yorg, + WindowPtr pWin +) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + RegionRec rgnClipped; + int i; + + SCREEN_INIT; + SCREEN_SAVE; + SCREEN_UNWRAP(BackingStoreFuncs.RestoreAreas); + + if (!IS_BANKED(pWin)) + { + (*pScreen->BackingStoreFuncs.RestoreAreas)(pPixmap, prgnRestore, + xorg, yorg, pWin); + } + else + { + REGION_NULL(pScreen, &rgnClipped); + + for (i = 0; i < pScreenPriv->nBanks; i++) + { + if (!pScreenPriv->pBanks[i]) + continue; + + REGION_INTERSECT(pScreen, &rgnClipped, + prgnRestore, pScreenPriv->pBanks[i]); + + if (REGION_NIL(&rgnClipped)) + continue; + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i); + + (*pScreen->BackingStoreFuncs.RestoreAreas)(pPixmap, &rgnClipped, + xorg, yorg, pWin); + } + + REGION_UNINIT(pScreen, &rgnClipped); + } + + SCREEN_WRAP(BackingStoreFuncs.RestoreAreas, miBankRestoreAreas); + SCREEN_RESTORE; +} + +_X_EXPORT Bool +miInitializeBanking( + ScreenPtr pScreen, + unsigned int xsize, + unsigned int ysize, + unsigned int width, + miBankInfoPtr pBankInfo +) +{ + miBankScreenPtr pScreenPriv; + unsigned long nBitsPerBank, nBitsPerScanline, nPixelsPerScanlinePadUnit; + unsigned long BankBase, ServerPad; + unsigned int type, iBank, nBanks, maxRects, we, nBankBPP; + int i; + + if (!pBankInfo || !pBankInfo->BankSize) + return TRUE; /* No banking required */ + + /* Sanity checks */ + + if (!pScreen || !xsize || !ysize || (xsize > width) || + !pBankInfo->SetSourceBank || !pBankInfo->SetDestinationBank || + !pBankInfo->SetSourceAndDestinationBanks || + !pBankInfo->pBankA || !pBankInfo->pBankB || + !pBankInfo->nBankDepth) + return FALSE; + + /* + * DDX *must* have registered a pixmap format whose depth is + * pBankInfo->nBankDepth. This is not necessarily the rootDepth + * pixmap format. + */ + i = 0; + while (screenInfo.formats[i].depth != pBankInfo->nBankDepth) + if (++i >= screenInfo.numPixmapFormats) + return FALSE; + nBankBPP = screenInfo.formats[i].bitsPerPixel; + + i = 0; + while (screenInfo.formats[i].depth != pScreen->rootDepth) + if (++i >= screenInfo.numPixmapFormats) + return FALSE; + + if (nBankBPP > screenInfo.formats[i].bitsPerPixel) + return FALSE; + + /* Determine banking type */ + if ((type = miBankDeriveType(pScreen, pBankInfo)) == BANK_NOBANK) + return FALSE; + + /* Internal data */ + + nBitsPerBank = pBankInfo->BankSize * 8; + ServerPad = PixmapBytePad(1, pBankInfo->nBankDepth) * 8; + if (nBitsPerBank % ServerPad) + return FALSE; + nBitsPerScanline = PixmapBytePad(width, pBankInfo->nBankDepth) * 8; + nBanks = ((nBitsPerScanline * (ysize - 1)) + + (nBankBPP * xsize) + nBitsPerBank - 1) / nBitsPerBank; + nPixelsPerScanlinePadUnit = miLCM(ServerPad, nBankBPP) / nBankBPP; + + /* Private areas */ + + if (miBankGeneration != serverGeneration) + { + if (((miBankScreenIndex = AllocateScreenPrivateIndex()) < 0) || + ((miBankGCIndex = AllocateGCPrivateIndex()) < 0)) + return FALSE; + + miBankGeneration = serverGeneration; + } + + if (!AllocateGCPrivate(pScreen, miBankGCIndex, + (nBanks * sizeof(RegionPtr)) + + (sizeof(miBankGCRec) - sizeof(RegionPtr)))) + return FALSE; + + if (!(pScreenPriv = (miBankScreenPtr)Xcalloc(sizeof(miBankScreenRec)))) + return FALSE; + + if (!(pScreenPriv->pBanks = /* Allocate and clear */ + (RegionPtr *)Xcalloc(nBanks * sizeof(RegionPtr)))) + { + Xfree(pScreenPriv); + return FALSE; + } + + /* + * Translate banks into clipping regions which are themselves clipped + * against the screen. This also ensures that pixels with imbedded bank + * boundaries are off-screen. + */ + + BankBase = 0; + maxRects = 0; + we = 0; + for (iBank = 0; iBank < nBanks; iBank++) + { + xRectangle pRects[3], *pRect = pRects; + unsigned int xb, yb, xe, ye; + + xb = ((BankBase + nBankBPP - 1) % nBitsPerScanline) / nBankBPP; + yb = (BankBase + nBankBPP - 1) / nBitsPerScanline; + if (xb >= xsize) + { + xb = we = 0; + yb++; + } + if (yb >= ysize) + { + we = 0; + break; + } + + if (we) + break; + + BankBase += nBitsPerBank; + + we = (BankBase % nBitsPerScanline) % nBankBPP; + xe = (BankBase % nBitsPerScanline) / nBankBPP; + ye = BankBase / nBitsPerScanline; + if (xe >= xsize) + { + we = xe = 0; + ye++; + } + if (ye >= ysize) + { + we = xe = 0; + ye = ysize; + } + + if (yb == ye) + { + if (xb >= xe) + continue; + + pRect->x = xb; + pRect->y = yb; + pRect->width = xe - xb; + pRect->height = 1; + maxRects += 2; + pRect++; + } + else + { + if (xb) + { + pRect->x = xb; + pRect->y = yb++; + pRect->width = xsize - xb; + pRect->height = 1; + maxRects += 2; + pRect++; + } + + if (yb < ye) + { + pRect->x = 0; + pRect->y = yb; + pRect->width = xsize; + pRect->height = ye - yb; + maxRects += min(pRect->height, 3) + 1; + pRect++; + } + + if (xe) + { + pRect->x = 0; + pRect->y = ye; + pRect->width = xe; + pRect->height = 1; + maxRects += 2; + pRect++; + } + } + + pScreenPriv->pBanks[iBank] = + RECTS_TO_REGION(pScreen, pRect - pRects, pRects, 0); + if (!pScreenPriv->pBanks[iBank] || + REGION_NAR(pScreenPriv->pBanks[iBank])) + { + we = 1; + break; + } + } + + if (we && (iBank < nBanks)) + { + for (i = iBank; i >= 0; i--) + if (pScreenPriv->pBanks[i]) + REGION_DESTROY(pScreen, pScreenPriv->pBanks[i]); + + Xfree(pScreenPriv->pBanks); + Xfree(pScreenPriv); + + return FALSE; + } + + /* Open for business */ + + pScreenPriv->type = type; + pScreenPriv->nBanks = nBanks; + pScreenPriv->maxRects = maxRects; + pScreenPriv->nBankBPP = nBankBPP; + pScreenPriv->BankInfo = *pBankInfo; + pScreenPriv->nBitsPerBank = nBitsPerBank; + pScreenPriv->nBitsPerScanline = nBitsPerScanline; + pScreenPriv->nPixelsPerScanlinePadUnit = nPixelsPerScanlinePadUnit; + + SCREEN_WRAP(CreateScreenResources, miBankCreateScreenResources); + SCREEN_WRAP(ModifyPixmapHeader, miBankModifyPixmapHeader); + SCREEN_WRAP(CloseScreen, miBankCloseScreen); + SCREEN_WRAP(GetImage, miBankGetImage); + SCREEN_WRAP(GetSpans, miBankGetSpans); + SCREEN_WRAP(CreateGC, miBankCreateGC); + SCREEN_WRAP(PaintWindowBackground, miBankPaintWindow); + SCREEN_WRAP(PaintWindowBorder, miBankPaintWindow); + SCREEN_WRAP(CopyWindow, miBankCopyWindow); + + pScreenPriv->BackingStoreFuncs = pScreen->BackingStoreFuncs; + + pScreen->BackingStoreFuncs.SaveAreas = miBankSaveAreas; + pScreen->BackingStoreFuncs.RestoreAreas = miBankRestoreAreas; + /* ?????????????????????????????????????????????????????????????? + pScreen->BackingStoreFuncs.SetClipmaskRgn = miBankSetClipmaskRgn; + ?????????????????????????????????????????????????????????????? */ + + BANK_SCRPRIVLVAL = (pointer)pScreenPriv; + + return TRUE; +} + +/* This is used to force GC revalidation when the banking type is changed */ +/*ARGSUSED*/ +static int +miBankNewSerialNumber( + WindowPtr pWin, + pointer unused +) +{ + pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; + return WT_WALKCHILDREN; +} + +/* This entry modifies the banking interface */ +_X_EXPORT Bool +miModifyBanking( + ScreenPtr pScreen, + miBankInfoPtr pBankInfo +) +{ + unsigned int type; + + if (!pScreen) + return FALSE; + + if (miBankGeneration == serverGeneration) + { + SCREEN_INIT; + + if (pScreenPriv) + { + if (!pBankInfo || !pBankInfo->BankSize || + !pBankInfo->pBankA || !pBankInfo->pBankB || + !pBankInfo->SetSourceBank || !pBankInfo->SetDestinationBank || + !pBankInfo->SetSourceAndDestinationBanks) + return FALSE; + + /* BankSize and nBankDepth cannot, as yet, be changed */ + if ((pScreenPriv->BankInfo.BankSize != pBankInfo->BankSize) || + (pScreenPriv->BankInfo.nBankDepth != pBankInfo->nBankDepth)) + return FALSE; + + if ((type = miBankDeriveType(pScreen, pBankInfo)) == BANK_NOBANK) + return FALSE; + + /* Reset banking info */ + pScreenPriv->BankInfo = *pBankInfo; + if (type != pScreenPriv->type) + { + /* + * Banking type is changing. Revalidate all window GC's. + */ + pScreenPriv->type = type; + WalkTree(pScreen, miBankNewSerialNumber, 0); + } + + return TRUE; + } + } + + if (!pBankInfo || !pBankInfo->BankSize) + return TRUE; /* No change requested */ + + return FALSE; +} + +/* + * Given various screen attributes, determine the minimum scanline width such + * that each scanline is server and DDX padded and any pixels with imbedded + * bank boundaries are off-screen. This function returns -1 if such a width + * cannot exist. This function exists because the DDX needs to be able to + * determine this width before initializing a frame buffer. + */ +int +miScanLineWidth( + unsigned int xsize, /* pixels */ + unsigned int ysize, /* pixels */ + unsigned int width, /* pixels */ + unsigned long BankSize, /* char's */ + PixmapFormatRec *pBankFormat, + unsigned int nWidthUnit /* bits */ +) +{ + unsigned long nBitsPerBank, nBitsPerScanline, nBitsPerScanlinePadUnit; + unsigned long minBitsPerScanline, maxBitsPerScanline; + + /* Sanity checks */ + + if (!nWidthUnit || !pBankFormat) + return -1; + + nBitsPerBank = BankSize * 8; + if (nBitsPerBank % pBankFormat->scanlinePad) + return -1; + + if (xsize > width) + width = xsize; + nBitsPerScanlinePadUnit = miLCM(pBankFormat->scanlinePad, nWidthUnit); + nBitsPerScanline = + (((width * pBankFormat->bitsPerPixel) + nBitsPerScanlinePadUnit - 1) / + nBitsPerScanlinePadUnit) * nBitsPerScanlinePadUnit; + width = nBitsPerScanline / pBankFormat->bitsPerPixel; + + if (!xsize || !(nBitsPerBank % pBankFormat->bitsPerPixel)) + return (int)width; + + /* + * Scanlines will be server-pad aligned at this point. They will also be + * a multiple of nWidthUnit bits long. Ensure that pixels with imbedded + * bank boundaries are off-screen. + * + * It seems reasonable to limit total frame buffer size to 1/16 of the + * theoretical maximum address space size. On a machine with 32-bit + * addresses (to 8-bit quantities) this turns out to be 256MB. Not only + * does this provide a simple limiting condition for the loops below, but + * it also prevents unsigned long wraparounds. + */ + if (!ysize) + return -1; + + minBitsPerScanline = xsize * pBankFormat->bitsPerPixel; + if (minBitsPerScanline > nBitsPerBank) + return -1; + + if (ysize == 1) + return (int)width; + + maxBitsPerScanline = + (((unsigned long)(-1) >> 1) - minBitsPerScanline) / (ysize - 1); + while (nBitsPerScanline <= maxBitsPerScanline) + { + unsigned long BankBase, BankUnit; + + BankUnit = ((nBitsPerBank + nBitsPerScanline - 1) / nBitsPerBank) * + nBitsPerBank; + if (!(BankUnit % nBitsPerScanline)) + return (int)width; + + for (BankBase = BankUnit; ; BankBase += nBitsPerBank) + { + unsigned long x, y; + + y = BankBase / nBitsPerScanline; + if (y >= ysize) + return (int)width; + + x = BankBase % nBitsPerScanline; + if (!(x % pBankFormat->bitsPerPixel)) + continue; + + if (x < minBitsPerScanline) + { + /* + * Skip ahead certain widths by dividing the excess scanline + * amongst the y's. + */ + y *= nBitsPerScanlinePadUnit; + nBitsPerScanline += + ((x + y - 1) / y) * nBitsPerScanlinePadUnit; + width = nBitsPerScanline / pBankFormat->bitsPerPixel; + break; + } + + if (BankBase != BankUnit) + continue; + + if (!(nBitsPerScanline % x)) + return (int)width; + + BankBase = ((nBitsPerScanline - minBitsPerScanline) / + (nBitsPerScanline - x)) * BankUnit; + } + } + + return -1; +} diff --git a/xserver/mi/mibank.h b/xserver/mi/mibank.h new file mode 100644 index 000000000..fe93ab41b --- /dev/null +++ b/xserver/mi/mibank.h @@ -0,0 +1,118 @@ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + +#ifndef __MIBANK_H__ +#define __MIBANK_H__ 1 + +#include "scrnintstr.h" + +/* + * Banking external interface. + */ + +/* + * This is the banking function type. The return value is normally zero. + * Non-zero returns can be used to implement the likes of scanline interleave, + * etc. + */ +typedef int miBankProc( + ScreenPtr /*pScreen*/, + unsigned int /*iBank*/ +); + +typedef miBankProc *miBankProcPtr; + +typedef struct _miBankInfo +{ + /* + * Banking refers to the use of one or more apertures (in the server's + * address space) to access various parts of a potentially larger hardware + * frame buffer. + * + * Three different banking schemes are supported: + * + * Single banking is indicated when pBankA and pBankB are equal and all + * three miBankProcPtr's point to the same function. Here, both reads and + * writes through the aperture access the same hardware location. + * + * Shared banking is indicated when pBankA and pBankB are equal but the + * source and destination functions differ. Here reads through the + * aperture do not necessarily access the same hardware location as writes. + * + * Double banking is indicated when pBankA and pBankB differ. Here two + * independent apertures are used to provide read/write access to + * potentially different hardware locations. + * + * Any other combination will result in no banking. + */ + miBankProcPtr SetSourceBank; /* Set pBankA bank number */ + miBankProcPtr SetDestinationBank; /* Set pBankB bank number */ + miBankProcPtr SetSourceAndDestinationBanks; /* Set both bank numbers */ + + pointer pBankA; /* First aperture location */ + pointer pBankB; /* First or second aperture location */ + + /* + * BankSize is in units of sizeof(char) and is the size of each bank. + */ + unsigned long BankSize; + + /* + * nBankDepth is the colour depth associated with the maximum number of a + * pixel's bits that are simultaneously accessible through the frame buffer + * aperture. + */ + unsigned int nBankDepth; +} miBankInfoRec, *miBankInfoPtr; + +Bool +miInitializeBanking( + ScreenPtr /*pScreen*/, + unsigned int /*xsize*/, + unsigned int /*ysize*/, + unsigned int /*width*/, + miBankInfoPtr /*pBankInfo*/ +); + +Bool +miModifyBanking( + ScreenPtr /*pScreen*/, + miBankInfoPtr /*pBankInfo*/ +); + +/* + * This function determines the minimum screen width, given a initial estimate + * and various screen attributes. DDX needs to determine this width before + * initializing the screen. + */ +int +miScanLineWidth( + unsigned int /*xsize*/, + unsigned int /*ysize*/, + unsigned int /*width*/, + unsigned long /*BankSize*/, + PixmapFormatRec * /*pBankFormat*/, + unsigned int /*nWidthUnit*/ +); + +#endif /* __MIBANK_H__ */ diff --git a/xserver/mi/mibitblt.c b/xserver/mi/mibitblt.c new file mode 100644 index 000000000..bf0e29ac0 --- /dev/null +++ b/xserver/mi/mibitblt.c @@ -0,0 +1,843 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +/* Author: Todd Newman (aided and abetted by Mr. Drewry) */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xprotostr.h> + +#include "misc.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "scrnintstr.h" +#include "mi.h" +#include "regionstr.h" +#include <X11/Xmd.h> +#include "servermd.h" + +#ifndef HAS_FFS +extern int ffs(int); +#endif + +/* MICOPYAREA -- public entry for the CopyArea request + * For each rectangle in the source region + * get the pixels with GetSpans + * set them in the destination with SetSpans + * We let SetSpans worry about clipping to the destination. + */ +_X_EXPORT RegionPtr +miCopyArea(pSrcDrawable, pDstDrawable, + pGC, xIn, yIn, widthSrc, heightSrc, xOut, yOut) + register DrawablePtr pSrcDrawable; + register DrawablePtr pDstDrawable; + GCPtr pGC; + int xIn, yIn; + int widthSrc, heightSrc; + int xOut, yOut; +{ + DDXPointPtr ppt, pptFirst; + unsigned int *pwidthFirst, *pwidth, *pbits; + BoxRec srcBox, *prect; + /* may be a new region, or just a copy */ + RegionPtr prgnSrcClip; + /* non-0 if we've created a src clip */ + RegionPtr prgnExposed; + int realSrcClip = 0; + int srcx, srcy, dstx, dsty, i, j, y, width, height, + xMin, xMax, yMin, yMax; + unsigned int *ordering; + int numRects; + BoxPtr boxes; + + srcx = xIn + pSrcDrawable->x; + srcy = yIn + pSrcDrawable->y; + + /* If the destination isn't realized, this is easy */ + if (pDstDrawable->type == DRAWABLE_WINDOW && + !((WindowPtr)pDstDrawable)->realized) + return (RegionPtr)NULL; + + /* clip the source */ + if (pSrcDrawable->type == DRAWABLE_PIXMAP) + { + BoxRec box; + + box.x1 = pSrcDrawable->x; + box.y1 = pSrcDrawable->y; + box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; + box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; + + prgnSrcClip = REGION_CREATE(pGC->pScreen, &box, 1); + realSrcClip = 1; + } + else + { + if (pGC->subWindowMode == IncludeInferiors) { + prgnSrcClip = NotClippedByChildren ((WindowPtr) pSrcDrawable); + realSrcClip = 1; + } else + prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList; + } + + /* If the src drawable is a window, we need to translate the srcBox so + * that we can compare it with the window's clip region later on. */ + srcBox.x1 = srcx; + srcBox.y1 = srcy; + srcBox.x2 = srcx + widthSrc; + srcBox.y2 = srcy + heightSrc; + + dstx = xOut; + dsty = yOut; + if (pGC->miTranslate) + { + dstx += pDstDrawable->x; + dsty += pDstDrawable->y; + } + + pptFirst = ppt = (DDXPointPtr) + ALLOCATE_LOCAL(heightSrc * sizeof(DDXPointRec)); + pwidthFirst = pwidth = (unsigned int *) + ALLOCATE_LOCAL(heightSrc * sizeof(unsigned int)); + numRects = REGION_NUM_RECTS(prgnSrcClip); + boxes = REGION_RECTS(prgnSrcClip); + ordering = (unsigned int *) + ALLOCATE_LOCAL(numRects * sizeof(unsigned int)); + if(!pptFirst || !pwidthFirst || !ordering) + { + if (ordering) + DEALLOCATE_LOCAL(ordering); + if (pwidthFirst) + DEALLOCATE_LOCAL(pwidthFirst); + if (pptFirst) + DEALLOCATE_LOCAL(pptFirst); + return (RegionPtr)NULL; + } + + /* If not the same drawable then order of move doesn't matter. + Following assumes that boxes are sorted from top + to bottom and left to right. + */ + if ((pSrcDrawable != pDstDrawable) && + ((pGC->subWindowMode != IncludeInferiors) || + (pSrcDrawable->type == DRAWABLE_PIXMAP) || + (pDstDrawable->type == DRAWABLE_PIXMAP))) + for (i=0; i < numRects; i++) + ordering[i] = i; + else { /* within same drawable, must sequence moves carefully! */ + if (dsty <= srcBox.y1) { /* Scroll up or stationary vertical. + Vertical order OK */ + if (dstx <= srcBox.x1) /* Scroll left or stationary horizontal. + Horizontal order OK as well */ + for (i=0; i < numRects; i++) + ordering[i] = i; + else { /* scroll right. must reverse horizontal banding of rects. */ + for (i=0, j=1, xMax=0; i < numRects; j=i+1, xMax=i) { + /* find extent of current horizontal band */ + y=boxes[i].y1; /* band has this y coordinate */ + while ((j < numRects) && (boxes[j].y1 == y)) + j++; + /* reverse the horizontal band in the output ordering */ + for (j-- ; j >= xMax; j--, i++) + ordering[i] = j; + } + } + } + else { /* Scroll down. Must reverse vertical banding. */ + if (dstx < srcBox.x1) { /* Scroll left. Horizontal order OK. */ + for (i=numRects-1, j=i-1, yMin=i, yMax=0; + i >= 0; + j=i-1, yMin=i) { + /* find extent of current horizontal band */ + y=boxes[i].y1; /* band has this y coordinate */ + while ((j >= 0) && (boxes[j].y1 == y)) + j--; + /* reverse the horizontal band in the output ordering */ + for (j++ ; j <= yMin; j++, i--, yMax++) + ordering[yMax] = j; + } + } + else /* Scroll right or horizontal stationary. + Reverse horizontal order as well (if stationary, horizontal + order can be swapped without penalty and this is faster + to compute). */ + for (i=0, j=numRects-1; i < numRects; i++, j--) + ordering[i] = j; + } + } + + for(i = 0; i < numRects; i++) + { + prect = &boxes[ordering[i]]; + xMin = max(prect->x1, srcBox.x1); + xMax = min(prect->x2, srcBox.x2); + yMin = max(prect->y1, srcBox.y1); + yMax = min(prect->y2, srcBox.y2); + /* is there anything visible here? */ + if(xMax <= xMin || yMax <= yMin) + continue; + + ppt = pptFirst; + pwidth = pwidthFirst; + y = yMin; + height = yMax - yMin; + width = xMax - xMin; + + for(j = 0; j < height; j++) + { + /* We must untranslate before calling GetSpans */ + ppt->x = xMin; + ppt++->y = y++; + *pwidth++ = width; + } + pbits = (unsigned int *)xalloc(height * PixmapBytePad(width, + pSrcDrawable->depth)); + if (pbits) + { + (*pSrcDrawable->pScreen->GetSpans)(pSrcDrawable, width, pptFirst, + (int *)pwidthFirst, height, (char *)pbits); + ppt = pptFirst; + pwidth = pwidthFirst; + xMin -= (srcx - dstx); + y = yMin - (srcy - dsty); + for(j = 0; j < height; j++) + { + ppt->x = xMin; + ppt++->y = y++; + *pwidth++ = width; + } + + (*pGC->ops->SetSpans)(pDstDrawable, pGC, (char *)pbits, pptFirst, + (int *)pwidthFirst, height, TRUE); + xfree(pbits); + } + } + prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn, + widthSrc, heightSrc, xOut, yOut, (unsigned long)0); + if(realSrcClip) + REGION_DESTROY(pGC->pScreen, prgnSrcClip); + + DEALLOCATE_LOCAL(ordering); + DEALLOCATE_LOCAL(pwidthFirst); + DEALLOCATE_LOCAL(pptFirst); + return prgnExposed; +} + +/* MIGETPLANE -- gets a bitmap representing one plane of pDraw + * A helper used for CopyPlane and XY format GetImage + * No clever strategy here, we grab a scanline at a time, pull out the + * bits and then stuff them in a 1 bit deep map. + */ +/* + * This should be replaced with something more general. mi shouldn't have to + * care about such things as scanline padding et alia. + */ +static +MiBits * +miGetPlane( + DrawablePtr pDraw, + int planeNum, /* number of the bitPlane */ + int sx, + int sy, + int w, + int h, + MiBits *result) +{ + int i, j, k, width, bitsPerPixel, widthInBytes; + DDXPointRec pt = {0, 0}; + MiBits pixel; + MiBits bit; + unsigned char *pCharsOut = NULL; + +#if BITMAP_SCANLINE_UNIT == 8 +#define OUT_TYPE unsigned char +#endif +#if BITMAP_SCANLINE_UNIT == 16 +#define OUT_TYPE CARD16 +#endif +#if BITMAP_SCANLINE_UNIT == 32 +#define OUT_TYPE CARD32 +#endif +#if BITMAP_SCANLINE_UNIT == 64 +#define OUT_TYPE CARD64 +#endif + + OUT_TYPE *pOut; + int delta = 0; + + sx += pDraw->x; + sy += pDraw->y; + widthInBytes = BitmapBytePad(w); + if(!result) + result = (MiBits *)xalloc(h * widthInBytes); + if (!result) + return (MiBits *)NULL; + bitsPerPixel = pDraw->bitsPerPixel; + bzero((char *)result, h * widthInBytes); + pOut = (OUT_TYPE *) result; + if(bitsPerPixel == 1) + { + pCharsOut = (unsigned char *) result; + width = w; + } + else + { + delta = (widthInBytes / (BITMAP_SCANLINE_UNIT / 8)) - + (w / BITMAP_SCANLINE_UNIT); + width = 1; +#if IMAGE_BYTE_ORDER == MSBFirst + planeNum += (32 - bitsPerPixel); +#endif + } + pt.y = sy; + for (i = h; --i >= 0; pt.y++) + { + pt.x = sx; + if(bitsPerPixel == 1) + { + (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1, + (char *)pCharsOut); + pCharsOut += widthInBytes; + } + else + { + k = 0; + for(j = w; --j >= 0; pt.x++) + { + /* Fetch the next pixel */ + (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1, + (char *)&pixel); + /* + * Now get the bit and insert into a bitmap in XY format. + */ + bit = (pixel >> planeNum) & 1; +#if 0 + /* XXX assuming bit order == byte order */ +#if BITMAP_BIT_ORDER == LSBFirst + bit <<= k; +#else + bit <<= ((BITMAP_SCANLINE_UNIT - 1) - k); +#endif +#else + /* XXX assuming byte order == LSBFirst */ + if (screenInfo.bitmapBitOrder == LSBFirst) + bit <<= k; + else + bit <<= ((screenInfo.bitmapScanlineUnit - 1) - + (k % screenInfo.bitmapScanlineUnit)) + + ((k / screenInfo.bitmapScanlineUnit) * + screenInfo.bitmapScanlineUnit); +#endif + *pOut |= (OUT_TYPE) bit; + k++; + if (k == BITMAP_SCANLINE_UNIT) + { + pOut++; + k = 0; + } + } + pOut += delta; + } + } + return(result); + +} + +/* MIOPQSTIPDRAWABLE -- use pbits as an opaque stipple for pDraw. + * Drawing through the clip mask we SetSpans() the bits into a + * bitmap and stipple those bits onto the destination drawable by doing a + * PolyFillRect over the whole drawable, + * then we invert the bitmap by copying it onto itself with an alu of + * GXinvert, invert the foreground/background colors of the gc, and draw + * the background bits. + * Note how the clipped out bits of the bitmap are always the background + * color so that the stipple never causes FillRect to draw them. + */ +void +miOpqStipDrawable(pDraw, pGC, prgnSrc, pbits, srcx, w, h, dstx, dsty) + DrawablePtr pDraw; + GCPtr pGC; + RegionPtr prgnSrc; + MiBits *pbits; + int srcx, w, h, dstx, dsty; +{ + int oldfill, i; + unsigned long oldfg; + int *pwidth, *pwidthFirst; + ChangeGCVal gcv[6]; + PixmapPtr pStipple, pPixmap; + DDXPointRec oldOrg; + GCPtr pGCT; + DDXPointPtr ppt, pptFirst; + xRectangle rect; + RegionPtr prgnSrcClip; + + pPixmap = (*pDraw->pScreen->CreatePixmap) + (pDraw->pScreen, w + srcx, h, 1); + if (!pPixmap) + return; + + /* Put the image into a 1 bit deep pixmap */ + pGCT = GetScratchGC(1, pDraw->pScreen); + if (!pGCT) + { + (*pDraw->pScreen->DestroyPixmap)(pPixmap); + return; + } + /* First set the whole pixmap to 0 */ + gcv[0].val = 0; + dixChangeGC(NullClient, pGCT, GCBackground, NULL, gcv); + ValidateGC((DrawablePtr)pPixmap, pGCT); + miClearDrawable((DrawablePtr)pPixmap, pGCT); + ppt = pptFirst = (DDXPointPtr)ALLOCATE_LOCAL(h * sizeof(DDXPointRec)); + pwidth = pwidthFirst = (int *)ALLOCATE_LOCAL(h * sizeof(int)); + if(!pptFirst || !pwidthFirst) + { + if (pwidthFirst) DEALLOCATE_LOCAL(pwidthFirst); + if (pptFirst) DEALLOCATE_LOCAL(pptFirst); + FreeScratchGC(pGCT); + return; + } + + /* we need a temporary region because ChangeClip must be assumed + to destroy what it's sent. note that this means we don't + have to free prgnSrcClip ourselves. + */ + prgnSrcClip = REGION_CREATE(pGCT->pScreen, NULL, 0); + REGION_COPY(pGCT->pScreen, prgnSrcClip, prgnSrc); + REGION_TRANSLATE(pGCT->pScreen, prgnSrcClip, srcx, 0); + (*pGCT->funcs->ChangeClip)(pGCT, CT_REGION, prgnSrcClip, 0); + ValidateGC((DrawablePtr)pPixmap, pGCT); + + /* Since we know pDraw is always a pixmap, we never need to think + * about translation here */ + for(i = 0; i < h; i++) + { + ppt->x = 0; + ppt++->y = i; + *pwidth++ = w + srcx; + } + + (*pGCT->ops->SetSpans)((DrawablePtr)pPixmap, pGCT, (char *)pbits, + pptFirst, pwidthFirst, h, TRUE); + DEALLOCATE_LOCAL(pwidthFirst); + DEALLOCATE_LOCAL(pptFirst); + + + /* Save current values from the client GC */ + oldfill = pGC->fillStyle; + pStipple = pGC->stipple; + if(pStipple) + pStipple->refcnt++; + oldOrg = pGC->patOrg; + + /* Set a new stipple in the drawable */ + gcv[0].val = FillStippled; + gcv[1].ptr = pPixmap; + gcv[2].val = dstx - srcx; + gcv[3].val = dsty; + + dixChangeGC(NullClient, pGC, + GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin, + NULL, gcv); + ValidateGC(pDraw, pGC); + + /* Fill the drawable with the stipple. This will draw the + * foreground color whereever 1 bits are set, leaving everything + * with 0 bits untouched. Note that the part outside the clip + * region is all 0s. */ + rect.x = dstx; + rect.y = dsty; + rect.width = w; + rect.height = h; + (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect); + + /* Invert the tiling pixmap. This sets 0s for 1s and 1s for 0s, only + * within the clipping region, the part outside is still all 0s */ + gcv[0].val = GXinvert; + dixChangeGC(NullClient, pGCT, GCFunction, NULL, gcv); + ValidateGC((DrawablePtr)pPixmap, pGCT); + (*pGCT->ops->CopyArea)((DrawablePtr)pPixmap, (DrawablePtr)pPixmap, + pGCT, 0, 0, w + srcx, h, 0, 0); + + /* Swap foreground and background colors on the GC for the drawable. + * Now when we fill the drawable, we will fill in the "Background" + * values */ + oldfg = pGC->fgPixel; + gcv[0].val = pGC->bgPixel; + gcv[1].val = oldfg; + gcv[2].ptr = pPixmap; + dixChangeGC(NullClient, pGC, GCForeground | GCBackground | GCStipple, + NULL, gcv); + ValidateGC(pDraw, pGC); + /* PolyFillRect might have bashed the rectangle */ + rect.x = dstx; + rect.y = dsty; + rect.width = w; + rect.height = h; + (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect); + + /* Now put things back */ + if(pStipple) + pStipple->refcnt--; + gcv[0].val = oldfg; + gcv[1].val = pGC->fgPixel; + gcv[2].val = oldfill; + gcv[3].ptr = pStipple; + gcv[4].val = oldOrg.x; + gcv[5].val = oldOrg.y; + dixChangeGC(NullClient, pGC, + GCForeground | GCBackground | GCFillStyle | GCStipple | + GCTileStipXOrigin | GCTileStipYOrigin, NULL, gcv); + + ValidateGC(pDraw, pGC); + /* put what we hope is a smaller clip region back in the scratch gc */ + (*pGCT->funcs->ChangeClip)(pGCT, CT_NONE, NULL, 0); + FreeScratchGC(pGCT); + (*pDraw->pScreen->DestroyPixmap)(pPixmap); + +} + +/* MICOPYPLANE -- public entry for the CopyPlane request. + * strategy: + * First build up a bitmap out of the bits requested + * build a source clip + * Use the bitmap we've built up as a Stipple for the destination + */ +_X_EXPORT RegionPtr +miCopyPlane(pSrcDrawable, pDstDrawable, + pGC, srcx, srcy, width, height, dstx, dsty, bitPlane) + DrawablePtr pSrcDrawable; + DrawablePtr pDstDrawable; + GCPtr pGC; + int srcx, srcy; + int width, height; + int dstx, dsty; + unsigned long bitPlane; +{ + MiBits *ptile; + BoxRec box; + RegionPtr prgnSrc, prgnExposed; + + /* incorporate the source clip */ + + box.x1 = srcx + pSrcDrawable->x; + box.y1 = srcy + pSrcDrawable->y; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + /* clip to visible drawable */ + if (box.x1 < pSrcDrawable->x) + box.x1 = pSrcDrawable->x; + if (box.y1 < pSrcDrawable->y) + box.y1 = pSrcDrawable->y; + if (box.x2 > pSrcDrawable->x + (int) pSrcDrawable->width) + box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; + if (box.y2 > pSrcDrawable->y + (int) pSrcDrawable->height) + box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; + if (box.x1 > box.x2) + box.x2 = box.x1; + if (box.y1 > box.y2) + box.y2 = box.y1; + prgnSrc = REGION_CREATE(pGC->pScreen, &box, 1); + + if (pSrcDrawable->type != DRAWABLE_PIXMAP) { + /* clip to visible drawable */ + + if (pGC->subWindowMode == IncludeInferiors) + { + RegionPtr clipList = NotClippedByChildren ((WindowPtr) pSrcDrawable); + REGION_INTERSECT(pGC->pScreen, prgnSrc, prgnSrc, clipList); + REGION_DESTROY(pGC->pScreen, clipList); + } else + REGION_INTERSECT(pGC->pScreen, prgnSrc, prgnSrc, + &((WindowPtr)pSrcDrawable)->clipList); + } + + box = *REGION_EXTENTS(pGC->pScreen, prgnSrc); + REGION_TRANSLATE(pGC->pScreen, prgnSrc, -box.x1, -box.y1); + + if ((box.x2 > box.x1) && (box.y2 > box.y1)) + { + /* minimize the size of the data extracted */ + /* note that we convert the plane mask bitPlane into a plane number */ + box.x1 -= pSrcDrawable->x; + box.x2 -= pSrcDrawable->x; + box.y1 -= pSrcDrawable->y; + box.y2 -= pSrcDrawable->y; + ptile = miGetPlane(pSrcDrawable, ffs(bitPlane) - 1, + box.x1, box.y1, + box.x2 - box.x1, box.y2 - box.y1, + (MiBits *) NULL); + if (ptile) + { + miOpqStipDrawable(pDstDrawable, pGC, prgnSrc, ptile, 0, + box.x2 - box.x1, box.y2 - box.y1, + dstx + box.x1 - srcx, dsty + box.y1 - srcy); + xfree(ptile); + } + } + prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, + width, height, dstx, dsty, bitPlane); + REGION_DESTROY(pGC->pScreen, prgnSrc); + return prgnExposed; +} + +/* MIGETIMAGE -- public entry for the GetImage Request + * We're getting the image into a memory buffer. While we have to use GetSpans + * to read a line from the device (since we don't know what that looks like), + * we can just write into the destination buffer + * + * two different strategies are used, depending on whether we're getting the + * image in Z format or XY format + * Z format: + * Line at a time, GetSpans a line into the destination buffer, then if the + * planemask is not all ones, we do a SetSpans into a temporary buffer (to get + * bits turned off) and then another GetSpans to get stuff back (because + * pixmaps are opaque, and we are passed in the memory to write into). This is + * pretty ugly and slow but works. Life is hard. + * XY format: + * get the single plane specified in planemask + */ +_X_EXPORT void +miGetImage(pDraw, sx, sy, w, h, format, planeMask, pDst) + DrawablePtr pDraw; + int sx, sy, w, h; + unsigned int format; + unsigned long planeMask; + char * pDst; +{ + unsigned char depth; + int i, linelength, width, srcx, srcy; + DDXPointRec pt = {0, 0}; + XID gcv[2]; + PixmapPtr pPixmap = (PixmapPtr)NULL; + GCPtr pGC = NULL; + + depth = pDraw->depth; + if(format == ZPixmap) + { + if ( (((1<<depth)-1)&planeMask) != (1<<depth)-1 ) + { + xPoint pt; + + pGC = GetScratchGC(depth, pDraw->pScreen); + if (!pGC) + return; + pPixmap = (*pDraw->pScreen->CreatePixmap) + (pDraw->pScreen, w, 1, depth); + if (!pPixmap) + { + FreeScratchGC(pGC); + return; + } + /* + * Clear the pixmap before doing anything else + */ + ValidateGC((DrawablePtr)pPixmap, pGC); + pt.x = pt.y = 0; + width = w; + (*pGC->ops->FillSpans)((DrawablePtr)pPixmap, pGC, 1, &pt, &width, + TRUE); + + /* alu is already GXCopy */ + gcv[0] = (XID)planeMask; + DoChangeGC(pGC, GCPlaneMask, gcv, 0); + ValidateGC((DrawablePtr)pPixmap, pGC); + } + + linelength = PixmapBytePad(w, depth); + srcx = sx + pDraw->x; + srcy = sy + pDraw->y; + for(i = 0; i < h; i++) + { + pt.x = srcx; + pt.y = srcy + i; + width = w; + (*pDraw->pScreen->GetSpans)(pDraw, w, &pt, &width, 1, pDst); + if (pPixmap) + { + pt.x = 0; + pt.y = 0; + width = w; + (*pGC->ops->SetSpans)((DrawablePtr)pPixmap, pGC, pDst, + &pt, &width, 1, TRUE); + (*pDraw->pScreen->GetSpans)((DrawablePtr)pPixmap, w, &pt, + &width, 1, pDst); + } + pDst += linelength; + } + if (pPixmap) + { + (*pGC->pScreen->DestroyPixmap)(pPixmap); + FreeScratchGC(pGC); + } + } + else + { + (void) miGetPlane(pDraw, ffs(planeMask) - 1, sx, sy, w, h, + (MiBits *)pDst); + } +} + +/* MIPUTIMAGE -- public entry for the PutImage request + * Here we benefit from knowing the format of the bits pointed to by pImage, + * even if we don't know how pDraw represents them. + * Three different strategies are used depending on the format + * XYBitmap Format: + * we just use the Opaque Stipple helper function to cover the destination + * Note that this covers all the planes of the drawable with the + * foreground color (masked with the GC planemask) where there are 1 bits + * and the background color (masked with the GC planemask) where there are + * 0 bits + * XYPixmap format: + * what we're called with is a series of XYBitmaps, but we only want + * each XYPixmap to update 1 plane, instead of updating all of them. + * we set the foreground color to be all 1s and the background to all 0s + * then for each plane, we set the plane mask to only effect that one + * plane and recursive call ourself with the format set to XYBitmap + * (This clever idea courtesy of RGD.) + * ZPixmap format: + * This part is simple, just call SetSpans + */ +_X_EXPORT void +miPutImage(pDraw, pGC, depth, x, y, w, h, leftPad, format, pImage) + DrawablePtr pDraw; + GCPtr pGC; + int depth, x, y, w, h, leftPad; + int format; + char *pImage; +{ + DDXPointPtr pptFirst, ppt; + int *pwidthFirst, *pwidth; + RegionPtr prgnSrc; + BoxRec box; + unsigned long oldFg, oldBg; + XID gcv[3]; + unsigned long oldPlanemask; + unsigned long i; + long bytesPer; + + if (!w || !h) + return; + switch(format) + { + case XYBitmap: + + box.x1 = 0; + box.y1 = 0; + box.x2 = w; + box.y2 = h; + prgnSrc = REGION_CREATE(pGC->pScreen, &box, 1); + + miOpqStipDrawable(pDraw, pGC, prgnSrc, (MiBits *) pImage, + leftPad, w, h, x, y); + REGION_DESTROY(pGC->pScreen, prgnSrc); + break; + + case XYPixmap: + depth = pGC->depth; + oldPlanemask = pGC->planemask; + oldFg = pGC->fgPixel; + oldBg = pGC->bgPixel; + gcv[0] = (XID)~0; + gcv[1] = (XID)0; + DoChangeGC(pGC, GCForeground | GCBackground, gcv, 0); + bytesPer = (long)h * BitmapBytePad(w + leftPad); + + for (i = 1 << (depth-1); i != 0; i >>= 1, pImage += bytesPer) + { + if (i & oldPlanemask) + { + gcv[0] = (XID)i; + DoChangeGC(pGC, GCPlaneMask, gcv, 0); + ValidateGC(pDraw, pGC); + (*pGC->ops->PutImage)(pDraw, pGC, 1, x, y, w, h, leftPad, + XYBitmap, (char *)pImage); + } + } + gcv[0] = (XID)oldPlanemask; + gcv[1] = (XID)oldFg; + gcv[2] = (XID)oldBg; + DoChangeGC(pGC, GCPlaneMask | GCForeground | GCBackground, gcv, 0); + ValidateGC(pDraw, pGC); + break; + + case ZPixmap: + ppt = pptFirst = (DDXPointPtr)ALLOCATE_LOCAL(h * sizeof(DDXPointRec)); + pwidth = pwidthFirst = (int *)ALLOCATE_LOCAL(h * sizeof(int)); + if(!pptFirst || !pwidthFirst) + { + if (pwidthFirst) + DEALLOCATE_LOCAL(pwidthFirst); + if (pptFirst) + DEALLOCATE_LOCAL(pptFirst); + return; + } + if (pGC->miTranslate) + { + x += pDraw->x; + y += pDraw->y; + } + + for(i = 0; i < h; i++) + { + ppt->x = x; + ppt->y = y + i; + ppt++; + *pwidth++ = w; + } + + (*pGC->ops->SetSpans)(pDraw, pGC, (char *)pImage, pptFirst, + pwidthFirst, h, TRUE); + DEALLOCATE_LOCAL(pwidthFirst); + DEALLOCATE_LOCAL(pptFirst); + break; + } +} diff --git a/xserver/mi/mibstore.c b/xserver/mi/mibstore.c new file mode 100644 index 000000000..6653c2345 --- /dev/null +++ b/xserver/mi/mibstore.c @@ -0,0 +1,3879 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by the Regents of the University of California + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, provided +that the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation, and that the name The Open Group not be used in advertising or publicity +pertaining to distribution of the software without specific, written prior +permission. + +The University of California makes no representations about the suitability +of this software for any purpose. It is provided "as is" without express or +implied warranty. + +******************************************************************/ + + +#define NEED_EVENTS +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xmd.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "regionstr.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include <X11/fonts/fontstruct.h> +#include "dixfontstr.h" +#include "dixstruct.h" /* For requestingClient */ +#include "mi.h" +#include "mibstorest.h" + +/* + * When the server fails to allocate a backing store pixmap, if you want + * it to dynamically retry to allocate backing store on every subsequent + * graphics op, you can enable BSEAGER; otherwise, backing store will be + * disabled on the window until it is unmapped and then remapped. + */ +/* #define BSEAGER */ + +/*- + * NOTES ON USAGE: + * + * The functions in this file implement a machine-independent backing-store + * scheme. To use it, the output library must do the following: + * - Provide a SaveAreas function that takes a destination pixmap, a + * region of the areas to save (in the pixmap's coordinate system) + * and the screen origin of the region. It should copy the areas from + * the screen into the pixmap. + * - Provide a RestoreAreas function that takes a source pixmap, a region + * of the areas to restore (in the screen's coordinate system) and the + * origin of the pixmap on the screen. It should copy the areas from + * the pixmap into the screen. + * - Provide a SetClipmaskRgn function that takes a gc and a region + * and merges the region into any CT_PIXMAP client clip that + * is specified in the GC. This routine is only needed if + * miValidateBackingStore will see CT_PIXMAP clip lists; not + * true for any of the sample servers (which convert the PIXMAP + * clip lists into CT_REGION clip lists; an expensive but simple + * to code option). + * - The function placed in a window's ClearToBackground vector must call + * pScreen->ClearBackingStore with the window, followed by + * the window-relative x and y coordinates, followed by the width and + * height of the area to be cleared, followed by the generateExposures + * flag. This has been taken care of in miClearToBackground. + * - Whatever determines GraphicsExpose events for the CopyArea and + * CopyPlane requests should call pWin->backStorage->ExposeCopy + * with the source and destination drawables, the GC used, a source- + * window-relative region of exposed areas, the source and destination + * coordinates and the bitplane copied, if CopyPlane, or 0, if + * CopyArea. + * + * JUSTIFICATION + * This is a cross between saving everything and just saving the + * obscued areas (as in Pike's layers.) This method has the advantage + * of only doing each output operation once per pixel, visible or + * invisible, and avoids having to do all the crufty storage + * management of keeping several separate rectangles. Since the + * ddx layer ouput primitives are required to draw through clipping + * rectangles anyway, sending multiple drawing requests for each of + * several rectangles isn't necessary. (Of course, it could be argued + * that the ddx routines should just take one rectangle each and + * get called multiple times, but that would make taking advantage of + * smart hardware harder, and probably be slower as well.) + */ + +#define SETUP_BACKING_TERSE(pGC) \ + miBSGCPtr pGCPrivate = (miBSGCPtr)(pGC)->devPrivates[miBSGCIndex].ptr; \ + GCFuncs *oldFuncs = pGC->funcs; + +#define SETUP_BACKING(pDrawable,pGC) \ + miBSWindowPtr pBackingStore = \ + (miBSWindowPtr)((WindowPtr)(pDrawable))->backStorage; \ + DrawablePtr pBackingDrawable = (DrawablePtr) \ + pBackingStore->pBackingPixmap; \ + SETUP_BACKING_TERSE(pGC) \ + GCPtr pBackingGC = pGCPrivate->pBackingGC; + +#define PROLOGUE(pGC) { \ + pGC->ops = pGCPrivate->wrapOps;\ + pGC->funcs = pGCPrivate->wrapFuncs; \ + } + +#define EPILOGUE(pGC) { \ + pGCPrivate->wrapOps = (pGC)->ops; \ + (pGC)->ops = &miBSGCOps; \ + (pGC)->funcs = oldFuncs; \ + } + +static void miCreateBSPixmap(WindowPtr pWin, BoxPtr pExtents); +static void miDestroyBSPixmap(WindowPtr pWin); +static void miTileVirtualBS(WindowPtr pWin); +static void miBSAllocate(WindowPtr pWin), miBSFree(WindowPtr pWin); +static Bool miBSCreateGCPrivate(GCPtr pGC); +static void miBSClearBackingRegion(WindowPtr pWin, RegionPtr pRgn); + +#define MoreCopy0 ; +#define MoreCopy2 *dstCopy++ = *srcCopy++; *dstCopy++ = *srcCopy++; +#define MoreCopy4 MoreCopy2 MoreCopy2 + +#define copyData(src,dst,n,morecopy) \ +{ \ + register short *srcCopy = (short *)(src); \ + register short *dstCopy = (short *)(dst); \ + register int i; \ + register int bsx = pBackingStore->x; \ + register int bsy = pBackingStore->y; \ + for (i = n; --i >= 0; ) \ + { \ + *dstCopy++ = *srcCopy++ - bsx; \ + *dstCopy++ = *srcCopy++ - bsy; \ + morecopy \ + } \ +} + +#define copyPoints(src,dst,n,mode) \ +if (mode == CoordModeOrigin) \ +{ \ + copyData(src,dst,n,MoreCopy0); \ +} \ +else \ +{ \ + memmove((char *)(dst), (char *)(src), (n) << 2); \ + *((short *)(dst)) -= pBackingStore->x; \ + *((short *)(dst) + 1) -= pBackingStore->y; \ +} + +/* + * wrappers for screen funcs + */ + +static int miBSScreenIndex; +static unsigned long miBSGeneration = 0; + +static Bool miBSCloseScreen(int i, ScreenPtr pScreen); +static void miBSGetImage(DrawablePtr pDrawable, int sx, int sy, + int w, int h, unsigned int format, + unsigned long planemask, char *pdstLine); +static void miBSGetSpans(DrawablePtr pDrawable, int wMax, + DDXPointPtr ppt, int *pwidth, int nspans, + char *pdstStart); +static Bool miBSChangeWindowAttributes(WindowPtr pWin, + unsigned long mask); +static Bool miBSCreateGC(GCPtr pGC); +static Bool miBSDestroyWindow(WindowPtr pWin); + +/* + * backing store screen functions + */ + +static void miBSSaveDoomedAreas(WindowPtr pWin, RegionPtr pObscured, + int dx, int dy); +static RegionPtr miBSRestoreAreas(WindowPtr pWin, RegionPtr prgnExposed); +static void miBSExposeCopy(WindowPtr pSrc, DrawablePtr pDst, + GCPtr pGC, RegionPtr prgnExposed, + int srcx, int srcy, int dstx, int dsty, + unsigned long plane); +static RegionPtr miBSTranslateBackingStore(WindowPtr pWin, int windx, + int windy, RegionPtr oldClip, + int oldx, int oldy); +static RegionPtr miBSClearBackingStore(WindowPtr pWin, int x, int y, + int w, int h, Bool generateExposures); +static void miBSDrawGuarantee(WindowPtr pWin, GCPtr pGC, + int guarantee); + +/* + * wrapper vectors for GC funcs and ops + */ + +static int miBSGCIndex; + +static void miBSValidateGC(GCPtr pGC, unsigned long stateChanges, + DrawablePtr pDrawable); +static void miBSCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); +static void miBSDestroyGC(GCPtr pGC); +static void miBSChangeGC(GCPtr pGC, unsigned long mask); +static void miBSChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects); +static void miBSDestroyClip(GCPtr pGC); +static void miBSCopyClip(GCPtr pgcDst, GCPtr pgcSrc); + +static GCFuncs miBSGCFuncs = { + miBSValidateGC, + miBSChangeGC, + miBSCopyGC, + miBSDestroyGC, + miBSChangeClip, + miBSDestroyClip, + miBSCopyClip, +}; + +static void miBSFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit, + DDXPointPtr pptInit, int *pwidthInit, + int fSorted); +static void miBSSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc, + DDXPointPtr ppt, int *pwidth, int nspans, + int fSorted); +static void miBSPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, + int x, int y, int w, int h, int leftPad, + int format, char *pBits); +static RegionPtr miBSCopyArea(DrawablePtr pSrc, DrawablePtr pDst, + GCPtr pGC, int srcx, int srcy, int w, int h, + int dstx, int dsty); +static RegionPtr miBSCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, + GCPtr pGC, int srcx, int srcy, int w, int h, + int dstx, int dsty, unsigned long plane); +static void miBSPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, + int npt, xPoint *pptInit); +static void miBSPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, + int npt, DDXPointPtr pptInit); +static void miBSPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, + xSegment *pSegs); +static void miBSPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, + int nrects, xRectangle *pRects); +static void miBSPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, + xArc *parcs); +static void miBSFillPolygon(DrawablePtr pDrawable, GCPtr pGC, + int shape, int mode, int count, + DDXPointPtr pPts); +static void miBSPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, + int nrectFill, xRectangle *prectInit); +static void miBSPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, + int narcs, xArc *parcs); +static int miBSPolyText8(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, int count, char *chars); +static int miBSPolyText16(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, int count, + unsigned short *chars); +static void miBSImageText8(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, int count, char *chars); +static void miBSImageText16(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, int count, + unsigned short *chars); +static void miBSImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase); +static void miBSPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase); +static void miBSPushPixels(GCPtr pGC, PixmapPtr pBitMap, + DrawablePtr pDst, int w, int h, + int x, int y); + +static GCOps miBSGCOps = { + miBSFillSpans, miBSSetSpans, miBSPutImage, + miBSCopyArea, miBSCopyPlane, miBSPolyPoint, + miBSPolylines, miBSPolySegment, miBSPolyRectangle, + miBSPolyArc, miBSFillPolygon, miBSPolyFillRect, + miBSPolyFillArc, miBSPolyText8, miBSPolyText16, + miBSImageText8, miBSImageText16, miBSImageGlyphBlt, + miBSPolyGlyphBlt, miBSPushPixels +}; + +#define FUNC_PROLOGUE(pGC, pPriv) \ + ((pGC)->funcs = pPriv->wrapFuncs),\ + ((pGC)->ops = pPriv->wrapOps) + +#define FUNC_EPILOGUE(pGC, pPriv) \ + ((pGC)->funcs = &miBSGCFuncs),\ + ((pGC)->ops = &miBSGCOps) + +/* + * every GC in the server is initially wrapped with these + * "cheap" functions. This allocates no memory and is used + * to discover GCs used with windows which have backing + * store enabled + */ + +static void miBSCheapValidateGC(GCPtr pGC, unsigned long stateChanges, + DrawablePtr pDrawable); +static void miBSCheapCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); +static void miBSCheapDestroyGC(GCPtr pGC); +static void miBSCheapChangeGC(GCPtr pGC, unsigned long mask); +static void miBSCheapChangeClip(GCPtr pGC, int type, pointer pvalue, + int nrects); +static void miBSCheapDestroyClip(GCPtr pGC); +static void miBSCheapCopyClip(GCPtr pgcDst, GCPtr pgcSrc); + +static GCFuncs miBSCheapGCFuncs = { + miBSCheapValidateGC, + miBSCheapChangeGC, + miBSCheapCopyGC, + miBSCheapDestroyGC, + miBSCheapChangeClip, + miBSCheapDestroyClip, + miBSCheapCopyClip, +}; + +#define CHEAP_FUNC_PROLOGUE(pGC) \ + ((pGC)->funcs = (GCFuncs *) (pGC)->devPrivates[miBSGCIndex].ptr) + +#define CHEAP_FUNC_EPILOGUE(pGC) \ + ((pGC)->funcs = &miBSCheapGCFuncs) + +/* + * called from device screen initialization proc. Gets a GCPrivateIndex + * and wraps appropriate per-screen functions. pScreen->BackingStoreFuncs + * must be previously initialized. + */ + +_X_EXPORT void +miInitializeBackingStore (pScreen) + ScreenPtr pScreen; +{ + miBSScreenPtr pScreenPriv; + + if (miBSGeneration != serverGeneration) + { + miBSScreenIndex = AllocateScreenPrivateIndex (); + if (miBSScreenIndex < 0) + return; + miBSGCIndex = AllocateGCPrivateIndex (); + miBSGeneration = serverGeneration; + } + if (!AllocateGCPrivate(pScreen, miBSGCIndex, 0)) + return; + pScreenPriv = (miBSScreenPtr) xalloc (sizeof (miBSScreenRec)); + if (!pScreenPriv) + return; + + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreenPriv->GetImage = pScreen->GetImage; + pScreenPriv->GetSpans = pScreen->GetSpans; + pScreenPriv->ChangeWindowAttributes = pScreen->ChangeWindowAttributes; + pScreenPriv->CreateGC = pScreen->CreateGC; + pScreenPriv->DestroyWindow = pScreen->DestroyWindow; + + pScreen->CloseScreen = miBSCloseScreen; + pScreen->GetImage = miBSGetImage; + pScreen->GetSpans = miBSGetSpans; + pScreen->ChangeWindowAttributes = miBSChangeWindowAttributes; + pScreen->CreateGC = miBSCreateGC; + pScreen->DestroyWindow = miBSDestroyWindow; + + pScreen->SaveDoomedAreas = miBSSaveDoomedAreas; + pScreen->RestoreAreas = miBSRestoreAreas; + pScreen->ExposeCopy = miBSExposeCopy; + pScreen->TranslateBackingStore = miBSTranslateBackingStore; + pScreen->ClearBackingStore = miBSClearBackingStore; + pScreen->DrawGuarantee = miBSDrawGuarantee; + + pScreen->devPrivates[miBSScreenIndex].ptr = (pointer) pScreenPriv; +} + +/* + * Screen function wrappers + */ + +#define SCREEN_PROLOGUE(pScreen, field)\ + ((pScreen)->field = \ + ((miBSScreenPtr) \ + (pScreen)->devPrivates[miBSScreenIndex].ptr)->field) + +#define SCREEN_EPILOGUE(pScreen, field, wrapper)\ + ((pScreen)->field = wrapper) + +/* + * CloseScreen wrapper -- unwrap everything, free the private data + * and call the wrapped function + */ + +static Bool +miBSCloseScreen (i, pScreen) + int i; + ScreenPtr pScreen; +{ + miBSScreenPtr pScreenPriv; + + pScreenPriv = (miBSScreenPtr) pScreen->devPrivates[miBSScreenIndex].ptr; + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + pScreen->GetImage = pScreenPriv->GetImage; + pScreen->GetSpans = pScreenPriv->GetSpans; + pScreen->ChangeWindowAttributes = pScreenPriv->ChangeWindowAttributes; + pScreen->CreateGC = pScreenPriv->CreateGC; + + xfree ((pointer) pScreenPriv); + + return (*pScreen->CloseScreen) (i, pScreen); +} + +static void miBSFillVirtualBits(DrawablePtr pDrawable, GCPtr pGC, + RegionPtr pRgn, int x, int y, int state, + PixUnion pixunion, unsigned long planemask); + +static void +miBSGetImage (pDrawable, sx, sy, w, h, format, planemask, pdstLine) + DrawablePtr pDrawable; + int sx, sy, w, h; + unsigned int format; + unsigned long planemask; + char *pdstLine; +{ + ScreenPtr pScreen = pDrawable->pScreen; + BoxRec bounds; + unsigned char depth; + + SCREEN_PROLOGUE (pScreen, GetImage); + + if (pDrawable->type != DRAWABLE_PIXMAP && + ((WindowPtr) pDrawable)->visibility != VisibilityUnobscured) + { + PixmapPtr pPixmap; + miBSWindowPtr pWindowPriv; + GCPtr pGC = NULL; + WindowPtr pWin, pSrcWin; + int xoff, yoff; + RegionRec Remaining; + RegionRec Border; + RegionRec Inside; + BoxPtr pBox; + int n; + + pWin = (WindowPtr) pDrawable; + pPixmap = 0; + depth = pDrawable->depth; + bounds.x1 = sx + pDrawable->x; + bounds.y1 = sy + pDrawable->y; + bounds.x2 = bounds.x1 + w; + bounds.y2 = bounds.y1 + h; + REGION_INIT(pScreen, &Remaining, &bounds, 0); + for (;;) + { + bounds.x1 = sx + pDrawable->x - pWin->drawable.x; + bounds.y1 = sy + pDrawable->y - pWin->drawable.y; + bounds.x2 = bounds.x1 + w; + bounds.y2 = bounds.y1 + h; + if (pWin->viewable && pWin->backStorage && + pWin->drawable.depth == depth && + (RECT_IN_REGION(pScreen, &(pWindowPriv = + (miBSWindowPtr) pWin->backStorage)->SavedRegion, + &bounds) != rgnOUT || + RECT_IN_REGION(pScreen, &Remaining, + REGION_EXTENTS(pScreen, &pWin->borderSize)) != rgnOUT)) + { + if (!pPixmap) + { + XID subWindowMode = IncludeInferiors; + int x, y; + + pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, depth); + if (!pPixmap) + goto punt; + pGC = GetScratchGC (depth, pScreen); + if (!pGC) + { + (*pScreen->DestroyPixmap) (pPixmap); + goto punt; + } + ChangeGC (pGC, GCSubwindowMode, &subWindowMode); + ValidateGC ((DrawablePtr)pPixmap, pGC); + REGION_NULL(pScreen, &Border); + REGION_NULL(pScreen, &Inside); + pSrcWin = (WindowPtr) pDrawable; + x = sx; + y = sy; + if (pSrcWin->parent) + { + x += pSrcWin->origin.x; + y += pSrcWin->origin.y; + pSrcWin = pSrcWin->parent; + } + (*pGC->ops->CopyArea) ((DrawablePtr)pSrcWin, + (DrawablePtr)pPixmap, pGC, + x, y, w, h, + 0, 0); + REGION_SUBTRACT(pScreen, &Remaining, &Remaining, + &((WindowPtr) pDrawable)->borderClip); + } + + REGION_INTERSECT(pScreen, &Inside, &Remaining, &pWin->winSize); + REGION_TRANSLATE(pScreen, &Inside, + -pWin->drawable.x, + -pWin->drawable.y); + REGION_INTERSECT(pScreen, &Inside, &Inside, + &pWindowPriv->SavedRegion); + + /* offset of sub-window in GetImage pixmap */ + xoff = pWin->drawable.x - pDrawable->x - sx; + yoff = pWin->drawable.y - pDrawable->y - sy; + + if (REGION_NUM_RECTS(&Inside) > 0) + { + switch (pWindowPriv->status) + { + case StatusContents: + pBox = REGION_RECTS(&Inside); + for (n = REGION_NUM_RECTS(&Inside); --n >= 0;) + { + (*pGC->ops->CopyArea) ( + (DrawablePtr)pWindowPriv->pBackingPixmap, + (DrawablePtr)pPixmap, pGC, + pBox->x1 - pWindowPriv->x, + pBox->y1 - pWindowPriv->y, + pBox->x2 - pBox->x1, + pBox->y2 - pBox->y1, + pBox->x1 + xoff, + pBox->y1 + yoff); + ++pBox; + } + break; + case StatusVirtual: + case StatusVDirty: + if (pWindowPriv->backgroundState == BackgroundPixmap || + pWindowPriv->backgroundState == BackgroundPixel) + miBSFillVirtualBits ((DrawablePtr) pPixmap, pGC, &Inside, + xoff, yoff, + (int) pWindowPriv->backgroundState, + pWindowPriv->background, ~0L); + break; + } + } + REGION_SUBTRACT(pScreen, &Border, &pWin->borderSize, + &pWin->winSize); + REGION_INTERSECT(pScreen, &Border, &Border, &Remaining); + if (REGION_NUM_RECTS(&Border) > 0) + { + REGION_TRANSLATE(pScreen, &Border, -pWin->drawable.x, + -pWin->drawable.y); + miBSFillVirtualBits ((DrawablePtr) pPixmap, pGC, &Border, + xoff, yoff, + pWin->borderIsPixel ? (int)BackgroundPixel : (int)BackgroundPixmap, + pWin->border, ~0L); + } + } + + if (pWin->viewable && pWin->firstChild) + pWin = pWin->firstChild; + else + { + while (!pWin->nextSib && pWin != (WindowPtr) pDrawable) + pWin = pWin->parent; + if (pWin == (WindowPtr) pDrawable) + break; + pWin = pWin->nextSib; + } + } + + REGION_UNINIT(pScreen, &Remaining); + + if (pPixmap) + { + REGION_UNINIT(pScreen, &Border); + REGION_UNINIT(pScreen, &Inside); + (*pScreen->GetImage) ((DrawablePtr) pPixmap, + 0, 0, w, h, format, planemask, pdstLine); + (*pScreen->DestroyPixmap) (pPixmap); + FreeScratchGC (pGC); + } + else + { + goto punt; + } + } + else + { +punt: ; + (*pScreen->GetImage) (pDrawable, sx, sy, w, h, + format, planemask, pdstLine); + } + + SCREEN_EPILOGUE (pScreen, GetImage, miBSGetImage); +} + +static void +miBSGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart) + DrawablePtr pDrawable; + int wMax; + DDXPointPtr ppt; + int *pwidth; + int nspans; + char *pdstStart; +{ + ScreenPtr pScreen = pDrawable->pScreen; + BoxRec bounds; + int i; + WindowPtr pWin; + int dx, dy; + + SCREEN_PROLOGUE (pScreen, GetSpans); + + if (pDrawable->type != DRAWABLE_PIXMAP && ((WindowPtr) pDrawable)->backStorage) + { + PixmapPtr pPixmap; + miBSWindowPtr pWindowPriv; + GCPtr pGC; + + pWin = (WindowPtr) pDrawable; + pWindowPriv = (miBSWindowPtr) pWin->backStorage; + pPixmap = pWindowPriv->pBackingPixmap; + + bounds.x1 = ppt->x; + bounds.y1 = ppt->y; + bounds.x2 = bounds.x1 + *pwidth; + bounds.y2 = ppt->y; + for (i = 0; i < nspans; i++) + { + if (ppt[i].x < bounds.x1) + bounds.x1 = ppt[i].x; + if (ppt[i].x + pwidth[i] > bounds.x2) + bounds.x2 = ppt[i].x + pwidth[i]; + if (ppt[i].y < bounds.y1) + bounds.y1 = ppt[i].y; + else if (ppt[i].y > bounds.y2) + bounds.y2 = ppt[i].y; + } + + switch (RECT_IN_REGION(pScreen, &pWindowPriv->SavedRegion, &bounds)) + { + case rgnPART: + if (!pPixmap) + { + miCreateBSPixmap (pWin, NullBox); + if (!(pPixmap = pWindowPriv->pBackingPixmap)) + break; + } + pWindowPriv->status = StatusNoPixmap; + pGC = GetScratchGC(pPixmap->drawable.depth, + pPixmap->drawable.pScreen); + if (pGC) + { + ValidateGC ((DrawablePtr) pPixmap, pGC); + (*pGC->ops->CopyArea) + (pDrawable, (DrawablePtr) pPixmap, pGC, + bounds.x1, bounds.y1, + bounds.x2 - bounds.x1, bounds.y2 - bounds.y1, + bounds.x1 + pPixmap->drawable.x - pWin->drawable.x - + pWindowPriv->x, + bounds.y1 + pPixmap->drawable.y - pWin->drawable.y - + pWindowPriv->y); + FreeScratchGC(pGC); + } + pWindowPriv->status = StatusContents; + /* fall through */ + case rgnIN: + if (!pPixmap) + { + miCreateBSPixmap (pWin, NullBox); + if (!(pPixmap = pWindowPriv->pBackingPixmap)) + break; + } + dx = pPixmap->drawable.x - pWin->drawable.x - pWindowPriv->x; + dy = pPixmap->drawable.y - pWin->drawable.y - pWindowPriv->y; + for (i = 0; i < nspans; i++) + { + ppt[i].x += dx; + ppt[i].y += dy; + } + (*pScreen->GetSpans) ((DrawablePtr) pPixmap, wMax, ppt, pwidth, + nspans, pdstStart); + break; + case rgnOUT: + (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, + pdstStart); + break; + } + } + else + { + (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); + } + + SCREEN_EPILOGUE (pScreen, GetSpans, miBSGetSpans); +} + +static Bool +miBSChangeWindowAttributes (pWin, mask) + WindowPtr pWin; + unsigned long mask; +{ + ScreenPtr pScreen; + Bool ret; + + pScreen = pWin->drawable.pScreen; + + SCREEN_PROLOGUE (pScreen, ChangeWindowAttributes); + + ret = (*pScreen->ChangeWindowAttributes) (pWin, mask); + + if (ret && (mask & CWBackingStore)) + { + if (pWin->backingStore != NotUseful || pWin->DIXsaveUnder) + miBSAllocate (pWin); + else + miBSFree (pWin); + } + + SCREEN_EPILOGUE (pScreen, ChangeWindowAttributes, miBSChangeWindowAttributes); + + return ret; +} + +/* + * GC Create wrapper. Set up the cheap GC func wrappers to track + * GC validation on BackingStore windows + */ + +static Bool +miBSCreateGC (pGC) + GCPtr pGC; +{ + ScreenPtr pScreen = pGC->pScreen; + Bool ret; + + SCREEN_PROLOGUE (pScreen, CreateGC); + + if ( (ret = (*pScreen->CreateGC) (pGC)) ) + { + pGC->devPrivates[miBSGCIndex].ptr = (pointer) pGC->funcs; + pGC->funcs = &miBSCheapGCFuncs; + } + + SCREEN_EPILOGUE (pScreen, CreateGC, miBSCreateGC); + + return ret; +} + +static Bool +miBSDestroyWindow (pWin) + WindowPtr pWin; +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + Bool ret; + + SCREEN_PROLOGUE (pScreen, DestroyWindow); + + ret = (*pScreen->DestroyWindow) (pWin); + + miBSFree (pWin); + + SCREEN_EPILOGUE (pScreen, DestroyWindow, miBSDestroyWindow); + + return ret; +} + +/* + * cheap GC func wrappers. Simply track validation on windows + * with backing store to enable the real func/op wrappers + */ + +static void +miBSCheapValidateGC (pGC, stateChanges, pDrawable) + GCPtr pGC; + unsigned long stateChanges; + DrawablePtr pDrawable; +{ + CHEAP_FUNC_PROLOGUE (pGC); + + if (pDrawable->type != DRAWABLE_PIXMAP && + ((WindowPtr) pDrawable)->backStorage != NULL && + miBSCreateGCPrivate (pGC)) + { + (*pGC->funcs->ValidateGC) (pGC, stateChanges, pDrawable); + } + else + { + (*pGC->funcs->ValidateGC) (pGC, stateChanges, pDrawable); + + /* rewrap funcs as Validate may have changed them */ + pGC->devPrivates[miBSGCIndex].ptr = (pointer) pGC->funcs; + + CHEAP_FUNC_EPILOGUE (pGC); + } +} + +static void +miBSCheapChangeGC (pGC, mask) + GCPtr pGC; + unsigned long mask; +{ + CHEAP_FUNC_PROLOGUE (pGC); + + (*pGC->funcs->ChangeGC) (pGC, mask); + + CHEAP_FUNC_EPILOGUE (pGC); +} + +static void +miBSCheapCopyGC (pGCSrc, mask, pGCDst) + GCPtr pGCSrc, pGCDst; + unsigned long mask; +{ + CHEAP_FUNC_PROLOGUE (pGCDst); + + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + + CHEAP_FUNC_EPILOGUE (pGCDst); +} + +static void +miBSCheapDestroyGC (pGC) + GCPtr pGC; +{ + CHEAP_FUNC_PROLOGUE (pGC); + + (*pGC->funcs->DestroyGC) (pGC); + + /* leave it unwrapped */ +} + +static void +miBSCheapChangeClip (pGC, type, pvalue, nrects) + GCPtr pGC; + int type; + pointer pvalue; + int nrects; +{ + CHEAP_FUNC_PROLOGUE (pGC); + + (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); + + CHEAP_FUNC_EPILOGUE (pGC); +} + +static void +miBSCheapCopyClip(pgcDst, pgcSrc) + GCPtr pgcDst, pgcSrc; +{ + CHEAP_FUNC_PROLOGUE (pgcDst); + + (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); + + CHEAP_FUNC_EPILOGUE (pgcDst); +} + +static void +miBSCheapDestroyClip(pGC) + GCPtr pGC; +{ + CHEAP_FUNC_PROLOGUE (pGC); + + (* pGC->funcs->DestroyClip)(pGC); + + CHEAP_FUNC_EPILOGUE (pGC); +} + +/* + * create the full func/op wrappers for a GC + */ + +static Bool +miBSCreateGCPrivate (pGC) + GCPtr pGC; +{ + miBSGCRec *pPriv; + + pPriv = (miBSGCRec *) xalloc (sizeof (miBSGCRec)); + if (!pPriv) + return FALSE; + pPriv->pBackingGC = NULL; + pPriv->guarantee = GuaranteeNothing; + pPriv->serialNumber = 0; + pPriv->stateChanges = (1 << (GCLastBit + 1)) - 1; + pPriv->wrapOps = pGC->ops; + pPriv->wrapFuncs = pGC->funcs; + pGC->funcs = &miBSGCFuncs; + pGC->ops = &miBSGCOps; + pGC->devPrivates[miBSGCIndex].ptr = (pointer) pPriv; + return TRUE; +} + +static void +miBSDestroyGCPrivate (GCPtr pGC) +{ + miBSGCRec *pPriv; + + pPriv = (miBSGCRec *) pGC->devPrivates[miBSGCIndex].ptr; + if (pPriv) + { + pGC->devPrivates[miBSGCIndex].ptr = (pointer) pPriv->wrapFuncs; + pGC->funcs = &miBSCheapGCFuncs; + pGC->ops = pPriv->wrapOps; + if (pPriv->pBackingGC) + FreeGC (pPriv->pBackingGC, (GContext) 0); + xfree ((pointer) pPriv); + } +} + +/* + * GC ops -- wrap each GC operation with our own function + */ + +/*- + *----------------------------------------------------------------------- + * miBSFillSpans -- + * Perform a FillSpans, routing output to backing-store as needed. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSFillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted) + DrawablePtr pDrawable; + GCPtr pGC; + int nInit; /* number of spans to fill */ + DDXPointPtr pptInit; /* pointer to list of start points */ + int *pwidthInit; /* pointer to list of n widths */ + int fSorted; +{ + DDXPointPtr pptCopy, pptReset; + int *pwidthCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pptCopy = (DDXPointPtr)ALLOCATE_LOCAL(nInit*sizeof(DDXPointRec)); + pwidthCopy=(int *)ALLOCATE_LOCAL(nInit*sizeof(int)); + if (pptCopy && pwidthCopy) + { + copyData(pptInit, pptCopy, nInit, MoreCopy0); + memmove((char *)pwidthCopy,(char *)pwidthInit,nInit*sizeof(int)); + + (* pGC->ops->FillSpans)(pDrawable, pGC, nInit, pptInit, + pwidthInit, fSorted); + if (pGC->miTranslate) + { + int dx, dy; + int nReset; + + pptReset = pptCopy; + dx = pDrawable->x - pBackingDrawable->x; + dy = pDrawable->y - pBackingDrawable->y; + nReset = nInit; + while (nReset--) + { + pptReset->x -= dx; + pptReset->y -= dy; + ++pptReset; + } + } + (* pBackingGC->ops->FillSpans)(pBackingDrawable, + pBackingGC, nInit, pptCopy, pwidthCopy, + fSorted); + } + if (pwidthCopy) DEALLOCATE_LOCAL(pwidthCopy); + if (pptCopy) DEALLOCATE_LOCAL(pptCopy); + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSSetSpans -- + * Perform a SetSpans, routing output to backing-store as needed. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted) + DrawablePtr pDrawable; + GCPtr pGC; + char *psrc; + register DDXPointPtr ppt; + int *pwidth; + int nspans; + int fSorted; +{ + DDXPointPtr pptCopy, pptReset; + int *pwidthCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pptCopy = (DDXPointPtr)ALLOCATE_LOCAL(nspans*sizeof(DDXPointRec)); + pwidthCopy=(int *)ALLOCATE_LOCAL(nspans*sizeof(int)); + if (pptCopy && pwidthCopy) + { + copyData(ppt, pptCopy, nspans, MoreCopy0); + memmove((char *)pwidthCopy,(char *)pwidth,nspans*sizeof(int)); + + (* pGC->ops->SetSpans)(pDrawable, pGC, psrc, ppt, pwidth, + nspans, fSorted); + if (pGC->miTranslate) + { + int dx, dy; + int nReset; + + pptReset = pptCopy; + dx = pDrawable->x - pBackingDrawable->x; + dy = pDrawable->y - pBackingDrawable->y; + nReset = nspans; + while (nReset--) + { + pptReset->x -= dx; + pptReset->y -= dy; + ++pptReset; + } + } + (* pBackingGC->ops->SetSpans)(pBackingDrawable, pBackingGC, + psrc, pptCopy, pwidthCopy, nspans, fSorted); + } + if (pwidthCopy) DEALLOCATE_LOCAL(pwidthCopy); + if (pptCopy) DEALLOCATE_LOCAL(pptCopy); + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPutImage -- + * Perform a PutImage, routing output to backing-store as needed. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits) + DrawablePtr pDrawable; + GCPtr pGC; + int depth; + int x; + int y; + int w; + int h; + int leftPad; + int format; + char *pBits; +{ + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + (*pGC->ops->PutImage)(pDrawable, pGC, + depth, x, y, w, h, leftPad, format, pBits); + (*pBackingGC->ops->PutImage)(pBackingDrawable, pBackingGC, + depth, x - pBackingStore->x, y - pBackingStore->y, + w, h, leftPad, format, pBits); + + EPILOGUE (pGC); +} + +typedef RegionPtr (* CopyAreaProcPtr)(DrawablePtr, DrawablePtr, GCPtr, + int, int, int, int, int, int); +typedef RegionPtr (* CopyPlaneProcPtr)(DrawablePtr, DrawablePtr, GCPtr, + int, int, int, int, int, int, + unsigned long bitPlane); +/*- + *----------------------------------------------------------------------- + * miBSDoCopy -- + * Perform a CopyArea or CopyPlane within a window that has backing + * store enabled. + * + * Results: + * TRUE if the copy was performed or FALSE if a regular one should + * be done. + * + * Side Effects: + * Things are copied (no s***!) + * + * Notes: + * The idea here is to form two regions that cover the source box. + * One contains the exposed rectangles while the other contains + * the obscured ones. An array of <box, drawable> pairs is then + * formed where the <box> indicates the area to be copied and the + * <drawable> indicates from where it is to be copied (exposed regions + * come from the screen while obscured ones come from the backing + * pixmap). The array 'sequence' is then filled with the indices of + * the pairs in the order in which they should be copied to prevent + * things from getting screwed up. A call is also made through the + * backingGC to take care of any copying into the backing pixmap. + * + *----------------------------------------------------------------------- + */ +static Bool +miBSDoCopy( + WindowPtr pWin, /* Window being scrolled */ + GCPtr pGC, /* GC we're called through */ + int srcx, /* X of source rectangle */ + int srcy, /* Y of source rectangle */ + int w, /* Width of source rectangle */ + int h, /* Height of source rectangle */ + int dstx, /* X of destination rectangle */ + int dsty, /* Y of destination rectangle */ + unsigned long plane, /* Plane to copy (0 for CopyArea) */ + CopyPlaneProcPtr copyProc, /* Procedure to call to perform the copy */ + RegionPtr *ppRgn) /* resultant Graphics Expose region */ +{ + RegionPtr pRgnExp; /* Exposed region */ + RegionPtr pRgnObs; /* Obscured region */ + BoxRec box; /* Source box (screen coord) */ + struct BoxDraw { + BoxPtr pBox; /* Source box */ + enum { + win, pix + } source; /* Place from which to copy */ + } *boxes; /* Array of box/drawable pairs covering + * source box. */ + int *sequence; /* Sequence of boxes to move */ + register int i, j, k, l, y; + register BoxPtr pBox; + int dx, dy, nrects; + Bool graphicsExposures; + CopyPlaneProcPtr pixCopyProc; + int numRectsExp, numRectsObs; + BoxPtr pBoxExp, pBoxObs; + + SETUP_BACKING (pWin, pGC); + (void)oldFuncs; + + /* + * Create a region of exposed boxes in pRgnExp. + */ + box.x1 = srcx + pWin->drawable.x; + box.x2 = box.x1 + w; + box.y1 = srcy + pWin->drawable.y; + box.y2 = box.y1 + h; + + pRgnExp = REGION_CREATE(pGC->pScreen, &box, 1); + REGION_INTERSECT(pGC->pScreen, pRgnExp, pRgnExp, &pWin->clipList); + pRgnObs = REGION_CREATE(pGC->pScreen, NULL, 1); + REGION_INVERSE( pGC->pScreen, pRgnObs, pRgnExp, &box); + + /* + * Translate regions into window coordinates for proper calls + * to the copyProc, then make sure none of the obscured region sticks + * into invalid areas of the backing pixmap. + */ + REGION_TRANSLATE(pGC->pScreen, pRgnExp, + -pWin->drawable.x, + -pWin->drawable.y); + REGION_TRANSLATE(pGC->pScreen, pRgnObs, + -pWin->drawable.x, + -pWin->drawable.y); + REGION_INTERSECT(pGC->pScreen, pRgnObs, pRgnObs, &pBackingStore->SavedRegion); + + /* + * If the obscured region is empty, there's no point being fancy. + */ + if (!REGION_NOTEMPTY(pGC->pScreen, pRgnObs)) + { + REGION_DESTROY(pGC->pScreen, pRgnExp); + REGION_DESTROY(pGC->pScreen, pRgnObs); + + return (FALSE); + } + + numRectsExp = REGION_NUM_RECTS(pRgnExp); + pBoxExp = REGION_RECTS(pRgnExp); + pBoxObs = REGION_RECTS(pRgnObs); + numRectsObs = REGION_NUM_RECTS(pRgnObs); + nrects = numRectsExp + numRectsObs; + + boxes = (struct BoxDraw *)ALLOCATE_LOCAL(nrects * sizeof(struct BoxDraw)); + sequence = (int *) ALLOCATE_LOCAL(nrects * sizeof(int)); + *ppRgn = NULL; + + if (!boxes || !sequence) + { + if (sequence) DEALLOCATE_LOCAL(sequence); + if (boxes) DEALLOCATE_LOCAL(boxes); + REGION_DESTROY(pGC->pScreen, pRgnExp); + REGION_DESTROY(pGC->pScreen, pRgnObs); + + return(TRUE); + } + + /* + * Order the boxes in the two regions so we know from which drawable + * to copy which box, storing the result in the boxes array + */ + for (i = 0, j = 0, k = 0; + (i < numRectsExp) && (j < numRectsObs); + k++) + { + if (pBoxExp[i].y1 < pBoxObs[j].y1) + { + boxes[k].pBox = &pBoxExp[i]; + boxes[k].source = win; + i++; + } + else if ((pBoxObs[j].y1 < pBoxExp[i].y1) || + (pBoxObs[j].x1 < pBoxExp[i].x1)) + { + boxes[k].pBox = &pBoxObs[j]; + boxes[k].source = pix; + j++; + } + else + { + boxes[k].pBox = &pBoxExp[i]; + boxes[k].source = win; + i++; + } + } + + /* + * Catch any leftover boxes from either region (note that only + * one can have leftover boxes...) + */ + if (i != numRectsExp) + { + do + { + boxes[k].pBox = &pBoxExp[i]; + boxes[k].source = win; + i++; + k++; + } while (i < numRectsExp); + + } + else + { + do + { + boxes[k].pBox = &pBoxObs[j]; + boxes[k].source = pix; + j++; + k++; + } while (j < numRectsObs); + } + + if (dsty <= srcy) + { + /* + * Scroll up or vertically stationary, so vertical order is ok. + */ + if (dstx <= srcx) + { + /* + * Scroll left or horizontally stationary, so horizontal order + * is ok as well. + */ + for (i = 0; i < nrects; i++) + { + sequence[i] = i; + } + } + else + { + /* + * Scroll right. Need to reverse the rectangles within each + * band. + */ + for (i = 0, j = 1, k = 0; + i < nrects; + j = i + 1, k = i) + { + y = boxes[i].pBox->y1; + while ((j < nrects) && (boxes[j].pBox->y1 == y)) + { + j++; + } + for (j--; j >= k; j--, i++) + { + sequence[i] = j; + } + } + } + } + else + { + /* + * Scroll down. Must reverse vertical banding, at least. + */ + if (dstx < srcx) + { + /* + * Scroll left. Horizontal order is ok. + */ + for (i = nrects - 1, j = i - 1, k = i, l = 0; + i >= 0; + j = i - 1, k = i) + { + /* + * Find extent of current horizontal band, then reverse + * the order of the whole band. + */ + y = boxes[i].pBox->y1; + while ((j >= 0) && (boxes[j].pBox->y1 == y)) + { + j--; + } + for (j++; j <= k; j++, i--, l++) + { + sequence[l] = j; + } + } + } + else + { + /* + * Scroll right or horizontal stationary. + * Reverse horizontal order as well (if stationary, horizontal + * order can be swapped without penalty and this is faster + * to compute). + */ + for (i = 0, j = nrects - 1; i < nrects; i++, j--) + { + sequence[i] = j; + } + } + } + + /* + * XXX: To avoid getting multiple NoExpose events from this operation, + * we turn OFF graphicsExposures in the gc and deal with any uncopied + * areas later, if there's something not in backing-store. + */ + + graphicsExposures = pGC->graphicsExposures; + pGC->graphicsExposures = FALSE; + + dx = dstx - srcx; + dy = dsty - srcy; + + /* + * Figure out which copy procedure to use from the backing GC. Note we + * must do this because some implementations (sun's, e.g.) have + * pBackingGC a fake GC with the real one below it, thus the devPriv for + * pBackingGC won't be what the output library expects. + */ + if (plane != 0) + { + pixCopyProc = pBackingGC->ops->CopyPlane; + } + else + { + pixCopyProc = (CopyPlaneProcPtr)pBackingGC->ops->CopyArea; + } + + for (i = 0; i < nrects; i++) + { + pBox = boxes[sequence[i]].pBox; + + /* + * If we're copying from the pixmap, we need to place its contents + * onto the screen before scrolling the pixmap itself. If we're copying + * from the window, we need to copy its contents into the pixmap before + * we scroll the window itself. + */ + if (boxes[sequence[i]].source == pix) + { + (void) (* copyProc) (pBackingDrawable, &(pWin->drawable), pGC, + pBox->x1 - pBackingStore->x, + pBox->y1 - pBackingStore->y, + pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, + pBox->x1 + dx, pBox->y1 + dy, plane); + (void) (* pixCopyProc) (pBackingDrawable, pBackingDrawable, pBackingGC, + pBox->x1 - pBackingStore->x, + pBox->y1 - pBackingStore->y, + pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, + pBox->x1 + dx - pBackingStore->x, + pBox->y1 + dy - pBackingStore->y, plane); + } + else + { + (void) (* pixCopyProc) (&(pWin->drawable), pBackingDrawable, pBackingGC, + pBox->x1, pBox->y1, + pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, + pBox->x1 + dx - pBackingStore->x, + pBox->y1 + dy - pBackingStore->y, plane); + (void) (* copyProc) (&(pWin->drawable), &(pWin->drawable), pGC, + pBox->x1, pBox->y1, + pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, + pBox->x1 + dx, pBox->y1 + dy, plane); + } + } + DEALLOCATE_LOCAL(sequence); + DEALLOCATE_LOCAL(boxes); + + pGC->graphicsExposures = graphicsExposures; + /* + * Form union of rgnExp and rgnObs and see if covers entire area + * to be copied. Store the resultant region for miBSCopyArea + * to return to dispatch which will send the appropriate expose + * events. + */ + REGION_UNION(pGC->pScreen, pRgnExp, pRgnExp, pRgnObs); + box.x1 = srcx; + box.x2 = srcx + w; + box.y1 = srcy; + box.y2 = srcy + h; + if (RECT_IN_REGION(pGC->pScreen, pRgnExp, &box) == rgnIN) + { + REGION_EMPTY(pGC->pScreen, pRgnExp); + } + else + { + REGION_INVERSE( pGC->pScreen, pRgnExp, pRgnExp, &box); + REGION_TRANSLATE( pGC->pScreen, pRgnExp, + dx + pWin->drawable.x, + dy + pWin->drawable.y); + REGION_INTERSECT( pGC->pScreen, pRgnObs, pRgnExp, &pWin->clipList); + (*pWin->drawable.pScreen->PaintWindowBackground) (pWin, + pRgnObs, PW_BACKGROUND); + REGION_TRANSLATE( pGC->pScreen, pRgnExp, + -pWin->drawable.x, + -pWin->drawable.y); + miBSClearBackingRegion (pWin, pRgnExp); + } + if (graphicsExposures) + *ppRgn = pRgnExp; + else + REGION_DESTROY(pGC->pScreen, pRgnExp); + REGION_DESTROY(pGC->pScreen, pRgnObs); + + return (TRUE); +} + +/*- + *----------------------------------------------------------------------- + * miBSCopyArea -- + * Perform a CopyArea from the source to the destination, extracting + * from the source's backing-store and storing into the destination's + * backing-store without messing anything up. If the source and + * destination are different, there's not too much to worry about: + * we can just issue several calls to the regular CopyArea function. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static RegionPtr +miBSCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty) + DrawablePtr pSrc; + DrawablePtr pDst; + GCPtr pGC; + int srcx; + int srcy; + int w; + int h; + int dstx; + int dsty; +{ + BoxPtr pExtents; + long dx, dy; + int bsrcx, bsrcy, bw, bh, bdstx, bdsty; + RegionPtr pixExposed = 0, winExposed = 0; + + SETUP_BACKING(pDst, pGC); + + PROLOGUE(pGC); + + if ((pSrc != pDst) || + (!miBSDoCopy((WindowPtr)pSrc, pGC, srcx, srcy, w, h, dstx, dsty, + (unsigned long) 0, (CopyPlaneProcPtr)pGC->ops->CopyArea, + &winExposed))) + { + /* + * always copy to the backing store first, miBSDoCopy + * returns FALSE if the *source* region is disjoint + * from the backing store saved region. So, copying + * *to* the backing store is always safe + */ + if (pGC->clientClipType != CT_PIXMAP) + { + /* + * adjust srcx, srcy, w, h, dstx, dsty to be clipped to + * the backing store. An unnecessary optimisation, + * but a useful one when GetSpans is slow. + */ + pExtents = REGION_EXTENTS(pDst->pScreen, + (RegionPtr)pBackingGC->clientClip); + bsrcx = srcx; + bsrcy = srcy; + bw = w; + bh = h; + bdstx = dstx; + bdsty = dsty; + dx = pExtents->x1 - bdstx; + if (dx > 0) + { + bsrcx += dx; + bdstx += dx; + bw -= dx; + } + dy = pExtents->y1 - bdsty; + if (dy > 0) + { + bsrcy += dy; + bdsty += dy; + bh -= dy; + } + dx = (bdstx + bw) - pExtents->x2; + if (dx > 0) + bw -= dx; + dy = (bdsty + bh) - pExtents->y2; + if (dy > 0) + bh -= dy; + if (bw > 0 && bh > 0) + pixExposed = (* pBackingGC->ops->CopyArea) (pSrc, + pBackingDrawable, pBackingGC, + bsrcx, bsrcy, bw, bh, bdstx - pBackingStore->x, + bdsty - pBackingStore->y); + } + else + pixExposed = (* pBackingGC->ops->CopyArea) (pSrc, + pBackingDrawable, pBackingGC, + srcx, srcy, w, h, + dstx - pBackingStore->x, dsty - pBackingStore->y); + + winExposed = (* pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); + } + + /* + * compute the composite graphics exposure region + */ + if (winExposed) + { + if (pixExposed){ + REGION_UNION(pDst->pScreen, winExposed, winExposed, pixExposed); + REGION_DESTROY(pDst->pScreen, pixExposed); + } + } else + winExposed = pixExposed; + + EPILOGUE (pGC); + + return winExposed; +} + +/*- + *----------------------------------------------------------------------- + * miBSCopyPlane -- + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static RegionPtr +miBSCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane) + DrawablePtr pSrc; + DrawablePtr pDst; + register GC *pGC; + int srcx, + srcy; + int w, + h; + int dstx, + dsty; + unsigned long plane; +{ + BoxPtr pExtents; + long dx, dy; + int bsrcx, bsrcy, bw, bh, bdstx, bdsty; + RegionPtr winExposed = 0, pixExposed = 0; + SETUP_BACKING(pDst, pGC); + + PROLOGUE(pGC); + + if ((pSrc != pDst) || + (!miBSDoCopy((WindowPtr)pSrc, pGC, srcx, srcy, w, h, dstx, dsty, + plane, pGC->ops->CopyPlane, &winExposed))) + { + /* + * always copy to the backing store first, miBSDoCopy + * returns FALSE if the *source* region is disjoint + * from the backing store saved region. So, copying + * *to* the backing store is always safe + */ + if (pGC->clientClipType != CT_PIXMAP) + { + /* + * adjust srcx, srcy, w, h, dstx, dsty to be clipped to + * the backing store. An unnecessary optimisation, + * but a useful one when GetSpans is slow. + */ + pExtents = REGION_EXTENTS(pDst->pScreen, + (RegionPtr)pBackingGC->clientClip); + bsrcx = srcx; + bsrcy = srcy; + bw = w; + bh = h; + bdstx = dstx; + bdsty = dsty; + dx = pExtents->x1 - bdstx; + if (dx > 0) + { + bsrcx += dx; + bdstx += dx; + bw -= dx; + } + dy = pExtents->y1 - bdsty; + if (dy > 0) + { + bsrcy += dy; + bdsty += dy; + bh -= dy; + } + dx = (bdstx + bw) - pExtents->x2; + if (dx > 0) + bw -= dx; + dy = (bdsty + bh) - pExtents->y2; + if (dy > 0) + bh -= dy; + if (bw > 0 && bh > 0) + pixExposed = (* pBackingGC->ops->CopyPlane) (pSrc, + pBackingDrawable, + pBackingGC, bsrcx, bsrcy, bw, bh, + bdstx - pBackingStore->x, + bdsty - pBackingStore->y, plane); + } + else + pixExposed = (* pBackingGC->ops->CopyPlane) (pSrc, + pBackingDrawable, + pBackingGC, srcx, srcy, w, h, + dstx - pBackingStore->x, + dsty - pBackingStore->y, plane); + + winExposed = (* pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h, + dstx, dsty, plane); + + } + + /* + * compute the composite graphics exposure region + */ + if (winExposed) + { + if (pixExposed) + { + REGION_UNION(pDst->pScreen, winExposed, winExposed, pixExposed); + REGION_DESTROY(pDst->pScreen, pixExposed); + } + } else + winExposed = pixExposed; + + EPILOGUE (pGC); + + return winExposed; +} + +/*- + *----------------------------------------------------------------------- + * miBSPolyPoint -- + * Perform a PolyPoint, routing output to backing-store as needed. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPolyPoint (pDrawable, pGC, mode, npt, pptInit) + DrawablePtr pDrawable; + GCPtr pGC; + int mode; /* Origin or Previous */ + int npt; + xPoint *pptInit; +{ + xPoint *pptCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pptCopy = (xPoint *)ALLOCATE_LOCAL(npt*sizeof(xPoint)); + if (pptCopy) + { + copyPoints(pptInit, pptCopy, npt, mode); + + (* pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pptInit); + + (* pBackingGC->ops->PolyPoint) (pBackingDrawable, + pBackingGC, mode, npt, pptCopy); + + DEALLOCATE_LOCAL(pptCopy); + } + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPolyLines -- + * Perform a Polylines, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPolylines (pDrawable, pGC, mode, npt, pptInit) + DrawablePtr pDrawable; + GCPtr pGC; + int mode; + int npt; + DDXPointPtr pptInit; +{ + DDXPointPtr pptCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pptCopy = (DDXPointPtr)ALLOCATE_LOCAL(npt*sizeof(DDXPointRec)); + if (pptCopy) + { + copyPoints(pptInit, pptCopy, npt, mode); + + (* pGC->ops->Polylines)(pDrawable, pGC, mode, npt, pptInit); + (* pBackingGC->ops->Polylines)(pBackingDrawable, + pBackingGC, mode, npt, pptCopy); + DEALLOCATE_LOCAL(pptCopy); + } + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPolySegment -- + * Perform a PolySegment, routing output to backing-store as needed. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPolySegment(pDrawable, pGC, nseg, pSegs) + DrawablePtr pDrawable; + GCPtr pGC; + int nseg; + xSegment *pSegs; +{ + xSegment *pSegsCopy; + + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pSegsCopy = (xSegment *)ALLOCATE_LOCAL(nseg*sizeof(xSegment)); + if (pSegsCopy) + { + copyData(pSegs, pSegsCopy, nseg << 1, MoreCopy0); + + (* pGC->ops->PolySegment)(pDrawable, pGC, nseg, pSegs); + (* pBackingGC->ops->PolySegment)(pBackingDrawable, + pBackingGC, nseg, pSegsCopy); + + DEALLOCATE_LOCAL(pSegsCopy); + } + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPolyRectangle -- + * Perform a PolyRectangle, routing output to backing-store as needed. + * + * Results: + * None + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPolyRectangle(pDrawable, pGC, nrects, pRects) + DrawablePtr pDrawable; + GCPtr pGC; + int nrects; + xRectangle *pRects; +{ + xRectangle *pRectsCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pRectsCopy =(xRectangle *)ALLOCATE_LOCAL(nrects*sizeof(xRectangle)); + if (pRectsCopy) + { + copyData(pRects, pRectsCopy, nrects, MoreCopy2); + + (* pGC->ops->PolyRectangle)(pDrawable, pGC, nrects, pRects); + (* pBackingGC->ops->PolyRectangle)(pBackingDrawable, + pBackingGC, nrects, pRectsCopy); + + DEALLOCATE_LOCAL(pRectsCopy); + } + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPolyArc -- + * Perform a PolyArc, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPolyArc(pDrawable, pGC, narcs, parcs) + DrawablePtr pDrawable; + GCPtr pGC; + int narcs; + xArc *parcs; +{ + xArc *pArcsCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pArcsCopy = (xArc *)ALLOCATE_LOCAL(narcs*sizeof(xArc)); + if (pArcsCopy) + { + copyData(parcs, pArcsCopy, narcs, MoreCopy4); + + (* pGC->ops->PolyArc)(pDrawable, pGC, narcs, parcs); + (* pBackingGC->ops->PolyArc)(pBackingDrawable, pBackingGC, + narcs, pArcsCopy); + + DEALLOCATE_LOCAL(pArcsCopy); + } + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSFillPolygon -- + * Perform a FillPolygon, routing output to backing-store as needed. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSFillPolygon(pDrawable, pGC, shape, mode, count, pPts) + DrawablePtr pDrawable; + register GCPtr pGC; + int shape, mode; + register int count; + DDXPointPtr pPts; +{ + DDXPointPtr pPtsCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pPtsCopy = (DDXPointPtr)ALLOCATE_LOCAL(count*sizeof(DDXPointRec)); + if (pPtsCopy) + { + copyPoints(pPts, pPtsCopy, count, mode); + (* pGC->ops->FillPolygon)(pDrawable, pGC, shape, mode, count, pPts); + (* pBackingGC->ops->FillPolygon)(pBackingDrawable, + pBackingGC, shape, mode, + count, pPtsCopy); + + DEALLOCATE_LOCAL(pPtsCopy); + } + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPolyFillRect -- + * Perform a PolyFillRect, routing output to backing-store as needed. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPolyFillRect(pDrawable, pGC, nrectFill, prectInit) + DrawablePtr pDrawable; + GCPtr pGC; + int nrectFill; /* number of rectangles to fill */ + xRectangle *prectInit; /* Pointer to first rectangle to fill */ +{ + xRectangle *pRectCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pRectCopy = + (xRectangle *)ALLOCATE_LOCAL(nrectFill*sizeof(xRectangle)); + if (pRectCopy) + { + copyData(prectInit, pRectCopy, nrectFill, MoreCopy2); + + (* pGC->ops->PolyFillRect)(pDrawable, pGC, nrectFill, prectInit); + (* pBackingGC->ops->PolyFillRect)(pBackingDrawable, + pBackingGC, nrectFill, pRectCopy); + + DEALLOCATE_LOCAL(pRectCopy); + } + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPolyFillArc -- + * Perform a PolyFillArc, routing output to backing-store as needed. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPolyFillArc(pDrawable, pGC, narcs, parcs) + DrawablePtr pDrawable; + GCPtr pGC; + int narcs; + xArc *parcs; +{ + xArc *pArcsCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pArcsCopy = (xArc *)ALLOCATE_LOCAL(narcs*sizeof(xArc)); + if (pArcsCopy) + { + copyData(parcs, pArcsCopy, narcs, MoreCopy4); + (* pGC->ops->PolyFillArc)(pDrawable, pGC, narcs, parcs); + (* pBackingGC->ops->PolyFillArc)(pBackingDrawable, + pBackingGC, narcs, pArcsCopy); + DEALLOCATE_LOCAL(pArcsCopy); + } + + EPILOGUE (pGC); +} + + +/*- + *----------------------------------------------------------------------- + * miBSPolyText8 -- + * Perform a PolyText8, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static int +miBSPolyText8(pDrawable, pGC, x, y, count, chars) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + int count; + char *chars; +{ + int result; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + result = (* pGC->ops->PolyText8)(pDrawable, pGC, x, y, count, chars); + (* pBackingGC->ops->PolyText8)(pBackingDrawable, pBackingGC, + x - pBackingStore->x, y - pBackingStore->y, + count, chars); + + EPILOGUE (pGC); + return result; +} + +/*- + *----------------------------------------------------------------------- + * miBSPolyText16 -- + * Perform a PolyText16, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static int +miBSPolyText16(pDrawable, pGC, x, y, count, chars) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + int count; + unsigned short *chars; +{ + int result; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + result = (* pGC->ops->PolyText16)(pDrawable, pGC, x, y, count, chars); + (* pBackingGC->ops->PolyText16)(pBackingDrawable, pBackingGC, + x - pBackingStore->x, y - pBackingStore->y, + count, chars); + + EPILOGUE (pGC); + + return result; +} + +/*- + *----------------------------------------------------------------------- + * miBSImageText8 -- + * Perform a ImageText8, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSImageText8(pDrawable, pGC, x, y, count, chars) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + int count; + char *chars; +{ + SETUP_BACKING (pDrawable, pGC); + PROLOGUE(pGC); + + (* pGC->ops->ImageText8)(pDrawable, pGC, x, y, count, chars); + (* pBackingGC->ops->ImageText8)(pBackingDrawable, pBackingGC, + x - pBackingStore->x, y - pBackingStore->y, + count, chars); + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSImageText16 -- + * Perform a ImageText16, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSImageText16(pDrawable, pGC, x, y, count, chars) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + int count; + unsigned short *chars; +{ + SETUP_BACKING (pDrawable, pGC); + PROLOGUE(pGC); + + (* pGC->ops->ImageText16)(pDrawable, pGC, x, y, count, chars); + (* pBackingGC->ops->ImageText16)(pBackingDrawable, pBackingGC, + x - pBackingStore->x, y - pBackingStore->y, + count, chars); + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSImageGlyphBlt -- + * Perform a ImageGlyphBlt, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + unsigned int nglyph; + CharInfoPtr *ppci; /* array of character info */ + pointer pglyphBase; /* start of array of glyphs */ +{ + SETUP_BACKING (pDrawable, pGC); + PROLOGUE(pGC); + + (* pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, nglyph, ppci, + pglyphBase); + (* pBackingGC->ops->ImageGlyphBlt)(pBackingDrawable, pBackingGC, + x - pBackingStore->x, y - pBackingStore->y, + nglyph, ppci, pglyphBase); + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPolyGlyphBlt -- + * Perform a PolyGlyphBlt, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + unsigned int nglyph; + CharInfoPtr *ppci; /* array of character info */ + pointer pglyphBase; /* start of array of glyphs */ +{ + SETUP_BACKING (pDrawable, pGC); + PROLOGUE(pGC); + + (* pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, nglyph, + ppci, pglyphBase); + (* pBackingGC->ops->PolyGlyphBlt)(pBackingDrawable, pBackingGC, + x - pBackingStore->x, y - pBackingStore->y, + nglyph, ppci, pglyphBase); + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPushPixels -- + * Perform a PushPixels, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPushPixels(pGC, pBitMap, pDst, w, h, x, y) + GCPtr pGC; + PixmapPtr pBitMap; + DrawablePtr pDst; + int w, h, x, y; +{ + SETUP_BACKING (pDst, pGC); + PROLOGUE(pGC); + + (* pGC->ops->PushPixels)(pGC, pBitMap, pDst, w, h, x, y); + if (pGC->miTranslate) { + x -= pDst->x; + y -= pDst->y; + } + (* pBackingGC->ops->PushPixels)(pBackingGC, pBitMap, + pBackingDrawable, w, h, + x - pBackingStore->x, y - pBackingStore->y); + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSClearBackingStore -- + * Clear the given area of the backing pixmap with the background of + * the window, whatever it is. If generateExposures is TRUE, generate + * exposure events for the area. Note that if the area has any + * part outside the saved portions of the window, we do not allow the + * count in the expose events to be 0, since there will be more + * expose events to come. + * + * Results: + * None. + * + * Side Effects: + * Areas of pixmap are cleared and Expose events are generated. + * + *----------------------------------------------------------------------- + */ +static RegionPtr +miBSClearBackingStore(pWin, x, y, w, h, generateExposures) + WindowPtr pWin; + int x; + int y; + int w; + int h; + Bool generateExposures; +{ + RegionPtr pRgn; + int i; + miBSWindowPtr pBackingStore; + ScreenPtr pScreen; + GCPtr pGC; + int ts_x_origin, + ts_y_origin; + pointer gcvalues[4]; + unsigned long gcmask; + xRectangle *rects; + BoxPtr pBox; + BoxRec box; + PixUnion background; + char backgroundState; + int numRects; + + pBackingStore = (miBSWindowPtr)pWin->backStorage; + pScreen = pWin->drawable.pScreen; + + if ((pBackingStore->status == StatusNoPixmap) || + (pBackingStore->status == StatusBadAlloc)) + return NullRegion; + + if (w == 0) + w = (int) pWin->drawable.width - x; + if (h == 0) + h = (int) pWin->drawable.height - y; + + box.x1 = x; + box.y1 = y; + box.x2 = x + w; + box.y2 = y + h; + pRgn = REGION_CREATE(pWin->drawable.pScreen, &box, 1); + if (!pRgn) + return NullRegion; + REGION_INTERSECT( pScreen, pRgn, pRgn, &pBackingStore->SavedRegion); + + if (REGION_NOTEMPTY( pScreen, pRgn)) + { + /* + * if clearing entire window, simply make new virtual + * tile. For the root window, we also destroy the pixmap + * to save a pile of memory + */ + if (x == 0 && y == 0 && + w == pWin->drawable.width && + h == pWin->drawable.height) + { + if (!pWin->parent) + miDestroyBSPixmap (pWin); + if (pBackingStore->status != StatusContents) + miTileVirtualBS (pWin); + } + + ts_x_origin = ts_y_origin = 0; + + backgroundState = pWin->backgroundState; + background = pWin->background; + if (backgroundState == ParentRelative) { + WindowPtr pParent; + + pParent = pWin; + while (pParent->backgroundState == ParentRelative) { + ts_x_origin -= pParent->origin.x; + ts_y_origin -= pParent->origin.y; + pParent = pParent->parent; + } + backgroundState = pParent->backgroundState; + background = pParent->background; + } + + if ((backgroundState != None) && + ((pBackingStore->status == StatusContents) || + !SameBackground (pBackingStore->backgroundState, + pBackingStore->background, + backgroundState, + background))) + { + if (!pBackingStore->pBackingPixmap) + miCreateBSPixmap(pWin, NullBox); + + pGC = GetScratchGC(pWin->drawable.depth, pScreen); + if (pGC && pBackingStore->pBackingPixmap) + { + /* + * First take care of any ParentRelative stuff by altering the + * tile/stipple origin to match the coordinates of the upper-left + * corner of the first ancestor without a ParentRelative background. + * This coordinate is, of course, negative. + */ + + if (backgroundState == BackgroundPixel) + { + gcvalues[0] = (pointer) background.pixel; + gcvalues[1] = (pointer)FillSolid; + gcmask = GCForeground|GCFillStyle; + } + else + { + gcvalues[0] = (pointer)FillTiled; + gcvalues[1] = (pointer) background.pixmap; + gcmask = GCFillStyle|GCTile; + } + gcvalues[2] = (pointer)(long)(ts_x_origin - pBackingStore->x); + gcvalues[3] = (pointer)(long)(ts_y_origin - pBackingStore->y); + gcmask |= GCTileStipXOrigin|GCTileStipYOrigin; + DoChangeGC(pGC, gcmask, (XID *)gcvalues, TRUE); + ValidateGC((DrawablePtr)pBackingStore->pBackingPixmap, pGC); + + /* + * Figure out the array of rectangles to fill and fill them with + * PolyFillRect in the proper mode, as set in the GC above. + */ + numRects = REGION_NUM_RECTS(pRgn); + rects = (xRectangle *)ALLOCATE_LOCAL(numRects*sizeof(xRectangle)); + + if (rects) + { + for (i = 0, pBox = REGION_RECTS(pRgn); + i < numRects; + i++, pBox++) + { + rects[i].x = pBox->x1 - pBackingStore->x; + rects[i].y = pBox->y1 - pBackingStore->y; + rects[i].width = pBox->x2 - pBox->x1; + rects[i].height = pBox->y2 - pBox->y1; + } + (* pGC->ops->PolyFillRect) ( + (DrawablePtr)pBackingStore->pBackingPixmap, + pGC, numRects, rects); + DEALLOCATE_LOCAL(rects); + } + FreeScratchGC(pGC); + } + } + + if (!generateExposures) + { + REGION_DESTROY(pScreen, pRgn); + pRgn = NULL; + } + else + { + /* + * result must be screen relative, but is currently + * drawable relative. + */ + REGION_TRANSLATE(pScreen, pRgn, pWin->drawable.x, + pWin->drawable.y); + } + } + else + { + REGION_DESTROY( pScreen, pRgn); + pRgn = NULL; + } + return pRgn; +} + +static void +miBSClearBackingRegion (pWin, pRgn) + WindowPtr pWin; + RegionPtr pRgn; +{ + BoxPtr pBox; + int i; + + i = REGION_NUM_RECTS(pRgn); + pBox = REGION_RECTS(pRgn); + while (i--) + { + (void) miBSClearBackingStore(pWin, pBox->x1, pBox->y1, + pBox->x2 - pBox->x1, + pBox->y2 - pBox->y1, + FALSE); + pBox++; + } +} + +/* + * fill a region of the destination with virtual bits + * + * pRgn is to be translated by (x,y) + */ + +static void +miBSFillVirtualBits (pDrawable, pGC, pRgn, x, y, state, pixunion, planeMask) + DrawablePtr pDrawable; + GCPtr pGC; + RegionPtr pRgn; + int x, y; + int state; + PixUnion pixunion; + unsigned long planeMask; +{ + int i; + BITS32 gcmask; + pointer gcval[5]; + xRectangle *pRect; + BoxPtr pBox; + WindowPtr pWin; + int numRects; + + if (state == None) + return; + numRects = REGION_NUM_RECTS(pRgn); + pRect = (xRectangle *)ALLOCATE_LOCAL(numRects * sizeof(xRectangle)); + if (!pRect) + return; + pWin = 0; + if (pDrawable->type != DRAWABLE_PIXMAP) + { + pWin = (WindowPtr) pDrawable; + if (!pWin->backStorage) + pWin = 0; + } + i = 0; + gcmask = 0; + gcval[i++] = (pointer)planeMask; + gcmask |= GCPlaneMask; + if (state == BackgroundPixel) + { + if (pGC->fgPixel != pixunion.pixel) + { + gcval[i++] = (pointer)pixunion.pixel; + gcmask |= GCForeground; + } + if (pGC->fillStyle != FillSolid) + { + gcval[i++] = (pointer)FillSolid; + gcmask |= GCFillStyle; + } + } + else + { + if (pGC->fillStyle != FillTiled) + { + gcval[i++] = (pointer)FillTiled; + gcmask |= GCFillStyle; + } + if (pGC->tileIsPixel || pGC->tile.pixmap != pixunion.pixmap) + { + gcval[i++] = (pointer)pixunion.pixmap; + gcmask |= GCTile; + } + if (pGC->patOrg.x != x) + { + gcval[i++] = (pointer)(long)x; + gcmask |= GCTileStipXOrigin; + } + if (pGC->patOrg.y != y) + { + gcval[i++] = (pointer)(long)y; + gcmask |= GCTileStipYOrigin; + } + } + if (gcmask) + DoChangeGC (pGC, gcmask, (XID *)gcval, 1); + + if (pWin) + (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeVisBack); + + if (pDrawable->serialNumber != pGC->serialNumber) + ValidateGC (pDrawable, pGC); + + pBox = REGION_RECTS(pRgn); + for (i = numRects; --i >= 0; pBox++, pRect++) + { + pRect->x = pBox->x1 + x; + pRect->y = pBox->y1 + y; + pRect->width = pBox->x2 - pBox->x1; + pRect->height = pBox->y2 - pBox->y1; + } + pRect -= numRects; + (*pGC->ops->PolyFillRect) (pDrawable, pGC, numRects, pRect); + if (pWin) + (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeNothing); + DEALLOCATE_LOCAL (pRect); +} + +/*- + *----------------------------------------------------------------------- + * miBSAllocate -- + * Create and install backing store info for a window + * + *----------------------------------------------------------------------- + */ + +static void +miBSAllocate(pWin) + WindowPtr pWin; +{ + register miBSWindowPtr pBackingStore; + register ScreenPtr pScreen; + + if (pWin->drawable.pScreen->backingStoreSupport == NotUseful) + return; + pScreen = pWin->drawable.pScreen; + if (!(pBackingStore = (miBSWindowPtr)pWin->backStorage)) + { + + pBackingStore = (miBSWindowPtr)xalloc(sizeof(miBSWindowRec)); + if (!pBackingStore) + return; + + pBackingStore->pBackingPixmap = NullPixmap; + pBackingStore->x = 0; + pBackingStore->y = 0; + REGION_NULL( pScreen, &pBackingStore->SavedRegion); + pBackingStore->viewable = (char)pWin->viewable; + pBackingStore->status = StatusNoPixmap; + pBackingStore->backgroundState = None; + pWin->backStorage = (pointer) pBackingStore; + } + + /* + * Now want to initialize the backing pixmap and SavedRegion if + * necessary. The initialization consists of finding all the + * currently-obscured regions, by taking the inverse of the window's + * clip list, storing the result in SavedRegion, and exposing those + * areas of the window. + */ + + if (pBackingStore->status == StatusNoPixmap && + ((pWin->backingStore == WhenMapped && pWin->viewable) || + (pWin->backingStore == Always))) + { + BoxRec box; + RegionPtr pSavedRegion; + + pSavedRegion = &pBackingStore->SavedRegion; + + box.x1 = pWin->drawable.x; + box.x2 = box.x1 + (int) pWin->drawable.width; + box.y1 = pWin->drawable.y; + box.y2 = pWin->drawable.y + (int) pWin->drawable.height; + + REGION_INVERSE( pScreen, pSavedRegion, &pWin->clipList, &box); + REGION_TRANSLATE( pScreen, pSavedRegion, + -pWin->drawable.x, + -pWin->drawable.y); +#ifdef SHAPE + if (wBoundingShape (pWin)) + REGION_INTERSECT(pScreen, pSavedRegion, pSavedRegion, + wBoundingShape (pWin)); + if (wClipShape (pWin)) + REGION_INTERSECT(pScreen, pSavedRegion, pSavedRegion, + wClipShape (pWin)); +#endif + /* if window is already on-screen, assume it has been drawn to */ + if (pWin->viewable) + pBackingStore->status = StatusVDirty; + miTileVirtualBS (pWin); + + /* + * deliver all the newly available regions + * as exposure events to the window + */ + + miSendExposures(pWin, pSavedRegion, 0, 0); + } + else if (!pWin->viewable) + { + /* + * Turn off backing store when we're not supposed to + * be saving anything + */ + if (pBackingStore->status != StatusNoPixmap) + { + REGION_EMPTY( pScreen, &pBackingStore->SavedRegion); + miDestroyBSPixmap (pWin); + } + } +} + +/*- + *----------------------------------------------------------------------- + * miBSFree -- + * Destroy and free all the stuff associated with the backing-store + * for the given window. + * + * Results: + * None. + * + * Side Effects: + * The backing pixmap and all the regions and GC's are destroyed. + * + *----------------------------------------------------------------------- + */ +static void +miBSFree(pWin) + WindowPtr pWin; +{ + miBSWindowPtr pBackingStore; + register ScreenPtr pScreen; + + pScreen = pWin->drawable.pScreen; + + pBackingStore = (miBSWindowPtr)pWin->backStorage; + if (pBackingStore) + { + miDestroyBSPixmap (pWin); + + REGION_UNINIT( pScreen, &pBackingStore->SavedRegion); + + xfree(pBackingStore); + pWin->backStorage = NULL; + } +} + +/*- + *----------------------------------------------------------------------- + * miResizeBackingStore -- + * Alter the size of the backing pixmap as necessary when the + * SavedRegion changes size. The contents of the old pixmap are + * copied/shifted into the new/same pixmap. + * + * Results: + * The new Pixmap is created as necessary. + * + * Side Effects: + * The old pixmap is destroyed. + * + *----------------------------------------------------------------------- + */ +static void +miResizeBackingStore( + WindowPtr pWin, + int dx, /* bits are moving this far */ + int dy, /* bits are moving this far */ + Bool saveBits) /* bits are useful */ +{ + miBSWindowPtr pBackingStore; + PixmapPtr pBackingPixmap; + ScreenPtr pScreen; + GC *pGC; + BoxPtr extents; + PixmapPtr pNewPixmap; + int nx, ny; + int nw, nh; + + pBackingStore = (miBSWindowPtr)(pWin->backStorage); + pBackingPixmap = pBackingStore->pBackingPixmap; + if (!pBackingPixmap) + return; + pScreen = pWin->drawable.pScreen; + extents = REGION_EXTENTS(pScreen, &pBackingStore->SavedRegion); + pNewPixmap = pBackingPixmap; + + nw = extents->x2 - extents->x1; + nh = extents->y2 - extents->y1; + + /* the policy here could be more sophisticated */ + if (nw != pBackingPixmap->drawable.width || + nh != pBackingPixmap->drawable.height) + { + if (!saveBits || !nw || !nh) + { + pNewPixmap = NullPixmap; + pBackingStore->status = StatusNoPixmap; + } + else + { + pNewPixmap = (PixmapPtr)(*pScreen->CreatePixmap) + (pScreen, + nw, nh, + pWin->drawable.depth); + if (!pNewPixmap) + { +#ifdef BSEAGER + pBackingStore->status = StatusNoPixmap; +#else + pBackingStore->status = StatusBadAlloc; +#endif + } + } + } + if (!pNewPixmap) + { + pBackingStore->x = 0; + pBackingStore->y = 0; + } + else + { + nx = pBackingStore->x - extents->x1 + dx; + ny = pBackingStore->y - extents->y1 + dy; + pBackingStore->x = extents->x1; + pBackingStore->y = extents->y1; + + if (saveBits && (pNewPixmap != pBackingPixmap || nx != 0 || ny != 0)) + { + pGC = GetScratchGC(pNewPixmap->drawable.depth, pScreen); + if (pGC) + { + ValidateGC((DrawablePtr)pNewPixmap, pGC); + /* if we implement a policy where the pixmap can be larger than + * the region extents, we might want to optimize this copyarea + * by only copying the old extents, rather than the entire + * pixmap + */ + (*pGC->ops->CopyArea)((DrawablePtr)pBackingPixmap, + (DrawablePtr)pNewPixmap, pGC, + 0, 0, + pBackingPixmap->drawable.width, + pBackingPixmap->drawable.height, + nx, ny); + FreeScratchGC(pGC); + } + } + } + /* SavedRegion is used in the backingGC clip; force an update */ + pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; + if (pNewPixmap != pBackingPixmap) + { + (* pScreen->DestroyPixmap)(pBackingPixmap); + pBackingStore->pBackingPixmap = pNewPixmap; + } +} + +/*- + *----------------------------------------------------------------------- + * miBSSaveDoomedAreas -- + * Saved the areas of the given window that are about to be + * obscured. If the window has moved, pObscured is expected to + * be at the new screen location and (dx,dy) is expected to be the offset + * to the window's previous location. + * + * Results: + * None. + * + * Side Effects: + * The region is copied from the screen into pBackingPixmap and + * SavedRegion is updated. + * + *----------------------------------------------------------------------- + */ +static void +miBSSaveDoomedAreas(pWin, pObscured, dx, dy) + register WindowPtr pWin; + RegionPtr pObscured; + int dx, dy; +{ + miBSWindowPtr pBackingStore; + ScreenPtr pScreen; + int x, y; + + pBackingStore = (miBSWindowPtr)pWin->backStorage; + pScreen = pWin->drawable.pScreen; + + /* + * If the window isn't realized, it's being unmapped, thus we don't + * want to save anything if backingStore isn't Always. + */ + if (!pWin->realized) + { + pBackingStore->viewable = (char)pWin->viewable; + if (pWin->backingStore != Always) + { + REGION_EMPTY( pScreen, &pBackingStore->SavedRegion); + miDestroyBSPixmap (pWin); + return; + } + if (pBackingStore->status == StatusBadAlloc) + pBackingStore->status = StatusNoPixmap; + } + + /* Don't even pretend to save anything for a virtual background None */ + if ((pBackingStore->status == StatusVirtual) && + (pBackingStore->backgroundState == None)) + return; + + if (REGION_NOTEMPTY(pScreen, pObscured)) + { + BoxRec oldExtents; + x = pWin->drawable.x; + y = pWin->drawable.y; + REGION_TRANSLATE(pScreen, pObscured, -x, -y); + oldExtents = *REGION_EXTENTS(pScreen, &pBackingStore->SavedRegion); + REGION_UNION( pScreen, &pBackingStore->SavedRegion, + &pBackingStore->SavedRegion, + pObscured); + /* + * only save the bits if we've actually + * started using backing store + */ + if (pBackingStore->status != StatusVirtual) + { + if (!pBackingStore->pBackingPixmap) + miCreateBSPixmap (pWin, &oldExtents); + else + miResizeBackingStore(pWin, 0, 0, TRUE); + + if (pBackingStore->pBackingPixmap) { + if (pBackingStore->x | pBackingStore->y) + { + REGION_TRANSLATE( pScreen, pObscured, + -pBackingStore->x, + -pBackingStore->y); + x += pBackingStore->x; + y += pBackingStore->y; + } + (* pScreen->BackingStoreFuncs.SaveAreas) + (pBackingStore->pBackingPixmap, pObscured, + x - dx, y - dy, pWin); + } + } + REGION_TRANSLATE(pScreen, pObscured, x, y); + } + else + { + if (REGION_BROKEN (pScreen, pObscured)) + { + REGION_EMPTY( pScreen, &pBackingStore->SavedRegion); + miDestroyBSPixmap (pWin); + return; + } + } +} + +/*- + *----------------------------------------------------------------------- + * miBSRestoreAreas -- + * Restore areas from backing-store that are no longer obscured. + * expects prgnExposed to contain a screen-relative area. + * + * Results: + * The region to generate exposure events on (which may be + * different from the region to paint). + * + * Side Effects: + * Areas are copied from pBackingPixmap to the screen. prgnExposed + * is altered to contain the region that could not be restored from + * backing-store. + * + * Notes: + * This is called before sending any exposure events to the client, + * and so might be called if the window has grown. Changing the backing + * pixmap doesn't require revalidating the backingGC because the + * client's next output request will result in a call to ValidateGC, + * since the window clip region has changed, which will in turn call + * miValidateBackingStore. + *----------------------------------------------------------------------- + */ +static RegionPtr +miBSRestoreAreas(pWin, prgnExposed) + register WindowPtr pWin; + RegionPtr prgnExposed; +{ + PixmapPtr pBackingPixmap; + miBSWindowPtr pBackingStore; + RegionPtr prgnSaved; + RegionPtr prgnRestored; + register ScreenPtr pScreen; + RegionPtr exposures = prgnExposed; + + pScreen = pWin->drawable.pScreen; + pBackingStore = (miBSWindowPtr)pWin->backStorage; + pBackingPixmap = pBackingStore->pBackingPixmap; + + prgnSaved = &pBackingStore->SavedRegion; + + if (pBackingStore->status == StatusContents) + { + REGION_TRANSLATE(pScreen, prgnSaved, pWin->drawable.x, + pWin->drawable.y); + + prgnRestored = REGION_CREATE( pScreen, (BoxPtr)NULL, 1); + REGION_INTERSECT( pScreen, prgnRestored, prgnExposed, prgnSaved); + + /* + * Since prgnExposed is no longer obscured, we no longer + * will have a valid copy of it in backing-store, but there is a valid + * copy of it on screen, so subtract the area we just restored from + * from the area to be exposed. + */ + + if (REGION_NOTEMPTY( pScreen, prgnRestored)) + { + REGION_SUBTRACT( pScreen, prgnSaved, prgnSaved, prgnExposed); + REGION_SUBTRACT( pScreen, prgnExposed, prgnExposed, prgnRestored); + + /* + * Do the actual restoration + */ + (* pScreen->BackingStoreFuncs.RestoreAreas) (pBackingPixmap, + prgnRestored, + pWin->drawable.x + pBackingStore->x, + pWin->drawable.y + pBackingStore->y, + pWin); + /* + * if the saved region is completely empty, dispose of the + * backing pixmap, otherwise, retranslate the saved + * region to window relative + */ + + if (REGION_NOTEMPTY(pScreen, prgnSaved)) + { + REGION_TRANSLATE(pScreen, prgnSaved, + -pWin->drawable.x, + -pWin->drawable.y); + miResizeBackingStore(pWin, 0, 0, TRUE); + } + else + miDestroyBSPixmap (pWin); + } + else + REGION_TRANSLATE(pScreen, prgnSaved, + -pWin->drawable.x, -pWin->drawable.y); + REGION_DESTROY( pScreen, prgnRestored); + + } + else if ((pBackingStore->status == StatusVirtual) || + (pBackingStore->status == StatusVDirty)) + { + REGION_TRANSLATE(pScreen, prgnSaved, + pWin->drawable.x, pWin->drawable.y); + exposures = REGION_CREATE( pScreen, NullBox, 1); + if (SameBackground (pBackingStore->backgroundState, + pBackingStore->background, + pWin->backgroundState, + pWin->background)) + { + REGION_SUBTRACT( pScreen, exposures, prgnExposed, prgnSaved); + } + else + { + miTileVirtualBS(pWin); + + /* we need to expose all we have (virtually) retiled */ + REGION_UNION( pScreen, exposures, prgnExposed, prgnSaved); + } + REGION_SUBTRACT( pScreen, prgnSaved, prgnSaved, prgnExposed); + REGION_TRANSLATE(pScreen, prgnSaved, + -pWin->drawable.x, -pWin->drawable.y); + } + else if (pWin->viewable && !pBackingStore->viewable && + pWin->backingStore != Always) + { + /* + * The window was just mapped and nothing has been saved in + * backing-store from the last time it was mapped. We want to capture + * any output to regions that are already obscured but there are no + * bits to snag off the screen, so we initialize things just as we did + * in miBSAllocate, above. + */ + BoxRec box; + + prgnSaved = &pBackingStore->SavedRegion; + + box.x1 = pWin->drawable.x; + box.x2 = box.x1 + (int) pWin->drawable.width; + box.y1 = pWin->drawable.y; + box.y2 = box.y1 + (int) pWin->drawable.height; + + REGION_INVERSE( pScreen, prgnSaved, &pWin->clipList, &box); + REGION_TRANSLATE( pScreen, prgnSaved, + -pWin->drawable.x, + -pWin->drawable.y); +#ifdef SHAPE + if (wBoundingShape (pWin)) + REGION_INTERSECT(pScreen, prgnSaved, prgnSaved, + wBoundingShape (pWin)); + if (wClipShape (pWin)) + REGION_INTERSECT(pScreen, prgnSaved, prgnSaved, + wClipShape (pWin)); +#endif + miTileVirtualBS(pWin); + + exposures = REGION_CREATE( pScreen, &box, 1); + } + pBackingStore->viewable = (char)pWin->viewable; + return exposures; +} + + +/*- + *----------------------------------------------------------------------- + * miBSTranslateBackingStore -- + * Shift the backing-store in the given direction. Called when bit + * gravity is shifting things around. + * + * Results: + * An occluded region of the window which should be sent exposure events. + * This region should be in absolute coordinates (i.e. include + * new window position). + * + * Side Effects: + * If the window changed size as well as position, the backing pixmap + * is resized. The contents of the backing pixmap are shifted + * + * Warning: + * Bob and I have rewritten this routine quite a few times, each + * time it gets a few more cases correct, and introducing some + * interesting bugs. Naturally, I think the code is correct this + * time. + * + * Let me try to explain what this routine is for: + * + * It's called from SlideAndSizeWindow whenever a window + * with backing store is resized. There are two separate + * possibilities: + * + * a) The window has ForgetGravity + * + * In this case, windx, windy will be 0 and oldClip will + * be NULL. This indicates that all of the window contents + * currently saved offscreen should be discarded, and the + * entire window exposed. TranslateBackingStore, then, should + * prepare a completely new backing store region based on the + * new window clipList and return that region for exposure. + * + * b) The window has some other gravity + * + * In this case, windx, windy will be set to the distance + * that the bits should move within the window. oldClip + * will be set to the old visible portion of the window. + * TranslateBackingStore, then, should adjust the backing + * store to accommodate the portion of the existing backing + * store bits which coorespond to backing store bits which + * will still be occluded in the new configuration. oldx,oldy + * are set to the old position of the window on the screen. + * + * Furthermore, in this case any contents of the screen which + * are about to become occluded should be fetched from the screen + * and placed in backing store. This is to avoid the eventual + * occlusion by the win gravity shifting the child window bits around + * on top of this window, and potentially losing information + * + * It's also called from SetShape, but I think (he says not + * really knowing for sure) that this code will even work + * in that case. + *----------------------------------------------------------------------- + */ + +static RegionPtr +miBSTranslateBackingStore(pWin, windx, windy, oldClip, oldx, oldy) + WindowPtr pWin; + int windx; /* bit translation distance in window */ + int windy; + RegionPtr oldClip; /* Region being copied */ + int oldx; /* old window position */ + int oldy; +{ + register miBSWindowPtr pBackingStore; + register RegionPtr pSavedRegion; + register RegionPtr newSaved, doomed; + register ScreenPtr pScreen; + BoxRec extents; + int scrdx; /* bit translation distance on screen */ + int scrdy; + int dx; /* distance window moved on screen */ + int dy; + + pScreen = pWin->drawable.pScreen; + pBackingStore = (miBSWindowPtr)(pWin->backStorage); + if ((pBackingStore->status == StatusNoPixmap) || + (pBackingStore->status == StatusBadAlloc)) + return NullRegion; + + /* + * Compute the new saved region + */ + + newSaved = REGION_CREATE( pScreen, NullBox, 1); + extents.x1 = pWin->drawable.x; + extents.x2 = pWin->drawable.x + (int) pWin->drawable.width; + extents.y1 = pWin->drawable.y; + extents.y2 = pWin->drawable.y + (int) pWin->drawable.height; + REGION_INVERSE( pScreen, newSaved, &pWin->clipList, &extents); + + REGION_TRANSLATE( pScreen, newSaved, + -pWin->drawable.x, -pWin->drawable.y); +#ifdef SHAPE + if (wBoundingShape (pWin) || wClipShape (pWin)) { + if (wBoundingShape (pWin)) + REGION_INTERSECT( pScreen, newSaved, newSaved, + wBoundingShape (pWin)); + if (wClipShape (pWin)) + REGION_INTERSECT( pScreen, newSaved, newSaved, wClipShape (pWin)); + } +#endif + + pSavedRegion = &pBackingStore->SavedRegion; + + /* now find any visible areas we can save from the screen */ + /* and then translate newSaved to old local coordinates */ + if (oldClip) + { + /* bit gravity makes things virtually too hard, punt */ + if (((windx != 0) || (windy != 0)) && + (pBackingStore->status != StatusContents)) + miCreateBSPixmap(pWin, NullBox); + + /* + * The window is moving this far on the screen + */ + dx = pWin->drawable.x - oldx; + dy = pWin->drawable.y - oldy; + /* + * The bits will be moving on the screen by the + * amount the window is moving + the amount the + * bits are moving within the window + */ + scrdx = windx + dx; + scrdy = windy + dy; + + /* + * intersect at old bit position to discover the + * bits on the screen which can be put into the + * new backing store + */ + REGION_TRANSLATE( pScreen, oldClip, windx - oldx, windy - oldy); + doomed = REGION_CREATE( pScreen, NullBox, 1); + REGION_INTERSECT( pScreen, doomed, oldClip, newSaved); + REGION_TRANSLATE( pScreen, oldClip, oldx - windx, oldy - windy); + + /* + * Translate the old saved region to the position in the + * window where it will appear to be + */ + REGION_TRANSLATE( pScreen, pSavedRegion, windx, windy); + + /* + * Add the old saved region to the new saved region, so + * that calls to RestoreAreas will be able to fetch those + * bits back + */ + REGION_UNION( pScreen, newSaved, newSaved, pSavedRegion); + + /* + * Swap the new saved region into the window + */ + { + RegionRec tmp; + + tmp = *pSavedRegion; + *pSavedRegion = *newSaved; + *newSaved = tmp; + } + miResizeBackingStore (pWin, windx, windy, TRUE); + + /* + * Compute the newly enabled region + * of backing store. This region will be + * set to background in the backing pixmap and + * sent as exposure events to the client. + */ + REGION_SUBTRACT( pScreen, newSaved, pSavedRegion, newSaved); + + /* + * Fetch bits which will be obscured from + * the screen + */ + if (REGION_NOTEMPTY( pScreen, doomed)) + { + /* + * Don't clear regions which have bits on the + * screen + */ + REGION_SUBTRACT( pScreen, newSaved, newSaved, doomed); + + /* + * Make the region to SaveDoomedAreas absolute, instead + * of window relative. + */ + REGION_TRANSLATE( pScreen, doomed, + pWin->drawable.x, pWin->drawable.y); + (* pScreen->SaveDoomedAreas) (pWin, doomed, scrdx, scrdy); + } + + REGION_DESTROY(pScreen, doomed); + + /* + * and clear whatever there is that's new + */ + if (REGION_NOTEMPTY( pScreen, newSaved)) + { + miBSClearBackingRegion (pWin, newSaved); + /* + * Make the exposed region absolute + */ + REGION_TRANSLATE(pScreen, newSaved, + pWin->drawable.x, + pWin->drawable.y); + } + else + { + REGION_DESTROY(pScreen, newSaved); + newSaved = NullRegion; + } + } + else + { + /* + * ForgetGravity: just reset backing store and + * expose the whole mess + */ + REGION_COPY( pScreen, pSavedRegion, newSaved); + REGION_TRANSLATE( pScreen, newSaved, + pWin->drawable.x, pWin->drawable.y); + + miResizeBackingStore (pWin, 0, 0, FALSE); + (void) miBSClearBackingStore (pWin, 0, 0, 0, 0, FALSE); + } + + return newSaved; +} + +/* + * Inform the backing store layer that you are about to validate + * a gc with a window, and that subsequent output to the window + * is (or is not) guaranteed to be already clipped to the visible + * regions of the window. + */ + +static void +miBSDrawGuarantee (pWin, pGC, guarantee) + WindowPtr pWin; + GCPtr pGC; + int guarantee; +{ + miBSGCPtr pPriv; + + if (pWin->backStorage) + { + pPriv = (miBSGCPtr)pGC->devPrivates[miBSGCIndex].ptr; + if (!pPriv) + (void) miBSCreateGCPrivate (pGC); + pPriv = (miBSGCPtr)pGC->devPrivates[miBSGCIndex].ptr; + if (pPriv) + { + /* + * XXX KLUDGE ALERT + * + * when the GC is Cheap pPriv will point + * at some device's gc func structure. guarantee + * will point at the ChangeGC entry of that struct + * and will never match a valid guarantee value. + */ + switch (pPriv->guarantee) + { + case GuaranteeNothing: + case GuaranteeVisBack: + pPriv->guarantee = guarantee; + break; + } + } + } +} + +#define noBackingCopy (GCGraphicsExposures|GCClipXOrigin|GCClipYOrigin| \ + GCClipMask|GCSubwindowMode| \ + GCTileStipXOrigin|GCTileStipYOrigin) + +/*- + *----------------------------------------------------------------------- + * miBSValidateGC -- + * Wrapper around output-library's ValidateGC routine + * + * Results: + * None. + * + * Side Effects: + * + * Notes: + * The idea here is to perform several functions: + * - All the output calls must be intercepted and routed to + * backing-store as necessary. + * - pGC in the window's devBackingStore must be set up with the + * clip list appropriate for writing to pBackingPixmap (i.e. + * the inverse of the window's clipList intersected with the + * clientClip of the GC). Since the destination for this GC is + * a pixmap, it is sufficient to set the clip list as its + * clientClip. + *----------------------------------------------------------------------- + */ + +static void +miBSValidateGC (pGC, stateChanges, pDrawable) + GCPtr pGC; + unsigned long stateChanges; + DrawablePtr pDrawable; +{ + GCPtr pBackingGC; + miBSWindowPtr pWindowPriv = NULL; + miBSGCPtr pPriv; + WindowPtr pWin; + int lift_functions; + RegionPtr backingCompositeClip = NULL; + + if (pDrawable->type != DRAWABLE_PIXMAP) + { + pWin = (WindowPtr) pDrawable; + pWindowPriv = (miBSWindowPtr) pWin->backStorage; + lift_functions = (pWindowPriv == (miBSWindowPtr) NULL); + } + else + { + pWin = (WindowPtr) NULL; + lift_functions = TRUE; + } + + pPriv = (miBSGCPtr)pGC->devPrivates[miBSGCIndex].ptr; + + FUNC_PROLOGUE (pGC, pPriv); + + (*pGC->funcs->ValidateGC) (pGC, stateChanges, pDrawable); + + /* + * rewrap funcs and ops as Validate may have changed them + */ + + pPriv->wrapFuncs = pGC->funcs; + pPriv->wrapOps = pGC->ops; + + if (!lift_functions && ((pPriv->guarantee == GuaranteeVisBack) || + (pWindowPriv->status == StatusNoPixmap) || + (pWindowPriv->status == StatusBadAlloc))) + lift_functions = TRUE; + + /* + * check to see if a new backingCompositeClip region must + * be generated + */ + + if (!lift_functions && + ((pDrawable->serialNumber != pPriv->serialNumber) || + (stateChanges&(GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)))) + { + if (REGION_NOTEMPTY(pGC->pScreen, &pWindowPriv->SavedRegion)) + { + backingCompositeClip = REGION_CREATE(pGC->pScreen, NULL, 1); + if ((pGC->clientClipType == CT_NONE) || + (pGC->clientClipType == CT_PIXMAP)) + { + REGION_COPY(pGC->pScreen, backingCompositeClip, + &pWindowPriv->SavedRegion); + } + else + { + /* + * Make a new copy of the client clip, translated to + * its proper origin. + */ + + REGION_COPY(pGC->pScreen, backingCompositeClip, + pGC->clientClip); + REGION_TRANSLATE(pGC->pScreen, backingCompositeClip, + pGC->clipOrg.x, + pGC->clipOrg.y); + REGION_INTERSECT(pGC->pScreen, backingCompositeClip, + backingCompositeClip, + &pWindowPriv->SavedRegion); + } + if (pGC->subWindowMode == IncludeInferiors) + { + RegionPtr translatedClip; + + /* XXX + * any output in IncludeInferiors mode will not + * be redirected to Inferiors backing store. This + * can be fixed only at great cost to the shadow routines. + */ + translatedClip = NotClippedByChildren (pWin); + REGION_TRANSLATE(pGC->pScreen, translatedClip, + -pDrawable->x, + -pDrawable->y); + REGION_SUBTRACT(pGC->pScreen, backingCompositeClip, + backingCompositeClip, translatedClip); + REGION_DESTROY(pGC->pScreen, translatedClip); + } + if (!REGION_NOTEMPTY(pGC->pScreen, backingCompositeClip)) + lift_functions = TRUE; + } + else + { + lift_functions = TRUE; + } + + /* Reset the status when drawing to an unoccluded window so that + * future SaveAreas will actually copy bits from the screen. Note that + * output to root window in IncludeInferiors mode will not cause this + * to change. This causes all transient graphics by the window + * manager to the root window to not enable backing store. + */ + if (lift_functions && (pWindowPriv->status == StatusVirtual) && + (pWin->parent || pGC->subWindowMode != IncludeInferiors)) + pWindowPriv->status = StatusVDirty; + } + + /* + * if no backing store has been allocated, and it's needed, + * create it now. + */ + + if (!lift_functions && !pWindowPriv->pBackingPixmap) + { + miCreateBSPixmap (pWin, NullBox); + if (!pWindowPriv->pBackingPixmap) + lift_functions = TRUE; + } + + /* + * create the backing GC if needed, lift functions + * if the creation fails + */ + + if (!lift_functions && !pPriv->pBackingGC) + { + int status; + XID noexpose = xFalse; + + /* We never want ops with the backingGC to generate GraphicsExpose */ + pBackingGC = CreateGC ((DrawablePtr)pWindowPriv->pBackingPixmap, + GCGraphicsExposures, &noexpose, &status); + if (status != Success) + lift_functions = TRUE; + else + pPriv->pBackingGC = pBackingGC; + } + + pBackingGC = pPriv->pBackingGC; + + pPriv->stateChanges |= stateChanges; + + if (lift_functions) + { + if (backingCompositeClip) + REGION_DESTROY( pGC->pScreen, backingCompositeClip); + + /* unwrap the GC again */ + miBSDestroyGCPrivate (pGC); + + return; + } + + /* + * the rest of this function gets the pBackingGC + * into shape for possible draws + */ + + pPriv->stateChanges &= ~noBackingCopy; + if (pPriv->stateChanges) + CopyGC(pGC, pBackingGC, pPriv->stateChanges); + if ((pGC->patOrg.x - pWindowPriv->x) != pBackingGC->patOrg.x || + (pGC->patOrg.y - pWindowPriv->y) != pBackingGC->patOrg.y) + { + XID vals[2]; + vals[0] = pGC->patOrg.x - pWindowPriv->x; + vals[1] = pGC->patOrg.y - pWindowPriv->y; + DoChangeGC(pBackingGC, GCTileStipXOrigin|GCTileStipYOrigin, vals, 0); + } + pPriv->stateChanges = 0; + + if (backingCompositeClip) + { + XID vals[2]; + + if (pGC->clientClipType == CT_PIXMAP) + { + (*pBackingGC->funcs->CopyClip)(pBackingGC, pGC); + REGION_TRANSLATE(pGC->pScreen, backingCompositeClip, + -pGC->clipOrg.x, -pGC->clipOrg.y); + vals[0] = pGC->clipOrg.x - pWindowPriv->x; + vals[1] = pGC->clipOrg.y - pWindowPriv->y; + DoChangeGC(pBackingGC, GCClipXOrigin|GCClipYOrigin, vals, 0); + (* pGC->pScreen->BackingStoreFuncs.SetClipmaskRgn) + (pBackingGC, backingCompositeClip); + REGION_DESTROY( pGC->pScreen, backingCompositeClip); + } + else + { + vals[0] = -pWindowPriv->x; + vals[1] = -pWindowPriv->y; + DoChangeGC(pBackingGC, GCClipXOrigin|GCClipYOrigin, vals, 0); + (*pBackingGC->funcs->ChangeClip) (pBackingGC, CT_REGION, backingCompositeClip, 0); + } + pPriv->serialNumber = pDrawable->serialNumber; + } + + if (pWindowPriv->pBackingPixmap->drawable.serialNumber + != pBackingGC->serialNumber) + { + ValidateGC((DrawablePtr)pWindowPriv->pBackingPixmap, pBackingGC); + } + + if (pBackingGC->clientClip == 0) + ErrorF ("backing store clip list nil"); + + FUNC_EPILOGUE (pGC, pPriv); +} + +static void +miBSChangeGC (pGC, mask) + GCPtr pGC; + unsigned long mask; +{ + miBSGCPtr pPriv = (miBSGCPtr) (pGC)->devPrivates[miBSGCIndex].ptr; + + FUNC_PROLOGUE (pGC, pPriv); + + (*pGC->funcs->ChangeGC) (pGC, mask); + + FUNC_EPILOGUE (pGC, pPriv); +} + +static void +miBSCopyGC (pGCSrc, mask, pGCDst) + GCPtr pGCSrc, pGCDst; + unsigned long mask; +{ + miBSGCPtr pPriv = (miBSGCPtr) (pGCDst)->devPrivates[miBSGCIndex].ptr; + + FUNC_PROLOGUE (pGCDst, pPriv); + + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + + FUNC_EPILOGUE (pGCDst, pPriv); +} + +static void +miBSDestroyGC (pGC) + GCPtr pGC; +{ + miBSGCPtr pPriv = (miBSGCPtr) (pGC)->devPrivates[miBSGCIndex].ptr; + + FUNC_PROLOGUE (pGC, pPriv); + + if (pPriv->pBackingGC) + FreeGC(pPriv->pBackingGC, (GContext)0); + + (*pGC->funcs->DestroyGC) (pGC); + + FUNC_EPILOGUE (pGC, pPriv); + + xfree(pPriv); +} + +static void +miBSChangeClip(pGC, type, pvalue, nrects) + GCPtr pGC; + int type; + pointer pvalue; + int nrects; +{ + miBSGCPtr pPriv = (miBSGCPtr) (pGC)->devPrivates[miBSGCIndex].ptr; + + FUNC_PROLOGUE (pGC, pPriv); + + (* pGC->funcs->ChangeClip)(pGC, type, pvalue, nrects); + + FUNC_EPILOGUE (pGC, pPriv); +} + +static void +miBSCopyClip(pgcDst, pgcSrc) + GCPtr pgcDst, pgcSrc; +{ + miBSGCPtr pPriv = (miBSGCPtr) (pgcDst)->devPrivates[miBSGCIndex].ptr; + + FUNC_PROLOGUE (pgcDst, pPriv); + + (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); + + FUNC_EPILOGUE (pgcDst, pPriv); +} + +static void +miBSDestroyClip(pGC) + GCPtr pGC; +{ + miBSGCPtr pPriv = (miBSGCPtr) (pGC)->devPrivates[miBSGCIndex].ptr; + + FUNC_PROLOGUE (pGC, pPriv); + + (* pGC->funcs->DestroyClip)(pGC); + + FUNC_EPILOGUE (pGC, pPriv); +} + +static void +miDestroyBSPixmap (pWin) + WindowPtr pWin; +{ + miBSWindowPtr pBackingStore; + ScreenPtr pScreen; + + pScreen = pWin->drawable.pScreen; + pBackingStore = (miBSWindowPtr) pWin->backStorage; + if (pBackingStore->pBackingPixmap) + (* pScreen->DestroyPixmap)(pBackingStore->pBackingPixmap); + pBackingStore->pBackingPixmap = NullPixmap; + pBackingStore->x = 0; + pBackingStore->y = 0; + if (pBackingStore->backgroundState == BackgroundPixmap) + (* pScreen->DestroyPixmap)(pBackingStore->background.pixmap); + pBackingStore->backgroundState = None; + pBackingStore->status = StatusNoPixmap; + pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; +} + +static void +miTileVirtualBS (pWin) + WindowPtr pWin; +{ + miBSWindowPtr pBackingStore; + + pBackingStore = (miBSWindowPtr) pWin->backStorage; + if (pBackingStore->backgroundState == BackgroundPixmap) + (* pWin->drawable.pScreen->DestroyPixmap) + (pBackingStore->background.pixmap); + pBackingStore->backgroundState = pWin->backgroundState; + pBackingStore->background = pWin->background; + if (pBackingStore->backgroundState == BackgroundPixmap) + pBackingStore->background.pixmap->refcnt++; + + if (pBackingStore->status != StatusVDirty) + pBackingStore->status = StatusVirtual; + + /* + * punt parent relative tiles and do it now + */ + if (pBackingStore->backgroundState == ParentRelative) + miCreateBSPixmap (pWin, NullBox); +} + +#ifdef DEBUG +static int BSAllocationsFailed = 0; +#define FAILEDSIZE 32 +static struct { int w, h; } failedRecord[FAILEDSIZE]; +static int failedIndex; +#endif + +static void +miCreateBSPixmap (pWin, pExtents) + WindowPtr pWin; + BoxPtr pExtents; +{ + miBSWindowPtr pBackingStore; + ScreenPtr pScreen; + PixUnion background; + char backgroundState = 0; + BoxPtr extents; + Bool backSet; + + pScreen = pWin->drawable.pScreen; + pBackingStore = (miBSWindowPtr) pWin->backStorage; + if (pBackingStore->status == StatusBadAlloc) + return; + backSet = ((pBackingStore->status == StatusVirtual) || + (pBackingStore->status == StatusVDirty)); + + extents = REGION_EXTENTS( pScreen, &pBackingStore->SavedRegion); + + if (!pBackingStore->pBackingPixmap && + extents->x2 != extents->x1 && + extents->y2 != extents->y1) + { + /* the policy here could be more sophisticated */ + pBackingStore->x = extents->x1; + pBackingStore->y = extents->y1; + pBackingStore->pBackingPixmap = + (PixmapPtr)(* pScreen->CreatePixmap) + (pScreen, + extents->x2 - extents->x1, + extents->y2 - extents->y1, + pWin->drawable.depth); + } + if (!pBackingStore->pBackingPixmap) + { +#ifdef DEBUG + BSAllocationsFailed++; + /* + * record failed allocations + */ + failedRecord[failedIndex].w = pWin->drawable.width; + failedRecord[failedIndex].h = pWin->drawable.height; + failedIndex++; + if (failedIndex == FAILEDSIZE) + failedIndex = 0; +#endif +#ifdef BSEAGER + pBackingStore->status = StatusNoPixmap; +#else + pBackingStore->status = StatusBadAlloc; +#endif + return; + } + + pBackingStore->status = StatusContents; + + if (backSet) + { + backgroundState = pWin->backgroundState; + background = pWin->background; + + pWin->backgroundState = pBackingStore->backgroundState; + pWin->background = pBackingStore->background; + if (pWin->backgroundState == BackgroundPixmap) + pWin->background.pixmap->refcnt++; + } + + if (!pExtents) + pExtents = extents; + + if (pExtents->y1 != pExtents->y2) + { + RegionPtr exposed; + + exposed = miBSClearBackingStore(pWin, + pExtents->x1, pExtents->y1, + pExtents->x2 - pExtents->x1, + pExtents->y2 - pExtents->y1, + !backSet); + if (exposed) + { + miSendExposures(pWin, exposed, pWin->drawable.x, pWin->drawable.y); + REGION_DESTROY( pScreen, exposed); + } + } + + if (backSet) + { + if (pWin->backgroundState == BackgroundPixmap) + (* pScreen->DestroyPixmap) (pWin->background.pixmap); + pWin->backgroundState = backgroundState; + pWin->background = background; + if (pBackingStore->backgroundState == BackgroundPixmap) + (* pScreen->DestroyPixmap) (pBackingStore->background.pixmap); + pBackingStore->backgroundState = None; + } +} + +/*- + *----------------------------------------------------------------------- + * miBSExposeCopy -- + * Handle the restoration of areas exposed by graphics operations. + * + * Results: + * None. + * + * Side Effects: + * prgnExposed has the areas exposed from backing-store removed + * from it. + * + *----------------------------------------------------------------------- + */ +static void +miBSExposeCopy (pSrc, pDst, pGC, prgnExposed, srcx, srcy, dstx, dsty, plane) + WindowPtr pSrc; + DrawablePtr pDst; + GCPtr pGC; + RegionPtr prgnExposed; + int srcx, srcy; + int dstx, dsty; + unsigned long plane; +{ + RegionRec tempRgn; + miBSWindowPtr pBackingStore; + CopyPlaneProcPtr copyProc; + GCPtr pScratchGC; + register BoxPtr pBox; + register int i; + register int dx, dy; + BITS32 gcMask; + + if (!REGION_NOTEMPTY(pGC->pScreen, prgnExposed)) + return; + pBackingStore = (miBSWindowPtr)pSrc->backStorage; + + if ((pBackingStore->status == StatusNoPixmap) || + (pBackingStore->status == StatusBadAlloc)) + return; + + REGION_NULL( pGC->pScreen, &tempRgn); + REGION_INTERSECT( pGC->pScreen, &tempRgn, prgnExposed, + &pBackingStore->SavedRegion); + REGION_SUBTRACT( pGC->pScreen, prgnExposed, prgnExposed, &tempRgn); + + if (plane != 0) { + copyProc = pGC->ops->CopyPlane; + } else { + copyProc = (CopyPlaneProcPtr)pGC->ops->CopyArea; + } + + dx = dstx - srcx; + dy = dsty - srcy; + + switch (pBackingStore->status) { + case StatusVirtual: + case StatusVDirty: + pScratchGC = GetScratchGC (pDst->depth, pDst->pScreen); + if (pScratchGC) + { + gcMask = 0; + if (pGC->alu != pScratchGC->alu) + gcMask = GCFunction; + if (pGC->planemask != pScratchGC->planemask) + gcMask |= GCPlaneMask; + if (gcMask) + CopyGC (pGC, pScratchGC, gcMask); + miBSFillVirtualBits (pDst, pScratchGC, &tempRgn, dx, dy, + (int) pBackingStore->backgroundState, + pBackingStore->background, + ~0L); + FreeScratchGC (pScratchGC); + } + break; + case StatusContents: + for (i = REGION_NUM_RECTS(&tempRgn), pBox = REGION_RECTS(&tempRgn); + --i >= 0; + pBox++) + { + (* copyProc) (&(pBackingStore->pBackingPixmap->drawable), pDst, pGC, + pBox->x1 - pBackingStore->x, + pBox->y1 - pBackingStore->y, + pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, + pBox->x1 + dx, pBox->y1 + dy, plane); + } + break; + } + REGION_UNINIT( pGC->pScreen, &tempRgn); +} diff --git a/xserver/mi/mibstore.h b/xserver/mi/mibstore.h new file mode 100644 index 000000000..23abde26e --- /dev/null +++ b/xserver/mi/mibstore.h @@ -0,0 +1,28 @@ +/*- + * mibstore.h -- + * Header file for users of the MI backing-store scheme. + * + * Copyright (c) 1987 by the Regents of the University of California + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + * + */ + + + +#ifndef _MIBSTORE_H +#define _MIBSTORE_H + +#include "screenint.h" + +extern void miInitializeBackingStore( + ScreenPtr /*pScreen*/ +); + +#endif /* _MIBSTORE_H */ diff --git a/xserver/mi/mibstorest.h b/xserver/mi/mibstorest.h new file mode 100644 index 000000000..ccf4fb701 --- /dev/null +++ b/xserver/mi/mibstorest.h @@ -0,0 +1,91 @@ +/* + * mibstorest.h + * + * internal structure definitions for mi backing store + */ + + +/* + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. +*/ + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "mibstore.h" +#include "regionstr.h" + +/* + * One of these structures is allocated per GC used with a backing-store + * drawable. + */ + +typedef struct { + GCPtr pBackingGC; /* Copy of the GC but with graphicsExposures + * set FALSE and the clientClip set to + * clip output to the valid regions of the + * backing pixmap. */ + int guarantee; /* GuaranteeNothing, etc. */ + unsigned long serialNumber; /* clientClip computed time */ + unsigned long stateChanges; /* changes in parent gc since last copy */ + GCOps *wrapOps; /* wrapped ops */ + GCFuncs *wrapFuncs; /* wrapped funcs */ +} miBSGCRec, *miBSGCPtr; + +/* + * one of these structures is allocated per Window with backing store + */ + +typedef struct { + PixmapPtr pBackingPixmap; /* Pixmap for saved areas */ + short x; /* origin of pixmap relative to window */ + short y; + RegionRec SavedRegion; /* Valid area in pBackingPixmap */ + char viewable; /* Tracks pWin->viewable so SavedRegion may + * be initialized correctly when the window + * is first mapped */ + char status; /* StatusNoPixmap, etc. */ + char backgroundState; /* background type */ + PixUnion background; /* background pattern */ +} miBSWindowRec, *miBSWindowPtr; + +#define StatusNoPixmap 1 /* pixmap has not been created */ +#define StatusVirtual 2 /* pixmap is virtual, tiled with background */ +#define StatusVDirty 3 /* pixmap is virtual, visiblt has contents */ +#define StatusBadAlloc 4 /* pixmap create failed, do not try again */ +#define StatusContents 5 /* pixmap is created, has valid contents */ + +typedef struct { + /* + * screen func wrappers + */ + CloseScreenProcPtr CloseScreen; + GetImageProcPtr GetImage; + GetSpansProcPtr GetSpans; + ChangeWindowAttributesProcPtr ChangeWindowAttributes; + CreateGCProcPtr CreateGC; + DestroyWindowProcPtr DestroyWindow; +} miBSScreenRec, *miBSScreenPtr; diff --git a/xserver/mi/micmap.c b/xserver/mi/micmap.c new file mode 100644 index 000000000..987affe96 --- /dev/null +++ b/xserver/mi/micmap.c @@ -0,0 +1,697 @@ +/************************************************************ +Copyright 1987 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this +software and its documentation for any purpose and without +fee is hereby granted, provided that the above copyright no- +tice appear in all copies and that both that copyright no- +tice and this permission notice appear in supporting docu- +mentation, and that the names of Sun or X Consortium +not be used in advertising or publicity pertaining to +distribution of the software without specific prior +written permission. Sun and X Consortium make no +representations about the suitability of this software for +any purpose. It is provided "as is" without any express or +implied warranty. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +********************************************************/ + +/* + * This is based on cfbcmap.c. The functions here are useful independently + * of cfb, which is the reason for including them here. How "mi" these + * are may be debatable. + */ + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "scrnintstr.h" +#include "colormapst.h" +#include "resource.h" +#include "globals.h" +#include "micmap.h" + +_X_EXPORT ColormapPtr miInstalledMaps[MAXSCREENS]; + +static Bool miDoInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp, + int *ndepthp, int *rootDepthp, VisualID *defaultVisp, + unsigned long sizes, int bitsPerRGB, int preferredVis); + +_X_EXPORT miInitVisualsProcPtr miInitVisualsProc = miDoInitVisuals; + +_X_EXPORT int +miListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps) +{ + if (miInstalledMaps[pScreen->myNum]) { + *pmaps = miInstalledMaps[pScreen->myNum]->mid; + return (1); + } + return 0; +} + +_X_EXPORT void +miInstallColormap(ColormapPtr pmap) +{ + int index = pmap->pScreen->myNum; + ColormapPtr oldpmap = miInstalledMaps[index]; + + if(pmap != oldpmap) + { + /* Uninstall pInstalledMap. No hardware changes required, just + * notify all interested parties. */ + if(oldpmap != (ColormapPtr)None) + WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid); + /* Install pmap */ + miInstalledMaps[index] = pmap; + WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid); + + } +} + +_X_EXPORT void +miUninstallColormap(ColormapPtr pmap) +{ + int index = pmap->pScreen->myNum; + ColormapPtr curpmap = miInstalledMaps[index]; + + if(pmap == curpmap) + { + if (pmap->mid != pmap->pScreen->defColormap) + { + curpmap = (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap, + RT_COLORMAP); + (*pmap->pScreen->InstallColormap)(curpmap); + } + } +} + +_X_EXPORT void +miResolveColor(unsigned short *pred, unsigned short *pgreen, + unsigned short *pblue, VisualPtr pVisual) +{ + int shift = 16 - pVisual->bitsPerRGBValue; + unsigned lim = (1 << pVisual->bitsPerRGBValue) - 1; + + if ((pVisual->class | DynamicClass) == GrayScale) + { + /* rescale to gray then rgb bits */ + *pred = (30L * *pred + 59L * *pgreen + 11L * *pblue) / 100; + *pblue = *pgreen = *pred = ((*pred >> shift) * 65535) / lim; + } + else + { + /* rescale to rgb bits */ + *pred = ((*pred >> shift) * 65535) / lim; + *pgreen = ((*pgreen >> shift) * 65535) / lim; + *pblue = ((*pblue >> shift) * 65535) / lim; + } +} + +_X_EXPORT Bool +miInitializeColormap(ColormapPtr pmap) +{ + register unsigned i; + register VisualPtr pVisual; + unsigned lim, maxent, shift; + + pVisual = pmap->pVisual; + lim = (1 << pVisual->bitsPerRGBValue) - 1; + shift = 16 - pVisual->bitsPerRGBValue; + maxent = pVisual->ColormapEntries - 1; + if (pVisual->class == TrueColor) + { + unsigned limr, limg, limb; + + limr = pVisual->redMask >> pVisual->offsetRed; + limg = pVisual->greenMask >> pVisual->offsetGreen; + limb = pVisual->blueMask >> pVisual->offsetBlue; + for(i = 0; i <= maxent; i++) + { + /* rescale to [0..65535] then rgb bits */ + pmap->red[i].co.local.red = + ((((i * 65535) / limr) >> shift) * 65535) / lim; + pmap->green[i].co.local.green = + ((((i * 65535) / limg) >> shift) * 65535) / lim; + pmap->blue[i].co.local.blue = + ((((i * 65535) / limb) >> shift) * 65535) / lim; + } + } + else if (pVisual->class == StaticColor) + { + unsigned limr, limg, limb; + + limr = pVisual->redMask >> pVisual->offsetRed; + limg = pVisual->greenMask >> pVisual->offsetGreen; + limb = pVisual->blueMask >> pVisual->offsetBlue; + for(i = 0; i <= maxent; i++) + { + /* rescale to [0..65535] then rgb bits */ + pmap->red[i].co.local.red = + ((((((i & pVisual->redMask) >> pVisual->offsetRed) + * 65535) / limr) >> shift) * 65535) / lim; + pmap->red[i].co.local.green = + ((((((i & pVisual->greenMask) >> pVisual->offsetGreen) + * 65535) / limg) >> shift) * 65535) / lim; + pmap->red[i].co.local.blue = + ((((((i & pVisual->blueMask) >> pVisual->offsetBlue) + * 65535) / limb) >> shift) * 65535) / lim; + } + } + else if (pVisual->class == StaticGray) + { + for(i = 0; i <= maxent; i++) + { + /* rescale to [0..65535] then rgb bits */ + pmap->red[i].co.local.red = ((((i * 65535) / maxent) >> shift) + * 65535) / lim; + pmap->red[i].co.local.green = pmap->red[i].co.local.red; + pmap->red[i].co.local.blue = pmap->red[i].co.local.red; + } + } + return TRUE; +} + +/* When simulating DirectColor on PseudoColor hardware, multiple + entries of the colormap must be updated + */ + +#define AddElement(mask) { \ + pixel = red | green | blue; \ + for (i = 0; i < nresult; i++) \ + if (outdefs[i].pixel == pixel) \ + break; \ + if (i == nresult) \ + { \ + nresult++; \ + outdefs[i].pixel = pixel; \ + outdefs[i].flags = 0; \ + } \ + outdefs[i].flags |= (mask); \ + outdefs[i].red = pmap->red[red >> pVisual->offsetRed].co.local.red; \ + outdefs[i].green = pmap->green[green >> pVisual->offsetGreen].co.local.green; \ + outdefs[i].blue = pmap->blue[blue >> pVisual->offsetBlue].co.local.blue; \ +} + +_X_EXPORT int +miExpandDirectColors(ColormapPtr pmap, int ndef, xColorItem *indefs, + xColorItem *outdefs) +{ + register int red, green, blue; + int maxred, maxgreen, maxblue; + int stepred, stepgreen, stepblue; + VisualPtr pVisual; + register int pixel; + register int nresult; + register int i; + + pVisual = pmap->pVisual; + + stepred = 1 << pVisual->offsetRed; + stepgreen = 1 << pVisual->offsetGreen; + stepblue = 1 << pVisual->offsetBlue; + maxred = pVisual->redMask; + maxgreen = pVisual->greenMask; + maxblue = pVisual->blueMask; + nresult = 0; + for (;ndef--; indefs++) + { + if (indefs->flags & DoRed) + { + red = indefs->pixel & pVisual->redMask; + for (green = 0; green <= maxgreen; green += stepgreen) + { + for (blue = 0; blue <= maxblue; blue += stepblue) + { + AddElement (DoRed) + } + } + } + if (indefs->flags & DoGreen) + { + green = indefs->pixel & pVisual->greenMask; + for (red = 0; red <= maxred; red += stepred) + { + for (blue = 0; blue <= maxblue; blue += stepblue) + { + AddElement (DoGreen) + } + } + } + if (indefs->flags & DoBlue) + { + blue = indefs->pixel & pVisual->blueMask; + for (red = 0; red <= maxred; red += stepred) + { + for (green = 0; green <= maxgreen; green += stepgreen) + { + AddElement (DoBlue) + } + } + } + } + return nresult; +} + +_X_EXPORT Bool +miCreateDefColormap(ScreenPtr pScreen) +{ +/* + * In the following sources PC X server vendors may want to delete + * "_not_tog" from "#ifdef WIN32_not_tog" + */ +#ifdef WIN32_not_tog + /* + * these are the MS-Windows desktop colors, adjusted for X's 16-bit + * color specifications. + */ + static xColorItem citems[] = { + { 0, 0, 0, 0, 0, 0 }, + { 1, 0x8000, 0, 0, 0, 0 }, + { 2, 0, 0x8000, 0, 0, 0 }, + { 3, 0x8000, 0x8000, 0, 0, 0 }, + { 4, 0, 0, 0x8000, 0, 0 }, + { 5, 0x8000, 0, 0x8000, 0, 0 }, + { 6, 0, 0x8000, 0x8000, 0, 0 }, + { 7, 0xc000, 0xc000, 0xc000, 0, 0 }, + { 8, 0xc000, 0xdc00, 0xc000, 0, 0 }, + { 9, 0xa600, 0xca00, 0xf000, 0, 0 }, + { 246, 0xff00, 0xfb00, 0xf000, 0, 0 }, + { 247, 0xa000, 0xa000, 0xa400, 0, 0 }, + { 248, 0x8000, 0x8000, 0x8000, 0, 0 }, + { 249, 0xff00, 0, 0, 0, 0 }, + { 250, 0, 0xff00, 0, 0, 0 }, + { 251, 0xff00, 0xff00, 0, 0, 0 }, + { 252, 0, 0, 0xff00, 0, 0 }, + { 253, 0xff00, 0, 0xff00, 0, 0 }, + { 254, 0, 0xff00, 0xff00, 0, 0 }, + { 255, 0xff00, 0xff00, 0xff00, 0, 0 } + }; +#define NUM_DESKTOP_COLORS sizeof citems / sizeof citems[0] + int i; +#else + unsigned short zero = 0, ones = 0xFFFF; +#endif + Pixel wp, bp; + VisualPtr pVisual; + ColormapPtr cmap; + int alloctype; + + for (pVisual = pScreen->visuals; + pVisual->vid != pScreen->rootVisual; + pVisual++) + ; + + if (pScreen->rootDepth == 1 || (pVisual->class & DynamicClass)) + alloctype = AllocNone; + else + alloctype = AllocAll; + + if (CreateColormap(pScreen->defColormap, pScreen, pVisual, &cmap, + alloctype, 0) != Success) + return FALSE; + + if (pScreen->rootDepth > 1) { + wp = pScreen->whitePixel; + bp = pScreen->blackPixel; +#ifdef WIN32_not_tog + for (i = 0; i < NUM_DESKTOP_COLORS; i++) { + if (AllocColor (cmap, + &citems[i].red, &citems[i].green, &citems[i].blue, + &citems[i].pixel, 0) != Success) + return FALSE; + } +#else + if ((AllocColor(cmap, &ones, &ones, &ones, &wp, 0) != + Success) || + (AllocColor(cmap, &zero, &zero, &zero, &bp, 0) != + Success)) + return FALSE; + pScreen->whitePixel = wp; + pScreen->blackPixel = bp; +#endif + } + + (*pScreen->InstallColormap)(cmap); + return TRUE; +} + +/* + * Default true color bitmasks, should be overridden by + * driver + */ + +#define _RZ(d) ((d + 2) / 3) +#define _RS(d) 0 +#define _RM(d) ((1 << _RZ(d)) - 1) +#define _GZ(d) ((d - _RZ(d) + 1) / 2) +#define _GS(d) _RZ(d) +#define _GM(d) (((1 << _GZ(d)) - 1) << _GS(d)) +#define _BZ(d) (d - _RZ(d) - _GZ(d)) +#define _BS(d) (_RZ(d) + _GZ(d)) +#define _BM(d) (((1 << _BZ(d)) - 1) << _BS(d)) +#define _CE(d) (1 << _RZ(d)) + +typedef struct _miVisuals { + struct _miVisuals *next; + int depth; + int bitsPerRGB; + int visuals; + int count; + int preferredCVC; + Pixel redMask, greenMask, blueMask; +} miVisualsRec, *miVisualsPtr; + +static int miVisualPriority[] = { + PseudoColor, GrayScale, StaticColor, TrueColor, DirectColor, StaticGray +}; + +#define NUM_PRIORITY 6 + +static miVisualsPtr miVisuals; + +_X_EXPORT void +miClearVisualTypes() +{ + miVisualsPtr v; + + while ((v = miVisuals)) { + miVisuals = v->next; + xfree(v); + } +} + + +_X_EXPORT Bool +miSetVisualTypesAndMasks(int depth, int visuals, int bitsPerRGB, + int preferredCVC, + Pixel redMask, Pixel greenMask, Pixel blueMask) +{ + miVisualsPtr new, *prev, v; + int count; + + new = (miVisualsPtr) xalloc (sizeof *new); + if (!new) + return FALSE; + if (!redMask || !greenMask || !blueMask) + { + redMask = _RM(depth); + greenMask = _GM(depth); + blueMask = _BM(depth); + } + new->next = 0; + new->depth = depth; + new->visuals = visuals; + new->bitsPerRGB = bitsPerRGB; + new->preferredCVC = preferredCVC; + new->redMask = redMask; + new->greenMask = greenMask; + new->blueMask = blueMask; + count = (visuals >> 1) & 033333333333; + count = visuals - count - ((count >> 1) & 033333333333); + count = (((count + (count >> 3)) & 030707070707) % 077); /* HAKMEM 169 */ + new->count = count; + for (prev = &miVisuals; (v = *prev); prev = &v->next); + *prev = new; + return TRUE; +} + +_X_EXPORT Bool +miSetVisualTypes(int depth, int visuals, int bitsPerRGB, int preferredCVC) +{ + return miSetVisualTypesAndMasks (depth, visuals, bitsPerRGB, + preferredCVC, 0, 0, 0); +} + +_X_EXPORT int +miGetDefaultVisualMask(int depth) +{ + if (depth > MAX_PSEUDO_DEPTH) + return LARGE_VISUALS; + else if (depth >= MIN_TRUE_DEPTH) + return ALL_VISUALS; + else if (depth == 1) + return StaticGrayMask; + else + return SMALL_VISUALS; +} + +static Bool +miVisualTypesSet (int depth) +{ + miVisualsPtr visuals; + + for (visuals = miVisuals; visuals; visuals = visuals->next) + if (visuals->depth == depth) + return TRUE; + return FALSE; +} + +_X_EXPORT Bool +miSetPixmapDepths (void) +{ + int d, f; + + /* Add any unlisted depths from the pixmap formats */ + for (f = 0; f < screenInfo.numPixmapFormats; f++) + { + d = screenInfo.formats[f].depth; + if (!miVisualTypesSet (d)) + { + if (!miSetVisualTypes (d, 0, 0, -1)) + return FALSE; + } + } + return TRUE; +} + +_X_EXPORT Bool +miInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp, + int *ndepthp, int *rootDepthp, VisualID *defaultVisp, + unsigned long sizes, int bitsPerRGB, int preferredVis) + +{ + if (miInitVisualsProc) + return miInitVisualsProc(visualp, depthp, nvisualp, ndepthp, + rootDepthp, defaultVisp, sizes, bitsPerRGB, + preferredVis); + else + return FALSE; +} + +/* + * Distance to least significant one bit + */ +static int +maskShift (Pixel p) +{ + int s; + + if (!p) return 0; + s = 0; + while (!(p & 1)) + { + s++; + p >>= 1; + } + return s; +} + +/* + * Given a list of formats for a screen, create a list + * of visuals and depths for the screen which corespond to + * the set which can be used with this version of cfb. + */ + +static Bool +miDoInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp, + int *ndepthp, int *rootDepthp, VisualID *defaultVisp, + unsigned long sizes, int bitsPerRGB, int preferredVis) +{ + int i, j = 0, k; + VisualPtr visual; + DepthPtr depth; + VisualID *vid; + int d, b; + int f; + int ndepth, nvisual; + int nvtype; + int vtype; + miVisualsPtr visuals, nextVisuals; + int *preferredCVCs, *prefp; + int first_depth; + + /* none specified, we'll guess from pixmap formats */ + if (!miVisuals) + { + for (f = 0; f < screenInfo.numPixmapFormats; f++) + { + d = screenInfo.formats[f].depth; + b = screenInfo.formats[f].bitsPerPixel; + if (sizes & (1 << (b - 1))) + vtype = miGetDefaultVisualMask(d); + else + vtype = 0; + if (!miSetVisualTypes (d, vtype, bitsPerRGB, -1)) + return FALSE; + } + } + nvisual = 0; + ndepth = 0; + for (visuals = miVisuals; visuals; visuals = nextVisuals) + { + nextVisuals = visuals->next; + ndepth++; + nvisual += visuals->count; + } + depth = (DepthPtr) xalloc (ndepth * sizeof (DepthRec)); + visual = (VisualPtr) xalloc (nvisual * sizeof (VisualRec)); + preferredCVCs = (int *)xalloc(ndepth * sizeof(int)); + if (!depth || !visual || !preferredCVCs) + { + xfree (depth); + xfree (visual); + xfree (preferredCVCs); + return FALSE; + } + *depthp = depth; + *visualp = visual; + *ndepthp = ndepth; + *nvisualp = nvisual; + prefp = preferredCVCs; + for (visuals = miVisuals; visuals; visuals = nextVisuals) + { + nextVisuals = visuals->next; + d = visuals->depth; + vtype = visuals->visuals; + nvtype = visuals->count; + *prefp = visuals->preferredCVC; + prefp++; + vid = NULL; + if (nvtype) + { + vid = (VisualID *) xalloc (nvtype * sizeof (VisualID)); + if (!vid) { + xfree(preferredCVCs); + return FALSE; + } + } + depth->depth = d; + depth->numVids = nvtype; + depth->vids = vid; + depth++; + for (i = 0; i < NUM_PRIORITY; i++) { + if (! (vtype & (1 << miVisualPriority[i]))) + continue; + visual->class = miVisualPriority[i]; + visual->bitsPerRGBValue = visuals->bitsPerRGB; + visual->ColormapEntries = 1 << d; + visual->nplanes = d; + visual->vid = *vid = FakeClientID (0); + switch (visual->class) { + case PseudoColor: + case GrayScale: + case StaticGray: + visual->redMask = 0; + visual->greenMask = 0; + visual->blueMask = 0; + visual->offsetRed = 0; + visual->offsetGreen = 0; + visual->offsetBlue = 0; + break; + case DirectColor: + case TrueColor: + visual->ColormapEntries = _CE(d); + /* fall through */ + case StaticColor: + visual->redMask = visuals->redMask; + visual->greenMask = visuals->greenMask; + visual->blueMask = visuals->blueMask; + visual->offsetRed = maskShift (visuals->redMask); + visual->offsetGreen = maskShift (visuals->greenMask); + visual->offsetBlue = maskShift (visuals->blueMask); + } + vid++; + visual++; + } + xfree (visuals); + } + miVisuals = NULL; + visual = *visualp; + depth = *depthp; + + /* + * if we did not supplyied by a preferred visual class + * check if there is a preferred class in one of the depth + * structures - if there is, we want to start looking for the + * default visual/depth from that depth. + */ + first_depth = 0; + if (preferredVis < 0 && defaultColorVisualClass < 0 ) { + for (i = 0; i < ndepth; i++) { + if (preferredCVCs[i] >= 0) { + first_depth = i; + break; + } + } + } + + for (i = first_depth; i < ndepth; i++) + { + int prefColorVisualClass = -1; + + if (defaultColorVisualClass >= 0) + prefColorVisualClass = defaultColorVisualClass; + else if (preferredVis >= 0) + prefColorVisualClass = preferredVis; + else if (preferredCVCs[i] >= 0) + prefColorVisualClass = preferredCVCs[i]; + + if (*rootDepthp && *rootDepthp != depth[i].depth) + continue; + + for (j = 0; j < depth[i].numVids; j++) + { + for (k = 0; k < nvisual; k++) + if (visual[k].vid == depth[i].vids[j]) + break; + if (k == nvisual) + continue; + if (prefColorVisualClass < 0 || + visual[k].class == prefColorVisualClass) + break; + } + if (j != depth[i].numVids) + break; + } + if (i == ndepth) { + i = 0; + j = 0; + } + *rootDepthp = depth[i].depth; + *defaultVisp = depth[i].vids[j]; + xfree(preferredCVCs); + + return TRUE; +} + +void +miResetInitVisuals() +{ + miInitVisualsProc = miDoInitVisuals; +} + diff --git a/xserver/mi/micmap.h b/xserver/mi/micmap.h new file mode 100644 index 000000000..9ee9f4ae4 --- /dev/null +++ b/xserver/mi/micmap.h @@ -0,0 +1,64 @@ + +#include "colormapst.h" + +#ifndef _MICMAP_H_ +#define _MICMAP_H_ + +extern ColormapPtr miInstalledMaps[MAXSCREENS]; + +typedef Bool (* miInitVisualsProcPtr)(VisualPtr *, DepthPtr *, int *, int *, + int *, VisualID *, unsigned long, int, + int); + +extern miInitVisualsProcPtr miInitVisualsProc; + +int miListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps); +void miInstallColormap(ColormapPtr pmap); +void miUninstallColormap(ColormapPtr pmap); + +void miResolveColor(unsigned short *, unsigned short *, unsigned short *, + VisualPtr); +Bool miInitializeColormap(ColormapPtr); +int miExpandDirectColors(ColormapPtr, int, xColorItem *, xColorItem *); +Bool miCreateDefColormap(ScreenPtr); +void miClearVisualTypes(void); +Bool miSetVisualTypes(int, int, int, int); +Bool miSetPixmapDepths(void); +Bool miSetVisualTypesAndMasks(int depth, int visuals, int bitsPerRGB, + int preferredCVC, + Pixel redMask, Pixel greenMask, Pixel blueMask); +int miGetDefaultVisualMask(int); +Bool miInitVisuals(VisualPtr *, DepthPtr *, int *, int *, int *, VisualID *, + unsigned long, int, int); +void miResetInitVisuals(void); + +void miHookInitVisuals(void (**old)(miInitVisualsProcPtr *), + void (*new)(miInitVisualsProcPtr *)); + + +#define MAX_PSEUDO_DEPTH 10 +#define MIN_TRUE_DEPTH 6 + +#define StaticGrayMask (1 << StaticGray) +#define GrayScaleMask (1 << GrayScale) +#define StaticColorMask (1 << StaticColor) +#define PseudoColorMask (1 << PseudoColor) +#define TrueColorMask (1 << TrueColor) +#define DirectColorMask (1 << DirectColor) + +#define ALL_VISUALS (StaticGrayMask|\ + GrayScaleMask|\ + StaticColorMask|\ + PseudoColorMask|\ + TrueColorMask|\ + DirectColorMask) + +#define LARGE_VISUALS (TrueColorMask|\ + DirectColorMask) + +#define SMALL_VISUALS (StaticGrayMask|\ + GrayScaleMask|\ + StaticColorMask|\ + PseudoColorMask) + +#endif /* _MICMAP_H_ */ diff --git a/xserver/mi/micoord.h b/xserver/mi/micoord.h new file mode 100644 index 000000000..b3d725b73 --- /dev/null +++ b/xserver/mi/micoord.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2000 The XFree86 Project, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the XFree86 Project shall + * not be used in advertising or otherwise to promote the sale, use or other + * dealings in this Software without prior written authorization from the + * XFree86 Project. + * + */ + +#ifndef _MICOORD_H_ +#define _MICOORD_H_ 1 + +#include "servermd.h" + +/* Macros which handle a coordinate in a single register */ + +/* + * Most compilers will convert divisions by 65536 into shifts, if signed + * shifts exist. If your machine does arithmetic shifts and your compiler + * can't get it right, add to this line. + */ + +/* + * mips compiler - what a joke - it CSEs the 65536 constant into a reg + * forcing as to use div instead of shift. Let's be explicit. + */ + +#if defined(mips) || defined(sgi) || \ + defined(sparc) || defined(__sparc64__) || \ + defined(__alpha) || defined(__alpha__) || \ + defined(__i386__) || defined(i386) || \ + defined(__ia64__) || defined(ia64) || \ + defined(__s390x__) || defined(__s390__) || \ + defined(__amd64__) || defined(amd64) || defined(__amd64) +#define GetHighWord(x) (((int) (x)) >> 16) +#else +#define GetHighWord(x) (((int) (x)) / 65536) +#endif + +#if IMAGE_BYTE_ORDER == MSBFirst +#define intToCoord(i,x,y) (((x) = GetHighWord(i)), ((y) = (int) ((short) (i)))) +#define coordToInt(x,y) (((x) << 16) | ((y) & 0xffff)) +#define intToX(i) (GetHighWord(i)) +#define intToY(i) ((int) ((short) i)) +#else +#define intToCoord(i,x,y) (((x) = (int) ((short) (i))), ((y) = GetHighWord(i))) +#define coordToInt(x,y) (((y) << 16) | ((x) & 0xffff)) +#define intToX(i) ((int) ((short) (i))) +#define intToY(i) (GetHighWord(i)) +#endif + +#endif /* _MICOORD_H_ */ diff --git a/xserver/mi/micursor.c b/xserver/mi/micursor.c new file mode 100644 index 000000000..6e06fbc07 --- /dev/null +++ b/xserver/mi/micursor.c @@ -0,0 +1,75 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "scrnintstr.h" +#include "cursor.h" +#include "misc.h" +#include "mi.h" + +extern Bool Must_have_memory; + +_X_EXPORT void +miRecolorCursor( pScr, pCurs, displayed) + ScreenPtr pScr; + CursorPtr pCurs; + Bool displayed; +{ + /* + * This is guaranteed to correct any color-dependent state which may have + * been bound up in private state created by RealizeCursor + */ + (* pScr->UnrealizeCursor)( pScr, pCurs); + Must_have_memory = TRUE; /* XXX */ + (* pScr->RealizeCursor)( pScr, pCurs); + Must_have_memory = FALSE; /* XXX */ + if ( displayed) + (* pScr->DisplayCursor)( pScr, pCurs); + +} diff --git a/xserver/mi/midash.c b/xserver/mi/midash.c new file mode 100644 index 000000000..6dd161a39 --- /dev/null +++ b/xserver/mi/midash.c @@ -0,0 +1,313 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "regionstr.h" +#include "mistruct.h" +#include "mifpoly.h" + +static miDashPtr CheckDashStorage(miDashPtr *ppseg, int nseg, int *pnsegMax); + +/* return a list of DashRec. there will be an extra +entry at the end holding the last point of the polyline. + this means that the code that actually draws dashes can +get a pair of points for every dash. only the point in the last +dash record is useful; the other fields are not used. + nseg is the number of segments, not the number of points. + +example: + + dash1.start + dash2.start + dash3.start + last-point + +defines a list of segments + (dash1.pt, dash2.pt) + (dash2.pt, dash3.pt) + (dash3.pt, last-point) +and nseg == 3. + +NOTE: + EVEN_DASH == ~ODD_DASH + +NOTE ALSO: + miDashLines may return 0 segments, going from pt[0] to pt[0] with one dash. +*/ + +miDashPtr +miDashLine(npt, ppt, nDash, pDash, offset, pnseg) +int npt; +DDXPointPtr ppt; +unsigned int nDash; +unsigned char *pDash; +unsigned int offset; +int *pnseg; +{ + DDXPointRec pt1, pt2; + int lenCur; /* npt used from this dash */ + int lenMax; /* npt in this dash */ + int iDash = 0; /* index of current dash */ + int which; /* EVEN_DASH or ODD_DASH */ + miDashPtr pseg; /* list of dash segments */ + miDashPtr psegBase; /* start of list */ + int nseg = 0; /* number of dashes so far */ + int nsegMax = 0; /* num segs we can fit in this list */ + + int x, y, len; + int adx, ady, signdx, signdy; + int du, dv, e1, e2, e, base_e = 0; + + lenCur = offset; + which = EVEN_DASH; + while(lenCur >= pDash[iDash]) + { + lenCur -= pDash[iDash]; + iDash++; + if (iDash >= nDash) + iDash = 0; + which = ~which; + } + lenMax = pDash[iDash]; + + psegBase = (miDashPtr)NULL; + pt2 = ppt[0]; /* just in case there is only one point */ + + while(--npt) + { + if (PtEqual(ppt[0], ppt[1])) + { + ppt++; + continue; /* no duplicated points in polyline */ + } + pt1 = *ppt++; + pt2 = *ppt; + + adx = pt2.x - pt1.x; + ady = pt2.y - pt1.y; + signdx = sign(adx); + signdy = sign(ady); + adx = abs(adx); + ady = abs(ady); + + if (adx > ady) + { + du = adx; + dv = ady; + len = adx; + } + else + { + du = ady; + dv = adx; + len = ady; + } + + e1 = dv * 2; + e2 = e1 - 2*du; + e = e1 - du; + x = pt1.x; + y = pt1.y; + + nseg++; + pseg = CheckDashStorage(&psegBase, nseg, &nsegMax); + if (!pseg) + return (miDashPtr)NULL; + pseg->pt = pt1; + pseg->e1 = e1; + pseg->e2 = e2; + base_e = pseg->e = e; + pseg->which = which; + pseg->newLine = 1; + + while (len--) + { + if (adx > ady) + { + /* X_AXIS */ + if (((signdx > 0) && (e < 0)) || + ((signdx <=0) && (e <=0)) + ) + { + e += e1; + } + else + { + y += signdy; + e += e2; + } + x += signdx; + } + else + { + /* Y_AXIS */ + if (((signdx > 0) && (e < 0)) || + ((signdx <=0) && (e <=0)) + ) + { + e +=e1; + } + else + { + x += signdx; + e += e2; + } + y += signdy; + } + + lenCur++; + if (lenCur >= lenMax && (len || npt <= 1)) + { + nseg++; + pseg = CheckDashStorage(&psegBase, nseg, &nsegMax); + if (!pseg) + return (miDashPtr)NULL; + pseg->pt.x = x; + pseg->pt.y = y; + pseg->e1 = e1; + pseg->e2 = e2; + pseg->e = e; + which = ~which; + pseg->which = which; + pseg->newLine = 0; + + /* move on to next dash */ + iDash++; + if (iDash >= nDash) + iDash = 0; + lenMax = pDash[iDash]; + lenCur = 0; + } + } /* while len-- */ + } /* while --npt */ + + if (lenCur == 0 && nseg != 0) + { + nseg--; + which = ~which; + } + *pnseg = nseg; + pseg = CheckDashStorage(&psegBase, nseg+1, &nsegMax); + if (!pseg) + return (miDashPtr)NULL; + pseg->pt = pt2; + pseg->e = base_e; + pseg->which = which; + pseg->newLine = 0; + return psegBase; +} + + +#define NSEGDELTA 16 + +/* returns a pointer to the pseg[nseg-1], growing the storage as +necessary. this interface seems unnecessarily cumbersome. + +*/ + +static +miDashPtr +CheckDashStorage( + miDashPtr *ppseg, /* base pointer */ + int nseg, /* number of segment we want to write to */ + int *pnsegMax) /* size (in segments) of list so far */ +{ + if (nseg > *pnsegMax) + { + miDashPtr newppseg; + + *pnsegMax += NSEGDELTA; + newppseg = (miDashPtr)xrealloc(*ppseg, + (*pnsegMax)*sizeof(miDashRec)); + if (!newppseg) + { + xfree(*ppseg); + return (miDashPtr)NULL; + } + *ppseg = newppseg; + } + return(*ppseg+(nseg-1)); +} + +_X_EXPORT void +miStepDash (dist, pDashIndex, pDash, numInDashList, pDashOffset) + int dist; /* distance to step */ + int *pDashIndex; /* current dash */ + unsigned char *pDash; /* dash list */ + int numInDashList; /* total length of dash list */ + int *pDashOffset; /* offset into current dash */ +{ + int dashIndex, dashOffset; + int totallen; + int i; + + dashIndex = *pDashIndex; + dashOffset = *pDashOffset; + if (dist < pDash[dashIndex] - dashOffset) + { + *pDashOffset = dashOffset + dist; + return; + } + dist -= pDash[dashIndex] - dashOffset; + if (++dashIndex == numInDashList) + dashIndex = 0; + totallen = 0; + for (i = 0; i < numInDashList; i++) + totallen += pDash[i]; + if (totallen <= dist) + dist = dist % totallen; + while (dist >= pDash[dashIndex]) + { + dist -= pDash[dashIndex]; + if (++dashIndex == numInDashList) + dashIndex = 0; + } + *pDashIndex = dashIndex; + *pDashOffset = dist; +} diff --git a/xserver/mi/midispcur.c b/xserver/mi/midispcur.c new file mode 100644 index 000000000..de009cbaf --- /dev/null +++ b/xserver/mi/midispcur.c @@ -0,0 +1,816 @@ +/* + * midispcur.c + * + * machine independent cursor display routines + */ + + +/* + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#define NEED_EVENTS +# include <X11/X.h> +# include "misc.h" +# include "input.h" +# include "cursorstr.h" +# include "windowstr.h" +# include "regionstr.h" +# include "dixstruct.h" +# include "scrnintstr.h" +# include "servermd.h" +# include "mipointer.h" +# include "misprite.h" +# include "gcstruct.h" + +#ifdef ARGB_CURSOR +# include "picturestr.h" +#endif + +/* per-screen private data */ + +static int miDCScreenIndex; +static unsigned long miDCGeneration = 0; + +static Bool miDCCloseScreen(int index, ScreenPtr pScreen); + +typedef struct { + GCPtr pSourceGC, pMaskGC; + GCPtr pSaveGC, pRestoreGC; + GCPtr pMoveGC; + GCPtr pPixSourceGC, pPixMaskGC; + CloseScreenProcPtr CloseScreen; + PixmapPtr pSave, pTemp; +#ifdef ARGB_CURSOR + PicturePtr pRootPicture; + PicturePtr pTempPicture; +#endif +} miDCScreenRec, *miDCScreenPtr; + +/* per-cursor per-screen private data */ +typedef struct { + PixmapPtr sourceBits; /* source bits */ + PixmapPtr maskBits; /* mask bits */ +#ifdef ARGB_CURSOR + PicturePtr pPicture; +#endif +} miDCCursorRec, *miDCCursorPtr; + +/* + * sprite/cursor method table + */ + +static Bool miDCRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); +static Bool miDCUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); +static Bool miDCPutUpCursor(ScreenPtr pScreen, CursorPtr pCursor, + int x, int y, unsigned long source, + unsigned long mask); +static Bool miDCSaveUnderCursor(ScreenPtr pScreen, int x, int y, + int w, int h); +static Bool miDCRestoreUnderCursor(ScreenPtr pScreen, int x, int y, + int w, int h); +static Bool miDCMoveCursor(ScreenPtr pScreen, CursorPtr pCursor, + int x, int y, int w, int h, int dx, int dy, + unsigned long source, unsigned long mask); +static Bool miDCChangeSave(ScreenPtr pScreen, int x, int y, int w, int h, + int dx, int dy); + +static miSpriteCursorFuncRec miDCFuncs = { + miDCRealizeCursor, + miDCUnrealizeCursor, + miDCPutUpCursor, + miDCSaveUnderCursor, + miDCRestoreUnderCursor, + miDCMoveCursor, + miDCChangeSave, +}; + +_X_EXPORT Bool +miDCInitialize (pScreen, screenFuncs) + ScreenPtr pScreen; + miPointerScreenFuncPtr screenFuncs; +{ + miDCScreenPtr pScreenPriv; + + if (miDCGeneration != serverGeneration) + { + miDCScreenIndex = AllocateScreenPrivateIndex (); + if (miDCScreenIndex < 0) + return FALSE; + miDCGeneration = serverGeneration; + } + pScreenPriv = (miDCScreenPtr) xalloc (sizeof (miDCScreenRec)); + if (!pScreenPriv) + return FALSE; + + /* + * initialize the entire private structure to zeros + */ + + pScreenPriv->pSourceGC = + pScreenPriv->pMaskGC = + pScreenPriv->pSaveGC = + pScreenPriv->pRestoreGC = + pScreenPriv->pMoveGC = + pScreenPriv->pPixSourceGC = + pScreenPriv->pPixMaskGC = NULL; +#ifdef ARGB_CURSOR + pScreenPriv->pRootPicture = NULL; + pScreenPriv->pTempPicture = NULL; +#endif + + pScreenPriv->pSave = pScreenPriv->pTemp = NULL; + + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = miDCCloseScreen; + + pScreen->devPrivates[miDCScreenIndex].ptr = (pointer) pScreenPriv; + + if (!miSpriteInitialize (pScreen, &miDCFuncs, screenFuncs)) + { + xfree ((pointer) pScreenPriv); + return FALSE; + } + return TRUE; +} + +#define tossGC(gc) (gc ? FreeGC (gc, (GContext) 0) : 0) +#define tossPix(pix) (pix ? (*pScreen->DestroyPixmap) (pix) : TRUE) +#define tossPict(pict) (pict ? FreePicture (pict, 0) : 0) + +static Bool +miDCCloseScreen (index, pScreen) + int index; + ScreenPtr pScreen; +{ + miDCScreenPtr pScreenPriv; + + pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr; + pScreen->CloseScreen = pScreenPriv->CloseScreen; + tossGC (pScreenPriv->pSourceGC); + tossGC (pScreenPriv->pMaskGC); + tossGC (pScreenPriv->pSaveGC); + tossGC (pScreenPriv->pRestoreGC); + tossGC (pScreenPriv->pMoveGC); + tossGC (pScreenPriv->pPixSourceGC); + tossGC (pScreenPriv->pPixMaskGC); + tossPix (pScreenPriv->pSave); + tossPix (pScreenPriv->pTemp); +#ifdef ARGB_CURSOR +#if 0 /* This has been free()d before */ + tossPict (pScreenPriv->pRootPicture); +#endif + tossPict (pScreenPriv->pTempPicture); +#endif + xfree ((pointer) pScreenPriv); + return (*pScreen->CloseScreen) (index, pScreen); +} + +static Bool +miDCRealizeCursor (pScreen, pCursor) + ScreenPtr pScreen; + CursorPtr pCursor; +{ + if (pCursor->bits->refcnt <= 1) + pCursor->bits->devPriv[pScreen->myNum] = (pointer)NULL; + return TRUE; +} + +#ifdef ARGB_CURSOR +#define EnsurePicture(picture,draw,win) (picture || miDCMakePicture(&picture,draw,win)) + +static VisualPtr +miDCGetWindowVisual (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + VisualID vid = wVisual (pWin); + int i; + + for (i = 0; i < pScreen->numVisuals; i++) + if (pScreen->visuals[i].vid == vid) + return &pScreen->visuals[i]; + return 0; +} + +static PicturePtr +miDCMakePicture (PicturePtr *ppPicture, DrawablePtr pDraw, WindowPtr pWin) +{ + ScreenPtr pScreen = pDraw->pScreen; + VisualPtr pVisual; + PictFormatPtr pFormat; + XID subwindow_mode = IncludeInferiors; + PicturePtr pPicture; + int error; + + pVisual = miDCGetWindowVisual (pWin); + if (!pVisual) + return 0; + pFormat = PictureMatchVisual (pScreen, pDraw->depth, pVisual); + if (!pFormat) + return 0; + pPicture = CreatePicture (0, pDraw, pFormat, + CPSubwindowMode, &subwindow_mode, + serverClient, &error); + *ppPicture = pPicture; + return pPicture; +} +#endif + +static miDCCursorPtr +miDCRealize ( + ScreenPtr pScreen, + CursorPtr pCursor) +{ + miDCCursorPtr pPriv; + GCPtr pGC; + XID gcvals[3]; + + pPriv = (miDCCursorPtr) xalloc (sizeof (miDCCursorRec)); + if (!pPriv) + return (miDCCursorPtr)NULL; +#ifdef ARGB_CURSOR + if (pCursor->bits->argb) + { + PixmapPtr pPixmap; + PictFormatPtr pFormat; + int error; + + pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); + if (!pFormat) + { + xfree ((pointer) pPriv); + return (miDCCursorPtr)NULL; + } + + pPriv->sourceBits = 0; + pPriv->maskBits = 0; + pPixmap = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, + pCursor->bits->height, 32); + if (!pPixmap) + { + xfree ((pointer) pPriv); + return (miDCCursorPtr)NULL; + } + pGC = GetScratchGC (32, pScreen); + if (!pGC) + { + (*pScreen->DestroyPixmap) (pPixmap); + xfree ((pointer) pPriv); + return (miDCCursorPtr)NULL; + } + ValidateGC (&pPixmap->drawable, pGC); + (*pGC->ops->PutImage) (&pPixmap->drawable, pGC, 32, + 0, 0, pCursor->bits->width, + pCursor->bits->height, + 0, ZPixmap, (char *) pCursor->bits->argb); + FreeScratchGC (pGC); + pPriv->pPicture = CreatePicture (0, &pPixmap->drawable, + pFormat, 0, 0, serverClient, &error); + (*pScreen->DestroyPixmap) (pPixmap); + if (!pPriv->pPicture) + { + xfree ((pointer) pPriv); + return (miDCCursorPtr)NULL; + } + pCursor->bits->devPriv[pScreen->myNum] = (pointer) pPriv; + return pPriv; + } + pPriv->pPicture = 0; +#endif + pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1); + if (!pPriv->sourceBits) + { + xfree ((pointer) pPriv); + return (miDCCursorPtr)NULL; + } + pPriv->maskBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1); + if (!pPriv->maskBits) + { + (*pScreen->DestroyPixmap) (pPriv->sourceBits); + xfree ((pointer) pPriv); + return (miDCCursorPtr)NULL; + } + pCursor->bits->devPriv[pScreen->myNum] = (pointer) pPriv; + + /* create the two sets of bits, clipping as appropriate */ + + pGC = GetScratchGC (1, pScreen); + if (!pGC) + { + (void) miDCUnrealizeCursor (pScreen, pCursor); + return (miDCCursorPtr)NULL; + } + + ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC); + (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1, + 0, 0, pCursor->bits->width, pCursor->bits->height, + 0, XYPixmap, (char *)pCursor->bits->source); + gcvals[0] = GXand; + ChangeGC (pGC, GCFunction, gcvals); + ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC); + (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1, + 0, 0, pCursor->bits->width, pCursor->bits->height, + 0, XYPixmap, (char *)pCursor->bits->mask); + + /* mask bits -- pCursor->mask & ~pCursor->source */ + gcvals[0] = GXcopy; + ChangeGC (pGC, GCFunction, gcvals); + ValidateGC ((DrawablePtr)pPriv->maskBits, pGC); + (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1, + 0, 0, pCursor->bits->width, pCursor->bits->height, + 0, XYPixmap, (char *)pCursor->bits->mask); + gcvals[0] = GXandInverted; + ChangeGC (pGC, GCFunction, gcvals); + ValidateGC ((DrawablePtr)pPriv->maskBits, pGC); + (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1, + 0, 0, pCursor->bits->width, pCursor->bits->height, + 0, XYPixmap, (char *)pCursor->bits->source); + FreeScratchGC (pGC); + return pPriv; +} + +static Bool +miDCUnrealizeCursor (pScreen, pCursor) + ScreenPtr pScreen; + CursorPtr pCursor; +{ + miDCCursorPtr pPriv; + + pPriv = (miDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum]; + if (pPriv && (pCursor->bits->refcnt <= 1)) + { + if (pPriv->sourceBits) + (*pScreen->DestroyPixmap) (pPriv->sourceBits); + if (pPriv->maskBits) + (*pScreen->DestroyPixmap) (pPriv->maskBits); +#ifdef ARGB_CURSOR + if (pPriv->pPicture) + FreePicture (pPriv->pPicture, 0); +#endif + xfree ((pointer) pPriv); + pCursor->bits->devPriv[pScreen->myNum] = (pointer)NULL; + } + return TRUE; +} + +static void +miDCPutBits ( + DrawablePtr pDrawable, + miDCCursorPtr pPriv, + GCPtr sourceGC, + GCPtr maskGC, + int x_org, + int y_org, + unsigned w, + unsigned h, + unsigned long source, + unsigned long mask) +{ + XID gcvals[1]; + int x, y; + + if (sourceGC->fgPixel != source) + { + gcvals[0] = source; + DoChangeGC (sourceGC, GCForeground, gcvals, 0); + } + if (sourceGC->serialNumber != pDrawable->serialNumber) + ValidateGC (pDrawable, sourceGC); + + if(sourceGC->miTranslate) + { + x = pDrawable->x + x_org; + y = pDrawable->y + y_org; + } + else + { + x = x_org; + y = y_org; + } + + (*sourceGC->ops->PushPixels) (sourceGC, pPriv->sourceBits, pDrawable, w, h, x, y); + if (maskGC->fgPixel != mask) + { + gcvals[0] = mask; + DoChangeGC (maskGC, GCForeground, gcvals, 0); + } + if (maskGC->serialNumber != pDrawable->serialNumber) + ValidateGC (pDrawable, maskGC); + + if(maskGC->miTranslate) + { + x = pDrawable->x + x_org; + y = pDrawable->y + y_org; + } + else + { + x = x_org; + y = y_org; + } + + (*maskGC->ops->PushPixels) (maskGC, pPriv->maskBits, pDrawable, w, h, x, y); +} + +#define EnsureGC(gc,win) (gc || miDCMakeGC(&gc, win)) + +static GCPtr +miDCMakeGC( + GCPtr *ppGC, + WindowPtr pWin) +{ + GCPtr pGC; + int status; + XID gcvals[2]; + + gcvals[0] = IncludeInferiors; + gcvals[1] = FALSE; + pGC = CreateGC((DrawablePtr)pWin, + GCSubwindowMode|GCGraphicsExposures, gcvals, &status); + if (pGC && pWin->drawable.pScreen->DrawGuarantee) + (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeVisBack); + *ppGC = pGC; + return pGC; +} + + +static Bool +miDCPutUpCursor (pScreen, pCursor, x, y, source, mask) + ScreenPtr pScreen; + CursorPtr pCursor; + int x, y; + unsigned long source, mask; +{ + miDCScreenPtr pScreenPriv; + miDCCursorPtr pPriv; + WindowPtr pWin; + + pPriv = (miDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum]; + if (!pPriv) + { + pPriv = miDCRealize(pScreen, pCursor); + if (!pPriv) + return FALSE; + } + pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr; + pWin = WindowTable[pScreen->myNum]; +#ifdef ARGB_CURSOR + if (pPriv->pPicture) + { + if (!EnsurePicture(pScreenPriv->pRootPicture, &pWin->drawable, pWin)) + return FALSE; + CompositePicture (PictOpOver, + pPriv->pPicture, + NULL, + pScreenPriv->pRootPicture, + 0, 0, 0, 0, + x, y, + pCursor->bits->width, + pCursor->bits->height); + } + else +#endif + { + if (!EnsureGC(pScreenPriv->pSourceGC, pWin)) + return FALSE; + if (!EnsureGC(pScreenPriv->pMaskGC, pWin)) + { + FreeGC (pScreenPriv->pSourceGC, (GContext) 0); + pScreenPriv->pSourceGC = 0; + return FALSE; + } + miDCPutBits ((DrawablePtr)pWin, pPriv, + pScreenPriv->pSourceGC, pScreenPriv->pMaskGC, + x, y, pCursor->bits->width, pCursor->bits->height, + source, mask); + } + return TRUE; +} + +static Bool +miDCSaveUnderCursor (pScreen, x, y, w, h) + ScreenPtr pScreen; + int x, y, w, h; +{ + miDCScreenPtr pScreenPriv; + PixmapPtr pSave; + WindowPtr pWin; + GCPtr pGC; + + pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr; + pSave = pScreenPriv->pSave; + pWin = WindowTable[pScreen->myNum]; + if (!pSave || pSave->drawable.width < w || pSave->drawable.height < h) + { + if (pSave) + (*pScreen->DestroyPixmap) (pSave); + pScreenPriv->pSave = pSave = + (*pScreen->CreatePixmap) (pScreen, w, h, pScreen->rootDepth); + if (!pSave) + return FALSE; + } + if (!EnsureGC(pScreenPriv->pSaveGC, pWin)) + return FALSE; + pGC = pScreenPriv->pSaveGC; + if (pSave->drawable.serialNumber != pGC->serialNumber) + ValidateGC ((DrawablePtr) pSave, pGC); + (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, + x, y, w, h, 0, 0); + return TRUE; +} + +static Bool +miDCRestoreUnderCursor (pScreen, x, y, w, h) + ScreenPtr pScreen; + int x, y, w, h; +{ + miDCScreenPtr pScreenPriv; + PixmapPtr pSave; + WindowPtr pWin; + GCPtr pGC; + + pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr; + pSave = pScreenPriv->pSave; + pWin = WindowTable[pScreen->myNum]; + if (!pSave) + return FALSE; + if (!EnsureGC(pScreenPriv->pRestoreGC, pWin)) + return FALSE; + pGC = pScreenPriv->pRestoreGC; + if (pWin->drawable.serialNumber != pGC->serialNumber) + ValidateGC ((DrawablePtr) pWin, pGC); + (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, + 0, 0, w, h, x, y); + return TRUE; +} + +static Bool +miDCChangeSave (pScreen, x, y, w, h, dx, dy) + ScreenPtr pScreen; + int x, y, w, h, dx, dy; +{ + miDCScreenPtr pScreenPriv; + PixmapPtr pSave; + WindowPtr pWin; + GCPtr pGC; + int sourcex, sourcey, destx, desty, copyw, copyh; + + pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr; + pSave = pScreenPriv->pSave; + pWin = WindowTable[pScreen->myNum]; + /* + * restore the bits which are about to get trashed + */ + if (!pSave) + return FALSE; + if (!EnsureGC(pScreenPriv->pRestoreGC, pWin)) + return FALSE; + pGC = pScreenPriv->pRestoreGC; + if (pWin->drawable.serialNumber != pGC->serialNumber) + ValidateGC ((DrawablePtr) pWin, pGC); + /* + * copy the old bits to the screen. + */ + if (dy > 0) + { + (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, + 0, h - dy, w, dy, x + dx, y + h); + } + else if (dy < 0) + { + (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, + 0, 0, w, -dy, x + dx, y + dy); + } + if (dy >= 0) + { + desty = y + dy; + sourcey = 0; + copyh = h - dy; + } + else + { + desty = y; + sourcey = - dy; + copyh = h + dy; + } + if (dx > 0) + { + (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, + w - dx, sourcey, dx, copyh, x + w, desty); + } + else if (dx < 0) + { + (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, + 0, sourcey, -dx, copyh, x + dx, desty); + } + if (!EnsureGC(pScreenPriv->pSaveGC, pWin)) + return FALSE; + pGC = pScreenPriv->pSaveGC; + if (pSave->drawable.serialNumber != pGC->serialNumber) + ValidateGC ((DrawablePtr) pSave, pGC); + /* + * move the bits that are still valid within the pixmap + */ + if (dx >= 0) + { + sourcex = 0; + destx = dx; + copyw = w - dx; + } + else + { + destx = 0; + sourcex = - dx; + copyw = w + dx; + } + if (dy >= 0) + { + sourcey = 0; + desty = dy; + copyh = h - dy; + } + else + { + desty = 0; + sourcey = -dy; + copyh = h + dy; + } + (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pSave, pGC, + sourcex, sourcey, copyw, copyh, destx, desty); + /* + * copy the new bits from the screen into the remaining areas of the + * pixmap + */ + if (dy > 0) + { + (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, + x, y, w, dy, 0, 0); + } + else if (dy < 0) + { + (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, + x, y + h + dy, w, -dy, 0, h + dy); + } + if (dy >= 0) + { + desty = dy; + sourcey = y + dy; + copyh = h - dy; + } + else + { + desty = 0; + sourcey = y; + copyh = h + dy; + } + if (dx > 0) + { + (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, + x, sourcey, dx, copyh, 0, desty); + } + else if (dx < 0) + { + (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, + x + w + dx, sourcey, -dx, copyh, w + dx, desty); + } + return TRUE; +} + +static Bool +miDCMoveCursor (pScreen, pCursor, x, y, w, h, dx, dy, source, mask) + ScreenPtr pScreen; + CursorPtr pCursor; + int x, y, w, h, dx, dy; + unsigned long source, mask; +{ + miDCCursorPtr pPriv; + miDCScreenPtr pScreenPriv; + int status; + WindowPtr pWin; + GCPtr pGC; + XID gcval = FALSE; + PixmapPtr pTemp; + + pPriv = (miDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum]; + if (!pPriv) + { + pPriv = miDCRealize(pScreen, pCursor); + if (!pPriv) + return FALSE; + } + pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr; + pWin = WindowTable[pScreen->myNum]; + pTemp = pScreenPriv->pTemp; + if (!pTemp || + pTemp->drawable.width != pScreenPriv->pSave->drawable.width || + pTemp->drawable.height != pScreenPriv->pSave->drawable.height) + { + if (pTemp) + (*pScreen->DestroyPixmap) (pTemp); +#ifdef ARGB_CURSOR + if (pScreenPriv->pTempPicture) + { + FreePicture (pScreenPriv->pTempPicture, 0); + pScreenPriv->pTempPicture = 0; + } +#endif + pScreenPriv->pTemp = pTemp = (*pScreen->CreatePixmap) + (pScreen, w, h, pScreenPriv->pSave->drawable.depth); + if (!pTemp) + return FALSE; + } + if (!pScreenPriv->pMoveGC) + { + pScreenPriv->pMoveGC = CreateGC ((DrawablePtr)pTemp, + GCGraphicsExposures, &gcval, &status); + if (!pScreenPriv->pMoveGC) + return FALSE; + } + /* + * copy the saved area to a temporary pixmap + */ + pGC = pScreenPriv->pMoveGC; + if (pGC->serialNumber != pTemp->drawable.serialNumber) + ValidateGC ((DrawablePtr) pTemp, pGC); + (*pGC->ops->CopyArea)((DrawablePtr)pScreenPriv->pSave, + (DrawablePtr)pTemp, pGC, 0, 0, w, h, 0, 0); + + /* + * draw the cursor in the temporary pixmap + */ +#ifdef ARGB_CURSOR + if (pPriv->pPicture) + { + if (!EnsurePicture(pScreenPriv->pTempPicture, &pTemp->drawable, pWin)) + return FALSE; + CompositePicture (PictOpOver, + pPriv->pPicture, + NULL, + pScreenPriv->pTempPicture, + 0, 0, 0, 0, + dx, dy, + pCursor->bits->width, + pCursor->bits->height); + } + else +#endif + { + if (!pScreenPriv->pPixSourceGC) + { + pScreenPriv->pPixSourceGC = CreateGC ((DrawablePtr)pTemp, + GCGraphicsExposures, &gcval, &status); + if (!pScreenPriv->pPixSourceGC) + return FALSE; + } + if (!pScreenPriv->pPixMaskGC) + { + pScreenPriv->pPixMaskGC = CreateGC ((DrawablePtr)pTemp, + GCGraphicsExposures, &gcval, &status); + if (!pScreenPriv->pPixMaskGC) + return FALSE; + } + miDCPutBits ((DrawablePtr)pTemp, pPriv, + pScreenPriv->pPixSourceGC, pScreenPriv->pPixMaskGC, + dx, dy, pCursor->bits->width, pCursor->bits->height, + source, mask); + } + + /* + * copy the temporary pixmap onto the screen + */ + + if (!EnsureGC(pScreenPriv->pRestoreGC, pWin)) + return FALSE; + pGC = pScreenPriv->pRestoreGC; + if (pWin->drawable.serialNumber != pGC->serialNumber) + ValidateGC ((DrawablePtr) pWin, pGC); + + (*pGC->ops->CopyArea) ((DrawablePtr) pTemp, (DrawablePtr) pWin, + pGC, + 0, 0, w, h, x, y); + return TRUE; +} diff --git a/xserver/mi/mieq.c b/xserver/mi/mieq.c new file mode 100644 index 000000000..a69ce7037 --- /dev/null +++ b/xserver/mi/mieq.c @@ -0,0 +1,194 @@ +/* + * +Copyright 1990, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + * + * Author: Keith Packard, MIT X Consortium + */ + +/* + * mieq.c + * + * Machine independent event queue + * + */ + +#if HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +# define NEED_EVENTS +# include <X11/X.h> +# include <X11/Xmd.h> +# include <X11/Xproto.h> +# include "misc.h" +# include "windowstr.h" +# include "pixmapstr.h" +# include "inputstr.h" +# include "mi.h" +# include "scrnintstr.h" + +#define QUEUE_SIZE 256 + +typedef struct _Event { + xEvent event; + ScreenPtr pScreen; +} EventRec, *EventPtr; + +typedef struct _EventQueue { + HWEventQueueType head, tail; /* long for SetInputCheck */ + CARD32 lastEventTime; /* to avoid time running backwards */ + Bool lastMotion; + EventRec events[QUEUE_SIZE]; /* static allocation for signals */ + DevicePtr pKbd, pPtr; /* device pointer, to get funcs */ + ScreenPtr pEnqueueScreen; /* screen events are being delivered to */ + ScreenPtr pDequeueScreen; /* screen events are being dispatched to */ +} EventQueueRec, *EventQueuePtr; + +static EventQueueRec miEventQueue; + +Bool +mieqInit (pKbd, pPtr) + DevicePtr pKbd, pPtr; +{ + miEventQueue.head = miEventQueue.tail = 0; + miEventQueue.lastEventTime = GetTimeInMillis (); + miEventQueue.pKbd = pKbd; + miEventQueue.pPtr = pPtr; + miEventQueue.lastMotion = FALSE; + miEventQueue.pEnqueueScreen = screenInfo.screens[0]; + miEventQueue.pDequeueScreen = miEventQueue.pEnqueueScreen; + SetInputCheck (&miEventQueue.head, &miEventQueue.tail); + return TRUE; +} + +/* + * Must be reentrant with ProcessInputEvents. Assumption: mieqEnqueue + * will never be interrupted. If this is called from both signal + * handlers and regular code, make sure the signal is suspended when + * called from regular code. + */ + +void +mieqEnqueue (e) + xEvent *e; +{ + HWEventQueueType oldtail, newtail; + Bool isMotion; + + oldtail = miEventQueue.tail; + isMotion = e->u.u.type == MotionNotify; + if (isMotion && miEventQueue.lastMotion && oldtail != miEventQueue.head) + { + if (oldtail == 0) + oldtail = QUEUE_SIZE; + oldtail = oldtail - 1; + } + else + { + newtail = oldtail + 1; + if (newtail == QUEUE_SIZE) + newtail = 0; + /* Toss events which come in late */ + if (newtail == miEventQueue.head) + return; + miEventQueue.tail = newtail; + } + miEventQueue.lastMotion = isMotion; + miEventQueue.events[oldtail].event = *e; + /* + * Make sure that event times don't go backwards - this + * is "unnecessary", but very useful + */ + if (e->u.keyButtonPointer.time < miEventQueue.lastEventTime && + miEventQueue.lastEventTime - e->u.keyButtonPointer.time < 10000) + { + miEventQueue.events[oldtail].event.u.keyButtonPointer.time = + miEventQueue.lastEventTime; + } + miEventQueue.lastEventTime = + miEventQueue.events[oldtail].event.u.keyButtonPointer.time; + miEventQueue.events[oldtail].pScreen = miEventQueue.pEnqueueScreen; +} + +void +mieqSwitchScreen (pScreen, fromDIX) + ScreenPtr pScreen; + Bool fromDIX; +{ + miEventQueue.pEnqueueScreen = pScreen; + if (fromDIX) + miEventQueue.pDequeueScreen = pScreen; +} + +/* + * Call this from ProcessInputEvents() + */ + +void mieqProcessInputEvents () +{ + EventRec *e; + int x, y; + xEvent xe; + + while (miEventQueue.head != miEventQueue.tail) + { + if (screenIsSaved == SCREEN_SAVER_ON) + SaveScreens (SCREEN_SAVER_OFF, ScreenSaverReset); + + e = &miEventQueue.events[miEventQueue.head]; + /* + * Assumption - screen switching can only occur on motion events + */ + if (e->pScreen != miEventQueue.pDequeueScreen) + { + miEventQueue.pDequeueScreen = e->pScreen; + x = e->event.u.keyButtonPointer.rootX; + y = e->event.u.keyButtonPointer.rootY; + if (miEventQueue.head == QUEUE_SIZE - 1) + miEventQueue.head = 0; + else + ++miEventQueue.head; + NewCurrentScreen (miEventQueue.pDequeueScreen, x, y); + } + else + { + xe = e->event; + if (miEventQueue.head == QUEUE_SIZE - 1) + miEventQueue.head = 0; + else + ++miEventQueue.head; + switch (xe.u.u.type) + { + case KeyPress: + case KeyRelease: + (*miEventQueue.pKbd->processInputProc) + (&xe, (DeviceIntPtr)miEventQueue.pKbd, 1); + break; + default: + (*miEventQueue.pPtr->processInputProc) + (&xe, (DeviceIntPtr)miEventQueue.pPtr, 1); + break; + } + } + } +} diff --git a/xserver/mi/miexpose.c b/xserver/mi/miexpose.c new file mode 100644 index 000000000..1ca5fc965 --- /dev/null +++ b/xserver/mi/miexpose.c @@ -0,0 +1,902 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#define NEED_EVENTS +#include <X11/Xproto.h> +#include <X11/Xprotostr.h> + +#include "misc.h" +#include "regionstr.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "windowstr.h" +#include "pixmap.h" +#include "input.h" + +#include "dixstruct.h" +#include "mi.h" +#include <X11/Xmd.h> + +#include "globals.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +/* + machine-independent graphics exposure code. any device that uses +the region package can call this. +*/ + +#ifndef RECTLIMIT +#define RECTLIMIT 25 /* pick a number, any number > 8 */ +#endif + +/* miHandleExposures + generate a region for exposures for areas that were copied from obscured or +non-existent areas to non-obscured areas of the destination. Paint the +background for the region, if the destination is a window. + +NOTE: + this should generally be called, even if graphicsExposures is false, +because this is where bits get recovered from backing store. + +NOTE: + added argument 'plane' is used to indicate how exposures from backing +store should be accomplished. If plane is 0 (i.e. no bit plane), CopyArea +should be used, else a CopyPlane of the indicated plane will be used. The +exposing is done by the backing store's GraphicsExpose function, of course. + +*/ + +_X_EXPORT RegionPtr +miHandleExposures(pSrcDrawable, pDstDrawable, + pGC, srcx, srcy, width, height, dstx, dsty, plane) + register DrawablePtr pSrcDrawable; + register DrawablePtr pDstDrawable; + GCPtr pGC; + int srcx, srcy; + int width, height; + int dstx, dsty; + unsigned long plane; +{ + register ScreenPtr pscr; + RegionPtr prgnSrcClip; /* drawable-relative source clip */ + RegionRec rgnSrcRec; + RegionPtr prgnDstClip; /* drawable-relative dest clip */ + RegionRec rgnDstRec; + BoxRec srcBox; /* unclipped source */ + RegionRec rgnExposed; /* exposed region, calculated source- + relative, made dst relative to + intersect with visible parts of + dest and send events to client, + and then screen relative to paint + the window background + */ + WindowPtr pSrcWin; + BoxRec expBox; + Bool extents; + + /* This prevents warning about pscr not being used. */ + pGC->pScreen = pscr = pGC->pScreen; + + /* avoid work if we can */ + if (!pGC->graphicsExposures && + (pDstDrawable->type == DRAWABLE_PIXMAP) && + ((pSrcDrawable->type == DRAWABLE_PIXMAP) || + (((WindowPtr)pSrcDrawable)->backStorage == NULL))) + return NULL; + + srcBox.x1 = srcx; + srcBox.y1 = srcy; + srcBox.x2 = srcx+width; + srcBox.y2 = srcy+height; + + if (pSrcDrawable->type != DRAWABLE_PIXMAP) + { + BoxRec TsrcBox; + + TsrcBox.x1 = srcx + pSrcDrawable->x; + TsrcBox.y1 = srcy + pSrcDrawable->y; + TsrcBox.x2 = TsrcBox.x1 + width; + TsrcBox.y2 = TsrcBox.y1 + height; + pSrcWin = (WindowPtr) pSrcDrawable; + if (pGC->subWindowMode == IncludeInferiors) + { + prgnSrcClip = NotClippedByChildren (pSrcWin); + if ((RECT_IN_REGION(pscr, prgnSrcClip, &TsrcBox)) == rgnIN) + { + REGION_DESTROY(pscr, prgnSrcClip); + return NULL; + } + } + else + { + if ((RECT_IN_REGION(pscr, &pSrcWin->clipList, &TsrcBox)) == rgnIN) + return NULL; + prgnSrcClip = &rgnSrcRec; + REGION_NULL(pscr, prgnSrcClip); + REGION_COPY(pscr, prgnSrcClip, &pSrcWin->clipList); + } + REGION_TRANSLATE(pscr, prgnSrcClip, + -pSrcDrawable->x, -pSrcDrawable->y); + } + else + { + BoxRec box; + + if ((srcBox.x1 >= 0) && (srcBox.y1 >= 0) && + (srcBox.x2 <= pSrcDrawable->width) && + (srcBox.y2 <= pSrcDrawable->height)) + return NULL; + + box.x1 = 0; + box.y1 = 0; + box.x2 = pSrcDrawable->width; + box.y2 = pSrcDrawable->height; + prgnSrcClip = &rgnSrcRec; + REGION_INIT(pscr, prgnSrcClip, &box, 1); + pSrcWin = (WindowPtr)NULL; + } + + if (pDstDrawable == pSrcDrawable) + { + prgnDstClip = prgnSrcClip; + } + else if (pDstDrawable->type != DRAWABLE_PIXMAP) + { + if (pGC->subWindowMode == IncludeInferiors) + { + prgnDstClip = NotClippedByChildren((WindowPtr)pDstDrawable); + } + else + { + prgnDstClip = &rgnDstRec; + REGION_NULL(pscr, prgnDstClip); + REGION_COPY(pscr, prgnDstClip, + &((WindowPtr)pDstDrawable)->clipList); + } + REGION_TRANSLATE(pscr, prgnDstClip, + -pDstDrawable->x, -pDstDrawable->y); + } + else + { + BoxRec box; + + box.x1 = 0; + box.y1 = 0; + box.x2 = pDstDrawable->width; + box.y2 = pDstDrawable->height; + prgnDstClip = &rgnDstRec; + REGION_INIT(pscr, prgnDstClip, &box, 1); + } + + /* drawable-relative source region */ + REGION_INIT(pscr, &rgnExposed, &srcBox, 1); + + /* now get the hidden parts of the source box*/ + REGION_SUBTRACT(pscr, &rgnExposed, &rgnExposed, prgnSrcClip); + + if (pSrcWin && pSrcWin->backStorage) + { + /* + * Copy any areas from the source backing store. Modifies + * rgnExposed. + */ + (* pSrcWin->drawable.pScreen->ExposeCopy) ((WindowPtr)pSrcDrawable, + pDstDrawable, + pGC, + &rgnExposed, + srcx, srcy, + dstx, dsty, + plane); + } + + /* move them over the destination */ + REGION_TRANSLATE(pscr, &rgnExposed, dstx-srcx, dsty-srcy); + + /* intersect with visible areas of dest */ + REGION_INTERSECT(pscr, &rgnExposed, &rgnExposed, prgnDstClip); + + /* + * If we have LOTS of rectangles, we decide to take the extents + * and force an exposure on that. This should require much less + * work overall, on both client and server. This is cheating, but + * isn't prohibited by the protocol ("spontaneous combustion" :-) + * for windows. + */ + extents = pGC->graphicsExposures && + (REGION_NUM_RECTS(&rgnExposed) > RECTLIMIT) && + (pDstDrawable->type != DRAWABLE_PIXMAP); +#ifdef SHAPE + if (pSrcWin) + { + RegionPtr region; + if (!(region = wClipShape (pSrcWin))) + region = wBoundingShape (pSrcWin); + /* + * If you try to CopyArea the extents of a shaped window, compacting the + * exposed region will undo all our work! + */ + if (extents && pSrcWin && region && + (RECT_IN_REGION(pscr, region, &srcBox) != rgnIN)) + extents = FALSE; + } +#endif + if (extents) + { + WindowPtr pWin = (WindowPtr)pDstDrawable; + + expBox = *REGION_EXTENTS(pscr, &rgnExposed); + REGION_RESET(pscr, &rgnExposed, &expBox); + /* need to clear out new areas of backing store */ + if (pWin->backStorage) + (void) (* pWin->drawable.pScreen->ClearBackingStore)( + pWin, + expBox.x1, + expBox.y1, + expBox.x2 - expBox.x1, + expBox.y2 - expBox.y1, + FALSE); + } + if ((pDstDrawable->type != DRAWABLE_PIXMAP) && + (((WindowPtr)pDstDrawable)->backgroundState != None)) + { + WindowPtr pWin = (WindowPtr)pDstDrawable; + + /* make the exposed area screen-relative */ + REGION_TRANSLATE(pscr, &rgnExposed, + pDstDrawable->x, pDstDrawable->y); + + if (extents) + { + /* PaintWindowBackground doesn't clip, so we have to */ + REGION_INTERSECT(pscr, &rgnExposed, &rgnExposed, &pWin->clipList); + } + (*pWin->drawable.pScreen->PaintWindowBackground)( + (WindowPtr)pDstDrawable, &rgnExposed, PW_BACKGROUND); + + if (extents) + { + REGION_RESET(pscr, &rgnExposed, &expBox); + } + else + REGION_TRANSLATE(pscr, &rgnExposed, + -pDstDrawable->x, -pDstDrawable->y); + } + if (prgnDstClip == &rgnDstRec) + { + REGION_UNINIT(pscr, prgnDstClip); + } + else if (prgnDstClip != prgnSrcClip) + { + REGION_DESTROY(pscr, prgnDstClip); + } + + if (prgnSrcClip == &rgnSrcRec) + { + REGION_UNINIT(pscr, prgnSrcClip); + } + else + { + REGION_DESTROY(pscr, prgnSrcClip); + } + + if (pGC->graphicsExposures) + { + /* don't look */ + RegionPtr exposed = REGION_CREATE(pscr, NullBox, 0); + *exposed = rgnExposed; + return exposed; + } + else + { + REGION_UNINIT(pscr, &rgnExposed); + return NULL; + } +} + +/* send GraphicsExpose events, or a NoExpose event, based on the region */ + +_X_EXPORT void +miSendGraphicsExpose (client, pRgn, drawable, major, minor) + ClientPtr client; + RegionPtr pRgn; + XID drawable; + int major; + int minor; +{ + if (pRgn && !REGION_NIL(pRgn)) + { + xEvent *pEvent; + register xEvent *pe; + register BoxPtr pBox; + register int i; + int numRects; + + numRects = REGION_NUM_RECTS(pRgn); + pBox = REGION_RECTS(pRgn); + if(!(pEvent = (xEvent *)ALLOCATE_LOCAL(numRects * sizeof(xEvent)))) + return; + pe = pEvent; + + for (i=1; i<=numRects; i++, pe++, pBox++) + { + pe->u.u.type = GraphicsExpose; + pe->u.graphicsExposure.drawable = drawable; + pe->u.graphicsExposure.x = pBox->x1; + pe->u.graphicsExposure.y = pBox->y1; + pe->u.graphicsExposure.width = pBox->x2 - pBox->x1; + pe->u.graphicsExposure.height = pBox->y2 - pBox->y1; + pe->u.graphicsExposure.count = numRects - i; + pe->u.graphicsExposure.majorEvent = major; + pe->u.graphicsExposure.minorEvent = minor; + } + TryClientEvents(client, pEvent, numRects, + (Mask)0, NoEventMask, NullGrab); + DEALLOCATE_LOCAL(pEvent); + } + else + { + xEvent event; + event.u.u.type = NoExpose; + event.u.noExposure.drawable = drawable; + event.u.noExposure.majorEvent = major; + event.u.noExposure.minorEvent = minor; + TryClientEvents(client, &event, 1, + (Mask)0, NoEventMask, NullGrab); + } +} + + +void +miSendExposures(pWin, pRgn, dx, dy) + WindowPtr pWin; + RegionPtr pRgn; + register int dx, dy; +{ + register BoxPtr pBox; + int numRects; + register xEvent *pEvent, *pe; + register int i; + + pBox = REGION_RECTS(pRgn); + numRects = REGION_NUM_RECTS(pRgn); + if(!(pEvent = (xEvent *) ALLOCATE_LOCAL(numRects * sizeof(xEvent)))) + return; + + for (i=numRects, pe = pEvent; --i >= 0; pe++, pBox++) + { + pe->u.u.type = Expose; + pe->u.expose.window = pWin->drawable.id; + pe->u.expose.x = pBox->x1 - dx; + pe->u.expose.y = pBox->y1 - dy; + pe->u.expose.width = pBox->x2 - pBox->x1; + pe->u.expose.height = pBox->y2 - pBox->y1; + pe->u.expose.count = i; + } + +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + int scrnum = pWin->drawable.pScreen->myNum; + int x = 0, y = 0; + XID realWin = 0; + + if(!pWin->parent) { + x = panoramiXdataPtr[scrnum].x; + y = panoramiXdataPtr[scrnum].y; + pWin = WindowTable[0]; + realWin = pWin->drawable.id; + } else if (scrnum) { + PanoramiXRes *win; + win = PanoramiXFindIDByScrnum(XRT_WINDOW, + pWin->drawable.id, scrnum); + if(!win) { + DEALLOCATE_LOCAL(pEvent); + return; + } + realWin = win->info[0].id; + pWin = LookupIDByType(realWin, RT_WINDOW); + } + if(x || y || scrnum) + for (i = 0; i < numRects; i++) { + pEvent[i].u.expose.window = realWin; + pEvent[i].u.expose.x += x; + pEvent[i].u.expose.y += y; + } + } +#endif + + DeliverEvents(pWin, pEvent, numRects, NullWindow); + + DEALLOCATE_LOCAL(pEvent); +} + +_X_EXPORT void +miWindowExposures(pWin, prgn, other_exposed) + WindowPtr pWin; + register RegionPtr prgn, other_exposed; +{ + RegionPtr exposures = prgn; + if (pWin->backStorage && prgn) + /* + * in some cases, backing store will cause a different + * region to be exposed than needs to be repainted + * (like when a window is mapped). RestoreAreas is + * allowed to return a region other than prgn, + * in which case this routine will free the resultant + * region. If exposures is null, then no events will + * be sent to the client; if prgn is empty + * no areas will be repainted. + */ + exposures = (*pWin->drawable.pScreen->RestoreAreas)(pWin, prgn); + if ((prgn && !REGION_NIL(prgn)) || + (exposures && !REGION_NIL(exposures)) || other_exposed) + { + RegionRec expRec; + int clientInterested; + + /* + * Restore from backing-store FIRST. + */ + clientInterested = (pWin->eventMask|wOtherEventMasks(pWin)) & ExposureMask; + if (other_exposed) + { + if (exposures) + { + REGION_UNION(pWin->drawable.pScreen, other_exposed, + exposures, + other_exposed); + if (exposures != prgn) + REGION_DESTROY(pWin->drawable.pScreen, exposures); + } + exposures = other_exposed; + } + if (clientInterested && exposures && (REGION_NUM_RECTS(exposures) > RECTLIMIT)) + { + /* + * If we have LOTS of rectangles, we decide to take the extents + * and force an exposure on that. This should require much less + * work overall, on both client and server. This is cheating, but + * isn't prohibited by the protocol ("spontaneous combustion" :-). + */ + BoxRec box; + + box = *REGION_EXTENTS( pWin->drawable.pScreen, exposures); + if (exposures == prgn) { + exposures = &expRec; + REGION_INIT( pWin->drawable.pScreen, exposures, &box, 1); + REGION_RESET( pWin->drawable.pScreen, prgn, &box); + } else { + REGION_RESET( pWin->drawable.pScreen, exposures, &box); + REGION_UNION( pWin->drawable.pScreen, prgn, prgn, exposures); + } + /* PaintWindowBackground doesn't clip, so we have to */ + REGION_INTERSECT( pWin->drawable.pScreen, prgn, prgn, &pWin->clipList); + /* need to clear out new areas of backing store, too */ + if (pWin->backStorage) + (void) (* pWin->drawable.pScreen->ClearBackingStore)( + pWin, + box.x1 - pWin->drawable.x, + box.y1 - pWin->drawable.y, + box.x2 - box.x1, + box.y2 - box.y1, + FALSE); + } + if (prgn && !REGION_NIL(prgn)) + (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, prgn, PW_BACKGROUND); + if (clientInterested && exposures && !REGION_NIL(exposures)) + miSendExposures(pWin, exposures, + pWin->drawable.x, pWin->drawable.y); + if (exposures == &expRec) + { + REGION_UNINIT( pWin->drawable.pScreen, exposures); + } + else if (exposures && exposures != prgn && exposures != other_exposed) + REGION_DESTROY( pWin->drawable.pScreen, exposures); + if (prgn) + REGION_EMPTY( pWin->drawable.pScreen, prgn); + } + else if (exposures && exposures != prgn) + REGION_DESTROY( pWin->drawable.pScreen, exposures); +} + + +/* + this code is highly unlikely. it is not haile selassie. + + there is some hair here. we can't just use the window's +clip region as it is, because if we are painting the border, +the border is not in the client area and so we will be excluded +when we validate the GC, and if we are painting a parent-relative +background, the area we want to paint is in some other window. +since we trust the code calling us to tell us to paint only areas +that are really ours, we will temporarily give the window a +clipList the size of the whole screen and an origin at (0,0). +this more or less assumes that ddX code will do translation +based on the window's absolute position, and that ValidateGC will +look at clipList, and that no other fields from the +window will be used. it's not possible to just draw +in the root because it may be a different depth. + +to get the tile to align correctly we set the GC's tile origin to +be the (x,y) of the window's upper left corner, after which we +get the right bits when drawing into the root. + +because the clip_mask is being set to None, we may call DoChangeGC with +fPointer set true, thus we no longer need to install the background or +border tile in the resource table. +*/ + +static RESTYPE ResType = 0; +static int numGCs = 0; +static GCPtr screenContext[MAXSCREENS]; + +/*ARGSUSED*/ +static int +tossGC ( + pointer value, + XID id) +{ + GCPtr pGC = (GCPtr)value; + screenContext[pGC->pScreen->myNum] = (GCPtr)NULL; + FreeGC (pGC, id); + numGCs--; + if (!numGCs) + ResType = 0; + + return 0; +} + + +_X_EXPORT void +miPaintWindow(pWin, prgn, what) +register WindowPtr pWin; +RegionPtr prgn; +int what; +{ + int status; + + Bool usingScratchGC = FALSE; + WindowPtr pRoot; + +#define FUNCTION 0 +#define FOREGROUND 1 +#define TILE 2 +#define FILLSTYLE 3 +#define ABSX 4 +#define ABSY 5 +#define CLIPMASK 6 +#define SUBWINDOW 7 +#define COUNT_BITS 8 + + ChangeGCVal gcval[7]; + ChangeGCVal newValues [COUNT_BITS]; + + BITS32 gcmask, index, mask; + RegionRec prgnWin; + DDXPointRec oldCorner; + BoxRec box; + WindowPtr pBgWin; + GCPtr pGC; + register int i; + register BoxPtr pbox; + register ScreenPtr pScreen = pWin->drawable.pScreen; + register xRectangle *prect; + int numRects; + + gcmask = 0; + + if (what == PW_BACKGROUND) + { + switch (pWin->backgroundState) { + case None: + return; + case ParentRelative: + (*pWin->parent->drawable.pScreen->PaintWindowBackground)(pWin->parent, prgn, what); + return; + case BackgroundPixel: + newValues[FOREGROUND].val = pWin->background.pixel; + newValues[FILLSTYLE].val = FillSolid; + gcmask |= GCForeground | GCFillStyle; + break; + case BackgroundPixmap: + newValues[TILE].ptr = (pointer)pWin->background.pixmap; + newValues[FILLSTYLE].val = FillTiled; + gcmask |= GCTile | GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin; + break; + } + } + else + { + if (pWin->borderIsPixel) + { + newValues[FOREGROUND].val = pWin->border.pixel; + newValues[FILLSTYLE].val = FillSolid; + gcmask |= GCForeground | GCFillStyle; + } + else + { + newValues[TILE].ptr = (pointer)pWin->border.pixmap; + newValues[FILLSTYLE].val = FillTiled; + gcmask |= GCTile | GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin; + } + } + + prect = (xRectangle *)ALLOCATE_LOCAL(REGION_NUM_RECTS(prgn) * + sizeof(xRectangle)); + if (!prect) + return; + + newValues[FUNCTION].val = GXcopy; + gcmask |= GCFunction | GCClipMask; + + i = pScreen->myNum; + pRoot = WindowTable[i]; + + pBgWin = pWin; + if (what == PW_BORDER) + { + while (pBgWin->backgroundState == ParentRelative) + pBgWin = pBgWin->parent; + } + + if ((pWin->drawable.depth != pRoot->drawable.depth) || + (pWin->drawable.bitsPerPixel != pRoot->drawable.bitsPerPixel)) + { + usingScratchGC = TRUE; + pGC = GetScratchGC(pWin->drawable.depth, pWin->drawable.pScreen); + if (!pGC) + { + DEALLOCATE_LOCAL(prect); + return; + } + /* + * mash the clip list so we can paint the border by + * mangling the window in place, pretending it + * spans the entire screen + */ + if (what == PW_BORDER) + { + prgnWin = pWin->clipList; + oldCorner.x = pWin->drawable.x; + oldCorner.y = pWin->drawable.y; + pWin->drawable.x = pWin->drawable.y = 0; + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + REGION_INIT(pScreen, &pWin->clipList, &box, 1); + pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; + newValues[ABSX].val = pBgWin->drawable.x; + newValues[ABSY].val = pBgWin->drawable.y; + } + else + { + newValues[ABSX].val = 0; + newValues[ABSY].val = 0; + } + } else { + /* + * draw the background to the root window + */ + if (screenContext[i] == (GCPtr)NULL) + { + if (!ResType && !(ResType = CreateNewResourceType(tossGC))) + return; + screenContext[i] = CreateGC((DrawablePtr)pWin, (BITS32) 0, + (XID *)NULL, &status); + if (!screenContext[i]) + return; + numGCs++; + if (!AddResource(FakeClientID(0), ResType, + (pointer)screenContext[i])) + return; + } + pGC = screenContext[i]; + newValues[SUBWINDOW].val = IncludeInferiors; + newValues[ABSX].val = pBgWin->drawable.x; + newValues[ABSY].val = pBgWin->drawable.y; + gcmask |= GCSubwindowMode; + pWin = pRoot; + } + + if (pWin->backStorage) + (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeVisBack); + + mask = gcmask; + gcmask = 0; + i = 0; + while (mask) { + index = lowbit (mask); + mask &= ~index; + switch (index) { + case GCFunction: + if (pGC->alu != newValues[FUNCTION].val) { + gcmask |= index; + gcval[i++].val = newValues[FUNCTION].val; + } + break; + case GCTileStipXOrigin: + if ( pGC->patOrg.x != newValues[ABSX].val) { + gcmask |= index; + gcval[i++].val = newValues[ABSX].val; + } + break; + case GCTileStipYOrigin: + if ( pGC->patOrg.y != newValues[ABSY].val) { + gcmask |= index; + gcval[i++].val = newValues[ABSY].val; + } + break; + case GCClipMask: + if ( pGC->clientClipType != CT_NONE) { + gcmask |= index; + gcval[i++].val = CT_NONE; + } + break; + case GCSubwindowMode: + if ( pGC->subWindowMode != newValues[SUBWINDOW].val) { + gcmask |= index; + gcval[i++].val = newValues[SUBWINDOW].val; + } + break; + case GCTile: + if (pGC->tileIsPixel || pGC->tile.pixmap != newValues[TILE].ptr) + { + gcmask |= index; + gcval[i++].ptr = newValues[TILE].ptr; + } + break; + case GCFillStyle: + if ( pGC->fillStyle != newValues[FILLSTYLE].val) { + gcmask |= index; + gcval[i++].val = newValues[FILLSTYLE].val; + } + break; + case GCForeground: + if ( pGC->fgPixel != newValues[FOREGROUND].val) { + gcmask |= index; + gcval[i++].val = newValues[FOREGROUND].val; + } + break; + } + } + + if (gcmask) + dixChangeGC(NullClient, pGC, gcmask, NULL, gcval); + + if (pWin->drawable.serialNumber != pGC->serialNumber) + ValidateGC((DrawablePtr)pWin, pGC); + + numRects = REGION_NUM_RECTS(prgn); + pbox = REGION_RECTS(prgn); + for (i= numRects; --i >= 0; pbox++, prect++) + { + prect->x = pbox->x1 - pWin->drawable.x; + prect->y = pbox->y1 - pWin->drawable.y; + prect->width = pbox->x2 - pbox->x1; + prect->height = pbox->y2 - pbox->y1; + } + prect -= numRects; + (*pGC->ops->PolyFillRect)((DrawablePtr)pWin, pGC, numRects, prect); + DEALLOCATE_LOCAL(prect); + + if (pWin->backStorage) + (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeNothing); + + if (usingScratchGC) + { + if (what == PW_BORDER) + { + REGION_UNINIT(pScreen, &pWin->clipList); + pWin->clipList = prgnWin; + pWin->drawable.x = oldCorner.x; + pWin->drawable.y = oldCorner.y; + pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; + } + FreeScratchGC(pGC); + } +} + + +/* MICLEARDRAWABLE -- sets the entire drawable to the background color of + * the GC. Useful when we have a scratch drawable and need to initialize + * it. */ +_X_EXPORT void +miClearDrawable(pDraw, pGC) + DrawablePtr pDraw; + GCPtr pGC; +{ + XID fg = pGC->fgPixel; + XID bg = pGC->bgPixel; + xRectangle rect; + + rect.x = 0; + rect.y = 0; + rect.width = pDraw->width; + rect.height = pDraw->height; + DoChangeGC(pGC, GCForeground, &bg, 0); + ValidateGC(pDraw, pGC); + (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect); + DoChangeGC(pGC, GCForeground, &fg, 0); + ValidateGC(pDraw, pGC); +} diff --git a/xserver/mi/mifillarc.c b/xserver/mi/mifillarc.c new file mode 100644 index 000000000..66063166a --- /dev/null +++ b/xserver/mi/mifillarc.c @@ -0,0 +1,815 @@ +/************************************************************ + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Author: Bob Scheifler, MIT X Consortium + +********************************************************/ + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <math.h> +#include <X11/X.h> +#include <X11/Xprotostr.h> +#include "regionstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "mifpoly.h" +#include "mi.h" +#include "mifillarc.h" + +#define QUADRANT (90 * 64) +#define HALFCIRCLE (180 * 64) +#define QUADRANT3 (270 * 64) + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#define Dsin(d) sin((double)d*(M_PI/11520.0)) +#define Dcos(d) cos((double)d*(M_PI/11520.0)) + +_X_EXPORT void +miFillArcSetup(arc, info) + register xArc *arc; + register miFillArcRec *info; +{ + info->y = arc->height >> 1; + info->dy = arc->height & 1; + info->yorg = arc->y + info->y; + info->dx = arc->width & 1; + info->xorg = arc->x + (arc->width >> 1) + info->dx; + info->dx = 1 - info->dx; + if (arc->width == arc->height) + { + /* (2x - 2xorg)^2 = d^2 - (2y - 2yorg)^2 */ + /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */ + info->ym = 8; + info->xm = 8; + info->yk = info->y << 3; + if (!info->dx) + { + info->xk = 0; + info->e = -1; + } + else + { + info->y++; + info->yk += 4; + info->xk = -4; + info->e = - (info->y << 3); + } + } + else + { + /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */ + /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */ + info->ym = (arc->width * arc->width) << 3; + info->xm = (arc->height * arc->height) << 3; + info->yk = info->y * info->ym; + if (!info->dy) + info->yk -= info->ym >> 1; + if (!info->dx) + { + info->xk = 0; + info->e = - (info->xm >> 3); + } + else + { + info->y++; + info->yk += info->ym; + info->xk = -(info->xm >> 1); + info->e = info->xk - info->yk; + } + } +} + +void +miFillArcDSetup(arc, info) + register xArc *arc; + register miFillArcDRec *info; +{ + /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */ + /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */ + info->y = arc->height >> 1; + info->dy = arc->height & 1; + info->yorg = arc->y + info->y; + info->dx = arc->width & 1; + info->xorg = arc->x + (arc->width >> 1) + info->dx; + info->dx = 1 - info->dx; + info->ym = ((double)arc->width) * (arc->width * 8); + info->xm = ((double)arc->height) * (arc->height * 8); + info->yk = info->y * info->ym; + if (!info->dy) + info->yk -= info->ym / 2.0; + if (!info->dx) + { + info->xk = 0; + info->e = - (info->xm / 8.0); + } + else + { + info->y++; + info->yk += info->ym; + info->xk = -info->xm / 2.0; + info->e = info->xk - info->yk; + } +} + +static void +miGetArcEdge( + register xArc *arc, + register miSliceEdgePtr edge, + int k, + Bool top, + Bool left ) +{ + register int xady, y; + + y = arc->height >> 1; + if (!(arc->width & 1)) + y++; + if (!top) + { + y = -y; + if (arc->height & 1) + y--; + } + xady = k + y * edge->dx; + if (xady <= 0) + edge->x = - ((-xady) / edge->dy + 1); + else + edge->x = (xady - 1) / edge->dy; + edge->e = xady - edge->x * edge->dy; + if ((top && (edge->dx < 0)) || (!top && (edge->dx > 0))) + edge->e = edge->dy - edge->e + 1; + if (left) + edge->x++; + edge->x += arc->x + (arc->width >> 1); + if (edge->dx > 0) + { + edge->deltax = 1; + edge->stepx = edge->dx / edge->dy; + edge->dx = edge->dx % edge->dy; + } + else + { + edge->deltax = -1; + edge->stepx = - ((-edge->dx) / edge->dy); + edge->dx = (-edge->dx) % edge->dy; + } + if (!top) + { + edge->deltax = -edge->deltax; + edge->stepx = -edge->stepx; + } +} + +void +miEllipseAngleToSlope (angle, width, height, dxp, dyp, d_dxp, d_dyp) + int angle; + int width; + int height; + int *dxp; + int *dyp; + double *d_dxp; + double *d_dyp; +{ + int dx, dy; + double d_dx, d_dy, scale; + Bool negative_dx, negative_dy; + + switch (angle) { + case 0: + *dxp = -1; + *dyp = 0; + if (d_dxp) { + *d_dxp = width / 2.0; + *d_dyp = 0; + } + break; + case QUADRANT: + *dxp = 0; + *dyp = 1; + if (d_dxp) { + *d_dxp = 0; + *d_dyp = - height / 2.0; + } + break; + case HALFCIRCLE: + *dxp = 1; + *dyp = 0; + if (d_dxp) { + *d_dxp = - width / 2.0; + *d_dyp = 0; + } + break; + case QUADRANT3: + *dxp = 0; + *dyp = -1; + if (d_dxp) { + *d_dxp = 0; + *d_dyp = height / 2.0; + } + break; + default: + d_dx = Dcos(angle) * width; + d_dy = Dsin(angle) * height; + if (d_dxp) { + *d_dxp = d_dx / 2.0; + *d_dyp = - d_dy / 2.0; + } + negative_dx = FALSE; + if (d_dx < 0.0) + { + d_dx = -d_dx; + negative_dx = TRUE; + } + negative_dy = FALSE; + if (d_dy < 0.0) + { + d_dy = -d_dy; + negative_dy = TRUE; + } + scale = d_dx; + if (d_dy > d_dx) + scale = d_dy; + dx = floor ((d_dx * 32768) / scale + 0.5); + if (negative_dx) + dx = -dx; + *dxp = dx; + dy = floor ((d_dy * 32768) / scale + 0.5); + if (negative_dy) + dy = -dy; + *dyp = dy; + break; + } +} + +static void +miGetPieEdge( + register xArc *arc, + register int angle, + register miSliceEdgePtr edge, + Bool top, + Bool left ) +{ + register int k; + int dx, dy; + + miEllipseAngleToSlope (angle, arc->width, arc->height, &dx, &dy, 0, 0); + + if (dy == 0) + { + edge->x = left ? -65536 : 65536; + edge->stepx = 0; + edge->e = 0; + edge->dx = -1; + return; + } + if (dx == 0) + { + edge->x = arc->x + (arc->width >> 1); + if (left && (arc->width & 1)) + edge->x++; + else if (!left && !(arc->width & 1)) + edge->x--; + edge->stepx = 0; + edge->e = 0; + edge->dx = -1; + return; + } + if (dy < 0) { + dx = -dx; + dy = -dy; + } + k = (arc->height & 1) ? dx : 0; + if (arc->width & 1) + k += dy; + edge->dx = dx << 1; + edge->dy = dy << 1; + miGetArcEdge(arc, edge, k, top, left); +} + +_X_EXPORT void +miFillArcSliceSetup(arc, slice, pGC) + register xArc *arc; + register miArcSliceRec *slice; + GCPtr pGC; +{ + register int angle1, angle2; + + angle1 = arc->angle1; + if (arc->angle2 < 0) + { + angle2 = angle1; + angle1 += arc->angle2; + } + else + angle2 = angle1 + arc->angle2; + while (angle1 < 0) + angle1 += FULLCIRCLE; + while (angle1 >= FULLCIRCLE) + angle1 -= FULLCIRCLE; + while (angle2 < 0) + angle2 += FULLCIRCLE; + while (angle2 >= FULLCIRCLE) + angle2 -= FULLCIRCLE; + slice->min_top_y = 0; + slice->max_top_y = arc->height >> 1; + slice->min_bot_y = 1 - (arc->height & 1); + slice->max_bot_y = slice->max_top_y - 1; + slice->flip_top = FALSE; + slice->flip_bot = FALSE; + if (pGC->arcMode == ArcPieSlice) + { + slice->edge1_top = (angle1 < HALFCIRCLE); + slice->edge2_top = (angle2 <= HALFCIRCLE); + if ((angle2 == 0) || (angle1 == HALFCIRCLE)) + { + if (angle2 ? slice->edge2_top : slice->edge1_top) + slice->min_top_y = slice->min_bot_y; + else + slice->min_top_y = arc->height; + slice->min_bot_y = 0; + } + else if ((angle1 == 0) || (angle2 == HALFCIRCLE)) + { + slice->min_top_y = slice->min_bot_y; + if (angle1 ? slice->edge1_top : slice->edge2_top) + slice->min_bot_y = arc->height; + else + slice->min_bot_y = 0; + } + else if (slice->edge1_top == slice->edge2_top) + { + if (angle2 < angle1) + { + slice->flip_top = slice->edge1_top; + slice->flip_bot = !slice->edge1_top; + } + else if (slice->edge1_top) + { + slice->min_top_y = 1; + slice->min_bot_y = arc->height; + } + else + { + slice->min_bot_y = 0; + slice->min_top_y = arc->height; + } + } + miGetPieEdge(arc, angle1, &slice->edge1, + slice->edge1_top, !slice->edge1_top); + miGetPieEdge(arc, angle2, &slice->edge2, + slice->edge2_top, slice->edge2_top); + } + else + { + double w2, h2, x1, y1, x2, y2, dx, dy, scale; + int signdx, signdy, y, k; + Bool isInt1 = TRUE, isInt2 = TRUE; + + w2 = (double)arc->width / 2.0; + h2 = (double)arc->height / 2.0; + if ((angle1 == 0) || (angle1 == HALFCIRCLE)) + { + x1 = angle1 ? -w2 : w2; + y1 = 0.0; + } + else if ((angle1 == QUADRANT) || (angle1 == QUADRANT3)) + { + x1 = 0.0; + y1 = (angle1 == QUADRANT) ? h2 : -h2; + } + else + { + isInt1 = FALSE; + x1 = Dcos(angle1) * w2; + y1 = Dsin(angle1) * h2; + } + if ((angle2 == 0) || (angle2 == HALFCIRCLE)) + { + x2 = angle2 ? -w2 : w2; + y2 = 0.0; + } + else if ((angle2 == QUADRANT) || (angle2 == QUADRANT3)) + { + x2 = 0.0; + y2 = (angle2 == QUADRANT) ? h2 : -h2; + } + else + { + isInt2 = FALSE; + x2 = Dcos(angle2) * w2; + y2 = Dsin(angle2) * h2; + } + dx = x2 - x1; + dy = y2 - y1; + if (arc->height & 1) + { + y1 -= 0.5; + y2 -= 0.5; + } + if (arc->width & 1) + { + x1 += 0.5; + x2 += 0.5; + } + if (dy < 0.0) + { + dy = -dy; + signdy = -1; + } + else + signdy = 1; + if (dx < 0.0) + { + dx = -dx; + signdx = -1; + } + else + signdx = 1; + if (isInt1 && isInt2) + { + slice->edge1.dx = dx * 2; + slice->edge1.dy = dy * 2; + } + else + { + scale = (dx > dy) ? dx : dy; + slice->edge1.dx = floor((dx * 32768) / scale + .5); + slice->edge1.dy = floor((dy * 32768) / scale + .5); + } + if (!slice->edge1.dy) + { + if (signdx < 0) + { + y = floor(y1 + 1.0); + if (y >= 0) + { + slice->min_top_y = y; + slice->min_bot_y = arc->height; + } + else + { + slice->max_bot_y = -y - (arc->height & 1); + } + } + else + { + y = floor(y1); + if (y >= 0) + slice->max_top_y = y; + else + { + slice->min_top_y = arc->height; + slice->min_bot_y = -y - (arc->height & 1); + } + } + slice->edge1_top = TRUE; + slice->edge1.x = 65536; + slice->edge1.stepx = 0; + slice->edge1.e = 0; + slice->edge1.dx = -1; + slice->edge2 = slice->edge1; + slice->edge2_top = FALSE; + } + else if (!slice->edge1.dx) + { + if (signdy < 0) + x1 -= 1.0; + slice->edge1.x = ceil(x1); + slice->edge1_top = signdy < 0; + slice->edge1.x += arc->x + (arc->width >> 1); + slice->edge1.stepx = 0; + slice->edge1.e = 0; + slice->edge1.dx = -1; + slice->edge2_top = !slice->edge1_top; + slice->edge2 = slice->edge1; + } + else + { + if (signdx < 0) + slice->edge1.dx = -slice->edge1.dx; + if (signdy < 0) + slice->edge1.dx = -slice->edge1.dx; + k = ceil(((x1 + x2) * slice->edge1.dy - (y1 + y2) * slice->edge1.dx) / 2.0); + slice->edge2.dx = slice->edge1.dx; + slice->edge2.dy = slice->edge1.dy; + slice->edge1_top = signdy < 0; + slice->edge2_top = !slice->edge1_top; + miGetArcEdge(arc, &slice->edge1, k, + slice->edge1_top, !slice->edge1_top); + miGetArcEdge(arc, &slice->edge2, k, + slice->edge2_top, slice->edge2_top); + } + } +} + +#define ADDSPANS() \ + pts->x = xorg - x; \ + pts->y = yorg - y; \ + *wids = slw; \ + pts++; \ + wids++; \ + if (miFillArcLower(slw)) \ + { \ + pts->x = xorg - x; \ + pts->y = yorg + y + dy; \ + pts++; \ + *wids++ = slw; \ + } + +static void +miFillEllipseI( + DrawablePtr pDraw, + GCPtr pGC, + xArc *arc ) +{ + register int x, y, e; + int yk, xk, ym, xm, dx, dy, xorg, yorg; + int slw; + miFillArcRec info; + DDXPointPtr points; + register DDXPointPtr pts; + int *widths; + register int *wids; + + points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * arc->height); + if (!points) + return; + widths = (int *)ALLOCATE_LOCAL(sizeof(int) * arc->height); + if (!widths) + { + DEALLOCATE_LOCAL(points); + return; + } + miFillArcSetup(arc, &info); + MIFILLARCSETUP(); + if (pGC->miTranslate) + { + xorg += pDraw->x; + yorg += pDraw->y; + } + pts = points; + wids = widths; + while (y > 0) + { + MIFILLARCSTEP(slw); + ADDSPANS(); + } + (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); + DEALLOCATE_LOCAL(widths); + DEALLOCATE_LOCAL(points); +} + +static void +miFillEllipseD( + DrawablePtr pDraw, + GCPtr pGC, + xArc *arc ) +{ + register int x, y; + int xorg, yorg, dx, dy, slw; + double e, yk, xk, ym, xm; + miFillArcDRec info; + DDXPointPtr points; + register DDXPointPtr pts; + int *widths; + register int *wids; + + points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * arc->height); + if (!points) + return; + widths = (int *)ALLOCATE_LOCAL(sizeof(int) * arc->height); + if (!widths) + { + DEALLOCATE_LOCAL(points); + return; + } + miFillArcDSetup(arc, &info); + MIFILLARCSETUP(); + if (pGC->miTranslate) + { + xorg += pDraw->x; + yorg += pDraw->y; + } + pts = points; + wids = widths; + while (y > 0) + { + MIFILLARCSTEP(slw); + ADDSPANS(); + } + (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); + DEALLOCATE_LOCAL(widths); + DEALLOCATE_LOCAL(points); +} + +#define ADDSPAN(l,r) \ + if (r >= l) \ + { \ + pts->x = l; \ + pts->y = ya; \ + pts++; \ + *wids++ = r - l + 1; \ + } + +#define ADDSLICESPANS(flip) \ + if (!flip) \ + { \ + ADDSPAN(xl, xr); \ + } \ + else \ + { \ + xc = xorg - x; \ + ADDSPAN(xc, xr); \ + xc += slw - 1; \ + ADDSPAN(xl, xc); \ + } + +static void +miFillArcSliceI( + DrawablePtr pDraw, + GCPtr pGC, + xArc *arc ) +{ + int yk, xk, ym, xm, dx, dy, xorg, yorg, slw; + register int x, y, e; + miFillArcRec info; + miArcSliceRec slice; + int ya, xl, xr, xc; + DDXPointPtr points; + register DDXPointPtr pts; + int *widths; + register int *wids; + + miFillArcSetup(arc, &info); + miFillArcSliceSetup(arc, &slice, pGC); + MIFILLARCSETUP(); + slw = arc->height; + if (slice.flip_top || slice.flip_bot) + slw += (arc->height >> 1) + 1; + points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * slw); + if (!points) + return; + widths = (int *)ALLOCATE_LOCAL(sizeof(int) * slw); + if (!widths) + { + DEALLOCATE_LOCAL(points); + return; + } + if (pGC->miTranslate) + { + xorg += pDraw->x; + yorg += pDraw->y; + slice.edge1.x += pDraw->x; + slice.edge2.x += pDraw->x; + } + pts = points; + wids = widths; + while (y > 0) + { + MIFILLARCSTEP(slw); + MIARCSLICESTEP(slice.edge1); + MIARCSLICESTEP(slice.edge2); + if (miFillSliceUpper(slice)) + { + ya = yorg - y; + MIARCSLICEUPPER(xl, xr, slice, slw); + ADDSLICESPANS(slice.flip_top); + } + if (miFillSliceLower(slice)) + { + ya = yorg + y + dy; + MIARCSLICELOWER(xl, xr, slice, slw); + ADDSLICESPANS(slice.flip_bot); + } + } + (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); + DEALLOCATE_LOCAL(widths); + DEALLOCATE_LOCAL(points); +} + +static void +miFillArcSliceD( + DrawablePtr pDraw, + GCPtr pGC, + xArc *arc ) +{ + register int x, y; + int dx, dy, xorg, yorg, slw; + double e, yk, xk, ym, xm; + miFillArcDRec info; + miArcSliceRec slice; + int ya, xl, xr, xc; + DDXPointPtr points; + register DDXPointPtr pts; + int *widths; + register int *wids; + + miFillArcDSetup(arc, &info); + miFillArcSliceSetup(arc, &slice, pGC); + MIFILLARCSETUP(); + slw = arc->height; + if (slice.flip_top || slice.flip_bot) + slw += (arc->height >> 1) + 1; + points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * slw); + if (!points) + return; + widths = (int *)ALLOCATE_LOCAL(sizeof(int) * slw); + if (!widths) + { + DEALLOCATE_LOCAL(points); + return; + } + if (pGC->miTranslate) + { + xorg += pDraw->x; + yorg += pDraw->y; + slice.edge1.x += pDraw->x; + slice.edge2.x += pDraw->x; + } + pts = points; + wids = widths; + while (y > 0) + { + MIFILLARCSTEP(slw); + MIARCSLICESTEP(slice.edge1); + MIARCSLICESTEP(slice.edge2); + if (miFillSliceUpper(slice)) + { + ya = yorg - y; + MIARCSLICEUPPER(xl, xr, slice, slw); + ADDSLICESPANS(slice.flip_top); + } + if (miFillSliceLower(slice)) + { + ya = yorg + y + dy; + MIARCSLICELOWER(xl, xr, slice, slw); + ADDSLICESPANS(slice.flip_bot); + } + } + (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); + DEALLOCATE_LOCAL(widths); + DEALLOCATE_LOCAL(points); +} + +/* MIPOLYFILLARC -- The public entry for the PolyFillArc request. + * Since we don't have to worry about overlapping segments, we can just + * fill each arc as it comes. + */ +_X_EXPORT void +miPolyFillArc(pDraw, pGC, narcs, parcs) + DrawablePtr pDraw; + GCPtr pGC; + int narcs; + xArc *parcs; +{ + register int i; + register xArc *arc; + + for(i = narcs, arc = parcs; --i >= 0; arc++) + { + if (miFillArcEmpty(arc)) + continue;; + if ((arc->angle2 >= FULLCIRCLE) || (arc->angle2 <= -FULLCIRCLE)) + { + if (miCanFillArc(arc)) + miFillEllipseI(pDraw, pGC, arc); + else + miFillEllipseD(pDraw, pGC, arc); + } + else + { + if (miCanFillArc(arc)) + miFillArcSliceI(pDraw, pGC, arc); + else + miFillArcSliceD(pDraw, pGC, arc); + } + } +} diff --git a/xserver/mi/mifillarc.h b/xserver/mi/mifillarc.h new file mode 100644 index 000000000..53f6f23ea --- /dev/null +++ b/xserver/mi/mifillarc.h @@ -0,0 +1,214 @@ +/************************************************************ + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +********************************************************/ + + +#ifndef __MIFILLARC_H__ +#define __MIFILLARC_H__ + +#define FULLCIRCLE (360 * 64) + +typedef struct _miFillArc { + int xorg, yorg; + int y; + int dx, dy; + int e; + int ym, yk, xm, xk; +} miFillArcRec; + +/* could use 64-bit integers */ +typedef struct _miFillArcD { + int xorg, yorg; + int y; + int dx, dy; + double e; + double ym, yk, xm, xk; +} miFillArcDRec; + +#define miFillArcEmpty(arc) (!(arc)->angle2 || \ + !(arc)->width || !(arc)->height || \ + (((arc)->width == 1) && ((arc)->height & 1))) + +#define miCanFillArc(arc) (((arc)->width == (arc)->height) || \ + (((arc)->width <= 800) && ((arc)->height <= 800))) + +#define MIFILLARCSETUP() \ + x = 0; \ + y = info.y; \ + e = info.e; \ + xk = info.xk; \ + xm = info.xm; \ + yk = info.yk; \ + ym = info.ym; \ + dx = info.dx; \ + dy = info.dy; \ + xorg = info.xorg; \ + yorg = info.yorg + +#define MIFILLARCSTEP(slw) \ + e += yk; \ + while (e >= 0) \ + { \ + x++; \ + xk -= xm; \ + e += xk; \ + } \ + y--; \ + yk -= ym; \ + slw = (x << 1) + dx; \ + if ((e == xk) && (slw > 1)) \ + slw-- + +#define MIFILLCIRCSTEP(slw) MIFILLARCSTEP(slw) +#define MIFILLELLSTEP(slw) MIFILLARCSTEP(slw) + +#define miFillArcLower(slw) (((y + dy) != 0) && ((slw > 1) || (e != xk))) + +typedef struct _miSliceEdge { + int x; + int stepx; + int deltax; + int e; + int dy; + int dx; +} miSliceEdgeRec, *miSliceEdgePtr; + +typedef struct _miArcSlice { + miSliceEdgeRec edge1, edge2; + int min_top_y, max_top_y; + int min_bot_y, max_bot_y; + Bool edge1_top, edge2_top; + Bool flip_top, flip_bot; +} miArcSliceRec; + +#define MIARCSLICESTEP(edge) \ + edge.x -= edge.stepx; \ + edge.e -= edge.dx; \ + if (edge.e <= 0) \ + { \ + edge.x -= edge.deltax; \ + edge.e += edge.dy; \ + } + +#define miFillSliceUpper(slice) \ + ((y >= slice.min_top_y) && (y <= slice.max_top_y)) + +#define miFillSliceLower(slice) \ + ((y >= slice.min_bot_y) && (y <= slice.max_bot_y)) + +#define MIARCSLICEUPPER(xl,xr,slice,slw) \ + xl = xorg - x; \ + xr = xl + slw - 1; \ + if (slice.edge1_top && (slice.edge1.x < xr)) \ + xr = slice.edge1.x; \ + if (slice.edge2_top && (slice.edge2.x > xl)) \ + xl = slice.edge2.x; + +#define MIARCSLICELOWER(xl,xr,slice,slw) \ + xl = xorg - x; \ + xr = xl + slw - 1; \ + if (!slice.edge1_top && (slice.edge1.x > xl)) \ + xl = slice.edge1.x; \ + if (!slice.edge2_top && (slice.edge2.x < xr)) \ + xr = slice.edge2.x; + +#define MIWIDEARCSETUP(x,y,dy,slw,e,xk,xm,yk,ym) \ + x = 0; \ + y = slw >> 1; \ + yk = y << 3; \ + xm = 8; \ + ym = 8; \ + if (dy) \ + { \ + xk = 0; \ + if (slw & 1) \ + e = -1; \ + else \ + e = -(y << 2) - 2; \ + } \ + else \ + { \ + y++; \ + yk += 4; \ + xk = -4; \ + if (slw & 1) \ + e = -(y << 2) - 3; \ + else \ + e = - (y << 3); \ + } + +#define MIFILLINARCSTEP(slw) \ + ine += inyk; \ + while (ine >= 0) \ + { \ + inx++; \ + inxk -= inxm; \ + ine += inxk; \ + } \ + iny--; \ + inyk -= inym; \ + slw = (inx << 1) + dx; \ + if ((ine == inxk) && (slw > 1)) \ + slw-- + +#define miFillInArcLower(slw) (((iny + dy) != 0) && \ + ((slw > 1) || (ine != inxk))) + +extern int miFreeArcCache( + pointer /*data*/, + XID /*id*/ +); + +extern struct finalSpan *realAllocSpan( + void +); + +extern void miFillArcSetup( + xArc * /*arc*/, + miFillArcRec * /*info*/ +); + +extern void miFillArcDSetup( + xArc * /*arc*/, + miFillArcDRec * /*info*/ +); + +extern void miEllipseAngleToSlope( + int /*angle*/, + int /*width*/, + int /*height*/, + int * /*dxp*/, + int * /*dyp*/, + double * /*d_dxp*/, + double * /*d_dyp*/ +); + +extern void miFillArcSliceSetup( + xArc * /*arc*/, + miArcSliceRec * /*slice*/, + GCPtr /*pGC*/ +); + +#endif /* __MIFILLARC_H__ */ diff --git a/xserver/mi/mifillrct.c b/xserver/mi/mifillrct.c new file mode 100644 index 000000000..78e89d69c --- /dev/null +++ b/xserver/mi/mifillrct.c @@ -0,0 +1,142 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xprotostr.h> +#include "gcstruct.h" +#include "windowstr.h" +#include "pixmap.h" +#include "mi.h" +#include "misc.h" + +/* mi rectangles + written by newman, with debts to all and sundry +*/ + +/* MIPOLYFILLRECT -- public entry for PolyFillRect request + * very straight forward: translate rectangles if necessary + * then call FillSpans to fill each rectangle. We let FillSpans worry about + * clipping to the destination + */ +_X_EXPORT void +miPolyFillRect(pDrawable, pGC, nrectFill, prectInit) + DrawablePtr pDrawable; + GCPtr pGC; + int nrectFill; /* number of rectangles to fill */ + xRectangle *prectInit; /* Pointer to first rectangle to fill */ +{ + int i; + register int height; + register int width; + register xRectangle *prect; + int xorg; + register int yorg; + int maxheight; + DDXPointPtr pptFirst; + register DDXPointPtr ppt; + int *pwFirst; + register int *pw; + + if (pGC->miTranslate) + { + xorg = pDrawable->x; + yorg = pDrawable->y; + prect = prectInit; + maxheight = 0; + for (i = 0; i<nrectFill; i++, prect++) + { + prect->x += xorg; + prect->y += yorg; + maxheight = max(maxheight, prect->height); + } + } + else + { + prect = prectInit; + maxheight = 0; + for (i = 0; i<nrectFill; i++, prect++) + maxheight = max(maxheight, prect->height); + } + + pptFirst = (DDXPointPtr) ALLOCATE_LOCAL(maxheight * sizeof(DDXPointRec)); + pwFirst = (int *) ALLOCATE_LOCAL(maxheight * sizeof(int)); + if(!pptFirst || !pwFirst) + { + if (pwFirst) DEALLOCATE_LOCAL(pwFirst); + if (pptFirst) DEALLOCATE_LOCAL(pptFirst); + return; + } + + prect = prectInit; + while(nrectFill--) + { + ppt = pptFirst; + pw = pwFirst; + height = prect->height; + width = prect->width; + xorg = prect->x; + yorg = prect->y; + while(height--) + { + *pw++ = width; + ppt->x = xorg; + ppt->y = yorg; + ppt++; + yorg++; + } + (* pGC->ops->FillSpans)(pDrawable, pGC, + prect->height, pptFirst, pwFirst, + 1); + prect++; + } + DEALLOCATE_LOCAL(pwFirst); + DEALLOCATE_LOCAL(pptFirst); +} diff --git a/xserver/mi/mifpoly.h b/xserver/mi/mifpoly.h new file mode 100644 index 000000000..8f0507601 --- /dev/null +++ b/xserver/mi/mifpoly.h @@ -0,0 +1,109 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#ifndef __MIFPOLY_H__ +#define __MIFPOLY_H__ + +#define EPSILON 0.000001 +#define ISEQUAL(a,b) (Fabs((a) - (b)) <= EPSILON) +#define UNEQUAL(a,b) (Fabs((a) - (b)) > EPSILON) +#define WITHINHALF(a, b) (((a) - (b) > 0.0) ? (a) - (b) < 0.5 : \ + (b) - (a) <= 0.5) +#define ROUNDTOINT(x) ((int) (((x) > 0.0) ? ((x) + 0.5) : ((x) - 0.5))) +#define ISZERO(x) (Fabs((x)) <= EPSILON) +#define PTISEQUAL(a,b) (ISEQUAL(a.x,b.x) && ISEQUAL(a.y,b.y)) +#define PTUNEQUAL(a,b) (UNEQUAL(a.x,b.x) || UNEQUAL(a.y,b.y)) +#define PtEqual(a, b) (((a).x == (b).x) && ((a).y == (b).y)) + +#define NotEnd 0 +#define FirstEnd 1 +#define SecondEnd 2 + +#define SQSECANT 108.856472512142 /* 1/sin^2(11/2) - for 11o miter cutoff */ +#define D2SECANT 5.21671526231167 /* 1/2*sin(11/2) - max extension per width */ + +#ifdef NOINLINEICEIL +#define ICEIL(x) ((int)ceil(x)) +#else +#ifdef __GNUC__ +static __inline int ICEIL(double x) +{ + int _cTmp = x; + return ((x == _cTmp) || (x < 0.0)) ? _cTmp : _cTmp+1; +} +#else +#define ICEIL(x) ((((x) == (_cTmp = (x))) || ((x) < 0.0)) ? _cTmp : _cTmp+1) +#define ICEILTEMPDECL static int _cTmp; +#endif +#endif + +/* Point with sub-pixel positioning. In this case we use doubles, but + * see mifpolycon.c for other suggestions + */ +typedef struct _SppPoint { + double x, y; +} SppPointRec, *SppPointPtr; + +typedef struct _SppArc { + double x, y, width, height; + double angle1, angle2; +} SppArcRec, *SppArcPtr; + +/* mifpolycon.c */ + +extern void miFillSppPoly( + DrawablePtr /*dst*/, + GCPtr /*pgc*/, + int /*count*/, + SppPointPtr /*ptsIn*/, + int /*xTrans*/, + int /*yTrans*/, + double /*xFtrans*/, + double /*yFtrans*/ +); + +#endif /* __MIFPOLY_H__ */ diff --git a/xserver/mi/mifpolycon.c b/xserver/mi/mifpolycon.c new file mode 100644 index 000000000..57229f639 --- /dev/null +++ b/xserver/mi/mifpolycon.c @@ -0,0 +1,282 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <math.h> +#include <X11/X.h> +#include "gcstruct.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "mifpoly.h" + +static int GetFPolyYBounds(register SppPointPtr pts, int n, double yFtrans, + int *by, int *ty); + +#ifdef ICEILTEMPDECL +ICEILTEMPDECL +#endif + +/* + * Written by Todd Newman; April. 1987. + * + * Fill a convex polygon. If the given polygon + * is not convex, then the result is undefined. + * The algorithm is to order the edges from smallest + * y to largest by partitioning the array into a left + * edge list and a right edge list. The algorithm used + * to traverse each edge is digital differencing analyzer + * line algorithm with y as the major axis. There's some funny linear + * interpolation involved because of the subpixel postioning. + */ +void +miFillSppPoly(dst, pgc, count, ptsIn, xTrans, yTrans, xFtrans, yFtrans) + DrawablePtr dst; + GCPtr pgc; + int count; /* number of points */ + SppPointPtr ptsIn; /* the points */ + int xTrans, yTrans; /* Translate each point by this */ + double xFtrans, yFtrans; /* translate before conversion + by this amount. This provides + a mechanism to match rounding + errors with any shape that must + meet the polygon exactly. + */ +{ + double xl = 0.0, xr = 0.0, /* x vals of left and right edges */ + ml = 0.0, /* left edge slope */ + mr = 0.0, /* right edge slope */ + dy, /* delta y */ + i; /* loop counter */ + int y, /* current scanline */ + j, + imin, /* index of vertex with smallest y */ + ymin, /* y-extents of polygon */ + ymax, + *width, + *FirstWidth, /* output buffer */ + *Marked; /* set if this vertex has been used */ + register int left, right, /* indices to first endpoints */ + nextleft, + nextright; /* indices to second endpoints */ + DDXPointPtr ptsOut, + FirstPoint; /* output buffer */ + + if (pgc->miTranslate) + { + xTrans += dst->x; + yTrans += dst->y; + } + + imin = GetFPolyYBounds(ptsIn, count, yFtrans, &ymin, &ymax); + + y = ymax - ymin + 1; + if ((count < 3) || (y <= 0)) + return; + ptsOut = FirstPoint = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * y); + width = FirstWidth = (int *) ALLOCATE_LOCAL(sizeof(int) * y); + Marked = (int *) ALLOCATE_LOCAL(sizeof(int) * count); + + if(!ptsOut || !width || !Marked) + { + if (Marked) DEALLOCATE_LOCAL(Marked); + if (width) DEALLOCATE_LOCAL(width); + if (ptsOut) DEALLOCATE_LOCAL(ptsOut); + return; + } + + for(j = 0; j < count; j++) + Marked[j] = 0; + nextleft = nextright = imin; + Marked[imin] = -1; + y = ICEIL(ptsIn[nextleft].y + yFtrans); + + /* + * loop through all edges of the polygon + */ + do + { + /* add a left edge if we need to */ + if ((y > (ptsIn[nextleft].y + yFtrans) || + ISEQUAL(y, ptsIn[nextleft].y + yFtrans)) && + Marked[nextleft] != 1) + { + Marked[nextleft]++; + left = nextleft++; + + /* find the next edge, considering the end conditions */ + if (nextleft >= count) + nextleft = 0; + + /* now compute the starting point and slope */ + dy = ptsIn[nextleft].y - ptsIn[left].y; + if (dy != 0.0) + { + ml = (ptsIn[nextleft].x - ptsIn[left].x) / dy; + dy = y - (ptsIn[left].y + yFtrans); + xl = (ptsIn[left].x + xFtrans) + ml * max(dy, 0); + } + } + + /* add a right edge if we need to */ + if ((y > ptsIn[nextright].y + yFtrans) || + (ISEQUAL(y, ptsIn[nextright].y + yFtrans) + && Marked[nextright] != 1)) + { + Marked[nextright]++; + right = nextright--; + + /* find the next edge, considering the end conditions */ + if (nextright < 0) + nextright = count - 1; + + /* now compute the starting point and slope */ + dy = ptsIn[nextright].y - ptsIn[right].y; + if (dy != 0.0) + { + mr = (ptsIn[nextright].x - ptsIn[right].x) / dy; + dy = y - (ptsIn[right].y + yFtrans); + xr = (ptsIn[right].x + xFtrans) + mr * max(dy, 0); + } + } + + + /* + * generate scans to fill while we still have + * a right edge as well as a left edge. + */ + i = (min(ptsIn[nextleft].y, ptsIn[nextright].y) + yFtrans) - y; + + if (i < EPSILON) + { + if(Marked[nextleft] && Marked[nextright]) + { + /* Arrgh, we're trapped! (no more points) + * Out, we've got to get out of here before this decadence saps + * our will completely! */ + break; + } + continue; + } + else + { + j = (int) i; + if(!j) + j++; + } + while (j > 0) + { + int cxl, cxr; + + ptsOut->y = (y) + yTrans; + + cxl = ICEIL(xl); + cxr = ICEIL(xr); + /* reverse the edges if necessary */ + if (xl < xr) + { + *(width++) = cxr - cxl; + (ptsOut++)->x = cxl + xTrans; + } + else + { + *(width++) = cxl - cxr; + (ptsOut++)->x = cxr + xTrans; + } + y++; + + /* increment down the edges */ + xl += ml; + xr += mr; + j--; + } + } while (y <= ymax); + + /* Finally, fill the spans we've collected */ + (*pgc->ops->FillSpans)(dst, pgc, + ptsOut-FirstPoint, FirstPoint, FirstWidth, 1); + DEALLOCATE_LOCAL(Marked); + DEALLOCATE_LOCAL(FirstWidth); + DEALLOCATE_LOCAL(FirstPoint); +} + + +/* Find the index of the point with the smallest y.also return the + * smallest and largest y */ +static +int +GetFPolyYBounds( + register SppPointPtr pts, + int n, + double yFtrans, + int *by, + int *ty) +{ + register SppPointPtr ptMin; + double ymin, ymax; + SppPointPtr ptsStart = pts; + + ptMin = pts; + ymin = ymax = (pts++)->y; + + while (--n > 0) { + if (pts->y < ymin) + { + ptMin = pts; + ymin = pts->y; + } + if(pts->y > ymax) + ymax = pts->y; + + pts++; + } + + *by = ICEIL(ymin + yFtrans); + *ty = ICEIL(ymax + yFtrans - 1); + return(ptMin-ptsStart); +} diff --git a/xserver/mi/migc.c b/xserver/mi/migc.c new file mode 100644 index 000000000..46643ab26 --- /dev/null +++ b/xserver/mi/migc.c @@ -0,0 +1,299 @@ +/* + +Copyright 1993, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "migc.h" + +/* ARGSUSED */ +_X_EXPORT void +miChangeGC(pGC, mask) + GCPtr pGC; + unsigned long mask; +{ + return; +} + +_X_EXPORT void +miDestroyGC(pGC) + GCPtr pGC; +{ + if (pGC->pRotatedPixmap) + (*pGC->pScreen->DestroyPixmap) (pGC->pRotatedPixmap); + if (pGC->freeCompClip) + REGION_DESTROY(pGC->pScreen, pGC->pCompositeClip); + miDestroyGCOps(pGC->ops); +} + +/* + * create a private op array for a gc + */ + +_X_EXPORT GCOpsPtr +miCreateGCOps(prototype) + GCOpsPtr prototype; +{ + GCOpsPtr ret; + + /* XXX */ Must_have_memory = TRUE; + ret = (GCOpsPtr) xalloc(sizeof(GCOps)); + /* XXX */ Must_have_memory = FALSE; + if (!ret) + return 0; + *ret = *prototype; + ret->devPrivate.val = 1; + return ret; +} + +_X_EXPORT void +miDestroyGCOps(ops) + GCOpsPtr ops; +{ + if (ops->devPrivate.val) + xfree(ops); +} + + +_X_EXPORT void +miDestroyClip(pGC) + GCPtr pGC; +{ + if (pGC->clientClipType == CT_NONE) + return; + else if (pGC->clientClipType == CT_PIXMAP) + { + (*pGC->pScreen->DestroyPixmap) ((PixmapPtr) (pGC->clientClip)); + } + else + { + /* + * we know we'll never have a list of rectangles, since ChangeClip + * immediately turns them into a region + */ + REGION_DESTROY(pGC->pScreen, pGC->clientClip); + } + pGC->clientClip = NULL; + pGC->clientClipType = CT_NONE; +} + +_X_EXPORT void +miChangeClip(pGC, type, pvalue, nrects) + GCPtr pGC; + int type; + pointer pvalue; + int nrects; +{ + (*pGC->funcs->DestroyClip) (pGC); + if (type == CT_PIXMAP) + { + /* convert the pixmap to a region */ + pGC->clientClip = (pointer) BITMAP_TO_REGION(pGC->pScreen, + (PixmapPtr) pvalue); + (*pGC->pScreen->DestroyPixmap) (pvalue); + } + else if (type == CT_REGION) + { + /* stuff the region in the GC */ + pGC->clientClip = pvalue; + } + else if (type != CT_NONE) + { + pGC->clientClip = (pointer) RECTS_TO_REGION(pGC->pScreen, nrects, + (xRectangle *) pvalue, + type); + xfree(pvalue); + } + pGC->clientClipType = (type != CT_NONE && pGC->clientClip) ? CT_REGION : CT_NONE; + pGC->stateChanges |= GCClipMask; +} + +_X_EXPORT void +miCopyClip(pgcDst, pgcSrc) + GCPtr pgcDst, pgcSrc; +{ + RegionPtr prgnNew; + + switch (pgcSrc->clientClipType) + { + case CT_PIXMAP: + ((PixmapPtr) pgcSrc->clientClip)->refcnt++; + /* Fall through !! */ + case CT_NONE: + (*pgcDst->funcs->ChangeClip) (pgcDst, (int) pgcSrc->clientClipType, + pgcSrc->clientClip, 0); + break; + case CT_REGION: + prgnNew = REGION_CREATE(pgcSrc->pScreen, NULL, 1); + REGION_COPY(pgcDst->pScreen, prgnNew, + (RegionPtr) (pgcSrc->clientClip)); + (*pgcDst->funcs->ChangeClip) (pgcDst, CT_REGION, (pointer) prgnNew, 0); + break; + } +} + +/* ARGSUSED */ +_X_EXPORT void +miCopyGC(pGCSrc, changes, pGCDst) + GCPtr pGCSrc; + unsigned long changes; + GCPtr pGCDst; +{ + return; +} + +_X_EXPORT void +miComputeCompositeClip(pGC, pDrawable) + GCPtr pGC; + DrawablePtr pDrawable; +{ + ScreenPtr pScreen; + + /* This prevents warnings about pScreen not being used. */ + pGC->pScreen = pScreen = pGC->pScreen; + + if (pDrawable->type == DRAWABLE_WINDOW) + { + WindowPtr pWin = (WindowPtr) pDrawable; + RegionPtr pregWin; + Bool freeTmpClip, freeCompClip; + + if (pGC->subWindowMode == IncludeInferiors) + { + pregWin = NotClippedByChildren(pWin); + freeTmpClip = TRUE; + } + else + { + pregWin = &pWin->clipList; + freeTmpClip = FALSE; + } + freeCompClip = pGC->freeCompClip; + + /* + * if there is no client clip, we can get by with just keeping the + * pointer we got, and remembering whether or not should destroy (or + * maybe re-use) it later. this way, we avoid unnecessary copying of + * regions. (this wins especially if many clients clip by children + * and have no client clip.) + */ + if (pGC->clientClipType == CT_NONE) + { + if (freeCompClip) + REGION_DESTROY(pScreen, pGC->pCompositeClip); + pGC->pCompositeClip = pregWin; + pGC->freeCompClip = freeTmpClip; + } + else + { + /* + * we need one 'real' region to put into the composite clip. if + * pregWin the current composite clip are real, we can get rid of + * one. if pregWin is real and the current composite clip isn't, + * use pregWin for the composite clip. if the current composite + * clip is real and pregWin isn't, use the current composite + * clip. if neither is real, create a new region. + */ + + REGION_TRANSLATE(pScreen, pGC->clientClip, + pDrawable->x + pGC->clipOrg.x, + pDrawable->y + pGC->clipOrg.y); + + if (freeCompClip) + { + REGION_INTERSECT(pGC->pScreen, pGC->pCompositeClip, + pregWin, pGC->clientClip); + if (freeTmpClip) + REGION_DESTROY(pScreen, pregWin); + } + else if (freeTmpClip) + { + REGION_INTERSECT(pScreen, pregWin, pregWin, pGC->clientClip); + pGC->pCompositeClip = pregWin; + } + else + { + pGC->pCompositeClip = REGION_CREATE(pScreen, NullBox, 0); + REGION_INTERSECT(pScreen, pGC->pCompositeClip, + pregWin, pGC->clientClip); + } + pGC->freeCompClip = TRUE; + REGION_TRANSLATE(pScreen, pGC->clientClip, + -(pDrawable->x + pGC->clipOrg.x), + -(pDrawable->y + pGC->clipOrg.y)); + } + } /* end of composite clip for a window */ + else + { + BoxRec pixbounds; + + /* XXX should we translate by drawable.x/y here ? */ + /* If you want pixmaps in offscreen memory, yes */ + pixbounds.x1 = pDrawable->x; + pixbounds.y1 = pDrawable->y; + pixbounds.x2 = pDrawable->x + pDrawable->width; + pixbounds.y2 = pDrawable->y + pDrawable->height; + + if (pGC->freeCompClip) + { + REGION_RESET(pScreen, pGC->pCompositeClip, &pixbounds); + } + else + { + pGC->freeCompClip = TRUE; + pGC->pCompositeClip = REGION_CREATE(pScreen, &pixbounds, 1); + } + + if (pGC->clientClipType == CT_REGION) + { + if(pDrawable->x || pDrawable->y) { + REGION_TRANSLATE(pScreen, pGC->clientClip, + pDrawable->x + pGC->clipOrg.x, + pDrawable->y + pGC->clipOrg.y); + REGION_INTERSECT(pScreen, pGC->pCompositeClip, + pGC->pCompositeClip, pGC->clientClip); + REGION_TRANSLATE(pScreen, pGC->clientClip, + -(pDrawable->x + pGC->clipOrg.x), + -(pDrawable->y + pGC->clipOrg.y)); + } else { + REGION_TRANSLATE(pScreen, pGC->pCompositeClip, + -pGC->clipOrg.x, -pGC->clipOrg.y); + REGION_INTERSECT(pScreen, pGC->pCompositeClip, + pGC->pCompositeClip, pGC->clientClip); + REGION_TRANSLATE(pScreen, pGC->pCompositeClip, + pGC->clipOrg.x, pGC->clipOrg.y); + } + } + } /* end of composite clip for pixmap */ +} /* end miComputeCompositeClip */ diff --git a/xserver/mi/migc.h b/xserver/mi/migc.h new file mode 100644 index 000000000..84dc75c6c --- /dev/null +++ b/xserver/mi/migc.h @@ -0,0 +1,72 @@ +/* + +Copyright 1993, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + + +extern void miChangeGC( + GCPtr /*pGC*/, + unsigned long /*mask*/ +); + +extern void miDestroyGC( + GCPtr /*pGC*/ +); + +extern GCOpsPtr miCreateGCOps( + GCOpsPtr /*prototype*/ +); + +extern void miDestroyGCOps( + GCOpsPtr /*ops*/ +); + +extern void miDestroyClip( + GCPtr /*pGC*/ +); + +extern void miChangeClip( + GCPtr /*pGC*/, + int /*type*/, + pointer /*pvalue*/, + int /*nrects*/ +); + +extern void miCopyClip( + GCPtr /*pgcDst*/, + GCPtr /*pgcSrc*/ +); + +extern void miCopyGC( + GCPtr /*pGCSrc*/, + unsigned long /*changes*/, + GCPtr /*pGCDst*/ +); + +extern void miComputeCompositeClip( + GCPtr /*pGC*/, + DrawablePtr /*pDrawable*/ +); diff --git a/xserver/mi/miglblt.c b/xserver/mi/miglblt.c new file mode 100644 index 000000000..db299a8ae --- /dev/null +++ b/xserver/mi/miglblt.c @@ -0,0 +1,253 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xmd.h> +#include <X11/Xproto.h> +#include "misc.h" +#include <X11/fonts/fontstruct.h> +#include "dixfontstr.h" +#include "gcstruct.h" +#include "windowstr.h" +#include "scrnintstr.h" +#include "pixmap.h" +#include "servermd.h" +#include "mi.h" + +/* + machine-independent glyph blt. + assumes that glyph bits in snf are written in bytes, +have same bit order as the server's bitmap format, +and are byte padded. this corresponds to the snf distributed +with the sample server. + + get a scratch GC. + in the scratch GC set alu = GXcopy, fg = 1, bg = 0 + allocate a bitmap big enough to hold the largest glyph in the font + validate the scratch gc with the bitmap + for each glyph + carefully put the bits of the glyph in a buffer, + padded to the server pixmap scanline padding rules + fake a call to PutImage from the buffer into the bitmap + use the bitmap in a call to PushPixels +*/ + +_X_EXPORT void +miPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) + DrawablePtr pDrawable; + GC *pGC; + int x, y; + unsigned int nglyph; + CharInfoPtr *ppci; /* array of character info */ + pointer pglyphBase; /* start of array of glyphs */ +{ + int width, height; + PixmapPtr pPixmap; + int nbyLine; /* bytes per line of padded pixmap */ + FontPtr pfont; + GCPtr pGCtmp; + register int i; + register int j; + unsigned char *pbits; /* buffer for PutImage */ + register unsigned char *pb; /* temp pointer into buffer */ + register CharInfoPtr pci; /* currect char info */ + register unsigned char *pglyph; /* pointer bits in glyph */ + int gWidth, gHeight; /* width and height of glyph */ + register int nbyGlyphWidth; /* bytes per scanline of glyph */ + int nbyPadGlyph; /* server padded line of glyph */ + + XID gcvals[3]; + + if (pGC->miTranslate) + { + x += pDrawable->x; + y += pDrawable->y; + } + + pfont = pGC->font; + width = FONTMAXBOUNDS(pfont,rightSideBearing) - + FONTMINBOUNDS(pfont,leftSideBearing); + height = FONTMAXBOUNDS(pfont,ascent) + + FONTMAXBOUNDS(pfont,descent); + + pPixmap = (*pDrawable->pScreen->CreatePixmap)(pDrawable->pScreen, + width, height, 1); + if (!pPixmap) + return; + + pGCtmp = GetScratchGC(1, pDrawable->pScreen); + if (!pGCtmp) + { + (*pDrawable->pScreen->DestroyPixmap)(pPixmap); + return; + } + + gcvals[0] = GXcopy; + gcvals[1] = 1; + gcvals[2] = 0; + + DoChangeGC(pGCtmp, GCFunction|GCForeground|GCBackground, gcvals, 0); + + nbyLine = BitmapBytePad(width); + pbits = (unsigned char *)ALLOCATE_LOCAL(height*nbyLine); + if (!pbits) + { + (*pDrawable->pScreen->DestroyPixmap)(pPixmap); + FreeScratchGC(pGCtmp); + return; + } + while(nglyph--) + { + pci = *ppci++; + pglyph = FONTGLYPHBITS(pglyphBase, pci); + gWidth = GLYPHWIDTHPIXELS(pci); + gHeight = GLYPHHEIGHTPIXELS(pci); + if (gWidth && gHeight) + { + nbyGlyphWidth = GLYPHWIDTHBYTESPADDED(pci); + nbyPadGlyph = BitmapBytePad(gWidth); + + if (nbyGlyphWidth == nbyPadGlyph +#if GLYPHPADBYTES != 4 + && (((int) pglyph) & 3) == 0 +#endif + ) + { + pb = pglyph; + } + else + { + for (i=0, pb = pbits; i<gHeight; i++, pb = pbits+(i*nbyPadGlyph)) + for (j = 0; j < nbyGlyphWidth; j++) + *pb++ = *pglyph++; + pb = pbits; + } + + if ((pGCtmp->serialNumber) != (pPixmap->drawable.serialNumber)) + ValidateGC((DrawablePtr)pPixmap, pGCtmp); + (*pGCtmp->ops->PutImage)((DrawablePtr)pPixmap, pGCtmp, + pPixmap->drawable.depth, + 0, 0, gWidth, gHeight, + 0, XYBitmap, (char *)pb); + + if ((pGC->serialNumber) != (pDrawable->serialNumber)) + ValidateGC(pDrawable, pGC); + (*pGC->ops->PushPixels)(pGC, pPixmap, pDrawable, + gWidth, gHeight, + x + pci->metrics.leftSideBearing, + y - pci->metrics.ascent); + } + x += pci->metrics.characterWidth; + } + (*pDrawable->pScreen->DestroyPixmap)(pPixmap); + DEALLOCATE_LOCAL(pbits); + FreeScratchGC(pGCtmp); +} + + +_X_EXPORT void +miImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) + DrawablePtr pDrawable; + GC *pGC; + int x, y; + unsigned int nglyph; + CharInfoPtr *ppci; /* array of character info */ + pointer pglyphBase; /* start of array of glyphs */ +{ + ExtentInfoRec info; /* used by QueryGlyphExtents() */ + XID gcvals[3]; + int oldAlu, oldFS; + unsigned long oldFG; + xRectangle backrect; + + QueryGlyphExtents(pGC->font, ppci, (unsigned long)nglyph, &info); + + if (info.overallWidth >= 0) + { + backrect.x = x; + backrect.width = info.overallWidth; + } + else + { + backrect.x = x + info.overallWidth; + backrect.width = -info.overallWidth; + } + backrect.y = y - FONTASCENT(pGC->font); + backrect.height = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font); + + oldAlu = pGC->alu; + oldFG = pGC->fgPixel; + oldFS = pGC->fillStyle; + + /* fill in the background */ + gcvals[0] = GXcopy; + gcvals[1] = pGC->bgPixel; + gcvals[2] = FillSolid; + DoChangeGC(pGC, GCFunction|GCForeground|GCFillStyle, gcvals, 0); + ValidateGC(pDrawable, pGC); + (*pGC->ops->PolyFillRect)(pDrawable, pGC, 1, &backrect); + + /* put down the glyphs */ + gcvals[0] = oldFG; + DoChangeGC(pGC, GCForeground, gcvals, 0); + ValidateGC(pDrawable, pGC); + (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, nglyph, ppci, + pglyphBase); + + /* put all the toys away when done playing */ + gcvals[0] = oldAlu; + gcvals[1] = oldFG; + gcvals[2] = oldFS; + DoChangeGC(pGC, GCFunction|GCForeground|GCFillStyle, gcvals, 0); + ValidateGC(pDrawable, pGC); + +} diff --git a/xserver/mi/miinitext.c b/xserver/mi/miinitext.c new file mode 100644 index 000000000..8fd8c9ce1 --- /dev/null +++ b/xserver/mi/miinitext.c @@ -0,0 +1,798 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#ifdef HAVE_XNEST_CONFIG_H +#include <xnest-config.h> +#undef DPMSExtension +#endif + +#ifdef HAVE_KDRIVE_CONFIG_H +#include <kdrive-config.h> +/* there must be a better way... */ +#undef XF86MISC +#undef XFreeXDGA +#undef XF86DRI +#undef XF86VIDMODE +#endif + +#ifdef HAVE_XGL_CONFIG_H +#include <xgl-config.h> +#undef XF86MISC +#undef XFreeXDGA +#undef XF86DRI +#undef XF86VIDMODE +#endif + +#include "misc.h" +#include "extension.h" +#include "micmap.h" +#include "globals.h" + +#if defined(QNX4) /* sleaze for Watcom on QNX4 ... */ +#undef GLXEXT +#endif + +/* Make sure Xprt only announces extensions it supports */ +#ifdef PRINT_ONLY_SERVER +#undef MITSHM /* this is incompatible to the vector-based Xprint DDX */ +#undef XKB +#undef PANORAMIX +#undef RES +#undef XINPUT +#undef XV +#undef SCREENSAVER +#undef XIDLE +#undef XRECORD +#undef XF86VIDMODE +#undef XF86MISC +#undef XFreeXDGA +#undef XF86DRI +#undef DPMSExtension +#undef FONTCACHE +#undef COMPOSITE +#undef DAMAGE +#undef XFIXES +#undef XEVIE +#else +#ifndef LOADABLEPRINTDDX +#undef XPRINT +#endif /* LOADABLEPRINTDDX */ +#endif /* PRINT_ONLY_SERVER */ + + +extern Bool noTestExtensions; + +#ifdef BIGREQS +extern Bool noBigReqExtension; +#endif +#ifdef COMPOSITE +extern Bool noCompositeExtension; +#endif +#ifdef DBE +extern Bool noDbeExtension; +#endif +#ifdef DPMSExtension +extern Bool noDPMSExtension; +#endif +#ifdef EVI +extern Bool noEVIExtension; +#endif +#ifdef FONTCACHE +extern Bool noFontCacheExtension; +#endif +#ifdef GLXEXT +extern Bool noGlxExtension; +#endif +#ifdef SCREENSAVER +extern Bool noScreenSaverExtension; +#endif +#ifdef MITSHM +extern Bool noMITShmExtension; +#endif +#ifdef MITMISC +extern Bool noMITMiscExtension; +#endif +#ifdef MULTIBUFFER +extern Bool noMultibufferExtension; +#endif +#ifdef RANDR +extern Bool noRRExtension; +#endif +#ifdef RENDER +extern Bool noRenderExtension; +#endif +#ifdef SHAPE +extern Bool noShapeExtension; +#endif +#ifdef XCSECURITY +extern Bool noSecurityExtension; +#endif +#ifdef XSYNC +extern Bool noSyncExtension; +#endif +#ifdef TOGCUP +extern Bool noXcupExtension; +#endif +#ifdef RES +extern Bool noResExtension; +#endif +#ifdef XAPPGROUP +extern Bool noXagExtension; +#endif +#ifdef XCMISC +extern Bool noXCMiscExtension; +#endif +#ifdef XEVIE +extern Bool noXevieExtension; +#endif +#ifdef XF86BIGFONT +extern Bool noXFree86BigfontExtension; +#endif +#ifdef XFreeXDGA +extern Bool noXFree86DGAExtension; +#endif +#ifdef XF86DRI +extern Bool noXFree86DRIExtension; +#endif +#ifdef XF86MISC +extern Bool noXFree86MiscExtension; +#endif +#ifdef XF86VIDMODE +extern Bool noXFree86VidModeExtension; +#endif +#ifdef XFIXES +extern Bool noXFixesExtension; +#endif +#ifdef XKB +/* |noXkbExtension| is defined in xc/programs/Xserver/xkb/xkbInit.c */ +extern Bool noXkbExtension; +#endif +#ifdef PANORAMIX +extern Bool noPanoramiXExtension; +#endif +#ifdef XINPUT +extern Bool noXInputExtension; +#endif +#ifdef XIDLE +extern Bool noXIdleExtension; +#endif +#ifdef XV +extern Bool noXvExtension; +#endif + +#ifndef XFree86LOADER +#define INITARGS void +typedef void (*InitExtension)(INITARGS); +#else /* XFree86Loader */ +#include "loaderProcs.h" +#endif + +#ifdef MITSHM +#define _XSHM_SERVER_ +#include <X11/extensions/shmstr.h> +#endif +#ifdef XTEST +#define _XTEST_SERVER_ +#include <X11/extensions/XTest.h> +#endif +#ifdef XKB +#include <X11/extensions/XKB.h> +#endif +#ifdef XPRINT +#include <X11/extensions/Print.h> +#endif +#ifdef XAPPGROUP +#define _XAG_SERVER_ +#include <X11/extensions/Xagstr.h> +#endif +#ifdef XACE +#include "xace.h" +#endif +#ifdef XCSECURITY +#include "securitysrv.h" +#include <X11/extensions/securstr.h> +#endif +#ifdef PANORAMIX +#include <X11/extensions/panoramiXproto.h> +#endif +#ifdef XF86BIGFONT +#include <X11/extensions/xf86bigfstr.h> +#endif +#ifdef RES +#include <X11/extensions/XResproto.h> +#endif + +/* FIXME: this whole block of externs should be from the appropriate headers */ +#ifdef EVI +extern void EVIExtensionInit(INITARGS); +#endif +#ifdef MITSHM +extern void ShmExtensionInit(INITARGS); +#endif +#ifdef MULTIBUFFER +extern void MultibufferExtensionInit(INITARGS); +#endif +#ifdef PANORAMIX +extern void PanoramiXExtensionInit(INITARGS); +#endif +#ifdef XINPUT +extern void XInputExtensionInit(INITARGS); +#endif +#ifdef XTEST +extern void XTestExtensionInit(INITARGS); +#endif +#ifdef BIGREQS +extern void BigReqExtensionInit(INITARGS); +#endif +#ifdef MITMISC +extern void MITMiscExtensionInit(INITARGS); +#endif +#ifdef XIDLE +extern void XIdleExtensionInit(INITARGS); +#endif +#ifdef XTRAP +extern void DEC_XTRAPInit(INITARGS); +#endif +#ifdef SCREENSAVER +extern void ScreenSaverExtensionInit (INITARGS); +#endif +#ifdef XV +extern void XvExtensionInit(INITARGS); +extern void XvMCExtensionInit(INITARGS); +#endif +#ifdef XSYNC +extern void SyncExtensionInit(INITARGS); +#endif +#ifdef XKB +extern void XkbExtensionInit(INITARGS); +#endif +#ifdef XCMISC +extern void XCMiscExtensionInit(INITARGS); +#endif +#ifdef XRECORD +extern void RecordExtensionInit(INITARGS); +#endif +#ifdef DBE +extern void DbeExtensionInit(INITARGS); +#endif +#ifdef XAPPGROUP +extern void XagExtensionInit(INITARGS); +#endif +#ifdef XACE +extern void XaceExtensionInit(INITARGS); +#endif +#ifdef XCSECURITY +extern void SecurityExtensionSetup(INITARGS); +extern void SecurityExtensionInit(INITARGS); +#endif +#ifdef XPRINT +extern void XpExtensionInit(INITARGS); +#endif +#ifdef XF86BIGFONT +extern void XFree86BigfontExtensionInit(INITARGS); +#endif +#ifdef XF86VIDMODE +extern void XFree86VidModeExtensionInit(INITARGS); +#endif +#ifdef XF86MISC +extern void XFree86MiscExtensionInit(INITARGS); +#endif +#ifdef XFreeXDGA +extern void XFree86DGAExtensionInit(INITARGS); +#endif +#ifdef GLXEXT +typedef struct __GLXprovider __GLXprovider; +extern __GLXprovider __glXMesaProvider; +extern void GlxPushProvider(__GLXprovider *impl); +#ifndef __DARWIN__ +extern void GlxExtensionInit(INITARGS); +extern void GlxWrapInitVisuals(miInitVisualsProcPtr *); +#else +extern void DarwinGlxExtensionInit(INITARGS); +extern void DarwinGlxWrapInitVisuals(miInitVisualsProcPtr *); +#endif +#endif +#ifdef XF86DRI +extern void XFree86DRIExtensionInit(INITARGS); +#endif +#ifdef TOGCUP +extern void XcupExtensionInit(INITARGS); +#endif +#ifdef DPMSExtension +extern void DPMSExtensionInit(INITARGS); +#endif +#ifdef FONTCACHE +extern void FontCacheExtensionInit(INITARGS); +#endif +#ifdef RENDER +extern void RenderExtensionInit(INITARGS); +#endif +#ifdef RANDR +extern void RRExtensionInit(INITARGS); +#endif +#ifdef RES +extern void ResExtensionInit(INITARGS); +#endif +#ifdef DMXEXT +extern void DMXExtensionInit(INITARGS); +#endif +#ifdef XEVIE +extern void XevieExtensionInit(INITARGS); +#endif +#ifdef XFIXES +extern void XFixesExtensionInit(INITARGS); +#endif +#ifdef DAMAGE +extern void DamageExtensionInit(INITARGS); +#endif +#ifdef COMPOSITE +extern void CompositeExtensionInit(INITARGS); +#endif + +/* The following is only a small first step towards run-time + * configurable extensions. + */ +typedef struct { + char *name; + Bool *disablePtr; +} ExtensionToggle; + +static ExtensionToggle ExtensionToggleList[] = +{ + /* sort order is extension name string as shown in xdpyinfo */ +#ifdef BIGREQS + { "BIG-REQUESTS", &noBigReqExtension }, +#endif +#ifdef COMPOSITE + { "Composite", &noCompositeExtension }, +#endif +#ifdef DAMAGE + { "DAMAGE", &noDamageExtension }, +#endif +#ifdef DBE + { "DOUBLE-BUFFER", &noDbeExtension }, +#endif +#ifdef DPMSExtension + { "DPMS", &noDPMSExtension }, +#endif +#ifdef EVI + { "Extended-Visual-Information", &noEVIExtension }, +#endif +#ifdef FONTCACHE + { "FontCache", &noFontCacheExtension }, +#endif +#ifdef GLXEXT + { "GLX", &noGlxExtension }, +#endif +#ifdef SCREENSAVER + { "MIT-SCREEN-SAVER", &noScreenSaverExtension }, +#endif +#ifdef MITSHM + { SHMNAME, &noMITShmExtension }, +#endif +#ifdef MITMISC + { "MIT-SUNDRY-NONSTANDARD", &noMITMiscExtension }, +#endif +#ifdef MULTIBUFFER + { "Multi-Buffering", &noMultibufferExtension }, +#endif +#ifdef RANDR + { "RANDR", &noRRExtension }, +#endif +#ifdef RENDER + { "RENDER", &noRenderExtension }, +#endif +#ifdef SHAPE + { "SHAPE", &noShapeExtension }, +#endif +#ifdef XCSECURITY + { "SECURITY", &noSecurityExtension }, +#endif +#ifdef XSYNC + { "SYNC", &noSyncExtension }, +#endif +#ifdef TOGCUP + { "TOG-CUP", &noXcupExtension }, +#endif +#ifdef RES + { "X-Resource", &noResExtension }, +#endif +#ifdef XAPPGROUP + { "XC-APPGROUP", &noXagExtension }, +#endif +#ifdef XCMISC + { "XC-MISC", &noXCMiscExtension }, +#endif +#ifdef XEVIE + { "XEVIE", &noXevieExtension }, +#endif +#ifdef XF86BIGFONT + { "XFree86-Bigfont", &noXFree86BigfontExtension }, +#endif +#ifdef XFreeXDGA + { "XFree86-DGA", &noXFree86DGAExtension }, +#endif +#ifdef XF86DRI + { "XFree86-DRI", &noXFree86DRIExtension }, +#endif +#ifdef XF86MISC + { "XFree86-Misc", &noXFree86MiscExtension }, +#endif +#ifdef XF86VIDMODE + { "XFree86-VidModeExtension", &noXFree86VidModeExtension }, +#endif +#ifdef XFIXES + { "XFIXES", &noXFixesExtension }, +#endif +#ifdef PANORAMIX + { "XINERAMA", &noPanoramiXExtension }, +#endif +#ifdef XINPUT + { "XInputExtension", &noXInputExtension }, +#endif +#ifdef XKB + { "XKEYBOARD", &noXkbExtension }, +#endif + { "XTEST", &noTestExtensions }, +#ifdef XV + { "XVideo", &noXvExtension }, +#endif + { NULL, NULL } +}; + +Bool EnableDisableExtension(char *name, Bool enable) +{ + ExtensionToggle *ext = &ExtensionToggleList[0]; + + for (ext = &ExtensionToggleList[0]; ext->name != NULL; ext++) { + if (strcmp(name, ext->name) == 0) { + *ext->disablePtr = !enable; + return TRUE; + } + } + + return FALSE; +} + +void EnableDisableExtensionError(char *name, Bool enable) +{ + ExtensionToggle *ext = &ExtensionToggleList[0]; + + ErrorF("Extension \"%s\" is not recognized\n", name); + ErrorF("Only the following extensions can be run-time %s:\n", + enable ? "enabled" : "disabled"); + for (ext = &ExtensionToggleList[0]; ext->name != NULL; ext++) + ErrorF(" %s\n", ext->name); +} + +#ifndef XFree86LOADER + +/*ARGSUSED*/ +void +InitExtensions(argc, argv) + int argc; + char *argv[]; +{ +#ifdef XCSECURITY + SecurityExtensionSetup(); +#endif +#ifdef PANORAMIX +# if !defined(PRINT_ONLY_SERVER) && !defined(NO_PANORAMIX) + if (!noPanoramiXExtension) PanoramiXExtensionInit(); +# endif +#endif +#ifdef SHAPE + if (!noShapeExtension) ShapeExtensionInit(); +#endif +#ifdef MITSHM + if (!noMITShmExtension) ShmExtensionInit(); +#endif +#ifdef EVI + if (!noEVIExtension) EVIExtensionInit(); +#endif +#ifdef MULTIBUFFER + if (!noMultibufferExtension) MultibufferExtensionInit(); +#endif +#if defined(XINPUT) && !defined(NO_HW_ONLY_EXTS) + if (!noXInputExtension) XInputExtensionInit(); +#endif +#ifdef XTEST + if (!noTestExtensions) XTestExtensionInit(); +#endif +#ifdef BIGREQS + if (!noBigReqExtension) BigReqExtensionInit(); +#endif +#ifdef MITMISC + if (!noMITMiscExtension) MITMiscExtensionInit(); +#endif +#ifdef XIDLE + if (!noXIdleExtension) XIdleExtensionInit(); +#endif +#ifdef XTRAP + if (!noTestExtensions) DEC_XTRAPInit(); +#endif +#if defined(SCREENSAVER) && !defined(PRINT_ONLY_SERVER) + if (!noScreenSaverExtension) ScreenSaverExtensionInit (); +#endif +#ifdef XV + if (!noXvExtension) { + XvExtensionInit(); + XvMCExtensionInit(); + } +#endif +#ifdef XSYNC + if (!noSyncExtension) SyncExtensionInit(); +#endif +#if defined(XKB) && !defined(PRINT_ONLY_SERVER) && !defined(NO_HW_ONLY_EXTS) + if (!noXkbExtension) XkbExtensionInit(); +#endif +#ifdef XCMISC + if (!noXCMiscExtension) XCMiscExtensionInit(); +#endif +#ifdef XRECORD + if (!noTestExtensions) RecordExtensionInit(); +#endif +#ifdef DBE + if (!noDbeExtension) DbeExtensionInit(); +#endif +#ifdef XAPPGROUP + if (!noXagExtension) XagExtensionInit(); +#endif +#ifdef XACE + XaceExtensionInit(); +#endif +#ifdef XCSECURITY + if (!noSecurityExtension) SecurityExtensionInit(); +#endif +#ifdef XPRINT + XpExtensionInit(); /* server-specific extension, cannot be disabled */ +#endif +#ifdef TOGCUP + if (!noXcupExtension) XcupExtensionInit(); +#endif +#if defined(DPMSExtension) && !defined(NO_HW_ONLY_EXTS) + if (!noDPMSExtension) DPMSExtensionInit(); +#endif +#ifdef FONTCACHE + if (!noFontCacheExtension) FontCacheExtensionInit(); +#endif +#ifdef XF86BIGFONT + if (!noXFree86BigfontExtension) XFree86BigfontExtensionInit(); +#endif +#if !defined(PRINT_ONLY_SERVER) && !defined(NO_HW_ONLY_EXTS) +#if defined(XF86VIDMODE) + if (!noXFree86VidModeExtension) XFree86VidModeExtensionInit(); +#endif +#if defined(XF86MISC) + if (!noXFree86MiscExtension) XFree86MiscExtensionInit(); +#endif +#if defined(XFreeXDGA) + if (!noXFree86DGAExtension) XFree86DGAExtensionInit(); +#endif +#ifdef XF86DRI + if (!noXFree86DRIExtension) XFree86DRIExtensionInit(); +#endif +#endif +#ifdef GLXEXT + + GlxPushProvider(&__glXMesaProvider); +#ifndef __DARWIN__ + if (!noGlxExtension) GlxExtensionInit(); +#else + if (!noGlxExtension) DarwinGlxExtensionInit(); +#endif +#endif +#ifdef XFIXES + /* must be before Render to layer DisplayCursor correctly */ + if (!noXFixesExtension) XFixesExtensionInit(); +#endif +#ifdef RENDER + if (!noRenderExtension) RenderExtensionInit(); +#endif +#ifdef RANDR + if (!noRRExtension) RRExtensionInit(); +#endif +#ifdef RES + if (!noResExtension) ResExtensionInit(); +#endif +#ifdef DMXEXT + DMXExtensionInit(); /* server-specific extension, cannot be disabled */ +#endif +#ifdef XEVIE + if (!noXevieExtension) XevieExtensionInit(); +#endif +#ifdef COMPOSITE + if (!noCompositeExtension) CompositeExtensionInit(); +#endif +#ifdef DAMAGE + if (!noDamageExtension) DamageExtensionInit(); +#endif +} + +void +InitVisualWrap() +{ + miResetInitVisuals(); +#ifdef GLXEXT +#ifndef __DARWIN__ + GlxWrapInitVisuals(&miInitVisualsProc); +#else + DarwinGlxWrapInitVisuals(&miInitVisualsProc); +#endif +#endif +} + +#else /* XFree86LOADER */ +/* List of built-in (statically linked) extensions */ +static ExtensionModule staticExtensions[] = { +#ifdef MITSHM + { ShmExtensionInit, SHMNAME, &noMITShmExtension, NULL, NULL }, +#endif +#ifdef XINPUT + { XInputExtensionInit, "XInputExtension", &noXInputExtension, NULL, NULL }, +#endif +#ifdef XTEST + { XTestExtensionInit, XTestExtensionName, &noTestExtensions, NULL, NULL }, +#endif +#ifdef XIDLE + { XIdleExtensionInit, "XIDLE", &noXIdleExtension, NULL, NULL }, +#endif +#ifdef XKB + { XkbExtensionInit, XkbName, &noXkbExtension, NULL, NULL }, +#endif +#ifdef XAPPGROUP + { XagExtensionInit, XAGNAME, &noXagExtension, NULL, NULL }, +#endif +#ifdef XACE + { XaceExtensionInit, XACE_EXTENSION_NAME, NULL, NULL, NULL }, +#endif +#ifdef XCSECURITY + { SecurityExtensionInit, SECURITY_EXTENSION_NAME, &noSecurityExtension, SecurityExtensionSetup, NULL }, +#endif +#ifdef XPRINT + { XpExtensionInit, XP_PRINTNAME, NULL, NULL, NULL }, +#endif +#ifdef PANORAMIX + { PanoramiXExtensionInit, PANORAMIX_PROTOCOL_NAME, &noPanoramiXExtension, NULL, NULL }, +#endif +#ifdef XFIXES + /* must be before Render to layer DisplayCursor correctly */ + { XFixesExtensionInit, "XFIXES", &noXFixesExtension, NULL, NULL }, +#endif +#ifdef XF86BIGFONT + { XFree86BigfontExtensionInit, XF86BIGFONTNAME, &noXFree86BigfontExtension, NULL, NULL }, +#endif +#ifdef RENDER + { RenderExtensionInit, "RENDER", &noRenderExtension, NULL, NULL }, +#endif +#ifdef RANDR + { RRExtensionInit, "RANDR", &noRRExtension, NULL, NULL }, +#endif +#ifdef COMPOSITE + { CompositeExtensionInit, "COMPOSITE", &noCompositeExtension, NULL }, +#endif +#ifdef DAMAGE + { DamageExtensionInit, "DAMAGE", &noDamageExtension, NULL }, +#endif +#ifdef XEVIE + { XevieExtensionInit, "XEVIE", &noXevieExtension, NULL }, +#endif + { NULL, NULL, NULL, NULL, NULL } +}; + +/*ARGSUSED*/ +void +InitExtensions(argc, argv) + int argc; + char *argv[]; +{ + int i; + ExtensionModule *ext; + static Bool listInitialised = FALSE; + + if (!listInitialised) { + /* Add built-in extensions to the list. */ + for (i = 0; staticExtensions[i].name; i++) + LoadExtension(&staticExtensions[i], TRUE); + + /* Sort the extensions according the init dependencies. */ + LoaderSortExtensions(); + listInitialised = TRUE; + } else { + /* Call the setup functions on subsequent server resets as well */ + for (i = 0; ExtensionModuleList[i].name != NULL; i++) { + ext = &ExtensionModuleList[i]; + if (ext->setupFunc != NULL && + (ext->disablePtr == NULL || + (ext->disablePtr != NULL && !*ext->disablePtr))) { + (ext->setupFunc)(); + } + } + } + + for (i = 0; ExtensionModuleList[i].name != NULL; i++) { + ext = &ExtensionModuleList[i]; + if (ext->initFunc != NULL && + (ext->disablePtr == NULL || + (ext->disablePtr != NULL && !*ext->disablePtr))) { + (ext->initFunc)(); + } + } +} + +static void (*__miHookInitVisualsFunction)(miInitVisualsProcPtr *); + +void +InitVisualWrap() +{ + miResetInitVisuals(); + if (__miHookInitVisualsFunction) + (*__miHookInitVisualsFunction)(&miInitVisualsProc); +} + +_X_EXPORT void +miHookInitVisuals(void (**old)(miInitVisualsProcPtr *), + void (*new)(miInitVisualsProcPtr *)) +{ + if (old) + *old = __miHookInitVisualsFunction; + __miHookInitVisualsFunction = new; +} + +#endif /* XFree86LOADER */ diff --git a/xserver/mi/miline.h b/xserver/mi/miline.h new file mode 100644 index 000000000..7028485f0 --- /dev/null +++ b/xserver/mi/miline.h @@ -0,0 +1,172 @@ + +/* + +Copyright 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#ifndef MILINE_H + +#include "screenint.h" + +/* + * Public definitions used for configuring basic pixelization aspects + * of the sample implementation line-drawing routines provided in + * {mfb,mi,cfb*} at run-time. + */ + +#define XDECREASING 4 +#define YDECREASING 2 +#define YMAJOR 1 + +#define OCTANT1 (1 << (YDECREASING)) +#define OCTANT2 (1 << (YDECREASING|YMAJOR)) +#define OCTANT3 (1 << (XDECREASING|YDECREASING|YMAJOR)) +#define OCTANT4 (1 << (XDECREASING|YDECREASING)) +#define OCTANT5 (1 << (XDECREASING)) +#define OCTANT6 (1 << (XDECREASING|YMAJOR)) +#define OCTANT7 (1 << (YMAJOR)) +#define OCTANT8 (1 << (0)) + +#define XMAJOROCTANTS (OCTANT1 | OCTANT4 | OCTANT5 | OCTANT8) + +#define DEFAULTZEROLINEBIAS (OCTANT2 | OCTANT3 | OCTANT4 | OCTANT5) + +/* + * Devices can configure the rendering of routines in mi, mfb, and cfb* + * by specifying a thin line bias to be applied to a particular screen + * using the following function. The bias parameter is an OR'ing of + * the appropriate OCTANT constants defined above to indicate which + * octants to bias a line to prefer an axial step when the Bresenham + * error term is exactly zero. The octants are mapped as follows: + * + * \ | / + * \ 3 | 2 / + * \ | / + * 4 \ | / 1 + * \|/ + * ----------- + * /|\ + * 5 / | \ 8 + * / | \ + * / 6 | 7 \ + * / | \ + * + * For more information, see "Ambiguities in Incremental Line Rastering," + * Jack E. Bresenham, IEEE CG&A, May 1987. + */ + +extern void miSetZeroLineBias( + ScreenPtr /* pScreen */, + unsigned int /* bias */ +); + +/* + * Private definitions needed for drawing thin (zero width) lines + * Used by the mi, mfb, and all cfb* components. + */ + +#define X_AXIS 0 +#define Y_AXIS 1 + +#define OUT_LEFT 0x08 +#define OUT_RIGHT 0x04 +#define OUT_ABOVE 0x02 +#define OUT_BELOW 0x01 + +#define OUTCODES(_result, _x, _y, _pbox) \ + if ( (_x) < (_pbox)->x1) (_result) |= OUT_LEFT; \ + else if ( (_x) >= (_pbox)->x2) (_result) |= OUT_RIGHT; \ + if ( (_y) < (_pbox)->y1) (_result) |= OUT_ABOVE; \ + else if ( (_y) >= (_pbox)->y2) (_result) |= OUT_BELOW; + +#define MIOUTCODES(outcode, x, y, xmin, ymin, xmax, ymax) \ +{\ + if (x < xmin) outcode |= OUT_LEFT;\ + if (x > xmax) outcode |= OUT_RIGHT;\ + if (y < ymin) outcode |= OUT_ABOVE;\ + if (y > ymax) outcode |= OUT_BELOW;\ +} + +#define SWAPINT(i, j) \ +{ register int _t = i; i = j; j = _t; } + +#define SWAPPT(i, j) \ +{ DDXPointRec _t; _t = i; i = j; j = _t; } + +#define SWAPINT_PAIR(x1, y1, x2, y2)\ +{ int t = x1; x1 = x2; x2 = t;\ + t = y1; y1 = y2; y2 = t;\ +} + +#define miGetZeroLineBias(_pScreen) \ + ((miZeroLineScreenIndex < 0) ? \ + 0 : ((_pScreen)->devPrivates[miZeroLineScreenIndex].uval)) + +#define CalcLineDeltas(_x1,_y1,_x2,_y2,_adx,_ady,_sx,_sy,_SX,_SY,_octant) \ + (_octant) = 0; \ + (_sx) = (_SX); \ + if (((_adx) = (_x2) - (_x1)) < 0) { \ + (_adx) = -(_adx); \ + (_sx = -(_sx)); \ + (_octant) |= XDECREASING; \ + } \ + (_sy) = (_SY); \ + if (((_ady) = (_y2) - (_y1)) < 0) { \ + (_ady) = -(_ady); \ + (_sy = -(_sy)); \ + (_octant) |= YDECREASING; \ + } + +#define SetYMajorOctant(_octant) ((_octant) |= YMAJOR) + +#define FIXUP_ERROR(_e, _octant, _bias) \ + (_e) -= (((_bias) >> (_octant)) & 1) + +#define IsXMajorOctant(_octant) (!((_octant) & YMAJOR)) +#define IsYMajorOctant(_octant) ((_octant) & YMAJOR) +#define IsXDecreasingOctant(_octant) ((_octant) & XDECREASING) +#define IsYDecreasingOctant(_octant) ((_octant) & YDECREASING) + +extern int miZeroLineScreenIndex; + +extern int miZeroClipLine( + int /*xmin*/, + int /*ymin*/, + int /*xmax*/, + int /*ymax*/, + int * /*new_x1*/, + int * /*new_y1*/, + int * /*new_x2*/, + int * /*new_y2*/, + unsigned int /*adx*/, + unsigned int /*ady*/, + int * /*pt1_clipped*/, + int * /*pt2_clipped*/, + int /*octant*/, + unsigned int /*bias*/, + int /*oc1*/, + int /*oc2*/ +); + +#endif /* MILINE_H */ diff --git a/xserver/mi/mioverlay.c b/xserver/mi/mioverlay.c new file mode 100644 index 000000000..c02ea2dc5 --- /dev/null +++ b/xserver/mi/mioverlay.c @@ -0,0 +1,2077 @@ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include "scrnintstr.h" +#include "validate.h" +#include "windowstr.h" +#include "mi.h" +#include "gcstruct.h" +#include "regionstr.h" +#include "mivalidate.h" +#include "mioverlay.h" +#include "migc.h" + +#include "globals.h" + + +typedef struct { + RegionRec exposed; + RegionRec borderExposed; + RegionPtr borderVisible; + DDXPointRec oldAbsCorner; +} miOverlayValDataRec, *miOverlayValDataPtr; + +typedef struct _TreeRec { + WindowPtr pWin; + struct _TreeRec *parent; + struct _TreeRec *firstChild; + struct _TreeRec *lastChild; + struct _TreeRec *prevSib; + struct _TreeRec *nextSib; + RegionRec borderClip; + RegionRec clipList; + unsigned visibility; + miOverlayValDataPtr valdata; +} miOverlayTreeRec, *miOverlayTreePtr; + +typedef struct { + miOverlayTreePtr tree; +} miOverlayWindowRec, *miOverlayWindowPtr; + +typedef struct { + CloseScreenProcPtr CloseScreen; + CreateWindowProcPtr CreateWindow; + DestroyWindowProcPtr DestroyWindow; + UnrealizeWindowProcPtr UnrealizeWindow; + RealizeWindowProcPtr RealizeWindow; + miOverlayTransFunc MakeTransparent; + miOverlayInOverlayFunc InOverlay; + Bool underlayMarked; + Bool copyUnderlay; +} miOverlayScreenRec, *miOverlayScreenPtr; + +static unsigned long miOverlayGeneration = 0; +int miOverlayWindowIndex = -1; +int miOverlayScreenIndex = -1; + +static void RebuildTree(WindowPtr); +static Bool HasUnderlayChildren(WindowPtr); +static void MarkUnderlayWindow(WindowPtr); +static Bool CollectUnderlayChildrenRegions(WindowPtr, RegionPtr); + +static Bool miOverlayCloseScreen(int, ScreenPtr); +static Bool miOverlayCreateWindow(WindowPtr); +static Bool miOverlayDestroyWindow(WindowPtr); +static Bool miOverlayUnrealizeWindow(WindowPtr); +static Bool miOverlayRealizeWindow(WindowPtr); +static void miOverlayMarkWindow(WindowPtr); +static void miOverlayReparentWindow(WindowPtr, WindowPtr); +static void miOverlayRestackWindow(WindowPtr, WindowPtr); +static Bool miOverlayMarkOverlappedWindows(WindowPtr, WindowPtr, WindowPtr*); +static void miOverlayMarkUnrealizedWindow(WindowPtr, WindowPtr, Bool); +static int miOverlayValidateTree(WindowPtr, WindowPtr, VTKind); +static void miOverlayHandleExposures(WindowPtr); +static void miOverlayMoveWindow(WindowPtr, int, int, WindowPtr, VTKind); +static void miOverlayWindowExposures(WindowPtr, RegionPtr, RegionPtr); +static void miOverlayResizeWindow(WindowPtr, int, int, unsigned int, + unsigned int, WindowPtr); +static void miOverlayClearToBackground(WindowPtr, int, int, int, int, Bool); + +#ifdef SHAPE +static void miOverlaySetShape(WindowPtr); +#endif +static void miOverlayChangeBorderWidth(WindowPtr, unsigned int); + +#define MIOVERLAY_GET_SCREEN_PRIVATE(pScreen) \ + ((miOverlayScreenPtr)((pScreen)->devPrivates[miOverlayScreenIndex].ptr)) +#define MIOVERLAY_GET_WINDOW_PRIVATE(pWin) \ + ((miOverlayWindowPtr)((pWin)->devPrivates[miOverlayWindowIndex].ptr)) +#define MIOVERLAY_GET_WINDOW_TREE(pWin) \ + (MIOVERLAY_GET_WINDOW_PRIVATE(pWin)->tree) + +#define IN_UNDERLAY(w) MIOVERLAY_GET_WINDOW_TREE(w) +#define IN_OVERLAY(w) !MIOVERLAY_GET_WINDOW_TREE(w) + +#define MARK_OVERLAY(w) miMarkWindow(w) +#define MARK_UNDERLAY(w) MarkUnderlayWindow(w) + +#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \ + HasBorder(w) && \ + (w)->backgroundState == ParentRelative) + +_X_EXPORT Bool +miInitOverlay( + ScreenPtr pScreen, + miOverlayInOverlayFunc inOverlayFunc, + miOverlayTransFunc transFunc +){ + miOverlayScreenPtr pScreenPriv; + + if(!inOverlayFunc || !transFunc) return FALSE; + + if(miOverlayGeneration != serverGeneration) { + if(((miOverlayScreenIndex = AllocateScreenPrivateIndex()) < 0) || + ((miOverlayWindowIndex = AllocateWindowPrivateIndex()) < 0)) + return FALSE; + + miOverlayGeneration = serverGeneration; + } + + if(!AllocateWindowPrivate(pScreen, miOverlayWindowIndex, + sizeof(miOverlayWindowRec))) + return FALSE; + + if(!(pScreenPriv = xalloc(sizeof(miOverlayScreenRec)))) + return FALSE; + + pScreen->devPrivates[miOverlayScreenIndex].ptr = (pointer)pScreenPriv; + + pScreenPriv->InOverlay = inOverlayFunc; + pScreenPriv->MakeTransparent = transFunc; + pScreenPriv->underlayMarked = FALSE; + + + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreenPriv->CreateWindow = pScreen->CreateWindow; + pScreenPriv->DestroyWindow = pScreen->DestroyWindow; + pScreenPriv->UnrealizeWindow = pScreen->UnrealizeWindow; + pScreenPriv->RealizeWindow = pScreen->RealizeWindow; + + pScreen->CloseScreen = miOverlayCloseScreen; + pScreen->CreateWindow = miOverlayCreateWindow; + pScreen->DestroyWindow = miOverlayDestroyWindow; + pScreen->UnrealizeWindow = miOverlayUnrealizeWindow; + pScreen->RealizeWindow = miOverlayRealizeWindow; + + pScreen->ReparentWindow = miOverlayReparentWindow; + pScreen->RestackWindow = miOverlayRestackWindow; + pScreen->MarkOverlappedWindows = miOverlayMarkOverlappedWindows; + pScreen->MarkUnrealizedWindow = miOverlayMarkUnrealizedWindow; + pScreen->ValidateTree = miOverlayValidateTree; + pScreen->HandleExposures = miOverlayHandleExposures; + pScreen->MoveWindow = miOverlayMoveWindow; + pScreen->WindowExposures = miOverlayWindowExposures; + pScreen->ResizeWindow = miOverlayResizeWindow; + pScreen->MarkWindow = miOverlayMarkWindow; + pScreen->ClearToBackground = miOverlayClearToBackground; +#ifdef SHAPE + pScreen->SetShape = miOverlaySetShape; +#endif + pScreen->ChangeBorderWidth = miOverlayChangeBorderWidth; + + return TRUE; +} + + +static Bool +miOverlayCloseScreen(int i, ScreenPtr pScreen) +{ + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + pScreen->CreateWindow = pScreenPriv->CreateWindow; + pScreen->DestroyWindow = pScreenPriv->DestroyWindow; + pScreen->UnrealizeWindow = pScreenPriv->UnrealizeWindow; + pScreen->RealizeWindow = pScreenPriv->RealizeWindow; + + xfree(pScreenPriv); + + return (*pScreen->CloseScreen)(i, pScreen); +} + + +static Bool +miOverlayCreateWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + miOverlayWindowPtr pWinPriv = MIOVERLAY_GET_WINDOW_PRIVATE(pWin); + miOverlayTreePtr pTree = NULL; + Bool result = TRUE; + + pWinPriv->tree = NULL; + + if(!pWin->parent || !((*pScreenPriv->InOverlay)(pWin))) { + if(!(pTree = (miOverlayTreePtr)xcalloc(1, sizeof(miOverlayTreeRec)))) + return FALSE; + } + + if(pScreenPriv->CreateWindow) { + pScreen->CreateWindow = pScreenPriv->CreateWindow; + result = (*pScreen->CreateWindow)(pWin); + pScreen->CreateWindow = miOverlayCreateWindow; + } + + if (pTree) { + if(result) { + pTree->pWin = pWin; + pTree->visibility = VisibilityNotViewable; + pWinPriv->tree = pTree; + if(pWin->parent) { + REGION_NULL(pScreen, &(pTree->borderClip)); + REGION_NULL(pScreen, &(pTree->clipList)); + RebuildTree(pWin); + } else { + BoxRec fullBox; + fullBox.x1 = 0; + fullBox.y1 = 0; + fullBox.x2 = pScreen->width; + fullBox.y2 = pScreen->height; + REGION_INIT(pScreen, &(pTree->borderClip), &fullBox, 1); + REGION_INIT(pScreen, &(pTree->clipList), &fullBox, 1); + } + } else xfree(pTree); + } + + return TRUE; +} + + +static Bool +miOverlayDestroyWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + Bool result = TRUE; + + if (pTree) { + if(pTree->prevSib) + pTree->prevSib->nextSib = pTree->nextSib; + else if(pTree->parent) + pTree->parent->firstChild = pTree->nextSib; + + if(pTree->nextSib) + pTree->nextSib->prevSib = pTree->prevSib; + else if(pTree->parent) + pTree->parent->lastChild = pTree->prevSib; + + REGION_UNINIT(pScreen, &(pTree->borderClip)); + REGION_UNINIT(pScreen, &(pTree->clipList)); + xfree(pTree); + } + + if(pScreenPriv->DestroyWindow) { + pScreen->DestroyWindow = pScreenPriv->DestroyWindow; + result = (*pScreen->DestroyWindow)(pWin); + pScreen->DestroyWindow = miOverlayDestroyWindow; + } + + return result; +} + +static Bool +miOverlayUnrealizeWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + Bool result = TRUE; + + if(pTree) pTree->visibility = VisibilityNotViewable; + + if(pScreenPriv->UnrealizeWindow) { + pScreen->UnrealizeWindow = pScreenPriv->UnrealizeWindow; + result = (*pScreen->UnrealizeWindow)(pWin); + pScreen->UnrealizeWindow = miOverlayUnrealizeWindow; + } + + return result; +} + + +static Bool +miOverlayRealizeWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + Bool result = TRUE; + + if(pScreenPriv->RealizeWindow) { + pScreen->RealizeWindow = pScreenPriv->RealizeWindow; + result = (*pScreen->RealizeWindow)(pWin); + pScreen->RealizeWindow = miOverlayRealizeWindow; + } + + /* we only need to catch the root window realization */ + + if(result && !pWin->parent && !((*pScreenPriv->InOverlay)(pWin))) + { + BoxRec box; + box.x1 = box.y1 = 0; + box.x2 = pWin->drawable.width; + box.y2 = pWin->drawable.height; + (*pScreenPriv->MakeTransparent)(pScreen, 1, &box); + } + + return result; +} + + +static void +miOverlayReparentWindow(WindowPtr pWin, WindowPtr pPriorParent) +{ + if(IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)) { + /* This could probably be more optimal */ + RebuildTree(WindowTable[pWin->drawable.pScreen->myNum]->firstChild); + } +} + +static void +miOverlayRestackWindow(WindowPtr pWin, WindowPtr oldNextSib) +{ + if(IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)) { + /* This could probably be more optimal */ + RebuildTree(pWin); + } +} + + +static Bool +miOverlayMarkOverlappedWindows( + WindowPtr pWin, + WindowPtr pFirst, + WindowPtr *pLayerWin +){ + ScreenPtr pScreen = pWin->drawable.pScreen; + WindowPtr pChild, pLast; + Bool overMarked, underMarked, doUnderlay, markAll; + miOverlayTreePtr pTree = NULL, tLast, tChild; + BoxPtr box; + + overMarked = underMarked = markAll = FALSE; + + if(pLayerWin) *pLayerWin = pWin; /* hah! */ + + doUnderlay = (IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)); + + box = REGION_EXTENTS(pScreen, &pWin->borderSize); + + if((pChild = pFirst)) { + pLast = pChild->parent->lastChild; + while (1) { + if (pChild == pWin) markAll = TRUE; + + if(doUnderlay && IN_UNDERLAY(pChild)) + pTree = MIOVERLAY_GET_WINDOW_TREE(pChild); + + if(pChild->viewable) { + if (REGION_BROKEN (pScreen, &pChild->winSize)) + SetWinSize (pChild); + if (REGION_BROKEN (pScreen, &pChild->borderSize)) + SetBorderSize (pChild); + + if (markAll || + RECT_IN_REGION(pScreen, &pChild->borderSize, box)) + { + MARK_OVERLAY(pChild); + overMarked = TRUE; + if(doUnderlay && IN_UNDERLAY(pChild)) { + MARK_UNDERLAY(pChild); + underMarked = TRUE; + } + if (pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + } + } + while (!pChild->nextSib && (pChild != pLast)) { + pChild = pChild->parent; + if(doUnderlay && IN_UNDERLAY(pChild)) + pTree = MIOVERLAY_GET_WINDOW_TREE(pChild); + } + + if(pChild == pWin) markAll = FALSE; + + if (pChild == pLast) break; + + pChild = pChild->nextSib; + } + if(overMarked) + MARK_OVERLAY(pWin->parent); + } + + if(doUnderlay && !pTree) { + if(!(pTree = MIOVERLAY_GET_WINDOW_TREE(pWin))) { + pChild = pWin->lastChild; + while(1) { + if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) + break; + + if(pChild->lastChild) { + pChild = pChild->lastChild; + continue; + } + + while(!pChild->prevSib) pChild = pChild->parent; + + pChild = pChild->prevSib; + } + } + } + + if(pTree && pTree->nextSib) { + tChild = pTree->parent->lastChild; + tLast = pTree->nextSib; + + while(1) { + if(tChild->pWin->viewable) { + if (REGION_BROKEN (pScreen, &tChild->pWin->winSize)) + SetWinSize (tChild->pWin); + if (REGION_BROKEN (pScreen, &tChild->pWin->borderSize)) + SetBorderSize (tChild->pWin); + + if(RECT_IN_REGION(pScreen, &(tChild->pWin->borderSize), box)) + { + MARK_UNDERLAY(tChild->pWin); + underMarked = TRUE; + } + } + + if(tChild->lastChild) { + tChild = tChild->lastChild; + continue; + } + + while(!tChild->prevSib && (tChild != tLast)) + tChild = tChild->parent; + + if(tChild == tLast) break; + + tChild = tChild->prevSib; + } + } + + if(underMarked) { + MARK_UNDERLAY(pTree->parent->pWin); + MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->underlayMarked = TRUE; + } + + return (underMarked || overMarked); +} + + +static void +miOverlayComputeClips( + WindowPtr pParent, + RegionPtr universe, + VTKind kind, + RegionPtr exposed +){ + ScreenPtr pScreen = pParent->drawable.pScreen; + int oldVis, newVis, dx, dy; + BoxRec borderSize; + RegionPtr borderVisible; + RegionRec childUniverse, childUnion; + miOverlayTreePtr tParent = MIOVERLAY_GET_WINDOW_TREE(pParent); + miOverlayTreePtr tChild; + Bool overlap; + + borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent); + borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent); + dx = (int) pParent->drawable.x + (int) pParent->drawable.width + + wBorderWidth(pParent); + if (dx > 32767) dx = 32767; + borderSize.x2 = dx; + dy = (int) pParent->drawable.y + (int) pParent->drawable.height + + wBorderWidth(pParent); + if (dy > 32767) dy = 32767; + borderSize.y2 = dy; + + oldVis = tParent->visibility; + switch (RECT_IN_REGION( pScreen, universe, &borderSize)) { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnPART: + newVis = VisibilityPartiallyObscured; +#ifdef SHAPE + { + RegionPtr pBounding; + + if ((pBounding = wBoundingShape (pParent))) { + switch (miShapedWindowIn (pScreen, universe, pBounding, + &borderSize, + pParent->drawable.x, + pParent->drawable.y)) + { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnOUT: + newVis = VisibilityFullyObscured; + break; + } + } + } +#endif + break; + default: + newVis = VisibilityFullyObscured; + break; + } + tParent->visibility = newVis; + + dx = pParent->drawable.x - tParent->valdata->oldAbsCorner.x; + dy = pParent->drawable.y - tParent->valdata->oldAbsCorner.y; + + switch (kind) { + case VTMap: + case VTStack: + case VTUnmap: + break; + case VTMove: + if ((oldVis == newVis) && + ((oldVis == VisibilityFullyObscured) || + (oldVis == VisibilityUnobscured))) + { + tChild = tParent; + while (1) { + if (tChild->pWin->viewable) { + if (tChild->visibility != VisibilityFullyObscured) { + REGION_TRANSLATE( pScreen, &tChild->borderClip, dx, dy); + REGION_TRANSLATE( pScreen, &tChild->clipList, dx, dy); + + tChild->pWin->drawable.serialNumber = + NEXT_SERIAL_NUMBER; + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (tChild->pWin, dx, dy); + } + if (tChild->valdata) { + REGION_NULL(pScreen, &tChild->valdata->borderExposed); + if (HasParentRelativeBorder(tChild->pWin)){ + REGION_SUBTRACT(pScreen, + &tChild->valdata->borderExposed, + &tChild->borderClip, + &tChild->pWin->winSize); + } + REGION_NULL(pScreen, &tChild->valdata->exposed); + } + if (tChild->firstChild) { + tChild = tChild->firstChild; + continue; + } + } + while (!tChild->nextSib && (tChild != tParent)) + tChild = tChild->parent; + if (tChild == tParent) + break; + tChild = tChild->nextSib; + } + return; + } + /* fall through */ + default: + if (dx || dy) { + REGION_TRANSLATE( pScreen, &tParent->borderClip, dx, dy); + REGION_TRANSLATE( pScreen, &tParent->clipList, dx, dy); + } + break; + case VTBroken: + REGION_EMPTY (pScreen, &tParent->borderClip); + REGION_EMPTY (pScreen, &tParent->clipList); + break; + } + + borderVisible = tParent->valdata->borderVisible; + REGION_NULL(pScreen, &tParent->valdata->borderExposed); + REGION_NULL(pScreen, &tParent->valdata->exposed); + + if (HasBorder (pParent)) { + if (borderVisible) { + REGION_SUBTRACT( pScreen, exposed, universe, borderVisible); + REGION_DESTROY( pScreen, borderVisible); + } else + REGION_SUBTRACT( pScreen, exposed, universe, &tParent->borderClip); + + if (HasParentRelativeBorder(pParent) && (dx || dy)) + REGION_SUBTRACT( pScreen, &tParent->valdata->borderExposed, + universe, &pParent->winSize); + else + REGION_SUBTRACT( pScreen, &tParent->valdata->borderExposed, + exposed, &pParent->winSize); + + REGION_COPY( pScreen, &tParent->borderClip, universe); + REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize); + } + else + REGION_COPY( pScreen, &tParent->borderClip, universe); + + if ((tChild = tParent->firstChild) && pParent->mapped) { + REGION_NULL(pScreen, &childUniverse); + REGION_NULL(pScreen, &childUnion); + + for (; tChild; tChild = tChild->nextSib) { + if (tChild->pWin->viewable) + REGION_APPEND( pScreen, &childUnion, &tChild->pWin->borderSize); + } + + REGION_VALIDATE( pScreen, &childUnion, &overlap); + + for (tChild = tParent->firstChild; + tChild; + tChild = tChild->nextSib) + { + if (tChild->pWin->viewable) { + if (tChild->valdata) { + REGION_INTERSECT( pScreen, &childUniverse, universe, + &tChild->pWin->borderSize); + miOverlayComputeClips (tChild->pWin, &childUniverse, + kind, exposed); + } + if (overlap) + REGION_SUBTRACT( pScreen, universe, universe, + &tChild->pWin->borderSize); + } + } + if (!overlap) + REGION_SUBTRACT( pScreen, universe, universe, &childUnion); + REGION_UNINIT( pScreen, &childUnion); + REGION_UNINIT( pScreen, &childUniverse); + } + + if (oldVis == VisibilityFullyObscured || + oldVis == VisibilityNotViewable) + { + REGION_COPY( pScreen, &tParent->valdata->exposed, universe); + } + else if (newVis != VisibilityFullyObscured && + newVis != VisibilityNotViewable) + { + REGION_SUBTRACT( pScreen, &tParent->valdata->exposed, + universe, &tParent->clipList); + } + + /* HACK ALERT - copying contents of regions, instead of regions */ + { + RegionRec tmp; + + tmp = tParent->clipList; + tParent->clipList = *universe; + *universe = tmp; + } + + pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pParent, dx, dy); +} + + +static void +miOverlayMarkWindow(WindowPtr pWin) +{ + miOverlayTreePtr pTree = NULL; + WindowPtr pChild, pGrandChild; + + miMarkWindow(pWin); + + /* look for UnmapValdata among immediate children */ + + if(!(pChild = pWin->firstChild)) return; + + for( ; pChild; pChild = pChild->nextSib) { + if(pChild->valdata == UnmapValData) { + if(IN_UNDERLAY(pChild)) { + pTree = MIOVERLAY_GET_WINDOW_TREE(pChild); + pTree->valdata = (miOverlayValDataPtr)UnmapValData; + continue; + } else { + if(!(pGrandChild = pChild->firstChild)) + continue; + + while(1) { + if(IN_UNDERLAY(pGrandChild)) { + pTree = MIOVERLAY_GET_WINDOW_TREE(pGrandChild); + pTree->valdata = (miOverlayValDataPtr)UnmapValData; + } else if(pGrandChild->firstChild) { + pGrandChild = pGrandChild->firstChild; + continue; + } + + while(!pGrandChild->nextSib && (pGrandChild != pChild)) + pGrandChild = pGrandChild->parent; + + if(pChild == pGrandChild) break; + + pGrandChild = pGrandChild->nextSib; + } + } + } + } + + if(pTree) { + MARK_UNDERLAY(pTree->parent->pWin); + MIOVERLAY_GET_SCREEN_PRIVATE( + pWin->drawable.pScreen)->underlayMarked = TRUE; + } +} + +static void +miOverlayMarkUnrealizedWindow( + WindowPtr pChild, + WindowPtr pWin, + Bool fromConfigure +){ + if ((pChild != pWin) || fromConfigure) { + miOverlayTreePtr pTree; + + REGION_EMPTY(pChild->drawable.pScreen, &pChild->clipList); + if (pChild->drawable.pScreen->ClipNotify) + (* pChild->drawable.pScreen->ClipNotify)(pChild, 0, 0); + REGION_EMPTY(pChild->drawable.pScreen, &pChild->borderClip); + if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) { + if(pTree->valdata != (miOverlayValDataPtr)UnmapValData) { + REGION_EMPTY(pChild->drawable.pScreen, &pTree->clipList); + REGION_EMPTY(pChild->drawable.pScreen, &pTree->borderClip); + } + } + } +} + + +static int +miOverlayValidateTree( + WindowPtr pParent, + WindowPtr pChild, /* first child effected */ + VTKind kind +){ + ScreenPtr pScreen = pParent->drawable.pScreen; + miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + RegionRec totalClip, childClip, exposed; + miOverlayTreePtr tParent, tChild, tWin; + Bool overlap; + WindowPtr newParent; + + if(!pPriv->underlayMarked) + goto SKIP_UNDERLAY; + + if (!pChild) pChild = pParent->firstChild; + + REGION_NULL(pScreen, &totalClip); + REGION_NULL(pScreen, &childClip); + REGION_NULL(pScreen, &exposed); + + newParent = pParent; + + while(IN_OVERLAY(newParent)) + newParent = newParent->parent; + + tParent = MIOVERLAY_GET_WINDOW_TREE(newParent); + + if(IN_UNDERLAY(pChild)) + tChild = MIOVERLAY_GET_WINDOW_TREE(pChild); + else + tChild = tParent->firstChild; + + if (REGION_BROKEN (pScreen, &tParent->clipList) && + !REGION_BROKEN (pScreen, &tParent->borderClip)) + { + kind = VTBroken; + REGION_COPY (pScreen, &totalClip, &tParent->borderClip); + REGION_INTERSECT (pScreen, &totalClip, &totalClip, + &tParent->pWin->winSize); + + for (tWin = tParent->firstChild; tWin != tChild; tWin = tWin->nextSib) { + if (tWin->pWin->viewable) + REGION_SUBTRACT (pScreen, &totalClip, &totalClip, + &tWin->pWin->borderSize); + } + REGION_EMPTY (pScreen, &tParent->clipList); + } else { + for(tWin = tChild; tWin; tWin = tWin->nextSib) { + if(tWin->valdata) + REGION_APPEND(pScreen, &totalClip, &tWin->borderClip); + } + REGION_VALIDATE(pScreen, &totalClip, &overlap); + } + + if(kind != VTStack) + REGION_UNION(pScreen, &totalClip, &totalClip, &tParent->clipList); + + for(tWin = tChild; tWin; tWin = tWin->nextSib) { + if(tWin->valdata) { + if(tWin->pWin->viewable) { + REGION_INTERSECT(pScreen, &childClip, &totalClip, + &tWin->pWin->borderSize); + miOverlayComputeClips(tWin->pWin, &childClip, kind, &exposed); + REGION_SUBTRACT(pScreen, &totalClip, &totalClip, + &tWin->pWin->borderSize); + } else { /* Means we are unmapping */ + REGION_EMPTY(pScreen, &tWin->clipList); + REGION_EMPTY( pScreen, &tWin->borderClip); + tWin->valdata = NULL; + } + } + } + + REGION_UNINIT(pScreen, &childClip); + + if(!((*pPriv->InOverlay)(newParent))) { + REGION_NULL(pScreen, &tParent->valdata->exposed); + REGION_NULL(pScreen, &tParent->valdata->borderExposed); + } + + switch (kind) { + case VTStack: + break; + default: + if(!((*pPriv->InOverlay)(newParent))) + REGION_SUBTRACT(pScreen, &tParent->valdata->exposed, &totalClip, + &tParent->clipList); + /* fall through */ + case VTMap: + REGION_COPY( pScreen, &tParent->clipList, &totalClip); + if(!((*pPriv->InOverlay)(newParent))) + newParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; + break; + } + + REGION_UNINIT( pScreen, &totalClip); + REGION_UNINIT( pScreen, &exposed); + +SKIP_UNDERLAY: + + miValidateTree(pParent, pChild, kind); + + return 1; +} + + +static void +miOverlayHandleExposures(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + WindowPtr pChild; + ValidatePtr val; + void (* WindowExposures)(WindowPtr, RegionPtr, RegionPtr); + + WindowExposures = pWin->drawable.pScreen->WindowExposures; + if(pPriv->underlayMarked) { + miOverlayTreePtr pTree; + miOverlayValDataPtr mival; + + pChild = pWin; + while(IN_OVERLAY(pChild)) + pChild = pChild->parent; + + pTree = MIOVERLAY_GET_WINDOW_TREE(pChild); + + while (1) { + if((mival = pTree->valdata)) { + if(!((*pPriv->InOverlay)(pTree->pWin))) { + if (REGION_NOTEMPTY(pScreen, &mival->borderExposed)) + (*pWin->drawable.pScreen->PaintWindowBorder)( + pTree->pWin, &mival->borderExposed, PW_BORDER); + REGION_UNINIT(pScreen, &mival->borderExposed); + + (*WindowExposures)(pTree->pWin,&mival->exposed,NullRegion); + REGION_UNINIT(pScreen, &mival->exposed); + } + xfree(mival); + pTree->valdata = NULL; + if (pTree->firstChild) { + pTree = pTree->firstChild; + continue; + } + } + while (!pTree->nextSib && (pTree->pWin != pChild)) + pTree = pTree->parent; + if (pTree->pWin == pChild) + break; + pTree = pTree->nextSib; + } + pPriv->underlayMarked = FALSE; + } + + pChild = pWin; + while (1) { + if ( (val = pChild->valdata) ) { + if(!((*pPriv->InOverlay)(pChild))) { + REGION_UNION(pScreen, &val->after.exposed, &val->after.exposed, + &val->after.borderExposed); + + if (REGION_NOTEMPTY(pScreen, &val->after.exposed)) { + (*(MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent))( + pScreen, + REGION_NUM_RECTS(&val->after.exposed), + REGION_RECTS(&val->after.exposed)); + } + } else { + if (REGION_NOTEMPTY(pScreen, &val->after.borderExposed)) + (*pChild->drawable.pScreen->PaintWindowBorder)(pChild, + &val->after.borderExposed, + PW_BORDER); + (*WindowExposures)(pChild, &val->after.exposed, NullRegion); + } + REGION_UNINIT(pScreen, &val->after.borderExposed); + REGION_UNINIT(pScreen, &val->after.exposed); + xfree(val); + pChild->valdata = (ValidatePtr)NULL; + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } +} + + +static void +miOverlayMoveWindow( + WindowPtr pWin, + int x, + int y, + WindowPtr pNextSib, + VTKind kind +){ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + WindowPtr pParent, windowToValidate; + Bool WasViewable = (Bool)(pWin->viewable); + short bw; + RegionRec overReg, underReg; + DDXPointRec oldpt; +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + + if (!(pParent = pWin->parent)) + return ; + bw = wBorderWidth (pWin); + + oldpt.x = pWin->drawable.x; + oldpt.y = pWin->drawable.y; + if (WasViewable) { + REGION_NULL(pScreen, &overReg); + REGION_NULL(pScreen, &underReg); + if(pTree) { + REGION_COPY(pScreen, &overReg, &pWin->borderClip); + REGION_COPY(pScreen, &underReg, &pTree->borderClip); + } else { + REGION_COPY(pScreen, &overReg, &pWin->borderClip); + CollectUnderlayChildrenRegions(pWin, &underReg); + } + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + } + pWin->origin.x = x + (int)bw; + pWin->origin.y = y + (int)bw; + x = pWin->drawable.x = pParent->drawable.x + x + (int)bw; + y = pWin->drawable.y = pParent->drawable.y + y + (int)bw; + + SetWinSize (pWin); + SetBorderSize (pWin); + + (*pScreen->PositionWindow)(pWin, x, y); + + windowToValidate = MoveWindowInStack(pWin, pNextSib); + + ResizeChildrenWinSize(pWin, x - oldpt.x, y - oldpt.y, 0, 0); + + if (WasViewable) { + miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + (*pScreen->MarkOverlappedWindows) (pWin, windowToValidate, NULL); + +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + dosave = (*pScreen->ChangeSaveUnder)(pWin, windowToValidate); +#endif /* DO_SAVE_UNDERS */ + + (*pScreen->ValidateTree)(pWin->parent, NullWindow, kind); + if(REGION_NOTEMPTY(pScreen, &underReg)) { + pPriv->copyUnderlay = TRUE; + (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, &underReg); + } + REGION_UNINIT(pScreen, &underReg); + if(REGION_NOTEMPTY(pScreen, &overReg)) { + pPriv->copyUnderlay = FALSE; + (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, &overReg); + } + REGION_UNINIT(pScreen, &overReg); + (*pScreen->HandleExposures)(pWin->parent); + +#ifdef DO_SAVE_UNDERS + if (dosave) + (*pScreen->PostChangeSaveUnder)(pWin, windowToValidate); +#endif /* DO_SAVE_UNDERS */ + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin->parent, NullWindow, kind); + } + if (pWin->realized) + WindowsRestructured (); +} + +#ifndef RECTLIMIT +#define RECTLIMIT 25 +#endif + +static void +miOverlayWindowExposures( + WindowPtr pWin, + register RegionPtr prgn, + RegionPtr other_exposed +){ + RegionPtr exposures = prgn; + ScreenPtr pScreen = pWin->drawable.pScreen; + + if (pWin->backStorage && prgn) + exposures = (*pScreen->RestoreAreas)(pWin, prgn); + if ((prgn && !REGION_NIL(prgn)) || + (exposures && !REGION_NIL(exposures)) || other_exposed) + { + RegionRec expRec; + int clientInterested; + + clientInterested = (pWin->eventMask|wOtherEventMasks(pWin)) & + ExposureMask; + if (other_exposed) { + if (exposures) { + REGION_UNION(pScreen, other_exposed, exposures, other_exposed); + if (exposures != prgn) + REGION_DESTROY(pScreen, exposures); + } + exposures = other_exposed; + } + if (clientInterested && exposures && + (REGION_NUM_RECTS(exposures) > RECTLIMIT)) + { + miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + BoxRec box; + + box = *REGION_EXTENTS(pScreen, exposures); + if (exposures == prgn) { + exposures = &expRec; + REGION_INIT(pScreen, exposures, &box, 1); + REGION_RESET(pScreen, prgn, &box); + } else { + REGION_RESET(pScreen, exposures, &box); + REGION_UNION(pScreen, prgn, prgn, exposures); + } + /* This is the only reason why we are replacing mi's version + of this file */ + + if(!((*pPriv->InOverlay)(pWin))) { + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + REGION_INTERSECT(pScreen, prgn, prgn, &pTree->clipList); + } else + REGION_INTERSECT(pScreen, prgn, prgn, &pWin->clipList); + + /* need to clear out new areas of backing store, too */ + if (pWin->backStorage) + (void) (*pScreen->ClearBackingStore)( + pWin, + box.x1 - pWin->drawable.x, + box.y1 - pWin->drawable.y, + box.x2 - box.x1, + box.y2 - box.y1, + FALSE); + } + if (prgn && !REGION_NIL(prgn)) + (*pScreen->PaintWindowBackground)( + pWin, prgn, PW_BACKGROUND); + if (clientInterested && exposures && !REGION_NIL(exposures)) + miSendExposures(pWin, exposures, + pWin->drawable.x, pWin->drawable.y); + if (exposures == &expRec) { + REGION_UNINIT(pScreen, exposures); + } + else if (exposures && exposures != prgn && exposures != other_exposed) + REGION_DESTROY(pScreen, exposures); + if (prgn) + REGION_EMPTY(pScreen, prgn); + } + else if (exposures && exposures != prgn) + REGION_DESTROY(pScreen, exposures); +} + + +typedef struct { + RegionPtr over; + RegionPtr under; +} miOverlayTwoRegions; + +static int +miOverlayRecomputeExposures ( + WindowPtr pWin, + pointer value +){ + register ScreenPtr pScreen; + miOverlayTwoRegions *pValid = (miOverlayTwoRegions*)value; + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + /* This prevents warning about pScreen not being used. */ + pWin->drawable.pScreen = pScreen = pWin->drawable.pScreen; + + if (pWin->valdata) { + /* + * compute exposed regions of this window + */ + REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed, + &pWin->clipList, pValid->over); + /* + * compute exposed regions of the border + */ + REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed, + &pWin->borderClip, &pWin->winSize); + REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed, + &pWin->valdata->after.borderExposed, pValid->over); + } + + if(pTree && pTree->valdata) { + REGION_SUBTRACT(pScreen, &pTree->valdata->exposed, + &pTree->clipList, pValid->under); + REGION_SUBTRACT(pScreen, &pTree->valdata->borderExposed, + &pTree->borderClip, &pWin->winSize); + REGION_SUBTRACT(pScreen, &pTree->valdata->borderExposed, + &pTree->valdata->borderExposed, pValid->under); + } else if (!pWin->valdata) + return WT_NOMATCH; + + return WT_WALKCHILDREN; +} + +static void +miOverlayResizeWindow( + WindowPtr pWin, + int x, int y, + unsigned int w, unsigned int h, + WindowPtr pSib +){ + ScreenPtr pScreen = pWin->drawable.pScreen; + WindowPtr pParent; + miOverlayTreePtr tChild, pTree; + Bool WasViewable = (Bool)(pWin->viewable); + unsigned short width = pWin->drawable.width; + unsigned short height = pWin->drawable.height; + short oldx = pWin->drawable.x; + short oldy = pWin->drawable.y; + int bw = wBorderWidth (pWin); + short dw, dh; + DDXPointRec oldpt; + RegionPtr oldRegion = NULL, oldRegion2 = NULL; + WindowPtr pFirstChange; + register WindowPtr pChild; + RegionPtr gravitate[StaticGravity + 1]; + RegionPtr gravitate2[StaticGravity + 1]; + register unsigned g; + int nx, ny; /* destination x,y */ + int newx, newy; /* new inner window position */ + RegionPtr pRegion = NULL; + RegionPtr destClip, destClip2; + RegionPtr oldWinClip = NULL, oldWinClip2 = NULL; + RegionPtr borderVisible = NullRegion; + RegionPtr borderVisible2 = NullRegion; + RegionPtr bsExposed = NullRegion; /* backing store exposures */ + Bool shrunk = FALSE; /* shrunk in an inner dimension */ + Bool moved = FALSE; /* window position changed */ +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + Bool doUnderlay; + + /* if this is a root window, can't be resized */ + if (!(pParent = pWin->parent)) + return ; + + pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + doUnderlay = ((pTree) || HasUnderlayChildren(pWin)); + newx = pParent->drawable.x + x + bw; + newy = pParent->drawable.y + y + bw; + if (WasViewable) + { + /* + * save the visible region of the window + */ + oldRegion = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldRegion, &pWin->winSize); + if(doUnderlay) { + oldRegion2 = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldRegion2, &pWin->winSize); + } + + /* + * categorize child windows into regions to be moved + */ + for (g = 0; g <= StaticGravity; g++) + gravitate[g] = gravitate2[g] = NULL; + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) { + g = pChild->winGravity; + if (g != UnmapGravity) { + if (!gravitate[g]) + gravitate[g] = REGION_CREATE(pScreen, NullBox, 1); + REGION_UNION(pScreen, gravitate[g], + gravitate[g], &pChild->borderClip); + + if(doUnderlay) { + if (!gravitate2[g]) + gravitate2[g] = REGION_CREATE(pScreen, NullBox, 0); + + if((tChild = MIOVERLAY_GET_WINDOW_TREE(pChild))) { + REGION_UNION(pScreen, gravitate2[g], + gravitate2[g], &tChild->borderClip); + } else + CollectUnderlayChildrenRegions(pChild, gravitate2[g]); + } + } else { + UnmapWindow(pChild, TRUE); + } + } + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + + + oldWinClip = oldWinClip2 = NULL; + if (pWin->bitGravity != ForgetGravity) { + oldWinClip = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldWinClip, &pWin->clipList); + if(pTree) { + oldWinClip2 = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldWinClip2, &pTree->clipList); + } + } + /* + * if the window is changing size, borderExposed + * can't be computed correctly without some help. + */ + if (pWin->drawable.height > h || pWin->drawable.width > w) + shrunk = TRUE; + + if (newx != oldx || newy != oldy) + moved = TRUE; + + if ((pWin->drawable.height != h || pWin->drawable.width != w) && + HasBorder (pWin)) + { + borderVisible = REGION_CREATE(pScreen, NullBox, 1); + if(pTree) + borderVisible2 = REGION_CREATE(pScreen, NullBox, 1); + /* for tiled borders, we punt and draw the whole thing */ + if (pWin->borderIsPixel || !moved) + { + if (shrunk || moved) + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, + &pWin->winSize); + else + REGION_COPY(pScreen, borderVisible, + &pWin->borderClip); + if(pTree) { + if (shrunk || moved) + REGION_SUBTRACT(pScreen, borderVisible, + &pTree->borderClip, + &pWin->winSize); + else + REGION_COPY(pScreen, borderVisible, + &pTree->borderClip); + } + } + } + } + pWin->origin.x = x + bw; + pWin->origin.y = y + bw; + pWin->drawable.height = h; + pWin->drawable.width = w; + + x = pWin->drawable.x = newx; + y = pWin->drawable.y = newy; + + SetWinSize (pWin); + SetBorderSize (pWin); + + dw = (int)w - (int)width; + dh = (int)h - (int)height; + ResizeChildrenWinSize(pWin, x - oldx, y - oldy, dw, dh); + + /* let the hardware adjust background and border pixmaps, if any */ + (*pScreen->PositionWindow)(pWin, x, y); + + pFirstChange = MoveWindowInStack(pWin, pSib); + + if (WasViewable) { + pRegion = REGION_CREATE(pScreen, NullBox, 1); + if (pWin->backStorage) + REGION_COPY(pScreen, pRegion, &pWin->clipList); + + (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, NULL); + + pWin->valdata->before.resized = TRUE; + pWin->valdata->before.borderVisible = borderVisible; + if(pTree) + pTree->valdata->borderVisible = borderVisible2; + +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + dosave = (*pScreen->ChangeSaveUnder)(pWin, pFirstChange); +#endif /* DO_SAVE_UNDERS */ + + (*pScreen->ValidateTree)(pWin->parent, pFirstChange, VTOther); + /* + * the entire window is trashed unless bitGravity + * recovers portions of it + */ + REGION_COPY(pScreen, &pWin->valdata->after.exposed, &pWin->clipList); + if(pTree) + REGION_COPY(pScreen, &pTree->valdata->exposed, &pTree->clipList); + } + + GravityTranslate (x, y, oldx, oldy, dw, dh, pWin->bitGravity, &nx, &ny); + + if (pWin->backStorage && ((pWin->backingStore == Always) || WasViewable)) { + if (!WasViewable) + pRegion = &pWin->clipList; /* a convenient empty region */ + if (pWin->bitGravity == ForgetGravity) + bsExposed = (*pScreen->TranslateBackingStore) + (pWin, 0, 0, NullRegion, oldx, oldy); + else + bsExposed = (*pScreen->TranslateBackingStore) + (pWin, nx - x, ny - y, pRegion, oldx, oldy); + } + + if (WasViewable) { + miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + miOverlayTwoRegions TwoRegions; + + /* avoid the border */ + if (HasBorder (pWin)) { + int offx, offy, dx, dy; + + /* kruft to avoid double translates for each gravity */ + offx = 0; + offy = 0; + for (g = 0; g <= StaticGravity; g++) { + if (!gravitate[g] && !gravitate2[g]) + continue; + + /* align winSize to gravitate[g]. + * winSize is in new coordinates, + * gravitate[g] is still in old coordinates */ + GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny); + + dx = (oldx - nx) - offx; + dy = (oldy - ny) - offy; + if (dx || dy) { + REGION_TRANSLATE(pScreen, &pWin->winSize, dx, dy); + offx += dx; + offy += dy; + } + if(gravitate[g]) + REGION_INTERSECT(pScreen, gravitate[g], gravitate[g], + &pWin->winSize); + if(gravitate2[g]) + REGION_INTERSECT(pScreen, gravitate2[g], gravitate2[g], + &pWin->winSize); + } + /* get winSize back where it belongs */ + if (offx || offy) + REGION_TRANSLATE(pScreen, &pWin->winSize, -offx, -offy); + } + /* + * add screen bits to the appropriate bucket + */ + + if (oldWinClip2) + { + REGION_COPY(pScreen, pRegion, oldWinClip2); + REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy); + REGION_INTERSECT(pScreen, oldWinClip2, pRegion, &pTree->clipList); + + for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) { + if (gravitate2[g]) + REGION_SUBTRACT(pScreen, oldWinClip2, oldWinClip2, + gravitate2[g]); + } + REGION_TRANSLATE(pScreen, oldWinClip2, oldx - nx, oldy - ny); + g = pWin->bitGravity; + if (!gravitate2[g]) + gravitate2[g] = oldWinClip2; + else { + REGION_UNION(pScreen,gravitate2[g],gravitate2[g],oldWinClip2); + REGION_DESTROY(pScreen, oldWinClip2); + } + } + + if (oldWinClip) + { + /* + * clip to new clipList + */ + REGION_COPY(pScreen, pRegion, oldWinClip); + REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy); + REGION_INTERSECT(pScreen, oldWinClip, pRegion, &pWin->clipList); + /* + * don't step on any gravity bits which will be copied after this + * region. Note -- this assumes that the regions will be copied + * in gravity order. + */ + for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) { + if (gravitate[g]) + REGION_SUBTRACT(pScreen, oldWinClip, oldWinClip, + gravitate[g]); + } + REGION_TRANSLATE(pScreen, oldWinClip, oldx - nx, oldy - ny); + g = pWin->bitGravity; + if (!gravitate[g]) + gravitate[g] = oldWinClip; + else { + REGION_UNION(pScreen, gravitate[g], gravitate[g], oldWinClip); + REGION_DESTROY(pScreen, oldWinClip); + } + } + + /* + * move the bits on the screen + */ + + destClip = destClip2 = NULL; + + for (g = 0; g <= StaticGravity; g++) { + if (!gravitate[g] && !gravitate2[g]) + continue; + + GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny); + + oldpt.x = oldx + (x - nx); + oldpt.y = oldy + (y - ny); + + /* Note that gravitate[g] is *translated* by CopyWindow */ + + /* only copy the remaining useful bits */ + + if(gravitate[g]) + REGION_INTERSECT(pScreen, gravitate[g], + gravitate[g], oldRegion); + if(gravitate2[g]) + REGION_INTERSECT(pScreen, gravitate2[g], + gravitate2[g], oldRegion2); + + /* clip to not overwrite already copied areas */ + + if (destClip && gravitate[g]) { + REGION_TRANSLATE(pScreen, destClip, oldpt.x - x, oldpt.y - y); + REGION_SUBTRACT(pScreen, gravitate[g], gravitate[g], destClip); + REGION_TRANSLATE(pScreen, destClip, x - oldpt.x, y - oldpt.y); + } + if (destClip2 && gravitate2[g]) { + REGION_TRANSLATE(pScreen, destClip2, oldpt.x - x, oldpt.y - y); + REGION_SUBTRACT(pScreen,gravitate2[g],gravitate2[g],destClip2); + REGION_TRANSLATE(pScreen, destClip2, x - oldpt.x, y - oldpt.y); + } + + /* and move those bits */ + + if (oldpt.x != x || oldpt.y != y) { + if(gravitate2[g]) { + pPriv->copyUnderlay = TRUE; + (*pWin->drawable.pScreen->CopyWindow)( + pWin, oldpt, gravitate2[g]); + } + if(gravitate[g]) { + pPriv->copyUnderlay = FALSE; + (*pWin->drawable.pScreen->CopyWindow)( + pWin, oldpt, gravitate[g]); + } + } + + /* remove any overwritten bits from the remaining useful bits */ + + if(gravitate[g]) + REGION_SUBTRACT(pScreen, oldRegion, oldRegion, gravitate[g]); + if(gravitate2[g]) + REGION_SUBTRACT(pScreen, oldRegion2, oldRegion2, gravitate2[g]); + + /* + * recompute exposed regions of child windows + */ + + + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) { + if (pChild->winGravity != g) + continue; + + TwoRegions.over = gravitate[g]; + TwoRegions.under = gravitate2[g]; + + TraverseTree (pChild, miOverlayRecomputeExposures, + (pointer)(&TwoRegions)); + } + + /* + * remove the successfully copied regions of the + * window from its exposed region + */ + + if (g == pWin->bitGravity) { + if(gravitate[g]) + REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed, + &pWin->valdata->after.exposed, gravitate[g]); + if(gravitate2[g] && pTree) + REGION_SUBTRACT(pScreen, &pTree->valdata->exposed, + &pTree->valdata->exposed, gravitate2[g]); + } + if(gravitate[g]) { + if (!destClip) + destClip = gravitate[g]; + else { + REGION_UNION(pScreen, destClip, destClip, gravitate[g]); + REGION_DESTROY(pScreen, gravitate[g]); + } + } + if(gravitate2[g]) { + if (!destClip2) + destClip2 = gravitate2[g]; + else { + REGION_UNION(pScreen, destClip2, destClip2, gravitate2[g]); + REGION_DESTROY(pScreen, gravitate2[g]); + } + } + } + + REGION_DESTROY(pScreen, pRegion); + REGION_DESTROY(pScreen, oldRegion); + if(doUnderlay) + REGION_DESTROY(pScreen, oldRegion2); + if (destClip) + REGION_DESTROY(pScreen, destClip); + if (destClip2) + REGION_DESTROY(pScreen, destClip2); + if (bsExposed) { + RegionPtr valExposed = NullRegion; + + if (pWin->valdata) + valExposed = &pWin->valdata->after.exposed; + (*pScreen->WindowExposures) (pWin, valExposed, bsExposed); + if (valExposed) + REGION_EMPTY(pScreen, valExposed); + REGION_DESTROY(pScreen, bsExposed); + } + (*pScreen->HandleExposures)(pWin->parent); +#ifdef DO_SAVE_UNDERS + if (dosave) + (*pScreen->PostChangeSaveUnder)(pWin, pFirstChange); +#endif /* DO_SAVE_UNDERS */ + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin->parent, pFirstChange, VTOther); + } + else if (bsExposed) { + (*pScreen->WindowExposures) (pWin, NullRegion, bsExposed); + REGION_DESTROY(pScreen, bsExposed); + } + if (pWin->realized) + WindowsRestructured (); +} + + +#ifdef SHAPE +static void +miOverlaySetShape(WindowPtr pWin) +{ + Bool WasViewable = (Bool)(pWin->viewable); + ScreenPtr pScreen = pWin->drawable.pScreen; + RegionPtr pOldClip = NULL, bsExposed; +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + + if (WasViewable) { + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + + if (HasBorder (pWin)) { + RegionPtr borderVisible; + + borderVisible = REGION_CREATE(pScreen, NullBox, 1); + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + pWin->valdata->before.resized = TRUE; + if(IN_UNDERLAY(pWin)) { + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + RegionPtr borderVisible2; + + borderVisible2 = REGION_CREATE(pScreen, NULL, 1); + REGION_SUBTRACT(pScreen, borderVisible2, + &pTree->borderClip, &pWin->winSize); + pTree->valdata->borderVisible = borderVisible2; + } + } + } + + SetWinSize (pWin); + SetBorderSize (pWin); + + ResizeChildrenWinSize(pWin, 0, 0, 0, 0); + + if (WasViewable) { + if (pWin->backStorage) { + pOldClip = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, pOldClip, &pWin->clipList); + } + + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + dosave = (*pScreen->ChangeSaveUnder)(pWin, pWin); +#endif /* DO_SAVE_UNDERS */ + + (*pScreen->ValidateTree)(pWin->parent, NullWindow, VTOther); + } + + if (pWin->backStorage && ((pWin->backingStore == Always) || WasViewable)) { + if (!WasViewable) + pOldClip = &pWin->clipList; /* a convenient empty region */ + bsExposed = (*pScreen->TranslateBackingStore) + (pWin, 0, 0, pOldClip, + pWin->drawable.x, pWin->drawable.y); + if (WasViewable) + REGION_DESTROY(pScreen, pOldClip); + if (bsExposed) + { + RegionPtr valExposed = NullRegion; + + if (pWin->valdata) + valExposed = &pWin->valdata->after.exposed; + (*pScreen->WindowExposures) (pWin, valExposed, bsExposed); + if (valExposed) + REGION_EMPTY(pScreen, valExposed); + REGION_DESTROY(pScreen, bsExposed); + } + } + if (WasViewable) { + (*pScreen->HandleExposures)(pWin->parent); +#ifdef DO_SAVE_UNDERS + if (dosave) + (*pScreen->PostChangeSaveUnder)(pWin, pWin); +#endif /* DO_SAVE_UNDERS */ + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin->parent, NullWindow, VTOther); + } + if (pWin->realized) + WindowsRestructured (); + CheckCursorConfinement(pWin); +} +#endif + + + +static void +miOverlayChangeBorderWidth( + WindowPtr pWin, + unsigned int width +){ + int oldwidth; + register ScreenPtr pScreen; + Bool WasViewable = (Bool)(pWin->viewable); + Bool HadBorder; +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + + oldwidth = wBorderWidth (pWin); + if (oldwidth == width) + return; + HadBorder = HasBorder(pWin); + pScreen = pWin->drawable.pScreen; + if (WasViewable && (width < oldwidth)) + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + + pWin->borderWidth = width; + SetBorderSize (pWin); + + if (WasViewable) { + if (width > oldwidth) { + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + + if (HadBorder) { + RegionPtr borderVisible; + borderVisible = REGION_CREATE(pScreen, NULL, 1); + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + if(IN_UNDERLAY(pWin)) { + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + RegionPtr borderVisible2; + + borderVisible2 = REGION_CREATE(pScreen, NULL, 1); + REGION_SUBTRACT(pScreen, borderVisible2, + &pTree->borderClip, &pWin->winSize); + pTree->valdata->borderVisible = borderVisible2; + } + } + } +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + dosave = (*pScreen->ChangeSaveUnder)(pWin, pWin->nextSib); +#endif /* DO_SAVE_UNDERS */ + (*pScreen->ValidateTree)(pWin->parent, pWin, VTOther); + (*pScreen->HandleExposures)(pWin->parent); + +#ifdef DO_SAVE_UNDERS + if (dosave) + (*pScreen->PostChangeSaveUnder)(pWin, pWin->nextSib); +#endif /* DO_SAVE_UNDERS */ + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin->parent, pWin, VTOther); + } + if (pWin->realized) + WindowsRestructured (); +} + +/* We need this as an addition since the xf86 common code doesn't + know about the second tree which is static to this file. */ + +_X_EXPORT void +miOverlaySetRootClip(ScreenPtr pScreen, Bool enable) +{ + WindowPtr pRoot = WindowTable[pScreen->myNum]; + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pRoot); + + MARK_UNDERLAY(pRoot); + + if(enable) { + BoxRec box; + + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + + REGION_RESET(pScreen, &pTree->borderClip, &box); + } else + REGION_EMPTY(pScreen, &pTree->borderClip); + + REGION_BREAK(pScreen, &pTree->clipList); +} + +static void +miOverlayClearToBackground( + WindowPtr pWin, + int x, int y, + int w, int h, + Bool generateExposures +) +{ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + BoxRec box; + RegionRec reg; + RegionPtr pBSReg = NullRegion; + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + RegionPtr clipList; + BoxPtr extents; + int x1, y1, x2, y2; + + x1 = pWin->drawable.x + x; + y1 = pWin->drawable.y + y; + if (w) + x2 = x1 + (int) w; + else + x2 = x1 + (int) pWin->drawable.width - (int) x; + if (h) + y2 = y1 + h; + else + y2 = y1 + (int) pWin->drawable.height - (int) y; + + clipList = ((*pScreenPriv->InOverlay)(pWin)) ? &pWin->clipList : + &pTree->clipList; + + extents = REGION_EXTENTS(pScreen, clipList); + + if (x1 < extents->x1) x1 = extents->x1; + if (x2 > extents->x2) x2 = extents->x2; + if (y1 < extents->y1) y1 = extents->y1; + if (y2 > extents->y2) y2 = extents->y2; + + if (x2 <= x1 || y2 <= y1) + x2 = x1 = y2 = y1 = 0; + + box.x1 = x1; box.x2 = x2; + box.y1 = y1; box.y2 = y2; + + REGION_INIT(pScreen, ®, &box, 1); + if (pWin->backStorage) { + pBSReg = (* pScreen->ClearBackingStore)(pWin, x, y, w, h, + generateExposures); + } + + REGION_INTERSECT(pScreen, ®, ®, clipList); + if (generateExposures) + (*pScreen->WindowExposures)(pWin, ®, pBSReg); + else if (pWin->backgroundState != None) + (*pScreen->PaintWindowBackground)(pWin, ®, PW_BACKGROUND); + REGION_UNINIT(pScreen, ®); + if (pBSReg) + REGION_DESTROY(pScreen, pBSReg); +} + + +/****************************************************************/ + +/* not used */ +_X_EXPORT Bool +miOverlayGetPrivateClips( + WindowPtr pWin, + RegionPtr *borderClip, + RegionPtr *clipList +){ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + if(pTree) { + *borderClip = &(pTree->borderClip); + *clipList = &(pTree->clipList); + return TRUE; + } + + *borderClip = *clipList = NULL; + + return FALSE; +} + +_X_EXPORT void +miOverlaySetTransFunction ( + ScreenPtr pScreen, + miOverlayTransFunc transFunc +){ + MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent = transFunc; +} + +_X_EXPORT Bool +miOverlayCopyUnderlay(ScreenPtr pScreen) +{ + return MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->copyUnderlay; +} + +_X_EXPORT void +miOverlayComputeCompositeClip(GCPtr pGC, WindowPtr pWin) +{ + ScreenPtr pScreen = pGC->pScreen; + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + RegionPtr pregWin; + Bool freeTmpClip, freeCompClip; + + if(!pTree) { + miComputeCompositeClip(pGC, &pWin->drawable); + return; + } + + if (pGC->subWindowMode == IncludeInferiors) { + pregWin = REGION_CREATE(pScreen, NullBox, 1); + freeTmpClip = TRUE; + if (pWin->parent || (screenIsSaved != SCREEN_SAVER_ON) || + !HasSaverWindow (pScreen->myNum)) + { + REGION_INTERSECT(pScreen,pregWin,&pTree->borderClip,&pWin->winSize); + } + } else { + pregWin = &pTree->clipList; + freeTmpClip = FALSE; + } + freeCompClip = pGC->freeCompClip; + if (pGC->clientClipType == CT_NONE) { + if (freeCompClip) + REGION_DESTROY(pScreen, pGC->pCompositeClip); + pGC->pCompositeClip = pregWin; + pGC->freeCompClip = freeTmpClip; + } else { + REGION_TRANSLATE(pScreen, pGC->clientClip, + pWin->drawable.x + pGC->clipOrg.x, + pWin->drawable.y + pGC->clipOrg.y); + + if (freeCompClip) { + REGION_INTERSECT(pGC->pScreen, pGC->pCompositeClip, + pregWin, pGC->clientClip); + if (freeTmpClip) + REGION_DESTROY(pScreen, pregWin); + } else if (freeTmpClip) { + REGION_INTERSECT(pScreen, pregWin, pregWin, pGC->clientClip); + pGC->pCompositeClip = pregWin; + } else { + pGC->pCompositeClip = REGION_CREATE(pScreen, NullBox, 0); + REGION_INTERSECT(pScreen, pGC->pCompositeClip, + pregWin, pGC->clientClip); + } + pGC->freeCompClip = TRUE; + REGION_TRANSLATE(pScreen, pGC->clientClip, + -(pWin->drawable.x + pGC->clipOrg.x), + -(pWin->drawable.y + pGC->clipOrg.y)); + } +} + +_X_EXPORT Bool +miOverlayCollectUnderlayRegions( + WindowPtr pWin, + RegionPtr *region +){ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + if(pTree) { + *region = &pTree->borderClip; + return FALSE; + } + + *region = REGION_CREATE(pWin->drawable.pScreen, NullBox, 0); + + CollectUnderlayChildrenRegions(pWin, *region); + + return TRUE; +} + + +static miOverlayTreePtr +DoLeaf( + WindowPtr pWin, + miOverlayTreePtr parent, + miOverlayTreePtr prevSib +){ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + pTree->parent = parent; + pTree->firstChild = NULL; + pTree->lastChild = NULL; + pTree->prevSib = prevSib; + pTree->nextSib = NULL; + + if(prevSib) + prevSib->nextSib = pTree; + + if(!parent->firstChild) + parent->firstChild = parent->lastChild = pTree; + else if(parent->lastChild == prevSib) + parent->lastChild = pTree; + + return pTree; +} + +static void +RebuildTree(WindowPtr pWin) +{ + miOverlayTreePtr parent, prevSib, tChild; + WindowPtr pChild; + + prevSib = tChild = NULL; + + pWin = pWin->parent; + + while(IN_OVERLAY(pWin)) + pWin = pWin->parent; + + parent = MIOVERLAY_GET_WINDOW_TREE(pWin); + + pChild = pWin->firstChild; + parent->firstChild = parent->lastChild = NULL; + + while(1) { + if(IN_UNDERLAY(pChild)) + prevSib = tChild = DoLeaf(pChild, parent, prevSib); + + if(pChild->firstChild) { + if(IN_UNDERLAY(pChild)) { + parent = tChild; + prevSib = NULL; + } + pChild = pChild->firstChild; + continue; + } + + while(!pChild->nextSib) { + pChild = pChild->parent; + if(pChild == pWin) return; + if(IN_UNDERLAY(pChild)) { + prevSib = tChild = MIOVERLAY_GET_WINDOW_TREE(pChild); + parent = tChild->parent; + } + } + + pChild = pChild->nextSib; + } +} + + +static Bool +HasUnderlayChildren(WindowPtr pWin) +{ + WindowPtr pChild; + + if(!(pChild = pWin->firstChild)) + return FALSE; + + while(1) { + if(IN_UNDERLAY(pChild)) + return TRUE; + + if(pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + + while(!pChild->nextSib && (pWin != pChild)) + pChild = pChild->parent; + + if(pChild == pWin) break; + + pChild = pChild->nextSib; + } + + return FALSE; +} + + +static Bool +CollectUnderlayChildrenRegions(WindowPtr pWin, RegionPtr pReg) +{ + WindowPtr pChild; + miOverlayTreePtr pTree; + Bool hasUnderlay; + + if(!(pChild = pWin->firstChild)) + return FALSE; + + hasUnderlay = FALSE; + + while(1) { + if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) { + REGION_APPEND(pScreen, pReg, &pTree->borderClip); + hasUnderlay = TRUE; + } else + if(pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + + while(!pChild->nextSib && (pWin != pChild)) + pChild = pChild->parent; + + if(pChild == pWin) break; + + pChild = pChild->nextSib; + } + + if(hasUnderlay) { + Bool overlap; + REGION_VALIDATE(pScreen, pReg, &overlap); + } + + return hasUnderlay; +} + + +static void +MarkUnderlayWindow(WindowPtr pWin) +{ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + if(pTree->valdata) return; + pTree->valdata = (miOverlayValDataPtr)xnfalloc(sizeof(miOverlayValDataRec)); + pTree->valdata->oldAbsCorner.x = pWin->drawable.x; + pTree->valdata->oldAbsCorner.y = pWin->drawable.y; + pTree->valdata->borderVisible = NullRegion; +} diff --git a/xserver/mi/mioverlay.h b/xserver/mi/mioverlay.h new file mode 100644 index 000000000..24b74f51c --- /dev/null +++ b/xserver/mi/mioverlay.h @@ -0,0 +1,32 @@ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifndef __MIOVERLAY_H +#define __MIOVERLAY_H + +typedef void (*miOverlayTransFunc)(ScreenPtr, int, BoxPtr); +typedef Bool (*miOverlayInOverlayFunc)(WindowPtr); + +Bool +miInitOverlay( + ScreenPtr pScreen, + miOverlayInOverlayFunc inOverlay, + miOverlayTransFunc trans +); + +Bool +miOverlayGetPrivateClips( + WindowPtr pWin, + RegionPtr *borderClip, + RegionPtr *clipList +); + +Bool miOverlayCollectUnderlayRegions(WindowPtr, RegionPtr*); +void miOverlayComputeCompositeClip(GCPtr, WindowPtr); +Bool miOverlayCopyUnderlay(ScreenPtr); +void miOverlaySetTransFunction(ScreenPtr, miOverlayTransFunc); +void miOverlaySetRootClip(ScreenPtr, Bool); + +#endif /* __MIOVERLAY_H */ diff --git a/xserver/mi/mipointer.c b/xserver/mi/mipointer.c new file mode 100644 index 000000000..1715965fa --- /dev/null +++ b/xserver/mi/mipointer.c @@ -0,0 +1,529 @@ +/* + * mipointer.c + */ + + +/* + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +# define NEED_EVENTS +# include <X11/X.h> +# include <X11/Xmd.h> +# include <X11/Xproto.h> +# include "misc.h" +# include "windowstr.h" +# include "pixmapstr.h" +# include "mi.h" +# include "scrnintstr.h" +# include "mipointrst.h" +# include "cursorstr.h" +# include "dixstruct.h" + +_X_EXPORT int miPointerScreenIndex; +static unsigned long miPointerGeneration = 0; + +#define GetScreenPrivate(s) ((miPointerScreenPtr) ((s)->devPrivates[miPointerScreenIndex].ptr)) +#define SetupScreen(s) miPointerScreenPtr pScreenPriv = GetScreenPrivate(s) + +/* + * until more than one pointer device exists. + */ + +static miPointerRec miPointer; + +static Bool miPointerRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); +static Bool miPointerUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); +static Bool miPointerDisplayCursor(ScreenPtr pScreen, CursorPtr pCursor); +static void miPointerConstrainCursor(ScreenPtr pScreen, BoxPtr pBox); +static void miPointerPointerNonInterestBox(ScreenPtr pScreen, BoxPtr pBox); +static void miPointerCursorLimits(ScreenPtr pScreen, CursorPtr pCursor, + BoxPtr pHotBox, BoxPtr pTopLeftBox); +static Bool miPointerSetCursorPosition(ScreenPtr pScreen, int x, int y, + Bool generateEvent); +static Bool miPointerCloseScreen(int index, ScreenPtr pScreen); +static void miPointerMove(ScreenPtr pScreen, int x, int y, unsigned long time); + +_X_EXPORT Bool +miPointerInitialize (pScreen, spriteFuncs, screenFuncs, waitForUpdate) + ScreenPtr pScreen; + miPointerSpriteFuncPtr spriteFuncs; + miPointerScreenFuncPtr screenFuncs; + Bool waitForUpdate; +{ + miPointerScreenPtr pScreenPriv; + + if (miPointerGeneration != serverGeneration) + { + miPointerScreenIndex = AllocateScreenPrivateIndex(); + if (miPointerScreenIndex < 0) + return FALSE; + miPointerGeneration = serverGeneration; + } + pScreenPriv = (miPointerScreenPtr) xalloc (sizeof (miPointerScreenRec)); + if (!pScreenPriv) + return FALSE; + pScreenPriv->spriteFuncs = spriteFuncs; + pScreenPriv->screenFuncs = screenFuncs; + /* + * check for uninitialized methods + */ + if (!screenFuncs->EnqueueEvent) + screenFuncs->EnqueueEvent = mieqEnqueue; + if (!screenFuncs->NewEventScreen) + screenFuncs->NewEventScreen = mieqSwitchScreen; + pScreenPriv->waitForUpdate = waitForUpdate; + pScreenPriv->showTransparent = FALSE; + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = miPointerCloseScreen; + pScreen->devPrivates[miPointerScreenIndex].ptr = (pointer) pScreenPriv; + /* + * set up screen cursor method table + */ + pScreen->ConstrainCursor = miPointerConstrainCursor; + pScreen->CursorLimits = miPointerCursorLimits; + pScreen->DisplayCursor = miPointerDisplayCursor; + pScreen->RealizeCursor = miPointerRealizeCursor; + pScreen->UnrealizeCursor = miPointerUnrealizeCursor; + pScreen->SetCursorPosition = miPointerSetCursorPosition; + pScreen->RecolorCursor = miRecolorCursor; + pScreen->PointerNonInterestBox = miPointerPointerNonInterestBox; + /* + * set up the pointer object + */ + miPointer.pScreen = NULL; + miPointer.pSpriteScreen = NULL; + miPointer.pCursor = NULL; + miPointer.pSpriteCursor = NULL; + miPointer.limits.x1 = 0; + miPointer.limits.x2 = 32767; + miPointer.limits.y1 = 0; + miPointer.limits.y2 = 32767; + miPointer.confined = FALSE; + miPointer.x = 0; + miPointer.y = 0; + miPointer.history_start = miPointer.history_end = 0; + return TRUE; +} + +static Bool +miPointerCloseScreen (index, pScreen) + int index; + ScreenPtr pScreen; +{ + SetupScreen(pScreen); + + if (pScreen == miPointer.pScreen) + miPointer.pScreen = 0; + if (pScreen == miPointer.pSpriteScreen) + miPointer.pSpriteScreen = 0; + pScreen->CloseScreen = pScreenPriv->CloseScreen; + xfree ((pointer) pScreenPriv); + return (*pScreen->CloseScreen) (index, pScreen); +} + +/* + * DIX/DDX interface routines + */ + +static Bool +miPointerRealizeCursor (pScreen, pCursor) + ScreenPtr pScreen; + CursorPtr pCursor; +{ + SetupScreen(pScreen); + + return (*pScreenPriv->spriteFuncs->RealizeCursor) (pScreen, pCursor); +} + +static Bool +miPointerUnrealizeCursor (pScreen, pCursor) + ScreenPtr pScreen; + CursorPtr pCursor; +{ + SetupScreen(pScreen); + + return (*pScreenPriv->spriteFuncs->UnrealizeCursor) (pScreen, pCursor); +} + +static Bool +miPointerDisplayCursor (pScreen, pCursor) + ScreenPtr pScreen; + CursorPtr pCursor; +{ + miPointer.pCursor = pCursor; + miPointer.pScreen = pScreen; + miPointerUpdate (); + return TRUE; +} + +static void +miPointerConstrainCursor (pScreen, pBox) + ScreenPtr pScreen; + BoxPtr pBox; +{ + miPointer.limits = *pBox; + miPointer.confined = PointerConfinedToScreen(); +} + +/*ARGSUSED*/ +static void +miPointerPointerNonInterestBox (pScreen, pBox) + ScreenPtr pScreen; + BoxPtr pBox; +{ + /* until DIX uses this, this will remain a stub */ +} + +/*ARGSUSED*/ +static void +miPointerCursorLimits(pScreen, pCursor, pHotBox, pTopLeftBox) + ScreenPtr pScreen; + CursorPtr pCursor; + BoxPtr pHotBox; + BoxPtr pTopLeftBox; +{ + *pTopLeftBox = *pHotBox; +} + +static Bool GenerateEvent; + +static Bool +miPointerSetCursorPosition(pScreen, x, y, generateEvent) + ScreenPtr pScreen; + int x, y; + Bool generateEvent; +{ + SetupScreen (pScreen); + + GenerateEvent = generateEvent; + /* device dependent - must pend signal and call miPointerWarpCursor */ + (*pScreenPriv->screenFuncs->WarpCursor) (pScreen, x, y); + if (!generateEvent) + miPointerUpdate(); + return TRUE; +} + +/* Once signals are ignored, the WarpCursor function can call this */ + +_X_EXPORT void +miPointerWarpCursor (pScreen, x, y) + ScreenPtr pScreen; + int x, y; +{ + SetupScreen (pScreen); + + if (miPointer.pScreen != pScreen) + (*pScreenPriv->screenFuncs->NewEventScreen) (pScreen, TRUE); + + if (GenerateEvent) + { + miPointerMove (pScreen, x, y, GetTimeInMillis()); + } + else + { + /* everything from miPointerMove except the event and history */ + + if (!pScreenPriv->waitForUpdate && pScreen == miPointer.pSpriteScreen) + { + miPointer.devx = x; + miPointer.devy = y; + if(!miPointer.pCursor->bits->emptyMask) + (*pScreenPriv->spriteFuncs->MoveCursor) (pScreen, x, y); + } + miPointer.x = x; + miPointer.y = y; + miPointer.pScreen = pScreen; + } +} + +/* + * Pointer/CursorDisplay interface routines + */ + +_X_EXPORT int +miPointerGetMotionBufferSize () +{ + return MOTION_SIZE; +} + +_X_EXPORT int +miPointerGetMotionEvents (pPtr, coords, start, stop, pScreen) + DeviceIntPtr pPtr; + xTimecoord *coords; + unsigned long start, stop; + ScreenPtr pScreen; +{ + int i; + int count = 0; + miHistoryPtr h; + + for (i = miPointer.history_start; i != miPointer.history_end;) + { + h = &miPointer.history[i]; + if (h->event.time >= stop) + break; + if (h->event.time >= start) + { + *coords++ = h->event; + count++; + } + if (++i == MOTION_SIZE) i = 0; + } + return count; +} + + +/* + * miPointerUpdate + * + * Syncronize the sprite with the cursor - called from ProcessInputEvents + */ + +void +miPointerUpdate () +{ + ScreenPtr pScreen; + miPointerScreenPtr pScreenPriv; + CursorPtr pCursor; + int x, y, devx, devy; + + pScreen = miPointer.pScreen; + x = miPointer.x; + y = miPointer.y; + devx = miPointer.devx; + devy = miPointer.devy; + if (!pScreen) + return; + pScreenPriv = GetScreenPrivate (pScreen); + /* + * if the cursor has switched screens, disable the sprite + * on the old screen + */ + if (pScreen != miPointer.pSpriteScreen) + { + if (miPointer.pSpriteScreen) + { + miPointerScreenPtr pOldPriv; + + pOldPriv = GetScreenPrivate (miPointer.pSpriteScreen); + if (miPointer.pCursor) + { + (*pOldPriv->spriteFuncs->SetCursor) + (miPointer.pSpriteScreen, NullCursor, 0, 0); + } + (*pOldPriv->screenFuncs->CrossScreen) (miPointer.pSpriteScreen, FALSE); + } + (*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE); + (*pScreenPriv->spriteFuncs->SetCursor) + (pScreen, miPointer.pCursor, x, y); + miPointer.devx = x; + miPointer.devy = y; + miPointer.pSpriteCursor = miPointer.pCursor; + miPointer.pSpriteScreen = pScreen; + } + /* + * if the cursor has changed, display the new one + */ + else if (miPointer.pCursor != miPointer.pSpriteCursor) + { + pCursor = miPointer.pCursor; + if (pCursor->bits->emptyMask && !pScreenPriv->showTransparent) + pCursor = NullCursor; + (*pScreenPriv->spriteFuncs->SetCursor) (pScreen, pCursor, x, y); + + miPointer.devx = x; + miPointer.devy = y; + miPointer.pSpriteCursor = miPointer.pCursor; + } + else if (x != devx || y != devy) + { + miPointer.devx = x; + miPointer.devy = y; + if(!miPointer.pCursor->bits->emptyMask) + (*pScreenPriv->spriteFuncs->MoveCursor) (pScreen, x, y); + } +} + +/* + * miPointerDeltaCursor. The pointer has moved dx,dy from it's previous + * position. + */ + +void +miPointerDeltaCursor (dx, dy, time) + int dx, dy; + unsigned long time; +{ + miPointerAbsoluteCursor (miPointer.x + dx, miPointer.y + dy, time); +} + +void +miPointerSetNewScreen(int screen_no, int x, int y) +{ + miPointerScreenPtr pScreenPriv; + ScreenPtr pScreen; + + pScreen = screenInfo.screens[screen_no]; + pScreenPriv = GetScreenPrivate (pScreen); + (*pScreenPriv->screenFuncs->NewEventScreen) (pScreen, FALSE); + NewCurrentScreen (pScreen, x, y); + miPointer.limits.x2 = pScreen->width; + miPointer.limits.y2 = pScreen->height; +} + +_X_EXPORT ScreenPtr +miPointerCurrentScreen () +{ + return (miPointer.pScreen); +} + +/* + * miPointerAbsoluteCursor. The pointer has moved to x,y + */ + +_X_EXPORT void +miPointerAbsoluteCursor (x, y, time) + int x, y; + unsigned long time; +{ + miPointerScreenPtr pScreenPriv; + ScreenPtr pScreen; + ScreenPtr newScreen; + + pScreen = miPointer.pScreen; + if (!pScreen) + return; /* called before ready */ + if (x < 0 || x >= pScreen->width || y < 0 || y >= pScreen->height) + { + pScreenPriv = GetScreenPrivate (pScreen); + if (!miPointer.confined) + { + newScreen = pScreen; + (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, &x, &y); + if (newScreen != pScreen) + { + pScreen = newScreen; + (*pScreenPriv->screenFuncs->NewEventScreen) (pScreen, FALSE); + pScreenPriv = GetScreenPrivate (pScreen); + /* Smash the confine to the new screen */ + miPointer.limits.x2 = pScreen->width; + miPointer.limits.y2 = pScreen->height; + } + } + } + /* + * constrain the hot-spot to the current + * limits + */ + if (x < miPointer.limits.x1) + x = miPointer.limits.x1; + if (x >= miPointer.limits.x2) + x = miPointer.limits.x2 - 1; + if (y < miPointer.limits.y1) + y = miPointer.limits.y1; + if (y >= miPointer.limits.y2) + y = miPointer.limits.y2 - 1; + if (miPointer.x == x && miPointer.y == y && miPointer.pScreen == pScreen) + return; + miPointerMove (pScreen, x, y, time); +} + +_X_EXPORT void +miPointerPosition (x, y) + int *x, *y; +{ + *x = miPointer.x; + *y = miPointer.y; +} + +/* + * miPointerMove. The pointer has moved to x,y on current screen + */ + +static void +miPointerMove (pScreen, x, y, time) + ScreenPtr pScreen; + int x, y; + unsigned long time; +{ + SetupScreen(pScreen); + xEvent xE; + miHistoryPtr history; + int prev, end, start; + + if (!pScreenPriv->waitForUpdate && pScreen == miPointer.pSpriteScreen) + { + miPointer.devx = x; + miPointer.devy = y; + if(!miPointer.pCursor->bits->emptyMask) + (*pScreenPriv->spriteFuncs->MoveCursor) (pScreen, x, y); + } + miPointer.x = x; + miPointer.y = y; + miPointer.pScreen = pScreen; + + xE.u.u.type = MotionNotify; + xE.u.keyButtonPointer.rootX = x; + xE.u.keyButtonPointer.rootY = y; + xE.u.keyButtonPointer.time = time; + (*pScreenPriv->screenFuncs->EnqueueEvent) (&xE); + + end = miPointer.history_end; + start = miPointer.history_start; + prev = end - 1; + if (end == 0) + prev = MOTION_SIZE - 1; + history = &miPointer.history[prev]; + if (end == start || history->event.time != time) + { + history = &miPointer.history[end]; + if (++end == MOTION_SIZE) + end = 0; + if (end == start) + { + start = end + 1; + if (start == MOTION_SIZE) + start = 0; + miPointer.history_start = start; + } + miPointer.history_end = end; + } + history->event.x = x; + history->event.y = y; + history->event.time = time; + history->pScreen = pScreen; +} + +void +miRegisterPointerDevice (pScreen, pDevice) + ScreenPtr pScreen; + DeviceIntPtr pDevice; +{ + miPointer.pPointer = (DevicePtr)pDevice; +} diff --git a/xserver/mi/mipointer.h b/xserver/mi/mipointer.h new file mode 100644 index 000000000..aae38377c --- /dev/null +++ b/xserver/mi/mipointer.h @@ -0,0 +1,151 @@ +/* + * mipointer.h + * + */ + + +/* + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. +*/ + +#ifndef MIPOINTER_H +#define MIPOINTER_H + +#include "cursor.h" +#include "input.h" + +typedef struct _miPointerSpriteFuncRec { + Bool (*RealizeCursor)( + ScreenPtr /* pScr */, + CursorPtr /* pCurs */ + ); + Bool (*UnrealizeCursor)( + ScreenPtr /* pScr */, + CursorPtr /* pCurs */ + ); + void (*SetCursor)( + ScreenPtr /* pScr */, + CursorPtr /* pCurs */, + int /* x */, + int /* y */ + ); + void (*MoveCursor)( + ScreenPtr /* pScr */, + int /* x */, + int /* y */ + ); +} miPointerSpriteFuncRec, *miPointerSpriteFuncPtr; + +typedef struct _miPointerScreenFuncRec { + Bool (*CursorOffScreen)( + ScreenPtr* /* ppScr */, + int* /* px */, + int* /* py */ + ); + void (*CrossScreen)( + ScreenPtr /* pScr */, + int /* entering */ + ); + void (*WarpCursor)( + ScreenPtr /* pScr */, + int /* x */, + int /* y */ + ); + void (*EnqueueEvent)( + xEventPtr /* event */ + ); + void (*NewEventScreen)( + ScreenPtr /* pScr */, + Bool /* fromDIX */ + ); +} miPointerScreenFuncRec, *miPointerScreenFuncPtr; + +extern Bool miDCInitialize( + ScreenPtr /*pScreen*/, + miPointerScreenFuncPtr /*screenFuncs*/ +); + +extern Bool miPointerInitialize( + ScreenPtr /*pScreen*/, + miPointerSpriteFuncPtr /*spriteFuncs*/, + miPointerScreenFuncPtr /*screenFuncs*/, + Bool /*waitForUpdate*/ +); + +extern void miPointerWarpCursor( + ScreenPtr /*pScreen*/, + int /*x*/, + int /*y*/ +); + +extern int miPointerGetMotionBufferSize( + void +); + +extern int miPointerGetMotionEvents( + DeviceIntPtr /*pPtr*/, + xTimecoord * /*coords*/, + unsigned long /*start*/, + unsigned long /*stop*/, + ScreenPtr /*pScreen*/ +); + +extern void miPointerUpdate( + void +); + +extern void miPointerDeltaCursor( + int /*dx*/, + int /*dy*/, + unsigned long /*time*/ +); + +extern void miPointerAbsoluteCursor( + int /*x*/, + int /*y*/, + unsigned long /*time*/ +); + +extern void miPointerPosition( + int * /*x*/, + int * /*y*/ +); + +extern void miPointerSetNewScreen( + int, /*screen_no*/ + int, /*x*/ + int /*y*/ +); +extern ScreenPtr miPointerCurrentScreen( + void +); + +extern void miRegisterPointerDevice( + ScreenPtr /*pScreen*/, + DeviceIntPtr /*pDevice*/ +); + +extern int miPointerScreenIndex; + +#endif /* MIPOINTER_H */ diff --git a/xserver/mi/mipointrst.h b/xserver/mi/mipointrst.h new file mode 100644 index 000000000..f1fbfe4f9 --- /dev/null +++ b/xserver/mi/mipointrst.h @@ -0,0 +1,62 @@ +/* + * mipointrst.h + * + */ + + +/* + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. +*/ + +#include "mipointer.h" +#include "scrnintstr.h" + +#define MOTION_SIZE 256 + +typedef struct { + xTimecoord event; + ScreenPtr pScreen; +} miHistoryRec, *miHistoryPtr; + +typedef struct { + ScreenPtr pScreen; /* current screen */ + ScreenPtr pSpriteScreen;/* screen containing current sprite */ + CursorPtr pCursor; /* current cursor */ + CursorPtr pSpriteCursor;/* cursor on screen */ + BoxRec limits; /* current constraints */ + Bool confined; /* pointer can't change screens */ + int x, y; /* hot spot location */ + int devx, devy; /* sprite position */ + DevicePtr pPointer; /* pointer device structure */ + miHistoryRec history[MOTION_SIZE]; + int history_start, history_end; +} miPointerRec, *miPointerPtr; + +typedef struct { + miPointerSpriteFuncPtr spriteFuncs; /* sprite-specific methods */ + miPointerScreenFuncPtr screenFuncs; /* screen-specific methods */ + CloseScreenProcPtr CloseScreen; + Bool waitForUpdate; /* don't move cursor in SIGIO */ + Bool showTransparent; /* show empty cursors */ +} miPointerScreenRec, *miPointerScreenPtr; diff --git a/xserver/mi/mipoly.c b/xserver/mi/mipoly.c new file mode 100644 index 000000000..b514b5ed2 --- /dev/null +++ b/xserver/mi/mipoly.c @@ -0,0 +1,128 @@ +/* $XFree86$ */ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +/* + * mipoly.c + * + * Written by Brian Kelleher; June 1986 + * + * Draw polygons. This routine translates the point by the + * origin if pGC->miTranslate is non-zero, and calls + * to the appropriate routine to actually scan convert the + * polygon. + */ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include "windowstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "mi.h" +#include "regionstr.h" + + +_X_EXPORT void +miFillPolygon(dst, pgc, shape, mode, count, pPts) + DrawablePtr dst; + register GCPtr pgc; + int shape, mode; + register int count; + DDXPointPtr pPts; +{ + int i; + register int xorg, yorg; + register DDXPointPtr ppt; + + if (count == 0) + return; + + ppt = pPts; + if (pgc->miTranslate) + { + xorg = dst->x; + yorg = dst->y; + + if (mode == CoordModeOrigin) + { + for (i = 0; i<count; i++) + { + ppt->x += xorg; + ppt++->y += yorg; + } + } + else + { + ppt->x += xorg; + ppt++->y += yorg; + for (i = 1; i<count; i++) + { + ppt->x += (ppt-1)->x; + ppt->y += (ppt-1)->y; + ppt++; + } + } + } + else + { + if (mode == CoordModePrevious) + { + ppt++; + for (i = 1; i<count; i++) + { + ppt->x += (ppt-1)->x; + ppt->y += (ppt-1)->y; + ppt++; + } + } + } + if (shape == Convex) + miFillConvexPoly(dst, pgc, count, pPts); + else + miFillGeneralPoly(dst, pgc, count, pPts); +} diff --git a/xserver/mi/mipoly.h b/xserver/mi/mipoly.h new file mode 100644 index 000000000..8e04f6737 --- /dev/null +++ b/xserver/mi/mipoly.h @@ -0,0 +1,215 @@ +/* + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + + +/* + * fill.h + * + * Created by Brian Kelleher; Oct 1985 + * + * Include file for filled polygon routines. + * + * These are the data structures needed to scan + * convert regions. Two different scan conversion + * methods are available -- the even-odd method, and + * the winding number method. + * The even-odd rule states that a point is inside + * the polygon if a ray drawn from that point in any + * direction will pass through an odd number of + * path segments. + * By the winding number rule, a point is decided + * to be inside the polygon if a ray drawn from that + * point in any direction passes through a different + * number of clockwise and counter-clockwise path + * segments. + * + * These data structures are adapted somewhat from + * the algorithm in (Foley/Van Dam) for scan converting + * polygons. + * The basic algorithm is to start at the top (smallest y) + * of the polygon, stepping down to the bottom of + * the polygon by incrementing the y coordinate. We + * keep a list of edges which the current scanline crosses, + * sorted by x. This list is called the Active Edge Table (AET) + * As we change the y-coordinate, we update each entry in + * in the active edge table to reflect the edges new xcoord. + * This list must be sorted at each scanline in case + * two edges intersect. + * We also keep a data structure known as the Edge Table (ET), + * which keeps track of all the edges which the current + * scanline has not yet reached. The ET is basically a + * list of ScanLineList structures containing a list of + * edges which are entered at a given scanline. There is one + * ScanLineList per scanline at which an edge is entered. + * When we enter a new edge, we move it from the ET to the AET. + * + * From the AET, we can implement the even-odd rule as in + * (Foley/Van Dam). + * The winding number rule is a little trickier. We also + * keep the EdgeTableEntries in the AET linked by the + * nextWETE (winding EdgeTableEntry) link. This allows + * the edges to be linked just as before for updating + * purposes, but only uses the edges linked by the nextWETE + * link as edges representing spans of the polygon to + * drawn (as with the even-odd rule). + */ + +/* + * for the winding number rule + */ +#define CLOCKWISE 1 +#define COUNTERCLOCKWISE -1 + +typedef struct _EdgeTableEntry { + int ymax; /* ycoord at which we exit this edge. */ + BRESINFO bres; /* Bresenham info to run the edge */ + struct _EdgeTableEntry *next; /* next in the list */ + struct _EdgeTableEntry *back; /* for insertion sort */ + struct _EdgeTableEntry *nextWETE; /* for winding num rule */ + int ClockWise; /* flag for winding number rule */ +} EdgeTableEntry; + + +typedef struct _ScanLineList{ + int scanline; /* the scanline represented */ + EdgeTableEntry *edgelist; /* header node */ + struct _ScanLineList *next; /* next in the list */ +} ScanLineList; + + +typedef struct { + int ymax; /* ymax for the polygon */ + int ymin; /* ymin for the polygon */ + ScanLineList scanlines; /* header node */ +} EdgeTable; + + +/* + * Here is a struct to help with storage allocation + * so we can allocate a big chunk at a time, and then take + * pieces from this heap when we need to. + */ +#define SLLSPERBLOCK 25 + +typedef struct _ScanLineListBlock { + ScanLineList SLLs[SLLSPERBLOCK]; + struct _ScanLineListBlock *next; +} ScanLineListBlock; + +/* + * number of points to buffer before sending them off + * to scanlines() : Must be an even number + */ +#define NUMPTSTOBUFFER 200 + + +/* + * + * a few macros for the inner loops of the fill code where + * performance considerations don't allow a procedure call. + * + * Evaluate the given edge at the given scanline. + * If the edge has expired, then we leave it and fix up + * the active edge table; otherwise, we increment the + * x value to be ready for the next scanline. + * The winding number rule is in effect, so we must notify + * the caller when the edge has been removed so he + * can reorder the Winding Active Edge Table. + */ +#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \ + if (pAET->ymax == y) { /* leaving this edge */ \ + pPrevAET->next = pAET->next; \ + pAET = pPrevAET->next; \ + fixWAET = 1; \ + if (pAET) \ + pAET->back = pPrevAET; \ + } \ + else { \ + BRESINCRPGONSTRUCT(pAET->bres); \ + pPrevAET = pAET; \ + pAET = pAET->next; \ + } \ +} + + +/* + * Evaluate the given edge at the given scanline. + * If the edge has expired, then we leave it and fix up + * the active edge table; otherwise, we increment the + * x value to be ready for the next scanline. + * The even-odd rule is in effect. + */ +#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \ + if (pAET->ymax == y) { /* leaving this edge */ \ + pPrevAET->next = pAET->next; \ + pAET = pPrevAET->next; \ + if (pAET) \ + pAET->back = pPrevAET; \ + } \ + else { \ + BRESINCRPGONSTRUCT(pAET->bres); \ + pPrevAET = pAET; \ + pAET = pAET->next; \ + } \ +} + +/* mipolyutil.c */ + +extern Bool miInsertEdgeInET( + EdgeTable * /*ET*/, + EdgeTableEntry * /*ETE*/, + int /*scanline*/, + ScanLineListBlock ** /*SLLBlock*/, + int * /*iSLLBlock*/ +); + +extern Bool miCreateETandAET( + int /*count*/, + DDXPointPtr /*pts*/, + EdgeTable * /*ET*/, + EdgeTableEntry * /*AET*/, + EdgeTableEntry * /*pETEs*/, + ScanLineListBlock * /*pSLLBlock*/ +); + +extern void miloadAET( + EdgeTableEntry * /*AET*/, + EdgeTableEntry * /*ETEs*/ +); + +extern void micomputeWAET( + EdgeTableEntry * /*AET*/ +); + +extern int miInsertionSort( + EdgeTableEntry * /*AET*/ +); + +extern void miFreeStorage( + ScanLineListBlock * /*pSLLBlock*/ +); diff --git a/xserver/mi/mipolycon.c b/xserver/mi/mipolycon.c new file mode 100644 index 000000000..b5ab89364 --- /dev/null +++ b/xserver/mi/mipolycon.c @@ -0,0 +1,246 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "gcstruct.h" +#include "pixmap.h" +#include "mi.h" +#include "miscanfill.h" + +static int getPolyYBounds(DDXPointPtr pts, int n, int *by, int *ty); + +/* + * convexpoly.c + * + * Written by Brian Kelleher; Dec. 1985. + * + * Fill a convex polygon. If the given polygon + * is not convex, then the result is undefined. + * The algorithm is to order the edges from smallest + * y to largest by partitioning the array into a left + * edge list and a right edge list. The algorithm used + * to traverse each edge is an extension of Bresenham's + * line algorithm with y as the major axis. + * For a derivation of the algorithm, see the author of + * this code. + */ +_X_EXPORT Bool +miFillConvexPoly(dst, pgc, count, ptsIn) + DrawablePtr dst; + GCPtr pgc; + int count; /* number of points */ + DDXPointPtr ptsIn; /* the points */ +{ + register int xl = 0, xr = 0; /* x vals of left and right edges */ + register int dl = 0, dr = 0; /* decision variables */ + register int ml = 0, m1l = 0;/* left edge slope and slope+1 */ + int mr = 0, m1r = 0; /* right edge slope and slope+1 */ + int incr1l = 0, incr2l = 0; /* left edge error increments */ + int incr1r = 0, incr2r = 0; /* right edge error increments */ + int dy; /* delta y */ + int y; /* current scanline */ + int left, right; /* indices to first endpoints */ + int i; /* loop counter */ + int nextleft, nextright; /* indices to second endpoints */ + DDXPointPtr ptsOut, FirstPoint; /* output buffer */ + int *width, *FirstWidth; /* output buffer */ + int imin; /* index of smallest vertex (in y) */ + int ymin; /* y-extents of polygon */ + int ymax; + + /* + * find leftx, bottomy, rightx, topy, and the index + * of bottomy. Also translate the points. + */ + imin = getPolyYBounds(ptsIn, count, &ymin, &ymax); + + dy = ymax - ymin + 1; + if ((count < 3) || (dy < 0)) + return(TRUE); + ptsOut = FirstPoint = (DDXPointPtr )ALLOCATE_LOCAL(sizeof(DDXPointRec)*dy); + width = FirstWidth = (int *)ALLOCATE_LOCAL(sizeof(int) * dy); + if(!FirstPoint || !FirstWidth) + { + if (FirstWidth) DEALLOCATE_LOCAL(FirstWidth); + if (FirstPoint) DEALLOCATE_LOCAL(FirstPoint); + return(FALSE); + } + + nextleft = nextright = imin; + y = ptsIn[nextleft].y; + + /* + * loop through all edges of the polygon + */ + do { + /* + * add a left edge if we need to + */ + if (ptsIn[nextleft].y == y) { + left = nextleft; + + /* + * find the next edge, considering the end + * conditions of the array. + */ + nextleft++; + if (nextleft >= count) + nextleft = 0; + + /* + * now compute all of the random information + * needed to run the iterative algorithm. + */ + BRESINITPGON(ptsIn[nextleft].y-ptsIn[left].y, + ptsIn[left].x,ptsIn[nextleft].x, + xl, dl, ml, m1l, incr1l, incr2l); + } + + /* + * add a right edge if we need to + */ + if (ptsIn[nextright].y == y) { + right = nextright; + + /* + * find the next edge, considering the end + * conditions of the array. + */ + nextright--; + if (nextright < 0) + nextright = count-1; + + /* + * now compute all of the random information + * needed to run the iterative algorithm. + */ + BRESINITPGON(ptsIn[nextright].y-ptsIn[right].y, + ptsIn[right].x,ptsIn[nextright].x, + xr, dr, mr, m1r, incr1r, incr2r); + } + + /* + * generate scans to fill while we still have + * a right edge as well as a left edge. + */ + i = min(ptsIn[nextleft].y, ptsIn[nextright].y) - y; + /* in case we're called with non-convex polygon */ + if(i < 0) + { + DEALLOCATE_LOCAL(FirstWidth); + DEALLOCATE_LOCAL(FirstPoint); + return(TRUE); + } + while (i-- > 0) + { + ptsOut->y = y; + + /* + * reverse the edges if necessary + */ + if (xl < xr) + { + *(width++) = xr - xl; + (ptsOut++)->x = xl; + } + else + { + *(width++) = xl - xr; + (ptsOut++)->x = xr; + } + y++; + + /* increment down the edges */ + BRESINCRPGON(dl, xl, ml, m1l, incr1l, incr2l); + BRESINCRPGON(dr, xr, mr, m1r, incr1r, incr2r); + } + } while (y != ymax); + + /* + * Finally, fill the <remaining> spans + */ + (*pgc->ops->FillSpans)(dst, pgc, + ptsOut-FirstPoint,FirstPoint,FirstWidth, + 1); + DEALLOCATE_LOCAL(FirstWidth); + DEALLOCATE_LOCAL(FirstPoint); + return(TRUE); +} + + +/* + * Find the index of the point with the smallest y. + */ +static int +getPolyYBounds(DDXPointPtr pts, int n, int *by, int *ty) +{ + register DDXPointPtr ptMin; + int ymin, ymax; + DDXPointPtr ptsStart = pts; + + ptMin = pts; + ymin = ymax = (pts++)->y; + + while (--n > 0) { + if (pts->y < ymin) + { + ptMin = pts; + ymin = pts->y; + } + if(pts->y > ymax) + ymax = pts->y; + + pts++; + } + + *by = ymin; + *ty = ymax; + return(ptMin-ptsStart); +} diff --git a/xserver/mi/mipolygen.c b/xserver/mi/mipolygen.c new file mode 100644 index 000000000..34da21f9e --- /dev/null +++ b/xserver/mi/mipolygen.c @@ -0,0 +1,230 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include "gcstruct.h" +#include "miscanfill.h" +#include "mipoly.h" +#include "pixmap.h" +#include "mi.h" + +/* + * + * Written by Brian Kelleher; Oct. 1985 + * + * Routine to fill a polygon. Two fill rules are + * supported: frWINDING and frEVENODD. + * + * See fillpoly.h for a complete description of the algorithm. + */ + +Bool +miFillGeneralPoly(dst, pgc, count, ptsIn) + DrawablePtr dst; + GCPtr pgc; + int count; /* number of points */ + DDXPointPtr ptsIn; /* the points */ +{ + register EdgeTableEntry *pAET; /* the Active Edge Table */ + register int y; /* the current scanline */ + register int nPts = 0; /* number of pts in buffer */ + register EdgeTableEntry *pWETE; /* Winding Edge Table */ + register ScanLineList *pSLL; /* Current ScanLineList */ + register DDXPointPtr ptsOut; /* ptr to output buffers */ + int *width; + DDXPointRec FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */ + int FirstWidth[NUMPTSTOBUFFER]; + EdgeTableEntry *pPrevAET; /* previous AET entry */ + EdgeTable ET; /* Edge Table header node */ + EdgeTableEntry AET; /* Active ET header node */ + EdgeTableEntry *pETEs; /* Edge Table Entries buff */ + ScanLineListBlock SLLBlock; /* header for ScanLineList */ + int fixWAET = 0; + + if (count < 3) + return(TRUE); + + if(!(pETEs = (EdgeTableEntry *) + ALLOCATE_LOCAL(sizeof(EdgeTableEntry) * count))) + return(FALSE); + ptsOut = FirstPoint; + width = FirstWidth; + if (!miCreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock)) + { + DEALLOCATE_LOCAL(pETEs); + return(FALSE); + } + pSLL = ET.scanlines.next; + + if (pgc->fillRule == EvenOddRule) + { + /* + * for each scanline + */ + for (y = ET.ymin; y < ET.ymax; y++) + { + /* + * Add a new edge to the active edge table when we + * get to the next edge. + */ + if (pSLL && y == pSLL->scanline) + { + miloadAET(&AET, pSLL->edgelist); + pSLL = pSLL->next; + } + pPrevAET = &AET; + pAET = AET.next; + + /* + * for each active edge + */ + while (pAET) + { + ptsOut->x = pAET->bres.minor; + ptsOut++->y = y; + *width++ = pAET->next->bres.minor - pAET->bres.minor; + nPts++; + + /* + * send out the buffer when its full + */ + if (nPts == NUMPTSTOBUFFER) + { + (*pgc->ops->FillSpans)(dst, pgc, + nPts, FirstPoint, FirstWidth, + 1); + ptsOut = FirstPoint; + width = FirstWidth; + nPts = 0; + } + EVALUATEEDGEEVENODD(pAET, pPrevAET, y) + EVALUATEEDGEEVENODD(pAET, pPrevAET, y); + } + miInsertionSort(&AET); + } + } + else /* default to WindingNumber */ + { + /* + * for each scanline + */ + for (y = ET.ymin; y < ET.ymax; y++) + { + /* + * Add a new edge to the active edge table when we + * get to the next edge. + */ + if (pSLL && y == pSLL->scanline) + { + miloadAET(&AET, pSLL->edgelist); + micomputeWAET(&AET); + pSLL = pSLL->next; + } + pPrevAET = &AET; + pAET = AET.next; + pWETE = pAET; + + /* + * for each active edge + */ + while (pAET) + { + /* + * if the next edge in the active edge table is + * also the next edge in the winding active edge + * table. + */ + if (pWETE == pAET) + { + ptsOut->x = pAET->bres.minor; + ptsOut++->y = y; + *width++ = pAET->nextWETE->bres.minor - pAET->bres.minor; + nPts++; + + /* + * send out the buffer + */ + if (nPts == NUMPTSTOBUFFER) + { + (*pgc->ops->FillSpans)(dst, pgc, nPts, FirstPoint, + FirstWidth, 1); + ptsOut = FirstPoint; + width = FirstWidth; + nPts = 0; + } + + pWETE = pWETE->nextWETE; + while (pWETE != pAET) + EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET); + pWETE = pWETE->nextWETE; + } + EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET); + } + + /* + * reevaluate the Winding active edge table if we + * just had to resort it or if we just exited an edge. + */ + if (miInsertionSort(&AET) || fixWAET) + { + micomputeWAET(&AET); + fixWAET = 0; + } + } + } + + /* + * Get any spans that we missed by buffering + */ + (*pgc->ops->FillSpans)(dst, pgc, nPts, FirstPoint, FirstWidth, 1); + DEALLOCATE_LOCAL(pETEs); + miFreeStorage(SLLBlock.next); + return(TRUE); +} diff --git a/xserver/mi/mipolypnt.c b/xserver/mi/mipolypnt.c new file mode 100644 index 000000000..245bda317 --- /dev/null +++ b/xserver/mi/mipolypnt.c @@ -0,0 +1,123 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xprotostr.h> +#include "pixmapstr.h" +#include "gcstruct.h" +#include "windowstr.h" +#include "mi.h" + +_X_EXPORT void +miPolyPoint(pDrawable, pGC, mode, npt, pptInit) + DrawablePtr pDrawable; + GCPtr pGC; + int mode; /* Origin or Previous */ + int npt; + xPoint *pptInit; +{ + + int xorg; + int yorg; + int nptTmp; + XID fsOld, fsNew; + int *pwidthInit, *pwidth; + int i; + register xPoint *ppt; + + /* make pointlist origin relative */ + if (mode == CoordModePrevious) + { + ppt = pptInit; + nptTmp = npt; + nptTmp--; + while(nptTmp--) + { + ppt++; + ppt->x += (ppt-1)->x; + ppt->y += (ppt-1)->y; + } + } + + if(pGC->miTranslate) + { + ppt = pptInit; + nptTmp = npt; + xorg = pDrawable->x; + yorg = pDrawable->y; + while(nptTmp--) + { + ppt->x += xorg; + ppt++->y += yorg; + } + } + + fsOld = pGC->fillStyle; + fsNew = FillSolid; + if(pGC->fillStyle != FillSolid) + { + DoChangeGC(pGC, GCFillStyle, &fsNew, 0); + ValidateGC(pDrawable, pGC); + } + if(!(pwidthInit = (int *)ALLOCATE_LOCAL(npt * sizeof(int)))) + return; + pwidth = pwidthInit; + for(i = 0; i < npt; i++) + *pwidth++ = 1; + (*pGC->ops->FillSpans)(pDrawable, pGC, npt, pptInit, pwidthInit, FALSE); + + if(fsOld != FillSolid) + { + DoChangeGC(pGC, GCFillStyle, &fsOld, 0); + ValidateGC(pDrawable, pGC); + } + DEALLOCATE_LOCAL(pwidthInit); +} + diff --git a/xserver/mi/mipolyrect.c b/xserver/mi/mipolyrect.c new file mode 100644 index 000000000..a9ab90928 --- /dev/null +++ b/xserver/mi/mipolyrect.c @@ -0,0 +1,191 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xprotostr.h> +#include "regionstr.h" +#include "gcstruct.h" +#include "pixmap.h" +#include "mi.h" + +_X_EXPORT void +miPolyRectangle(pDraw, pGC, nrects, pRects) + DrawablePtr pDraw; + GCPtr pGC; + int nrects; + xRectangle *pRects; +{ + int i; + xRectangle *pR = pRects; + DDXPointRec rect[5]; + int bound_tmp; + +#define MINBOUND(dst,eqn) bound_tmp = eqn; \ + if (bound_tmp < -32768) \ + bound_tmp = -32768; \ + dst = bound_tmp; + +#define MAXBOUND(dst,eqn) bound_tmp = eqn; \ + if (bound_tmp > 32767) \ + bound_tmp = 32767; \ + dst = bound_tmp; + +#define MAXUBOUND(dst,eqn) bound_tmp = eqn; \ + if (bound_tmp > 65535) \ + bound_tmp = 65535; \ + dst = bound_tmp; + + if (pGC->lineStyle == LineSolid && pGC->joinStyle == JoinMiter && + pGC->lineWidth != 0) + { + xRectangle *tmp, *t; + int ntmp; + int offset1, offset2, offset3; + int x, y, width, height; + + ntmp = (nrects << 2); + offset2 = pGC->lineWidth; + offset1 = offset2 >> 1; + offset3 = offset2 - offset1; + tmp = (xRectangle *) ALLOCATE_LOCAL(ntmp * sizeof (xRectangle)); + if (!tmp) + return; + t = tmp; + for (i = 0; i < nrects; i++) + { + x = pR->x; + y = pR->y; + width = pR->width; + height = pR->height; + pR++; + if (width == 0 && height == 0) + { + rect[0].x = x; + rect[0].y = y; + rect[1].x = x; + rect[1].y = y; + (*pGC->ops->Polylines)(pDraw, pGC, CoordModeOrigin, 2, rect); + } + else if (height < offset2 || width < offset1) + { + if (height == 0) + { + t->x = x; + t->width = width; + } + else + { + MINBOUND (t->x, x - offset1) + MAXUBOUND (t->width, width + offset2) + } + if (width == 0) + { + t->y = y; + t->height = height; + } + else + { + MINBOUND (t->y, y - offset1) + MAXUBOUND (t->height, height + offset2) + } + t++; + } + else + { + MINBOUND(t->x, x - offset1) + MINBOUND(t->y, y - offset1) + MAXUBOUND(t->width, width + offset2) + t->height = offset2; + t++; + MINBOUND(t->x, x - offset1) + MAXBOUND(t->y, y + offset3); + t->width = offset2; + t->height = height - offset2; + t++; + MAXBOUND(t->x, x + width - offset1); + MAXBOUND(t->y, y + offset3) + t->width = offset2; + t->height = height - offset2; + t++; + MINBOUND(t->x, x - offset1) + MAXBOUND(t->y, y + height - offset1) + MAXUBOUND(t->width, width + offset2) + t->height = offset2; + t++; + } + } + (*pGC->ops->PolyFillRect) (pDraw, pGC, t - tmp, tmp); + DEALLOCATE_LOCAL ((pointer) tmp); + } + else + { + + for (i=0; i<nrects; i++) + { + rect[0].x = pR->x; + rect[0].y = pR->y; + + MAXBOUND(rect[1].x, pR->x + (int) pR->width) + rect[1].y = rect[0].y; + + rect[2].x = rect[1].x; + MAXBOUND(rect[2].y, pR->y + (int) pR->height); + + rect[3].x = rect[0].x; + rect[3].y = rect[2].y; + + rect[4].x = rect[0].x; + rect[4].y = rect[0].y; + + (*pGC->ops->Polylines)(pDraw, pGC, CoordModeOrigin, 5, rect); + pR++; + } + } +} diff --git a/xserver/mi/mipolyseg.c b/xserver/mi/mipolyseg.c new file mode 100644 index 000000000..0cd9d416e --- /dev/null +++ b/xserver/mi/mipolyseg.c @@ -0,0 +1,83 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xprotostr.h> +#include "regionstr.h" +#include "gcstruct.h" +#include "pixmap.h" +#include "mi.h" + +/***************************************************************** + * miPolySegment + * + * For each segment, draws a line between (x1, y1) and (x2, y2). The + * lines are drawn in the order listed. + * + * Walks the segments, compressing them into format for PolyLines. + * + *****************************************************************/ + + +_X_EXPORT void +miPolySegment(pDraw, pGC, nseg, pSegs) + DrawablePtr pDraw; + GCPtr pGC; + int nseg; + xSegment *pSegs; +{ + int i; + + for (i=0; i<nseg; i++) + { + (*pGC->ops->Polylines)(pDraw, pGC, CoordModeOrigin, 2,(DDXPointPtr)pSegs); + pSegs++; + } +} diff --git a/xserver/mi/mipolytext.c b/xserver/mi/mipolytext.c new file mode 100644 index 000000000..6af02e046 --- /dev/null +++ b/xserver/mi/mipolytext.c @@ -0,0 +1,200 @@ +/******************************************************************* + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +************************************************************************/ +/* + * mipolytext.c - text routines + * + * Author: haynes + * Digital Equipment Corporation + * Western Software Laboratory + * Date: Thu Feb 5 1987 + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xmd.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "gcstruct.h" +#include <X11/fonts/fontstruct.h> +#include "dixfontstr.h" +#include "mi.h" + +int +miPolyText(pDraw, pGC, x, y, count, chars, fontEncoding) + DrawablePtr pDraw; + GCPtr pGC; + int x, y; + int count; + char *chars; + FontEncoding fontEncoding; +{ + unsigned long n, i; + int w; + CharInfoPtr charinfo[255]; /* encoding only has 1 byte for count */ + + GetGlyphs(pGC->font, (unsigned long)count, (unsigned char *)chars, + fontEncoding, &n, charinfo); + w = 0; + for (i=0; i < n; i++) w += charinfo[i]->metrics.characterWidth; + if (n != 0) + (*pGC->ops->PolyGlyphBlt)( + pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(pGC->font)); + return x+w; +} + + +_X_EXPORT int +miPolyText8(pDraw, pGC, x, y, count, chars) + DrawablePtr pDraw; + GCPtr pGC; + int x, y; + int count; + char *chars; +{ + unsigned long n, i; + int w; + CharInfoPtr charinfo[255]; /* encoding only has 1 byte for count */ + + GetGlyphs(pGC->font, (unsigned long)count, (unsigned char *)chars, + Linear8Bit, &n, charinfo); + w = 0; + for (i=0; i < n; i++) w += charinfo[i]->metrics.characterWidth; + if (n != 0) + (*pGC->ops->PolyGlyphBlt)( + pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(pGC->font)); + return x+w; +} + + +_X_EXPORT int +miPolyText16(pDraw, pGC, x, y, count, chars) + DrawablePtr pDraw; + GCPtr pGC; + int x, y; + int count; + unsigned short *chars; +{ + unsigned long n, i; + int w; + CharInfoPtr charinfo[255]; /* encoding only has 1 byte for count */ + + GetGlyphs(pGC->font, (unsigned long)count, (unsigned char *)chars, + (FONTLASTROW(pGC->font) == 0) ? Linear16Bit : TwoD16Bit, + &n, charinfo); + w = 0; + for (i=0; i < n; i++) w += charinfo[i]->metrics.characterWidth; + if (n != 0) + (*pGC->ops->PolyGlyphBlt)( + pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(pGC->font)); + return x+w; +} + + +int +miImageText(pDraw, pGC, x, y, count, chars, fontEncoding) + DrawablePtr pDraw; + GCPtr pGC; + int x, y; + int count; + char *chars; + FontEncoding fontEncoding; +{ + unsigned long n, i; + FontPtr font = pGC->font; + int w; + CharInfoPtr charinfo[255]; + + GetGlyphs(font, (unsigned long)count, (unsigned char *)chars, + fontEncoding, &n, charinfo); + w = 0; + for (i=0; i < n; i++) w += charinfo[i]->metrics.characterWidth; + if (n !=0 ) + (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(font)); + return x+w; +} + + +_X_EXPORT void +miImageText8(pDraw, pGC, x, y, count, chars) + DrawablePtr pDraw; + GCPtr pGC; + int x, y; + int count; + char *chars; +{ + unsigned long n; + FontPtr font = pGC->font; + CharInfoPtr charinfo[255]; /* encoding only has 1 byte for count */ + + GetGlyphs(font, (unsigned long)count, (unsigned char *)chars, + Linear8Bit, &n, charinfo); + if (n !=0 ) + (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(font)); +} + + +_X_EXPORT void +miImageText16(pDraw, pGC, x, y, count, chars) + DrawablePtr pDraw; + GCPtr pGC; + int x, y; + int count; + unsigned short *chars; +{ + unsigned long n; + FontPtr font = pGC->font; + CharInfoPtr charinfo[255]; /* encoding only has 1 byte for count */ + + GetGlyphs(font, (unsigned long)count, (unsigned char *)chars, + (FONTLASTROW(pGC->font) == 0) ? Linear16Bit : TwoD16Bit, + &n, charinfo); + if (n !=0 ) + (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(font)); +} diff --git a/xserver/mi/mipolyutil.c b/xserver/mi/mipolyutil.c new file mode 100644 index 000000000..5443ba5c3 --- /dev/null +++ b/xserver/mi/mipolyutil.c @@ -0,0 +1,399 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "regionstr.h" +#include "gc.h" +#include "miscanfill.h" +#include "mipoly.h" +#include "misc.h" /* MAXINT */ + +/* + * fillUtils.c + * + * Written by Brian Kelleher; Oct. 1985 + * + * This module contains all of the utility functions + * needed to scan convert a polygon. + * + */ + +/* + * InsertEdgeInET + * + * Insert the given edge into the edge table. + * First we must find the correct bucket in the + * Edge table, then find the right slot in the + * bucket. Finally, we can insert it. + * + */ +Bool +miInsertEdgeInET(ET, ETE, scanline, SLLBlock, iSLLBlock) + EdgeTable *ET; + EdgeTableEntry *ETE; + int scanline; + ScanLineListBlock **SLLBlock; + int *iSLLBlock; +{ + register EdgeTableEntry *start, *prev; + register ScanLineList *pSLL, *pPrevSLL; + ScanLineListBlock *tmpSLLBlock; + + /* + * find the right bucket to put the edge into + */ + pPrevSLL = &ET->scanlines; + pSLL = pPrevSLL->next; + while (pSLL && (pSLL->scanline < scanline)) + { + pPrevSLL = pSLL; + pSLL = pSLL->next; + } + + /* + * reassign pSLL (pointer to ScanLineList) if necessary + */ + if ((!pSLL) || (pSLL->scanline > scanline)) + { + if (*iSLLBlock > SLLSPERBLOCK-1) + { + tmpSLLBlock = + (ScanLineListBlock *)xalloc(sizeof(ScanLineListBlock)); + if (!tmpSLLBlock) + return FALSE; + (*SLLBlock)->next = tmpSLLBlock; + tmpSLLBlock->next = (ScanLineListBlock *)NULL; + *SLLBlock = tmpSLLBlock; + *iSLLBlock = 0; + } + pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]); + + pSLL->next = pPrevSLL->next; + pSLL->edgelist = (EdgeTableEntry *)NULL; + pPrevSLL->next = pSLL; + } + pSLL->scanline = scanline; + + /* + * now insert the edge in the right bucket + */ + prev = (EdgeTableEntry *)NULL; + start = pSLL->edgelist; + while (start && (start->bres.minor < ETE->bres.minor)) + { + prev = start; + start = start->next; + } + ETE->next = start; + + if (prev) + prev->next = ETE; + else + pSLL->edgelist = ETE; + return TRUE; +} + +/* + * CreateEdgeTable + * + * This routine creates the edge table for + * scan converting polygons. + * The Edge Table (ET) looks like: + * + * EdgeTable + * -------- + * | ymax | ScanLineLists + * |scanline|-->------------>-------------->... + * -------- |scanline| |scanline| + * |edgelist| |edgelist| + * --------- --------- + * | | + * | | + * V V + * list of ETEs list of ETEs + * + * where ETE is an EdgeTableEntry data structure, + * and there is one ScanLineList per scanline at + * which an edge is initially entered. + * + */ + +Bool +miCreateETandAET(count, pts, ET, AET, pETEs, pSLLBlock) + register int count; + register DDXPointPtr pts; + EdgeTable *ET; + EdgeTableEntry *AET; + register EdgeTableEntry *pETEs; + ScanLineListBlock *pSLLBlock; +{ + register DDXPointPtr top, bottom; + register DDXPointPtr PrevPt, CurrPt; + int iSLLBlock = 0; + + int dy; + + if (count < 2) return TRUE; + + /* + * initialize the Active Edge Table + */ + AET->next = (EdgeTableEntry *)NULL; + AET->back = (EdgeTableEntry *)NULL; + AET->nextWETE = (EdgeTableEntry *)NULL; + AET->bres.minor = MININT; + + /* + * initialize the Edge Table. + */ + ET->scanlines.next = (ScanLineList *)NULL; + ET->ymax = MININT; + ET->ymin = MAXINT; + pSLLBlock->next = (ScanLineListBlock *)NULL; + + PrevPt = &pts[count-1]; + + /* + * for each vertex in the array of points. + * In this loop we are dealing with two vertices at + * a time -- these make up one edge of the polygon. + */ + while (count--) + { + CurrPt = pts++; + + /* + * find out which point is above and which is below. + */ + if (PrevPt->y > CurrPt->y) + { + bottom = PrevPt, top = CurrPt; + pETEs->ClockWise = 0; + } + else + { + bottom = CurrPt, top = PrevPt; + pETEs->ClockWise = 1; + } + + /* + * don't add horizontal edges to the Edge table. + */ + if (bottom->y != top->y) + { + pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */ + + /* + * initialize integer edge algorithm + */ + dy = bottom->y - top->y; + BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres); + + if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock)) + { + miFreeStorage(pSLLBlock->next); + return FALSE; + } + + ET->ymax = max(ET->ymax, PrevPt->y); + ET->ymin = min(ET->ymin, PrevPt->y); + pETEs++; + } + + PrevPt = CurrPt; + } + return TRUE; +} + +/* + * loadAET + * + * This routine moves EdgeTableEntries from the + * EdgeTable into the Active Edge Table, + * leaving them sorted by smaller x coordinate. + * + */ + +void +miloadAET(AET, ETEs) + register EdgeTableEntry *AET, *ETEs; +{ + register EdgeTableEntry *pPrevAET; + register EdgeTableEntry *tmp; + + pPrevAET = AET; + AET = AET->next; + while (ETEs) + { + while (AET && (AET->bres.minor < ETEs->bres.minor)) + { + pPrevAET = AET; + AET = AET->next; + } + tmp = ETEs->next; + ETEs->next = AET; + if (AET) + AET->back = ETEs; + ETEs->back = pPrevAET; + pPrevAET->next = ETEs; + pPrevAET = ETEs; + + ETEs = tmp; + } +} + +/* + * computeWAET + * + * This routine links the AET by the + * nextWETE (winding EdgeTableEntry) link for + * use by the winding number rule. The final + * Active Edge Table (AET) might look something + * like: + * + * AET + * ---------- --------- --------- + * |ymax | |ymax | |ymax | + * | ... | |... | |... | + * |next |->|next |->|next |->... + * |nextWETE| |nextWETE| |nextWETE| + * --------- --------- ^-------- + * | | | + * V-------------------> V---> ... + * + */ +void +micomputeWAET(AET) + register EdgeTableEntry *AET; +{ + register EdgeTableEntry *pWETE; + register int inside = 1; + register int isInside = 0; + + AET->nextWETE = (EdgeTableEntry *)NULL; + pWETE = AET; + AET = AET->next; + while (AET) + { + if (AET->ClockWise) + isInside++; + else + isInside--; + + if ((!inside && !isInside) || + ( inside && isInside)) + { + pWETE->nextWETE = AET; + pWETE = AET; + inside = !inside; + } + AET = AET->next; + } + pWETE->nextWETE = (EdgeTableEntry *)NULL; +} + +/* + * InsertionSort + * + * Just a simple insertion sort using + * pointers and back pointers to sort the Active + * Edge Table. + * + */ + +int +miInsertionSort(AET) + register EdgeTableEntry *AET; +{ + register EdgeTableEntry *pETEchase; + register EdgeTableEntry *pETEinsert; + register EdgeTableEntry *pETEchaseBackTMP; + register int changed = 0; + + AET = AET->next; + while (AET) + { + pETEinsert = AET; + pETEchase = AET; + while (pETEchase->back->bres.minor > AET->bres.minor) + pETEchase = pETEchase->back; + + AET = AET->next; + if (pETEchase != pETEinsert) + { + pETEchaseBackTMP = pETEchase->back; + pETEinsert->back->next = AET; + if (AET) + AET->back = pETEinsert->back; + pETEinsert->next = pETEchase; + pETEchase->back->next = pETEinsert; + pETEchase->back = pETEinsert; + pETEinsert->back = pETEchaseBackTMP; + changed = 1; + } + } + return(changed); +} + +/* + * Clean up our act. + */ +void +miFreeStorage(pSLLBlock) + register ScanLineListBlock *pSLLBlock; +{ + register ScanLineListBlock *tmpSLLBlock; + + while (pSLLBlock) + { + tmpSLLBlock = pSLLBlock->next; + xfree(pSLLBlock); + pSLLBlock = tmpSLLBlock; + } +} diff --git a/xserver/mi/mipushpxl.c b/xserver/mi/mipushpxl.c new file mode 100644 index 000000000..6526aa02b --- /dev/null +++ b/xserver/mi/mipushpxl.c @@ -0,0 +1,259 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include "gcstruct.h" +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "regionstr.h" +#include "../mfb/maskbits.h" +#include "mi.h" + +#define NPT 128 + +/* miPushPixels -- squeegees the fill style of pGC through pBitMap + * into pDrawable. pBitMap is a stencil (dx by dy of it is used, it may + * be bigger) which is placed on the drawable at xOrg, yOrg. Where a 1 bit + * is set in the bitmap, the fill style is put onto the drawable using + * the GC's logical function. The drawable is not changed where the bitmap + * has a zero bit or outside the area covered by the stencil. + +WARNING: + this code works if the 1-bit deep pixmap format returned by GetSpans +is the same as the format defined by the mfb code (i.e. 32-bit padding +per scanline, scanline unit = 32 bits; later, this might mean +bitsizeof(int) padding and sacnline unit == bitsizeof(int).) + + */ + +/* + * in order to have both (MSB_FIRST and LSB_FIRST) versions of this + * in the server, we need to rename one of them + */ +_X_EXPORT void +miPushPixels(pGC, pBitMap, pDrawable, dx, dy, xOrg, yOrg) + GCPtr pGC; + PixmapPtr pBitMap; + DrawablePtr pDrawable; + int dx, dy, xOrg, yOrg; +{ + int h, dxDivPPW, ibEnd; + MiBits *pwLineStart; + register MiBits *pw, *pwEnd; + register MiBits msk; + register int ib, w; + register int ipt; /* index into above arrays */ + Bool fInBox; + DDXPointRec pt[NPT], ptThisLine; + int width[NPT]; +#if 1 + PixelType startmask; + if (screenInfo.bitmapBitOrder == IMAGE_BYTE_ORDER) + if (screenInfo.bitmapBitOrder == LSBFirst) + startmask = (MiBits)(-1) ^ + LONG2CHARSSAMEORDER((MiBits)(-1) << 1); + else + startmask = (MiBits)(-1) ^ + LONG2CHARSSAMEORDER((MiBits)(-1) >> 1); + else + if (screenInfo.bitmapBitOrder == LSBFirst) + startmask = (MiBits)(-1) ^ + LONG2CHARSDIFFORDER((MiBits)(-1) << 1); + else + startmask = (MiBits)(-1) ^ + LONG2CHARSDIFFORDER((MiBits)(-1) >> 1); +#endif + + pwLineStart = (MiBits *)xalloc(BitmapBytePad(dx)); + if (!pwLineStart) + return; + ipt = 0; + dxDivPPW = dx/PPW; + + for(h = 0, ptThisLine.x = 0, ptThisLine.y = 0; + h < dy; + h++, ptThisLine.y++) + { + + (*pBitMap->drawable.pScreen->GetSpans)((DrawablePtr)pBitMap, dx, + &ptThisLine, &dx, 1, (char *)pwLineStart); + + pw = pwLineStart; + /* Process all words which are fully in the pixmap */ + + fInBox = FALSE; + pwEnd = pwLineStart + dxDivPPW; + while(pw < pwEnd) + { + w = *pw; +#if 1 + msk = startmask; +#else + msk = (MiBits)(-1) ^ SCRRIGHT((MiBits)(-1), 1); +#endif + for(ib = 0; ib < PPW; ib++) + { + if(w & msk) + { + if(!fInBox) + { + pt[ipt].x = ((pw - pwLineStart) << PWSH) + ib + xOrg; + pt[ipt].y = h + yOrg; + /* start new box */ + fInBox = TRUE; + } + } + else + { + if(fInBox) + { + width[ipt] = ((pw - pwLineStart) << PWSH) + + ib + xOrg - pt[ipt].x; + if (++ipt >= NPT) + { + (*pGC->ops->FillSpans)(pDrawable, pGC, + NPT, pt, width, TRUE); + ipt = 0; + } + /* end box */ + fInBox = FALSE; + } + } +#if 1 + /* This is not quite right, but it'll do for now */ + if (screenInfo.bitmapBitOrder == IMAGE_BYTE_ORDER) + if (screenInfo.bitmapBitOrder == LSBFirst) + msk = LONG2CHARSSAMEORDER(LONG2CHARSSAMEORDER(msk) << 1); + else + msk = LONG2CHARSSAMEORDER(LONG2CHARSSAMEORDER(msk) >> 1); + else + if (screenInfo.bitmapBitOrder == LSBFirst) + msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) << 1); + else + msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) >> 1); +#else + msk = SCRRIGHT(msk, 1); +#endif + } + pw++; + } + ibEnd = dx & PIM; + if(ibEnd) + { + /* Process final partial word on line */ + w = *pw; +#if 1 + msk = startmask; +#else + msk = (MiBits)(-1) ^ SCRRIGHT((MiBits)(-1), 1); +#endif + for(ib = 0; ib < ibEnd; ib++) + { + if(w & msk) + { + if(!fInBox) + { + /* start new box */ + pt[ipt].x = ((pw - pwLineStart) << PWSH) + ib + xOrg; + pt[ipt].y = h + yOrg; + fInBox = TRUE; + } + } + else + { + if(fInBox) + { + /* end box */ + width[ipt] = ((pw - pwLineStart) << PWSH) + + ib + xOrg - pt[ipt].x; + if (++ipt >= NPT) + { + (*pGC->ops->FillSpans)(pDrawable, + pGC, NPT, pt, width, TRUE); + ipt = 0; + } + fInBox = FALSE; + } + } +#if 1 + /* This is not quite right, but it'll do for now */ + if (screenInfo.bitmapBitOrder == IMAGE_BYTE_ORDER) + if (screenInfo.bitmapBitOrder == LSBFirst) + msk = LONG2CHARSSAMEORDER(LONG2CHARSSAMEORDER(msk) << 1); + else + msk = LONG2CHARSSAMEORDER(LONG2CHARSSAMEORDER(msk) >> 1); + else + if (screenInfo.bitmapBitOrder == LSBFirst) + msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) << 1); + else + msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) >> 1); +#else + msk = SCRRIGHT(msk, 1); +#endif + } + } + /* If scanline ended with last bit set, end the box */ + if(fInBox) + { + width[ipt] = dx + xOrg - pt[ipt].x; + if (++ipt >= NPT) + { + (*pGC->ops->FillSpans)(pDrawable, pGC, NPT, pt, width, TRUE); + ipt = 0; + } + } + } + xfree(pwLineStart); + /* Flush any remaining spans */ + if (ipt) + { + (*pGC->ops->FillSpans)(pDrawable, pGC, ipt, pt, width, TRUE); + } +} diff --git a/xserver/mi/miregion.c b/xserver/mi/miregion.c new file mode 100644 index 000000000..fdb538c68 --- /dev/null +++ b/xserver/mi/miregion.c @@ -0,0 +1,2561 @@ +/*********************************************************** + +Copyright 1987, 1988, 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1988, 1989 by +Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "regionstr.h" +#include <X11/Xprotostr.h> +#include "gc.h" +#include "mi.h" +#include "mispans.h" + +#if defined (__GNUC__) && !defined (NO_INLINES) +#define INLINE __inline +#else +#define INLINE +#endif + +#undef assert +#ifdef DEBUG +#define assert(expr) {if (!(expr)) \ + FatalError("Assertion failed file %s, line %d: expr\n", \ + __FILE__, __LINE__); } +#else +#define assert(expr) +#endif + +#define good(reg) assert(miValidRegion(reg)) + +/* + * The functions in this file implement the Region abstraction used extensively + * throughout the X11 sample server. A Region is simply a set of disjoint + * (non-overlapping) rectangles, plus an "extent" rectangle which is the + * smallest single rectangle that contains all the non-overlapping rectangles. + * + * A Region is implemented as a "y-x-banded" array of rectangles. This array + * imposes two degrees of order. First, all rectangles are sorted by top side + * y coordinate first (y1), and then by left side x coordinate (x1). + * + * Furthermore, the rectangles are grouped into "bands". Each rectangle in a + * band has the same top y coordinate (y1), and each has the same bottom y + * coordinate (y2). Thus all rectangles in a band differ only in their left + * and right side (x1 and x2). Bands are implicit in the array of rectangles: + * there is no separate list of band start pointers. + * + * The y-x band representation does not minimize rectangles. In particular, + * if a rectangle vertically crosses a band (the rectangle has scanlines in + * the y1 to y2 area spanned by the band), then the rectangle may be broken + * down into two or more smaller rectangles stacked one atop the other. + * + * ----------- ----------- + * | | | | band 0 + * | | -------- ----------- -------- + * | | | | in y-x banded | | | | band 1 + * | | | | form is | | | | + * ----------- | | ----------- -------- + * | | | | band 2 + * -------- -------- + * + * An added constraint on the rectangles is that they must cover as much + * horizontal area as possible: no two rectangles within a band are allowed + * to touch. + * + * Whenever possible, bands will be merged together to cover a greater vertical + * distance (and thus reduce the number of rectangles). Two bands can be merged + * only if the bottom of one touches the top of the other and they have + * rectangles in the same places (of the same width, of course). + * + * Adam de Boor wrote most of the original region code. Joel McCormack + * substantially modified or rewrote most of the core arithmetic routines, + * and added miRegionValidate in order to support several speed improvements + * to miValidateTree. Bob Scheifler changed the representation to be more + * compact when empty or a single rectangle, and did a bunch of gratuitous + * reformatting. + */ + +/* true iff two Boxes overlap */ +#define EXTENTCHECK(r1,r2) \ + (!( ((r1)->x2 <= (r2)->x1) || \ + ((r1)->x1 >= (r2)->x2) || \ + ((r1)->y2 <= (r2)->y1) || \ + ((r1)->y1 >= (r2)->y2) ) ) + +/* true iff (x,y) is in Box */ +#define INBOX(r,x,y) \ + ( ((r)->x2 > x) && \ + ((r)->x1 <= x) && \ + ((r)->y2 > y) && \ + ((r)->y1 <= y) ) + +/* true iff Box r1 contains Box r2 */ +#define SUBSUMES(r1,r2) \ + ( ((r1)->x1 <= (r2)->x1) && \ + ((r1)->x2 >= (r2)->x2) && \ + ((r1)->y1 <= (r2)->y1) && \ + ((r1)->y2 >= (r2)->y2) ) + +#define xallocData(n) (RegDataPtr)xalloc(REGION_SZOF(n)) +#define xfreeData(reg) if ((reg)->data && (reg)->data->size) xfree((reg)->data) + +#define RECTALLOC_BAIL(pReg,n,bail) \ +if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \ + if (!miRectAlloc(pReg, n)) { goto bail; } + +#define RECTALLOC(pReg,n) \ +if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \ + if (!miRectAlloc(pReg, n)) { return FALSE; } + +#define ADDRECT(pNextRect,nx1,ny1,nx2,ny2) \ +{ \ + pNextRect->x1 = nx1; \ + pNextRect->y1 = ny1; \ + pNextRect->x2 = nx2; \ + pNextRect->y2 = ny2; \ + pNextRect++; \ +} + +#define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2) \ +{ \ + if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\ + { \ + if (!miRectAlloc(pReg, 1)) \ + return FALSE; \ + pNextRect = REGION_TOP(pReg); \ + } \ + ADDRECT(pNextRect,nx1,ny1,nx2,ny2); \ + pReg->data->numRects++; \ + assert(pReg->data->numRects<=pReg->data->size); \ +} + + +#define DOWNSIZE(reg,numRects) \ +if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \ +{ \ + RegDataPtr NewData; \ + NewData = (RegDataPtr)xrealloc((reg)->data, REGION_SZOF(numRects)); \ + if (NewData) \ + { \ + NewData->size = (numRects); \ + (reg)->data = NewData; \ + } \ +} + + +_X_EXPORT BoxRec miEmptyBox = {0, 0, 0, 0}; +_X_EXPORT RegDataRec miEmptyData = {0, 0}; + +RegDataRec miBrokenData = {0, 0}; +RegionRec miBrokenRegion = { { 0, 0, 0, 0 }, &miBrokenData }; + +#ifdef DEBUG +int +miPrintRegion(rgn) + RegionPtr rgn; +{ + int num, size; + register int i; + BoxPtr rects; + + num = REGION_NUM_RECTS(rgn); + size = REGION_SIZE(rgn); + rects = REGION_RECTS(rgn); + ErrorF("num: %d size: %d\n", num, size); + ErrorF("extents: %d %d %d %d\n", + rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2); + for (i = 0; i < num; i++) + ErrorF("%d %d %d %d \n", + rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2); + ErrorF("\n"); + return(num); +} +#endif /* DEBUG */ + +_X_EXPORT Bool +miRegionEqual(reg1, reg2) + RegionPtr reg1; + RegionPtr reg2; +{ + int i, num; + BoxPtr rects1, rects2; + + if (reg1->extents.x1 != reg2->extents.x1) return FALSE; + if (reg1->extents.x2 != reg2->extents.x2) return FALSE; + if (reg1->extents.y1 != reg2->extents.y1) return FALSE; + if (reg1->extents.y2 != reg2->extents.y2) return FALSE; + + num = REGION_NUM_RECTS(reg1); + if (num != REGION_NUM_RECTS(reg2)) return FALSE; + + rects1 = REGION_RECTS(reg1); + rects2 = REGION_RECTS(reg2); + for (i = 0; i != num; i++) { + if (rects1[i].x1 != rects2[i].x1) return FALSE; + if (rects1[i].x2 != rects2[i].x2) return FALSE; + if (rects1[i].y1 != rects2[i].y1) return FALSE; + if (rects1[i].y2 != rects2[i].y2) return FALSE; + } + return TRUE; +} + +#ifdef DEBUG +Bool +miValidRegion(reg) + RegionPtr reg; +{ + register int i, numRects; + + if ((reg->extents.x1 > reg->extents.x2) || + (reg->extents.y1 > reg->extents.y2)) + return FALSE; + numRects = REGION_NUM_RECTS(reg); + if (!numRects) + return ((reg->extents.x1 == reg->extents.x2) && + (reg->extents.y1 == reg->extents.y2) && + (reg->data->size || (reg->data == &miEmptyData))); + else if (numRects == 1) + return (!reg->data); + else + { + register BoxPtr pboxP, pboxN; + BoxRec box; + + pboxP = REGION_RECTS(reg); + box = *pboxP; + box.y2 = pboxP[numRects-1].y2; + pboxN = pboxP + 1; + for (i = numRects; --i > 0; pboxP++, pboxN++) + { + if ((pboxN->x1 >= pboxN->x2) || + (pboxN->y1 >= pboxN->y2)) + return FALSE; + if (pboxN->x1 < box.x1) + box.x1 = pboxN->x1; + if (pboxN->x2 > box.x2) + box.x2 = pboxN->x2; + if ((pboxN->y1 < pboxP->y1) || + ((pboxN->y1 == pboxP->y1) && + ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2)))) + return FALSE; + } + return ((box.x1 == reg->extents.x1) && + (box.x2 == reg->extents.x2) && + (box.y1 == reg->extents.y1) && + (box.y2 == reg->extents.y2)); + } +} + +#endif /* DEBUG */ + + +/***************************************************************** + * RegionCreate(rect, size) + * This routine does a simple malloc to make a structure of + * REGION of "size" number of rectangles. + *****************************************************************/ + +_X_EXPORT RegionPtr +miRegionCreate(rect, size) + BoxPtr rect; + int size; +{ + register RegionPtr pReg; + + pReg = (RegionPtr)xalloc(sizeof(RegionRec)); + if (!pReg) + return &miBrokenRegion; + if (rect) + { + pReg->extents = *rect; + pReg->data = (RegDataPtr)NULL; + } + else + { + pReg->extents = miEmptyBox; + if ((size > 1) && (pReg->data = xallocData(size))) + { + pReg->data->size = size; + pReg->data->numRects = 0; + } + else + pReg->data = &miEmptyData; + } + return(pReg); +} + +/***************************************************************** + * RegionInit(pReg, rect, size) + * Outer region rect is statically allocated. + *****************************************************************/ + +_X_EXPORT void +miRegionInit(pReg, rect, size) + RegionPtr pReg; + BoxPtr rect; + int size; +{ + if (rect) + { + pReg->extents = *rect; + pReg->data = (RegDataPtr)NULL; + } + else + { + pReg->extents = miEmptyBox; + if ((size > 1) && (pReg->data = xallocData(size))) + { + pReg->data->size = size; + pReg->data->numRects = 0; + } + else + pReg->data = &miEmptyData; + } +} + +_X_EXPORT void +miRegionDestroy(pReg) + RegionPtr pReg; +{ + good(pReg); + xfreeData(pReg); + if (pReg != &miBrokenRegion) + xfree(pReg); +} + +_X_EXPORT void +miRegionUninit(pReg) + RegionPtr pReg; +{ + good(pReg); + xfreeData(pReg); +} + +Bool +miRegionBreak (pReg) + RegionPtr pReg; +{ + xfreeData (pReg); + pReg->extents = miEmptyBox; + pReg->data = &miBrokenData; + return FALSE; +} + +_X_EXPORT Bool +miRectAlloc( + register RegionPtr pRgn, + int n) +{ + RegDataPtr data; + + if (!pRgn->data) + { + n++; + pRgn->data = xallocData(n); + if (!pRgn->data) + return miRegionBreak (pRgn); + pRgn->data->numRects = 1; + *REGION_BOXPTR(pRgn) = pRgn->extents; + } + else if (!pRgn->data->size) + { + pRgn->data = xallocData(n); + if (!pRgn->data) + return miRegionBreak (pRgn); + pRgn->data->numRects = 0; + } + else + { + if (n == 1) + { + n = pRgn->data->numRects; + if (n > 500) /* XXX pick numbers out of a hat */ + n = 250; + } + n += pRgn->data->numRects; + data = (RegDataPtr)xrealloc(pRgn->data, REGION_SZOF(n)); + if (!data) + return miRegionBreak (pRgn); + pRgn->data = data; + } + pRgn->data->size = n; + return TRUE; +} + +_X_EXPORT Bool +miRegionCopy(dst, src) + register RegionPtr dst; + register RegionPtr src; +{ + good(dst); + good(src); + if (dst == src) + return TRUE; + dst->extents = src->extents; + if (!src->data || !src->data->size) + { + xfreeData(dst); + dst->data = src->data; + return TRUE; + } + if (!dst->data || (dst->data->size < src->data->numRects)) + { + xfreeData(dst); + dst->data = xallocData(src->data->numRects); + if (!dst->data) + return miRegionBreak (dst); + dst->data->size = src->data->numRects; + } + dst->data->numRects = src->data->numRects; + memmove((char *)REGION_BOXPTR(dst),(char *)REGION_BOXPTR(src), + dst->data->numRects * sizeof(BoxRec)); + return TRUE; +} + + +/*====================================================================== + * Generic Region Operator + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * miCoalesce -- + * Attempt to merge the boxes in the current band with those in the + * previous one. We are guaranteed that the current band extends to + * the end of the rects array. Used only by miRegionOp. + * + * Results: + * The new index for the previous band. + * + * Side Effects: + * If coalescing takes place: + * - rectangles in the previous band will have their y2 fields + * altered. + * - pReg->data->numRects will be decreased. + * + *----------------------------------------------------------------------- + */ +INLINE static int +miCoalesce ( + register RegionPtr pReg, /* Region to coalesce */ + int prevStart, /* Index of start of previous band */ + int curStart) /* Index of start of current band */ +{ + register BoxPtr pPrevBox; /* Current box in previous band */ + register BoxPtr pCurBox; /* Current box in current band */ + register int numRects; /* Number rectangles in both bands */ + register int y2; /* Bottom of current band */ + /* + * Figure out how many rectangles are in the band. + */ + numRects = curStart - prevStart; + assert(numRects == pReg->data->numRects - curStart); + + if (!numRects) return curStart; + + /* + * The bands may only be coalesced if the bottom of the previous + * matches the top scanline of the current. + */ + pPrevBox = REGION_BOX(pReg, prevStart); + pCurBox = REGION_BOX(pReg, curStart); + if (pPrevBox->y2 != pCurBox->y1) return curStart; + + /* + * Make sure the bands have boxes in the same places. This + * assumes that boxes have been added in such a way that they + * cover the most area possible. I.e. two boxes in a band must + * have some horizontal space between them. + */ + y2 = pCurBox->y2; + + do { + if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) { + return (curStart); + } + pPrevBox++; + pCurBox++; + numRects--; + } while (numRects); + + /* + * The bands may be merged, so set the bottom y of each box + * in the previous band to the bottom y of the current band. + */ + numRects = curStart - prevStart; + pReg->data->numRects -= numRects; + do { + pPrevBox--; + pPrevBox->y2 = y2; + numRects--; + } while (numRects); + return prevStart; +} + + +/* Quicky macro to avoid trivial reject procedure calls to miCoalesce */ + +#define Coalesce(newReg, prevBand, curBand) \ + if (curBand - prevBand == newReg->data->numRects - curBand) { \ + prevBand = miCoalesce(newReg, prevBand, curBand); \ + } else { \ + prevBand = curBand; \ + } + +/*- + *----------------------------------------------------------------------- + * miAppendNonO -- + * Handle a non-overlapping band for the union and subtract operations. + * Just adds the (top/bottom-clipped) rectangles into the region. + * Doesn't have to check for subsumption or anything. + * + * Results: + * None. + * + * Side Effects: + * pReg->data->numRects is incremented and the rectangles overwritten + * with the rectangles we're passed. + * + *----------------------------------------------------------------------- + */ + +INLINE static Bool +miAppendNonO ( + register RegionPtr pReg, + register BoxPtr r, + BoxPtr rEnd, + register int y1, + register int y2) +{ + register BoxPtr pNextRect; + register int newRects; + + newRects = rEnd - r; + + assert(y1 < y2); + assert(newRects != 0); + + /* Make sure we have enough space for all rectangles to be added */ + RECTALLOC(pReg, newRects); + pNextRect = REGION_TOP(pReg); + pReg->data->numRects += newRects; + do { + assert(r->x1 < r->x2); + ADDRECT(pNextRect, r->x1, y1, r->x2, y2); + r++; + } while (r != rEnd); + + return TRUE; +} + +#define FindBand(r, rBandEnd, rEnd, ry1) \ +{ \ + ry1 = r->y1; \ + rBandEnd = r+1; \ + while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { \ + rBandEnd++; \ + } \ +} + +#define AppendRegions(newReg, r, rEnd) \ +{ \ + int newRects; \ + if ((newRects = rEnd - r)) { \ + RECTALLOC(newReg, newRects); \ + memmove((char *)REGION_TOP(newReg),(char *)r, \ + newRects * sizeof(BoxRec)); \ + newReg->data->numRects += newRects; \ + } \ +} + +/*- + *----------------------------------------------------------------------- + * miRegionOp -- + * Apply an operation to two regions. Called by miUnion, miInverse, + * miSubtract, miIntersect.... Both regions MUST have at least one + * rectangle, and cannot be the same object. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * The new region is overwritten. + * pOverlap set to TRUE if overlapFunc ever returns TRUE. + * + * Notes: + * The idea behind this function is to view the two regions as sets. + * Together they cover a rectangle of area that this function divides + * into horizontal bands where points are covered only by one region + * or by both. For the first case, the nonOverlapFunc is called with + * each the band and the band's upper and lower extents. For the + * second, the overlapFunc is called to process the entire band. It + * is responsible for clipping the rectangles in the band, though + * this function provides the boundaries. + * At the end of each band, the new region is coalesced, if possible, + * to reduce the number of rectangles in the region. + * + *----------------------------------------------------------------------- + */ + +typedef Bool (*OverlapProcPtr)( + RegionPtr pReg, + BoxPtr r1, + BoxPtr r1End, + BoxPtr r2, + BoxPtr r2End, + short y1, + short y2, + Bool *pOverlap); + +static Bool +miRegionOp( + RegionPtr newReg, /* Place to store result */ + RegionPtr reg1, /* First region in operation */ + RegionPtr reg2, /* 2d region in operation */ + OverlapProcPtr overlapFunc, /* Function to call for over- + * lapping bands */ + Bool appendNon1, /* Append non-overlapping bands */ + /* in region 1 ? */ + Bool appendNon2, /* Append non-overlapping bands */ + /* in region 2 ? */ + Bool *pOverlap) +{ + register BoxPtr r1; /* Pointer into first region */ + register BoxPtr r2; /* Pointer into 2d region */ + BoxPtr r1End; /* End of 1st region */ + BoxPtr r2End; /* End of 2d region */ + short ybot; /* Bottom of intersection */ + short ytop; /* Top of intersection */ + RegDataPtr oldData; /* Old data for newReg */ + int prevBand; /* Index of start of + * previous band in newReg */ + int curBand; /* Index of start of current + * band in newReg */ + register BoxPtr r1BandEnd; /* End of current band in r1 */ + register BoxPtr r2BandEnd; /* End of current band in r2 */ + short top; /* Top of non-overlapping band */ + short bot; /* Bottom of non-overlapping band*/ + register int r1y1; /* Temps for r1->y1 and r2->y1 */ + register int r2y1; + int newSize; + int numRects; + + /* + * Break any region computed from a broken region + */ + if (REGION_NAR (reg1) || REGION_NAR(reg2)) + return miRegionBreak (newReg); + + /* + * Initialization: + * set r1, r2, r1End and r2End appropriately, save the rectangles + * of the destination region until the end in case it's one of + * the two source regions, then mark the "new" region empty, allocating + * another array of rectangles for it to use. + */ + + r1 = REGION_RECTS(reg1); + newSize = REGION_NUM_RECTS(reg1); + r1End = r1 + newSize; + numRects = REGION_NUM_RECTS(reg2); + r2 = REGION_RECTS(reg2); + r2End = r2 + numRects; + assert(r1 != r1End); + assert(r2 != r2End); + + oldData = (RegDataPtr)NULL; + if (((newReg == reg1) && (newSize > 1)) || + ((newReg == reg2) && (numRects > 1))) + { + oldData = newReg->data; + newReg->data = &miEmptyData; + } + /* guess at new size */ + if (numRects > newSize) + newSize = numRects; + newSize <<= 1; + if (!newReg->data) + newReg->data = &miEmptyData; + else if (newReg->data->size) + newReg->data->numRects = 0; + if (newSize > newReg->data->size) + if (!miRectAlloc(newReg, newSize)) + return FALSE; + + /* + * Initialize ybot. + * In the upcoming loop, ybot and ytop serve different functions depending + * on whether the band being handled is an overlapping or non-overlapping + * band. + * In the case of a non-overlapping band (only one of the regions + * has points in the band), ybot is the bottom of the most recent + * intersection and thus clips the top of the rectangles in that band. + * ytop is the top of the next intersection between the two regions and + * serves to clip the bottom of the rectangles in the current band. + * For an overlapping band (where the two regions intersect), ytop clips + * the top of the rectangles of both regions and ybot clips the bottoms. + */ + + ybot = min(r1->y1, r2->y1); + + /* + * prevBand serves to mark the start of the previous band so rectangles + * can be coalesced into larger rectangles. qv. miCoalesce, above. + * In the beginning, there is no previous band, so prevBand == curBand + * (curBand is set later on, of course, but the first band will always + * start at index 0). prevBand and curBand must be indices because of + * the possible expansion, and resultant moving, of the new region's + * array of rectangles. + */ + prevBand = 0; + + do { + /* + * This algorithm proceeds one source-band (as opposed to a + * destination band, which is determined by where the two regions + * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the + * rectangle after the last one in the current band for their + * respective regions. + */ + assert(r1 != r1End); + assert(r2 != r2End); + + FindBand(r1, r1BandEnd, r1End, r1y1); + FindBand(r2, r2BandEnd, r2End, r2y1); + + /* + * First handle the band that doesn't intersect, if any. + * + * Note that attention is restricted to one band in the + * non-intersecting region at once, so if a region has n + * bands between the current position and the next place it overlaps + * the other, this entire loop will be passed through n times. + */ + if (r1y1 < r2y1) { + if (appendNon1) { + top = max(r1y1, ybot); + bot = min(r1->y2, r2y1); + if (top != bot) { + curBand = newReg->data->numRects; + miAppendNonO(newReg, r1, r1BandEnd, top, bot); + Coalesce(newReg, prevBand, curBand); + } + } + ytop = r2y1; + } else if (r2y1 < r1y1) { + if (appendNon2) { + top = max(r2y1, ybot); + bot = min(r2->y2, r1y1); + if (top != bot) { + curBand = newReg->data->numRects; + miAppendNonO(newReg, r2, r2BandEnd, top, bot); + Coalesce(newReg, prevBand, curBand); + } + } + ytop = r1y1; + } else { + ytop = r1y1; + } + + /* + * Now see if we've hit an intersecting band. The two bands only + * intersect if ybot > ytop + */ + ybot = min(r1->y2, r2->y2); + if (ybot > ytop) { + curBand = newReg->data->numRects; + (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, + pOverlap); + Coalesce(newReg, prevBand, curBand); + } + + /* + * If we've finished with a band (y2 == ybot) we skip forward + * in the region to the next band. + */ + if (r1->y2 == ybot) r1 = r1BandEnd; + if (r2->y2 == ybot) r2 = r2BandEnd; + + } while (r1 != r1End && r2 != r2End); + + /* + * Deal with whichever region (if any) still has rectangles left. + * + * We only need to worry about banding and coalescing for the very first + * band left. After that, we can just group all remaining boxes, + * regardless of how many bands, into one final append to the list. + */ + + if ((r1 != r1End) && appendNon1) { + /* Do first nonOverlap1Func call, which may be able to coalesce */ + FindBand(r1, r1BandEnd, r1End, r1y1); + curBand = newReg->data->numRects; + miAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2); + Coalesce(newReg, prevBand, curBand); + /* Just append the rest of the boxes */ + AppendRegions(newReg, r1BandEnd, r1End); + + } else if ((r2 != r2End) && appendNon2) { + /* Do first nonOverlap2Func call, which may be able to coalesce */ + FindBand(r2, r2BandEnd, r2End, r2y1); + curBand = newReg->data->numRects; + miAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2); + Coalesce(newReg, prevBand, curBand); + /* Append rest of boxes */ + AppendRegions(newReg, r2BandEnd, r2End); + } + + if (oldData) + xfree(oldData); + + if (!(numRects = newReg->data->numRects)) + { + xfreeData(newReg); + newReg->data = &miEmptyData; + } + else if (numRects == 1) + { + newReg->extents = *REGION_BOXPTR(newReg); + xfreeData(newReg); + newReg->data = (RegDataPtr)NULL; + } + else + { + DOWNSIZE(newReg, numRects); + } + + return TRUE; +} + +/*- + *----------------------------------------------------------------------- + * miSetExtents -- + * Reset the extents of a region to what they should be. Called by + * miSubtract and miIntersect as they can't figure it out along the + * way or do so easily, as miUnion can. + * + * Results: + * None. + * + * Side Effects: + * The region's 'extents' structure is overwritten. + * + *----------------------------------------------------------------------- + */ +void +miSetExtents (pReg) + register RegionPtr pReg; +{ + register BoxPtr pBox, pBoxEnd; + + if (!pReg->data) + return; + if (!pReg->data->size) + { + pReg->extents.x2 = pReg->extents.x1; + pReg->extents.y2 = pReg->extents.y1; + return; + } + + pBox = REGION_BOXPTR(pReg); + pBoxEnd = REGION_END(pReg); + + /* + * Since pBox is the first rectangle in the region, it must have the + * smallest y1 and since pBoxEnd is the last rectangle in the region, + * it must have the largest y2, because of banding. Initialize x1 and + * x2 from pBox and pBoxEnd, resp., as good things to initialize them + * to... + */ + pReg->extents.x1 = pBox->x1; + pReg->extents.y1 = pBox->y1; + pReg->extents.x2 = pBoxEnd->x2; + pReg->extents.y2 = pBoxEnd->y2; + + assert(pReg->extents.y1 < pReg->extents.y2); + while (pBox <= pBoxEnd) { + if (pBox->x1 < pReg->extents.x1) + pReg->extents.x1 = pBox->x1; + if (pBox->x2 > pReg->extents.x2) + pReg->extents.x2 = pBox->x2; + pBox++; + }; + + assert(pReg->extents.x1 < pReg->extents.x2); +} + +/*====================================================================== + * Region Intersection + *====================================================================*/ +/*- + *----------------------------------------------------------------------- + * miIntersectO -- + * Handle an overlapping band for miIntersect. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * Rectangles may be added to the region. + * + *----------------------------------------------------------------------- + */ +/*ARGSUSED*/ +static Bool +miIntersectO ( + register RegionPtr pReg, + register BoxPtr r1, + BoxPtr r1End, + register BoxPtr r2, + BoxPtr r2End, + short y1, + short y2, + Bool *pOverlap) +{ + register int x1; + register int x2; + register BoxPtr pNextRect; + + pNextRect = REGION_TOP(pReg); + + assert(y1 < y2); + assert(r1 != r1End && r2 != r2End); + + do { + x1 = max(r1->x1, r2->x1); + x2 = min(r1->x2, r2->x2); + + /* + * If there's any overlap between the two rectangles, add that + * overlap to the new region. + */ + if (x1 < x2) + NEWRECT(pReg, pNextRect, x1, y1, x2, y2); + + /* + * Advance the pointer(s) with the leftmost right side, since the next + * rectangle on that list may still overlap the other region's + * current rectangle. + */ + if (r1->x2 == x2) { + r1++; + } + if (r2->x2 == x2) { + r2++; + } + } while ((r1 != r1End) && (r2 != r2End)); + + return TRUE; +} + + +_X_EXPORT Bool +miIntersect(newReg, reg1, reg2) + register RegionPtr newReg; /* destination Region */ + register RegionPtr reg1; + register RegionPtr reg2; /* source regions */ +{ + good(reg1); + good(reg2); + good(newReg); + /* check for trivial reject */ + if (REGION_NIL(reg1) || REGION_NIL(reg2) || + !EXTENTCHECK(®1->extents, ®2->extents)) + { + /* Covers about 20% of all cases */ + xfreeData(newReg); + newReg->extents.x2 = newReg->extents.x1; + newReg->extents.y2 = newReg->extents.y1; + if (REGION_NAR(reg1) || REGION_NAR(reg2)) + { + newReg->data = &miBrokenData; + return FALSE; + } + else + newReg->data = &miEmptyData; + } + else if (!reg1->data && !reg2->data) + { + /* Covers about 80% of cases that aren't trivially rejected */ + newReg->extents.x1 = max(reg1->extents.x1, reg2->extents.x1); + newReg->extents.y1 = max(reg1->extents.y1, reg2->extents.y1); + newReg->extents.x2 = min(reg1->extents.x2, reg2->extents.x2); + newReg->extents.y2 = min(reg1->extents.y2, reg2->extents.y2); + xfreeData(newReg); + newReg->data = (RegDataPtr)NULL; + } + else if (!reg2->data && SUBSUMES(®2->extents, ®1->extents)) + { + return miRegionCopy(newReg, reg1); + } + else if (!reg1->data && SUBSUMES(®1->extents, ®2->extents)) + { + return miRegionCopy(newReg, reg2); + } + else if (reg1 == reg2) + { + return miRegionCopy(newReg, reg1); + } + else + { + /* General purpose intersection */ + Bool overlap; /* result ignored */ + if (!miRegionOp(newReg, reg1, reg2, miIntersectO, FALSE, FALSE, + &overlap)) + return FALSE; + miSetExtents(newReg); + } + + good(newReg); + return(TRUE); +} + +#define MERGERECT(r) \ +{ \ + if (r->x1 <= x2) { \ + /* Merge with current rectangle */ \ + if (r->x1 < x2) *pOverlap = TRUE; \ + if (x2 < r->x2) x2 = r->x2; \ + } else { \ + /* Add current rectangle, start new one */ \ + NEWRECT(pReg, pNextRect, x1, y1, x2, y2); \ + x1 = r->x1; \ + x2 = r->x2; \ + } \ + r++; \ +} + +/*====================================================================== + * Region Union + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * miUnionO -- + * Handle an overlapping band for the union operation. Picks the + * left-most rectangle each time and merges it into the region. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * pReg is overwritten. + * pOverlap is set to TRUE if any boxes overlap. + * + *----------------------------------------------------------------------- + */ +static Bool +miUnionO ( + register RegionPtr pReg, + register BoxPtr r1, + BoxPtr r1End, + register BoxPtr r2, + BoxPtr r2End, + short y1, + short y2, + Bool *pOverlap) +{ + register BoxPtr pNextRect; + register int x1; /* left and right side of current union */ + register int x2; + + assert (y1 < y2); + assert(r1 != r1End && r2 != r2End); + + pNextRect = REGION_TOP(pReg); + + /* Start off current rectangle */ + if (r1->x1 < r2->x1) + { + x1 = r1->x1; + x2 = r1->x2; + r1++; + } + else + { + x1 = r2->x1; + x2 = r2->x2; + r2++; + } + while (r1 != r1End && r2 != r2End) + { + if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2); + } + + /* Finish off whoever (if any) is left */ + if (r1 != r1End) + { + do + { + MERGERECT(r1); + } while (r1 != r1End); + } + else if (r2 != r2End) + { + do + { + MERGERECT(r2); + } while (r2 != r2End); + } + + /* Add current rectangle */ + NEWRECT(pReg, pNextRect, x1, y1, x2, y2); + + return TRUE; +} + +_X_EXPORT Bool +miUnion(newReg, reg1, reg2) + RegionPtr newReg; /* destination Region */ + register RegionPtr reg1; + register RegionPtr reg2; /* source regions */ +{ + Bool overlap; /* result ignored */ + + /* Return TRUE if some overlap between reg1, reg2 */ + good(reg1); + good(reg2); + good(newReg); + /* checks all the simple cases */ + + /* + * Region 1 and 2 are the same + */ + if (reg1 == reg2) + { + return miRegionCopy(newReg, reg1); + } + + /* + * Region 1 is empty + */ + if (REGION_NIL(reg1)) + { + if (REGION_NAR(reg1)) + return miRegionBreak (newReg); + if (newReg != reg2) + return miRegionCopy(newReg, reg2); + return TRUE; + } + + /* + * Region 2 is empty + */ + if (REGION_NIL(reg2)) + { + if (REGION_NAR(reg2)) + return miRegionBreak (newReg); + if (newReg != reg1) + return miRegionCopy(newReg, reg1); + return TRUE; + } + + /* + * Region 1 completely subsumes region 2 + */ + if (!reg1->data && SUBSUMES(®1->extents, ®2->extents)) + { + if (newReg != reg1) + return miRegionCopy(newReg, reg1); + return TRUE; + } + + /* + * Region 2 completely subsumes region 1 + */ + if (!reg2->data && SUBSUMES(®2->extents, ®1->extents)) + { + if (newReg != reg2) + return miRegionCopy(newReg, reg2); + return TRUE; + } + + if (!miRegionOp(newReg, reg1, reg2, miUnionO, TRUE, TRUE, &overlap)) + return FALSE; + + newReg->extents.x1 = min(reg1->extents.x1, reg2->extents.x1); + newReg->extents.y1 = min(reg1->extents.y1, reg2->extents.y1); + newReg->extents.x2 = max(reg1->extents.x2, reg2->extents.x2); + newReg->extents.y2 = max(reg1->extents.y2, reg2->extents.y2); + good(newReg); + return TRUE; +} + + +/*====================================================================== + * Batch Rectangle Union + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * miRegionAppend -- + * + * "Append" the rgn rectangles onto the end of dstrgn, maintaining + * knowledge of YX-banding when it's easy. Otherwise, dstrgn just + * becomes a non-y-x-banded random collection of rectangles, and not + * yet a true region. After a sequence of appends, the caller must + * call miRegionValidate to ensure that a valid region is constructed. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * dstrgn is modified if rgn has rectangles. + * + */ +_X_EXPORT Bool +miRegionAppend(dstrgn, rgn) + register RegionPtr dstrgn; + register RegionPtr rgn; +{ + int numRects, dnumRects, size; + BoxPtr new, old; + Bool prepend; + + if (REGION_NAR(rgn)) + return miRegionBreak (dstrgn); + + if (!rgn->data && (dstrgn->data == &miEmptyData)) + { + dstrgn->extents = rgn->extents; + dstrgn->data = (RegDataPtr)NULL; + return TRUE; + } + + numRects = REGION_NUM_RECTS(rgn); + if (!numRects) + return TRUE; + prepend = FALSE; + size = numRects; + dnumRects = REGION_NUM_RECTS(dstrgn); + if (!dnumRects && (size < 200)) + size = 200; /* XXX pick numbers out of a hat */ + RECTALLOC(dstrgn, size); + old = REGION_RECTS(rgn); + if (!dnumRects) + dstrgn->extents = rgn->extents; + else if (dstrgn->extents.x2 > dstrgn->extents.x1) + { + register BoxPtr first, last; + + first = old; + last = REGION_BOXPTR(dstrgn) + (dnumRects - 1); + if ((first->y1 > last->y2) || + ((first->y1 == last->y1) && (first->y2 == last->y2) && + (first->x1 > last->x2))) + { + if (rgn->extents.x1 < dstrgn->extents.x1) + dstrgn->extents.x1 = rgn->extents.x1; + if (rgn->extents.x2 > dstrgn->extents.x2) + dstrgn->extents.x2 = rgn->extents.x2; + dstrgn->extents.y2 = rgn->extents.y2; + } + else + { + first = REGION_BOXPTR(dstrgn); + last = old + (numRects - 1); + if ((first->y1 > last->y2) || + ((first->y1 == last->y1) && (first->y2 == last->y2) && + (first->x1 > last->x2))) + { + prepend = TRUE; + if (rgn->extents.x1 < dstrgn->extents.x1) + dstrgn->extents.x1 = rgn->extents.x1; + if (rgn->extents.x2 > dstrgn->extents.x2) + dstrgn->extents.x2 = rgn->extents.x2; + dstrgn->extents.y1 = rgn->extents.y1; + } + else + dstrgn->extents.x2 = dstrgn->extents.x1; + } + } + if (prepend) + { + new = REGION_BOX(dstrgn, numRects); + if (dnumRects == 1) + *new = *REGION_BOXPTR(dstrgn); + else + memmove((char *)new,(char *)REGION_BOXPTR(dstrgn), + dnumRects * sizeof(BoxRec)); + new = REGION_BOXPTR(dstrgn); + } + else + new = REGION_BOXPTR(dstrgn) + dnumRects; + if (numRects == 1) + *new = *old; + else + memmove((char *)new, (char *)old, numRects * sizeof(BoxRec)); + dstrgn->data->numRects += numRects; + return TRUE; +} + + +#define ExchangeRects(a, b) \ +{ \ + BoxRec t; \ + t = rects[a]; \ + rects[a] = rects[b]; \ + rects[b] = t; \ +} + +static void +QuickSortRects( + register BoxRec rects[], + register int numRects) +{ + register int y1; + register int x1; + register int i, j; + register BoxPtr r; + + /* Always called with numRects > 1 */ + + do + { + if (numRects == 2) + { + if (rects[0].y1 > rects[1].y1 || + (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1)) + ExchangeRects(0, 1); + return; + } + + /* Choose partition element, stick in location 0 */ + ExchangeRects(0, numRects >> 1); + y1 = rects[0].y1; + x1 = rects[0].x1; + + /* Partition array */ + i = 0; + j = numRects; + do + { + r = &(rects[i]); + do + { + r++; + i++; + } while (i != numRects && + (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1))); + r = &(rects[j]); + do + { + r--; + j--; + } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1)); + if (i < j) + ExchangeRects(i, j); + } while (i < j); + + /* Move partition element back to middle */ + ExchangeRects(0, j); + + /* Recurse */ + if (numRects-j-1 > 1) + QuickSortRects(&rects[j+1], numRects-j-1); + numRects = j; + } while (numRects > 1); +} + +/*- + *----------------------------------------------------------------------- + * miRegionValidate -- + * + * Take a ``region'' which is a non-y-x-banded random collection of + * rectangles, and compute a nice region which is the union of all the + * rectangles. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * The passed-in ``region'' may be modified. + * pOverlap set to TRUE if any retangles overlapped, else FALSE; + * + * Strategy: + * Step 1. Sort the rectangles into ascending order with primary key y1 + * and secondary key x1. + * + * Step 2. Split the rectangles into the minimum number of proper y-x + * banded regions. This may require horizontally merging + * rectangles, and vertically coalescing bands. With any luck, + * this step in an identity tranformation (ala the Box widget), + * or a coalescing into 1 box (ala Menus). + * + * Step 3. Merge the separate regions down to a single region by calling + * miUnion. Maximize the work each miUnion call does by using + * a binary merge. + * + *----------------------------------------------------------------------- + */ + +_X_EXPORT Bool +miRegionValidate(badreg, pOverlap) + RegionPtr badreg; + Bool *pOverlap; +{ + /* Descriptor for regions under construction in Step 2. */ + typedef struct { + RegionRec reg; + int prevBand; + int curBand; + } RegionInfo; + + int numRects; /* Original numRects for badreg */ + RegionInfo *ri; /* Array of current regions */ + int numRI; /* Number of entries used in ri */ + int sizeRI; /* Number of entries available in ri */ + int i; /* Index into rects */ + register int j; /* Index into ri */ + register RegionInfo *rit; /* &ri[j] */ + register RegionPtr reg; /* ri[j].reg */ + register BoxPtr box; /* Current box in rects */ + register BoxPtr riBox; /* Last box in ri[j].reg */ + register RegionPtr hreg; /* ri[j_half].reg */ + Bool ret = TRUE; + + *pOverlap = FALSE; + if (!badreg->data) + { + good(badreg); + return TRUE; + } + numRects = badreg->data->numRects; + if (!numRects) + { + if (REGION_NAR(badreg)) + return FALSE; + good(badreg); + return TRUE; + } + if (badreg->extents.x1 < badreg->extents.x2) + { + if ((numRects) == 1) + { + xfreeData(badreg); + badreg->data = (RegDataPtr) NULL; + } + else + { + DOWNSIZE(badreg, numRects); + } + good(badreg); + return TRUE; + } + + /* Step 1: Sort the rects array into ascending (y1, x1) order */ + QuickSortRects(REGION_BOXPTR(badreg), numRects); + + /* Step 2: Scatter the sorted array into the minimum number of regions */ + + /* Set up the first region to be the first rectangle in badreg */ + /* Note that step 2 code will never overflow the ri[0].reg rects array */ + ri = (RegionInfo *) xalloc(4 * sizeof(RegionInfo)); + if (!ri) + return miRegionBreak (badreg); + sizeRI = 4; + numRI = 1; + ri[0].prevBand = 0; + ri[0].curBand = 0; + ri[0].reg = *badreg; + box = REGION_BOXPTR(&ri[0].reg); + ri[0].reg.extents = *box; + ri[0].reg.data->numRects = 1; + + /* Now scatter rectangles into the minimum set of valid regions. If the + next rectangle to be added to a region would force an existing rectangle + in the region to be split up in order to maintain y-x banding, just + forget it. Try the next region. If it doesn't fit cleanly into any + region, make a new one. */ + + for (i = numRects; --i > 0;) + { + box++; + /* Look for a region to append box to */ + for (j = numRI, rit = ri; --j >= 0; rit++) + { + reg = &rit->reg; + riBox = REGION_END(reg); + + if (box->y1 == riBox->y1 && box->y2 == riBox->y2) + { + /* box is in same band as riBox. Merge or append it */ + if (box->x1 <= riBox->x2) + { + /* Merge it with riBox */ + if (box->x1 < riBox->x2) *pOverlap = TRUE; + if (box->x2 > riBox->x2) riBox->x2 = box->x2; + } + else + { + RECTALLOC_BAIL(reg, 1, bail); + *REGION_TOP(reg) = *box; + reg->data->numRects++; + } + goto NextRect; /* So sue me */ + } + else if (box->y1 >= riBox->y2) + { + /* Put box into new band */ + if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2; + if (reg->extents.x1 > box->x1) reg->extents.x1 = box->x1; + Coalesce(reg, rit->prevBand, rit->curBand); + rit->curBand = reg->data->numRects; + RECTALLOC_BAIL(reg, 1, bail); + *REGION_TOP(reg) = *box; + reg->data->numRects++; + goto NextRect; + } + /* Well, this region was inappropriate. Try the next one. */ + } /* for j */ + + /* Uh-oh. No regions were appropriate. Create a new one. */ + if (sizeRI == numRI) + { + /* Oops, allocate space for new region information */ + sizeRI <<= 1; + rit = (RegionInfo *) xrealloc(ri, sizeRI * sizeof(RegionInfo)); + if (!rit) + goto bail; + ri = rit; + rit = &ri[numRI]; + } + numRI++; + rit->prevBand = 0; + rit->curBand = 0; + rit->reg.extents = *box; + rit->reg.data = (RegDataPtr)NULL; + if (!miRectAlloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */ + goto bail; +NextRect: ; + } /* for i */ + + /* Make a final pass over each region in order to Coalesce and set + extents.x2 and extents.y2 */ + + for (j = numRI, rit = ri; --j >= 0; rit++) + { + reg = &rit->reg; + riBox = REGION_END(reg); + reg->extents.y2 = riBox->y2; + if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2; + Coalesce(reg, rit->prevBand, rit->curBand); + if (reg->data->numRects == 1) /* keep unions happy below */ + { + xfreeData(reg); + reg->data = (RegDataPtr)NULL; + } + } + + /* Step 3: Union all regions into a single region */ + while (numRI > 1) + { + int half = numRI/2; + for (j = numRI & 1; j < (half + (numRI & 1)); j++) + { + reg = &ri[j].reg; + hreg = &ri[j+half].reg; + if (!miRegionOp(reg, reg, hreg, miUnionO, TRUE, TRUE, pOverlap)) + ret = FALSE; + if (hreg->extents.x1 < reg->extents.x1) + reg->extents.x1 = hreg->extents.x1; + if (hreg->extents.y1 < reg->extents.y1) + reg->extents.y1 = hreg->extents.y1; + if (hreg->extents.x2 > reg->extents.x2) + reg->extents.x2 = hreg->extents.x2; + if (hreg->extents.y2 > reg->extents.y2) + reg->extents.y2 = hreg->extents.y2; + xfreeData(hreg); + } + numRI -= half; + } + *badreg = ri[0].reg; + xfree(ri); + good(badreg); + return ret; +bail: + for (i = 0; i < numRI; i++) + xfreeData(&ri[i].reg); + xfree (ri); + return miRegionBreak (badreg); +} + +_X_EXPORT RegionPtr +miRectsToRegion(nrects, prect, ctype) + int nrects; + register xRectangle *prect; + int ctype; +{ + register RegionPtr pRgn; + register RegDataPtr pData; + register BoxPtr pBox; + register int i; + int x1, y1, x2, y2; + + pRgn = miRegionCreate(NullBox, 0); + if (REGION_NAR (pRgn)) + return pRgn; + if (!nrects) + return pRgn; + if (nrects == 1) + { + x1 = prect->x; + y1 = prect->y; + if ((x2 = x1 + (int) prect->width) > MAXSHORT) + x2 = MAXSHORT; + if ((y2 = y1 + (int) prect->height) > MAXSHORT) + y2 = MAXSHORT; + if (x1 != x2 && y1 != y2) + { + pRgn->extents.x1 = x1; + pRgn->extents.y1 = y1; + pRgn->extents.x2 = x2; + pRgn->extents.y2 = y2; + pRgn->data = (RegDataPtr)NULL; + } + return pRgn; + } + pData = xallocData(nrects); + if (!pData) + { + miRegionBreak (pRgn); + return pRgn; + } + pBox = (BoxPtr) (pData + 1); + for (i = nrects; --i >= 0; prect++) + { + x1 = prect->x; + y1 = prect->y; + if ((x2 = x1 + (int) prect->width) > MAXSHORT) + x2 = MAXSHORT; + if ((y2 = y1 + (int) prect->height) > MAXSHORT) + y2 = MAXSHORT; + if (x1 != x2 && y1 != y2) + { + pBox->x1 = x1; + pBox->y1 = y1; + pBox->x2 = x2; + pBox->y2 = y2; + pBox++; + } + } + if (pBox != (BoxPtr) (pData + 1)) + { + pData->size = nrects; + pData->numRects = pBox - (BoxPtr) (pData + 1); + pRgn->data = pData; + if (ctype != CT_YXBANDED) + { + Bool overlap; /* result ignored */ + pRgn->extents.x1 = pRgn->extents.x2 = 0; + miRegionValidate(pRgn, &overlap); + } + else + miSetExtents(pRgn); + good(pRgn); + } + else + { + xfree (pData); + } + return pRgn; +} + +/*====================================================================== + * Region Subtraction + *====================================================================*/ + + +/*- + *----------------------------------------------------------------------- + * miSubtractO -- + * Overlapping band subtraction. x1 is the left-most point not yet + * checked. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * pReg may have rectangles added to it. + * + *----------------------------------------------------------------------- + */ +/*ARGSUSED*/ +static Bool +miSubtractO ( + register RegionPtr pReg, + register BoxPtr r1, + BoxPtr r1End, + register BoxPtr r2, + BoxPtr r2End, + register short y1, + short y2, + Bool *pOverlap) +{ + register BoxPtr pNextRect; + register int x1; + + x1 = r1->x1; + + assert(y1<y2); + assert(r1 != r1End && r2 != r2End); + + pNextRect = REGION_TOP(pReg); + + do + { + if (r2->x2 <= x1) + { + /* + * Subtrahend entirely to left of minuend: go to next subtrahend. + */ + r2++; + } + else if (r2->x1 <= x1) + { + /* + * Subtrahend preceeds minuend: nuke left edge of minuend. + */ + x1 = r2->x2; + if (x1 >= r1->x2) + { + /* + * Minuend completely covered: advance to next minuend and + * reset left fence to edge of new minuend. + */ + r1++; + if (r1 != r1End) + x1 = r1->x1; + } + else + { + /* + * Subtrahend now used up since it doesn't extend beyond + * minuend + */ + r2++; + } + } + else if (r2->x1 < r1->x2) + { + /* + * Left part of subtrahend covers part of minuend: add uncovered + * part of minuend to region and skip to next subtrahend. + */ + assert(x1<r2->x1); + NEWRECT(pReg, pNextRect, x1, y1, r2->x1, y2); + + x1 = r2->x2; + if (x1 >= r1->x2) + { + /* + * Minuend used up: advance to new... + */ + r1++; + if (r1 != r1End) + x1 = r1->x1; + } + else + { + /* + * Subtrahend used up + */ + r2++; + } + } + else + { + /* + * Minuend used up: add any remaining piece before advancing. + */ + if (r1->x2 > x1) + NEWRECT(pReg, pNextRect, x1, y1, r1->x2, y2); + r1++; + if (r1 != r1End) + x1 = r1->x1; + } + } while ((r1 != r1End) && (r2 != r2End)); + + + /* + * Add remaining minuend rectangles to region. + */ + while (r1 != r1End) + { + assert(x1<r1->x2); + NEWRECT(pReg, pNextRect, x1, y1, r1->x2, y2); + r1++; + if (r1 != r1End) + x1 = r1->x1; + } + return TRUE; +} + +/*- + *----------------------------------------------------------------------- + * miSubtract -- + * Subtract regS from regM and leave the result in regD. + * S stands for subtrahend, M for minuend and D for difference. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * regD is overwritten. + * + *----------------------------------------------------------------------- + */ +_X_EXPORT Bool +miSubtract(regD, regM, regS) + register RegionPtr regD; + register RegionPtr regM; + register RegionPtr regS; +{ + Bool overlap; /* result ignored */ + + good(regM); + good(regS); + good(regD); + /* check for trivial rejects */ + if (REGION_NIL(regM) || REGION_NIL(regS) || + !EXTENTCHECK(®M->extents, ®S->extents)) + { + if (REGION_NAR (regS)) + return miRegionBreak (regD); + return miRegionCopy(regD, regM); + } + else if (regM == regS) + { + xfreeData(regD); + regD->extents.x2 = regD->extents.x1; + regD->extents.y2 = regD->extents.y1; + regD->data = &miEmptyData; + return TRUE; + } + + /* Add those rectangles in region 1 that aren't in region 2, + do yucky substraction for overlaps, and + just throw away rectangles in region 2 that aren't in region 1 */ + if (!miRegionOp(regD, regM, regS, miSubtractO, TRUE, FALSE, &overlap)) + return FALSE; + + /* + * Can't alter RegD's extents before we call miRegionOp because + * it might be one of the source regions and miRegionOp depends + * on the extents of those regions being unaltered. Besides, this + * way there's no checking against rectangles that will be nuked + * due to coalescing, so we have to examine fewer rectangles. + */ + miSetExtents(regD); + good(regD); + return TRUE; +} + +/*====================================================================== + * Region Inversion + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * miInverse -- + * Take a region and a box and return a region that is everything + * in the box but not in the region. The careful reader will note + * that this is the same as subtracting the region from the box... + * + * Results: + * TRUE. + * + * Side Effects: + * newReg is overwritten. + * + *----------------------------------------------------------------------- + */ +_X_EXPORT Bool +miInverse(newReg, reg1, invRect) + RegionPtr newReg; /* Destination region */ + RegionPtr reg1; /* Region to invert */ + BoxPtr invRect; /* Bounding box for inversion */ +{ + RegionRec invReg; /* Quick and dirty region made from the + * bounding box */ + Bool overlap; /* result ignored */ + + good(reg1); + good(newReg); + /* check for trivial rejects */ + if (REGION_NIL(reg1) || !EXTENTCHECK(invRect, ®1->extents)) + { + if (REGION_NAR(reg1)) + return miRegionBreak (newReg); + newReg->extents = *invRect; + xfreeData(newReg); + newReg->data = (RegDataPtr)NULL; + return TRUE; + } + + /* Add those rectangles in region 1 that aren't in region 2, + do yucky substraction for overlaps, and + just throw away rectangles in region 2 that aren't in region 1 */ + invReg.extents = *invRect; + invReg.data = (RegDataPtr)NULL; + if (!miRegionOp(newReg, &invReg, reg1, miSubtractO, TRUE, FALSE, &overlap)) + return FALSE; + + /* + * Can't alter newReg's extents before we call miRegionOp because + * it might be one of the source regions and miRegionOp depends + * on the extents of those regions being unaltered. Besides, this + * way there's no checking against rectangles that will be nuked + * due to coalescing, so we have to examine fewer rectangles. + */ + miSetExtents(newReg); + good(newReg); + return TRUE; +} + +/* + * RectIn(region, rect) + * This routine takes a pointer to a region and a pointer to a box + * and determines if the box is outside/inside/partly inside the region. + * + * The idea is to travel through the list of rectangles trying to cover the + * passed box with them. Anytime a piece of the rectangle isn't covered + * by a band of rectangles, partOut is set TRUE. Any time a rectangle in + * the region covers part of the box, partIn is set TRUE. The process ends + * when either the box has been completely covered (we reached a band that + * doesn't overlap the box, partIn is TRUE and partOut is false), the + * box has been partially covered (partIn == partOut == TRUE -- because of + * the banding, the first time this is true we know the box is only + * partially in the region) or is outside the region (we reached a band + * that doesn't overlap the box at all and partIn is false) + */ + +_X_EXPORT int +miRectIn(region, prect) + register RegionPtr region; + register BoxPtr prect; +{ + register int x; + register int y; + register BoxPtr pbox; + register BoxPtr pboxEnd; + int partIn, partOut; + int numRects; + + good(region); + numRects = REGION_NUM_RECTS(region); + /* useful optimization */ + if (!numRects || !EXTENTCHECK(®ion->extents, prect)) + return(rgnOUT); + + if (numRects == 1) + { + /* We know that it must be rgnIN or rgnPART */ + if (SUBSUMES(®ion->extents, prect)) + return(rgnIN); + else + return(rgnPART); + } + + partOut = FALSE; + partIn = FALSE; + + /* (x,y) starts at upper left of rect, moving to the right and down */ + x = prect->x1; + y = prect->y1; + + /* can stop when both partOut and partIn are TRUE, or we reach prect->y2 */ + for (pbox = REGION_BOXPTR(region), pboxEnd = pbox + numRects; + pbox != pboxEnd; + pbox++) + { + + if (pbox->y2 <= y) + continue; /* getting up to speed or skipping remainder of band */ + + if (pbox->y1 > y) + { + partOut = TRUE; /* missed part of rectangle above */ + if (partIn || (pbox->y1 >= prect->y2)) + break; + y = pbox->y1; /* x guaranteed to be == prect->x1 */ + } + + if (pbox->x2 <= x) + continue; /* not far enough over yet */ + + if (pbox->x1 > x) + { + partOut = TRUE; /* missed part of rectangle to left */ + if (partIn) + break; + } + + if (pbox->x1 < prect->x2) + { + partIn = TRUE; /* definitely overlap */ + if (partOut) + break; + } + + if (pbox->x2 >= prect->x2) + { + y = pbox->y2; /* finished with this band */ + if (y >= prect->y2) + break; + x = prect->x1; /* reset x out to left again */ + } + else + { + /* + * Because boxes in a band are maximal width, if the first box + * to overlap the rectangle doesn't completely cover it in that + * band, the rectangle must be partially out, since some of it + * will be uncovered in that band. partIn will have been set true + * by now... + */ + partOut = TRUE; + break; + } + } + + return(partIn ? ((y < prect->y2) ? rgnPART : rgnIN) : rgnOUT); +} + +/* TranslateRegion(pReg, x, y) + translates in place +*/ + +_X_EXPORT void +miTranslateRegion(pReg, x, y) + register RegionPtr pReg; + register int x; + register int y; +{ + int x1, x2, y1, y2; + register int nbox; + register BoxPtr pbox; + + good(pReg); + pReg->extents.x1 = x1 = pReg->extents.x1 + x; + pReg->extents.y1 = y1 = pReg->extents.y1 + y; + pReg->extents.x2 = x2 = pReg->extents.x2 + x; + pReg->extents.y2 = y2 = pReg->extents.y2 + y; + if (((x1 - MINSHORT)|(y1 - MINSHORT)|(MAXSHORT - x2)|(MAXSHORT - y2)) >= 0) + { + if (pReg->data && (nbox = pReg->data->numRects)) + { + for (pbox = REGION_BOXPTR(pReg); nbox--; pbox++) + { + pbox->x1 += x; + pbox->y1 += y; + pbox->x2 += x; + pbox->y2 += y; + } + } + return; + } + if (((x2 - MINSHORT)|(y2 - MINSHORT)|(MAXSHORT - x1)|(MAXSHORT - y1)) <= 0) + { + pReg->extents.x2 = pReg->extents.x1; + pReg->extents.y2 = pReg->extents.y1; + xfreeData(pReg); + pReg->data = &miEmptyData; + return; + } + if (x1 < MINSHORT) + pReg->extents.x1 = MINSHORT; + else if (x2 > MAXSHORT) + pReg->extents.x2 = MAXSHORT; + if (y1 < MINSHORT) + pReg->extents.y1 = MINSHORT; + else if (y2 > MAXSHORT) + pReg->extents.y2 = MAXSHORT; + if (pReg->data && (nbox = pReg->data->numRects)) + { + register BoxPtr pboxout; + + for (pboxout = pbox = REGION_BOXPTR(pReg); nbox--; pbox++) + { + pboxout->x1 = x1 = pbox->x1 + x; + pboxout->y1 = y1 = pbox->y1 + y; + pboxout->x2 = x2 = pbox->x2 + x; + pboxout->y2 = y2 = pbox->y2 + y; + if (((x2 - MINSHORT)|(y2 - MINSHORT)| + (MAXSHORT - x1)|(MAXSHORT - y1)) <= 0) + { + pReg->data->numRects--; + continue; + } + if (x1 < MINSHORT) + pboxout->x1 = MINSHORT; + else if (x2 > MAXSHORT) + pboxout->x2 = MAXSHORT; + if (y1 < MINSHORT) + pboxout->y1 = MINSHORT; + else if (y2 > MAXSHORT) + pboxout->y2 = MAXSHORT; + pboxout++; + } + if (pboxout != pbox) + { + if (pReg->data->numRects == 1) + { + pReg->extents = *REGION_BOXPTR(pReg); + xfreeData(pReg); + pReg->data = (RegDataPtr)NULL; + } + else + miSetExtents(pReg); + } + } +} + +Bool +miRegionDataCopy( + register RegionPtr dst, + register RegionPtr src) +{ + good(dst); + good(src); + if (dst->data) + return TRUE; + if (dst == src) + return TRUE; + if (!src->data || !src->data->size) + { + xfreeData(dst); + dst->data = (RegDataPtr)NULL; + return TRUE; + } + if (!dst->data || (dst->data->size < src->data->numRects)) + { + xfreeData(dst); + dst->data = xallocData(src->data->numRects); + if (!dst->data) + return miRegionBreak (dst); + } + dst->data->size = src->data->size; + dst->data->numRects = src->data->numRects; + return TRUE; +} + +_X_EXPORT void +miRegionReset(pReg, pBox) + RegionPtr pReg; + BoxPtr pBox; +{ + good(pReg); + assert(pBox->x1<=pBox->x2); + assert(pBox->y1<=pBox->y2); + pReg->extents = *pBox; + xfreeData(pReg); + pReg->data = (RegDataPtr)NULL; +} + +_X_EXPORT Bool +miPointInRegion(pReg, x, y, box) + register RegionPtr pReg; + register int x, y; + BoxPtr box; /* "return" value */ +{ + register BoxPtr pbox, pboxEnd; + int numRects; + + good(pReg); + numRects = REGION_NUM_RECTS(pReg); + if (!numRects || !INBOX(&pReg->extents, x, y)) + return(FALSE); + if (numRects == 1) + { + *box = pReg->extents; + return(TRUE); + } + for (pbox = REGION_BOXPTR(pReg), pboxEnd = pbox + numRects; + pbox != pboxEnd; + pbox++) + { + if (y >= pbox->y2) + continue; /* not there yet */ + if ((y < pbox->y1) || (x < pbox->x1)) + break; /* missed it */ + if (x >= pbox->x2) + continue; /* not there yet */ + *box = *pbox; + return(TRUE); + } + return(FALSE); +} + +_X_EXPORT Bool +miRegionNotEmpty(pReg) + RegionPtr pReg; +{ + good(pReg); + return(!REGION_NIL(pReg)); +} + +Bool +miRegionBroken(RegionPtr pReg) +{ + good(pReg); + return (REGION_NAR(pReg)); +} + +_X_EXPORT void +miRegionEmpty(pReg) + RegionPtr pReg; +{ + good(pReg); + xfreeData(pReg); + pReg->extents.x2 = pReg->extents.x1; + pReg->extents.y2 = pReg->extents.y1; + pReg->data = &miEmptyData; +} + +_X_EXPORT BoxPtr +miRegionExtents(pReg) + RegionPtr pReg; +{ + good(pReg); + return(&pReg->extents); +} + +#define ExchangeSpans(a, b) \ +{ \ + DDXPointRec tpt; \ + register int tw; \ + \ + tpt = spans[a]; spans[a] = spans[b]; spans[b] = tpt; \ + tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \ +} + +/* ||| I should apply the merge sort code to rectangle sorting above, and see + if mapping time can be improved. But right now I've been at work 12 hours, + so forget it. +*/ + +static void QuickSortSpans( + register DDXPointRec spans[], + register int widths[], + register int numSpans) +{ + register int y; + register int i, j, m; + register DDXPointPtr r; + + /* Always called with numSpans > 1 */ + /* Sorts only by y, doesn't bother to sort by x */ + + do + { + if (numSpans < 9) + { + /* Do insertion sort */ + register int yprev; + + yprev = spans[0].y; + i = 1; + do + { /* while i != numSpans */ + y = spans[i].y; + if (yprev > y) + { + /* spans[i] is out of order. Move into proper location. */ + DDXPointRec tpt; + int tw, k; + + for (j = 0; y >= spans[j].y; j++) {} + tpt = spans[i]; + tw = widths[i]; + for (k = i; k != j; k--) + { + spans[k] = spans[k-1]; + widths[k] = widths[k-1]; + } + spans[j] = tpt; + widths[j] = tw; + y = spans[i].y; + } /* if out of order */ + yprev = y; + i++; + } while (i != numSpans); + return; + } + + /* Choose partition element, stick in location 0 */ + m = numSpans / 2; + if (spans[m].y > spans[0].y) ExchangeSpans(m, 0); + if (spans[m].y > spans[numSpans-1].y) ExchangeSpans(m, numSpans-1); + if (spans[m].y > spans[0].y) ExchangeSpans(m, 0); + y = spans[0].y; + + /* Partition array */ + i = 0; + j = numSpans; + do + { + r = &(spans[i]); + do + { + r++; + i++; + } while (i != numSpans && r->y < y); + r = &(spans[j]); + do + { + r--; + j--; + } while (y < r->y); + if (i < j) + ExchangeSpans(i, j); + } while (i < j); + + /* Move partition element back to middle */ + ExchangeSpans(0, j); + + /* Recurse */ + if (numSpans-j-1 > 1) + QuickSortSpans(&spans[j+1], &widths[j+1], numSpans-j-1); + numSpans = j; + } while (numSpans > 1); +} + +#define NextBand() \ +{ \ + clipy1 = pboxBandStart->y1; \ + clipy2 = pboxBandStart->y2; \ + pboxBandEnd = pboxBandStart + 1; \ + while (pboxBandEnd != pboxLast && pboxBandEnd->y1 == clipy1) { \ + pboxBandEnd++; \ + } \ + for (; ppt != pptLast && ppt->y < clipy1; ppt++, pwidth++) {} \ +} + +/* + Clip a list of scanlines to a region. The caller has allocated the + space. FSorted is non-zero if the scanline origins are in ascending + order. + returns the number of new, clipped scanlines. +*/ + +_X_EXPORT int +miClipSpans( + RegionPtr prgnDst, + register DDXPointPtr ppt, + register int *pwidth, + int nspans, + register DDXPointPtr pptNew, + int *pwidthNew, + int fSorted) +{ + register DDXPointPtr pptLast; + int *pwidthNewStart; /* the vengeance of Xerox! */ + register int y, x1, x2; + register int numRects; + + good(prgnDst); + pptLast = ppt + nspans; + pwidthNewStart = pwidthNew; + + if (!prgnDst->data) + { + /* Do special fast code with clip boundaries in registers(?) */ + /* It doesn't pay much to make use of fSorted in this case, + so we lump everything together. */ + + register int clipx1, clipx2, clipy1, clipy2; + + clipx1 = prgnDst->extents.x1; + clipy1 = prgnDst->extents.y1; + clipx2 = prgnDst->extents.x2; + clipy2 = prgnDst->extents.y2; + + for (; ppt != pptLast; ppt++, pwidth++) + { + y = ppt->y; + x1 = ppt->x; + if (clipy1 <= y && y < clipy2) + { + x2 = x1 + *pwidth; + if (x1 < clipx1) x1 = clipx1; + if (x2 > clipx2) x2 = clipx2; + if (x1 < x2) + { + /* part of span in clip rectangle */ + pptNew->x = x1; + pptNew->y = y; + *pwidthNew = x2 - x1; + pptNew++; + pwidthNew++; + } + } + } /* end for */ + + } + else if ((numRects = prgnDst->data->numRects)) + { + /* Have to clip against many boxes */ + BoxPtr pboxBandStart, pboxBandEnd; + register BoxPtr pbox; + register BoxPtr pboxLast; + register int clipy1, clipy2; + + /* In this case, taking advantage of sorted spans gains more than + the sorting costs. */ + if ((! fSorted) && (nspans > 1)) + QuickSortSpans(ppt, pwidth, nspans); + + pboxBandStart = REGION_BOXPTR(prgnDst); + pboxLast = pboxBandStart + numRects; + + NextBand(); + + for (; ppt != pptLast; ) + { + y = ppt->y; + if (y < clipy2) + { + /* span is in the current band */ + pbox = pboxBandStart; + x1 = ppt->x; + x2 = x1 + *pwidth; + do + { /* For each box in band */ + register int newx1, newx2; + + newx1 = x1; + newx2 = x2; + if (newx1 < pbox->x1) newx1 = pbox->x1; + if (newx2 > pbox->x2) newx2 = pbox->x2; + if (newx1 < newx2) + { + /* Part of span in clip rectangle */ + pptNew->x = newx1; + pptNew->y = y; + *pwidthNew = newx2 - newx1; + pptNew++; + pwidthNew++; + } + pbox++; + } while (pbox != pboxBandEnd); + ppt++; + pwidth++; + } + else + { + /* Move to next band, adjust ppt as needed */ + pboxBandStart = pboxBandEnd; + if (pboxBandStart == pboxLast) + break; /* We're completely done */ + NextBand(); + } + } + } + return (pwidthNew - pwidthNewStart); +} + +/* find the band in a region with the most rectangles */ +_X_EXPORT int +miFindMaxBand(prgn) + RegionPtr prgn; +{ + register int nbox; + register BoxPtr pbox; + register int nThisBand; + register int nMaxBand = 0; + short yThisBand; + + good(prgn); + nbox = REGION_NUM_RECTS(prgn); + pbox = REGION_RECTS(prgn); + + while(nbox > 0) + { + yThisBand = pbox->y1; + nThisBand = 0; + while((nbox > 0) && (pbox->y1 == yThisBand)) + { + nbox--; + pbox++; + nThisBand++; + } + if (nThisBand > nMaxBand) + nMaxBand = nThisBand; + } + return (nMaxBand); +} diff --git a/xserver/mi/miscanfill.h b/xserver/mi/miscanfill.h new file mode 100644 index 000000000..e318c45b4 --- /dev/null +++ b/xserver/mi/miscanfill.h @@ -0,0 +1,147 @@ +/* + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifndef SCANFILLINCLUDED +#define SCANFILLINCLUDED +/* + * scanfill.h + * + * Written by Brian Kelleher; Jan 1985 + * + * This file contains a few macros to help track + * the edge of a filled object. The object is assumed + * to be filled in scanline order, and thus the + * algorithm used is an extension of Bresenham's line + * drawing algorithm which assumes that y is always the + * major axis. + * Since these pieces of code are the same for any filled shape, + * it is more convenient to gather the library in one + * place, but since these pieces of code are also in + * the inner loops of output primitives, procedure call + * overhead is out of the question. + * See the author for a derivation if needed. + */ + + +/* + * In scan converting polygons, we want to choose those pixels + * which are inside the polygon. Thus, we add .5 to the starting + * x coordinate for both left and right edges. Now we choose the + * first pixel which is inside the pgon for the left edge and the + * first pixel which is outside the pgon for the right edge. + * Draw the left pixel, but not the right. + * + * How to add .5 to the starting x coordinate: + * If the edge is moving to the right, then subtract dy from the + * error term from the general form of the algorithm. + * If the edge is moving to the left, then add dy to the error term. + * + * The reason for the difference between edges moving to the left + * and edges moving to the right is simple: If an edge is moving + * to the right, then we want the algorithm to flip immediately. + * If it is moving to the left, then we don't want it to flip until + * we traverse an entire pixel. + */ +#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \ + int dx; /* local storage */ \ +\ + /* \ + * if the edge is horizontal, then it is ignored \ + * and assumed not to be processed. Otherwise, do this stuff. \ + */ \ + if ((dy) != 0) { \ + xStart = (x1); \ + dx = (x2) - xStart; \ + if (dx < 0) { \ + m = dx / (dy); \ + m1 = m - 1; \ + incr1 = -2 * dx + 2 * (dy) * m1; \ + incr2 = -2 * dx + 2 * (dy) * m; \ + d = 2 * m * (dy) - 2 * dx - 2 * (dy); \ + } else { \ + m = dx / (dy); \ + m1 = m + 1; \ + incr1 = 2 * dx - 2 * (dy) * m1; \ + incr2 = 2 * dx - 2 * (dy) * m; \ + d = -2 * m * (dy) + 2 * dx; \ + } \ + } \ +} + +#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \ + if (m1 > 0) { \ + if (d > 0) { \ + minval += m1; \ + d += incr1; \ + } \ + else { \ + minval += m; \ + d += incr2; \ + } \ + } else {\ + if (d >= 0) { \ + minval += m1; \ + d += incr1; \ + } \ + else { \ + minval += m; \ + d += incr2; \ + } \ + } \ +} + + +/* + * This structure contains all of the information needed + * to run the bresenham algorithm. + * The variables may be hardcoded into the declarations + * instead of using this structure to make use of + * register declarations. + */ +typedef struct { + int minor; /* minor axis */ + int d; /* decision variable */ + int m, m1; /* slope and slope+1 */ + int incr1, incr2; /* error increments */ +} BRESINFO; + + +#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \ + BRESINITPGON(dmaj, min1, min2, bres.minor, bres.d, \ + bres.m, bres.m1, bres.incr1, bres.incr2) + +#define BRESINCRPGONSTRUCT(bres) \ + BRESINCRPGON(bres.d, bres.minor, bres.m, bres.m1, bres.incr1, bres.incr2) + + +#endif diff --git a/xserver/mi/miscrinit.c b/xserver/mi/miscrinit.c new file mode 100644 index 000000000..ac1b82336 --- /dev/null +++ b/xserver/mi/miscrinit.c @@ -0,0 +1,344 @@ +/* + +Copyright 1990, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include "servermd.h" +#include "misc.h" +#include "mi.h" +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "dix.h" +#include "miline.h" +#ifdef MITSHM +#define _XSHM_SERVER_ +#include <X11/extensions/XShm.h> +#endif + +/* We use this structure to propogate some information from miScreenInit to + * miCreateScreenResources. miScreenInit allocates the structure, fills it + * in, and puts it into pScreen->devPrivate. miCreateScreenResources + * extracts the info and frees the structure. We could've accomplished the + * same thing by adding fields to the screen structure, but they would have + * ended up being redundant, and would have exposed this mi implementation + * detail to the whole server. + */ + +typedef struct +{ + pointer pbits; /* pointer to framebuffer */ + int width; /* delta to add to a framebuffer addr to move one row down */ +} miScreenInitParmsRec, *miScreenInitParmsPtr; + + +/* this plugs into pScreen->ModifyPixmapHeader */ +_X_EXPORT Bool +miModifyPixmapHeader(pPixmap, width, height, depth, bitsPerPixel, devKind, + pPixData) + PixmapPtr pPixmap; + int width; + int height; + int depth; + int bitsPerPixel; + int devKind; + pointer pPixData; +{ + if (!pPixmap) + return FALSE; + + /* + * If all arguments are specified, reinitialize everything (including + * validated state). + */ + if ((width > 0) && (height > 0) && (depth > 0) && (bitsPerPixel > 0) && + (devKind > 0) && pPixData) { + pPixmap->drawable.depth = depth; + pPixmap->drawable.bitsPerPixel = bitsPerPixel; + pPixmap->drawable.id = 0; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pPixmap->drawable.x = 0; + pPixmap->drawable.y = 0; + pPixmap->drawable.width = width; + pPixmap->drawable.height = height; + pPixmap->devKind = devKind; + pPixmap->refcnt = 1; + pPixmap->devPrivate.ptr = pPixData; + } else { + /* + * Only modify specified fields, keeping all others intact. + */ + + if (width > 0) + pPixmap->drawable.width = width; + + if (height > 0) + pPixmap->drawable.height = height; + + if (depth > 0) + pPixmap->drawable.depth = depth; + + if (bitsPerPixel > 0) + pPixmap->drawable.bitsPerPixel = bitsPerPixel; + else if ((bitsPerPixel < 0) && (depth > 0)) + pPixmap->drawable.bitsPerPixel = BitsPerPixel(depth); + + /* + * CAVEAT: Non-SI DDXen may use devKind and devPrivate fields for + * other purposes. + */ + if (devKind > 0) + pPixmap->devKind = devKind; + else if ((devKind < 0) && ((width > 0) || (depth > 0))) + pPixmap->devKind = PixmapBytePad(pPixmap->drawable.width, + pPixmap->drawable.depth); + + if (pPixData) + pPixmap->devPrivate.ptr = pPixData; + } + return TRUE; +} + + +/*ARGSUSED*/ +Bool +miCloseScreen (iScreen, pScreen) + int iScreen; + ScreenPtr pScreen; +{ + return ((*pScreen->DestroyPixmap)((PixmapPtr)pScreen->devPrivate)); +} + +/* With the introduction of pixmap privates, the "screen pixmap" can no + * longer be created in miScreenInit, since all the modules that could + * possibly ask for pixmap private space have not been initialized at + * that time. pScreen->CreateScreenResources is called after all + * possible private-requesting modules have been inited; we create the + * screen pixmap here. + */ +_X_EXPORT Bool +miCreateScreenResources(pScreen) + ScreenPtr pScreen; +{ + miScreenInitParmsPtr pScrInitParms; + pointer value; + + pScrInitParms = (miScreenInitParmsPtr)pScreen->devPrivate; + + /* if width is non-zero, pScreen->devPrivate will be a pixmap + * else it will just take the value pbits + */ + if (pScrInitParms->width) + { + PixmapPtr pPixmap; + + /* create a pixmap with no data, then redirect it to point to + * the screen + */ + pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth); + if (!pPixmap) + return FALSE; + + if (!(*pScreen->ModifyPixmapHeader)(pPixmap, pScreen->width, + pScreen->height, pScreen->rootDepth, + BitsPerPixel(pScreen->rootDepth), + PixmapBytePad(pScrInitParms->width, pScreen->rootDepth), + pScrInitParms->pbits)) + return FALSE; + value = (pointer)pPixmap; + } + else + { + value = pScrInitParms->pbits; + } + xfree(pScreen->devPrivate); /* freeing miScreenInitParmsRec */ + pScreen->devPrivate = value; /* pPixmap or pbits */ + return TRUE; +} + +Bool +miScreenDevPrivateInit(pScreen, width, pbits) + register ScreenPtr pScreen; + int width; + pointer pbits; +{ + miScreenInitParmsPtr pScrInitParms; + + /* Stash pbits and width in a short-lived miScreenInitParmsRec attached + * to the screen, until CreateScreenResources can put them in the + * screen pixmap. + */ + pScrInitParms = (miScreenInitParmsPtr)xalloc(sizeof(miScreenInitParmsRec)); + if (!pScrInitParms) + return FALSE; + pScrInitParms->pbits = pbits; + pScrInitParms->width = width; + pScreen->devPrivate = (pointer)pScrInitParms; + return TRUE; +} + +_X_EXPORT Bool +miScreenInit(pScreen, pbits, xsize, ysize, dpix, dpiy, width, + rootDepth, numDepths, depths, rootVisual, numVisuals, visuals) + register ScreenPtr pScreen; + pointer pbits; /* pointer to screen bits */ + int xsize, ysize; /* in pixels */ + int dpix, dpiy; /* dots per inch */ + int width; /* pixel width of frame buffer */ + int rootDepth; /* depth of root window */ + int numDepths; /* number of depths supported */ + DepthRec *depths; /* supported depths */ + VisualID rootVisual; /* root visual */ + int numVisuals; /* number of visuals supported */ + VisualRec *visuals; /* supported visuals */ +{ + pScreen->width = xsize; + pScreen->height = ysize; + pScreen->mmWidth = (xsize * 254 + dpix * 5) / (dpix * 10); + pScreen->mmHeight = (ysize * 254 + dpiy * 5) / (dpiy * 10); + pScreen->numDepths = numDepths; + pScreen->rootDepth = rootDepth; + pScreen->allowedDepths = depths; + pScreen->rootVisual = rootVisual; + /* defColormap */ + pScreen->minInstalledCmaps = 1; + pScreen->maxInstalledCmaps = 1; + pScreen->backingStoreSupport = NotUseful; + pScreen->saveUnderSupport = NotUseful; + /* whitePixel, blackPixel */ + pScreen->ModifyPixmapHeader = miModifyPixmapHeader; + pScreen->CreateScreenResources = miCreateScreenResources; + pScreen->GetScreenPixmap = miGetScreenPixmap; + pScreen->SetScreenPixmap = miSetScreenPixmap; + pScreen->numVisuals = numVisuals; + pScreen->visuals = visuals; + if (width) + { +#ifdef MITSHM + ShmRegisterFbFuncs(pScreen); +#endif + pScreen->CloseScreen = miCloseScreen; + } + /* else CloseScreen */ + /* QueryBestSize, SaveScreen, GetImage, GetSpans */ + pScreen->PointerNonInterestBox = (PointerNonInterestBoxProcPtr) 0; + pScreen->SourceValidate = (SourceValidateProcPtr) 0; + /* CreateWindow, DestroyWindow, PositionWindow, ChangeWindowAttributes */ + /* RealizeWindow, UnrealizeWindow */ + pScreen->ValidateTree = miValidateTree; + pScreen->PostValidateTree = (PostValidateTreeProcPtr) 0; + pScreen->WindowExposures = miWindowExposures; + /* PaintWindowBackground, PaintWindowBorder, CopyWindow */ + pScreen->ClearToBackground = miClearToBackground; + pScreen->ClipNotify = (ClipNotifyProcPtr) 0; + pScreen->RestackWindow = (RestackWindowProcPtr) 0; + /* CreatePixmap, DestroyPixmap */ + /* RealizeFont, UnrealizeFont */ + /* CreateGC */ + /* CreateColormap, DestroyColormap, InstallColormap, UninstallColormap */ + /* ListInstalledColormaps, StoreColors, ResolveColor */ + /* BitmapToRegion */ + pScreen->SendGraphicsExpose = miSendGraphicsExpose; + pScreen->BlockHandler = (ScreenBlockHandlerProcPtr)NoopDDA; + pScreen->WakeupHandler = (ScreenWakeupHandlerProcPtr)NoopDDA; + pScreen->blockData = (pointer)0; + pScreen->wakeupData = (pointer)0; + pScreen->MarkWindow = miMarkWindow; + pScreen->MarkOverlappedWindows = miMarkOverlappedWindows; + pScreen->ChangeSaveUnder = miChangeSaveUnder; + pScreen->PostChangeSaveUnder = miPostChangeSaveUnder; + pScreen->MoveWindow = miMoveWindow; + pScreen->ResizeWindow = miSlideAndSizeWindow; + pScreen->GetLayerWindow = miGetLayerWindow; + pScreen->HandleExposures = miHandleValidateExposures; + pScreen->ReparentWindow = (ReparentWindowProcPtr) 0; + pScreen->ChangeBorderWidth = miChangeBorderWidth; +#ifdef SHAPE + pScreen->SetShape = miSetShape; +#endif + pScreen->MarkUnrealizedWindow = miMarkUnrealizedWindow; + + pScreen->SaveDoomedAreas = 0; + pScreen->RestoreAreas = 0; + pScreen->ExposeCopy = 0; + pScreen->TranslateBackingStore = 0; + pScreen->ClearBackingStore = 0; + pScreen->DrawGuarantee = 0; + + miSetZeroLineBias(pScreen, DEFAULTZEROLINEBIAS); + + return miScreenDevPrivateInit(pScreen, width, pbits); +} + +_X_EXPORT int +miAllocateGCPrivateIndex() +{ + static int privateIndex = -1; + static unsigned long miGeneration = 0; + + if (miGeneration != serverGeneration) + { + privateIndex = AllocateGCPrivateIndex(); + miGeneration = serverGeneration; + } + return privateIndex; +} + +_X_EXPORT int miZeroLineScreenIndex; +unsigned int miZeroLineGeneration = 0; + +_X_EXPORT void +miSetZeroLineBias(pScreen, bias) + ScreenPtr pScreen; + unsigned int bias; +{ + if (miZeroLineGeneration != serverGeneration) + { + miZeroLineScreenIndex = AllocateScreenPrivateIndex(); + miZeroLineGeneration = serverGeneration; + } + if (miZeroLineScreenIndex >= 0) + pScreen->devPrivates[miZeroLineScreenIndex].uval = bias; +} + +_X_EXPORT PixmapPtr +miGetScreenPixmap(pScreen) + ScreenPtr pScreen; +{ + return (PixmapPtr)(pScreen->devPrivate); +} + +_X_EXPORT void +miSetScreenPixmap(pPix) + PixmapPtr pPix; +{ + if (pPix) + pPix->drawable.pScreen->devPrivate = (pointer)pPix; +} diff --git a/xserver/mi/mispans.c b/xserver/mi/mispans.c new file mode 100644 index 000000000..4c8b6d698 --- /dev/null +++ b/xserver/mi/mispans.c @@ -0,0 +1,561 @@ +/*********************************************************** + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1989 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "misc.h" +#include "pixmapstr.h" +#include "gcstruct.h" +#include "mispans.h" + +/* + +These routines maintain lists of Spans, in order to implement the +``touch-each-pixel-once'' rules of wide lines and arcs. + +Written by Joel McCormack, Summer 1989. + +*/ + + +void miInitSpanGroup(spanGroup) + SpanGroup *spanGroup; +{ + spanGroup->size = 0; + spanGroup->count = 0; + spanGroup->group = NULL; + spanGroup->ymin = MAXSHORT; + spanGroup->ymax = MINSHORT; +} /* InitSpanGroup */ + +#define YMIN(spans) (spans->points[0].y) +#define YMAX(spans) (spans->points[spans->count-1].y) + +void miSubtractSpans (spanGroup, sub) + SpanGroup *spanGroup; + Spans *sub; +{ + int i, subCount, spansCount; + int ymin, ymax, xmin, xmax; + Spans *spans; + DDXPointPtr subPt, spansPt; + int *subWid, *spansWid; + int extra; + + ymin = YMIN(sub); + ymax = YMAX(sub); + spans = spanGroup->group; + for (i = spanGroup->count; i; i--, spans++) { + if (YMIN(spans) <= ymax && ymin <= YMAX(spans)) { + subCount = sub->count; + subPt = sub->points; + subWid = sub->widths; + spansCount = spans->count; + spansPt = spans->points; + spansWid = spans->widths; + extra = 0; + for (;;) + { + while (spansCount && spansPt->y < subPt->y) + { + spansPt++; spansWid++; spansCount--; + } + if (!spansCount) + break; + while (subCount && subPt->y < spansPt->y) + { + subPt++; subWid++; subCount--; + } + if (!subCount) + break; + if (subPt->y == spansPt->y) + { + xmin = subPt->x; + xmax = xmin + *subWid; + if (xmin >= spansPt->x + *spansWid || spansPt->x >= xmax) + { + ; + } + else if (xmin <= spansPt->x) + { + if (xmax >= spansPt->x + *spansWid) + { + memmove (spansPt, spansPt + 1, sizeof *spansPt * (spansCount - 1)); + memmove (spansWid, spansWid + 1, sizeof *spansWid * (spansCount - 1)); + spansPt--; + spansWid--; + spans->count--; + extra++; + } + else + { + *spansWid = *spansWid - (xmax - spansPt->x); + spansPt->x = xmax; + } + } + else + { + if (xmax >= spansPt->x + *spansWid) + { + *spansWid = xmin - spansPt->x; + } + else + { + if (!extra) { + DDXPointPtr newPt; + int *newwid; + +#define EXTRA 8 + newPt = (DDXPointPtr) xrealloc (spans->points, (spans->count + EXTRA) * sizeof (DDXPointRec)); + if (!newPt) + break; + spansPt = newPt + (spansPt - spans->points); + spans->points = newPt; + newwid = (int *) xrealloc (spans->widths, (spans->count + EXTRA) * sizeof (int)); + if (!newwid) + break; + spansWid = newwid + (spansWid - spans->widths); + spans->widths = newwid; + extra = EXTRA; + } + memmove (spansPt + 1, spansPt, sizeof *spansPt * (spansCount)); + memmove (spansWid + 1, spansWid, sizeof *spansWid * (spansCount)); + spans->count++; + extra--; + *spansWid = xmin - spansPt->x; + spansWid++; + spansPt++; + *spansWid = *spansWid - (xmax - spansPt->x); + spansPt->x = xmax; + } + } + } + spansPt++; spansWid++; spansCount--; + } + } + } +} + +void miAppendSpans(spanGroup, otherGroup, spans) + SpanGroup *spanGroup; + SpanGroup *otherGroup; + Spans *spans; +{ + register int ymin, ymax; + register int spansCount; + + spansCount = spans->count; + if (spansCount > 0) { + if (spanGroup->size == spanGroup->count) { + spanGroup->size = (spanGroup->size + 8) * 2; + spanGroup->group = (Spans *) + xrealloc(spanGroup->group, sizeof(Spans) * spanGroup->size); + } + + spanGroup->group[spanGroup->count] = *spans; + (spanGroup->count)++; + ymin = spans->points[0].y; + if (ymin < spanGroup->ymin) spanGroup->ymin = ymin; + ymax = spans->points[spansCount - 1].y; + if (ymax > spanGroup->ymax) spanGroup->ymax = ymax; + if (otherGroup && + otherGroup->ymin < ymax && + ymin < otherGroup->ymax) + { + miSubtractSpans (otherGroup, spans); + } + } + else + { + xfree (spans->points); + xfree (spans->widths); + } +} /* AppendSpans */ + +void miFreeSpanGroup(spanGroup) + SpanGroup *spanGroup; +{ + if (spanGroup->group != NULL) xfree(spanGroup->group); +} + +static void QuickSortSpansX( + register DDXPointRec points[], + register int widths[], + register int numSpans ) +{ + register int x; + register int i, j, m; + register DDXPointPtr r; + +/* Always called with numSpans > 1 */ +/* Sorts only by x, as all y should be the same */ + +#define ExchangeSpans(a, b) \ +{ \ + DDXPointRec tpt; \ + register int tw; \ + \ + tpt = points[a]; points[a] = points[b]; points[b] = tpt; \ + tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \ +} + + do { + if (numSpans < 9) { + /* Do insertion sort */ + register int xprev; + + xprev = points[0].x; + i = 1; + do { /* while i != numSpans */ + x = points[i].x; + if (xprev > x) { + /* points[i] is out of order. Move into proper location. */ + DDXPointRec tpt; + int tw, k; + + for (j = 0; x >= points[j].x; j++) {} + tpt = points[i]; + tw = widths[i]; + for (k = i; k != j; k--) { + points[k] = points[k-1]; + widths[k] = widths[k-1]; + } + points[j] = tpt; + widths[j] = tw; + x = points[i].x; + } /* if out of order */ + xprev = x; + i++; + } while (i != numSpans); + return; + } + + /* Choose partition element, stick in location 0 */ + m = numSpans / 2; + if (points[m].x > points[0].x) ExchangeSpans(m, 0); + if (points[m].x > points[numSpans-1].x) ExchangeSpans(m, numSpans-1); + if (points[m].x > points[0].x) ExchangeSpans(m, 0); + x = points[0].x; + + /* Partition array */ + i = 0; + j = numSpans; + do { + r = &(points[i]); + do { + r++; + i++; + } while (i != numSpans && r->x < x); + r = &(points[j]); + do { + r--; + j--; + } while (x < r->x); + if (i < j) ExchangeSpans(i, j); + } while (i < j); + + /* Move partition element back to middle */ + ExchangeSpans(0, j); + + /* Recurse */ + if (numSpans-j-1 > 1) + QuickSortSpansX(&points[j+1], &widths[j+1], numSpans-j-1); + numSpans = j; + } while (numSpans > 1); +} /* QuickSortSpans */ + + +static int UniquifySpansX( + Spans *spans, + register DDXPointRec *newPoints, + register int *newWidths ) +{ + register int newx1, newx2, oldpt, i, y; + register DDXPointRec *oldPoints; + register int *oldWidths; + int *startNewWidths; + +/* Always called with numSpans > 1 */ +/* Uniquify the spans, and stash them into newPoints and newWidths. Return the + number of unique spans. */ + + + startNewWidths = newWidths; + + oldPoints = spans->points; + oldWidths = spans->widths; + + y = oldPoints->y; + newx1 = oldPoints->x; + newx2 = newx1 + *oldWidths; + + for (i = spans->count-1; i != 0; i--) { + oldPoints++; + oldWidths++; + oldpt = oldPoints->x; + if (oldpt > newx2) { + /* Write current span, start a new one */ + newPoints->x = newx1; + newPoints->y = y; + *newWidths = newx2 - newx1; + newPoints++; + newWidths++; + newx1 = oldpt; + newx2 = oldpt + *oldWidths; + } else { + /* extend current span, if old extends beyond new */ + oldpt = oldpt + *oldWidths; + if (oldpt > newx2) newx2 = oldpt; + } + } /* for */ + + /* Write final span */ + newPoints->x = newx1; + *newWidths = newx2 - newx1; + newPoints->y = y; + + return (newWidths - startNewWidths) + 1; +} /* UniquifySpansX */ + +void +miDisposeSpanGroup (spanGroup) + SpanGroup *spanGroup; +{ + int i; + Spans *spans; + + for (i = 0; i < spanGroup->count; i++) + { + spans = spanGroup->group + i; + xfree (spans->points); + xfree (spans->widths); + } +} + +void miFillUniqueSpanGroup(pDraw, pGC, spanGroup) + DrawablePtr pDraw; + GCPtr pGC; + SpanGroup *spanGroup; +{ + register int i; + register Spans *spans; + register Spans *yspans; + register int *ysizes; + register int ymin, ylength; + + /* Outgoing spans for one big call to FillSpans */ + register DDXPointPtr points; + register int *widths; + register int count; + + if (spanGroup->count == 0) return; + + if (spanGroup->count == 1) { + /* Already should be sorted, unique */ + spans = spanGroup->group; + (*pGC->ops->FillSpans) + (pDraw, pGC, spans->count, spans->points, spans->widths, TRUE); + xfree(spans->points); + xfree(spans->widths); + } + else + { + /* Yuck. Gross. Radix sort into y buckets, then sort x and uniquify */ + /* This seems to be the fastest thing to do. I've tried sorting on + both x and y at the same time rather than creating into all those + y buckets, but it was somewhat slower. */ + + ymin = spanGroup->ymin; + ylength = spanGroup->ymax - ymin + 1; + + /* Allocate Spans for y buckets */ + yspans = (Spans *) xalloc(ylength * sizeof(Spans)); + ysizes = (int *) xalloc(ylength * sizeof (int)); + + if (!yspans || !ysizes) + { + if (yspans) + xfree (yspans); + if (ysizes) + xfree (ysizes); + miDisposeSpanGroup (spanGroup); + return; + } + + for (i = 0; i != ylength; i++) { + ysizes[i] = 0; + yspans[i].count = 0; + yspans[i].points = NULL; + yspans[i].widths = NULL; + } + + /* Go through every single span and put it into the correct bucket */ + count = 0; + for (i = 0, spans = spanGroup->group; + i != spanGroup->count; + i++, spans++) { + int index; + int j; + + for (j = 0, points = spans->points, widths = spans->widths; + j != spans->count; + j++, points++, widths++) { + index = points->y - ymin; + if (index >= 0 && index < ylength) { + Spans *newspans = &(yspans[index]); + if (newspans->count == ysizes[index]) { + DDXPointPtr newpoints; + int *newwidths; + ysizes[index] = (ysizes[index] + 8) * 2; + newpoints = (DDXPointPtr) xrealloc( + newspans->points, + ysizes[index] * sizeof(DDXPointRec)); + newwidths = (int *) xrealloc( + newspans->widths, + ysizes[index] * sizeof(int)); + if (!newpoints || !newwidths) + { + int i; + + for (i = 0; i < ylength; i++) + { + xfree (yspans[i].points); + xfree (yspans[i].widths); + } + xfree (yspans); + xfree (ysizes); + miDisposeSpanGroup (spanGroup); + return; + } + newspans->points = newpoints; + newspans->widths = newwidths; + } + newspans->points[newspans->count] = *points; + newspans->widths[newspans->count] = *widths; + (newspans->count)++; + } /* if y value of span in range */ + } /* for j through spans */ + count += spans->count; + xfree(spans->points); + spans->points = NULL; + xfree(spans->widths); + spans->widths = NULL; + } /* for i thorough Spans */ + + /* Now sort by x and uniquify each bucket into the final array */ + points = (DDXPointPtr) xalloc(count * sizeof(DDXPointRec)); + widths = (int *) xalloc(count * sizeof(int)); + if (!points || !widths) + { + int i; + + for (i = 0; i < ylength; i++) + { + xfree (yspans[i].points); + xfree (yspans[i].widths); + } + xfree (yspans); + xfree (ysizes); + if (points) + xfree (points); + if (widths) + xfree (widths); + return; + } + count = 0; + for (i = 0; i != ylength; i++) { + int ycount = yspans[i].count; + if (ycount > 0) { + if (ycount > 1) { + QuickSortSpansX(yspans[i].points, yspans[i].widths, ycount); + count += UniquifySpansX + (&(yspans[i]), &(points[count]), &(widths[count])); + } else { + points[count] = yspans[i].points[0]; + widths[count] = yspans[i].widths[0]; + count++; + } + xfree(yspans[i].points); + xfree(yspans[i].widths); + } + } + + (*pGC->ops->FillSpans) (pDraw, pGC, count, points, widths, TRUE); + xfree(points); + xfree(widths); + xfree(yspans); + xfree(ysizes); /* use (DE)ALLOCATE_LOCAL for these? */ + } + + spanGroup->count = 0; + spanGroup->ymin = MAXSHORT; + spanGroup->ymax = MINSHORT; +} + + +void miFillSpanGroup(pDraw, pGC, spanGroup) + DrawablePtr pDraw; + GCPtr pGC; + SpanGroup *spanGroup; +{ + register int i; + register Spans *spans; + + for (i = 0, spans = spanGroup->group; i != spanGroup->count; i++, spans++) { + (*pGC->ops->FillSpans) + (pDraw, pGC, spans->count, spans->points, spans->widths, TRUE); + xfree(spans->points); + xfree(spans->widths); + } + + spanGroup->count = 0; + spanGroup->ymin = MAXSHORT; + spanGroup->ymax = MINSHORT; +} /* FillSpanGroup */ diff --git a/xserver/mi/mispans.h b/xserver/mi/mispans.h new file mode 100644 index 000000000..5b141afe2 --- /dev/null +++ b/xserver/mi/mispans.h @@ -0,0 +1,115 @@ +/*********************************************************** + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1989 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + + +typedef struct { + int count; /* number of spans */ + DDXPointPtr points; /* pointer to list of start points */ + int *widths; /* pointer to list of widths */ +} Spans; + +typedef struct { + int size; /* Total number of *Spans allocated */ + int count; /* Number of *Spans actually in group */ + Spans *group; /* List of Spans */ + int ymin, ymax; /* Min, max y values encountered */ +} SpanGroup; + +/* Initialize SpanGroup. MUST BE DONE before use. */ +extern void miInitSpanGroup( + SpanGroup * /*spanGroup*/ +); + +/* Add a Spans to a SpanGroup. The spans MUST BE in y-sorted order */ +extern void miAppendSpans( + SpanGroup * /*spanGroup*/, + SpanGroup * /*otherGroup*/, + Spans * /*spans*/ +); + +/* Paint a span group, possibly with some overlap */ +extern void miFillSpanGroup( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + SpanGroup * /*spanGroup*/ +); + +/* Paint a span group, insuring that each pixel is painted at most once */ +extern void miFillUniqueSpanGroup( + DrawablePtr /*pDraw*/, + GCPtr /*pGC*/, + SpanGroup * /*spanGroup*/ +); + +/* Free up data in a span group. MUST BE DONE or you'll suffer memory leaks */ +extern void miFreeSpanGroup( + SpanGroup * /*spanGroup*/ +); + +extern void miSubtractSpans( + SpanGroup * /*spanGroup*/, + Spans * /*sub*/ +); + +extern void miDisposeSpanGroup( + SpanGroup * /*spanGroup*/ +); + +extern int miClipSpans( + RegionPtr /*prgnDst*/, + DDXPointPtr /*ppt*/, + int * /*pwidth*/, + int /*nspans*/, + DDXPointPtr /*pptNew*/, + int * /*pwidthNew*/, + int /*fSorted*/ +); + +/* Rops which must use span groups */ +#define miSpansCarefulRop(rop) (((rop) & 0xc) == 0x8 || ((rop) & 0x3) == 0x2) +#define miSpansEasyRop(rop) (!miSpansCarefulRop(rop)) + diff --git a/xserver/mi/misprite.c b/xserver/mi/misprite.c new file mode 100644 index 000000000..286c7552a --- /dev/null +++ b/xserver/mi/misprite.c @@ -0,0 +1,829 @@ +/* + * misprite.c + * + * machine independent software sprite routines + */ + + +/* + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +# include <X11/X.h> +# include <X11/Xproto.h> +# include "misc.h" +# include "pixmapstr.h" +# include "input.h" +# include "mi.h" +# include "cursorstr.h" +# include <X11/fonts/font.h> +# include "scrnintstr.h" +# include "colormapst.h" +# include "windowstr.h" +# include "gcstruct.h" +# include "mipointer.h" +# include "mispritest.h" +# include "dixfontstr.h" +# include <X11/fonts/fontstruct.h> + +#ifdef RENDER +# include "mipict.h" +#endif +# include "damage.h" + +#define SPRITE_DEBUG_ENABLE 0 +#if SPRITE_DEBUG_ENABLE +#define SPRITE_DEBUG(x) ErrorF x +#else +#define SPRITE_DEBUG(x) +#endif + +/* + * screen wrappers + */ + +static int miSpriteScreenIndex; +static unsigned long miSpriteGeneration = 0; + +static Bool miSpriteCloseScreen(int i, ScreenPtr pScreen); +static void miSpriteGetImage(DrawablePtr pDrawable, int sx, int sy, + int w, int h, unsigned int format, + unsigned long planemask, char *pdstLine); +static void miSpriteGetSpans(DrawablePtr pDrawable, int wMax, + DDXPointPtr ppt, int *pwidth, int nspans, + char *pdstStart); +static void miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y, + int width, int height); +static void miSpriteCopyWindow (WindowPtr pWindow, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc); +static void miSpriteBlockHandler(int i, pointer blockData, + pointer pTimeout, + pointer pReadMask); +static void miSpriteInstallColormap(ColormapPtr pMap); +static void miSpriteStoreColors(ColormapPtr pMap, int ndef, + xColorItem *pdef); + +static void miSpriteSaveDoomedAreas(WindowPtr pWin, + RegionPtr pObscured, int dx, + int dy); +static void miSpriteComputeSaved(ScreenPtr pScreen); + +#define SCREEN_PROLOGUE(pScreen, field)\ + ((pScreen)->field = \ + ((miSpriteScreenPtr) (pScreen)->devPrivates[miSpriteScreenIndex].ptr)->field) + +#define SCREEN_EPILOGUE(pScreen, field)\ + ((pScreen)->field = miSprite##field) + +/* + * pointer-sprite method table + */ + +static Bool miSpriteRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); +static Bool miSpriteUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); +static void miSpriteSetCursor(ScreenPtr pScreen, CursorPtr pCursor, + int x, int y); +static void miSpriteMoveCursor(ScreenPtr pScreen, int x, int y); + +_X_EXPORT miPointerSpriteFuncRec miSpritePointerFuncs = { + miSpriteRealizeCursor, + miSpriteUnrealizeCursor, + miSpriteSetCursor, + miSpriteMoveCursor, +}; + +/* + * other misc functions + */ + +static void miSpriteRemoveCursor(ScreenPtr pScreen); +static void miSpriteRestoreCursor(ScreenPtr pScreen); + +static void +miSpriteReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure) +{ + ScreenPtr pScreen = closure; + miSpriteScreenPtr pScreenPriv; + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + + if (pScreenPriv->isUp && + RECT_IN_REGION (pScreen, pRegion, &pScreenPriv->saved) != rgnOUT) + { + SPRITE_DEBUG(("Damage remove\n")); + miSpriteRemoveCursor (pScreen); + } +} + +/* + * miSpriteInitialize -- called from device-dependent screen + * initialization proc after all of the function pointers have + * been stored in the screen structure. + */ + +Bool +miSpriteInitialize (pScreen, cursorFuncs, screenFuncs) + ScreenPtr pScreen; + miSpriteCursorFuncPtr cursorFuncs; + miPointerScreenFuncPtr screenFuncs; +{ + miSpriteScreenPtr pScreenPriv; + VisualPtr pVisual; + + if (!DamageSetup (pScreen)) + return FALSE; + + if (miSpriteGeneration != serverGeneration) + { + miSpriteScreenIndex = AllocateScreenPrivateIndex (); + if (miSpriteScreenIndex < 0) + return FALSE; + miSpriteGeneration = serverGeneration; + } + + pScreenPriv = (miSpriteScreenPtr) xalloc (sizeof (miSpriteScreenRec)); + if (!pScreenPriv) + return FALSE; + + pScreenPriv->pDamage = DamageCreate (miSpriteReportDamage, + (DamageDestroyFunc) 0, + DamageReportRawRegion, + TRUE, + pScreen, + (void *) pScreen); + + if (!miPointerInitialize (pScreen, &miSpritePointerFuncs, screenFuncs,TRUE)) + { + xfree ((pointer) pScreenPriv); + return FALSE; + } + for (pVisual = pScreen->visuals; + pVisual->vid != pScreen->rootVisual; + pVisual++) + ; + pScreenPriv->pVisual = pVisual; + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreenPriv->GetImage = pScreen->GetImage; + pScreenPriv->GetSpans = pScreen->GetSpans; + pScreenPriv->SourceValidate = pScreen->SourceValidate; + + pScreenPriv->CopyWindow = pScreen->CopyWindow; + + pScreenPriv->SaveDoomedAreas = pScreen->SaveDoomedAreas; + + pScreenPriv->InstallColormap = pScreen->InstallColormap; + pScreenPriv->StoreColors = pScreen->StoreColors; + + pScreenPriv->BlockHandler = pScreen->BlockHandler; + + pScreenPriv->pCursor = NULL; + pScreenPriv->x = 0; + pScreenPriv->y = 0; + pScreenPriv->isUp = FALSE; + pScreenPriv->shouldBeUp = FALSE; + pScreenPriv->pCacheWin = NullWindow; + pScreenPriv->isInCacheWin = FALSE; + pScreenPriv->checkPixels = TRUE; + pScreenPriv->pInstalledMap = NULL; + pScreenPriv->pColormap = NULL; + pScreenPriv->funcs = cursorFuncs; + pScreenPriv->colors[SOURCE_COLOR].red = 0; + pScreenPriv->colors[SOURCE_COLOR].green = 0; + pScreenPriv->colors[SOURCE_COLOR].blue = 0; + pScreenPriv->colors[MASK_COLOR].red = 0; + pScreenPriv->colors[MASK_COLOR].green = 0; + pScreenPriv->colors[MASK_COLOR].blue = 0; + pScreen->devPrivates[miSpriteScreenIndex].ptr = (pointer) pScreenPriv; + + pScreen->CloseScreen = miSpriteCloseScreen; + pScreen->GetImage = miSpriteGetImage; + pScreen->GetSpans = miSpriteGetSpans; + pScreen->SourceValidate = miSpriteSourceValidate; + + pScreen->CopyWindow = miSpriteCopyWindow; + + pScreen->SaveDoomedAreas = miSpriteSaveDoomedAreas; + + pScreen->InstallColormap = miSpriteInstallColormap; + pScreen->StoreColors = miSpriteStoreColors; + + pScreen->BlockHandler = miSpriteBlockHandler; + + return TRUE; +} + +/* + * Screen wrappers + */ + +/* + * CloseScreen wrapper -- unwrap everything, free the private data + * and call the wrapped function + */ + +static Bool +miSpriteCloseScreen (i, pScreen) + int i; + ScreenPtr pScreen; +{ + miSpriteScreenPtr pScreenPriv; + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + pScreen->GetImage = pScreenPriv->GetImage; + pScreen->GetSpans = pScreenPriv->GetSpans; + pScreen->SourceValidate = pScreenPriv->SourceValidate; + pScreen->BlockHandler = pScreenPriv->BlockHandler; + pScreen->InstallColormap = pScreenPriv->InstallColormap; + pScreen->StoreColors = pScreenPriv->StoreColors; + + pScreen->SaveDoomedAreas = pScreenPriv->SaveDoomedAreas; + miSpriteIsUpFALSE (pScreen, pScreenPriv); + DamageDestroy (pScreenPriv->pDamage); + + xfree ((pointer) pScreenPriv); + + return (*pScreen->CloseScreen) (i, pScreen); +} + +static void +miSpriteGetImage (pDrawable, sx, sy, w, h, format, planemask, pdstLine) + DrawablePtr pDrawable; + int sx, sy, w, h; + unsigned int format; + unsigned long planemask; + char *pdstLine; +{ + ScreenPtr pScreen = pDrawable->pScreen; + miSpriteScreenPtr pScreenPriv; + + SCREEN_PROLOGUE (pScreen, GetImage); + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + + if (pDrawable->type == DRAWABLE_WINDOW && + pScreenPriv->isUp && + ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y, sx, sy, w, h)) + { + SPRITE_DEBUG (("GetImage remove\n")); + miSpriteRemoveCursor (pScreen); + } + + (*pScreen->GetImage) (pDrawable, sx, sy, w, h, + format, planemask, pdstLine); + + SCREEN_EPILOGUE (pScreen, GetImage); +} + +static void +miSpriteGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart) + DrawablePtr pDrawable; + int wMax; + DDXPointPtr ppt; + int *pwidth; + int nspans; + char *pdstStart; +{ + ScreenPtr pScreen = pDrawable->pScreen; + miSpriteScreenPtr pScreenPriv; + + SCREEN_PROLOGUE (pScreen, GetSpans); + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + + if (pDrawable->type == DRAWABLE_WINDOW && pScreenPriv->isUp) + { + register DDXPointPtr pts; + register int *widths; + register int nPts; + register int xorg, + yorg; + + xorg = pDrawable->x; + yorg = pDrawable->y; + + for (pts = ppt, widths = pwidth, nPts = nspans; + nPts--; + pts++, widths++) + { + if (SPN_OVERLAP(&pScreenPriv->saved,pts->y+yorg, + pts->x+xorg,*widths)) + { + SPRITE_DEBUG (("GetSpans remove\n")); + miSpriteRemoveCursor (pScreen); + break; + } + } + } + + (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); + + SCREEN_EPILOGUE (pScreen, GetSpans); +} + +static void +miSpriteSourceValidate (pDrawable, x, y, width, height) + DrawablePtr pDrawable; + int x, y, width, height; +{ + ScreenPtr pScreen = pDrawable->pScreen; + miSpriteScreenPtr pScreenPriv; + + SCREEN_PROLOGUE (pScreen, SourceValidate); + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + + if (pDrawable->type == DRAWABLE_WINDOW && pScreenPriv->isUp && + ORG_OVERLAP(&pScreenPriv->saved, pDrawable->x, pDrawable->y, + x, y, width, height)) + { + SPRITE_DEBUG (("SourceValidate remove\n")); + miSpriteRemoveCursor (pScreen); + } + + if (pScreen->SourceValidate) + (*pScreen->SourceValidate) (pDrawable, x, y, width, height); + + SCREEN_EPILOGUE (pScreen, SourceValidate); +} + +static void +miSpriteCopyWindow (WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + miSpriteScreenPtr pScreenPriv; + + SCREEN_PROLOGUE (pScreen, CopyWindow); + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + /* + * Damage will take care of destination check + */ + if (pScreenPriv->isUp && + RECT_IN_REGION (pScreen, prgnSrc, &pScreenPriv->saved) != rgnOUT) + { + SPRITE_DEBUG (("CopyWindow remove\n")); + miSpriteRemoveCursor (pScreen); + } + + (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc); + SCREEN_EPILOGUE (pScreen, CopyWindow); +} + +static void +miSpriteBlockHandler (i, blockData, pTimeout, pReadmask) + int i; + pointer blockData; + pointer pTimeout; + pointer pReadmask; +{ + ScreenPtr pScreen = screenInfo.screens[i]; + miSpriteScreenPtr pPriv; + + pPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + + SCREEN_PROLOGUE(pScreen, BlockHandler); + + (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); + + SCREEN_EPILOGUE(pScreen, BlockHandler); + + if (!pPriv->isUp && pPriv->shouldBeUp) + { + SPRITE_DEBUG (("BlockHandler restore\n")); + miSpriteRestoreCursor (pScreen); + } +} + +static void +miSpriteInstallColormap (pMap) + ColormapPtr pMap; +{ + ScreenPtr pScreen = pMap->pScreen; + miSpriteScreenPtr pPriv; + + pPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + + SCREEN_PROLOGUE(pScreen, InstallColormap); + + (*pScreen->InstallColormap) (pMap); + + SCREEN_EPILOGUE(pScreen, InstallColormap); + + pPriv->pInstalledMap = pMap; + if (pPriv->pColormap != pMap) + { + pPriv->checkPixels = TRUE; + if (pPriv->isUp) + miSpriteRemoveCursor (pScreen); + } +} + +static void +miSpriteStoreColors (pMap, ndef, pdef) + ColormapPtr pMap; + int ndef; + xColorItem *pdef; +{ + ScreenPtr pScreen = pMap->pScreen; + miSpriteScreenPtr pPriv; + int i; + int updated; + VisualPtr pVisual; + + pPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + + SCREEN_PROLOGUE(pScreen, StoreColors); + + (*pScreen->StoreColors) (pMap, ndef, pdef); + + SCREEN_EPILOGUE(pScreen, StoreColors); + + if (pPriv->pColormap == pMap) + { + updated = 0; + pVisual = pMap->pVisual; + if (pVisual->class == DirectColor) + { + /* Direct color - match on any of the subfields */ + +#define MaskMatch(a,b,mask) (((a) & (pVisual->mask)) == ((b) & (pVisual->mask))) + +#define UpdateDAC(plane,dac,mask) {\ + if (MaskMatch (pPriv->colors[plane].pixel,pdef[i].pixel,mask)) {\ + pPriv->colors[plane].dac = pdef[i].dac; \ + updated = 1; \ + } \ +} + +#define CheckDirect(plane) \ + UpdateDAC(plane,red,redMask) \ + UpdateDAC(plane,green,greenMask) \ + UpdateDAC(plane,blue,blueMask) + + for (i = 0; i < ndef; i++) + { + CheckDirect (SOURCE_COLOR) + CheckDirect (MASK_COLOR) + } + } + else + { + /* PseudoColor/GrayScale - match on exact pixel */ + for (i = 0; i < ndef; i++) + { + if (pdef[i].pixel == pPriv->colors[SOURCE_COLOR].pixel) + { + pPriv->colors[SOURCE_COLOR] = pdef[i]; + if (++updated == 2) + break; + } + if (pdef[i].pixel == pPriv->colors[MASK_COLOR].pixel) + { + pPriv->colors[MASK_COLOR] = pdef[i]; + if (++updated == 2) + break; + } + } + } + if (updated) + { + pPriv->checkPixels = TRUE; + if (pPriv->isUp) + miSpriteRemoveCursor (pScreen); + } + } +} + +static void +miSpriteFindColors (ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv = (miSpriteScreenPtr) + pScreen->devPrivates[miSpriteScreenIndex].ptr; + CursorPtr pCursor; + xColorItem *sourceColor, *maskColor; + + pCursor = pScreenPriv->pCursor; + sourceColor = &pScreenPriv->colors[SOURCE_COLOR]; + maskColor = &pScreenPriv->colors[MASK_COLOR]; + if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap || + !(pCursor->foreRed == sourceColor->red && + pCursor->foreGreen == sourceColor->green && + pCursor->foreBlue == sourceColor->blue && + pCursor->backRed == maskColor->red && + pCursor->backGreen == maskColor->green && + pCursor->backBlue == maskColor->blue)) + { + pScreenPriv->pColormap = pScreenPriv->pInstalledMap; + sourceColor->red = pCursor->foreRed; + sourceColor->green = pCursor->foreGreen; + sourceColor->blue = pCursor->foreBlue; + FakeAllocColor (pScreenPriv->pColormap, sourceColor); + maskColor->red = pCursor->backRed; + maskColor->green = pCursor->backGreen; + maskColor->blue = pCursor->backBlue; + FakeAllocColor (pScreenPriv->pColormap, maskColor); + /* "free" the pixels right away, don't let this confuse you */ + FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel); + FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel); + } + pScreenPriv->checkPixels = FALSE; +} + +/* + * BackingStore wrappers + */ + +static void +miSpriteSaveDoomedAreas (pWin, pObscured, dx, dy) + WindowPtr pWin; + RegionPtr pObscured; + int dx, dy; +{ + ScreenPtr pScreen; + miSpriteScreenPtr pScreenPriv; + BoxRec cursorBox; + + pScreen = pWin->drawable.pScreen; + + SCREEN_PROLOGUE (pScreen, SaveDoomedAreas); + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + if (pScreenPriv->isUp) + { + cursorBox = pScreenPriv->saved; + + if (dx || dy) + { + cursorBox.x1 += dx; + cursorBox.y1 += dy; + cursorBox.x2 += dx; + cursorBox.y2 += dy; + } + if (RECT_IN_REGION( pScreen, pObscured, &cursorBox) != rgnOUT) + miSpriteRemoveCursor (pScreen); + } + + (*pScreen->SaveDoomedAreas) (pWin, pObscured, dx, dy); + + SCREEN_EPILOGUE (pScreen, SaveDoomedAreas); +} + +/* + * miPointer interface routines + */ + +#define SPRITE_PAD 8 + +static Bool +miSpriteRealizeCursor (pScreen, pCursor) + ScreenPtr pScreen; + CursorPtr pCursor; +{ + miSpriteScreenPtr pScreenPriv; + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + if (pCursor == pScreenPriv->pCursor) + pScreenPriv->checkPixels = TRUE; + return (*pScreenPriv->funcs->RealizeCursor) (pScreen, pCursor); +} + +static Bool +miSpriteUnrealizeCursor (pScreen, pCursor) + ScreenPtr pScreen; + CursorPtr pCursor; +{ + miSpriteScreenPtr pScreenPriv; + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + return (*pScreenPriv->funcs->UnrealizeCursor) (pScreen, pCursor); +} + +static void +miSpriteSetCursor (pScreen, pCursor, x, y) + ScreenPtr pScreen; + CursorPtr pCursor; + int x; + int y; +{ + miSpriteScreenPtr pScreenPriv; + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + if (!pCursor) + { + pScreenPriv->shouldBeUp = FALSE; + if (pScreenPriv->isUp) + miSpriteRemoveCursor (pScreen); + pScreenPriv->pCursor = 0; + return; + } + pScreenPriv->shouldBeUp = TRUE; + if (pScreenPriv->x == x && + pScreenPriv->y == y && + pScreenPriv->pCursor == pCursor && + !pScreenPriv->checkPixels) + { + return; + } + pScreenPriv->x = x; + pScreenPriv->y = y; + pScreenPriv->pCacheWin = NullWindow; + if (pScreenPriv->checkPixels || pScreenPriv->pCursor != pCursor) + { + pScreenPriv->pCursor = pCursor; + miSpriteFindColors (pScreen); + } + if (pScreenPriv->isUp) { + int sx, sy; + /* + * check to see if the old saved region + * encloses the new sprite, in which case we use + * the flicker-free MoveCursor primitive. + */ + sx = pScreenPriv->x - (int)pCursor->bits->xhot; + sy = pScreenPriv->y - (int)pCursor->bits->yhot; + if (sx + (int) pCursor->bits->width >= pScreenPriv->saved.x1 && + sx < pScreenPriv->saved.x2 && + sy + (int) pCursor->bits->height >= pScreenPriv->saved.y1 && + sy < pScreenPriv->saved.y2 && + (int) pCursor->bits->width + (2 * SPRITE_PAD) == + pScreenPriv->saved.x2 - pScreenPriv->saved.x1 && + (int) pCursor->bits->height + (2 * SPRITE_PAD) == + pScreenPriv->saved.y2 - pScreenPriv->saved.y1 + ) + { + DamageDrawInternal (pScreen, TRUE); + miSpriteIsUpFALSE (pScreen, pScreenPriv); + if (!(sx >= pScreenPriv->saved.x1 && + sx + (int)pCursor->bits->width < pScreenPriv->saved.x2 && + sy >= pScreenPriv->saved.y1 && + sy + (int)pCursor->bits->height < pScreenPriv->saved.y2)) + { + int oldx1, oldy1, dx, dy; + + oldx1 = pScreenPriv->saved.x1; + oldy1 = pScreenPriv->saved.y1; + dx = oldx1 - (sx - SPRITE_PAD); + dy = oldy1 - (sy - SPRITE_PAD); + pScreenPriv->saved.x1 -= dx; + pScreenPriv->saved.y1 -= dy; + pScreenPriv->saved.x2 -= dx; + pScreenPriv->saved.y2 -= dy; + (void) (*pScreenPriv->funcs->ChangeSave) (pScreen, + pScreenPriv->saved.x1, + pScreenPriv->saved.y1, + pScreenPriv->saved.x2 - pScreenPriv->saved.x1, + pScreenPriv->saved.y2 - pScreenPriv->saved.y1, + dx, dy); + } + (void) (*pScreenPriv->funcs->MoveCursor) (pScreen, pCursor, + pScreenPriv->saved.x1, + pScreenPriv->saved.y1, + pScreenPriv->saved.x2 - pScreenPriv->saved.x1, + pScreenPriv->saved.y2 - pScreenPriv->saved.y1, + sx - pScreenPriv->saved.x1, + sy - pScreenPriv->saved.y1, + pScreenPriv->colors[SOURCE_COLOR].pixel, + pScreenPriv->colors[MASK_COLOR].pixel); + miSpriteIsUpTRUE (pScreen, pScreenPriv); + DamageDrawInternal (pScreen, FALSE); + } + else + { + SPRITE_DEBUG (("SetCursor remove\n")); + miSpriteRemoveCursor (pScreen); + } + } + if (!pScreenPriv->isUp && pScreenPriv->pCursor) + { + SPRITE_DEBUG (("SetCursor restore\n")); + miSpriteRestoreCursor (pScreen); + } +} + +static void +miSpriteMoveCursor (pScreen, x, y) + ScreenPtr pScreen; + int x, y; +{ + miSpriteScreenPtr pScreenPriv; + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + miSpriteSetCursor (pScreen, pScreenPriv->pCursor, x, y); +} + +/* + * undraw/draw cursor + */ + +static void +miSpriteRemoveCursor (pScreen) + ScreenPtr pScreen; +{ + miSpriteScreenPtr pScreenPriv; + + DamageDrawInternal (pScreen, TRUE); + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + miSpriteIsUpFALSE (pScreen, pScreenPriv); + pScreenPriv->pCacheWin = NullWindow; + if (!(*pScreenPriv->funcs->RestoreUnderCursor) (pScreen, + pScreenPriv->saved.x1, + pScreenPriv->saved.y1, + pScreenPriv->saved.x2 - pScreenPriv->saved.x1, + pScreenPriv->saved.y2 - pScreenPriv->saved.y1)) + { + miSpriteIsUpTRUE (pScreen, pScreenPriv); + } + DamageDrawInternal (pScreen, FALSE); +} + +/* + * Called from the block handler, restores the cursor + * before waiting for something to do. + */ + +static void +miSpriteRestoreCursor (pScreen) + ScreenPtr pScreen; +{ + miSpriteScreenPtr pScreenPriv; + int x, y; + CursorPtr pCursor; + + DamageDrawInternal (pScreen, TRUE); + miSpriteComputeSaved (pScreen); + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + pCursor = pScreenPriv->pCursor; + x = pScreenPriv->x - (int)pCursor->bits->xhot; + y = pScreenPriv->y - (int)pCursor->bits->yhot; + if ((*pScreenPriv->funcs->SaveUnderCursor) (pScreen, + pScreenPriv->saved.x1, + pScreenPriv->saved.y1, + pScreenPriv->saved.x2 - pScreenPriv->saved.x1, + pScreenPriv->saved.y2 - pScreenPriv->saved.y1)) + { + if (pScreenPriv->checkPixels) + miSpriteFindColors (pScreen); + if ((*pScreenPriv->funcs->PutUpCursor) (pScreen, pCursor, x, y, + pScreenPriv->colors[SOURCE_COLOR].pixel, + pScreenPriv->colors[MASK_COLOR].pixel)) + { + miSpriteIsUpTRUE (pScreen, pScreenPriv); + } + } + DamageDrawInternal (pScreen, FALSE); +} + +/* + * compute the desired area of the screen to save + */ + +static void +miSpriteComputeSaved (pScreen) + ScreenPtr pScreen; +{ + miSpriteScreenPtr pScreenPriv; + int x, y, w, h; + int wpad, hpad; + CursorPtr pCursor; + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + pCursor = pScreenPriv->pCursor; + x = pScreenPriv->x - (int)pCursor->bits->xhot; + y = pScreenPriv->y - (int)pCursor->bits->yhot; + w = pCursor->bits->width; + h = pCursor->bits->height; + wpad = SPRITE_PAD; + hpad = SPRITE_PAD; + pScreenPriv->saved.x1 = x - wpad; + pScreenPriv->saved.y1 = y - hpad; + pScreenPriv->saved.x2 = pScreenPriv->saved.x1 + w + wpad * 2; + pScreenPriv->saved.y2 = pScreenPriv->saved.y1 + h + hpad * 2; +} diff --git a/xserver/mi/misprite.h b/xserver/mi/misprite.h new file mode 100644 index 000000000..5173b7736 --- /dev/null +++ b/xserver/mi/misprite.h @@ -0,0 +1,94 @@ +/* + * misprite.h + * + * software-sprite/sprite drawing interface spec + * + * mi versions of these routines exist. + */ + + +/* + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. +*/ + +typedef struct { + Bool (*RealizeCursor)( + ScreenPtr /*pScreen*/, + CursorPtr /*pCursor*/ +); + Bool (*UnrealizeCursor)( + ScreenPtr /*pScreen*/, + CursorPtr /*pCursor*/ +); + Bool (*PutUpCursor)( + ScreenPtr /*pScreen*/, + CursorPtr /*pCursor*/, + int /*x*/, + int /*y*/, + unsigned long /*source*/, + unsigned long /*mask*/ +); + Bool (*SaveUnderCursor)( + ScreenPtr /*pScreen*/, + int /*x*/, + int /*y*/, + int /*w*/, + int /*h*/ +); + Bool (*RestoreUnderCursor)( + ScreenPtr /*pScreen*/, + int /*x*/, + int /*y*/, + int /*w*/, + int /*h*/ +); + Bool (*MoveCursor)( + ScreenPtr /*pScreen*/, + CursorPtr /*pCursor*/, + int /*x*/, + int /*y*/, + int /*w*/, + int /*h*/, + int /*dx*/, + int /*dy*/, + unsigned long /*source*/, + unsigned long /*mask*/ +); + Bool (*ChangeSave)( + ScreenPtr /*pScreen*/, + int /*x*/, + int /*y*/, + int /*w*/, + int /*h*/, + int /*dx*/, + int /*dy*/ +); + +} miSpriteCursorFuncRec, *miSpriteCursorFuncPtr; + +extern Bool miSpriteInitialize( + ScreenPtr /*pScreen*/, + miSpriteCursorFuncPtr /*cursorFuncs*/, + miPointerScreenFuncPtr /*screenFuncs*/ +); diff --git a/xserver/mi/mispritest.h b/xserver/mi/mispritest.h new file mode 100644 index 000000000..5075f0580 --- /dev/null +++ b/xserver/mi/mispritest.h @@ -0,0 +1,132 @@ +/* + * mispritest.h + * + * mi sprite structures + */ + + +/* + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifndef _MISPRITEST_H_ +#define _MISPRITEST_H_ + +# include "misprite.h" +#ifdef RENDER +# include "picturestr.h" +#endif +# include "damage.h" + +/* + * per screen information + */ + +typedef struct { + /* screen procedures */ + CloseScreenProcPtr CloseScreen; + GetImageProcPtr GetImage; + GetSpansProcPtr GetSpans; + SourceValidateProcPtr SourceValidate; + + /* window procedures */ + CopyWindowProcPtr CopyWindow; + + /* backing store procedures */ + SaveDoomedAreasProcPtr SaveDoomedAreas; + + /* colormap procedures */ + InstallColormapProcPtr InstallColormap; + StoreColorsProcPtr StoreColors; + + /* os layer procedures */ + ScreenBlockHandlerProcPtr BlockHandler; + + CursorPtr pCursor; + int x; /* cursor hotspot */ + int y; + BoxRec saved; /* saved area from the screen */ + Bool isUp; /* cursor in frame buffer */ + Bool shouldBeUp; /* cursor should be displayed */ + WindowPtr pCacheWin; /* window the cursor last seen in */ + Bool isInCacheWin; + Bool checkPixels; /* check colormap collision */ + xColorItem colors[2]; + ColormapPtr pInstalledMap; + ColormapPtr pColormap; + VisualPtr pVisual; + miSpriteCursorFuncPtr funcs; + DamagePtr pDamage; /* damage tracking structure */ +} miSpriteScreenRec, *miSpriteScreenPtr; + +#define SOURCE_COLOR 0 +#define MASK_COLOR 1 + +#define miSpriteIsUpTRUE(pScreen, pScreenPriv) if (!pScreenPriv->isUp) { \ + pScreenPriv->isUp = TRUE; \ + DamageRegister (&(*pScreen->GetScreenPixmap) (pScreen)->drawable, pScreenPriv->pDamage); \ +} + +#define miSpriteIsUpFALSE(pScreen, pScreenPriv) if (pScreenPriv->isUp) { \ + DamageUnregister (&(*pScreen->GetScreenPixmap) (pScreen)->drawable, pScreenPriv->pDamage); \ + pScreenPriv->isUp = FALSE; \ +} + +/* + * Overlap BoxPtr and Box elements + */ +#define BOX_OVERLAP(pCbox,X1,Y1,X2,Y2) \ + (((pCbox)->x1 <= (X2)) && ((X1) <= (pCbox)->x2) && \ + ((pCbox)->y1 <= (Y2)) && ((Y1) <= (pCbox)->y2)) + +/* + * Overlap BoxPtr, origins, and rectangle + */ +#define ORG_OVERLAP(pCbox,xorg,yorg,x,y,w,h) \ + BOX_OVERLAP((pCbox),(x)+(xorg),(y)+(yorg),(x)+(xorg)+(w),(y)+(yorg)+(h)) + +/* + * Overlap BoxPtr, origins and RectPtr + */ +#define ORGRECT_OVERLAP(pCbox,xorg,yorg,pRect) \ + ORG_OVERLAP((pCbox),(xorg),(yorg),(pRect)->x,(pRect)->y, \ + (int)((pRect)->width), (int)((pRect)->height)) +/* + * Overlap BoxPtr and horizontal span + */ +#define SPN_OVERLAP(pCbox,y,x,w) BOX_OVERLAP((pCbox),(x),(y),(x)+(w),(y)) + +#define LINE_SORT(x1,y1,x2,y2) \ +{ int _t; \ + if (x1 > x2) { _t = x1; x1 = x2; x2 = _t; } \ + if (y1 > y2) { _t = y1; y1 = y2; y2 = _t; } } + +#define LINE_OVERLAP(pCbox,x1,y1,x2,y2,lw2) \ + BOX_OVERLAP((pCbox), (x1)-(lw2), (y1)-(lw2), (x2)+(lw2), (y2)+(lw2)) + +#endif /* _MISPRITEST_H_ */ diff --git a/xserver/mi/mistruct.h b/xserver/mi/mistruct.h new file mode 100644 index 000000000..9b9de8677 --- /dev/null +++ b/xserver/mi/mistruct.h @@ -0,0 +1,64 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +/* $XFree86$ */ + +#ifndef MISTRUCT_H +#define MISTRUCT_H + +#include "mi.h" +#include "regionstr.h" + +/* information about dashes */ +typedef struct _miDash { + DDXPointRec pt; + int e1, e2; /* keep these, so we don't have to do it again */ + int e; /* bresenham error term for this point on line */ + int which; + int newLine;/* 0 if part of same original line as previous dash */ + } miDashRec; + +#endif /* MISTRUCT_H */ diff --git a/xserver/mi/mivalidate.h b/xserver/mi/mivalidate.h new file mode 100644 index 000000000..91858328a --- /dev/null +++ b/xserver/mi/mivalidate.h @@ -0,0 +1,54 @@ +/* + +Copyright 1993, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ +/* $XFree86$ */ + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifndef MIVALIDATE_H +#define MIVALIDATE_H + +#include "regionstr.h" + +typedef union _Validate { + struct BeforeValidate { + DDXPointRec oldAbsCorner; /* old window position */ + RegionPtr borderVisible; /* visible region of border, */ + /* non-null when size changes */ + Bool resized; /* unclipped winSize has changed - */ + /* don't call SaveDoomedAreas */ + } before; + struct AfterValidate { + RegionRec exposed; /* exposed regions, absolute pos */ + RegionRec borderExposed; + } after; +} ValidateRec; + +#endif /* MIVALIDATE_H */ diff --git a/xserver/mi/mivaltree.c b/xserver/mi/mivaltree.c new file mode 100644 index 000000000..0e5ed61e7 --- /dev/null +++ b/xserver/mi/mivaltree.c @@ -0,0 +1,823 @@ +/* + * mivaltree.c -- + * Functions for recalculating window clip lists. Main function + * is miValidateTree. + * + +Copyright 1987, 1988, 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + * + * Copyright 1987, 1988, 1989 by + * Digital Equipment Corporation, Maynard, Massachusetts, + * + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + ******************************************************************/ + +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + + + /* + * Aug '86: Susan Angebranndt -- original code + * July '87: Adam de Boor -- substantially modified and commented + * Summer '89: Joel McCormack -- so fast you wouldn't believe it possible. + * In particular, much improved code for window mapping and + * circulating. + * Bob Scheifler -- avoid miComputeClips for unmapped windows, + * valdata changes + */ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include "scrnintstr.h" +#include "validate.h" +#include "windowstr.h" +#include "mi.h" +#include "regionstr.h" +#include "mivalidate.h" + +#include "globals.h" + +#ifdef SHAPE +/* + * Compute the visibility of a shaped window + */ +_X_EXPORT int +miShapedWindowIn (pScreen, universe, bounding, rect, x, y) + ScreenPtr pScreen; + RegionPtr universe, bounding; + BoxPtr rect; + register int x, y; +{ + BoxRec box; + register BoxPtr boundBox; + int nbox; + Bool someIn, someOut; + register int t, x1, y1, x2, y2; + + nbox = REGION_NUM_RECTS (bounding); + boundBox = REGION_RECTS (bounding); + someIn = someOut = FALSE; + x1 = rect->x1; + y1 = rect->y1; + x2 = rect->x2; + y2 = rect->y2; + while (nbox--) + { + if ((t = boundBox->x1 + x) < x1) + t = x1; + box.x1 = t; + if ((t = boundBox->y1 + y) < y1) + t = y1; + box.y1 = t; + if ((t = boundBox->x2 + x) > x2) + t = x2; + box.x2 = t; + if ((t = boundBox->y2 + y) > y2) + t = y2; + box.y2 = t; + if (box.x1 > box.x2) + box.x2 = box.x1; + if (box.y1 > box.y2) + box.y2 = box.y1; + switch (RECT_IN_REGION(pScreen, universe, &box)) + { + case rgnIN: + if (someOut) + return rgnPART; + someIn = TRUE; + break; + case rgnOUT: + if (someIn) + return rgnPART; + someOut = TRUE; + break; + default: + return rgnPART; + } + boundBox++; + } + if (someIn) + return rgnIN; + return rgnOUT; +} +#endif + +static GetRedirectBorderClipProcPtr miGetRedirectBorderClipProc; +static SetRedirectBorderClipProcPtr miSetRedirectBorderClipProc; + +void +miRegisterRedirectBorderClipProc (SetRedirectBorderClipProcPtr setBorderClip, + GetRedirectBorderClipProcPtr getBorderClip) +{ + miSetRedirectBorderClipProc = setBorderClip; + miGetRedirectBorderClipProc = getBorderClip; +} + +#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \ + HasBorder(w) && \ + (w)->backgroundState == ParentRelative) + + +/* + *----------------------------------------------------------------------- + * miComputeClips -- + * Recompute the clipList, borderClip, exposed and borderExposed + * regions for pParent and its children. Only viewable windows are + * taken into account. + * + * Results: + * None. + * + * Side Effects: + * clipList, borderClip, exposed and borderExposed are altered. + * A VisibilityNotify event may be generated on the parent window. + * + *----------------------------------------------------------------------- + */ +static void +miComputeClips ( + register WindowPtr pParent, + register ScreenPtr pScreen, + register RegionPtr universe, + VTKind kind, + RegionPtr exposed ) /* for intermediate calculations */ +{ + int dx, + dy; + RegionRec childUniverse; + register WindowPtr pChild; + int oldVis, newVis; + BoxRec borderSize; + RegionRec childUnion; + Bool overlap; + RegionPtr borderVisible; + Bool resized; + /* + * Figure out the new visibility of this window. + * The extent of the universe should be the same as the extent of + * the borderSize region. If the window is unobscured, this rectangle + * will be completely inside the universe (the universe will cover it + * completely). If the window is completely obscured, none of the + * universe will cover the rectangle. + */ + borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent); + borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent); + dx = (int) pParent->drawable.x + (int) pParent->drawable.width + wBorderWidth(pParent); + if (dx > 32767) + dx = 32767; + borderSize.x2 = dx; + dy = (int) pParent->drawable.y + (int) pParent->drawable.height + wBorderWidth(pParent); + if (dy > 32767) + dy = 32767; + borderSize.y2 = dy; + +#ifdef COMPOSITE + /* + * In redirected drawing case, reset universe to borderSize + */ + if (pParent->redirectDraw) + { + if (miSetRedirectBorderClipProc) + (*miSetRedirectBorderClipProc) (pParent, universe); + REGION_COPY(pScreen, universe, &pParent->borderSize); + } +#endif + + oldVis = pParent->visibility; + switch (RECT_IN_REGION( pScreen, universe, &borderSize)) + { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnPART: + newVis = VisibilityPartiallyObscured; +#ifdef SHAPE + { + RegionPtr pBounding; + + if ((pBounding = wBoundingShape (pParent))) + { + switch (miShapedWindowIn (pScreen, universe, pBounding, + &borderSize, + pParent->drawable.x, + pParent->drawable.y)) + { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnOUT: + newVis = VisibilityFullyObscured; + break; + } + } + } +#endif + break; + default: + newVis = VisibilityFullyObscured; + break; + } + pParent->visibility = newVis; + if (oldVis != newVis && + ((pParent->eventMask | wOtherEventMasks(pParent)) & VisibilityChangeMask)) + SendVisibilityNotify(pParent); + + dx = pParent->drawable.x - pParent->valdata->before.oldAbsCorner.x; + dy = pParent->drawable.y - pParent->valdata->before.oldAbsCorner.y; + + /* + * avoid computations when dealing with simple operations + */ + + switch (kind) { + case VTMap: + case VTStack: + case VTUnmap: + break; + case VTMove: + if ((oldVis == newVis) && + ((oldVis == VisibilityFullyObscured) || + (oldVis == VisibilityUnobscured))) + { + pChild = pParent; + while (1) + { + if (pChild->viewable) + { + if (pChild->visibility != VisibilityFullyObscured) + { + REGION_TRANSLATE( pScreen, &pChild->borderClip, + dx, dy); + REGION_TRANSLATE( pScreen, &pChild->clipList, + dx, dy); + pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER; + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pChild, dx, dy); + + } + if (pChild->valdata) + { + REGION_NULL(pScreen, + &pChild->valdata->after.borderExposed); + if (HasParentRelativeBorder(pChild)) + { + REGION_SUBTRACT(pScreen, + &pChild->valdata->after.borderExposed, + &pChild->borderClip, + &pChild->winSize); + } + REGION_NULL(pScreen, &pChild->valdata->after.exposed); + } + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pParent)) + pChild = pChild->parent; + if (pChild == pParent) + break; + pChild = pChild->nextSib; + } + return; + } + /* fall through */ + default: + /* + * To calculate exposures correctly, we have to translate the old + * borderClip and clipList regions to the window's new location so there + * is a correspondence between pieces of the new and old clipping regions. + */ + if (dx || dy) + { + /* + * We translate the old clipList because that will be exposed or copied + * if gravity is right. + */ + REGION_TRANSLATE( pScreen, &pParent->borderClip, dx, dy); + REGION_TRANSLATE( pScreen, &pParent->clipList, dx, dy); + } + break; + case VTBroken: + REGION_EMPTY (pScreen, &pParent->borderClip); + REGION_EMPTY (pScreen, &pParent->clipList); + break; + } + + borderVisible = pParent->valdata->before.borderVisible; + resized = pParent->valdata->before.resized; + REGION_NULL(pScreen, &pParent->valdata->after.borderExposed); + REGION_NULL(pScreen, &pParent->valdata->after.exposed); + + /* + * Since the borderClip must not be clipped by the children, we do + * the border exposure first... + * + * 'universe' is the window's borderClip. To figure the exposures, remove + * the area that used to be exposed from the new. + * This leaves a region of pieces that weren't exposed before. + */ + + if (HasBorder (pParent)) + { + if (borderVisible) + { + /* + * when the border changes shape, the old visible portions + * of the border will be saved by DIX in borderVisible -- + * use that region and destroy it + */ + REGION_SUBTRACT( pScreen, exposed, universe, borderVisible); + REGION_DESTROY( pScreen, borderVisible); + } + else + { + REGION_SUBTRACT( pScreen, exposed, universe, &pParent->borderClip); + } + if (HasParentRelativeBorder(pParent) && (dx || dy)) + REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed, + universe, + &pParent->winSize); + else + REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed, + exposed, &pParent->winSize); + + REGION_COPY( pScreen, &pParent->borderClip, universe); + + /* + * To get the right clipList for the parent, and to make doubly sure + * that no child overlaps the parent's border, we remove the parent's + * border from the universe before proceeding. + */ + + REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize); + } + else + REGION_COPY( pScreen, &pParent->borderClip, universe); + + if ((pChild = pParent->firstChild) && pParent->mapped) + { + REGION_NULL(pScreen, &childUniverse); + REGION_NULL(pScreen, &childUnion); + if ((pChild->drawable.y < pParent->lastChild->drawable.y) || + ((pChild->drawable.y == pParent->lastChild->drawable.y) && + (pChild->drawable.x < pParent->lastChild->drawable.x))) + { + for (; pChild; pChild = pChild->nextSib) + { + if (pChild->viewable) + REGION_APPEND( pScreen, &childUnion, &pChild->borderSize); + } + } + else + { + for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib) + { + if (pChild->viewable) + REGION_APPEND( pScreen, &childUnion, &pChild->borderSize); + } + } + REGION_VALIDATE( pScreen, &childUnion, &overlap); + + for (pChild = pParent->firstChild; + pChild; + pChild = pChild->nextSib) + { + if (pChild->viewable) { + /* + * If the child is viewable, we want to remove its extents + * from the current universe, but we only re-clip it if + * it's been marked. + */ + if (pChild->valdata) { + /* + * Figure out the new universe from the child's + * perspective and recurse. + */ + REGION_INTERSECT( pScreen, &childUniverse, + universe, + &pChild->borderSize); + miComputeClips (pChild, pScreen, &childUniverse, kind, + exposed); + } + /* + * Once the child has been processed, we remove its extents + * from the current universe, thus denying its space to any + * other sibling. + */ + if (overlap) + REGION_SUBTRACT( pScreen, universe, universe, + &pChild->borderSize); + } + } + if (!overlap) + REGION_SUBTRACT( pScreen, universe, universe, &childUnion); + REGION_UNINIT( pScreen, &childUnion); + REGION_UNINIT( pScreen, &childUniverse); + } /* if any children */ + + /* + * 'universe' now contains the new clipList for the parent window. + * + * To figure the exposure of the window we subtract the old clip from the + * new, just as for the border. + */ + + if (oldVis == VisibilityFullyObscured || + oldVis == VisibilityNotViewable) + { + REGION_COPY( pScreen, &pParent->valdata->after.exposed, universe); + } + else if (newVis != VisibilityFullyObscured && + newVis != VisibilityNotViewable) + { + REGION_SUBTRACT( pScreen, &pParent->valdata->after.exposed, + universe, &pParent->clipList); + } + + /* + * One last thing: backing storage. We have to try to save what parts of + * the window are about to be obscured. We can just subtract the universe + * from the old clipList and get the areas that were in the old but aren't + * in the new and, hence, are about to be obscured. + */ + if (pParent->backStorage && !resized) + { + REGION_SUBTRACT( pScreen, exposed, &pParent->clipList, universe); + (* pScreen->SaveDoomedAreas)(pParent, exposed, dx, dy); + } + + /* HACK ALERT - copying contents of regions, instead of regions */ + { + RegionRec tmp; + + tmp = pParent->clipList; + pParent->clipList = *universe; + *universe = tmp; + } + +#ifdef NOTDEF + REGION_COPY( pScreen, &pParent->clipList, universe); +#endif + + pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pParent, dx, dy); +} + +static void +miTreeObscured( + register WindowPtr pParent ) +{ + register WindowPtr pChild; + register int oldVis; + + pChild = pParent; + while (1) + { + if (pChild->viewable) + { + oldVis = pChild->visibility; + if (oldVis != (pChild->visibility = VisibilityFullyObscured) && + ((pChild->eventMask | wOtherEventMasks(pChild)) & VisibilityChangeMask)) + SendVisibilityNotify(pChild); + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pParent)) + pChild = pChild->parent; + if (pChild == pParent) + break; + pChild = pChild->nextSib; + } +} + +/* + *----------------------------------------------------------------------- + * miValidateTree -- + * Recomputes the clip list for pParent and all its inferiors. + * + * Results: + * Always returns 1. + * + * Side Effects: + * The clipList, borderClip, exposed, and borderExposed regions for + * each marked window are altered. + * + * Notes: + * This routine assumes that all affected windows have been marked + * (valdata created) and their winSize and borderSize regions + * adjusted to correspond to their new positions. The borderClip and + * clipList regions should not have been touched. + * + * The top-most level is treated differently from all lower levels + * because pParent is unchanged. For the top level, we merge the + * regions taken up by the marked children back into the clipList + * for pParent, thus forming a region from which the marked children + * can claim their areas. For lower levels, where the old clipList + * and borderClip are invalid, we can't do this and have to do the + * extra operations done in miComputeClips, but this is much faster + * e.g. when only one child has moved... + * + *----------------------------------------------------------------------- + */ +/*ARGSUSED*/ +int +miValidateTree (pParent, pChild, kind) + WindowPtr pParent; /* Parent to validate */ + WindowPtr pChild; /* First child of pParent that was + * affected */ + VTKind kind; /* What kind of configuration caused call */ +{ + RegionRec totalClip; /* Total clipping region available to + * the marked children. pParent's clipList + * merged with the borderClips of all + * the marked children. */ + RegionRec childClip; /* The new borderClip for the current + * child */ + RegionRec childUnion; /* the space covered by borderSize for + * all marked children */ + RegionRec exposed; /* For intermediate calculations */ + register ScreenPtr pScreen; + register WindowPtr pWin; + Bool overlap; + int viewvals; + Bool forward; + + pScreen = pParent->drawable.pScreen; + if (pChild == NullWindow) + pChild = pParent->firstChild; + + REGION_NULL(pScreen, &childClip); + REGION_NULL(pScreen, &exposed); + + /* + * compute the area of the parent window occupied + * by the marked children + the parent itself. This + * is the area which can be divied up among the marked + * children in their new configuration. + */ + REGION_NULL(pScreen, &totalClip); + viewvals = 0; + if (REGION_BROKEN (pScreen, &pParent->clipList) && + !REGION_BROKEN (pScreen, &pParent->borderClip)) + { + kind = VTBroken; + /* + * When rebuilding clip lists after out of memory, + * assume everything is busted. + */ + forward = TRUE; + REGION_COPY (pScreen, &totalClip, &pParent->borderClip); + REGION_INTERSECT (pScreen, &totalClip, &totalClip, &pParent->winSize); + + for (pWin = pParent->firstChild; pWin != pChild; pWin = pWin->nextSib) + { + if (pWin->viewable) + REGION_SUBTRACT (pScreen, &totalClip, &totalClip, &pWin->borderSize); + } + for (pWin = pChild; pWin; pWin = pWin->nextSib) + if (pWin->valdata && pWin->viewable) + viewvals++; + + REGION_EMPTY (pScreen, &pParent->clipList); + } + else + { + if ((pChild->drawable.y < pParent->lastChild->drawable.y) || + ((pChild->drawable.y == pParent->lastChild->drawable.y) && + (pChild->drawable.x < pParent->lastChild->drawable.x))) + { + forward = TRUE; + for (pWin = pChild; pWin; pWin = pWin->nextSib) + { + if (pWin->valdata) + { + RegionPtr pBorderClip = &pWin->borderClip; +#ifdef COMPOSITE + if (pWin->redirectDraw && miGetRedirectBorderClipProc) + pBorderClip = (*miGetRedirectBorderClipProc)(pWin); +#endif + REGION_APPEND( pScreen, &totalClip, pBorderClip ); + if (pWin->viewable) + viewvals++; + } + } + } + else + { + forward = FALSE; + pWin = pParent->lastChild; + while (1) + { + if (pWin->valdata) + { + RegionPtr pBorderClip = &pWin->borderClip; +#ifdef COMPOSITE + if (pWin->redirectDraw && miGetRedirectBorderClipProc) + pBorderClip = (*miGetRedirectBorderClipProc)(pWin); +#endif + REGION_APPEND( pScreen, &totalClip, pBorderClip ); + if (pWin->viewable) + viewvals++; + } + if (pWin == pChild) + break; + pWin = pWin->prevSib; + } + } + REGION_VALIDATE( pScreen, &totalClip, &overlap); + } + + /* + * Now go through the children of the root and figure their new + * borderClips from the totalClip, passing that off to miComputeClips + * to handle recursively. Once that's done, we remove the child + * from the totalClip to clip any siblings below it. + */ + + overlap = TRUE; + if (kind != VTStack) + { + REGION_UNION( pScreen, &totalClip, &totalClip, &pParent->clipList); + if (viewvals > 1) + { + /* + * precompute childUnion to discover whether any of them + * overlap. This seems redundant, but performance studies + * have demonstrated that the cost of this loop is + * lower than the cost of multiple Subtracts in the + * loop below. + */ + REGION_NULL(pScreen, &childUnion); + if (forward) + { + for (pWin = pChild; pWin; pWin = pWin->nextSib) + if (pWin->valdata && pWin->viewable) + REGION_APPEND( pScreen, &childUnion, + &pWin->borderSize); + } + else + { + pWin = pParent->lastChild; + while (1) + { + if (pWin->valdata && pWin->viewable) + REGION_APPEND( pScreen, &childUnion, + &pWin->borderSize); + if (pWin == pChild) + break; + pWin = pWin->prevSib; + } + } + REGION_VALIDATE(pScreen, &childUnion, &overlap); + if (overlap) + REGION_UNINIT(pScreen, &childUnion); + } + } + + for (pWin = pChild; + pWin != NullWindow; + pWin = pWin->nextSib) + { + if (pWin->viewable) { + if (pWin->valdata) { + REGION_INTERSECT( pScreen, &childClip, + &totalClip, + &pWin->borderSize); + miComputeClips (pWin, pScreen, &childClip, kind, &exposed); + if (overlap) + { + REGION_SUBTRACT( pScreen, &totalClip, + &totalClip, + &pWin->borderSize); + } + } else if (pWin->visibility == VisibilityNotViewable) { + miTreeObscured(pWin); + } + } else { + if (pWin->valdata) { + REGION_EMPTY( pScreen, &pWin->clipList); + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pWin, 0, 0); + REGION_EMPTY( pScreen, &pWin->borderClip); + pWin->valdata = (ValidatePtr)NULL; + } + } + } + + REGION_UNINIT( pScreen, &childClip); + if (!overlap) + { + REGION_SUBTRACT(pScreen, &totalClip, &totalClip, &childUnion); + REGION_UNINIT(pScreen, &childUnion); + } + + REGION_NULL(pScreen, &pParent->valdata->after.exposed); + REGION_NULL(pScreen, &pParent->valdata->after.borderExposed); + + /* + * each case below is responsible for updating the + * clipList and serial number for the parent window + */ + + switch (kind) { + case VTStack: + break; + default: + /* + * totalClip contains the new clipList for the parent. Figure out + * exposures and obscures as per miComputeClips and reset the parent's + * clipList. + */ + REGION_SUBTRACT( pScreen, &pParent->valdata->after.exposed, + &totalClip, &pParent->clipList); + /* fall through */ + case VTMap: + if (pParent->backStorage) { + REGION_SUBTRACT( pScreen, &exposed, &pParent->clipList, &totalClip); + (* pScreen->SaveDoomedAreas)(pParent, &exposed, 0, 0); + } + + REGION_COPY( pScreen, &pParent->clipList, &totalClip); + pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; + break; + } + + REGION_UNINIT( pScreen, &totalClip); + REGION_UNINIT( pScreen, &exposed); + if (pScreen->ClipNotify) + (*pScreen->ClipNotify) (pParent, 0, 0); + return (1); +} diff --git a/xserver/mi/miwideline.c b/xserver/mi/miwideline.c new file mode 100644 index 000000000..d57c2eaa7 --- /dev/null +++ b/xserver/mi/miwideline.c @@ -0,0 +1,2231 @@ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* Author: Keith Packard, MIT X Consortium */ + +/* + * Mostly integer wideline code. Uses a technique similar to + * bresenham zero-width lines, except walks an X edge + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <stdio.h> +#ifdef _XOPEN_SOURCE +#include <math.h> +#else +#define _XOPEN_SOURCE /* to get prototype for hypot on some systems */ +#include <math.h> +#undef _XOPEN_SOURCE +#endif +#include <X11/X.h> +#include "windowstr.h" +#include "gcstruct.h" +#include "regionstr.h" +#include "miwideline.h" +#include "mi.h" + +#ifdef ICEILTEMPDECL +ICEILTEMPDECL +#endif + +static void miLineArc(DrawablePtr pDraw, register GCPtr pGC, + unsigned long pixel, SpanDataPtr spanData, + register LineFacePtr leftFace, + register LineFacePtr rightFace, + double xorg, double yorg, Bool isInt); + + +/* + * spans-based polygon filler + */ + +void +miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, overall_height, + left, right, left_count, right_count) + DrawablePtr pDrawable; + GCPtr pGC; + unsigned long pixel; + SpanDataPtr spanData; + int y; /* start y coordinate */ + int overall_height; /* height of entire segment */ + PolyEdgePtr left, right; + int left_count, right_count; +{ + register int left_x = 0, left_e = 0; + int left_stepx = 0; + int left_signdx = 0; + int left_dy = 0, left_dx = 0; + + register int right_x = 0, right_e = 0; + int right_stepx = 0; + int right_signdx = 0; + int right_dy = 0, right_dx = 0; + + int height = 0; + int left_height = 0, right_height = 0; + + register DDXPointPtr ppt; + DDXPointPtr pptInit = NULL; + register int *pwidth; + int *pwidthInit = NULL; + XID oldPixel; + int xorg; + Spans spanRec; + + left_height = 0; + right_height = 0; + + if (!spanData) + { + pptInit = (DDXPointPtr) ALLOCATE_LOCAL (overall_height * sizeof(*ppt)); + if (!pptInit) + return; + pwidthInit = (int *) ALLOCATE_LOCAL (overall_height * sizeof(*pwidth)); + if (!pwidthInit) + { + DEALLOCATE_LOCAL (pptInit); + return; + } + ppt = pptInit; + pwidth = pwidthInit; + oldPixel = pGC->fgPixel; + if (pixel != oldPixel) + { + XID tmpPixel = (XID)pixel; + DoChangeGC (pGC, GCForeground, &tmpPixel, FALSE); + ValidateGC (pDrawable, pGC); + } + } + else + { + spanRec.points = (DDXPointPtr) xalloc (overall_height * sizeof (*ppt)); + if (!spanRec.points) + return; + spanRec.widths = (int *) xalloc (overall_height * sizeof (int)); + if (!spanRec.widths) + { + xfree (spanRec.points); + return; + } + ppt = spanRec.points; + pwidth = spanRec.widths; + } + + xorg = 0; + if (pGC->miTranslate) + { + y += pDrawable->y; + xorg = pDrawable->x; + } + while ((left_count || left_height) && + (right_count || right_height)) + { + MIPOLYRELOADLEFT + MIPOLYRELOADRIGHT + + height = left_height; + if (height > right_height) + height = right_height; + + left_height -= height; + right_height -= height; + + while (--height >= 0) + { + if (right_x >= left_x) + { + ppt->y = y; + ppt->x = left_x + xorg; + ppt++; + *pwidth++ = right_x - left_x + 1; + } + y++; + + MIPOLYSTEPLEFT + + MIPOLYSTEPRIGHT + } + } + if (!spanData) + { + (*pGC->ops->FillSpans) (pDrawable, pGC, ppt - pptInit, pptInit, pwidthInit, TRUE); + DEALLOCATE_LOCAL (pwidthInit); + DEALLOCATE_LOCAL (pptInit); + if (pixel != oldPixel) + { + DoChangeGC (pGC, GCForeground, &oldPixel, FALSE); + ValidateGC (pDrawable, pGC); + } + } + else + { + spanRec.count = ppt - spanRec.points; + AppendSpanGroup (pGC, pixel, &spanRec, spanData) + } +} + +static void +miFillRectPolyHelper ( + DrawablePtr pDrawable, + GCPtr pGC, + unsigned long pixel, + SpanDataPtr spanData, + int x, + int y, + int w, + int h) +{ + register DDXPointPtr ppt; + register int *pwidth; + XID oldPixel; + Spans spanRec; + xRectangle rect; + + if (!spanData) + { + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + oldPixel = pGC->fgPixel; + if (pixel != oldPixel) + { + XID tmpPixel = (XID)pixel; + DoChangeGC (pGC, GCForeground, &tmpPixel, FALSE); + ValidateGC (pDrawable, pGC); + } + (*pGC->ops->PolyFillRect) (pDrawable, pGC, 1, &rect); + if (pixel != oldPixel) + { + DoChangeGC (pGC, GCForeground, &oldPixel, FALSE); + ValidateGC (pDrawable, pGC); + } + } + else + { + spanRec.points = (DDXPointPtr) xalloc (h * sizeof (*ppt)); + if (!spanRec.points) + return; + spanRec.widths = (int *) xalloc (h * sizeof (int)); + if (!spanRec.widths) + { + xfree (spanRec.points); + return; + } + ppt = spanRec.points; + pwidth = spanRec.widths; + + if (pGC->miTranslate) + { + y += pDrawable->y; + x += pDrawable->x; + } + while (h--) + { + ppt->x = x; + ppt->y = y; + ppt++; + *pwidth++ = w; + y++; + } + spanRec.count = ppt - spanRec.points; + AppendSpanGroup (pGC, pixel, &spanRec, spanData) + } +} + +_X_EXPORT /* static */ int +miPolyBuildEdge (x0, y0, k, dx, dy, xi, yi, left, edge) + double x0, y0; + double k; /* x0 * dy - y0 * dx */ + register int dx, dy; + int xi, yi; + int left; + register PolyEdgePtr edge; +{ + int x, y, e; + int xady; + + if (dy < 0) + { + dy = -dy; + dx = -dx; + k = -k; + } + +#ifdef NOTDEF + { + double realk, kerror; + realk = x0 * dy - y0 * dx; + kerror = Fabs (realk - k); + if (kerror > .1) + printf ("realk: %g k: %g\n", realk, k); + } +#endif + y = ICEIL (y0); + xady = ICEIL (k) + y * dx; + + if (xady <= 0) + x = - (-xady / dy) - 1; + else + x = (xady - 1) / dy; + + e = xady - x * dy; + + if (dx >= 0) + { + edge->signdx = 1; + edge->stepx = dx / dy; + edge->dx = dx % dy; + } + else + { + edge->signdx = -1; + edge->stepx = - (-dx / dy); + edge->dx = -dx % dy; + e = dy - e + 1; + } + edge->dy = dy; + edge->x = x + left + xi; + edge->e = e - dy; /* bias to compare against 0 instead of dy */ + return y + yi; +} + +#define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr))) + +_X_EXPORT /* static */ int +miPolyBuildPoly (vertices, slopes, count, xi, yi, left, right, pnleft, pnright, h) + register PolyVertexPtr vertices; + register PolySlopePtr slopes; + int count; + int xi, yi; + PolyEdgePtr left, right; + int *pnleft, *pnright; + int *h; +{ + int top, bottom; + double miny, maxy; + register int i; + int j; + int clockwise; + int slopeoff; + register int s; + register int nright, nleft; + int y, lasty = 0, bottomy, topy = 0; + + /* find the top of the polygon */ + maxy = miny = vertices[0].y; + bottom = top = 0; + for (i = 1; i < count; i++) + { + if (vertices[i].y < miny) + { + top = i; + miny = vertices[i].y; + } + if (vertices[i].y >= maxy) + { + bottom = i; + maxy = vertices[i].y; + } + } + clockwise = 1; + slopeoff = 0; + + i = top; + j = StepAround (top, -1, count); + + if (slopes[j].dy * slopes[i].dx > slopes[i].dy * slopes[j].dx) + { + clockwise = -1; + slopeoff = -1; + } + + bottomy = ICEIL (maxy) + yi; + + nright = 0; + + s = StepAround (top, slopeoff, count); + i = top; + while (i != bottom) + { + if (slopes[s].dy != 0) + { + y = miPolyBuildEdge (vertices[i].x, vertices[i].y, + slopes[s].k, + slopes[s].dx, slopes[s].dy, + xi, yi, 0, + &right[nright]); + if (nright != 0) + right[nright-1].height = y - lasty; + else + topy = y; + nright++; + lasty = y; + } + + i = StepAround (i, clockwise, count); + s = StepAround (s, clockwise, count); + } + if (nright != 0) + right[nright-1].height = bottomy - lasty; + + if (slopeoff == 0) + slopeoff = -1; + else + slopeoff = 0; + + nleft = 0; + s = StepAround (top, slopeoff, count); + i = top; + while (i != bottom) + { + if (slopes[s].dy != 0) + { + y = miPolyBuildEdge (vertices[i].x, vertices[i].y, + slopes[s].k, + slopes[s].dx, slopes[s].dy, xi, yi, 1, + &left[nleft]); + + if (nleft != 0) + left[nleft-1].height = y - lasty; + nleft++; + lasty = y; + } + i = StepAround (i, -clockwise, count); + s = StepAround (s, -clockwise, count); + } + if (nleft != 0) + left[nleft-1].height = bottomy - lasty; + *pnleft = nleft; + *pnright = nright; + *h = bottomy - topy; + return topy; +} + +static void +miLineOnePoint ( + DrawablePtr pDrawable, + GCPtr pGC, + unsigned long pixel, + SpanDataPtr spanData, + int x, + int y) +{ + DDXPointRec pt; + int wid; + unsigned long oldPixel; + + MILINESETPIXEL (pDrawable, pGC, pixel, oldPixel); + if (pGC->fillStyle == FillSolid) + { + pt.x = x; + pt.y = y; + (*pGC->ops->PolyPoint) (pDrawable, pGC, CoordModeOrigin, 1, &pt); + } + else + { + wid = 1; + if (pGC->miTranslate) + { + x += pDrawable->x; + y += pDrawable->y; + } + pt.x = x; + pt.y = y; + (*pGC->ops->FillSpans) (pDrawable, pGC, 1, &pt, &wid, TRUE); + } + MILINERESETPIXEL (pDrawable, pGC, pixel, oldPixel); +} + +static void +miLineJoin ( + DrawablePtr pDrawable, + GCPtr pGC, + unsigned long pixel, + SpanDataPtr spanData, + register LineFacePtr pLeft, + register LineFacePtr pRight) +{ + double mx = 0, my = 0; + double denom = 0.0; + PolyVertexRec vertices[4]; + PolySlopeRec slopes[4]; + int edgecount; + PolyEdgeRec left[4], right[4]; + int nleft, nright; + int y, height; + int swapslopes; + int joinStyle = pGC->joinStyle; + int lw = pGC->lineWidth; + + if (lw == 1 && !spanData) { + /* See if one of the lines will draw the joining pixel */ + if (pLeft->dx > 0 || (pLeft->dx == 0 && pLeft->dy > 0)) + return; + if (pRight->dx > 0 || (pRight->dx == 0 && pRight->dy > 0)) + return; + if (joinStyle != JoinRound) { + denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy; + if (denom == 0) + return; /* no join to draw */ + } + if (joinStyle != JoinMiter) { + miLineOnePoint (pDrawable, pGC, pixel, spanData, pLeft->x, pLeft->y); + return; + } + } else { + if (joinStyle == JoinRound) + { + miLineArc(pDrawable, pGC, pixel, spanData, + pLeft, pRight, + (double)0.0, (double)0.0, TRUE); + return; + } + denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy; + if (denom == 0.0) + return; /* no join to draw */ + } + + swapslopes = 0; + if (denom > 0) + { + pLeft->xa = -pLeft->xa; + pLeft->ya = -pLeft->ya; + pLeft->dx = -pLeft->dx; + pLeft->dy = -pLeft->dy; + } + else + { + swapslopes = 1; + pRight->xa = -pRight->xa; + pRight->ya = -pRight->ya; + pRight->dx = -pRight->dx; + pRight->dy = -pRight->dy; + } + + vertices[0].x = pRight->xa; + vertices[0].y = pRight->ya; + slopes[0].dx = -pRight->dy; + slopes[0].dy = pRight->dx; + slopes[0].k = 0; + + vertices[1].x = 0; + vertices[1].y = 0; + slopes[1].dx = pLeft->dy; + slopes[1].dy = -pLeft->dx; + slopes[1].k = 0; + + vertices[2].x = pLeft->xa; + vertices[2].y = pLeft->ya; + + if (joinStyle == JoinMiter) + { + my = (pLeft->dy * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) - + pRight->dy * (pLeft->xa * pLeft->dy - pLeft->ya * pLeft->dx )) / + denom; + if (pLeft->dy != 0) + { + mx = pLeft->xa + (my - pLeft->ya) * + (double) pLeft->dx / (double) pLeft->dy; + } + else + { + mx = pRight->xa + (my - pRight->ya) * + (double) pRight->dx / (double) pRight->dy; + } + /* check miter limit */ + if ((mx * mx + my * my) * 4 > SQSECANT * lw * lw) + joinStyle = JoinBevel; + } + + if (joinStyle == JoinMiter) + { + slopes[2].dx = pLeft->dx; + slopes[2].dy = pLeft->dy; + slopes[2].k = pLeft->k; + if (swapslopes) + { + slopes[2].dx = -slopes[2].dx; + slopes[2].dy = -slopes[2].dy; + slopes[2].k = -slopes[2].k; + } + vertices[3].x = mx; + vertices[3].y = my; + slopes[3].dx = pRight->dx; + slopes[3].dy = pRight->dy; + slopes[3].k = pRight->k; + if (swapslopes) + { + slopes[3].dx = -slopes[3].dx; + slopes[3].dy = -slopes[3].dy; + slopes[3].k = -slopes[3].k; + } + edgecount = 4; + } + else + { + double scale, dx, dy, adx, ady; + + adx = dx = pRight->xa - pLeft->xa; + ady = dy = pRight->ya - pLeft->ya; + if (adx < 0) + adx = -adx; + if (ady < 0) + ady = -ady; + scale = ady; + if (adx > ady) + scale = adx; + slopes[2].dx = (dx * 65536) / scale; + slopes[2].dy = (dy * 65536) / scale; + slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy - + (pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0; + edgecount = 3; + } + + y = miPolyBuildPoly (vertices, slopes, edgecount, pLeft->x, pLeft->y, + left, right, &nleft, &nright, &height); + miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, height, left, right, nleft, nright); +} + +static int +miLineArcI ( + DrawablePtr pDraw, + GCPtr pGC, + int xorg, + int yorg, + DDXPointPtr points, + int *widths) +{ + register DDXPointPtr tpts, bpts; + register int *twids, *bwids; + register int x, y, e, ex, slw; + + tpts = points; + twids = widths; + if (pGC->miTranslate) + { + xorg += pDraw->x; + yorg += pDraw->y; + } + slw = pGC->lineWidth; + if (slw == 1) + { + tpts->x = xorg; + tpts->y = yorg; + *twids = 1; + return 1; + } + bpts = tpts + slw; + bwids = twids + slw; + y = (slw >> 1) + 1; + if (slw & 1) + e = - ((y << 2) + 3); + else + e = - (y << 3); + ex = -4; + x = 0; + while (y) + { + e += (y << 3) - 4; + while (e >= 0) + { + x++; + e += (ex = -((x << 3) + 4)); + } + y--; + slw = (x << 1) + 1; + if ((e == ex) && (slw > 1)) + slw--; + tpts->x = xorg - x; + tpts->y = yorg - y; + tpts++; + *twids++ = slw; + if ((y != 0) && ((slw > 1) || (e != ex))) + { + bpts--; + bpts->x = xorg - x; + bpts->y = yorg + y; + *--bwids = slw; + } + } + return (pGC->lineWidth); +} + +#define CLIPSTEPEDGE(edgey,edge,edgeleft) \ + if (ybase == edgey) \ + { \ + if (edgeleft) \ + { \ + if (edge->x > xcl) \ + xcl = edge->x; \ + } \ + else \ + { \ + if (edge->x < xcr) \ + xcr = edge->x; \ + } \ + edgey++; \ + edge->x += edge->stepx; \ + edge->e += edge->dx; \ + if (edge->e > 0) \ + { \ + edge->x += edge->signdx; \ + edge->e -= edge->dy; \ + } \ + } + +static int +miLineArcD ( + DrawablePtr pDraw, + GCPtr pGC, + double xorg, + double yorg, + DDXPointPtr points, + int *widths, + PolyEdgePtr edge1, + int edgey1, + Bool edgeleft1, + PolyEdgePtr edge2, + int edgey2, + Bool edgeleft2) +{ + register DDXPointPtr pts; + register int *wids; + double radius, x0, y0, el, er, yk, xlk, xrk, k; + int xbase, ybase, y, boty, xl, xr, xcl, xcr; + int ymin, ymax; + Bool edge1IsMin, edge2IsMin; + int ymin1, ymin2; + + pts = points; + wids = widths; + xbase = floor(xorg); + x0 = xorg - xbase; + ybase = ICEIL (yorg); + y0 = yorg - ybase; + if (pGC->miTranslate) + { + xbase += pDraw->x; + ybase += pDraw->y; + edge1->x += pDraw->x; + edge2->x += pDraw->x; + edgey1 += pDraw->y; + edgey2 += pDraw->y; + } + xlk = x0 + x0 + 1.0; + xrk = x0 + x0 - 1.0; + yk = y0 + y0 - 1.0; + radius = ((double)pGC->lineWidth) / 2.0; + y = floor(radius - y0 + 1.0); + ybase -= y; + ymin = ybase; + ymax = 65536; + edge1IsMin = FALSE; + ymin1 = edgey1; + if (edge1->dy >= 0) + { + if (!edge1->dy) + { + if (edgeleft1) + edge1IsMin = TRUE; + else + ymax = edgey1; + edgey1 = 65536; + } + else + { + if ((edge1->signdx < 0) == edgeleft1) + edge1IsMin = TRUE; + } + } + edge2IsMin = FALSE; + ymin2 = edgey2; + if (edge2->dy >= 0) + { + if (!edge2->dy) + { + if (edgeleft2) + edge2IsMin = TRUE; + else + ymax = edgey2; + edgey2 = 65536; + } + else + { + if ((edge2->signdx < 0) == edgeleft2) + edge2IsMin = TRUE; + } + } + if (edge1IsMin) + { + ymin = ymin1; + if (edge2IsMin && ymin1 > ymin2) + ymin = ymin2; + } else if (edge2IsMin) + ymin = ymin2; + el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0); + er = el + xrk; + xl = 1; + xr = 0; + if (x0 < 0.5) + { + xl = 0; + el -= xlk; + } + boty = (y0 < -0.5) ? 1 : 0; + if (ybase + y - boty > ymax) + boty = ymax - ybase - y; + while (y > boty) + { + k = (y << 1) + yk; + er += k; + while (er > 0.0) + { + xr++; + er += xrk - (xr << 1); + } + el += k; + while (el >= 0.0) + { + xl--; + el += (xl << 1) - xlk; + } + y--; + ybase++; + if (ybase < ymin) + continue; + xcl = xl + xbase; + xcr = xr + xbase; + CLIPSTEPEDGE(edgey1, edge1, edgeleft1); + CLIPSTEPEDGE(edgey2, edge2, edgeleft2); + if (xcr >= xcl) + { + pts->x = xcl; + pts->y = ybase; + pts++; + *wids++ = xcr - xcl + 1; + } + } + er = xrk - (xr << 1) - er; + el = (xl << 1) - xlk - el; + boty = floor(-y0 - radius + 1.0); + if (ybase + y - boty > ymax) + boty = ymax - ybase - y; + while (y > boty) + { + k = (y << 1) + yk; + er -= k; + while ((er >= 0.0) && (xr >= 0)) + { + xr--; + er += xrk - (xr << 1); + } + el -= k; + while ((el > 0.0) && (xl <= 0)) + { + xl++; + el += (xl << 1) - xlk; + } + y--; + ybase++; + if (ybase < ymin) + continue; + xcl = xl + xbase; + xcr = xr + xbase; + CLIPSTEPEDGE(edgey1, edge1, edgeleft1); + CLIPSTEPEDGE(edgey2, edge2, edgeleft2); + if (xcr >= xcl) + { + pts->x = xcl; + pts->y = ybase; + pts++; + *wids++ = xcr - xcl + 1; + } + } + return (pts - points); +} + +int +miRoundJoinFace (face, edge, leftEdge) + register LineFacePtr face; + register PolyEdgePtr edge; + Bool *leftEdge; +{ + int y; + int dx, dy; + double xa, ya; + Bool left; + + dx = -face->dy; + dy = face->dx; + xa = face->xa; + ya = face->ya; + left = 1; + if (ya > 0) + { + ya = 0.0; + xa = 0.0; + } + if (dy < 0 || (dy == 0 && dx > 0)) + { + dx = -dx; + dy = -dy; + left = !left; + } + if (dx == 0 && dy == 0) + dy = 1; + if (dy == 0) + { + y = ICEIL (face->ya) + face->y; + edge->x = -32767; + edge->stepx = 0; + edge->signdx = 0; + edge->e = -1; + edge->dy = 0; + edge->dx = 0; + edge->height = 0; + } + else + { + y = miPolyBuildEdge (xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge); + edge->height = 32767; + } + *leftEdge = !left; + return y; +} + +_X_EXPORT void +miRoundJoinClip (pLeft, pRight, edge1, edge2, y1, y2, left1, left2) + register LineFacePtr pLeft, pRight; + PolyEdgePtr edge1, edge2; + int *y1, *y2; + Bool *left1, *left2; +{ + double denom; + + denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy; + + if (denom >= 0) + { + pLeft->xa = -pLeft->xa; + pLeft->ya = -pLeft->ya; + } + else + { + pRight->xa = -pRight->xa; + pRight->ya = -pRight->ya; + } + *y1 = miRoundJoinFace (pLeft, edge1, left1); + *y2 = miRoundJoinFace (pRight, edge2, left2); +} + +_X_EXPORT int +miRoundCapClip (face, isInt, edge, leftEdge) + register LineFacePtr face; + Bool isInt; + register PolyEdgePtr edge; + Bool *leftEdge; +{ + int y; + register int dx, dy; + double xa, ya, k; + Bool left; + + dx = -face->dy; + dy = face->dx; + xa = face->xa; + ya = face->ya; + k = 0.0; + if (!isInt) + k = face->k; + left = 1; + if (dy < 0 || (dy == 0 && dx > 0)) + { + dx = -dx; + dy = -dy; + xa = -xa; + ya = -ya; + left = !left; + } + if (dx == 0 && dy == 0) + dy = 1; + if (dy == 0) + { + y = ICEIL (face->ya) + face->y; + edge->x = -32767; + edge->stepx = 0; + edge->signdx = 0; + edge->e = -1; + edge->dy = 0; + edge->dx = 0; + edge->height = 0; + } + else + { + y = miPolyBuildEdge (xa, ya, k, dx, dy, face->x, face->y, !left, edge); + edge->height = 32767; + } + *leftEdge = !left; + return y; +} + +static void +miLineArc ( + DrawablePtr pDraw, + register GCPtr pGC, + unsigned long pixel, + SpanDataPtr spanData, + register LineFacePtr leftFace, + register LineFacePtr rightFace, + double xorg, + double yorg, + Bool isInt) +{ + DDXPointPtr points; + int *widths; + int xorgi = 0, yorgi = 0; + XID oldPixel; + Spans spanRec; + int n; + PolyEdgeRec edge1, edge2; + int edgey1, edgey2; + Bool edgeleft1, edgeleft2; + + if (isInt) + { + xorgi = leftFace ? leftFace->x : rightFace->x; + yorgi = leftFace ? leftFace->y : rightFace->y; + } + edgey1 = 65536; + edgey2 = 65536; + edge1.x = 0; /* not used, keep memory checkers happy */ + edge1.dy = -1; + edge2.x = 0; /* not used, keep memory checkers happy */ + edge2.dy = -1; + edgeleft1 = FALSE; + edgeleft2 = FALSE; + if ((pGC->lineStyle != LineSolid || pGC->lineWidth > 2) && + ((pGC->capStyle == CapRound && pGC->joinStyle != JoinRound) || + (pGC->joinStyle == JoinRound && pGC->capStyle == CapButt))) + { + if (isInt) + { + xorg = (double) xorgi; + yorg = (double) yorgi; + } + if (leftFace && rightFace) + { + miRoundJoinClip (leftFace, rightFace, &edge1, &edge2, + &edgey1, &edgey2, &edgeleft1, &edgeleft2); + } + else if (leftFace) + { + edgey1 = miRoundCapClip (leftFace, isInt, &edge1, &edgeleft1); + } + else if (rightFace) + { + edgey2 = miRoundCapClip (rightFace, isInt, &edge2, &edgeleft2); + } + isInt = FALSE; + } + if (!spanData) + { + points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * pGC->lineWidth); + if (!points) + return; + widths = (int *)ALLOCATE_LOCAL(sizeof(int) * pGC->lineWidth); + if (!widths) + { + DEALLOCATE_LOCAL(points); + return; + } + oldPixel = pGC->fgPixel; + if (pixel != oldPixel) + { + XID tmpPixel = (XID)pixel; + DoChangeGC(pGC, GCForeground, &tmpPixel, FALSE); + ValidateGC (pDraw, pGC); + } + } + else + { + points = (DDXPointPtr) xalloc (pGC->lineWidth * sizeof (DDXPointRec)); + if (!points) + return; + widths = (int *) xalloc (pGC->lineWidth * sizeof (int)); + if (!widths) + { + xfree (points); + return; + } + spanRec.points = points; + spanRec.widths = widths; + } + if (isInt) + n = miLineArcI(pDraw, pGC, xorgi, yorgi, points, widths); + else + n = miLineArcD(pDraw, pGC, xorg, yorg, points, widths, + &edge1, edgey1, edgeleft1, + &edge2, edgey2, edgeleft2); + + if (!spanData) + { + (*pGC->ops->FillSpans)(pDraw, pGC, n, points, widths, TRUE); + DEALLOCATE_LOCAL(widths); + DEALLOCATE_LOCAL(points); + if (pixel != oldPixel) + { + DoChangeGC(pGC, GCForeground, &oldPixel, FALSE); + ValidateGC (pDraw, pGC); + } + } + else + { + spanRec.count = n; + AppendSpanGroup (pGC, pixel, &spanRec, spanData) + } +} + +void +miLineProjectingCap (pDrawable, pGC, pixel, spanData, face, isLeft, xorg, yorg, isInt) + DrawablePtr pDrawable; + register GCPtr pGC; + unsigned long pixel; + SpanDataPtr spanData; + register LineFacePtr face; + Bool isLeft; + double xorg, yorg; + Bool isInt; +{ + int xorgi = 0, yorgi = 0; + int lw; + PolyEdgeRec lefts[2], rights[2]; + int lefty, righty, topy, bottomy; + PolyEdgePtr left, right; + PolyEdgePtr top, bottom; + double xa,ya; + double k; + double xap, yap; + int dx, dy; + double projectXoff, projectYoff; + double maxy; + int finaly; + + if (isInt) + { + xorgi = face->x; + yorgi = face->y; + } + lw = pGC->lineWidth; + dx = face->dx; + dy = face->dy; + k = face->k; + if (dy == 0) + { + lefts[0].height = lw; + lefts[0].x = xorgi; + if (isLeft) + lefts[0].x -= (lw >> 1); + lefts[0].stepx = 0; + lefts[0].signdx = 1; + lefts[0].e = -lw; + lefts[0].dx = 0; + lefts[0].dy = lw; + rights[0].height = lw; + rights[0].x = xorgi; + if (!isLeft) + rights[0].x += ((lw + 1) >> 1); + rights[0].stepx = 0; + rights[0].signdx = 1; + rights[0].e = -lw; + rights[0].dx = 0; + rights[0].dy = lw; + miFillPolyHelper (pDrawable, pGC, pixel, spanData, yorgi - (lw >> 1), lw, + lefts, rights, 1, 1); + } + else if (dx == 0) + { + if (dy < 0) { + dy = -dy; + isLeft = !isLeft; + } + topy = yorgi; + bottomy = yorgi + dy; + if (isLeft) + topy -= (lw >> 1); + else + bottomy += (lw >> 1); + lefts[0].height = bottomy - topy; + lefts[0].x = xorgi - (lw >> 1); + lefts[0].stepx = 0; + lefts[0].signdx = 1; + lefts[0].e = -dy; + lefts[0].dx = dx; + lefts[0].dy = dy; + + rights[0].height = bottomy - topy; + rights[0].x = lefts[0].x + (lw-1); + rights[0].stepx = 0; + rights[0].signdx = 1; + rights[0].e = -dy; + rights[0].dx = dx; + rights[0].dy = dy; + miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, bottomy - topy, lefts, rights, 1, 1); + } + else + { + xa = face->xa; + ya = face->ya; + projectXoff = -ya; + projectYoff = xa; + if (dx < 0) + { + right = &rights[1]; + left = &lefts[0]; + top = &rights[0]; + bottom = &lefts[1]; + } + else + { + right = &rights[0]; + left = &lefts[1]; + top = &lefts[0]; + bottom = &rights[1]; + } + if (isLeft) + { + righty = miPolyBuildEdge (xa, ya, + k, dx, dy, xorgi, yorgi, 0, right); + + xa = -xa; + ya = -ya; + k = -k; + lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff, + k, dx, dy, xorgi, yorgi, 1, left); + if (dx > 0) + { + ya = -ya; + xa = -xa; + } + xap = xa - projectXoff; + yap = ya - projectYoff; + topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy, + -dy, dx, xorgi, yorgi, dx > 0, top); + bottomy = miPolyBuildEdge (xa, ya, + 0.0, -dy, dx, xorgi, yorgi, dx < 0, bottom); + maxy = -ya; + } + else + { + righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff, + k, dx, dy, xorgi, yorgi, 0, right); + + xa = -xa; + ya = -ya; + k = -k; + lefty = miPolyBuildEdge (xa, ya, + k, dx, dy, xorgi, yorgi, 1, left); + if (dx > 0) + { + ya = -ya; + xa = -xa; + } + xap = xa - projectXoff; + yap = ya - projectYoff; + topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, xorgi, xorgi, dx > 0, top); + bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy, + -dy, dx, xorgi, xorgi, dx < 0, bottom); + maxy = -ya + projectYoff; + } + finaly = ICEIL(maxy) + yorgi; + if (dx < 0) + { + left->height = bottomy - lefty; + right->height = finaly - righty; + top->height = righty - topy; + } + else + { + right->height = bottomy - righty; + left->height = finaly - lefty; + top->height = lefty - topy; + } + bottom->height = finaly - bottomy; + miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, + bottom->height + bottomy - topy, lefts, rights, 2, 2); + } +} + +static void +miWideSegment ( + DrawablePtr pDrawable, + GCPtr pGC, + unsigned long pixel, + SpanDataPtr spanData, + register int x1, + register int y1, + register int x2, + register int y2, + Bool projectLeft, + Bool projectRight, + register LineFacePtr leftFace, + register LineFacePtr rightFace) +{ + double l, L, r; + double xa, ya; + double projectXoff = 0.0, projectYoff = 0.0; + double k; + double maxy; + int x, y; + int dx, dy; + int finaly; + PolyEdgePtr left, right; + PolyEdgePtr top, bottom; + int lefty, righty, topy, bottomy; + int signdx; + PolyEdgeRec lefts[2], rights[2]; + LineFacePtr tface; + int lw = pGC->lineWidth; + + /* draw top-to-bottom always */ + if (y2 < y1 || (y2 == y1 && x2 < x1)) + { + x = x1; + x1 = x2; + x2 = x; + + y = y1; + y1 = y2; + y2 = y; + + x = projectLeft; + projectLeft = projectRight; + projectRight = x; + + tface = leftFace; + leftFace = rightFace; + rightFace = tface; + } + + dy = y2 - y1; + signdx = 1; + dx = x2 - x1; + if (dx < 0) + signdx = -1; + + leftFace->x = x1; + leftFace->y = y1; + leftFace->dx = dx; + leftFace->dy = dy; + + rightFace->x = x2; + rightFace->y = y2; + rightFace->dx = -dx; + rightFace->dy = -dy; + + if (dy == 0) + { + rightFace->xa = 0; + rightFace->ya = (double) lw / 2.0; + rightFace->k = -(double) (lw * dx) / 2.0; + leftFace->xa = 0; + leftFace->ya = -rightFace->ya; + leftFace->k = rightFace->k; + x = x1; + if (projectLeft) + x -= (lw >> 1); + y = y1 - (lw >> 1); + dx = x2 - x; + if (projectRight) + dx += ((lw + 1) >> 1); + dy = lw; + miFillRectPolyHelper (pDrawable, pGC, pixel, spanData, + x, y, dx, dy); + } + else if (dx == 0) + { + leftFace->xa = (double) lw / 2.0; + leftFace->ya = 0; + leftFace->k = (double) (lw * dy) / 2.0; + rightFace->xa = -leftFace->xa; + rightFace->ya = 0; + rightFace->k = leftFace->k; + y = y1; + if (projectLeft) + y -= lw >> 1; + x = x1 - (lw >> 1); + dy = y2 - y; + if (projectRight) + dy += ((lw + 1) >> 1); + dx = lw; + miFillRectPolyHelper (pDrawable, pGC, pixel, spanData, + x, y, dx, dy); + } + else + { + l = ((double) lw) / 2.0; + L = hypot ((double) dx, (double) dy); + + if (dx < 0) + { + right = &rights[1]; + left = &lefts[0]; + top = &rights[0]; + bottom = &lefts[1]; + } + else + { + right = &rights[0]; + left = &lefts[1]; + top = &lefts[0]; + bottom = &rights[1]; + } + r = l / L; + + /* coord of upper bound at integral y */ + ya = -r * dx; + xa = r * dy; + + if (projectLeft | projectRight) + { + projectXoff = -ya; + projectYoff = xa; + } + + /* xa * dy - ya * dx */ + k = l * L; + + leftFace->xa = xa; + leftFace->ya = ya; + leftFace->k = k; + rightFace->xa = -xa; + rightFace->ya = -ya; + rightFace->k = k; + + if (projectLeft) + righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff, + k, dx, dy, x1, y1, 0, right); + else + righty = miPolyBuildEdge (xa, ya, + k, dx, dy, x1, y1, 0, right); + + /* coord of lower bound at integral y */ + ya = -ya; + xa = -xa; + + /* xa * dy - ya * dx */ + k = - k; + + if (projectLeft) + lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff, + k, dx, dy, x1, y1, 1, left); + else + lefty = miPolyBuildEdge (xa, ya, + k, dx, dy, x1, y1, 1, left); + + /* coord of top face at integral y */ + + if (signdx > 0) + { + ya = -ya; + xa = -xa; + } + + if (projectLeft) + { + double xap = xa - projectXoff; + double yap = ya - projectYoff; + topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy, + -dy, dx, x1, y1, dx > 0, top); + } + else + topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, x1, y1, dx > 0, top); + + /* coord of bottom face at integral y */ + + if (projectRight) + { + double xap = xa + projectXoff; + double yap = ya + projectYoff; + bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy, + -dy, dx, x2, y2, dx < 0, bottom); + maxy = -ya + projectYoff; + } + else + { + bottomy = miPolyBuildEdge (xa, ya, + 0.0, -dy, dx, x2, y2, dx < 0, bottom); + maxy = -ya; + } + + finaly = ICEIL (maxy) + y2; + + if (dx < 0) + { + left->height = bottomy - lefty; + right->height = finaly - righty; + top->height = righty - topy; + } + else + { + right->height = bottomy - righty; + left->height = finaly - lefty; + top->height = lefty - topy; + } + bottom->height = finaly - bottomy; + miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, + bottom->height + bottomy - topy, lefts, rights, 2, 2); + } +} + +SpanDataPtr +miSetupSpanData (pGC, spanData, npt) + register GCPtr pGC; + SpanDataPtr spanData; + int npt; +{ + if ((npt < 3 && pGC->capStyle != CapRound) || miSpansEasyRop(pGC->alu)) + return (SpanDataPtr) NULL; + if (pGC->lineStyle == LineDoubleDash) + miInitSpanGroup (&spanData->bgGroup); + miInitSpanGroup (&spanData->fgGroup); + return spanData; +} + +void +miCleanupSpanData (pDrawable, pGC, spanData) + DrawablePtr pDrawable; + GCPtr pGC; + SpanDataPtr spanData; +{ + if (pGC->lineStyle == LineDoubleDash) + { + XID oldPixel, pixel; + + pixel = pGC->bgPixel; + oldPixel = pGC->fgPixel; + if (pixel != oldPixel) + { + DoChangeGC (pGC, GCForeground, &pixel, FALSE); + ValidateGC (pDrawable, pGC); + } + miFillUniqueSpanGroup (pDrawable, pGC, &spanData->bgGroup); + miFreeSpanGroup (&spanData->bgGroup); + if (pixel != oldPixel) + { + DoChangeGC (pGC, GCForeground, &oldPixel, FALSE); + ValidateGC (pDrawable, pGC); + } + } + miFillUniqueSpanGroup (pDrawable, pGC, &spanData->fgGroup); + miFreeSpanGroup (&spanData->fgGroup); +} + +_X_EXPORT void +miWideLine (pDrawable, pGC, mode, npt, pPts) + DrawablePtr pDrawable; + register GCPtr pGC; + int mode; + register int npt; + register DDXPointPtr pPts; +{ + int x1, y1, x2, y2; + SpanDataRec spanDataRec; + SpanDataPtr spanData; + unsigned long pixel; + Bool projectLeft, projectRight; + LineFaceRec leftFace, rightFace, prevRightFace; + LineFaceRec firstFace; + register int first; + Bool somethingDrawn = FALSE; + Bool selfJoin; + + spanData = miSetupSpanData (pGC, &spanDataRec, npt); + pixel = pGC->fgPixel; + x2 = pPts->x; + y2 = pPts->y; + first = TRUE; + selfJoin = FALSE; + if (npt > 1) + { + if (mode == CoordModePrevious) + { + int nptTmp; + DDXPointPtr pPtsTmp; + + x1 = x2; + y1 = y2; + nptTmp = npt; + pPtsTmp = pPts + 1; + while (--nptTmp) + { + x1 += pPtsTmp->x; + y1 += pPtsTmp->y; + ++pPtsTmp; + } + if (x2 == x1 && y2 == y1) + selfJoin = TRUE; + } + else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y) + { + selfJoin = TRUE; + } + } + projectLeft = pGC->capStyle == CapProjecting && !selfJoin; + projectRight = FALSE; + while (--npt) + { + x1 = x2; + y1 = y2; + ++pPts; + x2 = pPts->x; + y2 = pPts->y; + if (mode == CoordModePrevious) + { + x2 += x1; + y2 += y1; + } + if (x1 != x2 || y1 != y2) + { + somethingDrawn = TRUE; + if (npt == 1 && pGC->capStyle == CapProjecting && !selfJoin) + projectRight = TRUE; + miWideSegment (pDrawable, pGC, pixel, spanData, x1, y1, x2, y2, + projectLeft, projectRight, &leftFace, &rightFace); + if (first) + { + if (selfJoin) + firstFace = leftFace; + else if (pGC->capStyle == CapRound) + { + if (pGC->lineWidth == 1 && !spanData) + miLineOnePoint (pDrawable, pGC, pixel, spanData, x1, y1); + else + miLineArc (pDrawable, pGC, pixel, spanData, + &leftFace, (LineFacePtr) NULL, + (double)0.0, (double)0.0, + TRUE); + } + } + else + { + miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace, + &prevRightFace); + } + prevRightFace = rightFace; + first = FALSE; + projectLeft = FALSE; + } + if (npt == 1 && somethingDrawn) + { + if (selfJoin) + miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace, + &rightFace); + else if (pGC->capStyle == CapRound) + { + if (pGC->lineWidth == 1 && !spanData) + miLineOnePoint (pDrawable, pGC, pixel, spanData, x2, y2); + else + miLineArc (pDrawable, pGC, pixel, spanData, + (LineFacePtr) NULL, &rightFace, + (double)0.0, (double)0.0, + TRUE); + } + } + } + /* handle crock where all points are coincedent */ + if (!somethingDrawn) + { + projectLeft = pGC->capStyle == CapProjecting; + miWideSegment (pDrawable, pGC, pixel, spanData, + x2, y2, x2, y2, projectLeft, projectLeft, + &leftFace, &rightFace); + if (pGC->capStyle == CapRound) + { + miLineArc (pDrawable, pGC, pixel, spanData, + &leftFace, (LineFacePtr) NULL, + (double)0.0, (double)0.0, + TRUE); + rightFace.dx = -1; /* sleezy hack to make it work */ + miLineArc (pDrawable, pGC, pixel, spanData, + (LineFacePtr) NULL, &rightFace, + (double)0.0, (double)0.0, + TRUE); + } + } + if (spanData) + miCleanupSpanData (pDrawable, pGC, spanData); +} + +#define V_TOP 0 +#define V_RIGHT 1 +#define V_BOTTOM 2 +#define V_LEFT 3 + +static void +miWideDashSegment ( + DrawablePtr pDrawable, + register GCPtr pGC, + SpanDataPtr spanData, + int *pDashOffset, + int *pDashIndex, + int x1, + int y1, + int x2, + int y2, + Bool projectLeft, + Bool projectRight, + LineFacePtr leftFace, + LineFacePtr rightFace) +{ + int dashIndex, dashRemain; + unsigned char *pDash; + double L, l; + double k; + PolyVertexRec vertices[4]; + PolyVertexRec saveRight, saveBottom; + PolySlopeRec slopes[4]; + PolyEdgeRec left[2], right[2]; + LineFaceRec lcapFace, rcapFace; + int nleft, nright; + int h; + int y; + int dy, dx; + unsigned long pixel; + double LRemain; + double r; + double rdx, rdy; + double dashDx, dashDy; + double saveK = 0.0; + Bool first = TRUE; + double lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0; + unsigned long fgPixel, bgPixel; + + dx = x2 - x1; + dy = y2 - y1; + dashIndex = *pDashIndex; + pDash = pGC->dash; + dashRemain = pDash[dashIndex] - *pDashOffset; + fgPixel = pGC->fgPixel; + bgPixel = pGC->bgPixel; + if (pGC->fillStyle == FillOpaqueStippled || + pGC->fillStyle == FillTiled) + { + bgPixel = fgPixel; + } + + l = ((double) pGC->lineWidth) / 2.0; + if (dx == 0) + { + L = dy; + rdx = 0; + rdy = l; + if (dy < 0) + { + L = -dy; + rdy = -l; + } + } + else if (dy == 0) + { + L = dx; + rdx = l; + rdy = 0; + if (dx < 0) + { + L = -dx; + rdx = -l; + } + } + else + { + L = hypot ((double) dx, (double) dy); + r = l / L; + + rdx = r * dx; + rdy = r * dy; + } + k = l * L; + LRemain = L; + /* All position comments are relative to a line with dx and dy > 0, + * but the code does not depend on this */ + /* top */ + slopes[V_TOP].dx = dx; + slopes[V_TOP].dy = dy; + slopes[V_TOP].k = k; + /* right */ + slopes[V_RIGHT].dx = -dy; + slopes[V_RIGHT].dy = dx; + slopes[V_RIGHT].k = 0; + /* bottom */ + slopes[V_BOTTOM].dx = -dx; + slopes[V_BOTTOM].dy = -dy; + slopes[V_BOTTOM].k = k; + /* left */ + slopes[V_LEFT].dx = dy; + slopes[V_LEFT].dy = -dx; + slopes[V_LEFT].k = 0; + + /* preload the start coordinates */ + vertices[V_RIGHT].x = vertices[V_TOP].x = rdy; + vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx; + + vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy; + vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx; + + if (projectLeft) + { + vertices[V_TOP].x -= rdx; + vertices[V_TOP].y -= rdy; + + vertices[V_LEFT].x -= rdx; + vertices[V_LEFT].y -= rdy; + + slopes[V_LEFT].k = rdx * dx + rdy * dy; + } + + lcenterx = x1; + lcentery = y1; + + if (pGC->capStyle == CapRound) + { + lcapFace.dx = dx; + lcapFace.dy = dy; + lcapFace.x = x1; + lcapFace.y = y1; + + rcapFace.dx = -dx; + rcapFace.dy = -dy; + rcapFace.x = x1; + rcapFace.y = y1; + } + while (LRemain > dashRemain) + { + dashDx = (dashRemain * dx) / L; + dashDy = (dashRemain * dy) / L; + + rcenterx = lcenterx + dashDx; + rcentery = lcentery + dashDy; + + vertices[V_RIGHT].x += dashDx; + vertices[V_RIGHT].y += dashDy; + + vertices[V_BOTTOM].x += dashDx; + vertices[V_BOTTOM].y += dashDy; + + slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy; + + if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)) + { + if (pGC->lineStyle == LineOnOffDash && + pGC->capStyle == CapProjecting) + { + saveRight = vertices[V_RIGHT]; + saveBottom = vertices[V_BOTTOM]; + saveK = slopes[V_RIGHT].k; + + if (!first) + { + vertices[V_TOP].x -= rdx; + vertices[V_TOP].y -= rdy; + + vertices[V_LEFT].x -= rdx; + vertices[V_LEFT].y -= rdy; + + slopes[V_LEFT].k = vertices[V_LEFT].x * + slopes[V_LEFT].dy - + vertices[V_LEFT].y * + slopes[V_LEFT].dx; + } + + vertices[V_RIGHT].x += rdx; + vertices[V_RIGHT].y += rdy; + + vertices[V_BOTTOM].x += rdx; + vertices[V_BOTTOM].y += rdy; + + slopes[V_RIGHT].k = vertices[V_RIGHT].x * + slopes[V_RIGHT].dy - + vertices[V_RIGHT].y * + slopes[V_RIGHT].dx; + } + y = miPolyBuildPoly (vertices, slopes, 4, x1, y1, + left, right, &nleft, &nright, &h); + pixel = (dashIndex & 1) ? bgPixel : fgPixel; + miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright); + + if (pGC->lineStyle == LineOnOffDash) + { + switch (pGC->capStyle) + { + case CapProjecting: + vertices[V_BOTTOM] = saveBottom; + vertices[V_RIGHT] = saveRight; + slopes[V_RIGHT].k = saveK; + break; + case CapRound: + if (!first) + { + if (dx < 0) + { + lcapFace.xa = -vertices[V_LEFT].x; + lcapFace.ya = -vertices[V_LEFT].y; + lcapFace.k = slopes[V_LEFT].k; + } + else + { + lcapFace.xa = vertices[V_TOP].x; + lcapFace.ya = vertices[V_TOP].y; + lcapFace.k = -slopes[V_LEFT].k; + } + miLineArc (pDrawable, pGC, pixel, spanData, + &lcapFace, (LineFacePtr) NULL, + lcenterx, lcentery, FALSE); + } + if (dx < 0) + { + rcapFace.xa = vertices[V_BOTTOM].x; + rcapFace.ya = vertices[V_BOTTOM].y; + rcapFace.k = slopes[V_RIGHT].k; + } + else + { + rcapFace.xa = -vertices[V_RIGHT].x; + rcapFace.ya = -vertices[V_RIGHT].y; + rcapFace.k = -slopes[V_RIGHT].k; + } + miLineArc (pDrawable, pGC, pixel, spanData, + (LineFacePtr) NULL, &rcapFace, + rcenterx, rcentery, FALSE); + break; + } + } + } + LRemain -= dashRemain; + ++dashIndex; + if (dashIndex == pGC->numInDashList) + dashIndex = 0; + dashRemain = pDash[dashIndex]; + + lcenterx = rcenterx; + lcentery = rcentery; + + vertices[V_TOP] = vertices[V_RIGHT]; + vertices[V_LEFT] = vertices[V_BOTTOM]; + slopes[V_LEFT].k = -slopes[V_RIGHT].k; + first = FALSE; + } + + if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)) + { + vertices[V_TOP].x -= dx; + vertices[V_TOP].y -= dy; + + vertices[V_LEFT].x -= dx; + vertices[V_LEFT].y -= dy; + + vertices[V_RIGHT].x = rdy; + vertices[V_RIGHT].y = -rdx; + + vertices[V_BOTTOM].x = -rdy; + vertices[V_BOTTOM].y = rdx; + + + if (projectRight) + { + vertices[V_RIGHT].x += rdx; + vertices[V_RIGHT].y += rdy; + + vertices[V_BOTTOM].x += rdx; + vertices[V_BOTTOM].y += rdy; + slopes[V_RIGHT].k = vertices[V_RIGHT].x * + slopes[V_RIGHT].dy - + vertices[V_RIGHT].y * + slopes[V_RIGHT].dx; + } + else + slopes[V_RIGHT].k = 0; + + if (!first && pGC->lineStyle == LineOnOffDash && + pGC->capStyle == CapProjecting) + { + vertices[V_TOP].x -= rdx; + vertices[V_TOP].y -= rdy; + + vertices[V_LEFT].x -= rdx; + vertices[V_LEFT].y -= rdy; + slopes[V_LEFT].k = vertices[V_LEFT].x * + slopes[V_LEFT].dy - + vertices[V_LEFT].y * + slopes[V_LEFT].dx; + } + else + slopes[V_LEFT].k += dx * dx + dy * dy; + + + y = miPolyBuildPoly (vertices, slopes, 4, x2, y2, + left, right, &nleft, &nright, &h); + + pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel; + miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright); + if (!first && pGC->lineStyle == LineOnOffDash && + pGC->capStyle == CapRound) + { + lcapFace.x = x2; + lcapFace.y = y2; + if (dx < 0) + { + lcapFace.xa = -vertices[V_LEFT].x; + lcapFace.ya = -vertices[V_LEFT].y; + lcapFace.k = slopes[V_LEFT].k; + } + else + { + lcapFace.xa = vertices[V_TOP].x; + lcapFace.ya = vertices[V_TOP].y; + lcapFace.k = -slopes[V_LEFT].k; + } + miLineArc (pDrawable, pGC, pixel, spanData, + &lcapFace, (LineFacePtr) NULL, + rcenterx, rcentery, FALSE); + } + } + dashRemain = ((double) dashRemain) - LRemain; + if (dashRemain == 0) + { + dashIndex++; + if (dashIndex == pGC->numInDashList) + dashIndex = 0; + dashRemain = pDash[dashIndex]; + } + + leftFace->x = x1; + leftFace->y = y1; + leftFace->dx = dx; + leftFace->dy = dy; + leftFace->xa = rdy; + leftFace->ya = -rdx; + leftFace->k = k; + + rightFace->x = x2; + rightFace->y = y2; + rightFace->dx = -dx; + rightFace->dy = -dy; + rightFace->xa = -rdy; + rightFace->ya = rdx; + rightFace->k = k; + + *pDashIndex = dashIndex; + *pDashOffset = pDash[dashIndex] - dashRemain; +} + +_X_EXPORT void +miWideDash (pDrawable, pGC, mode, npt, pPts) + DrawablePtr pDrawable; + register GCPtr pGC; + int mode; + register int npt; + register DDXPointPtr pPts; +{ + int x1, y1, x2, y2; + unsigned long pixel; + Bool projectLeft, projectRight; + LineFaceRec leftFace, rightFace, prevRightFace; + LineFaceRec firstFace; + int first; + int dashIndex, dashOffset; + register int prevDashIndex; + SpanDataRec spanDataRec; + SpanDataPtr spanData; + Bool somethingDrawn = FALSE; + Bool selfJoin; + Bool endIsFg = FALSE, startIsFg = FALSE; + Bool firstIsFg = FALSE, prevIsFg = FALSE; + +#if 0 + /* XXX backward compatibility */ + if (pGC->lineWidth == 0) + { + miZeroDashLine (pDrawable, pGC, mode, npt, pPts); + return; + } +#endif + if (pGC->lineStyle == LineDoubleDash && + (pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled)) + { + miWideLine (pDrawable, pGC, mode, npt, pPts); + return; + } + if (npt == 0) + return; + spanData = miSetupSpanData (pGC, &spanDataRec, npt); + x2 = pPts->x; + y2 = pPts->y; + first = TRUE; + selfJoin = FALSE; + if (mode == CoordModePrevious) + { + int nptTmp; + DDXPointPtr pPtsTmp; + + x1 = x2; + y1 = y2; + nptTmp = npt; + pPtsTmp = pPts + 1; + while (--nptTmp) + { + x1 += pPtsTmp->x; + y1 += pPtsTmp->y; + ++pPtsTmp; + } + if (x2 == x1 && y2 == y1) + selfJoin = TRUE; + } + else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y) + { + selfJoin = TRUE; + } + projectLeft = pGC->capStyle == CapProjecting && !selfJoin; + projectRight = FALSE; + dashIndex = 0; + dashOffset = 0; + miStepDash ((int)pGC->dashOffset, &dashIndex, + pGC->dash, (int)pGC->numInDashList, &dashOffset); + while (--npt) + { + x1 = x2; + y1 = y2; + ++pPts; + x2 = pPts->x; + y2 = pPts->y; + if (mode == CoordModePrevious) + { + x2 += x1; + y2 += y1; + } + if (x1 != x2 || y1 != y2) + { + somethingDrawn = TRUE; + if (npt == 1 && pGC->capStyle == CapProjecting && + (!selfJoin || !firstIsFg)) + projectRight = TRUE; + prevDashIndex = dashIndex; + miWideDashSegment (pDrawable, pGC, spanData, &dashOffset, &dashIndex, + x1, y1, x2, y2, + projectLeft, projectRight, &leftFace, &rightFace); + startIsFg = !(prevDashIndex & 1); + endIsFg = (dashIndex & 1) ^ (dashOffset != 0); + if (pGC->lineStyle == LineDoubleDash || startIsFg) + { + pixel = startIsFg ? pGC->fgPixel : pGC->bgPixel; + if (first || (pGC->lineStyle == LineOnOffDash && !prevIsFg)) + { + if (first && selfJoin) + { + firstFace = leftFace; + firstIsFg = startIsFg; + } + else if (pGC->capStyle == CapRound) + miLineArc (pDrawable, pGC, pixel, spanData, + &leftFace, (LineFacePtr) NULL, + (double)0.0, (double)0.0, TRUE); + } + else + { + miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace, + &prevRightFace); + } + } + prevRightFace = rightFace; + prevIsFg = endIsFg; + first = FALSE; + projectLeft = FALSE; + } + if (npt == 1 && somethingDrawn) + { + if (pGC->lineStyle == LineDoubleDash || endIsFg) + { + pixel = endIsFg ? pGC->fgPixel : pGC->bgPixel; + if (selfJoin && (pGC->lineStyle == LineDoubleDash || firstIsFg)) + { + miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace, + &rightFace); + } + else + { + if (pGC->capStyle == CapRound) + miLineArc (pDrawable, pGC, pixel, spanData, + (LineFacePtr) NULL, &rightFace, + (double)0.0, (double)0.0, TRUE); + } + } + else + { + /* glue a cap to the start of the line if + * we're OnOffDash and ended on odd dash + */ + if (selfJoin && firstIsFg) + { + pixel = pGC->fgPixel; + if (pGC->capStyle == CapProjecting) + miLineProjectingCap (pDrawable, pGC, pixel, spanData, + &firstFace, TRUE, + (double)0.0, (double)0.0, TRUE); + else if (pGC->capStyle == CapRound) + miLineArc (pDrawable, pGC, pixel, spanData, + &firstFace, (LineFacePtr) NULL, + (double)0.0, (double)0.0, TRUE); + } + } + } + } + /* handle crock where all points are coincident */ + if (!somethingDrawn && (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))) + { + /* not the same as endIsFg computation above */ + pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel; + switch (pGC->capStyle) { + case CapRound: + miLineArc (pDrawable, pGC, pixel, spanData, + (LineFacePtr) NULL, (LineFacePtr) NULL, + (double)x2, (double)y2, + FALSE); + break; + case CapProjecting: + x1 = pGC->lineWidth; + miFillRectPolyHelper (pDrawable, pGC, pixel, spanData, + x2 - (x1 >> 1), y2 - (x1 >> 1), x1, x1); + break; + } + } + if (spanData) + miCleanupSpanData (pDrawable, pGC, spanData); +} diff --git a/xserver/mi/miwideline.h b/xserver/mi/miwideline.h new file mode 100644 index 000000000..8cfa63008 --- /dev/null +++ b/xserver/mi/miwideline.h @@ -0,0 +1,222 @@ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* Author: Keith Packard, MIT X Consortium */ + +#include "mispans.h" +#include "mifpoly.h" /* for ICEIL */ + +/* + * interface data to span-merging polygon filler + */ + +typedef struct _SpanData { + SpanGroup fgGroup, bgGroup; +} SpanDataRec, *SpanDataPtr; + +#define AppendSpanGroup(pGC, pixel, spanPtr, spanData) { \ + SpanGroup *group, *othergroup = NULL; \ + if (pixel == pGC->fgPixel) \ + { \ + group = &spanData->fgGroup; \ + if (pGC->lineStyle == LineDoubleDash) \ + othergroup = &spanData->bgGroup; \ + } \ + else \ + { \ + group = &spanData->bgGroup; \ + othergroup = &spanData->fgGroup; \ + } \ + miAppendSpans (group, othergroup, spanPtr); \ +} + +/* + * Polygon edge description for integer wide-line routines + */ + +typedef struct _PolyEdge { + int height; /* number of scanlines to process */ + int x; /* starting x coordinate */ + int stepx; /* fixed integral dx */ + int signdx; /* variable dx sign */ + int e; /* initial error term */ + int dy; + int dx; +} PolyEdgeRec, *PolyEdgePtr; + +#define SQSECANT 108.856472512142 /* 1/sin^2(11/2) - miter limit constant */ + +/* + * types for general polygon routines + */ + +typedef struct _PolyVertex { + double x, y; +} PolyVertexRec, *PolyVertexPtr; + +typedef struct _PolySlope { + int dx, dy; + double k; /* x0 * dy - y0 * dx */ +} PolySlopeRec, *PolySlopePtr; + +/* + * Line face description for caps/joins + */ + +typedef struct _LineFace { + double xa, ya; + int dx, dy; + int x, y; + double k; +} LineFaceRec, *LineFacePtr; + +/* + * macros for polygon fillers + */ + +#define MIPOLYRELOADLEFT if (!left_height && left_count) { \ + left_height = left->height; \ + left_x = left->x; \ + left_stepx = left->stepx; \ + left_signdx = left->signdx; \ + left_e = left->e; \ + left_dy = left->dy; \ + left_dx = left->dx; \ + --left_count; \ + ++left; \ + } + +#define MIPOLYRELOADRIGHT if (!right_height && right_count) { \ + right_height = right->height; \ + right_x = right->x; \ + right_stepx = right->stepx; \ + right_signdx = right->signdx; \ + right_e = right->e; \ + right_dy = right->dy; \ + right_dx = right->dx; \ + --right_count; \ + ++right; \ + } + +#define MIPOLYSTEPLEFT left_x += left_stepx; \ + left_e += left_dx; \ + if (left_e > 0) \ + { \ + left_x += left_signdx; \ + left_e -= left_dy; \ + } + +#define MIPOLYSTEPRIGHT right_x += right_stepx; \ + right_e += right_dx; \ + if (right_e > 0) \ + { \ + right_x += right_signdx; \ + right_e -= right_dy; \ + } + +#define MILINESETPIXEL(pDrawable, pGC, pixel, oldPixel) { \ + oldPixel = pGC->fgPixel; \ + if (pixel != oldPixel) { \ + DoChangeGC (pGC, GCForeground, (XID *) &pixel, FALSE); \ + ValidateGC (pDrawable, pGC); \ + } \ +} +#define MILINERESETPIXEL(pDrawable, pGC, pixel, oldPixel) { \ + if (pixel != oldPixel) { \ + DoChangeGC (pGC, GCForeground, (XID *) &oldPixel, FALSE); \ + ValidateGC (pDrawable, pGC); \ + } \ +} + +extern void miFillPolyHelper( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + unsigned long /*pixel*/, + SpanDataPtr /*spanData*/, + int /*y*/, + int /*overall_height*/, + PolyEdgePtr /*left*/, + PolyEdgePtr /*right*/, + int /*left_count*/, + int /*right_count*/ +); +extern int miRoundJoinFace( + LineFacePtr /*face*/, + PolyEdgePtr /*edge*/, + Bool * /*leftEdge*/ +); + +extern void miRoundJoinClip( + LineFacePtr /*pLeft*/, + LineFacePtr /*pRight*/, + PolyEdgePtr /*edge1*/, + PolyEdgePtr /*edge2*/, + int * /*y1*/, + int * /*y2*/, + Bool * /*left1*/, + Bool * /*left2*/ +); + +extern int miRoundCapClip( + LineFacePtr /*face*/, + Bool /*isInt*/, + PolyEdgePtr /*edge*/, + Bool * /*leftEdge*/ +); + +extern void miLineProjectingCap( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + unsigned long /*pixel*/, + SpanDataPtr /*spanData*/, + LineFacePtr /*face*/, + Bool /*isLeft*/, + double /*xorg*/, + double /*yorg*/, + Bool /*isInt*/ +); + +extern SpanDataPtr miSetupSpanData( + GCPtr /*pGC*/, + SpanDataPtr /*spanData*/, + int /*npt*/ +); + +extern void miCleanupSpanData( + DrawablePtr /*pDrawable*/, + GCPtr /*pGC*/, + SpanDataPtr /*spanData*/ +); + +extern int miPolyBuildEdge(double x0, double y0, double k, int dx, int dy, + int xi, int yi, int left, PolyEdgePtr edge); +extern int miPolyBuildPoly(PolyVertexPtr vertices, PolySlopePtr slopes, + int count, int xi, int yi, PolyEdgePtr left, + PolyEdgePtr right, int *pnleft, int *pnright, + int *h); + diff --git a/xserver/mi/miwindow.c b/xserver/mi/miwindow.c new file mode 100644 index 000000000..cd6bb8df3 --- /dev/null +++ b/xserver/mi/miwindow.c @@ -0,0 +1,1182 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include "regionstr.h" +#include "region.h" +#include "mi.h" +#include "windowstr.h" +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "mivalidate.h" + +_X_EXPORT void +miClearToBackground(pWin, x, y, w, h, generateExposures) + WindowPtr pWin; + int x,y; + int w,h; + Bool generateExposures; +{ + BoxRec box; + RegionRec reg; + RegionPtr pBSReg = NullRegion; + ScreenPtr pScreen; + BoxPtr extents; + int x1, y1, x2, y2; + + /* compute everything using ints to avoid overflow */ + + x1 = pWin->drawable.x + x; + y1 = pWin->drawable.y + y; + if (w) + x2 = x1 + (int) w; + else + x2 = x1 + (int) pWin->drawable.width - (int) x; + if (h) + y2 = y1 + h; + else + y2 = y1 + (int) pWin->drawable.height - (int) y; + + extents = &pWin->clipList.extents; + + /* clip the resulting rectangle to the window clipList extents. This + * makes sure that the result will fit in a box, given that the + * screen is < 32768 on a side. + */ + + if (x1 < extents->x1) + x1 = extents->x1; + if (x2 > extents->x2) + x2 = extents->x2; + if (y1 < extents->y1) + y1 = extents->y1; + if (y2 > extents->y2) + y2 = extents->y2; + + if (x2 <= x1 || y2 <= y1) + { + x2 = x1 = 0; + y2 = y1 = 0; + } + + box.x1 = x1; + box.x2 = x2; + box.y1 = y1; + box.y2 = y2; + + pScreen = pWin->drawable.pScreen; + REGION_INIT(pScreen, ®, &box, 1); + if (pWin->backStorage) + { + /* + * If the window has backing-store on, call through the + * ClearToBackground vector to handle the special semantics + * (i.e. things backing store is to be cleared out and + * an Expose event is to be generated for those areas in backing + * store if generateExposures is TRUE). + */ + pBSReg = (* pScreen->ClearBackingStore)(pWin, x, y, w, h, + generateExposures); + } + + REGION_INTERSECT(pScreen, ®, ®, &pWin->clipList); + if (generateExposures) + (*pScreen->WindowExposures)(pWin, ®, pBSReg); + else if (pWin->backgroundState != None) + (*pScreen->PaintWindowBackground)(pWin, ®, PW_BACKGROUND); + REGION_UNINIT(pScreen, ®); + if (pBSReg) + REGION_DESTROY(pScreen, pBSReg); +} + +/* + * For SaveUnders using backing-store. The idea is that when a window is mapped + * with saveUnder set TRUE, any windows it obscures will have its backing + * store turned on setting the DIXsaveUnder bit, + * The backing-store code must be written to allow for this + */ + +/*- + *----------------------------------------------------------------------- + * miCheckSubSaveUnder -- + * Check all the inferiors of a window for coverage by saveUnder + * windows. Called from ChangeSaveUnder and CheckSaveUnder. + * This code is very inefficient. + * + * Results: + * TRUE if any windows need to have backing-store removed. + * + * Side Effects: + * Windows may have backing-store turned on or off. + * + *----------------------------------------------------------------------- + */ +static Bool +miCheckSubSaveUnder( + register WindowPtr pParent, /* Parent to check */ + WindowPtr pFirst, /* first reconfigured window */ + RegionPtr pRegion) /* Initial area obscured by saveUnder */ +{ + register WindowPtr pChild; /* Current child */ + register ScreenPtr pScreen; /* Screen to use */ + RegionRec SubRegion; /* Area of children obscured */ + Bool res = FALSE; /* result */ + Bool subInited=FALSE;/* SubRegion initialized */ + + pScreen = pParent->drawable.pScreen; + if ( (pChild = pParent->firstChild) ) + { + /* + * build region above first changed window + */ + + for (; pChild != pFirst; pChild = pChild->nextSib) + if (pChild->viewable && pChild->saveUnder) + REGION_UNION(pScreen, pRegion, pRegion, &pChild->borderSize); + + /* + * check region below and including first changed window + */ + + for (; pChild; pChild = pChild->nextSib) + { + if (pChild->viewable) + { + /* + * don't save under nephew/niece windows; + * use a separate region + */ + + if (pChild->firstChild) + { + if (!subInited) + { + REGION_NULL(pScreen, &SubRegion); + subInited = TRUE; + } + REGION_COPY(pScreen, &SubRegion, pRegion); + res |= miCheckSubSaveUnder(pChild, pChild->firstChild, + &SubRegion); + } + else + { + res |= miCheckSubSaveUnder(pChild, pChild->firstChild, + pRegion); + } + + if (pChild->saveUnder) + REGION_UNION(pScreen, pRegion, pRegion, &pChild->borderSize); + } + } + + if (subInited) + REGION_UNINIT(pScreen, &SubRegion); + } + + /* + * Check the state of this window. DIX save unders are + * enabled for viewable windows with some client expressing + * exposure interest and which intersect the save under region + */ + + if (pParent->viewable && + ((pParent->eventMask | wOtherEventMasks(pParent)) & ExposureMask) && + REGION_NOTEMPTY(pScreen, &pParent->borderSize) && + RECT_IN_REGION(pScreen, pRegion, REGION_EXTENTS(pScreen, + &pParent->borderSize)) != rgnOUT) + { + if (!pParent->DIXsaveUnder) + { + pParent->DIXsaveUnder = TRUE; + (*pScreen->ChangeWindowAttributes) (pParent, CWBackingStore); + } + } + else + { + if (pParent->DIXsaveUnder) + { + res = TRUE; + pParent->DIXsaveUnder = FALSE; + } + } + return res; +} + + +/*- + *----------------------------------------------------------------------- + * miChangeSaveUnder -- + * Change the save-under state of a tree of windows. Called when + * a window with saveUnder TRUE is mapped/unmapped/reconfigured. + * + * Results: + * TRUE if any windows need to have backing-store removed (which + * means that PostChangeSaveUnder needs to be called later to + * finish the job). + * + * Side Effects: + * Windows may have backing-store turned on or off. + * + *----------------------------------------------------------------------- + */ +Bool +miChangeSaveUnder(pWin, first) + register WindowPtr pWin; + WindowPtr first; /* First window to check. + * Used when pWin was restacked */ +{ + RegionRec rgn; /* Area obscured by saveUnder windows */ + register ScreenPtr pScreen; + Bool res; + + if (!deltaSaveUndersViewable && !numSaveUndersViewable) + return FALSE; + numSaveUndersViewable += deltaSaveUndersViewable; + deltaSaveUndersViewable = 0; + pScreen = pWin->drawable.pScreen; + REGION_NULL(pScreen, &rgn); + res = miCheckSubSaveUnder (pWin->parent, + pWin->saveUnder ? first : pWin->nextSib, + &rgn); + REGION_UNINIT(pScreen, &rgn); + return res; +} + +/*- + *----------------------------------------------------------------------- + * miPostChangeSaveUnder -- + * Actually turn backing-store off for those windows that no longer + * need to have it on. + * + * Results: + * None. + * + * Side Effects: + * Backing-store and SAVE_UNDER_CHANGE_BIT are turned off for those + * windows affected. + * + *----------------------------------------------------------------------- + */ +void +miPostChangeSaveUnder(pWin, pFirst) + WindowPtr pWin; + WindowPtr pFirst; +{ + register WindowPtr pParent, pChild; + ChangeWindowAttributesProcPtr ChangeWindowAttributes; + + if (!(pParent = pWin->parent)) + return; + ChangeWindowAttributes = pParent->drawable.pScreen->ChangeWindowAttributes; + if (!pParent->DIXsaveUnder && + (pParent->backingStore == NotUseful) && pParent->backStorage) + (*ChangeWindowAttributes)(pParent, CWBackingStore); + if (!(pChild = pFirst)) + return; + while (1) + { + if (!pChild->DIXsaveUnder && + (pChild->backingStore == NotUseful) && pChild->backStorage) + (*ChangeWindowAttributes)(pChild, CWBackingStore); + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + while (!pChild->nextSib) + { + pChild = pChild->parent; + if (pChild == pParent) + return; + } + pChild = pChild->nextSib; + } +} + +void +miMarkWindow(pWin) + register WindowPtr pWin; +{ + register ValidatePtr val; + + if (pWin->valdata) + return; + val = (ValidatePtr)xnfalloc(sizeof(ValidateRec)); + val->before.oldAbsCorner.x = pWin->drawable.x; + val->before.oldAbsCorner.y = pWin->drawable.y; + val->before.borderVisible = NullRegion; + val->before.resized = FALSE; + pWin->valdata = val; +} + +Bool +miMarkOverlappedWindows(pWin, pFirst, ppLayerWin) + WindowPtr pWin; + WindowPtr pFirst; + WindowPtr *ppLayerWin; +{ + register BoxPtr box; + register WindowPtr pChild, pLast; + Bool anyMarked = FALSE; + MarkWindowProcPtr MarkWindow = pWin->drawable.pScreen->MarkWindow; + ScreenPtr pScreen; + + pScreen = pWin->drawable.pScreen; + + /* single layered systems are easy */ + if (ppLayerWin) *ppLayerWin = pWin; + + if (pWin == pFirst) + { + /* Blindly mark pWin and all of its inferiors. This is a slight + * overkill if there are mapped windows that outside pWin's border, + * but it's better than wasting time on RectIn checks. + */ + pChild = pWin; + while (1) + { + if (pChild->viewable) + { + if (REGION_BROKEN (pScreen, &pChild->winSize)) + SetWinSize (pChild); + if (REGION_BROKEN (pScreen, &pChild->borderSize)) + SetBorderSize (pChild); + (* MarkWindow)(pChild); + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } + anyMarked = TRUE; + pFirst = pFirst->nextSib; + } + if ( (pChild = pFirst) ) + { + box = REGION_EXTENTS(pChild->drawable.pScreen, &pWin->borderSize); + pLast = pChild->parent->lastChild; + while (1) + { + if (pChild->viewable) + { + if (REGION_BROKEN (pScreen, &pChild->winSize)) + SetWinSize (pChild); + if (REGION_BROKEN (pScreen, &pChild->borderSize)) + SetBorderSize (pChild); + if (RECT_IN_REGION(pScreen, &pChild->borderSize, box)) + { + (* MarkWindow)(pChild); + anyMarked = TRUE; + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + } + while (!pChild->nextSib && (pChild != pLast)) + pChild = pChild->parent; + if (pChild == pLast) + break; + pChild = pChild->nextSib; + } + } + if (anyMarked) + (* MarkWindow)(pWin->parent); + return anyMarked; +} + +/***** + * miHandleValidateExposures(pWin) + * starting at pWin, draw background in any windows that have exposure + * regions, translate the regions, restore any backing store, + * and then send any regions still exposed to the client + *****/ +_X_EXPORT void +miHandleValidateExposures(pWin) + WindowPtr pWin; +{ + register WindowPtr pChild; + register ValidatePtr val; + ScreenPtr pScreen; + WindowExposuresProcPtr WindowExposures; + + pScreen = pWin->drawable.pScreen; + + pChild = pWin; + WindowExposures = pChild->drawable.pScreen->WindowExposures; + while (1) + { + if ( (val = pChild->valdata) ) + { + if (REGION_NOTEMPTY(pScreen, &val->after.borderExposed)) + (*pChild->drawable.pScreen->PaintWindowBorder)(pChild, + &val->after.borderExposed, + PW_BORDER); + REGION_UNINIT(pScreen, &val->after.borderExposed); + (*WindowExposures)(pChild, &val->after.exposed, NullRegion); + REGION_UNINIT(pScreen, &val->after.exposed); + xfree(val); + pChild->valdata = (ValidatePtr)NULL; + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } +} + +void +miMoveWindow(pWin, x, y, pNextSib, kind) + register WindowPtr pWin; + int x,y; + WindowPtr pNextSib; + VTKind kind; +{ + WindowPtr pParent; + Bool WasViewable = (Bool)(pWin->viewable); + short bw; + RegionPtr oldRegion = NULL; + DDXPointRec oldpt; + Bool anyMarked = FALSE; + register ScreenPtr pScreen; + WindowPtr windowToValidate; +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + WindowPtr pLayerWin; + + /* if this is a root window, can't be moved */ + if (!(pParent = pWin->parent)) + return ; + pScreen = pWin->drawable.pScreen; + bw = wBorderWidth (pWin); + + oldpt.x = pWin->drawable.x; + oldpt.y = pWin->drawable.y; + if (WasViewable) + { + oldRegion = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldRegion, &pWin->borderClip); + anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, &pLayerWin); + } + pWin->origin.x = x + (int)bw; + pWin->origin.y = y + (int)bw; + x = pWin->drawable.x = pParent->drawable.x + x + (int)bw; + y = pWin->drawable.y = pParent->drawable.y + y + (int)bw; + + SetWinSize (pWin); + SetBorderSize (pWin); + + (*pScreen->PositionWindow)(pWin, x, y); + + windowToValidate = MoveWindowInStack(pWin, pNextSib); + + ResizeChildrenWinSize(pWin, x - oldpt.x, y - oldpt.y, 0, 0); + + if (WasViewable) + { + if (pLayerWin == pWin) + anyMarked |= (*pScreen->MarkOverlappedWindows) + (pWin, windowToValidate, (WindowPtr *)NULL); + else + anyMarked |= (*pScreen->MarkOverlappedWindows) + (pWin, pLayerWin, (WindowPtr *)NULL); + +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + { + dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, windowToValidate); + } +#endif /* DO_SAVE_UNDERS */ + + if (anyMarked) + { + (*pScreen->ValidateTree)(pLayerWin->parent, NullWindow, kind); + (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, oldRegion); + REGION_DESTROY(pScreen, oldRegion); + /* XXX need to retile border if ParentRelative origin */ + (*pScreen->HandleExposures)(pLayerWin->parent); + } +#ifdef DO_SAVE_UNDERS + if (dosave) + (*pScreen->PostChangeSaveUnder)(pLayerWin, windowToValidate); +#endif /* DO_SAVE_UNDERS */ + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, NullWindow, kind); + } + if (pWin->realized) + WindowsRestructured (); +} + + +/* + * pValid is a region of the screen which has been + * successfully copied -- recomputed exposed regions for affected windows + */ + +static int +miRecomputeExposures ( + register WindowPtr pWin, + pointer value) /* must conform to VisitWindowProcPtr */ +{ + register ScreenPtr pScreen; + RegionPtr pValid = (RegionPtr)value; + + if (pWin->valdata) + { + pScreen = pWin->drawable.pScreen; + /* + * compute exposed regions of this window + */ + REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed, + &pWin->clipList, pValid); + /* + * compute exposed regions of the border + */ + REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed, + &pWin->borderClip, &pWin->winSize); + REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed, + &pWin->valdata->after.borderExposed, pValid); + return WT_WALKCHILDREN; + } + return WT_NOMATCH; +} + +void +miSlideAndSizeWindow(pWin, x, y, w, h, pSib) + register WindowPtr pWin; + int x,y; + unsigned int w, h; + WindowPtr pSib; +{ + WindowPtr pParent; + Bool WasViewable = (Bool)(pWin->viewable); + unsigned short width = pWin->drawable.width, + height = pWin->drawable.height; + short oldx = pWin->drawable.x, + oldy = pWin->drawable.y; + int bw = wBorderWidth (pWin); + short dw, dh; + DDXPointRec oldpt; + RegionPtr oldRegion = NULL; + Bool anyMarked = FALSE; + register ScreenPtr pScreen; + WindowPtr pFirstChange; + register WindowPtr pChild; + RegionPtr gravitate[StaticGravity + 1]; + register unsigned g; + int nx, ny; /* destination x,y */ + int newx, newy; /* new inner window position */ + RegionPtr pRegion = NULL; + RegionPtr destClip; /* portions of destination already written */ + RegionPtr oldWinClip = NULL; /* old clip list for window */ + RegionPtr borderVisible = NullRegion; /* visible area of the border */ + RegionPtr bsExposed = NullRegion; /* backing store exposures */ + Bool shrunk = FALSE; /* shrunk in an inner dimension */ + Bool moved = FALSE; /* window position changed */ +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + WindowPtr pLayerWin; + + /* if this is a root window, can't be resized */ + if (!(pParent = pWin->parent)) + return ; + + pScreen = pWin->drawable.pScreen; + newx = pParent->drawable.x + x + bw; + newy = pParent->drawable.y + y + bw; + if (WasViewable) + { + anyMarked = FALSE; + /* + * save the visible region of the window + */ + oldRegion = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldRegion, &pWin->winSize); + + /* + * categorize child windows into regions to be moved + */ + for (g = 0; g <= StaticGravity; g++) + gravitate[g] = (RegionPtr) NULL; + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + g = pChild->winGravity; + if (g != UnmapGravity) + { + if (!gravitate[g]) + gravitate[g] = REGION_CREATE(pScreen, NullBox, 1); + REGION_UNION(pScreen, gravitate[g], + gravitate[g], &pChild->borderClip); + } + else + { + UnmapWindow(pChild, TRUE); + anyMarked = TRUE; + } + } + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pWin, + &pLayerWin); + + oldWinClip = NULL; + if (pWin->bitGravity != ForgetGravity) + { + oldWinClip = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldWinClip, &pWin->clipList); + } + /* + * if the window is changing size, borderExposed + * can't be computed correctly without some help. + */ + if (pWin->drawable.height > h || pWin->drawable.width > w) + shrunk = TRUE; + + if (newx != oldx || newy != oldy) + moved = TRUE; + + if ((pWin->drawable.height != h || pWin->drawable.width != w) && + HasBorder (pWin)) + { + borderVisible = REGION_CREATE(pScreen, NullBox, 1); + /* for tiled borders, we punt and draw the whole thing */ + if (pWin->borderIsPixel || !moved) + { + if (shrunk || moved) + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, + &pWin->winSize); + else + REGION_COPY(pScreen, borderVisible, + &pWin->borderClip); + } + } + } + pWin->origin.x = x + bw; + pWin->origin.y = y + bw; + pWin->drawable.height = h; + pWin->drawable.width = w; + + x = pWin->drawable.x = newx; + y = pWin->drawable.y = newy; + + SetWinSize (pWin); + SetBorderSize (pWin); + + dw = (int)w - (int)width; + dh = (int)h - (int)height; + ResizeChildrenWinSize(pWin, x - oldx, y - oldy, dw, dh); + + /* let the hardware adjust background and border pixmaps, if any */ + (*pScreen->PositionWindow)(pWin, x, y); + + pFirstChange = MoveWindowInStack(pWin, pSib); + + if (WasViewable) + { + pRegion = REGION_CREATE(pScreen, NullBox, 1); + if (pWin->backStorage) + REGION_COPY(pScreen, pRegion, &pWin->clipList); + + if (pLayerWin == pWin) + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, + (WindowPtr *)NULL); + else + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pLayerWin, + (WindowPtr *)NULL); + + if (pWin->valdata) + { + pWin->valdata->before.resized = TRUE; + pWin->valdata->before.borderVisible = borderVisible; + } + +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + { + dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pFirstChange); + } +#endif /* DO_SAVE_UNDERS */ + + if (anyMarked) + (*pScreen->ValidateTree)(pLayerWin->parent, pFirstChange, VTOther); + /* + * the entire window is trashed unless bitGravity + * recovers portions of it + */ + REGION_COPY(pScreen, &pWin->valdata->after.exposed, &pWin->clipList); + } + + GravityTranslate (x, y, oldx, oldy, dw, dh, pWin->bitGravity, &nx, &ny); + + if (pWin->backStorage && + ((pWin->backingStore == Always) || WasViewable)) + { + if (!WasViewable) + pRegion = &pWin->clipList; /* a convenient empty region */ + if (pWin->bitGravity == ForgetGravity) + bsExposed = (*pScreen->TranslateBackingStore) + (pWin, 0, 0, NullRegion, oldx, oldy); + else + { + bsExposed = (*pScreen->TranslateBackingStore) + (pWin, nx - x, ny - y, pRegion, oldx, oldy); + } + } + + if (WasViewable) + { + /* avoid the border */ + if (HasBorder (pWin)) + { + int offx, offy, dx, dy; + + /* kruft to avoid double translates for each gravity */ + offx = 0; + offy = 0; + for (g = 0; g <= StaticGravity; g++) + { + if (!gravitate[g]) + continue; + + /* align winSize to gravitate[g]. + * winSize is in new coordinates, + * gravitate[g] is still in old coordinates */ + GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny); + + dx = (oldx - nx) - offx; + dy = (oldy - ny) - offy; + if (dx || dy) + { + REGION_TRANSLATE(pScreen, &pWin->winSize, dx, dy); + offx += dx; + offy += dy; + } + REGION_INTERSECT(pScreen, gravitate[g], gravitate[g], + &pWin->winSize); + } + /* get winSize back where it belongs */ + if (offx || offy) + REGION_TRANSLATE(pScreen, &pWin->winSize, -offx, -offy); + } + /* + * add screen bits to the appropriate bucket + */ + + if (oldWinClip) + { + /* + * clip to new clipList + */ + REGION_COPY(pScreen, pRegion, oldWinClip); + REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy); + REGION_INTERSECT(pScreen, oldWinClip, pRegion, &pWin->clipList); + /* + * don't step on any gravity bits which will be copied after this + * region. Note -- this assumes that the regions will be copied + * in gravity order. + */ + for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) + { + if (gravitate[g]) + REGION_SUBTRACT(pScreen, oldWinClip, oldWinClip, + gravitate[g]); + } + REGION_TRANSLATE(pScreen, oldWinClip, oldx - nx, oldy - ny); + g = pWin->bitGravity; + if (!gravitate[g]) + gravitate[g] = oldWinClip; + else + { + REGION_UNION(pScreen, gravitate[g], gravitate[g], oldWinClip); + REGION_DESTROY(pScreen, oldWinClip); + } + } + + /* + * move the bits on the screen + */ + + destClip = NULL; + + for (g = 0; g <= StaticGravity; g++) + { + if (!gravitate[g]) + continue; + + GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny); + + oldpt.x = oldx + (x - nx); + oldpt.y = oldy + (y - ny); + + /* Note that gravitate[g] is *translated* by CopyWindow */ + + /* only copy the remaining useful bits */ + + REGION_INTERSECT(pScreen, gravitate[g], gravitate[g], oldRegion); + + /* clip to not overwrite already copied areas */ + + if (destClip) { + REGION_TRANSLATE(pScreen, destClip, oldpt.x - x, oldpt.y - y); + REGION_SUBTRACT(pScreen, gravitate[g], gravitate[g], destClip); + REGION_TRANSLATE(pScreen, destClip, x - oldpt.x, y - oldpt.y); + } + + /* and move those bits */ + + if (oldpt.x != x || oldpt.y != y +#ifdef COMPOSITE + || pWin->redirectDraw +#endif + ) + { + (*pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, gravitate[g]); + } + + /* remove any overwritten bits from the remaining useful bits */ + + REGION_SUBTRACT(pScreen, oldRegion, oldRegion, gravitate[g]); + + /* + * recompute exposed regions of child windows + */ + + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + if (pChild->winGravity != g) + continue; + REGION_INTERSECT(pScreen, pRegion, + &pChild->borderClip, gravitate[g]); + TraverseTree (pChild, miRecomputeExposures, (pointer)pRegion); + } + + /* + * remove the successfully copied regions of the + * window from its exposed region + */ + + if (g == pWin->bitGravity) + REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed, + &pWin->valdata->after.exposed, gravitate[g]); + if (!destClip) + destClip = gravitate[g]; + else + { + REGION_UNION(pScreen, destClip, destClip, gravitate[g]); + REGION_DESTROY(pScreen, gravitate[g]); + } + } + + REGION_DESTROY(pScreen, oldRegion); + REGION_DESTROY(pScreen, pRegion); + if (destClip) + REGION_DESTROY(pScreen, destClip); + if (bsExposed) + { + RegionPtr valExposed = NullRegion; + + if (pWin->valdata) + valExposed = &pWin->valdata->after.exposed; + (*pScreen->WindowExposures) (pWin, valExposed, bsExposed); + if (valExposed) + REGION_EMPTY(pScreen, valExposed); + REGION_DESTROY(pScreen, bsExposed); + } + if (anyMarked) + (*pScreen->HandleExposures)(pLayerWin->parent); +#ifdef DO_SAVE_UNDERS + if (dosave) + { + (*pScreen->PostChangeSaveUnder)(pLayerWin, pFirstChange); + } +#endif /* DO_SAVE_UNDERS */ + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstChange, + VTOther); + } + else if (bsExposed) + { + (*pScreen->WindowExposures) (pWin, NullRegion, bsExposed); + REGION_DESTROY(pScreen, bsExposed); + } + if (pWin->realized) + WindowsRestructured (); +} + +WindowPtr +miGetLayerWindow(pWin) + WindowPtr pWin; +{ + return pWin->firstChild; +} + +#ifdef SHAPE +/****** + * + * miSetShape + * The border/window shape has changed. Recompute winSize/borderSize + * and send appropriate exposure events + */ + +_X_EXPORT void +miSetShape(pWin) + register WindowPtr pWin; +{ + Bool WasViewable = (Bool)(pWin->viewable); + register ScreenPtr pScreen = pWin->drawable.pScreen; + Bool anyMarked = FALSE; + RegionPtr pOldClip = NULL, bsExposed; +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + WindowPtr pLayerWin; + + if (WasViewable) + { + anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, + &pLayerWin); + if (pWin->valdata) + { + if (HasBorder (pWin)) + { + RegionPtr borderVisible; + + borderVisible = REGION_CREATE(pScreen, NullBox, 1); + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + } + pWin->valdata->before.resized = TRUE; + } + } + + SetWinSize (pWin); + SetBorderSize (pWin); + + ResizeChildrenWinSize(pWin, 0, 0, 0, 0); + + if (WasViewable) + { + if (pWin->backStorage) + { + pOldClip = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, pOldClip, &pWin->clipList); + } + + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pWin, + (WindowPtr *)NULL); + +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + { + dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pLayerWin); + } +#endif /* DO_SAVE_UNDERS */ + + if (anyMarked) + (*pScreen->ValidateTree)(pLayerWin->parent, NullWindow, VTOther); + } + + if (pWin->backStorage && + ((pWin->backingStore == Always) || WasViewable)) + { + if (!WasViewable) + pOldClip = &pWin->clipList; /* a convenient empty region */ + bsExposed = (*pScreen->TranslateBackingStore) + (pWin, 0, 0, pOldClip, + pWin->drawable.x, pWin->drawable.y); + if (WasViewable) + REGION_DESTROY(pScreen, pOldClip); + if (bsExposed) + { + RegionPtr valExposed = NullRegion; + + if (pWin->valdata) + valExposed = &pWin->valdata->after.exposed; + (*pScreen->WindowExposures) (pWin, valExposed, bsExposed); + if (valExposed) + REGION_EMPTY(pScreen, valExposed); + REGION_DESTROY(pScreen, bsExposed); + } + } + if (WasViewable) + { + if (anyMarked) + (*pScreen->HandleExposures)(pLayerWin->parent); +#ifdef DO_SAVE_UNDERS + if (dosave) + (*pScreen->PostChangeSaveUnder)(pLayerWin, pLayerWin); +#endif /* DO_SAVE_UNDERS */ + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, NullWindow, VTOther); + } + if (pWin->realized) + WindowsRestructured (); + CheckCursorConfinement(pWin); +} +#endif + +/* Keeps the same inside(!) origin */ + +_X_EXPORT void +miChangeBorderWidth(pWin, width) + register WindowPtr pWin; + unsigned int width; +{ + int oldwidth; + Bool anyMarked = FALSE; + register ScreenPtr pScreen; + Bool WasViewable = (Bool)(pWin->viewable); + Bool HadBorder; +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + WindowPtr pLayerWin; + + oldwidth = wBorderWidth (pWin); + if (oldwidth == width) + return; + HadBorder = HasBorder(pWin); + pScreen = pWin->drawable.pScreen; + if (WasViewable && width < oldwidth) + anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, &pLayerWin); + + pWin->borderWidth = width; + SetBorderSize (pWin); + + if (WasViewable) + { + if (width > oldwidth) + { + anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, + &pLayerWin); + /* + * save the old border visible region to correctly compute + * borderExposed. + */ + if (pWin->valdata && HadBorder) + { + RegionPtr borderVisible; + borderVisible = REGION_CREATE(pScreen, NULL, 1); + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + } + } +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + { + dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pWin->nextSib); + } +#endif /* DO_SAVE_UNDERS */ + + if (anyMarked) + { + (*pScreen->ValidateTree)(pLayerWin->parent, pLayerWin, VTOther); + (*pScreen->HandleExposures)(pLayerWin->parent); + } +#ifdef DO_SAVE_UNDERS + if (dosave) + (*pScreen->PostChangeSaveUnder)(pLayerWin, pWin->nextSib); +#endif /* DO_SAVE_UNDERS */ + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pLayerWin, + VTOther); + } + if (pWin->realized) + WindowsRestructured (); +} + +void +miMarkUnrealizedWindow(pChild, pWin, fromConfigure) + WindowPtr pChild; + WindowPtr pWin; + Bool fromConfigure; +{ + if ((pChild != pWin) || fromConfigure) + { + REGION_EMPTY(pChild->drawable.pScreen, &pChild->clipList); + if (pChild->drawable.pScreen->ClipNotify) + (* pChild->drawable.pScreen->ClipNotify)(pChild, 0, 0); + REGION_EMPTY(pChild->drawable.pScreen, &pChild->borderClip); + } +} + +_X_EXPORT void +miSegregateChildren(WindowPtr pWin, RegionPtr pReg, int depth) +{ + ScreenPtr pScreen; + WindowPtr pChild; + + pScreen = pWin->drawable.pScreen; + + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + if (pChild->drawable.depth == depth) + REGION_UNION(pScreen, pReg, pReg, &pChild->borderClip); + + if (pChild->firstChild) + miSegregateChildren(pChild, pReg, depth); + } +} diff --git a/xserver/mi/mizerarc.c b/xserver/mi/mizerarc.c new file mode 100644 index 000000000..33e1acc19 --- /dev/null +++ b/xserver/mi/mizerarc.c @@ -0,0 +1,853 @@ +/************************************************************ + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Author: Bob Scheifler, MIT X Consortium + +********************************************************/ + + +/* Derived from: + * "Algorithm for drawing ellipses or hyperbolae with a digital plotter" + * by M. L. V. Pitteway + * The Computer Journal, November 1967, Volume 10, Number 3, pp. 282-289 + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <math.h> +#include <X11/X.h> +#include <X11/Xprotostr.h> +#include "regionstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "mi.h" +#include "mizerarc.h" + +#define FULLCIRCLE (360 * 64) +#define OCTANT (45 * 64) +#define QUADRANT (90 * 64) +#define HALFCIRCLE (180 * 64) +#define QUADRANT3 (270 * 64) + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#define Dsin(d) ((d) == 0 ? 0.0 : ((d) == QUADRANT ? 1.0 : \ + ((d) == HALFCIRCLE ? 0.0 : \ + ((d) == QUADRANT3 ? -1.0 : sin((double)d*(M_PI/11520.0)))))) + +#define Dcos(d) ((d) == 0 ? 1.0 : ((d) == QUADRANT ? 0.0 : \ + ((d) == HALFCIRCLE ? -1.0 : \ + ((d) == QUADRANT3 ? 0.0 : cos((double)d*(M_PI/11520.0)))))) + +#define EPSILON45 64 + +typedef struct { + int skipStart; + int haveStart; + DDXPointRec startPt; + int haveLast; + int skipLast; + DDXPointRec endPt; + int dashIndex; + int dashOffset; + int dashIndexInit; + int dashOffsetInit; +} DashInfo; + +static miZeroArcPtRec oob = {65536, 65536, 0}; + +/* + * (x - l)^2 / (W/2)^2 + (y + H/2)^2 / (H/2)^2 = 1 + * + * where l is either 0 or .5 + * + * alpha = 4(W^2) + * beta = 4(H^2) + * gamma = 0 + * u = 2(W^2)H + * v = 4(H^2)l + * k = -4(H^2)(l^2) + * + */ + +_X_EXPORT Bool +miZeroArcSetup(arc, info, ok360) + register xArc *arc; + register miZeroArcRec *info; + Bool ok360; +{ + int l; + int angle1, angle2; + int startseg, endseg; + int startAngle, endAngle; + int i, overlap; + miZeroArcPtRec start, end; + + l = arc->width & 1; + if (arc->width == arc->height) + { + info->alpha = 4; + info->beta = 4; + info->k1 = -8; + info->k3 = -16; + info->b = 12; + info->a = (arc->width << 2) - 12; + info->d = 17 - (arc->width << 1); + if (l) + { + info->b -= 4; + info->a += 4; + info->d -= 7; + } + } + else if (!arc->width || !arc->height) + { + info->alpha = 0; + info->beta = 0; + info->k1 = 0; + info->k3 = 0; + info->a = -(int)arc->height; + info->b = 0; + info->d = -1; + } + else + { + /* initial conditions */ + info->alpha = (arc->width * arc->width) << 2; + info->beta = (arc->height * arc->height) << 2; + info->k1 = info->beta << 1; + info->k3 = info->k1 + (info->alpha << 1); + info->b = l ? 0 : -info->beta; + info->a = info->alpha * arc->height; + info->d = info->b - (info->a >> 1) - (info->alpha >> 2); + if (l) + info->d -= info->beta >> 2; + info->a -= info->b; + /* take first step, d < 0 always */ + info->b -= info->k1; + info->a += info->k1; + info->d += info->b; + /* octant change, b < 0 always */ + info->k1 = -info->k1; + info->k3 = -info->k3; + info->b = -info->b; + info->d = info->b - info->a - info->d; + info->a = info->a - (info->b << 1); + } + info->dx = 1; + info->dy = 0; + info->w = (arc->width + 1) >> 1; + info->h = arc->height >> 1; + info->xorg = arc->x + (arc->width >> 1); + info->yorg = arc->y; + info->xorgo = info->xorg + l; + info->yorgo = info->yorg + arc->height; + if (!arc->width) + { + if (!arc->height) + { + info->x = 0; + info->y = 0; + info->initialMask = 0; + info->startAngle = 0; + info->endAngle = 0; + info->start = oob; + info->end = oob; + return FALSE; + } + info->x = 0; + info->y = 1; + } + else + { + info->x = 1; + info->y = 0; + } + angle1 = arc->angle1; + angle2 = arc->angle2; + if ((angle1 == 0) && (angle2 >= FULLCIRCLE)) + { + startAngle = 0; + endAngle = 0; + } + else + { + if (angle2 > FULLCIRCLE) + angle2 = FULLCIRCLE; + else if (angle2 < -FULLCIRCLE) + angle2 = -FULLCIRCLE; + if (angle2 < 0) + { + startAngle = angle1 + angle2; + endAngle = angle1; + } + else + { + startAngle = angle1; + endAngle = angle1 + angle2; + } + if (startAngle < 0) + startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE; + if (startAngle >= FULLCIRCLE) + startAngle = startAngle % FULLCIRCLE; + if (endAngle < 0) + endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE; + if (endAngle >= FULLCIRCLE) + endAngle = endAngle % FULLCIRCLE; + } + info->startAngle = startAngle; + info->endAngle = endAngle; + if (ok360 && (startAngle == endAngle) && arc->angle2 && + arc->width && arc->height) + { + info->initialMask = 0xf; + info->start = oob; + info->end = oob; + return TRUE; + } + startseg = startAngle / OCTANT; + if (!arc->height || (((startseg + 1) & 2) && arc->width)) + { + start.x = Dcos(startAngle) * ((arc->width + 1) / 2.0); + if (start.x < 0) + start.x = -start.x; + start.y = -1; + } + else + { + start.y = Dsin(startAngle) * (arc->height / 2.0); + if (start.y < 0) + start.y = -start.y; + start.y = info->h - start.y; + start.x = 65536; + } + endseg = endAngle / OCTANT; + if (!arc->height || (((endseg + 1) & 2) && arc->width)) + { + end.x = Dcos(endAngle) * ((arc->width + 1) / 2.0); + if (end.x < 0) + end.x = -end.x; + end.y = -1; + } + else + { + end.y = Dsin(endAngle) * (arc->height / 2.0); + if (end.y < 0) + end.y = -end.y; + end.y = info->h - end.y; + end.x = 65536; + } + info->firstx = start.x; + info->firsty = start.y; + info->initialMask = 0; + overlap = arc->angle2 && (endAngle <= startAngle); + for (i = 0; i < 4; i++) + { + if (overlap ? + ((i * QUADRANT <= endAngle) || ((i + 1) * QUADRANT > startAngle)) : + ((i * QUADRANT <= endAngle) && ((i + 1) * QUADRANT > startAngle))) + info->initialMask |= (1 << i); + } + start.mask = info->initialMask; + end.mask = info->initialMask; + startseg >>= 1; + endseg >>= 1; + overlap = overlap && (endseg == startseg); + if (start.x != end.x || start.y != end.y || !overlap) + { + if (startseg & 1) + { + if (!overlap) + info->initialMask &= ~(1 << startseg); + if (start.x > end.x || start.y > end.y) + end.mask &= ~(1 << startseg); + } + else + { + start.mask &= ~(1 << startseg); + if (((start.x < end.x || start.y < end.y) || + (start.x == end.x && start.y == end.y && (endseg & 1))) && + !overlap) + end.mask &= ~(1 << startseg); + } + if (endseg & 1) + { + end.mask &= ~(1 << endseg); + if (((start.x > end.x || start.y > end.y) || + (start.x == end.x && start.y == end.y && !(startseg & 1))) && + !overlap) + start.mask &= ~(1 << endseg); + } + else + { + if (!overlap) + info->initialMask &= ~(1 << endseg); + if (start.x < end.x || start.y < end.y) + start.mask &= ~(1 << endseg); + } + } + /* take care of case when start and stop are both near 45 */ + /* handle here rather than adding extra code to pixelization loops */ + if (startAngle && + ((start.y < 0 && end.y >= 0) || (start.y >= 0 && end.y < 0))) + { + i = (startAngle + OCTANT) % OCTANT; + if (i < EPSILON45 || i > OCTANT - EPSILON45) + { + i = (endAngle + OCTANT) % OCTANT; + if (i < EPSILON45 || i > OCTANT - EPSILON45) + { + if (start.y < 0) + { + i = Dsin(startAngle) * (arc->height / 2.0); + if (i < 0) + i = -i; + if (info->h - i == end.y) + start.mask = end.mask; + } + else + { + i = Dsin(endAngle) * (arc->height / 2.0); + if (i < 0) + i = -i; + if (info->h - i == start.y) + end.mask = start.mask; + } + } + } + } + if (startseg & 1) + { + info->start = start; + info->end = oob; + } + else + { + info->end = start; + info->start = oob; + } + if (endseg & 1) + { + info->altend = end; + if (info->altend.x < info->end.x || info->altend.y < info->end.y) + { + miZeroArcPtRec tmp; + tmp = info->altend; + info->altend = info->end; + info->end = tmp; + } + info->altstart = oob; + } + else + { + info->altstart = end; + if (info->altstart.x < info->start.x || + info->altstart.y < info->start.y) + { + miZeroArcPtRec tmp; + tmp = info->altstart; + info->altstart = info->start; + info->start = tmp; + } + info->altend = oob; + } + if (!info->start.x || !info->start.y) + { + info->initialMask = info->start.mask; + info->start = info->altstart; + } + if (!arc->width && (arc->height == 1)) + { + /* kludge! */ + info->initialMask |= info->end.mask; + info->initialMask |= info->initialMask << 1; + info->end.x = 0; + info->end.mask = 0; + } + return FALSE; +} + +#define Pixelate(xval,yval) \ + { \ + pts->x = xval; \ + pts->y = yval; \ + pts++; \ + } + +#define DoPix(idx,xval,yval) if (mask & (1 << idx)) Pixelate(xval, yval); + +DDXPointPtr +miZeroArcPts(arc, pts) + xArc *arc; + register DDXPointPtr pts; +{ + miZeroArcRec info; + register int x, y, a, b, d, mask; + register int k1, k3, dx, dy; + Bool do360; + + do360 = miZeroArcSetup(arc, &info, TRUE); + MIARCSETUP(); + mask = info.initialMask; + if (!(arc->width & 1)) + { + DoPix(1, info.xorgo, info.yorg); + DoPix(3, info.xorgo, info.yorgo); + } + if (!info.end.x || !info.end.y) + { + mask = info.end.mask; + info.end = info.altend; + } + if (do360 && (arc->width == arc->height) && !(arc->width & 1)) + { + int yorgh = info.yorg + info.h; + int xorghp = info.xorg + info.h; + int xorghn = info.xorg - info.h; + + while (1) + { + Pixelate(info.xorg + x, info.yorg + y); + Pixelate(info.xorg - x, info.yorg + y); + Pixelate(info.xorg - x, info.yorgo - y); + Pixelate(info.xorg + x, info.yorgo - y); + if (a < 0) + break; + Pixelate(xorghp - y, yorgh - x); + Pixelate(xorghn + y, yorgh - x); + Pixelate(xorghn + y, yorgh + x); + Pixelate(xorghp - y, yorgh + x); + MIARCCIRCLESTEP(;); + } + if (x > 1 && pts[-1].x == pts[-5].x && pts[-1].y == pts[-5].y) + pts -= 4; + x = info.w; + y = info.h; + } + else if (do360) + { + while (y < info.h || x < info.w) + { + MIARCOCTANTSHIFT(;); + Pixelate(info.xorg + x, info.yorg + y); + Pixelate(info.xorgo - x, info.yorg + y); + Pixelate(info.xorgo - x, info.yorgo - y); + Pixelate(info.xorg + x, info.yorgo - y); + MIARCSTEP(;,;); + } + } + else + { + while (y < info.h || x < info.w) + { + MIARCOCTANTSHIFT(;); + if ((x == info.start.x) || (y == info.start.y)) + { + mask = info.start.mask; + info.start = info.altstart; + } + DoPix(0, info.xorg + x, info.yorg + y); + DoPix(1, info.xorgo - x, info.yorg + y); + DoPix(2, info.xorgo - x, info.yorgo - y); + DoPix(3, info.xorg + x, info.yorgo - y); + if ((x == info.end.x) || (y == info.end.y)) + { + mask = info.end.mask; + info.end = info.altend; + } + MIARCSTEP(;,;); + } + } + if ((x == info.start.x) || (y == info.start.y)) + mask = info.start.mask; + DoPix(0, info.xorg + x, info.yorg + y); + DoPix(2, info.xorgo - x, info.yorgo - y); + if (arc->height & 1) + { + DoPix(1, info.xorgo - x, info.yorg + y); + DoPix(3, info.xorg + x, info.yorgo - y); + } + return pts; +} + +#undef DoPix +#define DoPix(idx,xval,yval) \ + if (mask & (1 << idx)) \ + { \ + arcPts[idx]->x = xval; \ + arcPts[idx]->y = yval; \ + arcPts[idx]++; \ + } + +static void +miZeroArcDashPts( + GCPtr pGC, + xArc *arc, + DashInfo *dinfo, + register DDXPointPtr points, + int maxPts, + register DDXPointPtr *evenPts, + register DDXPointPtr *oddPts ) +{ + miZeroArcRec info; + register int x, y, a, b, d, mask; + register int k1, k3, dx, dy; + int dashRemaining; + DDXPointPtr arcPts[4]; + DDXPointPtr startPts[5], endPts[5]; + int deltas[5]; + DDXPointPtr startPt, pt, lastPt, pts; + int i, j, delta, ptsdelta, seg, startseg; + + for (i = 0; i < 4; i++) + arcPts[i] = points + (i * maxPts); + (void)miZeroArcSetup(arc, &info, FALSE); + MIARCSETUP(); + mask = info.initialMask; + startseg = info.startAngle / QUADRANT; + startPt = arcPts[startseg]; + if (!(arc->width & 1)) + { + DoPix(1, info.xorgo, info.yorg); + DoPix(3, info.xorgo, info.yorgo); + } + if (!info.end.x || !info.end.y) + { + mask = info.end.mask; + info.end = info.altend; + } + while (y < info.h || x < info.w) + { + MIARCOCTANTSHIFT(;); + if ((x == info.firstx) || (y == info.firsty)) + startPt = arcPts[startseg]; + if ((x == info.start.x) || (y == info.start.y)) + { + mask = info.start.mask; + info.start = info.altstart; + } + DoPix(0, info.xorg + x, info.yorg + y); + DoPix(1, info.xorgo - x, info.yorg + y); + DoPix(2, info.xorgo - x, info.yorgo - y); + DoPix(3, info.xorg + x, info.yorgo - y); + if ((x == info.end.x) || (y == info.end.y)) + { + mask = info.end.mask; + info.end = info.altend; + } + MIARCSTEP(;,;); + } + if ((x == info.firstx) || (y == info.firsty)) + startPt = arcPts[startseg]; + if ((x == info.start.x) || (y == info.start.y)) + mask = info.start.mask; + DoPix(0, info.xorg + x, info.yorg + y); + DoPix(2, info.xorgo - x, info.yorgo - y); + if (arc->height & 1) + { + DoPix(1, info.xorgo - x, info.yorg + y); + DoPix(3, info.xorg + x, info.yorgo - y); + } + for (i = 0; i < 4; i++) + { + seg = (startseg + i) & 3; + pt = points + (seg * maxPts); + if (seg & 1) + { + startPts[i] = pt; + endPts[i] = arcPts[seg]; + deltas[i] = 1; + } + else + { + startPts[i] = arcPts[seg] - 1; + endPts[i] = pt - 1; + deltas[i] = -1; + } + } + startPts[4] = startPts[0]; + endPts[4] = startPt; + startPts[0] = startPt; + if (startseg & 1) + { + if (startPts[4] != endPts[4]) + endPts[4]--; + deltas[4] = 1; + } + else + { + if (startPts[0] > startPts[4]) + startPts[0]--; + if (startPts[4] < endPts[4]) + endPts[4]--; + deltas[4] = -1; + } + if (arc->angle2 < 0) + { + DDXPointPtr tmps, tmpe; + int tmpd; + + tmpd = deltas[0]; + tmps = startPts[0] - tmpd; + tmpe = endPts[0] - tmpd; + startPts[0] = endPts[4] - deltas[4]; + endPts[0] = startPts[4] - deltas[4]; + deltas[0] = -deltas[4]; + startPts[4] = tmpe; + endPts[4] = tmps; + deltas[4] = -tmpd; + tmpd = deltas[1]; + tmps = startPts[1] - tmpd; + tmpe = endPts[1] - tmpd; + startPts[1] = endPts[3] - deltas[3]; + endPts[1] = startPts[3] - deltas[3]; + deltas[1] = -deltas[3]; + startPts[3] = tmpe; + endPts[3] = tmps; + deltas[3] = -tmpd; + tmps = startPts[2] - deltas[2]; + startPts[2] = endPts[2] - deltas[2]; + endPts[2] = tmps; + deltas[2] = -deltas[2]; + } + for (i = 0; i < 5 && startPts[i] == endPts[i]; i++) + ; + if (i == 5) + return; + pt = startPts[i]; + for (j = 4; startPts[j] == endPts[j]; j--) + ; + lastPt = endPts[j] - deltas[j]; + if (dinfo->haveLast && + (pt->x == dinfo->endPt.x) && (pt->y == dinfo->endPt.y)) + { + startPts[i] += deltas[i]; + } + else + { + dinfo->dashIndex = dinfo->dashIndexInit; + dinfo->dashOffset = dinfo->dashOffsetInit; + } + if (!dinfo->skipStart && (info.startAngle != info.endAngle)) + { + dinfo->startPt = *pt; + dinfo->haveStart = TRUE; + } + else if (!dinfo->skipLast && dinfo->haveStart && + (lastPt->x == dinfo->startPt.x) && + (lastPt->y == dinfo->startPt.y) && + (lastPt != startPts[i])) + endPts[j] = lastPt; + if (info.startAngle != info.endAngle) + { + dinfo->haveLast = TRUE; + dinfo->endPt = *lastPt; + } + dashRemaining = pGC->dash[dinfo->dashIndex] - dinfo->dashOffset; + for (i = 0; i < 5; i++) + { + pt = startPts[i]; + lastPt = endPts[i]; + delta = deltas[i]; + while (pt != lastPt) + { + if (dinfo->dashIndex & 1) + { + pts = *oddPts; + ptsdelta = -1; + } + else + { + pts = *evenPts; + ptsdelta = 1; + } + while ((pt != lastPt) && --dashRemaining >= 0) + { + *pts = *pt; + pts += ptsdelta; + pt += delta; + } + if (dinfo->dashIndex & 1) + *oddPts = pts; + else + *evenPts = pts; + if (dashRemaining <= 0) + { + if (++(dinfo->dashIndex) == pGC->numInDashList) + dinfo->dashIndex = 0; + dashRemaining = pGC->dash[dinfo->dashIndex]; + } + } + } + dinfo->dashOffset = pGC->dash[dinfo->dashIndex] - dashRemaining; +} + +_X_EXPORT void +miZeroPolyArc(pDraw, pGC, narcs, parcs) + DrawablePtr pDraw; + GCPtr pGC; + int narcs; + xArc *parcs; +{ + int maxPts = 0; + register int n, maxw = 0; + register xArc *arc; + register int i; + DDXPointPtr points, pts, oddPts; + register DDXPointPtr pt; + int numPts; + Bool dospans; + int *widths = NULL; + XID fgPixel = pGC->fgPixel; + DashInfo dinfo; + + for (arc = parcs, i = narcs; --i >= 0; arc++) + { + if (!miCanZeroArc(arc)) + miPolyArc(pDraw, pGC, 1, arc); + else + { + if (arc->width > arc->height) + n = arc->width + (arc->height >> 1); + else + n = arc->height + (arc->width >> 1); + if (n > maxPts) + maxPts = n; + } + } + if (!maxPts) + return; + numPts = maxPts << 2; + dospans = (pGC->fillStyle != FillSolid); + if (dospans) + { + widths = (int *)ALLOCATE_LOCAL(sizeof(int) * numPts); + if (!widths) + return; + maxw = 0; + } + if (pGC->lineStyle != LineSolid) + { + numPts <<= 1; + dinfo.haveStart = FALSE; + dinfo.skipStart = FALSE; + dinfo.haveLast = FALSE; + dinfo.dashIndexInit = 0; + dinfo.dashOffsetInit = 0; + miStepDash((int)pGC->dashOffset, &dinfo.dashIndexInit, + (unsigned char *) pGC->dash, (int)pGC->numInDashList, + &dinfo.dashOffsetInit); + } + points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * numPts); + if (!points) + { + if (dospans) + { + DEALLOCATE_LOCAL(widths); + } + return; + } + for (arc = parcs, i = narcs; --i >= 0; arc++) + { + if (miCanZeroArc(arc)) + { + if (pGC->lineStyle == LineSolid) + pts = miZeroArcPts(arc, points); + else + { + pts = points; + oddPts = &points[(numPts >> 1) - 1]; + dinfo.skipLast = i; + miZeroArcDashPts(pGC, arc, &dinfo, + oddPts + 1, maxPts, &pts, &oddPts); + dinfo.skipStart = TRUE; + } + n = pts - points; + if (!dospans) + (*pGC->ops->PolyPoint)(pDraw, pGC, CoordModeOrigin, n, points); + else + { + if (n > maxw) + { + while (maxw < n) + widths[maxw++] = 1; + } + if (pGC->miTranslate) + { + for (pt = points; pt != pts; pt++) + { + pt->x += pDraw->x; + pt->y += pDraw->y; + } + } + (*pGC->ops->FillSpans)(pDraw, pGC, n, points, widths, FALSE); + } + if (pGC->lineStyle != LineDoubleDash) + continue; + if ((pGC->fillStyle == FillSolid) || + (pGC->fillStyle == FillStippled)) + { + DoChangeGC(pGC, GCForeground, (XID *)&pGC->bgPixel, 0); + ValidateGC(pDraw, pGC); + } + pts = &points[numPts >> 1]; + oddPts++; + n = pts - oddPts; + if (!dospans) + (*pGC->ops->PolyPoint)(pDraw, pGC, CoordModeOrigin, n, oddPts); + else + { + if (n > maxw) + { + while (maxw < n) + widths[maxw++] = 1; + } + if (pGC->miTranslate) + { + for (pt = oddPts; pt != pts; pt++) + { + pt->x += pDraw->x; + pt->y += pDraw->y; + } + } + (*pGC->ops->FillSpans)(pDraw, pGC, n, oddPts, widths, FALSE); + } + if ((pGC->fillStyle == FillSolid) || + (pGC->fillStyle == FillStippled)) + { + DoChangeGC(pGC, GCForeground, &fgPixel, 0); + ValidateGC(pDraw, pGC); + } + } + } + DEALLOCATE_LOCAL(points); + if (dospans) + { + DEALLOCATE_LOCAL(widths); + } +} diff --git a/xserver/mi/mizerarc.h b/xserver/mi/mizerarc.h new file mode 100644 index 000000000..8119d885e --- /dev/null +++ b/xserver/mi/mizerarc.h @@ -0,0 +1,132 @@ +/************************************************************ + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +********************************************************/ + + +typedef struct { + int x; + int y; + int mask; +} miZeroArcPtRec; + +typedef struct { + int x, y, k1, k3, a, b, d, dx, dy; + int alpha, beta; + int xorg, yorg; + int xorgo, yorgo; + int w, h; + int initialMask; + miZeroArcPtRec start, altstart, end, altend; + int firstx, firsty; + int startAngle, endAngle; +} miZeroArcRec; + +#define miCanZeroArc(arc) (((arc)->width == (arc)->height) || \ + (((arc)->width <= 800) && ((arc)->height <= 800))) + +#define MIARCSETUP() \ + x = info.x; \ + y = info.y; \ + k1 = info.k1; \ + k3 = info.k3; \ + a = info.a; \ + b = info.b; \ + d = info.d; \ + dx = info.dx; \ + dy = info.dy + +#define MIARCOCTANTSHIFT(clause) \ + if (a < 0) \ + { \ + if (y == info.h) \ + { \ + d = -1; \ + a = b = k1 = 0; \ + } \ + else \ + { \ + dx = (k1 << 1) - k3; \ + k1 = dx - k1; \ + k3 = -k3; \ + b = b + a - (k1 >> 1); \ + d = b + ((-a) >> 1) - d + (k3 >> 3); \ + if (dx < 0) \ + a = -((-dx) >> 1) - a; \ + else \ + a = (dx >> 1) - a; \ + dx = 0; \ + dy = 1; \ + clause \ + } \ + } + +#define MIARCSTEP(move1,move2) \ + b -= k1; \ + if (d < 0) \ + { \ + x += dx; \ + y += dy; \ + a += k1; \ + d += b; \ + move1 \ + } \ + else \ + { \ + x++; \ + y++; \ + a += k3; \ + d -= a; \ + move2 \ + } + +#define MIARCCIRCLESTEP(clause) \ + b -= k1; \ + x++; \ + if (d < 0) \ + { \ + a += k1; \ + d += b; \ + } \ + else \ + { \ + y++; \ + a += k3; \ + d -= a; \ + clause \ + } + +/* mizerarc.c */ + +extern Bool miZeroArcSetup( + xArc * /*arc*/, + miZeroArcRec * /*info*/, + Bool /*ok360*/ +); + +extern DDXPointPtr miZeroArcPts( + xArc * /*arc*/, + DDXPointPtr /*pts*/ +); + diff --git a/xserver/mi/mizerclip.c b/xserver/mi/mizerclip.c new file mode 100644 index 000000000..b167c5475 --- /dev/null +++ b/xserver/mi/mizerclip.c @@ -0,0 +1,635 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> + +#include "misc.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "windowstr.h" +#include "pixmap.h" +#include "mi.h" +#include "miline.h" + +/* + +The bresenham error equation used in the mi/mfb/cfb line routines is: + + e = error + dx = difference in raw X coordinates + dy = difference in raw Y coordinates + M = # of steps in X direction + N = # of steps in Y direction + B = 0 to prefer diagonal steps in a given octant, + 1 to prefer axial steps in a given octant + + For X major lines: + e = 2Mdy - 2Ndx - dx - B + -2dx <= e < 0 + + For Y major lines: + e = 2Ndx - 2Mdy - dy - B + -2dy <= e < 0 + +At the start of the line, we have taken 0 X steps and 0 Y steps, +so M = 0 and N = 0: + + X major e = 2Mdy - 2Ndx - dx - B + = -dx - B + + Y major e = 2Ndx - 2Mdy - dy - B + = -dy - B + +At the end of the line, we have taken dx X steps and dy Y steps, +so M = dx and N = dy: + + X major e = 2Mdy - 2Ndx - dx - B + = 2dxdy - 2dydx - dx - B + = -dx - B + Y major e = 2Ndx - 2Mdy - dy - B + = 2dydx - 2dxdy - dy - B + = -dy - B + +Thus, the error term is the same at the start and end of the line. + +Let us consider clipping an X coordinate. There are 4 cases which +represent the two independent cases of clipping the start vs. the +end of the line and an X major vs. a Y major line. In any of these +cases, we know the number of X steps (M) and we wish to find the +number of Y steps (N). Thus, we will solve our error term equation. +If we are clipping the start of the line, we will find the smallest +N that satisfies our error term inequality. If we are clipping the +end of the line, we will find the largest number of Y steps that +satisfies the inequality. In that case, since we are representing +the Y steps as (dy - N), we will actually want to solve for the +smallest N in that equation. + +Case 1: X major, starting X coordinate moved by M steps + + -2dx <= 2Mdy - 2Ndx - dx - B < 0 + 2Ndx <= 2Mdy - dx - B + 2dx 2Ndx > 2Mdy - dx - B + 2Ndx <= 2Mdy + dx - B N > (2Mdy - dx - B) / 2dx + N <= (2Mdy + dx - B) / 2dx + +Since we are trying to find the smallest N that satisfies these +equations, we should use the > inequality to find the smallest: + + N = floor((2Mdy - dx - B) / 2dx) + 1 + = floor((2Mdy - dx - B + 2dx) / 2dx) + = floor((2Mdy + dx - B) / 2dx) + +Case 1b: X major, ending X coordinate moved to M steps + +Same derivations as Case 1, but we want the largest N that satisfies +the equations, so we use the <= inequality: + + N = floor((2Mdy + dx - B) / 2dx) + +Case 2: X major, ending X coordinate moved by M steps + + -2dx <= 2(dx - M)dy - 2(dy - N)dx - dx - B < 0 + -2dx <= 2dxdy - 2Mdy - 2dxdy + 2Ndx - dx - B < 0 + -2dx <= 2Ndx - 2Mdy - dx - B < 0 + 2Ndx >= 2Mdy + dx + B - 2dx 2Ndx < 2Mdy + dx + B + 2Ndx >= 2Mdy - dx + B N < (2Mdy + dx + B) / 2dx + N >= (2Mdy - dx + B) / 2dx + +Since we are trying to find the highest number of Y steps that +satisfies these equations, we need to find the smallest N, so +we should use the >= inequality to find the smallest: + + N = ceiling((2Mdy - dx + B) / 2dx) + = floor((2Mdy - dx + B + 2dx - 1) / 2dx) + = floor((2Mdy + dx + B - 1) / 2dx) + +Case 2b: X major, starting X coordinate moved to M steps from end + +Same derivations as Case 2, but we want the smallest number of Y +steps, so we want the highest N, so we use the < inequality: + + N = ceiling((2Mdy + dx + B) / 2dx) - 1 + = floor((2Mdy + dx + B + 2dx - 1) / 2dx) - 1 + = floor((2Mdy + dx + B + 2dx - 1 - 2dx) / 2dx) + = floor((2Mdy + dx + B - 1) / 2dx) + +Case 3: Y major, starting X coordinate moved by M steps + + -2dy <= 2Ndx - 2Mdy - dy - B < 0 + 2Ndx >= 2Mdy + dy + B - 2dy 2Ndx < 2Mdy + dy + B + 2Ndx >= 2Mdy - dy + B N < (2Mdy + dy + B) / 2dx + N >= (2Mdy - dy + B) / 2dx + +Since we are trying to find the smallest N that satisfies these +equations, we should use the >= inequality to find the smallest: + + N = ceiling((2Mdy - dy + B) / 2dx) + = floor((2Mdy - dy + B + 2dx - 1) / 2dx) + = floor((2Mdy - dy + B - 1) / 2dx) + 1 + +Case 3b: Y major, ending X coordinate moved to M steps + +Same derivations as Case 3, but we want the largest N that satisfies +the equations, so we use the < inequality: + + N = ceiling((2Mdy + dy + B) / 2dx) - 1 + = floor((2Mdy + dy + B + 2dx - 1) / 2dx) - 1 + = floor((2Mdy + dy + B + 2dx - 1 - 2dx) / 2dx) + = floor((2Mdy + dy + B - 1) / 2dx) + +Case 4: Y major, ending X coordinate moved by M steps + + -2dy <= 2(dy - N)dx - 2(dx - M)dy - dy - B < 0 + -2dy <= 2dxdy - 2Ndx - 2dxdy + 2Mdy - dy - B < 0 + -2dy <= 2Mdy - 2Ndx - dy - B < 0 + 2Ndx <= 2Mdy - dy - B + 2dy 2Ndx > 2Mdy - dy - B + 2Ndx <= 2Mdy + dy - B N > (2Mdy - dy - B) / 2dx + N <= (2Mdy + dy - B) / 2dx + +Since we are trying to find the highest number of Y steps that +satisfies these equations, we need to find the smallest N, so +we should use the > inequality to find the smallest: + + N = floor((2Mdy - dy - B) / 2dx) + 1 + +Case 4b: Y major, starting X coordinate moved to M steps from end + +Same analysis as Case 4, but we want the smallest number of Y steps +which means the largest N, so we use the <= inequality: + + N = floor((2Mdy + dy - B) / 2dx) + +Now let's try the Y coordinates, we have the same 4 cases. + +Case 5: X major, starting Y coordinate moved by N steps + + -2dx <= 2Mdy - 2Ndx - dx - B < 0 + 2Mdy >= 2Ndx + dx + B - 2dx 2Mdy < 2Ndx + dx + B + 2Mdy >= 2Ndx - dx + B M < (2Ndx + dx + B) / 2dy + M >= (2Ndx - dx + B) / 2dy + +Since we are trying to find the smallest M, we use the >= inequality: + + M = ceiling((2Ndx - dx + B) / 2dy) + = floor((2Ndx - dx + B + 2dy - 1) / 2dy) + = floor((2Ndx - dx + B - 1) / 2dy) + 1 + +Case 5b: X major, ending Y coordinate moved to N steps + +Same derivations as Case 5, but we want the largest M that satisfies +the equations, so we use the < inequality: + + M = ceiling((2Ndx + dx + B) / 2dy) - 1 + = floor((2Ndx + dx + B + 2dy - 1) / 2dy) - 1 + = floor((2Ndx + dx + B + 2dy - 1 - 2dy) / 2dy) + = floor((2Ndx + dx + B - 1) / 2dy) + +Case 6: X major, ending Y coordinate moved by N steps + + -2dx <= 2(dx - M)dy - 2(dy - N)dx - dx - B < 0 + -2dx <= 2dxdy - 2Mdy - 2dxdy + 2Ndx - dx - B < 0 + -2dx <= 2Ndx - 2Mdy - dx - B < 0 + 2Mdy <= 2Ndx - dx - B + 2dx 2Mdy > 2Ndx - dx - B + 2Mdy <= 2Ndx + dx - B M > (2Ndx - dx - B) / 2dy + M <= (2Ndx + dx - B) / 2dy + +Largest # of X steps means smallest M, so use the > inequality: + + M = floor((2Ndx - dx - B) / 2dy) + 1 + +Case 6b: X major, starting Y coordinate moved to N steps from end + +Same derivations as Case 6, but we want the smallest # of X steps +which means the largest M, so use the <= inequality: + + M = floor((2Ndx + dx - B) / 2dy) + +Case 7: Y major, starting Y coordinate moved by N steps + + -2dy <= 2Ndx - 2Mdy - dy - B < 0 + 2Mdy <= 2Ndx - dy - B + 2dy 2Mdy > 2Ndx - dy - B + 2Mdy <= 2Ndx + dy - B M > (2Ndx - dy - B) / 2dy + M <= (2Ndx + dy - B) / 2dy + +To find the smallest M, use the > inequality: + + M = floor((2Ndx - dy - B) / 2dy) + 1 + = floor((2Ndx - dy - B + 2dy) / 2dy) + = floor((2Ndx + dy - B) / 2dy) + +Case 7b: Y major, ending Y coordinate moved to N steps + +Same derivations as Case 7, but we want the largest M that satisfies +the equations, so use the <= inequality: + + M = floor((2Ndx + dy - B) / 2dy) + +Case 8: Y major, ending Y coordinate moved by N steps + + -2dy <= 2(dy - N)dx - 2(dx - M)dy - dy - B < 0 + -2dy <= 2dxdy - 2Ndx - 2dxdy + 2Mdy - dy - B < 0 + -2dy <= 2Mdy - 2Ndx - dy - B < 0 + 2Mdy >= 2Ndx + dy + B - 2dy 2Mdy < 2Ndx + dy + B + 2Mdy >= 2Ndx - dy + B M < (2Ndx + dy + B) / 2dy + M >= (2Ndx - dy + B) / 2dy + +To find the highest X steps, find the smallest M, use the >= inequality: + + M = ceiling((2Ndx - dy + B) / 2dy) + = floor((2Ndx - dy + B + 2dy - 1) / 2dy) + = floor((2Ndx + dy + B - 1) / 2dy) + +Case 8b: Y major, starting Y coordinate moved to N steps from the end + +Same derivations as Case 8, but we want to find the smallest # of X +steps which means the largest M, so we use the < inequality: + + M = ceiling((2Ndx + dy + B) / 2dy) - 1 + = floor((2Ndx + dy + B + 2dy - 1) / 2dy) - 1 + = floor((2Ndx + dy + B + 2dy - 1 - 2dy) / 2dy) + = floor((2Ndx + dy + B - 1) / 2dy) + +So, our equations are: + + 1: X major move x1 to x1+M floor((2Mdy + dx - B) / 2dx) + 1b: X major move x2 to x1+M floor((2Mdy + dx - B) / 2dx) + 2: X major move x2 to x2-M floor((2Mdy + dx + B - 1) / 2dx) + 2b: X major move x1 to x2-M floor((2Mdy + dx + B - 1) / 2dx) + + 3: Y major move x1 to x1+M floor((2Mdy - dy + B - 1) / 2dx) + 1 + 3b: Y major move x2 to x1+M floor((2Mdy + dy + B - 1) / 2dx) + 4: Y major move x2 to x2-M floor((2Mdy - dy - B) / 2dx) + 1 + 4b: Y major move x1 to x2-M floor((2Mdy + dy - B) / 2dx) + + 5: X major move y1 to y1+N floor((2Ndx - dx + B - 1) / 2dy) + 1 + 5b: X major move y2 to y1+N floor((2Ndx + dx + B - 1) / 2dy) + 6: X major move y2 to y2-N floor((2Ndx - dx - B) / 2dy) + 1 + 6b: X major move y1 to y2-N floor((2Ndx + dx - B) / 2dy) + + 7: Y major move y1 to y1+N floor((2Ndx + dy - B) / 2dy) + 7b: Y major move y2 to y1+N floor((2Ndx + dy - B) / 2dy) + 8: Y major move y2 to y2-N floor((2Ndx + dy + B - 1) / 2dy) + 8b: Y major move y1 to y2-N floor((2Ndx + dy + B - 1) / 2dy) + +We have the following constraints on all of the above terms: + + 0 < M,N <= 2^15 2^15 can be imposed by miZeroClipLine + 0 <= dx/dy <= 2^16 - 1 + 0 <= B <= 1 + +The floor in all of the above equations can be accomplished with a +simple C divide operation provided that both numerator and denominator +are positive. + +Since dx,dy >= 0 and since moving an X coordinate implies that dx != 0 +and moving a Y coordinate implies dy != 0, we know that the denominators +are all > 0. + +For all lines, (-B) and (B-1) are both either 0 or -1, depending on the +bias. Thus, we have to show that the 2MNdxy +/- dxy terms are all >= 1 +or > 0 to prove that the numerators are positive (or zero). + +For X Major lines we know that dx > 0 and since 2Mdy is >= 0 due to the +constraints, the first four equations all have numerators >= 0. + +For the second four equations, M > 0, so 2Mdy >= 2dy so (2Mdy - dy) >= dy +So (2Mdy - dy) > 0, since they are Y major lines. Also, (2Mdy + dy) >= 3dy +or (2Mdy + dy) > 0. So all of their numerators are >= 0. + +For the third set of four equations, N > 0, so 2Ndx >= 2dx so (2Ndx - dx) +>= dx > 0. Similarly (2Ndx + dx) >= 3dx > 0. So all numerators >= 0. + +For the fourth set of equations, dy > 0 and 2Ndx >= 0, so all numerators +are > 0. + +To consider overflow, consider the case of 2 * M,N * dx,dy + dx,dy. This +is bounded <= 2 * 2^15 * (2^16 - 1) + (2^16 - 1) + <= 2^16 * (2^16 - 1) + (2^16 - 1) + <= 2^32 - 2^16 + 2^16 - 1 + <= 2^32 - 1 +Since the (-B) and (B-1) terms are all 0 or -1, the maximum value of +the numerator is therefore (2^32 - 1), which does not overflow an unsigned +32 bit variable. + +*/ + +/* Bit codes for the terms of the 16 clipping equations defined below. */ + +#define T_2NDX (1 << 0) +#define T_2MDY (0) /* implicit term */ +#define T_DXNOTY (1 << 1) +#define T_DYNOTX (0) /* implicit term */ +#define T_SUBDXORY (1 << 2) +#define T_ADDDX (T_DXNOTY) /* composite term */ +#define T_SUBDX (T_DXNOTY | T_SUBDXORY) /* composite term */ +#define T_ADDDY (T_DYNOTX) /* composite term */ +#define T_SUBDY (T_DYNOTX | T_SUBDXORY) /* composite term */ +#define T_BIASSUBONE (1 << 3) +#define T_SUBBIAS (0) /* implicit term */ +#define T_DIV2DX (1 << 4) +#define T_DIV2DY (0) /* implicit term */ +#define T_ADDONE (1 << 5) + +/* Bit masks defining the 16 equations used in miZeroClipLine. */ + +#define EQN1 (T_2MDY | T_ADDDX | T_SUBBIAS | T_DIV2DX) +#define EQN1B (T_2MDY | T_ADDDX | T_SUBBIAS | T_DIV2DX) +#define EQN2 (T_2MDY | T_ADDDX | T_BIASSUBONE | T_DIV2DX) +#define EQN2B (T_2MDY | T_ADDDX | T_BIASSUBONE | T_DIV2DX) + +#define EQN3 (T_2MDY | T_SUBDY | T_BIASSUBONE | T_DIV2DX | T_ADDONE) +#define EQN3B (T_2MDY | T_ADDDY | T_BIASSUBONE | T_DIV2DX) +#define EQN4 (T_2MDY | T_SUBDY | T_SUBBIAS | T_DIV2DX | T_ADDONE) +#define EQN4B (T_2MDY | T_ADDDY | T_SUBBIAS | T_DIV2DX) + +#define EQN5 (T_2NDX | T_SUBDX | T_BIASSUBONE | T_DIV2DY | T_ADDONE) +#define EQN5B (T_2NDX | T_ADDDX | T_BIASSUBONE | T_DIV2DY) +#define EQN6 (T_2NDX | T_SUBDX | T_SUBBIAS | T_DIV2DY | T_ADDONE) +#define EQN6B (T_2NDX | T_ADDDX | T_SUBBIAS | T_DIV2DY) + +#define EQN7 (T_2NDX | T_ADDDY | T_SUBBIAS | T_DIV2DY) +#define EQN7B (T_2NDX | T_ADDDY | T_SUBBIAS | T_DIV2DY) +#define EQN8 (T_2NDX | T_ADDDY | T_BIASSUBONE | T_DIV2DY) +#define EQN8B (T_2NDX | T_ADDDY | T_BIASSUBONE | T_DIV2DY) + +/* miZeroClipLine + * + * returns: 1 for partially clipped line + * -1 for completely clipped line + * + */ +_X_EXPORT int +miZeroClipLine(xmin, ymin, xmax, ymax, + new_x1, new_y1, new_x2, new_y2, + adx, ady, + pt1_clipped, pt2_clipped, octant, bias, oc1, oc2) + int xmin, ymin, xmax, ymax; + int *new_x1, *new_y1, *new_x2, *new_y2; + int *pt1_clipped, *pt2_clipped; + unsigned int adx, ady; + int octant; + unsigned int bias; + int oc1, oc2; +{ + int swapped = 0; + int clipDone = 0; + CARD32 utmp = 0; + int clip1, clip2; + int x1, y1, x2, y2; + int x1_orig, y1_orig, x2_orig, y2_orig; + int xmajor; + int negslope = 0, anchorval = 0; + unsigned int eqn = 0; + + x1 = x1_orig = *new_x1; + y1 = y1_orig = *new_y1; + x2 = x2_orig = *new_x2; + y2 = y2_orig = *new_y2; + + clip1 = 0; + clip2 = 0; + + xmajor = IsXMajorOctant(octant); + bias = ((bias >> octant) & 1); + + while (1) + { + if ((oc1 & oc2) != 0) /* trivial reject */ + { + clipDone = -1; + clip1 = oc1; + clip2 = oc2; + break; + } + else if ((oc1 | oc2) == 0) /* trivial accept */ + { + clipDone = 1; + if (swapped) + { + SWAPINT_PAIR(x1, y1, x2, y2); + SWAPINT(clip1, clip2); + } + break; + } + else /* have to clip */ + { + /* only clip one point at a time */ + if (oc1 == 0) + { + SWAPINT_PAIR(x1, y1, x2, y2); + SWAPINT_PAIR(x1_orig, y1_orig, x2_orig, y2_orig); + SWAPINT(oc1, oc2); + SWAPINT(clip1, clip2); + swapped = !swapped; + } + + clip1 |= oc1; + if (oc1 & OUT_LEFT) + { + negslope = IsYDecreasingOctant(octant); + utmp = xmin - x1_orig; + if (utmp <= 32767) /* clip based on near endpt */ + { + if (xmajor) + eqn = (swapped) ? EQN2 : EQN1; + else + eqn = (swapped) ? EQN4 : EQN3; + anchorval = y1_orig; + } + else /* clip based on far endpt */ + { + utmp = x2_orig - xmin; + if (xmajor) + eqn = (swapped) ? EQN1B : EQN2B; + else + eqn = (swapped) ? EQN3B : EQN4B; + anchorval = y2_orig; + negslope = !negslope; + } + x1 = xmin; + } + else if (oc1 & OUT_ABOVE) + { + negslope = IsXDecreasingOctant(octant); + utmp = ymin - y1_orig; + if (utmp <= 32767) /* clip based on near endpt */ + { + if (xmajor) + eqn = (swapped) ? EQN6 : EQN5; + else + eqn = (swapped) ? EQN8 : EQN7; + anchorval = x1_orig; + } + else /* clip based on far endpt */ + { + utmp = y2_orig - ymin; + if (xmajor) + eqn = (swapped) ? EQN5B : EQN6B; + else + eqn = (swapped) ? EQN7B : EQN8B; + anchorval = x2_orig; + negslope = !negslope; + } + y1 = ymin; + } + else if (oc1 & OUT_RIGHT) + { + negslope = IsYDecreasingOctant(octant); + utmp = x1_orig - xmax; + if (utmp <= 32767) /* clip based on near endpt */ + { + if (xmajor) + eqn = (swapped) ? EQN2 : EQN1; + else + eqn = (swapped) ? EQN4 : EQN3; + anchorval = y1_orig; + } + else /* clip based on far endpt */ + { + /* + * Technically since the equations can handle + * utmp == 32768, this overflow code isn't + * needed since X11 protocol can't generate + * a line which goes more than 32768 pixels + * to the right of a clip rectangle. + */ + utmp = xmax - x2_orig; + if (xmajor) + eqn = (swapped) ? EQN1B : EQN2B; + else + eqn = (swapped) ? EQN3B : EQN4B; + anchorval = y2_orig; + negslope = !negslope; + } + x1 = xmax; + } + else if (oc1 & OUT_BELOW) + { + negslope = IsXDecreasingOctant(octant); + utmp = y1_orig - ymax; + if (utmp <= 32767) /* clip based on near endpt */ + { + if (xmajor) + eqn = (swapped) ? EQN6 : EQN5; + else + eqn = (swapped) ? EQN8 : EQN7; + anchorval = x1_orig; + } + else /* clip based on far endpt */ + { + /* + * Technically since the equations can handle + * utmp == 32768, this overflow code isn't + * needed since X11 protocol can't generate + * a line which goes more than 32768 pixels + * below the bottom of a clip rectangle. + */ + utmp = ymax - y2_orig; + if (xmajor) + eqn = (swapped) ? EQN5B : EQN6B; + else + eqn = (swapped) ? EQN7B : EQN8B; + anchorval = x2_orig; + negslope = !negslope; + } + y1 = ymax; + } + + if (swapped) + negslope = !negslope; + + utmp <<= 1; /* utmp = 2N or 2M */ + if (eqn & T_2NDX) + utmp = (utmp * adx); + else /* (eqn & T_2MDY) */ + utmp = (utmp * ady); + if (eqn & T_DXNOTY) + if (eqn & T_SUBDXORY) + utmp -= adx; + else + utmp += adx; + else /* (eqn & T_DYNOTX) */ + if (eqn & T_SUBDXORY) + utmp -= ady; + else + utmp += ady; + if (eqn & T_BIASSUBONE) + utmp += bias - 1; + else /* (eqn & T_SUBBIAS) */ + utmp -= bias; + if (eqn & T_DIV2DX) + utmp /= (adx << 1); + else /* (eqn & T_DIV2DY) */ + utmp /= (ady << 1); + if (eqn & T_ADDONE) + utmp++; + + if (negslope) + utmp = -utmp; + + if (eqn & T_2NDX) /* We are calculating X steps */ + x1 = anchorval + utmp; + else /* else, Y steps */ + y1 = anchorval + utmp; + + oc1 = 0; + MIOUTCODES(oc1, x1, y1, xmin, ymin, xmax, ymax); + } + } + + *new_x1 = x1; + *new_y1 = y1; + *new_x2 = x2; + *new_y2 = y2; + + *pt1_clipped = clip1; + *pt2_clipped = clip2; + + return clipDone; +} diff --git a/xserver/mi/mizerline.c b/xserver/mi/mizerline.c new file mode 100644 index 000000000..073f1b20f --- /dev/null +++ b/xserver/mi/mizerline.c @@ -0,0 +1,378 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> + +#include "misc.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "windowstr.h" +#include "pixmap.h" +#include "mi.h" +#include "miline.h" + +/* Draw lineSolid, fillStyle-independent zero width lines. + * + * Must keep X and Y coordinates in "ints" at least until after they're + * translated and clipped to accomodate CoordModePrevious lines with very + * large coordinates. + * + * Draws the same pixels regardless of sign(dx) or sign(dy). + * + * Ken Whaley + * + */ + +/* largest positive value that can fit into a component of a point. + * Assumes that the point structure is {type x, y;} where type is + * a signed type. + */ +#define MAX_COORDINATE ((1 << (((sizeof(DDXPointRec) >> 1) << 3) - 1)) - 1) + +#define MI_OUTPUT_POINT(xx, yy)\ +{\ + if ( !new_span && yy == current_y)\ + {\ + if (xx < spans->x)\ + spans->x = xx;\ + ++*widths;\ + }\ + else\ + {\ + ++Nspans;\ + ++spans;\ + ++widths;\ + spans->x = xx;\ + spans->y = yy;\ + *widths = 1;\ + current_y = yy;\ + new_span = FALSE;\ + }\ +} + +_X_EXPORT void +miZeroLine(pDraw, pGC, mode, npt, pptInit) + DrawablePtr pDraw; + GCPtr pGC; + int mode; /* Origin or Previous */ + int npt; /* number of points */ + DDXPointPtr pptInit; +{ + int Nspans, current_y = 0; + DDXPointPtr ppt; + DDXPointPtr pspanInit, spans; + int *pwidthInit, *widths, list_len; + int xleft, ytop, xright, ybottom; + int new_x1, new_y1, new_x2, new_y2; + int x = 0, y = 0, x1, y1, x2, y2, xstart, ystart; + int oc1, oc2; + int result; + int pt1_clipped, pt2_clipped = 0; + Bool new_span; + int signdx, signdy; + int clipdx, clipdy; + int width, height; + int adx, ady; + int octant; + unsigned int bias = miGetZeroLineBias(pDraw->pScreen); + int e, e1, e2, e3; /* Bresenham error terms */ + int length; /* length of lines == # of pixels on major axis */ + + xleft = pDraw->x; + ytop = pDraw->y; + xright = pDraw->x + pDraw->width - 1; + ybottom = pDraw->y + pDraw->height - 1; + + if (!pGC->miTranslate) + { + /* do everything in drawable-relative coordinates */ + xleft = 0; + ytop = 0; + xright -= pDraw->x; + ybottom -= pDraw->y; + } + + /* it doesn't matter whether we're in drawable or screen coordinates, + * FillSpans simply cannot take starting coordinates outside of the + * range of a DDXPointRec component. + */ + if (xright > MAX_COORDINATE) + xright = MAX_COORDINATE; + if (ybottom > MAX_COORDINATE) + ybottom = MAX_COORDINATE; + + /* since we're clipping to the drawable's boundaries & coordinate + * space boundaries, we're guaranteed that the larger of width/height + * is the longest span we'll need to output + */ + width = xright - xleft + 1; + height = ybottom - ytop + 1; + list_len = (height >= width) ? height : width; + pspanInit = (DDXPointPtr)ALLOCATE_LOCAL(list_len * sizeof(DDXPointRec)); + pwidthInit = (int *)ALLOCATE_LOCAL(list_len * sizeof(int)); + if (!pspanInit || !pwidthInit) + return; + + Nspans = 0; + new_span = TRUE; + spans = pspanInit - 1; + widths = pwidthInit - 1; + ppt = pptInit; + + xstart = ppt->x; + ystart = ppt->y; + if (pGC->miTranslate) + { + xstart += pDraw->x; + ystart += pDraw->y; + } + + /* x2, y2, oc2 copied to x1, y1, oc1 at top of loop to simplify + * iteration logic + */ + x2 = xstart; + y2 = ystart; + oc2 = 0; + MIOUTCODES(oc2, x2, y2, xleft, ytop, xright, ybottom); + + while (--npt > 0) + { + if (Nspans > 0) + (*pGC->ops->FillSpans)(pDraw, pGC, Nspans, pspanInit, + pwidthInit, FALSE); + Nspans = 0; + new_span = TRUE; + spans = pspanInit - 1; + widths = pwidthInit - 1; + + x1 = x2; + y1 = y2; + oc1 = oc2; + ++ppt; + + x2 = ppt->x; + y2 = ppt->y; + if (pGC->miTranslate && (mode != CoordModePrevious)) + { + x2 += pDraw->x; + y2 += pDraw->y; + } + else if (mode == CoordModePrevious) + { + x2 += x1; + y2 += y1; + } + + oc2 = 0; + MIOUTCODES(oc2, x2, y2, xleft, ytop, xright, ybottom); + + CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, 1, 1, octant); + + if (adx > ady) + { + e1 = ady << 1; + e2 = e1 - (adx << 1); + e = e1 - adx; + length = adx; /* don't draw endpoint in main loop */ + + FIXUP_ERROR(e, octant, bias); + + new_x1 = x1; + new_y1 = y1; + new_x2 = x2; + new_y2 = y2; + pt1_clipped = 0; + pt2_clipped = 0; + + if ((oc1 | oc2) != 0) + { + result = miZeroClipLine(xleft, ytop, xright, ybottom, + &new_x1, &new_y1, &new_x2, &new_y2, + adx, ady, + &pt1_clipped, &pt2_clipped, + octant, bias, oc1, oc2); + if (result == -1) + continue; + + length = abs(new_x2 - new_x1); + + /* if we've clipped the endpoint, always draw the full length + * of the segment, because then the capstyle doesn't matter + */ + if (pt2_clipped) + length++; + + if (pt1_clipped) + { + /* must calculate new error terms */ + clipdx = abs(new_x1 - x1); + clipdy = abs(new_y1 - y1); + e += (clipdy * e2) + ((clipdx - clipdy) * e1); + } + } + + /* draw the segment */ + + x = new_x1; + y = new_y1; + + e3 = e2 - e1; + e = e - e1; + + while (length--) + { + MI_OUTPUT_POINT(x, y); + e += e1; + if (e >= 0) + { + y += signdy; + e += e3; + } + x += signdx; + } + } + else /* Y major line */ + { + e1 = adx << 1; + e2 = e1 - (ady << 1); + e = e1 - ady; + length = ady; /* don't draw endpoint in main loop */ + + SetYMajorOctant(octant); + FIXUP_ERROR(e, octant, bias); + + new_x1 = x1; + new_y1 = y1; + new_x2 = x2; + new_y2 = y2; + pt1_clipped = 0; + pt2_clipped = 0; + + if ((oc1 | oc2) != 0) + { + result = miZeroClipLine(xleft, ytop, xright, ybottom, + &new_x1, &new_y1, &new_x2, &new_y2, + adx, ady, + &pt1_clipped, &pt2_clipped, + octant, bias, oc1, oc2); + if (result == -1) + continue; + + length = abs(new_y2 - new_y1); + + /* if we've clipped the endpoint, always draw the full length + * of the segment, because then the capstyle doesn't matter + */ + if (pt2_clipped) + length++; + + if (pt1_clipped) + { + /* must calculate new error terms */ + clipdx = abs(new_x1 - x1); + clipdy = abs(new_y1 - y1); + e += (clipdx * e2) + ((clipdy - clipdx) * e1); + } + } + + /* draw the segment */ + + x = new_x1; + y = new_y1; + + e3 = e2 - e1; + e = e - e1; + + while (length--) + { + MI_OUTPUT_POINT(x, y); + e += e1; + if (e >= 0) + { + x += signdx; + e += e3; + } + y += signdy; + } + } + } + + /* only do the capnotlast check on the last segment + * and only if the endpoint wasn't clipped. And then, if the last + * point is the same as the first point, do not draw it, unless the + * line is degenerate + */ + if ( (! pt2_clipped) && (pGC->capStyle != CapNotLast) && + (((xstart != x2) || (ystart != y2)) || (ppt == pptInit + 1))) + { + MI_OUTPUT_POINT(x, y); + } + + if (Nspans > 0) + (*pGC->ops->FillSpans)(pDraw, pGC, Nspans, pspanInit, + pwidthInit, FALSE); + + DEALLOCATE_LOCAL(pwidthInit); + DEALLOCATE_LOCAL(pspanInit); +} + +_X_EXPORT void +miZeroDashLine(dst, pgc, mode, nptInit, pptInit) +DrawablePtr dst; +GCPtr pgc; +int mode; +int nptInit; /* number of points in polyline */ +DDXPointRec *pptInit; /* points in the polyline */ +{ + /* XXX kludge until real zero-width dash code is written */ + pgc->lineWidth = 1; + miWideDash (dst, pgc, mode, nptInit, pptInit); + pgc->lineWidth = 0; +} |