Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 4348 → Rev 4349

/contrib/sdk/sources/pixman/COPYING
0,0 → 1,42
The following is the MIT license, agreed upon by most contributors.
Copyright holders of new code should use this license statement where
possible. They may also add themselves to the list below.
 
/*
* Copyright 1987, 1988, 1989, 1998 The Open Group
* Copyright 1987, 1988, 1989 Digital Equipment Corporation
* Copyright 1999, 2004, 2008 Keith Packard
* Copyright 2000 SuSE, Inc.
* Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
* Copyright 2004, 2005, 2007, 2008, 2009, 2010 Red Hat, Inc.
* Copyright 2004 Nicholas Miell
* Copyright 2005 Lars Knoll & Zack Rusin, Trolltech
* Copyright 2005 Trolltech AS
* Copyright 2007 Luca Barbato
* Copyright 2008 Aaron Plattner, NVIDIA Corporation
* Copyright 2008 Rodrigo Kumpera
* Copyright 2008 André Tupinambá
* Copyright 2008 Mozilla Corporation
* Copyright 2008 Frederic Plourde
* Copyright 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright 2009, 2010 Nokia Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/contrib/sdk/sources/pixman/Makefile
0,0 → 1,86
 
LIBRARY = pixman-1
 
CC = gcc
CFLAGS = -U_Win32 -U_WIN32 -U__MINGW32__ -c -O2 -Wall -Winline -fomit-frame-pointer
 
LD = ld
LDFLAGS = -shared -s -nostdlib -T ../newlib/dll.lds --entry _DllStartup --image-base=0 --out-implib lib$(LIBRARY).dll.a
 
STRIP = $(PREFIX)strip
 
INCLUDES= -I. -I../newlib/include
 
LIBPATH:= -L../../lib
 
LIBS:= -ldll -lc.dll -lgcc
 
#DEFINES = -DHAVE_CONFIG_H -DPIXMAN_NO_TLS
DEFINES = -DHAVE_CONFIG_H
 
 
SOURCES = \
pixman.c \
pixman-access.c \
pixman-access-accessors.c \
pixman-bits-image.c \
pixman-combine32.c \
pixman-combine-float.c \
pixman-conical-gradient.c \
pixman-edge.c \
pixman-edge-accessors.c \
pixman-fast-path.c \
pixman-filter.c \
pixman-general.c \
pixman-glyph.c \
pixman-gradient-walker.c \
pixman-image.c \
pixman-implementation.c \
pixman-linear-gradient.c \
pixman-matrix.c \
pixman-noop.c \
pixman-radial-gradient.c \
pixman-region16.c \
pixman-region32.c \
pixman-solid-fill.c \
pixman-timer.c \
pixman-trap.c \
pixman-utils.c \
pixman-x86.c \
pixman-mmx.c \
pixman-sse2.c \
$(NULL)
OBJECTS = $(patsubst %.c, %.o, $(SOURCES))
 
# targets
 
all:$(LIBRARY).a $(LIBRARY).dll
 
 
$(LIBRARY).a: $(OBJECTS) Makefile
ar cvrs $(LIBRARY).a $(OBJECTS)
mv -f $(LIBRARY).a ../../static
 
$(LIBRARY).dll: $(LIBRARY).def $(OBJECTS) Makefile
$(LD) $(LDFLAGS) $(LIBPATH) -o $@ $(LIBRARY).def $(OBJECTS) $(LIBS)
$(STRIP) $@
sed -f ../newlib/cmd1.sed $(LIBRARY).def > mem
sed -f ../newlib/cmd2.sed mem >$(LIBRARY).inc
mv -f $@ ../../bin
mv -f lib$(LIBRARY).dll.a ../../lib
 
%.o : %.c Makefile
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o $@ $<
 
pixman-mmx.o: pixman-mmx.c Makefile
$(CC) $(CFLAGS) -mmmx $(DEFINES) $(INCLUDES) -o $@ $<
 
pixman-sse2.o: pixman-sse2.c Makefile
$(CC) $(CFLAGS) -msse2 $(DEFINES) $(INCLUDES) -o $@ $<
 
 
clean:
-rm -f *.o
/contrib/sdk/sources/pixman/Makefile.ebox
0,0 → 1,86
 
LIBRARY = pixman-1
 
CC = gcc
CFLAGS = -U_Win32 -U_WIN32 -U__MINGW32__ -c -O2 -march=pentium-mmx -Wall -Winline -fomit-frame-pointer
 
LD = ld
LDFLAGS = -shared -s -nostdlib -T ../newlib/dll.lds --entry _DllStartup --image-base=0 --out-implib lib$(LIBRARY).dll.a
 
STRIP = $(PREFIX)strip
 
INCLUDES= -I. -I../newlib/include
 
LIBPATH:= -L../../import -L../../static
 
LIBS:= -ldll -lc.dll -lgcc
 
#DEFINES = -DHAVE_CONFIG_H -DPIXMAN_NO_TLS
DEFINES = -DHAVE_CONFIG_H
 
 
SOURCES = \
pixman.c \
pixman-access.c \
pixman-access-accessors.c \
pixman-bits-image.c \
pixman-combine32.c \
pixman-combine-float.c \
pixman-conical-gradient.c \
pixman-edge.c \
pixman-edge-accessors.c \
pixman-fast-path.c \
pixman-filter.c \
pixman-general.c \
pixman-glyph.c \
pixman-gradient-walker.c \
pixman-image.c \
pixman-implementation.c \
pixman-linear-gradient.c \
pixman-matrix.c \
pixman-noop.c \
pixman-radial-gradient.c \
pixman-region16.c \
pixman-region32.c \
pixman-solid-fill.c \
pixman-timer.c \
pixman-trap.c \
pixman-utils.c \
pixman-x86.c \
pixman-mmx.c \
pixman-sse2.c \
$(NULL)
OBJECTS = $(patsubst %.c, %.o, $(SOURCES))
 
# targets
 
all:$(LIBRARY).a $(LIBRARY).dll
 
 
$(LIBRARY).a: $(OBJECTS) Makefile
ar cvrs $(LIBRARY).a $(OBJECTS)
mv -f $(LIBRARY).a ../../static
 
$(LIBRARY).dll: $(LIBRARY).def $(OBJECTS) Makefile
$(LD) $(LDFLAGS) $(LIBPATH) -o $@ $(LIBRARY).def $(OBJECTS) $(LIBS)
$(STRIP) $@
sed -f ../newlib/cmd1.sed $(LIBRARY).def > mem
sed -f ../newlib/cmd2.sed mem >$(LIBRARY).inc
mv -f $@ ../../lib
mv -f lib$(LIBRARY).dll.a ../../import
 
%.o : %.c Makefile
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o $@ $<
 
pixman-mmx.o: pixman-mmx.c Makefile
$(CC) $(CFLAGS) -mmmx $(DEFINES) $(INCLUDES) -o $@ $<
 
pixman-sse2.o: pixman-sse2.c Makefile
$(CC) $(CFLAGS) -msse2 $(DEFINES) $(INCLUDES) -o $@ $<
 
 
clean:
-rm -f *.o
/contrib/sdk/sources/pixman/README
0,0 → 1,116
Pixman is a library that provides low-level pixel manipulation
features such as image compositing and trapezoid rasterization.
 
Questions, bug reports and patches should be directed to the pixman
mailing list:
 
http://lists.freedesktop.org/mailman/listinfo/pixman
 
You can also file bugs at
 
https://bugs.freedesktop.org/enter_bug.cgi?product=pixman
 
For real time discussions about pixman, feel free to join the IRC
channels #cairo and #xorg-devel on the FreeNode IRC network.
 
 
Contributing
------------
 
In order to contribute to pixman, you will need a working knowledge of
the git version control system. For a quick getting started guide,
there is the "Everyday Git With 20 Commands Or So guide"
 
http://www.kernel.org/pub/software/scm/git/docs/everyday.html
 
from the Git homepage. For more in depth git documentation, see the
resources on the Git community documentation page:
 
http://git-scm.com/documentation
 
Pixman uses the infrastructure from the freedesktop.org umbrella
project. For instructions about how to use the git service on
freedesktop.org, see:
 
http://www.freedesktop.org/wiki/Infrastructure/git/Developers
 
The Pixman master repository can be found at:
 
git://anongit.freedesktop.org/git/pixman
 
and browsed on the web here:
 
http://cgit.freedesktop.org/pixman/
 
 
Sending patches
---------------
 
The general workflow for sending patches is to first make sure that
git can send mail on your system. Then,
 
- create a branch off of master in your local git repository
 
- make your changes as one or more commits
 
- use the
 
git send-email
 
command to send the patch series to pixman@lists.freedesktop.org.
 
In order for your patches to be accepted, please consider the
following guidelines:
 
- This link:
 
http://www.kernel.org/pub/software/scm/git/docs/user-manual.html#patch-series
 
describes how what a good patch series is, and to create one with
git.
 
- At each point in the series, pixman should compile and the test
suite should pass.
 
The exception here is if you are changing the test suite to
demonstrate a bug. In this case, make one commit that makes the
test suite fail due to the bug, and then another commit that fixes
the bug.
 
You can run the test suite with
 
make check
 
It will take around two minutes to run on a modern PC.
 
- Follow the coding style described in the CODING_STYLE file
 
- For bug fixes, include an update to the test suite to make sure
the bug doesn't reappear.
 
- For new features, add tests of the feature to the test
suite. Also, add a program demonstrating the new feature to the
demos/ directory.
 
- Write descriptive commit messages. Useful information to include:
- Benchmark results, before and after
- Description of the bug that was fixed
- Detailed rationale for any new API
- Alternative approaches that were rejected (and why they
don't work)
- If review comments were incorporated, a brief version
history describing what those changes were.
 
- For big patch series, send an introductory email with an overall
description of the patch series, including benchmarks and
motivation. Each commit message should still be descriptive and
include enough information to understand why this particular commit
was necessary.
 
Pixman has high standards for code quality and so almost everybody
should expect to have the first versions of their patches rejected.
 
If you think that the reviewers are wrong about something, or that the
guidelines above are wrong, feel free to discuss the issue on the
list. The purpose of the guidelines and code review is to ensure high
code quality; it is not an exercise in compliance.
/contrib/sdk/sources/pixman/config.h
0,0 → 1,174
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
 
/* Define if building universal (internal helper macro) */
/* #undef AC_APPLE_UNIVERSAL_BUILD */
 
/* Whether we have alarm() */
/* #undef HAVE_ALARM */
 
/* Define to 1 if you have the <dlfcn.h> header file. */
/* #undef HAVE_DLFCN_H */
 
/* Whether we have feenableexcept() */
/* #undef HAVE_FEENABLEEXCEPT */
 
/* Define to 1 if we have <fenv.h> */
#define HAVE_FENV_H 1
 
/* Whether the tool chain supports __float128 */
#define HAVE_FLOAT128 /**/
 
/* Define to 1 if you have the `getisax' function. */
/* #undef HAVE_GETISAX */
 
/* Whether we have getpagesize() */
#define HAVE_GETPAGESIZE 1
 
/* Whether we have gettimeofday() */
#define HAVE_GETTIMEOFDAY 1
 
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
 
/* Define to 1 if you have the `pixman-1' library (-lpixman-1). */
/* #undef HAVE_LIBPIXMAN_1 */
 
/* Whether we have libpng */
#define HAVE_LIBPNG 1
 
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
 
/* Whether we have mmap() */
#define HAVE_MMAP
 
/* Whether we have mprotect() */
#define HAVE_MPROTECT 1
 
/* Whether we have posix_memalign() */
/* #undef HAVE_POSIX_MEMALIGN */
 
/* Whether pthread_setspecific() is supported */
/* #undef HAVE_PTHREAD_SETSPECIFIC */
 
/* Whether we have sigaction() */
/* #undef HAVE_SIGACTION */
 
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
 
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
 
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
 
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
 
/* Define to 1 if we have <sys/mman.h> */
/* #undef HAVE_SYS_MMAN_H */
 
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
 
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
 
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
 
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
 
/* Name of package */
#define PACKAGE "pixman"
 
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "pixman@lists.freedesktop.org"
 
/* Define to the full name of this package. */
#define PACKAGE_NAME "pixman"
 
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "pixman 0.30.2"
 
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "pixman"
 
/* Define to the home page for this package. */
#define PACKAGE_URL ""
 
/* Define to the version of this package. */
#define PACKAGE_VERSION "0.30.2"
 
/* enable TIMER_BEGIN/TIMER_END macros */
/* #undef PIXMAN_TIMERS */
 
/* The size of `long', as computed by sizeof. */
#define SIZEOF_LONG 4
 
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
 
/* The compiler supported TLS storage class */
#define TLS __thread
 
/* Whether the tool chain supports __attribute__((constructor)) */
//#define TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR /**/
 
/* use ARM IWMMXT compiler intrinsics */
/* #undef USE_ARM_IWMMXT */
 
/* use ARM NEON assembly optimizations */
/* #undef USE_ARM_NEON */
 
/* use ARM SIMD assembly optimizations */
/* #undef USE_ARM_SIMD */
 
/* use GNU-style inline assembler */
#define USE_GCC_INLINE_ASM 1
 
/* use Loongson Multimedia Instructions */
/* #undef USE_LOONGSON_MMI */
 
/* use MIPS DSPr2 assembly optimizations */
/* #undef USE_MIPS_DSPR2 */
 
/* use OpenMP in the test suite */
/* #undef USE_OPENMP */
 
/* use SSE2 compiler intrinsics */
#define USE_SSE2 1
 
/* use VMX compiler intrinsics */
/* #undef USE_VMX */
 
/* use x86 MMX compiler intrinsics */
#define USE_X86_MMX 1
 
/* Version number of package */
#define VERSION "0.30.2"
 
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
/* # undef WORDS_BIGENDIAN */
# endif
#endif
 
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
/* #undef inline */
#endif
 
/* Define to sqrt if you do not have the `sqrtf' function. */
/* #undef sqrtf */
/contrib/sdk/sources/pixman/mem
0,0 → 1,148
EXPORTS,'EXPORTS',\
_pixman_internal_only_get_implementation,'_pixman_internal_only_get_implementation',\
pixman_add_trapezoids,'pixman_add_trapezoids',\
pixman_add_traps,'pixman_add_traps',\
pixman_add_triangles,'pixman_add_triangles',\
pixman_blt,'pixman_blt',\
pixman_composite_glyphs,'pixman_composite_glyphs',\
pixman_composite_glyphs_no_mask,'pixman_composite_glyphs_no_mask',\
pixman_composite_trapezoids,'pixman_composite_trapezoids',\
pixman_composite_triangles,'pixman_composite_triangles',\
pixman_compute_composite_region,'pixman_compute_composite_region',\
pixman_disable_out_of_bounds_workaround,'pixman_disable_out_of_bounds_workaround',\
pixman_edge_init,'pixman_edge_init',\
pixman_edge_step,'pixman_edge_step',\
pixman_f_transform_bounds,'pixman_f_transform_bounds',\
pixman_f_transform_from_pixman_transform,'pixman_f_transform_from_pixman_transform',\
pixman_f_transform_init_identity,'pixman_f_transform_init_identity',\
pixman_f_transform_init_rotate,'pixman_f_transform_init_rotate',\
pixman_f_transform_init_scale,'pixman_f_transform_init_scale',\
pixman_f_transform_init_translate,'pixman_f_transform_init_translate',\
pixman_f_transform_invert,'pixman_f_transform_invert',\
pixman_f_transform_multiply,'pixman_f_transform_multiply',\
pixman_f_transform_point,'pixman_f_transform_point',\
pixman_f_transform_point_3d,'pixman_f_transform_point_3d',\
pixman_f_transform_rotate,'pixman_f_transform_rotate',\
pixman_f_transform_scale,'pixman_f_transform_scale',\
pixman_f_transform_translate,'pixman_f_transform_translate',\
pixman_fill,'pixman_fill',\
pixman_filter_create_separable_convolution,'pixman_filter_create_separable_convolution',\
pixman_format_supported_destination,'pixman_format_supported_destination',\
pixman_format_supported_source,'pixman_format_supported_source',\
pixman_glyph_cache_create,'pixman_glyph_cache_create',\
pixman_glyph_cache_destroy,'pixman_glyph_cache_destroy',\
pixman_glyph_cache_freeze,'pixman_glyph_cache_freeze',\
pixman_glyph_cache_insert,'pixman_glyph_cache_insert',\
pixman_glyph_cache_lookup,'pixman_glyph_cache_lookup',\
pixman_glyph_cache_remove,'pixman_glyph_cache_remove',\
pixman_glyph_cache_thaw,'pixman_glyph_cache_thaw',\
pixman_glyph_get_extents,'pixman_glyph_get_extents',\
pixman_glyph_get_mask_format,'pixman_glyph_get_mask_format',\
pixman_image_composite,'pixman_image_composite',\
pixman_image_composite32,'pixman_image_composite32',\
pixman_image_create_bits,'pixman_image_create_bits',\
pixman_image_create_bits_no_clear,'pixman_image_create_bits_no_clear',\
pixman_image_create_conical_gradient,'pixman_image_create_conical_gradient',\
pixman_image_create_linear_gradient,'pixman_image_create_linear_gradient',\
pixman_image_create_radial_gradient,'pixman_image_create_radial_gradient',\
pixman_image_create_solid_fill,'pixman_image_create_solid_fill',\
pixman_image_fill_boxes,'pixman_image_fill_boxes',\
pixman_image_fill_rectangles,'pixman_image_fill_rectangles',\
pixman_image_get_component_alpha,'pixman_image_get_component_alpha',\
pixman_image_get_data,'pixman_image_get_data',\
pixman_image_get_depth,'pixman_image_get_depth',\
pixman_image_get_destroy_data,'pixman_image_get_destroy_data',\
pixman_image_get_format,'pixman_image_get_format',\
pixman_image_get_height,'pixman_image_get_height',\
pixman_image_get_stride,'pixman_image_get_stride',\
pixman_image_get_width,'pixman_image_get_width',\
pixman_image_ref,'pixman_image_ref',\
pixman_image_set_accessors,'pixman_image_set_accessors',\
pixman_image_set_alpha_map,'pixman_image_set_alpha_map',\
pixman_image_set_clip_region,'pixman_image_set_clip_region',\
pixman_image_set_clip_region32,'pixman_image_set_clip_region32',\
pixman_image_set_component_alpha,'pixman_image_set_component_alpha',\
pixman_image_set_destroy_function,'pixman_image_set_destroy_function',\
pixman_image_set_filter,'pixman_image_set_filter',\
pixman_image_set_has_client_clip,'pixman_image_set_has_client_clip',\
pixman_image_set_indexed,'pixman_image_set_indexed',\
pixman_image_set_repeat,'pixman_image_set_repeat',\
pixman_image_set_source_clipping,'pixman_image_set_source_clipping',\
pixman_image_set_transform,'pixman_image_set_transform',\
pixman_image_unref,'pixman_image_unref',\
pixman_line_fixed_edge_init,'pixman_line_fixed_edge_init',\
pixman_rasterize_edges,'pixman_rasterize_edges',\
pixman_rasterize_trapezoid,'pixman_rasterize_trapezoid',\
pixman_region32_clear,'pixman_region32_clear',\
pixman_region32_contains_point,'pixman_region32_contains_point',\
pixman_region32_contains_rectangle,'pixman_region32_contains_rectangle',\
pixman_region32_copy,'pixman_region32_copy',\
pixman_region32_equal,'pixman_region32_equal',\
pixman_region32_extents,'pixman_region32_extents',\
pixman_region32_fini,'pixman_region32_fini',\
pixman_region32_init,'pixman_region32_init',\
pixman_region32_init_from_image,'pixman_region32_init_from_image',\
pixman_region32_init_rect,'pixman_region32_init_rect',\
pixman_region32_init_rects,'pixman_region32_init_rects',\
pixman_region32_init_with_extents,'pixman_region32_init_with_extents',\
pixman_region32_intersect,'pixman_region32_intersect',\
pixman_region32_intersect_rect,'pixman_region32_intersect_rect',\
pixman_region32_inverse,'pixman_region32_inverse',\
pixman_region32_n_rects,'pixman_region32_n_rects',\
pixman_region32_not_empty,'pixman_region32_not_empty',\
pixman_region32_rectangles,'pixman_region32_rectangles',\
pixman_region32_reset,'pixman_region32_reset',\
pixman_region32_selfcheck,'pixman_region32_selfcheck',\
pixman_region32_subtract,'pixman_region32_subtract',\
pixman_region32_translate,'pixman_region32_translate',\
pixman_region32_union,'pixman_region32_union',\
pixman_region32_union_rect,'pixman_region32_union_rect',\
pixman_region_clear,'pixman_region_clear',\
pixman_region_contains_point,'pixman_region_contains_point',\
pixman_region_contains_rectangle,'pixman_region_contains_rectangle',\
pixman_region_copy,'pixman_region_copy',\
pixman_region_equal,'pixman_region_equal',\
pixman_region_extents,'pixman_region_extents',\
pixman_region_fini,'pixman_region_fini',\
pixman_region_init,'pixman_region_init',\
pixman_region_init_from_image,'pixman_region_init_from_image',\
pixman_region_init_rect,'pixman_region_init_rect',\
pixman_region_init_rects,'pixman_region_init_rects',\
pixman_region_init_with_extents,'pixman_region_init_with_extents',\
pixman_region_intersect,'pixman_region_intersect',\
pixman_region_intersect_rect,'pixman_region_intersect_rect',\
pixman_region_inverse,'pixman_region_inverse',\
pixman_region_n_rects,'pixman_region_n_rects',\
pixman_region_not_empty,'pixman_region_not_empty',\
pixman_region_rectangles,'pixman_region_rectangles',\
pixman_region_reset,'pixman_region_reset',\
pixman_region_selfcheck,'pixman_region_selfcheck',\
pixman_region_set_static_pointers,'pixman_region_set_static_pointers',\
pixman_region_subtract,'pixman_region_subtract',\
pixman_region_translate,'pixman_region_translate',\
pixman_region_union,'pixman_region_union',\
pixman_region_union_rect,'pixman_region_union_rect',\
pixman_sample_ceil_y,'pixman_sample_ceil_y',\
pixman_sample_floor_y,'pixman_sample_floor_y',\
pixman_transform_bounds,'pixman_transform_bounds',\
pixman_transform_from_pixman_f_transform,'pixman_transform_from_pixman_f_transform',\
pixman_transform_init_identity,'pixman_transform_init_identity',\
pixman_transform_init_rotate,'pixman_transform_init_rotate',\
pixman_transform_init_scale,'pixman_transform_init_scale',\
pixman_transform_init_translate,'pixman_transform_init_translate',\
pixman_transform_invert,'pixman_transform_invert',\
pixman_transform_is_identity,'pixman_transform_is_identity',\
pixman_transform_is_int_translate,'pixman_transform_is_int_translate',\
pixman_transform_is_inverse,'pixman_transform_is_inverse',\
pixman_transform_is_scale,'pixman_transform_is_scale',\
pixman_transform_multiply,'pixman_transform_multiply',\
pixman_transform_point,'pixman_transform_point',\
pixman_transform_point_31_16,'pixman_transform_point_31_16',\
pixman_transform_point_31_16_3d,'pixman_transform_point_31_16_3d',\
pixman_transform_point_31_16_affine,'pixman_transform_point_31_16_affine',\
pixman_transform_point_3d,'pixman_transform_point_3d',\
pixman_transform_rotate,'pixman_transform_rotate',\
pixman_transform_scale,'pixman_transform_scale',\
pixman_transform_translate,'pixman_transform_translate',\
pixman_version,'pixman_version',\
pixman_version_string,'pixman_version_string',\
/contrib/sdk/sources/pixman/pixman-1.def
0,0 → 1,148
EXPORTS
_pixman_internal_only_get_implementation
pixman_add_trapezoids
pixman_add_traps
pixman_add_triangles
pixman_blt
pixman_composite_glyphs
pixman_composite_glyphs_no_mask
pixman_composite_trapezoids
pixman_composite_triangles
pixman_compute_composite_region
pixman_disable_out_of_bounds_workaround
pixman_edge_init
pixman_edge_step
pixman_f_transform_bounds
pixman_f_transform_from_pixman_transform
pixman_f_transform_init_identity
pixman_f_transform_init_rotate
pixman_f_transform_init_scale
pixman_f_transform_init_translate
pixman_f_transform_invert
pixman_f_transform_multiply
pixman_f_transform_point
pixman_f_transform_point_3d
pixman_f_transform_rotate
pixman_f_transform_scale
pixman_f_transform_translate
pixman_fill
pixman_filter_create_separable_convolution
pixman_format_supported_destination
pixman_format_supported_source
pixman_glyph_cache_create
pixman_glyph_cache_destroy
pixman_glyph_cache_freeze
pixman_glyph_cache_insert
pixman_glyph_cache_lookup
pixman_glyph_cache_remove
pixman_glyph_cache_thaw
pixman_glyph_get_extents
pixman_glyph_get_mask_format
pixman_image_composite
pixman_image_composite32
pixman_image_create_bits
pixman_image_create_bits_no_clear
pixman_image_create_conical_gradient
pixman_image_create_linear_gradient
pixman_image_create_radial_gradient
pixman_image_create_solid_fill
pixman_image_fill_boxes
pixman_image_fill_rectangles
pixman_image_get_component_alpha
pixman_image_get_data
pixman_image_get_depth
pixman_image_get_destroy_data
pixman_image_get_format
pixman_image_get_height
pixman_image_get_stride
pixman_image_get_width
pixman_image_ref
pixman_image_set_accessors
pixman_image_set_alpha_map
pixman_image_set_clip_region
pixman_image_set_clip_region32
pixman_image_set_component_alpha
pixman_image_set_destroy_function
pixman_image_set_filter
pixman_image_set_has_client_clip
pixman_image_set_indexed
pixman_image_set_repeat
pixman_image_set_source_clipping
pixman_image_set_transform
pixman_image_unref
pixman_line_fixed_edge_init
pixman_rasterize_edges
pixman_rasterize_trapezoid
pixman_region32_clear
pixman_region32_contains_point
pixman_region32_contains_rectangle
pixman_region32_copy
pixman_region32_equal
pixman_region32_extents
pixman_region32_fini
pixman_region32_init
pixman_region32_init_from_image
pixman_region32_init_rect
pixman_region32_init_rects
pixman_region32_init_with_extents
pixman_region32_intersect
pixman_region32_intersect_rect
pixman_region32_inverse
pixman_region32_n_rects
pixman_region32_not_empty
pixman_region32_rectangles
pixman_region32_reset
pixman_region32_selfcheck
pixman_region32_subtract
pixman_region32_translate
pixman_region32_union
pixman_region32_union_rect
pixman_region_clear
pixman_region_contains_point
pixman_region_contains_rectangle
pixman_region_copy
pixman_region_equal
pixman_region_extents
pixman_region_fini
pixman_region_init
pixman_region_init_from_image
pixman_region_init_rect
pixman_region_init_rects
pixman_region_init_with_extents
pixman_region_intersect
pixman_region_intersect_rect
pixman_region_inverse
pixman_region_n_rects
pixman_region_not_empty
pixman_region_rectangles
pixman_region_reset
pixman_region_selfcheck
pixman_region_set_static_pointers
pixman_region_subtract
pixman_region_translate
pixman_region_union
pixman_region_union_rect
pixman_sample_ceil_y
pixman_sample_floor_y
pixman_transform_bounds
pixman_transform_from_pixman_f_transform
pixman_transform_init_identity
pixman_transform_init_rotate
pixman_transform_init_scale
pixman_transform_init_translate
pixman_transform_invert
pixman_transform_is_identity
pixman_transform_is_int_translate
pixman_transform_is_inverse
pixman_transform_is_scale
pixman_transform_multiply
pixman_transform_point
pixman_transform_point_31_16
pixman_transform_point_31_16_3d
pixman_transform_point_31_16_affine
pixman_transform_point_3d
pixman_transform_rotate
pixman_transform_scale
pixman_transform_translate
pixman_version
pixman_version_string
/contrib/sdk/sources/pixman/pixman-1.inc
0,0 → 1,148
EXPORTS,'EXPORTS',\
_pixman_internal_only_get_implementation,'_pixman_internal_only_get_implementation',\
pixman_add_trapezoids,'pixman_add_trapezoids',\
pixman_add_traps,'pixman_add_traps',\
pixman_add_triangles,'pixman_add_triangles',\
pixman_blt,'pixman_blt',\
pixman_composite_glyphs,'pixman_composite_glyphs',\
pixman_composite_glyphs_no_mask,'pixman_composite_glyphs_no_mask',\
pixman_composite_trapezoids,'pixman_composite_trapezoids',\
pixman_composite_triangles,'pixman_composite_triangles',\
pixman_compute_composite_region,'pixman_compute_composite_region',\
pixman_disable_out_of_bounds_workaround,'pixman_disable_out_of_bounds_workaround',\
pixman_edge_init,'pixman_edge_init',\
pixman_edge_step,'pixman_edge_step',\
pixman_f_transform_bounds,'pixman_f_transform_bounds',\
pixman_f_transform_from_pixman_transform,'pixman_f_transform_from_pixman_transform',\
pixman_f_transform_init_identity,'pixman_f_transform_init_identity',\
pixman_f_transform_init_rotate,'pixman_f_transform_init_rotate',\
pixman_f_transform_init_scale,'pixman_f_transform_init_scale',\
pixman_f_transform_init_translate,'pixman_f_transform_init_translate',\
pixman_f_transform_invert,'pixman_f_transform_invert',\
pixman_f_transform_multiply,'pixman_f_transform_multiply',\
pixman_f_transform_point,'pixman_f_transform_point',\
pixman_f_transform_point_3d,'pixman_f_transform_point_3d',\
pixman_f_transform_rotate,'pixman_f_transform_rotate',\
pixman_f_transform_scale,'pixman_f_transform_scale',\
pixman_f_transform_translate,'pixman_f_transform_translate',\
pixman_fill,'pixman_fill',\
pixman_filter_create_separable_convolution,'pixman_filter_create_separable_convolution',\
pixman_format_supported_destination,'pixman_format_supported_destination',\
pixman_format_supported_source,'pixman_format_supported_source',\
pixman_glyph_cache_create,'pixman_glyph_cache_create',\
pixman_glyph_cache_destroy,'pixman_glyph_cache_destroy',\
pixman_glyph_cache_freeze,'pixman_glyph_cache_freeze',\
pixman_glyph_cache_insert,'pixman_glyph_cache_insert',\
pixman_glyph_cache_lookup,'pixman_glyph_cache_lookup',\
pixman_glyph_cache_remove,'pixman_glyph_cache_remove',\
pixman_glyph_cache_thaw,'pixman_glyph_cache_thaw',\
pixman_glyph_get_extents,'pixman_glyph_get_extents',\
pixman_glyph_get_mask_format,'pixman_glyph_get_mask_format',\
pixman_image_composite,'pixman_image_composite',\
pixman_image_composite32,'pixman_image_composite32',\
pixman_image_create_bits,'pixman_image_create_bits',\
pixman_image_create_bits_no_clear,'pixman_image_create_bits_no_clear',\
pixman_image_create_conical_gradient,'pixman_image_create_conical_gradient',\
pixman_image_create_linear_gradient,'pixman_image_create_linear_gradient',\
pixman_image_create_radial_gradient,'pixman_image_create_radial_gradient',\
pixman_image_create_solid_fill,'pixman_image_create_solid_fill',\
pixman_image_fill_boxes,'pixman_image_fill_boxes',\
pixman_image_fill_rectangles,'pixman_image_fill_rectangles',\
pixman_image_get_component_alpha,'pixman_image_get_component_alpha',\
pixman_image_get_data,'pixman_image_get_data',\
pixman_image_get_depth,'pixman_image_get_depth',\
pixman_image_get_destroy_data,'pixman_image_get_destroy_data',\
pixman_image_get_format,'pixman_image_get_format',\
pixman_image_get_height,'pixman_image_get_height',\
pixman_image_get_stride,'pixman_image_get_stride',\
pixman_image_get_width,'pixman_image_get_width',\
pixman_image_ref,'pixman_image_ref',\
pixman_image_set_accessors,'pixman_image_set_accessors',\
pixman_image_set_alpha_map,'pixman_image_set_alpha_map',\
pixman_image_set_clip_region,'pixman_image_set_clip_region',\
pixman_image_set_clip_region32,'pixman_image_set_clip_region32',\
pixman_image_set_component_alpha,'pixman_image_set_component_alpha',\
pixman_image_set_destroy_function,'pixman_image_set_destroy_function',\
pixman_image_set_filter,'pixman_image_set_filter',\
pixman_image_set_has_client_clip,'pixman_image_set_has_client_clip',\
pixman_image_set_indexed,'pixman_image_set_indexed',\
pixman_image_set_repeat,'pixman_image_set_repeat',\
pixman_image_set_source_clipping,'pixman_image_set_source_clipping',\
pixman_image_set_transform,'pixman_image_set_transform',\
pixman_image_unref,'pixman_image_unref',\
pixman_line_fixed_edge_init,'pixman_line_fixed_edge_init',\
pixman_rasterize_edges,'pixman_rasterize_edges',\
pixman_rasterize_trapezoid,'pixman_rasterize_trapezoid',\
pixman_region32_clear,'pixman_region32_clear',\
pixman_region32_contains_point,'pixman_region32_contains_point',\
pixman_region32_contains_rectangle,'pixman_region32_contains_rectangle',\
pixman_region32_copy,'pixman_region32_copy',\
pixman_region32_equal,'pixman_region32_equal',\
pixman_region32_extents,'pixman_region32_extents',\
pixman_region32_fini,'pixman_region32_fini',\
pixman_region32_init,'pixman_region32_init',\
pixman_region32_init_from_image,'pixman_region32_init_from_image',\
pixman_region32_init_rect,'pixman_region32_init_rect',\
pixman_region32_init_rects,'pixman_region32_init_rects',\
pixman_region32_init_with_extents,'pixman_region32_init_with_extents',\
pixman_region32_intersect,'pixman_region32_intersect',\
pixman_region32_intersect_rect,'pixman_region32_intersect_rect',\
pixman_region32_inverse,'pixman_region32_inverse',\
pixman_region32_n_rects,'pixman_region32_n_rects',\
pixman_region32_not_empty,'pixman_region32_not_empty',\
pixman_region32_rectangles,'pixman_region32_rectangles',\
pixman_region32_reset,'pixman_region32_reset',\
pixman_region32_selfcheck,'pixman_region32_selfcheck',\
pixman_region32_subtract,'pixman_region32_subtract',\
pixman_region32_translate,'pixman_region32_translate',\
pixman_region32_union,'pixman_region32_union',\
pixman_region32_union_rect,'pixman_region32_union_rect',\
pixman_region_clear,'pixman_region_clear',\
pixman_region_contains_point,'pixman_region_contains_point',\
pixman_region_contains_rectangle,'pixman_region_contains_rectangle',\
pixman_region_copy,'pixman_region_copy',\
pixman_region_equal,'pixman_region_equal',\
pixman_region_extents,'pixman_region_extents',\
pixman_region_fini,'pixman_region_fini',\
pixman_region_init,'pixman_region_init',\
pixman_region_init_from_image,'pixman_region_init_from_image',\
pixman_region_init_rect,'pixman_region_init_rect',\
pixman_region_init_rects,'pixman_region_init_rects',\
pixman_region_init_with_extents,'pixman_region_init_with_extents',\
pixman_region_intersect,'pixman_region_intersect',\
pixman_region_intersect_rect,'pixman_region_intersect_rect',\
pixman_region_inverse,'pixman_region_inverse',\
pixman_region_n_rects,'pixman_region_n_rects',\
pixman_region_not_empty,'pixman_region_not_empty',\
pixman_region_rectangles,'pixman_region_rectangles',\
pixman_region_reset,'pixman_region_reset',\
pixman_region_selfcheck,'pixman_region_selfcheck',\
pixman_region_set_static_pointers,'pixman_region_set_static_pointers',\
pixman_region_subtract,'pixman_region_subtract',\
pixman_region_translate,'pixman_region_translate',\
pixman_region_union,'pixman_region_union',\
pixman_region_union_rect,'pixman_region_union_rect',\
pixman_sample_ceil_y,'pixman_sample_ceil_y',\
pixman_sample_floor_y,'pixman_sample_floor_y',\
pixman_transform_bounds,'pixman_transform_bounds',\
pixman_transform_from_pixman_f_transform,'pixman_transform_from_pixman_f_transform',\
pixman_transform_init_identity,'pixman_transform_init_identity',\
pixman_transform_init_rotate,'pixman_transform_init_rotate',\
pixman_transform_init_scale,'pixman_transform_init_scale',\
pixman_transform_init_translate,'pixman_transform_init_translate',\
pixman_transform_invert,'pixman_transform_invert',\
pixman_transform_is_identity,'pixman_transform_is_identity',\
pixman_transform_is_int_translate,'pixman_transform_is_int_translate',\
pixman_transform_is_inverse,'pixman_transform_is_inverse',\
pixman_transform_is_scale,'pixman_transform_is_scale',\
pixman_transform_multiply,'pixman_transform_multiply',\
pixman_transform_point,'pixman_transform_point',\
pixman_transform_point_31_16,'pixman_transform_point_31_16',\
pixman_transform_point_31_16_3d,'pixman_transform_point_31_16_3d',\
pixman_transform_point_31_16_affine,'pixman_transform_point_31_16_affine',\
pixman_transform_point_3d,'pixman_transform_point_3d',\
pixman_transform_rotate,'pixman_transform_rotate',\
pixman_transform_scale,'pixman_transform_scale',\
pixman_transform_translate,'pixman_transform_translate',\
pixman_version,'pixman_version',\
pixman_version_string,'pixman_version_string',\
/contrib/sdk/sources/pixman/pixman-access-accessors.c
0,0 → 1,3
#define PIXMAN_FB_ACCESSORS
 
#include "pixman-access.c"
/contrib/sdk/sources/pixman/pixman-access.c
0,0 → 1,1433
/*
*
* Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
* 2005 Lars Knoll & Zack Rusin, Trolltech
* 2008 Aaron Plattner, NVIDIA Corporation
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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_CONFIG_H
#include <config.h>
#endif
 
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
 
#include "pixman-accessor.h"
#include "pixman-private.h"
 
#define CONVERT_RGB24_TO_Y15(s) \
(((((s) >> 16) & 0xff) * 153 + \
(((s) >> 8) & 0xff) * 301 + \
(((s) ) & 0xff) * 58) >> 2)
 
#define CONVERT_RGB24_TO_RGB15(s) \
((((s) >> 3) & 0x001f) | \
(((s) >> 6) & 0x03e0) | \
(((s) >> 9) & 0x7c00))
 
/* Fetch macros */
 
#ifdef WORDS_BIGENDIAN
#define FETCH_1(img,l,o) \
(((READ ((img), ((uint32_t *)(l)) + ((o) >> 5))) >> (0x1f - ((o) & 0x1f))) & 0x1)
#else
#define FETCH_1(img,l,o) \
((((READ ((img), ((uint32_t *)(l)) + ((o) >> 5))) >> ((o) & 0x1f))) & 0x1)
#endif
 
#define FETCH_8(img,l,o) (READ (img, (((uint8_t *)(l)) + ((o) >> 3))))
 
#ifdef WORDS_BIGENDIAN
#define FETCH_4(img,l,o) \
(((4 * (o)) & 4) ? (FETCH_8 (img,l, 4 * (o)) & 0xf) : (FETCH_8 (img,l,(4 * (o))) >> 4))
#else
#define FETCH_4(img,l,o) \
(((4 * (o)) & 4) ? (FETCH_8 (img, l, 4 * (o)) >> 4) : (FETCH_8 (img, l, (4 * (o))) & 0xf))
#endif
 
#ifdef WORDS_BIGENDIAN
#define FETCH_24(img,l,o) \
((READ (img, (((uint8_t *)(l)) + ((o) * 3) + 0)) << 16) | \
(READ (img, (((uint8_t *)(l)) + ((o) * 3) + 1)) << 8) | \
(READ (img, (((uint8_t *)(l)) + ((o) * 3) + 2)) << 0))
#else
#define FETCH_24(img,l,o) \
((READ (img, (((uint8_t *)(l)) + ((o) * 3) + 0)) << 0) | \
(READ (img, (((uint8_t *)(l)) + ((o) * 3) + 1)) << 8) | \
(READ (img, (((uint8_t *)(l)) + ((o) * 3) + 2)) << 16))
#endif
 
/* Store macros */
 
#ifdef WORDS_BIGENDIAN
#define STORE_1(img,l,o,v) \
do \
{ \
uint32_t *__d = ((uint32_t *)(l)) + ((o) >> 5); \
uint32_t __m, __v; \
\
__m = 1 << (0x1f - ((o) & 0x1f)); \
__v = (v)? __m : 0; \
\
WRITE((img), __d, (READ((img), __d) & ~__m) | __v); \
} \
while (0)
#else
#define STORE_1(img,l,o,v) \
do \
{ \
uint32_t *__d = ((uint32_t *)(l)) + ((o) >> 5); \
uint32_t __m, __v; \
\
__m = 1 << ((o) & 0x1f); \
__v = (v)? __m : 0; \
\
WRITE((img), __d, (READ((img), __d) & ~__m) | __v); \
} \
while (0)
#endif
 
#define STORE_8(img,l,o,v) (WRITE (img, (uint8_t *)(l) + ((o) >> 3), (v)))
 
#ifdef WORDS_BIGENDIAN
#define STORE_4(img,l,o,v) \
do \
{ \
int bo = 4 * (o); \
int v4 = (v) & 0x0f; \
\
STORE_8 (img, l, bo, ( \
bo & 4 ? \
(FETCH_8 (img, l, bo) & 0xf0) | (v4) : \
(FETCH_8 (img, l, bo) & 0x0f) | (v4 << 4))); \
} while (0)
#else
#define STORE_4(img,l,o,v) \
do \
{ \
int bo = 4 * (o); \
int v4 = (v) & 0x0f; \
\
STORE_8 (img, l, bo, ( \
bo & 4 ? \
(FETCH_8 (img, l, bo) & 0x0f) | (v4 << 4) : \
(FETCH_8 (img, l, bo) & 0xf0) | (v4))); \
} while (0)
#endif
 
#ifdef WORDS_BIGENDIAN
#define STORE_24(img,l,o,v) \
do \
{ \
uint8_t *__tmp = (l) + 3 * (o); \
\
WRITE ((img), __tmp++, ((v) & 0x00ff0000) >> 16); \
WRITE ((img), __tmp++, ((v) & 0x0000ff00) >> 8); \
WRITE ((img), __tmp++, ((v) & 0x000000ff) >> 0); \
} \
while (0)
#else
#define STORE_24(img,l,o,v) \
do \
{ \
uint8_t *__tmp = (l) + 3 * (o); \
\
WRITE ((img), __tmp++, ((v) & 0x000000ff) >> 0); \
WRITE ((img), __tmp++, ((v) & 0x0000ff00) >> 8); \
WRITE ((img), __tmp++, ((v) & 0x00ff0000) >> 16); \
} \
while (0)
#endif
 
/*
* YV12 setup and access macros
*/
 
#define YV12_SETUP(image) \
bits_image_t *__bits_image = (bits_image_t *)image; \
uint32_t *bits = __bits_image->bits; \
int stride = __bits_image->rowstride; \
int offset0 = stride < 0 ? \
((-stride) >> 1) * ((__bits_image->height - 1) >> 1) - stride : \
stride * __bits_image->height; \
int offset1 = stride < 0 ? \
offset0 + ((-stride) >> 1) * ((__bits_image->height) >> 1) : \
offset0 + (offset0 >> 2)
 
/* Note no trailing semicolon on the above macro; if it's there, then
* the typical usage of YV12_SETUP(image); will have an extra trailing ;
* that some compilers will interpret as a statement -- and then any further
* variable declarations will cause an error.
*/
 
#define YV12_Y(line) \
((uint8_t *) ((bits) + (stride) * (line)))
 
#define YV12_U(line) \
((uint8_t *) ((bits) + offset1 + \
((stride) >> 1) * ((line) >> 1)))
 
#define YV12_V(line) \
((uint8_t *) ((bits) + offset0 + \
((stride) >> 1) * ((line) >> 1)))
 
/* Misc. helpers */
 
static force_inline void
get_shifts (pixman_format_code_t format,
int *a,
int *r,
int *g,
int *b)
{
switch (PIXMAN_FORMAT_TYPE (format))
{
case PIXMAN_TYPE_A:
*b = 0;
*g = 0;
*r = 0;
*a = 0;
break;
 
case PIXMAN_TYPE_ARGB:
case PIXMAN_TYPE_ARGB_SRGB:
*b = 0;
*g = *b + PIXMAN_FORMAT_B (format);
*r = *g + PIXMAN_FORMAT_G (format);
*a = *r + PIXMAN_FORMAT_R (format);
break;
 
case PIXMAN_TYPE_ABGR:
*r = 0;
*g = *r + PIXMAN_FORMAT_R (format);
*b = *g + PIXMAN_FORMAT_G (format);
*a = *b + PIXMAN_FORMAT_B (format);
break;
 
case PIXMAN_TYPE_BGRA:
/* With BGRA formats we start counting at the high end of the pixel */
*b = PIXMAN_FORMAT_BPP (format) - PIXMAN_FORMAT_B (format);
*g = *b - PIXMAN_FORMAT_B (format);
*r = *g - PIXMAN_FORMAT_G (format);
*a = *r - PIXMAN_FORMAT_R (format);
break;
 
case PIXMAN_TYPE_RGBA:
/* With BGRA formats we start counting at the high end of the pixel */
*r = PIXMAN_FORMAT_BPP (format) - PIXMAN_FORMAT_R (format);
*g = *r - PIXMAN_FORMAT_R (format);
*b = *g - PIXMAN_FORMAT_G (format);
*a = *b - PIXMAN_FORMAT_B (format);
break;
 
default:
assert (0);
break;
}
}
 
static force_inline uint32_t
convert_channel (uint32_t pixel, uint32_t def_value,
int n_from_bits, int from_shift,
int n_to_bits, int to_shift)
{
uint32_t v;
 
if (n_from_bits && n_to_bits)
v = unorm_to_unorm (pixel >> from_shift, n_from_bits, n_to_bits);
else if (n_to_bits)
v = def_value;
else
v = 0;
 
return (v & ((1 << n_to_bits) - 1)) << to_shift;
}
 
static force_inline uint32_t
convert_pixel (pixman_format_code_t from, pixman_format_code_t to, uint32_t pixel)
{
int a_from_shift, r_from_shift, g_from_shift, b_from_shift;
int a_to_shift, r_to_shift, g_to_shift, b_to_shift;
uint32_t a, r, g, b;
 
get_shifts (from, &a_from_shift, &r_from_shift, &g_from_shift, &b_from_shift);
get_shifts (to, &a_to_shift, &r_to_shift, &g_to_shift, &b_to_shift);
 
a = convert_channel (pixel, ~0,
PIXMAN_FORMAT_A (from), a_from_shift,
PIXMAN_FORMAT_A (to), a_to_shift);
 
r = convert_channel (pixel, 0,
PIXMAN_FORMAT_R (from), r_from_shift,
PIXMAN_FORMAT_R (to), r_to_shift);
 
g = convert_channel (pixel, 0,
PIXMAN_FORMAT_G (from), g_from_shift,
PIXMAN_FORMAT_G (to), g_to_shift);
 
b = convert_channel (pixel, 0,
PIXMAN_FORMAT_B (from), b_from_shift,
PIXMAN_FORMAT_B (to), b_to_shift);
 
return a | r | g | b;
}
 
static force_inline uint32_t
convert_pixel_to_a8r8g8b8 (pixman_image_t *image,
pixman_format_code_t format,
uint32_t pixel)
{
if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_GRAY ||
PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_COLOR)
{
return image->bits.indexed->rgba[pixel];
}
else
{
return convert_pixel (format, PIXMAN_a8r8g8b8, pixel);
}
}
 
static force_inline uint32_t
convert_pixel_from_a8r8g8b8 (pixman_image_t *image,
pixman_format_code_t format, uint32_t pixel)
{
if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_GRAY)
{
pixel = CONVERT_RGB24_TO_Y15 (pixel);
 
return image->bits.indexed->ent[pixel & 0x7fff];
}
else if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_COLOR)
{
pixel = convert_pixel (PIXMAN_a8r8g8b8, PIXMAN_x1r5g5b5, pixel);
 
return image->bits.indexed->ent[pixel & 0x7fff];
}
else
{
return convert_pixel (PIXMAN_a8r8g8b8, format, pixel);
}
}
 
static force_inline uint32_t
fetch_and_convert_pixel (pixman_image_t * image,
const uint8_t * bits,
int offset,
pixman_format_code_t format)
{
uint32_t pixel;
 
switch (PIXMAN_FORMAT_BPP (format))
{
case 1:
pixel = FETCH_1 (image, bits, offset);
break;
 
case 4:
pixel = FETCH_4 (image, bits, offset);
break;
 
case 8:
pixel = READ (image, bits + offset);
break;
 
case 16:
pixel = READ (image, ((uint16_t *)bits + offset));
break;
 
case 24:
pixel = FETCH_24 (image, bits, offset);
break;
 
case 32:
pixel = READ (image, ((uint32_t *)bits + offset));
break;
 
default:
pixel = 0xffff00ff; /* As ugly as possible to detect the bug */
break;
}
 
return convert_pixel_to_a8r8g8b8 (image, format, pixel);
}
 
static force_inline void
convert_and_store_pixel (bits_image_t * image,
uint8_t * dest,
int offset,
pixman_format_code_t format,
uint32_t pixel)
{
uint32_t converted = convert_pixel_from_a8r8g8b8 (
(pixman_image_t *)image, format, pixel);
 
switch (PIXMAN_FORMAT_BPP (format))
{
case 1:
STORE_1 (image, dest, offset, converted & 0x01);
break;
 
case 4:
STORE_4 (image, dest, offset, converted & 0xf);
break;
 
case 8:
WRITE (image, (dest + offset), converted & 0xff);
break;
 
case 16:
WRITE (image, ((uint16_t *)dest + offset), converted & 0xffff);
break;
 
case 24:
STORE_24 (image, dest, offset, converted);
break;
 
case 32:
WRITE (image, ((uint32_t *)dest + offset), converted);
break;
 
default:
*dest = 0x0;
break;
}
}
 
#define MAKE_ACCESSORS(format) \
static void \
fetch_scanline_ ## format (pixman_image_t *image, \
int x, \
int y, \
int width, \
uint32_t * buffer, \
const uint32_t *mask) \
{ \
uint8_t *bits = \
(uint8_t *)(image->bits.bits + y * image->bits.rowstride); \
int i; \
\
for (i = 0; i < width; ++i) \
{ \
*buffer++ = \
fetch_and_convert_pixel (image, bits, x + i, PIXMAN_ ## format); \
} \
} \
\
static void \
store_scanline_ ## format (bits_image_t * image, \
int x, \
int y, \
int width, \
const uint32_t *values) \
{ \
uint8_t *dest = \
(uint8_t *)(image->bits + y * image->rowstride); \
int i; \
\
for (i = 0; i < width; ++i) \
{ \
convert_and_store_pixel ( \
image, dest, i + x, PIXMAN_ ## format, values[i]); \
} \
} \
\
static uint32_t \
fetch_pixel_ ## format (bits_image_t *image, \
int offset, \
int line) \
{ \
uint8_t *bits = \
(uint8_t *)(image->bits + line * image->rowstride); \
\
return fetch_and_convert_pixel ((pixman_image_t *)image, \
bits, offset, PIXMAN_ ## format); \
} \
\
static const void *const __dummy__ ## format
 
MAKE_ACCESSORS(a8r8g8b8);
MAKE_ACCESSORS(x8r8g8b8);
MAKE_ACCESSORS(a8b8g8r8);
MAKE_ACCESSORS(x8b8g8r8);
MAKE_ACCESSORS(x14r6g6b6);
MAKE_ACCESSORS(b8g8r8a8);
MAKE_ACCESSORS(b8g8r8x8);
MAKE_ACCESSORS(r8g8b8x8);
MAKE_ACCESSORS(r8g8b8a8);
MAKE_ACCESSORS(r8g8b8);
MAKE_ACCESSORS(b8g8r8);
MAKE_ACCESSORS(r5g6b5);
MAKE_ACCESSORS(b5g6r5);
MAKE_ACCESSORS(a1r5g5b5);
MAKE_ACCESSORS(x1r5g5b5);
MAKE_ACCESSORS(a1b5g5r5);
MAKE_ACCESSORS(x1b5g5r5);
MAKE_ACCESSORS(a4r4g4b4);
MAKE_ACCESSORS(x4r4g4b4);
MAKE_ACCESSORS(a4b4g4r4);
MAKE_ACCESSORS(x4b4g4r4);
MAKE_ACCESSORS(a8);
MAKE_ACCESSORS(c8);
MAKE_ACCESSORS(g8);
MAKE_ACCESSORS(r3g3b2);
MAKE_ACCESSORS(b2g3r3);
MAKE_ACCESSORS(a2r2g2b2);
MAKE_ACCESSORS(a2b2g2r2);
MAKE_ACCESSORS(x4a4);
MAKE_ACCESSORS(a4);
MAKE_ACCESSORS(g4);
MAKE_ACCESSORS(c4);
MAKE_ACCESSORS(r1g2b1);
MAKE_ACCESSORS(b1g2r1);
MAKE_ACCESSORS(a1r1g1b1);
MAKE_ACCESSORS(a1b1g1r1);
MAKE_ACCESSORS(a1);
MAKE_ACCESSORS(g1);
 
/********************************** Fetch ************************************/
/* Table mapping sRGB-encoded 8 bit numbers to linearly encoded
* floating point numbers. We assume that single precision
* floating point follows the IEEE 754 format.
*/
static const uint32_t to_linear_u[256] =
{
0x00000000, 0x399f22b4, 0x3a1f22b4, 0x3a6eb40e, 0x3a9f22b4, 0x3ac6eb61,
0x3aeeb40e, 0x3b0b3e5d, 0x3b1f22b4, 0x3b33070b, 0x3b46eb61, 0x3b5b518a,
0x3b70f18a, 0x3b83e1c5, 0x3b8fe614, 0x3b9c87fb, 0x3ba9c9b5, 0x3bb7ad6d,
0x3bc63547, 0x3bd5635f, 0x3be539bd, 0x3bf5ba70, 0x3c0373b5, 0x3c0c6152,
0x3c15a703, 0x3c1f45bc, 0x3c293e68, 0x3c3391f4, 0x3c3e4149, 0x3c494d43,
0x3c54b6c7, 0x3c607eb1, 0x3c6ca5df, 0x3c792d22, 0x3c830aa8, 0x3c89af9e,
0x3c9085db, 0x3c978dc5, 0x3c9ec7c0, 0x3ca63432, 0x3cadd37d, 0x3cb5a601,
0x3cbdac20, 0x3cc5e639, 0x3cce54ab, 0x3cd6f7d2, 0x3cdfd00e, 0x3ce8ddb9,
0x3cf2212c, 0x3cfb9ac1, 0x3d02a569, 0x3d0798dc, 0x3d0ca7e4, 0x3d11d2ae,
0x3d171963, 0x3d1c7c2e, 0x3d21fb3a, 0x3d2796af, 0x3d2d4ebb, 0x3d332380,
0x3d39152b, 0x3d3f23e3, 0x3d454fd0, 0x3d4b991c, 0x3d51ffeb, 0x3d588466,
0x3d5f26b7, 0x3d65e6fe, 0x3d6cc564, 0x3d73c210, 0x3d7add25, 0x3d810b65,
0x3d84b793, 0x3d88732e, 0x3d8c3e48, 0x3d9018f4, 0x3d940343, 0x3d97fd48,
0x3d9c0714, 0x3da020b9, 0x3da44a48, 0x3da883d6, 0x3daccd70, 0x3db12728,
0x3db59110, 0x3dba0b38, 0x3dbe95b2, 0x3dc3308f, 0x3dc7dbe0, 0x3dcc97b4,
0x3dd1641c, 0x3dd6412a, 0x3ddb2eec, 0x3de02d75, 0x3de53cd3, 0x3dea5d16,
0x3def8e52, 0x3df4d091, 0x3dfa23e5, 0x3dff885e, 0x3e027f06, 0x3e05427f,
0x3e080ea2, 0x3e0ae376, 0x3e0dc104, 0x3e10a752, 0x3e139669, 0x3e168e50,
0x3e198f0e, 0x3e1c98ab, 0x3e1fab2e, 0x3e22c6a0, 0x3e25eb08, 0x3e29186a,
0x3e2c4ed0, 0x3e2f8e42, 0x3e32d6c4, 0x3e362861, 0x3e39831e, 0x3e3ce702,
0x3e405416, 0x3e43ca5e, 0x3e4749e4, 0x3e4ad2ae, 0x3e4e64c2, 0x3e520027,
0x3e55a4e6, 0x3e595303, 0x3e5d0a8a, 0x3e60cb7c, 0x3e6495e0, 0x3e6869bf,
0x3e6c4720, 0x3e702e08, 0x3e741e7f, 0x3e78188c, 0x3e7c1c34, 0x3e8014c0,
0x3e822039, 0x3e84308b, 0x3e8645b8, 0x3e885fc3, 0x3e8a7eb0, 0x3e8ca281,
0x3e8ecb3a, 0x3e90f8df, 0x3e932b72, 0x3e9562f6, 0x3e979f6f, 0x3e99e0e0,
0x3e9c274e, 0x3e9e72b8, 0x3ea0c322, 0x3ea31892, 0x3ea57308, 0x3ea7d28a,
0x3eaa3718, 0x3eaca0b7, 0x3eaf0f69, 0x3eb18332, 0x3eb3fc16, 0x3eb67a15,
0x3eb8fd34, 0x3ebb8576, 0x3ebe12de, 0x3ec0a56e, 0x3ec33d2a, 0x3ec5da14,
0x3ec87c30, 0x3ecb2380, 0x3ecdd008, 0x3ed081ca, 0x3ed338c9, 0x3ed5f508,
0x3ed8b68a, 0x3edb7d52, 0x3ede4962, 0x3ee11abe, 0x3ee3f168, 0x3ee6cd64,
0x3ee9aeb6, 0x3eec955d, 0x3eef815d, 0x3ef272ba, 0x3ef56976, 0x3ef86594,
0x3efb6717, 0x3efe6e02, 0x3f00bd2b, 0x3f02460c, 0x3f03d1a5, 0x3f055ff8,
0x3f06f105, 0x3f0884ce, 0x3f0a1b54, 0x3f0bb499, 0x3f0d509f, 0x3f0eef65,
0x3f1090ef, 0x3f12353c, 0x3f13dc50, 0x3f15862a, 0x3f1732cc, 0x3f18e237,
0x3f1a946d, 0x3f1c4970, 0x3f1e013f, 0x3f1fbbde, 0x3f21794c, 0x3f23398c,
0x3f24fca0, 0x3f26c286, 0x3f288b42, 0x3f2a56d3, 0x3f2c253d, 0x3f2df680,
0x3f2fca9d, 0x3f31a195, 0x3f337b6a, 0x3f35581e, 0x3f3737b1, 0x3f391a24,
0x3f3aff7a, 0x3f3ce7b2, 0x3f3ed2d0, 0x3f40c0d2, 0x3f42b1bc, 0x3f44a58e,
0x3f469c49, 0x3f4895ee, 0x3f4a9280, 0x3f4c91ff, 0x3f4e946c, 0x3f5099c8,
0x3f52a216, 0x3f54ad55, 0x3f56bb88, 0x3f58ccae, 0x3f5ae0cb, 0x3f5cf7de,
0x3f5f11ec, 0x3f612ef0, 0x3f634eef, 0x3f6571ea, 0x3f6797e1, 0x3f69c0d6,
0x3f6beccb, 0x3f6e1bc0, 0x3f704db6, 0x3f7282af, 0x3f74baac, 0x3f76f5ae,
0x3f7933b6, 0x3f7b74c6, 0x3f7db8de, 0x3f800000
};
 
static const float * const to_linear = (const float *)to_linear_u;
 
static uint8_t
to_srgb (float f)
{
uint8_t low = 0;
uint8_t high = 255;
 
while (high - low > 1)
{
uint8_t mid = (low + high) / 2;
 
if (to_linear[mid] > f)
high = mid;
else
low = mid;
}
 
if (to_linear[high] - f < f - to_linear[low])
return high;
else
return low;
}
 
static void
fetch_scanline_a8r8g8b8_sRGB_float (pixman_image_t *image,
int x,
int y,
int width,
uint32_t * b,
const uint32_t *mask)
{
const uint32_t *bits = image->bits.bits + y * image->bits.rowstride;
const uint32_t *pixel = bits + x;
const uint32_t *end = pixel + width;
argb_t *buffer = (argb_t *)b;
 
while (pixel < end)
{
uint32_t p = READ (image, pixel++);
argb_t *argb = buffer;
 
argb->a = pixman_unorm_to_float ((p >> 24) & 0xff, 8);
 
argb->r = to_linear [(p >> 16) & 0xff];
argb->g = to_linear [(p >> 8) & 0xff];
argb->b = to_linear [(p >> 0) & 0xff];
 
buffer++;
}
}
 
/* Expects a float buffer */
static void
fetch_scanline_a2r10g10b10_float (pixman_image_t *image,
int x,
int y,
int width,
uint32_t * b,
const uint32_t *mask)
{
const uint32_t *bits = image->bits.bits + y * image->bits.rowstride;
const uint32_t *pixel = bits + x;
const uint32_t *end = pixel + width;
argb_t *buffer = (argb_t *)b;
 
while (pixel < end)
{
uint32_t p = READ (image, pixel++);
uint64_t a = p >> 30;
uint64_t r = (p >> 20) & 0x3ff;
uint64_t g = (p >> 10) & 0x3ff;
uint64_t b = p & 0x3ff;
 
buffer->a = pixman_unorm_to_float (a, 2);
buffer->r = pixman_unorm_to_float (r, 10);
buffer->g = pixman_unorm_to_float (g, 10);
buffer->b = pixman_unorm_to_float (b, 10);
 
buffer++;
}
}
 
/* Expects a float buffer */
static void
fetch_scanline_x2r10g10b10_float (pixman_image_t *image,
int x,
int y,
int width,
uint32_t * b,
const uint32_t *mask)
{
const uint32_t *bits = image->bits.bits + y * image->bits.rowstride;
const uint32_t *pixel = (uint32_t *)bits + x;
const uint32_t *end = pixel + width;
argb_t *buffer = (argb_t *)b;
 
while (pixel < end)
{
uint32_t p = READ (image, pixel++);
uint64_t r = (p >> 20) & 0x3ff;
uint64_t g = (p >> 10) & 0x3ff;
uint64_t b = p & 0x3ff;
 
buffer->a = 1.0;
buffer->r = pixman_unorm_to_float (r, 10);
buffer->g = pixman_unorm_to_float (g, 10);
buffer->b = pixman_unorm_to_float (b, 10);
 
buffer++;
}
}
 
/* Expects a float buffer */
static void
fetch_scanline_a2b10g10r10_float (pixman_image_t *image,
int x,
int y,
int width,
uint32_t * b,
const uint32_t *mask)
{
const uint32_t *bits = image->bits.bits + y * image->bits.rowstride;
const uint32_t *pixel = bits + x;
const uint32_t *end = pixel + width;
argb_t *buffer = (argb_t *)b;
 
while (pixel < end)
{
uint32_t p = READ (image, pixel++);
uint64_t a = p >> 30;
uint64_t b = (p >> 20) & 0x3ff;
uint64_t g = (p >> 10) & 0x3ff;
uint64_t r = p & 0x3ff;
 
buffer->a = pixman_unorm_to_float (a, 2);
buffer->r = pixman_unorm_to_float (r, 10);
buffer->g = pixman_unorm_to_float (g, 10);
buffer->b = pixman_unorm_to_float (b, 10);
 
buffer++;
}
}
 
/* Expects a float buffer */
static void
fetch_scanline_x2b10g10r10_float (pixman_image_t *image,
int x,
int y,
int width,
uint32_t * b,
const uint32_t *mask)
{
const uint32_t *bits = image->bits.bits + y * image->bits.rowstride;
const uint32_t *pixel = (uint32_t *)bits + x;
const uint32_t *end = pixel + width;
argb_t *buffer = (argb_t *)b;
 
while (pixel < end)
{
uint32_t p = READ (image, pixel++);
uint64_t b = (p >> 20) & 0x3ff;
uint64_t g = (p >> 10) & 0x3ff;
uint64_t r = p & 0x3ff;
 
buffer->a = 1.0;
buffer->r = pixman_unorm_to_float (r, 10);
buffer->g = pixman_unorm_to_float (g, 10);
buffer->b = pixman_unorm_to_float (b, 10);
 
buffer++;
}
}
 
static void
fetch_scanline_yuy2 (pixman_image_t *image,
int x,
int line,
int width,
uint32_t * buffer,
const uint32_t *mask)
{
const uint32_t *bits = image->bits.bits + image->bits.rowstride * line;
int i;
for (i = 0; i < width; i++)
{
int16_t y, u, v;
int32_t r, g, b;
y = ((uint8_t *) bits)[(x + i) << 1] - 16;
u = ((uint8_t *) bits)[(((x + i) << 1) & - 4) + 1] - 128;
v = ((uint8_t *) bits)[(((x + i) << 1) & - 4) + 3] - 128;
/* R = 1.164(Y - 16) + 1.596(V - 128) */
r = 0x012b27 * y + 0x019a2e * v;
/* G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128) */
g = 0x012b27 * y - 0x00d0f2 * v - 0x00647e * u;
/* B = 1.164(Y - 16) + 2.018(U - 128) */
b = 0x012b27 * y + 0x0206a2 * u;
*buffer++ = 0xff000000 |
(r >= 0 ? r < 0x1000000 ? r & 0xff0000 : 0xff0000 : 0) |
(g >= 0 ? g < 0x1000000 ? (g >> 8) & 0x00ff00 : 0x00ff00 : 0) |
(b >= 0 ? b < 0x1000000 ? (b >> 16) & 0x0000ff : 0x0000ff : 0);
}
}
 
static void
fetch_scanline_yv12 (pixman_image_t *image,
int x,
int line,
int width,
uint32_t * buffer,
const uint32_t *mask)
{
YV12_SETUP (image);
uint8_t *y_line = YV12_Y (line);
uint8_t *u_line = YV12_U (line);
uint8_t *v_line = YV12_V (line);
int i;
for (i = 0; i < width; i++)
{
int16_t y, u, v;
int32_t r, g, b;
 
y = y_line[x + i] - 16;
u = u_line[(x + i) >> 1] - 128;
v = v_line[(x + i) >> 1] - 128;
 
/* R = 1.164(Y - 16) + 1.596(V - 128) */
r = 0x012b27 * y + 0x019a2e * v;
/* G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128) */
g = 0x012b27 * y - 0x00d0f2 * v - 0x00647e * u;
/* B = 1.164(Y - 16) + 2.018(U - 128) */
b = 0x012b27 * y + 0x0206a2 * u;
 
*buffer++ = 0xff000000 |
(r >= 0 ? r < 0x1000000 ? r & 0xff0000 : 0xff0000 : 0) |
(g >= 0 ? g < 0x1000000 ? (g >> 8) & 0x00ff00 : 0x00ff00 : 0) |
(b >= 0 ? b < 0x1000000 ? (b >> 16) & 0x0000ff : 0x0000ff : 0);
}
}
 
/**************************** Pixel wise fetching *****************************/
 
static argb_t
fetch_pixel_x2r10g10b10_float (bits_image_t *image,
int offset,
int line)
{
uint32_t *bits = image->bits + line * image->rowstride;
uint32_t p = READ (image, bits + offset);
uint64_t r = (p >> 20) & 0x3ff;
uint64_t g = (p >> 10) & 0x3ff;
uint64_t b = p & 0x3ff;
argb_t argb;
 
argb.a = 1.0;
argb.r = pixman_unorm_to_float (r, 10);
argb.g = pixman_unorm_to_float (g, 10);
argb.b = pixman_unorm_to_float (b, 10);
 
return argb;
}
 
static argb_t
fetch_pixel_a2r10g10b10_float (bits_image_t *image,
int offset,
int line)
{
uint32_t *bits = image->bits + line * image->rowstride;
uint32_t p = READ (image, bits + offset);
uint64_t a = p >> 30;
uint64_t r = (p >> 20) & 0x3ff;
uint64_t g = (p >> 10) & 0x3ff;
uint64_t b = p & 0x3ff;
argb_t argb;
 
argb.a = pixman_unorm_to_float (a, 2);
argb.r = pixman_unorm_to_float (r, 10);
argb.g = pixman_unorm_to_float (g, 10);
argb.b = pixman_unorm_to_float (b, 10);
 
return argb;
}
 
static argb_t
fetch_pixel_a2b10g10r10_float (bits_image_t *image,
int offset,
int line)
{
uint32_t *bits = image->bits + line * image->rowstride;
uint32_t p = READ (image, bits + offset);
uint64_t a = p >> 30;
uint64_t b = (p >> 20) & 0x3ff;
uint64_t g = (p >> 10) & 0x3ff;
uint64_t r = p & 0x3ff;
argb_t argb;
 
argb.a = pixman_unorm_to_float (a, 2);
argb.r = pixman_unorm_to_float (r, 10);
argb.g = pixman_unorm_to_float (g, 10);
argb.b = pixman_unorm_to_float (b, 10);
 
return argb;
}
 
static argb_t
fetch_pixel_x2b10g10r10_float (bits_image_t *image,
int offset,
int line)
{
uint32_t *bits = image->bits + line * image->rowstride;
uint32_t p = READ (image, bits + offset);
uint64_t b = (p >> 20) & 0x3ff;
uint64_t g = (p >> 10) & 0x3ff;
uint64_t r = p & 0x3ff;
argb_t argb;
 
argb.a = 1.0;
argb.r = pixman_unorm_to_float (r, 10);
argb.g = pixman_unorm_to_float (g, 10);
argb.b = pixman_unorm_to_float (b, 10);
 
return argb;
}
 
static argb_t
fetch_pixel_a8r8g8b8_sRGB_float (bits_image_t *image,
int offset,
int line)
{
uint32_t *bits = image->bits + line * image->rowstride;
uint32_t p = READ (image, bits + offset);
argb_t argb;
 
argb.a = pixman_unorm_to_float ((p >> 24) & 0xff, 8);
 
argb.r = to_linear [(p >> 16) & 0xff];
argb.g = to_linear [(p >> 8) & 0xff];
argb.b = to_linear [(p >> 0) & 0xff];
 
return argb;
}
 
static uint32_t
fetch_pixel_yuy2 (bits_image_t *image,
int offset,
int line)
{
const uint32_t *bits = image->bits + image->rowstride * line;
int16_t y, u, v;
int32_t r, g, b;
y = ((uint8_t *) bits)[offset << 1] - 16;
u = ((uint8_t *) bits)[((offset << 1) & - 4) + 1] - 128;
v = ((uint8_t *) bits)[((offset << 1) & - 4) + 3] - 128;
/* R = 1.164(Y - 16) + 1.596(V - 128) */
r = 0x012b27 * y + 0x019a2e * v;
/* G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128) */
g = 0x012b27 * y - 0x00d0f2 * v - 0x00647e * u;
/* B = 1.164(Y - 16) + 2.018(U - 128) */
b = 0x012b27 * y + 0x0206a2 * u;
return 0xff000000 |
(r >= 0 ? r < 0x1000000 ? r & 0xff0000 : 0xff0000 : 0) |
(g >= 0 ? g < 0x1000000 ? (g >> 8) & 0x00ff00 : 0x00ff00 : 0) |
(b >= 0 ? b < 0x1000000 ? (b >> 16) & 0x0000ff : 0x0000ff : 0);
}
 
static uint32_t
fetch_pixel_yv12 (bits_image_t *image,
int offset,
int line)
{
YV12_SETUP (image);
int16_t y = YV12_Y (line)[offset] - 16;
int16_t u = YV12_U (line)[offset >> 1] - 128;
int16_t v = YV12_V (line)[offset >> 1] - 128;
int32_t r, g, b;
/* R = 1.164(Y - 16) + 1.596(V - 128) */
r = 0x012b27 * y + 0x019a2e * v;
/* G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128) */
g = 0x012b27 * y - 0x00d0f2 * v - 0x00647e * u;
/* B = 1.164(Y - 16) + 2.018(U - 128) */
b = 0x012b27 * y + 0x0206a2 * u;
return 0xff000000 |
(r >= 0 ? r < 0x1000000 ? r & 0xff0000 : 0xff0000 : 0) |
(g >= 0 ? g < 0x1000000 ? (g >> 8) & 0x00ff00 : 0x00ff00 : 0) |
(b >= 0 ? b < 0x1000000 ? (b >> 16) & 0x0000ff : 0x0000ff : 0);
}
 
/*********************************** Store ************************************/
 
static void
store_scanline_a2r10g10b10_float (bits_image_t * image,
int x,
int y,
int width,
const uint32_t *v)
{
uint32_t *bits = image->bits + image->rowstride * y;
uint32_t *pixel = bits + x;
argb_t *values = (argb_t *)v;
int i;
 
for (i = 0; i < width; ++i)
{
uint16_t a, r, g, b;
 
a = pixman_float_to_unorm (values[i].a, 2);
r = pixman_float_to_unorm (values[i].r, 10);
g = pixman_float_to_unorm (values[i].g, 10);
b = pixman_float_to_unorm (values[i].b, 10);
 
WRITE (image, pixel++,
(a << 30) | (r << 20) | (g << 10) | b);
}
}
 
static void
store_scanline_x2r10g10b10_float (bits_image_t * image,
int x,
int y,
int width,
const uint32_t *v)
{
uint32_t *bits = image->bits + image->rowstride * y;
uint32_t *pixel = bits + x;
argb_t *values = (argb_t *)v;
int i;
 
for (i = 0; i < width; ++i)
{
uint16_t r, g, b;
 
r = pixman_float_to_unorm (values[i].r, 10);
g = pixman_float_to_unorm (values[i].g, 10);
b = pixman_float_to_unorm (values[i].b, 10);
 
WRITE (image, pixel++,
(r << 20) | (g << 10) | b);
}
}
 
static void
store_scanline_a2b10g10r10_float (bits_image_t * image,
int x,
int y,
int width,
const uint32_t *v)
{
uint32_t *bits = image->bits + image->rowstride * y;
uint32_t *pixel = bits + x;
argb_t *values = (argb_t *)v;
int i;
 
for (i = 0; i < width; ++i)
{
uint16_t a, r, g, b;
 
a = pixman_float_to_unorm (values[i].a, 2);
r = pixman_float_to_unorm (values[i].r, 10);
g = pixman_float_to_unorm (values[i].g, 10);
b = pixman_float_to_unorm (values[i].b, 10);
 
WRITE (image, pixel++,
(a << 30) | (b << 20) | (g << 10) | r);
}
}
 
static void
store_scanline_x2b10g10r10_float (bits_image_t * image,
int x,
int y,
int width,
const uint32_t *v)
{
uint32_t *bits = image->bits + image->rowstride * y;
uint32_t *pixel = bits + x;
argb_t *values = (argb_t *)v;
int i;
 
for (i = 0; i < width; ++i)
{
uint16_t r, g, b;
 
r = pixman_float_to_unorm (values[i].r, 10);
g = pixman_float_to_unorm (values[i].g, 10);
b = pixman_float_to_unorm (values[i].b, 10);
 
WRITE (image, pixel++,
(b << 20) | (g << 10) | r);
}
}
 
static void
store_scanline_a8r8g8b8_sRGB_float (bits_image_t * image,
int x,
int y,
int width,
const uint32_t *v)
{
uint32_t *bits = image->bits + image->rowstride * y;
uint32_t *pixel = bits + x;
argb_t *values = (argb_t *)v;
int i;
 
for (i = 0; i < width; ++i)
{
uint8_t a, r, g, b;
 
a = pixman_float_to_unorm (values[i].a, 8);
r = to_srgb (values[i].r);
g = to_srgb (values[i].g);
b = to_srgb (values[i].b);
 
WRITE (image, pixel++,
(a << 24) | (r << 16) | (g << 8) | b);
}
}
 
/*
* Contracts a floating point image to 32bpp and then stores it using a
* regular 32-bit store proc. Despite the type, this function expects an
* argb_t buffer.
*/
static void
store_scanline_generic_float (bits_image_t * image,
int x,
int y,
int width,
const uint32_t *values)
{
uint32_t *argb8_pixels;
 
assert (image->common.type == BITS);
 
argb8_pixels = pixman_malloc_ab (width, sizeof(uint32_t));
if (!argb8_pixels)
return;
 
/* Contract the scanline. We could do this in place if values weren't
* const.
*/
pixman_contract_from_float (argb8_pixels, (argb_t *)values, width);
 
image->store_scanline_32 (image, x, y, width, argb8_pixels);
 
free (argb8_pixels);
}
 
static void
fetch_scanline_generic_float (pixman_image_t *image,
int x,
int y,
int width,
uint32_t * buffer,
const uint32_t *mask)
{
image->bits.fetch_scanline_32 (image, x, y, width, buffer, NULL);
 
pixman_expand_to_float ((argb_t *)buffer, buffer, image->bits.format, width);
}
 
/* The 32_sRGB paths should be deleted after narrow processing
* is no longer invoked for formats that are considered wide.
* (Also see fetch_pixel_generic_lossy_32) */
static void
fetch_scanline_a8r8g8b8_32_sRGB (pixman_image_t *image,
int x,
int y,
int width,
uint32_t *buffer,
const uint32_t *mask)
{
const uint32_t *bits = image->bits.bits + y * image->bits.rowstride;
const uint32_t *pixel = (uint32_t *)bits + x;
const uint32_t *end = pixel + width;
uint32_t tmp;
while (pixel < end)
{
uint8_t a, r, g, b;
 
tmp = READ (image, pixel++);
 
a = (tmp >> 24) & 0xff;
r = (tmp >> 16) & 0xff;
g = (tmp >> 8) & 0xff;
b = (tmp >> 0) & 0xff;
 
r = to_linear[r] * 255.0f + 0.5f;
g = to_linear[g] * 255.0f + 0.5f;
b = to_linear[b] * 255.0f + 0.5f;
 
*buffer++ = (a << 24) | (r << 16) | (g << 8) | (b << 0);
}
}
 
static uint32_t
fetch_pixel_a8r8g8b8_32_sRGB (bits_image_t *image,
int offset,
int line)
{
uint32_t *bits = image->bits + line * image->rowstride;
uint32_t tmp = READ (image, bits + offset);
uint8_t a, r, g, b;
 
a = (tmp >> 24) & 0xff;
r = (tmp >> 16) & 0xff;
g = (tmp >> 8) & 0xff;
b = (tmp >> 0) & 0xff;
 
r = to_linear[r] * 255.0f + 0.5f;
g = to_linear[g] * 255.0f + 0.5f;
b = to_linear[b] * 255.0f + 0.5f;
 
return (a << 24) | (r << 16) | (g << 8) | (b << 0);
}
 
static void
store_scanline_a8r8g8b8_32_sRGB (bits_image_t *image,
int x,
int y,
int width,
const uint32_t *v)
{
uint32_t *bits = image->bits + image->rowstride * y;
uint64_t *values = (uint64_t *)v;
uint32_t *pixel = bits + x;
uint64_t tmp;
int i;
for (i = 0; i < width; ++i)
{
uint8_t a, r, g, b;
 
tmp = values[i];
 
a = (tmp >> 24) & 0xff;
r = (tmp >> 16) & 0xff;
g = (tmp >> 8) & 0xff;
b = (tmp >> 0) & 0xff;
 
r = to_srgb (r * (1/255.0f));
g = to_srgb (g * (1/255.0f));
b = to_srgb (b * (1/255.0f));
WRITE (image, pixel++, a | (r << 16) | (g << 8) | (b << 0));
}
}
 
static argb_t
fetch_pixel_generic_float (bits_image_t *image,
int offset,
int line)
{
uint32_t pixel32 = image->fetch_pixel_32 (image, offset, line);
argb_t f;
 
pixman_expand_to_float (&f, &pixel32, image->format, 1);
 
return f;
}
 
/*
* XXX: The transformed fetch path only works at 32-bpp so far. When all
* paths have wide versions, this can be removed.
*
* WARNING: This function loses precision!
*/
static uint32_t
fetch_pixel_generic_lossy_32 (bits_image_t *image,
int offset,
int line)
{
argb_t pixel64 = image->fetch_pixel_float (image, offset, line);
uint32_t result;
 
pixman_contract_from_float (&result, &pixel64, 1);
 
return result;
}
 
typedef struct
{
pixman_format_code_t format;
fetch_scanline_t fetch_scanline_32;
fetch_scanline_t fetch_scanline_float;
fetch_pixel_32_t fetch_pixel_32;
fetch_pixel_float_t fetch_pixel_float;
store_scanline_t store_scanline_32;
store_scanline_t store_scanline_float;
} format_info_t;
 
#define FORMAT_INFO(format) \
{ \
PIXMAN_ ## format, \
fetch_scanline_ ## format, \
fetch_scanline_generic_float, \
fetch_pixel_ ## format, \
fetch_pixel_generic_float, \
store_scanline_ ## format, \
store_scanline_generic_float \
}
 
static const format_info_t accessors[] =
{
/* 32 bpp formats */
FORMAT_INFO (a8r8g8b8),
FORMAT_INFO (x8r8g8b8),
FORMAT_INFO (a8b8g8r8),
FORMAT_INFO (x8b8g8r8),
FORMAT_INFO (b8g8r8a8),
FORMAT_INFO (b8g8r8x8),
FORMAT_INFO (r8g8b8a8),
FORMAT_INFO (r8g8b8x8),
FORMAT_INFO (x14r6g6b6),
 
/* sRGB formats */
{ PIXMAN_a8r8g8b8_sRGB,
fetch_scanline_a8r8g8b8_32_sRGB, fetch_scanline_a8r8g8b8_sRGB_float,
fetch_pixel_a8r8g8b8_32_sRGB, fetch_pixel_a8r8g8b8_sRGB_float,
store_scanline_a8r8g8b8_32_sRGB, store_scanline_a8r8g8b8_sRGB_float,
},
 
/* 24bpp formats */
FORMAT_INFO (r8g8b8),
FORMAT_INFO (b8g8r8),
/* 16bpp formats */
FORMAT_INFO (r5g6b5),
FORMAT_INFO (b5g6r5),
FORMAT_INFO (a1r5g5b5),
FORMAT_INFO (x1r5g5b5),
FORMAT_INFO (a1b5g5r5),
FORMAT_INFO (x1b5g5r5),
FORMAT_INFO (a4r4g4b4),
FORMAT_INFO (x4r4g4b4),
FORMAT_INFO (a4b4g4r4),
FORMAT_INFO (x4b4g4r4),
/* 8bpp formats */
FORMAT_INFO (a8),
FORMAT_INFO (r3g3b2),
FORMAT_INFO (b2g3r3),
FORMAT_INFO (a2r2g2b2),
FORMAT_INFO (a2b2g2r2),
FORMAT_INFO (c8),
FORMAT_INFO (g8),
#define fetch_scanline_x4c4 fetch_scanline_c8
#define fetch_pixel_x4c4 fetch_pixel_c8
#define store_scanline_x4c4 store_scanline_c8
FORMAT_INFO (x4c4),
#define fetch_scanline_x4g4 fetch_scanline_g8
#define fetch_pixel_x4g4 fetch_pixel_g8
#define store_scanline_x4g4 store_scanline_g8
FORMAT_INFO (x4g4),
FORMAT_INFO (x4a4),
/* 4bpp formats */
FORMAT_INFO (a4),
FORMAT_INFO (r1g2b1),
FORMAT_INFO (b1g2r1),
FORMAT_INFO (a1r1g1b1),
FORMAT_INFO (a1b1g1r1),
FORMAT_INFO (c4),
FORMAT_INFO (g4),
/* 1bpp formats */
FORMAT_INFO (a1),
FORMAT_INFO (g1),
/* Wide formats */
{ PIXMAN_a2r10g10b10,
NULL, fetch_scanline_a2r10g10b10_float,
fetch_pixel_generic_lossy_32, fetch_pixel_a2r10g10b10_float,
NULL, store_scanline_a2r10g10b10_float },
 
{ PIXMAN_x2r10g10b10,
NULL, fetch_scanline_x2r10g10b10_float,
fetch_pixel_generic_lossy_32, fetch_pixel_x2r10g10b10_float,
NULL, store_scanline_x2r10g10b10_float },
 
{ PIXMAN_a2b10g10r10,
NULL, fetch_scanline_a2b10g10r10_float,
fetch_pixel_generic_lossy_32, fetch_pixel_a2b10g10r10_float,
NULL, store_scanline_a2b10g10r10_float },
 
{ PIXMAN_x2b10g10r10,
NULL, fetch_scanline_x2b10g10r10_float,
fetch_pixel_generic_lossy_32, fetch_pixel_x2b10g10r10_float,
NULL, store_scanline_x2b10g10r10_float },
 
/* YUV formats */
{ PIXMAN_yuy2,
fetch_scanline_yuy2, fetch_scanline_generic_float,
fetch_pixel_yuy2, fetch_pixel_generic_float,
NULL, NULL },
 
{ PIXMAN_yv12,
fetch_scanline_yv12, fetch_scanline_generic_float,
fetch_pixel_yv12, fetch_pixel_generic_float,
NULL, NULL },
{ PIXMAN_null },
};
 
static void
setup_accessors (bits_image_t *image)
{
const format_info_t *info = accessors;
while (info->format != PIXMAN_null)
{
if (info->format == image->format)
{
image->fetch_scanline_32 = info->fetch_scanline_32;
image->fetch_scanline_float = info->fetch_scanline_float;
image->fetch_pixel_32 = info->fetch_pixel_32;
image->fetch_pixel_float = info->fetch_pixel_float;
image->store_scanline_32 = info->store_scanline_32;
image->store_scanline_float = info->store_scanline_float;
return;
}
info++;
}
}
 
#ifndef PIXMAN_FB_ACCESSORS
void
_pixman_bits_image_setup_accessors_accessors (bits_image_t *image);
 
void
_pixman_bits_image_setup_accessors (bits_image_t *image)
{
if (image->read_func || image->write_func)
_pixman_bits_image_setup_accessors_accessors (image);
else
setup_accessors (image);
}
 
#else
 
void
_pixman_bits_image_setup_accessors_accessors (bits_image_t *image)
{
setup_accessors (image);
}
 
#endif
/contrib/sdk/sources/pixman/pixman-accessor.h
0,0 → 1,25
#ifdef PIXMAN_FB_ACCESSORS
 
#define READ(img, ptr) \
(((bits_image_t *)(img))->read_func ((ptr), sizeof(*(ptr))))
#define WRITE(img, ptr,val) \
(((bits_image_t *)(img))->write_func ((ptr), (val), sizeof (*(ptr))))
 
#define MEMSET_WRAPPED(img, dst, val, size) \
do { \
size_t _i; \
uint8_t *_dst = (uint8_t*)(dst); \
for(_i = 0; _i < (size_t) size; _i++) { \
WRITE((img), _dst +_i, (val)); \
} \
} while (0)
 
#else
 
#define READ(img, ptr) (*(ptr))
#define WRITE(img, ptr, val) (*(ptr) = (val))
#define MEMSET_WRAPPED(img, dst, val, size) \
memset(dst, val, size)
 
#endif
 
/contrib/sdk/sources/pixman/pixman-bits-image.c
0,0 → 1,1808
/*
* Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
* 2005 Lars Knoll & Zack Rusin, Trolltech
* 2008 Aaron Plattner, NVIDIA Corporation
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007, 2009 Red Hat, Inc.
* Copyright © 2008 André Tupinambá <andrelrt@gmail.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pixman-private.h"
#include "pixman-combine32.h"
#include "pixman-inlines.h"
 
static uint32_t *
_pixman_image_get_scanline_generic_float (pixman_iter_t * iter,
const uint32_t *mask)
{
pixman_iter_get_scanline_t fetch_32 = iter->data;
uint32_t *buffer = iter->buffer;
 
fetch_32 (iter, NULL);
 
pixman_expand_to_float ((argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
 
return iter->buffer;
}
 
/* Fetch functions */
 
static force_inline uint32_t
fetch_pixel_no_alpha (bits_image_t *image,
int x, int y, pixman_bool_t check_bounds)
{
if (check_bounds &&
(x < 0 || x >= image->width || y < 0 || y >= image->height))
{
return 0;
}
 
return image->fetch_pixel_32 (image, x, y);
}
 
typedef uint32_t (* get_pixel_t) (bits_image_t *image,
int x, int y, pixman_bool_t check_bounds);
 
static force_inline uint32_t
bits_image_fetch_pixel_nearest (bits_image_t *image,
pixman_fixed_t x,
pixman_fixed_t y,
get_pixel_t get_pixel)
{
int x0 = pixman_fixed_to_int (x - pixman_fixed_e);
int y0 = pixman_fixed_to_int (y - pixman_fixed_e);
 
if (image->common.repeat != PIXMAN_REPEAT_NONE)
{
repeat (image->common.repeat, &x0, image->width);
repeat (image->common.repeat, &y0, image->height);
 
return get_pixel (image, x0, y0, FALSE);
}
else
{
return get_pixel (image, x0, y0, TRUE);
}
}
 
static force_inline uint32_t
bits_image_fetch_pixel_bilinear (bits_image_t *image,
pixman_fixed_t x,
pixman_fixed_t y,
get_pixel_t get_pixel)
{
pixman_repeat_t repeat_mode = image->common.repeat;
int width = image->width;
int height = image->height;
int x1, y1, x2, y2;
uint32_t tl, tr, bl, br;
int32_t distx, disty;
 
x1 = x - pixman_fixed_1 / 2;
y1 = y - pixman_fixed_1 / 2;
 
distx = pixman_fixed_to_bilinear_weight (x1);
disty = pixman_fixed_to_bilinear_weight (y1);
 
x1 = pixman_fixed_to_int (x1);
y1 = pixman_fixed_to_int (y1);
x2 = x1 + 1;
y2 = y1 + 1;
 
if (repeat_mode != PIXMAN_REPEAT_NONE)
{
repeat (repeat_mode, &x1, width);
repeat (repeat_mode, &y1, height);
repeat (repeat_mode, &x2, width);
repeat (repeat_mode, &y2, height);
 
tl = get_pixel (image, x1, y1, FALSE);
bl = get_pixel (image, x1, y2, FALSE);
tr = get_pixel (image, x2, y1, FALSE);
br = get_pixel (image, x2, y2, FALSE);
}
else
{
tl = get_pixel (image, x1, y1, TRUE);
tr = get_pixel (image, x2, y1, TRUE);
bl = get_pixel (image, x1, y2, TRUE);
br = get_pixel (image, x2, y2, TRUE);
}
 
return bilinear_interpolation (tl, tr, bl, br, distx, disty);
}
 
static uint32_t *
bits_image_fetch_bilinear_no_repeat_8888 (pixman_iter_t *iter,
const uint32_t *mask)
{
 
pixman_image_t * ima = iter->image;
int offset = iter->x;
int line = iter->y++;
int width = iter->width;
uint32_t * buffer = iter->buffer;
 
bits_image_t *bits = &ima->bits;
pixman_fixed_t x_top, x_bottom, x;
pixman_fixed_t ux_top, ux_bottom, ux;
pixman_vector_t v;
uint32_t top_mask, bottom_mask;
uint32_t *top_row;
uint32_t *bottom_row;
uint32_t *end;
uint32_t zero[2] = { 0, 0 };
uint32_t one = 1;
int y, y1, y2;
int disty;
int mask_inc;
int w;
 
/* reference point is the center of the pixel */
v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
 
if (!pixman_transform_point_3d (bits->common.transform, &v))
return iter->buffer;
 
ux = ux_top = ux_bottom = bits->common.transform->matrix[0][0];
x = x_top = x_bottom = v.vector[0] - pixman_fixed_1/2;
 
y = v.vector[1] - pixman_fixed_1/2;
disty = pixman_fixed_to_bilinear_weight (y);
 
/* Load the pointers to the first and second lines from the source
* image that bilinear code must read.
*
* The main trick in this code is about the check if any line are
* outside of the image;
*
* When I realize that a line (any one) is outside, I change
* the pointer to a dummy area with zeros. Once I change this, I
* must be sure the pointer will not change, so I set the
* variables to each pointer increments inside the loop.
*/
y1 = pixman_fixed_to_int (y);
y2 = y1 + 1;
 
if (y1 < 0 || y1 >= bits->height)
{
top_row = zero;
x_top = 0;
ux_top = 0;
}
else
{
top_row = bits->bits + y1 * bits->rowstride;
x_top = x;
ux_top = ux;
}
 
if (y2 < 0 || y2 >= bits->height)
{
bottom_row = zero;
x_bottom = 0;
ux_bottom = 0;
}
else
{
bottom_row = bits->bits + y2 * bits->rowstride;
x_bottom = x;
ux_bottom = ux;
}
 
/* Instead of checking whether the operation uses the mast in
* each loop iteration, verify this only once and prepare the
* variables to make the code smaller inside the loop.
*/
if (!mask)
{
mask_inc = 0;
mask = &one;
}
else
{
/* If have a mask, prepare the variables to check it */
mask_inc = 1;
}
 
/* If both are zero, then the whole thing is zero */
if (top_row == zero && bottom_row == zero)
{
memset (buffer, 0, width * sizeof (uint32_t));
return iter->buffer;
}
else if (bits->format == PIXMAN_x8r8g8b8)
{
if (top_row == zero)
{
top_mask = 0;
bottom_mask = 0xff000000;
}
else if (bottom_row == zero)
{
top_mask = 0xff000000;
bottom_mask = 0;
}
else
{
top_mask = 0xff000000;
bottom_mask = 0xff000000;
}
}
else
{
top_mask = 0;
bottom_mask = 0;
}
 
end = buffer + width;
 
/* Zero fill to the left of the image */
while (buffer < end && x < pixman_fixed_minus_1)
{
*buffer++ = 0;
x += ux;
x_top += ux_top;
x_bottom += ux_bottom;
mask += mask_inc;
}
 
/* Left edge
*/
while (buffer < end && x < 0)
{
uint32_t tr, br;
int32_t distx;
 
tr = top_row[pixman_fixed_to_int (x_top) + 1] | top_mask;
br = bottom_row[pixman_fixed_to_int (x_bottom) + 1] | bottom_mask;
 
distx = pixman_fixed_to_bilinear_weight (x);
 
*buffer++ = bilinear_interpolation (0, tr, 0, br, distx, disty);
 
x += ux;
x_top += ux_top;
x_bottom += ux_bottom;
mask += mask_inc;
}
 
/* Main part */
w = pixman_int_to_fixed (bits->width - 1);
 
while (buffer < end && x < w)
{
if (*mask)
{
uint32_t tl, tr, bl, br;
int32_t distx;
 
tl = top_row [pixman_fixed_to_int (x_top)] | top_mask;
tr = top_row [pixman_fixed_to_int (x_top) + 1] | top_mask;
bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask;
br = bottom_row [pixman_fixed_to_int (x_bottom) + 1] | bottom_mask;
 
distx = pixman_fixed_to_bilinear_weight (x);
 
*buffer = bilinear_interpolation (tl, tr, bl, br, distx, disty);
}
 
buffer++;
x += ux;
x_top += ux_top;
x_bottom += ux_bottom;
mask += mask_inc;
}
 
/* Right Edge */
w = pixman_int_to_fixed (bits->width);
while (buffer < end && x < w)
{
if (*mask)
{
uint32_t tl, bl;
int32_t distx;
 
tl = top_row [pixman_fixed_to_int (x_top)] | top_mask;
bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask;
 
distx = pixman_fixed_to_bilinear_weight (x);
 
*buffer = bilinear_interpolation (tl, 0, bl, 0, distx, disty);
}
 
buffer++;
x += ux;
x_top += ux_top;
x_bottom += ux_bottom;
mask += mask_inc;
}
 
/* Zero fill to the left of the image */
while (buffer < end)
*buffer++ = 0;
 
return iter->buffer;
}
 
static force_inline uint32_t
bits_image_fetch_pixel_convolution (bits_image_t *image,
pixman_fixed_t x,
pixman_fixed_t y,
get_pixel_t get_pixel)
{
pixman_fixed_t *params = image->common.filter_params;
int x_off = (params[0] - pixman_fixed_1) >> 1;
int y_off = (params[1] - pixman_fixed_1) >> 1;
int32_t cwidth = pixman_fixed_to_int (params[0]);
int32_t cheight = pixman_fixed_to_int (params[1]);
int32_t i, j, x1, x2, y1, y2;
pixman_repeat_t repeat_mode = image->common.repeat;
int width = image->width;
int height = image->height;
int srtot, sgtot, sbtot, satot;
 
params += 2;
 
x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off);
y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off);
x2 = x1 + cwidth;
y2 = y1 + cheight;
 
srtot = sgtot = sbtot = satot = 0;
 
for (i = y1; i < y2; ++i)
{
for (j = x1; j < x2; ++j)
{
int rx = j;
int ry = i;
 
pixman_fixed_t f = *params;
 
if (f)
{
uint32_t pixel;
 
if (repeat_mode != PIXMAN_REPEAT_NONE)
{
repeat (repeat_mode, &rx, width);
repeat (repeat_mode, &ry, height);
 
pixel = get_pixel (image, rx, ry, FALSE);
}
else
{
pixel = get_pixel (image, rx, ry, TRUE);
}
 
srtot += (int)RED_8 (pixel) * f;
sgtot += (int)GREEN_8 (pixel) * f;
sbtot += (int)BLUE_8 (pixel) * f;
satot += (int)ALPHA_8 (pixel) * f;
}
 
params++;
}
}
 
satot = (satot + 0x8000) >> 16;
srtot = (srtot + 0x8000) >> 16;
sgtot = (sgtot + 0x8000) >> 16;
sbtot = (sbtot + 0x8000) >> 16;
 
satot = CLIP (satot, 0, 0xff);
srtot = CLIP (srtot, 0, 0xff);
sgtot = CLIP (sgtot, 0, 0xff);
sbtot = CLIP (sbtot, 0, 0xff);
 
return ((satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot));
}
 
static uint32_t
bits_image_fetch_pixel_separable_convolution (bits_image_t *image,
pixman_fixed_t x,
pixman_fixed_t y,
get_pixel_t get_pixel)
{
pixman_fixed_t *params = image->common.filter_params;
pixman_repeat_t repeat_mode = image->common.repeat;
int width = image->width;
int height = image->height;
int cwidth = pixman_fixed_to_int (params[0]);
int cheight = pixman_fixed_to_int (params[1]);
int x_phase_bits = pixman_fixed_to_int (params[2]);
int y_phase_bits = pixman_fixed_to_int (params[3]);
int x_phase_shift = 16 - x_phase_bits;
int y_phase_shift = 16 - y_phase_bits;
int x_off = ((cwidth << 16) - pixman_fixed_1) >> 1;
int y_off = ((cheight << 16) - pixman_fixed_1) >> 1;
pixman_fixed_t *y_params;
int srtot, sgtot, sbtot, satot;
int32_t x1, x2, y1, y2;
int32_t px, py;
int i, j;
 
/* Round x and y to the middle of the closest phase before continuing. This
* ensures that the convolution matrix is aligned right, since it was
* positioned relative to a particular phase (and not relative to whatever
* exact fraction we happen to get here).
*/
x = ((x >> x_phase_shift) << x_phase_shift) + ((1 << x_phase_shift) >> 1);
y = ((y >> y_phase_shift) << y_phase_shift) + ((1 << y_phase_shift) >> 1);
 
px = (x & 0xffff) >> x_phase_shift;
py = (y & 0xffff) >> y_phase_shift;
 
y_params = params + 4 + (1 << x_phase_bits) * cwidth + py * cheight;
 
x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off);
y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off);
x2 = x1 + cwidth;
y2 = y1 + cheight;
 
srtot = sgtot = sbtot = satot = 0;
 
for (i = y1; i < y2; ++i)
{
pixman_fixed_48_16_t fy = *y_params++;
pixman_fixed_t *x_params = params + 4 + px * cwidth;
 
if (fy)
{
for (j = x1; j < x2; ++j)
{
pixman_fixed_t fx = *x_params++;
int rx = j;
int ry = i;
 
if (fx)
{
pixman_fixed_t f;
uint32_t pixel;
 
if (repeat_mode != PIXMAN_REPEAT_NONE)
{
repeat (repeat_mode, &rx, width);
repeat (repeat_mode, &ry, height);
 
pixel = get_pixel (image, rx, ry, FALSE);
}
else
{
pixel = get_pixel (image, rx, ry, TRUE);
}
 
f = (fy * fx + 0x8000) >> 16;
 
srtot += (int)RED_8 (pixel) * f;
sgtot += (int)GREEN_8 (pixel) * f;
sbtot += (int)BLUE_8 (pixel) * f;
satot += (int)ALPHA_8 (pixel) * f;
}
}
}
}
 
satot = (satot + 0x8000) >> 16;
srtot = (srtot + 0x8000) >> 16;
sgtot = (sgtot + 0x8000) >> 16;
sbtot = (sbtot + 0x8000) >> 16;
 
satot = CLIP (satot, 0, 0xff);
srtot = CLIP (srtot, 0, 0xff);
sgtot = CLIP (sgtot, 0, 0xff);
sbtot = CLIP (sbtot, 0, 0xff);
 
return ((satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot));
}
 
static force_inline uint32_t
bits_image_fetch_pixel_filtered (bits_image_t *image,
pixman_fixed_t x,
pixman_fixed_t y,
get_pixel_t get_pixel)
{
switch (image->common.filter)
{
case PIXMAN_FILTER_NEAREST:
case PIXMAN_FILTER_FAST:
return bits_image_fetch_pixel_nearest (image, x, y, get_pixel);
break;
 
case PIXMAN_FILTER_BILINEAR:
case PIXMAN_FILTER_GOOD:
case PIXMAN_FILTER_BEST:
return bits_image_fetch_pixel_bilinear (image, x, y, get_pixel);
break;
 
case PIXMAN_FILTER_CONVOLUTION:
return bits_image_fetch_pixel_convolution (image, x, y, get_pixel);
break;
 
case PIXMAN_FILTER_SEPARABLE_CONVOLUTION:
return bits_image_fetch_pixel_separable_convolution (image, x, y, get_pixel);
break;
 
default:
break;
}
 
return 0;
}
 
static uint32_t *
bits_image_fetch_affine_no_alpha (pixman_iter_t * iter,
const uint32_t * mask)
{
pixman_image_t *image = iter->image;
int offset = iter->x;
int line = iter->y++;
int width = iter->width;
uint32_t * buffer = iter->buffer;
 
pixman_fixed_t x, y;
pixman_fixed_t ux, uy;
pixman_vector_t v;
int i;
 
/* reference point is the center of the pixel */
v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
 
if (image->common.transform)
{
if (!pixman_transform_point_3d (image->common.transform, &v))
return iter->buffer;
 
ux = image->common.transform->matrix[0][0];
uy = image->common.transform->matrix[1][0];
}
else
{
ux = pixman_fixed_1;
uy = 0;
}
 
x = v.vector[0];
y = v.vector[1];
 
for (i = 0; i < width; ++i)
{
if (!mask || mask[i])
{
buffer[i] = bits_image_fetch_pixel_filtered (
&image->bits, x, y, fetch_pixel_no_alpha);
}
 
x += ux;
y += uy;
}
 
return buffer;
}
 
/* General fetcher */
static force_inline uint32_t
fetch_pixel_general (bits_image_t *image, int x, int y, pixman_bool_t check_bounds)
{
uint32_t pixel;
 
if (check_bounds &&
(x < 0 || x >= image->width || y < 0 || y >= image->height))
{
return 0;
}
 
pixel = image->fetch_pixel_32 (image, x, y);
 
if (image->common.alpha_map)
{
uint32_t pixel_a;
 
x -= image->common.alpha_origin_x;
y -= image->common.alpha_origin_y;
 
if (x < 0 || x >= image->common.alpha_map->width ||
y < 0 || y >= image->common.alpha_map->height)
{
pixel_a = 0;
}
else
{
pixel_a = image->common.alpha_map->fetch_pixel_32 (
image->common.alpha_map, x, y);
 
pixel_a = ALPHA_8 (pixel_a);
}
 
pixel &= 0x00ffffff;
pixel |= (pixel_a << 24);
}
 
return pixel;
}
 
static uint32_t *
bits_image_fetch_general (pixman_iter_t *iter,
const uint32_t *mask)
{
pixman_image_t *image = iter->image;
int offset = iter->x;
int line = iter->y++;
int width = iter->width;
uint32_t * buffer = iter->buffer;
 
pixman_fixed_t x, y, w;
pixman_fixed_t ux, uy, uw;
pixman_vector_t v;
int i;
 
/* reference point is the center of the pixel */
v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
 
if (image->common.transform)
{
if (!pixman_transform_point_3d (image->common.transform, &v))
return buffer;
 
ux = image->common.transform->matrix[0][0];
uy = image->common.transform->matrix[1][0];
uw = image->common.transform->matrix[2][0];
}
else
{
ux = pixman_fixed_1;
uy = 0;
uw = 0;
}
 
x = v.vector[0];
y = v.vector[1];
w = v.vector[2];
 
for (i = 0; i < width; ++i)
{
pixman_fixed_t x0, y0;
 
if (!mask || mask[i])
{
if (w != 0)
{
x0 = ((pixman_fixed_48_16_t)x << 16) / w;
y0 = ((pixman_fixed_48_16_t)y << 16) / w;
}
else
{
x0 = 0;
y0 = 0;
}
 
buffer[i] = bits_image_fetch_pixel_filtered (
&image->bits, x0, y0, fetch_pixel_general);
}
 
x += ux;
y += uy;
w += uw;
}
 
return buffer;
}
 
typedef uint32_t (* convert_pixel_t) (const uint8_t *row, int x);
 
static force_inline void
bits_image_fetch_separable_convolution_affine (pixman_image_t * image,
int offset,
int line,
int width,
uint32_t * buffer,
const uint32_t * mask,
 
convert_pixel_t convert_pixel,
pixman_format_code_t format,
pixman_repeat_t repeat_mode)
{
bits_image_t *bits = &image->bits;
pixman_fixed_t *params = image->common.filter_params;
int cwidth = pixman_fixed_to_int (params[0]);
int cheight = pixman_fixed_to_int (params[1]);
int x_off = ((cwidth << 16) - pixman_fixed_1) >> 1;
int y_off = ((cheight << 16) - pixman_fixed_1) >> 1;
int x_phase_bits = pixman_fixed_to_int (params[2]);
int y_phase_bits = pixman_fixed_to_int (params[3]);
int x_phase_shift = 16 - x_phase_bits;
int y_phase_shift = 16 - y_phase_bits;
pixman_fixed_t vx, vy;
pixman_fixed_t ux, uy;
pixman_vector_t v;
int k;
 
/* reference point is the center of the pixel */
v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
 
if (!pixman_transform_point_3d (image->common.transform, &v))
return;
 
ux = image->common.transform->matrix[0][0];
uy = image->common.transform->matrix[1][0];
 
vx = v.vector[0];
vy = v.vector[1];
 
for (k = 0; k < width; ++k)
{
pixman_fixed_t *y_params;
int satot, srtot, sgtot, sbtot;
pixman_fixed_t x, y;
int32_t x1, x2, y1, y2;
int32_t px, py;
int i, j;
 
if (mask && !mask[k])
goto next;
 
/* Round x and y to the middle of the closest phase before continuing. This
* ensures that the convolution matrix is aligned right, since it was
* positioned relative to a particular phase (and not relative to whatever
* exact fraction we happen to get here).
*/
x = ((vx >> x_phase_shift) << x_phase_shift) + ((1 << x_phase_shift) >> 1);
y = ((vy >> y_phase_shift) << y_phase_shift) + ((1 << y_phase_shift) >> 1);
 
px = (x & 0xffff) >> x_phase_shift;
py = (y & 0xffff) >> y_phase_shift;
 
x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off);
y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off);
x2 = x1 + cwidth;
y2 = y1 + cheight;
 
satot = srtot = sgtot = sbtot = 0;
 
y_params = params + 4 + (1 << x_phase_bits) * cwidth + py * cheight;
 
for (i = y1; i < y2; ++i)
{
pixman_fixed_t fy = *y_params++;
 
if (fy)
{
pixman_fixed_t *x_params = params + 4 + px * cwidth;
 
for (j = x1; j < x2; ++j)
{
pixman_fixed_t fx = *x_params++;
int rx = j;
int ry = i;
if (fx)
{
pixman_fixed_t f;
uint32_t pixel, mask;
uint8_t *row;
 
mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000;
 
if (repeat_mode != PIXMAN_REPEAT_NONE)
{
repeat (repeat_mode, &rx, bits->width);
repeat (repeat_mode, &ry, bits->height);
 
row = (uint8_t *)bits->bits + bits->rowstride * 4 * ry;
pixel = convert_pixel (row, rx) | mask;
}
else
{
if (rx < 0 || ry < 0 || rx >= bits->width || ry >= bits->height)
{
pixel = 0;
}
else
{
row = (uint8_t *)bits->bits + bits->rowstride * 4 * ry;
pixel = convert_pixel (row, rx) | mask;
}
}
 
f = ((pixman_fixed_32_32_t)fx * fy + 0x8000) >> 16;
srtot += (int)RED_8 (pixel) * f;
sgtot += (int)GREEN_8 (pixel) * f;
sbtot += (int)BLUE_8 (pixel) * f;
satot += (int)ALPHA_8 (pixel) * f;
}
}
}
}
 
satot = (satot + 0x8000) >> 16;
srtot = (srtot + 0x8000) >> 16;
sgtot = (sgtot + 0x8000) >> 16;
sbtot = (sbtot + 0x8000) >> 16;
 
satot = CLIP (satot, 0, 0xff);
srtot = CLIP (srtot, 0, 0xff);
sgtot = CLIP (sgtot, 0, 0xff);
sbtot = CLIP (sbtot, 0, 0xff);
 
buffer[k] = (satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot << 0);
 
next:
vx += ux;
vy += uy;
}
}
 
static const uint8_t zero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
static force_inline void
bits_image_fetch_bilinear_affine (pixman_image_t * image,
int offset,
int line,
int width,
uint32_t * buffer,
const uint32_t * mask,
 
convert_pixel_t convert_pixel,
pixman_format_code_t format,
pixman_repeat_t repeat_mode)
{
pixman_fixed_t x, y;
pixman_fixed_t ux, uy;
pixman_vector_t v;
bits_image_t *bits = &image->bits;
int i;
 
/* reference point is the center of the pixel */
v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
 
if (!pixman_transform_point_3d (image->common.transform, &v))
return;
 
ux = image->common.transform->matrix[0][0];
uy = image->common.transform->matrix[1][0];
 
x = v.vector[0];
y = v.vector[1];
 
for (i = 0; i < width; ++i)
{
int x1, y1, x2, y2;
uint32_t tl, tr, bl, br;
int32_t distx, disty;
int width = image->bits.width;
int height = image->bits.height;
const uint8_t *row1;
const uint8_t *row2;
 
if (mask && !mask[i])
goto next;
 
x1 = x - pixman_fixed_1 / 2;
y1 = y - pixman_fixed_1 / 2;
 
distx = pixman_fixed_to_bilinear_weight (x1);
disty = pixman_fixed_to_bilinear_weight (y1);
 
y1 = pixman_fixed_to_int (y1);
y2 = y1 + 1;
x1 = pixman_fixed_to_int (x1);
x2 = x1 + 1;
 
if (repeat_mode != PIXMAN_REPEAT_NONE)
{
uint32_t mask;
 
mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000;
 
repeat (repeat_mode, &x1, width);
repeat (repeat_mode, &y1, height);
repeat (repeat_mode, &x2, width);
repeat (repeat_mode, &y2, height);
 
row1 = (uint8_t *)bits->bits + bits->rowstride * 4 * y1;
row2 = (uint8_t *)bits->bits + bits->rowstride * 4 * y2;
 
tl = convert_pixel (row1, x1) | mask;
tr = convert_pixel (row1, x2) | mask;
bl = convert_pixel (row2, x1) | mask;
br = convert_pixel (row2, x2) | mask;
}
else
{
uint32_t mask1, mask2;
int bpp;
 
/* Note: PIXMAN_FORMAT_BPP() returns an unsigned value,
* which means if you use it in expressions, those
* expressions become unsigned themselves. Since
* the variables below can be negative in some cases,
* that will lead to crashes on 64 bit architectures.
*
* So this line makes sure bpp is signed
*/
bpp = PIXMAN_FORMAT_BPP (format);
 
if (x1 >= width || x2 < 0 || y1 >= height || y2 < 0)
{
buffer[i] = 0;
goto next;
}
 
if (y2 == 0)
{
row1 = zero;
mask1 = 0;
}
else
{
row1 = (uint8_t *)bits->bits + bits->rowstride * 4 * y1;
row1 += bpp / 8 * x1;
 
mask1 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000;
}
 
if (y1 == height - 1)
{
row2 = zero;
mask2 = 0;
}
else
{
row2 = (uint8_t *)bits->bits + bits->rowstride * 4 * y2;
row2 += bpp / 8 * x1;
 
mask2 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000;
}
 
if (x2 == 0)
{
tl = 0;
bl = 0;
}
else
{
tl = convert_pixel (row1, 0) | mask1;
bl = convert_pixel (row2, 0) | mask2;
}
 
if (x1 == width - 1)
{
tr = 0;
br = 0;
}
else
{
tr = convert_pixel (row1, 1) | mask1;
br = convert_pixel (row2, 1) | mask2;
}
}
 
buffer[i] = bilinear_interpolation (
tl, tr, bl, br, distx, disty);
 
next:
x += ux;
y += uy;
}
}
 
static force_inline void
bits_image_fetch_nearest_affine (pixman_image_t * image,
int offset,
int line,
int width,
uint32_t * buffer,
const uint32_t * mask,
convert_pixel_t convert_pixel,
pixman_format_code_t format,
pixman_repeat_t repeat_mode)
{
pixman_fixed_t x, y;
pixman_fixed_t ux, uy;
pixman_vector_t v;
bits_image_t *bits = &image->bits;
int i;
 
/* reference point is the center of the pixel */
v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
 
if (!pixman_transform_point_3d (image->common.transform, &v))
return;
 
ux = image->common.transform->matrix[0][0];
uy = image->common.transform->matrix[1][0];
 
x = v.vector[0];
y = v.vector[1];
 
for (i = 0; i < width; ++i)
{
int width, height, x0, y0;
const uint8_t *row;
 
if (mask && !mask[i])
goto next;
width = image->bits.width;
height = image->bits.height;
x0 = pixman_fixed_to_int (x - pixman_fixed_e);
y0 = pixman_fixed_to_int (y - pixman_fixed_e);
 
if (repeat_mode == PIXMAN_REPEAT_NONE &&
(y0 < 0 || y0 >= height || x0 < 0 || x0 >= width))
{
buffer[i] = 0;
}
else
{
uint32_t mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000;
 
if (repeat_mode != PIXMAN_REPEAT_NONE)
{
repeat (repeat_mode, &x0, width);
repeat (repeat_mode, &y0, height);
}
 
row = (uint8_t *)bits->bits + bits->rowstride * 4 * y0;
 
buffer[i] = convert_pixel (row, x0) | mask;
}
 
next:
x += ux;
y += uy;
}
}
 
static force_inline uint32_t
convert_a8r8g8b8 (const uint8_t *row, int x)
{
return *(((uint32_t *)row) + x);
}
 
static force_inline uint32_t
convert_x8r8g8b8 (const uint8_t *row, int x)
{
return *(((uint32_t *)row) + x);
}
 
static force_inline uint32_t
convert_a8 (const uint8_t *row, int x)
{
return *(row + x) << 24;
}
 
static force_inline uint32_t
convert_r5g6b5 (const uint8_t *row, int x)
{
return convert_0565_to_0888 (*((uint16_t *)row + x));
}
 
#define MAKE_SEPARABLE_CONVOLUTION_FETCHER(name, format, repeat_mode) \
static uint32_t * \
bits_image_fetch_separable_convolution_affine_ ## name (pixman_iter_t *iter, \
const uint32_t * mask) \
{ \
bits_image_fetch_separable_convolution_affine ( \
iter->image, \
iter->x, iter->y++, \
iter->width, \
iter->buffer, mask, \
convert_ ## format, \
PIXMAN_ ## format, \
repeat_mode); \
\
return iter->buffer; \
}
 
#define MAKE_BILINEAR_FETCHER(name, format, repeat_mode) \
static uint32_t * \
bits_image_fetch_bilinear_affine_ ## name (pixman_iter_t *iter, \
const uint32_t * mask) \
{ \
bits_image_fetch_bilinear_affine (iter->image, \
iter->x, iter->y++, \
iter->width, \
iter->buffer, mask, \
convert_ ## format, \
PIXMAN_ ## format, \
repeat_mode); \
return iter->buffer; \
}
 
#define MAKE_NEAREST_FETCHER(name, format, repeat_mode) \
static uint32_t * \
bits_image_fetch_nearest_affine_ ## name (pixman_iter_t *iter, \
const uint32_t * mask) \
{ \
bits_image_fetch_nearest_affine (iter->image, \
iter->x, iter->y++, \
iter->width, \
iter->buffer, mask, \
convert_ ## format, \
PIXMAN_ ## format, \
repeat_mode); \
return iter->buffer; \
}
 
#define MAKE_FETCHERS(name, format, repeat_mode) \
MAKE_NEAREST_FETCHER (name, format, repeat_mode) \
MAKE_BILINEAR_FETCHER (name, format, repeat_mode) \
MAKE_SEPARABLE_CONVOLUTION_FETCHER (name, format, repeat_mode)
 
MAKE_FETCHERS (pad_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_PAD)
MAKE_FETCHERS (none_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_NONE)
MAKE_FETCHERS (reflect_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_REFLECT)
MAKE_FETCHERS (normal_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_NORMAL)
MAKE_FETCHERS (pad_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_PAD)
MAKE_FETCHERS (none_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_NONE)
MAKE_FETCHERS (reflect_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_REFLECT)
MAKE_FETCHERS (normal_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_NORMAL)
MAKE_FETCHERS (pad_a8, a8, PIXMAN_REPEAT_PAD)
MAKE_FETCHERS (none_a8, a8, PIXMAN_REPEAT_NONE)
MAKE_FETCHERS (reflect_a8, a8, PIXMAN_REPEAT_REFLECT)
MAKE_FETCHERS (normal_a8, a8, PIXMAN_REPEAT_NORMAL)
MAKE_FETCHERS (pad_r5g6b5, r5g6b5, PIXMAN_REPEAT_PAD)
MAKE_FETCHERS (none_r5g6b5, r5g6b5, PIXMAN_REPEAT_NONE)
MAKE_FETCHERS (reflect_r5g6b5, r5g6b5, PIXMAN_REPEAT_REFLECT)
MAKE_FETCHERS (normal_r5g6b5, r5g6b5, PIXMAN_REPEAT_NORMAL)
 
static void
replicate_pixel_32 (bits_image_t * bits,
int x,
int y,
int width,
uint32_t * buffer)
{
uint32_t color;
uint32_t *end;
 
color = bits->fetch_pixel_32 (bits, x, y);
 
end = buffer + width;
while (buffer < end)
*(buffer++) = color;
}
 
static void
replicate_pixel_float (bits_image_t * bits,
int x,
int y,
int width,
uint32_t * b)
{
argb_t color;
argb_t *buffer = (argb_t *)b;
argb_t *end;
 
color = bits->fetch_pixel_float (bits, x, y);
 
end = buffer + width;
while (buffer < end)
*(buffer++) = color;
}
 
static void
bits_image_fetch_untransformed_repeat_none (bits_image_t *image,
pixman_bool_t wide,
int x,
int y,
int width,
uint32_t * buffer)
{
uint32_t w;
 
if (y < 0 || y >= image->height)
{
memset (buffer, 0, width * (wide? sizeof (argb_t) : 4));
return;
}
 
if (x < 0)
{
w = MIN (width, -x);
 
memset (buffer, 0, w * (wide ? sizeof (argb_t) : 4));
 
width -= w;
buffer += w * (wide? 4 : 1);
x += w;
}
 
if (x < image->width)
{
w = MIN (width, image->width - x);
 
if (wide)
image->fetch_scanline_float ((pixman_image_t *)image, x, y, w, buffer, NULL);
else
image->fetch_scanline_32 ((pixman_image_t *)image, x, y, w, buffer, NULL);
 
width -= w;
buffer += w * (wide? 4 : 1);
x += w;
}
 
memset (buffer, 0, width * (wide ? sizeof (argb_t) : 4));
}
 
static void
bits_image_fetch_untransformed_repeat_normal (bits_image_t *image,
pixman_bool_t wide,
int x,
int y,
int width,
uint32_t * buffer)
{
uint32_t w;
 
while (y < 0)
y += image->height;
 
while (y >= image->height)
y -= image->height;
 
if (image->width == 1)
{
if (wide)
replicate_pixel_float (image, 0, y, width, buffer);
else
replicate_pixel_32 (image, 0, y, width, buffer);
 
return;
}
 
while (width)
{
while (x < 0)
x += image->width;
while (x >= image->width)
x -= image->width;
 
w = MIN (width, image->width - x);
 
if (wide)
image->fetch_scanline_float ((pixman_image_t *)image, x, y, w, buffer, NULL);
else
image->fetch_scanline_32 ((pixman_image_t *)image, x, y, w, buffer, NULL);
 
buffer += w * (wide? 4 : 1);
x += w;
width -= w;
}
}
 
static uint32_t *
bits_image_fetch_untransformed_32 (pixman_iter_t * iter,
const uint32_t *mask)
{
pixman_image_t *image = iter->image;
int x = iter->x;
int y = iter->y;
int width = iter->width;
uint32_t * buffer = iter->buffer;
 
if (image->common.repeat == PIXMAN_REPEAT_NONE)
{
bits_image_fetch_untransformed_repeat_none (
&image->bits, FALSE, x, y, width, buffer);
}
else
{
bits_image_fetch_untransformed_repeat_normal (
&image->bits, FALSE, x, y, width, buffer);
}
 
iter->y++;
return buffer;
}
 
static uint32_t *
bits_image_fetch_untransformed_float (pixman_iter_t * iter,
const uint32_t *mask)
{
pixman_image_t *image = iter->image;
int x = iter->x;
int y = iter->y;
int width = iter->width;
uint32_t * buffer = iter->buffer;
 
if (image->common.repeat == PIXMAN_REPEAT_NONE)
{
bits_image_fetch_untransformed_repeat_none (
&image->bits, TRUE, x, y, width, buffer);
}
else
{
bits_image_fetch_untransformed_repeat_normal (
&image->bits, TRUE, x, y, width, buffer);
}
 
iter->y++;
return buffer;
}
 
typedef struct
{
pixman_format_code_t format;
uint32_t flags;
pixman_iter_get_scanline_t get_scanline_32;
pixman_iter_get_scanline_t get_scanline_float;
} fetcher_info_t;
 
static const fetcher_info_t fetcher_info[] =
{
{ PIXMAN_any,
(FAST_PATH_NO_ALPHA_MAP |
FAST_PATH_ID_TRANSFORM |
FAST_PATH_NO_CONVOLUTION_FILTER |
FAST_PATH_NO_PAD_REPEAT |
FAST_PATH_NO_REFLECT_REPEAT),
bits_image_fetch_untransformed_32,
bits_image_fetch_untransformed_float
},
 
#define FAST_BILINEAR_FLAGS \
(FAST_PATH_NO_ALPHA_MAP | \
FAST_PATH_NO_ACCESSORS | \
FAST_PATH_HAS_TRANSFORM | \
FAST_PATH_AFFINE_TRANSFORM | \
FAST_PATH_X_UNIT_POSITIVE | \
FAST_PATH_Y_UNIT_ZERO | \
FAST_PATH_NONE_REPEAT | \
FAST_PATH_BILINEAR_FILTER)
 
{ PIXMAN_a8r8g8b8,
FAST_BILINEAR_FLAGS,
bits_image_fetch_bilinear_no_repeat_8888,
_pixman_image_get_scanline_generic_float
},
 
{ PIXMAN_x8r8g8b8,
FAST_BILINEAR_FLAGS,
bits_image_fetch_bilinear_no_repeat_8888,
_pixman_image_get_scanline_generic_float
},
 
#define GENERAL_BILINEAR_FLAGS \
(FAST_PATH_NO_ALPHA_MAP | \
FAST_PATH_NO_ACCESSORS | \
FAST_PATH_HAS_TRANSFORM | \
FAST_PATH_AFFINE_TRANSFORM | \
FAST_PATH_BILINEAR_FILTER)
 
#define GENERAL_NEAREST_FLAGS \
(FAST_PATH_NO_ALPHA_MAP | \
FAST_PATH_NO_ACCESSORS | \
FAST_PATH_HAS_TRANSFORM | \
FAST_PATH_AFFINE_TRANSFORM | \
FAST_PATH_NEAREST_FILTER)
 
#define GENERAL_SEPARABLE_CONVOLUTION_FLAGS \
(FAST_PATH_NO_ALPHA_MAP | \
FAST_PATH_NO_ACCESSORS | \
FAST_PATH_HAS_TRANSFORM | \
FAST_PATH_AFFINE_TRANSFORM | \
FAST_PATH_SEPARABLE_CONVOLUTION_FILTER)
#define SEPARABLE_CONVOLUTION_AFFINE_FAST_PATH(name, format, repeat) \
{ PIXMAN_ ## format, \
GENERAL_SEPARABLE_CONVOLUTION_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \
bits_image_fetch_separable_convolution_affine_ ## name, \
_pixman_image_get_scanline_generic_float \
},
 
#define BILINEAR_AFFINE_FAST_PATH(name, format, repeat) \
{ PIXMAN_ ## format, \
GENERAL_BILINEAR_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \
bits_image_fetch_bilinear_affine_ ## name, \
_pixman_image_get_scanline_generic_float \
},
 
#define NEAREST_AFFINE_FAST_PATH(name, format, repeat) \
{ PIXMAN_ ## format, \
GENERAL_NEAREST_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \
bits_image_fetch_nearest_affine_ ## name, \
_pixman_image_get_scanline_generic_float \
},
 
#define AFFINE_FAST_PATHS(name, format, repeat) \
SEPARABLE_CONVOLUTION_AFFINE_FAST_PATH(name, format, repeat) \
BILINEAR_AFFINE_FAST_PATH(name, format, repeat) \
NEAREST_AFFINE_FAST_PATH(name, format, repeat)
AFFINE_FAST_PATHS (pad_a8r8g8b8, a8r8g8b8, PAD)
AFFINE_FAST_PATHS (none_a8r8g8b8, a8r8g8b8, NONE)
AFFINE_FAST_PATHS (reflect_a8r8g8b8, a8r8g8b8, REFLECT)
AFFINE_FAST_PATHS (normal_a8r8g8b8, a8r8g8b8, NORMAL)
AFFINE_FAST_PATHS (pad_x8r8g8b8, x8r8g8b8, PAD)
AFFINE_FAST_PATHS (none_x8r8g8b8, x8r8g8b8, NONE)
AFFINE_FAST_PATHS (reflect_x8r8g8b8, x8r8g8b8, REFLECT)
AFFINE_FAST_PATHS (normal_x8r8g8b8, x8r8g8b8, NORMAL)
AFFINE_FAST_PATHS (pad_a8, a8, PAD)
AFFINE_FAST_PATHS (none_a8, a8, NONE)
AFFINE_FAST_PATHS (reflect_a8, a8, REFLECT)
AFFINE_FAST_PATHS (normal_a8, a8, NORMAL)
AFFINE_FAST_PATHS (pad_r5g6b5, r5g6b5, PAD)
AFFINE_FAST_PATHS (none_r5g6b5, r5g6b5, NONE)
AFFINE_FAST_PATHS (reflect_r5g6b5, r5g6b5, REFLECT)
AFFINE_FAST_PATHS (normal_r5g6b5, r5g6b5, NORMAL)
 
/* Affine, no alpha */
{ PIXMAN_any,
(FAST_PATH_NO_ALPHA_MAP | FAST_PATH_HAS_TRANSFORM | FAST_PATH_AFFINE_TRANSFORM),
bits_image_fetch_affine_no_alpha,
_pixman_image_get_scanline_generic_float
},
 
/* General */
{ PIXMAN_any,
0,
bits_image_fetch_general,
_pixman_image_get_scanline_generic_float
},
 
{ PIXMAN_null },
};
 
static void
bits_image_property_changed (pixman_image_t *image)
{
_pixman_bits_image_setup_accessors (&image->bits);
}
 
void
_pixman_bits_image_src_iter_init (pixman_image_t *image, pixman_iter_t *iter)
{
pixman_format_code_t format = image->common.extended_format_code;
uint32_t flags = image->common.flags;
const fetcher_info_t *info;
 
for (info = fetcher_info; info->format != PIXMAN_null; ++info)
{
if ((info->format == format || info->format == PIXMAN_any) &&
(info->flags & flags) == info->flags)
{
if (iter->iter_flags & ITER_NARROW)
{
iter->get_scanline = info->get_scanline_32;
}
else
{
iter->data = info->get_scanline_32;
iter->get_scanline = info->get_scanline_float;
}
return;
}
}
 
/* Just in case we somehow didn't find a scanline function */
iter->get_scanline = _pixman_iter_get_scanline_noop;
}
 
static uint32_t *
dest_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
{
pixman_image_t *image = iter->image;
int x = iter->x;
int y = iter->y;
int width = iter->width;
uint32_t * buffer = iter->buffer;
 
image->bits.fetch_scanline_32 (image, x, y, width, buffer, mask);
if (image->common.alpha_map)
{
uint32_t *alpha;
 
if ((alpha = malloc (width * sizeof (uint32_t))))
{
int i;
 
x -= image->common.alpha_origin_x;
y -= image->common.alpha_origin_y;
 
image->common.alpha_map->fetch_scanline_32 (
(pixman_image_t *)image->common.alpha_map,
x, y, width, alpha, mask);
 
for (i = 0; i < width; ++i)
{
buffer[i] &= ~0xff000000;
buffer[i] |= (alpha[i] & 0xff000000);
}
 
free (alpha);
}
}
 
return iter->buffer;
}
 
static uint32_t *
dest_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
{
bits_image_t * image = &iter->image->bits;
int x = iter->x;
int y = iter->y;
int width = iter->width;
argb_t * buffer = (argb_t *)iter->buffer;
 
image->fetch_scanline_float (
(pixman_image_t *)image, x, y, width, (uint32_t *)buffer, mask);
if (image->common.alpha_map)
{
argb_t *alpha;
 
if ((alpha = malloc (width * sizeof (argb_t))))
{
int i;
 
x -= image->common.alpha_origin_x;
y -= image->common.alpha_origin_y;
 
image->common.alpha_map->fetch_scanline_float (
(pixman_image_t *)image->common.alpha_map,
x, y, width, (uint32_t *)alpha, mask);
 
for (i = 0; i < width; ++i)
buffer[i].a = alpha[i].a;
 
free (alpha);
}
}
 
return iter->buffer;
}
 
static void
dest_write_back_narrow (pixman_iter_t *iter)
{
bits_image_t * image = &iter->image->bits;
int x = iter->x;
int y = iter->y;
int width = iter->width;
const uint32_t *buffer = iter->buffer;
 
image->store_scanline_32 (image, x, y, width, buffer);
 
if (image->common.alpha_map)
{
x -= image->common.alpha_origin_x;
y -= image->common.alpha_origin_y;
 
image->common.alpha_map->store_scanline_32 (
image->common.alpha_map, x, y, width, buffer);
}
 
iter->y++;
}
 
static void
dest_write_back_wide (pixman_iter_t *iter)
{
bits_image_t * image = &iter->image->bits;
int x = iter->x;
int y = iter->y;
int width = iter->width;
const uint32_t *buffer = iter->buffer;
 
image->store_scanline_float (image, x, y, width, buffer);
 
if (image->common.alpha_map)
{
x -= image->common.alpha_origin_x;
y -= image->common.alpha_origin_y;
 
image->common.alpha_map->store_scanline_float (
image->common.alpha_map, x, y, width, buffer);
}
 
iter->y++;
}
 
void
_pixman_bits_image_dest_iter_init (pixman_image_t *image, pixman_iter_t *iter)
{
if (iter->iter_flags & ITER_NARROW)
{
if ((iter->iter_flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) ==
(ITER_IGNORE_RGB | ITER_IGNORE_ALPHA))
{
iter->get_scanline = _pixman_iter_get_scanline_noop;
}
else
{
iter->get_scanline = dest_get_scanline_narrow;
}
iter->write_back = dest_write_back_narrow;
}
else
{
iter->get_scanline = dest_get_scanline_wide;
iter->write_back = dest_write_back_wide;
}
}
 
static uint32_t *
create_bits (pixman_format_code_t format,
int width,
int height,
int * rowstride_bytes,
pixman_bool_t clear)
{
int stride;
size_t buf_size;
int bpp;
 
/* what follows is a long-winded way, avoiding any possibility of integer
* overflows, of saying:
* stride = ((width * bpp + 0x1f) >> 5) * sizeof (uint32_t);
*/
 
bpp = PIXMAN_FORMAT_BPP (format);
if (_pixman_multiply_overflows_int (width, bpp))
return NULL;
 
stride = width * bpp;
if (_pixman_addition_overflows_int (stride, 0x1f))
return NULL;
 
stride += 0x1f;
stride >>= 5;
 
stride *= sizeof (uint32_t);
 
if (_pixman_multiply_overflows_size (height, stride))
return NULL;
 
buf_size = height * stride;
 
if (rowstride_bytes)
*rowstride_bytes = stride;
 
if (clear)
return calloc (buf_size, 1);
else
return malloc (buf_size);
}
 
pixman_bool_t
_pixman_bits_image_init (pixman_image_t * image,
pixman_format_code_t format,
int width,
int height,
uint32_t * bits,
int rowstride,
pixman_bool_t clear)
{
uint32_t *free_me = NULL;
 
if (!bits && width && height)
{
int rowstride_bytes;
 
free_me = bits = create_bits (format, width, height, &rowstride_bytes, clear);
 
if (!bits)
return FALSE;
 
rowstride = rowstride_bytes / (int) sizeof (uint32_t);
}
 
_pixman_image_init (image);
 
image->type = BITS;
image->bits.format = format;
image->bits.width = width;
image->bits.height = height;
image->bits.bits = bits;
image->bits.free_me = free_me;
image->bits.read_func = NULL;
image->bits.write_func = NULL;
image->bits.rowstride = rowstride;
image->bits.indexed = NULL;
 
image->common.property_changed = bits_image_property_changed;
 
_pixman_image_reset_clip_region (image);
 
return TRUE;
}
 
static pixman_image_t *
create_bits_image_internal (pixman_format_code_t format,
int width,
int height,
uint32_t * bits,
int rowstride_bytes,
pixman_bool_t clear)
{
pixman_image_t *image;
 
/* must be a whole number of uint32_t's
*/
return_val_if_fail (
bits == NULL || (rowstride_bytes % sizeof (uint32_t)) == 0, NULL);
 
return_val_if_fail (PIXMAN_FORMAT_BPP (format) >= PIXMAN_FORMAT_DEPTH (format), NULL);
 
image = _pixman_image_allocate ();
 
if (!image)
return NULL;
 
if (!_pixman_bits_image_init (image, format, width, height, bits,
rowstride_bytes / (int) sizeof (uint32_t),
clear))
{
free (image);
return NULL;
}
 
return image;
}
 
/* If bits is NULL, a buffer will be allocated and initialized to 0 */
PIXMAN_EXPORT pixman_image_t *
pixman_image_create_bits (pixman_format_code_t format,
int width,
int height,
uint32_t * bits,
int rowstride_bytes)
{
return create_bits_image_internal (
format, width, height, bits, rowstride_bytes, TRUE);
}
 
 
/* If bits is NULL, a buffer will be allocated and _not_ initialized */
PIXMAN_EXPORT pixman_image_t *
pixman_image_create_bits_no_clear (pixman_format_code_t format,
int width,
int height,
uint32_t * bits,
int rowstride_bytes)
{
return create_bits_image_internal (
format, width, height, bits, rowstride_bytes, FALSE);
}
/contrib/sdk/sources/pixman/pixman-combine-float.c
0,0 → 1,1016
/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
/*
* Copyright © 2010, 2012 Soren Sandmann Pedersen
* Copyright © 2010, 2012 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Author: Soren Sandmann Pedersen (sandmann@cs.au.dk)
*/
 
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
 
#include <math.h>
#include <string.h>
#include <float.h>
 
#include "pixman-private.h"
 
/* Workaround for http://gcc.gnu.org/PR54965 */
/* GCC 4.6 has problems with force_inline, so just use normal inline instead */
#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 6)
#undef force_inline
#define force_inline __inline__
#endif
 
typedef float (* combine_channel_t) (float sa, float s, float da, float d);
 
static force_inline void
combine_inner (pixman_bool_t component,
float *dest, const float *src, const float *mask, int n_pixels,
combine_channel_t combine_a, combine_channel_t combine_c)
{
int i;
 
if (!mask)
{
for (i = 0; i < 4 * n_pixels; i += 4)
{
float sa = src[i + 0];
float sr = src[i + 1];
float sg = src[i + 2];
float sb = src[i + 3];
float da = dest[i + 0];
float dr = dest[i + 1];
float dg = dest[i + 2];
float db = dest[i + 3];
dest[i + 0] = combine_a (sa, sa, da, da);
dest[i + 1] = combine_c (sa, sr, da, dr);
dest[i + 2] = combine_c (sa, sg, da, dg);
dest[i + 3] = combine_c (sa, sb, da, db);
}
}
else
{
for (i = 0; i < 4 * n_pixels; i += 4)
{
float sa, sr, sg, sb;
float ma, mr, mg, mb;
float da, dr, dg, db;
sa = src[i + 0];
sr = src[i + 1];
sg = src[i + 2];
sb = src[i + 3];
if (component)
{
ma = mask[i + 0];
mr = mask[i + 1];
mg = mask[i + 2];
mb = mask[i + 3];
 
sr *= mr;
sg *= mg;
sb *= mb;
 
ma *= sa;
mr *= sa;
mg *= sa;
mb *= sa;
sa = ma;
}
else
{
ma = mask[i + 0];
 
sa *= ma;
sr *= ma;
sg *= ma;
sb *= ma;
 
ma = mr = mg = mb = sa;
}
da = dest[i + 0];
dr = dest[i + 1];
dg = dest[i + 2];
db = dest[i + 3];
dest[i + 0] = combine_a (ma, sa, da, da);
dest[i + 1] = combine_c (mr, sr, da, dr);
dest[i + 2] = combine_c (mg, sg, da, dg);
dest[i + 3] = combine_c (mb, sb, da, db);
}
}
}
 
#define MAKE_COMBINER(name, component, combine_a, combine_c) \
static void \
combine_ ## name ## _float (pixman_implementation_t *imp, \
pixman_op_t op, \
float *dest, \
const float *src, \
const float *mask, \
int n_pixels) \
{ \
combine_inner (component, dest, src, mask, n_pixels, \
combine_a, combine_c); \
}
 
#define MAKE_COMBINERS(name, combine_a, combine_c) \
MAKE_COMBINER(name ## _ca, TRUE, combine_a, combine_c) \
MAKE_COMBINER(name ## _u, FALSE, combine_a, combine_c)
 
 
/*
* Porter/Duff operators
*/
typedef enum
{
ZERO,
ONE,
SRC_ALPHA,
DEST_ALPHA,
INV_SA,
INV_DA,
SA_OVER_DA,
DA_OVER_SA,
INV_SA_OVER_DA,
INV_DA_OVER_SA,
ONE_MINUS_SA_OVER_DA,
ONE_MINUS_DA_OVER_SA,
ONE_MINUS_INV_DA_OVER_SA,
ONE_MINUS_INV_SA_OVER_DA
} combine_factor_t;
 
#define CLAMP(f) \
(((f) < 0)? 0 : (((f) > 1.0) ? 1.0 : (f)))
 
static force_inline float
get_factor (combine_factor_t factor, float sa, float da)
{
float f = -1;
 
switch (factor)
{
case ZERO:
f = 0.0f;
break;
 
case ONE:
f = 1.0f;
break;
 
case SRC_ALPHA:
f = sa;
break;
 
case DEST_ALPHA:
f = da;
break;
 
case INV_SA:
f = 1 - sa;
break;
 
case INV_DA:
f = 1 - da;
break;
 
case SA_OVER_DA:
if (FLOAT_IS_ZERO (da))
f = 1.0f;
else
f = CLAMP (sa / da);
break;
 
case DA_OVER_SA:
if (FLOAT_IS_ZERO (sa))
f = 1.0f;
else
f = CLAMP (da / sa);
break;
 
case INV_SA_OVER_DA:
if (FLOAT_IS_ZERO (da))
f = 1.0f;
else
f = CLAMP ((1.0f - sa) / da);
break;
 
case INV_DA_OVER_SA:
if (FLOAT_IS_ZERO (sa))
f = 1.0f;
else
f = CLAMP ((1.0f - da) / sa);
break;
 
case ONE_MINUS_SA_OVER_DA:
if (FLOAT_IS_ZERO (da))
f = 0.0f;
else
f = CLAMP (1.0f - sa / da);
break;
 
case ONE_MINUS_DA_OVER_SA:
if (FLOAT_IS_ZERO (sa))
f = 0.0f;
else
f = CLAMP (1.0f - da / sa);
break;
 
case ONE_MINUS_INV_DA_OVER_SA:
if (FLOAT_IS_ZERO (sa))
f = 0.0f;
else
f = CLAMP (1.0f - (1.0f - da) / sa);
break;
 
case ONE_MINUS_INV_SA_OVER_DA:
if (FLOAT_IS_ZERO (da))
f = 0.0f;
else
f = CLAMP (1.0f - (1.0f - sa) / da);
break;
}
 
return f;
}
 
#define MAKE_PD_COMBINERS(name, a, b) \
static float force_inline \
pd_combine_ ## name (float sa, float s, float da, float d) \
{ \
const float fa = get_factor (a, sa, da); \
const float fb = get_factor (b, sa, da); \
\
return MIN (1.0f, s * fa + d * fb); \
} \
\
MAKE_COMBINERS(name, pd_combine_ ## name, pd_combine_ ## name)
 
MAKE_PD_COMBINERS (clear, ZERO, ZERO)
MAKE_PD_COMBINERS (src, ONE, ZERO)
MAKE_PD_COMBINERS (dst, ZERO, ONE)
MAKE_PD_COMBINERS (over, ONE, INV_SA)
MAKE_PD_COMBINERS (over_reverse, INV_DA, ONE)
MAKE_PD_COMBINERS (in, DEST_ALPHA, ZERO)
MAKE_PD_COMBINERS (in_reverse, ZERO, SRC_ALPHA)
MAKE_PD_COMBINERS (out, INV_DA, ZERO)
MAKE_PD_COMBINERS (out_reverse, ZERO, INV_SA)
MAKE_PD_COMBINERS (atop, DEST_ALPHA, INV_SA)
MAKE_PD_COMBINERS (atop_reverse, INV_DA, SRC_ALPHA)
MAKE_PD_COMBINERS (xor, INV_DA, INV_SA)
MAKE_PD_COMBINERS (add, ONE, ONE)
 
MAKE_PD_COMBINERS (saturate, INV_DA_OVER_SA, ONE)
 
MAKE_PD_COMBINERS (disjoint_clear, ZERO, ZERO)
MAKE_PD_COMBINERS (disjoint_src, ONE, ZERO)
MAKE_PD_COMBINERS (disjoint_dst, ZERO, ONE)
MAKE_PD_COMBINERS (disjoint_over, ONE, INV_SA_OVER_DA)
MAKE_PD_COMBINERS (disjoint_over_reverse, INV_DA_OVER_SA, ONE)
MAKE_PD_COMBINERS (disjoint_in, ONE_MINUS_INV_DA_OVER_SA, ZERO)
MAKE_PD_COMBINERS (disjoint_in_reverse, ZERO, ONE_MINUS_INV_SA_OVER_DA)
MAKE_PD_COMBINERS (disjoint_out, INV_DA_OVER_SA, ZERO)
MAKE_PD_COMBINERS (disjoint_out_reverse, ZERO, INV_SA_OVER_DA)
MAKE_PD_COMBINERS (disjoint_atop, ONE_MINUS_INV_DA_OVER_SA, INV_SA_OVER_DA)
MAKE_PD_COMBINERS (disjoint_atop_reverse, INV_DA_OVER_SA, ONE_MINUS_INV_SA_OVER_DA)
MAKE_PD_COMBINERS (disjoint_xor, INV_DA_OVER_SA, INV_SA_OVER_DA)
 
MAKE_PD_COMBINERS (conjoint_clear, ZERO, ZERO)
MAKE_PD_COMBINERS (conjoint_src, ONE, ZERO)
MAKE_PD_COMBINERS (conjoint_dst, ZERO, ONE)
MAKE_PD_COMBINERS (conjoint_over, ONE, ONE_MINUS_SA_OVER_DA)
MAKE_PD_COMBINERS (conjoint_over_reverse, ONE_MINUS_DA_OVER_SA, ONE)
MAKE_PD_COMBINERS (conjoint_in, DA_OVER_SA, ZERO)
MAKE_PD_COMBINERS (conjoint_in_reverse, ZERO, SA_OVER_DA)
MAKE_PD_COMBINERS (conjoint_out, ONE_MINUS_DA_OVER_SA, ZERO)
MAKE_PD_COMBINERS (conjoint_out_reverse, ZERO, ONE_MINUS_SA_OVER_DA)
MAKE_PD_COMBINERS (conjoint_atop, DA_OVER_SA, ONE_MINUS_SA_OVER_DA)
MAKE_PD_COMBINERS (conjoint_atop_reverse, ONE_MINUS_DA_OVER_SA, SA_OVER_DA)
MAKE_PD_COMBINERS (conjoint_xor, ONE_MINUS_DA_OVER_SA, ONE_MINUS_SA_OVER_DA)
 
/*
* PDF blend modes:
*
* The following blend modes have been taken from the PDF ISO 32000
* specification, which at this point in time is available from
* http://www.adobe.com/devnet/acrobat/pdfs/PDF32000_2008.pdf
* The relevant chapters are 11.3.5 and 11.3.6.
* The formula for computing the final pixel color given in 11.3.6 is:
* αr × Cr = (1 – αs) × αb × Cb + (1 – αb) × αs × Cs + αb × αs × B(Cb, Cs)
* with B() being the blend function.
* Note that OVER is a special case of this operation, using B(Cb, Cs) = Cs
*
* These blend modes should match the SVG filter draft specification, as
* it has been designed to mirror ISO 32000. Note that at the current point
* no released draft exists that shows this, as the formulas have not been
* updated yet after the release of ISO 32000.
*
* The default implementation here uses the PDF_SEPARABLE_BLEND_MODE and
* PDF_NON_SEPARABLE_BLEND_MODE macros, which take the blend function as an
* argument. Note that this implementation operates on premultiplied colors,
* while the PDF specification does not. Therefore the code uses the formula
* ar.Cra = (1 – as) . Dca + (1 – ad) . Sca + B(Dca, ad, Sca, as)
*/
 
#define MAKE_SEPARABLE_PDF_COMBINERS(name) \
static force_inline float \
combine_ ## name ## _a (float sa, float s, float da, float d) \
{ \
return da + sa - da * sa; \
} \
\
static force_inline float \
combine_ ## name ## _c (float sa, float s, float da, float d) \
{ \
float f = (1 - sa) * d + (1 - da) * s; \
\
return f + blend_ ## name (sa, s, da, d); \
} \
\
MAKE_COMBINERS (name, combine_ ## name ## _a, combine_ ## name ## _c)
 
static force_inline float
blend_multiply (float sa, float s, float da, float d)
{
return d * s;
}
 
static force_inline float
blend_screen (float sa, float s, float da, float d)
{
return d * sa + s * da - s * d;
}
 
static force_inline float
blend_overlay (float sa, float s, float da, float d)
{
if (2 * d < da)
return 2 * s * d;
else
return sa * da - 2 * (da - d) * (sa - s);
}
 
static force_inline float
blend_darken (float sa, float s, float da, float d)
{
s = s * da;
d = d * sa;
 
if (s > d)
return d;
else
return s;
}
 
static force_inline float
blend_lighten (float sa, float s, float da, float d)
{
s = s * da;
d = d * sa;
 
if (s > d)
return s;
else
return d;
}
 
static force_inline float
blend_color_dodge (float sa, float s, float da, float d)
{
if (FLOAT_IS_ZERO (d))
return 0.0f;
else if (d * sa >= sa * da - s * da)
return sa * da;
else if (FLOAT_IS_ZERO (sa - s))
return sa * da;
else
return sa * sa * d / (sa - s);
}
 
static force_inline float
blend_color_burn (float sa, float s, float da, float d)
{
if (d >= da)
return sa * da;
else if (sa * (da - d) >= s * da)
return 0.0f;
else if (FLOAT_IS_ZERO (s))
return 0.0f;
else
return sa * (da - sa * (da - d) / s);
}
 
static force_inline float
blend_hard_light (float sa, float s, float da, float d)
{
if (2 * s < sa)
return 2 * s * d;
else
return sa * da - 2 * (da - d) * (sa - s);
}
 
static force_inline float
blend_soft_light (float sa, float s, float da, float d)
{
if (2 * s < sa)
{
if (FLOAT_IS_ZERO (da))
return d * sa;
else
return d * sa - d * (da - d) * (sa - 2 * s) / da;
}
else
{
if (FLOAT_IS_ZERO (da))
{
return 0.0f;
}
else
{
if (4 * d <= da)
return d * sa + (2 * s - sa) * d * ((16 * d / da - 12) * d / da + 3);
else
return d * sa + (sqrtf (d * da) - d) * (2 * s - sa);
}
}
}
 
static force_inline float
blend_difference (float sa, float s, float da, float d)
{
float dsa = d * sa;
float sda = s * da;
 
if (sda < dsa)
return dsa - sda;
else
return sda - dsa;
}
 
static force_inline float
blend_exclusion (float sa, float s, float da, float d)
{
return s * da + d * sa - 2 * d * s;
}
 
MAKE_SEPARABLE_PDF_COMBINERS (multiply)
MAKE_SEPARABLE_PDF_COMBINERS (screen)
MAKE_SEPARABLE_PDF_COMBINERS (overlay)
MAKE_SEPARABLE_PDF_COMBINERS (darken)
MAKE_SEPARABLE_PDF_COMBINERS (lighten)
MAKE_SEPARABLE_PDF_COMBINERS (color_dodge)
MAKE_SEPARABLE_PDF_COMBINERS (color_burn)
MAKE_SEPARABLE_PDF_COMBINERS (hard_light)
MAKE_SEPARABLE_PDF_COMBINERS (soft_light)
MAKE_SEPARABLE_PDF_COMBINERS (difference)
MAKE_SEPARABLE_PDF_COMBINERS (exclusion)
 
/*
* PDF nonseperable blend modes.
*
* These are implemented using the following functions to operate in Hsl
* space, with Cmax, Cmid, Cmin referring to the max, mid and min value
* of the red, green and blue components.
*
* LUM (C) = 0.3 × Cred + 0.59 × Cgreen + 0.11 × Cblue
*
* clip_color (C):
* l = LUM (C)
* min = Cmin
* max = Cmax
* if n < 0.0
* C = l + (((C – l) × l) ⁄ (l – min))
* if x > 1.0
* C = l + (((C – l) × (1 – l)) (max – l))
* return C
*
* set_lum (C, l):
* d = l – LUM (C)
* C += d
* return clip_color (C)
*
* SAT (C) = CH_MAX (C) - CH_MIN (C)
*
* set_sat (C, s):
* if Cmax > Cmin
* Cmid = ( ( ( Cmid – Cmin ) × s ) ⁄ ( Cmax – Cmin ) )
* Cmax = s
* else
* Cmid = Cmax = 0.0
* Cmin = 0.0
* return C
*/
 
/* For premultiplied colors, we need to know what happens when C is
* multiplied by a real number. LUM and SAT are linear:
*
* LUM (r × C) = r × LUM (C) SAT (r × C) = r × SAT (C)
*
* If we extend clip_color with an extra argument a and change
*
* if x >= 1.0
*
* into
*
* if x >= a
*
* then clip_color is also linear:
*
* r * clip_color (C, a) = clip_color (r_c, ra);
*
* for positive r.
*
* Similarly, we can extend set_lum with an extra argument that is just passed
* on to clip_color:
*
* r × set_lum ( C, l, a)
*
* = r × clip_color ( C + l - LUM (C), a)
*
* = clip_color ( r * C + r × l - LUM (r × C), r * a)
*
* = set_lum ( r * C, r * l, r * a)
*
* Finally, set_sat:
*
* r * set_sat (C, s) = set_sat (x * C, r * s)
*
* The above holds for all non-zero x because they x'es in the fraction for
* C_mid cancel out. Specifically, it holds for x = r:
*
* r * set_sat (C, s) = set_sat (r_c, rs)
*
*
*
*
* So, for the non-separable PDF blend modes, we have (using s, d for
* non-premultiplied colors, and S, D for premultiplied:
*
* Color:
*
* a_s * a_d * B(s, d)
* = a_s * a_d * set_lum (S/a_s, LUM (D/a_d), 1)
* = set_lum (S * a_d, a_s * LUM (D), a_s * a_d)
*
*
* Luminosity:
*
* a_s * a_d * B(s, d)
* = a_s * a_d * set_lum (D/a_d, LUM(S/a_s), 1)
* = set_lum (a_s * D, a_d * LUM(S), a_s * a_d)
*
*
* Saturation:
*
* a_s * a_d * B(s, d)
* = a_s * a_d * set_lum (set_sat (D/a_d, SAT (S/a_s)), LUM (D/a_d), 1)
* = set_lum (a_s * a_d * set_sat (D/a_d, SAT (S/a_s)),
* a_s * LUM (D), a_s * a_d)
* = set_lum (set_sat (a_s * D, a_d * SAT (S), a_s * LUM (D), a_s * a_d))
*
* Hue:
*
* a_s * a_d * B(s, d)
* = a_s * a_d * set_lum (set_sat (S/a_s, SAT (D/a_d)), LUM (D/a_d), 1)
* = set_lum (set_sat (a_d * S, a_s * SAT (D)), a_s * LUM (D), a_s * a_d)
*
*/
 
typedef struct
{
float r;
float g;
float b;
} rgb_t;
 
static force_inline float
minf (float a, float b)
{
return a < b? a : b;
}
 
static force_inline float
maxf (float a, float b)
{
return a > b? a : b;
}
 
static force_inline float
channel_min (const rgb_t *c)
{
return minf (minf (c->r, c->g), c->b);
}
 
static force_inline float
channel_max (const rgb_t *c)
{
return maxf (maxf (c->r, c->g), c->b);
}
 
static force_inline float
get_lum (const rgb_t *c)
{
return c->r * 0.3f + c->g * 0.59f + c->b * 0.11f;
}
 
static force_inline float
get_sat (const rgb_t *c)
{
return channel_max (c) - channel_min (c);
}
 
static void
clip_color (rgb_t *color, float a)
{
float l = get_lum (color);
float n = channel_min (color);
float x = channel_max (color);
float t;
 
if (n < 0.0f)
{
t = l - n;
if (FLOAT_IS_ZERO (t))
{
color->r = 0.0f;
color->g = 0.0f;
color->b = 0.0f;
}
else
{
color->r = l + (((color->r - l) * l) / t);
color->g = l + (((color->g - l) * l) / t);
color->b = l + (((color->b - l) * l) / t);
}
}
if (x > a)
{
t = x - l;
if (FLOAT_IS_ZERO (t))
{
color->r = a;
color->g = a;
color->b = a;
}
else
{
color->r = l + (((color->r - l) * (a - l) / t));
color->g = l + (((color->g - l) * (a - l) / t));
color->b = l + (((color->b - l) * (a - l) / t));
}
}
}
 
static void
set_lum (rgb_t *color, float sa, float l)
{
float d = l - get_lum (color);
 
color->r = color->r + d;
color->g = color->g + d;
color->b = color->b + d;
 
clip_color (color, sa);
}
 
static void
set_sat (rgb_t *src, float sat)
{
float *max, *mid, *min;
float t;
 
if (src->r > src->g)
{
if (src->r > src->b)
{
max = &(src->r);
 
if (src->g > src->b)
{
mid = &(src->g);
min = &(src->b);
}
else
{
mid = &(src->b);
min = &(src->g);
}
}
else
{
max = &(src->b);
mid = &(src->r);
min = &(src->g);
}
}
else
{
if (src->r > src->b)
{
max = &(src->g);
mid = &(src->r);
min = &(src->b);
}
else
{
min = &(src->r);
 
if (src->g > src->b)
{
max = &(src->g);
mid = &(src->b);
}
else
{
max = &(src->b);
mid = &(src->g);
}
}
}
 
t = *max - *min;
 
if (FLOAT_IS_ZERO (t))
{
*mid = *max = 0.0f;
}
else
{
*mid = ((*mid - *min) * sat) / t;
*max = sat;
}
 
*min = 0.0f;
}
 
/*
* Hue:
* B(Cb, Cs) = set_lum (set_sat (Cs, SAT (Cb)), LUM (Cb))
*/
static force_inline void
blend_hsl_hue (rgb_t *res,
const rgb_t *dest, float da,
const rgb_t *src, float sa)
{
res->r = src->r * da;
res->g = src->g * da;
res->b = src->b * da;
 
set_sat (res, get_sat (dest) * sa);
set_lum (res, sa * da, get_lum (dest) * sa);
}
 
/*
* Saturation:
* B(Cb, Cs) = set_lum (set_sat (Cb, SAT (Cs)), LUM (Cb))
*/
static force_inline void
blend_hsl_saturation (rgb_t *res,
const rgb_t *dest, float da,
const rgb_t *src, float sa)
{
res->r = dest->r * sa;
res->g = dest->g * sa;
res->b = dest->b * sa;
 
set_sat (res, get_sat (src) * da);
set_lum (res, sa * da, get_lum (dest) * sa);
}
 
/*
* Color:
* B(Cb, Cs) = set_lum (Cs, LUM (Cb))
*/
static force_inline void
blend_hsl_color (rgb_t *res,
const rgb_t *dest, float da,
const rgb_t *src, float sa)
{
res->r = src->r * da;
res->g = src->g * da;
res->b = src->b * da;
 
set_lum (res, sa * da, get_lum (dest) * sa);
}
 
/*
* Luminosity:
* B(Cb, Cs) = set_lum (Cb, LUM (Cs))
*/
static force_inline void
blend_hsl_luminosity (rgb_t *res,
const rgb_t *dest, float da,
const rgb_t *src, float sa)
{
res->r = dest->r * sa;
res->g = dest->g * sa;
res->b = dest->b * sa;
 
set_lum (res, sa * da, get_lum (src) * da);
}
 
#define MAKE_NON_SEPARABLE_PDF_COMBINERS(name) \
static void \
combine_ ## name ## _u_float (pixman_implementation_t *imp, \
pixman_op_t op, \
float *dest, \
const float *src, \
const float *mask, \
int n_pixels) \
{ \
int i; \
\
for (i = 0; i < 4 * n_pixels; i += 4) \
{ \
float sa, da; \
rgb_t sc, dc, rc; \
\
sa = src[i + 0]; \
sc.r = src[i + 1]; \
sc.g = src[i + 2]; \
sc.b = src[i + 3]; \
\
da = dest[i + 0]; \
dc.r = dest[i + 1]; \
dc.g = dest[i + 2]; \
dc.b = dest[i + 3]; \
\
if (mask) \
{ \
float ma = mask[i + 0]; \
\
/* Component alpha is not supported for HSL modes */ \
sa *= ma; \
sc.r *= ma; \
sc.g *= ma; \
sc.g *= ma; \
} \
\
blend_ ## name (&rc, &dc, da, &sc, sa); \
\
dest[i + 0] = sa + da - sa * da; \
dest[i + 1] = (1 - sa) * dc.r + (1 - da) * sc.r + rc.r; \
dest[i + 2] = (1 - sa) * dc.g + (1 - da) * sc.g + rc.g; \
dest[i + 3] = (1 - sa) * dc.b + (1 - da) * sc.b + rc.b; \
} \
}
 
MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_hue)
MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_saturation)
MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_color)
MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_luminosity)
 
void
_pixman_setup_combiner_functions_float (pixman_implementation_t *imp)
{
/* Unified alpha */
imp->combine_float[PIXMAN_OP_CLEAR] = combine_clear_u_float;
imp->combine_float[PIXMAN_OP_SRC] = combine_src_u_float;
imp->combine_float[PIXMAN_OP_DST] = combine_dst_u_float;
imp->combine_float[PIXMAN_OP_OVER] = combine_over_u_float;
imp->combine_float[PIXMAN_OP_OVER_REVERSE] = combine_over_reverse_u_float;
imp->combine_float[PIXMAN_OP_IN] = combine_in_u_float;
imp->combine_float[PIXMAN_OP_IN_REVERSE] = combine_in_reverse_u_float;
imp->combine_float[PIXMAN_OP_OUT] = combine_out_u_float;
imp->combine_float[PIXMAN_OP_OUT_REVERSE] = combine_out_reverse_u_float;
imp->combine_float[PIXMAN_OP_ATOP] = combine_atop_u_float;
imp->combine_float[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_u_float;
imp->combine_float[PIXMAN_OP_XOR] = combine_xor_u_float;
imp->combine_float[PIXMAN_OP_ADD] = combine_add_u_float;
imp->combine_float[PIXMAN_OP_SATURATE] = combine_saturate_u_float;
 
/* Disjoint, unified */
imp->combine_float[PIXMAN_OP_DISJOINT_CLEAR] = combine_disjoint_clear_u_float;
imp->combine_float[PIXMAN_OP_DISJOINT_SRC] = combine_disjoint_src_u_float;
imp->combine_float[PIXMAN_OP_DISJOINT_DST] = combine_disjoint_dst_u_float;
imp->combine_float[PIXMAN_OP_DISJOINT_OVER] = combine_disjoint_over_u_float;
imp->combine_float[PIXMAN_OP_DISJOINT_OVER_REVERSE] = combine_disjoint_over_reverse_u_float;
imp->combine_float[PIXMAN_OP_DISJOINT_IN] = combine_disjoint_in_u_float;
imp->combine_float[PIXMAN_OP_DISJOINT_IN_REVERSE] = combine_disjoint_in_reverse_u_float;
imp->combine_float[PIXMAN_OP_DISJOINT_OUT] = combine_disjoint_out_u_float;
imp->combine_float[PIXMAN_OP_DISJOINT_OUT_REVERSE] = combine_disjoint_out_reverse_u_float;
imp->combine_float[PIXMAN_OP_DISJOINT_ATOP] = combine_disjoint_atop_u_float;
imp->combine_float[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = combine_disjoint_atop_reverse_u_float;
imp->combine_float[PIXMAN_OP_DISJOINT_XOR] = combine_disjoint_xor_u_float;
 
/* Conjoint, unified */
imp->combine_float[PIXMAN_OP_CONJOINT_CLEAR] = combine_conjoint_clear_u_float;
imp->combine_float[PIXMAN_OP_CONJOINT_SRC] = combine_conjoint_src_u_float;
imp->combine_float[PIXMAN_OP_CONJOINT_DST] = combine_conjoint_dst_u_float;
imp->combine_float[PIXMAN_OP_CONJOINT_OVER] = combine_conjoint_over_u_float;
imp->combine_float[PIXMAN_OP_CONJOINT_OVER_REVERSE] = combine_conjoint_over_reverse_u_float;
imp->combine_float[PIXMAN_OP_CONJOINT_IN] = combine_conjoint_in_u_float;
imp->combine_float[PIXMAN_OP_CONJOINT_IN_REVERSE] = combine_conjoint_in_reverse_u_float;
imp->combine_float[PIXMAN_OP_CONJOINT_OUT] = combine_conjoint_out_u_float;
imp->combine_float[PIXMAN_OP_CONJOINT_OUT_REVERSE] = combine_conjoint_out_reverse_u_float;
imp->combine_float[PIXMAN_OP_CONJOINT_ATOP] = combine_conjoint_atop_u_float;
imp->combine_float[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = combine_conjoint_atop_reverse_u_float;
imp->combine_float[PIXMAN_OP_CONJOINT_XOR] = combine_conjoint_xor_u_float;
 
/* PDF operators, unified */
imp->combine_float[PIXMAN_OP_MULTIPLY] = combine_multiply_u_float;
imp->combine_float[PIXMAN_OP_SCREEN] = combine_screen_u_float;
imp->combine_float[PIXMAN_OP_OVERLAY] = combine_overlay_u_float;
imp->combine_float[PIXMAN_OP_DARKEN] = combine_darken_u_float;
imp->combine_float[PIXMAN_OP_LIGHTEN] = combine_lighten_u_float;
imp->combine_float[PIXMAN_OP_COLOR_DODGE] = combine_color_dodge_u_float;
imp->combine_float[PIXMAN_OP_COLOR_BURN] = combine_color_burn_u_float;
imp->combine_float[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_u_float;
imp->combine_float[PIXMAN_OP_SOFT_LIGHT] = combine_soft_light_u_float;
imp->combine_float[PIXMAN_OP_DIFFERENCE] = combine_difference_u_float;
imp->combine_float[PIXMAN_OP_EXCLUSION] = combine_exclusion_u_float;
 
imp->combine_float[PIXMAN_OP_HSL_HUE] = combine_hsl_hue_u_float;
imp->combine_float[PIXMAN_OP_HSL_SATURATION] = combine_hsl_saturation_u_float;
imp->combine_float[PIXMAN_OP_HSL_COLOR] = combine_hsl_color_u_float;
imp->combine_float[PIXMAN_OP_HSL_LUMINOSITY] = combine_hsl_luminosity_u_float;
 
/* Component alpha combiners */
imp->combine_float_ca[PIXMAN_OP_CLEAR] = combine_clear_ca_float;
imp->combine_float_ca[PIXMAN_OP_SRC] = combine_src_ca_float;
imp->combine_float_ca[PIXMAN_OP_DST] = combine_dst_ca_float;
imp->combine_float_ca[PIXMAN_OP_OVER] = combine_over_ca_float;
imp->combine_float_ca[PIXMAN_OP_OVER_REVERSE] = combine_over_reverse_ca_float;
imp->combine_float_ca[PIXMAN_OP_IN] = combine_in_ca_float;
imp->combine_float_ca[PIXMAN_OP_IN_REVERSE] = combine_in_reverse_ca_float;
imp->combine_float_ca[PIXMAN_OP_OUT] = combine_out_ca_float;
imp->combine_float_ca[PIXMAN_OP_OUT_REVERSE] = combine_out_reverse_ca_float;
imp->combine_float_ca[PIXMAN_OP_ATOP] = combine_atop_ca_float;
imp->combine_float_ca[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_ca_float;
imp->combine_float_ca[PIXMAN_OP_XOR] = combine_xor_ca_float;
imp->combine_float_ca[PIXMAN_OP_ADD] = combine_add_ca_float;
imp->combine_float_ca[PIXMAN_OP_SATURATE] = combine_saturate_ca_float;
 
/* Disjoint CA */
imp->combine_float_ca[PIXMAN_OP_DISJOINT_CLEAR] = combine_disjoint_clear_ca_float;
imp->combine_float_ca[PIXMAN_OP_DISJOINT_SRC] = combine_disjoint_src_ca_float;
imp->combine_float_ca[PIXMAN_OP_DISJOINT_DST] = combine_disjoint_dst_ca_float;
imp->combine_float_ca[PIXMAN_OP_DISJOINT_OVER] = combine_disjoint_over_ca_float;
imp->combine_float_ca[PIXMAN_OP_DISJOINT_OVER_REVERSE] = combine_disjoint_over_reverse_ca_float;
imp->combine_float_ca[PIXMAN_OP_DISJOINT_IN] = combine_disjoint_in_ca_float;
imp->combine_float_ca[PIXMAN_OP_DISJOINT_IN_REVERSE] = combine_disjoint_in_reverse_ca_float;
imp->combine_float_ca[PIXMAN_OP_DISJOINT_OUT] = combine_disjoint_out_ca_float;
imp->combine_float_ca[PIXMAN_OP_DISJOINT_OUT_REVERSE] = combine_disjoint_out_reverse_ca_float;
imp->combine_float_ca[PIXMAN_OP_DISJOINT_ATOP] = combine_disjoint_atop_ca_float;
imp->combine_float_ca[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = combine_disjoint_atop_reverse_ca_float;
imp->combine_float_ca[PIXMAN_OP_DISJOINT_XOR] = combine_disjoint_xor_ca_float;
 
/* Conjoint CA */
imp->combine_float_ca[PIXMAN_OP_CONJOINT_CLEAR] = combine_conjoint_clear_ca_float;
imp->combine_float_ca[PIXMAN_OP_CONJOINT_SRC] = combine_conjoint_src_ca_float;
imp->combine_float_ca[PIXMAN_OP_CONJOINT_DST] = combine_conjoint_dst_ca_float;
imp->combine_float_ca[PIXMAN_OP_CONJOINT_OVER] = combine_conjoint_over_ca_float;
imp->combine_float_ca[PIXMAN_OP_CONJOINT_OVER_REVERSE] = combine_conjoint_over_reverse_ca_float;
imp->combine_float_ca[PIXMAN_OP_CONJOINT_IN] = combine_conjoint_in_ca_float;
imp->combine_float_ca[PIXMAN_OP_CONJOINT_IN_REVERSE] = combine_conjoint_in_reverse_ca_float;
imp->combine_float_ca[PIXMAN_OP_CONJOINT_OUT] = combine_conjoint_out_ca_float;
imp->combine_float_ca[PIXMAN_OP_CONJOINT_OUT_REVERSE] = combine_conjoint_out_reverse_ca_float;
imp->combine_float_ca[PIXMAN_OP_CONJOINT_ATOP] = combine_conjoint_atop_ca_float;
imp->combine_float_ca[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = combine_conjoint_atop_reverse_ca_float;
imp->combine_float_ca[PIXMAN_OP_CONJOINT_XOR] = combine_conjoint_xor_ca_float;
 
/* PDF operators CA */
imp->combine_float_ca[PIXMAN_OP_MULTIPLY] = combine_multiply_ca_float;
imp->combine_float_ca[PIXMAN_OP_SCREEN] = combine_screen_ca_float;
imp->combine_float_ca[PIXMAN_OP_OVERLAY] = combine_overlay_ca_float;
imp->combine_float_ca[PIXMAN_OP_DARKEN] = combine_darken_ca_float;
imp->combine_float_ca[PIXMAN_OP_LIGHTEN] = combine_lighten_ca_float;
imp->combine_float_ca[PIXMAN_OP_COLOR_DODGE] = combine_color_dodge_ca_float;
imp->combine_float_ca[PIXMAN_OP_COLOR_BURN] = combine_color_burn_ca_float;
imp->combine_float_ca[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_ca_float;
imp->combine_float_ca[PIXMAN_OP_SOFT_LIGHT] = combine_soft_light_ca_float;
imp->combine_float_ca[PIXMAN_OP_DIFFERENCE] = combine_difference_ca_float;
imp->combine_float_ca[PIXMAN_OP_EXCLUSION] = combine_exclusion_ca_float;
 
/* It is not clear that these make sense, so make them noops for now */
imp->combine_float_ca[PIXMAN_OP_HSL_HUE] = combine_dst_u_float;
imp->combine_float_ca[PIXMAN_OP_HSL_SATURATION] = combine_dst_u_float;
imp->combine_float_ca[PIXMAN_OP_HSL_COLOR] = combine_dst_u_float;
imp->combine_float_ca[PIXMAN_OP_HSL_LUMINOSITY] = combine_dst_u_float;
}
/contrib/sdk/sources/pixman/pixman-combine32.c
0,0 → 1,2504
/*
* Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
* 2005 Lars Knoll & Zack Rusin, Trolltech
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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_CONFIG_H
#include <config.h>
#endif
 
#include <math.h>
#include <string.h>
 
#include "pixman-private.h"
#include "pixman-combine32.h"
 
/* component alpha helper functions */
 
static void
combine_mask_ca (uint32_t *src, uint32_t *mask)
{
uint32_t a = *mask;
 
uint32_t x;
uint16_t xa;
 
if (!a)
{
*(src) = 0;
return;
}
 
x = *(src);
if (a == ~0)
{
x = x >> A_SHIFT;
x |= x << G_SHIFT;
x |= x << R_SHIFT;
*(mask) = x;
return;
}
 
xa = x >> A_SHIFT;
UN8x4_MUL_UN8x4 (x, a);
*(src) = x;
UN8x4_MUL_UN8 (a, xa);
*(mask) = a;
}
 
static void
combine_mask_value_ca (uint32_t *src, const uint32_t *mask)
{
uint32_t a = *mask;
uint32_t x;
 
if (!a)
{
*(src) = 0;
return;
}
 
if (a == ~0)
return;
 
x = *(src);
UN8x4_MUL_UN8x4 (x, a);
*(src) = x;
}
 
static void
combine_mask_alpha_ca (const uint32_t *src, uint32_t *mask)
{
uint32_t a = *(mask);
uint32_t x;
 
if (!a)
return;
 
x = *(src) >> A_SHIFT;
if (x == MASK)
return;
 
if (a == ~0)
{
x |= x << G_SHIFT;
x |= x << R_SHIFT;
*(mask) = x;
return;
}
 
UN8x4_MUL_UN8 (a, x);
*(mask) = a;
}
 
/*
* There are two ways of handling alpha -- either as a single unified value or
* a separate value for each component, hence each macro must have two
* versions. The unified alpha version has a 'u' at the end of the name,
* the component version has a 'ca'. Similarly, functions which deal with
* this difference will have two versions using the same convention.
*/
 
static force_inline uint32_t
combine_mask (const uint32_t *src, const uint32_t *mask, int i)
{
uint32_t s, m;
 
if (mask)
{
m = *(mask + i) >> A_SHIFT;
 
if (!m)
return 0;
}
 
s = *(src + i);
 
if (mask)
UN8x4_MUL_UN8 (s, m);
 
return s;
}
 
static void
combine_clear (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
memset (dest, 0, width * sizeof(uint32_t));
}
 
static void
combine_dst (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
return;
}
 
static void
combine_src_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
if (!mask)
{
memcpy (dest, src, width * sizeof (uint32_t));
}
else
{
for (i = 0; i < width; ++i)
{
uint32_t s = combine_mask (src, mask, i);
 
*(dest + i) = s;
}
}
}
 
static void
combine_over_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
if (!mask)
{
for (i = 0; i < width; ++i)
{
uint32_t s = *(src + i);
uint32_t a = ALPHA_8 (s);
if (a == 0xFF)
{
*(dest + i) = s;
}
else if (s)
{
uint32_t d = *(dest + i);
uint32_t ia = a ^ 0xFF;
UN8x4_MUL_UN8_ADD_UN8x4 (d, ia, s);
*(dest + i) = d;
}
}
}
else
{
for (i = 0; i < width; ++i)
{
uint32_t m = ALPHA_8 (*(mask + i));
if (m == 0xFF)
{
uint32_t s = *(src + i);
uint32_t a = ALPHA_8 (s);
if (a == 0xFF)
{
*(dest + i) = s;
}
else if (s)
{
uint32_t d = *(dest + i);
uint32_t ia = a ^ 0xFF;
UN8x4_MUL_UN8_ADD_UN8x4 (d, ia, s);
*(dest + i) = d;
}
}
else if (m)
{
uint32_t s = *(src + i);
if (s)
{
uint32_t d = *(dest + i);
UN8x4_MUL_UN8 (s, m);
UN8x4_MUL_UN8_ADD_UN8x4 (d, ALPHA_8 (~s), s);
*(dest + i) = d;
}
}
}
}
}
 
static void
combine_over_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = combine_mask (src, mask, i);
uint32_t d = *(dest + i);
uint32_t ia = ALPHA_8 (~*(dest + i));
UN8x4_MUL_UN8_ADD_UN8x4 (s, ia, d);
*(dest + i) = s;
}
}
 
static void
combine_in_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = combine_mask (src, mask, i);
uint32_t a = ALPHA_8 (*(dest + i));
UN8x4_MUL_UN8 (s, a);
*(dest + i) = s;
}
}
 
static void
combine_in_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = combine_mask (src, mask, i);
uint32_t d = *(dest + i);
uint32_t a = ALPHA_8 (s);
UN8x4_MUL_UN8 (d, a);
*(dest + i) = d;
}
}
 
static void
combine_out_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = combine_mask (src, mask, i);
uint32_t a = ALPHA_8 (~*(dest + i));
UN8x4_MUL_UN8 (s, a);
*(dest + i) = s;
}
}
 
static void
combine_out_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = combine_mask (src, mask, i);
uint32_t d = *(dest + i);
uint32_t a = ALPHA_8 (~s);
UN8x4_MUL_UN8 (d, a);
*(dest + i) = d;
}
}
 
static void
combine_atop_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = combine_mask (src, mask, i);
uint32_t d = *(dest + i);
uint32_t dest_a = ALPHA_8 (d);
uint32_t src_ia = ALPHA_8 (~s);
 
UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (s, dest_a, d, src_ia);
*(dest + i) = s;
}
}
 
static void
combine_atop_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = combine_mask (src, mask, i);
uint32_t d = *(dest + i);
uint32_t src_a = ALPHA_8 (s);
uint32_t dest_ia = ALPHA_8 (~d);
 
UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (s, dest_ia, d, src_a);
*(dest + i) = s;
}
}
 
static void
combine_xor_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = combine_mask (src, mask, i);
uint32_t d = *(dest + i);
uint32_t src_ia = ALPHA_8 (~s);
uint32_t dest_ia = ALPHA_8 (~d);
 
UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (s, dest_ia, d, src_ia);
*(dest + i) = s;
}
}
 
static void
combine_add_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = combine_mask (src, mask, i);
uint32_t d = *(dest + i);
UN8x4_ADD_UN8x4 (d, s);
*(dest + i) = d;
}
}
 
static void
combine_saturate_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = combine_mask (src, mask, i);
uint32_t d = *(dest + i);
uint16_t sa, da;
 
sa = s >> A_SHIFT;
da = ~d >> A_SHIFT;
if (sa > da)
{
sa = DIV_UN8 (da, sa);
UN8x4_MUL_UN8 (s, sa);
}
;
UN8x4_ADD_UN8x4 (d, s);
*(dest + i) = d;
}
}
 
/*
* PDF blend modes:
* The following blend modes have been taken from the PDF ISO 32000
* specification, which at this point in time is available from
* http://www.adobe.com/devnet/acrobat/pdfs/PDF32000_2008.pdf
* The relevant chapters are 11.3.5 and 11.3.6.
* The formula for computing the final pixel color given in 11.3.6 is:
* αr × Cr = (1 – αs) × αb × Cb + (1 – αb) × αs × Cs + αb × αs × B(Cb, Cs)
* with B() being the blend function.
* Note that OVER is a special case of this operation, using B(Cb, Cs) = Cs
*
* These blend modes should match the SVG filter draft specification, as
* it has been designed to mirror ISO 32000. Note that at the current point
* no released draft exists that shows this, as the formulas have not been
* updated yet after the release of ISO 32000.
*
* The default implementation here uses the PDF_SEPARABLE_BLEND_MODE and
* PDF_NON_SEPARABLE_BLEND_MODE macros, which take the blend function as an
* argument. Note that this implementation operates on premultiplied colors,
* while the PDF specification does not. Therefore the code uses the formula
* Cra = (1 – as) . Dca + (1 – ad) . Sca + B(Dca, ad, Sca, as)
*/
 
/*
* Multiply
* B(Dca, ad, Sca, as) = Dca.Sca
*/
static void
combine_multiply_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = combine_mask (src, mask, i);
uint32_t d = *(dest + i);
uint32_t ss = s;
uint32_t src_ia = ALPHA_8 (~s);
uint32_t dest_ia = ALPHA_8 (~d);
 
UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (ss, dest_ia, d, src_ia);
UN8x4_MUL_UN8x4 (d, s);
UN8x4_ADD_UN8x4 (d, ss);
 
*(dest + i) = d;
}
}
 
static void
combine_multiply_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t m = *(mask + i);
uint32_t s = *(src + i);
uint32_t d = *(dest + i);
uint32_t r = d;
uint32_t dest_ia = ALPHA_8 (~d);
 
combine_mask_ca (&s, &m);
 
UN8x4_MUL_UN8x4_ADD_UN8x4_MUL_UN8 (r, ~m, s, dest_ia);
UN8x4_MUL_UN8x4 (d, s);
UN8x4_ADD_UN8x4 (r, d);
 
*(dest + i) = r;
}
}
 
#define PDF_SEPARABLE_BLEND_MODE(name) \
static void \
combine_ ## name ## _u (pixman_implementation_t *imp, \
pixman_op_t op, \
uint32_t * dest, \
const uint32_t * src, \
const uint32_t * mask, \
int width) \
{ \
int i; \
for (i = 0; i < width; ++i) { \
uint32_t s = combine_mask (src, mask, i); \
uint32_t d = *(dest + i); \
uint8_t sa = ALPHA_8 (s); \
uint8_t isa = ~sa; \
uint8_t da = ALPHA_8 (d); \
uint8_t ida = ~da; \
uint32_t result; \
\
result = d; \
UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (result, isa, s, ida); \
\
*(dest + i) = result + \
(DIV_ONE_UN8 (sa * (uint32_t)da) << A_SHIFT) + \
(blend_ ## name (RED_8 (d), da, RED_8 (s), sa) << R_SHIFT) + \
(blend_ ## name (GREEN_8 (d), da, GREEN_8 (s), sa) << G_SHIFT) + \
(blend_ ## name (BLUE_8 (d), da, BLUE_8 (s), sa)); \
} \
} \
\
static void \
combine_ ## name ## _ca (pixman_implementation_t *imp, \
pixman_op_t op, \
uint32_t * dest, \
const uint32_t * src, \
const uint32_t * mask, \
int width) \
{ \
int i; \
for (i = 0; i < width; ++i) { \
uint32_t m = *(mask + i); \
uint32_t s = *(src + i); \
uint32_t d = *(dest + i); \
uint8_t da = ALPHA_8 (d); \
uint8_t ida = ~da; \
uint32_t result; \
\
combine_mask_ca (&s, &m); \
\
result = d; \
UN8x4_MUL_UN8x4_ADD_UN8x4_MUL_UN8 (result, ~m, s, ida); \
\
result += \
(DIV_ONE_UN8 (ALPHA_8 (m) * (uint32_t)da) << A_SHIFT) + \
(blend_ ## name (RED_8 (d), da, RED_8 (s), RED_8 (m)) << R_SHIFT) + \
(blend_ ## name (GREEN_8 (d), da, GREEN_8 (s), GREEN_8 (m)) << G_SHIFT) + \
(blend_ ## name (BLUE_8 (d), da, BLUE_8 (s), BLUE_8 (m))); \
\
*(dest + i) = result; \
} \
}
 
/*
* Screen
* B(Dca, ad, Sca, as) = Dca.sa + Sca.da - Dca.Sca
*/
static inline uint32_t
blend_screen (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa)
{
return DIV_ONE_UN8 (sca * da + dca * sa - sca * dca);
}
 
PDF_SEPARABLE_BLEND_MODE (screen)
 
/*
* Overlay
* B(Dca, Da, Sca, Sa) =
* if 2.Dca < Da
* 2.Sca.Dca
* otherwise
* Sa.Da - 2.(Da - Dca).(Sa - Sca)
*/
static inline uint32_t
blend_overlay (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa)
{
uint32_t rca;
 
if (2 * dca < da)
rca = 2 * sca * dca;
else
rca = sa * da - 2 * (da - dca) * (sa - sca);
return DIV_ONE_UN8 (rca);
}
 
PDF_SEPARABLE_BLEND_MODE (overlay)
 
/*
* Darken
* B(Dca, Da, Sca, Sa) = min (Sca.Da, Dca.Sa)
*/
static inline uint32_t
blend_darken (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa)
{
uint32_t s, d;
 
s = sca * da;
d = dca * sa;
return DIV_ONE_UN8 (s > d ? d : s);
}
 
PDF_SEPARABLE_BLEND_MODE (darken)
 
/*
* Lighten
* B(Dca, Da, Sca, Sa) = max (Sca.Da, Dca.Sa)
*/
static inline uint32_t
blend_lighten (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa)
{
uint32_t s, d;
 
s = sca * da;
d = dca * sa;
return DIV_ONE_UN8 (s > d ? s : d);
}
 
PDF_SEPARABLE_BLEND_MODE (lighten)
 
/*
* Color dodge
* B(Dca, Da, Sca, Sa) =
* if Dca == 0
* 0
* if Sca == Sa
* Sa.Da
* otherwise
* Sa.Da. min (1, Dca / Da / (1 - Sca/Sa))
*/
static inline uint32_t
blend_color_dodge (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa)
{
if (sca >= sa)
{
return dca == 0 ? 0 : DIV_ONE_UN8 (sa * da);
}
else
{
uint32_t rca = dca * sa / (sa - sca);
return DIV_ONE_UN8 (sa * MIN (rca, da));
}
}
 
PDF_SEPARABLE_BLEND_MODE (color_dodge)
 
/*
* Color burn
* B(Dca, Da, Sca, Sa) =
* if Dca == Da
* Sa.Da
* if Sca == 0
* 0
* otherwise
* Sa.Da.(1 - min (1, (1 - Dca/Da).Sa / Sca))
*/
static inline uint32_t
blend_color_burn (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa)
{
if (sca == 0)
{
return dca < da ? 0 : DIV_ONE_UN8 (sa * da);
}
else
{
uint32_t rca = (da - dca) * sa / sca;
return DIV_ONE_UN8 (sa * (MAX (rca, da) - rca));
}
}
 
PDF_SEPARABLE_BLEND_MODE (color_burn)
 
/*
* Hard light
* B(Dca, Da, Sca, Sa) =
* if 2.Sca < Sa
* 2.Sca.Dca
* otherwise
* Sa.Da - 2.(Da - Dca).(Sa - Sca)
*/
static inline uint32_t
blend_hard_light (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa)
{
if (2 * sca < sa)
return DIV_ONE_UN8 (2 * sca * dca);
else
return DIV_ONE_UN8 (sa * da - 2 * (da - dca) * (sa - sca));
}
 
PDF_SEPARABLE_BLEND_MODE (hard_light)
 
/*
* Soft light
* B(Dca, Da, Sca, Sa) =
* if (2.Sca <= Sa)
* Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa))
* otherwise if Dca.4 <= Da
* Dca.(Sa + (2.Sca - Sa).((16.Dca/Da - 12).Dca/Da + 3)
* otherwise
* (Dca.Sa + (SQRT (Dca/Da).Da - Dca).(2.Sca - Sa))
*/
static inline uint32_t
blend_soft_light (uint32_t dca_org,
uint32_t da_org,
uint32_t sca_org,
uint32_t sa_org)
{
double dca = dca_org * (1.0 / MASK);
double da = da_org * (1.0 / MASK);
double sca = sca_org * (1.0 / MASK);
double sa = sa_org * (1.0 / MASK);
double rca;
 
if (2 * sca < sa)
{
if (da == 0)
rca = dca * sa;
else
rca = dca * sa - dca * (da - dca) * (sa - 2 * sca) / da;
}
else if (da == 0)
{
rca = 0;
}
else if (4 * dca <= da)
{
rca = dca * sa +
(2 * sca - sa) * dca * ((16 * dca / da - 12) * dca / da + 3);
}
else
{
rca = dca * sa + (sqrt (dca * da) - dca) * (2 * sca - sa);
}
return rca * MASK + 0.5;
}
 
PDF_SEPARABLE_BLEND_MODE (soft_light)
 
/*
* Difference
* B(Dca, Da, Sca, Sa) = abs (Dca.Sa - Sca.Da)
*/
static inline uint32_t
blend_difference (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa)
{
uint32_t dcasa = dca * sa;
uint32_t scada = sca * da;
 
if (scada < dcasa)
return DIV_ONE_UN8 (dcasa - scada);
else
return DIV_ONE_UN8 (scada - dcasa);
}
 
PDF_SEPARABLE_BLEND_MODE (difference)
 
/*
* Exclusion
* B(Dca, Da, Sca, Sa) = (Sca.Da + Dca.Sa - 2.Sca.Dca)
*/
 
/* This can be made faster by writing it directly and not using
* PDF_SEPARABLE_BLEND_MODE, but that's a performance optimization */
 
static inline uint32_t
blend_exclusion (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa)
{
return DIV_ONE_UN8 (sca * da + dca * sa - 2 * dca * sca);
}
 
PDF_SEPARABLE_BLEND_MODE (exclusion)
 
#undef PDF_SEPARABLE_BLEND_MODE
 
/*
* PDF nonseperable blend modes are implemented using the following functions
* to operate in Hsl space, with Cmax, Cmid, Cmin referring to the max, mid
* and min value of the red, green and blue components.
*
* LUM (C) = 0.3 × Cred + 0.59 × Cgreen + 0.11 × Cblue
*
* clip_color (C):
* l = LUM (C)
* min = Cmin
* max = Cmax
* if n < 0.0
* C = l + ( ( ( C – l ) × l ) ⁄ ( l – min ) )
* if x > 1.0
* C = l + ( ( ( C – l ) × ( 1 – l ) ) ⁄ ( max – l ) )
* return C
*
* set_lum (C, l):
* d = l – LUM (C)
* C += d
* return clip_color (C)
*
* SAT (C) = CH_MAX (C) - CH_MIN (C)
*
* set_sat (C, s):
* if Cmax > Cmin
* Cmid = ( ( ( Cmid – Cmin ) × s ) ⁄ ( Cmax – Cmin ) )
* Cmax = s
* else
* Cmid = Cmax = 0.0
* Cmin = 0.0
* return C
*/
 
/* For premultiplied colors, we need to know what happens when C is
* multiplied by a real number. LUM and SAT are linear:
*
* LUM (r × C) = r × LUM (C) SAT (r * C) = r * SAT (C)
*
* If we extend clip_color with an extra argument a and change
*
* if x >= 1.0
*
* into
*
* if x >= a
*
* then clip_color is also linear:
*
* r * clip_color (C, a) = clip_color (r_c, ra);
*
* for positive r.
*
* Similarly, we can extend set_lum with an extra argument that is just passed
* on to clip_color:
*
* r * set_lum ( C, l, a)
*
* = r × clip_color ( C + l - LUM (C), a)
*
* = clip_color ( r * C + r × l - r * LUM (C), r * a)
*
* = set_lum ( r * C, r * l, r * a)
*
* Finally, set_sat:
*
* r * set_sat (C, s) = set_sat (x * C, r * s)
*
* The above holds for all non-zero x, because the x'es in the fraction for
* C_mid cancel out. Specifically, it holds for x = r:
*
* r * set_sat (C, s) = set_sat (r_c, rs)
*
*/
 
/* So, for the non-separable PDF blend modes, we have (using s, d for
* non-premultiplied colors, and S, D for premultiplied:
*
* Color:
*
* a_s * a_d * B(s, d)
* = a_s * a_d * set_lum (S/a_s, LUM (D/a_d), 1)
* = set_lum (S * a_d, a_s * LUM (D), a_s * a_d)
*
*
* Luminosity:
*
* a_s * a_d * B(s, d)
* = a_s * a_d * set_lum (D/a_d, LUM(S/a_s), 1)
* = set_lum (a_s * D, a_d * LUM(S), a_s * a_d)
*
*
* Saturation:
*
* a_s * a_d * B(s, d)
* = a_s * a_d * set_lum (set_sat (D/a_d, SAT (S/a_s)), LUM (D/a_d), 1)
* = set_lum (a_s * a_d * set_sat (D/a_d, SAT (S/a_s)),
* a_s * LUM (D), a_s * a_d)
* = set_lum (set_sat (a_s * D, a_d * SAT (S), a_s * LUM (D), a_s * a_d))
*
* Hue:
*
* a_s * a_d * B(s, d)
* = a_s * a_d * set_lum (set_sat (S/a_s, SAT (D/a_d)), LUM (D/a_d), 1)
* = set_lum (set_sat (a_d * S, a_s * SAT (D)), a_s * LUM (D), a_s * a_d)
*
*/
 
#define CH_MIN(c) (c[0] < c[1] ? (c[0] < c[2] ? c[0] : c[2]) : (c[1] < c[2] ? c[1] : c[2]))
#define CH_MAX(c) (c[0] > c[1] ? (c[0] > c[2] ? c[0] : c[2]) : (c[1] > c[2] ? c[1] : c[2]))
#define LUM(c) ((c[0] * 30 + c[1] * 59 + c[2] * 11) / 100)
#define SAT(c) (CH_MAX (c) - CH_MIN (c))
 
#define PDF_NON_SEPARABLE_BLEND_MODE(name) \
static void \
combine_ ## name ## _u (pixman_implementation_t *imp, \
pixman_op_t op, \
uint32_t *dest, \
const uint32_t *src, \
const uint32_t *mask, \
int width) \
{ \
int i; \
for (i = 0; i < width; ++i) \
{ \
uint32_t s = combine_mask (src, mask, i); \
uint32_t d = *(dest + i); \
uint8_t sa = ALPHA_8 (s); \
uint8_t isa = ~sa; \
uint8_t da = ALPHA_8 (d); \
uint8_t ida = ~da; \
uint32_t result; \
uint32_t sc[3], dc[3], c[3]; \
\
result = d; \
UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (result, isa, s, ida); \
dc[0] = RED_8 (d); \
sc[0] = RED_8 (s); \
dc[1] = GREEN_8 (d); \
sc[1] = GREEN_8 (s); \
dc[2] = BLUE_8 (d); \
sc[2] = BLUE_8 (s); \
blend_ ## name (c, dc, da, sc, sa); \
\
*(dest + i) = result + \
(DIV_ONE_UN8 (sa * (uint32_t)da) << A_SHIFT) + \
(DIV_ONE_UN8 (c[0]) << R_SHIFT) + \
(DIV_ONE_UN8 (c[1]) << G_SHIFT) + \
(DIV_ONE_UN8 (c[2])); \
} \
}
 
static void
set_lum (uint32_t dest[3], uint32_t src[3], uint32_t sa, uint32_t lum)
{
double a, l, min, max;
double tmp[3];
 
a = sa * (1.0 / MASK);
 
l = lum * (1.0 / MASK);
tmp[0] = src[0] * (1.0 / MASK);
tmp[1] = src[1] * (1.0 / MASK);
tmp[2] = src[2] * (1.0 / MASK);
 
l = l - LUM (tmp);
tmp[0] += l;
tmp[1] += l;
tmp[2] += l;
 
/* clip_color */
l = LUM (tmp);
min = CH_MIN (tmp);
max = CH_MAX (tmp);
 
if (min < 0)
{
if (l - min == 0.0)
{
tmp[0] = 0;
tmp[1] = 0;
tmp[2] = 0;
}
else
{
tmp[0] = l + (tmp[0] - l) * l / (l - min);
tmp[1] = l + (tmp[1] - l) * l / (l - min);
tmp[2] = l + (tmp[2] - l) * l / (l - min);
}
}
if (max > a)
{
if (max - l == 0.0)
{
tmp[0] = a;
tmp[1] = a;
tmp[2] = a;
}
else
{
tmp[0] = l + (tmp[0] - l) * (a - l) / (max - l);
tmp[1] = l + (tmp[1] - l) * (a - l) / (max - l);
tmp[2] = l + (tmp[2] - l) * (a - l) / (max - l);
}
}
 
dest[0] = tmp[0] * MASK + 0.5;
dest[1] = tmp[1] * MASK + 0.5;
dest[2] = tmp[2] * MASK + 0.5;
}
 
static void
set_sat (uint32_t dest[3], uint32_t src[3], uint32_t sat)
{
int id[3];
uint32_t min, max;
 
if (src[0] > src[1])
{
if (src[0] > src[2])
{
id[0] = 0;
if (src[1] > src[2])
{
id[1] = 1;
id[2] = 2;
}
else
{
id[1] = 2;
id[2] = 1;
}
}
else
{
id[0] = 2;
id[1] = 0;
id[2] = 1;
}
}
else
{
if (src[0] > src[2])
{
id[0] = 1;
id[1] = 0;
id[2] = 2;
}
else
{
id[2] = 0;
if (src[1] > src[2])
{
id[0] = 1;
id[1] = 2;
}
else
{
id[0] = 2;
id[1] = 1;
}
}
}
 
max = dest[id[0]];
min = dest[id[2]];
if (max > min)
{
dest[id[1]] = (dest[id[1]] - min) * sat / (max - min);
dest[id[0]] = sat;
dest[id[2]] = 0;
}
else
{
dest[0] = dest[1] = dest[2] = 0;
}
}
 
/*
* Hue:
* B(Cb, Cs) = set_lum (set_sat (Cs, SAT (Cb)), LUM (Cb))
*/
static inline void
blend_hsl_hue (uint32_t c[3],
uint32_t dc[3],
uint32_t da,
uint32_t sc[3],
uint32_t sa)
{
c[0] = sc[0] * da;
c[1] = sc[1] * da;
c[2] = sc[2] * da;
set_sat (c, c, SAT (dc) * sa);
set_lum (c, c, sa * da, LUM (dc) * sa);
}
 
PDF_NON_SEPARABLE_BLEND_MODE (hsl_hue)
 
/*
* Saturation:
* B(Cb, Cs) = set_lum (set_sat (Cb, SAT (Cs)), LUM (Cb))
*/
static inline void
blend_hsl_saturation (uint32_t c[3],
uint32_t dc[3],
uint32_t da,
uint32_t sc[3],
uint32_t sa)
{
c[0] = dc[0] * sa;
c[1] = dc[1] * sa;
c[2] = dc[2] * sa;
set_sat (c, c, SAT (sc) * da);
set_lum (c, c, sa * da, LUM (dc) * sa);
}
 
PDF_NON_SEPARABLE_BLEND_MODE (hsl_saturation)
 
/*
* Color:
* B(Cb, Cs) = set_lum (Cs, LUM (Cb))
*/
static inline void
blend_hsl_color (uint32_t c[3],
uint32_t dc[3],
uint32_t da,
uint32_t sc[3],
uint32_t sa)
{
c[0] = sc[0] * da;
c[1] = sc[1] * da;
c[2] = sc[2] * da;
set_lum (c, c, sa * da, LUM (dc) * sa);
}
 
PDF_NON_SEPARABLE_BLEND_MODE (hsl_color)
 
/*
* Luminosity:
* B(Cb, Cs) = set_lum (Cb, LUM (Cs))
*/
static inline void
blend_hsl_luminosity (uint32_t c[3],
uint32_t dc[3],
uint32_t da,
uint32_t sc[3],
uint32_t sa)
{
c[0] = dc[0] * sa;
c[1] = dc[1] * sa;
c[2] = dc[2] * sa;
set_lum (c, c, sa * da, LUM (sc) * da);
}
 
PDF_NON_SEPARABLE_BLEND_MODE (hsl_luminosity)
 
#undef SAT
#undef LUM
#undef CH_MAX
#undef CH_MIN
#undef PDF_NON_SEPARABLE_BLEND_MODE
 
/* All of the disjoint/conjoint composing functions
*
* The four entries in the first column indicate what source contributions
* come from each of the four areas of the picture -- areas covered by neither
* A nor B, areas covered only by A, areas covered only by B and finally
* areas covered by both A and B.
*
* Disjoint Conjoint
* Fa Fb Fa Fb
* (0,0,0,0) 0 0 0 0
* (0,A,0,A) 1 0 1 0
* (0,0,B,B) 0 1 0 1
* (0,A,B,A) 1 min((1-a)/b,1) 1 max(1-a/b,0)
* (0,A,B,B) min((1-b)/a,1) 1 max(1-b/a,0) 1
* (0,0,0,A) max(1-(1-b)/a,0) 0 min(1,b/a) 0
* (0,0,0,B) 0 max(1-(1-a)/b,0) 0 min(a/b,1)
* (0,A,0,0) min(1,(1-b)/a) 0 max(1-b/a,0) 0
* (0,0,B,0) 0 min(1,(1-a)/b) 0 max(1-a/b,0)
* (0,0,B,A) max(1-(1-b)/a,0) min(1,(1-a)/b) min(1,b/a) max(1-a/b,0)
* (0,A,0,B) min(1,(1-b)/a) max(1-(1-a)/b,0) max(1-b/a,0) min(1,a/b)
* (0,A,B,0) min(1,(1-b)/a) min(1,(1-a)/b) max(1-b/a,0) max(1-a/b,0)
*
* See http://marc.info/?l=xfree-render&m=99792000027857&w=2 for more
* information about these operators.
*/
 
#define COMBINE_A_OUT 1
#define COMBINE_A_IN 2
#define COMBINE_B_OUT 4
#define COMBINE_B_IN 8
 
#define COMBINE_CLEAR 0
#define COMBINE_A (COMBINE_A_OUT | COMBINE_A_IN)
#define COMBINE_B (COMBINE_B_OUT | COMBINE_B_IN)
#define COMBINE_A_OVER (COMBINE_A_OUT | COMBINE_B_OUT | COMBINE_A_IN)
#define COMBINE_B_OVER (COMBINE_A_OUT | COMBINE_B_OUT | COMBINE_B_IN)
#define COMBINE_A_ATOP (COMBINE_B_OUT | COMBINE_A_IN)
#define COMBINE_B_ATOP (COMBINE_A_OUT | COMBINE_B_IN)
#define COMBINE_XOR (COMBINE_A_OUT | COMBINE_B_OUT)
 
/* portion covered by a but not b */
static uint8_t
combine_disjoint_out_part (uint8_t a, uint8_t b)
{
/* min (1, (1-b) / a) */
 
b = ~b; /* 1 - b */
if (b >= a) /* 1 - b >= a -> (1-b)/a >= 1 */
return MASK; /* 1 */
return DIV_UN8 (b, a); /* (1-b) / a */
}
 
/* portion covered by both a and b */
static uint8_t
combine_disjoint_in_part (uint8_t a, uint8_t b)
{
/* max (1-(1-b)/a,0) */
/* = - min ((1-b)/a - 1, 0) */
/* = 1 - min (1, (1-b)/a) */
 
b = ~b; /* 1 - b */
if (b >= a) /* 1 - b >= a -> (1-b)/a >= 1 */
return 0; /* 1 - 1 */
return ~DIV_UN8(b, a); /* 1 - (1-b) / a */
}
 
/* portion covered by a but not b */
static uint8_t
combine_conjoint_out_part (uint8_t a, uint8_t b)
{
/* max (1-b/a,0) */
/* = 1-min(b/a,1) */
 
/* min (1, (1-b) / a) */
 
if (b >= a) /* b >= a -> b/a >= 1 */
return 0x00; /* 0 */
return ~DIV_UN8(b, a); /* 1 - b/a */
}
 
/* portion covered by both a and b */
static uint8_t
combine_conjoint_in_part (uint8_t a, uint8_t b)
{
/* min (1,b/a) */
 
if (b >= a) /* b >= a -> b/a >= 1 */
return MASK; /* 1 */
return DIV_UN8 (b, a); /* b/a */
}
 
#define GET_COMP(v, i) ((uint16_t) (uint8_t) ((v) >> i))
 
#define ADD(x, y, i, t) \
((t) = GET_COMP (x, i) + GET_COMP (y, i), \
(uint32_t) ((uint8_t) ((t) | (0 - ((t) >> G_SHIFT)))) << (i))
 
#define GENERIC(x, y, i, ax, ay, t, u, v) \
((t) = (MUL_UN8 (GET_COMP (y, i), ay, (u)) + \
MUL_UN8 (GET_COMP (x, i), ax, (v))), \
(uint32_t) ((uint8_t) ((t) | \
(0 - ((t) >> G_SHIFT)))) << (i))
 
static void
combine_disjoint_general_u (uint32_t * dest,
const uint32_t *src,
const uint32_t *mask,
int width,
uint8_t combine)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = combine_mask (src, mask, i);
uint32_t d = *(dest + i);
uint32_t m, n, o, p;
uint16_t Fa, Fb, t, u, v;
uint8_t sa = s >> A_SHIFT;
uint8_t da = d >> A_SHIFT;
 
switch (combine & COMBINE_A)
{
default:
Fa = 0;
break;
 
case COMBINE_A_OUT:
Fa = combine_disjoint_out_part (sa, da);
break;
 
case COMBINE_A_IN:
Fa = combine_disjoint_in_part (sa, da);
break;
 
case COMBINE_A:
Fa = MASK;
break;
}
 
switch (combine & COMBINE_B)
{
default:
Fb = 0;
break;
 
case COMBINE_B_OUT:
Fb = combine_disjoint_out_part (da, sa);
break;
 
case COMBINE_B_IN:
Fb = combine_disjoint_in_part (da, sa);
break;
 
case COMBINE_B:
Fb = MASK;
break;
}
m = GENERIC (s, d, 0, Fa, Fb, t, u, v);
n = GENERIC (s, d, G_SHIFT, Fa, Fb, t, u, v);
o = GENERIC (s, d, R_SHIFT, Fa, Fb, t, u, v);
p = GENERIC (s, d, A_SHIFT, Fa, Fb, t, u, v);
s = m | n | o | p;
*(dest + i) = s;
}
}
 
static void
combine_disjoint_over_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = combine_mask (src, mask, i);
uint16_t a = s >> A_SHIFT;
 
if (s != 0x00)
{
uint32_t d = *(dest + i);
a = combine_disjoint_out_part (d >> A_SHIFT, a);
UN8x4_MUL_UN8_ADD_UN8x4 (d, a, s);
 
*(dest + i) = d;
}
}
}
 
static void
combine_disjoint_in_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_disjoint_general_u (dest, src, mask, width, COMBINE_A_IN);
}
 
static void
combine_disjoint_in_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_disjoint_general_u (dest, src, mask, width, COMBINE_B_IN);
}
 
static void
combine_disjoint_out_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_disjoint_general_u (dest, src, mask, width, COMBINE_A_OUT);
}
 
static void
combine_disjoint_out_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_disjoint_general_u (dest, src, mask, width, COMBINE_B_OUT);
}
 
static void
combine_disjoint_atop_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_disjoint_general_u (dest, src, mask, width, COMBINE_A_ATOP);
}
 
static void
combine_disjoint_atop_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_disjoint_general_u (dest, src, mask, width, COMBINE_B_ATOP);
}
 
static void
combine_disjoint_xor_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_disjoint_general_u (dest, src, mask, width, COMBINE_XOR);
}
 
static void
combine_conjoint_general_u (uint32_t * dest,
const uint32_t *src,
const uint32_t *mask,
int width,
uint8_t combine)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = combine_mask (src, mask, i);
uint32_t d = *(dest + i);
uint32_t m, n, o, p;
uint16_t Fa, Fb, t, u, v;
uint8_t sa = s >> A_SHIFT;
uint8_t da = d >> A_SHIFT;
 
switch (combine & COMBINE_A)
{
default:
Fa = 0;
break;
 
case COMBINE_A_OUT:
Fa = combine_conjoint_out_part (sa, da);
break;
 
case COMBINE_A_IN:
Fa = combine_conjoint_in_part (sa, da);
break;
 
case COMBINE_A:
Fa = MASK;
break;
}
 
switch (combine & COMBINE_B)
{
default:
Fb = 0;
break;
 
case COMBINE_B_OUT:
Fb = combine_conjoint_out_part (da, sa);
break;
 
case COMBINE_B_IN:
Fb = combine_conjoint_in_part (da, sa);
break;
 
case COMBINE_B:
Fb = MASK;
break;
}
 
m = GENERIC (s, d, 0, Fa, Fb, t, u, v);
n = GENERIC (s, d, G_SHIFT, Fa, Fb, t, u, v);
o = GENERIC (s, d, R_SHIFT, Fa, Fb, t, u, v);
p = GENERIC (s, d, A_SHIFT, Fa, Fb, t, u, v);
 
s = m | n | o | p;
 
*(dest + i) = s;
}
}
 
static void
combine_conjoint_over_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_u (dest, src, mask, width, COMBINE_A_OVER);
}
 
static void
combine_conjoint_over_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_u (dest, src, mask, width, COMBINE_B_OVER);
}
 
static void
combine_conjoint_in_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_u (dest, src, mask, width, COMBINE_A_IN);
}
 
static void
combine_conjoint_in_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_u (dest, src, mask, width, COMBINE_B_IN);
}
 
static void
combine_conjoint_out_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_u (dest, src, mask, width, COMBINE_A_OUT);
}
 
static void
combine_conjoint_out_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_u (dest, src, mask, width, COMBINE_B_OUT);
}
 
static void
combine_conjoint_atop_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_u (dest, src, mask, width, COMBINE_A_ATOP);
}
 
static void
combine_conjoint_atop_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_u (dest, src, mask, width, COMBINE_B_ATOP);
}
 
static void
combine_conjoint_xor_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_u (dest, src, mask, width, COMBINE_XOR);
}
 
 
/* Component alpha combiners */
 
static void
combine_clear_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
memset (dest, 0, width * sizeof(uint32_t));
}
 
static void
combine_src_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = *(src + i);
uint32_t m = *(mask + i);
 
combine_mask_value_ca (&s, &m);
 
*(dest + i) = s;
}
}
 
static void
combine_over_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = *(src + i);
uint32_t m = *(mask + i);
uint32_t a;
 
combine_mask_ca (&s, &m);
 
a = ~m;
if (a)
{
uint32_t d = *(dest + i);
UN8x4_MUL_UN8x4_ADD_UN8x4 (d, a, s);
s = d;
}
 
*(dest + i) = s;
}
}
 
static void
combine_over_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t d = *(dest + i);
uint32_t a = ~d >> A_SHIFT;
 
if (a)
{
uint32_t s = *(src + i);
uint32_t m = *(mask + i);
 
UN8x4_MUL_UN8x4 (s, m);
UN8x4_MUL_UN8_ADD_UN8x4 (s, a, d);
 
*(dest + i) = s;
}
}
}
 
static void
combine_in_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t d = *(dest + i);
uint16_t a = d >> A_SHIFT;
uint32_t s = 0;
 
if (a)
{
uint32_t m = *(mask + i);
 
s = *(src + i);
combine_mask_value_ca (&s, &m);
 
if (a != MASK)
UN8x4_MUL_UN8 (s, a);
}
 
*(dest + i) = s;
}
}
 
static void
combine_in_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = *(src + i);
uint32_t m = *(mask + i);
uint32_t a;
 
combine_mask_alpha_ca (&s, &m);
 
a = m;
if (a != ~0)
{
uint32_t d = 0;
 
if (a)
{
d = *(dest + i);
UN8x4_MUL_UN8x4 (d, a);
}
 
*(dest + i) = d;
}
}
}
 
static void
combine_out_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t d = *(dest + i);
uint16_t a = ~d >> A_SHIFT;
uint32_t s = 0;
 
if (a)
{
uint32_t m = *(mask + i);
 
s = *(src + i);
combine_mask_value_ca (&s, &m);
 
if (a != MASK)
UN8x4_MUL_UN8 (s, a);
}
 
*(dest + i) = s;
}
}
 
static void
combine_out_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = *(src + i);
uint32_t m = *(mask + i);
uint32_t a;
 
combine_mask_alpha_ca (&s, &m);
 
a = ~m;
if (a != ~0)
{
uint32_t d = 0;
 
if (a)
{
d = *(dest + i);
UN8x4_MUL_UN8x4 (d, a);
}
 
*(dest + i) = d;
}
}
}
 
static void
combine_atop_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t d = *(dest + i);
uint32_t s = *(src + i);
uint32_t m = *(mask + i);
uint32_t ad;
uint16_t as = d >> A_SHIFT;
 
combine_mask_ca (&s, &m);
 
ad = ~m;
 
UN8x4_MUL_UN8x4_ADD_UN8x4_MUL_UN8 (d, ad, s, as);
 
*(dest + i) = d;
}
}
 
static void
combine_atop_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t d = *(dest + i);
uint32_t s = *(src + i);
uint32_t m = *(mask + i);
uint32_t ad;
uint16_t as = ~d >> A_SHIFT;
 
combine_mask_ca (&s, &m);
 
ad = m;
 
UN8x4_MUL_UN8x4_ADD_UN8x4_MUL_UN8 (d, ad, s, as);
 
*(dest + i) = d;
}
}
 
static void
combine_xor_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t d = *(dest + i);
uint32_t s = *(src + i);
uint32_t m = *(mask + i);
uint32_t ad;
uint16_t as = ~d >> A_SHIFT;
 
combine_mask_ca (&s, &m);
 
ad = ~m;
 
UN8x4_MUL_UN8x4_ADD_UN8x4_MUL_UN8 (d, ad, s, as);
 
*(dest + i) = d;
}
}
 
static void
combine_add_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s = *(src + i);
uint32_t m = *(mask + i);
uint32_t d = *(dest + i);
 
combine_mask_value_ca (&s, &m);
 
UN8x4_ADD_UN8x4 (d, s);
 
*(dest + i) = d;
}
}
 
static void
combine_saturate_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s, d;
uint16_t sa, sr, sg, sb, da;
uint16_t t, u, v;
uint32_t m, n, o, p;
 
d = *(dest + i);
s = *(src + i);
m = *(mask + i);
 
combine_mask_ca (&s, &m);
 
sa = (m >> A_SHIFT);
sr = (m >> R_SHIFT) & MASK;
sg = (m >> G_SHIFT) & MASK;
sb = m & MASK;
da = ~d >> A_SHIFT;
 
if (sb <= da)
m = ADD (s, d, 0, t);
else
m = GENERIC (s, d, 0, (da << G_SHIFT) / sb, MASK, t, u, v);
 
if (sg <= da)
n = ADD (s, d, G_SHIFT, t);
else
n = GENERIC (s, d, G_SHIFT, (da << G_SHIFT) / sg, MASK, t, u, v);
 
if (sr <= da)
o = ADD (s, d, R_SHIFT, t);
else
o = GENERIC (s, d, R_SHIFT, (da << G_SHIFT) / sr, MASK, t, u, v);
 
if (sa <= da)
p = ADD (s, d, A_SHIFT, t);
else
p = GENERIC (s, d, A_SHIFT, (da << G_SHIFT) / sa, MASK, t, u, v);
 
*(dest + i) = m | n | o | p;
}
}
 
static void
combine_disjoint_general_ca (uint32_t * dest,
const uint32_t *src,
const uint32_t *mask,
int width,
uint8_t combine)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s, d;
uint32_t m, n, o, p;
uint32_t Fa, Fb;
uint16_t t, u, v;
uint32_t sa;
uint8_t da;
 
s = *(src + i);
m = *(mask + i);
d = *(dest + i);
da = d >> A_SHIFT;
 
combine_mask_ca (&s, &m);
 
sa = m;
 
switch (combine & COMBINE_A)
{
default:
Fa = 0;
break;
 
case COMBINE_A_OUT:
m = (uint32_t)combine_disjoint_out_part ((uint8_t) (sa >> 0), da);
n = (uint32_t)combine_disjoint_out_part ((uint8_t) (sa >> G_SHIFT), da) << G_SHIFT;
o = (uint32_t)combine_disjoint_out_part ((uint8_t) (sa >> R_SHIFT), da) << R_SHIFT;
p = (uint32_t)combine_disjoint_out_part ((uint8_t) (sa >> A_SHIFT), da) << A_SHIFT;
Fa = m | n | o | p;
break;
 
case COMBINE_A_IN:
m = (uint32_t)combine_disjoint_in_part ((uint8_t) (sa >> 0), da);
n = (uint32_t)combine_disjoint_in_part ((uint8_t) (sa >> G_SHIFT), da) << G_SHIFT;
o = (uint32_t)combine_disjoint_in_part ((uint8_t) (sa >> R_SHIFT), da) << R_SHIFT;
p = (uint32_t)combine_disjoint_in_part ((uint8_t) (sa >> A_SHIFT), da) << A_SHIFT;
Fa = m | n | o | p;
break;
 
case COMBINE_A:
Fa = ~0;
break;
}
 
switch (combine & COMBINE_B)
{
default:
Fb = 0;
break;
 
case COMBINE_B_OUT:
m = (uint32_t)combine_disjoint_out_part (da, (uint8_t) (sa >> 0));
n = (uint32_t)combine_disjoint_out_part (da, (uint8_t) (sa >> G_SHIFT)) << G_SHIFT;
o = (uint32_t)combine_disjoint_out_part (da, (uint8_t) (sa >> R_SHIFT)) << R_SHIFT;
p = (uint32_t)combine_disjoint_out_part (da, (uint8_t) (sa >> A_SHIFT)) << A_SHIFT;
Fb = m | n | o | p;
break;
 
case COMBINE_B_IN:
m = (uint32_t)combine_disjoint_in_part (da, (uint8_t) (sa >> 0));
n = (uint32_t)combine_disjoint_in_part (da, (uint8_t) (sa >> G_SHIFT)) << G_SHIFT;
o = (uint32_t)combine_disjoint_in_part (da, (uint8_t) (sa >> R_SHIFT)) << R_SHIFT;
p = (uint32_t)combine_disjoint_in_part (da, (uint8_t) (sa >> A_SHIFT)) << A_SHIFT;
Fb = m | n | o | p;
break;
 
case COMBINE_B:
Fb = ~0;
break;
}
m = GENERIC (s, d, 0, GET_COMP (Fa, 0), GET_COMP (Fb, 0), t, u, v);
n = GENERIC (s, d, G_SHIFT, GET_COMP (Fa, G_SHIFT), GET_COMP (Fb, G_SHIFT), t, u, v);
o = GENERIC (s, d, R_SHIFT, GET_COMP (Fa, R_SHIFT), GET_COMP (Fb, R_SHIFT), t, u, v);
p = GENERIC (s, d, A_SHIFT, GET_COMP (Fa, A_SHIFT), GET_COMP (Fb, A_SHIFT), t, u, v);
 
s = m | n | o | p;
 
*(dest + i) = s;
}
}
 
static void
combine_disjoint_over_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_disjoint_general_ca (dest, src, mask, width, COMBINE_A_OVER);
}
 
static void
combine_disjoint_in_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_disjoint_general_ca (dest, src, mask, width, COMBINE_A_IN);
}
 
static void
combine_disjoint_in_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_disjoint_general_ca (dest, src, mask, width, COMBINE_B_IN);
}
 
static void
combine_disjoint_out_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_disjoint_general_ca (dest, src, mask, width, COMBINE_A_OUT);
}
 
static void
combine_disjoint_out_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_disjoint_general_ca (dest, src, mask, width, COMBINE_B_OUT);
}
 
static void
combine_disjoint_atop_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_disjoint_general_ca (dest, src, mask, width, COMBINE_A_ATOP);
}
 
static void
combine_disjoint_atop_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_disjoint_general_ca (dest, src, mask, width, COMBINE_B_ATOP);
}
 
static void
combine_disjoint_xor_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_disjoint_general_ca (dest, src, mask, width, COMBINE_XOR);
}
 
static void
combine_conjoint_general_ca (uint32_t * dest,
const uint32_t *src,
const uint32_t *mask,
int width,
uint8_t combine)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint32_t s, d;
uint32_t m, n, o, p;
uint32_t Fa, Fb;
uint16_t t, u, v;
uint32_t sa;
uint8_t da;
 
s = *(src + i);
m = *(mask + i);
d = *(dest + i);
da = d >> A_SHIFT;
 
combine_mask_ca (&s, &m);
 
sa = m;
 
switch (combine & COMBINE_A)
{
default:
Fa = 0;
break;
 
case COMBINE_A_OUT:
m = (uint32_t)combine_conjoint_out_part ((uint8_t) (sa >> 0), da);
n = (uint32_t)combine_conjoint_out_part ((uint8_t) (sa >> G_SHIFT), da) << G_SHIFT;
o = (uint32_t)combine_conjoint_out_part ((uint8_t) (sa >> R_SHIFT), da) << R_SHIFT;
p = (uint32_t)combine_conjoint_out_part ((uint8_t) (sa >> A_SHIFT), da) << A_SHIFT;
Fa = m | n | o | p;
break;
 
case COMBINE_A_IN:
m = (uint32_t)combine_conjoint_in_part ((uint8_t) (sa >> 0), da);
n = (uint32_t)combine_conjoint_in_part ((uint8_t) (sa >> G_SHIFT), da) << G_SHIFT;
o = (uint32_t)combine_conjoint_in_part ((uint8_t) (sa >> R_SHIFT), da) << R_SHIFT;
p = (uint32_t)combine_conjoint_in_part ((uint8_t) (sa >> A_SHIFT), da) << A_SHIFT;
Fa = m | n | o | p;
break;
 
case COMBINE_A:
Fa = ~0;
break;
}
 
switch (combine & COMBINE_B)
{
default:
Fb = 0;
break;
 
case COMBINE_B_OUT:
m = (uint32_t)combine_conjoint_out_part (da, (uint8_t) (sa >> 0));
n = (uint32_t)combine_conjoint_out_part (da, (uint8_t) (sa >> G_SHIFT)) << G_SHIFT;
o = (uint32_t)combine_conjoint_out_part (da, (uint8_t) (sa >> R_SHIFT)) << R_SHIFT;
p = (uint32_t)combine_conjoint_out_part (da, (uint8_t) (sa >> A_SHIFT)) << A_SHIFT;
Fb = m | n | o | p;
break;
 
case COMBINE_B_IN:
m = (uint32_t)combine_conjoint_in_part (da, (uint8_t) (sa >> 0));
n = (uint32_t)combine_conjoint_in_part (da, (uint8_t) (sa >> G_SHIFT)) << G_SHIFT;
o = (uint32_t)combine_conjoint_in_part (da, (uint8_t) (sa >> R_SHIFT)) << R_SHIFT;
p = (uint32_t)combine_conjoint_in_part (da, (uint8_t) (sa >> A_SHIFT)) << A_SHIFT;
Fb = m | n | o | p;
break;
 
case COMBINE_B:
Fb = ~0;
break;
}
m = GENERIC (s, d, 0, GET_COMP (Fa, 0), GET_COMP (Fb, 0), t, u, v);
n = GENERIC (s, d, G_SHIFT, GET_COMP (Fa, G_SHIFT), GET_COMP (Fb, G_SHIFT), t, u, v);
o = GENERIC (s, d, R_SHIFT, GET_COMP (Fa, R_SHIFT), GET_COMP (Fb, R_SHIFT), t, u, v);
p = GENERIC (s, d, A_SHIFT, GET_COMP (Fa, A_SHIFT), GET_COMP (Fb, A_SHIFT), t, u, v);
 
s = m | n | o | p;
 
*(dest + i) = s;
}
}
 
static void
combine_conjoint_over_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_ca (dest, src, mask, width, COMBINE_A_OVER);
}
 
static void
combine_conjoint_over_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_ca (dest, src, mask, width, COMBINE_B_OVER);
}
 
static void
combine_conjoint_in_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_ca (dest, src, mask, width, COMBINE_A_IN);
}
 
static void
combine_conjoint_in_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_ca (dest, src, mask, width, COMBINE_B_IN);
}
 
static void
combine_conjoint_out_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_ca (dest, src, mask, width, COMBINE_A_OUT);
}
 
static void
combine_conjoint_out_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_ca (dest, src, mask, width, COMBINE_B_OUT);
}
 
static void
combine_conjoint_atop_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_ca (dest, src, mask, width, COMBINE_A_ATOP);
}
 
static void
combine_conjoint_atop_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_ca (dest, src, mask, width, COMBINE_B_ATOP);
}
 
static void
combine_conjoint_xor_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
combine_conjoint_general_ca (dest, src, mask, width, COMBINE_XOR);
}
 
void
_pixman_setup_combiner_functions_32 (pixman_implementation_t *imp)
{
/* Unified alpha */
imp->combine_32[PIXMAN_OP_CLEAR] = combine_clear;
imp->combine_32[PIXMAN_OP_SRC] = combine_src_u;
imp->combine_32[PIXMAN_OP_DST] = combine_dst;
imp->combine_32[PIXMAN_OP_OVER] = combine_over_u;
imp->combine_32[PIXMAN_OP_OVER_REVERSE] = combine_over_reverse_u;
imp->combine_32[PIXMAN_OP_IN] = combine_in_u;
imp->combine_32[PIXMAN_OP_IN_REVERSE] = combine_in_reverse_u;
imp->combine_32[PIXMAN_OP_OUT] = combine_out_u;
imp->combine_32[PIXMAN_OP_OUT_REVERSE] = combine_out_reverse_u;
imp->combine_32[PIXMAN_OP_ATOP] = combine_atop_u;
imp->combine_32[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_u;
imp->combine_32[PIXMAN_OP_XOR] = combine_xor_u;
imp->combine_32[PIXMAN_OP_ADD] = combine_add_u;
imp->combine_32[PIXMAN_OP_SATURATE] = combine_saturate_u;
 
/* Disjoint, unified */
imp->combine_32[PIXMAN_OP_DISJOINT_CLEAR] = combine_clear;
imp->combine_32[PIXMAN_OP_DISJOINT_SRC] = combine_src_u;
imp->combine_32[PIXMAN_OP_DISJOINT_DST] = combine_dst;
imp->combine_32[PIXMAN_OP_DISJOINT_OVER] = combine_disjoint_over_u;
imp->combine_32[PIXMAN_OP_DISJOINT_OVER_REVERSE] = combine_saturate_u;
imp->combine_32[PIXMAN_OP_DISJOINT_IN] = combine_disjoint_in_u;
imp->combine_32[PIXMAN_OP_DISJOINT_IN_REVERSE] = combine_disjoint_in_reverse_u;
imp->combine_32[PIXMAN_OP_DISJOINT_OUT] = combine_disjoint_out_u;
imp->combine_32[PIXMAN_OP_DISJOINT_OUT_REVERSE] = combine_disjoint_out_reverse_u;
imp->combine_32[PIXMAN_OP_DISJOINT_ATOP] = combine_disjoint_atop_u;
imp->combine_32[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = combine_disjoint_atop_reverse_u;
imp->combine_32[PIXMAN_OP_DISJOINT_XOR] = combine_disjoint_xor_u;
 
/* Conjoint, unified */
imp->combine_32[PIXMAN_OP_CONJOINT_CLEAR] = combine_clear;
imp->combine_32[PIXMAN_OP_CONJOINT_SRC] = combine_src_u;
imp->combine_32[PIXMAN_OP_CONJOINT_DST] = combine_dst;
imp->combine_32[PIXMAN_OP_CONJOINT_OVER] = combine_conjoint_over_u;
imp->combine_32[PIXMAN_OP_CONJOINT_OVER_REVERSE] = combine_conjoint_over_reverse_u;
imp->combine_32[PIXMAN_OP_CONJOINT_IN] = combine_conjoint_in_u;
imp->combine_32[PIXMAN_OP_CONJOINT_IN_REVERSE] = combine_conjoint_in_reverse_u;
imp->combine_32[PIXMAN_OP_CONJOINT_OUT] = combine_conjoint_out_u;
imp->combine_32[PIXMAN_OP_CONJOINT_OUT_REVERSE] = combine_conjoint_out_reverse_u;
imp->combine_32[PIXMAN_OP_CONJOINT_ATOP] = combine_conjoint_atop_u;
imp->combine_32[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = combine_conjoint_atop_reverse_u;
imp->combine_32[PIXMAN_OP_CONJOINT_XOR] = combine_conjoint_xor_u;
 
imp->combine_32[PIXMAN_OP_MULTIPLY] = combine_multiply_u;
imp->combine_32[PIXMAN_OP_SCREEN] = combine_screen_u;
imp->combine_32[PIXMAN_OP_OVERLAY] = combine_overlay_u;
imp->combine_32[PIXMAN_OP_DARKEN] = combine_darken_u;
imp->combine_32[PIXMAN_OP_LIGHTEN] = combine_lighten_u;
imp->combine_32[PIXMAN_OP_COLOR_DODGE] = combine_color_dodge_u;
imp->combine_32[PIXMAN_OP_COLOR_BURN] = combine_color_burn_u;
imp->combine_32[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_u;
imp->combine_32[PIXMAN_OP_SOFT_LIGHT] = combine_soft_light_u;
imp->combine_32[PIXMAN_OP_DIFFERENCE] = combine_difference_u;
imp->combine_32[PIXMAN_OP_EXCLUSION] = combine_exclusion_u;
imp->combine_32[PIXMAN_OP_HSL_HUE] = combine_hsl_hue_u;
imp->combine_32[PIXMAN_OP_HSL_SATURATION] = combine_hsl_saturation_u;
imp->combine_32[PIXMAN_OP_HSL_COLOR] = combine_hsl_color_u;
imp->combine_32[PIXMAN_OP_HSL_LUMINOSITY] = combine_hsl_luminosity_u;
 
/* Component alpha combiners */
imp->combine_32_ca[PIXMAN_OP_CLEAR] = combine_clear_ca;
imp->combine_32_ca[PIXMAN_OP_SRC] = combine_src_ca;
/* dest */
imp->combine_32_ca[PIXMAN_OP_OVER] = combine_over_ca;
imp->combine_32_ca[PIXMAN_OP_OVER_REVERSE] = combine_over_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_IN] = combine_in_ca;
imp->combine_32_ca[PIXMAN_OP_IN_REVERSE] = combine_in_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_OUT] = combine_out_ca;
imp->combine_32_ca[PIXMAN_OP_OUT_REVERSE] = combine_out_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_ATOP] = combine_atop_ca;
imp->combine_32_ca[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_XOR] = combine_xor_ca;
imp->combine_32_ca[PIXMAN_OP_ADD] = combine_add_ca;
imp->combine_32_ca[PIXMAN_OP_SATURATE] = combine_saturate_ca;
 
/* Disjoint CA */
imp->combine_32_ca[PIXMAN_OP_DISJOINT_CLEAR] = combine_clear_ca;
imp->combine_32_ca[PIXMAN_OP_DISJOINT_SRC] = combine_src_ca;
imp->combine_32_ca[PIXMAN_OP_DISJOINT_DST] = combine_dst;
imp->combine_32_ca[PIXMAN_OP_DISJOINT_OVER] = combine_disjoint_over_ca;
imp->combine_32_ca[PIXMAN_OP_DISJOINT_OVER_REVERSE] = combine_saturate_ca;
imp->combine_32_ca[PIXMAN_OP_DISJOINT_IN] = combine_disjoint_in_ca;
imp->combine_32_ca[PIXMAN_OP_DISJOINT_IN_REVERSE] = combine_disjoint_in_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_DISJOINT_OUT] = combine_disjoint_out_ca;
imp->combine_32_ca[PIXMAN_OP_DISJOINT_OUT_REVERSE] = combine_disjoint_out_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_DISJOINT_ATOP] = combine_disjoint_atop_ca;
imp->combine_32_ca[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = combine_disjoint_atop_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_DISJOINT_XOR] = combine_disjoint_xor_ca;
 
/* Conjoint CA */
imp->combine_32_ca[PIXMAN_OP_CONJOINT_CLEAR] = combine_clear_ca;
imp->combine_32_ca[PIXMAN_OP_CONJOINT_SRC] = combine_src_ca;
imp->combine_32_ca[PIXMAN_OP_CONJOINT_DST] = combine_dst;
imp->combine_32_ca[PIXMAN_OP_CONJOINT_OVER] = combine_conjoint_over_ca;
imp->combine_32_ca[PIXMAN_OP_CONJOINT_OVER_REVERSE] = combine_conjoint_over_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_CONJOINT_IN] = combine_conjoint_in_ca;
imp->combine_32_ca[PIXMAN_OP_CONJOINT_IN_REVERSE] = combine_conjoint_in_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_CONJOINT_OUT] = combine_conjoint_out_ca;
imp->combine_32_ca[PIXMAN_OP_CONJOINT_OUT_REVERSE] = combine_conjoint_out_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_CONJOINT_ATOP] = combine_conjoint_atop_ca;
imp->combine_32_ca[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = combine_conjoint_atop_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_CONJOINT_XOR] = combine_conjoint_xor_ca;
 
imp->combine_32_ca[PIXMAN_OP_MULTIPLY] = combine_multiply_ca;
imp->combine_32_ca[PIXMAN_OP_SCREEN] = combine_screen_ca;
imp->combine_32_ca[PIXMAN_OP_OVERLAY] = combine_overlay_ca;
imp->combine_32_ca[PIXMAN_OP_DARKEN] = combine_darken_ca;
imp->combine_32_ca[PIXMAN_OP_LIGHTEN] = combine_lighten_ca;
imp->combine_32_ca[PIXMAN_OP_COLOR_DODGE] = combine_color_dodge_ca;
imp->combine_32_ca[PIXMAN_OP_COLOR_BURN] = combine_color_burn_ca;
imp->combine_32_ca[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_ca;
imp->combine_32_ca[PIXMAN_OP_SOFT_LIGHT] = combine_soft_light_ca;
imp->combine_32_ca[PIXMAN_OP_DIFFERENCE] = combine_difference_ca;
imp->combine_32_ca[PIXMAN_OP_EXCLUSION] = combine_exclusion_ca;
 
/* It is not clear that these make sense, so make them noops for now */
imp->combine_32_ca[PIXMAN_OP_HSL_HUE] = combine_dst;
imp->combine_32_ca[PIXMAN_OP_HSL_SATURATION] = combine_dst;
imp->combine_32_ca[PIXMAN_OP_HSL_COLOR] = combine_dst;
imp->combine_32_ca[PIXMAN_OP_HSL_LUMINOSITY] = combine_dst;
}
/contrib/sdk/sources/pixman/pixman-combine32.h
0,0 → 1,272
#define COMPONENT_SIZE 8
#define MASK 0xff
#define ONE_HALF 0x80
 
#define A_SHIFT 8 * 3
#define R_SHIFT 8 * 2
#define G_SHIFT 8
#define A_MASK 0xff000000
#define R_MASK 0xff0000
#define G_MASK 0xff00
 
#define RB_MASK 0xff00ff
#define AG_MASK 0xff00ff00
#define RB_ONE_HALF 0x800080
#define RB_MASK_PLUS_ONE 0x10000100
 
#define ALPHA_8(x) ((x) >> A_SHIFT)
#define RED_8(x) (((x) >> R_SHIFT) & MASK)
#define GREEN_8(x) (((x) >> G_SHIFT) & MASK)
#define BLUE_8(x) ((x) & MASK)
 
/*
* ARMv6 has UQADD8 instruction, which implements unsigned saturated
* addition for 8-bit values packed in 32-bit registers. It is very useful
* for UN8x4_ADD_UN8x4, UN8_rb_ADD_UN8_rb and ADD_UN8 macros (which would
* otherwise need a lot of arithmetic operations to simulate this operation).
* Since most of the major ARM linux distros are built for ARMv7, we are
* much less dependent on runtime CPU detection and can get practical
* benefits from conditional compilation here for a lot of users.
*/
 
#if defined(USE_GCC_INLINE_ASM) && defined(__arm__) && \
!defined(__aarch64__) && (!defined(__thumb__) || defined(__thumb2__))
#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \
defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) || \
defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_7__) || \
defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || \
defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
 
static force_inline uint32_t
un8x4_add_un8x4 (uint32_t x, uint32_t y)
{
uint32_t t;
asm ("uqadd8 %0, %1, %2" : "=r" (t) : "%r" (x), "r" (y));
return t;
}
 
#define UN8x4_ADD_UN8x4(x, y) \
((x) = un8x4_add_un8x4 ((x), (y)))
 
#define UN8_rb_ADD_UN8_rb(x, y, t) \
((t) = un8x4_add_un8x4 ((x), (y)), (x) = (t))
 
#define ADD_UN8(x, y, t) \
((t) = (x), un8x4_add_un8x4 ((t), (y)))
 
#endif
#endif
 
/*****************************************************************************/
 
/*
* Helper macros.
*/
 
#define MUL_UN8(a, b, t) \
((t) = (a) * (uint16_t)(b) + ONE_HALF, ((((t) >> G_SHIFT ) + (t) ) >> G_SHIFT ))
 
#define DIV_UN8(a, b) \
(((uint16_t) (a) * MASK + ((b) / 2)) / (b))
 
#ifndef ADD_UN8
#define ADD_UN8(x, y, t) \
((t) = (x) + (y), \
(uint32_t) (uint8_t) ((t) | (0 - ((t) >> G_SHIFT))))
#endif
 
#define DIV_ONE_UN8(x) \
(((x) + ONE_HALF + (((x) + ONE_HALF) >> G_SHIFT)) >> G_SHIFT)
 
/*
* The methods below use some tricks to be able to do two color
* components at the same time.
*/
 
/*
* x_rb = (x_rb * a) / 255
*/
#define UN8_rb_MUL_UN8(x, a, t) \
do \
{ \
t = ((x) & RB_MASK) * (a); \
t += RB_ONE_HALF; \
x = (t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT; \
x &= RB_MASK; \
} while (0)
 
/*
* x_rb = min (x_rb + y_rb, 255)
*/
#ifndef UN8_rb_ADD_UN8_rb
#define UN8_rb_ADD_UN8_rb(x, y, t) \
do \
{ \
t = ((x) + (y)); \
t |= RB_MASK_PLUS_ONE - ((t >> G_SHIFT) & RB_MASK); \
x = (t & RB_MASK); \
} while (0)
#endif
 
/*
* x_rb = (x_rb * a_rb) / 255
*/
#define UN8_rb_MUL_UN8_rb(x, a, t) \
do \
{ \
t = (x & MASK) * (a & MASK); \
t |= (x & R_MASK) * ((a >> R_SHIFT) & MASK); \
t += RB_ONE_HALF; \
t = (t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT; \
x = t & RB_MASK; \
} while (0)
 
/*
* x_c = (x_c * a) / 255
*/
#define UN8x4_MUL_UN8(x, a) \
do \
{ \
uint32_t r1__, r2__, t__; \
\
r1__ = (x); \
UN8_rb_MUL_UN8 (r1__, (a), t__); \
\
r2__ = (x) >> G_SHIFT; \
UN8_rb_MUL_UN8 (r2__, (a), t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
 
/*
* x_c = (x_c * a) / 255 + y_c
*/
#define UN8x4_MUL_UN8_ADD_UN8x4(x, a, y) \
do \
{ \
uint32_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (y) & RB_MASK; \
UN8_rb_MUL_UN8 (r1__, (a), t__); \
UN8_rb_ADD_UN8_rb (r1__, r2__, t__); \
\
r2__ = (x) >> G_SHIFT; \
r3__ = ((y) >> G_SHIFT) & RB_MASK; \
UN8_rb_MUL_UN8 (r2__, (a), t__); \
UN8_rb_ADD_UN8_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
 
/*
* x_c = (x_c * a + y_c * b) / 255
*/
#define UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8(x, a, y, b) \
do \
{ \
uint32_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (y); \
UN8_rb_MUL_UN8 (r1__, (a), t__); \
UN8_rb_MUL_UN8 (r2__, (b), t__); \
UN8_rb_ADD_UN8_rb (r1__, r2__, t__); \
\
r2__ = ((x) >> G_SHIFT); \
r3__ = ((y) >> G_SHIFT); \
UN8_rb_MUL_UN8 (r2__, (a), t__); \
UN8_rb_MUL_UN8 (r3__, (b), t__); \
UN8_rb_ADD_UN8_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
 
/*
* x_c = (x_c * a_c) / 255
*/
#define UN8x4_MUL_UN8x4(x, a) \
do \
{ \
uint32_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (a); \
UN8_rb_MUL_UN8_rb (r1__, r2__, t__); \
\
r2__ = (x) >> G_SHIFT; \
r3__ = (a) >> G_SHIFT; \
UN8_rb_MUL_UN8_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
 
/*
* x_c = (x_c * a_c) / 255 + y_c
*/
#define UN8x4_MUL_UN8x4_ADD_UN8x4(x, a, y) \
do \
{ \
uint32_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (a); \
UN8_rb_MUL_UN8_rb (r1__, r2__, t__); \
r2__ = (y) & RB_MASK; \
UN8_rb_ADD_UN8_rb (r1__, r2__, t__); \
\
r2__ = ((x) >> G_SHIFT); \
r3__ = ((a) >> G_SHIFT); \
UN8_rb_MUL_UN8_rb (r2__, r3__, t__); \
r3__ = ((y) >> G_SHIFT) & RB_MASK; \
UN8_rb_ADD_UN8_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
 
/*
* x_c = (x_c * a_c + y_c * b) / 255
*/
#define UN8x4_MUL_UN8x4_ADD_UN8x4_MUL_UN8(x, a, y, b) \
do \
{ \
uint32_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (a); \
UN8_rb_MUL_UN8_rb (r1__, r2__, t__); \
r2__ = (y); \
UN8_rb_MUL_UN8 (r2__, (b), t__); \
UN8_rb_ADD_UN8_rb (r1__, r2__, t__); \
\
r2__ = (x) >> G_SHIFT; \
r3__ = (a) >> G_SHIFT; \
UN8_rb_MUL_UN8_rb (r2__, r3__, t__); \
r3__ = (y) >> G_SHIFT; \
UN8_rb_MUL_UN8 (r3__, (b), t__); \
UN8_rb_ADD_UN8_rb (r2__, r3__, t__); \
\
x = r1__ | (r2__ << G_SHIFT); \
} while (0)
 
/*
x_c = min(x_c + y_c, 255)
*/
#ifndef UN8x4_ADD_UN8x4
#define UN8x4_ADD_UN8x4(x, y) \
do \
{ \
uint32_t r1__, r2__, r3__, t__; \
\
r1__ = (x) & RB_MASK; \
r2__ = (y) & RB_MASK; \
UN8_rb_ADD_UN8_rb (r1__, r2__, t__); \
\
r2__ = ((x) >> G_SHIFT) & RB_MASK; \
r3__ = ((y) >> G_SHIFT) & RB_MASK; \
UN8_rb_ADD_UN8_rb (r2__, r3__, t__); \
\
x = r1__ | (r2__ << G_SHIFT); \
} while (0)
#endif
/contrib/sdk/sources/pixman/pixman-compiler.h
0,0 → 1,232
/* Pixman uses some non-standard compiler features. This file ensures
* they exist
*
* The features are:
*
* FUNC must be defined to expand to the current function
* PIXMAN_EXPORT should be defined to whatever is required to
* export functions from a shared library
* limits limits for various types must be defined
* inline must be defined
* force_inline must be defined
*/
#if defined (__GNUC__)
# define FUNC ((const char*) (__PRETTY_FUNCTION__))
#elif defined (__sun) || (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
# define FUNC ((const char*) (__func__))
#else
# define FUNC ((const char*) ("???"))
#endif
 
#if defined (__GNUC__)
# define unlikely(expr) __builtin_expect ((expr), 0)
#else
# define unlikely(expr) (expr)
#endif
 
#if defined (__GNUC__)
# define MAYBE_UNUSED __attribute__((unused))
#else
# define MAYBE_UNUSED
#endif
 
#ifndef INT16_MIN
# define INT16_MIN (-32767-1)
#endif
 
#ifndef INT16_MAX
# define INT16_MAX (32767)
#endif
 
#ifndef INT32_MIN
# define INT32_MIN (-2147483647-1)
#endif
 
#ifndef INT32_MAX
# define INT32_MAX (2147483647)
#endif
 
#ifndef UINT32_MIN
# define UINT32_MIN (0)
#endif
 
#ifndef UINT32_MAX
# define UINT32_MAX (4294967295U)
#endif
 
#ifndef INT64_MIN
# define INT64_MIN (-9223372036854775807-1)
#endif
 
#ifndef INT64_MAX
# define INT64_MAX (9223372036854775807)
#endif
 
#ifndef SIZE_MAX
# define SIZE_MAX ((size_t)-1)
#endif
 
 
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
 
#ifdef _MSC_VER
/* 'inline' is available only in C++ in MSVC */
# define inline __inline
# define force_inline __forceinline
# define noinline __declspec(noinline)
#elif defined __GNUC__ || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590))
# define inline __inline__
# define force_inline __inline__ __attribute__ ((__always_inline__))
# define noinline __attribute__((noinline))
#else
# ifndef force_inline
# define force_inline inline
# endif
# ifndef noinline
# define noinline
# endif
#endif
 
/* GCC visibility */
#if defined(__GNUC__) && __GNUC__ >= 4 && !defined(_WIN32)
# define PIXMAN_EXPORT __attribute__ ((visibility("default")))
/* Sun Studio 8 visibility */
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
# define PIXMAN_EXPORT __global
#else
# define PIXMAN_EXPORT
#endif
 
/* member offsets */
#define CONTAINER_OF(type, member, data) \
((type *)(((uint8_t *)data) - offsetof (type, member)))
 
/* TLS */
#if defined(PIXMAN_NO_TLS)
 
# define PIXMAN_DEFINE_THREAD_LOCAL(type, name) \
static type name
# define PIXMAN_GET_THREAD_LOCAL(name) \
(&name)
 
#elif defined(TLS)
 
# define PIXMAN_DEFINE_THREAD_LOCAL(type, name) \
static TLS type name
# define PIXMAN_GET_THREAD_LOCAL(name) \
(&name)
 
#elif defined(__MINGW32__)
 
# define _NO_W32_PSEUDO_MODIFIERS
# include <windows.h>
 
# define PIXMAN_DEFINE_THREAD_LOCAL(type, name) \
static volatile int tls_ ## name ## _initialized = 0; \
static void *tls_ ## name ## _mutex = NULL; \
static unsigned tls_ ## name ## _index; \
\
static type * \
tls_ ## name ## _alloc (void) \
{ \
type *value = calloc (1, sizeof (type)); \
if (value) \
TlsSetValue (tls_ ## name ## _index, value); \
return value; \
} \
\
static force_inline type * \
tls_ ## name ## _get (void) \
{ \
type *value; \
if (!tls_ ## name ## _initialized) \
{ \
if (!tls_ ## name ## _mutex) \
{ \
void *mutex = CreateMutexA (NULL, 0, NULL); \
if (InterlockedCompareExchangePointer ( \
&tls_ ## name ## _mutex, mutex, NULL) != NULL) \
{ \
CloseHandle (mutex); \
} \
} \
WaitForSingleObject (tls_ ## name ## _mutex, 0xFFFFFFFF); \
if (!tls_ ## name ## _initialized) \
{ \
tls_ ## name ## _index = TlsAlloc (); \
tls_ ## name ## _initialized = 1; \
} \
ReleaseMutex (tls_ ## name ## _mutex); \
} \
if (tls_ ## name ## _index == 0xFFFFFFFF) \
return NULL; \
value = TlsGetValue (tls_ ## name ## _index); \
if (!value) \
value = tls_ ## name ## _alloc (); \
return value; \
}
 
# define PIXMAN_GET_THREAD_LOCAL(name) \
tls_ ## name ## _get ()
 
#elif defined(_MSC_VER)
 
# define PIXMAN_DEFINE_THREAD_LOCAL(type, name) \
static __declspec(thread) type name
# define PIXMAN_GET_THREAD_LOCAL(name) \
(&name)
 
#elif defined(HAVE_PTHREAD_SETSPECIFIC)
 
#include <pthread.h>
 
# define PIXMAN_DEFINE_THREAD_LOCAL(type, name) \
static pthread_once_t tls_ ## name ## _once_control = PTHREAD_ONCE_INIT; \
static pthread_key_t tls_ ## name ## _key; \
\
static void \
tls_ ## name ## _destroy_value (void *value) \
{ \
free (value); \
} \
\
static void \
tls_ ## name ## _make_key (void) \
{ \
pthread_key_create (&tls_ ## name ## _key, \
tls_ ## name ## _destroy_value); \
} \
\
static type * \
tls_ ## name ## _alloc (void) \
{ \
type *value = calloc (1, sizeof (type)); \
if (value) \
pthread_setspecific (tls_ ## name ## _key, value); \
return value; \
} \
\
static force_inline type * \
tls_ ## name ## _get (void) \
{ \
type *value = NULL; \
if (pthread_once (&tls_ ## name ## _once_control, \
tls_ ## name ## _make_key) == 0) \
{ \
value = pthread_getspecific (tls_ ## name ## _key); \
if (!value) \
value = tls_ ## name ## _alloc (); \
} \
return value; \
}
 
# define PIXMAN_GET_THREAD_LOCAL(name) \
tls_ ## name ## _get ()
 
#else
 
# error "Unknown thread local support for this system. Pixman will not work with multiple threads. Define PIXMAN_NO_TLS to acknowledge and accept this limitation and compile pixman without thread-safety support."
 
#endif
/contrib/sdk/sources/pixman/pixman-conical-gradient.c
0,0 → 1,212
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007 Red Hat, Inc.
* Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
* 2005 Lars Knoll & Zack Rusin, Trolltech
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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_CONFIG_H
#include <config.h>
#endif
 
#include <stdlib.h>
#include <math.h>
#include "pixman-private.h"
 
static force_inline double
coordinates_to_parameter (double x, double y, double angle)
{
double t;
 
t = atan2 (y, x) + angle;
 
while (t < 0)
t += 2 * M_PI;
 
while (t >= 2 * M_PI)
t -= 2 * M_PI;
 
return 1 - t * (1 / (2 * M_PI)); /* Scale t to [0, 1] and
* make rotation CCW
*/
}
 
static uint32_t *
conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
{
pixman_image_t *image = iter->image;
int x = iter->x;
int y = iter->y;
int width = iter->width;
uint32_t *buffer = iter->buffer;
 
gradient_t *gradient = (gradient_t *)image;
conical_gradient_t *conical = (conical_gradient_t *)image;
uint32_t *end = buffer + width;
pixman_gradient_walker_t walker;
pixman_bool_t affine = TRUE;
double cx = 1.;
double cy = 0.;
double cz = 0.;
double rx = x + 0.5;
double ry = y + 0.5;
double rz = 1.;
 
_pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
 
if (image->common.transform)
{
pixman_vector_t v;
 
/* reference point is the center of the pixel */
v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
 
if (!pixman_transform_point_3d (image->common.transform, &v))
return iter->buffer;
 
cx = image->common.transform->matrix[0][0] / 65536.;
cy = image->common.transform->matrix[1][0] / 65536.;
cz = image->common.transform->matrix[2][0] / 65536.;
 
rx = v.vector[0] / 65536.;
ry = v.vector[1] / 65536.;
rz = v.vector[2] / 65536.;
 
affine =
image->common.transform->matrix[2][0] == 0 &&
v.vector[2] == pixman_fixed_1;
}
 
if (affine)
{
rx -= conical->center.x / 65536.;
ry -= conical->center.y / 65536.;
 
while (buffer < end)
{
if (!mask || *mask++)
{
double t = coordinates_to_parameter (rx, ry, conical->angle);
 
*buffer = _pixman_gradient_walker_pixel (
&walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t));
}
 
++buffer;
 
rx += cx;
ry += cy;
}
}
else
{
while (buffer < end)
{
double x, y;
 
if (!mask || *mask++)
{
double t;
 
if (rz != 0)
{
x = rx / rz;
y = ry / rz;
}
else
{
x = y = 0.;
}
 
x -= conical->center.x / 65536.;
y -= conical->center.y / 65536.;
 
t = coordinates_to_parameter (x, y, conical->angle);
 
*buffer = _pixman_gradient_walker_pixel (
&walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t));
}
 
++buffer;
 
rx += cx;
ry += cy;
rz += cz;
}
}
 
iter->y++;
return iter->buffer;
}
 
static uint32_t *
conical_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
{
uint32_t *buffer = conical_get_scanline_narrow (iter, NULL);
 
pixman_expand_to_float (
(argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
 
return buffer;
}
 
void
_pixman_conical_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter)
{
if (iter->iter_flags & ITER_NARROW)
iter->get_scanline = conical_get_scanline_narrow;
else
iter->get_scanline = conical_get_scanline_wide;
}
 
PIXMAN_EXPORT pixman_image_t *
pixman_image_create_conical_gradient (const pixman_point_fixed_t * center,
pixman_fixed_t angle,
const pixman_gradient_stop_t *stops,
int n_stops)
{
pixman_image_t *image = _pixman_image_allocate ();
conical_gradient_t *conical;
 
if (!image)
return NULL;
 
conical = &image->conical;
 
if (!_pixman_init_gradient (&conical->common, stops, n_stops))
{
free (image);
return NULL;
}
 
angle = MOD (angle, pixman_int_to_fixed (360));
 
image->type = CONICAL;
 
conical->center = *center;
conical->angle = (pixman_fixed_to_double (angle) / 180.0) * M_PI;
 
return image;
}
 
/contrib/sdk/sources/pixman/pixman-edge-accessors.c
0,0 → 1,4
 
#define PIXMAN_FB_ACCESSORS
 
#include "pixman-edge.c"
/contrib/sdk/sources/pixman/pixman-edge-imp.h
0,0 → 1,182
/*
* Copyright © 2004 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
 
#ifndef rasterize_span
#endif
 
static void
RASTERIZE_EDGES (pixman_image_t *image,
pixman_edge_t *l,
pixman_edge_t *r,
pixman_fixed_t t,
pixman_fixed_t b)
{
pixman_fixed_t y = t;
uint32_t *line;
uint32_t *buf = (image)->bits.bits;
int stride = (image)->bits.rowstride;
int width = (image)->bits.width;
 
line = buf + pixman_fixed_to_int (y) * stride;
 
for (;;)
{
pixman_fixed_t lx;
pixman_fixed_t rx;
int lxi;
int rxi;
 
lx = l->x;
rx = r->x;
#if N_BITS == 1
/* For the non-antialiased case, round the coordinates up, in effect
* sampling just slightly to the left of the pixel. This is so that
* when the sample point lies exactly on the line, we round towards
* north-west.
*
* (The AA case does a similar adjustment in RENDER_SAMPLES_X)
*/
lx += X_FRAC_FIRST(1) - pixman_fixed_e;
rx += X_FRAC_FIRST(1) - pixman_fixed_e;
#endif
/* clip X */
if (lx < 0)
lx = 0;
if (pixman_fixed_to_int (rx) >= width)
#if N_BITS == 1
rx = pixman_int_to_fixed (width);
#else
/* Use the last pixel of the scanline, covered 100%.
* We can't use the first pixel following the scanline,
* because accessing it could result in a buffer overrun.
*/
rx = pixman_int_to_fixed (width) - 1;
#endif
 
/* Skip empty (or backwards) sections */
if (rx > lx)
{
 
/* Find pixel bounds for span */
lxi = pixman_fixed_to_int (lx);
rxi = pixman_fixed_to_int (rx);
 
#if N_BITS == 1
{
 
#define LEFT_MASK(x) \
(((x) & 0x1f) ? \
SCREEN_SHIFT_RIGHT (0xffffffff, (x) & 0x1f) : 0)
#define RIGHT_MASK(x) \
(((32 - (x)) & 0x1f) ? \
SCREEN_SHIFT_LEFT (0xffffffff, (32 - (x)) & 0x1f) : 0)
#define MASK_BITS(x,w,l,n,r) { \
n = (w); \
r = RIGHT_MASK ((x) + n); \
l = LEFT_MASK (x); \
if (l) { \
n -= 32 - ((x) & 0x1f); \
if (n < 0) { \
n = 0; \
l &= r; \
r = 0; \
} \
} \
n >>= 5; \
}
uint32_t *a = line;
uint32_t startmask;
uint32_t endmask;
int nmiddle;
int width = rxi - lxi;
int x = lxi;
a += x >> 5;
x &= 0x1f;
MASK_BITS (x, width, startmask, nmiddle, endmask);
 
if (startmask) {
WRITE(image, a, READ(image, a) | startmask);
a++;
}
while (nmiddle--)
WRITE(image, a++, 0xffffffff);
if (endmask)
WRITE(image, a, READ(image, a) | endmask);
}
#else
{
DEFINE_ALPHA(line,lxi);
int lxs;
int rxs;
 
/* Sample coverage for edge pixels */
lxs = RENDER_SAMPLES_X (lx, N_BITS);
rxs = RENDER_SAMPLES_X (rx, N_BITS);
 
/* Add coverage across row */
if (lxi == rxi)
{
ADD_ALPHA (rxs - lxs);
}
else
{
int xi;
 
ADD_ALPHA (N_X_FRAC(N_BITS) - lxs);
STEP_ALPHA;
for (xi = lxi + 1; xi < rxi; xi++)
{
ADD_ALPHA (N_X_FRAC(N_BITS));
STEP_ALPHA;
}
ADD_ALPHA (rxs);
}
}
#endif
}
 
if (y == b)
break;
 
#if N_BITS > 1
if (pixman_fixed_frac (y) != Y_FRAC_LAST(N_BITS))
{
RENDER_EDGE_STEP_SMALL (l);
RENDER_EDGE_STEP_SMALL (r);
y += STEP_Y_SMALL(N_BITS);
}
else
#endif
{
RENDER_EDGE_STEP_BIG (l);
RENDER_EDGE_STEP_BIG (r);
y += STEP_Y_BIG(N_BITS);
line += stride;
}
}
}
 
#undef rasterize_span
/contrib/sdk/sources/pixman/pixman-edge.c
0,0 → 1,385
/*
* Copyright © 2004 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
 
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
 
#include <string.h>
 
#include "pixman-private.h"
#include "pixman-accessor.h"
 
/*
* Step across a small sample grid gap
*/
#define RENDER_EDGE_STEP_SMALL(edge) \
{ \
edge->x += edge->stepx_small; \
edge->e += edge->dx_small; \
if (edge->e > 0) \
{ \
edge->e -= edge->dy; \
edge->x += edge->signdx; \
} \
}
 
/*
* Step across a large sample grid gap
*/
#define RENDER_EDGE_STEP_BIG(edge) \
{ \
edge->x += edge->stepx_big; \
edge->e += edge->dx_big; \
if (edge->e > 0) \
{ \
edge->e -= edge->dy; \
edge->x += edge->signdx; \
} \
}
 
#ifdef PIXMAN_FB_ACCESSORS
#define PIXMAN_RASTERIZE_EDGES pixman_rasterize_edges_accessors
#else
#define PIXMAN_RASTERIZE_EDGES pixman_rasterize_edges_no_accessors
#endif
 
/*
* 4 bit alpha
*/
 
#define N_BITS 4
#define RASTERIZE_EDGES rasterize_edges_4
 
#ifndef WORDS_BIGENDIAN
#define SHIFT_4(o) ((o) << 2)
#else
#define SHIFT_4(o) ((1 - (o)) << 2)
#endif
 
#define GET_4(x, o) (((x) >> SHIFT_4 (o)) & 0xf)
#define PUT_4(x, o, v) \
(((x) & ~(0xf << SHIFT_4 (o))) | (((v) & 0xf) << SHIFT_4 (o)))
 
#define DEFINE_ALPHA(line, x) \
uint8_t *__ap = (uint8_t *) line + ((x) >> 1); \
int __ao = (x) & 1
 
#define STEP_ALPHA ((__ap += __ao), (__ao ^= 1))
 
#define ADD_ALPHA(a) \
{ \
uint8_t __o = READ (image, __ap); \
uint8_t __a = (a) + GET_4 (__o, __ao); \
WRITE (image, __ap, PUT_4 (__o, __ao, __a | (0 - ((__a) >> 4)))); \
}
 
#include "pixman-edge-imp.h"
 
#undef ADD_ALPHA
#undef STEP_ALPHA
#undef DEFINE_ALPHA
#undef RASTERIZE_EDGES
#undef N_BITS
 
 
/*
* 1 bit alpha
*/
 
#define N_BITS 1
#define RASTERIZE_EDGES rasterize_edges_1
 
#include "pixman-edge-imp.h"
 
#undef RASTERIZE_EDGES
#undef N_BITS
 
/*
* 8 bit alpha
*/
 
static force_inline uint8_t
clip255 (int x)
{
if (x > 255)
return 255;
 
return x;
}
 
#define ADD_SATURATE_8(buf, val, length) \
do \
{ \
int i__ = (length); \
uint8_t *buf__ = (buf); \
int val__ = (val); \
\
while (i__--) \
{ \
WRITE (image, (buf__), clip255 (READ (image, (buf__)) + (val__))); \
(buf__)++; \
} \
} while (0)
 
/*
* We want to detect the case where we add the same value to a long
* span of pixels. The triangles on the end are filled in while we
* count how many sub-pixel scanlines contribute to the middle section.
*
* +--------------------------+
* fill_height =| \ /
* +------------------+
* |================|
* fill_start fill_end
*/
static void
rasterize_edges_8 (pixman_image_t *image,
pixman_edge_t * l,
pixman_edge_t * r,
pixman_fixed_t t,
pixman_fixed_t b)
{
pixman_fixed_t y = t;
uint32_t *line;
int fill_start = -1, fill_end = -1;
int fill_size = 0;
uint32_t *buf = (image)->bits.bits;
int stride = (image)->bits.rowstride;
int width = (image)->bits.width;
 
line = buf + pixman_fixed_to_int (y) * stride;
 
for (;;)
{
uint8_t *ap = (uint8_t *) line;
pixman_fixed_t lx, rx;
int lxi, rxi;
 
/* clip X */
lx = l->x;
if (lx < 0)
lx = 0;
 
rx = r->x;
 
if (pixman_fixed_to_int (rx) >= width)
{
/* Use the last pixel of the scanline, covered 100%.
* We can't use the first pixel following the scanline,
* because accessing it could result in a buffer overrun.
*/
rx = pixman_int_to_fixed (width) - 1;
}
 
/* Skip empty (or backwards) sections */
if (rx > lx)
{
int lxs, rxs;
 
/* Find pixel bounds for span. */
lxi = pixman_fixed_to_int (lx);
rxi = pixman_fixed_to_int (rx);
 
/* Sample coverage for edge pixels */
lxs = RENDER_SAMPLES_X (lx, 8);
rxs = RENDER_SAMPLES_X (rx, 8);
 
/* Add coverage across row */
if (lxi == rxi)
{
WRITE (image, ap + lxi,
clip255 (READ (image, ap + lxi) + rxs - lxs));
}
else
{
WRITE (image, ap + lxi,
clip255 (READ (image, ap + lxi) + N_X_FRAC (8) - lxs));
 
/* Move forward so that lxi/rxi is the pixel span */
lxi++;
 
/* Don't bother trying to optimize the fill unless
* the span is longer than 4 pixels. */
if (rxi - lxi > 4)
{
if (fill_start < 0)
{
fill_start = lxi;
fill_end = rxi;
fill_size++;
}
else
{
if (lxi >= fill_end || rxi < fill_start)
{
/* We're beyond what we saved, just fill it */
ADD_SATURATE_8 (ap + fill_start,
fill_size * N_X_FRAC (8),
fill_end - fill_start);
fill_start = lxi;
fill_end = rxi;
fill_size = 1;
}
else
{
/* Update fill_start */
if (lxi > fill_start)
{
ADD_SATURATE_8 (ap + fill_start,
fill_size * N_X_FRAC (8),
lxi - fill_start);
fill_start = lxi;
}
else if (lxi < fill_start)
{
ADD_SATURATE_8 (ap + lxi, N_X_FRAC (8),
fill_start - lxi);
}
 
/* Update fill_end */
if (rxi < fill_end)
{
ADD_SATURATE_8 (ap + rxi,
fill_size * N_X_FRAC (8),
fill_end - rxi);
fill_end = rxi;
}
else if (fill_end < rxi)
{
ADD_SATURATE_8 (ap + fill_end,
N_X_FRAC (8),
rxi - fill_end);
}
fill_size++;
}
}
}
else
{
ADD_SATURATE_8 (ap + lxi, N_X_FRAC (8), rxi - lxi);
}
 
WRITE (image, ap + rxi, clip255 (READ (image, ap + rxi) + rxs));
}
}
 
if (y == b)
{
/* We're done, make sure we clean up any remaining fill. */
if (fill_start != fill_end)
{
if (fill_size == N_Y_FRAC (8))
{
MEMSET_WRAPPED (image, ap + fill_start,
0xff, fill_end - fill_start);
}
else
{
ADD_SATURATE_8 (ap + fill_start, fill_size * N_X_FRAC (8),
fill_end - fill_start);
}
}
break;
}
 
if (pixman_fixed_frac (y) != Y_FRAC_LAST (8))
{
RENDER_EDGE_STEP_SMALL (l);
RENDER_EDGE_STEP_SMALL (r);
y += STEP_Y_SMALL (8);
}
else
{
RENDER_EDGE_STEP_BIG (l);
RENDER_EDGE_STEP_BIG (r);
y += STEP_Y_BIG (8);
if (fill_start != fill_end)
{
if (fill_size == N_Y_FRAC (8))
{
MEMSET_WRAPPED (image, ap + fill_start,
0xff, fill_end - fill_start);
}
else
{
ADD_SATURATE_8 (ap + fill_start, fill_size * N_X_FRAC (8),
fill_end - fill_start);
}
fill_start = fill_end = -1;
fill_size = 0;
}
line += stride;
}
}
}
 
#ifndef PIXMAN_FB_ACCESSORS
static
#endif
void
PIXMAN_RASTERIZE_EDGES (pixman_image_t *image,
pixman_edge_t * l,
pixman_edge_t * r,
pixman_fixed_t t,
pixman_fixed_t b)
{
switch (PIXMAN_FORMAT_BPP (image->bits.format))
{
case 1:
rasterize_edges_1 (image, l, r, t, b);
break;
 
case 4:
rasterize_edges_4 (image, l, r, t, b);
break;
 
case 8:
rasterize_edges_8 (image, l, r, t, b);
break;
 
default:
break;
}
}
 
#ifndef PIXMAN_FB_ACCESSORS
 
PIXMAN_EXPORT void
pixman_rasterize_edges (pixman_image_t *image,
pixman_edge_t * l,
pixman_edge_t * r,
pixman_fixed_t t,
pixman_fixed_t b)
{
return_if_fail (image->type == BITS);
return_if_fail (PIXMAN_FORMAT_TYPE (image->bits.format) == PIXMAN_TYPE_A);
if (image->bits.read_func || image->bits.write_func)
pixman_rasterize_edges_accessors (image, l, r, t, b);
else
pixman_rasterize_edges_no_accessors (image, l, r, t, b);
}
 
#endif
/contrib/sdk/sources/pixman/pixman-fast-path.c
0,0 → 1,2358
/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Keith Packard, SuSE, Inc.
*/
 
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <stdlib.h>
#include "pixman-private.h"
#include "pixman-combine32.h"
#include "pixman-inlines.h"
 
static force_inline uint32_t
fetch_24 (uint8_t *a)
{
if (((uintptr_t)a) & 1)
{
#ifdef WORDS_BIGENDIAN
return (*a << 16) | (*(uint16_t *)(a + 1));
#else
return *a | (*(uint16_t *)(a + 1) << 8);
#endif
}
else
{
#ifdef WORDS_BIGENDIAN
return (*(uint16_t *)a << 8) | *(a + 2);
#else
return *(uint16_t *)a | (*(a + 2) << 16);
#endif
}
}
 
static force_inline void
store_24 (uint8_t *a,
uint32_t v)
{
if (((uintptr_t)a) & 1)
{
#ifdef WORDS_BIGENDIAN
*a = (uint8_t) (v >> 16);
*(uint16_t *)(a + 1) = (uint16_t) (v);
#else
*a = (uint8_t) (v);
*(uint16_t *)(a + 1) = (uint16_t) (v >> 8);
#endif
}
else
{
#ifdef WORDS_BIGENDIAN
*(uint16_t *)a = (uint16_t)(v >> 8);
*(a + 2) = (uint8_t)v;
#else
*(uint16_t *)a = (uint16_t)v;
*(a + 2) = (uint8_t)(v >> 16);
#endif
}
}
 
static force_inline uint32_t
over (uint32_t src,
uint32_t dest)
{
uint32_t a = ~src >> 24;
 
UN8x4_MUL_UN8_ADD_UN8x4 (dest, a, src);
 
return dest;
}
 
static force_inline uint32_t
in (uint32_t x,
uint8_t y)
{
uint16_t a = y;
 
UN8x4_MUL_UN8 (x, a);
 
return x;
}
 
/*
* Naming convention:
*
* op_src_mask_dest
*/
static void
fast_composite_over_x888_8_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *src, *src_line;
uint32_t *dst, *dst_line;
uint8_t *mask, *mask_line;
int src_stride, mask_stride, dst_stride;
uint8_t m;
uint32_t s, d;
int32_t w;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
while (height--)
{
src = src_line;
src_line += src_stride;
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
 
w = width;
while (w--)
{
m = *mask++;
if (m)
{
s = *src | 0xff000000;
 
if (m == 0xff)
{
*dst = s;
}
else
{
d = in (s, m);
*dst = over (d, *dst);
}
}
src++;
dst++;
}
}
}
 
static void
fast_composite_in_n_8_8 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src, srca;
uint8_t *dst_line, *dst;
uint8_t *mask_line, *mask, m;
int dst_stride, mask_stride;
int32_t w;
uint16_t t;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
srca = src >> 24;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
 
if (srca == 0xff)
{
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w--)
{
m = *mask++;
 
if (m == 0)
*dst = 0;
else if (m != 0xff)
*dst = MUL_UN8 (m, *dst, t);
 
dst++;
}
}
}
else
{
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w--)
{
m = *mask++;
m = MUL_UN8 (m, srca, t);
 
if (m == 0)
*dst = 0;
else if (m != 0xff)
*dst = MUL_UN8 (m, *dst, t);
 
dst++;
}
}
}
}
 
static void
fast_composite_in_8_8 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint8_t *dst_line, *dst;
uint8_t *src_line, *src;
int dst_stride, src_stride;
int32_t w;
uint8_t s;
uint16_t t;
 
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint8_t, src_stride, src_line, 1);
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w--)
{
s = *src++;
 
if (s == 0)
*dst = 0;
else if (s != 0xff)
*dst = MUL_UN8 (s, *dst, t);
 
dst++;
}
}
}
 
static void
fast_composite_over_n_8_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src, srca;
uint32_t *dst_line, *dst, d;
uint8_t *mask_line, *mask, m;
int dst_stride, mask_stride;
int32_t w;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
srca = src >> 24;
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w--)
{
m = *mask++;
if (m == 0xff)
{
if (srca == 0xff)
*dst = src;
else
*dst = over (src, *dst);
}
else if (m)
{
d = in (src, m);
*dst = over (d, *dst);
}
dst++;
}
}
}
 
static void
fast_composite_add_n_8888_8888_ca (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src, s;
uint32_t *dst_line, *dst, d;
uint32_t *mask_line, *mask, ma;
int dst_stride, mask_stride;
int32_t w;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint32_t, mask_stride, mask_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w--)
{
ma = *mask++;
 
if (ma)
{
d = *dst;
s = src;
 
UN8x4_MUL_UN8x4_ADD_UN8x4 (s, ma, d);
 
*dst = s;
}
 
dst++;
}
}
}
 
static void
fast_composite_over_n_8888_8888_ca (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src, srca, s;
uint32_t *dst_line, *dst, d;
uint32_t *mask_line, *mask, ma;
int dst_stride, mask_stride;
int32_t w;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
srca = src >> 24;
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint32_t, mask_stride, mask_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w--)
{
ma = *mask++;
if (ma == 0xffffffff)
{
if (srca == 0xff)
*dst = src;
else
*dst = over (src, *dst);
}
else if (ma)
{
d = *dst;
s = src;
 
UN8x4_MUL_UN8x4 (s, ma);
UN8x4_MUL_UN8 (ma, srca);
ma = ~ma;
UN8x4_MUL_UN8x4_ADD_UN8x4 (d, ma, s);
 
*dst = d;
}
 
dst++;
}
}
}
 
static void
fast_composite_over_n_8_0888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src, srca;
uint8_t *dst_line, *dst;
uint32_t d;
uint8_t *mask_line, *mask, m;
int dst_stride, mask_stride;
int32_t w;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
srca = src >> 24;
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 3);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w--)
{
m = *mask++;
if (m == 0xff)
{
if (srca == 0xff)
{
d = src;
}
else
{
d = fetch_24 (dst);
d = over (src, d);
}
store_24 (dst, d);
}
else if (m)
{
d = over (in (src, m), fetch_24 (dst));
store_24 (dst, d);
}
dst += 3;
}
}
}
 
static void
fast_composite_over_n_8_0565 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src, srca;
uint16_t *dst_line, *dst;
uint32_t d;
uint8_t *mask_line, *mask, m;
int dst_stride, mask_stride;
int32_t w;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
srca = src >> 24;
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w--)
{
m = *mask++;
if (m == 0xff)
{
if (srca == 0xff)
{
d = src;
}
else
{
d = *dst;
d = over (src, convert_0565_to_0888 (d));
}
*dst = convert_8888_to_0565 (d);
}
else if (m)
{
d = *dst;
d = over (in (src, m), convert_0565_to_0888 (d));
*dst = convert_8888_to_0565 (d);
}
dst++;
}
}
}
 
static void
fast_composite_over_n_8888_0565_ca (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src, srca, s;
uint16_t src16;
uint16_t *dst_line, *dst;
uint32_t d;
uint32_t *mask_line, *mask, ma;
int dst_stride, mask_stride;
int32_t w;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
srca = src >> 24;
if (src == 0)
return;
 
src16 = convert_8888_to_0565 (src);
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint32_t, mask_stride, mask_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w--)
{
ma = *mask++;
if (ma == 0xffffffff)
{
if (srca == 0xff)
{
*dst = src16;
}
else
{
d = *dst;
d = over (src, convert_0565_to_0888 (d));
*dst = convert_8888_to_0565 (d);
}
}
else if (ma)
{
d = *dst;
d = convert_0565_to_0888 (d);
 
s = src;
 
UN8x4_MUL_UN8x4 (s, ma);
UN8x4_MUL_UN8 (ma, srca);
ma = ~ma;
UN8x4_MUL_UN8x4_ADD_UN8x4 (d, ma, s);
 
*dst = convert_8888_to_0565 (d);
}
dst++;
}
}
}
 
static void
fast_composite_over_8888_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line, *dst;
uint32_t *src_line, *src, s;
int dst_stride, src_stride;
uint8_t a;
int32_t w;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w--)
{
s = *src++;
a = s >> 24;
if (a == 0xff)
*dst = s;
else if (s)
*dst = over (s, *dst);
dst++;
}
}
}
 
static void
fast_composite_src_x888_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line, *dst;
uint32_t *src_line, *src;
int dst_stride, src_stride;
int32_t w;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w--)
*dst++ = (*src++) | 0xff000000;
}
}
 
#if 0
static void
fast_composite_over_8888_0888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint8_t *dst_line, *dst;
uint32_t d;
uint32_t *src_line, *src, s;
uint8_t a;
int dst_stride, src_stride;
int32_t w;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 3);
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w--)
{
s = *src++;
a = s >> 24;
if (a)
{
if (a == 0xff)
d = s;
else
d = over (s, fetch_24 (dst));
 
store_24 (dst, d);
}
dst += 3;
}
}
}
#endif
 
static void
fast_composite_over_8888_0565 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint16_t *dst_line, *dst;
uint32_t d;
uint32_t *src_line, *src, s;
uint8_t a;
int dst_stride, src_stride;
int32_t w;
 
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w--)
{
s = *src++;
a = s >> 24;
if (s)
{
if (a == 0xff)
{
d = s;
}
else
{
d = *dst;
d = over (s, convert_0565_to_0888 (d));
}
*dst = convert_8888_to_0565 (d);
}
dst++;
}
}
}
 
static void
fast_composite_add_8_8 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint8_t *dst_line, *dst;
uint8_t *src_line, *src;
int dst_stride, src_stride;
int32_t w;
uint8_t s, d;
uint16_t t;
 
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint8_t, src_stride, src_line, 1);
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w--)
{
s = *src++;
if (s)
{
if (s != 0xff)
{
d = *dst;
t = d + s;
s = t | (0 - (t >> 8));
}
*dst = s;
}
dst++;
}
}
}
 
static void
fast_composite_add_0565_0565 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint16_t *dst_line, *dst;
uint32_t d;
uint16_t *src_line, *src;
uint32_t s;
int dst_stride, src_stride;
int32_t w;
 
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint16_t, src_stride, src_line, 1);
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w--)
{
s = *src++;
if (s)
{
d = *dst;
s = convert_0565_to_8888 (s);
if (d)
{
d = convert_0565_to_8888 (d);
UN8x4_ADD_UN8x4 (s, d);
}
*dst = convert_8888_to_0565 (s);
}
dst++;
}
}
}
 
static void
fast_composite_add_8888_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line, *dst;
uint32_t *src_line, *src;
int dst_stride, src_stride;
int32_t w;
uint32_t s, d;
 
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w--)
{
s = *src++;
if (s)
{
if (s != 0xffffffff)
{
d = *dst;
if (d)
UN8x4_ADD_UN8x4 (s, d);
}
*dst = s;
}
dst++;
}
}
}
 
static void
fast_composite_add_n_8_8 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint8_t *dst_line, *dst;
uint8_t *mask_line, *mask;
int dst_stride, mask_stride;
int32_t w;
uint32_t src;
uint8_t sa;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
sa = (src >> 24);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w--)
{
uint16_t tmp;
uint16_t a;
uint32_t m, d;
uint32_t r;
 
a = *mask++;
d = *dst;
 
m = MUL_UN8 (sa, a, tmp);
r = ADD_UN8 (m, d, tmp);
 
*dst++ = r;
}
}
}
 
#ifdef WORDS_BIGENDIAN
#define CREATE_BITMASK(n) (0x80000000 >> (n))
#define UPDATE_BITMASK(n) ((n) >> 1)
#else
#define CREATE_BITMASK(n) (1 << (n))
#define UPDATE_BITMASK(n) ((n) << 1)
#endif
 
#define TEST_BIT(p, n) \
(*((p) + ((n) >> 5)) & CREATE_BITMASK ((n) & 31))
#define SET_BIT(p, n) \
do { *((p) + ((n) >> 5)) |= CREATE_BITMASK ((n) & 31); } while (0);
 
static void
fast_composite_add_1_1 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line, *dst;
uint32_t *src_line, *src;
int dst_stride, src_stride;
int32_t w;
 
PIXMAN_IMAGE_GET_LINE (src_image, 0, src_y, uint32_t,
src_stride, src_line, 1);
PIXMAN_IMAGE_GET_LINE (dest_image, 0, dest_y, uint32_t,
dst_stride, dst_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w--)
{
/*
* TODO: improve performance by processing uint32_t data instead
* of individual bits
*/
if (TEST_BIT (src, src_x + w))
SET_BIT (dst, dest_x + w);
}
}
}
 
static void
fast_composite_over_n_1_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src, srca;
uint32_t *dst, *dst_line;
uint32_t *mask, *mask_line;
int mask_stride, dst_stride;
uint32_t bitcache, bitmask;
int32_t w;
 
if (width <= 0)
return;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
srca = src >> 24;
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t,
dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, 0, mask_y, uint32_t,
mask_stride, mask_line, 1);
mask_line += mask_x >> 5;
 
if (srca == 0xff)
{
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
bitcache = *mask++;
bitmask = CREATE_BITMASK (mask_x & 31);
 
while (w--)
{
if (bitmask == 0)
{
bitcache = *mask++;
bitmask = CREATE_BITMASK (0);
}
if (bitcache & bitmask)
*dst = src;
bitmask = UPDATE_BITMASK (bitmask);
dst++;
}
}
}
else
{
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
bitcache = *mask++;
bitmask = CREATE_BITMASK (mask_x & 31);
 
while (w--)
{
if (bitmask == 0)
{
bitcache = *mask++;
bitmask = CREATE_BITMASK (0);
}
if (bitcache & bitmask)
*dst = over (src, *dst);
bitmask = UPDATE_BITMASK (bitmask);
dst++;
}
}
}
}
 
static void
fast_composite_over_n_1_0565 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src, srca;
uint16_t *dst, *dst_line;
uint32_t *mask, *mask_line;
int mask_stride, dst_stride;
uint32_t bitcache, bitmask;
int32_t w;
uint32_t d;
uint16_t src565;
 
if (width <= 0)
return;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
srca = src >> 24;
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint16_t,
dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, 0, mask_y, uint32_t,
mask_stride, mask_line, 1);
mask_line += mask_x >> 5;
 
if (srca == 0xff)
{
src565 = convert_8888_to_0565 (src);
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
bitcache = *mask++;
bitmask = CREATE_BITMASK (mask_x & 31);
 
while (w--)
{
if (bitmask == 0)
{
bitcache = *mask++;
bitmask = CREATE_BITMASK (0);
}
if (bitcache & bitmask)
*dst = src565;
bitmask = UPDATE_BITMASK (bitmask);
dst++;
}
}
}
else
{
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
bitcache = *mask++;
bitmask = CREATE_BITMASK (mask_x & 31);
 
while (w--)
{
if (bitmask == 0)
{
bitcache = *mask++;
bitmask = CREATE_BITMASK (0);
}
if (bitcache & bitmask)
{
d = over (src, convert_0565_to_0888 (*dst));
*dst = convert_8888_to_0565 (d);
}
bitmask = UPDATE_BITMASK (bitmask);
dst++;
}
}
}
}
 
/*
* Simple bitblt
*/
 
static void
fast_composite_solid_fill (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
if (dest_image->bits.format == PIXMAN_a1)
{
src = src >> 31;
}
else if (dest_image->bits.format == PIXMAN_a8)
{
src = src >> 24;
}
else if (dest_image->bits.format == PIXMAN_r5g6b5 ||
dest_image->bits.format == PIXMAN_b5g6r5)
{
src = convert_8888_to_0565 (src);
}
 
pixman_fill (dest_image->bits.bits, dest_image->bits.rowstride,
PIXMAN_FORMAT_BPP (dest_image->bits.format),
dest_x, dest_y,
width, height,
src);
}
 
static void
fast_composite_src_memcpy (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
int bpp = PIXMAN_FORMAT_BPP (dest_image->bits.format) / 8;
uint32_t n_bytes = width * bpp;
int dst_stride, src_stride;
uint8_t *dst;
uint8_t *src;
 
src_stride = src_image->bits.rowstride * 4;
dst_stride = dest_image->bits.rowstride * 4;
 
src = (uint8_t *)src_image->bits.bits + src_y * src_stride + src_x * bpp;
dst = (uint8_t *)dest_image->bits.bits + dest_y * dst_stride + dest_x * bpp;
 
while (height--)
{
memcpy (dst, src, n_bytes);
 
dst += dst_stride;
src += src_stride;
}
}
 
FAST_NEAREST (8888_8888_cover, 8888, 8888, uint32_t, uint32_t, SRC, COVER)
FAST_NEAREST (8888_8888_none, 8888, 8888, uint32_t, uint32_t, SRC, NONE)
FAST_NEAREST (8888_8888_pad, 8888, 8888, uint32_t, uint32_t, SRC, PAD)
FAST_NEAREST (8888_8888_normal, 8888, 8888, uint32_t, uint32_t, SRC, NORMAL)
FAST_NEAREST (x888_8888_cover, x888, 8888, uint32_t, uint32_t, SRC, COVER)
FAST_NEAREST (x888_8888_pad, x888, 8888, uint32_t, uint32_t, SRC, PAD)
FAST_NEAREST (x888_8888_normal, x888, 8888, uint32_t, uint32_t, SRC, NORMAL)
FAST_NEAREST (8888_8888_cover, 8888, 8888, uint32_t, uint32_t, OVER, COVER)
FAST_NEAREST (8888_8888_none, 8888, 8888, uint32_t, uint32_t, OVER, NONE)
FAST_NEAREST (8888_8888_pad, 8888, 8888, uint32_t, uint32_t, OVER, PAD)
FAST_NEAREST (8888_8888_normal, 8888, 8888, uint32_t, uint32_t, OVER, NORMAL)
FAST_NEAREST (8888_565_cover, 8888, 0565, uint32_t, uint16_t, SRC, COVER)
FAST_NEAREST (8888_565_none, 8888, 0565, uint32_t, uint16_t, SRC, NONE)
FAST_NEAREST (8888_565_pad, 8888, 0565, uint32_t, uint16_t, SRC, PAD)
FAST_NEAREST (8888_565_normal, 8888, 0565, uint32_t, uint16_t, SRC, NORMAL)
FAST_NEAREST (565_565_normal, 0565, 0565, uint16_t, uint16_t, SRC, NORMAL)
FAST_NEAREST (8888_565_cover, 8888, 0565, uint32_t, uint16_t, OVER, COVER)
FAST_NEAREST (8888_565_none, 8888, 0565, uint32_t, uint16_t, OVER, NONE)
FAST_NEAREST (8888_565_pad, 8888, 0565, uint32_t, uint16_t, OVER, PAD)
FAST_NEAREST (8888_565_normal, 8888, 0565, uint32_t, uint16_t, OVER, NORMAL)
 
#define REPEAT_MIN_WIDTH 32
 
static void
fast_composite_tiled_repeat (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
pixman_composite_func_t func;
pixman_format_code_t mask_format;
uint32_t src_flags, mask_flags;
int32_t sx, sy;
int32_t width_remain;
int32_t num_pixels;
int32_t src_width;
int32_t i, j;
pixman_image_t extended_src_image;
uint32_t extended_src[REPEAT_MIN_WIDTH * 2];
pixman_bool_t need_src_extension;
uint32_t *src_line;
int32_t src_stride;
int32_t src_bpp;
pixman_composite_info_t info2 = *info;
 
src_flags = (info->src_flags & ~FAST_PATH_NORMAL_REPEAT) |
FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
 
if (mask_image)
{
mask_format = mask_image->common.extended_format_code;
mask_flags = info->mask_flags;
}
else
{
mask_format = PIXMAN_null;
mask_flags = FAST_PATH_IS_OPAQUE;
}
 
_pixman_implementation_lookup_composite (
imp->toplevel, info->op,
src_image->common.extended_format_code, src_flags,
mask_format, mask_flags,
dest_image->common.extended_format_code, info->dest_flags,
&imp, &func);
 
src_bpp = PIXMAN_FORMAT_BPP (src_image->bits.format);
 
if (src_image->bits.width < REPEAT_MIN_WIDTH &&
(src_bpp == 32 || src_bpp == 16 || src_bpp == 8) &&
!src_image->bits.indexed)
{
sx = src_x;
sx = MOD (sx, src_image->bits.width);
sx += width;
src_width = 0;
 
while (src_width < REPEAT_MIN_WIDTH && src_width <= sx)
src_width += src_image->bits.width;
 
src_stride = (src_width * (src_bpp >> 3) + 3) / (int) sizeof (uint32_t);
 
/* Initialize/validate stack-allocated temporary image */
_pixman_bits_image_init (&extended_src_image, src_image->bits.format,
src_width, 1, &extended_src[0], src_stride,
FALSE);
_pixman_image_validate (&extended_src_image);
 
info2.src_image = &extended_src_image;
need_src_extension = TRUE;
}
else
{
src_width = src_image->bits.width;
need_src_extension = FALSE;
}
 
sx = src_x;
sy = src_y;
 
while (--height >= 0)
{
sx = MOD (sx, src_width);
sy = MOD (sy, src_image->bits.height);
 
if (need_src_extension)
{
if (src_bpp == 32)
{
PIXMAN_IMAGE_GET_LINE (src_image, 0, sy, uint32_t, src_stride, src_line, 1);
 
for (i = 0; i < src_width; )
{
for (j = 0; j < src_image->bits.width; j++, i++)
extended_src[i] = src_line[j];
}
}
else if (src_bpp == 16)
{
uint16_t *src_line_16;
 
PIXMAN_IMAGE_GET_LINE (src_image, 0, sy, uint16_t, src_stride,
src_line_16, 1);
src_line = (uint32_t*)src_line_16;
 
for (i = 0; i < src_width; )
{
for (j = 0; j < src_image->bits.width; j++, i++)
((uint16_t*)extended_src)[i] = ((uint16_t*)src_line)[j];
}
}
else if (src_bpp == 8)
{
uint8_t *src_line_8;
 
PIXMAN_IMAGE_GET_LINE (src_image, 0, sy, uint8_t, src_stride,
src_line_8, 1);
src_line = (uint32_t*)src_line_8;
 
for (i = 0; i < src_width; )
{
for (j = 0; j < src_image->bits.width; j++, i++)
((uint8_t*)extended_src)[i] = ((uint8_t*)src_line)[j];
}
}
 
info2.src_y = 0;
}
else
{
info2.src_y = sy;
}
 
width_remain = width;
 
while (width_remain > 0)
{
num_pixels = src_width - sx;
 
if (num_pixels > width_remain)
num_pixels = width_remain;
 
info2.src_x = sx;
info2.width = num_pixels;
info2.height = 1;
 
func (imp, &info2);
 
width_remain -= num_pixels;
info2.mask_x += num_pixels;
info2.dest_x += num_pixels;
sx = 0;
}
 
sx = src_x;
sy++;
info2.mask_x = info->mask_x;
info2.mask_y++;
info2.dest_x = info->dest_x;
info2.dest_y++;
}
 
if (need_src_extension)
_pixman_image_fini (&extended_src_image);
}
 
/* Use more unrolling for src_0565_0565 because it is typically CPU bound */
static force_inline void
scaled_nearest_scanline_565_565_SRC (uint16_t * dst,
const uint16_t * src,
int32_t w,
pixman_fixed_t vx,
pixman_fixed_t unit_x,
pixman_fixed_t max_vx,
pixman_bool_t fully_transparent_src)
{
uint16_t tmp1, tmp2, tmp3, tmp4;
while ((w -= 4) >= 0)
{
tmp1 = *(src + pixman_fixed_to_int (vx));
vx += unit_x;
tmp2 = *(src + pixman_fixed_to_int (vx));
vx += unit_x;
tmp3 = *(src + pixman_fixed_to_int (vx));
vx += unit_x;
tmp4 = *(src + pixman_fixed_to_int (vx));
vx += unit_x;
*dst++ = tmp1;
*dst++ = tmp2;
*dst++ = tmp3;
*dst++ = tmp4;
}
if (w & 2)
{
tmp1 = *(src + pixman_fixed_to_int (vx));
vx += unit_x;
tmp2 = *(src + pixman_fixed_to_int (vx));
vx += unit_x;
*dst++ = tmp1;
*dst++ = tmp2;
}
if (w & 1)
*dst = *(src + pixman_fixed_to_int (vx));
}
 
FAST_NEAREST_MAINLOOP (565_565_cover_SRC,
scaled_nearest_scanline_565_565_SRC,
uint16_t, uint16_t, COVER)
FAST_NEAREST_MAINLOOP (565_565_none_SRC,
scaled_nearest_scanline_565_565_SRC,
uint16_t, uint16_t, NONE)
FAST_NEAREST_MAINLOOP (565_565_pad_SRC,
scaled_nearest_scanline_565_565_SRC,
uint16_t, uint16_t, PAD)
 
static force_inline uint32_t
fetch_nearest (pixman_repeat_t src_repeat,
pixman_format_code_t format,
uint32_t *src, int x, int src_width)
{
if (repeat (src_repeat, &x, src_width))
{
if (format == PIXMAN_x8r8g8b8 || format == PIXMAN_x8b8g8r8)
return *(src + x) | 0xff000000;
else
return *(src + x);
}
else
{
return 0;
}
}
 
static force_inline void
combine_over (uint32_t s, uint32_t *dst)
{
if (s)
{
uint8_t ia = 0xff - (s >> 24);
 
if (ia)
UN8x4_MUL_UN8_ADD_UN8x4 (*dst, ia, s);
else
*dst = s;
}
}
 
static force_inline void
combine_src (uint32_t s, uint32_t *dst)
{
*dst = s;
}
 
static void
fast_composite_scaled_nearest (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line;
uint32_t *src_line;
int dst_stride, src_stride;
int src_width, src_height;
pixman_repeat_t src_repeat;
pixman_fixed_t unit_x, unit_y;
pixman_format_code_t src_format;
pixman_vector_t v;
pixman_fixed_t vy;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
/* pass in 0 instead of src_x and src_y because src_x and src_y need to be
* transformed from destination space to source space
*/
PIXMAN_IMAGE_GET_LINE (src_image, 0, 0, uint32_t, src_stride, src_line, 1);
 
/* reference point is the center of the pixel */
v.vector[0] = pixman_int_to_fixed (src_x) + pixman_fixed_1 / 2;
v.vector[1] = pixman_int_to_fixed (src_y) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
 
if (!pixman_transform_point_3d (src_image->common.transform, &v))
return;
 
unit_x = src_image->common.transform->matrix[0][0];
unit_y = src_image->common.transform->matrix[1][1];
 
/* Round down to closest integer, ensuring that 0.5 rounds to 0, not 1 */
v.vector[0] -= pixman_fixed_e;
v.vector[1] -= pixman_fixed_e;
 
src_height = src_image->bits.height;
src_width = src_image->bits.width;
src_repeat = src_image->common.repeat;
src_format = src_image->bits.format;
 
vy = v.vector[1];
while (height--)
{
pixman_fixed_t vx = v.vector[0];
int y = pixman_fixed_to_int (vy);
uint32_t *dst = dst_line;
 
dst_line += dst_stride;
 
/* adjust the y location by a unit vector in the y direction
* this is equivalent to transforming y+1 of the destination point to source space */
vy += unit_y;
 
if (!repeat (src_repeat, &y, src_height))
{
if (op == PIXMAN_OP_SRC)
memset (dst, 0, sizeof (*dst) * width);
}
else
{
int w = width;
 
uint32_t *src = src_line + y * src_stride;
 
while (w >= 2)
{
uint32_t s1, s2;
int x1, x2;
 
x1 = pixman_fixed_to_int (vx);
vx += unit_x;
 
x2 = pixman_fixed_to_int (vx);
vx += unit_x;
 
w -= 2;
 
s1 = fetch_nearest (src_repeat, src_format, src, x1, src_width);
s2 = fetch_nearest (src_repeat, src_format, src, x2, src_width);
 
if (op == PIXMAN_OP_OVER)
{
combine_over (s1, dst++);
combine_over (s2, dst++);
}
else
{
combine_src (s1, dst++);
combine_src (s2, dst++);
}
}
 
while (w--)
{
uint32_t s;
int x;
 
x = pixman_fixed_to_int (vx);
vx += unit_x;
 
s = fetch_nearest (src_repeat, src_format, src, x, src_width);
 
if (op == PIXMAN_OP_OVER)
combine_over (s, dst++);
else
combine_src (s, dst++);
}
}
}
}
 
#define CACHE_LINE_SIZE 64
 
#define FAST_SIMPLE_ROTATE(suffix, pix_type) \
\
static void \
blt_rotated_90_trivial_##suffix (pix_type *dst, \
int dst_stride, \
const pix_type *src, \
int src_stride, \
int w, \
int h) \
{ \
int x, y; \
for (y = 0; y < h; y++) \
{ \
const pix_type *s = src + (h - y - 1); \
pix_type *d = dst + dst_stride * y; \
for (x = 0; x < w; x++) \
{ \
*d++ = *s; \
s += src_stride; \
} \
} \
} \
\
static void \
blt_rotated_270_trivial_##suffix (pix_type *dst, \
int dst_stride, \
const pix_type *src, \
int src_stride, \
int w, \
int h) \
{ \
int x, y; \
for (y = 0; y < h; y++) \
{ \
const pix_type *s = src + src_stride * (w - 1) + y; \
pix_type *d = dst + dst_stride * y; \
for (x = 0; x < w; x++) \
{ \
*d++ = *s; \
s -= src_stride; \
} \
} \
} \
\
static void \
blt_rotated_90_##suffix (pix_type *dst, \
int dst_stride, \
const pix_type *src, \
int src_stride, \
int W, \
int H) \
{ \
int x; \
int leading_pixels = 0, trailing_pixels = 0; \
const int TILE_SIZE = CACHE_LINE_SIZE / sizeof(pix_type); \
\
/* \
* split processing into handling destination as TILE_SIZExH cache line \
* aligned vertical stripes (optimistically assuming that destination \
* stride is a multiple of cache line, if not - it will be just a bit \
* slower) \
*/ \
\
if ((uintptr_t)dst & (CACHE_LINE_SIZE - 1)) \
{ \
leading_pixels = TILE_SIZE - (((uintptr_t)dst & \
(CACHE_LINE_SIZE - 1)) / sizeof(pix_type)); \
if (leading_pixels > W) \
leading_pixels = W; \
\
/* unaligned leading part NxH (where N < TILE_SIZE) */ \
blt_rotated_90_trivial_##suffix ( \
dst, \
dst_stride, \
src, \
src_stride, \
leading_pixels, \
H); \
\
dst += leading_pixels; \
src += leading_pixels * src_stride; \
W -= leading_pixels; \
} \
\
if ((uintptr_t)(dst + W) & (CACHE_LINE_SIZE - 1)) \
{ \
trailing_pixels = (((uintptr_t)(dst + W) & \
(CACHE_LINE_SIZE - 1)) / sizeof(pix_type)); \
if (trailing_pixels > W) \
trailing_pixels = W; \
W -= trailing_pixels; \
} \
\
for (x = 0; x < W; x += TILE_SIZE) \
{ \
/* aligned middle part TILE_SIZExH */ \
blt_rotated_90_trivial_##suffix ( \
dst + x, \
dst_stride, \
src + src_stride * x, \
src_stride, \
TILE_SIZE, \
H); \
} \
\
if (trailing_pixels) \
{ \
/* unaligned trailing part NxH (where N < TILE_SIZE) */ \
blt_rotated_90_trivial_##suffix ( \
dst + W, \
dst_stride, \
src + W * src_stride, \
src_stride, \
trailing_pixels, \
H); \
} \
} \
\
static void \
blt_rotated_270_##suffix (pix_type *dst, \
int dst_stride, \
const pix_type *src, \
int src_stride, \
int W, \
int H) \
{ \
int x; \
int leading_pixels = 0, trailing_pixels = 0; \
const int TILE_SIZE = CACHE_LINE_SIZE / sizeof(pix_type); \
\
/* \
* split processing into handling destination as TILE_SIZExH cache line \
* aligned vertical stripes (optimistically assuming that destination \
* stride is a multiple of cache line, if not - it will be just a bit \
* slower) \
*/ \
\
if ((uintptr_t)dst & (CACHE_LINE_SIZE - 1)) \
{ \
leading_pixels = TILE_SIZE - (((uintptr_t)dst & \
(CACHE_LINE_SIZE - 1)) / sizeof(pix_type)); \
if (leading_pixels > W) \
leading_pixels = W; \
\
/* unaligned leading part NxH (where N < TILE_SIZE) */ \
blt_rotated_270_trivial_##suffix ( \
dst, \
dst_stride, \
src + src_stride * (W - leading_pixels), \
src_stride, \
leading_pixels, \
H); \
\
dst += leading_pixels; \
W -= leading_pixels; \
} \
\
if ((uintptr_t)(dst + W) & (CACHE_LINE_SIZE - 1)) \
{ \
trailing_pixels = (((uintptr_t)(dst + W) & \
(CACHE_LINE_SIZE - 1)) / sizeof(pix_type)); \
if (trailing_pixels > W) \
trailing_pixels = W; \
W -= trailing_pixels; \
src += trailing_pixels * src_stride; \
} \
\
for (x = 0; x < W; x += TILE_SIZE) \
{ \
/* aligned middle part TILE_SIZExH */ \
blt_rotated_270_trivial_##suffix ( \
dst + x, \
dst_stride, \
src + src_stride * (W - x - TILE_SIZE), \
src_stride, \
TILE_SIZE, \
H); \
} \
\
if (trailing_pixels) \
{ \
/* unaligned trailing part NxH (where N < TILE_SIZE) */ \
blt_rotated_270_trivial_##suffix ( \
dst + W, \
dst_stride, \
src - trailing_pixels * src_stride, \
src_stride, \
trailing_pixels, \
H); \
} \
} \
\
static void \
fast_composite_rotate_90_##suffix (pixman_implementation_t *imp, \
pixman_composite_info_t *info) \
{ \
PIXMAN_COMPOSITE_ARGS (info); \
pix_type *dst_line; \
pix_type *src_line; \
int dst_stride, src_stride; \
int src_x_t, src_y_t; \
\
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, pix_type, \
dst_stride, dst_line, 1); \
src_x_t = -src_y + pixman_fixed_to_int ( \
src_image->common.transform->matrix[0][2] + \
pixman_fixed_1 / 2 - pixman_fixed_e) - height;\
src_y_t = src_x + pixman_fixed_to_int ( \
src_image->common.transform->matrix[1][2] + \
pixman_fixed_1 / 2 - pixman_fixed_e); \
PIXMAN_IMAGE_GET_LINE (src_image, src_x_t, src_y_t, pix_type, \
src_stride, src_line, 1); \
blt_rotated_90_##suffix (dst_line, dst_stride, src_line, src_stride, \
width, height); \
} \
\
static void \
fast_composite_rotate_270_##suffix (pixman_implementation_t *imp, \
pixman_composite_info_t *info) \
{ \
PIXMAN_COMPOSITE_ARGS (info); \
pix_type *dst_line; \
pix_type *src_line; \
int dst_stride, src_stride; \
int src_x_t, src_y_t; \
\
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, pix_type, \
dst_stride, dst_line, 1); \
src_x_t = src_y + pixman_fixed_to_int ( \
src_image->common.transform->matrix[0][2] + \
pixman_fixed_1 / 2 - pixman_fixed_e); \
src_y_t = -src_x + pixman_fixed_to_int ( \
src_image->common.transform->matrix[1][2] + \
pixman_fixed_1 / 2 - pixman_fixed_e) - width; \
PIXMAN_IMAGE_GET_LINE (src_image, src_x_t, src_y_t, pix_type, \
src_stride, src_line, 1); \
blt_rotated_270_##suffix (dst_line, dst_stride, src_line, src_stride, \
width, height); \
}
 
FAST_SIMPLE_ROTATE (8, uint8_t)
FAST_SIMPLE_ROTATE (565, uint16_t)
FAST_SIMPLE_ROTATE (8888, uint32_t)
 
static const pixman_fast_path_t c_fast_paths[] =
{
PIXMAN_STD_FAST_PATH (OVER, solid, a8, r5g6b5, fast_composite_over_n_8_0565),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, b5g6r5, fast_composite_over_n_8_0565),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, r8g8b8, fast_composite_over_n_8_0888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, b8g8r8, fast_composite_over_n_8_0888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8r8g8b8, fast_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8r8g8b8, fast_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8b8g8r8, fast_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8b8g8r8, fast_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a1, a8r8g8b8, fast_composite_over_n_1_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a1, x8r8g8b8, fast_composite_over_n_1_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a1, a8b8g8r8, fast_composite_over_n_1_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a1, x8b8g8r8, fast_composite_over_n_1_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a1, r5g6b5, fast_composite_over_n_1_0565),
PIXMAN_STD_FAST_PATH (OVER, solid, a1, b5g6r5, fast_composite_over_n_1_0565),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, a8r8g8b8, fast_composite_over_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, x8r8g8b8, fast_composite_over_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, r5g6b5, fast_composite_over_n_8888_0565_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, a8b8g8r8, fast_composite_over_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, x8b8g8r8, fast_composite_over_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, b5g6r5, fast_composite_over_n_8888_0565_ca),
PIXMAN_STD_FAST_PATH (OVER, x8r8g8b8, a8, x8r8g8b8, fast_composite_over_x888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, x8r8g8b8, a8, a8r8g8b8, fast_composite_over_x888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, x8b8g8r8, a8, x8b8g8r8, fast_composite_over_x888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, x8b8g8r8, a8, a8b8g8r8, fast_composite_over_x888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, a8r8g8b8, fast_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, x8r8g8b8, fast_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, r5g6b5, fast_composite_over_8888_0565),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, a8b8g8r8, fast_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, x8b8g8r8, fast_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, b5g6r5, fast_composite_over_8888_0565),
PIXMAN_STD_FAST_PATH (ADD, r5g6b5, null, r5g6b5, fast_composite_add_0565_0565),
PIXMAN_STD_FAST_PATH (ADD, b5g6r5, null, b5g6r5, fast_composite_add_0565_0565),
PIXMAN_STD_FAST_PATH (ADD, a8r8g8b8, null, a8r8g8b8, fast_composite_add_8888_8888),
PIXMAN_STD_FAST_PATH (ADD, a8b8g8r8, null, a8b8g8r8, fast_composite_add_8888_8888),
PIXMAN_STD_FAST_PATH (ADD, a8, null, a8, fast_composite_add_8_8),
PIXMAN_STD_FAST_PATH (ADD, a1, null, a1, fast_composite_add_1_1),
PIXMAN_STD_FAST_PATH_CA (ADD, solid, a8r8g8b8, a8r8g8b8, fast_composite_add_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH (ADD, solid, a8, a8, fast_composite_add_n_8_8),
PIXMAN_STD_FAST_PATH (SRC, solid, null, a8r8g8b8, fast_composite_solid_fill),
PIXMAN_STD_FAST_PATH (SRC, solid, null, x8r8g8b8, fast_composite_solid_fill),
PIXMAN_STD_FAST_PATH (SRC, solid, null, a8b8g8r8, fast_composite_solid_fill),
PIXMAN_STD_FAST_PATH (SRC, solid, null, x8b8g8r8, fast_composite_solid_fill),
PIXMAN_STD_FAST_PATH (SRC, solid, null, a1, fast_composite_solid_fill),
PIXMAN_STD_FAST_PATH (SRC, solid, null, a8, fast_composite_solid_fill),
PIXMAN_STD_FAST_PATH (SRC, solid, null, r5g6b5, fast_composite_solid_fill),
PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, a8r8g8b8, fast_composite_src_x888_8888),
PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, a8b8g8r8, fast_composite_src_x888_8888),
PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, x8r8g8b8, fast_composite_src_memcpy),
PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, a8r8g8b8, fast_composite_src_memcpy),
PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, x8r8g8b8, fast_composite_src_memcpy),
PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, x8b8g8r8, fast_composite_src_memcpy),
PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, a8b8g8r8, fast_composite_src_memcpy),
PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, x8b8g8r8, fast_composite_src_memcpy),
PIXMAN_STD_FAST_PATH (SRC, b8g8r8a8, null, b8g8r8x8, fast_composite_src_memcpy),
PIXMAN_STD_FAST_PATH (SRC, b8g8r8a8, null, b8g8r8a8, fast_composite_src_memcpy),
PIXMAN_STD_FAST_PATH (SRC, b8g8r8x8, null, b8g8r8x8, fast_composite_src_memcpy),
PIXMAN_STD_FAST_PATH (SRC, r5g6b5, null, r5g6b5, fast_composite_src_memcpy),
PIXMAN_STD_FAST_PATH (SRC, b5g6r5, null, b5g6r5, fast_composite_src_memcpy),
PIXMAN_STD_FAST_PATH (SRC, r8g8b8, null, r8g8b8, fast_composite_src_memcpy),
PIXMAN_STD_FAST_PATH (SRC, b8g8r8, null, b8g8r8, fast_composite_src_memcpy),
PIXMAN_STD_FAST_PATH (SRC, x1r5g5b5, null, x1r5g5b5, fast_composite_src_memcpy),
PIXMAN_STD_FAST_PATH (SRC, a1r5g5b5, null, x1r5g5b5, fast_composite_src_memcpy),
PIXMAN_STD_FAST_PATH (SRC, a8, null, a8, fast_composite_src_memcpy),
PIXMAN_STD_FAST_PATH (IN, a8, null, a8, fast_composite_in_8_8),
PIXMAN_STD_FAST_PATH (IN, solid, a8, a8, fast_composite_in_n_8_8),
 
SIMPLE_NEAREST_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8, 8888_8888),
SIMPLE_NEAREST_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, 8888_8888),
SIMPLE_NEAREST_FAST_PATH (SRC, x8b8g8r8, x8b8g8r8, 8888_8888),
SIMPLE_NEAREST_FAST_PATH (SRC, a8b8g8r8, x8b8g8r8, 8888_8888),
 
SIMPLE_NEAREST_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8, 8888_8888),
SIMPLE_NEAREST_FAST_PATH (SRC, a8b8g8r8, a8b8g8r8, 8888_8888),
 
SIMPLE_NEAREST_FAST_PATH (SRC, x8r8g8b8, r5g6b5, 8888_565),
SIMPLE_NEAREST_FAST_PATH (SRC, a8r8g8b8, r5g6b5, 8888_565),
 
SIMPLE_NEAREST_FAST_PATH (SRC, r5g6b5, r5g6b5, 565_565),
 
SIMPLE_NEAREST_FAST_PATH_COVER (SRC, x8r8g8b8, a8r8g8b8, x888_8888),
SIMPLE_NEAREST_FAST_PATH_COVER (SRC, x8b8g8r8, a8b8g8r8, x888_8888),
SIMPLE_NEAREST_FAST_PATH_PAD (SRC, x8r8g8b8, a8r8g8b8, x888_8888),
SIMPLE_NEAREST_FAST_PATH_PAD (SRC, x8b8g8r8, a8b8g8r8, x888_8888),
SIMPLE_NEAREST_FAST_PATH_NORMAL (SRC, x8r8g8b8, a8r8g8b8, x888_8888),
SIMPLE_NEAREST_FAST_PATH_NORMAL (SRC, x8b8g8r8, a8b8g8r8, x888_8888),
 
SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, 8888_8888),
SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, 8888_8888),
SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, 8888_8888),
SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, 8888_8888),
 
SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, r5g6b5, 8888_565),
 
#define NEAREST_FAST_PATH(op,s,d) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, SCALED_NEAREST_FLAGS, \
PIXMAN_null, 0, \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_nearest, \
}
 
NEAREST_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8),
NEAREST_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8),
NEAREST_FAST_PATH (SRC, x8b8g8r8, x8b8g8r8),
NEAREST_FAST_PATH (SRC, a8b8g8r8, x8b8g8r8),
 
NEAREST_FAST_PATH (SRC, x8r8g8b8, a8r8g8b8),
NEAREST_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8),
NEAREST_FAST_PATH (SRC, x8b8g8r8, a8b8g8r8),
NEAREST_FAST_PATH (SRC, a8b8g8r8, a8b8g8r8),
 
NEAREST_FAST_PATH (OVER, x8r8g8b8, x8r8g8b8),
NEAREST_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8),
NEAREST_FAST_PATH (OVER, x8b8g8r8, x8b8g8r8),
NEAREST_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8),
 
NEAREST_FAST_PATH (OVER, x8r8g8b8, a8r8g8b8),
NEAREST_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8),
NEAREST_FAST_PATH (OVER, x8b8g8r8, a8b8g8r8),
NEAREST_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8),
 
#define SIMPLE_ROTATE_FLAGS(angle) \
(FAST_PATH_ROTATE_ ## angle ## _TRANSFORM | \
FAST_PATH_NEAREST_FILTER | \
FAST_PATH_SAMPLES_COVER_CLIP_NEAREST | \
FAST_PATH_STANDARD_FLAGS)
 
#define SIMPLE_ROTATE_FAST_PATH(op,s,d,suffix) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, SIMPLE_ROTATE_FLAGS (90), \
PIXMAN_null, 0, \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_rotate_90_##suffix, \
}, \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, SIMPLE_ROTATE_FLAGS (270), \
PIXMAN_null, 0, \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_rotate_270_##suffix, \
}
 
SIMPLE_ROTATE_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8, 8888),
SIMPLE_ROTATE_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, 8888),
SIMPLE_ROTATE_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8, 8888),
SIMPLE_ROTATE_FAST_PATH (SRC, r5g6b5, r5g6b5, 565),
SIMPLE_ROTATE_FAST_PATH (SRC, a8, a8, 8),
 
/* Simple repeat fast path entry. */
{ PIXMAN_OP_any,
PIXMAN_any,
(FAST_PATH_STANDARD_FLAGS | FAST_PATH_ID_TRANSFORM | FAST_PATH_BITS_IMAGE |
FAST_PATH_NORMAL_REPEAT),
PIXMAN_any, 0,
PIXMAN_any, FAST_PATH_STD_DEST_FLAGS,
fast_composite_tiled_repeat
},
 
{ PIXMAN_OP_NONE },
};
 
#ifdef WORDS_BIGENDIAN
#define A1_FILL_MASK(n, offs) (((1U << (n)) - 1) << (32 - (offs) - (n)))
#else
#define A1_FILL_MASK(n, offs) (((1U << (n)) - 1) << (offs))
#endif
 
static force_inline void
pixman_fill1_line (uint32_t *dst, int offs, int width, int v)
{
if (offs)
{
int leading_pixels = 32 - offs;
if (leading_pixels >= width)
{
if (v)
*dst |= A1_FILL_MASK (width, offs);
else
*dst &= ~A1_FILL_MASK (width, offs);
return;
}
else
{
if (v)
*dst++ |= A1_FILL_MASK (leading_pixels, offs);
else
*dst++ &= ~A1_FILL_MASK (leading_pixels, offs);
width -= leading_pixels;
}
}
while (width >= 32)
{
if (v)
*dst++ = 0xFFFFFFFF;
else
*dst++ = 0;
width -= 32;
}
if (width > 0)
{
if (v)
*dst |= A1_FILL_MASK (width, 0);
else
*dst &= ~A1_FILL_MASK (width, 0);
}
}
 
static void
pixman_fill1 (uint32_t *bits,
int stride,
int x,
int y,
int width,
int height,
uint32_t filler)
{
uint32_t *dst = bits + y * stride + (x >> 5);
int offs = x & 31;
 
if (filler & 1)
{
while (height--)
{
pixman_fill1_line (dst, offs, width, 1);
dst += stride;
}
}
else
{
while (height--)
{
pixman_fill1_line (dst, offs, width, 0);
dst += stride;
}
}
}
 
static void
pixman_fill8 (uint32_t *bits,
int stride,
int x,
int y,
int width,
int height,
uint32_t filler)
{
int byte_stride = stride * (int) sizeof (uint32_t);
uint8_t *dst = (uint8_t *) bits;
uint8_t v = filler & 0xff;
int i;
 
dst = dst + y * byte_stride + x;
 
while (height--)
{
for (i = 0; i < width; ++i)
dst[i] = v;
 
dst += byte_stride;
}
}
 
static void
pixman_fill16 (uint32_t *bits,
int stride,
int x,
int y,
int width,
int height,
uint32_t filler)
{
int short_stride =
(stride * (int)sizeof (uint32_t)) / (int)sizeof (uint16_t);
uint16_t *dst = (uint16_t *)bits;
uint16_t v = filler & 0xffff;
int i;
 
dst = dst + y * short_stride + x;
 
while (height--)
{
for (i = 0; i < width; ++i)
dst[i] = v;
 
dst += short_stride;
}
}
 
static void
pixman_fill32 (uint32_t *bits,
int stride,
int x,
int y,
int width,
int height,
uint32_t filler)
{
int i;
 
bits = bits + y * stride + x;
 
while (height--)
{
for (i = 0; i < width; ++i)
bits[i] = filler;
 
bits += stride;
}
}
 
static pixman_bool_t
fast_path_fill (pixman_implementation_t *imp,
uint32_t * bits,
int stride,
int bpp,
int x,
int y,
int width,
int height,
uint32_t filler)
{
switch (bpp)
{
case 1:
pixman_fill1 (bits, stride, x, y, width, height, filler);
break;
 
case 8:
pixman_fill8 (bits, stride, x, y, width, height, filler);
break;
 
case 16:
pixman_fill16 (bits, stride, x, y, width, height, filler);
break;
 
case 32:
pixman_fill32 (bits, stride, x, y, width, height, filler);
break;
 
default:
return FALSE;
}
 
return TRUE;
}
 
/*****************************************************************************/
 
static uint32_t *
fast_fetch_r5g6b5 (pixman_iter_t *iter, const uint32_t *mask)
{
int32_t w = iter->width;
uint32_t *dst = iter->buffer;
const uint16_t *src = (const uint16_t *)iter->bits;
 
iter->bits += iter->stride;
 
/* Align the source buffer at 4 bytes boundary */
if (w > 0 && ((uintptr_t)src & 3))
{
*dst++ = convert_0565_to_8888 (*src++);
w--;
}
/* Process two pixels per iteration */
while ((w -= 2) >= 0)
{
uint32_t sr, sb, sg, t0, t1;
uint32_t s = *(const uint32_t *)src;
src += 2;
sr = (s >> 8) & 0x00F800F8;
sb = (s << 3) & 0x00F800F8;
sg = (s >> 3) & 0x00FC00FC;
sr |= sr >> 5;
sb |= sb >> 5;
sg |= sg >> 6;
t0 = ((sr << 16) & 0x00FF0000) | ((sg << 8) & 0x0000FF00) |
(sb & 0xFF) | 0xFF000000;
t1 = (sr & 0x00FF0000) | ((sg >> 8) & 0x0000FF00) |
(sb >> 16) | 0xFF000000;
#ifdef WORDS_BIGENDIAN
*dst++ = t1;
*dst++ = t0;
#else
*dst++ = t0;
*dst++ = t1;
#endif
}
if (w & 1)
{
*dst = convert_0565_to_8888 (*src);
}
 
return iter->buffer;
}
 
static uint32_t *
fast_dest_fetch_noop (pixman_iter_t *iter, const uint32_t *mask)
{
iter->bits += iter->stride;
return iter->buffer;
}
 
/* Helper function for a workaround, which tries to ensure that 0x1F001F
* constant is always allocated in a register on RISC architectures.
*/
static force_inline uint32_t
convert_8888_to_0565_workaround (uint32_t s, uint32_t x1F001F)
{
uint32_t a, b;
a = (s >> 3) & x1F001F;
b = s & 0xFC00;
a |= a >> 5;
a |= b >> 5;
return a;
}
 
static void
fast_write_back_r5g6b5 (pixman_iter_t *iter)
{
int32_t w = iter->width;
uint16_t *dst = (uint16_t *)(iter->bits - iter->stride);
const uint32_t *src = iter->buffer;
/* Workaround to ensure that x1F001F variable is allocated in a register */
static volatile uint32_t volatile_x1F001F = 0x1F001F;
uint32_t x1F001F = volatile_x1F001F;
 
while ((w -= 4) >= 0)
{
uint32_t s1 = *src++;
uint32_t s2 = *src++;
uint32_t s3 = *src++;
uint32_t s4 = *src++;
*dst++ = convert_8888_to_0565_workaround (s1, x1F001F);
*dst++ = convert_8888_to_0565_workaround (s2, x1F001F);
*dst++ = convert_8888_to_0565_workaround (s3, x1F001F);
*dst++ = convert_8888_to_0565_workaround (s4, x1F001F);
}
if (w & 2)
{
*dst++ = convert_8888_to_0565_workaround (*src++, x1F001F);
*dst++ = convert_8888_to_0565_workaround (*src++, x1F001F);
}
if (w & 1)
{
*dst = convert_8888_to_0565_workaround (*src, x1F001F);
}
}
 
typedef struct
{
pixman_format_code_t format;
pixman_iter_get_scanline_t get_scanline;
pixman_iter_write_back_t write_back;
} fetcher_info_t;
 
static const fetcher_info_t fetchers[] =
{
{ PIXMAN_r5g6b5, fast_fetch_r5g6b5, fast_write_back_r5g6b5 },
{ PIXMAN_null }
};
 
static pixman_bool_t
fast_src_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter)
{
pixman_image_t *image = iter->image;
 
#define FLAGS \
(FAST_PATH_STANDARD_FLAGS | FAST_PATH_ID_TRANSFORM | \
FAST_PATH_BITS_IMAGE | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST)
 
if ((iter->iter_flags & ITER_NARROW) &&
(iter->image_flags & FLAGS) == FLAGS)
{
const fetcher_info_t *f;
 
for (f = &fetchers[0]; f->format != PIXMAN_null; f++)
{
if (image->common.extended_format_code == f->format)
{
uint8_t *b = (uint8_t *)image->bits.bits;
int s = image->bits.rowstride * 4;
 
iter->bits = b + s * iter->y + iter->x * PIXMAN_FORMAT_BPP (f->format) / 8;
iter->stride = s;
 
iter->get_scanline = f->get_scanline;
return TRUE;
}
}
}
 
return FALSE;
}
 
static pixman_bool_t
fast_dest_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter)
{
pixman_image_t *image = iter->image;
 
if ((iter->iter_flags & ITER_NARROW) &&
(iter->image_flags & FAST_PATH_STD_DEST_FLAGS) == FAST_PATH_STD_DEST_FLAGS)
{
const fetcher_info_t *f;
 
for (f = &fetchers[0]; f->format != PIXMAN_null; f++)
{
if (image->common.extended_format_code == f->format)
{
uint8_t *b = (uint8_t *)image->bits.bits;
int s = image->bits.rowstride * 4;
 
iter->bits = b + s * iter->y + iter->x * PIXMAN_FORMAT_BPP (f->format) / 8;
iter->stride = s;
 
if ((iter->iter_flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) ==
(ITER_IGNORE_RGB | ITER_IGNORE_ALPHA))
{
iter->get_scanline = fast_dest_fetch_noop;
}
else
{
iter->get_scanline = f->get_scanline;
}
iter->write_back = f->write_back;
return TRUE;
}
}
}
return FALSE;
}
 
 
pixman_implementation_t *
_pixman_implementation_create_fast_path (pixman_implementation_t *fallback)
{
pixman_implementation_t *imp = _pixman_implementation_create (fallback, c_fast_paths);
 
imp->fill = fast_path_fill;
imp->src_iter_init = fast_src_iter_init;
imp->dest_iter_init = fast_dest_iter_init;
 
return imp;
}
/contrib/sdk/sources/pixman/pixman-filter.c
0,0 → 1,350
/*
* Copyright 2012, Red Hat, Inc.
* Copyright 2012, Soren Sandmann
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Author: Soren Sandmann <soren.sandmann@gmail.com>
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <assert.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "pixman-private.h"
 
typedef double (* kernel_func_t) (double x);
 
typedef struct
{
pixman_kernel_t kernel;
kernel_func_t func;
double width;
} filter_info_t;
 
static double
impulse_kernel (double x)
{
return (x == 0.0)? 1.0 : 0.0;
}
 
static double
box_kernel (double x)
{
return 1;
}
 
static double
linear_kernel (double x)
{
return 1 - fabs (x);
}
 
static double
gaussian_kernel (double x)
{
#define SQRT2 (1.4142135623730950488016887242096980785696718753769480)
#define SIGMA (SQRT2 / 2.0)
return exp (- x * x / (2 * SIGMA * SIGMA)) / (SIGMA * sqrt (2.0 * M_PI));
}
 
static double
sinc (double x)
{
if (x == 0.0)
return 1.0;
else
return sin (M_PI * x) / (M_PI * x);
}
 
static double
lanczos (double x, int n)
{
return sinc (x) * sinc (x * (1.0 / n));
}
 
static double
lanczos2_kernel (double x)
{
return lanczos (x, 2);
}
 
static double
lanczos3_kernel (double x)
{
return lanczos (x, 3);
}
 
static double
nice_kernel (double x)
{
return lanczos3_kernel (x * 0.75);
}
 
static double
general_cubic (double x, double B, double C)
{
double ax = fabs(x);
 
if (ax < 1)
{
return ((12 - 9 * B - 6 * C) * ax * ax * ax +
(-18 + 12 * B + 6 * C) * ax * ax + (6 - 2 * B)) / 6;
}
else if (ax >= 1 && ax < 2)
{
return ((-B - 6 * C) * ax * ax * ax +
(6 * B + 30 * C) * ax * ax + (-12 * B - 48 * C) *
ax + (8 * B + 24 * C)) / 6;
}
else
{
return 0;
}
}
 
static double
cubic_kernel (double x)
{
/* This is the Mitchell-Netravali filter.
*
* (0.0, 0.5) would give us the Catmull-Rom spline,
* but that one seems to be indistinguishable from Lanczos2.
*/
return general_cubic (x, 1/3.0, 1/3.0);
}
 
static const filter_info_t filters[] =
{
{ PIXMAN_KERNEL_IMPULSE, impulse_kernel, 0.0 },
{ PIXMAN_KERNEL_BOX, box_kernel, 1.0 },
{ PIXMAN_KERNEL_LINEAR, linear_kernel, 2.0 },
{ PIXMAN_KERNEL_CUBIC, cubic_kernel, 4.0 },
{ PIXMAN_KERNEL_GAUSSIAN, gaussian_kernel, 6 * SIGMA },
{ PIXMAN_KERNEL_LANCZOS2, lanczos2_kernel, 4.0 },
{ PIXMAN_KERNEL_LANCZOS3, lanczos3_kernel, 6.0 },
{ PIXMAN_KERNEL_LANCZOS3_STRETCHED, nice_kernel, 8.0 },
};
 
/* This function scales @kernel2 by @scale, then
* aligns @x1 in @kernel1 with @x2 in @kernel2 and
* and integrates the product of the kernels across @width.
*
* This function assumes that the intervals are within
* the kernels in question. E.g., the caller must not
* try to integrate a linear kernel ouside of [-1:1]
*/
static double
integral (pixman_kernel_t kernel1, double x1,
pixman_kernel_t kernel2, double scale, double x2,
double width)
{
/* If the integration interval crosses zero, break it into
* two separate integrals. This ensures that filters such
* as LINEAR that are not differentiable at 0 will still
* integrate properly.
*/
if (x1 < 0 && x1 + width > 0)
{
return
integral (kernel1, x1, kernel2, scale, x2, - x1) +
integral (kernel1, 0, kernel2, scale, x2 - x1, width + x1);
}
else if (x2 < 0 && x2 + width > 0)
{
return
integral (kernel1, x1, kernel2, scale, x2, - x2) +
integral (kernel1, x1 - x2, kernel2, scale, 0, width + x2);
}
else if (kernel1 == PIXMAN_KERNEL_IMPULSE)
{
assert (width == 0.0);
return filters[kernel2].func (x2 * scale);
}
else if (kernel2 == PIXMAN_KERNEL_IMPULSE)
{
assert (width == 0.0);
return filters[kernel1].func (x1);
}
else
{
/* Integration via Simpson's rule */
#define N_SEGMENTS 128
#define SAMPLE(a1, a2) \
(filters[kernel1].func ((a1)) * filters[kernel2].func ((a2) * scale))
double s = 0.0;
double h = width / (double)N_SEGMENTS;
int i;
 
s = SAMPLE (x1, x2);
 
for (i = 1; i < N_SEGMENTS; i += 2)
{
double a1 = x1 + h * i;
double a2 = x2 + h * i;
 
s += 2 * SAMPLE (a1, a2);
 
if (i >= 2 && i < N_SEGMENTS - 1)
s += 4 * SAMPLE (a1, a2);
}
 
s += SAMPLE (x1 + width, x2 + width);
return h * s * (1.0 / 3.0);
}
}
 
static pixman_fixed_t *
create_1d_filter (int *width,
pixman_kernel_t reconstruct,
pixman_kernel_t sample,
double scale,
int n_phases)
{
pixman_fixed_t *params, *p;
double step;
double size;
int i;
 
size = scale * filters[sample].width + filters[reconstruct].width;
*width = ceil (size);
 
p = params = malloc (*width * n_phases * sizeof (pixman_fixed_t));
if (!params)
return NULL;
 
step = 1.0 / n_phases;
 
for (i = 0; i < n_phases; ++i)
{
double frac = step / 2.0 + i * step;
pixman_fixed_t new_total;
int x, x1, x2;
double total;
 
/* Sample convolution of reconstruction and sampling
* filter. See rounding.txt regarding the rounding
* and sample positions.
*/
 
x1 = ceil (frac - *width / 2.0 - 0.5);
x2 = x1 + *width;
 
total = 0;
for (x = x1; x < x2; ++x)
{
double pos = x + 0.5 - frac;
double rlow = - filters[reconstruct].width / 2.0;
double rhigh = rlow + filters[reconstruct].width;
double slow = pos - scale * filters[sample].width / 2.0;
double shigh = slow + scale * filters[sample].width;
double c = 0.0;
double ilow, ihigh;
 
if (rhigh >= slow && rlow <= shigh)
{
ilow = MAX (slow, rlow);
ihigh = MIN (shigh, rhigh);
 
c = integral (reconstruct, ilow,
sample, 1.0 / scale, ilow - pos,
ihigh - ilow);
}
 
total += c;
*p++ = (pixman_fixed_t)(c * 65535.0 + 0.5);
}
 
/* Normalize */
p -= *width;
total = 1 / total;
new_total = 0;
for (x = x1; x < x2; ++x)
{
pixman_fixed_t t = (*p) * total + 0.5;
 
new_total += t;
*p++ = t;
}
 
if (new_total != pixman_fixed_1)
*(p - *width / 2) += (pixman_fixed_1 - new_total);
}
 
return params;
}
 
/* Create the parameter list for a SEPARABLE_CONVOLUTION filter
* with the given kernels and scale parameters
*/
PIXMAN_EXPORT pixman_fixed_t *
pixman_filter_create_separable_convolution (int *n_values,
pixman_fixed_t scale_x,
pixman_fixed_t scale_y,
pixman_kernel_t reconstruct_x,
pixman_kernel_t reconstruct_y,
pixman_kernel_t sample_x,
pixman_kernel_t sample_y,
int subsample_bits_x,
int subsample_bits_y)
{
double sx = fabs (pixman_fixed_to_double (scale_x));
double sy = fabs (pixman_fixed_to_double (scale_y));
pixman_fixed_t *horz = NULL, *vert = NULL, *params = NULL;
int subsample_x, subsample_y;
int width, height;
 
subsample_x = (1 << subsample_bits_x);
subsample_y = (1 << subsample_bits_y);
 
horz = create_1d_filter (&width, reconstruct_x, sample_x, sx, subsample_x);
vert = create_1d_filter (&height, reconstruct_y, sample_y, sy, subsample_y);
 
if (!horz || !vert)
goto out;
*n_values = 4 + width * subsample_x + height * subsample_y;
params = malloc (*n_values * sizeof (pixman_fixed_t));
if (!params)
goto out;
 
params[0] = pixman_int_to_fixed (width);
params[1] = pixman_int_to_fixed (height);
params[2] = pixman_int_to_fixed (subsample_bits_x);
params[3] = pixman_int_to_fixed (subsample_bits_y);
 
memcpy (params + 4, horz,
width * subsample_x * sizeof (pixman_fixed_t));
memcpy (params + 4 + width * subsample_x, vert,
height * subsample_y * sizeof (pixman_fixed_t));
 
out:
free (horz);
free (vert);
 
return params;
}
/contrib/sdk/sources/pixman/pixman-general.c
0,0 → 1,227
/*
* Copyright © 2009 Red Hat, Inc.
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007 Red Hat, Inc.
* Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
* 2005 Lars Knoll & Zack Rusin, Trolltech
* 2008 Aaron Plattner, NVIDIA Corporation
*
* 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 Red Hat not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. Red Hat makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pixman-private.h"
 
static pixman_bool_t
general_src_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter)
{
pixman_image_t *image = iter->image;
 
if (image->type == LINEAR)
_pixman_linear_gradient_iter_init (image, iter);
else if (image->type == RADIAL)
_pixman_radial_gradient_iter_init (image, iter);
else if (image->type == CONICAL)
_pixman_conical_gradient_iter_init (image, iter);
else if (image->type == BITS)
_pixman_bits_image_src_iter_init (image, iter);
else if (image->type == SOLID)
_pixman_log_error (FUNC, "Solid image not handled by noop");
else
_pixman_log_error (FUNC, "Pixman bug: unknown image type\n");
 
return TRUE;
}
 
static pixman_bool_t
general_dest_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter)
{
if (iter->image->type == BITS)
{
_pixman_bits_image_dest_iter_init (iter->image, iter);
 
return TRUE;
}
else
{
_pixman_log_error (FUNC, "Trying to write to a non-writable image");
 
return FALSE;
}
}
 
typedef struct op_info_t op_info_t;
struct op_info_t
{
uint8_t src, dst;
};
 
#define ITER_IGNORE_BOTH \
(ITER_IGNORE_ALPHA | ITER_IGNORE_RGB | ITER_LOCALIZED_ALPHA)
 
static const op_info_t op_flags[PIXMAN_N_OPERATORS] =
{
/* Src Dst */
{ ITER_IGNORE_BOTH, ITER_IGNORE_BOTH }, /* CLEAR */
{ ITER_LOCALIZED_ALPHA, ITER_IGNORE_BOTH }, /* SRC */
{ ITER_IGNORE_BOTH, ITER_LOCALIZED_ALPHA }, /* DST */
{ 0, ITER_LOCALIZED_ALPHA }, /* OVER */
{ ITER_LOCALIZED_ALPHA, 0 }, /* OVER_REVERSE */
{ ITER_LOCALIZED_ALPHA, ITER_IGNORE_RGB }, /* IN */
{ ITER_IGNORE_RGB, ITER_LOCALIZED_ALPHA }, /* IN_REVERSE */
{ ITER_LOCALIZED_ALPHA, ITER_IGNORE_RGB }, /* OUT */
{ ITER_IGNORE_RGB, ITER_LOCALIZED_ALPHA }, /* OUT_REVERSE */
{ 0, 0 }, /* ATOP */
{ 0, 0 }, /* ATOP_REVERSE */
{ 0, 0 }, /* XOR */
{ ITER_LOCALIZED_ALPHA, ITER_LOCALIZED_ALPHA }, /* ADD */
{ 0, 0 }, /* SATURATE */
};
 
#define SCANLINE_BUFFER_LENGTH 8192
 
static void
general_composite_rect (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint64_t stack_scanline_buffer[(SCANLINE_BUFFER_LENGTH * 3 + 7) / 8];
uint8_t *scanline_buffer = (uint8_t *) stack_scanline_buffer;
uint8_t *src_buffer, *mask_buffer, *dest_buffer;
pixman_iter_t src_iter, mask_iter, dest_iter;
pixman_combine_32_func_t compose;
pixman_bool_t component_alpha;
iter_flags_t narrow, src_iter_flags;
int Bpp;
int i;
 
if ((src_image->common.flags & FAST_PATH_NARROW_FORMAT) &&
(!mask_image || mask_image->common.flags & FAST_PATH_NARROW_FORMAT) &&
(dest_image->common.flags & FAST_PATH_NARROW_FORMAT))
{
narrow = ITER_NARROW;
Bpp = 4;
}
else
{
narrow = 0;
Bpp = 16;
}
 
if (width * Bpp > SCANLINE_BUFFER_LENGTH)
{
scanline_buffer = pixman_malloc_abc (width, 3, Bpp);
 
if (!scanline_buffer)
return;
}
 
src_buffer = scanline_buffer;
mask_buffer = src_buffer + width * Bpp;
dest_buffer = mask_buffer + width * Bpp;
 
if (!narrow)
{
/* To make sure there aren't any NANs in the buffers */
memset (src_buffer, 0, width * Bpp);
memset (mask_buffer, 0, width * Bpp);
memset (dest_buffer, 0, width * Bpp);
}
/* src iter */
src_iter_flags = narrow | op_flags[op].src;
 
_pixman_implementation_src_iter_init (imp->toplevel, &src_iter, src_image,
src_x, src_y, width, height,
src_buffer, src_iter_flags, info->src_flags);
 
/* mask iter */
if ((src_iter_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) ==
(ITER_IGNORE_ALPHA | ITER_IGNORE_RGB))
{
/* If it doesn't matter what the source is, then it doesn't matter
* what the mask is
*/
mask_image = NULL;
}
 
component_alpha =
mask_image &&
mask_image->common.type == BITS &&
mask_image->common.component_alpha &&
PIXMAN_FORMAT_RGB (mask_image->bits.format);
 
_pixman_implementation_src_iter_init (
imp->toplevel, &mask_iter, mask_image, mask_x, mask_y, width, height,
mask_buffer, narrow | (component_alpha? 0 : ITER_IGNORE_RGB), info->mask_flags);
 
/* dest iter */
_pixman_implementation_dest_iter_init (
imp->toplevel, &dest_iter, dest_image, dest_x, dest_y, width, height,
dest_buffer, narrow | op_flags[op].dst, info->dest_flags);
 
compose = _pixman_implementation_lookup_combiner (
imp->toplevel, op, component_alpha, narrow);
 
for (i = 0; i < height; ++i)
{
uint32_t *s, *m, *d;
 
m = mask_iter.get_scanline (&mask_iter, NULL);
s = src_iter.get_scanline (&src_iter, m);
d = dest_iter.get_scanline (&dest_iter, NULL);
 
compose (imp->toplevel, op, d, s, m, width);
 
dest_iter.write_back (&dest_iter);
}
 
if (scanline_buffer != (uint8_t *) stack_scanline_buffer)
free (scanline_buffer);
}
 
static const pixman_fast_path_t general_fast_path[] =
{
{ PIXMAN_OP_any, PIXMAN_any, 0, PIXMAN_any, 0, PIXMAN_any, 0, general_composite_rect },
{ PIXMAN_OP_NONE }
};
 
pixman_implementation_t *
_pixman_implementation_create_general (void)
{
pixman_implementation_t *imp = _pixman_implementation_create (NULL, general_fast_path);
 
_pixman_setup_combiner_functions_32 (imp);
_pixman_setup_combiner_functions_float (imp);
 
imp->src_iter_init = general_src_iter_init;
imp->dest_iter_init = general_dest_iter_init;
 
return imp;
}
 
/contrib/sdk/sources/pixman/pixman-glyph.c
0,0 → 1,670
/*
* Copyright 2010, 2012, Soren Sandmann <sandmann@cs.au.dk>
* Copyright 2010, 2011, 2012, Red Hat, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Author: Soren Sandmann <sandmann@cs.au.dk>
*/
 
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "pixman-private.h"
 
#include <stdlib.h>
 
typedef struct glyph_metrics_t glyph_metrics_t;
typedef struct glyph_t glyph_t;
 
#define TOMBSTONE ((glyph_t *)0x1)
 
/* XXX: These numbers are arbitrary---we've never done any measurements.
*/
#define N_GLYPHS_HIGH_WATER (16384)
#define N_GLYPHS_LOW_WATER (8192)
#define HASH_SIZE (2 * N_GLYPHS_HIGH_WATER)
#define HASH_MASK (HASH_SIZE - 1)
 
struct glyph_t
{
void * font_key;
void * glyph_key;
int origin_x;
int origin_y;
pixman_image_t * image;
pixman_link_t mru_link;
};
 
struct pixman_glyph_cache_t
{
int n_glyphs;
int n_tombstones;
int freeze_count;
pixman_list_t mru;
glyph_t * glyphs[HASH_SIZE];
};
 
static void
free_glyph (glyph_t *glyph)
{
pixman_list_unlink (&glyph->mru_link);
pixman_image_unref (glyph->image);
free (glyph);
}
 
static unsigned int
hash (const void *font_key, const void *glyph_key)
{
size_t key = (size_t)font_key + (size_t)glyph_key;
 
/* This hash function is based on one found on Thomas Wang's
* web page at
*
* http://www.concentric.net/~Ttwang/tech/inthash.htm
*
*/
key = (key << 15) - key - 1;
key = key ^ (key >> 12);
key = key + (key << 2);
key = key ^ (key >> 4);
key = key + (key << 3) + (key << 11);
key = key ^ (key >> 16);
 
return key;
}
 
static glyph_t *
lookup_glyph (pixman_glyph_cache_t *cache,
void *font_key,
void *glyph_key)
{
unsigned idx;
glyph_t *g;
 
idx = hash (font_key, glyph_key);
while ((g = cache->glyphs[idx++ & HASH_MASK]))
{
if (g != TOMBSTONE &&
g->font_key == font_key &&
g->glyph_key == glyph_key)
{
return g;
}
}
 
return NULL;
}
 
static void
insert_glyph (pixman_glyph_cache_t *cache,
glyph_t *glyph)
{
unsigned idx;
glyph_t **loc;
 
idx = hash (glyph->font_key, glyph->glyph_key);
 
/* Note: we assume that there is room in the table. If there isn't,
* this will be an infinite loop.
*/
do
{
loc = &cache->glyphs[idx++ & HASH_MASK];
} while (*loc && *loc != TOMBSTONE);
 
if (*loc == TOMBSTONE)
cache->n_tombstones--;
cache->n_glyphs++;
 
*loc = glyph;
}
 
static void
remove_glyph (pixman_glyph_cache_t *cache,
glyph_t *glyph)
{
unsigned idx;
 
idx = hash (glyph->font_key, glyph->glyph_key);
while (cache->glyphs[idx & HASH_MASK] != glyph)
idx++;
 
cache->glyphs[idx & HASH_MASK] = TOMBSTONE;
cache->n_tombstones++;
cache->n_glyphs--;
 
/* Eliminate tombstones if possible */
if (cache->glyphs[(idx + 1) & HASH_MASK] == NULL)
{
while (cache->glyphs[idx & HASH_MASK] == TOMBSTONE)
{
cache->glyphs[idx & HASH_MASK] = NULL;
cache->n_tombstones--;
idx--;
}
}
}
 
static void
clear_table (pixman_glyph_cache_t *cache)
{
int i;
 
for (i = 0; i < HASH_SIZE; ++i)
{
glyph_t *glyph = cache->glyphs[i];
 
if (glyph && glyph != TOMBSTONE)
free_glyph (glyph);
 
cache->glyphs[i] = NULL;
}
 
cache->n_glyphs = 0;
cache->n_tombstones = 0;
}
 
PIXMAN_EXPORT pixman_glyph_cache_t *
pixman_glyph_cache_create (void)
{
pixman_glyph_cache_t *cache;
 
if (!(cache = malloc (sizeof *cache)))
return NULL;
 
memset (cache->glyphs, 0, sizeof (cache->glyphs));
cache->n_glyphs = 0;
cache->n_tombstones = 0;
cache->freeze_count = 0;
 
pixman_list_init (&cache->mru);
 
return cache;
}
 
PIXMAN_EXPORT void
pixman_glyph_cache_destroy (pixman_glyph_cache_t *cache)
{
return_if_fail (cache->freeze_count == 0);
 
clear_table (cache);
 
free (cache);
}
 
PIXMAN_EXPORT void
pixman_glyph_cache_freeze (pixman_glyph_cache_t *cache)
{
cache->freeze_count++;
}
 
PIXMAN_EXPORT void
pixman_glyph_cache_thaw (pixman_glyph_cache_t *cache)
{
if (--cache->freeze_count == 0 &&
cache->n_glyphs + cache->n_tombstones > N_GLYPHS_HIGH_WATER)
{
if (cache->n_tombstones > N_GLYPHS_HIGH_WATER)
{
/* More than half the entries are
* tombstones. Just dump the whole table.
*/
clear_table (cache);
}
 
while (cache->n_glyphs > N_GLYPHS_LOW_WATER)
{
glyph_t *glyph = CONTAINER_OF (glyph_t, mru_link, cache->mru.tail);
 
remove_glyph (cache, glyph);
free_glyph (glyph);
}
}
}
 
PIXMAN_EXPORT const void *
pixman_glyph_cache_lookup (pixman_glyph_cache_t *cache,
void *font_key,
void *glyph_key)
{
return lookup_glyph (cache, font_key, glyph_key);
}
 
PIXMAN_EXPORT const void *
pixman_glyph_cache_insert (pixman_glyph_cache_t *cache,
void *font_key,
void *glyph_key,
int origin_x,
int origin_y,
pixman_image_t *image)
{
glyph_t *glyph;
int32_t width, height;
 
return_val_if_fail (cache->freeze_count > 0, NULL);
return_val_if_fail (image->type == BITS, NULL);
 
width = image->bits.width;
height = image->bits.height;
 
if (cache->n_glyphs >= HASH_SIZE)
return NULL;
 
if (!(glyph = malloc (sizeof *glyph)))
return NULL;
 
glyph->font_key = font_key;
glyph->glyph_key = glyph_key;
glyph->origin_x = origin_x;
glyph->origin_y = origin_y;
 
if (!(glyph->image = pixman_image_create_bits (
image->bits.format, width, height, NULL, -1)))
{
free (glyph);
return NULL;
}
 
pixman_image_composite32 (PIXMAN_OP_SRC,
image, NULL, glyph->image, 0, 0, 0, 0, 0, 0,
width, height);
 
if (PIXMAN_FORMAT_A (glyph->image->bits.format) != 0 &&
PIXMAN_FORMAT_RGB (glyph->image->bits.format) != 0)
{
pixman_image_set_component_alpha (glyph->image, TRUE);
}
 
pixman_list_prepend (&cache->mru, &glyph->mru_link);
 
_pixman_image_validate (glyph->image);
insert_glyph (cache, glyph);
 
return glyph;
}
 
PIXMAN_EXPORT void
pixman_glyph_cache_remove (pixman_glyph_cache_t *cache,
void *font_key,
void *glyph_key)
{
glyph_t *glyph;
 
if ((glyph = lookup_glyph (cache, font_key, glyph_key)))
{
remove_glyph (cache, glyph);
 
free_glyph (glyph);
}
}
 
PIXMAN_EXPORT void
pixman_glyph_get_extents (pixman_glyph_cache_t *cache,
int n_glyphs,
pixman_glyph_t *glyphs,
pixman_box32_t *extents)
{
int i;
 
extents->x1 = extents->y1 = INT32_MAX;
extents->x2 = extents->y2 = INT32_MIN;
 
for (i = 0; i < n_glyphs; ++i)
{
glyph_t *glyph = (glyph_t *)glyphs[i].glyph;
int x1, y1, x2, y2;
 
x1 = glyphs[i].x - glyph->origin_x;
y1 = glyphs[i].y - glyph->origin_y;
x2 = glyphs[i].x - glyph->origin_x + glyph->image->bits.width;
y2 = glyphs[i].y - glyph->origin_y + glyph->image->bits.height;
 
if (x1 < extents->x1)
extents->x1 = x1;
if (y1 < extents->y1)
extents->y1 = y1;
if (x2 > extents->x2)
extents->x2 = x2;
if (y2 > extents->y2)
extents->y2 = y2;
}
}
 
/* This function returns a format that is suitable for use as a mask for the
* set of glyphs in question.
*/
PIXMAN_EXPORT pixman_format_code_t
pixman_glyph_get_mask_format (pixman_glyph_cache_t *cache,
int n_glyphs,
const pixman_glyph_t *glyphs)
{
pixman_format_code_t format = PIXMAN_a1;
int i;
 
for (i = 0; i < n_glyphs; ++i)
{
const glyph_t *glyph = glyphs[i].glyph;
pixman_format_code_t glyph_format = glyph->image->bits.format;
 
if (PIXMAN_FORMAT_TYPE (glyph_format) == PIXMAN_TYPE_A)
{
if (PIXMAN_FORMAT_A (glyph_format) > PIXMAN_FORMAT_A (format))
format = glyph_format;
}
else
{
return PIXMAN_a8r8g8b8;
}
}
 
return format;
}
 
static pixman_bool_t
box32_intersect (pixman_box32_t *dest,
const pixman_box32_t *box1,
const pixman_box32_t *box2)
{
dest->x1 = MAX (box1->x1, box2->x1);
dest->y1 = MAX (box1->y1, box2->y1);
dest->x2 = MIN (box1->x2, box2->x2);
dest->y2 = MIN (box1->y2, box2->y2);
 
return dest->x2 > dest->x1 && dest->y2 > dest->y1;
}
 
PIXMAN_EXPORT void
pixman_composite_glyphs_no_mask (pixman_op_t op,
pixman_image_t *src,
pixman_image_t *dest,
int32_t src_x,
int32_t src_y,
int32_t dest_x,
int32_t dest_y,
pixman_glyph_cache_t *cache,
int n_glyphs,
const pixman_glyph_t *glyphs)
{
pixman_region32_t region;
pixman_format_code_t glyph_format = PIXMAN_null;
uint32_t glyph_flags = 0;
pixman_format_code_t dest_format;
uint32_t dest_flags;
pixman_composite_func_t func = NULL;
pixman_implementation_t *implementation = NULL;
pixman_composite_info_t info;
int i;
 
_pixman_image_validate (src);
_pixman_image_validate (dest);
dest_format = dest->common.extended_format_code;
dest_flags = dest->common.flags;
pixman_region32_init (&region);
if (!_pixman_compute_composite_region32 (
&region,
src, NULL, dest,
src_x - dest_x, src_y - dest_y, 0, 0, 0, 0,
dest->bits.width, dest->bits.height))
{
goto out;
}
 
info.op = op;
info.src_image = src;
info.dest_image = dest;
info.src_flags = src->common.flags;
info.dest_flags = dest->common.flags;
 
for (i = 0; i < n_glyphs; ++i)
{
glyph_t *glyph = (glyph_t *)glyphs[i].glyph;
pixman_image_t *glyph_img = glyph->image;
pixman_box32_t glyph_box;
pixman_box32_t *pbox;
uint32_t extra = FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
pixman_box32_t composite_box;
int n;
 
glyph_box.x1 = dest_x + glyphs[i].x - glyph->origin_x;
glyph_box.y1 = dest_y + glyphs[i].y - glyph->origin_y;
glyph_box.x2 = glyph_box.x1 + glyph->image->bits.width;
glyph_box.y2 = glyph_box.y1 + glyph->image->bits.height;
pbox = pixman_region32_rectangles (&region, &n);
info.mask_image = glyph_img;
 
while (n--)
{
if (box32_intersect (&composite_box, pbox, &glyph_box))
{
if (glyph_img->common.extended_format_code != glyph_format ||
glyph_img->common.flags != glyph_flags)
{
glyph_format = glyph_img->common.extended_format_code;
glyph_flags = glyph_img->common.flags;
 
_pixman_implementation_lookup_composite (
get_implementation(), op,
src->common.extended_format_code, src->common.flags,
glyph_format, glyph_flags | extra,
dest_format, dest_flags,
&implementation, &func);
}
 
info.src_x = src_x + composite_box.x1 - dest_x;
info.src_y = src_y + composite_box.y1 - dest_y;
info.mask_x = composite_box.x1 - (dest_x + glyphs[i].x - glyph->origin_x);
info.mask_y = composite_box.y1 - (dest_y + glyphs[i].y - glyph->origin_y);
info.dest_x = composite_box.x1;
info.dest_y = composite_box.y1;
info.width = composite_box.x2 - composite_box.x1;
info.height = composite_box.y2 - composite_box.y1;
 
info.mask_flags = glyph_flags;
 
func (implementation, &info);
}
 
pbox++;
}
pixman_list_move_to_front (&cache->mru, &glyph->mru_link);
}
 
out:
pixman_region32_fini (&region);
}
 
static void
add_glyphs (pixman_glyph_cache_t *cache,
pixman_image_t *dest,
int off_x, int off_y,
int n_glyphs, const pixman_glyph_t *glyphs)
{
pixman_format_code_t glyph_format = PIXMAN_null;
uint32_t glyph_flags = 0;
pixman_composite_func_t func = NULL;
pixman_implementation_t *implementation = NULL;
pixman_format_code_t dest_format;
uint32_t dest_flags;
pixman_box32_t dest_box;
pixman_composite_info_t info;
pixman_image_t *white_img = NULL;
pixman_bool_t white_src = FALSE;
int i;
 
_pixman_image_validate (dest);
 
dest_format = dest->common.extended_format_code;
dest_flags = dest->common.flags;
 
info.op = PIXMAN_OP_ADD;
info.dest_image = dest;
info.src_x = 0;
info.src_y = 0;
info.dest_flags = dest_flags;
 
dest_box.x1 = 0;
dest_box.y1 = 0;
dest_box.x2 = dest->bits.width;
dest_box.y2 = dest->bits.height;
 
for (i = 0; i < n_glyphs; ++i)
{
glyph_t *glyph = (glyph_t *)glyphs[i].glyph;
pixman_image_t *glyph_img = glyph->image;
pixman_box32_t glyph_box;
pixman_box32_t composite_box;
 
if (glyph_img->common.extended_format_code != glyph_format ||
glyph_img->common.flags != glyph_flags)
{
pixman_format_code_t src_format, mask_format;
 
glyph_format = glyph_img->common.extended_format_code;
glyph_flags = glyph_img->common.flags;
 
if (glyph_format == dest->bits.format)
{
src_format = glyph_format;
mask_format = PIXMAN_null;
info.src_flags = glyph_flags | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
info.mask_flags = FAST_PATH_IS_OPAQUE;
info.mask_image = NULL;
white_src = FALSE;
}
else
{
if (!white_img)
{
static const pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff };
 
if (!(white_img = pixman_image_create_solid_fill (&white)))
goto out;
 
_pixman_image_validate (white_img);
}
 
src_format = PIXMAN_solid;
mask_format = glyph_format;
info.src_flags = white_img->common.flags;
info.mask_flags = glyph_flags | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
info.src_image = white_img;
white_src = TRUE;
}
 
_pixman_implementation_lookup_composite (
get_implementation(), PIXMAN_OP_ADD,
src_format, info.src_flags,
mask_format, info.mask_flags,
dest_format, dest_flags,
&implementation, &func);
}
 
glyph_box.x1 = glyphs[i].x - glyph->origin_x + off_x;
glyph_box.y1 = glyphs[i].y - glyph->origin_y + off_y;
glyph_box.x2 = glyph_box.x1 + glyph->image->bits.width;
glyph_box.y2 = glyph_box.y1 + glyph->image->bits.height;
if (box32_intersect (&composite_box, &glyph_box, &dest_box))
{
int src_x = composite_box.x1 - glyph_box.x1;
int src_y = composite_box.y1 - glyph_box.y1;
 
if (white_src)
info.mask_image = glyph_img;
else
info.src_image = glyph_img;
 
info.mask_x = info.src_x = src_x;
info.mask_y = info.src_y = src_y;
info.dest_x = composite_box.x1;
info.dest_y = composite_box.y1;
info.width = composite_box.x2 - composite_box.x1;
info.height = composite_box.y2 - composite_box.y1;
 
func (implementation, &info);
 
pixman_list_move_to_front (&cache->mru, &glyph->mru_link);
}
}
 
out:
if (white_img)
pixman_image_unref (white_img);
}
 
/* Conceptually, for each glyph, (white IN glyph) is PIXMAN_OP_ADDed to an
* infinitely big mask image at the position such that the glyph origin point
* is positioned at the (glyphs[i].x, glyphs[i].y) point.
*
* Then (mask_x, mask_y) in the infinite mask and (src_x, src_y) in the source
* image are both aligned with (dest_x, dest_y) in the destination image. Then
* these three images are composited within the
*
* (dest_x, dest_y, dst_x + width, dst_y + height)
*
* rectangle.
*
* TODO:
* - Trim the mask to the destination clip/image?
* - Trim composite region based on sources, when the op ignores 0s.
*/
PIXMAN_EXPORT void
pixman_composite_glyphs (pixman_op_t op,
pixman_image_t *src,
pixman_image_t *dest,
pixman_format_code_t mask_format,
int32_t src_x,
int32_t src_y,
int32_t mask_x,
int32_t mask_y,
int32_t dest_x,
int32_t dest_y,
int32_t width,
int32_t height,
pixman_glyph_cache_t *cache,
int n_glyphs,
const pixman_glyph_t *glyphs)
{
pixman_image_t *mask;
 
if (!(mask = pixman_image_create_bits (mask_format, width, height, NULL, -1)))
return;
 
if (PIXMAN_FORMAT_A (mask_format) != 0 &&
PIXMAN_FORMAT_RGB (mask_format) != 0)
{
pixman_image_set_component_alpha (mask, TRUE);
}
 
add_glyphs (cache, mask, - mask_x, - mask_y, n_glyphs, glyphs);
 
pixman_image_composite32 (op, src, mask, dest,
src_x, src_y,
0, 0,
dest_x, dest_y,
width, height);
 
pixman_image_unref (mask);
}
/contrib/sdk/sources/pixman/pixman-gradient-walker.c
0,0 → 1,202
/*
*
* Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
* 2005 Lars Knoll & Zack Rusin, Trolltech
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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_CONFIG_H
#include <config.h>
#endif
#include "pixman-private.h"
 
void
_pixman_gradient_walker_init (pixman_gradient_walker_t *walker,
gradient_t * gradient,
pixman_repeat_t repeat)
{
walker->num_stops = gradient->n_stops;
walker->stops = gradient->stops;
walker->left_x = 0;
walker->right_x = 0x10000;
walker->a_s = 0.0f;
walker->a_b = 0.0f;
walker->r_s = 0.0f;
walker->r_b = 0.0f;
walker->g_s = 0.0f;
walker->g_b = 0.0f;
walker->b_s = 0.0f;
walker->b_b = 0.0f;
walker->repeat = repeat;
 
walker->need_reset = TRUE;
}
 
static void
gradient_walker_reset (pixman_gradient_walker_t *walker,
pixman_fixed_48_16_t pos)
{
int32_t x, left_x, right_x;
pixman_color_t *left_c, *right_c;
int n, count = walker->num_stops;
pixman_gradient_stop_t *stops = walker->stops;
float la, lr, lg, lb;
float ra, rr, rg, rb;
float lx, rx;
 
if (walker->repeat == PIXMAN_REPEAT_NORMAL)
{
x = (int32_t)pos & 0xffff;
}
else if (walker->repeat == PIXMAN_REPEAT_REFLECT)
{
x = (int32_t)pos & 0xffff;
if ((int32_t)pos & 0x10000)
x = 0x10000 - x;
}
else
{
x = pos;
}
for (n = 0; n < count; n++)
{
if (x < stops[n].x)
break;
}
left_x = stops[n - 1].x;
left_c = &stops[n - 1].color;
right_x = stops[n].x;
right_c = &stops[n].color;
 
if (walker->repeat == PIXMAN_REPEAT_NORMAL)
{
left_x += (pos - x);
right_x += (pos - x);
}
else if (walker->repeat == PIXMAN_REPEAT_REFLECT)
{
if ((int32_t)pos & 0x10000)
{
pixman_color_t *tmp_c;
int32_t tmp_x;
 
tmp_x = 0x10000 - right_x;
right_x = 0x10000 - left_x;
left_x = tmp_x;
 
tmp_c = right_c;
right_c = left_c;
left_c = tmp_c;
 
x = 0x10000 - x;
}
left_x += (pos - x);
right_x += (pos - x);
}
else if (walker->repeat == PIXMAN_REPEAT_NONE)
{
if (n == 0)
right_c = left_c;
else if (n == count)
left_c = right_c;
}
 
/* The alpha channel is scaled to be in the [0, 255] interval,
* and the red/green/blue channels are scaled to be in [0, 1].
* This ensures that after premultiplication all channels will
* be in the [0, 255] interval.
*/
la = (left_c->alpha * (1.0f/257.0f));
lr = (left_c->red * (1.0f/257.0f));
lg = (left_c->green * (1.0f/257.0f));
lb = (left_c->blue * (1.0f/257.0f));
 
ra = (right_c->alpha * (1.0f/257.0f));
rr = (right_c->red * (1.0f/257.0f));
rg = (right_c->green * (1.0f/257.0f));
rb = (right_c->blue * (1.0f/257.0f));
lx = left_x * (1.0f/65536.0f);
rx = right_x * (1.0f/65536.0f);
if (FLOAT_IS_ZERO (rx - lx) || left_x == INT32_MIN || right_x == INT32_MAX)
{
walker->a_s = walker->r_s = walker->g_s = walker->b_s = 0.0f;
walker->a_b = (la + ra) / 2.0f;
walker->r_b = (lr + rr) / 510.0f;
walker->g_b = (lg + rg) / 510.0f;
walker->b_b = (lb + rb) / 510.0f;
}
else
{
float w_rec = 1.0f / (rx - lx);
 
walker->a_b = (la * rx - ra * lx) * w_rec;
walker->r_b = (lr * rx - rr * lx) * w_rec * (1.0f/255.0f);
walker->g_b = (lg * rx - rg * lx) * w_rec * (1.0f/255.0f);
walker->b_b = (lb * rx - rb * lx) * w_rec * (1.0f/255.0f);
 
walker->a_s = (ra - la) * w_rec;
walker->r_s = (rr - lr) * w_rec * (1.0f/255.0f);
walker->g_s = (rg - lg) * w_rec * (1.0f/255.0f);
walker->b_s = (rb - lb) * w_rec * (1.0f/255.0f);
}
walker->left_x = left_x;
walker->right_x = right_x;
 
walker->need_reset = FALSE;
}
 
uint32_t
_pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker,
pixman_fixed_48_16_t x)
{
float a, r, g, b;
uint8_t a8, r8, g8, b8;
uint32_t v;
float y;
 
if (walker->need_reset || x < walker->left_x || x >= walker->right_x)
gradient_walker_reset (walker, x);
 
y = x * (1.0f / 65536.0f);
 
a = walker->a_s * y + walker->a_b;
r = a * (walker->r_s * y + walker->r_b);
g = a * (walker->g_s * y + walker->g_b);
b = a * (walker->b_s * y + walker->b_b);
 
a8 = a + 0.5f;
r8 = r + 0.5f;
g8 = g + 0.5f;
b8 = b + 0.5f;
 
v = ((a8 << 24) & 0xff000000) |
((r8 << 16) & 0x00ff0000) |
((g8 << 8) & 0x0000ff00) |
((b8 >> 0) & 0x000000ff);
 
return v;
}
/contrib/sdk/sources/pixman/pixman-image.c
0,0 → 1,940
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
 
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
 
#include "pixman-private.h"
 
static const pixman_color_t transparent_black = { 0, 0, 0, 0 };
 
static void
gradient_property_changed (pixman_image_t *image)
{
gradient_t *gradient = &image->gradient;
int n = gradient->n_stops;
pixman_gradient_stop_t *stops = gradient->stops;
pixman_gradient_stop_t *begin = &(gradient->stops[-1]);
pixman_gradient_stop_t *end = &(gradient->stops[n]);
 
switch (gradient->common.repeat)
{
default:
case PIXMAN_REPEAT_NONE:
begin->x = INT32_MIN;
begin->color = transparent_black;
end->x = INT32_MAX;
end->color = transparent_black;
break;
 
case PIXMAN_REPEAT_NORMAL:
begin->x = stops[n - 1].x - pixman_fixed_1;
begin->color = stops[n - 1].color;
end->x = stops[0].x + pixman_fixed_1;
end->color = stops[0].color;
break;
 
case PIXMAN_REPEAT_REFLECT:
begin->x = - stops[0].x;
begin->color = stops[0].color;
end->x = pixman_int_to_fixed (2) - stops[n - 1].x;
end->color = stops[n - 1].color;
break;
 
case PIXMAN_REPEAT_PAD:
begin->x = INT32_MIN;
begin->color = stops[0].color;
end->x = INT32_MAX;
end->color = stops[n - 1].color;
break;
}
}
 
pixman_bool_t
_pixman_init_gradient (gradient_t * gradient,
const pixman_gradient_stop_t *stops,
int n_stops)
{
return_val_if_fail (n_stops > 0, FALSE);
 
/* We allocate two extra stops, one before the beginning of the stop list,
* and one after the end. These stops are initialized to whatever color
* would be used for positions outside the range of the stop list.
*
* This saves a bit of computation in the gradient walker.
*
* The pointer we store in the gradient_t struct still points to the
* first user-supplied struct, so when freeing, we will have to
* subtract one.
*/
gradient->stops =
pixman_malloc_ab (n_stops + 2, sizeof (pixman_gradient_stop_t));
if (!gradient->stops)
return FALSE;
 
gradient->stops += 1;
memcpy (gradient->stops, stops, n_stops * sizeof (pixman_gradient_stop_t));
gradient->n_stops = n_stops;
 
gradient->common.property_changed = gradient_property_changed;
 
return TRUE;
}
 
void
_pixman_image_init (pixman_image_t *image)
{
image_common_t *common = &image->common;
 
pixman_region32_init (&common->clip_region);
 
common->alpha_count = 0;
common->have_clip_region = FALSE;
common->clip_sources = FALSE;
common->transform = NULL;
common->repeat = PIXMAN_REPEAT_NONE;
common->filter = PIXMAN_FILTER_NEAREST;
common->filter_params = NULL;
common->n_filter_params = 0;
common->alpha_map = NULL;
common->component_alpha = FALSE;
common->ref_count = 1;
common->property_changed = NULL;
common->client_clip = FALSE;
common->destroy_func = NULL;
common->destroy_data = NULL;
common->dirty = TRUE;
}
 
pixman_bool_t
_pixman_image_fini (pixman_image_t *image)
{
image_common_t *common = (image_common_t *)image;
 
common->ref_count--;
 
if (common->ref_count == 0)
{
if (image->common.destroy_func)
image->common.destroy_func (image, image->common.destroy_data);
 
pixman_region32_fini (&common->clip_region);
 
free (common->transform);
free (common->filter_params);
 
if (common->alpha_map)
pixman_image_unref ((pixman_image_t *)common->alpha_map);
 
if (image->type == LINEAR ||
image->type == RADIAL ||
image->type == CONICAL)
{
if (image->gradient.stops)
{
/* See _pixman_init_gradient() for an explanation of the - 1 */
free (image->gradient.stops - 1);
}
 
/* This will trigger if someone adds a property_changed
* method to the linear/radial/conical gradient overwriting
* the general one.
*/
assert (
image->common.property_changed == gradient_property_changed);
}
 
if (image->type == BITS && image->bits.free_me)
free (image->bits.free_me);
 
return TRUE;
}
 
return FALSE;
}
 
pixman_image_t *
_pixman_image_allocate (void)
{
pixman_image_t *image = malloc (sizeof (pixman_image_t));
 
if (image)
_pixman_image_init (image);
 
return image;
}
 
static void
image_property_changed (pixman_image_t *image)
{
image->common.dirty = TRUE;
}
 
/* Ref Counting */
PIXMAN_EXPORT pixman_image_t *
pixman_image_ref (pixman_image_t *image)
{
image->common.ref_count++;
 
return image;
}
 
/* returns TRUE when the image is freed */
PIXMAN_EXPORT pixman_bool_t
pixman_image_unref (pixman_image_t *image)
{
if (_pixman_image_fini (image))
{
free (image);
return TRUE;
}
 
return FALSE;
}
 
PIXMAN_EXPORT void
pixman_image_set_destroy_function (pixman_image_t * image,
pixman_image_destroy_func_t func,
void * data)
{
image->common.destroy_func = func;
image->common.destroy_data = data;
}
 
PIXMAN_EXPORT void *
pixman_image_get_destroy_data (pixman_image_t *image)
{
return image->common.destroy_data;
}
 
void
_pixman_image_reset_clip_region (pixman_image_t *image)
{
image->common.have_clip_region = FALSE;
}
 
/* Executive Summary: This function is a no-op that only exists
* for historical reasons.
*
* There used to be a bug in the X server where it would rely on
* out-of-bounds accesses when it was asked to composite with a
* window as the source. It would create a pixman image pointing
* to some bogus position in memory, but then set a clip region
* to the position where the actual bits were.
*
* Due to a bug in old versions of pixman, where it would not clip
* against the image bounds when a clip region was set, this would
* actually work. So when the pixman bug was fixed, a workaround was
* added to allow certain out-of-bound accesses. This function disabled
* those workarounds.
*
* Since 0.21.2, pixman doesn't do these workarounds anymore, so now
* this function is a no-op.
*/
PIXMAN_EXPORT void
pixman_disable_out_of_bounds_workaround (void)
{
}
 
static void
compute_image_info (pixman_image_t *image)
{
pixman_format_code_t code;
uint32_t flags = 0;
 
/* Transform */
if (!image->common.transform)
{
flags |= (FAST_PATH_ID_TRANSFORM |
FAST_PATH_X_UNIT_POSITIVE |
FAST_PATH_Y_UNIT_ZERO |
FAST_PATH_AFFINE_TRANSFORM);
}
else
{
flags |= FAST_PATH_HAS_TRANSFORM;
 
if (image->common.transform->matrix[2][0] == 0 &&
image->common.transform->matrix[2][1] == 0 &&
image->common.transform->matrix[2][2] == pixman_fixed_1)
{
flags |= FAST_PATH_AFFINE_TRANSFORM;
 
if (image->common.transform->matrix[0][1] == 0 &&
image->common.transform->matrix[1][0] == 0)
{
if (image->common.transform->matrix[0][0] == -pixman_fixed_1 &&
image->common.transform->matrix[1][1] == -pixman_fixed_1)
{
flags |= FAST_PATH_ROTATE_180_TRANSFORM;
}
flags |= FAST_PATH_SCALE_TRANSFORM;
}
else if (image->common.transform->matrix[0][0] == 0 &&
image->common.transform->matrix[1][1] == 0)
{
pixman_fixed_t m01 = image->common.transform->matrix[0][1];
pixman_fixed_t m10 = image->common.transform->matrix[1][0];
 
if (m01 == -pixman_fixed_1 && m10 == pixman_fixed_1)
flags |= FAST_PATH_ROTATE_90_TRANSFORM;
else if (m01 == pixman_fixed_1 && m10 == -pixman_fixed_1)
flags |= FAST_PATH_ROTATE_270_TRANSFORM;
}
}
 
if (image->common.transform->matrix[0][0] > 0)
flags |= FAST_PATH_X_UNIT_POSITIVE;
 
if (image->common.transform->matrix[1][0] == 0)
flags |= FAST_PATH_Y_UNIT_ZERO;
}
 
/* Filter */
switch (image->common.filter)
{
case PIXMAN_FILTER_NEAREST:
case PIXMAN_FILTER_FAST:
flags |= (FAST_PATH_NEAREST_FILTER | FAST_PATH_NO_CONVOLUTION_FILTER);
break;
 
case PIXMAN_FILTER_BILINEAR:
case PIXMAN_FILTER_GOOD:
case PIXMAN_FILTER_BEST:
flags |= (FAST_PATH_BILINEAR_FILTER | FAST_PATH_NO_CONVOLUTION_FILTER);
 
/* Here we have a chance to optimize BILINEAR filter to NEAREST if
* they are equivalent for the currently used transformation matrix.
*/
if (flags & FAST_PATH_ID_TRANSFORM)
{
flags |= FAST_PATH_NEAREST_FILTER;
}
else if (
/* affine and integer translation components in matrix ... */
((flags & FAST_PATH_AFFINE_TRANSFORM) &&
!pixman_fixed_frac (image->common.transform->matrix[0][2] |
image->common.transform->matrix[1][2])) &&
(
/* ... combined with a simple rotation */
(flags & (FAST_PATH_ROTATE_90_TRANSFORM |
FAST_PATH_ROTATE_180_TRANSFORM |
FAST_PATH_ROTATE_270_TRANSFORM)) ||
/* ... or combined with a simple non-rotated translation */
(image->common.transform->matrix[0][0] == pixman_fixed_1 &&
image->common.transform->matrix[1][1] == pixman_fixed_1 &&
image->common.transform->matrix[0][1] == 0 &&
image->common.transform->matrix[1][0] == 0)
)
)
{
/* FIXME: there are some affine-test failures, showing that
* handling of BILINEAR and NEAREST filter is not quite
* equivalent when getting close to 32K for the translation
* components of the matrix. That's likely some bug, but for
* now just skip BILINEAR->NEAREST optimization in this case.
*/
pixman_fixed_t magic_limit = pixman_int_to_fixed (30000);
if (image->common.transform->matrix[0][2] <= magic_limit &&
image->common.transform->matrix[1][2] <= magic_limit &&
image->common.transform->matrix[0][2] >= -magic_limit &&
image->common.transform->matrix[1][2] >= -magic_limit)
{
flags |= FAST_PATH_NEAREST_FILTER;
}
}
break;
 
case PIXMAN_FILTER_CONVOLUTION:
break;
 
case PIXMAN_FILTER_SEPARABLE_CONVOLUTION:
flags |= FAST_PATH_SEPARABLE_CONVOLUTION_FILTER;
break;
 
default:
flags |= FAST_PATH_NO_CONVOLUTION_FILTER;
break;
}
 
/* Repeat mode */
switch (image->common.repeat)
{
case PIXMAN_REPEAT_NONE:
flags |=
FAST_PATH_NO_REFLECT_REPEAT |
FAST_PATH_NO_PAD_REPEAT |
FAST_PATH_NO_NORMAL_REPEAT;
break;
 
case PIXMAN_REPEAT_REFLECT:
flags |=
FAST_PATH_NO_PAD_REPEAT |
FAST_PATH_NO_NONE_REPEAT |
FAST_PATH_NO_NORMAL_REPEAT;
break;
 
case PIXMAN_REPEAT_PAD:
flags |=
FAST_PATH_NO_REFLECT_REPEAT |
FAST_PATH_NO_NONE_REPEAT |
FAST_PATH_NO_NORMAL_REPEAT;
break;
 
default:
flags |=
FAST_PATH_NO_REFLECT_REPEAT |
FAST_PATH_NO_PAD_REPEAT |
FAST_PATH_NO_NONE_REPEAT;
break;
}
 
/* Component alpha */
if (image->common.component_alpha)
flags |= FAST_PATH_COMPONENT_ALPHA;
else
flags |= FAST_PATH_UNIFIED_ALPHA;
 
flags |= (FAST_PATH_NO_ACCESSORS | FAST_PATH_NARROW_FORMAT);
 
/* Type specific checks */
switch (image->type)
{
case SOLID:
code = PIXMAN_solid;
 
if (image->solid.color.alpha == 0xffff)
flags |= FAST_PATH_IS_OPAQUE;
break;
 
case BITS:
if (image->bits.width == 1 &&
image->bits.height == 1 &&
image->common.repeat != PIXMAN_REPEAT_NONE)
{
code = PIXMAN_solid;
}
else
{
code = image->bits.format;
flags |= FAST_PATH_BITS_IMAGE;
}
 
if (!PIXMAN_FORMAT_A (image->bits.format) &&
PIXMAN_FORMAT_TYPE (image->bits.format) != PIXMAN_TYPE_GRAY &&
PIXMAN_FORMAT_TYPE (image->bits.format) != PIXMAN_TYPE_COLOR)
{
flags |= FAST_PATH_SAMPLES_OPAQUE;
 
if (image->common.repeat != PIXMAN_REPEAT_NONE)
flags |= FAST_PATH_IS_OPAQUE;
}
 
if (image->bits.read_func || image->bits.write_func)
flags &= ~FAST_PATH_NO_ACCESSORS;
 
if (PIXMAN_FORMAT_IS_WIDE (image->bits.format))
flags &= ~FAST_PATH_NARROW_FORMAT;
break;
 
case RADIAL:
code = PIXMAN_unknown;
 
/*
* As explained in pixman-radial-gradient.c, every point of
* the plane has a valid associated radius (and thus will be
* colored) if and only if a is negative (i.e. one of the two
* circles contains the other one).
*/
 
if (image->radial.a >= 0)
break;
 
/* Fall through */
 
case CONICAL:
case LINEAR:
code = PIXMAN_unknown;
 
if (image->common.repeat != PIXMAN_REPEAT_NONE)
{
int i;
 
flags |= FAST_PATH_IS_OPAQUE;
for (i = 0; i < image->gradient.n_stops; ++i)
{
if (image->gradient.stops[i].color.alpha != 0xffff)
{
flags &= ~FAST_PATH_IS_OPAQUE;
break;
}
}
}
break;
 
default:
code = PIXMAN_unknown;
break;
}
 
/* Alpha map */
if (!image->common.alpha_map)
{
flags |= FAST_PATH_NO_ALPHA_MAP;
}
else
{
if (PIXMAN_FORMAT_IS_WIDE (image->common.alpha_map->format))
flags &= ~FAST_PATH_NARROW_FORMAT;
}
 
/* Both alpha maps and convolution filters can introduce
* non-opaqueness in otherwise opaque images. Also
* an image with component alpha turned on is only opaque
* if all channels are opaque, so we simply turn it off
* unconditionally for those images.
*/
if (image->common.alpha_map ||
image->common.filter == PIXMAN_FILTER_CONVOLUTION ||
image->common.filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION ||
image->common.component_alpha)
{
flags &= ~(FAST_PATH_IS_OPAQUE | FAST_PATH_SAMPLES_OPAQUE);
}
 
image->common.flags = flags;
image->common.extended_format_code = code;
}
 
void
_pixman_image_validate (pixman_image_t *image)
{
if (image->common.dirty)
{
compute_image_info (image);
 
/* It is important that property_changed is
* called *after* compute_image_info() because
* property_changed() can make use of the flags
* to set up accessors etc.
*/
if (image->common.property_changed)
image->common.property_changed (image);
 
image->common.dirty = FALSE;
}
 
if (image->common.alpha_map)
_pixman_image_validate ((pixman_image_t *)image->common.alpha_map);
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_image_set_clip_region32 (pixman_image_t * image,
pixman_region32_t *region)
{
image_common_t *common = (image_common_t *)image;
pixman_bool_t result;
 
if (region)
{
if ((result = pixman_region32_copy (&common->clip_region, region)))
image->common.have_clip_region = TRUE;
}
else
{
_pixman_image_reset_clip_region (image);
 
result = TRUE;
}
 
image_property_changed (image);
 
return result;
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_image_set_clip_region (pixman_image_t * image,
pixman_region16_t *region)
{
image_common_t *common = (image_common_t *)image;
pixman_bool_t result;
 
if (region)
{
if ((result = pixman_region32_copy_from_region16 (&common->clip_region, region)))
image->common.have_clip_region = TRUE;
}
else
{
_pixman_image_reset_clip_region (image);
 
result = TRUE;
}
 
image_property_changed (image);
 
return result;
}
 
PIXMAN_EXPORT void
pixman_image_set_has_client_clip (pixman_image_t *image,
pixman_bool_t client_clip)
{
image->common.client_clip = client_clip;
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_image_set_transform (pixman_image_t * image,
const pixman_transform_t *transform)
{
static const pixman_transform_t id =
{
{ { pixman_fixed_1, 0, 0 },
{ 0, pixman_fixed_1, 0 },
{ 0, 0, pixman_fixed_1 } }
};
 
image_common_t *common = (image_common_t *)image;
pixman_bool_t result;
 
if (common->transform == transform)
return TRUE;
 
if (!transform || memcmp (&id, transform, sizeof (pixman_transform_t)) == 0)
{
free (common->transform);
common->transform = NULL;
result = TRUE;
 
goto out;
}
 
if (common->transform &&
memcmp (common->transform, transform, sizeof (pixman_transform_t)) == 0)
{
return TRUE;
}
 
if (common->transform == NULL)
common->transform = malloc (sizeof (pixman_transform_t));
 
if (common->transform == NULL)
{
result = FALSE;
 
goto out;
}
 
memcpy (common->transform, transform, sizeof(pixman_transform_t));
 
result = TRUE;
 
out:
image_property_changed (image);
 
return result;
}
 
PIXMAN_EXPORT void
pixman_image_set_repeat (pixman_image_t *image,
pixman_repeat_t repeat)
{
if (image->common.repeat == repeat)
return;
 
image->common.repeat = repeat;
 
image_property_changed (image);
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_image_set_filter (pixman_image_t * image,
pixman_filter_t filter,
const pixman_fixed_t *params,
int n_params)
{
image_common_t *common = (image_common_t *)image;
pixman_fixed_t *new_params;
 
if (params == common->filter_params && filter == common->filter)
return TRUE;
 
if (filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION)
{
int width = pixman_fixed_to_int (params[0]);
int height = pixman_fixed_to_int (params[1]);
int x_phase_bits = pixman_fixed_to_int (params[2]);
int y_phase_bits = pixman_fixed_to_int (params[3]);
int n_x_phases = (1 << x_phase_bits);
int n_y_phases = (1 << y_phase_bits);
 
return_val_if_fail (
n_params == 4 + n_x_phases * width + n_y_phases * height, FALSE);
}
new_params = NULL;
if (params)
{
new_params = pixman_malloc_ab (n_params, sizeof (pixman_fixed_t));
if (!new_params)
return FALSE;
 
memcpy (new_params,
params, n_params * sizeof (pixman_fixed_t));
}
 
common->filter = filter;
 
if (common->filter_params)
free (common->filter_params);
 
common->filter_params = new_params;
common->n_filter_params = n_params;
 
image_property_changed (image);
return TRUE;
}
 
PIXMAN_EXPORT void
pixman_image_set_source_clipping (pixman_image_t *image,
pixman_bool_t clip_sources)
{
if (image->common.clip_sources == clip_sources)
return;
 
image->common.clip_sources = clip_sources;
 
image_property_changed (image);
}
 
/* Unlike all the other property setters, this function does not
* copy the content of indexed. Doing this copying is simply
* way, way too expensive.
*/
PIXMAN_EXPORT void
pixman_image_set_indexed (pixman_image_t * image,
const pixman_indexed_t *indexed)
{
bits_image_t *bits = (bits_image_t *)image;
 
if (bits->indexed == indexed)
return;
 
bits->indexed = indexed;
 
image_property_changed (image);
}
 
PIXMAN_EXPORT void
pixman_image_set_alpha_map (pixman_image_t *image,
pixman_image_t *alpha_map,
int16_t x,
int16_t y)
{
image_common_t *common = (image_common_t *)image;
 
return_if_fail (!alpha_map || alpha_map->type == BITS);
 
if (alpha_map && common->alpha_count > 0)
{
/* If this image is being used as an alpha map itself,
* then you can't give it an alpha map of its own.
*/
return;
}
 
if (alpha_map && alpha_map->common.alpha_map)
{
/* If the image has an alpha map of its own,
* then it can't be used as an alpha map itself
*/
return;
}
 
if (common->alpha_map != (bits_image_t *)alpha_map)
{
if (common->alpha_map)
{
common->alpha_map->common.alpha_count--;
 
pixman_image_unref ((pixman_image_t *)common->alpha_map);
}
 
if (alpha_map)
{
common->alpha_map = (bits_image_t *)pixman_image_ref (alpha_map);
 
common->alpha_map->common.alpha_count++;
}
else
{
common->alpha_map = NULL;
}
}
 
common->alpha_origin_x = x;
common->alpha_origin_y = y;
 
image_property_changed (image);
}
 
PIXMAN_EXPORT void
pixman_image_set_component_alpha (pixman_image_t *image,
pixman_bool_t component_alpha)
{
if (image->common.component_alpha == component_alpha)
return;
 
image->common.component_alpha = component_alpha;
 
image_property_changed (image);
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_image_get_component_alpha (pixman_image_t *image)
{
return image->common.component_alpha;
}
 
PIXMAN_EXPORT void
pixman_image_set_accessors (pixman_image_t * image,
pixman_read_memory_func_t read_func,
pixman_write_memory_func_t write_func)
{
return_if_fail (image != NULL);
 
if (image->type == BITS)
{
image->bits.read_func = read_func;
image->bits.write_func = write_func;
 
image_property_changed (image);
}
}
 
PIXMAN_EXPORT uint32_t *
pixman_image_get_data (pixman_image_t *image)
{
if (image->type == BITS)
return image->bits.bits;
 
return NULL;
}
 
PIXMAN_EXPORT int
pixman_image_get_width (pixman_image_t *image)
{
if (image->type == BITS)
return image->bits.width;
 
return 0;
}
 
PIXMAN_EXPORT int
pixman_image_get_height (pixman_image_t *image)
{
if (image->type == BITS)
return image->bits.height;
 
return 0;
}
 
PIXMAN_EXPORT int
pixman_image_get_stride (pixman_image_t *image)
{
if (image->type == BITS)
return image->bits.rowstride * (int) sizeof (uint32_t);
 
return 0;
}
 
PIXMAN_EXPORT int
pixman_image_get_depth (pixman_image_t *image)
{
if (image->type == BITS)
return PIXMAN_FORMAT_DEPTH (image->bits.format);
 
return 0;
}
 
PIXMAN_EXPORT pixman_format_code_t
pixman_image_get_format (pixman_image_t *image)
{
if (image->type == BITS)
return image->bits.format;
 
return PIXMAN_null;
}
 
uint32_t
_pixman_image_get_solid (pixman_implementation_t *imp,
pixman_image_t * image,
pixman_format_code_t format)
{
uint32_t result;
 
if (image->type == SOLID)
{
result = image->solid.color_32;
}
else if (image->type == BITS)
{
if (image->bits.format == PIXMAN_a8r8g8b8)
result = image->bits.bits[0];
else if (image->bits.format == PIXMAN_x8r8g8b8)
result = image->bits.bits[0] | 0xff000000;
else if (image->bits.format == PIXMAN_a8)
result = (*(uint8_t *)image->bits.bits) << 24;
else
goto otherwise;
}
else
{
pixman_iter_t iter;
 
otherwise:
_pixman_implementation_src_iter_init (
imp, &iter, image, 0, 0, 1, 1,
(uint8_t *)&result,
ITER_NARROW, image->common.flags);
result = *iter.get_scanline (&iter, NULL);
}
 
/* If necessary, convert RGB <--> BGR. */
if (PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB
&& PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB_SRGB)
{
result = (((result & 0xff000000) >> 0) |
((result & 0x00ff0000) >> 16) |
((result & 0x0000ff00) >> 0) |
((result & 0x000000ff) << 16));
}
 
return result;
}
/contrib/sdk/sources/pixman/pixman-implementation.c
0,0 → 1,398
/*
* Copyright © 2009 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Red Hat not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. Red Hat makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include "pixman-private.h"
 
pixman_implementation_t *
_pixman_implementation_create (pixman_implementation_t *fallback,
const pixman_fast_path_t *fast_paths)
{
pixman_implementation_t *imp;
 
assert (fast_paths);
 
if ((imp = malloc (sizeof (pixman_implementation_t))))
{
pixman_implementation_t *d;
 
memset (imp, 0, sizeof *imp);
 
imp->fallback = fallback;
imp->fast_paths = fast_paths;
 
/* Make sure the whole fallback chain has the right toplevel */
for (d = imp; d != NULL; d = d->fallback)
d->toplevel = imp;
}
 
return imp;
}
 
#define N_CACHED_FAST_PATHS 8
 
typedef struct
{
struct
{
pixman_implementation_t * imp;
pixman_fast_path_t fast_path;
} cache [N_CACHED_FAST_PATHS];
} cache_t;
 
PIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache);
 
static void
dummy_composite_rect (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
}
 
void
_pixman_implementation_lookup_composite (pixman_implementation_t *toplevel,
pixman_op_t op,
pixman_format_code_t src_format,
uint32_t src_flags,
pixman_format_code_t mask_format,
uint32_t mask_flags,
pixman_format_code_t dest_format,
uint32_t dest_flags,
pixman_implementation_t **out_imp,
pixman_composite_func_t *out_func)
{
pixman_implementation_t *imp;
cache_t *cache;
int i;
 
/* Check cache for fast paths */
cache = PIXMAN_GET_THREAD_LOCAL (fast_path_cache);
 
for (i = 0; i < N_CACHED_FAST_PATHS; ++i)
{
const pixman_fast_path_t *info = &(cache->cache[i].fast_path);
 
/* Note that we check for equality here, not whether
* the cached fast path matches. This is to prevent
* us from selecting an overly general fast path
* when a more specific one would work.
*/
if (info->op == op &&
info->src_format == src_format &&
info->mask_format == mask_format &&
info->dest_format == dest_format &&
info->src_flags == src_flags &&
info->mask_flags == mask_flags &&
info->dest_flags == dest_flags &&
info->func)
{
*out_imp = cache->cache[i].imp;
*out_func = cache->cache[i].fast_path.func;
 
goto update_cache;
}
}
 
for (imp = toplevel; imp != NULL; imp = imp->fallback)
{
const pixman_fast_path_t *info = imp->fast_paths;
 
while (info->op != PIXMAN_OP_NONE)
{
if ((info->op == op || info->op == PIXMAN_OP_any) &&
/* Formats */
((info->src_format == src_format) ||
(info->src_format == PIXMAN_any)) &&
((info->mask_format == mask_format) ||
(info->mask_format == PIXMAN_any)) &&
((info->dest_format == dest_format) ||
(info->dest_format == PIXMAN_any)) &&
/* Flags */
(info->src_flags & src_flags) == info->src_flags &&
(info->mask_flags & mask_flags) == info->mask_flags &&
(info->dest_flags & dest_flags) == info->dest_flags)
{
*out_imp = imp;
*out_func = info->func;
 
/* Set i to the last spot in the cache so that the
* move-to-front code below will work
*/
i = N_CACHED_FAST_PATHS - 1;
 
goto update_cache;
}
 
++info;
}
}
 
/* We should never reach this point */
_pixman_log_error (
FUNC,
"No composite function found\n"
"\n"
"The most likely cause of this is that this system has issues with\n"
"thread local storage\n");
 
*out_imp = NULL;
*out_func = dummy_composite_rect;
return;
 
update_cache:
if (i)
{
while (i--)
cache->cache[i + 1] = cache->cache[i];
 
cache->cache[0].imp = *out_imp;
cache->cache[0].fast_path.op = op;
cache->cache[0].fast_path.src_format = src_format;
cache->cache[0].fast_path.src_flags = src_flags;
cache->cache[0].fast_path.mask_format = mask_format;
cache->cache[0].fast_path.mask_flags = mask_flags;
cache->cache[0].fast_path.dest_format = dest_format;
cache->cache[0].fast_path.dest_flags = dest_flags;
cache->cache[0].fast_path.func = *out_func;
}
}
 
static void
dummy_combine (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
}
 
pixman_combine_32_func_t
_pixman_implementation_lookup_combiner (pixman_implementation_t *imp,
pixman_op_t op,
pixman_bool_t component_alpha,
pixman_bool_t narrow)
{
while (imp)
{
pixman_combine_32_func_t f = NULL;
 
switch ((narrow << 1) | component_alpha)
{
case 0: /* not narrow, not component alpha */
f = (pixman_combine_32_func_t)imp->combine_float[op];
break;
 
case 1: /* not narrow, component_alpha */
f = (pixman_combine_32_func_t)imp->combine_float_ca[op];
break;
 
case 2: /* narrow, not component alpha */
f = imp->combine_32[op];
break;
 
case 3: /* narrow, component_alpha */
f = imp->combine_32_ca[op];
break;
}
 
if (f)
return f;
 
imp = imp->fallback;
}
 
/* We should never reach this point */
_pixman_log_error (FUNC, "No known combine function\n");
return dummy_combine;
}
 
pixman_bool_t
_pixman_implementation_blt (pixman_implementation_t * imp,
uint32_t * src_bits,
uint32_t * dst_bits,
int src_stride,
int dst_stride,
int src_bpp,
int dst_bpp,
int src_x,
int src_y,
int dest_x,
int dest_y,
int width,
int height)
{
while (imp)
{
if (imp->blt &&
(*imp->blt) (imp, src_bits, dst_bits, src_stride, dst_stride,
src_bpp, dst_bpp, src_x, src_y, dest_x, dest_y,
width, height))
{
return TRUE;
}
 
imp = imp->fallback;
}
 
return FALSE;
}
 
pixman_bool_t
_pixman_implementation_fill (pixman_implementation_t *imp,
uint32_t * bits,
int stride,
int bpp,
int x,
int y,
int width,
int height,
uint32_t filler)
{
while (imp)
{
if (imp->fill &&
((*imp->fill) (imp, bits, stride, bpp, x, y, width, height, filler)))
{
return TRUE;
}
 
imp = imp->fallback;
}
 
return FALSE;
}
 
pixman_bool_t
_pixman_implementation_src_iter_init (pixman_implementation_t *imp,
pixman_iter_t *iter,
pixman_image_t *image,
int x,
int y,
int width,
int height,
uint8_t *buffer,
iter_flags_t iter_flags,
uint32_t image_flags)
{
iter->image = image;
iter->buffer = (uint32_t *)buffer;
iter->x = x;
iter->y = y;
iter->width = width;
iter->height = height;
iter->iter_flags = iter_flags;
iter->image_flags = image_flags;
 
while (imp)
{
if (imp->src_iter_init && (*imp->src_iter_init) (imp, iter))
return TRUE;
 
imp = imp->fallback;
}
 
return FALSE;
}
 
pixman_bool_t
_pixman_implementation_dest_iter_init (pixman_implementation_t *imp,
pixman_iter_t *iter,
pixman_image_t *image,
int x,
int y,
int width,
int height,
uint8_t *buffer,
iter_flags_t iter_flags,
uint32_t image_flags)
{
iter->image = image;
iter->buffer = (uint32_t *)buffer;
iter->x = x;
iter->y = y;
iter->width = width;
iter->height = height;
iter->iter_flags = iter_flags;
iter->image_flags = image_flags;
 
while (imp)
{
if (imp->dest_iter_init && (*imp->dest_iter_init) (imp, iter))
return TRUE;
 
imp = imp->fallback;
}
 
return FALSE;
}
 
pixman_bool_t
_pixman_disabled (const char *name)
{
const char *env;
 
if ((env = getenv ("PIXMAN_DISABLE")))
{
do
{
const char *end;
int len;
 
if ((end = strchr (env, ' ')))
len = end - env;
else
len = strlen (env);
 
if (strlen (name) == len && strncmp (name, env, len) == 0)
{
printf ("pixman: Disabled %s implementation\n", name);
return TRUE;
}
 
env += len;
}
while (*env++);
}
 
return FALSE;
}
 
pixman_implementation_t *
_pixman_choose_implementation (void)
{
pixman_implementation_t *imp;
 
imp = _pixman_implementation_create_general();
 
if (!_pixman_disabled ("fast"))
imp = _pixman_implementation_create_fast_path (imp);
 
imp = _pixman_x86_get_implementations (imp);
 
imp = _pixman_implementation_create_noop (imp);
 
return imp;
}
/contrib/sdk/sources/pixman/pixman-inlines.h
0,0 → 1,1339
/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Keith Packard, SuSE, Inc.
*/
 
#ifndef PIXMAN_FAST_PATH_H__
#define PIXMAN_FAST_PATH_H__
 
#include "pixman-private.h"
 
#define PIXMAN_REPEAT_COVER -1
 
/* Flags describing input parameters to fast path macro template.
* Turning on some flag values may indicate that
* "some property X is available so template can use this" or
* "some property X should be handled by template".
*
* FLAG_HAVE_SOLID_MASK
* Input mask is solid so template should handle this.
*
* FLAG_HAVE_NON_SOLID_MASK
* Input mask is bits mask so template should handle this.
*
* FLAG_HAVE_SOLID_MASK and FLAG_HAVE_NON_SOLID_MASK are mutually
* exclusive. (It's not allowed to turn both flags on)
*/
#define FLAG_NONE (0)
#define FLAG_HAVE_SOLID_MASK (1 << 1)
#define FLAG_HAVE_NON_SOLID_MASK (1 << 2)
 
/* To avoid too short repeated scanline function calls, extend source
* scanlines having width less than below constant value.
*/
#define REPEAT_NORMAL_MIN_WIDTH 64
 
static force_inline pixman_bool_t
repeat (pixman_repeat_t repeat, int *c, int size)
{
if (repeat == PIXMAN_REPEAT_NONE)
{
if (*c < 0 || *c >= size)
return FALSE;
}
else if (repeat == PIXMAN_REPEAT_NORMAL)
{
while (*c >= size)
*c -= size;
while (*c < 0)
*c += size;
}
else if (repeat == PIXMAN_REPEAT_PAD)
{
*c = CLIP (*c, 0, size - 1);
}
else /* REFLECT */
{
*c = MOD (*c, size * 2);
if (*c >= size)
*c = size * 2 - *c - 1;
}
return TRUE;
}
 
static force_inline int
pixman_fixed_to_bilinear_weight (pixman_fixed_t x)
{
return (x >> (16 - BILINEAR_INTERPOLATION_BITS)) &
((1 << BILINEAR_INTERPOLATION_BITS) - 1);
}
 
#if BILINEAR_INTERPOLATION_BITS <= 4
/* Inspired by Filter_32_opaque from Skia */
static force_inline uint32_t
bilinear_interpolation (uint32_t tl, uint32_t tr,
uint32_t bl, uint32_t br,
int distx, int disty)
{
int distxy, distxiy, distixy, distixiy;
uint32_t lo, hi;
 
distx <<= (4 - BILINEAR_INTERPOLATION_BITS);
disty <<= (4 - BILINEAR_INTERPOLATION_BITS);
 
distxy = distx * disty;
distxiy = (distx << 4) - distxy; /* distx * (16 - disty) */
distixy = (disty << 4) - distxy; /* disty * (16 - distx) */
distixiy =
16 * 16 - (disty << 4) -
(distx << 4) + distxy; /* (16 - distx) * (16 - disty) */
 
lo = (tl & 0xff00ff) * distixiy;
hi = ((tl >> 8) & 0xff00ff) * distixiy;
 
lo += (tr & 0xff00ff) * distxiy;
hi += ((tr >> 8) & 0xff00ff) * distxiy;
 
lo += (bl & 0xff00ff) * distixy;
hi += ((bl >> 8) & 0xff00ff) * distixy;
 
lo += (br & 0xff00ff) * distxy;
hi += ((br >> 8) & 0xff00ff) * distxy;
 
return ((lo >> 8) & 0xff00ff) | (hi & ~0xff00ff);
}
 
#else
#if SIZEOF_LONG > 4
 
static force_inline uint32_t
bilinear_interpolation (uint32_t tl, uint32_t tr,
uint32_t bl, uint32_t br,
int distx, int disty)
{
uint64_t distxy, distxiy, distixy, distixiy;
uint64_t tl64, tr64, bl64, br64;
uint64_t f, r;
 
distx <<= (8 - BILINEAR_INTERPOLATION_BITS);
disty <<= (8 - BILINEAR_INTERPOLATION_BITS);
 
distxy = distx * disty;
distxiy = distx * (256 - disty);
distixy = (256 - distx) * disty;
distixiy = (256 - distx) * (256 - disty);
 
/* Alpha and Blue */
tl64 = tl & 0xff0000ff;
tr64 = tr & 0xff0000ff;
bl64 = bl & 0xff0000ff;
br64 = br & 0xff0000ff;
 
f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy;
r = f & 0x0000ff0000ff0000ull;
 
/* Red and Green */
tl64 = tl;
tl64 = ((tl64 << 16) & 0x000000ff00000000ull) | (tl64 & 0x0000ff00ull);
 
tr64 = tr;
tr64 = ((tr64 << 16) & 0x000000ff00000000ull) | (tr64 & 0x0000ff00ull);
 
bl64 = bl;
bl64 = ((bl64 << 16) & 0x000000ff00000000ull) | (bl64 & 0x0000ff00ull);
 
br64 = br;
br64 = ((br64 << 16) & 0x000000ff00000000ull) | (br64 & 0x0000ff00ull);
 
f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy;
r |= ((f >> 16) & 0x000000ff00000000ull) | (f & 0xff000000ull);
 
return (uint32_t)(r >> 16);
}
 
#else
 
static force_inline uint32_t
bilinear_interpolation (uint32_t tl, uint32_t tr,
uint32_t bl, uint32_t br,
int distx, int disty)
{
int distxy, distxiy, distixy, distixiy;
uint32_t f, r;
 
distx <<= (8 - BILINEAR_INTERPOLATION_BITS);
disty <<= (8 - BILINEAR_INTERPOLATION_BITS);
 
distxy = distx * disty;
distxiy = (distx << 8) - distxy; /* distx * (256 - disty) */
distixy = (disty << 8) - distxy; /* disty * (256 - distx) */
distixiy =
256 * 256 - (disty << 8) -
(distx << 8) + distxy; /* (256 - distx) * (256 - disty) */
 
/* Blue */
r = (tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy
+ (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy;
 
/* Green */
f = (tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
+ (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy;
r |= f & 0xff000000;
 
tl >>= 16;
tr >>= 16;
bl >>= 16;
br >>= 16;
r >>= 16;
 
/* Red */
f = (tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy
+ (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy;
r |= f & 0x00ff0000;
 
/* Alpha */
f = (tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
+ (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy;
r |= f & 0xff000000;
 
return r;
}
 
#endif
#endif // BILINEAR_INTERPOLATION_BITS <= 4
 
/*
* For each scanline fetched from source image with PAD repeat:
* - calculate how many pixels need to be padded on the left side
* - calculate how many pixels need to be padded on the right side
* - update width to only count pixels which are fetched from the image
* All this information is returned via 'width', 'left_pad', 'right_pad'
* arguments. The code is assuming that 'unit_x' is positive.
*
* Note: 64-bit math is used in order to avoid potential overflows, which
* is probably excessive in many cases. This particular function
* may need its own correctness test and performance tuning.
*/
static force_inline void
pad_repeat_get_scanline_bounds (int32_t source_image_width,
pixman_fixed_t vx,
pixman_fixed_t unit_x,
int32_t * width,
int32_t * left_pad,
int32_t * right_pad)
{
int64_t max_vx = (int64_t) source_image_width << 16;
int64_t tmp;
if (vx < 0)
{
tmp = ((int64_t) unit_x - 1 - vx) / unit_x;
if (tmp > *width)
{
*left_pad = *width;
*width = 0;
}
else
{
*left_pad = (int32_t) tmp;
*width -= (int32_t) tmp;
}
}
else
{
*left_pad = 0;
}
tmp = ((int64_t) unit_x - 1 - vx + max_vx) / unit_x - *left_pad;
if (tmp < 0)
{
*right_pad = *width;
*width = 0;
}
else if (tmp >= *width)
{
*right_pad = 0;
}
else
{
*right_pad = *width - (int32_t) tmp;
*width = (int32_t) tmp;
}
}
 
/* A macroified version of specialized nearest scalers for some
* common 8888 and 565 formats. It supports SRC and OVER ops.
*
* There are two repeat versions, one that handles repeat normal,
* and one without repeat handling that only works if the src region
* used is completely covered by the pre-repeated source samples.
*
* The loops are unrolled to process two pixels per iteration for better
* performance on most CPU architectures (superscalar processors
* can issue several operations simultaneously, other processors can hide
* instructions latencies by pipelining operations). Unrolling more
* does not make much sense because the compiler will start running out
* of spare registers soon.
*/
 
#define GET_8888_ALPHA(s) ((s) >> 24)
/* This is not actually used since we don't have an OVER with
565 source, but it is needed to build. */
#define GET_0565_ALPHA(s) 0xff
#define GET_x888_ALPHA(s) 0xff
 
#define FAST_NEAREST_SCANLINE(scanline_func_name, SRC_FORMAT, DST_FORMAT, \
src_type_t, dst_type_t, OP, repeat_mode) \
static force_inline void \
scanline_func_name (dst_type_t *dst, \
const src_type_t *src, \
int32_t w, \
pixman_fixed_t vx, \
pixman_fixed_t unit_x, \
pixman_fixed_t src_width_fixed, \
pixman_bool_t fully_transparent_src) \
{ \
uint32_t d; \
src_type_t s1, s2; \
uint8_t a1, a2; \
int x1, x2; \
\
if (PIXMAN_OP_ ## OP == PIXMAN_OP_OVER && fully_transparent_src) \
return; \
\
if (PIXMAN_OP_ ## OP != PIXMAN_OP_SRC && PIXMAN_OP_ ## OP != PIXMAN_OP_OVER) \
abort(); \
\
while ((w -= 2) >= 0) \
{ \
x1 = pixman_fixed_to_int (vx); \
vx += unit_x; \
if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
{ \
/* This works because we know that unit_x is positive */ \
while (vx >= 0) \
vx -= src_width_fixed; \
} \
s1 = *(src + x1); \
\
x2 = pixman_fixed_to_int (vx); \
vx += unit_x; \
if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
{ \
/* This works because we know that unit_x is positive */ \
while (vx >= 0) \
vx -= src_width_fixed; \
} \
s2 = *(src + x2); \
\
if (PIXMAN_OP_ ## OP == PIXMAN_OP_OVER) \
{ \
a1 = GET_ ## SRC_FORMAT ## _ALPHA(s1); \
a2 = GET_ ## SRC_FORMAT ## _ALPHA(s2); \
\
if (a1 == 0xff) \
{ \
*dst = convert_ ## SRC_FORMAT ## _to_ ## DST_FORMAT (s1); \
} \
else if (s1) \
{ \
d = convert_ ## DST_FORMAT ## _to_8888 (*dst); \
s1 = convert_ ## SRC_FORMAT ## _to_8888 (s1); \
a1 ^= 0xff; \
UN8x4_MUL_UN8_ADD_UN8x4 (d, a1, s1); \
*dst = convert_8888_to_ ## DST_FORMAT (d); \
} \
dst++; \
\
if (a2 == 0xff) \
{ \
*dst = convert_ ## SRC_FORMAT ## _to_ ## DST_FORMAT (s2); \
} \
else if (s2) \
{ \
d = convert_## DST_FORMAT ## _to_8888 (*dst); \
s2 = convert_## SRC_FORMAT ## _to_8888 (s2); \
a2 ^= 0xff; \
UN8x4_MUL_UN8_ADD_UN8x4 (d, a2, s2); \
*dst = convert_8888_to_ ## DST_FORMAT (d); \
} \
dst++; \
} \
else /* PIXMAN_OP_SRC */ \
{ \
*dst++ = convert_ ## SRC_FORMAT ## _to_ ## DST_FORMAT (s1); \
*dst++ = convert_ ## SRC_FORMAT ## _to_ ## DST_FORMAT (s2); \
} \
} \
\
if (w & 1) \
{ \
x1 = pixman_fixed_to_int (vx); \
s1 = *(src + x1); \
\
if (PIXMAN_OP_ ## OP == PIXMAN_OP_OVER) \
{ \
a1 = GET_ ## SRC_FORMAT ## _ALPHA(s1); \
\
if (a1 == 0xff) \
{ \
*dst = convert_ ## SRC_FORMAT ## _to_ ## DST_FORMAT (s1); \
} \
else if (s1) \
{ \
d = convert_## DST_FORMAT ## _to_8888 (*dst); \
s1 = convert_ ## SRC_FORMAT ## _to_8888 (s1); \
a1 ^= 0xff; \
UN8x4_MUL_UN8_ADD_UN8x4 (d, a1, s1); \
*dst = convert_8888_to_ ## DST_FORMAT (d); \
} \
dst++; \
} \
else /* PIXMAN_OP_SRC */ \
{ \
*dst++ = convert_ ## SRC_FORMAT ## _to_ ## DST_FORMAT (s1); \
} \
} \
}
 
#define FAST_NEAREST_MAINLOOP_INT(scale_func_name, scanline_func, src_type_t, mask_type_t, \
dst_type_t, repeat_mode, have_mask, mask_is_solid) \
static void \
fast_composite_scaled_nearest ## scale_func_name (pixman_implementation_t *imp, \
pixman_composite_info_t *info) \
{ \
PIXMAN_COMPOSITE_ARGS (info); \
dst_type_t *dst_line; \
mask_type_t *mask_line; \
src_type_t *src_first_line; \
int y; \
pixman_fixed_t src_width_fixed = pixman_int_to_fixed (src_image->bits.width); \
pixman_fixed_t max_vy; \
pixman_vector_t v; \
pixman_fixed_t vx, vy; \
pixman_fixed_t unit_x, unit_y; \
int32_t left_pad, right_pad; \
\
src_type_t *src; \
dst_type_t *dst; \
mask_type_t solid_mask; \
const mask_type_t *mask = &solid_mask; \
int src_stride, mask_stride, dst_stride; \
\
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, dst_type_t, dst_stride, dst_line, 1); \
if (have_mask) \
{ \
if (mask_is_solid) \
solid_mask = _pixman_image_get_solid (imp, mask_image, dest_image->bits.format); \
else \
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, mask_type_t, \
mask_stride, mask_line, 1); \
} \
/* pass in 0 instead of src_x and src_y because src_x and src_y need to be \
* transformed from destination space to source space */ \
PIXMAN_IMAGE_GET_LINE (src_image, 0, 0, src_type_t, src_stride, src_first_line, 1); \
\
/* reference point is the center of the pixel */ \
v.vector[0] = pixman_int_to_fixed (src_x) + pixman_fixed_1 / 2; \
v.vector[1] = pixman_int_to_fixed (src_y) + pixman_fixed_1 / 2; \
v.vector[2] = pixman_fixed_1; \
\
if (!pixman_transform_point_3d (src_image->common.transform, &v)) \
return; \
\
unit_x = src_image->common.transform->matrix[0][0]; \
unit_y = src_image->common.transform->matrix[1][1]; \
\
/* Round down to closest integer, ensuring that 0.5 rounds to 0, not 1 */ \
v.vector[0] -= pixman_fixed_e; \
v.vector[1] -= pixman_fixed_e; \
\
vx = v.vector[0]; \
vy = v.vector[1]; \
\
if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
{ \
max_vy = pixman_int_to_fixed (src_image->bits.height); \
\
/* Clamp repeating positions inside the actual samples */ \
repeat (PIXMAN_REPEAT_NORMAL, &vx, src_width_fixed); \
repeat (PIXMAN_REPEAT_NORMAL, &vy, max_vy); \
} \
\
if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD || \
PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \
{ \
pad_repeat_get_scanline_bounds (src_image->bits.width, vx, unit_x, \
&width, &left_pad, &right_pad); \
vx += left_pad * unit_x; \
} \
\
while (--height >= 0) \
{ \
dst = dst_line; \
dst_line += dst_stride; \
if (have_mask && !mask_is_solid) \
{ \
mask = mask_line; \
mask_line += mask_stride; \
} \
\
y = pixman_fixed_to_int (vy); \
vy += unit_y; \
if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
repeat (PIXMAN_REPEAT_NORMAL, &vy, max_vy); \
if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD) \
{ \
repeat (PIXMAN_REPEAT_PAD, &y, src_image->bits.height); \
src = src_first_line + src_stride * y; \
if (left_pad > 0) \
{ \
scanline_func (mask, dst, \
src + src_image->bits.width - src_image->bits.width + 1, \
left_pad, -pixman_fixed_e, 0, src_width_fixed, FALSE); \
} \
if (width > 0) \
{ \
scanline_func (mask + (mask_is_solid ? 0 : left_pad), \
dst + left_pad, src + src_image->bits.width, width, \
vx - src_width_fixed, unit_x, src_width_fixed, FALSE); \
} \
if (right_pad > 0) \
{ \
scanline_func (mask + (mask_is_solid ? 0 : left_pad + width), \
dst + left_pad + width, src + src_image->bits.width, \
right_pad, -pixman_fixed_e, 0, src_width_fixed, FALSE); \
} \
} \
else if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \
{ \
static const src_type_t zero[1] = { 0 }; \
if (y < 0 || y >= src_image->bits.height) \
{ \
scanline_func (mask, dst, zero + 1, left_pad + width + right_pad, \
-pixman_fixed_e, 0, src_width_fixed, TRUE); \
continue; \
} \
src = src_first_line + src_stride * y; \
if (left_pad > 0) \
{ \
scanline_func (mask, dst, zero + 1, left_pad, \
-pixman_fixed_e, 0, src_width_fixed, TRUE); \
} \
if (width > 0) \
{ \
scanline_func (mask + (mask_is_solid ? 0 : left_pad), \
dst + left_pad, src + src_image->bits.width, width, \
vx - src_width_fixed, unit_x, src_width_fixed, FALSE); \
} \
if (right_pad > 0) \
{ \
scanline_func (mask + (mask_is_solid ? 0 : left_pad + width), \
dst + left_pad + width, zero + 1, right_pad, \
-pixman_fixed_e, 0, src_width_fixed, TRUE); \
} \
} \
else \
{ \
src = src_first_line + src_stride * y; \
scanline_func (mask, dst, src + src_image->bits.width, width, vx - src_width_fixed, \
unit_x, src_width_fixed, FALSE); \
} \
} \
}
 
/* A workaround for old sun studio, see: https://bugs.freedesktop.org/show_bug.cgi?id=32764 */
#define FAST_NEAREST_MAINLOOP_COMMON(scale_func_name, scanline_func, src_type_t, mask_type_t, \
dst_type_t, repeat_mode, have_mask, mask_is_solid) \
FAST_NEAREST_MAINLOOP_INT(_ ## scale_func_name, scanline_func, src_type_t, mask_type_t, \
dst_type_t, repeat_mode, have_mask, mask_is_solid)
 
#define FAST_NEAREST_MAINLOOP_NOMASK(scale_func_name, scanline_func, src_type_t, dst_type_t, \
repeat_mode) \
static force_inline void \
scanline_func##scale_func_name##_wrapper ( \
const uint8_t *mask, \
dst_type_t *dst, \
const src_type_t *src, \
int32_t w, \
pixman_fixed_t vx, \
pixman_fixed_t unit_x, \
pixman_fixed_t max_vx, \
pixman_bool_t fully_transparent_src) \
{ \
scanline_func (dst, src, w, vx, unit_x, max_vx, fully_transparent_src); \
} \
FAST_NEAREST_MAINLOOP_INT (scale_func_name, scanline_func##scale_func_name##_wrapper, \
src_type_t, uint8_t, dst_type_t, repeat_mode, FALSE, FALSE)
 
#define FAST_NEAREST_MAINLOOP(scale_func_name, scanline_func, src_type_t, dst_type_t, \
repeat_mode) \
FAST_NEAREST_MAINLOOP_NOMASK(_ ## scale_func_name, scanline_func, src_type_t, \
dst_type_t, repeat_mode)
 
#define FAST_NEAREST(scale_func_name, SRC_FORMAT, DST_FORMAT, \
src_type_t, dst_type_t, OP, repeat_mode) \
FAST_NEAREST_SCANLINE(scaled_nearest_scanline_ ## scale_func_name ## _ ## OP, \
SRC_FORMAT, DST_FORMAT, src_type_t, dst_type_t, \
OP, repeat_mode) \
FAST_NEAREST_MAINLOOP_NOMASK(_ ## scale_func_name ## _ ## OP, \
scaled_nearest_scanline_ ## scale_func_name ## _ ## OP, \
src_type_t, dst_type_t, repeat_mode)
 
 
#define SCALED_NEAREST_FLAGS \
(FAST_PATH_SCALE_TRANSFORM | \
FAST_PATH_NO_ALPHA_MAP | \
FAST_PATH_NEAREST_FILTER | \
FAST_PATH_NO_ACCESSORS | \
FAST_PATH_NARROW_FORMAT)
 
#define SIMPLE_NEAREST_FAST_PATH_NORMAL(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_NEAREST_FLAGS | \
FAST_PATH_NORMAL_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_null, 0, \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_nearest_ ## func ## _normal ## _ ## op, \
}
 
#define SIMPLE_NEAREST_FAST_PATH_PAD(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_NEAREST_FLAGS | \
FAST_PATH_PAD_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_null, 0, \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_nearest_ ## func ## _pad ## _ ## op, \
}
 
#define SIMPLE_NEAREST_FAST_PATH_NONE(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_NEAREST_FLAGS | \
FAST_PATH_NONE_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_null, 0, \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_nearest_ ## func ## _none ## _ ## op, \
}
 
#define SIMPLE_NEAREST_FAST_PATH_COVER(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST, \
PIXMAN_null, 0, \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_nearest_ ## func ## _cover ## _ ## op, \
}
 
#define SIMPLE_NEAREST_A8_MASK_FAST_PATH_NORMAL(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_NEAREST_FLAGS | \
FAST_PATH_NORMAL_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_nearest_ ## func ## _normal ## _ ## op, \
}
 
#define SIMPLE_NEAREST_A8_MASK_FAST_PATH_PAD(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_NEAREST_FLAGS | \
FAST_PATH_PAD_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_nearest_ ## func ## _pad ## _ ## op, \
}
 
#define SIMPLE_NEAREST_A8_MASK_FAST_PATH_NONE(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_NEAREST_FLAGS | \
FAST_PATH_NONE_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_nearest_ ## func ## _none ## _ ## op, \
}
 
#define SIMPLE_NEAREST_A8_MASK_FAST_PATH_COVER(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST, \
PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_nearest_ ## func ## _cover ## _ ## op, \
}
 
#define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NORMAL(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_NEAREST_FLAGS | \
FAST_PATH_NORMAL_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_nearest_ ## func ## _normal ## _ ## op, \
}
 
#define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_PAD(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_NEAREST_FLAGS | \
FAST_PATH_PAD_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_nearest_ ## func ## _pad ## _ ## op, \
}
 
#define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NONE(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_NEAREST_FLAGS | \
FAST_PATH_NONE_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_nearest_ ## func ## _none ## _ ## op, \
}
 
#define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_COVER(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST, \
PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_nearest_ ## func ## _cover ## _ ## op, \
}
 
/* Prefer the use of 'cover' variant, because it is faster */
#define SIMPLE_NEAREST_FAST_PATH(op,s,d,func) \
SIMPLE_NEAREST_FAST_PATH_COVER (op,s,d,func), \
SIMPLE_NEAREST_FAST_PATH_NONE (op,s,d,func), \
SIMPLE_NEAREST_FAST_PATH_PAD (op,s,d,func), \
SIMPLE_NEAREST_FAST_PATH_NORMAL (op,s,d,func)
 
#define SIMPLE_NEAREST_A8_MASK_FAST_PATH(op,s,d,func) \
SIMPLE_NEAREST_A8_MASK_FAST_PATH_COVER (op,s,d,func), \
SIMPLE_NEAREST_A8_MASK_FAST_PATH_NONE (op,s,d,func), \
SIMPLE_NEAREST_A8_MASK_FAST_PATH_PAD (op,s,d,func)
 
#define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH(op,s,d,func) \
SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_COVER (op,s,d,func), \
SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NONE (op,s,d,func), \
SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_PAD (op,s,d,func)
 
/*****************************************************************************/
 
/*
* Identify 5 zones in each scanline for bilinear scaling. Depending on
* whether 2 pixels to be interpolated are fetched from the image itself,
* from the padding area around it or from both image and padding area.
*/
static force_inline void
bilinear_pad_repeat_get_scanline_bounds (int32_t source_image_width,
pixman_fixed_t vx,
pixman_fixed_t unit_x,
int32_t * left_pad,
int32_t * left_tz,
int32_t * width,
int32_t * right_tz,
int32_t * right_pad)
{
int width1 = *width, left_pad1, right_pad1;
int width2 = *width, left_pad2, right_pad2;
 
pad_repeat_get_scanline_bounds (source_image_width, vx, unit_x,
&width1, &left_pad1, &right_pad1);
pad_repeat_get_scanline_bounds (source_image_width, vx + pixman_fixed_1,
unit_x, &width2, &left_pad2, &right_pad2);
 
*left_pad = left_pad2;
*left_tz = left_pad1 - left_pad2;
*right_tz = right_pad2 - right_pad1;
*right_pad = right_pad1;
*width -= *left_pad + *left_tz + *right_tz + *right_pad;
}
 
/*
* Main loop template for single pass bilinear scaling. It needs to be
* provided with 'scanline_func' which should do the compositing operation.
* The needed function has the following prototype:
*
* scanline_func (dst_type_t * dst,
* const mask_type_ * mask,
* const src_type_t * src_top,
* const src_type_t * src_bottom,
* int32_t width,
* int weight_top,
* int weight_bottom,
* pixman_fixed_t vx,
* pixman_fixed_t unit_x,
* pixman_fixed_t max_vx,
* pixman_bool_t zero_src)
*
* Where:
* dst - destination scanline buffer for storing results
* mask - mask buffer (or single value for solid mask)
* src_top, src_bottom - two source scanlines
* width - number of pixels to process
* weight_top - weight of the top row for interpolation
* weight_bottom - weight of the bottom row for interpolation
* vx - initial position for fetching the first pair of
* pixels from the source buffer
* unit_x - position increment needed to move to the next pair
* of pixels
* max_vx - image size as a fixed point value, can be used for
* implementing NORMAL repeat (when it is supported)
* zero_src - boolean hint variable, which is set to TRUE when
* all source pixels are fetched from zero padding
* zone for NONE repeat
*
* Note: normally the sum of 'weight_top' and 'weight_bottom' is equal to
* BILINEAR_INTERPOLATION_RANGE, but sometimes it may be less than that
* for NONE repeat when handling fuzzy antialiased top or bottom image
* edges. Also both top and bottom weight variables are guaranteed to
* have value, which is less than BILINEAR_INTERPOLATION_RANGE.
* For example, the weights can fit into unsigned byte or be used
* with 8-bit SIMD multiplication instructions for 8-bit interpolation
* precision.
*/
#define FAST_BILINEAR_MAINLOOP_INT(scale_func_name, scanline_func, src_type_t, mask_type_t, \
dst_type_t, repeat_mode, flags) \
static void \
fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, \
pixman_composite_info_t *info) \
{ \
PIXMAN_COMPOSITE_ARGS (info); \
dst_type_t *dst_line; \
mask_type_t *mask_line; \
src_type_t *src_first_line; \
int y1, y2; \
pixman_fixed_t max_vx = INT32_MAX; /* suppress uninitialized variable warning */ \
pixman_vector_t v; \
pixman_fixed_t vx, vy; \
pixman_fixed_t unit_x, unit_y; \
int32_t left_pad, left_tz, right_tz, right_pad; \
\
dst_type_t *dst; \
mask_type_t solid_mask; \
const mask_type_t *mask = &solid_mask; \
int src_stride, mask_stride, dst_stride; \
\
int src_width; \
pixman_fixed_t src_width_fixed; \
int max_x; \
pixman_bool_t need_src_extension; \
\
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, dst_type_t, dst_stride, dst_line, 1); \
if (flags & FLAG_HAVE_SOLID_MASK) \
{ \
solid_mask = _pixman_image_get_solid (imp, mask_image, dest_image->bits.format); \
mask_stride = 0; \
} \
else if (flags & FLAG_HAVE_NON_SOLID_MASK) \
{ \
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, mask_type_t, \
mask_stride, mask_line, 1); \
} \
\
/* pass in 0 instead of src_x and src_y because src_x and src_y need to be \
* transformed from destination space to source space */ \
PIXMAN_IMAGE_GET_LINE (src_image, 0, 0, src_type_t, src_stride, src_first_line, 1); \
\
/* reference point is the center of the pixel */ \
v.vector[0] = pixman_int_to_fixed (src_x) + pixman_fixed_1 / 2; \
v.vector[1] = pixman_int_to_fixed (src_y) + pixman_fixed_1 / 2; \
v.vector[2] = pixman_fixed_1; \
\
if (!pixman_transform_point_3d (src_image->common.transform, &v)) \
return; \
\
unit_x = src_image->common.transform->matrix[0][0]; \
unit_y = src_image->common.transform->matrix[1][1]; \
\
v.vector[0] -= pixman_fixed_1 / 2; \
v.vector[1] -= pixman_fixed_1 / 2; \
\
vy = v.vector[1]; \
\
if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD || \
PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \
{ \
bilinear_pad_repeat_get_scanline_bounds (src_image->bits.width, v.vector[0], unit_x, \
&left_pad, &left_tz, &width, &right_tz, &right_pad); \
if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD) \
{ \
/* PAD repeat does not need special handling for 'transition zones' and */ \
/* they can be combined with 'padding zones' safely */ \
left_pad += left_tz; \
right_pad += right_tz; \
left_tz = right_tz = 0; \
} \
v.vector[0] += left_pad * unit_x; \
} \
\
if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
{ \
vx = v.vector[0]; \
repeat (PIXMAN_REPEAT_NORMAL, &vx, pixman_int_to_fixed(src_image->bits.width)); \
max_x = pixman_fixed_to_int (vx + (width - 1) * (int64_t)unit_x) + 1; \
\
if (src_image->bits.width < REPEAT_NORMAL_MIN_WIDTH) \
{ \
src_width = 0; \
\
while (src_width < REPEAT_NORMAL_MIN_WIDTH && src_width <= max_x) \
src_width += src_image->bits.width; \
\
need_src_extension = TRUE; \
} \
else \
{ \
src_width = src_image->bits.width; \
need_src_extension = FALSE; \
} \
\
src_width_fixed = pixman_int_to_fixed (src_width); \
} \
\
while (--height >= 0) \
{ \
int weight1, weight2; \
dst = dst_line; \
dst_line += dst_stride; \
vx = v.vector[0]; \
if (flags & FLAG_HAVE_NON_SOLID_MASK) \
{ \
mask = mask_line; \
mask_line += mask_stride; \
} \
\
y1 = pixman_fixed_to_int (vy); \
weight2 = pixman_fixed_to_bilinear_weight (vy); \
if (weight2) \
{ \
/* both weight1 and weight2 are smaller than BILINEAR_INTERPOLATION_RANGE */ \
y2 = y1 + 1; \
weight1 = BILINEAR_INTERPOLATION_RANGE - weight2; \
} \
else \
{ \
/* set both top and bottom row to the same scanline and tweak weights */ \
y2 = y1; \
weight1 = weight2 = BILINEAR_INTERPOLATION_RANGE / 2; \
} \
vy += unit_y; \
if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD) \
{ \
src_type_t *src1, *src2; \
src_type_t buf1[2]; \
src_type_t buf2[2]; \
repeat (PIXMAN_REPEAT_PAD, &y1, src_image->bits.height); \
repeat (PIXMAN_REPEAT_PAD, &y2, src_image->bits.height); \
src1 = src_first_line + src_stride * y1; \
src2 = src_first_line + src_stride * y2; \
\
if (left_pad > 0) \
{ \
buf1[0] = buf1[1] = src1[0]; \
buf2[0] = buf2[1] = src2[0]; \
scanline_func (dst, mask, \
buf1, buf2, left_pad, weight1, weight2, 0, 0, 0, FALSE); \
dst += left_pad; \
if (flags & FLAG_HAVE_NON_SOLID_MASK) \
mask += left_pad; \
} \
if (width > 0) \
{ \
scanline_func (dst, mask, \
src1, src2, width, weight1, weight2, vx, unit_x, 0, FALSE); \
dst += width; \
if (flags & FLAG_HAVE_NON_SOLID_MASK) \
mask += width; \
} \
if (right_pad > 0) \
{ \
buf1[0] = buf1[1] = src1[src_image->bits.width - 1]; \
buf2[0] = buf2[1] = src2[src_image->bits.width - 1]; \
scanline_func (dst, mask, \
buf1, buf2, right_pad, weight1, weight2, 0, 0, 0, FALSE); \
} \
} \
else if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \
{ \
src_type_t *src1, *src2; \
src_type_t buf1[2]; \
src_type_t buf2[2]; \
/* handle top/bottom zero padding by just setting weights to 0 if needed */ \
if (y1 < 0) \
{ \
weight1 = 0; \
y1 = 0; \
} \
if (y1 >= src_image->bits.height) \
{ \
weight1 = 0; \
y1 = src_image->bits.height - 1; \
} \
if (y2 < 0) \
{ \
weight2 = 0; \
y2 = 0; \
} \
if (y2 >= src_image->bits.height) \
{ \
weight2 = 0; \
y2 = src_image->bits.height - 1; \
} \
src1 = src_first_line + src_stride * y1; \
src2 = src_first_line + src_stride * y2; \
\
if (left_pad > 0) \
{ \
buf1[0] = buf1[1] = 0; \
buf2[0] = buf2[1] = 0; \
scanline_func (dst, mask, \
buf1, buf2, left_pad, weight1, weight2, 0, 0, 0, TRUE); \
dst += left_pad; \
if (flags & FLAG_HAVE_NON_SOLID_MASK) \
mask += left_pad; \
} \
if (left_tz > 0) \
{ \
buf1[0] = 0; \
buf1[1] = src1[0]; \
buf2[0] = 0; \
buf2[1] = src2[0]; \
scanline_func (dst, mask, \
buf1, buf2, left_tz, weight1, weight2, \
pixman_fixed_frac (vx), unit_x, 0, FALSE); \
dst += left_tz; \
if (flags & FLAG_HAVE_NON_SOLID_MASK) \
mask += left_tz; \
vx += left_tz * unit_x; \
} \
if (width > 0) \
{ \
scanline_func (dst, mask, \
src1, src2, width, weight1, weight2, vx, unit_x, 0, FALSE); \
dst += width; \
if (flags & FLAG_HAVE_NON_SOLID_MASK) \
mask += width; \
vx += width * unit_x; \
} \
if (right_tz > 0) \
{ \
buf1[0] = src1[src_image->bits.width - 1]; \
buf1[1] = 0; \
buf2[0] = src2[src_image->bits.width - 1]; \
buf2[1] = 0; \
scanline_func (dst, mask, \
buf1, buf2, right_tz, weight1, weight2, \
pixman_fixed_frac (vx), unit_x, 0, FALSE); \
dst += right_tz; \
if (flags & FLAG_HAVE_NON_SOLID_MASK) \
mask += right_tz; \
} \
if (right_pad > 0) \
{ \
buf1[0] = buf1[1] = 0; \
buf2[0] = buf2[1] = 0; \
scanline_func (dst, mask, \
buf1, buf2, right_pad, weight1, weight2, 0, 0, 0, TRUE); \
} \
} \
else if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
{ \
int32_t num_pixels; \
int32_t width_remain; \
src_type_t * src_line_top; \
src_type_t * src_line_bottom; \
src_type_t buf1[2]; \
src_type_t buf2[2]; \
src_type_t extended_src_line0[REPEAT_NORMAL_MIN_WIDTH*2]; \
src_type_t extended_src_line1[REPEAT_NORMAL_MIN_WIDTH*2]; \
int i, j; \
\
repeat (PIXMAN_REPEAT_NORMAL, &y1, src_image->bits.height); \
repeat (PIXMAN_REPEAT_NORMAL, &y2, src_image->bits.height); \
src_line_top = src_first_line + src_stride * y1; \
src_line_bottom = src_first_line + src_stride * y2; \
\
if (need_src_extension) \
{ \
for (i=0; i<src_width;) \
{ \
for (j=0; j<src_image->bits.width; j++, i++) \
{ \
extended_src_line0[i] = src_line_top[j]; \
extended_src_line1[i] = src_line_bottom[j]; \
} \
} \
\
src_line_top = &extended_src_line0[0]; \
src_line_bottom = &extended_src_line1[0]; \
} \
\
/* Top & Bottom wrap around buffer */ \
buf1[0] = src_line_top[src_width - 1]; \
buf1[1] = src_line_top[0]; \
buf2[0] = src_line_bottom[src_width - 1]; \
buf2[1] = src_line_bottom[0]; \
\
width_remain = width; \
\
while (width_remain > 0) \
{ \
/* We use src_width_fixed because it can make vx in original source range */ \
repeat (PIXMAN_REPEAT_NORMAL, &vx, src_width_fixed); \
\
/* Wrap around part */ \
if (pixman_fixed_to_int (vx) == src_width - 1) \
{ \
/* for positive unit_x \
* num_pixels = max(n) + 1, where vx + n*unit_x < src_width_fixed \
* \
* vx is in range [0, src_width_fixed - pixman_fixed_e] \
* So we are safe from overflow. \
*/ \
num_pixels = ((src_width_fixed - vx - pixman_fixed_e) / unit_x) + 1; \
\
if (num_pixels > width_remain) \
num_pixels = width_remain; \
\
scanline_func (dst, mask, buf1, buf2, num_pixels, \
weight1, weight2, pixman_fixed_frac(vx), \
unit_x, src_width_fixed, FALSE); \
\
width_remain -= num_pixels; \
vx += num_pixels * unit_x; \
dst += num_pixels; \
\
if (flags & FLAG_HAVE_NON_SOLID_MASK) \
mask += num_pixels; \
\
repeat (PIXMAN_REPEAT_NORMAL, &vx, src_width_fixed); \
} \
\
/* Normal scanline composite */ \
if (pixman_fixed_to_int (vx) != src_width - 1 && width_remain > 0) \
{ \
/* for positive unit_x \
* num_pixels = max(n) + 1, where vx + n*unit_x < (src_width_fixed - 1) \
* \
* vx is in range [0, src_width_fixed - pixman_fixed_e] \
* So we are safe from overflow here. \
*/ \
num_pixels = ((src_width_fixed - pixman_fixed_1 - vx - pixman_fixed_e) \
/ unit_x) + 1; \
\
if (num_pixels > width_remain) \
num_pixels = width_remain; \
\
scanline_func (dst, mask, src_line_top, src_line_bottom, num_pixels, \
weight1, weight2, vx, unit_x, src_width_fixed, FALSE); \
\
width_remain -= num_pixels; \
vx += num_pixels * unit_x; \
dst += num_pixels; \
\
if (flags & FLAG_HAVE_NON_SOLID_MASK) \
mask += num_pixels; \
} \
} \
} \
else \
{ \
scanline_func (dst, mask, src_first_line + src_stride * y1, \
src_first_line + src_stride * y2, width, \
weight1, weight2, vx, unit_x, max_vx, FALSE); \
} \
} \
}
 
/* A workaround for old sun studio, see: https://bugs.freedesktop.org/show_bug.cgi?id=32764 */
#define FAST_BILINEAR_MAINLOOP_COMMON(scale_func_name, scanline_func, src_type_t, mask_type_t, \
dst_type_t, repeat_mode, flags) \
FAST_BILINEAR_MAINLOOP_INT(_ ## scale_func_name, scanline_func, src_type_t, mask_type_t,\
dst_type_t, repeat_mode, flags)
 
#define SCALED_BILINEAR_FLAGS \
(FAST_PATH_SCALE_TRANSFORM | \
FAST_PATH_NO_ALPHA_MAP | \
FAST_PATH_BILINEAR_FILTER | \
FAST_PATH_NO_ACCESSORS | \
FAST_PATH_NARROW_FORMAT)
 
#define SIMPLE_BILINEAR_FAST_PATH_PAD(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_BILINEAR_FLAGS | \
FAST_PATH_PAD_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_null, 0, \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_bilinear_ ## func ## _pad ## _ ## op, \
}
 
#define SIMPLE_BILINEAR_FAST_PATH_NONE(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_BILINEAR_FLAGS | \
FAST_PATH_NONE_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_null, 0, \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_bilinear_ ## func ## _none ## _ ## op, \
}
 
#define SIMPLE_BILINEAR_FAST_PATH_COVER(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR, \
PIXMAN_null, 0, \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_bilinear_ ## func ## _cover ## _ ## op, \
}
 
#define SIMPLE_BILINEAR_FAST_PATH_NORMAL(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_BILINEAR_FLAGS | \
FAST_PATH_NORMAL_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_null, 0, \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_bilinear_ ## func ## _normal ## _ ## op, \
}
 
#define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_PAD(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_BILINEAR_FLAGS | \
FAST_PATH_PAD_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_bilinear_ ## func ## _pad ## _ ## op, \
}
 
#define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_NONE(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_BILINEAR_FLAGS | \
FAST_PATH_NONE_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_bilinear_ ## func ## _none ## _ ## op, \
}
 
#define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_COVER(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR, \
PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_bilinear_ ## func ## _cover ## _ ## op, \
}
 
#define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_NORMAL(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_BILINEAR_FLAGS | \
FAST_PATH_NORMAL_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_bilinear_ ## func ## _normal ## _ ## op, \
}
 
#define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_PAD(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_BILINEAR_FLAGS | \
FAST_PATH_PAD_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_bilinear_ ## func ## _pad ## _ ## op, \
}
 
#define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_NONE(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_BILINEAR_FLAGS | \
FAST_PATH_NONE_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_bilinear_ ## func ## _none ## _ ## op, \
}
 
#define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_COVER(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR, \
PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_bilinear_ ## func ## _cover ## _ ## op, \
}
 
#define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_NORMAL(op,s,d,func) \
{ PIXMAN_OP_ ## op, \
PIXMAN_ ## s, \
(SCALED_BILINEAR_FLAGS | \
FAST_PATH_NORMAL_REPEAT | \
FAST_PATH_X_UNIT_POSITIVE), \
PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
fast_composite_scaled_bilinear_ ## func ## _normal ## _ ## op, \
}
 
/* Prefer the use of 'cover' variant, because it is faster */
#define SIMPLE_BILINEAR_FAST_PATH(op,s,d,func) \
SIMPLE_BILINEAR_FAST_PATH_COVER (op,s,d,func), \
SIMPLE_BILINEAR_FAST_PATH_NONE (op,s,d,func), \
SIMPLE_BILINEAR_FAST_PATH_PAD (op,s,d,func), \
SIMPLE_BILINEAR_FAST_PATH_NORMAL (op,s,d,func)
 
#define SIMPLE_BILINEAR_A8_MASK_FAST_PATH(op,s,d,func) \
SIMPLE_BILINEAR_A8_MASK_FAST_PATH_COVER (op,s,d,func), \
SIMPLE_BILINEAR_A8_MASK_FAST_PATH_NONE (op,s,d,func), \
SIMPLE_BILINEAR_A8_MASK_FAST_PATH_PAD (op,s,d,func), \
SIMPLE_BILINEAR_A8_MASK_FAST_PATH_NORMAL (op,s,d,func)
 
#define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH(op,s,d,func) \
SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_COVER (op,s,d,func), \
SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_NONE (op,s,d,func), \
SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_PAD (op,s,d,func), \
SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_NORMAL (op,s,d,func)
 
#endif
/contrib/sdk/sources/pixman/pixman-linear-gradient.c
0,0 → 1,287
/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007 Red Hat, Inc.
* Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
* 2005 Lars Knoll & Zack Rusin, Trolltech
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include "pixman-private.h"
 
static pixman_bool_t
linear_gradient_is_horizontal (pixman_image_t *image,
int x,
int y,
int width,
int height)
{
linear_gradient_t *linear = (linear_gradient_t *)image;
pixman_vector_t v;
pixman_fixed_32_32_t l;
pixman_fixed_48_16_t dx, dy;
double inc;
 
if (image->common.transform)
{
/* projective transformation */
if (image->common.transform->matrix[2][0] != 0 ||
image->common.transform->matrix[2][1] != 0 ||
image->common.transform->matrix[2][2] == 0)
{
return FALSE;
}
 
v.vector[0] = image->common.transform->matrix[0][1];
v.vector[1] = image->common.transform->matrix[1][1];
v.vector[2] = image->common.transform->matrix[2][2];
}
else
{
v.vector[0] = 0;
v.vector[1] = pixman_fixed_1;
v.vector[2] = pixman_fixed_1;
}
 
dx = linear->p2.x - linear->p1.x;
dy = linear->p2.y - linear->p1.y;
 
l = dx * dx + dy * dy;
 
if (l == 0)
return FALSE;
 
/*
* compute how much the input of the gradient walked changes
* when moving vertically through the whole image
*/
inc = height * (double) pixman_fixed_1 * pixman_fixed_1 *
(dx * v.vector[0] + dy * v.vector[1]) /
(v.vector[2] * (double) l);
 
/* check that casting to integer would result in 0 */
if (-1 < inc && inc < 1)
return TRUE;
 
return FALSE;
}
 
static uint32_t *
linear_get_scanline_narrow (pixman_iter_t *iter,
const uint32_t *mask)
{
pixman_image_t *image = iter->image;
int x = iter->x;
int y = iter->y;
int width = iter->width;
uint32_t * buffer = iter->buffer;
 
pixman_vector_t v, unit;
pixman_fixed_32_32_t l;
pixman_fixed_48_16_t dx, dy;
gradient_t *gradient = (gradient_t *)image;
linear_gradient_t *linear = (linear_gradient_t *)image;
uint32_t *end = buffer + width;
pixman_gradient_walker_t walker;
 
_pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
 
/* reference point is the center of the pixel */
v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
 
if (image->common.transform)
{
if (!pixman_transform_point_3d (image->common.transform, &v))
return iter->buffer;
 
unit.vector[0] = image->common.transform->matrix[0][0];
unit.vector[1] = image->common.transform->matrix[1][0];
unit.vector[2] = image->common.transform->matrix[2][0];
}
else
{
unit.vector[0] = pixman_fixed_1;
unit.vector[1] = 0;
unit.vector[2] = 0;
}
 
dx = linear->p2.x - linear->p1.x;
dy = linear->p2.y - linear->p1.y;
 
l = dx * dx + dy * dy;
 
if (l == 0 || unit.vector[2] == 0)
{
/* affine transformation only */
pixman_fixed_32_32_t t, next_inc;
double inc;
 
if (l == 0 || v.vector[2] == 0)
{
t = 0;
inc = 0;
}
else
{
double invden, v2;
 
invden = pixman_fixed_1 * (double) pixman_fixed_1 /
(l * (double) v.vector[2]);
v2 = v.vector[2] * (1. / pixman_fixed_1);
t = ((dx * v.vector[0] + dy * v.vector[1]) -
(dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden;
}
next_inc = 0;
 
if (((pixman_fixed_32_32_t )(inc * width)) == 0)
{
register uint32_t color;
 
color = _pixman_gradient_walker_pixel (&walker, t);
while (buffer < end)
*buffer++ = color;
}
else
{
int i;
 
i = 0;
while (buffer < end)
{
if (!mask || *mask++)
{
*buffer = _pixman_gradient_walker_pixel (&walker,
t + next_inc);
}
i++;
next_inc = inc * i;
buffer++;
}
}
}
else
{
/* projective transformation */
double t;
 
t = 0;
 
while (buffer < end)
{
if (!mask || *mask++)
{
if (v.vector[2] != 0)
{
double invden, v2;
 
invden = pixman_fixed_1 * (double) pixman_fixed_1 /
(l * (double) v.vector[2]);
v2 = v.vector[2] * (1. / pixman_fixed_1);
t = ((dx * v.vector[0] + dy * v.vector[1]) -
(dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
}
 
*buffer = _pixman_gradient_walker_pixel (&walker, t);
}
 
++buffer;
 
v.vector[0] += unit.vector[0];
v.vector[1] += unit.vector[1];
v.vector[2] += unit.vector[2];
}
}
 
iter->y++;
 
return iter->buffer;
}
 
static uint32_t *
linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
{
uint32_t *buffer = linear_get_scanline_narrow (iter, NULL);
 
pixman_expand_to_float (
(argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
 
return buffer;
}
 
void
_pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter)
{
if (linear_gradient_is_horizontal (
iter->image, iter->x, iter->y, iter->width, iter->height))
{
if (iter->iter_flags & ITER_NARROW)
linear_get_scanline_narrow (iter, NULL);
else
linear_get_scanline_wide (iter, NULL);
 
iter->get_scanline = _pixman_iter_get_scanline_noop;
}
else
{
if (iter->iter_flags & ITER_NARROW)
iter->get_scanline = linear_get_scanline_narrow;
else
iter->get_scanline = linear_get_scanline_wide;
}
}
 
PIXMAN_EXPORT pixman_image_t *
pixman_image_create_linear_gradient (const pixman_point_fixed_t * p1,
const pixman_point_fixed_t * p2,
const pixman_gradient_stop_t *stops,
int n_stops)
{
pixman_image_t *image;
linear_gradient_t *linear;
 
image = _pixman_image_allocate ();
 
if (!image)
return NULL;
 
linear = &image->linear;
 
if (!_pixman_init_gradient (&linear->common, stops, n_stops))
{
free (image);
return NULL;
}
 
linear->p1 = *p1;
linear->p2 = *p2;
 
image->type = LINEAR;
 
return image;
}
 
/contrib/sdk/sources/pixman/pixman-matrix.c
0,0 → 1,1073
/*
* Copyright © 2008 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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.
*/
 
/*
* Matrix interfaces
*/
 
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
 
#include <math.h>
#include <string.h>
#include "pixman-private.h"
 
#define F(x) pixman_int_to_fixed (x)
 
static force_inline int
count_leading_zeros (uint32_t x)
{
#ifdef __GNUC__
return __builtin_clz (x);
#else
int n = 0;
while (x)
{
n++;
x >>= 1;
}
return 32 - n;
#endif
}
 
/*
* Large signed/unsigned integer division with rounding for the platforms with
* only 64-bit integer data type supported (no 128-bit data type).
*
* Arguments:
* hi, lo - high and low 64-bit parts of the dividend
* div - 48-bit divisor
*
* Returns: lowest 64 bits of the result as a return value and highest 64
* bits of the result to "result_hi" pointer
*/
 
/* grade-school unsigned division (128-bit by 48-bit) with rounding to nearest */
static force_inline uint64_t
rounded_udiv_128_by_48 (uint64_t hi,
uint64_t lo,
uint64_t div,
uint64_t *result_hi)
{
uint64_t tmp, remainder, result_lo;
assert(div < ((uint64_t)1 << 48));
 
remainder = hi % div;
*result_hi = hi / div;
 
tmp = (remainder << 16) + (lo >> 48);
result_lo = tmp / div;
remainder = tmp % div;
 
tmp = (remainder << 16) + ((lo >> 32) & 0xFFFF);
result_lo = (result_lo << 16) + (tmp / div);
remainder = tmp % div;
 
tmp = (remainder << 16) + ((lo >> 16) & 0xFFFF);
result_lo = (result_lo << 16) + (tmp / div);
remainder = tmp % div;
 
tmp = (remainder << 16) + (lo & 0xFFFF);
result_lo = (result_lo << 16) + (tmp / div);
remainder = tmp % div;
 
/* round to nearest */
if (remainder * 2 >= div && ++result_lo == 0)
*result_hi += 1;
 
return result_lo;
}
 
/* signed division (128-bit by 49-bit) with rounding to nearest */
static inline int64_t
rounded_sdiv_128_by_49 (int64_t hi,
uint64_t lo,
int64_t div,
int64_t *signed_result_hi)
{
uint64_t result_lo, result_hi;
int sign = 0;
if (div < 0)
{
div = -div;
sign ^= 1;
}
if (hi < 0)
{
if (lo != 0)
hi++;
hi = -hi;
lo = -lo;
sign ^= 1;
}
result_lo = rounded_udiv_128_by_48 (hi, lo, div, &result_hi);
if (sign)
{
if (result_lo != 0)
result_hi++;
result_hi = -result_hi;
result_lo = -result_lo;
}
if (signed_result_hi)
{
*signed_result_hi = result_hi;
}
return result_lo;
}
 
/*
* Multiply 64.16 fixed point value by (2^scalebits) and convert
* to 128-bit integer.
*/
static force_inline void
fixed_64_16_to_int128 (int64_t hi,
int64_t lo,
int64_t *rhi,
int64_t *rlo,
int scalebits)
{
/* separate integer and fractional parts */
hi += lo >> 16;
lo &= 0xFFFF;
 
if (scalebits <= 0)
{
*rlo = hi >> (-scalebits);
*rhi = *rlo >> 63;
}
else
{
*rhi = hi >> (64 - scalebits);
*rlo = (uint64_t)hi << scalebits;
if (scalebits < 16)
*rlo += lo >> (16 - scalebits);
else
*rlo += lo << (scalebits - 16);
}
}
 
/*
* Convert 112.16 fixed point value to 48.16 with clamping for the out
* of range values.
*/
static force_inline pixman_fixed_48_16_t
fixed_112_16_to_fixed_48_16 (int64_t hi, int64_t lo, pixman_bool_t *clampflag)
{
if ((lo >> 63) != hi)
{
*clampflag = TRUE;
return hi >= 0 ? INT64_MAX : INT64_MIN;
}
else
{
return lo;
}
}
 
/*
* Transform a point with 31.16 fixed point coordinates from the destination
* space to a point with 48.16 fixed point coordinates in the source space.
* No overflows are possible for affine transformations and the results are
* accurate including the least significant bit. Projective transformations
* may overflow, in this case the results are just clamped to return maximum
* or minimum 48.16 values (so that the caller can at least handle the NONE
* and PAD repeats correctly) and the return value is FALSE to indicate that
* such clamping has happened.
*/
PIXMAN_EXPORT pixman_bool_t
pixman_transform_point_31_16 (const pixman_transform_t *t,
const pixman_vector_48_16_t *v,
pixman_vector_48_16_t *result)
{
pixman_bool_t clampflag = FALSE;
int i;
int64_t tmp[3][2], divint;
uint16_t divfrac;
 
/* input vector values must have no more than 31 bits (including sign)
* in the integer part */
assert (v->v[0] < ((pixman_fixed_48_16_t)1 << (30 + 16)));
assert (v->v[0] >= -((pixman_fixed_48_16_t)1 << (30 + 16)));
assert (v->v[1] < ((pixman_fixed_48_16_t)1 << (30 + 16)));
assert (v->v[1] >= -((pixman_fixed_48_16_t)1 << (30 + 16)));
assert (v->v[2] < ((pixman_fixed_48_16_t)1 << (30 + 16)));
assert (v->v[2] >= -((pixman_fixed_48_16_t)1 << (30 + 16)));
 
for (i = 0; i < 3; i++)
{
tmp[i][0] = (int64_t)t->matrix[i][0] * (v->v[0] >> 16);
tmp[i][1] = (int64_t)t->matrix[i][0] * (v->v[0] & 0xFFFF);
tmp[i][0] += (int64_t)t->matrix[i][1] * (v->v[1] >> 16);
tmp[i][1] += (int64_t)t->matrix[i][1] * (v->v[1] & 0xFFFF);
tmp[i][0] += (int64_t)t->matrix[i][2] * (v->v[2] >> 16);
tmp[i][1] += (int64_t)t->matrix[i][2] * (v->v[2] & 0xFFFF);
}
 
/*
* separate 64-bit integer and 16-bit fractional parts for the divisor,
* which is also scaled by 65536 after fixed point multiplication.
*/
divint = tmp[2][0] + (tmp[2][1] >> 16);
divfrac = tmp[2][1] & 0xFFFF;
 
if (divint == pixman_fixed_1 && divfrac == 0)
{
/*
* this is a simple affine transformation
*/
result->v[0] = tmp[0][0] + ((tmp[0][1] + 0x8000) >> 16);
result->v[1] = tmp[1][0] + ((tmp[1][1] + 0x8000) >> 16);
result->v[2] = pixman_fixed_1;
}
else if (divint == 0 && divfrac == 0)
{
/*
* handle zero divisor (if the values are non-zero, set the
* results to maximum positive or minimum negative)
*/
clampflag = TRUE;
 
result->v[0] = tmp[0][0] + ((tmp[0][1] + 0x8000) >> 16);
result->v[1] = tmp[1][0] + ((tmp[1][1] + 0x8000) >> 16);
 
if (result->v[0] > 0)
result->v[0] = INT64_MAX;
else if (result->v[0] < 0)
result->v[0] = INT64_MIN;
 
if (result->v[1] > 0)
result->v[1] = INT64_MAX;
else if (result->v[1] < 0)
result->v[1] = INT64_MIN;
}
else
{
/*
* projective transformation, analyze the top 32 bits of the divisor
*/
int32_t hi32divbits = divint >> 32;
if (hi32divbits < 0)
hi32divbits = ~hi32divbits;
 
if (hi32divbits == 0)
{
/* the divisor is small, we can actually keep all the bits */
int64_t hi, rhi, lo, rlo;
int64_t div = (divint << 16) + divfrac;
 
fixed_64_16_to_int128 (tmp[0][0], tmp[0][1], &hi, &lo, 32);
rlo = rounded_sdiv_128_by_49 (hi, lo, div, &rhi);
result->v[0] = fixed_112_16_to_fixed_48_16 (rhi, rlo, &clampflag);
 
fixed_64_16_to_int128 (tmp[1][0], tmp[1][1], &hi, &lo, 32);
rlo = rounded_sdiv_128_by_49 (hi, lo, div, &rhi);
result->v[1] = fixed_112_16_to_fixed_48_16 (rhi, rlo, &clampflag);
}
else
{
/* the divisor needs to be reduced to 48 bits */
int64_t hi, rhi, lo, rlo, div;
int shift = 32 - count_leading_zeros (hi32divbits);
fixed_64_16_to_int128 (divint, divfrac, &hi, &div, 16 - shift);
 
fixed_64_16_to_int128 (tmp[0][0], tmp[0][1], &hi, &lo, 32 - shift);
rlo = rounded_sdiv_128_by_49 (hi, lo, div, &rhi);
result->v[0] = fixed_112_16_to_fixed_48_16 (rhi, rlo, &clampflag);
 
fixed_64_16_to_int128 (tmp[1][0], tmp[1][1], &hi, &lo, 32 - shift);
rlo = rounded_sdiv_128_by_49 (hi, lo, div, &rhi);
result->v[1] = fixed_112_16_to_fixed_48_16 (rhi, rlo, &clampflag);
}
}
result->v[2] = pixman_fixed_1;
return !clampflag;
}
 
PIXMAN_EXPORT void
pixman_transform_point_31_16_affine (const pixman_transform_t *t,
const pixman_vector_48_16_t *v,
pixman_vector_48_16_t *result)
{
int64_t hi0, lo0, hi1, lo1;
 
/* input vector values must have no more than 31 bits (including sign)
* in the integer part */
assert (v->v[0] < ((pixman_fixed_48_16_t)1 << (30 + 16)));
assert (v->v[0] >= -((pixman_fixed_48_16_t)1 << (30 + 16)));
assert (v->v[1] < ((pixman_fixed_48_16_t)1 << (30 + 16)));
assert (v->v[1] >= -((pixman_fixed_48_16_t)1 << (30 + 16)));
 
hi0 = (int64_t)t->matrix[0][0] * (v->v[0] >> 16);
lo0 = (int64_t)t->matrix[0][0] * (v->v[0] & 0xFFFF);
hi0 += (int64_t)t->matrix[0][1] * (v->v[1] >> 16);
lo0 += (int64_t)t->matrix[0][1] * (v->v[1] & 0xFFFF);
hi0 += (int64_t)t->matrix[0][2];
 
hi1 = (int64_t)t->matrix[1][0] * (v->v[0] >> 16);
lo1 = (int64_t)t->matrix[1][0] * (v->v[0] & 0xFFFF);
hi1 += (int64_t)t->matrix[1][1] * (v->v[1] >> 16);
lo1 += (int64_t)t->matrix[1][1] * (v->v[1] & 0xFFFF);
hi1 += (int64_t)t->matrix[1][2];
 
result->v[0] = hi0 + ((lo0 + 0x8000) >> 16);
result->v[1] = hi1 + ((lo1 + 0x8000) >> 16);
result->v[2] = pixman_fixed_1;
}
 
PIXMAN_EXPORT void
pixman_transform_point_31_16_3d (const pixman_transform_t *t,
const pixman_vector_48_16_t *v,
pixman_vector_48_16_t *result)
{
int i;
int64_t tmp[3][2];
 
/* input vector values must have no more than 31 bits (including sign)
* in the integer part */
assert (v->v[0] < ((pixman_fixed_48_16_t)1 << (30 + 16)));
assert (v->v[0] >= -((pixman_fixed_48_16_t)1 << (30 + 16)));
assert (v->v[1] < ((pixman_fixed_48_16_t)1 << (30 + 16)));
assert (v->v[1] >= -((pixman_fixed_48_16_t)1 << (30 + 16)));
assert (v->v[2] < ((pixman_fixed_48_16_t)1 << (30 + 16)));
assert (v->v[2] >= -((pixman_fixed_48_16_t)1 << (30 + 16)));
 
for (i = 0; i < 3; i++)
{
tmp[i][0] = (int64_t)t->matrix[i][0] * (v->v[0] >> 16);
tmp[i][1] = (int64_t)t->matrix[i][0] * (v->v[0] & 0xFFFF);
tmp[i][0] += (int64_t)t->matrix[i][1] * (v->v[1] >> 16);
tmp[i][1] += (int64_t)t->matrix[i][1] * (v->v[1] & 0xFFFF);
tmp[i][0] += (int64_t)t->matrix[i][2] * (v->v[2] >> 16);
tmp[i][1] += (int64_t)t->matrix[i][2] * (v->v[2] & 0xFFFF);
}
 
result->v[0] = tmp[0][0] + ((tmp[0][1] + 0x8000) >> 16);
result->v[1] = tmp[1][0] + ((tmp[1][1] + 0x8000) >> 16);
result->v[2] = tmp[2][0] + ((tmp[2][1] + 0x8000) >> 16);
}
 
PIXMAN_EXPORT void
pixman_transform_init_identity (struct pixman_transform *matrix)
{
int i;
 
memset (matrix, '\0', sizeof (struct pixman_transform));
for (i = 0; i < 3; i++)
matrix->matrix[i][i] = F (1);
}
 
typedef pixman_fixed_32_32_t pixman_fixed_34_30_t;
 
PIXMAN_EXPORT pixman_bool_t
pixman_transform_point_3d (const struct pixman_transform *transform,
struct pixman_vector * vector)
{
pixman_vector_48_16_t tmp;
tmp.v[0] = vector->vector[0];
tmp.v[1] = vector->vector[1];
tmp.v[2] = vector->vector[2];
 
pixman_transform_point_31_16_3d (transform, &tmp, &tmp);
 
vector->vector[0] = tmp.v[0];
vector->vector[1] = tmp.v[1];
vector->vector[2] = tmp.v[2];
 
return vector->vector[0] == tmp.v[0] &&
vector->vector[1] == tmp.v[1] &&
vector->vector[2] == tmp.v[2];
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_transform_point (const struct pixman_transform *transform,
struct pixman_vector * vector)
{
pixman_vector_48_16_t tmp;
tmp.v[0] = vector->vector[0];
tmp.v[1] = vector->vector[1];
tmp.v[2] = vector->vector[2];
 
if (!pixman_transform_point_31_16 (transform, &tmp, &tmp))
return FALSE;
 
vector->vector[0] = tmp.v[0];
vector->vector[1] = tmp.v[1];
vector->vector[2] = tmp.v[2];
 
return vector->vector[0] == tmp.v[0] &&
vector->vector[1] == tmp.v[1] &&
vector->vector[2] == tmp.v[2];
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_transform_multiply (struct pixman_transform * dst,
const struct pixman_transform *l,
const struct pixman_transform *r)
{
struct pixman_transform d;
int dx, dy;
int o;
 
for (dy = 0; dy < 3; dy++)
{
for (dx = 0; dx < 3; dx++)
{
pixman_fixed_48_16_t v;
pixman_fixed_32_32_t partial;
v = 0;
for (o = 0; o < 3; o++)
{
partial =
(pixman_fixed_32_32_t) l->matrix[dy][o] *
(pixman_fixed_32_32_t) r->matrix[o][dx];
 
v += (partial + 0x8000) >> 16;
}
 
if (v > pixman_max_fixed_48_16 || v < pixman_min_fixed_48_16)
return FALSE;
d.matrix[dy][dx] = (pixman_fixed_t) v;
}
}
 
*dst = d;
return TRUE;
}
 
PIXMAN_EXPORT void
pixman_transform_init_scale (struct pixman_transform *t,
pixman_fixed_t sx,
pixman_fixed_t sy)
{
memset (t, '\0', sizeof (struct pixman_transform));
 
t->matrix[0][0] = sx;
t->matrix[1][1] = sy;
t->matrix[2][2] = F (1);
}
 
static pixman_fixed_t
fixed_inverse (pixman_fixed_t x)
{
return (pixman_fixed_t) ((((pixman_fixed_48_16_t) F (1)) * F (1)) / x);
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_transform_scale (struct pixman_transform *forward,
struct pixman_transform *reverse,
pixman_fixed_t sx,
pixman_fixed_t sy)
{
struct pixman_transform t;
 
if (sx == 0 || sy == 0)
return FALSE;
 
if (forward)
{
pixman_transform_init_scale (&t, sx, sy);
if (!pixman_transform_multiply (forward, &t, forward))
return FALSE;
}
if (reverse)
{
pixman_transform_init_scale (&t, fixed_inverse (sx),
fixed_inverse (sy));
if (!pixman_transform_multiply (reverse, reverse, &t))
return FALSE;
}
return TRUE;
}
 
PIXMAN_EXPORT void
pixman_transform_init_rotate (struct pixman_transform *t,
pixman_fixed_t c,
pixman_fixed_t s)
{
memset (t, '\0', sizeof (struct pixman_transform));
 
t->matrix[0][0] = c;
t->matrix[0][1] = -s;
t->matrix[1][0] = s;
t->matrix[1][1] = c;
t->matrix[2][2] = F (1);
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_transform_rotate (struct pixman_transform *forward,
struct pixman_transform *reverse,
pixman_fixed_t c,
pixman_fixed_t s)
{
struct pixman_transform t;
 
if (forward)
{
pixman_transform_init_rotate (&t, c, s);
if (!pixman_transform_multiply (forward, &t, forward))
return FALSE;
}
 
if (reverse)
{
pixman_transform_init_rotate (&t, c, -s);
if (!pixman_transform_multiply (reverse, reverse, &t))
return FALSE;
}
return TRUE;
}
 
PIXMAN_EXPORT void
pixman_transform_init_translate (struct pixman_transform *t,
pixman_fixed_t tx,
pixman_fixed_t ty)
{
memset (t, '\0', sizeof (struct pixman_transform));
 
t->matrix[0][0] = F (1);
t->matrix[0][2] = tx;
t->matrix[1][1] = F (1);
t->matrix[1][2] = ty;
t->matrix[2][2] = F (1);
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_transform_translate (struct pixman_transform *forward,
struct pixman_transform *reverse,
pixman_fixed_t tx,
pixman_fixed_t ty)
{
struct pixman_transform t;
 
if (forward)
{
pixman_transform_init_translate (&t, tx, ty);
 
if (!pixman_transform_multiply (forward, &t, forward))
return FALSE;
}
 
if (reverse)
{
pixman_transform_init_translate (&t, -tx, -ty);
 
if (!pixman_transform_multiply (reverse, reverse, &t))
return FALSE;
}
return TRUE;
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_transform_bounds (const struct pixman_transform *matrix,
struct pixman_box16 * b)
 
{
struct pixman_vector v[4];
int i;
int x1, y1, x2, y2;
 
v[0].vector[0] = F (b->x1);
v[0].vector[1] = F (b->y1);
v[0].vector[2] = F (1);
 
v[1].vector[0] = F (b->x2);
v[1].vector[1] = F (b->y1);
v[1].vector[2] = F (1);
 
v[2].vector[0] = F (b->x2);
v[2].vector[1] = F (b->y2);
v[2].vector[2] = F (1);
 
v[3].vector[0] = F (b->x1);
v[3].vector[1] = F (b->y2);
v[3].vector[2] = F (1);
 
for (i = 0; i < 4; i++)
{
if (!pixman_transform_point (matrix, &v[i]))
return FALSE;
 
x1 = pixman_fixed_to_int (v[i].vector[0]);
y1 = pixman_fixed_to_int (v[i].vector[1]);
x2 = pixman_fixed_to_int (pixman_fixed_ceil (v[i].vector[0]));
y2 = pixman_fixed_to_int (pixman_fixed_ceil (v[i].vector[1]));
 
if (i == 0)
{
b->x1 = x1;
b->y1 = y1;
b->x2 = x2;
b->y2 = y2;
}
else
{
if (x1 < b->x1) b->x1 = x1;
if (y1 < b->y1) b->y1 = y1;
if (x2 > b->x2) b->x2 = x2;
if (y2 > b->y2) b->y2 = y2;
}
}
 
return TRUE;
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_transform_invert (struct pixman_transform * dst,
const struct pixman_transform *src)
{
struct pixman_f_transform m;
 
pixman_f_transform_from_pixman_transform (&m, src);
 
if (!pixman_f_transform_invert (&m, &m))
return FALSE;
 
if (!pixman_transform_from_pixman_f_transform (dst, &m))
return FALSE;
 
return TRUE;
}
 
static pixman_bool_t
within_epsilon (pixman_fixed_t a,
pixman_fixed_t b,
pixman_fixed_t epsilon)
{
pixman_fixed_t t = a - b;
 
if (t < 0)
t = -t;
 
return t <= epsilon;
}
 
#define EPSILON (pixman_fixed_t) (2)
 
#define IS_SAME(a, b) (within_epsilon (a, b, EPSILON))
#define IS_ZERO(a) (within_epsilon (a, 0, EPSILON))
#define IS_ONE(a) (within_epsilon (a, F (1), EPSILON))
#define IS_UNIT(a) \
(within_epsilon (a, F (1), EPSILON) || \
within_epsilon (a, F (-1), EPSILON) || \
IS_ZERO (a))
#define IS_INT(a) (IS_ZERO (pixman_fixed_frac (a)))
 
PIXMAN_EXPORT pixman_bool_t
pixman_transform_is_identity (const struct pixman_transform *t)
{
return (IS_SAME (t->matrix[0][0], t->matrix[1][1]) &&
IS_SAME (t->matrix[0][0], t->matrix[2][2]) &&
!IS_ZERO (t->matrix[0][0]) &&
IS_ZERO (t->matrix[0][1]) &&
IS_ZERO (t->matrix[0][2]) &&
IS_ZERO (t->matrix[1][0]) &&
IS_ZERO (t->matrix[1][2]) &&
IS_ZERO (t->matrix[2][0]) &&
IS_ZERO (t->matrix[2][1]));
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_transform_is_scale (const struct pixman_transform *t)
{
return (!IS_ZERO (t->matrix[0][0]) &&
IS_ZERO (t->matrix[0][1]) &&
IS_ZERO (t->matrix[0][2]) &&
 
IS_ZERO (t->matrix[1][0]) &&
!IS_ZERO (t->matrix[1][1]) &&
IS_ZERO (t->matrix[1][2]) &&
 
IS_ZERO (t->matrix[2][0]) &&
IS_ZERO (t->matrix[2][1]) &&
!IS_ZERO (t->matrix[2][2]));
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_transform_is_int_translate (const struct pixman_transform *t)
{
return (IS_ONE (t->matrix[0][0]) &&
IS_ZERO (t->matrix[0][1]) &&
IS_INT (t->matrix[0][2]) &&
 
IS_ZERO (t->matrix[1][0]) &&
IS_ONE (t->matrix[1][1]) &&
IS_INT (t->matrix[1][2]) &&
 
IS_ZERO (t->matrix[2][0]) &&
IS_ZERO (t->matrix[2][1]) &&
IS_ONE (t->matrix[2][2]));
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_transform_is_inverse (const struct pixman_transform *a,
const struct pixman_transform *b)
{
struct pixman_transform t;
 
if (!pixman_transform_multiply (&t, a, b))
return FALSE;
 
return pixman_transform_is_identity (&t);
}
 
PIXMAN_EXPORT void
pixman_f_transform_from_pixman_transform (struct pixman_f_transform * ft,
const struct pixman_transform *t)
{
int i, j;
 
for (j = 0; j < 3; j++)
{
for (i = 0; i < 3; i++)
ft->m[j][i] = pixman_fixed_to_double (t->matrix[j][i]);
}
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_transform_from_pixman_f_transform (struct pixman_transform * t,
const struct pixman_f_transform *ft)
{
int i, j;
 
for (j = 0; j < 3; j++)
{
for (i = 0; i < 3; i++)
{
double d = ft->m[j][i];
if (d < -32767.0 || d > 32767.0)
return FALSE;
d = d * 65536.0 + 0.5;
t->matrix[j][i] = (pixman_fixed_t) floor (d);
}
}
return TRUE;
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_f_transform_invert (struct pixman_f_transform * dst,
const struct pixman_f_transform *src)
{
static const int a[3] = { 2, 2, 1 };
static const int b[3] = { 1, 0, 0 };
pixman_f_transform_t d;
double det;
int i, j;
 
det = 0;
for (i = 0; i < 3; i++)
{
double p;
int ai = a[i];
int bi = b[i];
p = src->m[i][0] * (src->m[ai][2] * src->m[bi][1] -
src->m[ai][1] * src->m[bi][2]);
if (i == 1)
p = -p;
det += p;
}
if (det == 0)
return FALSE;
det = 1 / det;
for (j = 0; j < 3; j++)
{
for (i = 0; i < 3; i++)
{
double p;
int ai = a[i];
int aj = a[j];
int bi = b[i];
int bj = b[j];
 
p = (src->m[ai][aj] * src->m[bi][bj] -
src->m[ai][bj] * src->m[bi][aj]);
if (((i + j) & 1) != 0)
p = -p;
d.m[j][i] = det * p;
}
}
 
*dst = d;
 
return TRUE;
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_f_transform_point (const struct pixman_f_transform *t,
struct pixman_f_vector * v)
{
struct pixman_f_vector result;
int i, j;
double a;
 
for (j = 0; j < 3; j++)
{
a = 0;
for (i = 0; i < 3; i++)
a += t->m[j][i] * v->v[i];
result.v[j] = a;
}
if (!result.v[2])
return FALSE;
 
for (j = 0; j < 2; j++)
v->v[j] = result.v[j] / result.v[2];
 
v->v[2] = 1;
 
return TRUE;
}
 
PIXMAN_EXPORT void
pixman_f_transform_point_3d (const struct pixman_f_transform *t,
struct pixman_f_vector * v)
{
struct pixman_f_vector result;
int i, j;
double a;
 
for (j = 0; j < 3; j++)
{
a = 0;
for (i = 0; i < 3; i++)
a += t->m[j][i] * v->v[i];
result.v[j] = a;
}
*v = result;
}
 
PIXMAN_EXPORT void
pixman_f_transform_multiply (struct pixman_f_transform * dst,
const struct pixman_f_transform *l,
const struct pixman_f_transform *r)
{
struct pixman_f_transform d;
int dx, dy;
int o;
 
for (dy = 0; dy < 3; dy++)
{
for (dx = 0; dx < 3; dx++)
{
double v = 0;
for (o = 0; o < 3; o++)
v += l->m[dy][o] * r->m[o][dx];
d.m[dy][dx] = v;
}
}
*dst = d;
}
 
PIXMAN_EXPORT void
pixman_f_transform_init_scale (struct pixman_f_transform *t,
double sx,
double sy)
{
t->m[0][0] = sx;
t->m[0][1] = 0;
t->m[0][2] = 0;
t->m[1][0] = 0;
t->m[1][1] = sy;
t->m[1][2] = 0;
t->m[2][0] = 0;
t->m[2][1] = 0;
t->m[2][2] = 1;
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_f_transform_scale (struct pixman_f_transform *forward,
struct pixman_f_transform *reverse,
double sx,
double sy)
{
struct pixman_f_transform t;
 
if (sx == 0 || sy == 0)
return FALSE;
 
if (forward)
{
pixman_f_transform_init_scale (&t, sx, sy);
pixman_f_transform_multiply (forward, &t, forward);
}
if (reverse)
{
pixman_f_transform_init_scale (&t, 1 / sx, 1 / sy);
pixman_f_transform_multiply (reverse, reverse, &t);
}
return TRUE;
}
 
PIXMAN_EXPORT void
pixman_f_transform_init_rotate (struct pixman_f_transform *t,
double c,
double s)
{
t->m[0][0] = c;
t->m[0][1] = -s;
t->m[0][2] = 0;
t->m[1][0] = s;
t->m[1][1] = c;
t->m[1][2] = 0;
t->m[2][0] = 0;
t->m[2][1] = 0;
t->m[2][2] = 1;
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_f_transform_rotate (struct pixman_f_transform *forward,
struct pixman_f_transform *reverse,
double c,
double s)
{
struct pixman_f_transform t;
 
if (forward)
{
pixman_f_transform_init_rotate (&t, c, s);
pixman_f_transform_multiply (forward, &t, forward);
}
if (reverse)
{
pixman_f_transform_init_rotate (&t, c, -s);
pixman_f_transform_multiply (reverse, reverse, &t);
}
 
return TRUE;
}
 
PIXMAN_EXPORT void
pixman_f_transform_init_translate (struct pixman_f_transform *t,
double tx,
double ty)
{
t->m[0][0] = 1;
t->m[0][1] = 0;
t->m[0][2] = tx;
t->m[1][0] = 0;
t->m[1][1] = 1;
t->m[1][2] = ty;
t->m[2][0] = 0;
t->m[2][1] = 0;
t->m[2][2] = 1;
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_f_transform_translate (struct pixman_f_transform *forward,
struct pixman_f_transform *reverse,
double tx,
double ty)
{
struct pixman_f_transform t;
 
if (forward)
{
pixman_f_transform_init_translate (&t, tx, ty);
pixman_f_transform_multiply (forward, &t, forward);
}
 
if (reverse)
{
pixman_f_transform_init_translate (&t, -tx, -ty);
pixman_f_transform_multiply (reverse, reverse, &t);
}
 
return TRUE;
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_f_transform_bounds (const struct pixman_f_transform *t,
struct pixman_box16 * b)
{
struct pixman_f_vector v[4];
int i;
int x1, y1, x2, y2;
 
v[0].v[0] = b->x1;
v[0].v[1] = b->y1;
v[0].v[2] = 1;
v[1].v[0] = b->x2;
v[1].v[1] = b->y1;
v[1].v[2] = 1;
v[2].v[0] = b->x2;
v[2].v[1] = b->y2;
v[2].v[2] = 1;
v[3].v[0] = b->x1;
v[3].v[1] = b->y2;
v[3].v[2] = 1;
 
for (i = 0; i < 4; i++)
{
if (!pixman_f_transform_point (t, &v[i]))
return FALSE;
 
x1 = floor (v[i].v[0]);
y1 = floor (v[i].v[1]);
x2 = ceil (v[i].v[0]);
y2 = ceil (v[i].v[1]);
 
if (i == 0)
{
b->x1 = x1;
b->y1 = y1;
b->x2 = x2;
b->y2 = y2;
}
else
{
if (x1 < b->x1) b->x1 = x1;
if (y1 < b->y1) b->y1 = y1;
if (x2 > b->x2) b->x2 = x2;
if (y2 > b->y2) b->y2 = y2;
}
}
 
return TRUE;
}
 
PIXMAN_EXPORT void
pixman_f_transform_init_identity (struct pixman_f_transform *t)
{
int i, j;
 
for (j = 0; j < 3; j++)
{
for (i = 0; i < 3; i++)
t->m[j][i] = i == j ? 1 : 0;
}
}
/contrib/sdk/sources/pixman/pixman-mmx.c
0,0 → 1,4082
/*
* Copyright © 2004, 2005 Red Hat, Inc.
* Copyright © 2004 Nicholas Miell
* Copyright © 2005 Trolltech AS
*
* 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 Red Hat not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. Red Hat makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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: Søren Sandmann (sandmann@redhat.com)
* Minor Improvements: Nicholas Miell (nmiell@gmail.com)
* MMX code paths for fbcompose.c by Lars Knoll (lars@trolltech.com)
*
* Based on work by Owen Taylor
*/
 
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
 
#if defined USE_X86_MMX || defined USE_ARM_IWMMXT || defined USE_LOONGSON_MMI
 
#ifdef USE_LOONGSON_MMI
#include <loongson-mmintrin.h>
#else
#include <mmintrin.h>
#endif
#include "pixman-private.h"
#include "pixman-combine32.h"
#include "pixman-inlines.h"
 
#ifdef VERBOSE
#define CHECKPOINT() error_f ("at %s %d\n", __FUNCTION__, __LINE__)
#else
#define CHECKPOINT()
#endif
 
#if defined USE_ARM_IWMMXT && __GNUC__ == 4 && __GNUC_MINOR__ < 8
/* Empty the multimedia state. For some reason, ARM's mmintrin.h doesn't provide this. */
extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_empty (void)
{
 
}
#endif
 
#ifdef USE_X86_MMX
# if (defined(__SUNPRO_C) || defined(_MSC_VER) || defined(_WIN64))
# include <xmmintrin.h>
# else
/* We have to compile with -msse to use xmmintrin.h, but that causes SSE
* instructions to be generated that we don't want. Just duplicate the
* functions we want to use. */
extern __inline int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_movemask_pi8 (__m64 __A)
{
int ret;
 
asm ("pmovmskb %1, %0\n\t"
: "=r" (ret)
: "y" (__A)
);
 
return ret;
}
 
extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_mulhi_pu16 (__m64 __A, __m64 __B)
{
asm ("pmulhuw %1, %0\n\t"
: "+y" (__A)
: "y" (__B)
);
return __A;
}
 
# ifdef __OPTIMIZE__
extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_shuffle_pi16 (__m64 __A, int8_t const __N)
{
__m64 ret;
 
asm ("pshufw %2, %1, %0\n\t"
: "=y" (ret)
: "y" (__A), "K" (__N)
);
 
return ret;
}
# else
# define _mm_shuffle_pi16(A, N) \
({ \
__m64 ret; \
\
asm ("pshufw %2, %1, %0\n\t" \
: "=y" (ret) \
: "y" (A), "K" ((const int8_t)N) \
); \
\
ret; \
})
# endif
# endif
#endif
 
#ifndef _MSC_VER
#define _MM_SHUFFLE(fp3,fp2,fp1,fp0) \
(((fp3) << 6) | ((fp2) << 4) | ((fp1) << 2) | (fp0))
#endif
 
/* Notes about writing mmx code
*
* give memory operands as the second operand. If you give it as the
* first, gcc will first load it into a register, then use that
* register
*
* ie. use
*
* _mm_mullo_pi16 (x, mmx_constant);
*
* not
*
* _mm_mullo_pi16 (mmx_constant, x);
*
* Also try to minimize dependencies. i.e. when you need a value, try
* to calculate it from a value that was calculated as early as
* possible.
*/
 
/* --------------- MMX primitives ------------------------------------- */
 
/* If __m64 is defined as a struct or union, then define M64_MEMBER to be
* the name of the member used to access the data.
* If __m64 requires using mm_cvt* intrinsics functions to convert between
* uint64_t and __m64 values, then define USE_CVT_INTRINSICS.
* If __m64 and uint64_t values can just be cast to each other directly,
* then define USE_M64_CASTS.
* If __m64 is a double datatype, then define USE_M64_DOUBLE.
*/
#ifdef _MSC_VER
# define M64_MEMBER m64_u64
#elif defined(__ICC)
# define USE_CVT_INTRINSICS
#elif defined(USE_LOONGSON_MMI)
# define USE_M64_DOUBLE
#elif defined(__GNUC__)
# define USE_M64_CASTS
#elif defined(__SUNPRO_C)
# if (__SUNPRO_C >= 0x5120) && !defined(__NOVECTORSIZE__)
/* Solaris Studio 12.3 (Sun C 5.12) introduces __attribute__(__vector_size__)
* support, and defaults to using it to define __m64, unless __NOVECTORSIZE__
* is defined. If it is used, then the mm_cvt* intrinsics must be used.
*/
# define USE_CVT_INTRINSICS
# else
/* For Studio 12.2 or older, or when __attribute__(__vector_size__) is
* disabled, __m64 is defined as a struct containing "unsigned long long l_".
*/
# define M64_MEMBER l_
# endif
#endif
 
#if defined(USE_M64_CASTS) || defined(USE_CVT_INTRINSICS) || defined(USE_M64_DOUBLE)
typedef uint64_t mmxdatafield;
#else
typedef __m64 mmxdatafield;
#endif
 
typedef struct
{
mmxdatafield mmx_4x00ff;
mmxdatafield mmx_4x0080;
mmxdatafield mmx_565_rgb;
mmxdatafield mmx_565_unpack_multiplier;
mmxdatafield mmx_565_pack_multiplier;
mmxdatafield mmx_565_r;
mmxdatafield mmx_565_g;
mmxdatafield mmx_565_b;
mmxdatafield mmx_packed_565_rb;
mmxdatafield mmx_packed_565_g;
mmxdatafield mmx_expand_565_g;
mmxdatafield mmx_expand_565_b;
mmxdatafield mmx_expand_565_r;
#ifndef USE_LOONGSON_MMI
mmxdatafield mmx_mask_0;
mmxdatafield mmx_mask_1;
mmxdatafield mmx_mask_2;
mmxdatafield mmx_mask_3;
#endif
mmxdatafield mmx_full_alpha;
mmxdatafield mmx_4x0101;
mmxdatafield mmx_ff000000;
} mmx_data_t;
 
#if defined(_MSC_VER)
# define MMXDATA_INIT(field, val) { val ## UI64 }
#elif defined(M64_MEMBER) /* __m64 is a struct, not an integral type */
# define MMXDATA_INIT(field, val) field = { val ## ULL }
#else /* mmxdatafield is an integral type */
# define MMXDATA_INIT(field, val) field = val ## ULL
#endif
 
static const mmx_data_t c =
{
MMXDATA_INIT (.mmx_4x00ff, 0x00ff00ff00ff00ff),
MMXDATA_INIT (.mmx_4x0080, 0x0080008000800080),
MMXDATA_INIT (.mmx_565_rgb, 0x000001f0003f001f),
MMXDATA_INIT (.mmx_565_unpack_multiplier, 0x0000008404100840),
MMXDATA_INIT (.mmx_565_pack_multiplier, 0x2000000420000004),
MMXDATA_INIT (.mmx_565_r, 0x000000f800000000),
MMXDATA_INIT (.mmx_565_g, 0x0000000000fc0000),
MMXDATA_INIT (.mmx_565_b, 0x00000000000000f8),
MMXDATA_INIT (.mmx_packed_565_rb, 0x00f800f800f800f8),
MMXDATA_INIT (.mmx_packed_565_g, 0x0000fc000000fc00),
MMXDATA_INIT (.mmx_expand_565_g, 0x07e007e007e007e0),
MMXDATA_INIT (.mmx_expand_565_b, 0x001f001f001f001f),
MMXDATA_INIT (.mmx_expand_565_r, 0xf800f800f800f800),
#ifndef USE_LOONGSON_MMI
MMXDATA_INIT (.mmx_mask_0, 0xffffffffffff0000),
MMXDATA_INIT (.mmx_mask_1, 0xffffffff0000ffff),
MMXDATA_INIT (.mmx_mask_2, 0xffff0000ffffffff),
MMXDATA_INIT (.mmx_mask_3, 0x0000ffffffffffff),
#endif
MMXDATA_INIT (.mmx_full_alpha, 0x00ff000000000000),
MMXDATA_INIT (.mmx_4x0101, 0x0101010101010101),
MMXDATA_INIT (.mmx_ff000000, 0xff000000ff000000),
};
 
#ifdef USE_CVT_INTRINSICS
# define MC(x) to_m64 (c.mmx_ ## x)
#elif defined(USE_M64_CASTS)
# define MC(x) ((__m64)c.mmx_ ## x)
#elif defined(USE_M64_DOUBLE)
# define MC(x) (*(__m64 *)&c.mmx_ ## x)
#else
# define MC(x) c.mmx_ ## x
#endif
 
static force_inline __m64
to_m64 (uint64_t x)
{
#ifdef USE_CVT_INTRINSICS
return _mm_cvtsi64_m64 (x);
#elif defined M64_MEMBER /* __m64 is a struct, not an integral type */
__m64 res;
 
res.M64_MEMBER = x;
return res;
#elif defined USE_M64_DOUBLE
return *(__m64 *)&x;
#else /* USE_M64_CASTS */
return (__m64)x;
#endif
}
 
static force_inline uint64_t
to_uint64 (__m64 x)
{
#ifdef USE_CVT_INTRINSICS
return _mm_cvtm64_si64 (x);
#elif defined M64_MEMBER /* __m64 is a struct, not an integral type */
uint64_t res = x.M64_MEMBER;
return res;
#elif defined USE_M64_DOUBLE
return *(uint64_t *)&x;
#else /* USE_M64_CASTS */
return (uint64_t)x;
#endif
}
 
static force_inline __m64
shift (__m64 v,
int s)
{
if (s > 0)
return _mm_slli_si64 (v, s);
else if (s < 0)
return _mm_srli_si64 (v, -s);
else
return v;
}
 
static force_inline __m64
negate (__m64 mask)
{
return _mm_xor_si64 (mask, MC (4x00ff));
}
 
static force_inline __m64
pix_multiply (__m64 a, __m64 b)
{
__m64 res;
 
res = _mm_mullo_pi16 (a, b);
res = _mm_adds_pu16 (res, MC (4x0080));
res = _mm_mulhi_pu16 (res, MC (4x0101));
 
return res;
}
 
static force_inline __m64
pix_add (__m64 a, __m64 b)
{
return _mm_adds_pu8 (a, b);
}
 
static force_inline __m64
expand_alpha (__m64 pixel)
{
return _mm_shuffle_pi16 (pixel, _MM_SHUFFLE (3, 3, 3, 3));
}
 
static force_inline __m64
expand_alpha_rev (__m64 pixel)
{
return _mm_shuffle_pi16 (pixel, _MM_SHUFFLE (0, 0, 0, 0));
}
 
static force_inline __m64
invert_colors (__m64 pixel)
{
return _mm_shuffle_pi16 (pixel, _MM_SHUFFLE (3, 0, 1, 2));
}
 
static force_inline __m64
over (__m64 src,
__m64 srca,
__m64 dest)
{
return _mm_adds_pu8 (src, pix_multiply (dest, negate (srca)));
}
 
static force_inline __m64
over_rev_non_pre (__m64 src, __m64 dest)
{
__m64 srca = expand_alpha (src);
__m64 srcfaaa = _mm_or_si64 (srca, MC (full_alpha));
 
return over (pix_multiply (invert_colors (src), srcfaaa), srca, dest);
}
 
static force_inline __m64
in (__m64 src, __m64 mask)
{
return pix_multiply (src, mask);
}
 
#ifndef _MSC_VER
static force_inline __m64
in_over (__m64 src, __m64 srca, __m64 mask, __m64 dest)
{
return over (in (src, mask), pix_multiply (srca, mask), dest);
}
 
#else
 
#define in_over(src, srca, mask, dest) \
over (in (src, mask), pix_multiply (srca, mask), dest)
 
#endif
 
/* Elemental unaligned loads */
 
static force_inline __m64 ldq_u(__m64 *p)
{
#ifdef USE_X86_MMX
/* x86's alignment restrictions are very relaxed. */
return *(__m64 *)p;
#elif defined USE_ARM_IWMMXT
int align = (uintptr_t)p & 7;
__m64 *aligned_p;
if (align == 0)
return *p;
aligned_p = (__m64 *)((uintptr_t)p & ~7);
return (__m64) _mm_align_si64 (aligned_p[0], aligned_p[1], align);
#else
struct __una_u64 { __m64 x __attribute__((packed)); };
const struct __una_u64 *ptr = (const struct __una_u64 *) p;
return (__m64) ptr->x;
#endif
}
 
static force_inline uint32_t ldl_u(const uint32_t *p)
{
#ifdef USE_X86_MMX
/* x86's alignment restrictions are very relaxed. */
return *p;
#else
struct __una_u32 { uint32_t x __attribute__((packed)); };
const struct __una_u32 *ptr = (const struct __una_u32 *) p;
return ptr->x;
#endif
}
 
static force_inline __m64
load (const uint32_t *v)
{
#ifdef USE_LOONGSON_MMI
__m64 ret;
asm ("lwc1 %0, %1\n\t"
: "=f" (ret)
: "m" (*v)
);
return ret;
#else
return _mm_cvtsi32_si64 (*v);
#endif
}
 
static force_inline __m64
load8888 (const uint32_t *v)
{
#ifdef USE_LOONGSON_MMI
return _mm_unpacklo_pi8_f (*(__m32 *)v, _mm_setzero_si64 ());
#else
return _mm_unpacklo_pi8 (load (v), _mm_setzero_si64 ());
#endif
}
 
static force_inline __m64
load8888u (const uint32_t *v)
{
uint32_t l = ldl_u (v);
return load8888 (&l);
}
 
static force_inline __m64
pack8888 (__m64 lo, __m64 hi)
{
return _mm_packs_pu16 (lo, hi);
}
 
static force_inline void
store (uint32_t *dest, __m64 v)
{
#ifdef USE_LOONGSON_MMI
asm ("swc1 %1, %0\n\t"
: "=m" (*dest)
: "f" (v)
: "memory"
);
#else
*dest = _mm_cvtsi64_si32 (v);
#endif
}
 
static force_inline void
store8888 (uint32_t *dest, __m64 v)
{
v = pack8888 (v, _mm_setzero_si64 ());
store (dest, v);
}
 
static force_inline pixman_bool_t
is_equal (__m64 a, __m64 b)
{
#ifdef USE_LOONGSON_MMI
/* __m64 is double, we can compare directly. */
return a == b;
#else
return _mm_movemask_pi8 (_mm_cmpeq_pi8 (a, b)) == 0xff;
#endif
}
 
static force_inline pixman_bool_t
is_opaque (__m64 v)
{
#ifdef USE_LOONGSON_MMI
return is_equal (_mm_and_si64 (v, MC (full_alpha)), MC (full_alpha));
#else
__m64 ffs = _mm_cmpeq_pi8 (v, v);
return (_mm_movemask_pi8 (_mm_cmpeq_pi8 (v, ffs)) & 0x40);
#endif
}
 
static force_inline pixman_bool_t
is_zero (__m64 v)
{
return is_equal (v, _mm_setzero_si64 ());
}
 
/* Expand 16 bits positioned at @pos (0-3) of a mmx register into
*
* 00RR00GG00BB
*
* --- Expanding 565 in the low word ---
*
* m = (m << (32 - 3)) | (m << (16 - 5)) | m;
* m = m & (01f0003f001f);
* m = m * (008404100840);
* m = m >> 8;
*
* Note the trick here - the top word is shifted by another nibble to
* avoid it bumping into the middle word
*/
static force_inline __m64
expand565 (__m64 pixel, int pos)
{
__m64 p = pixel;
__m64 t1, t2;
 
/* move pixel to low 16 bit and zero the rest */
#ifdef USE_LOONGSON_MMI
p = loongson_extract_pi16 (p, pos);
#else
p = shift (shift (p, (3 - pos) * 16), -48);
#endif
 
t1 = shift (p, 36 - 11);
t2 = shift (p, 16 - 5);
 
p = _mm_or_si64 (t1, p);
p = _mm_or_si64 (t2, p);
p = _mm_and_si64 (p, MC (565_rgb));
 
pixel = _mm_mullo_pi16 (p, MC (565_unpack_multiplier));
return _mm_srli_pi16 (pixel, 8);
}
 
/* Expand 4 16 bit pixels in an mmx register into two mmx registers of
*
* AARRGGBBRRGGBB
*/
static force_inline void
expand_4xpacked565 (__m64 vin, __m64 *vout0, __m64 *vout1, int full_alpha)
{
__m64 t0, t1, alpha = _mm_setzero_si64 ();
__m64 r = _mm_and_si64 (vin, MC (expand_565_r));
__m64 g = _mm_and_si64 (vin, MC (expand_565_g));
__m64 b = _mm_and_si64 (vin, MC (expand_565_b));
if (full_alpha)
alpha = _mm_cmpeq_pi32 (alpha, alpha);
 
/* Replicate high bits into empty low bits. */
r = _mm_or_si64 (_mm_srli_pi16 (r, 8), _mm_srli_pi16 (r, 13));
g = _mm_or_si64 (_mm_srli_pi16 (g, 3), _mm_srli_pi16 (g, 9));
b = _mm_or_si64 (_mm_slli_pi16 (b, 3), _mm_srli_pi16 (b, 2));
 
r = _mm_packs_pu16 (r, _mm_setzero_si64 ()); /* 00 00 00 00 R3 R2 R1 R0 */
g = _mm_packs_pu16 (g, _mm_setzero_si64 ()); /* 00 00 00 00 G3 G2 G1 G0 */
b = _mm_packs_pu16 (b, _mm_setzero_si64 ()); /* 00 00 00 00 B3 B2 B1 B0 */
 
t1 = _mm_unpacklo_pi8 (r, alpha); /* A3 R3 A2 R2 A1 R1 A0 R0 */
t0 = _mm_unpacklo_pi8 (b, g); /* G3 B3 G2 B2 G1 B1 G0 B0 */
 
*vout0 = _mm_unpacklo_pi16 (t0, t1); /* A1 R1 G1 B1 A0 R0 G0 B0 */
*vout1 = _mm_unpackhi_pi16 (t0, t1); /* A3 R3 G3 B3 A2 R2 G2 B2 */
}
 
static force_inline __m64
expand8888 (__m64 in, int pos)
{
if (pos == 0)
return _mm_unpacklo_pi8 (in, _mm_setzero_si64 ());
else
return _mm_unpackhi_pi8 (in, _mm_setzero_si64 ());
}
 
static force_inline __m64
expandx888 (__m64 in, int pos)
{
return _mm_or_si64 (expand8888 (in, pos), MC (full_alpha));
}
 
static force_inline void
expand_4x565 (__m64 vin, __m64 *vout0, __m64 *vout1, __m64 *vout2, __m64 *vout3, int full_alpha)
{
__m64 v0, v1;
expand_4xpacked565 (vin, &v0, &v1, full_alpha);
*vout0 = expand8888 (v0, 0);
*vout1 = expand8888 (v0, 1);
*vout2 = expand8888 (v1, 0);
*vout3 = expand8888 (v1, 1);
}
 
static force_inline __m64
pack_565 (__m64 pixel, __m64 target, int pos)
{
__m64 p = pixel;
__m64 t = target;
__m64 r, g, b;
 
r = _mm_and_si64 (p, MC (565_r));
g = _mm_and_si64 (p, MC (565_g));
b = _mm_and_si64 (p, MC (565_b));
 
#ifdef USE_LOONGSON_MMI
r = shift (r, -(32 - 8));
g = shift (g, -(16 - 3));
b = shift (b, -(0 + 3));
 
p = _mm_or_si64 (r, g);
p = _mm_or_si64 (p, b);
return loongson_insert_pi16 (t, p, pos);
#else
r = shift (r, -(32 - 8) + pos * 16);
g = shift (g, -(16 - 3) + pos * 16);
b = shift (b, -(0 + 3) + pos * 16);
 
if (pos == 0)
t = _mm_and_si64 (t, MC (mask_0));
else if (pos == 1)
t = _mm_and_si64 (t, MC (mask_1));
else if (pos == 2)
t = _mm_and_si64 (t, MC (mask_2));
else if (pos == 3)
t = _mm_and_si64 (t, MC (mask_3));
 
p = _mm_or_si64 (r, t);
p = _mm_or_si64 (g, p);
 
return _mm_or_si64 (b, p);
#endif
}
 
static force_inline __m64
pack_4xpacked565 (__m64 a, __m64 b)
{
__m64 rb0 = _mm_and_si64 (a, MC (packed_565_rb));
__m64 rb1 = _mm_and_si64 (b, MC (packed_565_rb));
 
__m64 t0 = _mm_madd_pi16 (rb0, MC (565_pack_multiplier));
__m64 t1 = _mm_madd_pi16 (rb1, MC (565_pack_multiplier));
 
__m64 g0 = _mm_and_si64 (a, MC (packed_565_g));
__m64 g1 = _mm_and_si64 (b, MC (packed_565_g));
 
t0 = _mm_or_si64 (t0, g0);
t1 = _mm_or_si64 (t1, g1);
 
t0 = shift(t0, -5);
#ifdef USE_ARM_IWMMXT
t1 = shift(t1, -5);
return _mm_packs_pu32 (t0, t1);
#else
t1 = shift(t1, -5 + 16);
return _mm_shuffle_pi16 (_mm_or_si64 (t0, t1), _MM_SHUFFLE (3, 1, 2, 0));
#endif
}
 
#ifndef _MSC_VER
 
static force_inline __m64
pack_4x565 (__m64 v0, __m64 v1, __m64 v2, __m64 v3)
{
return pack_4xpacked565 (pack8888 (v0, v1), pack8888 (v2, v3));
}
 
static force_inline __m64
pix_add_mul (__m64 x, __m64 a, __m64 y, __m64 b)
{
x = pix_multiply (x, a);
y = pix_multiply (y, b);
 
return pix_add (x, y);
}
 
#else
 
/* MSVC only handles a "pass by register" of up to three SSE intrinsics */
 
#define pack_4x565(v0, v1, v2, v3) \
pack_4xpacked565 (pack8888 (v0, v1), pack8888 (v2, v3))
 
#define pix_add_mul(x, a, y, b) \
( x = pix_multiply (x, a), \
y = pix_multiply (y, b), \
pix_add (x, y) )
 
#endif
 
/* --------------- MMX code patch for fbcompose.c --------------------- */
 
static force_inline __m64
combine (const uint32_t *src, const uint32_t *mask)
{
__m64 vsrc = load8888 (src);
 
if (mask)
{
__m64 m = load8888 (mask);
 
m = expand_alpha (m);
vsrc = pix_multiply (vsrc, m);
}
 
return vsrc;
}
 
static force_inline __m64
core_combine_over_u_pixel_mmx (__m64 vsrc, __m64 vdst)
{
vsrc = _mm_unpacklo_pi8 (vsrc, _mm_setzero_si64 ());
 
if (is_opaque (vsrc))
{
return vsrc;
}
else if (!is_zero (vsrc))
{
return over (vsrc, expand_alpha (vsrc),
_mm_unpacklo_pi8 (vdst, _mm_setzero_si64 ()));
}
 
return _mm_unpacklo_pi8 (vdst, _mm_setzero_si64 ());
}
 
static void
mmx_combine_over_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = dest + width;
 
while (dest < end)
{
__m64 vsrc = combine (src, mask);
 
if (is_opaque (vsrc))
{
store8888 (dest, vsrc);
}
else if (!is_zero (vsrc))
{
__m64 sa = expand_alpha (vsrc);
store8888 (dest, over (vsrc, sa, load8888 (dest)));
}
 
++dest;
++src;
if (mask)
++mask;
}
_mm_empty ();
}
 
static void
mmx_combine_over_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = dest + width;
 
while (dest < end)
{
__m64 d, da;
__m64 s = combine (src, mask);
 
d = load8888 (dest);
da = expand_alpha (d);
store8888 (dest, over (d, da, s));
 
++dest;
++src;
if (mask)
mask++;
}
_mm_empty ();
}
 
static void
mmx_combine_in_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = dest + width;
 
while (dest < end)
{
__m64 a;
__m64 x = combine (src, mask);
 
a = load8888 (dest);
a = expand_alpha (a);
x = pix_multiply (x, a);
 
store8888 (dest, x);
 
++dest;
++src;
if (mask)
mask++;
}
_mm_empty ();
}
 
static void
mmx_combine_in_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = dest + width;
 
while (dest < end)
{
__m64 a = combine (src, mask);
__m64 x;
 
x = load8888 (dest);
a = expand_alpha (a);
x = pix_multiply (x, a);
store8888 (dest, x);
 
++dest;
++src;
if (mask)
mask++;
}
_mm_empty ();
}
 
static void
mmx_combine_out_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = dest + width;
 
while (dest < end)
{
__m64 a;
__m64 x = combine (src, mask);
 
a = load8888 (dest);
a = expand_alpha (a);
a = negate (a);
x = pix_multiply (x, a);
store8888 (dest, x);
 
++dest;
++src;
if (mask)
mask++;
}
_mm_empty ();
}
 
static void
mmx_combine_out_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = dest + width;
 
while (dest < end)
{
__m64 a = combine (src, mask);
__m64 x;
 
x = load8888 (dest);
a = expand_alpha (a);
a = negate (a);
x = pix_multiply (x, a);
 
store8888 (dest, x);
 
++dest;
++src;
if (mask)
mask++;
}
_mm_empty ();
}
 
static void
mmx_combine_atop_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = dest + width;
 
while (dest < end)
{
__m64 da, d, sia;
__m64 s = combine (src, mask);
 
d = load8888 (dest);
sia = expand_alpha (s);
sia = negate (sia);
da = expand_alpha (d);
s = pix_add_mul (s, da, d, sia);
store8888 (dest, s);
 
++dest;
++src;
if (mask)
mask++;
}
_mm_empty ();
}
 
static void
mmx_combine_atop_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end;
 
end = dest + width;
 
while (dest < end)
{
__m64 dia, d, sa;
__m64 s = combine (src, mask);
 
d = load8888 (dest);
sa = expand_alpha (s);
dia = expand_alpha (d);
dia = negate (dia);
s = pix_add_mul (s, dia, d, sa);
store8888 (dest, s);
 
++dest;
++src;
if (mask)
mask++;
}
_mm_empty ();
}
 
static void
mmx_combine_xor_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = dest + width;
 
while (dest < end)
{
__m64 dia, d, sia;
__m64 s = combine (src, mask);
 
d = load8888 (dest);
sia = expand_alpha (s);
dia = expand_alpha (d);
sia = negate (sia);
dia = negate (dia);
s = pix_add_mul (s, dia, d, sia);
store8888 (dest, s);
 
++dest;
++src;
if (mask)
mask++;
}
_mm_empty ();
}
 
static void
mmx_combine_add_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = dest + width;
 
while (dest < end)
{
__m64 d;
__m64 s = combine (src, mask);
 
d = load8888 (dest);
s = pix_add (s, d);
store8888 (dest, s);
 
++dest;
++src;
if (mask)
mask++;
}
_mm_empty ();
}
 
static void
mmx_combine_saturate_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = dest + width;
 
while (dest < end)
{
uint32_t s, sa, da;
uint32_t d = *dest;
__m64 ms = combine (src, mask);
__m64 md = load8888 (dest);
 
store8888(&s, ms);
da = ~d >> 24;
sa = s >> 24;
 
if (sa > da)
{
uint32_t quot = DIV_UN8 (da, sa) << 24;
__m64 msa = load8888 (&quot);
msa = expand_alpha (msa);
ms = pix_multiply (ms, msa);
}
 
md = pix_add (md, ms);
store8888 (dest, md);
 
++src;
++dest;
if (mask)
mask++;
}
_mm_empty ();
}
 
static void
mmx_combine_src_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = src + width;
 
while (src < end)
{
__m64 a = load8888 (mask);
__m64 s = load8888 (src);
 
s = pix_multiply (s, a);
store8888 (dest, s);
 
++src;
++mask;
++dest;
}
_mm_empty ();
}
 
static void
mmx_combine_over_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = src + width;
 
while (src < end)
{
__m64 a = load8888 (mask);
__m64 s = load8888 (src);
__m64 d = load8888 (dest);
__m64 sa = expand_alpha (s);
 
store8888 (dest, in_over (s, sa, a, d));
 
++src;
++dest;
++mask;
}
_mm_empty ();
}
 
static void
mmx_combine_over_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = src + width;
 
while (src < end)
{
__m64 a = load8888 (mask);
__m64 s = load8888 (src);
__m64 d = load8888 (dest);
__m64 da = expand_alpha (d);
 
store8888 (dest, over (d, da, in (s, a)));
 
++src;
++dest;
++mask;
}
_mm_empty ();
}
 
static void
mmx_combine_in_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = src + width;
 
while (src < end)
{
__m64 a = load8888 (mask);
__m64 s = load8888 (src);
__m64 d = load8888 (dest);
__m64 da = expand_alpha (d);
 
s = pix_multiply (s, a);
s = pix_multiply (s, da);
store8888 (dest, s);
 
++src;
++dest;
++mask;
}
_mm_empty ();
}
 
static void
mmx_combine_in_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = src + width;
 
while (src < end)
{
__m64 a = load8888 (mask);
__m64 s = load8888 (src);
__m64 d = load8888 (dest);
__m64 sa = expand_alpha (s);
 
a = pix_multiply (a, sa);
d = pix_multiply (d, a);
store8888 (dest, d);
 
++src;
++dest;
++mask;
}
_mm_empty ();
}
 
static void
mmx_combine_out_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = src + width;
 
while (src < end)
{
__m64 a = load8888 (mask);
__m64 s = load8888 (src);
__m64 d = load8888 (dest);
__m64 da = expand_alpha (d);
 
da = negate (da);
s = pix_multiply (s, a);
s = pix_multiply (s, da);
store8888 (dest, s);
 
++src;
++dest;
++mask;
}
_mm_empty ();
}
 
static void
mmx_combine_out_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = src + width;
 
while (src < end)
{
__m64 a = load8888 (mask);
__m64 s = load8888 (src);
__m64 d = load8888 (dest);
__m64 sa = expand_alpha (s);
 
a = pix_multiply (a, sa);
a = negate (a);
d = pix_multiply (d, a);
store8888 (dest, d);
 
++src;
++dest;
++mask;
}
_mm_empty ();
}
 
static void
mmx_combine_atop_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = src + width;
 
while (src < end)
{
__m64 a = load8888 (mask);
__m64 s = load8888 (src);
__m64 d = load8888 (dest);
__m64 da = expand_alpha (d);
__m64 sa = expand_alpha (s);
 
s = pix_multiply (s, a);
a = pix_multiply (a, sa);
a = negate (a);
d = pix_add_mul (d, a, s, da);
store8888 (dest, d);
 
++src;
++dest;
++mask;
}
_mm_empty ();
}
 
static void
mmx_combine_atop_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = src + width;
 
while (src < end)
{
__m64 a = load8888 (mask);
__m64 s = load8888 (src);
__m64 d = load8888 (dest);
__m64 da = expand_alpha (d);
__m64 sa = expand_alpha (s);
 
s = pix_multiply (s, a);
a = pix_multiply (a, sa);
da = negate (da);
d = pix_add_mul (d, a, s, da);
store8888 (dest, d);
 
++src;
++dest;
++mask;
}
_mm_empty ();
}
 
static void
mmx_combine_xor_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = src + width;
 
while (src < end)
{
__m64 a = load8888 (mask);
__m64 s = load8888 (src);
__m64 d = load8888 (dest);
__m64 da = expand_alpha (d);
__m64 sa = expand_alpha (s);
 
s = pix_multiply (s, a);
a = pix_multiply (a, sa);
da = negate (da);
a = negate (a);
d = pix_add_mul (d, a, s, da);
store8888 (dest, d);
 
++src;
++dest;
++mask;
}
_mm_empty ();
}
 
static void
mmx_combine_add_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
const uint32_t *end = src + width;
 
while (src < end)
{
__m64 a = load8888 (mask);
__m64 s = load8888 (src);
__m64 d = load8888 (dest);
 
s = pix_multiply (s, a);
d = pix_add (s, d);
store8888 (dest, d);
 
++src;
++dest;
++mask;
}
_mm_empty ();
}
 
/* ------------- MMX code paths called from fbpict.c -------------------- */
 
static void
mmx_composite_over_n_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src;
uint32_t *dst_line, *dst;
int32_t w;
int dst_stride;
__m64 vsrc, vsrca;
 
CHECKPOINT ();
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
 
vsrc = load8888 (&src);
vsrca = expand_alpha (vsrc);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
w = width;
 
CHECKPOINT ();
 
while (w && (uintptr_t)dst & 7)
{
store8888 (dst, over (vsrc, vsrca, load8888 (dst)));
 
w--;
dst++;
}
 
while (w >= 2)
{
__m64 vdest;
__m64 dest0, dest1;
 
vdest = *(__m64 *)dst;
 
dest0 = over (vsrc, vsrca, expand8888 (vdest, 0));
dest1 = over (vsrc, vsrca, expand8888 (vdest, 1));
 
*(__m64 *)dst = pack8888 (dest0, dest1);
 
dst += 2;
w -= 2;
}
 
CHECKPOINT ();
 
if (w)
{
store8888 (dst, over (vsrc, vsrca, load8888 (dst)));
}
}
 
_mm_empty ();
}
 
static void
mmx_composite_over_n_0565 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src;
uint16_t *dst_line, *dst;
int32_t w;
int dst_stride;
__m64 vsrc, vsrca;
 
CHECKPOINT ();
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
 
vsrc = load8888 (&src);
vsrca = expand_alpha (vsrc);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
w = width;
 
CHECKPOINT ();
 
while (w && (uintptr_t)dst & 7)
{
uint64_t d = *dst;
__m64 vdest = expand565 (to_m64 (d), 0);
 
vdest = pack_565 (over (vsrc, vsrca, vdest), vdest, 0);
*dst = to_uint64 (vdest);
 
w--;
dst++;
}
 
while (w >= 4)
{
__m64 vdest = *(__m64 *)dst;
__m64 v0, v1, v2, v3;
 
expand_4x565 (vdest, &v0, &v1, &v2, &v3, 0);
 
v0 = over (vsrc, vsrca, v0);
v1 = over (vsrc, vsrca, v1);
v2 = over (vsrc, vsrca, v2);
v3 = over (vsrc, vsrca, v3);
 
*(__m64 *)dst = pack_4x565 (v0, v1, v2, v3);
 
dst += 4;
w -= 4;
}
 
CHECKPOINT ();
 
while (w)
{
uint64_t d = *dst;
__m64 vdest = expand565 (to_m64 (d), 0);
 
vdest = pack_565 (over (vsrc, vsrca, vdest), vdest, 0);
*dst = to_uint64 (vdest);
 
w--;
dst++;
}
}
 
_mm_empty ();
}
 
static void
mmx_composite_over_n_8888_8888_ca (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src;
uint32_t *dst_line;
uint32_t *mask_line;
int dst_stride, mask_stride;
__m64 vsrc, vsrca;
 
CHECKPOINT ();
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint32_t, mask_stride, mask_line, 1);
 
vsrc = load8888 (&src);
vsrca = expand_alpha (vsrc);
 
while (height--)
{
int twidth = width;
uint32_t *p = (uint32_t *)mask_line;
uint32_t *q = (uint32_t *)dst_line;
 
while (twidth && (uintptr_t)q & 7)
{
uint32_t m = *(uint32_t *)p;
 
if (m)
{
__m64 vdest = load8888 (q);
vdest = in_over (vsrc, vsrca, load8888 (&m), vdest);
store8888 (q, vdest);
}
 
twidth--;
p++;
q++;
}
 
while (twidth >= 2)
{
uint32_t m0, m1;
m0 = *p;
m1 = *(p + 1);
 
if (m0 | m1)
{
__m64 dest0, dest1;
__m64 vdest = *(__m64 *)q;
 
dest0 = in_over (vsrc, vsrca, load8888 (&m0),
expand8888 (vdest, 0));
dest1 = in_over (vsrc, vsrca, load8888 (&m1),
expand8888 (vdest, 1));
 
*(__m64 *)q = pack8888 (dest0, dest1);
}
 
p += 2;
q += 2;
twidth -= 2;
}
 
if (twidth)
{
uint32_t m = *(uint32_t *)p;
 
if (m)
{
__m64 vdest = load8888 (q);
vdest = in_over (vsrc, vsrca, load8888 (&m), vdest);
store8888 (q, vdest);
}
 
twidth--;
p++;
q++;
}
 
dst_line += dst_stride;
mask_line += mask_stride;
}
 
_mm_empty ();
}
 
static void
mmx_composite_over_8888_n_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line, *dst;
uint32_t *src_line, *src;
uint32_t mask;
__m64 vmask;
int dst_stride, src_stride;
int32_t w;
 
CHECKPOINT ();
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
mask = _pixman_image_get_solid (imp, mask_image, dest_image->bits.format);
vmask = expand_alpha (load8888 (&mask));
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w && (uintptr_t)dst & 7)
{
__m64 s = load8888 (src);
__m64 d = load8888 (dst);
 
store8888 (dst, in_over (s, expand_alpha (s), vmask, d));
 
w--;
dst++;
src++;
}
 
while (w >= 2)
{
__m64 vs = ldq_u ((__m64 *)src);
__m64 vd = *(__m64 *)dst;
__m64 vsrc0 = expand8888 (vs, 0);
__m64 vsrc1 = expand8888 (vs, 1);
 
*(__m64 *)dst = pack8888 (
in_over (vsrc0, expand_alpha (vsrc0), vmask, expand8888 (vd, 0)),
in_over (vsrc1, expand_alpha (vsrc1), vmask, expand8888 (vd, 1)));
 
w -= 2;
dst += 2;
src += 2;
}
 
if (w)
{
__m64 s = load8888 (src);
__m64 d = load8888 (dst);
 
store8888 (dst, in_over (s, expand_alpha (s), vmask, d));
}
}
 
_mm_empty ();
}
 
static void
mmx_composite_over_x888_n_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line, *dst;
uint32_t *src_line, *src;
uint32_t mask;
__m64 vmask;
int dst_stride, src_stride;
int32_t w;
__m64 srca;
 
CHECKPOINT ();
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
mask = _pixman_image_get_solid (imp, mask_image, dest_image->bits.format);
 
vmask = expand_alpha (load8888 (&mask));
srca = MC (4x00ff);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w && (uintptr_t)dst & 7)
{
uint32_t ssrc = *src | 0xff000000;
__m64 s = load8888 (&ssrc);
__m64 d = load8888 (dst);
 
store8888 (dst, in_over (s, srca, vmask, d));
 
w--;
dst++;
src++;
}
 
while (w >= 16)
{
__m64 vd0 = *(__m64 *)(dst + 0);
__m64 vd1 = *(__m64 *)(dst + 2);
__m64 vd2 = *(__m64 *)(dst + 4);
__m64 vd3 = *(__m64 *)(dst + 6);
__m64 vd4 = *(__m64 *)(dst + 8);
__m64 vd5 = *(__m64 *)(dst + 10);
__m64 vd6 = *(__m64 *)(dst + 12);
__m64 vd7 = *(__m64 *)(dst + 14);
 
__m64 vs0 = ldq_u ((__m64 *)(src + 0));
__m64 vs1 = ldq_u ((__m64 *)(src + 2));
__m64 vs2 = ldq_u ((__m64 *)(src + 4));
__m64 vs3 = ldq_u ((__m64 *)(src + 6));
__m64 vs4 = ldq_u ((__m64 *)(src + 8));
__m64 vs5 = ldq_u ((__m64 *)(src + 10));
__m64 vs6 = ldq_u ((__m64 *)(src + 12));
__m64 vs7 = ldq_u ((__m64 *)(src + 14));
 
vd0 = pack8888 (
in_over (expandx888 (vs0, 0), srca, vmask, expand8888 (vd0, 0)),
in_over (expandx888 (vs0, 1), srca, vmask, expand8888 (vd0, 1)));
 
vd1 = pack8888 (
in_over (expandx888 (vs1, 0), srca, vmask, expand8888 (vd1, 0)),
in_over (expandx888 (vs1, 1), srca, vmask, expand8888 (vd1, 1)));
 
vd2 = pack8888 (
in_over (expandx888 (vs2, 0), srca, vmask, expand8888 (vd2, 0)),
in_over (expandx888 (vs2, 1), srca, vmask, expand8888 (vd2, 1)));
 
vd3 = pack8888 (
in_over (expandx888 (vs3, 0), srca, vmask, expand8888 (vd3, 0)),
in_over (expandx888 (vs3, 1), srca, vmask, expand8888 (vd3, 1)));
 
vd4 = pack8888 (
in_over (expandx888 (vs4, 0), srca, vmask, expand8888 (vd4, 0)),
in_over (expandx888 (vs4, 1), srca, vmask, expand8888 (vd4, 1)));
 
vd5 = pack8888 (
in_over (expandx888 (vs5, 0), srca, vmask, expand8888 (vd5, 0)),
in_over (expandx888 (vs5, 1), srca, vmask, expand8888 (vd5, 1)));
 
vd6 = pack8888 (
in_over (expandx888 (vs6, 0), srca, vmask, expand8888 (vd6, 0)),
in_over (expandx888 (vs6, 1), srca, vmask, expand8888 (vd6, 1)));
 
vd7 = pack8888 (
in_over (expandx888 (vs7, 0), srca, vmask, expand8888 (vd7, 0)),
in_over (expandx888 (vs7, 1), srca, vmask, expand8888 (vd7, 1)));
 
*(__m64 *)(dst + 0) = vd0;
*(__m64 *)(dst + 2) = vd1;
*(__m64 *)(dst + 4) = vd2;
*(__m64 *)(dst + 6) = vd3;
*(__m64 *)(dst + 8) = vd4;
*(__m64 *)(dst + 10) = vd5;
*(__m64 *)(dst + 12) = vd6;
*(__m64 *)(dst + 14) = vd7;
 
w -= 16;
dst += 16;
src += 16;
}
 
while (w)
{
uint32_t ssrc = *src | 0xff000000;
__m64 s = load8888 (&ssrc);
__m64 d = load8888 (dst);
 
store8888 (dst, in_over (s, srca, vmask, d));
 
w--;
dst++;
src++;
}
}
 
_mm_empty ();
}
 
static void
mmx_composite_over_8888_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line, *dst;
uint32_t *src_line, *src;
uint32_t s;
int dst_stride, src_stride;
uint8_t a;
int32_t w;
 
CHECKPOINT ();
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w--)
{
s = *src++;
a = s >> 24;
 
if (a == 0xff)
{
*dst = s;
}
else if (s)
{
__m64 ms, sa;
ms = load8888 (&s);
sa = expand_alpha (ms);
store8888 (dst, over (ms, sa, load8888 (dst)));
}
 
dst++;
}
}
_mm_empty ();
}
 
static void
mmx_composite_over_8888_0565 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint16_t *dst_line, *dst;
uint32_t *src_line, *src;
int dst_stride, src_stride;
int32_t w;
 
CHECKPOINT ();
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
#if 0
/* FIXME */
assert (src_image->drawable == mask_image->drawable);
#endif
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
CHECKPOINT ();
 
while (w && (uintptr_t)dst & 7)
{
__m64 vsrc = load8888 (src);
uint64_t d = *dst;
__m64 vdest = expand565 (to_m64 (d), 0);
 
vdest = pack_565 (
over (vsrc, expand_alpha (vsrc), vdest), vdest, 0);
 
*dst = to_uint64 (vdest);
 
w--;
dst++;
src++;
}
 
CHECKPOINT ();
 
while (w >= 4)
{
__m64 vdest = *(__m64 *)dst;
__m64 v0, v1, v2, v3;
__m64 vsrc0, vsrc1, vsrc2, vsrc3;
 
expand_4x565 (vdest, &v0, &v1, &v2, &v3, 0);
 
vsrc0 = load8888 ((src + 0));
vsrc1 = load8888 ((src + 1));
vsrc2 = load8888 ((src + 2));
vsrc3 = load8888 ((src + 3));
 
v0 = over (vsrc0, expand_alpha (vsrc0), v0);
v1 = over (vsrc1, expand_alpha (vsrc1), v1);
v2 = over (vsrc2, expand_alpha (vsrc2), v2);
v3 = over (vsrc3, expand_alpha (vsrc3), v3);
 
*(__m64 *)dst = pack_4x565 (v0, v1, v2, v3);
 
w -= 4;
dst += 4;
src += 4;
}
 
CHECKPOINT ();
 
while (w)
{
__m64 vsrc = load8888 (src);
uint64_t d = *dst;
__m64 vdest = expand565 (to_m64 (d), 0);
 
vdest = pack_565 (over (vsrc, expand_alpha (vsrc), vdest), vdest, 0);
 
*dst = to_uint64 (vdest);
 
w--;
dst++;
src++;
}
}
 
_mm_empty ();
}
 
static void
mmx_composite_over_n_8_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src, srca;
uint32_t *dst_line, *dst;
uint8_t *mask_line, *mask;
int dst_stride, mask_stride;
int32_t w;
__m64 vsrc, vsrca;
uint64_t srcsrc;
 
CHECKPOINT ();
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
srca = src >> 24;
if (src == 0)
return;
 
srcsrc = (uint64_t)src << 32 | src;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
 
vsrc = load8888 (&src);
vsrca = expand_alpha (vsrc);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
CHECKPOINT ();
 
while (w && (uintptr_t)dst & 7)
{
uint64_t m = *mask;
 
if (m)
{
__m64 vdest = in_over (vsrc, vsrca,
expand_alpha_rev (to_m64 (m)),
load8888 (dst));
 
store8888 (dst, vdest);
}
 
w--;
mask++;
dst++;
}
 
CHECKPOINT ();
 
while (w >= 2)
{
uint64_t m0, m1;
 
m0 = *mask;
m1 = *(mask + 1);
 
if (srca == 0xff && (m0 & m1) == 0xff)
{
*(uint64_t *)dst = srcsrc;
}
else if (m0 | m1)
{
__m64 vdest;
__m64 dest0, dest1;
 
vdest = *(__m64 *)dst;
 
dest0 = in_over (vsrc, vsrca, expand_alpha_rev (to_m64 (m0)),
expand8888 (vdest, 0));
dest1 = in_over (vsrc, vsrca, expand_alpha_rev (to_m64 (m1)),
expand8888 (vdest, 1));
 
*(__m64 *)dst = pack8888 (dest0, dest1);
}
 
mask += 2;
dst += 2;
w -= 2;
}
 
CHECKPOINT ();
 
if (w)
{
uint64_t m = *mask;
 
if (m)
{
__m64 vdest = load8888 (dst);
 
vdest = in_over (
vsrc, vsrca, expand_alpha_rev (to_m64 (m)), vdest);
store8888 (dst, vdest);
}
}
}
 
_mm_empty ();
}
 
static pixman_bool_t
mmx_fill (pixman_implementation_t *imp,
uint32_t * bits,
int stride,
int bpp,
int x,
int y,
int width,
int height,
uint32_t filler)
{
uint64_t fill;
__m64 vfill;
uint32_t byte_width;
uint8_t *byte_line;
 
#if defined __GNUC__ && defined USE_X86_MMX
__m64 v1, v2, v3, v4, v5, v6, v7;
#endif
 
if (bpp != 16 && bpp != 32 && bpp != 8)
return FALSE;
 
if (bpp == 8)
{
stride = stride * (int) sizeof (uint32_t) / 1;
byte_line = (uint8_t *)(((uint8_t *)bits) + stride * y + x);
byte_width = width;
stride *= 1;
filler = (filler & 0xff) * 0x01010101;
}
else if (bpp == 16)
{
stride = stride * (int) sizeof (uint32_t) / 2;
byte_line = (uint8_t *)(((uint16_t *)bits) + stride * y + x);
byte_width = 2 * width;
stride *= 2;
filler = (filler & 0xffff) * 0x00010001;
}
else
{
stride = stride * (int) sizeof (uint32_t) / 4;
byte_line = (uint8_t *)(((uint32_t *)bits) + stride * y + x);
byte_width = 4 * width;
stride *= 4;
}
 
fill = ((uint64_t)filler << 32) | filler;
vfill = to_m64 (fill);
 
#if defined __GNUC__ && defined USE_X86_MMX
__asm__ (
"movq %7, %0\n"
"movq %7, %1\n"
"movq %7, %2\n"
"movq %7, %3\n"
"movq %7, %4\n"
"movq %7, %5\n"
"movq %7, %6\n"
: "=&y" (v1), "=&y" (v2), "=&y" (v3),
"=&y" (v4), "=&y" (v5), "=&y" (v6), "=y" (v7)
: "y" (vfill));
#endif
 
while (height--)
{
int w;
uint8_t *d = byte_line;
 
byte_line += stride;
w = byte_width;
 
if (w >= 1 && ((uintptr_t)d & 1))
{
*(uint8_t *)d = (filler & 0xff);
w--;
d++;
}
 
if (w >= 2 && ((uintptr_t)d & 3))
{
*(uint16_t *)d = filler;
w -= 2;
d += 2;
}
 
while (w >= 4 && ((uintptr_t)d & 7))
{
*(uint32_t *)d = filler;
 
w -= 4;
d += 4;
}
 
while (w >= 64)
{
#if defined __GNUC__ && defined USE_X86_MMX
__asm__ (
"movq %1, (%0)\n"
"movq %2, 8(%0)\n"
"movq %3, 16(%0)\n"
"movq %4, 24(%0)\n"
"movq %5, 32(%0)\n"
"movq %6, 40(%0)\n"
"movq %7, 48(%0)\n"
"movq %8, 56(%0)\n"
:
: "r" (d),
"y" (vfill), "y" (v1), "y" (v2), "y" (v3),
"y" (v4), "y" (v5), "y" (v6), "y" (v7)
: "memory");
#else
*(__m64*) (d + 0) = vfill;
*(__m64*) (d + 8) = vfill;
*(__m64*) (d + 16) = vfill;
*(__m64*) (d + 24) = vfill;
*(__m64*) (d + 32) = vfill;
*(__m64*) (d + 40) = vfill;
*(__m64*) (d + 48) = vfill;
*(__m64*) (d + 56) = vfill;
#endif
w -= 64;
d += 64;
}
 
while (w >= 4)
{
*(uint32_t *)d = filler;
 
w -= 4;
d += 4;
}
if (w >= 2)
{
*(uint16_t *)d = filler;
w -= 2;
d += 2;
}
if (w >= 1)
{
*(uint8_t *)d = (filler & 0xff);
w--;
d++;
}
 
}
 
_mm_empty ();
return TRUE;
}
 
static void
mmx_composite_src_x888_0565 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint16_t *dst_line, *dst;
uint32_t *src_line, *src, s;
int dst_stride, src_stride;
int32_t w;
 
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w && (uintptr_t)dst & 7)
{
s = *src++;
*dst = convert_8888_to_0565 (s);
dst++;
w--;
}
 
while (w >= 4)
{
__m64 vdest;
__m64 vsrc0 = ldq_u ((__m64 *)(src + 0));
__m64 vsrc1 = ldq_u ((__m64 *)(src + 2));
 
vdest = pack_4xpacked565 (vsrc0, vsrc1);
 
*(__m64 *)dst = vdest;
 
w -= 4;
src += 4;
dst += 4;
}
 
while (w)
{
s = *src++;
*dst = convert_8888_to_0565 (s);
dst++;
w--;
}
}
 
_mm_empty ();
}
 
static void
mmx_composite_src_n_8_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src, srca;
uint32_t *dst_line, *dst;
uint8_t *mask_line, *mask;
int dst_stride, mask_stride;
int32_t w;
__m64 vsrc;
uint64_t srcsrc;
 
CHECKPOINT ();
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
srca = src >> 24;
if (src == 0)
{
mmx_fill (imp, dest_image->bits.bits, dest_image->bits.rowstride,
PIXMAN_FORMAT_BPP (dest_image->bits.format),
dest_x, dest_y, width, height, 0);
return;
}
 
srcsrc = (uint64_t)src << 32 | src;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
 
vsrc = load8888 (&src);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
CHECKPOINT ();
 
while (w && (uintptr_t)dst & 7)
{
uint64_t m = *mask;
 
if (m)
{
__m64 vdest = in (vsrc, expand_alpha_rev (to_m64 (m)));
 
store8888 (dst, vdest);
}
else
{
*dst = 0;
}
 
w--;
mask++;
dst++;
}
 
CHECKPOINT ();
 
while (w >= 2)
{
uint64_t m0, m1;
m0 = *mask;
m1 = *(mask + 1);
 
if (srca == 0xff && (m0 & m1) == 0xff)
{
*(uint64_t *)dst = srcsrc;
}
else if (m0 | m1)
{
__m64 dest0, dest1;
 
dest0 = in (vsrc, expand_alpha_rev (to_m64 (m0)));
dest1 = in (vsrc, expand_alpha_rev (to_m64 (m1)));
 
*(__m64 *)dst = pack8888 (dest0, dest1);
}
else
{
*(uint64_t *)dst = 0;
}
 
mask += 2;
dst += 2;
w -= 2;
}
 
CHECKPOINT ();
 
if (w)
{
uint64_t m = *mask;
 
if (m)
{
__m64 vdest = load8888 (dst);
 
vdest = in (vsrc, expand_alpha_rev (to_m64 (m)));
store8888 (dst, vdest);
}
else
{
*dst = 0;
}
}
}
 
_mm_empty ();
}
 
static void
mmx_composite_over_n_8_0565 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src, srca;
uint16_t *dst_line, *dst;
uint8_t *mask_line, *mask;
int dst_stride, mask_stride;
int32_t w;
__m64 vsrc, vsrca, tmp;
__m64 srcsrcsrcsrc;
 
CHECKPOINT ();
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
srca = src >> 24;
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
 
vsrc = load8888 (&src);
vsrca = expand_alpha (vsrc);
 
tmp = pack_565 (vsrc, _mm_setzero_si64 (), 0);
srcsrcsrcsrc = expand_alpha_rev (tmp);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
CHECKPOINT ();
 
while (w && (uintptr_t)dst & 7)
{
uint64_t m = *mask;
 
if (m)
{
uint64_t d = *dst;
__m64 vd = to_m64 (d);
__m64 vdest = in_over (
vsrc, vsrca, expand_alpha_rev (to_m64 (m)), expand565 (vd, 0));
 
vd = pack_565 (vdest, _mm_setzero_si64 (), 0);
*dst = to_uint64 (vd);
}
 
w--;
mask++;
dst++;
}
 
CHECKPOINT ();
 
while (w >= 4)
{
uint64_t m0, m1, m2, m3;
m0 = *mask;
m1 = *(mask + 1);
m2 = *(mask + 2);
m3 = *(mask + 3);
 
if (srca == 0xff && (m0 & m1 & m2 & m3) == 0xff)
{
*(__m64 *)dst = srcsrcsrcsrc;
}
else if (m0 | m1 | m2 | m3)
{
__m64 vdest = *(__m64 *)dst;
__m64 v0, v1, v2, v3;
__m64 vm0, vm1, vm2, vm3;
 
expand_4x565 (vdest, &v0, &v1, &v2, &v3, 0);
 
vm0 = to_m64 (m0);
v0 = in_over (vsrc, vsrca, expand_alpha_rev (vm0), v0);
 
vm1 = to_m64 (m1);
v1 = in_over (vsrc, vsrca, expand_alpha_rev (vm1), v1);
 
vm2 = to_m64 (m2);
v2 = in_over (vsrc, vsrca, expand_alpha_rev (vm2), v2);
 
vm3 = to_m64 (m3);
v3 = in_over (vsrc, vsrca, expand_alpha_rev (vm3), v3);
 
*(__m64 *)dst = pack_4x565 (v0, v1, v2, v3);;
}
 
w -= 4;
mask += 4;
dst += 4;
}
 
CHECKPOINT ();
 
while (w)
{
uint64_t m = *mask;
 
if (m)
{
uint64_t d = *dst;
__m64 vd = to_m64 (d);
__m64 vdest = in_over (vsrc, vsrca, expand_alpha_rev (to_m64 (m)),
expand565 (vd, 0));
vd = pack_565 (vdest, _mm_setzero_si64 (), 0);
*dst = to_uint64 (vd);
}
 
w--;
mask++;
dst++;
}
}
 
_mm_empty ();
}
 
static void
mmx_composite_over_pixbuf_0565 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint16_t *dst_line, *dst;
uint32_t *src_line, *src;
int dst_stride, src_stride;
int32_t w;
 
CHECKPOINT ();
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
#if 0
/* FIXME */
assert (src_image->drawable == mask_image->drawable);
#endif
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
CHECKPOINT ();
 
while (w && (uintptr_t)dst & 7)
{
__m64 vsrc = load8888 (src);
uint64_t d = *dst;
__m64 vdest = expand565 (to_m64 (d), 0);
 
vdest = pack_565 (over_rev_non_pre (vsrc, vdest), vdest, 0);
 
*dst = to_uint64 (vdest);
 
w--;
dst++;
src++;
}
 
CHECKPOINT ();
 
while (w >= 4)
{
uint32_t s0, s1, s2, s3;
unsigned char a0, a1, a2, a3;
 
s0 = *src;
s1 = *(src + 1);
s2 = *(src + 2);
s3 = *(src + 3);
 
a0 = (s0 >> 24);
a1 = (s1 >> 24);
a2 = (s2 >> 24);
a3 = (s3 >> 24);
 
if ((a0 & a1 & a2 & a3) == 0xFF)
{
__m64 v0 = invert_colors (load8888 (&s0));
__m64 v1 = invert_colors (load8888 (&s1));
__m64 v2 = invert_colors (load8888 (&s2));
__m64 v3 = invert_colors (load8888 (&s3));
 
*(__m64 *)dst = pack_4x565 (v0, v1, v2, v3);
}
else if (s0 | s1 | s2 | s3)
{
__m64 vdest = *(__m64 *)dst;
__m64 v0, v1, v2, v3;
 
__m64 vsrc0 = load8888 (&s0);
__m64 vsrc1 = load8888 (&s1);
__m64 vsrc2 = load8888 (&s2);
__m64 vsrc3 = load8888 (&s3);
 
expand_4x565 (vdest, &v0, &v1, &v2, &v3, 0);
 
v0 = over_rev_non_pre (vsrc0, v0);
v1 = over_rev_non_pre (vsrc1, v1);
v2 = over_rev_non_pre (vsrc2, v2);
v3 = over_rev_non_pre (vsrc3, v3);
 
*(__m64 *)dst = pack_4x565 (v0, v1, v2, v3);
}
 
w -= 4;
dst += 4;
src += 4;
}
 
CHECKPOINT ();
 
while (w)
{
__m64 vsrc = load8888 (src);
uint64_t d = *dst;
__m64 vdest = expand565 (to_m64 (d), 0);
 
vdest = pack_565 (over_rev_non_pre (vsrc, vdest), vdest, 0);
 
*dst = to_uint64 (vdest);
 
w--;
dst++;
src++;
}
}
 
_mm_empty ();
}
 
static void
mmx_composite_over_pixbuf_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line, *dst;
uint32_t *src_line, *src;
int dst_stride, src_stride;
int32_t w;
 
CHECKPOINT ();
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
#if 0
/* FIXME */
assert (src_image->drawable == mask_image->drawable);
#endif
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w && (uintptr_t)dst & 7)
{
__m64 s = load8888 (src);
__m64 d = load8888 (dst);
 
store8888 (dst, over_rev_non_pre (s, d));
 
w--;
dst++;
src++;
}
 
while (w >= 2)
{
uint32_t s0, s1;
unsigned char a0, a1;
__m64 d0, d1;
 
s0 = *src;
s1 = *(src + 1);
 
a0 = (s0 >> 24);
a1 = (s1 >> 24);
 
if ((a0 & a1) == 0xFF)
{
d0 = invert_colors (load8888 (&s0));
d1 = invert_colors (load8888 (&s1));
 
*(__m64 *)dst = pack8888 (d0, d1);
}
else if (s0 | s1)
{
__m64 vdest = *(__m64 *)dst;
 
d0 = over_rev_non_pre (load8888 (&s0), expand8888 (vdest, 0));
d1 = over_rev_non_pre (load8888 (&s1), expand8888 (vdest, 1));
 
*(__m64 *)dst = pack8888 (d0, d1);
}
 
w -= 2;
dst += 2;
src += 2;
}
 
if (w)
{
__m64 s = load8888 (src);
__m64 d = load8888 (dst);
 
store8888 (dst, over_rev_non_pre (s, d));
}
}
 
_mm_empty ();
}
 
static void
mmx_composite_over_n_8888_0565_ca (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src;
uint16_t *dst_line;
uint32_t *mask_line;
int dst_stride, mask_stride;
__m64 vsrc, vsrca;
 
CHECKPOINT ();
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint32_t, mask_stride, mask_line, 1);
 
vsrc = load8888 (&src);
vsrca = expand_alpha (vsrc);
 
while (height--)
{
int twidth = width;
uint32_t *p = (uint32_t *)mask_line;
uint16_t *q = (uint16_t *)dst_line;
 
while (twidth && ((uintptr_t)q & 7))
{
uint32_t m = *(uint32_t *)p;
 
if (m)
{
uint64_t d = *q;
__m64 vdest = expand565 (to_m64 (d), 0);
vdest = pack_565 (in_over (vsrc, vsrca, load8888 (&m), vdest), vdest, 0);
*q = to_uint64 (vdest);
}
 
twidth--;
p++;
q++;
}
 
while (twidth >= 4)
{
uint32_t m0, m1, m2, m3;
 
m0 = *p;
m1 = *(p + 1);
m2 = *(p + 2);
m3 = *(p + 3);
 
if ((m0 | m1 | m2 | m3))
{
__m64 vdest = *(__m64 *)q;
__m64 v0, v1, v2, v3;
 
expand_4x565 (vdest, &v0, &v1, &v2, &v3, 0);
 
v0 = in_over (vsrc, vsrca, load8888 (&m0), v0);
v1 = in_over (vsrc, vsrca, load8888 (&m1), v1);
v2 = in_over (vsrc, vsrca, load8888 (&m2), v2);
v3 = in_over (vsrc, vsrca, load8888 (&m3), v3);
 
*(__m64 *)q = pack_4x565 (v0, v1, v2, v3);
}
twidth -= 4;
p += 4;
q += 4;
}
 
while (twidth)
{
uint32_t m;
 
m = *(uint32_t *)p;
if (m)
{
uint64_t d = *q;
__m64 vdest = expand565 (to_m64 (d), 0);
vdest = pack_565 (in_over (vsrc, vsrca, load8888 (&m), vdest), vdest, 0);
*q = to_uint64 (vdest);
}
 
twidth--;
p++;
q++;
}
 
mask_line += mask_stride;
dst_line += dst_stride;
}
 
_mm_empty ();
}
 
static void
mmx_composite_in_n_8_8 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint8_t *dst_line, *dst;
uint8_t *mask_line, *mask;
int dst_stride, mask_stride;
int32_t w;
uint32_t src;
uint8_t sa;
__m64 vsrc, vsrca;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
sa = src >> 24;
 
vsrc = load8888 (&src);
vsrca = expand_alpha (vsrc);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w && (uintptr_t)dst & 7)
{
uint16_t tmp;
uint8_t a;
uint32_t m, d;
 
a = *mask++;
d = *dst;
 
m = MUL_UN8 (sa, a, tmp);
d = MUL_UN8 (m, d, tmp);
 
*dst++ = d;
w--;
}
 
while (w >= 4)
{
__m64 vmask;
__m64 vdest;
 
vmask = load8888u ((uint32_t *)mask);
vdest = load8888 ((uint32_t *)dst);
 
store8888 ((uint32_t *)dst, in (in (vsrca, vmask), vdest));
 
dst += 4;
mask += 4;
w -= 4;
}
 
while (w--)
{
uint16_t tmp;
uint8_t a;
uint32_t m, d;
 
a = *mask++;
d = *dst;
 
m = MUL_UN8 (sa, a, tmp);
d = MUL_UN8 (m, d, tmp);
 
*dst++ = d;
}
}
 
_mm_empty ();
}
 
static void
mmx_composite_in_8_8 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint8_t *dst_line, *dst;
uint8_t *src_line, *src;
int src_stride, dst_stride;
int32_t w;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint8_t, src_stride, src_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w && (uintptr_t)dst & 3)
{
uint8_t s, d;
uint16_t tmp;
 
s = *src;
d = *dst;
 
*dst = MUL_UN8 (s, d, tmp);
 
src++;
dst++;
w--;
}
 
while (w >= 4)
{
uint32_t *s = (uint32_t *)src;
uint32_t *d = (uint32_t *)dst;
 
store8888 (d, in (load8888u (s), load8888 (d)));
 
w -= 4;
dst += 4;
src += 4;
}
 
while (w--)
{
uint8_t s, d;
uint16_t tmp;
 
s = *src;
d = *dst;
 
*dst = MUL_UN8 (s, d, tmp);
 
src++;
dst++;
}
}
 
_mm_empty ();
}
 
static void
mmx_composite_add_n_8_8 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint8_t *dst_line, *dst;
uint8_t *mask_line, *mask;
int dst_stride, mask_stride;
int32_t w;
uint32_t src;
uint8_t sa;
__m64 vsrc, vsrca;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
sa = src >> 24;
 
if (src == 0)
return;
 
vsrc = load8888 (&src);
vsrca = expand_alpha (vsrc);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w && (uintptr_t)dst & 3)
{
uint16_t tmp;
uint16_t a;
uint32_t m, d;
uint32_t r;
 
a = *mask++;
d = *dst;
 
m = MUL_UN8 (sa, a, tmp);
r = ADD_UN8 (m, d, tmp);
 
*dst++ = r;
w--;
}
 
while (w >= 4)
{
__m64 vmask;
__m64 vdest;
 
vmask = load8888u ((uint32_t *)mask);
vdest = load8888 ((uint32_t *)dst);
 
store8888 ((uint32_t *)dst, _mm_adds_pu8 (in (vsrca, vmask), vdest));
 
dst += 4;
mask += 4;
w -= 4;
}
 
while (w--)
{
uint16_t tmp;
uint16_t a;
uint32_t m, d;
uint32_t r;
 
a = *mask++;
d = *dst;
 
m = MUL_UN8 (sa, a, tmp);
r = ADD_UN8 (m, d, tmp);
 
*dst++ = r;
}
}
 
_mm_empty ();
}
 
static void
mmx_composite_add_8_8 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint8_t *dst_line, *dst;
uint8_t *src_line, *src;
int dst_stride, src_stride;
int32_t w;
uint8_t s, d;
uint16_t t;
 
CHECKPOINT ();
 
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint8_t, src_stride, src_line, 1);
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w && (uintptr_t)dst & 7)
{
s = *src;
d = *dst;
t = d + s;
s = t | (0 - (t >> 8));
*dst = s;
 
dst++;
src++;
w--;
}
 
while (w >= 8)
{
*(__m64*)dst = _mm_adds_pu8 (ldq_u ((__m64 *)src), *(__m64*)dst);
dst += 8;
src += 8;
w -= 8;
}
 
while (w)
{
s = *src;
d = *dst;
t = d + s;
s = t | (0 - (t >> 8));
*dst = s;
 
dst++;
src++;
w--;
}
}
 
_mm_empty ();
}
 
static void
mmx_composite_add_0565_0565 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint16_t *dst_line, *dst;
uint32_t d;
uint16_t *src_line, *src;
uint32_t s;
int dst_stride, src_stride;
int32_t w;
 
CHECKPOINT ();
 
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint16_t, src_stride, src_line, 1);
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w && (uintptr_t)dst & 7)
{
s = *src++;
if (s)
{
d = *dst;
s = convert_0565_to_8888 (s);
if (d)
{
d = convert_0565_to_8888 (d);
UN8x4_ADD_UN8x4 (s, d);
}
*dst = convert_8888_to_0565 (s);
}
dst++;
w--;
}
 
while (w >= 4)
{
__m64 vdest = *(__m64 *)dst;
__m64 vsrc = ldq_u ((__m64 *)src);
__m64 vd0, vd1;
__m64 vs0, vs1;
 
expand_4xpacked565 (vdest, &vd0, &vd1, 0);
expand_4xpacked565 (vsrc, &vs0, &vs1, 0);
 
vd0 = _mm_adds_pu8 (vd0, vs0);
vd1 = _mm_adds_pu8 (vd1, vs1);
 
*(__m64 *)dst = pack_4xpacked565 (vd0, vd1);
 
dst += 4;
src += 4;
w -= 4;
}
 
while (w--)
{
s = *src++;
if (s)
{
d = *dst;
s = convert_0565_to_8888 (s);
if (d)
{
d = convert_0565_to_8888 (d);
UN8x4_ADD_UN8x4 (s, d);
}
*dst = convert_8888_to_0565 (s);
}
dst++;
}
}
 
_mm_empty ();
}
 
static void
mmx_composite_add_8888_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line, *dst;
uint32_t *src_line, *src;
int dst_stride, src_stride;
int32_t w;
 
CHECKPOINT ();
 
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w && (uintptr_t)dst & 7)
{
store (dst, _mm_adds_pu8 (load ((const uint32_t *)src),
load ((const uint32_t *)dst)));
dst++;
src++;
w--;
}
 
while (w >= 2)
{
*(__m64 *)dst = _mm_adds_pu8 (ldq_u ((__m64 *)src), *(__m64*)dst);
dst += 2;
src += 2;
w -= 2;
}
 
if (w)
{
store (dst, _mm_adds_pu8 (load ((const uint32_t *)src),
load ((const uint32_t *)dst)));
 
}
}
 
_mm_empty ();
}
 
static pixman_bool_t
mmx_blt (pixman_implementation_t *imp,
uint32_t * src_bits,
uint32_t * dst_bits,
int src_stride,
int dst_stride,
int src_bpp,
int dst_bpp,
int src_x,
int src_y,
int dest_x,
int dest_y,
int width,
int height)
{
uint8_t * src_bytes;
uint8_t * dst_bytes;
int byte_width;
 
if (src_bpp != dst_bpp)
return FALSE;
 
if (src_bpp == 16)
{
src_stride = src_stride * (int) sizeof (uint32_t) / 2;
dst_stride = dst_stride * (int) sizeof (uint32_t) / 2;
src_bytes = (uint8_t *)(((uint16_t *)src_bits) + src_stride * (src_y) + (src_x));
dst_bytes = (uint8_t *)(((uint16_t *)dst_bits) + dst_stride * (dest_y) + (dest_x));
byte_width = 2 * width;
src_stride *= 2;
dst_stride *= 2;
}
else if (src_bpp == 32)
{
src_stride = src_stride * (int) sizeof (uint32_t) / 4;
dst_stride = dst_stride * (int) sizeof (uint32_t) / 4;
src_bytes = (uint8_t *)(((uint32_t *)src_bits) + src_stride * (src_y) + (src_x));
dst_bytes = (uint8_t *)(((uint32_t *)dst_bits) + dst_stride * (dest_y) + (dest_x));
byte_width = 4 * width;
src_stride *= 4;
dst_stride *= 4;
}
else
{
return FALSE;
}
 
while (height--)
{
int w;
uint8_t *s = src_bytes;
uint8_t *d = dst_bytes;
src_bytes += src_stride;
dst_bytes += dst_stride;
w = byte_width;
 
if (w >= 1 && ((uintptr_t)d & 1))
{
*(uint8_t *)d = *(uint8_t *)s;
w -= 1;
s += 1;
d += 1;
}
 
if (w >= 2 && ((uintptr_t)d & 3))
{
*(uint16_t *)d = *(uint16_t *)s;
w -= 2;
s += 2;
d += 2;
}
 
while (w >= 4 && ((uintptr_t)d & 7))
{
*(uint32_t *)d = ldl_u ((uint32_t *)s);
 
w -= 4;
s += 4;
d += 4;
}
 
while (w >= 64)
{
#if (defined (__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590))) && defined USE_X86_MMX
__asm__ (
"movq (%1), %%mm0\n"
"movq 8(%1), %%mm1\n"
"movq 16(%1), %%mm2\n"
"movq 24(%1), %%mm3\n"
"movq 32(%1), %%mm4\n"
"movq 40(%1), %%mm5\n"
"movq 48(%1), %%mm6\n"
"movq 56(%1), %%mm7\n"
 
"movq %%mm0, (%0)\n"
"movq %%mm1, 8(%0)\n"
"movq %%mm2, 16(%0)\n"
"movq %%mm3, 24(%0)\n"
"movq %%mm4, 32(%0)\n"
"movq %%mm5, 40(%0)\n"
"movq %%mm6, 48(%0)\n"
"movq %%mm7, 56(%0)\n"
:
: "r" (d), "r" (s)
: "memory",
"%mm0", "%mm1", "%mm2", "%mm3",
"%mm4", "%mm5", "%mm6", "%mm7");
#else
__m64 v0 = ldq_u ((__m64 *)(s + 0));
__m64 v1 = ldq_u ((__m64 *)(s + 8));
__m64 v2 = ldq_u ((__m64 *)(s + 16));
__m64 v3 = ldq_u ((__m64 *)(s + 24));
__m64 v4 = ldq_u ((__m64 *)(s + 32));
__m64 v5 = ldq_u ((__m64 *)(s + 40));
__m64 v6 = ldq_u ((__m64 *)(s + 48));
__m64 v7 = ldq_u ((__m64 *)(s + 56));
*(__m64 *)(d + 0) = v0;
*(__m64 *)(d + 8) = v1;
*(__m64 *)(d + 16) = v2;
*(__m64 *)(d + 24) = v3;
*(__m64 *)(d + 32) = v4;
*(__m64 *)(d + 40) = v5;
*(__m64 *)(d + 48) = v6;
*(__m64 *)(d + 56) = v7;
#endif
 
w -= 64;
s += 64;
d += 64;
}
while (w >= 4)
{
*(uint32_t *)d = ldl_u ((uint32_t *)s);
 
w -= 4;
s += 4;
d += 4;
}
if (w >= 2)
{
*(uint16_t *)d = *(uint16_t *)s;
w -= 2;
s += 2;
d += 2;
}
}
 
_mm_empty ();
 
return TRUE;
}
 
static void
mmx_composite_copy_area (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
 
mmx_blt (imp, src_image->bits.bits,
dest_image->bits.bits,
src_image->bits.rowstride,
dest_image->bits.rowstride,
PIXMAN_FORMAT_BPP (src_image->bits.format),
PIXMAN_FORMAT_BPP (dest_image->bits.format),
src_x, src_y, dest_x, dest_y, width, height);
}
 
static void
mmx_composite_over_x888_8_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *src, *src_line;
uint32_t *dst, *dst_line;
uint8_t *mask, *mask_line;
int src_stride, mask_stride, dst_stride;
int32_t w;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
while (height--)
{
src = src_line;
src_line += src_stride;
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
 
w = width;
 
while (w--)
{
uint64_t m = *mask;
 
if (m)
{
uint32_t ssrc = *src | 0xff000000;
__m64 s = load8888 (&ssrc);
 
if (m == 0xff)
{
store8888 (dst, s);
}
else
{
__m64 sa = expand_alpha (s);
__m64 vm = expand_alpha_rev (to_m64 (m));
__m64 vdest = in_over (s, sa, vm, load8888 (dst));
 
store8888 (dst, vdest);
}
}
 
mask++;
dst++;
src++;
}
}
 
_mm_empty ();
}
 
static void
mmx_composite_over_reverse_n_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src;
uint32_t *dst_line, *dst;
int32_t w;
int dst_stride;
__m64 vsrc;
 
CHECKPOINT ();
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
 
vsrc = load8888 (&src);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
w = width;
 
CHECKPOINT ();
 
while (w && (uintptr_t)dst & 7)
{
__m64 vdest = load8888 (dst);
 
store8888 (dst, over (vdest, expand_alpha (vdest), vsrc));
 
w--;
dst++;
}
 
while (w >= 2)
{
__m64 vdest = *(__m64 *)dst;
__m64 dest0 = expand8888 (vdest, 0);
__m64 dest1 = expand8888 (vdest, 1);
 
 
dest0 = over (dest0, expand_alpha (dest0), vsrc);
dest1 = over (dest1, expand_alpha (dest1), vsrc);
 
*(__m64 *)dst = pack8888 (dest0, dest1);
 
dst += 2;
w -= 2;
}
 
CHECKPOINT ();
 
if (w)
{
__m64 vdest = load8888 (dst);
 
store8888 (dst, over (vdest, expand_alpha (vdest), vsrc));
}
}
 
_mm_empty ();
}
 
#define BSHIFT ((1 << BILINEAR_INTERPOLATION_BITS))
#define BMSK (BSHIFT - 1)
 
#define BILINEAR_DECLARE_VARIABLES \
const __m64 mm_wt = _mm_set_pi16 (wt, wt, wt, wt); \
const __m64 mm_wb = _mm_set_pi16 (wb, wb, wb, wb); \
const __m64 mm_BSHIFT = _mm_set_pi16 (BSHIFT, BSHIFT, BSHIFT, BSHIFT); \
const __m64 mm_addc7 = _mm_set_pi16 (0, 1, 0, 1); \
const __m64 mm_xorc7 = _mm_set_pi16 (0, BMSK, 0, BMSK); \
const __m64 mm_ux = _mm_set_pi16 (unit_x, unit_x, unit_x, unit_x); \
const __m64 mm_zero = _mm_setzero_si64 (); \
__m64 mm_x = _mm_set_pi16 (vx, vx, vx, vx)
 
#define BILINEAR_INTERPOLATE_ONE_PIXEL(pix) \
do { \
/* fetch 2x2 pixel block into 2 mmx registers */ \
__m64 t = ldq_u ((__m64 *)&src_top [pixman_fixed_to_int (vx)]); \
__m64 b = ldq_u ((__m64 *)&src_bottom [pixman_fixed_to_int (vx)]); \
/* vertical interpolation */ \
__m64 t_hi = _mm_mullo_pi16 (_mm_unpackhi_pi8 (t, mm_zero), mm_wt); \
__m64 t_lo = _mm_mullo_pi16 (_mm_unpacklo_pi8 (t, mm_zero), mm_wt); \
__m64 b_hi = _mm_mullo_pi16 (_mm_unpackhi_pi8 (b, mm_zero), mm_wb); \
__m64 b_lo = _mm_mullo_pi16 (_mm_unpacklo_pi8 (b, mm_zero), mm_wb); \
__m64 hi = _mm_add_pi16 (t_hi, b_hi); \
__m64 lo = _mm_add_pi16 (t_lo, b_lo); \
vx += unit_x; \
if (BILINEAR_INTERPOLATION_BITS < 8) \
{ \
/* calculate horizontal weights */ \
__m64 mm_wh = _mm_add_pi16 (mm_addc7, _mm_xor_si64 (mm_xorc7, \
_mm_srli_pi16 (mm_x, \
16 - BILINEAR_INTERPOLATION_BITS))); \
/* horizontal interpolation */ \
__m64 p = _mm_unpacklo_pi16 (lo, hi); \
__m64 q = _mm_unpackhi_pi16 (lo, hi); \
lo = _mm_madd_pi16 (p, mm_wh); \
hi = _mm_madd_pi16 (q, mm_wh); \
} \
else \
{ \
/* calculate horizontal weights */ \
__m64 mm_wh_lo = _mm_sub_pi16 (mm_BSHIFT, _mm_srli_pi16 (mm_x, \
16 - BILINEAR_INTERPOLATION_BITS)); \
__m64 mm_wh_hi = _mm_srli_pi16 (mm_x, \
16 - BILINEAR_INTERPOLATION_BITS); \
/* horizontal interpolation */ \
__m64 mm_lo_lo = _mm_mullo_pi16 (lo, mm_wh_lo); \
__m64 mm_lo_hi = _mm_mullo_pi16 (hi, mm_wh_hi); \
__m64 mm_hi_lo = _mm_mulhi_pu16 (lo, mm_wh_lo); \
__m64 mm_hi_hi = _mm_mulhi_pu16 (hi, mm_wh_hi); \
lo = _mm_add_pi32 (_mm_unpacklo_pi16 (mm_lo_lo, mm_hi_lo), \
_mm_unpacklo_pi16 (mm_lo_hi, mm_hi_hi)); \
hi = _mm_add_pi32 (_mm_unpackhi_pi16 (mm_lo_lo, mm_hi_lo), \
_mm_unpackhi_pi16 (mm_lo_hi, mm_hi_hi)); \
} \
mm_x = _mm_add_pi16 (mm_x, mm_ux); \
/* shift and pack the result */ \
hi = _mm_srli_pi32 (hi, BILINEAR_INTERPOLATION_BITS * 2); \
lo = _mm_srli_pi32 (lo, BILINEAR_INTERPOLATION_BITS * 2); \
lo = _mm_packs_pi32 (lo, hi); \
lo = _mm_packs_pu16 (lo, lo); \
pix = lo; \
} while (0)
 
#define BILINEAR_SKIP_ONE_PIXEL() \
do { \
vx += unit_x; \
mm_x = _mm_add_pi16 (mm_x, mm_ux); \
} while(0)
 
static force_inline void
scaled_bilinear_scanline_mmx_8888_8888_SRC (uint32_t * dst,
const uint32_t * mask,
const uint32_t * src_top,
const uint32_t * src_bottom,
int32_t w,
int wt,
int wb,
pixman_fixed_t vx,
pixman_fixed_t unit_x,
pixman_fixed_t max_vx,
pixman_bool_t zero_src)
{
BILINEAR_DECLARE_VARIABLES;
__m64 pix;
 
while (w--)
{
BILINEAR_INTERPOLATE_ONE_PIXEL (pix);
store (dst, pix);
dst++;
}
 
_mm_empty ();
}
 
FAST_BILINEAR_MAINLOOP_COMMON (mmx_8888_8888_cover_SRC,
scaled_bilinear_scanline_mmx_8888_8888_SRC,
uint32_t, uint32_t, uint32_t,
COVER, FLAG_NONE)
FAST_BILINEAR_MAINLOOP_COMMON (mmx_8888_8888_pad_SRC,
scaled_bilinear_scanline_mmx_8888_8888_SRC,
uint32_t, uint32_t, uint32_t,
PAD, FLAG_NONE)
FAST_BILINEAR_MAINLOOP_COMMON (mmx_8888_8888_none_SRC,
scaled_bilinear_scanline_mmx_8888_8888_SRC,
uint32_t, uint32_t, uint32_t,
NONE, FLAG_NONE)
FAST_BILINEAR_MAINLOOP_COMMON (mmx_8888_8888_normal_SRC,
scaled_bilinear_scanline_mmx_8888_8888_SRC,
uint32_t, uint32_t, uint32_t,
NORMAL, FLAG_NONE)
 
static force_inline void
scaled_bilinear_scanline_mmx_8888_8888_OVER (uint32_t * dst,
const uint32_t * mask,
const uint32_t * src_top,
const uint32_t * src_bottom,
int32_t w,
int wt,
int wb,
pixman_fixed_t vx,
pixman_fixed_t unit_x,
pixman_fixed_t max_vx,
pixman_bool_t zero_src)
{
BILINEAR_DECLARE_VARIABLES;
__m64 pix1, pix2;
 
while (w)
{
BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
 
if (!is_zero (pix1))
{
pix2 = load (dst);
store8888 (dst, core_combine_over_u_pixel_mmx (pix1, pix2));
}
 
w--;
dst++;
}
 
_mm_empty ();
}
 
FAST_BILINEAR_MAINLOOP_COMMON (mmx_8888_8888_cover_OVER,
scaled_bilinear_scanline_mmx_8888_8888_OVER,
uint32_t, uint32_t, uint32_t,
COVER, FLAG_NONE)
FAST_BILINEAR_MAINLOOP_COMMON (mmx_8888_8888_pad_OVER,
scaled_bilinear_scanline_mmx_8888_8888_OVER,
uint32_t, uint32_t, uint32_t,
PAD, FLAG_NONE)
FAST_BILINEAR_MAINLOOP_COMMON (mmx_8888_8888_none_OVER,
scaled_bilinear_scanline_mmx_8888_8888_OVER,
uint32_t, uint32_t, uint32_t,
NONE, FLAG_NONE)
FAST_BILINEAR_MAINLOOP_COMMON (mmx_8888_8888_normal_OVER,
scaled_bilinear_scanline_mmx_8888_8888_OVER,
uint32_t, uint32_t, uint32_t,
NORMAL, FLAG_NONE)
 
static force_inline void
scaled_bilinear_scanline_mmx_8888_8_8888_OVER (uint32_t * dst,
const uint8_t * mask,
const uint32_t * src_top,
const uint32_t * src_bottom,
int32_t w,
int wt,
int wb,
pixman_fixed_t vx,
pixman_fixed_t unit_x,
pixman_fixed_t max_vx,
pixman_bool_t zero_src)
{
BILINEAR_DECLARE_VARIABLES;
__m64 pix1, pix2;
uint32_t m;
 
while (w)
{
m = (uint32_t) *mask++;
 
if (m)
{
BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
 
if (m == 0xff && is_opaque (pix1))
{
store (dst, pix1);
}
else
{
__m64 ms, md, ma, msa;
 
pix2 = load (dst);
ma = expand_alpha_rev (to_m64 (m));
ms = _mm_unpacklo_pi8 (pix1, _mm_setzero_si64 ());
md = _mm_unpacklo_pi8 (pix2, _mm_setzero_si64 ());
 
msa = expand_alpha (ms);
 
store8888 (dst, (in_over (ms, msa, ma, md)));
}
}
else
{
BILINEAR_SKIP_ONE_PIXEL ();
}
 
w--;
dst++;
}
 
_mm_empty ();
}
 
FAST_BILINEAR_MAINLOOP_COMMON (mmx_8888_8_8888_cover_OVER,
scaled_bilinear_scanline_mmx_8888_8_8888_OVER,
uint32_t, uint8_t, uint32_t,
COVER, FLAG_HAVE_NON_SOLID_MASK)
FAST_BILINEAR_MAINLOOP_COMMON (mmx_8888_8_8888_pad_OVER,
scaled_bilinear_scanline_mmx_8888_8_8888_OVER,
uint32_t, uint8_t, uint32_t,
PAD, FLAG_HAVE_NON_SOLID_MASK)
FAST_BILINEAR_MAINLOOP_COMMON (mmx_8888_8_8888_none_OVER,
scaled_bilinear_scanline_mmx_8888_8_8888_OVER,
uint32_t, uint8_t, uint32_t,
NONE, FLAG_HAVE_NON_SOLID_MASK)
FAST_BILINEAR_MAINLOOP_COMMON (mmx_8888_8_8888_normal_OVER,
scaled_bilinear_scanline_mmx_8888_8_8888_OVER,
uint32_t, uint8_t, uint32_t,
NORMAL, FLAG_HAVE_NON_SOLID_MASK)
 
static uint32_t *
mmx_fetch_x8r8g8b8 (pixman_iter_t *iter, const uint32_t *mask)
{
int w = iter->width;
uint32_t *dst = iter->buffer;
uint32_t *src = (uint32_t *)iter->bits;
 
iter->bits += iter->stride;
 
while (w && ((uintptr_t)dst) & 7)
{
*dst++ = (*src++) | 0xff000000;
w--;
}
 
while (w >= 8)
{
__m64 vsrc1 = ldq_u ((__m64 *)(src + 0));
__m64 vsrc2 = ldq_u ((__m64 *)(src + 2));
__m64 vsrc3 = ldq_u ((__m64 *)(src + 4));
__m64 vsrc4 = ldq_u ((__m64 *)(src + 6));
 
*(__m64 *)(dst + 0) = _mm_or_si64 (vsrc1, MC (ff000000));
*(__m64 *)(dst + 2) = _mm_or_si64 (vsrc2, MC (ff000000));
*(__m64 *)(dst + 4) = _mm_or_si64 (vsrc3, MC (ff000000));
*(__m64 *)(dst + 6) = _mm_or_si64 (vsrc4, MC (ff000000));
 
dst += 8;
src += 8;
w -= 8;
}
 
while (w)
{
*dst++ = (*src++) | 0xff000000;
w--;
}
 
_mm_empty ();
return iter->buffer;
}
 
static uint32_t *
mmx_fetch_r5g6b5 (pixman_iter_t *iter, const uint32_t *mask)
{
int w = iter->width;
uint32_t *dst = iter->buffer;
uint16_t *src = (uint16_t *)iter->bits;
 
iter->bits += iter->stride;
 
while (w && ((uintptr_t)dst) & 0x0f)
{
uint16_t s = *src++;
 
*dst++ = convert_0565_to_8888 (s);
w--;
}
 
while (w >= 4)
{
__m64 vsrc = ldq_u ((__m64 *)src);
__m64 mm0, mm1;
 
expand_4xpacked565 (vsrc, &mm0, &mm1, 1);
 
*(__m64 *)(dst + 0) = mm0;
*(__m64 *)(dst + 2) = mm1;
 
dst += 4;
src += 4;
w -= 4;
}
 
while (w)
{
uint16_t s = *src++;
 
*dst++ = convert_0565_to_8888 (s);
w--;
}
 
_mm_empty ();
return iter->buffer;
}
 
static uint32_t *
mmx_fetch_a8 (pixman_iter_t *iter, const uint32_t *mask)
{
int w = iter->width;
uint32_t *dst = iter->buffer;
uint8_t *src = iter->bits;
 
iter->bits += iter->stride;
 
while (w && (((uintptr_t)dst) & 15))
{
*dst++ = *(src++) << 24;
w--;
}
 
while (w >= 8)
{
__m64 mm0 = ldq_u ((__m64 *)src);
 
__m64 mm1 = _mm_unpacklo_pi8 (_mm_setzero_si64(), mm0);
__m64 mm2 = _mm_unpackhi_pi8 (_mm_setzero_si64(), mm0);
__m64 mm3 = _mm_unpacklo_pi16 (_mm_setzero_si64(), mm1);
__m64 mm4 = _mm_unpackhi_pi16 (_mm_setzero_si64(), mm1);
__m64 mm5 = _mm_unpacklo_pi16 (_mm_setzero_si64(), mm2);
__m64 mm6 = _mm_unpackhi_pi16 (_mm_setzero_si64(), mm2);
 
*(__m64 *)(dst + 0) = mm3;
*(__m64 *)(dst + 2) = mm4;
*(__m64 *)(dst + 4) = mm5;
*(__m64 *)(dst + 6) = mm6;
 
dst += 8;
src += 8;
w -= 8;
}
 
while (w)
{
*dst++ = *(src++) << 24;
w--;
}
 
_mm_empty ();
return iter->buffer;
}
 
typedef struct
{
pixman_format_code_t format;
pixman_iter_get_scanline_t get_scanline;
} fetcher_info_t;
 
static const fetcher_info_t fetchers[] =
{
{ PIXMAN_x8r8g8b8, mmx_fetch_x8r8g8b8 },
{ PIXMAN_r5g6b5, mmx_fetch_r5g6b5 },
{ PIXMAN_a8, mmx_fetch_a8 },
{ PIXMAN_null }
};
 
static pixman_bool_t
mmx_src_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter)
{
pixman_image_t *image = iter->image;
 
#define FLAGS \
(FAST_PATH_STANDARD_FLAGS | FAST_PATH_ID_TRANSFORM | \
FAST_PATH_BITS_IMAGE | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST)
 
if ((iter->iter_flags & ITER_NARROW) &&
(iter->image_flags & FLAGS) == FLAGS)
{
const fetcher_info_t *f;
 
for (f = &fetchers[0]; f->format != PIXMAN_null; f++)
{
if (image->common.extended_format_code == f->format)
{
uint8_t *b = (uint8_t *)image->bits.bits;
int s = image->bits.rowstride * 4;
 
iter->bits = b + s * iter->y + iter->x * PIXMAN_FORMAT_BPP (f->format) / 8;
iter->stride = s;
 
iter->get_scanline = f->get_scanline;
return TRUE;
}
}
}
 
return FALSE;
}
 
static const pixman_fast_path_t mmx_fast_paths[] =
{
PIXMAN_STD_FAST_PATH (OVER, solid, a8, r5g6b5, mmx_composite_over_n_8_0565 ),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, b5g6r5, mmx_composite_over_n_8_0565 ),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8r8g8b8, mmx_composite_over_n_8_8888 ),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8r8g8b8, mmx_composite_over_n_8_8888 ),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8b8g8r8, mmx_composite_over_n_8_8888 ),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8b8g8r8, mmx_composite_over_n_8_8888 ),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, a8r8g8b8, mmx_composite_over_n_8888_8888_ca ),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, x8r8g8b8, mmx_composite_over_n_8888_8888_ca ),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, r5g6b5, mmx_composite_over_n_8888_0565_ca ),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, a8b8g8r8, mmx_composite_over_n_8888_8888_ca ),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, x8b8g8r8, mmx_composite_over_n_8888_8888_ca ),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, b5g6r5, mmx_composite_over_n_8888_0565_ca ),
PIXMAN_STD_FAST_PATH (OVER, pixbuf, pixbuf, a8r8g8b8, mmx_composite_over_pixbuf_8888 ),
PIXMAN_STD_FAST_PATH (OVER, pixbuf, pixbuf, x8r8g8b8, mmx_composite_over_pixbuf_8888 ),
PIXMAN_STD_FAST_PATH (OVER, pixbuf, pixbuf, r5g6b5, mmx_composite_over_pixbuf_0565 ),
PIXMAN_STD_FAST_PATH (OVER, rpixbuf, rpixbuf, a8b8g8r8, mmx_composite_over_pixbuf_8888 ),
PIXMAN_STD_FAST_PATH (OVER, rpixbuf, rpixbuf, x8b8g8r8, mmx_composite_over_pixbuf_8888 ),
PIXMAN_STD_FAST_PATH (OVER, rpixbuf, rpixbuf, b5g6r5, mmx_composite_over_pixbuf_0565 ),
PIXMAN_STD_FAST_PATH (OVER, x8r8g8b8, solid, a8r8g8b8, mmx_composite_over_x888_n_8888 ),
PIXMAN_STD_FAST_PATH (OVER, x8r8g8b8, solid, x8r8g8b8, mmx_composite_over_x888_n_8888 ),
PIXMAN_STD_FAST_PATH (OVER, x8b8g8r8, solid, a8b8g8r8, mmx_composite_over_x888_n_8888 ),
PIXMAN_STD_FAST_PATH (OVER, x8b8g8r8, solid, x8b8g8r8, mmx_composite_over_x888_n_8888 ),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, solid, a8r8g8b8, mmx_composite_over_8888_n_8888 ),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, solid, x8r8g8b8, mmx_composite_over_8888_n_8888 ),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, solid, a8b8g8r8, mmx_composite_over_8888_n_8888 ),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, solid, x8b8g8r8, mmx_composite_over_8888_n_8888 ),
PIXMAN_STD_FAST_PATH (OVER, x8r8g8b8, a8, x8r8g8b8, mmx_composite_over_x888_8_8888 ),
PIXMAN_STD_FAST_PATH (OVER, x8r8g8b8, a8, a8r8g8b8, mmx_composite_over_x888_8_8888 ),
PIXMAN_STD_FAST_PATH (OVER, x8b8g8r8, a8, x8b8g8r8, mmx_composite_over_x888_8_8888 ),
PIXMAN_STD_FAST_PATH (OVER, x8b8g8r8, a8, a8b8g8r8, mmx_composite_over_x888_8_8888 ),
PIXMAN_STD_FAST_PATH (OVER, solid, null, a8r8g8b8, mmx_composite_over_n_8888 ),
PIXMAN_STD_FAST_PATH (OVER, solid, null, x8r8g8b8, mmx_composite_over_n_8888 ),
PIXMAN_STD_FAST_PATH (OVER, solid, null, r5g6b5, mmx_composite_over_n_0565 ),
PIXMAN_STD_FAST_PATH (OVER, solid, null, b5g6r5, mmx_composite_over_n_0565 ),
PIXMAN_STD_FAST_PATH (OVER, x8r8g8b8, null, x8r8g8b8, mmx_composite_copy_area ),
PIXMAN_STD_FAST_PATH (OVER, x8b8g8r8, null, x8b8g8r8, mmx_composite_copy_area ),
 
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, a8r8g8b8, mmx_composite_over_8888_8888 ),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, x8r8g8b8, mmx_composite_over_8888_8888 ),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, r5g6b5, mmx_composite_over_8888_0565 ),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, a8b8g8r8, mmx_composite_over_8888_8888 ),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, x8b8g8r8, mmx_composite_over_8888_8888 ),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, b5g6r5, mmx_composite_over_8888_0565 ),
 
PIXMAN_STD_FAST_PATH (OVER_REVERSE, solid, null, a8r8g8b8, mmx_composite_over_reverse_n_8888),
PIXMAN_STD_FAST_PATH (OVER_REVERSE, solid, null, a8b8g8r8, mmx_composite_over_reverse_n_8888),
 
PIXMAN_STD_FAST_PATH (ADD, r5g6b5, null, r5g6b5, mmx_composite_add_0565_0565 ),
PIXMAN_STD_FAST_PATH (ADD, b5g6r5, null, b5g6r5, mmx_composite_add_0565_0565 ),
PIXMAN_STD_FAST_PATH (ADD, a8r8g8b8, null, a8r8g8b8, mmx_composite_add_8888_8888 ),
PIXMAN_STD_FAST_PATH (ADD, a8b8g8r8, null, a8b8g8r8, mmx_composite_add_8888_8888 ),
PIXMAN_STD_FAST_PATH (ADD, a8, null, a8, mmx_composite_add_8_8 ),
PIXMAN_STD_FAST_PATH (ADD, solid, a8, a8, mmx_composite_add_n_8_8 ),
 
PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, r5g6b5, mmx_composite_src_x888_0565 ),
PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, b5g6r5, mmx_composite_src_x888_0565 ),
PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, r5g6b5, mmx_composite_src_x888_0565 ),
PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, b5g6r5, mmx_composite_src_x888_0565 ),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, a8r8g8b8, mmx_composite_src_n_8_8888 ),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, x8r8g8b8, mmx_composite_src_n_8_8888 ),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, a8b8g8r8, mmx_composite_src_n_8_8888 ),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, x8b8g8r8, mmx_composite_src_n_8_8888 ),
PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, a8r8g8b8, mmx_composite_copy_area ),
PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, a8b8g8r8, mmx_composite_copy_area ),
PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, x8r8g8b8, mmx_composite_copy_area ),
PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, x8b8g8r8, mmx_composite_copy_area ),
PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, x8r8g8b8, mmx_composite_copy_area ),
PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, x8b8g8r8, mmx_composite_copy_area ),
PIXMAN_STD_FAST_PATH (SRC, r5g6b5, null, r5g6b5, mmx_composite_copy_area ),
PIXMAN_STD_FAST_PATH (SRC, b5g6r5, null, b5g6r5, mmx_composite_copy_area ),
 
PIXMAN_STD_FAST_PATH (IN, a8, null, a8, mmx_composite_in_8_8 ),
PIXMAN_STD_FAST_PATH (IN, solid, a8, a8, mmx_composite_in_n_8_8 ),
 
SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8, mmx_8888_8888 ),
SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, mmx_8888_8888 ),
SIMPLE_BILINEAR_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8, mmx_8888_8888 ),
SIMPLE_BILINEAR_FAST_PATH (SRC, a8b8g8r8, a8b8g8r8, mmx_8888_8888 ),
SIMPLE_BILINEAR_FAST_PATH (SRC, a8b8g8r8, x8b8g8r8, mmx_8888_8888 ),
SIMPLE_BILINEAR_FAST_PATH (SRC, x8b8g8r8, x8b8g8r8, mmx_8888_8888 ),
 
SIMPLE_BILINEAR_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, mmx_8888_8888 ),
SIMPLE_BILINEAR_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, mmx_8888_8888 ),
SIMPLE_BILINEAR_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, mmx_8888_8888 ),
SIMPLE_BILINEAR_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, mmx_8888_8888 ),
 
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, mmx_8888_8_8888 ),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, mmx_8888_8_8888 ),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, mmx_8888_8_8888 ),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, mmx_8888_8_8888 ),
 
{ PIXMAN_OP_NONE },
};
 
pixman_implementation_t *
_pixman_implementation_create_mmx (pixman_implementation_t *fallback)
{
pixman_implementation_t *imp = _pixman_implementation_create (fallback, mmx_fast_paths);
 
imp->combine_32[PIXMAN_OP_OVER] = mmx_combine_over_u;
imp->combine_32[PIXMAN_OP_OVER_REVERSE] = mmx_combine_over_reverse_u;
imp->combine_32[PIXMAN_OP_IN] = mmx_combine_in_u;
imp->combine_32[PIXMAN_OP_IN_REVERSE] = mmx_combine_in_reverse_u;
imp->combine_32[PIXMAN_OP_OUT] = mmx_combine_out_u;
imp->combine_32[PIXMAN_OP_OUT_REVERSE] = mmx_combine_out_reverse_u;
imp->combine_32[PIXMAN_OP_ATOP] = mmx_combine_atop_u;
imp->combine_32[PIXMAN_OP_ATOP_REVERSE] = mmx_combine_atop_reverse_u;
imp->combine_32[PIXMAN_OP_XOR] = mmx_combine_xor_u;
imp->combine_32[PIXMAN_OP_ADD] = mmx_combine_add_u;
imp->combine_32[PIXMAN_OP_SATURATE] = mmx_combine_saturate_u;
 
imp->combine_32_ca[PIXMAN_OP_SRC] = mmx_combine_src_ca;
imp->combine_32_ca[PIXMAN_OP_OVER] = mmx_combine_over_ca;
imp->combine_32_ca[PIXMAN_OP_OVER_REVERSE] = mmx_combine_over_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_IN] = mmx_combine_in_ca;
imp->combine_32_ca[PIXMAN_OP_IN_REVERSE] = mmx_combine_in_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_OUT] = mmx_combine_out_ca;
imp->combine_32_ca[PIXMAN_OP_OUT_REVERSE] = mmx_combine_out_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_ATOP] = mmx_combine_atop_ca;
imp->combine_32_ca[PIXMAN_OP_ATOP_REVERSE] = mmx_combine_atop_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_XOR] = mmx_combine_xor_ca;
imp->combine_32_ca[PIXMAN_OP_ADD] = mmx_combine_add_ca;
 
imp->blt = mmx_blt;
imp->fill = mmx_fill;
 
imp->src_iter_init = mmx_src_iter_init;
 
return imp;
}
 
#endif /* USE_X86_MMX || USE_ARM_IWMMXT || USE_LOONGSON_MMI */
/contrib/sdk/sources/pixman/pixman-noop.c
0,0 → 1,176
/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
/*
* Copyright © 2011 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <stdlib.h>
#include "pixman-private.h"
#include "pixman-combine32.h"
#include "pixman-inlines.h"
 
static void
noop_composite (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
return;
}
 
static void
dest_write_back_direct (pixman_iter_t *iter)
{
iter->buffer += iter->image->bits.rowstride;
}
 
static uint32_t *
noop_get_scanline (pixman_iter_t *iter, const uint32_t *mask)
{
uint32_t *result = iter->buffer;
 
iter->buffer += iter->image->bits.rowstride;
 
return result;
}
 
static uint32_t *
get_scanline_null (pixman_iter_t *iter, const uint32_t *mask)
{
return NULL;
}
 
static pixman_bool_t
noop_src_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter)
{
pixman_image_t *image = iter->image;
 
#define FLAGS \
(FAST_PATH_STANDARD_FLAGS | FAST_PATH_ID_TRANSFORM)
 
if (!image)
{
iter->get_scanline = get_scanline_null;
}
else if ((iter->iter_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) ==
(ITER_IGNORE_ALPHA | ITER_IGNORE_RGB))
{
iter->get_scanline = _pixman_iter_get_scanline_noop;
}
else if (image->common.extended_format_code == PIXMAN_solid &&
(iter->image->type == SOLID ||
(iter->image_flags & FAST_PATH_NO_ALPHA_MAP)))
{
if (iter->iter_flags & ITER_NARROW)
{
uint32_t *buffer = iter->buffer;
uint32_t *end = buffer + iter->width;
uint32_t color;
 
if (image->type == SOLID)
color = image->solid.color_32;
else
color = image->bits.fetch_pixel_32 (&image->bits, 0, 0);
 
while (buffer < end)
*(buffer++) = color;
}
else
{
argb_t *buffer = (argb_t *)iter->buffer;
argb_t *end = buffer + iter->width;
argb_t color;
 
if (image->type == SOLID)
color = image->solid.color_float;
else
color = image->bits.fetch_pixel_float (&image->bits, 0, 0);
 
while (buffer < end)
*(buffer++) = color;
}
 
iter->get_scanline = _pixman_iter_get_scanline_noop;
}
else if (image->common.extended_format_code == PIXMAN_a8r8g8b8 &&
(iter->iter_flags & ITER_NARROW) &&
(iter->image_flags & FLAGS) == FLAGS &&
iter->x >= 0 && iter->y >= 0 &&
iter->x + iter->width <= image->bits.width &&
iter->y + iter->height <= image->bits.height)
{
iter->buffer =
image->bits.bits + iter->y * image->bits.rowstride + iter->x;
 
iter->get_scanline = noop_get_scanline;
}
else
{
return FALSE;
}
 
return TRUE;
}
 
static pixman_bool_t
noop_dest_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter)
{
pixman_image_t *image = iter->image;
uint32_t image_flags = iter->image_flags;
uint32_t iter_flags = iter->iter_flags;
if ((image_flags & FAST_PATH_STD_DEST_FLAGS) == FAST_PATH_STD_DEST_FLAGS &&
(iter_flags & ITER_NARROW) == ITER_NARROW &&
((image->common.extended_format_code == PIXMAN_a8r8g8b8) ||
(image->common.extended_format_code == PIXMAN_x8r8g8b8 &&
(iter_flags & (ITER_LOCALIZED_ALPHA)))))
{
iter->buffer = image->bits.bits + iter->y * image->bits.rowstride + iter->x;
 
iter->get_scanline = _pixman_iter_get_scanline_noop;
iter->write_back = dest_write_back_direct;
 
return TRUE;
}
else
{
return FALSE;
}
}
 
static const pixman_fast_path_t noop_fast_paths[] =
{
{ PIXMAN_OP_DST, PIXMAN_any, 0, PIXMAN_any, 0, PIXMAN_any, 0, noop_composite },
{ PIXMAN_OP_NONE },
};
 
pixman_implementation_t *
_pixman_implementation_create_noop (pixman_implementation_t *fallback)
{
pixman_implementation_t *imp =
_pixman_implementation_create (fallback, noop_fast_paths);
imp->src_iter_init = noop_src_iter_init;
imp->dest_iter_init = noop_dest_iter_init;
 
return imp;
}
/contrib/sdk/sources/pixman/pixman-private.h
0,0 → 1,1135
#include <float.h>
 
#ifndef PIXMAN_PRIVATE_H
#define PIXMAN_PRIVATE_H
 
/*
* The defines which are shared between C and assembly code
*/
 
/* bilinear interpolation precision (must be <= 8) */
#define BILINEAR_INTERPOLATION_BITS 7
#define BILINEAR_INTERPOLATION_RANGE (1 << BILINEAR_INTERPOLATION_BITS)
 
/*
* C specific part
*/
 
#ifndef __ASSEMBLER__
 
#ifndef PACKAGE
# error config.h must be included before pixman-private.h
#endif
 
#define PIXMAN_DISABLE_DEPRECATED
#define PIXMAN_USE_INTERNAL_API
 
#include "pixman.h"
#include <time.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
 
#include "pixman-compiler.h"
 
/*
* Images
*/
typedef struct image_common image_common_t;
typedef struct solid_fill solid_fill_t;
typedef struct gradient gradient_t;
typedef struct linear_gradient linear_gradient_t;
typedef struct horizontal_gradient horizontal_gradient_t;
typedef struct vertical_gradient vertical_gradient_t;
typedef struct conical_gradient conical_gradient_t;
typedef struct radial_gradient radial_gradient_t;
typedef struct bits_image bits_image_t;
typedef struct circle circle_t;
 
typedef struct argb_t argb_t;
 
struct argb_t
{
float a;
float r;
float g;
float b;
};
 
typedef void (*fetch_scanline_t) (pixman_image_t *image,
int x,
int y,
int width,
uint32_t *buffer,
const uint32_t *mask);
 
typedef uint32_t (*fetch_pixel_32_t) (bits_image_t *image,
int x,
int y);
 
typedef argb_t (*fetch_pixel_float_t) (bits_image_t *image,
int x,
int y);
 
typedef void (*store_scanline_t) (bits_image_t * image,
int x,
int y,
int width,
const uint32_t *values);
 
typedef enum
{
BITS,
LINEAR,
CONICAL,
RADIAL,
SOLID
} image_type_t;
 
typedef void (*property_changed_func_t) (pixman_image_t *image);
 
struct image_common
{
image_type_t type;
int32_t ref_count;
pixman_region32_t clip_region;
int32_t alpha_count; /* How many times this image is being used as an alpha map */
pixman_bool_t have_clip_region; /* FALSE if there is no clip */
pixman_bool_t client_clip; /* Whether the source clip was
set by a client */
pixman_bool_t clip_sources; /* Whether the clip applies when
* the image is used as a source
*/
pixman_bool_t dirty;
pixman_transform_t * transform;
pixman_repeat_t repeat;
pixman_filter_t filter;
pixman_fixed_t * filter_params;
int n_filter_params;
bits_image_t * alpha_map;
int alpha_origin_x;
int alpha_origin_y;
pixman_bool_t component_alpha;
property_changed_func_t property_changed;
 
pixman_image_destroy_func_t destroy_func;
void * destroy_data;
 
uint32_t flags;
pixman_format_code_t extended_format_code;
};
 
struct solid_fill
{
image_common_t common;
pixman_color_t color;
 
uint32_t color_32;
argb_t color_float;
};
 
struct gradient
{
image_common_t common;
int n_stops;
pixman_gradient_stop_t *stops;
};
 
struct linear_gradient
{
gradient_t common;
pixman_point_fixed_t p1;
pixman_point_fixed_t p2;
};
 
struct circle
{
pixman_fixed_t x;
pixman_fixed_t y;
pixman_fixed_t radius;
};
 
struct radial_gradient
{
gradient_t common;
 
circle_t c1;
circle_t c2;
 
circle_t delta;
double a;
double inva;
double mindr;
};
 
struct conical_gradient
{
gradient_t common;
pixman_point_fixed_t center;
double angle;
};
 
struct bits_image
{
image_common_t common;
pixman_format_code_t format;
const pixman_indexed_t * indexed;
int width;
int height;
uint32_t * bits;
uint32_t * free_me;
int rowstride; /* in number of uint32_t's */
 
fetch_scanline_t fetch_scanline_32;
fetch_pixel_32_t fetch_pixel_32;
store_scanline_t store_scanline_32;
 
fetch_scanline_t fetch_scanline_float;
fetch_pixel_float_t fetch_pixel_float;
store_scanline_t store_scanline_float;
 
/* Used for indirect access to the bits */
pixman_read_memory_func_t read_func;
pixman_write_memory_func_t write_func;
};
 
union pixman_image
{
image_type_t type;
image_common_t common;
bits_image_t bits;
gradient_t gradient;
linear_gradient_t linear;
conical_gradient_t conical;
radial_gradient_t radial;
solid_fill_t solid;
};
 
typedef struct pixman_iter_t pixman_iter_t;
typedef uint32_t *(* pixman_iter_get_scanline_t) (pixman_iter_t *iter, const uint32_t *mask);
typedef void (* pixman_iter_write_back_t) (pixman_iter_t *iter);
 
typedef enum
{
ITER_NARROW = (1 << 0),
 
/* "Localized alpha" is when the alpha channel is used only to compute
* the alpha value of the destination. This means that the computation
* of the RGB values of the result is independent of the alpha value.
*
* For example, the OVER operator has localized alpha for the
* destination, because the RGB values of the result can be computed
* without knowing the destination alpha. Similarly, ADD has localized
* alpha for both source and destination because the RGB values of the
* result can be computed without knowing the alpha value of source or
* destination.
*
* When he destination is xRGB, this is useful knowledge, because then
* we can treat it as if it were ARGB, which means in some cases we can
* avoid copying it to a temporary buffer.
*/
ITER_LOCALIZED_ALPHA = (1 << 1),
ITER_IGNORE_ALPHA = (1 << 2),
ITER_IGNORE_RGB = (1 << 3)
} iter_flags_t;
 
struct pixman_iter_t
{
/* These are initialized by _pixman_implementation_{src,dest}_init */
pixman_image_t * image;
uint32_t * buffer;
int x, y;
int width;
int height;
iter_flags_t iter_flags;
uint32_t image_flags;
 
/* These function pointers are initialized by the implementation */
pixman_iter_get_scanline_t get_scanline;
pixman_iter_write_back_t write_back;
 
/* These fields are scratch data that implementations can use */
void * data;
uint8_t * bits;
int stride;
};
 
void
_pixman_bits_image_setup_accessors (bits_image_t *image);
 
void
_pixman_bits_image_src_iter_init (pixman_image_t *image, pixman_iter_t *iter);
 
void
_pixman_bits_image_dest_iter_init (pixman_image_t *image, pixman_iter_t *iter);
 
void
_pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter);
 
void
_pixman_radial_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter);
 
void
_pixman_conical_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter);
 
void
_pixman_image_init (pixman_image_t *image);
 
pixman_bool_t
_pixman_bits_image_init (pixman_image_t * image,
pixman_format_code_t format,
int width,
int height,
uint32_t * bits,
int rowstride,
pixman_bool_t clear);
pixman_bool_t
_pixman_image_fini (pixman_image_t *image);
 
pixman_image_t *
_pixman_image_allocate (void);
 
pixman_bool_t
_pixman_init_gradient (gradient_t * gradient,
const pixman_gradient_stop_t *stops,
int n_stops);
void
_pixman_image_reset_clip_region (pixman_image_t *image);
 
void
_pixman_image_validate (pixman_image_t *image);
 
#define PIXMAN_IMAGE_GET_LINE(image, x, y, type, out_stride, line, mul) \
do \
{ \
uint32_t *__bits__; \
int __stride__; \
\
__bits__ = image->bits.bits; \
__stride__ = image->bits.rowstride; \
(out_stride) = \
__stride__ * (int) sizeof (uint32_t) / (int) sizeof (type); \
(line) = \
((type *) __bits__) + (out_stride) * (y) + (mul) * (x); \
} while (0)
 
/*
* Gradient walker
*/
typedef struct
{
float a_s, a_b;
float r_s, r_b;
float g_s, g_b;
float b_s, b_b;
pixman_fixed_t left_x;
pixman_fixed_t right_x;
 
pixman_gradient_stop_t *stops;
int num_stops;
pixman_repeat_t repeat;
 
pixman_bool_t need_reset;
} pixman_gradient_walker_t;
 
void
_pixman_gradient_walker_init (pixman_gradient_walker_t *walker,
gradient_t * gradient,
pixman_repeat_t repeat);
 
void
_pixman_gradient_walker_reset (pixman_gradient_walker_t *walker,
pixman_fixed_48_16_t pos);
 
uint32_t
_pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker,
pixman_fixed_48_16_t x);
 
/*
* Edges
*/
 
#define MAX_ALPHA(n) ((1 << (n)) - 1)
#define N_Y_FRAC(n) ((n) == 1 ? 1 : (1 << ((n) / 2)) - 1)
#define N_X_FRAC(n) ((n) == 1 ? 1 : (1 << ((n) / 2)) + 1)
 
#define STEP_Y_SMALL(n) (pixman_fixed_1 / N_Y_FRAC (n))
#define STEP_Y_BIG(n) (pixman_fixed_1 - (N_Y_FRAC (n) - 1) * STEP_Y_SMALL (n))
 
#define Y_FRAC_FIRST(n) (STEP_Y_BIG (n) / 2)
#define Y_FRAC_LAST(n) (Y_FRAC_FIRST (n) + (N_Y_FRAC (n) - 1) * STEP_Y_SMALL (n))
 
#define STEP_X_SMALL(n) (pixman_fixed_1 / N_X_FRAC (n))
#define STEP_X_BIG(n) (pixman_fixed_1 - (N_X_FRAC (n) - 1) * STEP_X_SMALL (n))
 
#define X_FRAC_FIRST(n) (STEP_X_BIG (n) / 2)
#define X_FRAC_LAST(n) (X_FRAC_FIRST (n) + (N_X_FRAC (n) - 1) * STEP_X_SMALL (n))
 
#define RENDER_SAMPLES_X(x, n) \
((n) == 1? 0 : (pixman_fixed_frac (x) + \
X_FRAC_FIRST (n)) / STEP_X_SMALL (n))
 
void
pixman_rasterize_edges_accessors (pixman_image_t *image,
pixman_edge_t * l,
pixman_edge_t * r,
pixman_fixed_t t,
pixman_fixed_t b);
 
/*
* Implementations
*/
typedef struct pixman_implementation_t pixman_implementation_t;
 
typedef struct
{
pixman_op_t op;
pixman_image_t * src_image;
pixman_image_t * mask_image;
pixman_image_t * dest_image;
int32_t src_x;
int32_t src_y;
int32_t mask_x;
int32_t mask_y;
int32_t dest_x;
int32_t dest_y;
int32_t width;
int32_t height;
 
uint32_t src_flags;
uint32_t mask_flags;
uint32_t dest_flags;
} pixman_composite_info_t;
 
#define PIXMAN_COMPOSITE_ARGS(info) \
MAYBE_UNUSED pixman_op_t op = info->op; \
MAYBE_UNUSED pixman_image_t * src_image = info->src_image; \
MAYBE_UNUSED pixman_image_t * mask_image = info->mask_image; \
MAYBE_UNUSED pixman_image_t * dest_image = info->dest_image; \
MAYBE_UNUSED int32_t src_x = info->src_x; \
MAYBE_UNUSED int32_t src_y = info->src_y; \
MAYBE_UNUSED int32_t mask_x = info->mask_x; \
MAYBE_UNUSED int32_t mask_y = info->mask_y; \
MAYBE_UNUSED int32_t dest_x = info->dest_x; \
MAYBE_UNUSED int32_t dest_y = info->dest_y; \
MAYBE_UNUSED int32_t width = info->width; \
MAYBE_UNUSED int32_t height = info->height
 
typedef void (*pixman_combine_32_func_t) (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width);
 
typedef void (*pixman_combine_float_func_t) (pixman_implementation_t *imp,
pixman_op_t op,
float * dest,
const float * src,
const float * mask,
int n_pixels);
 
typedef void (*pixman_composite_func_t) (pixman_implementation_t *imp,
pixman_composite_info_t *info);
typedef pixman_bool_t (*pixman_blt_func_t) (pixman_implementation_t *imp,
uint32_t * src_bits,
uint32_t * dst_bits,
int src_stride,
int dst_stride,
int src_bpp,
int dst_bpp,
int src_x,
int src_y,
int dest_x,
int dest_y,
int width,
int height);
typedef pixman_bool_t (*pixman_fill_func_t) (pixman_implementation_t *imp,
uint32_t * bits,
int stride,
int bpp,
int x,
int y,
int width,
int height,
uint32_t filler);
typedef pixman_bool_t (*pixman_iter_init_func_t) (pixman_implementation_t *imp,
pixman_iter_t *iter);
 
void _pixman_setup_combiner_functions_32 (pixman_implementation_t *imp);
void _pixman_setup_combiner_functions_float (pixman_implementation_t *imp);
 
typedef struct
{
pixman_op_t op;
pixman_format_code_t src_format;
uint32_t src_flags;
pixman_format_code_t mask_format;
uint32_t mask_flags;
pixman_format_code_t dest_format;
uint32_t dest_flags;
pixman_composite_func_t func;
} pixman_fast_path_t;
 
struct pixman_implementation_t
{
pixman_implementation_t * toplevel;
pixman_implementation_t * fallback;
const pixman_fast_path_t * fast_paths;
 
pixman_blt_func_t blt;
pixman_fill_func_t fill;
pixman_iter_init_func_t src_iter_init;
pixman_iter_init_func_t dest_iter_init;
 
pixman_combine_32_func_t combine_32[PIXMAN_N_OPERATORS];
pixman_combine_32_func_t combine_32_ca[PIXMAN_N_OPERATORS];
pixman_combine_float_func_t combine_float[PIXMAN_N_OPERATORS];
pixman_combine_float_func_t combine_float_ca[PIXMAN_N_OPERATORS];
};
 
uint32_t
_pixman_image_get_solid (pixman_implementation_t *imp,
pixman_image_t * image,
pixman_format_code_t format);
 
pixman_implementation_t *
_pixman_implementation_create (pixman_implementation_t *fallback,
const pixman_fast_path_t *fast_paths);
 
void
_pixman_implementation_lookup_composite (pixman_implementation_t *toplevel,
pixman_op_t op,
pixman_format_code_t src_format,
uint32_t src_flags,
pixman_format_code_t mask_format,
uint32_t mask_flags,
pixman_format_code_t dest_format,
uint32_t dest_flags,
pixman_implementation_t **out_imp,
pixman_composite_func_t *out_func);
 
pixman_combine_32_func_t
_pixman_implementation_lookup_combiner (pixman_implementation_t *imp,
pixman_op_t op,
pixman_bool_t component_alpha,
pixman_bool_t wide);
 
pixman_bool_t
_pixman_implementation_blt (pixman_implementation_t *imp,
uint32_t * src_bits,
uint32_t * dst_bits,
int src_stride,
int dst_stride,
int src_bpp,
int dst_bpp,
int src_x,
int src_y,
int dest_x,
int dest_y,
int width,
int height);
 
pixman_bool_t
_pixman_implementation_fill (pixman_implementation_t *imp,
uint32_t * bits,
int stride,
int bpp,
int x,
int y,
int width,
int height,
uint32_t filler);
 
pixman_bool_t
_pixman_implementation_src_iter_init (pixman_implementation_t *imp,
pixman_iter_t *iter,
pixman_image_t *image,
int x,
int y,
int width,
int height,
uint8_t *buffer,
iter_flags_t flags,
uint32_t image_flags);
 
pixman_bool_t
_pixman_implementation_dest_iter_init (pixman_implementation_t *imp,
pixman_iter_t *iter,
pixman_image_t *image,
int x,
int y,
int width,
int height,
uint8_t *buffer,
iter_flags_t flags,
uint32_t image_flags);
 
/* Specific implementations */
pixman_implementation_t *
_pixman_implementation_create_general (void);
 
pixman_implementation_t *
_pixman_implementation_create_fast_path (pixman_implementation_t *fallback);
 
pixman_implementation_t *
_pixman_implementation_create_noop (pixman_implementation_t *fallback);
 
#if defined USE_X86_MMX || defined USE_ARM_IWMMXT || defined USE_LOONGSON_MMI
pixman_implementation_t *
_pixman_implementation_create_mmx (pixman_implementation_t *fallback);
#endif
 
#ifdef USE_SSE2
pixman_implementation_t *
_pixman_implementation_create_sse2 (pixman_implementation_t *fallback);
#endif
 
#ifdef USE_ARM_SIMD
pixman_implementation_t *
_pixman_implementation_create_arm_simd (pixman_implementation_t *fallback);
#endif
 
#ifdef USE_ARM_NEON
pixman_implementation_t *
_pixman_implementation_create_arm_neon (pixman_implementation_t *fallback);
#endif
 
#ifdef USE_MIPS_DSPR2
pixman_implementation_t *
_pixman_implementation_create_mips_dspr2 (pixman_implementation_t *fallback);
#endif
 
#ifdef USE_VMX
pixman_implementation_t *
_pixman_implementation_create_vmx (pixman_implementation_t *fallback);
#endif
 
pixman_bool_t
_pixman_implementation_disabled (const char *name);
 
pixman_implementation_t *
_pixman_x86_get_implementations (pixman_implementation_t *imp);
 
pixman_implementation_t *
_pixman_arm_get_implementations (pixman_implementation_t *imp);
 
pixman_implementation_t *
_pixman_ppc_get_implementations (pixman_implementation_t *imp);
 
pixman_implementation_t *
_pixman_mips_get_implementations (pixman_implementation_t *imp);
 
pixman_implementation_t *
_pixman_choose_implementation (void);
 
pixman_bool_t
_pixman_disabled (const char *name);
 
 
/*
* Utilities
*/
pixman_bool_t
_pixman_compute_composite_region32 (pixman_region32_t * region,
pixman_image_t * src_image,
pixman_image_t * mask_image,
pixman_image_t * dest_image,
int32_t src_x,
int32_t src_y,
int32_t mask_x,
int32_t mask_y,
int32_t dest_x,
int32_t dest_y,
int32_t width,
int32_t height);
uint32_t *
_pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask);
 
/* These "formats" all have depth 0, so they
* will never clash with any real ones
*/
#define PIXMAN_null PIXMAN_FORMAT (0, 0, 0, 0, 0, 0)
#define PIXMAN_solid PIXMAN_FORMAT (0, 1, 0, 0, 0, 0)
#define PIXMAN_pixbuf PIXMAN_FORMAT (0, 2, 0, 0, 0, 0)
#define PIXMAN_rpixbuf PIXMAN_FORMAT (0, 3, 0, 0, 0, 0)
#define PIXMAN_unknown PIXMAN_FORMAT (0, 4, 0, 0, 0, 0)
#define PIXMAN_any PIXMAN_FORMAT (0, 5, 0, 0, 0, 0)
 
#define PIXMAN_OP_any (PIXMAN_N_OPERATORS + 1)
 
#define FAST_PATH_ID_TRANSFORM (1 << 0)
#define FAST_PATH_NO_ALPHA_MAP (1 << 1)
#define FAST_PATH_NO_CONVOLUTION_FILTER (1 << 2)
#define FAST_PATH_NO_PAD_REPEAT (1 << 3)
#define FAST_PATH_NO_REFLECT_REPEAT (1 << 4)
#define FAST_PATH_NO_ACCESSORS (1 << 5)
#define FAST_PATH_NARROW_FORMAT (1 << 6)
#define FAST_PATH_COMPONENT_ALPHA (1 << 8)
#define FAST_PATH_SAMPLES_OPAQUE (1 << 7)
#define FAST_PATH_UNIFIED_ALPHA (1 << 9)
#define FAST_PATH_SCALE_TRANSFORM (1 << 10)
#define FAST_PATH_NEAREST_FILTER (1 << 11)
#define FAST_PATH_HAS_TRANSFORM (1 << 12)
#define FAST_PATH_IS_OPAQUE (1 << 13)
#define FAST_PATH_NO_NORMAL_REPEAT (1 << 14)
#define FAST_PATH_NO_NONE_REPEAT (1 << 15)
#define FAST_PATH_X_UNIT_POSITIVE (1 << 16)
#define FAST_PATH_AFFINE_TRANSFORM (1 << 17)
#define FAST_PATH_Y_UNIT_ZERO (1 << 18)
#define FAST_PATH_BILINEAR_FILTER (1 << 19)
#define FAST_PATH_ROTATE_90_TRANSFORM (1 << 20)
#define FAST_PATH_ROTATE_180_TRANSFORM (1 << 21)
#define FAST_PATH_ROTATE_270_TRANSFORM (1 << 22)
#define FAST_PATH_SAMPLES_COVER_CLIP_NEAREST (1 << 23)
#define FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR (1 << 24)
#define FAST_PATH_BITS_IMAGE (1 << 25)
#define FAST_PATH_SEPARABLE_CONVOLUTION_FILTER (1 << 26)
 
#define FAST_PATH_PAD_REPEAT \
(FAST_PATH_NO_NONE_REPEAT | \
FAST_PATH_NO_NORMAL_REPEAT | \
FAST_PATH_NO_REFLECT_REPEAT)
 
#define FAST_PATH_NORMAL_REPEAT \
(FAST_PATH_NO_NONE_REPEAT | \
FAST_PATH_NO_PAD_REPEAT | \
FAST_PATH_NO_REFLECT_REPEAT)
 
#define FAST_PATH_NONE_REPEAT \
(FAST_PATH_NO_NORMAL_REPEAT | \
FAST_PATH_NO_PAD_REPEAT | \
FAST_PATH_NO_REFLECT_REPEAT)
 
#define FAST_PATH_REFLECT_REPEAT \
(FAST_PATH_NO_NONE_REPEAT | \
FAST_PATH_NO_NORMAL_REPEAT | \
FAST_PATH_NO_PAD_REPEAT)
 
#define FAST_PATH_STANDARD_FLAGS \
(FAST_PATH_NO_CONVOLUTION_FILTER | \
FAST_PATH_NO_ACCESSORS | \
FAST_PATH_NO_ALPHA_MAP | \
FAST_PATH_NARROW_FORMAT)
 
#define FAST_PATH_STD_DEST_FLAGS \
(FAST_PATH_NO_ACCESSORS | \
FAST_PATH_NO_ALPHA_MAP | \
FAST_PATH_NARROW_FORMAT)
 
#define SOURCE_FLAGS(format) \
(FAST_PATH_STANDARD_FLAGS | \
((PIXMAN_ ## format == PIXMAN_solid) ? \
0 : (FAST_PATH_SAMPLES_COVER_CLIP_NEAREST | FAST_PATH_NEAREST_FILTER | FAST_PATH_ID_TRANSFORM)))
 
#define MASK_FLAGS(format, extra) \
((PIXMAN_ ## format == PIXMAN_null) ? 0 : (SOURCE_FLAGS (format) | extra))
 
#define FAST_PATH(op, src, src_flags, mask, mask_flags, dest, dest_flags, func) \
PIXMAN_OP_ ## op, \
PIXMAN_ ## src, \
src_flags, \
PIXMAN_ ## mask, \
mask_flags, \
PIXMAN_ ## dest, \
dest_flags, \
func
 
#define PIXMAN_STD_FAST_PATH(op, src, mask, dest, func) \
{ FAST_PATH ( \
op, \
src, SOURCE_FLAGS (src), \
mask, MASK_FLAGS (mask, FAST_PATH_UNIFIED_ALPHA), \
dest, FAST_PATH_STD_DEST_FLAGS, \
func) }
 
#define PIXMAN_STD_FAST_PATH_CA(op, src, mask, dest, func) \
{ FAST_PATH ( \
op, \
src, SOURCE_FLAGS (src), \
mask, MASK_FLAGS (mask, FAST_PATH_COMPONENT_ALPHA), \
dest, FAST_PATH_STD_DEST_FLAGS, \
func) }
 
extern pixman_implementation_t *global_implementation;
 
static force_inline pixman_implementation_t *
get_implementation (void)
{
#ifndef TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR
if (!global_implementation)
global_implementation = _pixman_choose_implementation ();
#endif
return global_implementation;
}
 
/* This function is exported for the sake of the test suite and not part
* of the ABI.
*/
PIXMAN_EXPORT pixman_implementation_t *
_pixman_internal_only_get_implementation (void);
 
/* Memory allocation helpers */
void *
pixman_malloc_ab (unsigned int n, unsigned int b);
 
void *
pixman_malloc_abc (unsigned int a, unsigned int b, unsigned int c);
 
pixman_bool_t
_pixman_multiply_overflows_size (size_t a, size_t b);
 
pixman_bool_t
_pixman_multiply_overflows_int (unsigned int a, unsigned int b);
 
pixman_bool_t
_pixman_addition_overflows_int (unsigned int a, unsigned int b);
 
/* Compositing utilities */
void
pixman_expand_to_float (argb_t *dst,
const uint32_t *src,
pixman_format_code_t format,
int width);
 
void
pixman_contract_from_float (uint32_t *dst,
const argb_t *src,
int width);
 
/* Region Helpers */
pixman_bool_t
pixman_region32_copy_from_region16 (pixman_region32_t *dst,
pixman_region16_t *src);
 
pixman_bool_t
pixman_region16_copy_from_region32 (pixman_region16_t *dst,
pixman_region32_t *src);
 
/* Doubly linked lists */
typedef struct pixman_link_t pixman_link_t;
struct pixman_link_t
{
pixman_link_t *next;
pixman_link_t *prev;
};
 
typedef struct pixman_list_t pixman_list_t;
struct pixman_list_t
{
pixman_link_t *head;
pixman_link_t *tail;
};
 
static force_inline void
pixman_list_init (pixman_list_t *list)
{
list->head = (pixman_link_t *)list;
list->tail = (pixman_link_t *)list;
}
 
static force_inline void
pixman_list_prepend (pixman_list_t *list, pixman_link_t *link)
{
link->next = list->head;
link->prev = (pixman_link_t *)list;
list->head->prev = link;
list->head = link;
}
 
static force_inline void
pixman_list_unlink (pixman_link_t *link)
{
link->prev->next = link->next;
link->next->prev = link->prev;
}
 
static force_inline void
pixman_list_move_to_front (pixman_list_t *list, pixman_link_t *link)
{
pixman_list_unlink (link);
pixman_list_prepend (list, link);
}
 
/* Misc macros */
 
#ifndef FALSE
# define FALSE 0
#endif
 
#ifndef TRUE
# define TRUE 1
#endif
 
#ifndef MIN
# define MIN(a, b) ((a < b) ? a : b)
#endif
 
#ifndef MAX
# define MAX(a, b) ((a > b) ? a : b)
#endif
 
/* Integer division that rounds towards -infinity */
#define DIV(a, b) \
((((a) < 0) == ((b) < 0)) ? (a) / (b) : \
((a) - (b) + 1 - (((b) < 0) << 1)) / (b))
 
/* Modulus that produces the remainder wrt. DIV */
#define MOD(a, b) ((a) < 0 ? ((b) - ((-(a) - 1) % (b))) - 1 : (a) % (b))
 
#define CLIP(v, low, high) ((v) < (low) ? (low) : ((v) > (high) ? (high) : (v)))
 
#define FLOAT_IS_ZERO(f) (-FLT_MIN < (f) && (f) < FLT_MIN)
 
/* Conversion between 8888 and 0565 */
 
static force_inline uint16_t
convert_8888_to_0565 (uint32_t s)
{
/* The following code can be compiled into just 4 instructions on ARM */
uint32_t a, b;
a = (s >> 3) & 0x1F001F;
b = s & 0xFC00;
a |= a >> 5;
a |= b >> 5;
return (uint16_t)a;
}
 
static force_inline uint32_t
convert_0565_to_0888 (uint16_t s)
{
return (((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7)) |
((((s) << 5) & 0xfc00) | (((s) >> 1) & 0x300)) |
((((s) << 8) & 0xf80000) | (((s) << 3) & 0x70000)));
}
 
static force_inline uint32_t
convert_0565_to_8888 (uint16_t s)
{
return convert_0565_to_0888 (s) | 0xff000000;
}
 
/* Trivial versions that are useful in macros */
 
static force_inline uint32_t
convert_8888_to_8888 (uint32_t s)
{
return s;
}
 
static force_inline uint32_t
convert_x888_to_8888 (uint32_t s)
{
return s | 0xff000000;
}
 
static force_inline uint16_t
convert_0565_to_0565 (uint16_t s)
{
return s;
}
 
#define PIXMAN_FORMAT_IS_WIDE(f) \
(PIXMAN_FORMAT_A (f) > 8 || \
PIXMAN_FORMAT_R (f) > 8 || \
PIXMAN_FORMAT_G (f) > 8 || \
PIXMAN_FORMAT_B (f) > 8 || \
PIXMAN_FORMAT_TYPE (f) == PIXMAN_TYPE_ARGB_SRGB)
 
#ifdef WORDS_BIGENDIAN
# define SCREEN_SHIFT_LEFT(x,n) ((x) << (n))
# define SCREEN_SHIFT_RIGHT(x,n) ((x) >> (n))
#else
# define SCREEN_SHIFT_LEFT(x,n) ((x) >> (n))
# define SCREEN_SHIFT_RIGHT(x,n) ((x) << (n))
#endif
 
static force_inline uint32_t
unorm_to_unorm (uint32_t val, int from_bits, int to_bits)
{
uint32_t result;
 
if (from_bits == 0)
return 0;
 
/* Delete any extra bits */
val &= ((1 << from_bits) - 1);
 
if (from_bits >= to_bits)
return val >> (from_bits - to_bits);
 
/* Start out with the high bit of val in the high bit of result. */
result = val << (to_bits - from_bits);
 
/* Copy the bits in result, doubling the number of bits each time, until
* we fill all to_bits. Unrolled manually because from_bits and to_bits
* are usually known statically, so the compiler can turn all of this
* into a few shifts.
*/
#define REPLICATE() \
do \
{ \
if (from_bits < to_bits) \
{ \
result |= result >> from_bits; \
\
from_bits *= 2; \
} \
} \
while (0)
 
REPLICATE();
REPLICATE();
REPLICATE();
REPLICATE();
REPLICATE();
 
return result;
}
 
uint16_t pixman_float_to_unorm (float f, int n_bits);
float pixman_unorm_to_float (uint16_t u, int n_bits);
 
/*
* Various debugging code
*/
 
#undef DEBUG
 
#define COMPILE_TIME_ASSERT(x) \
do { typedef int compile_time_assertion [(x)?1:-1]; } while (0)
 
/* Turn on debugging depending on what type of release this is
*/
#if (((PIXMAN_VERSION_MICRO % 2) == 0) && ((PIXMAN_VERSION_MINOR % 2) == 1))
 
/* Debugging gets turned on for development releases because these
* are the things that end up in bleeding edge distributions such
* as Rawhide etc.
*
* For performance reasons we don't turn it on for stable releases or
* random git checkouts. (Random git checkouts are often used for
* performance work).
*/
 
# define DEBUG
 
#endif
 
void
_pixman_log_error (const char *function, const char *message);
 
#define return_if_fail(expr) \
do \
{ \
if (unlikely (!(expr))) \
{ \
_pixman_log_error (FUNC, "The expression " # expr " was false"); \
return; \
} \
} \
while (0)
 
#define return_val_if_fail(expr, retval) \
do \
{ \
if (unlikely (!(expr))) \
{ \
_pixman_log_error (FUNC, "The expression " # expr " was false"); \
return (retval); \
} \
} \
while (0)
 
#define critical_if_fail(expr) \
do \
{ \
if (unlikely (!(expr))) \
_pixman_log_error (FUNC, "The expression " # expr " was false"); \
} \
while (0)
 
/*
* Matrix
*/
 
typedef struct { pixman_fixed_48_16_t v[3]; } pixman_vector_48_16_t;
 
pixman_bool_t
pixman_transform_point_31_16 (const pixman_transform_t *t,
const pixman_vector_48_16_t *v,
pixman_vector_48_16_t *result);
 
void
pixman_transform_point_31_16_3d (const pixman_transform_t *t,
const pixman_vector_48_16_t *v,
pixman_vector_48_16_t *result);
 
void
pixman_transform_point_31_16_affine (const pixman_transform_t *t,
const pixman_vector_48_16_t *v,
pixman_vector_48_16_t *result);
 
/*
* Timers
*/
 
#ifdef PIXMAN_TIMERS
 
static inline uint64_t
oil_profile_stamp_rdtsc (void)
{
uint32_t hi, lo;
 
__asm__ __volatile__ ("rdtsc\n" : "=a" (lo), "=d" (hi));
 
return lo | (((uint64_t)hi) << 32);
}
 
#define OIL_STAMP oil_profile_stamp_rdtsc
 
typedef struct pixman_timer_t pixman_timer_t;
 
struct pixman_timer_t
{
int initialized;
const char * name;
uint64_t n_times;
uint64_t total;
pixman_timer_t *next;
};
 
extern int timer_defined;
 
void pixman_timer_register (pixman_timer_t *timer);
 
#define TIMER_BEGIN(tname) \
{ \
static pixman_timer_t timer ## tname; \
uint64_t begin ## tname; \
\
if (!timer ## tname.initialized) \
{ \
timer ## tname.initialized = 1; \
timer ## tname.name = # tname; \
pixman_timer_register (&timer ## tname); \
} \
\
timer ## tname.n_times++; \
begin ## tname = OIL_STAMP ();
 
#define TIMER_END(tname) \
timer ## tname.total += OIL_STAMP () - begin ## tname; \
}
 
#else
 
#define TIMER_BEGIN(tname)
#define TIMER_END(tname)
 
#endif /* PIXMAN_TIMERS */
 
#endif /* __ASSEMBLER__ */
 
#endif /* PIXMAN_PRIVATE_H */
/contrib/sdk/sources/pixman/pixman-radial-gradient.c
0,0 → 1,471
/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
/*
*
* Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
* Copyright © 2000 SuSE, Inc.
* 2005 Lars Knoll & Zack Rusin, Trolltech
* Copyright © 2007 Red Hat, Inc.
*
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <math.h>
#include "pixman-private.h"
 
static inline pixman_fixed_32_32_t
dot (pixman_fixed_48_16_t x1,
pixman_fixed_48_16_t y1,
pixman_fixed_48_16_t z1,
pixman_fixed_48_16_t x2,
pixman_fixed_48_16_t y2,
pixman_fixed_48_16_t z2)
{
/*
* Exact computation, assuming that the input values can
* be represented as pixman_fixed_16_16_t
*/
return x1 * x2 + y1 * y2 + z1 * z2;
}
 
static inline double
fdot (double x1,
double y1,
double z1,
double x2,
double y2,
double z2)
{
/*
* Error can be unbound in some special cases.
* Using clever dot product algorithms (for example compensated
* dot product) would improve this but make the code much less
* obvious
*/
return x1 * x2 + y1 * y2 + z1 * z2;
}
 
static uint32_t
radial_compute_color (double a,
double b,
double c,
double inva,
double dr,
double mindr,
pixman_gradient_walker_t *walker,
pixman_repeat_t repeat)
{
/*
* In this function error propagation can lead to bad results:
* - discr can have an unbound error (if b*b-a*c is very small),
* potentially making it the opposite sign of what it should have been
* (thus clearing a pixel that would have been colored or vice-versa)
* or propagating the error to sqrtdiscr;
* if discr has the wrong sign or b is very small, this can lead to bad
* results
*
* - the algorithm used to compute the solutions of the quadratic
* equation is not numerically stable (but saves one division compared
* to the numerically stable one);
* this can be a problem if a*c is much smaller than b*b
*
* - the above problems are worse if a is small (as inva becomes bigger)
*/
double discr;
 
if (a == 0)
{
double t;
 
if (b == 0)
return 0;
 
t = pixman_fixed_1 / 2 * c / b;
if (repeat == PIXMAN_REPEAT_NONE)
{
if (0 <= t && t <= pixman_fixed_1)
return _pixman_gradient_walker_pixel (walker, t);
}
else
{
if (t * dr >= mindr)
return _pixman_gradient_walker_pixel (walker, t);
}
 
return 0;
}
 
discr = fdot (b, a, 0, b, -c, 0);
if (discr >= 0)
{
double sqrtdiscr, t0, t1;
 
sqrtdiscr = sqrt (discr);
t0 = (b + sqrtdiscr) * inva;
t1 = (b - sqrtdiscr) * inva;
 
/*
* The root that must be used is the biggest one that belongs
* to the valid range ([0,1] for PIXMAN_REPEAT_NONE, any
* solution that results in a positive radius otherwise).
*
* If a > 0, t0 is the biggest solution, so if it is valid, it
* is the correct result.
*
* If a < 0, only one of the solutions can be valid, so the
* order in which they are tested is not important.
*/
if (repeat == PIXMAN_REPEAT_NONE)
{
if (0 <= t0 && t0 <= pixman_fixed_1)
return _pixman_gradient_walker_pixel (walker, t0);
else if (0 <= t1 && t1 <= pixman_fixed_1)
return _pixman_gradient_walker_pixel (walker, t1);
}
else
{
if (t0 * dr >= mindr)
return _pixman_gradient_walker_pixel (walker, t0);
else if (t1 * dr >= mindr)
return _pixman_gradient_walker_pixel (walker, t1);
}
}
 
return 0;
}
 
static uint32_t *
radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
{
/*
* Implementation of radial gradients following the PDF specification.
* See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference
* Manual (PDF 32000-1:2008 at the time of this writing).
*
* In the radial gradient problem we are given two circles (c₁,r₁) and
* (c₂,r₂) that define the gradient itself.
*
* Mathematically the gradient can be defined as the family of circles
*
* ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂)
*
* excluding those circles whose radius would be < 0. When a point
* belongs to more than one circle, the one with a bigger t is the only
* one that contributes to its color. When a point does not belong
* to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0).
* Further limitations on the range of values for t are imposed when
* the gradient is not repeated, namely t must belong to [0,1].
*
* The graphical result is the same as drawing the valid (radius > 0)
* circles with increasing t in [-inf, +inf] (or in [0,1] if the gradient
* is not repeated) using SOURCE operator composition.
*
* It looks like a cone pointing towards the viewer if the ending circle
* is smaller than the starting one, a cone pointing inside the page if
* the starting circle is the smaller one and like a cylinder if they
* have the same radius.
*
* What we actually do is, given the point whose color we are interested
* in, compute the t values for that point, solving for t in:
*
* length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂
*
* Let's rewrite it in a simpler way, by defining some auxiliary
* variables:
*
* cd = c₂ - c₁
* pd = p - c₁
* dr = r₂ - r₁
* length(t·cd - pd) = r₁ + t·dr
*
* which actually means
*
* hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr
*
* or
*
* ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr.
*
* If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes:
*
* (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)²
*
* where we can actually expand the squares and solve for t:
*
* t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² =
* = r₁² + 2·r₁·t·dr + t²·dr²
*
* (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t +
* (pdx² + pdy² - r₁²) = 0
*
* A = cdx² + cdy² - dr²
* B = pdx·cdx + pdy·cdy + r₁·dr
* C = pdx² + pdy² - r₁²
* At² - 2Bt + C = 0
*
* The solutions (unless the equation degenerates because of A = 0) are:
*
* t = (B ± ⎷(B² - A·C)) / A
*
* The solution we are going to prefer is the bigger one, unless the
* radius associated to it is negative (or it falls outside the valid t
* range).
*
* Additional observations (useful for optimizations):
* A does not depend on p
*
* A < 0 <=> one of the two circles completely contains the other one
* <=> for every p, the radiuses associated with the two t solutions
* have opposite sign
*/
pixman_image_t *image = iter->image;
int x = iter->x;
int y = iter->y;
int width = iter->width;
uint32_t *buffer = iter->buffer;
 
gradient_t *gradient = (gradient_t *)image;
radial_gradient_t *radial = (radial_gradient_t *)image;
uint32_t *end = buffer + width;
pixman_gradient_walker_t walker;
pixman_vector_t v, unit;
 
/* reference point is the center of the pixel */
v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
 
_pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
 
if (image->common.transform)
{
if (!pixman_transform_point_3d (image->common.transform, &v))
return iter->buffer;
 
unit.vector[0] = image->common.transform->matrix[0][0];
unit.vector[1] = image->common.transform->matrix[1][0];
unit.vector[2] = image->common.transform->matrix[2][0];
}
else
{
unit.vector[0] = pixman_fixed_1;
unit.vector[1] = 0;
unit.vector[2] = 0;
}
 
if (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1)
{
/*
* Given:
*
* t = (B ± ⎷(B² - A·C)) / A
*
* where
*
* A = cdx² + cdy² - dr²
* B = pdx·cdx + pdy·cdy + r₁·dr
* C = pdx² + pdy² - r₁²
* det = B² - A·C
*
* Since we have an affine transformation, we know that (pdx, pdy)
* increase linearly with each pixel,
*
* pdx = pdx₀ + n·ux,
* pdy = pdy₀ + n·uy,
*
* we can then express B, C and det through multiple differentiation.
*/
pixman_fixed_32_32_t b, db, c, dc, ddc;
 
/* warning: this computation may overflow */
v.vector[0] -= radial->c1.x;
v.vector[1] -= radial->c1.y;
 
/*
* B and C are computed and updated exactly.
* If fdot was used instead of dot, in the worst case it would
* lose 11 bits of precision in each of the multiplication and
* summing up would zero out all the bit that were preserved,
* thus making the result 0 instead of the correct one.
* This would mean a worst case of unbound relative error or
* about 2^10 absolute error
*/
b = dot (v.vector[0], v.vector[1], radial->c1.radius,
radial->delta.x, radial->delta.y, radial->delta.radius);
db = dot (unit.vector[0], unit.vector[1], 0,
radial->delta.x, radial->delta.y, 0);
 
c = dot (v.vector[0], v.vector[1],
-((pixman_fixed_48_16_t) radial->c1.radius),
v.vector[0], v.vector[1], radial->c1.radius);
dc = dot (2 * (pixman_fixed_48_16_t) v.vector[0] + unit.vector[0],
2 * (pixman_fixed_48_16_t) v.vector[1] + unit.vector[1],
0,
unit.vector[0], unit.vector[1], 0);
ddc = 2 * dot (unit.vector[0], unit.vector[1], 0,
unit.vector[0], unit.vector[1], 0);
 
while (buffer < end)
{
if (!mask || *mask++)
{
*buffer = radial_compute_color (radial->a, b, c,
radial->inva,
radial->delta.radius,
radial->mindr,
&walker,
image->common.repeat);
}
 
b += db;
c += dc;
dc += ddc;
++buffer;
}
}
else
{
/* projective */
/* Warning:
* error propagation guarantees are much looser than in the affine case
*/
while (buffer < end)
{
if (!mask || *mask++)
{
if (v.vector[2] != 0)
{
double pdx, pdy, invv2, b, c;
 
invv2 = 1. * pixman_fixed_1 / v.vector[2];
 
pdx = v.vector[0] * invv2 - radial->c1.x;
/* / pixman_fixed_1 */
 
pdy = v.vector[1] * invv2 - radial->c1.y;
/* / pixman_fixed_1 */
 
b = fdot (pdx, pdy, radial->c1.radius,
radial->delta.x, radial->delta.y,
radial->delta.radius);
/* / pixman_fixed_1 / pixman_fixed_1 */
 
c = fdot (pdx, pdy, -radial->c1.radius,
pdx, pdy, radial->c1.radius);
/* / pixman_fixed_1 / pixman_fixed_1 */
 
*buffer = radial_compute_color (radial->a, b, c,
radial->inva,
radial->delta.radius,
radial->mindr,
&walker,
image->common.repeat);
}
else
{
*buffer = 0;
}
}
 
++buffer;
 
v.vector[0] += unit.vector[0];
v.vector[1] += unit.vector[1];
v.vector[2] += unit.vector[2];
}
}
 
iter->y++;
return iter->buffer;
}
 
static uint32_t *
radial_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
{
uint32_t *buffer = radial_get_scanline_narrow (iter, NULL);
 
pixman_expand_to_float (
(argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
 
return buffer;
}
 
void
_pixman_radial_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter)
{
if (iter->iter_flags & ITER_NARROW)
iter->get_scanline = radial_get_scanline_narrow;
else
iter->get_scanline = radial_get_scanline_wide;
}
 
PIXMAN_EXPORT pixman_image_t *
pixman_image_create_radial_gradient (const pixman_point_fixed_t * inner,
const pixman_point_fixed_t * outer,
pixman_fixed_t inner_radius,
pixman_fixed_t outer_radius,
const pixman_gradient_stop_t *stops,
int n_stops)
{
pixman_image_t *image;
radial_gradient_t *radial;
 
image = _pixman_image_allocate ();
 
if (!image)
return NULL;
 
radial = &image->radial;
 
if (!_pixman_init_gradient (&radial->common, stops, n_stops))
{
free (image);
return NULL;
}
 
image->type = RADIAL;
 
radial->c1.x = inner->x;
radial->c1.y = inner->y;
radial->c1.radius = inner_radius;
radial->c2.x = outer->x;
radial->c2.y = outer->y;
radial->c2.radius = outer_radius;
 
/* warning: this computations may overflow */
radial->delta.x = radial->c2.x - radial->c1.x;
radial->delta.y = radial->c2.y - radial->c1.y;
radial->delta.radius = radial->c2.radius - radial->c1.radius;
 
/* computed exactly, then cast to double -> every bit of the double
representation is correct (53 bits) */
radial->a = dot (radial->delta.x, radial->delta.y, -radial->delta.radius,
radial->delta.x, radial->delta.y, radial->delta.radius);
if (radial->a != 0)
radial->inva = 1. * pixman_fixed_1 / radial->a;
 
radial->mindr = -1. * pixman_fixed_1 * radial->c1.radius;
 
return image;
}
/contrib/sdk/sources/pixman/pixman-region.c
0,0 → 1,2792
/*
* 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.
*
* Copyright © 1998 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
 
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include "pixman-private.h"
 
#define PIXREGION_NIL(reg) ((reg)->data && !(reg)->data->numRects)
/* not a region */
#define PIXREGION_NAR(reg) ((reg)->data == pixman_broken_data)
#define PIXREGION_NUMRECTS(reg) ((reg)->data ? (reg)->data->numRects : 1)
#define PIXREGION_SIZE(reg) ((reg)->data ? (reg)->data->size : 0)
#define PIXREGION_RECTS(reg) \
((reg)->data ? (box_type_t *)((reg)->data + 1) \
: &(reg)->extents)
#define PIXREGION_BOXPTR(reg) ((box_type_t *)((reg)->data + 1))
#define PIXREGION_BOX(reg, i) (&PIXREGION_BOXPTR (reg)[i])
#define PIXREGION_TOP(reg) PIXREGION_BOX (reg, (reg)->data->numRects)
#define PIXREGION_END(reg) PIXREGION_BOX (reg, (reg)->data->numRects - 1)
 
#define GOOD_RECT(rect) ((rect)->x1 < (rect)->x2 && (rect)->y1 < (rect)->y2)
#define BAD_RECT(rect) ((rect)->x1 > (rect)->x2 || (rect)->y1 > (rect)->y2)
 
#ifdef DEBUG
 
#define GOOD(reg) \
do \
{ \
if (!PREFIX (_selfcheck (reg))) \
_pixman_log_error (FUNC, "Malformed region " # reg); \
} while (0)
 
#else
 
#define GOOD(reg)
 
#endif
 
static const box_type_t PREFIX (_empty_box_) = { 0, 0, 0, 0 };
static const region_data_type_t PREFIX (_empty_data_) = { 0, 0 };
#if defined (__llvm__) && !defined (__clang__)
static const volatile region_data_type_t PREFIX (_broken_data_) = { 0, 0 };
#else
static const region_data_type_t PREFIX (_broken_data_) = { 0, 0 };
#endif
 
static box_type_t *pixman_region_empty_box =
(box_type_t *)&PREFIX (_empty_box_);
static region_data_type_t *pixman_region_empty_data =
(region_data_type_t *)&PREFIX (_empty_data_);
static region_data_type_t *pixman_broken_data =
(region_data_type_t *)&PREFIX (_broken_data_);
 
static pixman_bool_t
pixman_break (region_type_t *region);
 
/*
* The functions in this file implement the Region abstraction used extensively
* throughout the X11 sample server. A Region is simply a set of disjoint
* (non-overlapping) rectangles, plus an "extent" rectangle which is the
* smallest single rectangle that contains all the non-overlapping rectangles.
*
* A Region is implemented as a "y-x-banded" array of rectangles. This array
* imposes two degrees of order. First, all rectangles are sorted by top side
* y coordinate first (y1), and then by left side x coordinate (x1).
*
* Furthermore, the rectangles are grouped into "bands". Each rectangle in a
* band has the same top y coordinate (y1), and each has the same bottom y
* coordinate (y2). Thus all rectangles in a band differ only in their left
* and right side (x1 and x2). Bands are implicit in the array of rectangles:
* there is no separate list of band start pointers.
*
* The y-x band representation does not minimize rectangles. In particular,
* if a rectangle vertically crosses a band (the rectangle has scanlines in
* the y1 to y2 area spanned by the band), then the rectangle may be broken
* down into two or more smaller rectangles stacked one atop the other.
*
* ----------- -----------
* | | | | band 0
* | | -------- ----------- --------
* | | | | in y-x banded | | | | band 1
* | | | | form is | | | |
* ----------- | | ----------- --------
* | | | | band 2
* -------- --------
*
* An added constraint on the rectangles is that they must cover as much
* horizontal area as possible: no two rectangles within a band are allowed
* to touch.
*
* Whenever possible, bands will be merged together to cover a greater vertical
* distance (and thus reduce the number of rectangles). Two bands can be merged
* only if the bottom of one touches the top of the other and they have
* rectangles in the same places (of the same width, of course).
*
* Adam de Boor wrote most of the original region code. Joel McCormack
* substantially modified or rewrote most of the core arithmetic routines, and
* added pixman_region_validate in order to support several speed improvements
* to pixman_region_validate_tree. Bob Scheifler changed the representation
* to be more compact when empty or a single rectangle, and did a bunch of
* gratuitous reformatting. Carl Worth did further gratuitous reformatting
* while re-merging the server and client region code into libpixregion.
* Soren Sandmann did even more 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) )
 
static size_t
PIXREGION_SZOF (size_t n)
{
size_t size = n * sizeof(box_type_t);
if (n > UINT32_MAX / sizeof(box_type_t))
return 0;
 
if (sizeof(region_data_type_t) > UINT32_MAX - size)
return 0;
 
return size + sizeof(region_data_type_t);
}
 
static region_data_type_t *
alloc_data (size_t n)
{
size_t sz = PIXREGION_SZOF (n);
 
if (!sz)
return NULL;
 
return malloc (sz);
}
 
#define FREE_DATA(reg) if ((reg)->data && (reg)->data->size) free ((reg)->data)
 
#define RECTALLOC_BAIL(region, n, bail) \
do \
{ \
if (!(region)->data || \
(((region)->data->numRects + (n)) > (region)->data->size)) \
{ \
if (!pixman_rect_alloc (region, n)) \
goto bail; \
} \
} while (0)
 
#define RECTALLOC(region, n) \
do \
{ \
if (!(region)->data || \
(((region)->data->numRects + (n)) > (region)->data->size)) \
{ \
if (!pixman_rect_alloc (region, n)) { \
return FALSE; \
} \
} \
} while (0)
 
#define ADDRECT(next_rect, nx1, ny1, nx2, ny2) \
do \
{ \
next_rect->x1 = nx1; \
next_rect->y1 = ny1; \
next_rect->x2 = nx2; \
next_rect->y2 = ny2; \
next_rect++; \
} \
while (0)
 
#define NEWRECT(region, next_rect, nx1, ny1, nx2, ny2) \
do \
{ \
if (!(region)->data || \
((region)->data->numRects == (region)->data->size)) \
{ \
if (!pixman_rect_alloc (region, 1)) \
return FALSE; \
next_rect = PIXREGION_TOP (region); \
} \
ADDRECT (next_rect, nx1, ny1, nx2, ny2); \
region->data->numRects++; \
critical_if_fail (region->data->numRects <= region->data->size); \
} while (0)
 
#define DOWNSIZE(reg, numRects) \
do \
{ \
if (((numRects) < ((reg)->data->size >> 1)) && \
((reg)->data->size > 50)) \
{ \
region_data_type_t * new_data; \
size_t data_size = PIXREGION_SZOF (numRects); \
\
if (!data_size) \
{ \
new_data = NULL; \
} \
else \
{ \
new_data = (region_data_type_t *) \
realloc ((reg)->data, data_size); \
} \
\
if (new_data) \
{ \
new_data->size = (numRects); \
(reg)->data = new_data; \
} \
} \
} while (0)
 
PIXMAN_EXPORT pixman_bool_t
PREFIX (_equal) (region_type_t *reg1, region_type_t *reg2)
{
int i;
box_type_t *rects1;
box_type_t *rects2;
 
if (reg1->extents.x1 != reg2->extents.x1)
return FALSE;
if (reg1->extents.x2 != reg2->extents.x2)
return FALSE;
if (reg1->extents.y1 != reg2->extents.y1)
return FALSE;
if (reg1->extents.y2 != reg2->extents.y2)
return FALSE;
if (PIXREGION_NUMRECTS (reg1) != PIXREGION_NUMRECTS (reg2))
return FALSE;
 
rects1 = PIXREGION_RECTS (reg1);
rects2 = PIXREGION_RECTS (reg2);
for (i = 0; i != PIXREGION_NUMRECTS (reg1); i++)
{
if (rects1[i].x1 != rects2[i].x1)
return FALSE;
if (rects1[i].x2 != rects2[i].x2)
return FALSE;
if (rects1[i].y1 != rects2[i].y1)
return FALSE;
if (rects1[i].y2 != rects2[i].y2)
return FALSE;
}
 
return TRUE;
}
 
int
PREFIX (_print) (region_type_t *rgn)
{
int num, size;
int i;
box_type_t * rects;
 
num = PIXREGION_NUMRECTS (rgn);
size = PIXREGION_SIZE (rgn);
rects = PIXREGION_RECTS (rgn);
 
fprintf (stderr, "num: %d size: %d\n", num, size);
fprintf (stderr, "extents: %d %d %d %d\n",
rgn->extents.x1,
rgn->extents.y1,
rgn->extents.x2,
rgn->extents.y2);
for (i = 0; i < num; i++)
{
fprintf (stderr, "%d %d %d %d \n",
rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2);
}
fprintf (stderr, "\n");
 
return(num);
}
 
 
PIXMAN_EXPORT void
PREFIX (_init) (region_type_t *region)
{
region->extents = *pixman_region_empty_box;
region->data = pixman_region_empty_data;
}
 
PIXMAN_EXPORT void
PREFIX (_init_rect) (region_type_t * region,
int x,
int y,
unsigned int width,
unsigned int height)
{
region->extents.x1 = x;
region->extents.y1 = y;
region->extents.x2 = x + width;
region->extents.y2 = y + height;
 
if (!GOOD_RECT (&region->extents))
{
if (BAD_RECT (&region->extents))
_pixman_log_error (FUNC, "Invalid rectangle passed");
PREFIX (_init) (region);
return;
}
 
region->data = NULL;
}
 
PIXMAN_EXPORT void
PREFIX (_init_with_extents) (region_type_t *region, box_type_t *extents)
{
if (!GOOD_RECT (extents))
{
if (BAD_RECT (extents))
_pixman_log_error (FUNC, "Invalid rectangle passed");
PREFIX (_init) (region);
return;
}
region->extents = *extents;
 
region->data = NULL;
}
 
PIXMAN_EXPORT void
PREFIX (_fini) (region_type_t *region)
{
GOOD (region);
FREE_DATA (region);
}
 
PIXMAN_EXPORT int
PREFIX (_n_rects) (region_type_t *region)
{
return PIXREGION_NUMRECTS (region);
}
 
PIXMAN_EXPORT box_type_t *
PREFIX (_rectangles) (region_type_t *region,
int *n_rects)
{
if (n_rects)
*n_rects = PIXREGION_NUMRECTS (region);
 
return PIXREGION_RECTS (region);
}
 
static pixman_bool_t
pixman_break (region_type_t *region)
{
FREE_DATA (region);
 
region->extents = *pixman_region_empty_box;
region->data = pixman_broken_data;
 
return FALSE;
}
 
static pixman_bool_t
pixman_rect_alloc (region_type_t * region,
int n)
{
region_data_type_t *data;
 
if (!region->data)
{
n++;
region->data = alloc_data (n);
 
if (!region->data)
return pixman_break (region);
 
region->data->numRects = 1;
*PIXREGION_BOXPTR (region) = region->extents;
}
else if (!region->data->size)
{
region->data = alloc_data (n);
 
if (!region->data)
return pixman_break (region);
 
region->data->numRects = 0;
}
else
{
size_t data_size;
 
if (n == 1)
{
n = region->data->numRects;
if (n > 500) /* XXX pick numbers out of a hat */
n = 250;
}
 
n += region->data->numRects;
data_size = PIXREGION_SZOF (n);
 
if (!data_size)
{
data = NULL;
}
else
{
data = (region_data_type_t *)
realloc (region->data, PIXREGION_SZOF (n));
}
if (!data)
return pixman_break (region);
region->data = data;
}
region->data->size = n;
 
return TRUE;
}
 
PIXMAN_EXPORT pixman_bool_t
PREFIX (_copy) (region_type_t *dst, region_type_t *src)
{
GOOD (dst);
GOOD (src);
 
if (dst == src)
return TRUE;
dst->extents = src->extents;
 
if (!src->data || !src->data->size)
{
FREE_DATA (dst);
dst->data = src->data;
return TRUE;
}
if (!dst->data || (dst->data->size < src->data->numRects))
{
FREE_DATA (dst);
 
dst->data = alloc_data (src->data->numRects);
 
if (!dst->data)
return pixman_break (dst);
 
dst->data->size = src->data->numRects;
}
 
dst->data->numRects = src->data->numRects;
 
memmove ((char *)PIXREGION_BOXPTR (dst), (char *)PIXREGION_BOXPTR (src),
dst->data->numRects * sizeof(box_type_t));
 
return TRUE;
}
 
/*======================================================================
* Generic Region Operator
*====================================================================*/
 
/*-
*-----------------------------------------------------------------------
* pixman_coalesce --
* Attempt to merge the boxes in the current band with those in the
* previous one. We are guaranteed that the current band extends to
* the end of the rects array. Used only by pixman_op.
*
* Results:
* The new index for the previous band.
*
* Side Effects:
* If coalescing takes place:
* - rectangles in the previous band will have their y2 fields
* altered.
* - region->data->numRects will be decreased.
*
*-----------------------------------------------------------------------
*/
static inline int
pixman_coalesce (region_type_t * region, /* Region to coalesce */
int prev_start, /* Index of start of previous band */
int cur_start) /* Index of start of current band */
{
box_type_t *prev_box; /* Current box in previous band */
box_type_t *cur_box; /* Current box in current band */
int numRects; /* Number rectangles in both bands */
int y2; /* Bottom of current band */
 
/*
* Figure out how many rectangles are in the band.
*/
numRects = cur_start - prev_start;
critical_if_fail (numRects == region->data->numRects - cur_start);
 
if (!numRects) return cur_start;
 
/*
* The bands may only be coalesced if the bottom of the previous
* matches the top scanline of the current.
*/
prev_box = PIXREGION_BOX (region, prev_start);
cur_box = PIXREGION_BOX (region, cur_start);
if (prev_box->y2 != cur_box->y1) return cur_start;
 
/*
* 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 = cur_box->y2;
 
do
{
if ((prev_box->x1 != cur_box->x1) || (prev_box->x2 != cur_box->x2))
return (cur_start);
prev_box++;
cur_box++;
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 = cur_start - prev_start;
region->data->numRects -= numRects;
 
do
{
prev_box--;
prev_box->y2 = y2;
numRects--;
}
while (numRects);
 
return prev_start;
}
 
/* Quicky macro to avoid trivial reject procedure calls to pixman_coalesce */
 
#define COALESCE(new_reg, prev_band, cur_band) \
do \
{ \
if (cur_band - prev_band == new_reg->data->numRects - cur_band) \
prev_band = pixman_coalesce (new_reg, prev_band, cur_band); \
else \
prev_band = cur_band; \
} while (0)
 
/*-
*-----------------------------------------------------------------------
* pixman_region_append_non_o --
* Handle a non-overlapping band for the union and subtract operations.
* Just adds the (top/bottom-clipped) rectangles into the region.
* Doesn't have to check for subsumption or anything.
*
* Results:
* None.
*
* Side Effects:
* region->data->numRects is incremented and the rectangles overwritten
* with the rectangles we're passed.
*
*-----------------------------------------------------------------------
*/
static inline pixman_bool_t
pixman_region_append_non_o (region_type_t * region,
box_type_t * r,
box_type_t * r_end,
int y1,
int y2)
{
box_type_t *next_rect;
int new_rects;
 
new_rects = r_end - r;
 
critical_if_fail (y1 < y2);
critical_if_fail (new_rects != 0);
 
/* Make sure we have enough space for all rectangles to be added */
RECTALLOC (region, new_rects);
next_rect = PIXREGION_TOP (region);
region->data->numRects += new_rects;
 
do
{
critical_if_fail (r->x1 < r->x2);
ADDRECT (next_rect, r->x1, y1, r->x2, y2);
r++;
}
while (r != r_end);
 
return TRUE;
}
 
#define FIND_BAND(r, r_band_end, r_end, ry1) \
do \
{ \
ry1 = r->y1; \
r_band_end = r + 1; \
while ((r_band_end != r_end) && (r_band_end->y1 == ry1)) { \
r_band_end++; \
} \
} while (0)
 
#define APPEND_REGIONS(new_reg, r, r_end) \
do \
{ \
int new_rects; \
if ((new_rects = r_end - r)) { \
RECTALLOC_BAIL (new_reg, new_rects, bail); \
memmove ((char *)PIXREGION_TOP (new_reg), (char *)r, \
new_rects * sizeof(box_type_t)); \
new_reg->data->numRects += new_rects; \
} \
} while (0)
 
/*-
*-----------------------------------------------------------------------
* pixman_op --
* Apply an operation to two regions. Called by pixman_region_union, pixman_region_inverse,
* pixman_region_subtract, pixman_region_intersect.... Both regions MUST have at least one
* rectangle, and cannot be the same object.
*
* Results:
* TRUE if successful.
*
* Side Effects:
* The new region is overwritten.
* overlap set to TRUE if overlap_func 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 non_overlap_func is called with
* each the band and the band's upper and lower extents. For the
* second, the overlap_func is called to process the entire band. It
* is responsible for clipping the rectangles in the band, though
* this function provides the boundaries.
* At the end of each band, the new region is coalesced, if possible,
* to reduce the number of rectangles in the region.
*
*-----------------------------------------------------------------------
*/
 
typedef pixman_bool_t (*overlap_proc_ptr) (region_type_t *region,
box_type_t * r1,
box_type_t * r1_end,
box_type_t * r2,
box_type_t * r2_end,
int y1,
int y2);
 
static pixman_bool_t
pixman_op (region_type_t * new_reg, /* Place to store result */
region_type_t * reg1, /* First region in operation */
region_type_t * reg2, /* 2d region in operation */
overlap_proc_ptr overlap_func, /* Function to call for over-
* lapping bands */
int append_non1, /* Append non-overlapping bands
* in region 1 ?
*/
int append_non2 /* Append non-overlapping bands
* in region 2 ?
*/
)
{
box_type_t *r1; /* Pointer into first region */
box_type_t *r2; /* Pointer into 2d region */
box_type_t *r1_end; /* End of 1st region */
box_type_t *r2_end; /* End of 2d region */
int ybot; /* Bottom of intersection */
int ytop; /* Top of intersection */
region_data_type_t *old_data; /* Old data for new_reg */
int prev_band; /* Index of start of
* previous band in new_reg */
int cur_band; /* Index of start of current
* band in new_reg */
box_type_t * r1_band_end; /* End of current band in r1 */
box_type_t * r2_band_end; /* End of current band in r2 */
int top; /* Top of non-overlapping band */
int bot; /* Bottom of non-overlapping band*/
int r1y1; /* Temps for r1->y1 and r2->y1 */
int r2y1;
int new_size;
int numRects;
 
/*
* Break any region computed from a broken region
*/
if (PIXREGION_NAR (reg1) || PIXREGION_NAR (reg2))
return pixman_break (new_reg);
 
/*
* Initialization:
* set r1, r2, r1_end and r2_end 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 = PIXREGION_RECTS (reg1);
new_size = PIXREGION_NUMRECTS (reg1);
r1_end = r1 + new_size;
 
numRects = PIXREGION_NUMRECTS (reg2);
r2 = PIXREGION_RECTS (reg2);
r2_end = r2 + numRects;
critical_if_fail (r1 != r1_end);
critical_if_fail (r2 != r2_end);
 
old_data = (region_data_type_t *)NULL;
 
if (((new_reg == reg1) && (new_size > 1)) ||
((new_reg == reg2) && (numRects > 1)))
{
old_data = new_reg->data;
new_reg->data = pixman_region_empty_data;
}
 
/* guess at new size */
if (numRects > new_size)
new_size = numRects;
 
new_size <<= 1;
 
if (!new_reg->data)
new_reg->data = pixman_region_empty_data;
else if (new_reg->data->size)
new_reg->data->numRects = 0;
 
if (new_size > new_reg->data->size)
{
if (!pixman_rect_alloc (new_reg, new_size))
{
free (old_data);
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);
 
/*
* prev_band serves to mark the start of the previous band so rectangles
* can be coalesced into larger rectangles. qv. pixman_coalesce, above.
* In the beginning, there is no previous band, so prev_band == cur_band
* (cur_band is set later on, of course, but the first band will always
* start at index 0). prev_band and cur_band must be indices because of
* the possible expansion, and resultant moving, of the new region's
* array of rectangles.
*/
prev_band = 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. r1_band_end and r2_band_end serve to mark the
* rectangle after the last one in the current band for their
* respective regions.
*/
critical_if_fail (r1 != r1_end);
critical_if_fail (r2 != r2_end);
 
FIND_BAND (r1, r1_band_end, r1_end, r1y1);
FIND_BAND (r2, r2_band_end, r2_end, 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 (append_non1)
{
top = MAX (r1y1, ybot);
bot = MIN (r1->y2, r2y1);
if (top != bot)
{
cur_band = new_reg->data->numRects;
if (!pixman_region_append_non_o (new_reg, r1, r1_band_end, top, bot))
goto bail;
COALESCE (new_reg, prev_band, cur_band);
}
}
ytop = r2y1;
}
else if (r2y1 < r1y1)
{
if (append_non2)
{
top = MAX (r2y1, ybot);
bot = MIN (r2->y2, r1y1);
if (top != bot)
{
cur_band = new_reg->data->numRects;
 
if (!pixman_region_append_non_o (new_reg, r2, r2_band_end, top, bot))
goto bail;
 
COALESCE (new_reg, prev_band, cur_band);
}
}
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)
{
cur_band = new_reg->data->numRects;
 
if (!(*overlap_func)(new_reg,
r1, r1_band_end,
r2, r2_band_end,
ytop, ybot))
{
goto bail;
}
COALESCE (new_reg, prev_band, cur_band);
}
 
/*
* If we've finished with a band (y2 == ybot) we skip forward
* in the region to the next band.
*/
if (r1->y2 == ybot)
r1 = r1_band_end;
 
if (r2->y2 == ybot)
r2 = r2_band_end;
 
}
while (r1 != r1_end && r2 != r2_end);
 
/*
* 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 != r1_end) && append_non1)
{
/* Do first non_overlap1Func call, which may be able to coalesce */
FIND_BAND (r1, r1_band_end, r1_end, r1y1);
cur_band = new_reg->data->numRects;
if (!pixman_region_append_non_o (new_reg,
r1, r1_band_end,
MAX (r1y1, ybot), r1->y2))
{
goto bail;
}
COALESCE (new_reg, prev_band, cur_band);
 
/* Just append the rest of the boxes */
APPEND_REGIONS (new_reg, r1_band_end, r1_end);
}
else if ((r2 != r2_end) && append_non2)
{
/* Do first non_overlap2Func call, which may be able to coalesce */
FIND_BAND (r2, r2_band_end, r2_end, r2y1);
 
cur_band = new_reg->data->numRects;
 
if (!pixman_region_append_non_o (new_reg,
r2, r2_band_end,
MAX (r2y1, ybot), r2->y2))
{
goto bail;
}
 
COALESCE (new_reg, prev_band, cur_band);
 
/* Append rest of boxes */
APPEND_REGIONS (new_reg, r2_band_end, r2_end);
}
 
free (old_data);
 
if (!(numRects = new_reg->data->numRects))
{
FREE_DATA (new_reg);
new_reg->data = pixman_region_empty_data;
}
else if (numRects == 1)
{
new_reg->extents = *PIXREGION_BOXPTR (new_reg);
FREE_DATA (new_reg);
new_reg->data = (region_data_type_t *)NULL;
}
else
{
DOWNSIZE (new_reg, numRects);
}
 
return TRUE;
 
bail:
free (old_data);
 
return pixman_break (new_reg);
}
 
/*-
*-----------------------------------------------------------------------
* pixman_set_extents --
* Reset the extents of a region to what they should be. Called by
* pixman_region_subtract and pixman_region_intersect as they can't
* figure it out along the way or do so easily, as pixman_region_union can.
*
* Results:
* None.
*
* Side Effects:
* The region's 'extents' structure is overwritten.
*
*-----------------------------------------------------------------------
*/
static void
pixman_set_extents (region_type_t *region)
{
box_type_t *box, *box_end;
 
if (!region->data)
return;
 
if (!region->data->size)
{
region->extents.x2 = region->extents.x1;
region->extents.y2 = region->extents.y1;
return;
}
 
box = PIXREGION_BOXPTR (region);
box_end = PIXREGION_END (region);
 
/*
* Since box is the first rectangle in the region, it must have the
* smallest y1 and since box_end is the last rectangle in the region,
* it must have the largest y2, because of banding. Initialize x1 and
* x2 from box and box_end, resp., as good things to initialize them
* to...
*/
region->extents.x1 = box->x1;
region->extents.y1 = box->y1;
region->extents.x2 = box_end->x2;
region->extents.y2 = box_end->y2;
 
critical_if_fail (region->extents.y1 < region->extents.y2);
 
while (box <= box_end)
{
if (box->x1 < region->extents.x1)
region->extents.x1 = box->x1;
if (box->x2 > region->extents.x2)
region->extents.x2 = box->x2;
box++;
}
 
critical_if_fail (region->extents.x1 < region->extents.x2);
}
 
/*======================================================================
* Region Intersection
*====================================================================*/
/*-
*-----------------------------------------------------------------------
* pixman_region_intersect_o --
* Handle an overlapping band for pixman_region_intersect.
*
* Results:
* TRUE if successful.
*
* Side Effects:
* Rectangles may be added to the region.
*
*-----------------------------------------------------------------------
*/
/*ARGSUSED*/
static pixman_bool_t
pixman_region_intersect_o (region_type_t *region,
box_type_t * r1,
box_type_t * r1_end,
box_type_t * r2,
box_type_t * r2_end,
int y1,
int y2)
{
int x1;
int x2;
box_type_t * next_rect;
 
next_rect = PIXREGION_TOP (region);
 
critical_if_fail (y1 < y2);
critical_if_fail (r1 != r1_end && r2 != r2_end);
 
do
{
x1 = MAX (r1->x1, r2->x1);
x2 = MIN (r1->x2, r2->x2);
 
/*
* If there's any overlap between the two rectangles, add that
* overlap to the new region.
*/
if (x1 < x2)
NEWRECT (region, next_rect, 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 != r1_end) && (r2 != r2_end));
 
return TRUE;
}
 
PIXMAN_EXPORT pixman_bool_t
PREFIX (_intersect) (region_type_t * new_reg,
region_type_t * reg1,
region_type_t * reg2)
{
GOOD (reg1);
GOOD (reg2);
GOOD (new_reg);
 
/* check for trivial reject */
if (PIXREGION_NIL (reg1) || PIXREGION_NIL (reg2) ||
!EXTENTCHECK (&reg1->extents, &reg2->extents))
{
/* Covers about 20% of all cases */
FREE_DATA (new_reg);
new_reg->extents.x2 = new_reg->extents.x1;
new_reg->extents.y2 = new_reg->extents.y1;
if (PIXREGION_NAR (reg1) || PIXREGION_NAR (reg2))
{
new_reg->data = pixman_broken_data;
return FALSE;
}
else
{
new_reg->data = pixman_region_empty_data;
}
}
else if (!reg1->data && !reg2->data)
{
/* Covers about 80% of cases that aren't trivially rejected */
new_reg->extents.x1 = MAX (reg1->extents.x1, reg2->extents.x1);
new_reg->extents.y1 = MAX (reg1->extents.y1, reg2->extents.y1);
new_reg->extents.x2 = MIN (reg1->extents.x2, reg2->extents.x2);
new_reg->extents.y2 = MIN (reg1->extents.y2, reg2->extents.y2);
 
FREE_DATA (new_reg);
 
new_reg->data = (region_data_type_t *)NULL;
}
else if (!reg2->data && SUBSUMES (&reg2->extents, &reg1->extents))
{
return PREFIX (_copy) (new_reg, reg1);
}
else if (!reg1->data && SUBSUMES (&reg1->extents, &reg2->extents))
{
return PREFIX (_copy) (new_reg, reg2);
}
else if (reg1 == reg2)
{
return PREFIX (_copy) (new_reg, reg1);
}
else
{
/* General purpose intersection */
 
if (!pixman_op (new_reg, reg1, reg2, pixman_region_intersect_o, FALSE, FALSE))
return FALSE;
pixman_set_extents (new_reg);
}
 
GOOD (new_reg);
return(TRUE);
}
 
#define MERGERECT(r) \
do \
{ \
if (r->x1 <= x2) \
{ \
/* Merge with current rectangle */ \
if (x2 < r->x2) \
x2 = r->x2; \
} \
else \
{ \
/* Add current rectangle, start new one */ \
NEWRECT (region, next_rect, x1, y1, x2, y2); \
x1 = r->x1; \
x2 = r->x2; \
} \
r++; \
} while (0)
 
/*======================================================================
* Region Union
*====================================================================*/
 
/*-
*-----------------------------------------------------------------------
* pixman_region_union_o --
* Handle an overlapping band for the union operation. Picks the
* left-most rectangle each time and merges it into the region.
*
* Results:
* TRUE if successful.
*
* Side Effects:
* region is overwritten.
* overlap is set to TRUE if any boxes overlap.
*
*-----------------------------------------------------------------------
*/
static pixman_bool_t
pixman_region_union_o (region_type_t *region,
box_type_t * r1,
box_type_t * r1_end,
box_type_t * r2,
box_type_t * r2_end,
int y1,
int y2)
{
box_type_t *next_rect;
int x1; /* left and right side of current union */
int x2;
 
critical_if_fail (y1 < y2);
critical_if_fail (r1 != r1_end && r2 != r2_end);
 
next_rect = PIXREGION_TOP (region);
 
/* 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 != r1_end && r2 != r2_end)
{
if (r1->x1 < r2->x1)
MERGERECT (r1);
else
MERGERECT (r2);
}
 
/* Finish off whoever (if any) is left */
if (r1 != r1_end)
{
do
{
MERGERECT (r1);
}
while (r1 != r1_end);
}
else if (r2 != r2_end)
{
do
{
MERGERECT (r2);
}
while (r2 != r2_end);
}
 
/* Add current rectangle */
NEWRECT (region, next_rect, x1, y1, x2, y2);
 
return TRUE;
}
 
PIXMAN_EXPORT pixman_bool_t
PREFIX(_intersect_rect) (region_type_t *dest,
region_type_t *source,
int x, int y,
unsigned int width,
unsigned int height)
{
region_type_t region;
 
region.data = NULL;
region.extents.x1 = x;
region.extents.y1 = y;
region.extents.x2 = x + width;
region.extents.y2 = y + height;
 
return PREFIX(_intersect) (dest, source, &region);
}
 
/* Convenience function for performing union of region with a
* single rectangle
*/
PIXMAN_EXPORT pixman_bool_t
PREFIX (_union_rect) (region_type_t *dest,
region_type_t *source,
int x,
int y,
unsigned int width,
unsigned int height)
{
region_type_t region;
 
region.extents.x1 = x;
region.extents.y1 = y;
region.extents.x2 = x + width;
region.extents.y2 = y + height;
 
if (!GOOD_RECT (&region.extents))
{
if (BAD_RECT (&region.extents))
_pixman_log_error (FUNC, "Invalid rectangle passed");
return PREFIX (_copy) (dest, source);
}
 
region.data = NULL;
 
return PREFIX (_union) (dest, source, &region);
}
 
PIXMAN_EXPORT pixman_bool_t
PREFIX (_union) (region_type_t *new_reg,
region_type_t *reg1,
region_type_t *reg2)
{
/* Return TRUE if some overlap
* between reg1, reg2
*/
GOOD (reg1);
GOOD (reg2);
GOOD (new_reg);
 
/* checks all the simple cases */
 
/*
* Region 1 and 2 are the same
*/
if (reg1 == reg2)
return PREFIX (_copy) (new_reg, reg1);
 
/*
* Region 1 is empty
*/
if (PIXREGION_NIL (reg1))
{
if (PIXREGION_NAR (reg1))
return pixman_break (new_reg);
 
if (new_reg != reg2)
return PREFIX (_copy) (new_reg, reg2);
 
return TRUE;
}
 
/*
* Region 2 is empty
*/
if (PIXREGION_NIL (reg2))
{
if (PIXREGION_NAR (reg2))
return pixman_break (new_reg);
 
if (new_reg != reg1)
return PREFIX (_copy) (new_reg, reg1);
 
return TRUE;
}
 
/*
* Region 1 completely subsumes region 2
*/
if (!reg1->data && SUBSUMES (&reg1->extents, &reg2->extents))
{
if (new_reg != reg1)
return PREFIX (_copy) (new_reg, reg1);
 
return TRUE;
}
 
/*
* Region 2 completely subsumes region 1
*/
if (!reg2->data && SUBSUMES (&reg2->extents, &reg1->extents))
{
if (new_reg != reg2)
return PREFIX (_copy) (new_reg, reg2);
 
return TRUE;
}
 
if (!pixman_op (new_reg, reg1, reg2, pixman_region_union_o, TRUE, TRUE))
return FALSE;
 
new_reg->extents.x1 = MIN (reg1->extents.x1, reg2->extents.x1);
new_reg->extents.y1 = MIN (reg1->extents.y1, reg2->extents.y1);
new_reg->extents.x2 = MAX (reg1->extents.x2, reg2->extents.x2);
new_reg->extents.y2 = MAX (reg1->extents.y2, reg2->extents.y2);
GOOD (new_reg);
 
return TRUE;
}
 
/*======================================================================
* Batch Rectangle Union
*====================================================================*/
 
#define EXCHANGE_RECTS(a, b) \
{ \
box_type_t t; \
t = rects[a]; \
rects[a] = rects[b]; \
rects[b] = t; \
}
 
static void
quick_sort_rects (
box_type_t rects[],
int numRects)
{
int y1;
int x1;
int i, j;
box_type_t *r;
 
/* Always called with numRects > 1 */
 
do
{
if (numRects == 2)
{
if (rects[0].y1 > rects[1].y1 ||
(rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1))
{
EXCHANGE_RECTS (0, 1);
}
 
return;
}
 
/* Choose partition element, stick in location 0 */
EXCHANGE_RECTS (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)
EXCHANGE_RECTS (i, j);
}
while (i < j);
 
/* Move partition element back to middle */
EXCHANGE_RECTS (0, j);
 
/* Recurse */
if (numRects - j - 1 > 1)
quick_sort_rects (&rects[j + 1], numRects - j - 1);
 
numRects = j;
}
while (numRects > 1);
}
 
/*-
*-----------------------------------------------------------------------
* pixman_region_validate --
*
* Take a ``region'' which is a non-y-x-banded random collection of
* rectangles, and compute a nice region which is the union of all the
* rectangles.
*
* Results:
* TRUE if successful.
*
* Side Effects:
* The passed-in ``region'' may be modified.
* overlap set to TRUE if any retangles overlapped,
* else FALSE;
*
* Strategy:
* Step 1. Sort the rectangles into ascending order with primary key y1
* and secondary key x1.
*
* Step 2. Split the rectangles into the minimum number of proper y-x
* banded regions. This may require horizontally merging
* rectangles, and vertically coalescing bands. With any luck,
* this step in an identity transformation (ala the Box widget),
* or a coalescing into 1 box (ala Menus).
*
* Step 3. Merge the separate regions down to a single region by calling
* pixman_region_union. Maximize the work each pixman_region_union call does by using
* a binary merge.
*
*-----------------------------------------------------------------------
*/
 
static pixman_bool_t
validate (region_type_t * badreg)
{
/* Descriptor for regions under construction in Step 2. */
typedef struct
{
region_type_t reg;
int prev_band;
int cur_band;
} region_info_t;
 
region_info_t stack_regions[64];
 
int numRects; /* Original numRects for badreg */
region_info_t *ri; /* Array of current regions */
int num_ri; /* Number of entries used in ri */
int size_ri; /* Number of entries available in ri */
int i; /* Index into rects */
int j; /* Index into ri */
region_info_t *rit; /* &ri[j] */
region_type_t *reg; /* ri[j].reg */
box_type_t *box; /* Current box in rects */
box_type_t *ri_box; /* Last box in ri[j].reg */
region_type_t *hreg; /* ri[j_half].reg */
pixman_bool_t ret = TRUE;
 
if (!badreg->data)
{
GOOD (badreg);
return TRUE;
}
numRects = badreg->data->numRects;
if (!numRects)
{
if (PIXREGION_NAR (badreg))
return FALSE;
GOOD (badreg);
return TRUE;
}
if (badreg->extents.x1 < badreg->extents.x2)
{
if ((numRects) == 1)
{
FREE_DATA (badreg);
badreg->data = (region_data_type_t *) NULL;
}
else
{
DOWNSIZE (badreg, numRects);
}
 
GOOD (badreg);
 
return TRUE;
}
 
/* Step 1: Sort the rects array into ascending (y1, x1) order */
quick_sort_rects (PIXREGION_BOXPTR (badreg), numRects);
 
/* Step 2: Scatter the sorted array into the minimum number of regions */
 
/* Set up the first region to be the first rectangle in badreg */
/* Note that step 2 code will never overflow the ri[0].reg rects array */
ri = stack_regions;
size_ri = sizeof (stack_regions) / sizeof (stack_regions[0]);
num_ri = 1;
ri[0].prev_band = 0;
ri[0].cur_band = 0;
ri[0].reg = *badreg;
box = PIXREGION_BOXPTR (&ri[0].reg);
ri[0].reg.extents = *box;
ri[0].reg.data->numRects = 1;
badreg->extents = *pixman_region_empty_box;
badreg->data = pixman_region_empty_data;
 
/* 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 = num_ri, rit = ri; --j >= 0; rit++)
{
reg = &rit->reg;
ri_box = PIXREGION_END (reg);
 
if (box->y1 == ri_box->y1 && box->y2 == ri_box->y2)
{
/* box is in same band as ri_box. Merge or append it */
if (box->x1 <= ri_box->x2)
{
/* Merge it with ri_box */
if (box->x2 > ri_box->x2)
ri_box->x2 = box->x2;
}
else
{
RECTALLOC_BAIL (reg, 1, bail);
*PIXREGION_TOP (reg) = *box;
reg->data->numRects++;
}
goto next_rect; /* So sue me */
}
else if (box->y1 >= ri_box->y2)
{
/* Put box into new band */
if (reg->extents.x2 < ri_box->x2)
reg->extents.x2 = ri_box->x2;
if (reg->extents.x1 > box->x1)
reg->extents.x1 = box->x1;
COALESCE (reg, rit->prev_band, rit->cur_band);
rit->cur_band = reg->data->numRects;
RECTALLOC_BAIL (reg, 1, bail);
*PIXREGION_TOP (reg) = *box;
reg->data->numRects++;
 
goto next_rect;
}
/* Well, this region was inappropriate. Try the next one. */
} /* for j */
 
/* Uh-oh. No regions were appropriate. Create a new one. */
if (size_ri == num_ri)
{
size_t data_size;
 
/* Oops, allocate space for new region information */
size_ri <<= 1;
 
data_size = size_ri * sizeof(region_info_t);
if (data_size / size_ri != sizeof(region_info_t))
goto bail;
 
if (ri == stack_regions)
{
rit = malloc (data_size);
if (!rit)
goto bail;
memcpy (rit, ri, num_ri * sizeof (region_info_t));
}
else
{
rit = (region_info_t *) realloc (ri, data_size);
if (!rit)
goto bail;
}
ri = rit;
rit = &ri[num_ri];
}
num_ri++;
rit->prev_band = 0;
rit->cur_band = 0;
rit->reg.extents = *box;
rit->reg.data = (region_data_type_t *)NULL;
 
/* MUST force allocation */
if (!pixman_rect_alloc (&rit->reg, (i + num_ri) / num_ri))
goto bail;
next_rect: ;
} /* for i */
 
/* Make a final pass over each region in order to COALESCE and set
* extents.x2 and extents.y2
*/
for (j = num_ri, rit = ri; --j >= 0; rit++)
{
reg = &rit->reg;
ri_box = PIXREGION_END (reg);
reg->extents.y2 = ri_box->y2;
 
if (reg->extents.x2 < ri_box->x2)
reg->extents.x2 = ri_box->x2;
COALESCE (reg, rit->prev_band, rit->cur_band);
 
if (reg->data->numRects == 1) /* keep unions happy below */
{
FREE_DATA (reg);
reg->data = (region_data_type_t *)NULL;
}
}
 
/* Step 3: Union all regions into a single region */
while (num_ri > 1)
{
int half = num_ri / 2;
for (j = num_ri & 1; j < (half + (num_ri & 1)); j++)
{
reg = &ri[j].reg;
hreg = &ri[j + half].reg;
 
if (!pixman_op (reg, reg, hreg, pixman_region_union_o, TRUE, TRUE))
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;
 
FREE_DATA (hreg);
}
 
num_ri -= half;
 
if (!ret)
goto bail;
}
 
*badreg = ri[0].reg;
 
if (ri != stack_regions)
free (ri);
 
GOOD (badreg);
return ret;
 
bail:
for (i = 0; i < num_ri; i++)
FREE_DATA (&ri[i].reg);
 
if (ri != stack_regions)
free (ri);
 
return pixman_break (badreg);
}
 
/*======================================================================
* Region Subtraction
*====================================================================*/
 
/*-
*-----------------------------------------------------------------------
* pixman_region_subtract_o --
* Overlapping band subtraction. x1 is the left-most point not yet
* checked.
*
* Results:
* TRUE if successful.
*
* Side Effects:
* region may have rectangles added to it.
*
*-----------------------------------------------------------------------
*/
/*ARGSUSED*/
static pixman_bool_t
pixman_region_subtract_o (region_type_t * region,
box_type_t * r1,
box_type_t * r1_end,
box_type_t * r2,
box_type_t * r2_end,
int y1,
int y2)
{
box_type_t * next_rect;
int x1;
 
x1 = r1->x1;
 
critical_if_fail (y1 < y2);
critical_if_fail (r1 != r1_end && r2 != r2_end);
 
next_rect = PIXREGION_TOP (region);
 
do
{
if (r2->x2 <= x1)
{
/*
* Subtrahend entirely to left of minuend: go to next subtrahend.
*/
r2++;
}
else if (r2->x1 <= x1)
{
/*
* Subtrahend precedes 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 != r1_end)
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.
*/
critical_if_fail (x1 < r2->x1);
NEWRECT (region, next_rect, x1, y1, r2->x1, y2);
 
x1 = r2->x2;
if (x1 >= r1->x2)
{
/*
* Minuend used up: advance to new...
*/
r1++;
if (r1 != r1_end)
x1 = r1->x1;
}
else
{
/*
* Subtrahend used up
*/
r2++;
}
}
else
{
/*
* Minuend used up: add any remaining piece before advancing.
*/
if (r1->x2 > x1)
NEWRECT (region, next_rect, x1, y1, r1->x2, y2);
 
r1++;
 
if (r1 != r1_end)
x1 = r1->x1;
}
}
while ((r1 != r1_end) && (r2 != r2_end));
 
/*
* Add remaining minuend rectangles to region.
*/
while (r1 != r1_end)
{
critical_if_fail (x1 < r1->x2);
 
NEWRECT (region, next_rect, x1, y1, r1->x2, y2);
 
r1++;
if (r1 != r1_end)
x1 = r1->x1;
}
return TRUE;
}
 
/*-
*-----------------------------------------------------------------------
* pixman_region_subtract --
* Subtract reg_s from reg_m and leave the result in reg_d.
* S stands for subtrahend, M for minuend and D for difference.
*
* Results:
* TRUE if successful.
*
* Side Effects:
* reg_d is overwritten.
*
*-----------------------------------------------------------------------
*/
PIXMAN_EXPORT pixman_bool_t
PREFIX (_subtract) (region_type_t *reg_d,
region_type_t *reg_m,
region_type_t *reg_s)
{
GOOD (reg_m);
GOOD (reg_s);
GOOD (reg_d);
/* check for trivial rejects */
if (PIXREGION_NIL (reg_m) || PIXREGION_NIL (reg_s) ||
!EXTENTCHECK (&reg_m->extents, &reg_s->extents))
{
if (PIXREGION_NAR (reg_s))
return pixman_break (reg_d);
return PREFIX (_copy) (reg_d, reg_m);
}
else if (reg_m == reg_s)
{
FREE_DATA (reg_d);
reg_d->extents.x2 = reg_d->extents.x1;
reg_d->extents.y2 = reg_d->extents.y1;
reg_d->data = pixman_region_empty_data;
 
return TRUE;
}
 
/* Add those rectangles in region 1 that aren't in region 2,
do yucky subtraction for overlaps, and
just throw away rectangles in region 2 that aren't in region 1 */
if (!pixman_op (reg_d, reg_m, reg_s, pixman_region_subtract_o, TRUE, FALSE))
return FALSE;
 
/*
* Can't alter reg_d's extents before we call pixman_op because
* it might be one of the source regions and pixman_op depends
* on the extents of those regions being unaltered. Besides, this
* way there's no checking against rectangles that will be nuked
* due to coalescing, so we have to examine fewer rectangles.
*/
pixman_set_extents (reg_d);
GOOD (reg_d);
return TRUE;
}
 
/*======================================================================
* Region Inversion
*====================================================================*/
 
/*-
*-----------------------------------------------------------------------
* pixman_region_inverse --
* Take a region and a box and return a region that is everything
* in the box but not in the region. The careful reader will note
* that this is the same as subtracting the region from the box...
*
* Results:
* TRUE.
*
* Side Effects:
* new_reg is overwritten.
*
*-----------------------------------------------------------------------
*/
PIXMAN_EXPORT pixman_bool_t
PREFIX (_inverse) (region_type_t *new_reg, /* Destination region */
region_type_t *reg1, /* Region to invert */
box_type_t * inv_rect) /* Bounding box for inversion */
{
region_type_t inv_reg; /* Quick and dirty region made from the
* bounding box */
GOOD (reg1);
GOOD (new_reg);
/* check for trivial rejects */
if (PIXREGION_NIL (reg1) || !EXTENTCHECK (inv_rect, &reg1->extents))
{
if (PIXREGION_NAR (reg1))
return pixman_break (new_reg);
new_reg->extents = *inv_rect;
FREE_DATA (new_reg);
new_reg->data = (region_data_type_t *)NULL;
return TRUE;
}
 
/* Add those rectangles in region 1 that aren't in region 2,
* do yucky subtraction for overlaps, and
* just throw away rectangles in region 2 that aren't in region 1
*/
inv_reg.extents = *inv_rect;
inv_reg.data = (region_data_type_t *)NULL;
if (!pixman_op (new_reg, &inv_reg, reg1, pixman_region_subtract_o, TRUE, FALSE))
return FALSE;
 
/*
* Can't alter new_reg's extents before we call pixman_op because
* it might be one of the source regions and pixman_op depends
* on the extents of those regions being unaltered. Besides, this
* way there's no checking against rectangles that will be nuked
* due to coalescing, so we have to examine fewer rectangles.
*/
pixman_set_extents (new_reg);
GOOD (new_reg);
return TRUE;
}
 
/* In time O(log n), locate the first box whose y2 is greater than y.
* Return @end if no such box exists.
*/
static box_type_t *
find_box_for_y (box_type_t *begin, box_type_t *end, int y)
{
box_type_t *mid;
 
if (end == begin)
return end;
 
if (end - begin == 1)
{
if (begin->y2 > y)
return begin;
else
return end;
}
 
mid = begin + (end - begin) / 2;
if (mid->y2 > y)
{
/* If no box is found in [begin, mid], the function
* will return @mid, which is then known to be the
* correct answer.
*/
return find_box_for_y (begin, mid, y);
}
else
{
return find_box_for_y (mid, end, y);
}
}
 
/*
* rect_in(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, part_out is set TRUE. Any time a rectangle in
* the region covers part of the box, part_in is set TRUE. The process ends
* when either the box has been completely covered (we reached a band that
* doesn't overlap the box, part_in is TRUE and part_out is false), the
* box has been partially covered (part_in == part_out == 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 part_in is false)
*/
PIXMAN_EXPORT pixman_region_overlap_t
PREFIX (_contains_rectangle) (region_type_t * region,
box_type_t * prect)
{
box_type_t * pbox;
box_type_t * pbox_end;
int part_in, part_out;
int numRects;
int x, y;
 
GOOD (region);
 
numRects = PIXREGION_NUMRECTS (region);
 
/* useful optimization */
if (!numRects || !EXTENTCHECK (&region->extents, prect))
return(PIXMAN_REGION_OUT);
 
if (numRects == 1)
{
/* We know that it must be PIXMAN_REGION_IN or PIXMAN_REGION_PART */
if (SUBSUMES (&region->extents, prect))
return(PIXMAN_REGION_IN);
else
return(PIXMAN_REGION_PART);
}
 
part_out = FALSE;
part_in = 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 part_out and part_in are TRUE, or we reach prect->y2 */
for (pbox = PIXREGION_BOXPTR (region), pbox_end = pbox + numRects;
pbox != pbox_end;
pbox++)
{
/* getting up to speed or skipping remainder of band */
if (pbox->y2 <= y)
{
if ((pbox = find_box_for_y (pbox, pbox_end, y)) == pbox_end)
break;
}
 
if (pbox->y1 > y)
{
part_out = TRUE; /* missed part of rectangle above */
if (part_in || (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)
{
part_out = TRUE; /* missed part of rectangle to left */
if (part_in)
break;
}
 
if (pbox->x1 < prect->x2)
{
part_in = TRUE; /* definitely overlap */
if (part_out)
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. part_in will have been set true
* by now...
*/
part_out = TRUE;
break;
}
}
 
if (part_in)
{
if (y < prect->y2)
return PIXMAN_REGION_PART;
else
return PIXMAN_REGION_IN;
}
else
{
return PIXMAN_REGION_OUT;
}
}
 
/* PREFIX(_translate) (region, x, y)
* translates in place
*/
 
PIXMAN_EXPORT void
PREFIX (_translate) (region_type_t *region, int x, int y)
{
overflow_int_t x1, x2, y1, y2;
int nbox;
box_type_t * pbox;
 
GOOD (region);
region->extents.x1 = x1 = region->extents.x1 + x;
region->extents.y1 = y1 = region->extents.y1 + y;
region->extents.x2 = x2 = region->extents.x2 + x;
region->extents.y2 = y2 = region->extents.y2 + y;
if (((x1 - PIXMAN_REGION_MIN) | (y1 - PIXMAN_REGION_MIN) | (PIXMAN_REGION_MAX - x2) | (PIXMAN_REGION_MAX - y2)) >= 0)
{
if (region->data && (nbox = region->data->numRects))
{
for (pbox = PIXREGION_BOXPTR (region); nbox--; pbox++)
{
pbox->x1 += x;
pbox->y1 += y;
pbox->x2 += x;
pbox->y2 += y;
}
}
return;
}
 
if (((x2 - PIXMAN_REGION_MIN) | (y2 - PIXMAN_REGION_MIN) | (PIXMAN_REGION_MAX - x1) | (PIXMAN_REGION_MAX - y1)) <= 0)
{
region->extents.x2 = region->extents.x1;
region->extents.y2 = region->extents.y1;
FREE_DATA (region);
region->data = pixman_region_empty_data;
return;
}
 
if (x1 < PIXMAN_REGION_MIN)
region->extents.x1 = PIXMAN_REGION_MIN;
else if (x2 > PIXMAN_REGION_MAX)
region->extents.x2 = PIXMAN_REGION_MAX;
 
if (y1 < PIXMAN_REGION_MIN)
region->extents.y1 = PIXMAN_REGION_MIN;
else if (y2 > PIXMAN_REGION_MAX)
region->extents.y2 = PIXMAN_REGION_MAX;
 
if (region->data && (nbox = region->data->numRects))
{
box_type_t * pbox_out;
 
for (pbox_out = pbox = PIXREGION_BOXPTR (region); nbox--; pbox++)
{
pbox_out->x1 = x1 = pbox->x1 + x;
pbox_out->y1 = y1 = pbox->y1 + y;
pbox_out->x2 = x2 = pbox->x2 + x;
pbox_out->y2 = y2 = pbox->y2 + y;
 
if (((x2 - PIXMAN_REGION_MIN) | (y2 - PIXMAN_REGION_MIN) |
(PIXMAN_REGION_MAX - x1) | (PIXMAN_REGION_MAX - y1)) <= 0)
{
region->data->numRects--;
continue;
}
 
if (x1 < PIXMAN_REGION_MIN)
pbox_out->x1 = PIXMAN_REGION_MIN;
else if (x2 > PIXMAN_REGION_MAX)
pbox_out->x2 = PIXMAN_REGION_MAX;
 
if (y1 < PIXMAN_REGION_MIN)
pbox_out->y1 = PIXMAN_REGION_MIN;
else if (y2 > PIXMAN_REGION_MAX)
pbox_out->y2 = PIXMAN_REGION_MAX;
 
pbox_out++;
}
 
if (pbox_out != pbox)
{
if (region->data->numRects == 1)
{
region->extents = *PIXREGION_BOXPTR (region);
FREE_DATA (region);
region->data = (region_data_type_t *)NULL;
}
else
{
pixman_set_extents (region);
}
}
}
 
GOOD (region);
}
 
PIXMAN_EXPORT void
PREFIX (_reset) (region_type_t *region, box_type_t *box)
{
GOOD (region);
 
critical_if_fail (GOOD_RECT (box));
 
region->extents = *box;
 
FREE_DATA (region);
 
region->data = NULL;
}
 
PIXMAN_EXPORT void
PREFIX (_clear) (region_type_t *region)
{
GOOD (region);
FREE_DATA (region);
 
region->extents = *pixman_region_empty_box;
region->data = pixman_region_empty_data;
}
 
/* box is "return" value */
PIXMAN_EXPORT int
PREFIX (_contains_point) (region_type_t * region,
int x, int y,
box_type_t * box)
{
box_type_t *pbox, *pbox_end;
int numRects;
 
GOOD (region);
numRects = PIXREGION_NUMRECTS (region);
 
if (!numRects || !INBOX (&region->extents, x, y))
return(FALSE);
 
if (numRects == 1)
{
if (box)
*box = region->extents;
 
return(TRUE);
}
 
pbox = PIXREGION_BOXPTR (region);
pbox_end = pbox + numRects;
 
pbox = find_box_for_y (pbox, pbox_end, y);
 
for (;pbox != pbox_end; pbox++)
{
if ((y < pbox->y1) || (x < pbox->x1))
break; /* missed it */
 
if (x >= pbox->x2)
continue; /* not there yet */
 
if (box)
*box = *pbox;
 
return(TRUE);
}
 
return(FALSE);
}
 
PIXMAN_EXPORT int
PREFIX (_not_empty) (region_type_t * region)
{
GOOD (region);
 
return(!PIXREGION_NIL (region));
}
 
PIXMAN_EXPORT box_type_t *
PREFIX (_extents) (region_type_t * region)
{
GOOD (region);
 
return(&region->extents);
}
 
/*
* 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.
*/
 
PIXMAN_EXPORT pixman_bool_t
PREFIX (_selfcheck) (region_type_t *reg)
{
int i, numRects;
 
if ((reg->extents.x1 > reg->extents.x2) ||
(reg->extents.y1 > reg->extents.y2))
{
return FALSE;
}
 
numRects = PIXREGION_NUMRECTS (reg);
if (!numRects)
{
return ((reg->extents.x1 == reg->extents.x2) &&
(reg->extents.y1 == reg->extents.y2) &&
(reg->data->size || (reg->data == pixman_region_empty_data)));
}
else if (numRects == 1)
{
return (!reg->data);
}
else
{
box_type_t * pbox_p, * pbox_n;
box_type_t box;
 
pbox_p = PIXREGION_RECTS (reg);
box = *pbox_p;
box.y2 = pbox_p[numRects - 1].y2;
pbox_n = pbox_p + 1;
 
for (i = numRects; --i > 0; pbox_p++, pbox_n++)
{
if ((pbox_n->x1 >= pbox_n->x2) ||
(pbox_n->y1 >= pbox_n->y2))
{
return FALSE;
}
 
if (pbox_n->x1 < box.x1)
box.x1 = pbox_n->x1;
if (pbox_n->x2 > box.x2)
box.x2 = pbox_n->x2;
if ((pbox_n->y1 < pbox_p->y1) ||
((pbox_n->y1 == pbox_p->y1) &&
((pbox_n->x1 < pbox_p->x2) || (pbox_n->y2 != pbox_p->y2))))
{
return FALSE;
}
}
 
return ((box.x1 == reg->extents.x1) &&
(box.x2 == reg->extents.x2) &&
(box.y1 == reg->extents.y1) &&
(box.y2 == reg->extents.y2));
}
}
 
PIXMAN_EXPORT pixman_bool_t
PREFIX (_init_rects) (region_type_t *region,
const box_type_t *boxes, int count)
{
box_type_t *rects;
int displacement;
int i;
 
/* if it's 1, then we just want to set the extents, so call
* the existing method. */
if (count == 1)
{
PREFIX (_init_rect) (region,
boxes[0].x1,
boxes[0].y1,
boxes[0].x2 - boxes[0].x1,
boxes[0].y2 - boxes[0].y1);
return TRUE;
}
 
PREFIX (_init) (region);
 
/* if it's 0, don't call pixman_rect_alloc -- 0 rectangles is
* a special case, and causing pixman_rect_alloc would cause
* us to leak memory (because the 0-rect case should be the
* static pixman_region_empty_data data).
*/
if (count == 0)
return TRUE;
 
if (!pixman_rect_alloc (region, count))
return FALSE;
 
rects = PIXREGION_RECTS (region);
 
/* Copy in the rects */
memcpy (rects, boxes, sizeof(box_type_t) * count);
region->data->numRects = count;
 
/* Eliminate empty and malformed rectangles */
displacement = 0;
 
for (i = 0; i < count; ++i)
{
box_type_t *box = &rects[i];
 
if (box->x1 >= box->x2 || box->y1 >= box->y2)
displacement++;
else if (displacement)
rects[i - displacement] = rects[i];
}
 
region->data->numRects -= displacement;
 
/* If eliminating empty rectangles caused there
* to be only 0 or 1 rectangles, deal with that.
*/
if (region->data->numRects == 0)
{
FREE_DATA (region);
PREFIX (_init) (region);
 
return TRUE;
}
 
if (region->data->numRects == 1)
{
region->extents = rects[0];
 
FREE_DATA (region);
region->data = NULL;
 
GOOD (region);
 
return TRUE;
}
 
/* Validate */
region->extents.x1 = region->extents.x2 = 0;
 
return validate (region);
}
 
#define READ(_ptr) (*(_ptr))
 
static inline box_type_t *
bitmap_addrect (region_type_t *reg,
box_type_t *r,
box_type_t **first_rect,
int rx1, int ry1,
int rx2, int ry2)
{
if ((rx1 < rx2) && (ry1 < ry2) &&
(!(reg->data->numRects &&
((r-1)->y1 == ry1) && ((r-1)->y2 == ry2) &&
((r-1)->x1 <= rx1) && ((r-1)->x2 >= rx2))))
{
if (reg->data->numRects == reg->data->size)
{
if (!pixman_rect_alloc (reg, 1))
return NULL;
*first_rect = PIXREGION_BOXPTR(reg);
r = *first_rect + reg->data->numRects;
}
r->x1 = rx1;
r->y1 = ry1;
r->x2 = rx2;
r->y2 = ry2;
reg->data->numRects++;
if (r->x1 < reg->extents.x1)
reg->extents.x1 = r->x1;
if (r->x2 > reg->extents.x2)
reg->extents.x2 = r->x2;
r++;
}
return r;
}
 
/* Convert bitmap clip mask into clipping region.
* First, goes through each line and makes boxes by noting the transitions
* from 0 to 1 and 1 to 0.
* Then it coalesces the current line with the previous if they have boxes
* at the same X coordinates.
* Stride is in number of uint32_t per line.
*/
PIXMAN_EXPORT void
PREFIX (_init_from_image) (region_type_t *region,
pixman_image_t *image)
{
uint32_t mask0 = 0xffffffff & ~SCREEN_SHIFT_RIGHT(0xffffffff, 1);
box_type_t *first_rect, *rects, *prect_line_start;
box_type_t *old_rect, *new_rect;
uint32_t *pw, w, *pw_line, *pw_line_end;
int irect_prev_start, irect_line_start;
int h, base, rx1 = 0, crects;
int ib;
pixman_bool_t in_box, same;
int width, height, stride;
 
PREFIX(_init) (region);
 
critical_if_fail (region->data);
 
return_if_fail (image->type == BITS);
return_if_fail (image->bits.format == PIXMAN_a1);
 
pw_line = pixman_image_get_data (image);
width = pixman_image_get_width (image);
height = pixman_image_get_height (image);
stride = pixman_image_get_stride (image) / 4;
 
first_rect = PIXREGION_BOXPTR(region);
rects = first_rect;
 
region->extents.x1 = width - 1;
region->extents.x2 = 0;
irect_prev_start = -1;
for (h = 0; h < height; h++)
{
pw = pw_line;
pw_line += stride;
irect_line_start = rects - first_rect;
 
/* If the Screen left most bit of the word is set, we're starting in
* a box */
if (READ(pw) & mask0)
{
in_box = TRUE;
rx1 = 0;
}
else
{
in_box = FALSE;
}
 
/* Process all words which are fully in the pixmap */
pw_line_end = pw + (width >> 5);
for (base = 0; pw < pw_line_end; base += 32)
{
w = READ(pw++);
if (in_box)
{
if (!~w)
continue;
}
else
{
if (!w)
continue;
}
for (ib = 0; ib < 32; ib++)
{
/* If the Screen left most bit of the word is set, we're
* starting a box */
if (w & mask0)
{
if (!in_box)
{
rx1 = base + ib;
/* start new box */
in_box = TRUE;
}
}
else
{
if (in_box)
{
/* end box */
rects = bitmap_addrect (region, rects, &first_rect,
rx1, h, base + ib, h + 1);
if (rects == NULL)
goto error;
in_box = FALSE;
}
}
/* Shift the word VISUALLY left one. */
w = SCREEN_SHIFT_LEFT(w, 1);
}
}
 
if (width & 31)
{
/* Process final partial word on line */
w = READ(pw++);
for (ib = 0; ib < (width & 31); ib++)
{
/* If the Screen left most bit of the word is set, we're
* starting a box */
if (w & mask0)
{
if (!in_box)
{
rx1 = base + ib;
/* start new box */
in_box = TRUE;
}
}
else
{
if (in_box)
{
/* end box */
rects = bitmap_addrect(region, rects, &first_rect,
rx1, h, base + ib, h + 1);
if (rects == NULL)
goto error;
in_box = FALSE;
}
}
/* Shift the word VISUALLY left one. */
w = SCREEN_SHIFT_LEFT(w, 1);
}
}
/* If scanline ended with last bit set, end the box */
if (in_box)
{
rects = bitmap_addrect(region, rects, &first_rect,
rx1, h, base + (width & 31), h + 1);
if (rects == NULL)
goto error;
}
/* if all rectangles on this line have the same x-coords as
* those on the previous line, then add 1 to all the previous y2s and
* throw away all the rectangles from this line
*/
same = FALSE;
if (irect_prev_start != -1)
{
crects = irect_line_start - irect_prev_start;
if (crects != 0 &&
crects == ((rects - first_rect) - irect_line_start))
{
old_rect = first_rect + irect_prev_start;
new_rect = prect_line_start = first_rect + irect_line_start;
same = TRUE;
while (old_rect < prect_line_start)
{
if ((old_rect->x1 != new_rect->x1) ||
(old_rect->x2 != new_rect->x2))
{
same = FALSE;
break;
}
old_rect++;
new_rect++;
}
if (same)
{
old_rect = first_rect + irect_prev_start;
while (old_rect < prect_line_start)
{
old_rect->y2 += 1;
old_rect++;
}
rects -= crects;
region->data->numRects -= crects;
}
}
}
if(!same)
irect_prev_start = irect_line_start;
}
if (!region->data->numRects)
{
region->extents.x1 = region->extents.x2 = 0;
}
else
{
region->extents.y1 = PIXREGION_BOXPTR(region)->y1;
region->extents.y2 = PIXREGION_END(region)->y2;
if (region->data->numRects == 1)
{
free (region->data);
region->data = NULL;
}
}
 
error:
return;
}
/contrib/sdk/sources/pixman/pixman-region16.c
0,0 → 1,67
/*
* Copyright © 2008 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of
* Red Hat, Inc. not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Red Hat, Inc. makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL RED HAT, INC. 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: Soren Sandmann <sandmann@redhat.com>
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
 
#undef PIXMAN_DISABLE_DEPRECATED
 
#include "pixman-private.h"
 
#include <stdlib.h>
 
typedef pixman_box16_t box_type_t;
typedef pixman_region16_data_t region_data_type_t;
typedef pixman_region16_t region_type_t;
typedef int32_t overflow_int_t;
 
typedef struct {
int x, y;
} point_type_t;
 
#define PREFIX(x) pixman_region##x
 
#define PIXMAN_REGION_MAX INT16_MAX
#define PIXMAN_REGION_MIN INT16_MIN
 
#include "pixman-region.c"
 
/* This function exists only to make it possible to preserve the X ABI -
* it should go away at first opportunity.
*
* The problem is that the X ABI exports the three structs and has used
* them through macros. So the X server calls this function with
* the addresses of those structs which makes the existing code continue to
* work.
*/
PIXMAN_EXPORT void
pixman_region_set_static_pointers (pixman_box16_t *empty_box,
pixman_region16_data_t *empty_data,
pixman_region16_data_t *broken_data)
{
pixman_region_empty_box = empty_box;
pixman_region_empty_data = empty_data;
pixman_broken_data = broken_data;
}
/contrib/sdk/sources/pixman/pixman-region32.c
0,0 → 1,47
/*
* Copyright © 2008 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of
* Red Hat, Inc. not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Red Hat, Inc. makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL RED HAT, INC. 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: Soren Sandmann <sandmann@redhat.com>
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
 
#include "pixman-private.h"
 
#include <stdlib.h>
 
typedef pixman_box32_t box_type_t;
typedef pixman_region32_data_t region_data_type_t;
typedef pixman_region32_t region_type_t;
typedef int64_t overflow_int_t;
 
typedef struct {
int x, y;
} point_type_t;
 
#define PREFIX(x) pixman_region32##x
 
#define PIXMAN_REGION_MAX INT32_MAX
#define PIXMAN_REGION_MIN INT32_MIN
 
#include "pixman-region.c"
/contrib/sdk/sources/pixman/pixman-solid-fill.c
0,0 → 1,67
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007, 2009 Red Hat, Inc.
* Copyright © 2009 Soren Sandmann
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
 
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "pixman-private.h"
 
static uint32_t
color_to_uint32 (const pixman_color_t *color)
{
return
(color->alpha >> 8 << 24) |
(color->red >> 8 << 16) |
(color->green & 0xff00) |
(color->blue >> 8);
}
 
static argb_t
color_to_float (const pixman_color_t *color)
{
argb_t result;
 
result.a = pixman_unorm_to_float (color->alpha, 16);
result.r = pixman_unorm_to_float (color->red, 16);
result.g = pixman_unorm_to_float (color->green, 16);
result.b = pixman_unorm_to_float (color->blue, 16);
 
return result;
}
 
PIXMAN_EXPORT pixman_image_t *
pixman_image_create_solid_fill (const pixman_color_t *color)
{
pixman_image_t *img = _pixman_image_allocate ();
 
if (!img)
return NULL;
 
img->type = SOLID;
img->solid.color = *color;
img->solid.color_32 = color_to_uint32 (color);
img->solid.color_float = color_to_float (color);
 
return img;
}
 
/contrib/sdk/sources/pixman/pixman-sse2.c
0,0 → 1,6449
/*
* Copyright © 2008 Rodrigo Kumpera
* Copyright © 2008 André Tupinambá
*
* 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 Red Hat not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. Red Hat makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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: Rodrigo Kumpera (kumpera@gmail.com)
* André Tupinambá (andrelrt@gmail.com)
*
* Based on work by Owen Taylor and Søren Sandmann
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
 
#include <xmmintrin.h> /* for _mm_shuffle_pi16 and _MM_SHUFFLE */
#include <emmintrin.h> /* for SSE2 intrinsics */
#include "pixman-private.h"
#include "pixman-combine32.h"
#include "pixman-inlines.h"
 
static __m128i mask_0080;
static __m128i mask_00ff;
static __m128i mask_0101;
static __m128i mask_ffff;
static __m128i mask_ff000000;
static __m128i mask_alpha;
 
static __m128i mask_565_r;
static __m128i mask_565_g1, mask_565_g2;
static __m128i mask_565_b;
static __m128i mask_red;
static __m128i mask_green;
static __m128i mask_blue;
 
static __m128i mask_565_fix_rb;
static __m128i mask_565_fix_g;
 
static __m128i mask_565_rb;
static __m128i mask_565_pack_multiplier;
 
static force_inline __m128i
unpack_32_1x128 (uint32_t data)
{
return _mm_unpacklo_epi8 (_mm_cvtsi32_si128 (data), _mm_setzero_si128 ());
}
 
static force_inline void
unpack_128_2x128 (__m128i data, __m128i* data_lo, __m128i* data_hi)
{
*data_lo = _mm_unpacklo_epi8 (data, _mm_setzero_si128 ());
*data_hi = _mm_unpackhi_epi8 (data, _mm_setzero_si128 ());
}
 
static force_inline __m128i
unpack_565_to_8888 (__m128i lo)
{
__m128i r, g, b, rb, t;
 
r = _mm_and_si128 (_mm_slli_epi32 (lo, 8), mask_red);
g = _mm_and_si128 (_mm_slli_epi32 (lo, 5), mask_green);
b = _mm_and_si128 (_mm_slli_epi32 (lo, 3), mask_blue);
 
rb = _mm_or_si128 (r, b);
t = _mm_and_si128 (rb, mask_565_fix_rb);
t = _mm_srli_epi32 (t, 5);
rb = _mm_or_si128 (rb, t);
 
t = _mm_and_si128 (g, mask_565_fix_g);
t = _mm_srli_epi32 (t, 6);
g = _mm_or_si128 (g, t);
 
return _mm_or_si128 (rb, g);
}
 
static force_inline void
unpack_565_128_4x128 (__m128i data,
__m128i* data0,
__m128i* data1,
__m128i* data2,
__m128i* data3)
{
__m128i lo, hi;
 
lo = _mm_unpacklo_epi16 (data, _mm_setzero_si128 ());
hi = _mm_unpackhi_epi16 (data, _mm_setzero_si128 ());
 
lo = unpack_565_to_8888 (lo);
hi = unpack_565_to_8888 (hi);
 
unpack_128_2x128 (lo, data0, data1);
unpack_128_2x128 (hi, data2, data3);
}
 
static force_inline uint16_t
pack_565_32_16 (uint32_t pixel)
{
return (uint16_t) (((pixel >> 8) & 0xf800) |
((pixel >> 5) & 0x07e0) |
((pixel >> 3) & 0x001f));
}
 
static force_inline __m128i
pack_2x128_128 (__m128i lo, __m128i hi)
{
return _mm_packus_epi16 (lo, hi);
}
 
static force_inline __m128i
pack_565_2packedx128_128 (__m128i lo, __m128i hi)
{
__m128i rb0 = _mm_and_si128 (lo, mask_565_rb);
__m128i rb1 = _mm_and_si128 (hi, mask_565_rb);
 
__m128i t0 = _mm_madd_epi16 (rb0, mask_565_pack_multiplier);
__m128i t1 = _mm_madd_epi16 (rb1, mask_565_pack_multiplier);
 
__m128i g0 = _mm_and_si128 (lo, mask_green);
__m128i g1 = _mm_and_si128 (hi, mask_green);
 
t0 = _mm_or_si128 (t0, g0);
t1 = _mm_or_si128 (t1, g1);
 
/* Simulates _mm_packus_epi32 */
t0 = _mm_slli_epi32 (t0, 16 - 5);
t1 = _mm_slli_epi32 (t1, 16 - 5);
t0 = _mm_srai_epi32 (t0, 16);
t1 = _mm_srai_epi32 (t1, 16);
return _mm_packs_epi32 (t0, t1);
}
 
static force_inline __m128i
pack_565_2x128_128 (__m128i lo, __m128i hi)
{
__m128i data;
__m128i r, g1, g2, b;
 
data = pack_2x128_128 (lo, hi);
 
r = _mm_and_si128 (data, mask_565_r);
g1 = _mm_and_si128 (_mm_slli_epi32 (data, 3), mask_565_g1);
g2 = _mm_and_si128 (_mm_srli_epi32 (data, 5), mask_565_g2);
b = _mm_and_si128 (_mm_srli_epi32 (data, 3), mask_565_b);
 
return _mm_or_si128 (_mm_or_si128 (_mm_or_si128 (r, g1), g2), b);
}
 
static force_inline __m128i
pack_565_4x128_128 (__m128i* xmm0, __m128i* xmm1, __m128i* xmm2, __m128i* xmm3)
{
return _mm_packus_epi16 (pack_565_2x128_128 (*xmm0, *xmm1),
pack_565_2x128_128 (*xmm2, *xmm3));
}
 
static force_inline int
is_opaque (__m128i x)
{
__m128i ffs = _mm_cmpeq_epi8 (x, x);
 
return (_mm_movemask_epi8 (_mm_cmpeq_epi8 (x, ffs)) & 0x8888) == 0x8888;
}
 
static force_inline int
is_zero (__m128i x)
{
return _mm_movemask_epi8 (
_mm_cmpeq_epi8 (x, _mm_setzero_si128 ())) == 0xffff;
}
 
static force_inline int
is_transparent (__m128i x)
{
return (_mm_movemask_epi8 (
_mm_cmpeq_epi8 (x, _mm_setzero_si128 ())) & 0x8888) == 0x8888;
}
 
static force_inline __m128i
expand_pixel_32_1x128 (uint32_t data)
{
return _mm_shuffle_epi32 (unpack_32_1x128 (data), _MM_SHUFFLE (1, 0, 1, 0));
}
 
static force_inline __m128i
expand_alpha_1x128 (__m128i data)
{
return _mm_shufflehi_epi16 (_mm_shufflelo_epi16 (data,
_MM_SHUFFLE (3, 3, 3, 3)),
_MM_SHUFFLE (3, 3, 3, 3));
}
 
static force_inline void
expand_alpha_2x128 (__m128i data_lo,
__m128i data_hi,
__m128i* alpha_lo,
__m128i* alpha_hi)
{
__m128i lo, hi;
 
lo = _mm_shufflelo_epi16 (data_lo, _MM_SHUFFLE (3, 3, 3, 3));
hi = _mm_shufflelo_epi16 (data_hi, _MM_SHUFFLE (3, 3, 3, 3));
 
*alpha_lo = _mm_shufflehi_epi16 (lo, _MM_SHUFFLE (3, 3, 3, 3));
*alpha_hi = _mm_shufflehi_epi16 (hi, _MM_SHUFFLE (3, 3, 3, 3));
}
 
static force_inline void
expand_alpha_rev_2x128 (__m128i data_lo,
__m128i data_hi,
__m128i* alpha_lo,
__m128i* alpha_hi)
{
__m128i lo, hi;
 
lo = _mm_shufflelo_epi16 (data_lo, _MM_SHUFFLE (0, 0, 0, 0));
hi = _mm_shufflelo_epi16 (data_hi, _MM_SHUFFLE (0, 0, 0, 0));
*alpha_lo = _mm_shufflehi_epi16 (lo, _MM_SHUFFLE (0, 0, 0, 0));
*alpha_hi = _mm_shufflehi_epi16 (hi, _MM_SHUFFLE (0, 0, 0, 0));
}
 
static force_inline void
pix_multiply_2x128 (__m128i* data_lo,
__m128i* data_hi,
__m128i* alpha_lo,
__m128i* alpha_hi,
__m128i* ret_lo,
__m128i* ret_hi)
{
__m128i lo, hi;
 
lo = _mm_mullo_epi16 (*data_lo, *alpha_lo);
hi = _mm_mullo_epi16 (*data_hi, *alpha_hi);
lo = _mm_adds_epu16 (lo, mask_0080);
hi = _mm_adds_epu16 (hi, mask_0080);
*ret_lo = _mm_mulhi_epu16 (lo, mask_0101);
*ret_hi = _mm_mulhi_epu16 (hi, mask_0101);
}
 
static force_inline void
pix_add_multiply_2x128 (__m128i* src_lo,
__m128i* src_hi,
__m128i* alpha_dst_lo,
__m128i* alpha_dst_hi,
__m128i* dst_lo,
__m128i* dst_hi,
__m128i* alpha_src_lo,
__m128i* alpha_src_hi,
__m128i* ret_lo,
__m128i* ret_hi)
{
__m128i t1_lo, t1_hi;
__m128i t2_lo, t2_hi;
 
pix_multiply_2x128 (src_lo, src_hi, alpha_dst_lo, alpha_dst_hi, &t1_lo, &t1_hi);
pix_multiply_2x128 (dst_lo, dst_hi, alpha_src_lo, alpha_src_hi, &t2_lo, &t2_hi);
 
*ret_lo = _mm_adds_epu8 (t1_lo, t2_lo);
*ret_hi = _mm_adds_epu8 (t1_hi, t2_hi);
}
 
static force_inline void
negate_2x128 (__m128i data_lo,
__m128i data_hi,
__m128i* neg_lo,
__m128i* neg_hi)
{
*neg_lo = _mm_xor_si128 (data_lo, mask_00ff);
*neg_hi = _mm_xor_si128 (data_hi, mask_00ff);
}
 
static force_inline void
invert_colors_2x128 (__m128i data_lo,
__m128i data_hi,
__m128i* inv_lo,
__m128i* inv_hi)
{
__m128i lo, hi;
 
lo = _mm_shufflelo_epi16 (data_lo, _MM_SHUFFLE (3, 0, 1, 2));
hi = _mm_shufflelo_epi16 (data_hi, _MM_SHUFFLE (3, 0, 1, 2));
*inv_lo = _mm_shufflehi_epi16 (lo, _MM_SHUFFLE (3, 0, 1, 2));
*inv_hi = _mm_shufflehi_epi16 (hi, _MM_SHUFFLE (3, 0, 1, 2));
}
 
static force_inline void
over_2x128 (__m128i* src_lo,
__m128i* src_hi,
__m128i* alpha_lo,
__m128i* alpha_hi,
__m128i* dst_lo,
__m128i* dst_hi)
{
__m128i t1, t2;
 
negate_2x128 (*alpha_lo, *alpha_hi, &t1, &t2);
 
pix_multiply_2x128 (dst_lo, dst_hi, &t1, &t2, dst_lo, dst_hi);
 
*dst_lo = _mm_adds_epu8 (*src_lo, *dst_lo);
*dst_hi = _mm_adds_epu8 (*src_hi, *dst_hi);
}
 
static force_inline void
over_rev_non_pre_2x128 (__m128i src_lo,
__m128i src_hi,
__m128i* dst_lo,
__m128i* dst_hi)
{
__m128i lo, hi;
__m128i alpha_lo, alpha_hi;
 
expand_alpha_2x128 (src_lo, src_hi, &alpha_lo, &alpha_hi);
 
lo = _mm_or_si128 (alpha_lo, mask_alpha);
hi = _mm_or_si128 (alpha_hi, mask_alpha);
 
invert_colors_2x128 (src_lo, src_hi, &src_lo, &src_hi);
 
pix_multiply_2x128 (&src_lo, &src_hi, &lo, &hi, &lo, &hi);
 
over_2x128 (&lo, &hi, &alpha_lo, &alpha_hi, dst_lo, dst_hi);
}
 
static force_inline void
in_over_2x128 (__m128i* src_lo,
__m128i* src_hi,
__m128i* alpha_lo,
__m128i* alpha_hi,
__m128i* mask_lo,
__m128i* mask_hi,
__m128i* dst_lo,
__m128i* dst_hi)
{
__m128i s_lo, s_hi;
__m128i a_lo, a_hi;
 
pix_multiply_2x128 (src_lo, src_hi, mask_lo, mask_hi, &s_lo, &s_hi);
pix_multiply_2x128 (alpha_lo, alpha_hi, mask_lo, mask_hi, &a_lo, &a_hi);
 
over_2x128 (&s_lo, &s_hi, &a_lo, &a_hi, dst_lo, dst_hi);
}
 
/* load 4 pixels from a 16-byte boundary aligned address */
static force_inline __m128i
load_128_aligned (__m128i* src)
{
return _mm_load_si128 (src);
}
 
/* load 4 pixels from a unaligned address */
static force_inline __m128i
load_128_unaligned (const __m128i* src)
{
return _mm_loadu_si128 (src);
}
 
/* save 4 pixels using Write Combining memory on a 16-byte
* boundary aligned address
*/
static force_inline void
save_128_write_combining (__m128i* dst,
__m128i data)
{
_mm_stream_si128 (dst, data);
}
 
/* save 4 pixels on a 16-byte boundary aligned address */
static force_inline void
save_128_aligned (__m128i* dst,
__m128i data)
{
_mm_store_si128 (dst, data);
}
 
/* save 4 pixels on a unaligned address */
static force_inline void
save_128_unaligned (__m128i* dst,
__m128i data)
{
_mm_storeu_si128 (dst, data);
}
 
static force_inline __m128i
load_32_1x128 (uint32_t data)
{
return _mm_cvtsi32_si128 (data);
}
 
static force_inline __m128i
expand_alpha_rev_1x128 (__m128i data)
{
return _mm_shufflelo_epi16 (data, _MM_SHUFFLE (0, 0, 0, 0));
}
 
static force_inline __m128i
expand_pixel_8_1x128 (uint8_t data)
{
return _mm_shufflelo_epi16 (
unpack_32_1x128 ((uint32_t)data), _MM_SHUFFLE (0, 0, 0, 0));
}
 
static force_inline __m128i
pix_multiply_1x128 (__m128i data,
__m128i alpha)
{
return _mm_mulhi_epu16 (_mm_adds_epu16 (_mm_mullo_epi16 (data, alpha),
mask_0080),
mask_0101);
}
 
static force_inline __m128i
pix_add_multiply_1x128 (__m128i* src,
__m128i* alpha_dst,
__m128i* dst,
__m128i* alpha_src)
{
__m128i t1 = pix_multiply_1x128 (*src, *alpha_dst);
__m128i t2 = pix_multiply_1x128 (*dst, *alpha_src);
 
return _mm_adds_epu8 (t1, t2);
}
 
static force_inline __m128i
negate_1x128 (__m128i data)
{
return _mm_xor_si128 (data, mask_00ff);
}
 
static force_inline __m128i
invert_colors_1x128 (__m128i data)
{
return _mm_shufflelo_epi16 (data, _MM_SHUFFLE (3, 0, 1, 2));
}
 
static force_inline __m128i
over_1x128 (__m128i src, __m128i alpha, __m128i dst)
{
return _mm_adds_epu8 (src, pix_multiply_1x128 (dst, negate_1x128 (alpha)));
}
 
static force_inline __m128i
in_over_1x128 (__m128i* src, __m128i* alpha, __m128i* mask, __m128i* dst)
{
return over_1x128 (pix_multiply_1x128 (*src, *mask),
pix_multiply_1x128 (*alpha, *mask),
*dst);
}
 
static force_inline __m128i
over_rev_non_pre_1x128 (__m128i src, __m128i dst)
{
__m128i alpha = expand_alpha_1x128 (src);
 
return over_1x128 (pix_multiply_1x128 (invert_colors_1x128 (src),
_mm_or_si128 (alpha, mask_alpha)),
alpha,
dst);
}
 
static force_inline uint32_t
pack_1x128_32 (__m128i data)
{
return _mm_cvtsi128_si32 (_mm_packus_epi16 (data, _mm_setzero_si128 ()));
}
 
static force_inline __m128i
expand565_16_1x128 (uint16_t pixel)
{
__m128i m = _mm_cvtsi32_si128 (pixel);
 
m = unpack_565_to_8888 (m);
 
return _mm_unpacklo_epi8 (m, _mm_setzero_si128 ());
}
 
static force_inline uint32_t
core_combine_over_u_pixel_sse2 (uint32_t src, uint32_t dst)
{
uint8_t a;
__m128i xmms;
 
a = src >> 24;
 
if (a == 0xff)
{
return src;
}
else if (src)
{
xmms = unpack_32_1x128 (src);
return pack_1x128_32 (
over_1x128 (xmms, expand_alpha_1x128 (xmms),
unpack_32_1x128 (dst)));
}
 
return dst;
}
 
static force_inline uint32_t
combine1 (const uint32_t *ps, const uint32_t *pm)
{
uint32_t s = *ps;
 
if (pm)
{
__m128i ms, mm;
 
mm = unpack_32_1x128 (*pm);
mm = expand_alpha_1x128 (mm);
 
ms = unpack_32_1x128 (s);
ms = pix_multiply_1x128 (ms, mm);
 
s = pack_1x128_32 (ms);
}
 
return s;
}
 
static force_inline __m128i
combine4 (const __m128i *ps, const __m128i *pm)
{
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_msk_lo, xmm_msk_hi;
__m128i s;
 
if (pm)
{
xmm_msk_lo = load_128_unaligned (pm);
 
if (is_transparent (xmm_msk_lo))
return _mm_setzero_si128 ();
}
 
s = load_128_unaligned (ps);
 
if (pm)
{
unpack_128_2x128 (s, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_msk_lo, &xmm_msk_lo, &xmm_msk_hi);
 
expand_alpha_2x128 (xmm_msk_lo, xmm_msk_hi, &xmm_msk_lo, &xmm_msk_hi);
 
pix_multiply_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_msk_lo, &xmm_msk_hi,
&xmm_src_lo, &xmm_src_hi);
 
s = pack_2x128_128 (xmm_src_lo, xmm_src_hi);
}
 
return s;
}
 
static force_inline void
core_combine_over_u_sse2_mask (uint32_t * pd,
const uint32_t* ps,
const uint32_t* pm,
int w)
{
uint32_t s, d;
 
/* Align dst on a 16-byte boundary */
while (w && ((uintptr_t)pd & 15))
{
d = *pd;
s = combine1 (ps, pm);
 
if (s)
*pd = core_combine_over_u_pixel_sse2 (s, d);
pd++;
ps++;
pm++;
w--;
}
 
while (w >= 4)
{
__m128i mask = load_128_unaligned ((__m128i *)pm);
 
if (!is_zero (mask))
{
__m128i src;
__m128i src_hi, src_lo;
__m128i mask_hi, mask_lo;
__m128i alpha_hi, alpha_lo;
 
src = load_128_unaligned ((__m128i *)ps);
 
if (is_opaque (_mm_and_si128 (src, mask)))
{
save_128_aligned ((__m128i *)pd, src);
}
else
{
__m128i dst = load_128_aligned ((__m128i *)pd);
__m128i dst_hi, dst_lo;
 
unpack_128_2x128 (mask, &mask_lo, &mask_hi);
unpack_128_2x128 (src, &src_lo, &src_hi);
 
expand_alpha_2x128 (mask_lo, mask_hi, &mask_lo, &mask_hi);
pix_multiply_2x128 (&src_lo, &src_hi,
&mask_lo, &mask_hi,
&src_lo, &src_hi);
 
unpack_128_2x128 (dst, &dst_lo, &dst_hi);
 
expand_alpha_2x128 (src_lo, src_hi,
&alpha_lo, &alpha_hi);
 
over_2x128 (&src_lo, &src_hi, &alpha_lo, &alpha_hi,
&dst_lo, &dst_hi);
 
save_128_aligned (
(__m128i *)pd,
pack_2x128_128 (dst_lo, dst_hi));
}
}
 
pm += 4;
ps += 4;
pd += 4;
w -= 4;
}
while (w)
{
d = *pd;
s = combine1 (ps, pm);
 
if (s)
*pd = core_combine_over_u_pixel_sse2 (s, d);
pd++;
ps++;
pm++;
 
w--;
}
}
 
static force_inline void
core_combine_over_u_sse2_no_mask (uint32_t * pd,
const uint32_t* ps,
int w)
{
uint32_t s, d;
 
/* Align dst on a 16-byte boundary */
while (w && ((uintptr_t)pd & 15))
{
d = *pd;
s = *ps;
 
if (s)
*pd = core_combine_over_u_pixel_sse2 (s, d);
pd++;
ps++;
w--;
}
 
while (w >= 4)
{
__m128i src;
__m128i src_hi, src_lo, dst_hi, dst_lo;
__m128i alpha_hi, alpha_lo;
 
src = load_128_unaligned ((__m128i *)ps);
 
if (!is_zero (src))
{
if (is_opaque (src))
{
save_128_aligned ((__m128i *)pd, src);
}
else
{
__m128i dst = load_128_aligned ((__m128i *)pd);
 
unpack_128_2x128 (src, &src_lo, &src_hi);
unpack_128_2x128 (dst, &dst_lo, &dst_hi);
 
expand_alpha_2x128 (src_lo, src_hi,
&alpha_lo, &alpha_hi);
over_2x128 (&src_lo, &src_hi, &alpha_lo, &alpha_hi,
&dst_lo, &dst_hi);
 
save_128_aligned (
(__m128i *)pd,
pack_2x128_128 (dst_lo, dst_hi));
}
}
 
ps += 4;
pd += 4;
w -= 4;
}
while (w)
{
d = *pd;
s = *ps;
 
if (s)
*pd = core_combine_over_u_pixel_sse2 (s, d);
pd++;
ps++;
 
w--;
}
}
 
static force_inline void
sse2_combine_over_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
if (pm)
core_combine_over_u_sse2_mask (pd, ps, pm, w);
else
core_combine_over_u_sse2_no_mask (pd, ps, w);
}
 
static void
sse2_combine_over_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, d;
 
__m128i xmm_dst_lo, xmm_dst_hi;
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_alpha_lo, xmm_alpha_hi;
 
/* Align dst on a 16-byte boundary */
while (w &&
((uintptr_t)pd & 15))
{
d = *pd;
s = combine1 (ps, pm);
 
*pd++ = core_combine_over_u_pixel_sse2 (d, s);
w--;
ps++;
if (pm)
pm++;
}
 
while (w >= 4)
{
/* I'm loading unaligned because I'm not sure
* about the address alignment.
*/
xmm_src_hi = combine4 ((__m128i*)ps, (__m128i*)pm);
xmm_dst_hi = load_128_aligned ((__m128i*) pd);
 
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
 
expand_alpha_2x128 (xmm_dst_lo, xmm_dst_hi,
&xmm_alpha_lo, &xmm_alpha_hi);
 
over_2x128 (&xmm_dst_lo, &xmm_dst_hi,
&xmm_alpha_lo, &xmm_alpha_hi,
&xmm_src_lo, &xmm_src_hi);
 
/* rebuid the 4 pixel data and save*/
save_128_aligned ((__m128i*)pd,
pack_2x128_128 (xmm_src_lo, xmm_src_hi));
 
w -= 4;
ps += 4;
pd += 4;
 
if (pm)
pm += 4;
}
 
while (w)
{
d = *pd;
s = combine1 (ps, pm);
 
*pd++ = core_combine_over_u_pixel_sse2 (d, s);
ps++;
w--;
if (pm)
pm++;
}
}
 
static force_inline uint32_t
core_combine_in_u_pixel_sse2 (uint32_t src, uint32_t dst)
{
uint32_t maska = src >> 24;
 
if (maska == 0)
{
return 0;
}
else if (maska != 0xff)
{
return pack_1x128_32 (
pix_multiply_1x128 (unpack_32_1x128 (dst),
expand_alpha_1x128 (unpack_32_1x128 (src))));
}
 
return dst;
}
 
static void
sse2_combine_in_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, d;
 
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
 
while (w && ((uintptr_t)pd & 15))
{
s = combine1 (ps, pm);
d = *pd;
 
*pd++ = core_combine_in_u_pixel_sse2 (d, s);
w--;
ps++;
if (pm)
pm++;
}
 
while (w >= 4)
{
xmm_dst_hi = load_128_aligned ((__m128i*) pd);
xmm_src_hi = combine4 ((__m128i*) ps, (__m128i*) pm);
 
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
expand_alpha_2x128 (xmm_dst_lo, xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
 
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
pix_multiply_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_dst_lo, &xmm_dst_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned ((__m128i*)pd,
pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
ps += 4;
pd += 4;
w -= 4;
if (pm)
pm += 4;
}
 
while (w)
{
s = combine1 (ps, pm);
d = *pd;
 
*pd++ = core_combine_in_u_pixel_sse2 (d, s);
w--;
ps++;
if (pm)
pm++;
}
}
 
static void
sse2_combine_in_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, d;
 
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
 
while (w && ((uintptr_t)pd & 15))
{
s = combine1 (ps, pm);
d = *pd;
 
*pd++ = core_combine_in_u_pixel_sse2 (s, d);
ps++;
w--;
if (pm)
pm++;
}
 
while (w >= 4)
{
xmm_dst_hi = load_128_aligned ((__m128i*) pd);
xmm_src_hi = combine4 ((__m128i*) ps, (__m128i*)pm);
 
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
 
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
pix_multiply_2x128 (&xmm_dst_lo, &xmm_dst_hi,
&xmm_src_lo, &xmm_src_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
ps += 4;
pd += 4;
w -= 4;
if (pm)
pm += 4;
}
 
while (w)
{
s = combine1 (ps, pm);
d = *pd;
 
*pd++ = core_combine_in_u_pixel_sse2 (s, d);
w--;
ps++;
if (pm)
pm++;
}
}
 
static void
sse2_combine_out_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
while (w && ((uintptr_t)pd & 15))
{
uint32_t s = combine1 (ps, pm);
uint32_t d = *pd;
 
*pd++ = pack_1x128_32 (
pix_multiply_1x128 (
unpack_32_1x128 (d), negate_1x128 (
expand_alpha_1x128 (unpack_32_1x128 (s)))));
 
if (pm)
pm++;
ps++;
w--;
}
 
while (w >= 4)
{
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
 
xmm_src_hi = combine4 ((__m128i*)ps, (__m128i*)pm);
xmm_dst_hi = load_128_aligned ((__m128i*) pd);
 
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
 
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
negate_2x128 (xmm_src_lo, xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
 
pix_multiply_2x128 (&xmm_dst_lo, &xmm_dst_hi,
&xmm_src_lo, &xmm_src_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
ps += 4;
pd += 4;
if (pm)
pm += 4;
 
w -= 4;
}
 
while (w)
{
uint32_t s = combine1 (ps, pm);
uint32_t d = *pd;
 
*pd++ = pack_1x128_32 (
pix_multiply_1x128 (
unpack_32_1x128 (d), negate_1x128 (
expand_alpha_1x128 (unpack_32_1x128 (s)))));
ps++;
if (pm)
pm++;
w--;
}
}
 
static void
sse2_combine_out_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
while (w && ((uintptr_t)pd & 15))
{
uint32_t s = combine1 (ps, pm);
uint32_t d = *pd;
 
*pd++ = pack_1x128_32 (
pix_multiply_1x128 (
unpack_32_1x128 (s), negate_1x128 (
expand_alpha_1x128 (unpack_32_1x128 (d)))));
w--;
ps++;
if (pm)
pm++;
}
 
while (w >= 4)
{
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
 
xmm_src_hi = combine4 ((__m128i*) ps, (__m128i*)pm);
xmm_dst_hi = load_128_aligned ((__m128i*) pd);
 
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
 
expand_alpha_2x128 (xmm_dst_lo, xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
negate_2x128 (xmm_dst_lo, xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
 
pix_multiply_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_dst_lo, &xmm_dst_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
ps += 4;
pd += 4;
w -= 4;
if (pm)
pm += 4;
}
 
while (w)
{
uint32_t s = combine1 (ps, pm);
uint32_t d = *pd;
 
*pd++ = pack_1x128_32 (
pix_multiply_1x128 (
unpack_32_1x128 (s), negate_1x128 (
expand_alpha_1x128 (unpack_32_1x128 (d)))));
w--;
ps++;
if (pm)
pm++;
}
}
 
static force_inline uint32_t
core_combine_atop_u_pixel_sse2 (uint32_t src,
uint32_t dst)
{
__m128i s = unpack_32_1x128 (src);
__m128i d = unpack_32_1x128 (dst);
 
__m128i sa = negate_1x128 (expand_alpha_1x128 (s));
__m128i da = expand_alpha_1x128 (d);
 
return pack_1x128_32 (pix_add_multiply_1x128 (&s, &da, &d, &sa));
}
 
static void
sse2_combine_atop_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, d;
 
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
__m128i xmm_alpha_src_lo, xmm_alpha_src_hi;
__m128i xmm_alpha_dst_lo, xmm_alpha_dst_hi;
 
while (w && ((uintptr_t)pd & 15))
{
s = combine1 (ps, pm);
d = *pd;
 
*pd++ = core_combine_atop_u_pixel_sse2 (s, d);
w--;
ps++;
if (pm)
pm++;
}
 
while (w >= 4)
{
xmm_src_hi = combine4 ((__m128i*)ps, (__m128i*)pm);
xmm_dst_hi = load_128_aligned ((__m128i*) pd);
 
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
 
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_alpha_src_lo, &xmm_alpha_src_hi);
expand_alpha_2x128 (xmm_dst_lo, xmm_dst_hi,
&xmm_alpha_dst_lo, &xmm_alpha_dst_hi);
 
negate_2x128 (xmm_alpha_src_lo, xmm_alpha_src_hi,
&xmm_alpha_src_lo, &xmm_alpha_src_hi);
 
pix_add_multiply_2x128 (
&xmm_src_lo, &xmm_src_hi, &xmm_alpha_dst_lo, &xmm_alpha_dst_hi,
&xmm_dst_lo, &xmm_dst_hi, &xmm_alpha_src_lo, &xmm_alpha_src_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
ps += 4;
pd += 4;
w -= 4;
if (pm)
pm += 4;
}
 
while (w)
{
s = combine1 (ps, pm);
d = *pd;
 
*pd++ = core_combine_atop_u_pixel_sse2 (s, d);
w--;
ps++;
if (pm)
pm++;
}
}
 
static force_inline uint32_t
core_combine_reverse_atop_u_pixel_sse2 (uint32_t src,
uint32_t dst)
{
__m128i s = unpack_32_1x128 (src);
__m128i d = unpack_32_1x128 (dst);
 
__m128i sa = expand_alpha_1x128 (s);
__m128i da = negate_1x128 (expand_alpha_1x128 (d));
 
return pack_1x128_32 (pix_add_multiply_1x128 (&s, &da, &d, &sa));
}
 
static void
sse2_combine_atop_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, d;
 
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
__m128i xmm_alpha_src_lo, xmm_alpha_src_hi;
__m128i xmm_alpha_dst_lo, xmm_alpha_dst_hi;
 
while (w && ((uintptr_t)pd & 15))
{
s = combine1 (ps, pm);
d = *pd;
 
*pd++ = core_combine_reverse_atop_u_pixel_sse2 (s, d);
ps++;
w--;
if (pm)
pm++;
}
 
while (w >= 4)
{
xmm_src_hi = combine4 ((__m128i*)ps, (__m128i*)pm);
xmm_dst_hi = load_128_aligned ((__m128i*) pd);
 
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
 
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_alpha_src_lo, &xmm_alpha_src_hi);
expand_alpha_2x128 (xmm_dst_lo, xmm_dst_hi,
&xmm_alpha_dst_lo, &xmm_alpha_dst_hi);
 
negate_2x128 (xmm_alpha_dst_lo, xmm_alpha_dst_hi,
&xmm_alpha_dst_lo, &xmm_alpha_dst_hi);
 
pix_add_multiply_2x128 (
&xmm_src_lo, &xmm_src_hi, &xmm_alpha_dst_lo, &xmm_alpha_dst_hi,
&xmm_dst_lo, &xmm_dst_hi, &xmm_alpha_src_lo, &xmm_alpha_src_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
ps += 4;
pd += 4;
w -= 4;
if (pm)
pm += 4;
}
 
while (w)
{
s = combine1 (ps, pm);
d = *pd;
 
*pd++ = core_combine_reverse_atop_u_pixel_sse2 (s, d);
ps++;
w--;
if (pm)
pm++;
}
}
 
static force_inline uint32_t
core_combine_xor_u_pixel_sse2 (uint32_t src,
uint32_t dst)
{
__m128i s = unpack_32_1x128 (src);
__m128i d = unpack_32_1x128 (dst);
 
__m128i neg_d = negate_1x128 (expand_alpha_1x128 (d));
__m128i neg_s = negate_1x128 (expand_alpha_1x128 (s));
 
return pack_1x128_32 (pix_add_multiply_1x128 (&s, &neg_d, &d, &neg_s));
}
 
static void
sse2_combine_xor_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dst,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int w = width;
uint32_t s, d;
uint32_t* pd = dst;
const uint32_t* ps = src;
const uint32_t* pm = mask;
 
__m128i xmm_src, xmm_src_lo, xmm_src_hi;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
__m128i xmm_alpha_src_lo, xmm_alpha_src_hi;
__m128i xmm_alpha_dst_lo, xmm_alpha_dst_hi;
 
while (w && ((uintptr_t)pd & 15))
{
s = combine1 (ps, pm);
d = *pd;
 
*pd++ = core_combine_xor_u_pixel_sse2 (s, d);
w--;
ps++;
if (pm)
pm++;
}
 
while (w >= 4)
{
xmm_src = combine4 ((__m128i*) ps, (__m128i*) pm);
xmm_dst = load_128_aligned ((__m128i*) pd);
 
unpack_128_2x128 (xmm_src, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
 
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_alpha_src_lo, &xmm_alpha_src_hi);
expand_alpha_2x128 (xmm_dst_lo, xmm_dst_hi,
&xmm_alpha_dst_lo, &xmm_alpha_dst_hi);
 
negate_2x128 (xmm_alpha_src_lo, xmm_alpha_src_hi,
&xmm_alpha_src_lo, &xmm_alpha_src_hi);
negate_2x128 (xmm_alpha_dst_lo, xmm_alpha_dst_hi,
&xmm_alpha_dst_lo, &xmm_alpha_dst_hi);
 
pix_add_multiply_2x128 (
&xmm_src_lo, &xmm_src_hi, &xmm_alpha_dst_lo, &xmm_alpha_dst_hi,
&xmm_dst_lo, &xmm_dst_hi, &xmm_alpha_src_lo, &xmm_alpha_src_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
ps += 4;
pd += 4;
w -= 4;
if (pm)
pm += 4;
}
 
while (w)
{
s = combine1 (ps, pm);
d = *pd;
 
*pd++ = core_combine_xor_u_pixel_sse2 (s, d);
w--;
ps++;
if (pm)
pm++;
}
}
 
static force_inline void
sse2_combine_add_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dst,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int w = width;
uint32_t s, d;
uint32_t* pd = dst;
const uint32_t* ps = src;
const uint32_t* pm = mask;
 
while (w && (uintptr_t)pd & 15)
{
s = combine1 (ps, pm);
d = *pd;
 
ps++;
if (pm)
pm++;
*pd++ = _mm_cvtsi128_si32 (
_mm_adds_epu8 (_mm_cvtsi32_si128 (s), _mm_cvtsi32_si128 (d)));
w--;
}
 
while (w >= 4)
{
__m128i s;
 
s = combine4 ((__m128i*)ps, (__m128i*)pm);
 
save_128_aligned (
(__m128i*)pd, _mm_adds_epu8 (s, load_128_aligned ((__m128i*)pd)));
 
pd += 4;
ps += 4;
if (pm)
pm += 4;
w -= 4;
}
 
while (w--)
{
s = combine1 (ps, pm);
d = *pd;
 
ps++;
*pd++ = _mm_cvtsi128_si32 (
_mm_adds_epu8 (_mm_cvtsi32_si128 (s), _mm_cvtsi32_si128 (d)));
if (pm)
pm++;
}
}
 
static force_inline uint32_t
core_combine_saturate_u_pixel_sse2 (uint32_t src,
uint32_t dst)
{
__m128i ms = unpack_32_1x128 (src);
__m128i md = unpack_32_1x128 (dst);
uint32_t sa = src >> 24;
uint32_t da = ~dst >> 24;
 
if (sa > da)
{
ms = pix_multiply_1x128 (
ms, expand_alpha_1x128 (unpack_32_1x128 (DIV_UN8 (da, sa) << 24)));
}
 
return pack_1x128_32 (_mm_adds_epu16 (md, ms));
}
 
static void
sse2_combine_saturate_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, d;
 
uint32_t pack_cmp;
__m128i xmm_src, xmm_dst;
 
while (w && (uintptr_t)pd & 15)
{
s = combine1 (ps, pm);
d = *pd;
 
*pd++ = core_combine_saturate_u_pixel_sse2 (s, d);
w--;
ps++;
if (pm)
pm++;
}
 
while (w >= 4)
{
xmm_dst = load_128_aligned ((__m128i*)pd);
xmm_src = combine4 ((__m128i*)ps, (__m128i*)pm);
 
pack_cmp = _mm_movemask_epi8 (
_mm_cmpgt_epi32 (
_mm_srli_epi32 (xmm_src, 24),
_mm_srli_epi32 (_mm_xor_si128 (xmm_dst, mask_ff000000), 24)));
 
/* if some alpha src is grater than respective ~alpha dst */
if (pack_cmp)
{
s = combine1 (ps++, pm);
d = *pd;
*pd++ = core_combine_saturate_u_pixel_sse2 (s, d);
if (pm)
pm++;
 
s = combine1 (ps++, pm);
d = *pd;
*pd++ = core_combine_saturate_u_pixel_sse2 (s, d);
if (pm)
pm++;
 
s = combine1 (ps++, pm);
d = *pd;
*pd++ = core_combine_saturate_u_pixel_sse2 (s, d);
if (pm)
pm++;
 
s = combine1 (ps++, pm);
d = *pd;
*pd++ = core_combine_saturate_u_pixel_sse2 (s, d);
if (pm)
pm++;
}
else
{
save_128_aligned ((__m128i*)pd, _mm_adds_epu8 (xmm_dst, xmm_src));
 
pd += 4;
ps += 4;
if (pm)
pm += 4;
}
 
w -= 4;
}
 
while (w--)
{
s = combine1 (ps, pm);
d = *pd;
 
*pd++ = core_combine_saturate_u_pixel_sse2 (s, d);
ps++;
if (pm)
pm++;
}
}
 
static void
sse2_combine_src_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, m;
 
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_mask_lo, xmm_mask_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
 
while (w && (uintptr_t)pd & 15)
{
s = *ps++;
m = *pm++;
*pd++ = pack_1x128_32 (
pix_multiply_1x128 (unpack_32_1x128 (s), unpack_32_1x128 (m)));
w--;
}
 
while (w >= 4)
{
xmm_src_hi = load_128_unaligned ((__m128i*)ps);
xmm_mask_hi = load_128_unaligned ((__m128i*)pm);
 
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_mask_hi, &xmm_mask_lo, &xmm_mask_hi);
 
pix_multiply_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
ps += 4;
pd += 4;
pm += 4;
w -= 4;
}
 
while (w)
{
s = *ps++;
m = *pm++;
*pd++ = pack_1x128_32 (
pix_multiply_1x128 (unpack_32_1x128 (s), unpack_32_1x128 (m)));
w--;
}
}
 
static force_inline uint32_t
core_combine_over_ca_pixel_sse2 (uint32_t src,
uint32_t mask,
uint32_t dst)
{
__m128i s = unpack_32_1x128 (src);
__m128i expAlpha = expand_alpha_1x128 (s);
__m128i unpk_mask = unpack_32_1x128 (mask);
__m128i unpk_dst = unpack_32_1x128 (dst);
 
return pack_1x128_32 (in_over_1x128 (&s, &expAlpha, &unpk_mask, &unpk_dst));
}
 
static void
sse2_combine_over_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, m, d;
 
__m128i xmm_alpha_lo, xmm_alpha_hi;
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
__m128i xmm_mask_lo, xmm_mask_hi;
 
while (w && (uintptr_t)pd & 15)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = core_combine_over_ca_pixel_sse2 (s, m, d);
w--;
}
 
while (w >= 4)
{
xmm_dst_hi = load_128_aligned ((__m128i*)pd);
xmm_src_hi = load_128_unaligned ((__m128i*)ps);
xmm_mask_hi = load_128_unaligned ((__m128i*)pm);
 
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_mask_hi, &xmm_mask_lo, &xmm_mask_hi);
 
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_alpha_lo, &xmm_alpha_hi);
 
in_over_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_alpha_lo, &xmm_alpha_hi,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
ps += 4;
pd += 4;
pm += 4;
w -= 4;
}
 
while (w)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = core_combine_over_ca_pixel_sse2 (s, m, d);
w--;
}
}
 
static force_inline uint32_t
core_combine_over_reverse_ca_pixel_sse2 (uint32_t src,
uint32_t mask,
uint32_t dst)
{
__m128i d = unpack_32_1x128 (dst);
 
return pack_1x128_32 (
over_1x128 (d, expand_alpha_1x128 (d),
pix_multiply_1x128 (unpack_32_1x128 (src),
unpack_32_1x128 (mask))));
}
 
static void
sse2_combine_over_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, m, d;
 
__m128i xmm_alpha_lo, xmm_alpha_hi;
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
__m128i xmm_mask_lo, xmm_mask_hi;
 
while (w && (uintptr_t)pd & 15)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = core_combine_over_reverse_ca_pixel_sse2 (s, m, d);
w--;
}
 
while (w >= 4)
{
xmm_dst_hi = load_128_aligned ((__m128i*)pd);
xmm_src_hi = load_128_unaligned ((__m128i*)ps);
xmm_mask_hi = load_128_unaligned ((__m128i*)pm);
 
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_mask_hi, &xmm_mask_lo, &xmm_mask_hi);
 
expand_alpha_2x128 (xmm_dst_lo, xmm_dst_hi,
&xmm_alpha_lo, &xmm_alpha_hi);
pix_multiply_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_mask_lo, &xmm_mask_hi);
 
over_2x128 (&xmm_dst_lo, &xmm_dst_hi,
&xmm_alpha_lo, &xmm_alpha_hi,
&xmm_mask_lo, &xmm_mask_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_mask_lo, xmm_mask_hi));
 
ps += 4;
pd += 4;
pm += 4;
w -= 4;
}
 
while (w)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = core_combine_over_reverse_ca_pixel_sse2 (s, m, d);
w--;
}
}
 
static void
sse2_combine_in_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, m, d;
 
__m128i xmm_alpha_lo, xmm_alpha_hi;
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
__m128i xmm_mask_lo, xmm_mask_hi;
 
while (w && (uintptr_t)pd & 15)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = pack_1x128_32 (
pix_multiply_1x128 (
pix_multiply_1x128 (unpack_32_1x128 (s), unpack_32_1x128 (m)),
expand_alpha_1x128 (unpack_32_1x128 (d))));
 
w--;
}
 
while (w >= 4)
{
xmm_dst_hi = load_128_aligned ((__m128i*)pd);
xmm_src_hi = load_128_unaligned ((__m128i*)ps);
xmm_mask_hi = load_128_unaligned ((__m128i*)pm);
 
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_mask_hi, &xmm_mask_lo, &xmm_mask_hi);
 
expand_alpha_2x128 (xmm_dst_lo, xmm_dst_hi,
&xmm_alpha_lo, &xmm_alpha_hi);
 
pix_multiply_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
pix_multiply_2x128 (&xmm_dst_lo, &xmm_dst_hi,
&xmm_alpha_lo, &xmm_alpha_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
ps += 4;
pd += 4;
pm += 4;
w -= 4;
}
 
while (w)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = pack_1x128_32 (
pix_multiply_1x128 (
pix_multiply_1x128 (
unpack_32_1x128 (s), unpack_32_1x128 (m)),
expand_alpha_1x128 (unpack_32_1x128 (d))));
 
w--;
}
}
 
static void
sse2_combine_in_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, m, d;
 
__m128i xmm_alpha_lo, xmm_alpha_hi;
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
__m128i xmm_mask_lo, xmm_mask_hi;
 
while (w && (uintptr_t)pd & 15)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = pack_1x128_32 (
pix_multiply_1x128 (
unpack_32_1x128 (d),
pix_multiply_1x128 (unpack_32_1x128 (m),
expand_alpha_1x128 (unpack_32_1x128 (s)))));
w--;
}
 
while (w >= 4)
{
xmm_dst_hi = load_128_aligned ((__m128i*)pd);
xmm_src_hi = load_128_unaligned ((__m128i*)ps);
xmm_mask_hi = load_128_unaligned ((__m128i*)pm);
 
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_mask_hi, &xmm_mask_lo, &xmm_mask_hi);
 
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_alpha_lo, &xmm_alpha_hi);
pix_multiply_2x128 (&xmm_mask_lo, &xmm_mask_hi,
&xmm_alpha_lo, &xmm_alpha_hi,
&xmm_alpha_lo, &xmm_alpha_hi);
 
pix_multiply_2x128 (&xmm_dst_lo, &xmm_dst_hi,
&xmm_alpha_lo, &xmm_alpha_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
ps += 4;
pd += 4;
pm += 4;
w -= 4;
}
 
while (w)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = pack_1x128_32 (
pix_multiply_1x128 (
unpack_32_1x128 (d),
pix_multiply_1x128 (unpack_32_1x128 (m),
expand_alpha_1x128 (unpack_32_1x128 (s)))));
w--;
}
}
 
static void
sse2_combine_out_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, m, d;
 
__m128i xmm_alpha_lo, xmm_alpha_hi;
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
__m128i xmm_mask_lo, xmm_mask_hi;
 
while (w && (uintptr_t)pd & 15)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = pack_1x128_32 (
pix_multiply_1x128 (
pix_multiply_1x128 (
unpack_32_1x128 (s), unpack_32_1x128 (m)),
negate_1x128 (expand_alpha_1x128 (unpack_32_1x128 (d)))));
w--;
}
 
while (w >= 4)
{
xmm_dst_hi = load_128_aligned ((__m128i*)pd);
xmm_src_hi = load_128_unaligned ((__m128i*)ps);
xmm_mask_hi = load_128_unaligned ((__m128i*)pm);
 
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_mask_hi, &xmm_mask_lo, &xmm_mask_hi);
 
expand_alpha_2x128 (xmm_dst_lo, xmm_dst_hi,
&xmm_alpha_lo, &xmm_alpha_hi);
negate_2x128 (xmm_alpha_lo, xmm_alpha_hi,
&xmm_alpha_lo, &xmm_alpha_hi);
 
pix_multiply_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_dst_lo, &xmm_dst_hi);
pix_multiply_2x128 (&xmm_dst_lo, &xmm_dst_hi,
&xmm_alpha_lo, &xmm_alpha_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
ps += 4;
pd += 4;
pm += 4;
w -= 4;
}
 
while (w)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = pack_1x128_32 (
pix_multiply_1x128 (
pix_multiply_1x128 (
unpack_32_1x128 (s), unpack_32_1x128 (m)),
negate_1x128 (expand_alpha_1x128 (unpack_32_1x128 (d)))));
 
w--;
}
}
 
static void
sse2_combine_out_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, m, d;
 
__m128i xmm_alpha_lo, xmm_alpha_hi;
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
__m128i xmm_mask_lo, xmm_mask_hi;
 
while (w && (uintptr_t)pd & 15)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = pack_1x128_32 (
pix_multiply_1x128 (
unpack_32_1x128 (d),
negate_1x128 (pix_multiply_1x128 (
unpack_32_1x128 (m),
expand_alpha_1x128 (unpack_32_1x128 (s))))));
w--;
}
 
while (w >= 4)
{
xmm_dst_hi = load_128_aligned ((__m128i*)pd);
xmm_src_hi = load_128_unaligned ((__m128i*)ps);
xmm_mask_hi = load_128_unaligned ((__m128i*)pm);
 
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_mask_hi, &xmm_mask_lo, &xmm_mask_hi);
 
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_alpha_lo, &xmm_alpha_hi);
 
pix_multiply_2x128 (&xmm_mask_lo, &xmm_mask_hi,
&xmm_alpha_lo, &xmm_alpha_hi,
&xmm_mask_lo, &xmm_mask_hi);
 
negate_2x128 (xmm_mask_lo, xmm_mask_hi,
&xmm_mask_lo, &xmm_mask_hi);
 
pix_multiply_2x128 (&xmm_dst_lo, &xmm_dst_hi,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
ps += 4;
pd += 4;
pm += 4;
w -= 4;
}
 
while (w)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = pack_1x128_32 (
pix_multiply_1x128 (
unpack_32_1x128 (d),
negate_1x128 (pix_multiply_1x128 (
unpack_32_1x128 (m),
expand_alpha_1x128 (unpack_32_1x128 (s))))));
w--;
}
}
 
static force_inline uint32_t
core_combine_atop_ca_pixel_sse2 (uint32_t src,
uint32_t mask,
uint32_t dst)
{
__m128i m = unpack_32_1x128 (mask);
__m128i s = unpack_32_1x128 (src);
__m128i d = unpack_32_1x128 (dst);
__m128i sa = expand_alpha_1x128 (s);
__m128i da = expand_alpha_1x128 (d);
 
s = pix_multiply_1x128 (s, m);
m = negate_1x128 (pix_multiply_1x128 (m, sa));
 
return pack_1x128_32 (pix_add_multiply_1x128 (&d, &m, &s, &da));
}
 
static void
sse2_combine_atop_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, m, d;
 
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
__m128i xmm_alpha_src_lo, xmm_alpha_src_hi;
__m128i xmm_alpha_dst_lo, xmm_alpha_dst_hi;
__m128i xmm_mask_lo, xmm_mask_hi;
 
while (w && (uintptr_t)pd & 15)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = core_combine_atop_ca_pixel_sse2 (s, m, d);
w--;
}
 
while (w >= 4)
{
xmm_dst_hi = load_128_aligned ((__m128i*)pd);
xmm_src_hi = load_128_unaligned ((__m128i*)ps);
xmm_mask_hi = load_128_unaligned ((__m128i*)pm);
 
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_mask_hi, &xmm_mask_lo, &xmm_mask_hi);
 
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_alpha_src_lo, &xmm_alpha_src_hi);
expand_alpha_2x128 (xmm_dst_lo, xmm_dst_hi,
&xmm_alpha_dst_lo, &xmm_alpha_dst_hi);
 
pix_multiply_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_src_lo, &xmm_src_hi);
pix_multiply_2x128 (&xmm_mask_lo, &xmm_mask_hi,
&xmm_alpha_src_lo, &xmm_alpha_src_hi,
&xmm_mask_lo, &xmm_mask_hi);
 
negate_2x128 (xmm_mask_lo, xmm_mask_hi, &xmm_mask_lo, &xmm_mask_hi);
 
pix_add_multiply_2x128 (
&xmm_dst_lo, &xmm_dst_hi, &xmm_mask_lo, &xmm_mask_hi,
&xmm_src_lo, &xmm_src_hi, &xmm_alpha_dst_lo, &xmm_alpha_dst_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
ps += 4;
pd += 4;
pm += 4;
w -= 4;
}
 
while (w)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = core_combine_atop_ca_pixel_sse2 (s, m, d);
w--;
}
}
 
static force_inline uint32_t
core_combine_reverse_atop_ca_pixel_sse2 (uint32_t src,
uint32_t mask,
uint32_t dst)
{
__m128i m = unpack_32_1x128 (mask);
__m128i s = unpack_32_1x128 (src);
__m128i d = unpack_32_1x128 (dst);
 
__m128i da = negate_1x128 (expand_alpha_1x128 (d));
__m128i sa = expand_alpha_1x128 (s);
 
s = pix_multiply_1x128 (s, m);
m = pix_multiply_1x128 (m, sa);
 
return pack_1x128_32 (pix_add_multiply_1x128 (&d, &m, &s, &da));
}
 
static void
sse2_combine_atop_reverse_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, m, d;
 
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
__m128i xmm_alpha_src_lo, xmm_alpha_src_hi;
__m128i xmm_alpha_dst_lo, xmm_alpha_dst_hi;
__m128i xmm_mask_lo, xmm_mask_hi;
 
while (w && (uintptr_t)pd & 15)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = core_combine_reverse_atop_ca_pixel_sse2 (s, m, d);
w--;
}
 
while (w >= 4)
{
xmm_dst_hi = load_128_aligned ((__m128i*)pd);
xmm_src_hi = load_128_unaligned ((__m128i*)ps);
xmm_mask_hi = load_128_unaligned ((__m128i*)pm);
 
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_mask_hi, &xmm_mask_lo, &xmm_mask_hi);
 
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_alpha_src_lo, &xmm_alpha_src_hi);
expand_alpha_2x128 (xmm_dst_lo, xmm_dst_hi,
&xmm_alpha_dst_lo, &xmm_alpha_dst_hi);
 
pix_multiply_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_src_lo, &xmm_src_hi);
pix_multiply_2x128 (&xmm_mask_lo, &xmm_mask_hi,
&xmm_alpha_src_lo, &xmm_alpha_src_hi,
&xmm_mask_lo, &xmm_mask_hi);
 
negate_2x128 (xmm_alpha_dst_lo, xmm_alpha_dst_hi,
&xmm_alpha_dst_lo, &xmm_alpha_dst_hi);
 
pix_add_multiply_2x128 (
&xmm_dst_lo, &xmm_dst_hi, &xmm_mask_lo, &xmm_mask_hi,
&xmm_src_lo, &xmm_src_hi, &xmm_alpha_dst_lo, &xmm_alpha_dst_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
ps += 4;
pd += 4;
pm += 4;
w -= 4;
}
 
while (w)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = core_combine_reverse_atop_ca_pixel_sse2 (s, m, d);
w--;
}
}
 
static force_inline uint32_t
core_combine_xor_ca_pixel_sse2 (uint32_t src,
uint32_t mask,
uint32_t dst)
{
__m128i a = unpack_32_1x128 (mask);
__m128i s = unpack_32_1x128 (src);
__m128i d = unpack_32_1x128 (dst);
 
__m128i alpha_dst = negate_1x128 (pix_multiply_1x128 (
a, expand_alpha_1x128 (s)));
__m128i dest = pix_multiply_1x128 (s, a);
__m128i alpha_src = negate_1x128 (expand_alpha_1x128 (d));
 
return pack_1x128_32 (pix_add_multiply_1x128 (&d,
&alpha_dst,
&dest,
&alpha_src));
}
 
static void
sse2_combine_xor_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, m, d;
 
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
__m128i xmm_alpha_src_lo, xmm_alpha_src_hi;
__m128i xmm_alpha_dst_lo, xmm_alpha_dst_hi;
__m128i xmm_mask_lo, xmm_mask_hi;
 
while (w && (uintptr_t)pd & 15)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = core_combine_xor_ca_pixel_sse2 (s, m, d);
w--;
}
 
while (w >= 4)
{
xmm_dst_hi = load_128_aligned ((__m128i*)pd);
xmm_src_hi = load_128_unaligned ((__m128i*)ps);
xmm_mask_hi = load_128_unaligned ((__m128i*)pm);
 
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_mask_hi, &xmm_mask_lo, &xmm_mask_hi);
 
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_alpha_src_lo, &xmm_alpha_src_hi);
expand_alpha_2x128 (xmm_dst_lo, xmm_dst_hi,
&xmm_alpha_dst_lo, &xmm_alpha_dst_hi);
 
pix_multiply_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_src_lo, &xmm_src_hi);
pix_multiply_2x128 (&xmm_mask_lo, &xmm_mask_hi,
&xmm_alpha_src_lo, &xmm_alpha_src_hi,
&xmm_mask_lo, &xmm_mask_hi);
 
negate_2x128 (xmm_alpha_dst_lo, xmm_alpha_dst_hi,
&xmm_alpha_dst_lo, &xmm_alpha_dst_hi);
negate_2x128 (xmm_mask_lo, xmm_mask_hi,
&xmm_mask_lo, &xmm_mask_hi);
 
pix_add_multiply_2x128 (
&xmm_dst_lo, &xmm_dst_hi, &xmm_mask_lo, &xmm_mask_hi,
&xmm_src_lo, &xmm_src_hi, &xmm_alpha_dst_lo, &xmm_alpha_dst_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
ps += 4;
pd += 4;
pm += 4;
w -= 4;
}
 
while (w)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = core_combine_xor_ca_pixel_sse2 (s, m, d);
w--;
}
}
 
static void
sse2_combine_add_ca (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
uint32_t s, m, d;
 
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
__m128i xmm_mask_lo, xmm_mask_hi;
 
while (w && (uintptr_t)pd & 15)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = pack_1x128_32 (
_mm_adds_epu8 (pix_multiply_1x128 (unpack_32_1x128 (s),
unpack_32_1x128 (m)),
unpack_32_1x128 (d)));
w--;
}
 
while (w >= 4)
{
xmm_src_hi = load_128_unaligned ((__m128i*)ps);
xmm_mask_hi = load_128_unaligned ((__m128i*)pm);
xmm_dst_hi = load_128_aligned ((__m128i*)pd);
 
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_mask_hi, &xmm_mask_lo, &xmm_mask_hi);
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
 
pix_multiply_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_src_lo, &xmm_src_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (
_mm_adds_epu8 (xmm_src_lo, xmm_dst_lo),
_mm_adds_epu8 (xmm_src_hi, xmm_dst_hi)));
 
ps += 4;
pd += 4;
pm += 4;
w -= 4;
}
 
while (w)
{
s = *ps++;
m = *pm++;
d = *pd;
 
*pd++ = pack_1x128_32 (
_mm_adds_epu8 (pix_multiply_1x128 (unpack_32_1x128 (s),
unpack_32_1x128 (m)),
unpack_32_1x128 (d)));
w--;
}
}
 
static force_inline __m128i
create_mask_16_128 (uint16_t mask)
{
return _mm_set1_epi16 (mask);
}
 
/* Work around a code generation bug in Sun Studio 12. */
#if defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
# define create_mask_2x32_128(mask0, mask1) \
(_mm_set_epi32 ((mask0), (mask1), (mask0), (mask1)))
#else
static force_inline __m128i
create_mask_2x32_128 (uint32_t mask0,
uint32_t mask1)
{
return _mm_set_epi32 (mask0, mask1, mask0, mask1);
}
#endif
 
static void
sse2_composite_over_n_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src;
uint32_t *dst_line, *dst, d;
int32_t w;
int dst_stride;
__m128i xmm_src, xmm_alpha;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
 
xmm_src = expand_pixel_32_1x128 (src);
xmm_alpha = expand_alpha_1x128 (xmm_src);
 
while (height--)
{
dst = dst_line;
 
dst_line += dst_stride;
w = width;
 
while (w && (uintptr_t)dst & 15)
{
d = *dst;
*dst++ = pack_1x128_32 (over_1x128 (xmm_src,
xmm_alpha,
unpack_32_1x128 (d)));
w--;
}
 
while (w >= 4)
{
xmm_dst = load_128_aligned ((__m128i*)dst);
 
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
 
over_2x128 (&xmm_src, &xmm_src,
&xmm_alpha, &xmm_alpha,
&xmm_dst_lo, &xmm_dst_hi);
 
/* rebuid the 4 pixel data and save*/
save_128_aligned (
(__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
w -= 4;
dst += 4;
}
 
while (w)
{
d = *dst;
*dst++ = pack_1x128_32 (over_1x128 (xmm_src,
xmm_alpha,
unpack_32_1x128 (d)));
w--;
}
 
}
}
 
static void
sse2_composite_over_n_0565 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src;
uint16_t *dst_line, *dst, d;
int32_t w;
int dst_stride;
__m128i xmm_src, xmm_alpha;
__m128i xmm_dst, xmm_dst0, xmm_dst1, xmm_dst2, xmm_dst3;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
 
xmm_src = expand_pixel_32_1x128 (src);
xmm_alpha = expand_alpha_1x128 (xmm_src);
 
while (height--)
{
dst = dst_line;
 
dst_line += dst_stride;
w = width;
 
while (w && (uintptr_t)dst & 15)
{
d = *dst;
 
*dst++ = pack_565_32_16 (
pack_1x128_32 (over_1x128 (xmm_src,
xmm_alpha,
expand565_16_1x128 (d))));
w--;
}
 
while (w >= 8)
{
xmm_dst = load_128_aligned ((__m128i*)dst);
 
unpack_565_128_4x128 (xmm_dst,
&xmm_dst0, &xmm_dst1, &xmm_dst2, &xmm_dst3);
 
over_2x128 (&xmm_src, &xmm_src,
&xmm_alpha, &xmm_alpha,
&xmm_dst0, &xmm_dst1);
over_2x128 (&xmm_src, &xmm_src,
&xmm_alpha, &xmm_alpha,
&xmm_dst2, &xmm_dst3);
 
xmm_dst = pack_565_4x128_128 (
&xmm_dst0, &xmm_dst1, &xmm_dst2, &xmm_dst3);
 
save_128_aligned ((__m128i*)dst, xmm_dst);
 
dst += 8;
w -= 8;
}
 
while (w--)
{
d = *dst;
*dst++ = pack_565_32_16 (
pack_1x128_32 (over_1x128 (xmm_src, xmm_alpha,
expand565_16_1x128 (d))));
}
}
 
}
 
static void
sse2_composite_add_n_8888_8888_ca (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src;
uint32_t *dst_line, d;
uint32_t *mask_line, m;
uint32_t pack_cmp;
int dst_stride, mask_stride;
 
__m128i xmm_src;
__m128i xmm_dst;
__m128i xmm_mask, xmm_mask_lo, xmm_mask_hi;
 
__m128i mmx_src, mmx_mask, mmx_dest;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
mask_image, mask_x, mask_y, uint32_t, mask_stride, mask_line, 1);
 
xmm_src = _mm_unpacklo_epi8 (
create_mask_2x32_128 (src, src), _mm_setzero_si128 ());
mmx_src = xmm_src;
 
while (height--)
{
int w = width;
const uint32_t *pm = (uint32_t *)mask_line;
uint32_t *pd = (uint32_t *)dst_line;
 
dst_line += dst_stride;
mask_line += mask_stride;
 
while (w && (uintptr_t)pd & 15)
{
m = *pm++;
 
if (m)
{
d = *pd;
 
mmx_mask = unpack_32_1x128 (m);
mmx_dest = unpack_32_1x128 (d);
 
*pd = pack_1x128_32 (
_mm_adds_epu8 (pix_multiply_1x128 (mmx_mask, mmx_src),
mmx_dest));
}
 
pd++;
w--;
}
 
while (w >= 4)
{
xmm_mask = load_128_unaligned ((__m128i*)pm);
 
pack_cmp =
_mm_movemask_epi8 (
_mm_cmpeq_epi32 (xmm_mask, _mm_setzero_si128 ()));
 
/* if all bits in mask are zero, pack_cmp are equal to 0xffff */
if (pack_cmp != 0xffff)
{
xmm_dst = load_128_aligned ((__m128i*)pd);
 
unpack_128_2x128 (xmm_mask, &xmm_mask_lo, &xmm_mask_hi);
 
pix_multiply_2x128 (&xmm_src, &xmm_src,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_mask_lo, &xmm_mask_hi);
xmm_mask_hi = pack_2x128_128 (xmm_mask_lo, xmm_mask_hi);
 
save_128_aligned (
(__m128i*)pd, _mm_adds_epu8 (xmm_mask_hi, xmm_dst));
}
 
pd += 4;
pm += 4;
w -= 4;
}
 
while (w)
{
m = *pm++;
 
if (m)
{
d = *pd;
 
mmx_mask = unpack_32_1x128 (m);
mmx_dest = unpack_32_1x128 (d);
 
*pd = pack_1x128_32 (
_mm_adds_epu8 (pix_multiply_1x128 (mmx_mask, mmx_src),
mmx_dest));
}
 
pd++;
w--;
}
}
 
}
 
static void
sse2_composite_over_n_8888_8888_ca (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src;
uint32_t *dst_line, d;
uint32_t *mask_line, m;
uint32_t pack_cmp;
int dst_stride, mask_stride;
 
__m128i xmm_src, xmm_alpha;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
__m128i xmm_mask, xmm_mask_lo, xmm_mask_hi;
 
__m128i mmx_src, mmx_alpha, mmx_mask, mmx_dest;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
mask_image, mask_x, mask_y, uint32_t, mask_stride, mask_line, 1);
 
xmm_src = _mm_unpacklo_epi8 (
create_mask_2x32_128 (src, src), _mm_setzero_si128 ());
xmm_alpha = expand_alpha_1x128 (xmm_src);
mmx_src = xmm_src;
mmx_alpha = xmm_alpha;
 
while (height--)
{
int w = width;
const uint32_t *pm = (uint32_t *)mask_line;
uint32_t *pd = (uint32_t *)dst_line;
 
dst_line += dst_stride;
mask_line += mask_stride;
 
while (w && (uintptr_t)pd & 15)
{
m = *pm++;
 
if (m)
{
d = *pd;
mmx_mask = unpack_32_1x128 (m);
mmx_dest = unpack_32_1x128 (d);
 
*pd = pack_1x128_32 (in_over_1x128 (&mmx_src,
&mmx_alpha,
&mmx_mask,
&mmx_dest));
}
 
pd++;
w--;
}
 
while (w >= 4)
{
xmm_mask = load_128_unaligned ((__m128i*)pm);
 
pack_cmp =
_mm_movemask_epi8 (
_mm_cmpeq_epi32 (xmm_mask, _mm_setzero_si128 ()));
 
/* if all bits in mask are zero, pack_cmp are equal to 0xffff */
if (pack_cmp != 0xffff)
{
xmm_dst = load_128_aligned ((__m128i*)pd);
 
unpack_128_2x128 (xmm_mask, &xmm_mask_lo, &xmm_mask_hi);
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
 
in_over_2x128 (&xmm_src, &xmm_src,
&xmm_alpha, &xmm_alpha,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)pd, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
}
 
pd += 4;
pm += 4;
w -= 4;
}
 
while (w)
{
m = *pm++;
 
if (m)
{
d = *pd;
mmx_mask = unpack_32_1x128 (m);
mmx_dest = unpack_32_1x128 (d);
 
*pd = pack_1x128_32 (
in_over_1x128 (&mmx_src, &mmx_alpha, &mmx_mask, &mmx_dest));
}
 
pd++;
w--;
}
}
 
}
 
static void
sse2_composite_over_8888_n_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line, *dst;
uint32_t *src_line, *src;
uint32_t mask;
int32_t w;
int dst_stride, src_stride;
 
__m128i xmm_mask;
__m128i xmm_src, xmm_src_lo, xmm_src_hi;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
__m128i xmm_alpha_lo, xmm_alpha_hi;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
mask = _pixman_image_get_solid (imp, mask_image, PIXMAN_a8r8g8b8);
 
xmm_mask = create_mask_16_128 (mask >> 24);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w && (uintptr_t)dst & 15)
{
uint32_t s = *src++;
 
if (s)
{
uint32_t d = *dst;
__m128i ms = unpack_32_1x128 (s);
__m128i alpha = expand_alpha_1x128 (ms);
__m128i dest = xmm_mask;
__m128i alpha_dst = unpack_32_1x128 (d);
*dst = pack_1x128_32 (
in_over_1x128 (&ms, &alpha, &dest, &alpha_dst));
}
dst++;
w--;
}
 
while (w >= 4)
{
xmm_src = load_128_unaligned ((__m128i*)src);
 
if (!is_zero (xmm_src))
{
xmm_dst = load_128_aligned ((__m128i*)dst);
unpack_128_2x128 (xmm_src, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_alpha_lo, &xmm_alpha_hi);
in_over_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_alpha_lo, &xmm_alpha_hi,
&xmm_mask, &xmm_mask,
&xmm_dst_lo, &xmm_dst_hi);
save_128_aligned (
(__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
}
dst += 4;
src += 4;
w -= 4;
}
 
while (w)
{
uint32_t s = *src++;
 
if (s)
{
uint32_t d = *dst;
__m128i ms = unpack_32_1x128 (s);
__m128i alpha = expand_alpha_1x128 (ms);
__m128i mask = xmm_mask;
__m128i dest = unpack_32_1x128 (d);
*dst = pack_1x128_32 (
in_over_1x128 (&ms, &alpha, &mask, &dest));
}
 
dst++;
w--;
}
}
 
}
 
static void
sse2_composite_src_x888_0565 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint16_t *dst_line, *dst;
uint32_t *src_line, *src, s;
int dst_stride, src_stride;
int32_t w;
 
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w && (uintptr_t)dst & 15)
{
s = *src++;
*dst = convert_8888_to_0565 (s);
dst++;
w--;
}
 
while (w >= 8)
{
__m128i xmm_src0 = load_128_unaligned ((__m128i *)src + 0);
__m128i xmm_src1 = load_128_unaligned ((__m128i *)src + 1);
 
save_128_aligned ((__m128i*)dst, pack_565_2packedx128_128 (xmm_src0, xmm_src1));
 
w -= 8;
src += 8;
dst += 8;
}
 
while (w)
{
s = *src++;
*dst = convert_8888_to_0565 (s);
dst++;
w--;
}
}
}
 
static void
sse2_composite_src_x888_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line, *dst;
uint32_t *src_line, *src;
int32_t w;
int dst_stride, src_stride;
 
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w && (uintptr_t)dst & 15)
{
*dst++ = *src++ | 0xff000000;
w--;
}
 
while (w >= 16)
{
__m128i xmm_src1, xmm_src2, xmm_src3, xmm_src4;
xmm_src1 = load_128_unaligned ((__m128i*)src + 0);
xmm_src2 = load_128_unaligned ((__m128i*)src + 1);
xmm_src3 = load_128_unaligned ((__m128i*)src + 2);
xmm_src4 = load_128_unaligned ((__m128i*)src + 3);
save_128_aligned ((__m128i*)dst + 0, _mm_or_si128 (xmm_src1, mask_ff000000));
save_128_aligned ((__m128i*)dst + 1, _mm_or_si128 (xmm_src2, mask_ff000000));
save_128_aligned ((__m128i*)dst + 2, _mm_or_si128 (xmm_src3, mask_ff000000));
save_128_aligned ((__m128i*)dst + 3, _mm_or_si128 (xmm_src4, mask_ff000000));
dst += 16;
src += 16;
w -= 16;
}
 
while (w)
{
*dst++ = *src++ | 0xff000000;
w--;
}
}
 
}
 
static void
sse2_composite_over_x888_n_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line, *dst;
uint32_t *src_line, *src;
uint32_t mask;
int dst_stride, src_stride;
int32_t w;
 
__m128i xmm_mask, xmm_alpha;
__m128i xmm_src, xmm_src_lo, xmm_src_hi;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
mask = _pixman_image_get_solid (imp, mask_image, PIXMAN_a8r8g8b8);
 
xmm_mask = create_mask_16_128 (mask >> 24);
xmm_alpha = mask_00ff;
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w && (uintptr_t)dst & 15)
{
uint32_t s = (*src++) | 0xff000000;
uint32_t d = *dst;
 
__m128i src = unpack_32_1x128 (s);
__m128i alpha = xmm_alpha;
__m128i mask = xmm_mask;
__m128i dest = unpack_32_1x128 (d);
 
*dst++ = pack_1x128_32 (
in_over_1x128 (&src, &alpha, &mask, &dest));
 
w--;
}
 
while (w >= 4)
{
xmm_src = _mm_or_si128 (
load_128_unaligned ((__m128i*)src), mask_ff000000);
xmm_dst = load_128_aligned ((__m128i*)dst);
 
unpack_128_2x128 (xmm_src, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
 
in_over_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_alpha, &xmm_alpha,
&xmm_mask, &xmm_mask,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
dst += 4;
src += 4;
w -= 4;
 
}
 
while (w)
{
uint32_t s = (*src++) | 0xff000000;
uint32_t d = *dst;
 
__m128i src = unpack_32_1x128 (s);
__m128i alpha = xmm_alpha;
__m128i mask = xmm_mask;
__m128i dest = unpack_32_1x128 (d);
 
*dst++ = pack_1x128_32 (
in_over_1x128 (&src, &alpha, &mask, &dest));
 
w--;
}
}
 
}
 
static void
sse2_composite_over_8888_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
int dst_stride, src_stride;
uint32_t *dst_line, *dst;
uint32_t *src_line, *src;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
dst = dst_line;
src = src_line;
 
while (height--)
{
sse2_combine_over_u (imp, op, dst, src, NULL, width);
 
dst += dst_stride;
src += src_stride;
}
}
 
static force_inline uint16_t
composite_over_8888_0565pixel (uint32_t src, uint16_t dst)
{
__m128i ms;
 
ms = unpack_32_1x128 (src);
return pack_565_32_16 (
pack_1x128_32 (
over_1x128 (
ms, expand_alpha_1x128 (ms), expand565_16_1x128 (dst))));
}
 
static void
sse2_composite_over_8888_0565 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint16_t *dst_line, *dst, d;
uint32_t *src_line, *src, s;
int dst_stride, src_stride;
int32_t w;
 
__m128i xmm_alpha_lo, xmm_alpha_hi;
__m128i xmm_src, xmm_src_lo, xmm_src_hi;
__m128i xmm_dst, xmm_dst0, xmm_dst1, xmm_dst2, xmm_dst3;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
while (height--)
{
dst = dst_line;
src = src_line;
 
dst_line += dst_stride;
src_line += src_stride;
w = width;
 
/* Align dst on a 16-byte boundary */
while (w &&
((uintptr_t)dst & 15))
{
s = *src++;
d = *dst;
 
*dst++ = composite_over_8888_0565pixel (s, d);
w--;
}
 
/* It's a 8 pixel loop */
while (w >= 8)
{
/* I'm loading unaligned because I'm not sure
* about the address alignment.
*/
xmm_src = load_128_unaligned ((__m128i*) src);
xmm_dst = load_128_aligned ((__m128i*) dst);
 
/* Unpacking */
unpack_128_2x128 (xmm_src, &xmm_src_lo, &xmm_src_hi);
unpack_565_128_4x128 (xmm_dst,
&xmm_dst0, &xmm_dst1, &xmm_dst2, &xmm_dst3);
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_alpha_lo, &xmm_alpha_hi);
 
/* I'm loading next 4 pixels from memory
* before to optimze the memory read.
*/
xmm_src = load_128_unaligned ((__m128i*) (src + 4));
 
over_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_alpha_lo, &xmm_alpha_hi,
&xmm_dst0, &xmm_dst1);
 
/* Unpacking */
unpack_128_2x128 (xmm_src, &xmm_src_lo, &xmm_src_hi);
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_alpha_lo, &xmm_alpha_hi);
 
over_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_alpha_lo, &xmm_alpha_hi,
&xmm_dst2, &xmm_dst3);
 
save_128_aligned (
(__m128i*)dst, pack_565_4x128_128 (
&xmm_dst0, &xmm_dst1, &xmm_dst2, &xmm_dst3));
 
w -= 8;
dst += 8;
src += 8;
}
 
while (w--)
{
s = *src++;
d = *dst;
 
*dst++ = composite_over_8888_0565pixel (s, d);
}
}
 
}
 
static void
sse2_composite_over_n_8_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src, srca;
uint32_t *dst_line, *dst;
uint8_t *mask_line, *mask;
int dst_stride, mask_stride;
int32_t w;
uint32_t m, d;
 
__m128i xmm_src, xmm_alpha, xmm_def;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
__m128i xmm_mask, xmm_mask_lo, xmm_mask_hi;
 
__m128i mmx_src, mmx_alpha, mmx_mask, mmx_dest;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
srca = src >> 24;
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
 
xmm_def = create_mask_2x32_128 (src, src);
xmm_src = expand_pixel_32_1x128 (src);
xmm_alpha = expand_alpha_1x128 (xmm_src);
mmx_src = xmm_src;
mmx_alpha = xmm_alpha;
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w && (uintptr_t)dst & 15)
{
uint8_t m = *mask++;
 
if (m)
{
d = *dst;
mmx_mask = expand_pixel_8_1x128 (m);
mmx_dest = unpack_32_1x128 (d);
 
*dst = pack_1x128_32 (in_over_1x128 (&mmx_src,
&mmx_alpha,
&mmx_mask,
&mmx_dest));
}
 
w--;
dst++;
}
 
while (w >= 4)
{
m = *((uint32_t*)mask);
 
if (srca == 0xff && m == 0xffffffff)
{
save_128_aligned ((__m128i*)dst, xmm_def);
}
else if (m)
{
xmm_dst = load_128_aligned ((__m128i*) dst);
xmm_mask = unpack_32_1x128 (m);
xmm_mask = _mm_unpacklo_epi8 (xmm_mask, _mm_setzero_si128 ());
 
/* Unpacking */
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
unpack_128_2x128 (xmm_mask, &xmm_mask_lo, &xmm_mask_hi);
 
expand_alpha_rev_2x128 (xmm_mask_lo, xmm_mask_hi,
&xmm_mask_lo, &xmm_mask_hi);
 
in_over_2x128 (&xmm_src, &xmm_src,
&xmm_alpha, &xmm_alpha,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
}
 
w -= 4;
dst += 4;
mask += 4;
}
 
while (w)
{
uint8_t m = *mask++;
 
if (m)
{
d = *dst;
mmx_mask = expand_pixel_8_1x128 (m);
mmx_dest = unpack_32_1x128 (d);
 
*dst = pack_1x128_32 (in_over_1x128 (&mmx_src,
&mmx_alpha,
&mmx_mask,
&mmx_dest));
}
 
w--;
dst++;
}
}
 
}
 
#if defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
__attribute__((__force_align_arg_pointer__))
#endif
static pixman_bool_t
sse2_fill (pixman_implementation_t *imp,
uint32_t * bits,
int stride,
int bpp,
int x,
int y,
int width,
int height,
uint32_t filler)
{
uint32_t byte_width;
uint8_t *byte_line;
 
__m128i xmm_def;
 
if (bpp == 8)
{
uint8_t b;
uint16_t w;
 
stride = stride * (int) sizeof (uint32_t) / 1;
byte_line = (uint8_t *)(((uint8_t *)bits) + stride * y + x);
byte_width = width;
stride *= 1;
 
b = filler & 0xff;
w = (b << 8) | b;
filler = (w << 16) | w;
}
else if (bpp == 16)
{
stride = stride * (int) sizeof (uint32_t) / 2;
byte_line = (uint8_t *)(((uint16_t *)bits) + stride * y + x);
byte_width = 2 * width;
stride *= 2;
 
filler = (filler & 0xffff) * 0x00010001;
}
else if (bpp == 32)
{
stride = stride * (int) sizeof (uint32_t) / 4;
byte_line = (uint8_t *)(((uint32_t *)bits) + stride * y + x);
byte_width = 4 * width;
stride *= 4;
}
else
{
return FALSE;
}
 
xmm_def = create_mask_2x32_128 (filler, filler);
 
while (height--)
{
int w;
uint8_t *d = byte_line;
byte_line += stride;
w = byte_width;
 
if (w >= 1 && ((uintptr_t)d & 1))
{
*(uint8_t *)d = filler;
w -= 1;
d += 1;
}
 
while (w >= 2 && ((uintptr_t)d & 3))
{
*(uint16_t *)d = filler;
w -= 2;
d += 2;
}
 
while (w >= 4 && ((uintptr_t)d & 15))
{
*(uint32_t *)d = filler;
 
w -= 4;
d += 4;
}
 
while (w >= 128)
{
save_128_aligned ((__m128i*)(d), xmm_def);
save_128_aligned ((__m128i*)(d + 16), xmm_def);
save_128_aligned ((__m128i*)(d + 32), xmm_def);
save_128_aligned ((__m128i*)(d + 48), xmm_def);
save_128_aligned ((__m128i*)(d + 64), xmm_def);
save_128_aligned ((__m128i*)(d + 80), xmm_def);
save_128_aligned ((__m128i*)(d + 96), xmm_def);
save_128_aligned ((__m128i*)(d + 112), xmm_def);
 
d += 128;
w -= 128;
}
 
if (w >= 64)
{
save_128_aligned ((__m128i*)(d), xmm_def);
save_128_aligned ((__m128i*)(d + 16), xmm_def);
save_128_aligned ((__m128i*)(d + 32), xmm_def);
save_128_aligned ((__m128i*)(d + 48), xmm_def);
 
d += 64;
w -= 64;
}
 
if (w >= 32)
{
save_128_aligned ((__m128i*)(d), xmm_def);
save_128_aligned ((__m128i*)(d + 16), xmm_def);
 
d += 32;
w -= 32;
}
 
if (w >= 16)
{
save_128_aligned ((__m128i*)(d), xmm_def);
 
d += 16;
w -= 16;
}
 
while (w >= 4)
{
*(uint32_t *)d = filler;
 
w -= 4;
d += 4;
}
 
if (w >= 2)
{
*(uint16_t *)d = filler;
w -= 2;
d += 2;
}
 
if (w >= 1)
{
*(uint8_t *)d = filler;
w -= 1;
d += 1;
}
}
 
return TRUE;
}
 
static void
sse2_composite_src_n_8_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src, srca;
uint32_t *dst_line, *dst;
uint8_t *mask_line, *mask;
int dst_stride, mask_stride;
int32_t w;
uint32_t m;
 
__m128i xmm_src, xmm_def;
__m128i xmm_mask, xmm_mask_lo, xmm_mask_hi;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
srca = src >> 24;
if (src == 0)
{
sse2_fill (imp, dest_image->bits.bits, dest_image->bits.rowstride,
PIXMAN_FORMAT_BPP (dest_image->bits.format),
dest_x, dest_y, width, height, 0);
return;
}
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
 
xmm_def = create_mask_2x32_128 (src, src);
xmm_src = expand_pixel_32_1x128 (src);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w && (uintptr_t)dst & 15)
{
uint8_t m = *mask++;
 
if (m)
{
*dst = pack_1x128_32 (
pix_multiply_1x128 (xmm_src, expand_pixel_8_1x128 (m)));
}
else
{
*dst = 0;
}
 
w--;
dst++;
}
 
while (w >= 4)
{
m = *((uint32_t*)mask);
 
if (srca == 0xff && m == 0xffffffff)
{
save_128_aligned ((__m128i*)dst, xmm_def);
}
else if (m)
{
xmm_mask = unpack_32_1x128 (m);
xmm_mask = _mm_unpacklo_epi8 (xmm_mask, _mm_setzero_si128 ());
 
/* Unpacking */
unpack_128_2x128 (xmm_mask, &xmm_mask_lo, &xmm_mask_hi);
 
expand_alpha_rev_2x128 (xmm_mask_lo, xmm_mask_hi,
&xmm_mask_lo, &xmm_mask_hi);
 
pix_multiply_2x128 (&xmm_src, &xmm_src,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_mask_lo, &xmm_mask_hi);
 
save_128_aligned (
(__m128i*)dst, pack_2x128_128 (xmm_mask_lo, xmm_mask_hi));
}
else
{
save_128_aligned ((__m128i*)dst, _mm_setzero_si128 ());
}
 
w -= 4;
dst += 4;
mask += 4;
}
 
while (w)
{
uint8_t m = *mask++;
 
if (m)
{
*dst = pack_1x128_32 (
pix_multiply_1x128 (
xmm_src, expand_pixel_8_1x128 (m)));
}
else
{
*dst = 0;
}
 
w--;
dst++;
}
}
 
}
 
static void
sse2_composite_over_n_8_0565 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src;
uint16_t *dst_line, *dst, d;
uint8_t *mask_line, *mask;
int dst_stride, mask_stride;
int32_t w;
uint32_t m;
__m128i mmx_src, mmx_alpha, mmx_mask, mmx_dest;
 
__m128i xmm_src, xmm_alpha;
__m128i xmm_mask, xmm_mask_lo, xmm_mask_hi;
__m128i xmm_dst, xmm_dst0, xmm_dst1, xmm_dst2, xmm_dst3;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
 
xmm_src = expand_pixel_32_1x128 (src);
xmm_alpha = expand_alpha_1x128 (xmm_src);
mmx_src = xmm_src;
mmx_alpha = xmm_alpha;
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w && (uintptr_t)dst & 15)
{
m = *mask++;
 
if (m)
{
d = *dst;
mmx_mask = expand_alpha_rev_1x128 (unpack_32_1x128 (m));
mmx_dest = expand565_16_1x128 (d);
 
*dst = pack_565_32_16 (
pack_1x128_32 (
in_over_1x128 (
&mmx_src, &mmx_alpha, &mmx_mask, &mmx_dest)));
}
 
w--;
dst++;
}
 
while (w >= 8)
{
xmm_dst = load_128_aligned ((__m128i*) dst);
unpack_565_128_4x128 (xmm_dst,
&xmm_dst0, &xmm_dst1, &xmm_dst2, &xmm_dst3);
 
m = *((uint32_t*)mask);
mask += 4;
 
if (m)
{
xmm_mask = unpack_32_1x128 (m);
xmm_mask = _mm_unpacklo_epi8 (xmm_mask, _mm_setzero_si128 ());
 
/* Unpacking */
unpack_128_2x128 (xmm_mask, &xmm_mask_lo, &xmm_mask_hi);
 
expand_alpha_rev_2x128 (xmm_mask_lo, xmm_mask_hi,
&xmm_mask_lo, &xmm_mask_hi);
 
in_over_2x128 (&xmm_src, &xmm_src,
&xmm_alpha, &xmm_alpha,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_dst0, &xmm_dst1);
}
 
m = *((uint32_t*)mask);
mask += 4;
 
if (m)
{
xmm_mask = unpack_32_1x128 (m);
xmm_mask = _mm_unpacklo_epi8 (xmm_mask, _mm_setzero_si128 ());
 
/* Unpacking */
unpack_128_2x128 (xmm_mask, &xmm_mask_lo, &xmm_mask_hi);
 
expand_alpha_rev_2x128 (xmm_mask_lo, xmm_mask_hi,
&xmm_mask_lo, &xmm_mask_hi);
in_over_2x128 (&xmm_src, &xmm_src,
&xmm_alpha, &xmm_alpha,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_dst2, &xmm_dst3);
}
 
save_128_aligned (
(__m128i*)dst, pack_565_4x128_128 (
&xmm_dst0, &xmm_dst1, &xmm_dst2, &xmm_dst3));
 
w -= 8;
dst += 8;
}
 
while (w)
{
m = *mask++;
 
if (m)
{
d = *dst;
mmx_mask = expand_alpha_rev_1x128 (unpack_32_1x128 (m));
mmx_dest = expand565_16_1x128 (d);
 
*dst = pack_565_32_16 (
pack_1x128_32 (
in_over_1x128 (
&mmx_src, &mmx_alpha, &mmx_mask, &mmx_dest)));
}
 
w--;
dst++;
}
}
 
}
 
static void
sse2_composite_over_pixbuf_0565 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint16_t *dst_line, *dst, d;
uint32_t *src_line, *src, s;
int dst_stride, src_stride;
int32_t w;
uint32_t opaque, zero;
 
__m128i ms;
__m128i xmm_src, xmm_src_lo, xmm_src_hi;
__m128i xmm_dst, xmm_dst0, xmm_dst1, xmm_dst2, xmm_dst3;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w && (uintptr_t)dst & 15)
{
s = *src++;
d = *dst;
 
ms = unpack_32_1x128 (s);
 
*dst++ = pack_565_32_16 (
pack_1x128_32 (
over_rev_non_pre_1x128 (ms, expand565_16_1x128 (d))));
w--;
}
 
while (w >= 8)
{
/* First round */
xmm_src = load_128_unaligned ((__m128i*)src);
xmm_dst = load_128_aligned ((__m128i*)dst);
 
opaque = is_opaque (xmm_src);
zero = is_zero (xmm_src);
 
unpack_565_128_4x128 (xmm_dst,
&xmm_dst0, &xmm_dst1, &xmm_dst2, &xmm_dst3);
unpack_128_2x128 (xmm_src, &xmm_src_lo, &xmm_src_hi);
 
/* preload next round*/
xmm_src = load_128_unaligned ((__m128i*)(src + 4));
 
if (opaque)
{
invert_colors_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_dst0, &xmm_dst1);
}
else if (!zero)
{
over_rev_non_pre_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_dst0, &xmm_dst1);
}
 
/* Second round */
opaque = is_opaque (xmm_src);
zero = is_zero (xmm_src);
 
unpack_128_2x128 (xmm_src, &xmm_src_lo, &xmm_src_hi);
 
if (opaque)
{
invert_colors_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_dst2, &xmm_dst3);
}
else if (!zero)
{
over_rev_non_pre_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_dst2, &xmm_dst3);
}
 
save_128_aligned (
(__m128i*)dst, pack_565_4x128_128 (
&xmm_dst0, &xmm_dst1, &xmm_dst2, &xmm_dst3));
 
w -= 8;
src += 8;
dst += 8;
}
 
while (w)
{
s = *src++;
d = *dst;
 
ms = unpack_32_1x128 (s);
 
*dst++ = pack_565_32_16 (
pack_1x128_32 (
over_rev_non_pre_1x128 (ms, expand565_16_1x128 (d))));
w--;
}
}
 
}
 
static void
sse2_composite_over_pixbuf_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line, *dst, d;
uint32_t *src_line, *src, s;
int dst_stride, src_stride;
int32_t w;
uint32_t opaque, zero;
 
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w && (uintptr_t)dst & 15)
{
s = *src++;
d = *dst;
 
*dst++ = pack_1x128_32 (
over_rev_non_pre_1x128 (
unpack_32_1x128 (s), unpack_32_1x128 (d)));
 
w--;
}
 
while (w >= 4)
{
xmm_src_hi = load_128_unaligned ((__m128i*)src);
 
opaque = is_opaque (xmm_src_hi);
zero = is_zero (xmm_src_hi);
 
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
 
if (opaque)
{
invert_colors_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
}
else if (!zero)
{
xmm_dst_hi = load_128_aligned ((__m128i*)dst);
 
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
 
over_rev_non_pre_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
}
 
w -= 4;
dst += 4;
src += 4;
}
 
while (w)
{
s = *src++;
d = *dst;
 
*dst++ = pack_1x128_32 (
over_rev_non_pre_1x128 (
unpack_32_1x128 (s), unpack_32_1x128 (d)));
 
w--;
}
}
 
}
 
static void
sse2_composite_over_n_8888_0565_ca (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src;
uint16_t *dst_line, *dst, d;
uint32_t *mask_line, *mask, m;
int dst_stride, mask_stride;
int w;
uint32_t pack_cmp;
 
__m128i xmm_src, xmm_alpha;
__m128i xmm_mask, xmm_mask_lo, xmm_mask_hi;
__m128i xmm_dst, xmm_dst0, xmm_dst1, xmm_dst2, xmm_dst3;
 
__m128i mmx_src, mmx_alpha, mmx_mask, mmx_dest;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
mask_image, mask_x, mask_y, uint32_t, mask_stride, mask_line, 1);
 
xmm_src = expand_pixel_32_1x128 (src);
xmm_alpha = expand_alpha_1x128 (xmm_src);
mmx_src = xmm_src;
mmx_alpha = xmm_alpha;
 
while (height--)
{
w = width;
mask = mask_line;
dst = dst_line;
mask_line += mask_stride;
dst_line += dst_stride;
 
while (w && ((uintptr_t)dst & 15))
{
m = *(uint32_t *) mask;
 
if (m)
{
d = *dst;
mmx_mask = unpack_32_1x128 (m);
mmx_dest = expand565_16_1x128 (d);
 
*dst = pack_565_32_16 (
pack_1x128_32 (
in_over_1x128 (
&mmx_src, &mmx_alpha, &mmx_mask, &mmx_dest)));
}
 
w--;
dst++;
mask++;
}
 
while (w >= 8)
{
/* First round */
xmm_mask = load_128_unaligned ((__m128i*)mask);
xmm_dst = load_128_aligned ((__m128i*)dst);
 
pack_cmp = _mm_movemask_epi8 (
_mm_cmpeq_epi32 (xmm_mask, _mm_setzero_si128 ()));
 
unpack_565_128_4x128 (xmm_dst,
&xmm_dst0, &xmm_dst1, &xmm_dst2, &xmm_dst3);
unpack_128_2x128 (xmm_mask, &xmm_mask_lo, &xmm_mask_hi);
 
/* preload next round */
xmm_mask = load_128_unaligned ((__m128i*)(mask + 4));
 
/* preload next round */
if (pack_cmp != 0xffff)
{
in_over_2x128 (&xmm_src, &xmm_src,
&xmm_alpha, &xmm_alpha,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_dst0, &xmm_dst1);
}
 
/* Second round */
pack_cmp = _mm_movemask_epi8 (
_mm_cmpeq_epi32 (xmm_mask, _mm_setzero_si128 ()));
 
unpack_128_2x128 (xmm_mask, &xmm_mask_lo, &xmm_mask_hi);
 
if (pack_cmp != 0xffff)
{
in_over_2x128 (&xmm_src, &xmm_src,
&xmm_alpha, &xmm_alpha,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_dst2, &xmm_dst3);
}
 
save_128_aligned (
(__m128i*)dst, pack_565_4x128_128 (
&xmm_dst0, &xmm_dst1, &xmm_dst2, &xmm_dst3));
 
w -= 8;
dst += 8;
mask += 8;
}
 
while (w)
{
m = *(uint32_t *) mask;
 
if (m)
{
d = *dst;
mmx_mask = unpack_32_1x128 (m);
mmx_dest = expand565_16_1x128 (d);
 
*dst = pack_565_32_16 (
pack_1x128_32 (
in_over_1x128 (
&mmx_src, &mmx_alpha, &mmx_mask, &mmx_dest)));
}
 
w--;
dst++;
mask++;
}
}
 
}
 
static void
sse2_composite_in_n_8_8 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint8_t *dst_line, *dst;
uint8_t *mask_line, *mask;
int dst_stride, mask_stride;
uint32_t d, m;
uint32_t src;
int32_t w;
 
__m128i xmm_alpha;
__m128i xmm_mask, xmm_mask_lo, xmm_mask_hi;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
xmm_alpha = expand_alpha_1x128 (expand_pixel_32_1x128 (src));
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w && ((uintptr_t)dst & 15))
{
m = (uint32_t) *mask++;
d = (uint32_t) *dst;
 
*dst++ = (uint8_t) pack_1x128_32 (
pix_multiply_1x128 (
pix_multiply_1x128 (xmm_alpha,
unpack_32_1x128 (m)),
unpack_32_1x128 (d)));
w--;
}
 
while (w >= 16)
{
xmm_mask = load_128_unaligned ((__m128i*)mask);
xmm_dst = load_128_aligned ((__m128i*)dst);
 
unpack_128_2x128 (xmm_mask, &xmm_mask_lo, &xmm_mask_hi);
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
 
pix_multiply_2x128 (&xmm_alpha, &xmm_alpha,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_mask_lo, &xmm_mask_hi);
 
pix_multiply_2x128 (&xmm_mask_lo, &xmm_mask_hi,
&xmm_dst_lo, &xmm_dst_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
mask += 16;
dst += 16;
w -= 16;
}
 
while (w)
{
m = (uint32_t) *mask++;
d = (uint32_t) *dst;
 
*dst++ = (uint8_t) pack_1x128_32 (
pix_multiply_1x128 (
pix_multiply_1x128 (
xmm_alpha, unpack_32_1x128 (m)),
unpack_32_1x128 (d)));
w--;
}
}
 
}
 
static void
sse2_composite_in_n_8 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint8_t *dst_line, *dst;
int dst_stride;
uint32_t d;
uint32_t src;
int32_t w;
 
__m128i xmm_alpha;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 1);
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
xmm_alpha = expand_alpha_1x128 (expand_pixel_32_1x128 (src));
 
src = src >> 24;
 
if (src == 0xff)
return;
 
if (src == 0x00)
{
pixman_fill (dest_image->bits.bits, dest_image->bits.rowstride,
8, dest_x, dest_y, width, height, src);
 
return;
}
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
w = width;
 
while (w && ((uintptr_t)dst & 15))
{
d = (uint32_t) *dst;
 
*dst++ = (uint8_t) pack_1x128_32 (
pix_multiply_1x128 (
xmm_alpha,
unpack_32_1x128 (d)));
w--;
}
 
while (w >= 16)
{
xmm_dst = load_128_aligned ((__m128i*)dst);
 
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
pix_multiply_2x128 (&xmm_alpha, &xmm_alpha,
&xmm_dst_lo, &xmm_dst_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
dst += 16;
w -= 16;
}
 
while (w)
{
d = (uint32_t) *dst;
 
*dst++ = (uint8_t) pack_1x128_32 (
pix_multiply_1x128 (
xmm_alpha,
unpack_32_1x128 (d)));
w--;
}
}
 
}
 
static void
sse2_composite_in_8_8 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint8_t *dst_line, *dst;
uint8_t *src_line, *src;
int src_stride, dst_stride;
int32_t w;
uint32_t s, d;
 
__m128i xmm_src, xmm_src_lo, xmm_src_hi;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
src_image, src_x, src_y, uint8_t, src_stride, src_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
w = width;
 
while (w && ((uintptr_t)dst & 15))
{
s = (uint32_t) *src++;
d = (uint32_t) *dst;
 
*dst++ = (uint8_t) pack_1x128_32 (
pix_multiply_1x128 (
unpack_32_1x128 (s), unpack_32_1x128 (d)));
w--;
}
 
while (w >= 16)
{
xmm_src = load_128_unaligned ((__m128i*)src);
xmm_dst = load_128_aligned ((__m128i*)dst);
 
unpack_128_2x128 (xmm_src, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
 
pix_multiply_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_dst_lo, &xmm_dst_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
src += 16;
dst += 16;
w -= 16;
}
 
while (w)
{
s = (uint32_t) *src++;
d = (uint32_t) *dst;
 
*dst++ = (uint8_t) pack_1x128_32 (
pix_multiply_1x128 (unpack_32_1x128 (s), unpack_32_1x128 (d)));
w--;
}
}
 
}
 
static void
sse2_composite_add_n_8_8 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint8_t *dst_line, *dst;
uint8_t *mask_line, *mask;
int dst_stride, mask_stride;
int32_t w;
uint32_t src;
uint32_t m, d;
 
__m128i xmm_alpha;
__m128i xmm_mask, xmm_mask_lo, xmm_mask_hi;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
xmm_alpha = expand_alpha_1x128 (expand_pixel_32_1x128 (src));
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w && ((uintptr_t)dst & 15))
{
m = (uint32_t) *mask++;
d = (uint32_t) *dst;
 
*dst++ = (uint8_t) pack_1x128_32 (
_mm_adds_epu16 (
pix_multiply_1x128 (
xmm_alpha, unpack_32_1x128 (m)),
unpack_32_1x128 (d)));
w--;
}
 
while (w >= 16)
{
xmm_mask = load_128_unaligned ((__m128i*)mask);
xmm_dst = load_128_aligned ((__m128i*)dst);
 
unpack_128_2x128 (xmm_mask, &xmm_mask_lo, &xmm_mask_hi);
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
 
pix_multiply_2x128 (&xmm_alpha, &xmm_alpha,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_mask_lo, &xmm_mask_hi);
 
xmm_dst_lo = _mm_adds_epu16 (xmm_mask_lo, xmm_dst_lo);
xmm_dst_hi = _mm_adds_epu16 (xmm_mask_hi, xmm_dst_hi);
 
save_128_aligned (
(__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
 
mask += 16;
dst += 16;
w -= 16;
}
 
while (w)
{
m = (uint32_t) *mask++;
d = (uint32_t) *dst;
 
*dst++ = (uint8_t) pack_1x128_32 (
_mm_adds_epu16 (
pix_multiply_1x128 (
xmm_alpha, unpack_32_1x128 (m)),
unpack_32_1x128 (d)));
 
w--;
}
}
 
}
 
static void
sse2_composite_add_n_8 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint8_t *dst_line, *dst;
int dst_stride;
int32_t w;
uint32_t src;
 
__m128i xmm_src;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 1);
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
src >>= 24;
 
if (src == 0x00)
return;
 
if (src == 0xff)
{
pixman_fill (dest_image->bits.bits, dest_image->bits.rowstride,
8, dest_x, dest_y, width, height, 0xff);
 
return;
}
 
src = (src << 24) | (src << 16) | (src << 8) | src;
xmm_src = _mm_set_epi32 (src, src, src, src);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
w = width;
 
while (w && ((uintptr_t)dst & 15))
{
*dst = (uint8_t)_mm_cvtsi128_si32 (
_mm_adds_epu8 (
xmm_src,
_mm_cvtsi32_si128 (*dst)));
 
w--;
dst++;
}
 
while (w >= 16)
{
save_128_aligned (
(__m128i*)dst, _mm_adds_epu8 (xmm_src, load_128_aligned ((__m128i*)dst)));
 
dst += 16;
w -= 16;
}
 
while (w)
{
*dst = (uint8_t)_mm_cvtsi128_si32 (
_mm_adds_epu8 (
xmm_src,
_mm_cvtsi32_si128 (*dst)));
 
w--;
dst++;
}
}
 
}
 
static void
sse2_composite_add_8_8 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint8_t *dst_line, *dst;
uint8_t *src_line, *src;
int dst_stride, src_stride;
int32_t w;
uint16_t t;
 
PIXMAN_IMAGE_GET_LINE (
src_image, src_x, src_y, uint8_t, src_stride, src_line, 1);
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 1);
 
while (height--)
{
dst = dst_line;
src = src_line;
 
dst_line += dst_stride;
src_line += src_stride;
w = width;
 
/* Small head */
while (w && (uintptr_t)dst & 3)
{
t = (*dst) + (*src++);
*dst++ = t | (0 - (t >> 8));
w--;
}
 
sse2_combine_add_u (imp, op,
(uint32_t*)dst, (uint32_t*)src, NULL, w >> 2);
 
/* Small tail */
dst += w & 0xfffc;
src += w & 0xfffc;
 
w &= 3;
 
while (w)
{
t = (*dst) + (*src++);
*dst++ = t | (0 - (t >> 8));
w--;
}
}
 
}
 
static void
sse2_composite_add_8888_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line, *dst;
uint32_t *src_line, *src;
int dst_stride, src_stride;
 
PIXMAN_IMAGE_GET_LINE (
src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
src = src_line;
src_line += src_stride;
 
sse2_combine_add_u (imp, op, dst, src, NULL, width);
}
}
 
static void
sse2_composite_add_n_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line, *dst, src;
int dst_stride;
 
__m128i xmm_src;
 
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
if (src == 0)
return;
 
if (src == ~0)
{
pixman_fill (dest_image->bits.bits, dest_image->bits.rowstride, 32,
dest_x, dest_y, width, height, ~0);
 
return;
}
 
xmm_src = _mm_set_epi32 (src, src, src, src);
while (height--)
{
int w = width;
uint32_t d;
 
dst = dst_line;
dst_line += dst_stride;
 
while (w && (uintptr_t)dst & 15)
{
d = *dst;
*dst++ =
_mm_cvtsi128_si32 ( _mm_adds_epu8 (xmm_src, _mm_cvtsi32_si128 (d)));
w--;
}
 
while (w >= 4)
{
save_128_aligned
((__m128i*)dst,
_mm_adds_epu8 (xmm_src, load_128_aligned ((__m128i*)dst)));
 
dst += 4;
w -= 4;
}
 
while (w--)
{
d = *dst;
*dst++ =
_mm_cvtsi128_si32 (_mm_adds_epu8 (xmm_src,
_mm_cvtsi32_si128 (d)));
}
}
}
 
static void
sse2_composite_add_n_8_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *dst_line, *dst;
uint8_t *mask_line, *mask;
int dst_stride, mask_stride;
int32_t w;
uint32_t src;
 
__m128i xmm_src;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
if (src == 0)
return;
xmm_src = expand_pixel_32_1x128 (src);
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
 
while (height--)
{
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
w = width;
 
while (w && ((uintptr_t)dst & 15))
{
uint8_t m = *mask++;
if (m)
{
*dst = pack_1x128_32
(_mm_adds_epu16
(pix_multiply_1x128 (xmm_src, expand_pixel_8_1x128 (m)),
unpack_32_1x128 (*dst)));
}
dst++;
w--;
}
 
while (w >= 4)
{
uint32_t m = *(uint32_t*)mask;
if (m)
{
__m128i xmm_mask_lo, xmm_mask_hi;
__m128i xmm_dst_lo, xmm_dst_hi;
 
__m128i xmm_dst = load_128_aligned ((__m128i*)dst);
__m128i xmm_mask =
_mm_unpacklo_epi8 (unpack_32_1x128(m),
_mm_setzero_si128 ());
 
unpack_128_2x128 (xmm_mask, &xmm_mask_lo, &xmm_mask_hi);
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
 
expand_alpha_rev_2x128 (xmm_mask_lo, xmm_mask_hi,
&xmm_mask_lo, &xmm_mask_hi);
 
pix_multiply_2x128 (&xmm_src, &xmm_src,
&xmm_mask_lo, &xmm_mask_hi,
&xmm_mask_lo, &xmm_mask_hi);
 
xmm_dst_lo = _mm_adds_epu16 (xmm_mask_lo, xmm_dst_lo);
xmm_dst_hi = _mm_adds_epu16 (xmm_mask_hi, xmm_dst_hi);
 
save_128_aligned (
(__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
}
 
w -= 4;
dst += 4;
mask += 4;
}
 
while (w)
{
uint8_t m = *mask++;
if (m)
{
*dst = pack_1x128_32
(_mm_adds_epu16
(pix_multiply_1x128 (xmm_src, expand_pixel_8_1x128 (m)),
unpack_32_1x128 (*dst)));
}
dst++;
w--;
}
}
}
 
static pixman_bool_t
sse2_blt (pixman_implementation_t *imp,
uint32_t * src_bits,
uint32_t * dst_bits,
int src_stride,
int dst_stride,
int src_bpp,
int dst_bpp,
int src_x,
int src_y,
int dest_x,
int dest_y,
int width,
int height)
{
uint8_t * src_bytes;
uint8_t * dst_bytes;
int byte_width;
 
if (src_bpp != dst_bpp)
return FALSE;
 
if (src_bpp == 16)
{
src_stride = src_stride * (int) sizeof (uint32_t) / 2;
dst_stride = dst_stride * (int) sizeof (uint32_t) / 2;
src_bytes =(uint8_t *)(((uint16_t *)src_bits) + src_stride * (src_y) + (src_x));
dst_bytes = (uint8_t *)(((uint16_t *)dst_bits) + dst_stride * (dest_y) + (dest_x));
byte_width = 2 * width;
src_stride *= 2;
dst_stride *= 2;
}
else if (src_bpp == 32)
{
src_stride = src_stride * (int) sizeof (uint32_t) / 4;
dst_stride = dst_stride * (int) sizeof (uint32_t) / 4;
src_bytes = (uint8_t *)(((uint32_t *)src_bits) + src_stride * (src_y) + (src_x));
dst_bytes = (uint8_t *)(((uint32_t *)dst_bits) + dst_stride * (dest_y) + (dest_x));
byte_width = 4 * width;
src_stride *= 4;
dst_stride *= 4;
}
else
{
return FALSE;
}
 
while (height--)
{
int w;
uint8_t *s = src_bytes;
uint8_t *d = dst_bytes;
src_bytes += src_stride;
dst_bytes += dst_stride;
w = byte_width;
 
while (w >= 2 && ((uintptr_t)d & 3))
{
*(uint16_t *)d = *(uint16_t *)s;
w -= 2;
s += 2;
d += 2;
}
 
while (w >= 4 && ((uintptr_t)d & 15))
{
*(uint32_t *)d = *(uint32_t *)s;
 
w -= 4;
s += 4;
d += 4;
}
 
while (w >= 64)
{
__m128i xmm0, xmm1, xmm2, xmm3;
 
xmm0 = load_128_unaligned ((__m128i*)(s));
xmm1 = load_128_unaligned ((__m128i*)(s + 16));
xmm2 = load_128_unaligned ((__m128i*)(s + 32));
xmm3 = load_128_unaligned ((__m128i*)(s + 48));
 
save_128_aligned ((__m128i*)(d), xmm0);
save_128_aligned ((__m128i*)(d + 16), xmm1);
save_128_aligned ((__m128i*)(d + 32), xmm2);
save_128_aligned ((__m128i*)(d + 48), xmm3);
 
s += 64;
d += 64;
w -= 64;
}
 
while (w >= 16)
{
save_128_aligned ((__m128i*)d, load_128_unaligned ((__m128i*)s) );
 
w -= 16;
d += 16;
s += 16;
}
 
while (w >= 4)
{
*(uint32_t *)d = *(uint32_t *)s;
 
w -= 4;
s += 4;
d += 4;
}
 
if (w >= 2)
{
*(uint16_t *)d = *(uint16_t *)s;
w -= 2;
s += 2;
d += 2;
}
}
 
return TRUE;
}
 
static void
sse2_composite_copy_area (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
sse2_blt (imp, src_image->bits.bits,
dest_image->bits.bits,
src_image->bits.rowstride,
dest_image->bits.rowstride,
PIXMAN_FORMAT_BPP (src_image->bits.format),
PIXMAN_FORMAT_BPP (dest_image->bits.format),
src_x, src_y, dest_x, dest_y, width, height);
}
 
static void
sse2_composite_over_x888_8_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *src, *src_line, s;
uint32_t *dst, *dst_line, d;
uint8_t *mask, *mask_line;
uint32_t m;
int src_stride, mask_stride, dst_stride;
int32_t w;
__m128i ms;
 
__m128i xmm_src, xmm_src_lo, xmm_src_hi;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
__m128i xmm_mask, xmm_mask_lo, xmm_mask_hi;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
PIXMAN_IMAGE_GET_LINE (
src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
while (height--)
{
src = src_line;
src_line += src_stride;
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
 
w = width;
 
while (w && (uintptr_t)dst & 15)
{
s = 0xff000000 | *src++;
m = (uint32_t) *mask++;
d = *dst;
ms = unpack_32_1x128 (s);
 
if (m != 0xff)
{
__m128i ma = expand_alpha_rev_1x128 (unpack_32_1x128 (m));
__m128i md = unpack_32_1x128 (d);
 
ms = in_over_1x128 (&ms, &mask_00ff, &ma, &md);
}
 
*dst++ = pack_1x128_32 (ms);
w--;
}
 
while (w >= 4)
{
m = *(uint32_t*) mask;
xmm_src = _mm_or_si128 (
load_128_unaligned ((__m128i*)src), mask_ff000000);
 
if (m == 0xffffffff)
{
save_128_aligned ((__m128i*)dst, xmm_src);
}
else
{
xmm_dst = load_128_aligned ((__m128i*)dst);
 
xmm_mask = _mm_unpacklo_epi16 (unpack_32_1x128 (m), _mm_setzero_si128());
 
unpack_128_2x128 (xmm_src, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_mask, &xmm_mask_lo, &xmm_mask_hi);
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
 
expand_alpha_rev_2x128 (
xmm_mask_lo, xmm_mask_hi, &xmm_mask_lo, &xmm_mask_hi);
 
in_over_2x128 (&xmm_src_lo, &xmm_src_hi,
&mask_00ff, &mask_00ff, &xmm_mask_lo, &xmm_mask_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned ((__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
}
 
src += 4;
dst += 4;
mask += 4;
w -= 4;
}
 
while (w)
{
m = (uint32_t) *mask++;
 
if (m)
{
s = 0xff000000 | *src;
 
if (m == 0xff)
{
*dst = s;
}
else
{
__m128i ma, md, ms;
 
d = *dst;
 
ma = expand_alpha_rev_1x128 (unpack_32_1x128 (m));
md = unpack_32_1x128 (d);
ms = unpack_32_1x128 (s);
 
*dst = pack_1x128_32 (in_over_1x128 (&ms, &mask_00ff, &ma, &md));
}
 
}
 
src++;
dst++;
w--;
}
}
 
}
 
static void
sse2_composite_over_8888_8_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *src, *src_line, s;
uint32_t *dst, *dst_line, d;
uint8_t *mask, *mask_line;
uint32_t m;
int src_stride, mask_stride, dst_stride;
int32_t w;
 
__m128i xmm_src, xmm_src_lo, xmm_src_hi, xmm_srca_lo, xmm_srca_hi;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
__m128i xmm_mask, xmm_mask_lo, xmm_mask_hi;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1);
PIXMAN_IMAGE_GET_LINE (
src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
while (height--)
{
src = src_line;
src_line += src_stride;
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
 
w = width;
 
while (w && (uintptr_t)dst & 15)
{
uint32_t sa;
 
s = *src++;
m = (uint32_t) *mask++;
d = *dst;
 
sa = s >> 24;
 
if (m)
{
if (sa == 0xff && m == 0xff)
{
*dst = s;
}
else
{
__m128i ms, md, ma, msa;
 
ma = expand_alpha_rev_1x128 (load_32_1x128 (m));
ms = unpack_32_1x128 (s);
md = unpack_32_1x128 (d);
 
msa = expand_alpha_rev_1x128 (load_32_1x128 (sa));
 
*dst = pack_1x128_32 (in_over_1x128 (&ms, &msa, &ma, &md));
}
}
 
dst++;
w--;
}
 
while (w >= 4)
{
m = *(uint32_t *) mask;
 
if (m)
{
xmm_src = load_128_unaligned ((__m128i*)src);
 
if (m == 0xffffffff && is_opaque (xmm_src))
{
save_128_aligned ((__m128i *)dst, xmm_src);
}
else
{
xmm_dst = load_128_aligned ((__m128i *)dst);
 
xmm_mask = _mm_unpacklo_epi16 (unpack_32_1x128 (m), _mm_setzero_si128());
 
unpack_128_2x128 (xmm_src, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_mask, &xmm_mask_lo, &xmm_mask_hi);
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
 
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi, &xmm_srca_lo, &xmm_srca_hi);
expand_alpha_rev_2x128 (xmm_mask_lo, xmm_mask_hi, &xmm_mask_lo, &xmm_mask_hi);
 
in_over_2x128 (&xmm_src_lo, &xmm_src_hi, &xmm_srca_lo, &xmm_srca_hi,
&xmm_mask_lo, &xmm_mask_hi, &xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned ((__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
}
}
 
src += 4;
dst += 4;
mask += 4;
w -= 4;
}
 
while (w)
{
uint32_t sa;
 
s = *src++;
m = (uint32_t) *mask++;
d = *dst;
 
sa = s >> 24;
 
if (m)
{
if (sa == 0xff && m == 0xff)
{
*dst = s;
}
else
{
__m128i ms, md, ma, msa;
 
ma = expand_alpha_rev_1x128 (load_32_1x128 (m));
ms = unpack_32_1x128 (s);
md = unpack_32_1x128 (d);
 
msa = expand_alpha_rev_1x128 (load_32_1x128 (sa));
 
*dst = pack_1x128_32 (in_over_1x128 (&ms, &msa, &ma, &md));
}
}
 
dst++;
w--;
}
}
 
}
 
static void
sse2_composite_over_reverse_n_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t src;
uint32_t *dst_line, *dst;
__m128i xmm_src;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
__m128i xmm_dsta_hi, xmm_dsta_lo;
int dst_stride;
int32_t w;
 
src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format);
 
if (src == 0)
return;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
 
xmm_src = expand_pixel_32_1x128 (src);
 
while (height--)
{
dst = dst_line;
 
dst_line += dst_stride;
w = width;
 
while (w && (uintptr_t)dst & 15)
{
__m128i vd;
 
vd = unpack_32_1x128 (*dst);
 
*dst = pack_1x128_32 (over_1x128 (vd, expand_alpha_1x128 (vd),
xmm_src));
w--;
dst++;
}
 
while (w >= 4)
{
__m128i tmp_lo, tmp_hi;
 
xmm_dst = load_128_aligned ((__m128i*)dst);
 
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
expand_alpha_2x128 (xmm_dst_lo, xmm_dst_hi, &xmm_dsta_lo, &xmm_dsta_hi);
 
tmp_lo = xmm_src;
tmp_hi = xmm_src;
 
over_2x128 (&xmm_dst_lo, &xmm_dst_hi,
&xmm_dsta_lo, &xmm_dsta_hi,
&tmp_lo, &tmp_hi);
 
save_128_aligned (
(__m128i*)dst, pack_2x128_128 (tmp_lo, tmp_hi));
 
w -= 4;
dst += 4;
}
 
while (w)
{
__m128i vd;
 
vd = unpack_32_1x128 (*dst);
 
*dst = pack_1x128_32 (over_1x128 (vd, expand_alpha_1x128 (vd),
xmm_src));
w--;
dst++;
}
 
}
 
}
 
static void
sse2_composite_over_8888_8888_8888 (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
uint32_t *src, *src_line, s;
uint32_t *dst, *dst_line, d;
uint32_t *mask, *mask_line;
uint32_t m;
int src_stride, mask_stride, dst_stride;
int32_t w;
 
__m128i xmm_src, xmm_src_lo, xmm_src_hi, xmm_srca_lo, xmm_srca_hi;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
__m128i xmm_mask, xmm_mask_lo, xmm_mask_hi;
 
PIXMAN_IMAGE_GET_LINE (
dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1);
PIXMAN_IMAGE_GET_LINE (
mask_image, mask_x, mask_y, uint32_t, mask_stride, mask_line, 1);
PIXMAN_IMAGE_GET_LINE (
src_image, src_x, src_y, uint32_t, src_stride, src_line, 1);
 
while (height--)
{
src = src_line;
src_line += src_stride;
dst = dst_line;
dst_line += dst_stride;
mask = mask_line;
mask_line += mask_stride;
 
w = width;
 
while (w && (uintptr_t)dst & 15)
{
uint32_t sa;
 
s = *src++;
m = (*mask++) >> 24;
d = *dst;
 
sa = s >> 24;
 
if (m)
{
if (sa == 0xff && m == 0xff)
{
*dst = s;
}
else
{
__m128i ms, md, ma, msa;
 
ma = expand_alpha_rev_1x128 (load_32_1x128 (m));
ms = unpack_32_1x128 (s);
md = unpack_32_1x128 (d);
 
msa = expand_alpha_rev_1x128 (load_32_1x128 (sa));
 
*dst = pack_1x128_32 (in_over_1x128 (&ms, &msa, &ma, &md));
}
}
 
dst++;
w--;
}
 
while (w >= 4)
{
xmm_mask = load_128_unaligned ((__m128i*)mask);
 
if (!is_transparent (xmm_mask))
{
xmm_src = load_128_unaligned ((__m128i*)src);
 
if (is_opaque (xmm_mask) && is_opaque (xmm_src))
{
save_128_aligned ((__m128i *)dst, xmm_src);
}
else
{
xmm_dst = load_128_aligned ((__m128i *)dst);
 
unpack_128_2x128 (xmm_src, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_mask, &xmm_mask_lo, &xmm_mask_hi);
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
 
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi, &xmm_srca_lo, &xmm_srca_hi);
expand_alpha_2x128 (xmm_mask_lo, xmm_mask_hi, &xmm_mask_lo, &xmm_mask_hi);
 
in_over_2x128 (&xmm_src_lo, &xmm_src_hi, &xmm_srca_lo, &xmm_srca_hi,
&xmm_mask_lo, &xmm_mask_hi, &xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned ((__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
}
}
 
src += 4;
dst += 4;
mask += 4;
w -= 4;
}
 
while (w)
{
uint32_t sa;
 
s = *src++;
m = (*mask++) >> 24;
d = *dst;
 
sa = s >> 24;
 
if (m)
{
if (sa == 0xff && m == 0xff)
{
*dst = s;
}
else
{
__m128i ms, md, ma, msa;
 
ma = expand_alpha_rev_1x128 (load_32_1x128 (m));
ms = unpack_32_1x128 (s);
md = unpack_32_1x128 (d);
 
msa = expand_alpha_rev_1x128 (load_32_1x128 (sa));
 
*dst = pack_1x128_32 (in_over_1x128 (&ms, &msa, &ma, &md));
}
}
 
dst++;
w--;
}
}
 
}
 
/* A variant of 'sse2_combine_over_u' with minor tweaks */
static force_inline void
scaled_nearest_scanline_sse2_8888_8888_OVER (uint32_t* pd,
const uint32_t* ps,
int32_t w,
pixman_fixed_t vx,
pixman_fixed_t unit_x,
pixman_fixed_t src_width_fixed,
pixman_bool_t fully_transparent_src)
{
uint32_t s, d;
const uint32_t* pm = NULL;
 
__m128i xmm_dst_lo, xmm_dst_hi;
__m128i xmm_src_lo, xmm_src_hi;
__m128i xmm_alpha_lo, xmm_alpha_hi;
 
if (fully_transparent_src)
return;
 
/* Align dst on a 16-byte boundary */
while (w && ((uintptr_t)pd & 15))
{
d = *pd;
s = combine1 (ps + pixman_fixed_to_int (vx), pm);
vx += unit_x;
while (vx >= 0)
vx -= src_width_fixed;
 
*pd++ = core_combine_over_u_pixel_sse2 (s, d);
if (pm)
pm++;
w--;
}
 
while (w >= 4)
{
__m128i tmp;
uint32_t tmp1, tmp2, tmp3, tmp4;
 
tmp1 = *(ps + pixman_fixed_to_int (vx));
vx += unit_x;
while (vx >= 0)
vx -= src_width_fixed;
tmp2 = *(ps + pixman_fixed_to_int (vx));
vx += unit_x;
while (vx >= 0)
vx -= src_width_fixed;
tmp3 = *(ps + pixman_fixed_to_int (vx));
vx += unit_x;
while (vx >= 0)
vx -= src_width_fixed;
tmp4 = *(ps + pixman_fixed_to_int (vx));
vx += unit_x;
while (vx >= 0)
vx -= src_width_fixed;
 
tmp = _mm_set_epi32 (tmp4, tmp3, tmp2, tmp1);
 
xmm_src_hi = combine4 ((__m128i*)&tmp, (__m128i*)pm);
 
if (is_opaque (xmm_src_hi))
{
save_128_aligned ((__m128i*)pd, xmm_src_hi);
}
else if (!is_zero (xmm_src_hi))
{
xmm_dst_hi = load_128_aligned ((__m128i*) pd);
 
unpack_128_2x128 (xmm_src_hi, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_dst_hi, &xmm_dst_lo, &xmm_dst_hi);
 
expand_alpha_2x128 (
xmm_src_lo, xmm_src_hi, &xmm_alpha_lo, &xmm_alpha_hi);
 
over_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_alpha_lo, &xmm_alpha_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
/* rebuid the 4 pixel data and save*/
save_128_aligned ((__m128i*)pd,
pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
}
 
w -= 4;
pd += 4;
if (pm)
pm += 4;
}
 
while (w)
{
d = *pd;
s = combine1 (ps + pixman_fixed_to_int (vx), pm);
vx += unit_x;
while (vx >= 0)
vx -= src_width_fixed;
 
*pd++ = core_combine_over_u_pixel_sse2 (s, d);
if (pm)
pm++;
 
w--;
}
}
 
FAST_NEAREST_MAINLOOP (sse2_8888_8888_cover_OVER,
scaled_nearest_scanline_sse2_8888_8888_OVER,
uint32_t, uint32_t, COVER)
FAST_NEAREST_MAINLOOP (sse2_8888_8888_none_OVER,
scaled_nearest_scanline_sse2_8888_8888_OVER,
uint32_t, uint32_t, NONE)
FAST_NEAREST_MAINLOOP (sse2_8888_8888_pad_OVER,
scaled_nearest_scanline_sse2_8888_8888_OVER,
uint32_t, uint32_t, PAD)
FAST_NEAREST_MAINLOOP (sse2_8888_8888_normal_OVER,
scaled_nearest_scanline_sse2_8888_8888_OVER,
uint32_t, uint32_t, NORMAL)
 
static force_inline void
scaled_nearest_scanline_sse2_8888_n_8888_OVER (const uint32_t * mask,
uint32_t * dst,
const uint32_t * src,
int32_t w,
pixman_fixed_t vx,
pixman_fixed_t unit_x,
pixman_fixed_t src_width_fixed,
pixman_bool_t zero_src)
{
__m128i xmm_mask;
__m128i xmm_src, xmm_src_lo, xmm_src_hi;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
__m128i xmm_alpha_lo, xmm_alpha_hi;
 
if (zero_src || (*mask >> 24) == 0)
return;
 
xmm_mask = create_mask_16_128 (*mask >> 24);
 
while (w && (uintptr_t)dst & 15)
{
uint32_t s = *(src + pixman_fixed_to_int (vx));
vx += unit_x;
while (vx >= 0)
vx -= src_width_fixed;
 
if (s)
{
uint32_t d = *dst;
 
__m128i ms = unpack_32_1x128 (s);
__m128i alpha = expand_alpha_1x128 (ms);
__m128i dest = xmm_mask;
__m128i alpha_dst = unpack_32_1x128 (d);
 
*dst = pack_1x128_32 (
in_over_1x128 (&ms, &alpha, &dest, &alpha_dst));
}
dst++;
w--;
}
 
while (w >= 4)
{
uint32_t tmp1, tmp2, tmp3, tmp4;
 
tmp1 = *(src + pixman_fixed_to_int (vx));
vx += unit_x;
while (vx >= 0)
vx -= src_width_fixed;
tmp2 = *(src + pixman_fixed_to_int (vx));
vx += unit_x;
while (vx >= 0)
vx -= src_width_fixed;
tmp3 = *(src + pixman_fixed_to_int (vx));
vx += unit_x;
while (vx >= 0)
vx -= src_width_fixed;
tmp4 = *(src + pixman_fixed_to_int (vx));
vx += unit_x;
while (vx >= 0)
vx -= src_width_fixed;
 
xmm_src = _mm_set_epi32 (tmp4, tmp3, tmp2, tmp1);
 
if (!is_zero (xmm_src))
{
xmm_dst = load_128_aligned ((__m128i*)dst);
 
unpack_128_2x128 (xmm_src, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_alpha_lo, &xmm_alpha_hi);
 
in_over_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_alpha_lo, &xmm_alpha_hi,
&xmm_mask, &xmm_mask,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned (
(__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
}
 
dst += 4;
w -= 4;
}
 
while (w)
{
uint32_t s = *(src + pixman_fixed_to_int (vx));
vx += unit_x;
while (vx >= 0)
vx -= src_width_fixed;
 
if (s)
{
uint32_t d = *dst;
 
__m128i ms = unpack_32_1x128 (s);
__m128i alpha = expand_alpha_1x128 (ms);
__m128i mask = xmm_mask;
__m128i dest = unpack_32_1x128 (d);
 
*dst = pack_1x128_32 (
in_over_1x128 (&ms, &alpha, &mask, &dest));
}
 
dst++;
w--;
}
 
}
 
FAST_NEAREST_MAINLOOP_COMMON (sse2_8888_n_8888_cover_OVER,
scaled_nearest_scanline_sse2_8888_n_8888_OVER,
uint32_t, uint32_t, uint32_t, COVER, TRUE, TRUE)
FAST_NEAREST_MAINLOOP_COMMON (sse2_8888_n_8888_pad_OVER,
scaled_nearest_scanline_sse2_8888_n_8888_OVER,
uint32_t, uint32_t, uint32_t, PAD, TRUE, TRUE)
FAST_NEAREST_MAINLOOP_COMMON (sse2_8888_n_8888_none_OVER,
scaled_nearest_scanline_sse2_8888_n_8888_OVER,
uint32_t, uint32_t, uint32_t, NONE, TRUE, TRUE)
FAST_NEAREST_MAINLOOP_COMMON (sse2_8888_n_8888_normal_OVER,
scaled_nearest_scanline_sse2_8888_n_8888_OVER,
uint32_t, uint32_t, uint32_t, NORMAL, TRUE, TRUE)
 
#if BILINEAR_INTERPOLATION_BITS < 8
# define BILINEAR_DECLARE_VARIABLES \
const __m128i xmm_wt = _mm_set_epi16 (wt, wt, wt, wt, wt, wt, wt, wt); \
const __m128i xmm_wb = _mm_set_epi16 (wb, wb, wb, wb, wb, wb, wb, wb); \
const __m128i xmm_addc = _mm_set_epi16 (0, 1, 0, 1, 0, 1, 0, 1); \
const __m128i xmm_ux = _mm_set_epi16 (unit_x, -unit_x, unit_x, -unit_x, \
unit_x, -unit_x, unit_x, -unit_x); \
const __m128i xmm_zero = _mm_setzero_si128 (); \
__m128i xmm_x = _mm_set_epi16 (vx, -(vx + 1), vx, -(vx + 1), \
vx, -(vx + 1), vx, -(vx + 1))
#else
# define BILINEAR_DECLARE_VARIABLES \
const __m128i xmm_wt = _mm_set_epi16 (wt, wt, wt, wt, wt, wt, wt, wt); \
const __m128i xmm_wb = _mm_set_epi16 (wb, wb, wb, wb, wb, wb, wb, wb); \
const __m128i xmm_addc = _mm_set_epi16 (0, 0, 0, 0, 1, 1, 1, 1); \
const __m128i xmm_ux = _mm_set_epi16 (unit_x, unit_x, unit_x, unit_x, \
-unit_x, -unit_x, -unit_x, -unit_x); \
const __m128i xmm_zero = _mm_setzero_si128 (); \
__m128i xmm_x = _mm_set_epi16 (vx, vx, vx, vx, \
-(vx + 1), -(vx + 1), -(vx + 1), -(vx + 1))
#endif
 
#define BILINEAR_INTERPOLATE_ONE_PIXEL(pix) \
do { \
__m128i xmm_wh, xmm_lo, xmm_hi, a; \
/* fetch 2x2 pixel block into sse2 registers */ \
__m128i tltr = _mm_loadl_epi64 ( \
(__m128i *)&src_top[pixman_fixed_to_int (vx)]); \
__m128i blbr = _mm_loadl_epi64 ( \
(__m128i *)&src_bottom[pixman_fixed_to_int (vx)]); \
vx += unit_x; \
/* vertical interpolation */ \
a = _mm_add_epi16 (_mm_mullo_epi16 (_mm_unpacklo_epi8 (tltr, xmm_zero), \
xmm_wt), \
_mm_mullo_epi16 (_mm_unpacklo_epi8 (blbr, xmm_zero), \
xmm_wb)); \
if (BILINEAR_INTERPOLATION_BITS < 8) \
{ \
/* calculate horizontal weights */ \
xmm_wh = _mm_add_epi16 (xmm_addc, _mm_srli_epi16 (xmm_x, \
16 - BILINEAR_INTERPOLATION_BITS)); \
xmm_x = _mm_add_epi16 (xmm_x, xmm_ux); \
/* horizontal interpolation */ \
a = _mm_madd_epi16 (_mm_unpackhi_epi16 (_mm_shuffle_epi32 ( \
a, _MM_SHUFFLE (1, 0, 3, 2)), a), xmm_wh); \
} \
else \
{ \
/* calculate horizontal weights */ \
xmm_wh = _mm_add_epi16 (xmm_addc, _mm_srli_epi16 (xmm_x, \
16 - BILINEAR_INTERPOLATION_BITS)); \
xmm_x = _mm_add_epi16 (xmm_x, xmm_ux); \
/* horizontal interpolation */ \
xmm_lo = _mm_mullo_epi16 (a, xmm_wh); \
xmm_hi = _mm_mulhi_epu16 (a, xmm_wh); \
a = _mm_add_epi32 (_mm_unpacklo_epi16 (xmm_lo, xmm_hi), \
_mm_unpackhi_epi16 (xmm_lo, xmm_hi)); \
} \
/* shift and pack the result */ \
a = _mm_srli_epi32 (a, BILINEAR_INTERPOLATION_BITS * 2); \
a = _mm_packs_epi32 (a, a); \
a = _mm_packus_epi16 (a, a); \
pix = _mm_cvtsi128_si32 (a); \
} while (0)
 
#define BILINEAR_SKIP_ONE_PIXEL() \
do { \
vx += unit_x; \
xmm_x = _mm_add_epi16 (xmm_x, xmm_ux); \
} while(0)
 
static force_inline void
scaled_bilinear_scanline_sse2_8888_8888_SRC (uint32_t * dst,
const uint32_t * mask,
const uint32_t * src_top,
const uint32_t * src_bottom,
int32_t w,
int wt,
int wb,
pixman_fixed_t vx,
pixman_fixed_t unit_x,
pixman_fixed_t max_vx,
pixman_bool_t zero_src)
{
BILINEAR_DECLARE_VARIABLES;
uint32_t pix1, pix2, pix3, pix4;
 
while ((w -= 4) >= 0)
{
BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
BILINEAR_INTERPOLATE_ONE_PIXEL (pix2);
BILINEAR_INTERPOLATE_ONE_PIXEL (pix3);
BILINEAR_INTERPOLATE_ONE_PIXEL (pix4);
*dst++ = pix1;
*dst++ = pix2;
*dst++ = pix3;
*dst++ = pix4;
}
 
if (w & 2)
{
BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
BILINEAR_INTERPOLATE_ONE_PIXEL (pix2);
*dst++ = pix1;
*dst++ = pix2;
}
 
if (w & 1)
{
BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
*dst = pix1;
}
 
}
 
FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_cover_SRC,
scaled_bilinear_scanline_sse2_8888_8888_SRC,
uint32_t, uint32_t, uint32_t,
COVER, FLAG_NONE)
FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_pad_SRC,
scaled_bilinear_scanline_sse2_8888_8888_SRC,
uint32_t, uint32_t, uint32_t,
PAD, FLAG_NONE)
FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_none_SRC,
scaled_bilinear_scanline_sse2_8888_8888_SRC,
uint32_t, uint32_t, uint32_t,
NONE, FLAG_NONE)
FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_normal_SRC,
scaled_bilinear_scanline_sse2_8888_8888_SRC,
uint32_t, uint32_t, uint32_t,
NORMAL, FLAG_NONE)
 
static force_inline void
scaled_bilinear_scanline_sse2_8888_8888_OVER (uint32_t * dst,
const uint32_t * mask,
const uint32_t * src_top,
const uint32_t * src_bottom,
int32_t w,
int wt,
int wb,
pixman_fixed_t vx,
pixman_fixed_t unit_x,
pixman_fixed_t max_vx,
pixman_bool_t zero_src)
{
BILINEAR_DECLARE_VARIABLES;
uint32_t pix1, pix2, pix3, pix4;
 
while (w && ((uintptr_t)dst & 15))
{
BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
 
if (pix1)
{
pix2 = *dst;
*dst = core_combine_over_u_pixel_sse2 (pix1, pix2);
}
 
w--;
dst++;
}
 
while (w >= 4)
{
__m128i xmm_src;
__m128i xmm_src_hi, xmm_src_lo, xmm_dst_hi, xmm_dst_lo;
__m128i xmm_alpha_hi, xmm_alpha_lo;
 
BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
BILINEAR_INTERPOLATE_ONE_PIXEL (pix2);
BILINEAR_INTERPOLATE_ONE_PIXEL (pix3);
BILINEAR_INTERPOLATE_ONE_PIXEL (pix4);
 
xmm_src = _mm_set_epi32 (pix4, pix3, pix2, pix1);
 
if (!is_zero (xmm_src))
{
if (is_opaque (xmm_src))
{
save_128_aligned ((__m128i *)dst, xmm_src);
}
else
{
__m128i xmm_dst = load_128_aligned ((__m128i *)dst);
 
unpack_128_2x128 (xmm_src, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
 
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi, &xmm_alpha_lo, &xmm_alpha_hi);
over_2x128 (&xmm_src_lo, &xmm_src_hi, &xmm_alpha_lo, &xmm_alpha_hi,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned ((__m128i *)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
}
}
 
w -= 4;
dst += 4;
}
 
while (w)
{
BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
 
if (pix1)
{
pix2 = *dst;
*dst = core_combine_over_u_pixel_sse2 (pix1, pix2);
}
 
w--;
dst++;
}
}
 
FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_cover_OVER,
scaled_bilinear_scanline_sse2_8888_8888_OVER,
uint32_t, uint32_t, uint32_t,
COVER, FLAG_NONE)
FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_pad_OVER,
scaled_bilinear_scanline_sse2_8888_8888_OVER,
uint32_t, uint32_t, uint32_t,
PAD, FLAG_NONE)
FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_none_OVER,
scaled_bilinear_scanline_sse2_8888_8888_OVER,
uint32_t, uint32_t, uint32_t,
NONE, FLAG_NONE)
FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_normal_OVER,
scaled_bilinear_scanline_sse2_8888_8888_OVER,
uint32_t, uint32_t, uint32_t,
NORMAL, FLAG_NONE)
 
static force_inline void
scaled_bilinear_scanline_sse2_8888_8_8888_OVER (uint32_t * dst,
const uint8_t * mask,
const uint32_t * src_top,
const uint32_t * src_bottom,
int32_t w,
int wt,
int wb,
pixman_fixed_t vx,
pixman_fixed_t unit_x,
pixman_fixed_t max_vx,
pixman_bool_t zero_src)
{
BILINEAR_DECLARE_VARIABLES;
uint32_t pix1, pix2, pix3, pix4;
uint32_t m;
 
while (w && ((uintptr_t)dst & 15))
{
uint32_t sa;
 
m = (uint32_t) *mask++;
 
if (m)
{
BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
sa = pix1 >> 24;
 
if (sa == 0xff && m == 0xff)
{
*dst = pix1;
}
else
{
__m128i ms, md, ma, msa;
 
pix2 = *dst;
ma = expand_alpha_rev_1x128 (load_32_1x128 (m));
ms = unpack_32_1x128 (pix1);
md = unpack_32_1x128 (pix2);
 
msa = expand_alpha_rev_1x128 (load_32_1x128 (sa));
 
*dst = pack_1x128_32 (in_over_1x128 (&ms, &msa, &ma, &md));
}
}
else
{
BILINEAR_SKIP_ONE_PIXEL ();
}
 
w--;
dst++;
}
 
while (w >= 4)
{
__m128i xmm_src, xmm_src_lo, xmm_src_hi, xmm_srca_lo, xmm_srca_hi;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
__m128i xmm_mask, xmm_mask_lo, xmm_mask_hi;
 
m = *(uint32_t*)mask;
 
if (m)
{
BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
BILINEAR_INTERPOLATE_ONE_PIXEL (pix2);
BILINEAR_INTERPOLATE_ONE_PIXEL (pix3);
BILINEAR_INTERPOLATE_ONE_PIXEL (pix4);
 
xmm_src = _mm_set_epi32 (pix4, pix3, pix2, pix1);
 
if (m == 0xffffffff && is_opaque (xmm_src))
{
save_128_aligned ((__m128i *)dst, xmm_src);
}
else
{
xmm_dst = load_128_aligned ((__m128i *)dst);
 
xmm_mask = _mm_unpacklo_epi16 (unpack_32_1x128 (m), _mm_setzero_si128());
 
unpack_128_2x128 (xmm_src, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_mask, &xmm_mask_lo, &xmm_mask_hi);
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
 
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi, &xmm_srca_lo, &xmm_srca_hi);
expand_alpha_rev_2x128 (xmm_mask_lo, xmm_mask_hi, &xmm_mask_lo, &xmm_mask_hi);
 
in_over_2x128 (&xmm_src_lo, &xmm_src_hi, &xmm_srca_lo, &xmm_srca_hi,
&xmm_mask_lo, &xmm_mask_hi, &xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned ((__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
}
}
else
{
BILINEAR_SKIP_ONE_PIXEL ();
BILINEAR_SKIP_ONE_PIXEL ();
BILINEAR_SKIP_ONE_PIXEL ();
BILINEAR_SKIP_ONE_PIXEL ();
}
 
w -= 4;
dst += 4;
mask += 4;
}
 
while (w)
{
uint32_t sa;
 
m = (uint32_t) *mask++;
 
if (m)
{
BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
sa = pix1 >> 24;
 
if (sa == 0xff && m == 0xff)
{
*dst = pix1;
}
else
{
__m128i ms, md, ma, msa;
 
pix2 = *dst;
ma = expand_alpha_rev_1x128 (load_32_1x128 (m));
ms = unpack_32_1x128 (pix1);
md = unpack_32_1x128 (pix2);
 
msa = expand_alpha_rev_1x128 (load_32_1x128 (sa));
 
*dst = pack_1x128_32 (in_over_1x128 (&ms, &msa, &ma, &md));
}
}
else
{
BILINEAR_SKIP_ONE_PIXEL ();
}
 
w--;
dst++;
}
}
 
FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8_8888_cover_OVER,
scaled_bilinear_scanline_sse2_8888_8_8888_OVER,
uint32_t, uint8_t, uint32_t,
COVER, FLAG_HAVE_NON_SOLID_MASK)
FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8_8888_pad_OVER,
scaled_bilinear_scanline_sse2_8888_8_8888_OVER,
uint32_t, uint8_t, uint32_t,
PAD, FLAG_HAVE_NON_SOLID_MASK)
FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8_8888_none_OVER,
scaled_bilinear_scanline_sse2_8888_8_8888_OVER,
uint32_t, uint8_t, uint32_t,
NONE, FLAG_HAVE_NON_SOLID_MASK)
FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8_8888_normal_OVER,
scaled_bilinear_scanline_sse2_8888_8_8888_OVER,
uint32_t, uint8_t, uint32_t,
NORMAL, FLAG_HAVE_NON_SOLID_MASK)
 
static force_inline void
scaled_bilinear_scanline_sse2_8888_n_8888_OVER (uint32_t * dst,
const uint32_t * mask,
const uint32_t * src_top,
const uint32_t * src_bottom,
int32_t w,
int wt,
int wb,
pixman_fixed_t vx,
pixman_fixed_t unit_x,
pixman_fixed_t max_vx,
pixman_bool_t zero_src)
{
BILINEAR_DECLARE_VARIABLES;
uint32_t pix1, pix2, pix3, pix4;
__m128i xmm_mask;
 
if (zero_src || (*mask >> 24) == 0)
return;
 
xmm_mask = create_mask_16_128 (*mask >> 24);
 
while (w && ((uintptr_t)dst & 15))
{
BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
if (pix1)
{
uint32_t d = *dst;
 
__m128i ms = unpack_32_1x128 (pix1);
__m128i alpha = expand_alpha_1x128 (ms);
__m128i dest = xmm_mask;
__m128i alpha_dst = unpack_32_1x128 (d);
 
*dst = pack_1x128_32
(in_over_1x128 (&ms, &alpha, &dest, &alpha_dst));
}
 
dst++;
w--;
}
 
while (w >= 4)
{
BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
BILINEAR_INTERPOLATE_ONE_PIXEL (pix2);
BILINEAR_INTERPOLATE_ONE_PIXEL (pix3);
BILINEAR_INTERPOLATE_ONE_PIXEL (pix4);
 
if (pix1 | pix2 | pix3 | pix4)
{
__m128i xmm_src, xmm_src_lo, xmm_src_hi;
__m128i xmm_dst, xmm_dst_lo, xmm_dst_hi;
__m128i xmm_alpha_lo, xmm_alpha_hi;
 
xmm_src = _mm_set_epi32 (pix4, pix3, pix2, pix1);
 
xmm_dst = load_128_aligned ((__m128i*)dst);
 
unpack_128_2x128 (xmm_src, &xmm_src_lo, &xmm_src_hi);
unpack_128_2x128 (xmm_dst, &xmm_dst_lo, &xmm_dst_hi);
expand_alpha_2x128 (xmm_src_lo, xmm_src_hi,
&xmm_alpha_lo, &xmm_alpha_hi);
 
in_over_2x128 (&xmm_src_lo, &xmm_src_hi,
&xmm_alpha_lo, &xmm_alpha_hi,
&xmm_mask, &xmm_mask,
&xmm_dst_lo, &xmm_dst_hi);
 
save_128_aligned
((__m128i*)dst, pack_2x128_128 (xmm_dst_lo, xmm_dst_hi));
}
 
dst += 4;
w -= 4;
}
 
while (w)
{
BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
if (pix1)
{
uint32_t d = *dst;
 
__m128i ms = unpack_32_1x128 (pix1);
__m128i alpha = expand_alpha_1x128 (ms);
__m128i dest = xmm_mask;
__m128i alpha_dst = unpack_32_1x128 (d);
 
*dst = pack_1x128_32
(in_over_1x128 (&ms, &alpha, &dest, &alpha_dst));
}
 
dst++;
w--;
}
}
 
FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_n_8888_cover_OVER,
scaled_bilinear_scanline_sse2_8888_n_8888_OVER,
uint32_t, uint32_t, uint32_t,
COVER, FLAG_HAVE_SOLID_MASK)
FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_n_8888_pad_OVER,
scaled_bilinear_scanline_sse2_8888_n_8888_OVER,
uint32_t, uint32_t, uint32_t,
PAD, FLAG_HAVE_SOLID_MASK)
FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_n_8888_none_OVER,
scaled_bilinear_scanline_sse2_8888_n_8888_OVER,
uint32_t, uint32_t, uint32_t,
NONE, FLAG_HAVE_SOLID_MASK)
FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_n_8888_normal_OVER,
scaled_bilinear_scanline_sse2_8888_n_8888_OVER,
uint32_t, uint32_t, uint32_t,
NORMAL, FLAG_HAVE_SOLID_MASK)
 
static const pixman_fast_path_t sse2_fast_paths[] =
{
/* PIXMAN_OP_OVER */
PIXMAN_STD_FAST_PATH (OVER, solid, a8, r5g6b5, sse2_composite_over_n_8_0565),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, b5g6r5, sse2_composite_over_n_8_0565),
PIXMAN_STD_FAST_PATH (OVER, solid, null, a8r8g8b8, sse2_composite_over_n_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, null, x8r8g8b8, sse2_composite_over_n_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, null, r5g6b5, sse2_composite_over_n_0565),
PIXMAN_STD_FAST_PATH (OVER, solid, null, b5g6r5, sse2_composite_over_n_0565),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, a8r8g8b8, sse2_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, x8r8g8b8, sse2_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, a8b8g8r8, sse2_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, x8b8g8r8, sse2_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, r5g6b5, sse2_composite_over_8888_0565),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, b5g6r5, sse2_composite_over_8888_0565),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8r8g8b8, sse2_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8r8g8b8, sse2_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8b8g8r8, sse2_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8b8g8r8, sse2_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, a8r8g8b8, sse2_composite_over_8888_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, a8, x8r8g8b8, sse2_composite_over_8888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, a8, a8r8g8b8, sse2_composite_over_8888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, a8, x8b8g8r8, sse2_composite_over_8888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, a8, a8b8g8r8, sse2_composite_over_8888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, x8r8g8b8, a8, x8r8g8b8, sse2_composite_over_x888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, x8r8g8b8, a8, a8r8g8b8, sse2_composite_over_x888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, x8b8g8r8, a8, x8b8g8r8, sse2_composite_over_x888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, x8b8g8r8, a8, a8b8g8r8, sse2_composite_over_x888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, x8r8g8b8, solid, a8r8g8b8, sse2_composite_over_x888_n_8888),
PIXMAN_STD_FAST_PATH (OVER, x8r8g8b8, solid, x8r8g8b8, sse2_composite_over_x888_n_8888),
PIXMAN_STD_FAST_PATH (OVER, x8b8g8r8, solid, a8b8g8r8, sse2_composite_over_x888_n_8888),
PIXMAN_STD_FAST_PATH (OVER, x8b8g8r8, solid, x8b8g8r8, sse2_composite_over_x888_n_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, solid, a8r8g8b8, sse2_composite_over_8888_n_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, solid, x8r8g8b8, sse2_composite_over_8888_n_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, solid, a8b8g8r8, sse2_composite_over_8888_n_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, solid, x8b8g8r8, sse2_composite_over_8888_n_8888),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, a8r8g8b8, sse2_composite_over_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, x8r8g8b8, sse2_composite_over_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, a8b8g8r8, sse2_composite_over_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, x8b8g8r8, sse2_composite_over_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, r5g6b5, sse2_composite_over_n_8888_0565_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, b5g6r5, sse2_composite_over_n_8888_0565_ca),
PIXMAN_STD_FAST_PATH (OVER, pixbuf, pixbuf, a8r8g8b8, sse2_composite_over_pixbuf_8888),
PIXMAN_STD_FAST_PATH (OVER, pixbuf, pixbuf, x8r8g8b8, sse2_composite_over_pixbuf_8888),
PIXMAN_STD_FAST_PATH (OVER, rpixbuf, rpixbuf, a8b8g8r8, sse2_composite_over_pixbuf_8888),
PIXMAN_STD_FAST_PATH (OVER, rpixbuf, rpixbuf, x8b8g8r8, sse2_composite_over_pixbuf_8888),
PIXMAN_STD_FAST_PATH (OVER, pixbuf, pixbuf, r5g6b5, sse2_composite_over_pixbuf_0565),
PIXMAN_STD_FAST_PATH (OVER, rpixbuf, rpixbuf, b5g6r5, sse2_composite_over_pixbuf_0565),
PIXMAN_STD_FAST_PATH (OVER, x8r8g8b8, null, x8r8g8b8, sse2_composite_copy_area),
PIXMAN_STD_FAST_PATH (OVER, x8b8g8r8, null, x8b8g8r8, sse2_composite_copy_area),
/* PIXMAN_OP_OVER_REVERSE */
PIXMAN_STD_FAST_PATH (OVER_REVERSE, solid, null, a8r8g8b8, sse2_composite_over_reverse_n_8888),
PIXMAN_STD_FAST_PATH (OVER_REVERSE, solid, null, a8b8g8r8, sse2_composite_over_reverse_n_8888),
 
/* PIXMAN_OP_ADD */
PIXMAN_STD_FAST_PATH_CA (ADD, solid, a8r8g8b8, a8r8g8b8, sse2_composite_add_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH (ADD, a8, null, a8, sse2_composite_add_8_8),
PIXMAN_STD_FAST_PATH (ADD, a8r8g8b8, null, a8r8g8b8, sse2_composite_add_8888_8888),
PIXMAN_STD_FAST_PATH (ADD, a8b8g8r8, null, a8b8g8r8, sse2_composite_add_8888_8888),
PIXMAN_STD_FAST_PATH (ADD, solid, a8, a8, sse2_composite_add_n_8_8),
PIXMAN_STD_FAST_PATH (ADD, solid, null, a8, sse2_composite_add_n_8),
PIXMAN_STD_FAST_PATH (ADD, solid, null, x8r8g8b8, sse2_composite_add_n_8888),
PIXMAN_STD_FAST_PATH (ADD, solid, null, a8r8g8b8, sse2_composite_add_n_8888),
PIXMAN_STD_FAST_PATH (ADD, solid, null, x8b8g8r8, sse2_composite_add_n_8888),
PIXMAN_STD_FAST_PATH (ADD, solid, null, a8b8g8r8, sse2_composite_add_n_8888),
PIXMAN_STD_FAST_PATH (ADD, solid, a8, x8r8g8b8, sse2_composite_add_n_8_8888),
PIXMAN_STD_FAST_PATH (ADD, solid, a8, a8r8g8b8, sse2_composite_add_n_8_8888),
PIXMAN_STD_FAST_PATH (ADD, solid, a8, x8b8g8r8, sse2_composite_add_n_8_8888),
PIXMAN_STD_FAST_PATH (ADD, solid, a8, a8b8g8r8, sse2_composite_add_n_8_8888),
 
/* PIXMAN_OP_SRC */
PIXMAN_STD_FAST_PATH (SRC, solid, a8, a8r8g8b8, sse2_composite_src_n_8_8888),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, x8r8g8b8, sse2_composite_src_n_8_8888),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, a8b8g8r8, sse2_composite_src_n_8_8888),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, x8b8g8r8, sse2_composite_src_n_8_8888),
PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, r5g6b5, sse2_composite_src_x888_0565),
PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, b5g6r5, sse2_composite_src_x888_0565),
PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, r5g6b5, sse2_composite_src_x888_0565),
PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, b5g6r5, sse2_composite_src_x888_0565),
PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, a8r8g8b8, sse2_composite_src_x888_8888),
PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, a8b8g8r8, sse2_composite_src_x888_8888),
PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, a8r8g8b8, sse2_composite_copy_area),
PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, a8b8g8r8, sse2_composite_copy_area),
PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, x8r8g8b8, sse2_composite_copy_area),
PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, x8b8g8r8, sse2_composite_copy_area),
PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, x8r8g8b8, sse2_composite_copy_area),
PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, x8b8g8r8, sse2_composite_copy_area),
PIXMAN_STD_FAST_PATH (SRC, r5g6b5, null, r5g6b5, sse2_composite_copy_area),
PIXMAN_STD_FAST_PATH (SRC, b5g6r5, null, b5g6r5, sse2_composite_copy_area),
 
/* PIXMAN_OP_IN */
PIXMAN_STD_FAST_PATH (IN, a8, null, a8, sse2_composite_in_8_8),
PIXMAN_STD_FAST_PATH (IN, solid, a8, a8, sse2_composite_in_n_8_8),
PIXMAN_STD_FAST_PATH (IN, solid, null, a8, sse2_composite_in_n_8),
 
SIMPLE_NEAREST_FAST_PATH_COVER (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_8888),
SIMPLE_NEAREST_FAST_PATH_COVER (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_8888),
SIMPLE_NEAREST_FAST_PATH_COVER (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_8888),
SIMPLE_NEAREST_FAST_PATH_COVER (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_8888),
SIMPLE_NEAREST_FAST_PATH_NONE (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_8888),
SIMPLE_NEAREST_FAST_PATH_NONE (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_8888),
SIMPLE_NEAREST_FAST_PATH_NONE (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_8888),
SIMPLE_NEAREST_FAST_PATH_NONE (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_8888),
SIMPLE_NEAREST_FAST_PATH_PAD (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_8888),
SIMPLE_NEAREST_FAST_PATH_PAD (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_8888),
SIMPLE_NEAREST_FAST_PATH_PAD (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_8888),
SIMPLE_NEAREST_FAST_PATH_PAD (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_8888),
SIMPLE_NEAREST_FAST_PATH_NORMAL (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_8888),
SIMPLE_NEAREST_FAST_PATH_NORMAL (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_8888),
SIMPLE_NEAREST_FAST_PATH_NORMAL (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_8888),
SIMPLE_NEAREST_FAST_PATH_NORMAL (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_8888),
 
SIMPLE_NEAREST_SOLID_MASK_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_n_8888),
SIMPLE_NEAREST_SOLID_MASK_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_n_8888),
SIMPLE_NEAREST_SOLID_MASK_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_n_8888),
SIMPLE_NEAREST_SOLID_MASK_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_n_8888),
SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NORMAL (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_n_8888),
SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NORMAL (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_n_8888),
SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NORMAL (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_n_8888),
SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NORMAL (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_n_8888),
 
SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8, sse2_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, sse2_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8, sse2_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (SRC, a8b8g8r8, a8b8g8r8, sse2_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (SRC, a8b8g8r8, x8b8g8r8, sse2_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (SRC, x8b8g8r8, x8b8g8r8, sse2_8888_8888),
 
SIMPLE_BILINEAR_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_8888),
 
SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_n_8888),
SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_n_8888),
SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_n_8888),
SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_n_8888),
 
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_8_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_8_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_8_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_8_8888),
 
{ PIXMAN_OP_NONE },
};
 
static uint32_t *
sse2_fetch_x8r8g8b8 (pixman_iter_t *iter, const uint32_t *mask)
{
int w = iter->width;
__m128i ff000000 = mask_ff000000;
uint32_t *dst = iter->buffer;
uint32_t *src = (uint32_t *)iter->bits;
 
iter->bits += iter->stride;
 
while (w && ((uintptr_t)dst) & 0x0f)
{
*dst++ = (*src++) | 0xff000000;
w--;
}
 
while (w >= 4)
{
save_128_aligned (
(__m128i *)dst, _mm_or_si128 (
load_128_unaligned ((__m128i *)src), ff000000));
 
dst += 4;
src += 4;
w -= 4;
}
 
while (w)
{
*dst++ = (*src++) | 0xff000000;
w--;
}
 
return iter->buffer;
}
 
static uint32_t *
sse2_fetch_r5g6b5 (pixman_iter_t *iter, const uint32_t *mask)
{
int w = iter->width;
uint32_t *dst = iter->buffer;
uint16_t *src = (uint16_t *)iter->bits;
__m128i ff000000 = mask_ff000000;
 
iter->bits += iter->stride;
 
while (w && ((uintptr_t)dst) & 0x0f)
{
uint16_t s = *src++;
 
*dst++ = convert_0565_to_8888 (s);
w--;
}
 
while (w >= 8)
{
__m128i lo, hi, s;
 
s = _mm_loadu_si128 ((__m128i *)src);
 
lo = unpack_565_to_8888 (_mm_unpacklo_epi16 (s, _mm_setzero_si128 ()));
hi = unpack_565_to_8888 (_mm_unpackhi_epi16 (s, _mm_setzero_si128 ()));
 
save_128_aligned ((__m128i *)(dst + 0), _mm_or_si128 (lo, ff000000));
save_128_aligned ((__m128i *)(dst + 4), _mm_or_si128 (hi, ff000000));
 
dst += 8;
src += 8;
w -= 8;
}
 
while (w)
{
uint16_t s = *src++;
 
*dst++ = convert_0565_to_8888 (s);
w--;
}
 
return iter->buffer;
}
 
static uint32_t *
sse2_fetch_a8 (pixman_iter_t *iter, const uint32_t *mask)
{
int w = iter->width;
uint32_t *dst = iter->buffer;
uint8_t *src = iter->bits;
__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6;
 
iter->bits += iter->stride;
 
while (w && (((uintptr_t)dst) & 15))
{
*dst++ = *(src++) << 24;
w--;
}
 
while (w >= 16)
{
xmm0 = _mm_loadu_si128((__m128i *)src);
 
xmm1 = _mm_unpacklo_epi8 (_mm_setzero_si128(), xmm0);
xmm2 = _mm_unpackhi_epi8 (_mm_setzero_si128(), xmm0);
xmm3 = _mm_unpacklo_epi16 (_mm_setzero_si128(), xmm1);
xmm4 = _mm_unpackhi_epi16 (_mm_setzero_si128(), xmm1);
xmm5 = _mm_unpacklo_epi16 (_mm_setzero_si128(), xmm2);
xmm6 = _mm_unpackhi_epi16 (_mm_setzero_si128(), xmm2);
 
_mm_store_si128(((__m128i *)(dst + 0)), xmm3);
_mm_store_si128(((__m128i *)(dst + 4)), xmm4);
_mm_store_si128(((__m128i *)(dst + 8)), xmm5);
_mm_store_si128(((__m128i *)(dst + 12)), xmm6);
 
dst += 16;
src += 16;
w -= 16;
}
 
while (w)
{
*dst++ = *(src++) << 24;
w--;
}
 
return iter->buffer;
}
 
typedef struct
{
pixman_format_code_t format;
pixman_iter_get_scanline_t get_scanline;
} fetcher_info_t;
 
static const fetcher_info_t fetchers[] =
{
{ PIXMAN_x8r8g8b8, sse2_fetch_x8r8g8b8 },
{ PIXMAN_r5g6b5, sse2_fetch_r5g6b5 },
{ PIXMAN_a8, sse2_fetch_a8 },
{ PIXMAN_null }
};
 
static pixman_bool_t
sse2_src_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter)
{
pixman_image_t *image = iter->image;
 
#define FLAGS \
(FAST_PATH_STANDARD_FLAGS | FAST_PATH_ID_TRANSFORM | \
FAST_PATH_BITS_IMAGE | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST)
 
if ((iter->iter_flags & ITER_NARROW) &&
(iter->image_flags & FLAGS) == FLAGS)
{
const fetcher_info_t *f;
 
for (f = &fetchers[0]; f->format != PIXMAN_null; f++)
{
if (image->common.extended_format_code == f->format)
{
uint8_t *b = (uint8_t *)image->bits.bits;
int s = image->bits.rowstride * 4;
 
iter->bits = b + s * iter->y + iter->x * PIXMAN_FORMAT_BPP (f->format) / 8;
iter->stride = s;
 
iter->get_scanline = f->get_scanline;
return TRUE;
}
}
}
 
return FALSE;
}
 
#if defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
__attribute__((__force_align_arg_pointer__))
#endif
pixman_implementation_t *
_pixman_implementation_create_sse2 (pixman_implementation_t *fallback)
{
pixman_implementation_t *imp = _pixman_implementation_create (fallback, sse2_fast_paths);
 
/* SSE2 constants */
mask_565_r = create_mask_2x32_128 (0x00f80000, 0x00f80000);
mask_565_g1 = create_mask_2x32_128 (0x00070000, 0x00070000);
mask_565_g2 = create_mask_2x32_128 (0x000000e0, 0x000000e0);
mask_565_b = create_mask_2x32_128 (0x0000001f, 0x0000001f);
mask_red = create_mask_2x32_128 (0x00f80000, 0x00f80000);
mask_green = create_mask_2x32_128 (0x0000fc00, 0x0000fc00);
mask_blue = create_mask_2x32_128 (0x000000f8, 0x000000f8);
mask_565_fix_rb = create_mask_2x32_128 (0x00e000e0, 0x00e000e0);
mask_565_fix_g = create_mask_2x32_128 (0x0000c000, 0x0000c000);
mask_0080 = create_mask_16_128 (0x0080);
mask_00ff = create_mask_16_128 (0x00ff);
mask_0101 = create_mask_16_128 (0x0101);
mask_ffff = create_mask_16_128 (0xffff);
mask_ff000000 = create_mask_2x32_128 (0xff000000, 0xff000000);
mask_alpha = create_mask_2x32_128 (0x00ff0000, 0x00000000);
mask_565_rb = create_mask_2x32_128 (0x00f800f8, 0x00f800f8);
mask_565_pack_multiplier = create_mask_2x32_128 (0x20000004, 0x20000004);
 
/* Set up function pointers */
imp->combine_32[PIXMAN_OP_OVER] = sse2_combine_over_u;
imp->combine_32[PIXMAN_OP_OVER_REVERSE] = sse2_combine_over_reverse_u;
imp->combine_32[PIXMAN_OP_IN] = sse2_combine_in_u;
imp->combine_32[PIXMAN_OP_IN_REVERSE] = sse2_combine_in_reverse_u;
imp->combine_32[PIXMAN_OP_OUT] = sse2_combine_out_u;
imp->combine_32[PIXMAN_OP_OUT_REVERSE] = sse2_combine_out_reverse_u;
imp->combine_32[PIXMAN_OP_ATOP] = sse2_combine_atop_u;
imp->combine_32[PIXMAN_OP_ATOP_REVERSE] = sse2_combine_atop_reverse_u;
imp->combine_32[PIXMAN_OP_XOR] = sse2_combine_xor_u;
imp->combine_32[PIXMAN_OP_ADD] = sse2_combine_add_u;
 
imp->combine_32[PIXMAN_OP_SATURATE] = sse2_combine_saturate_u;
 
imp->combine_32_ca[PIXMAN_OP_SRC] = sse2_combine_src_ca;
imp->combine_32_ca[PIXMAN_OP_OVER] = sse2_combine_over_ca;
imp->combine_32_ca[PIXMAN_OP_OVER_REVERSE] = sse2_combine_over_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_IN] = sse2_combine_in_ca;
imp->combine_32_ca[PIXMAN_OP_IN_REVERSE] = sse2_combine_in_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_OUT] = sse2_combine_out_ca;
imp->combine_32_ca[PIXMAN_OP_OUT_REVERSE] = sse2_combine_out_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_ATOP] = sse2_combine_atop_ca;
imp->combine_32_ca[PIXMAN_OP_ATOP_REVERSE] = sse2_combine_atop_reverse_ca;
imp->combine_32_ca[PIXMAN_OP_XOR] = sse2_combine_xor_ca;
imp->combine_32_ca[PIXMAN_OP_ADD] = sse2_combine_add_ca;
 
imp->blt = sse2_blt;
imp->fill = sse2_fill;
 
imp->src_iter_init = sse2_src_iter_init;
 
return imp;
}
/contrib/sdk/sources/pixman/pixman-timer.c
0,0 → 1,66
/*
* Copyright © 2007 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Red Hat not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. Red Hat makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
* 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_CONFIG_H
#include <config.h>
#endif
 
#include <stdlib.h>
#include <stdio.h>
#include "pixman-private.h"
 
#ifdef PIXMAN_TIMERS
 
static pixman_timer_t *timers;
 
static void
dump_timers (void)
{
pixman_timer_t *timer;
 
for (timer = timers; timer != NULL; timer = timer->next)
{
printf ("%s: total: %llu n: %llu avg: %f\n",
timer->name,
timer->total,
timer->n_times,
timer->total / (double)timer->n_times);
}
}
 
void
pixman_timer_register (pixman_timer_t *timer)
{
static int initialized;
 
int atexit (void (*function)(void));
 
if (!initialized)
{
atexit (dump_timers);
initialized = 1;
}
 
timer->next = timers;
timers = timer;
}
 
#endif
/contrib/sdk/sources/pixman/pixman-trap.c
0,0 → 1,711
/*
* Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
* Copyright © 2004 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
 
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
 
#include <stdio.h>
#include <stdlib.h>
#include "pixman-private.h"
 
/*
* Compute the smallest value greater than or equal to y which is on a
* grid row.
*/
 
PIXMAN_EXPORT pixman_fixed_t
pixman_sample_ceil_y (pixman_fixed_t y, int n)
{
pixman_fixed_t f = pixman_fixed_frac (y);
pixman_fixed_t i = pixman_fixed_floor (y);
 
f = DIV (f - Y_FRAC_FIRST (n) + (STEP_Y_SMALL (n) - pixman_fixed_e), STEP_Y_SMALL (n)) * STEP_Y_SMALL (n) +
Y_FRAC_FIRST (n);
if (f > Y_FRAC_LAST (n))
{
if (pixman_fixed_to_int (i) == 0x7fff)
{
f = 0xffff; /* saturate */
}
else
{
f = Y_FRAC_FIRST (n);
i += pixman_fixed_1;
}
}
return (i | f);
}
 
/*
* Compute the largest value strictly less than y which is on a
* grid row.
*/
PIXMAN_EXPORT pixman_fixed_t
pixman_sample_floor_y (pixman_fixed_t y,
int n)
{
pixman_fixed_t f = pixman_fixed_frac (y);
pixman_fixed_t i = pixman_fixed_floor (y);
 
f = DIV (f - pixman_fixed_e - Y_FRAC_FIRST (n), STEP_Y_SMALL (n)) * STEP_Y_SMALL (n) +
Y_FRAC_FIRST (n);
 
if (f < Y_FRAC_FIRST (n))
{
if (pixman_fixed_to_int (i) == 0x8000)
{
f = 0; /* saturate */
}
else
{
f = Y_FRAC_LAST (n);
i -= pixman_fixed_1;
}
}
return (i | f);
}
 
/*
* Step an edge by any amount (including negative values)
*/
PIXMAN_EXPORT void
pixman_edge_step (pixman_edge_t *e,
int n)
{
pixman_fixed_48_16_t ne;
 
e->x += n * e->stepx;
 
ne = e->e + n * (pixman_fixed_48_16_t) e->dx;
 
if (n >= 0)
{
if (ne > 0)
{
int nx = (ne + e->dy - 1) / e->dy;
e->e = ne - nx * (pixman_fixed_48_16_t) e->dy;
e->x += nx * e->signdx;
}
}
else
{
if (ne <= -e->dy)
{
int nx = (-ne) / e->dy;
e->e = ne + nx * (pixman_fixed_48_16_t) e->dy;
e->x -= nx * e->signdx;
}
}
}
 
/*
* A private routine to initialize the multi-step
* elements of an edge structure
*/
static void
_pixman_edge_multi_init (pixman_edge_t * e,
int n,
pixman_fixed_t *stepx_p,
pixman_fixed_t *dx_p)
{
pixman_fixed_t stepx;
pixman_fixed_48_16_t ne;
 
ne = n * (pixman_fixed_48_16_t) e->dx;
stepx = n * e->stepx;
 
if (ne > 0)
{
int nx = ne / e->dy;
ne -= nx * (pixman_fixed_48_16_t)e->dy;
stepx += nx * e->signdx;
}
 
*dx_p = ne;
*stepx_p = stepx;
}
 
/*
* Initialize one edge structure given the line endpoints and a
* starting y value
*/
PIXMAN_EXPORT void
pixman_edge_init (pixman_edge_t *e,
int n,
pixman_fixed_t y_start,
pixman_fixed_t x_top,
pixman_fixed_t y_top,
pixman_fixed_t x_bot,
pixman_fixed_t y_bot)
{
pixman_fixed_t dx, dy;
 
e->x = x_top;
e->e = 0;
dx = x_bot - x_top;
dy = y_bot - y_top;
e->dy = dy;
e->dx = 0;
 
if (dy)
{
if (dx >= 0)
{
e->signdx = 1;
e->stepx = dx / dy;
e->dx = dx % dy;
e->e = -dy;
}
else
{
e->signdx = -1;
e->stepx = -(-dx / dy);
e->dx = -dx % dy;
e->e = 0;
}
 
_pixman_edge_multi_init (e, STEP_Y_SMALL (n),
&e->stepx_small, &e->dx_small);
 
_pixman_edge_multi_init (e, STEP_Y_BIG (n),
&e->stepx_big, &e->dx_big);
}
pixman_edge_step (e, y_start - y_top);
}
 
/*
* Initialize one edge structure given a line, starting y value
* and a pixel offset for the line
*/
PIXMAN_EXPORT void
pixman_line_fixed_edge_init (pixman_edge_t * e,
int n,
pixman_fixed_t y,
const pixman_line_fixed_t *line,
int x_off,
int y_off)
{
pixman_fixed_t x_off_fixed = pixman_int_to_fixed (x_off);
pixman_fixed_t y_off_fixed = pixman_int_to_fixed (y_off);
const pixman_point_fixed_t *top, *bot;
 
if (line->p1.y <= line->p2.y)
{
top = &line->p1;
bot = &line->p2;
}
else
{
top = &line->p2;
bot = &line->p1;
}
pixman_edge_init (e, n, y,
top->x + x_off_fixed,
top->y + y_off_fixed,
bot->x + x_off_fixed,
bot->y + y_off_fixed);
}
 
PIXMAN_EXPORT void
pixman_add_traps (pixman_image_t * image,
int16_t x_off,
int16_t y_off,
int ntrap,
const pixman_trap_t *traps)
{
int bpp;
int height;
 
pixman_fixed_t x_off_fixed;
pixman_fixed_t y_off_fixed;
pixman_edge_t l, r;
pixman_fixed_t t, b;
 
_pixman_image_validate (image);
height = image->bits.height;
bpp = PIXMAN_FORMAT_BPP (image->bits.format);
 
x_off_fixed = pixman_int_to_fixed (x_off);
y_off_fixed = pixman_int_to_fixed (y_off);
 
while (ntrap--)
{
t = traps->top.y + y_off_fixed;
if (t < 0)
t = 0;
t = pixman_sample_ceil_y (t, bpp);
 
b = traps->bot.y + y_off_fixed;
if (pixman_fixed_to_int (b) >= height)
b = pixman_int_to_fixed (height) - 1;
b = pixman_sample_floor_y (b, bpp);
 
if (b >= t)
{
/* initialize edge walkers */
pixman_edge_init (&l, bpp, t,
traps->top.l + x_off_fixed,
traps->top.y + y_off_fixed,
traps->bot.l + x_off_fixed,
traps->bot.y + y_off_fixed);
 
pixman_edge_init (&r, bpp, t,
traps->top.r + x_off_fixed,
traps->top.y + y_off_fixed,
traps->bot.r + x_off_fixed,
traps->bot.y + y_off_fixed);
 
pixman_rasterize_edges (image, &l, &r, t, b);
}
 
traps++;
}
}
 
#if 0
static void
dump_image (pixman_image_t *image,
const char * title)
{
int i, j;
 
if (!image->type == BITS)
printf ("%s is not a regular image\n", title);
 
if (!image->bits.format == PIXMAN_a8)
printf ("%s is not an alpha mask\n", title);
 
printf ("\n\n\n%s: \n", title);
 
for (i = 0; i < image->bits.height; ++i)
{
uint8_t *line =
(uint8_t *)&(image->bits.bits[i * image->bits.rowstride]);
 
for (j = 0; j < image->bits.width; ++j)
printf ("%c", line[j] ? '#' : ' ');
 
printf ("\n");
}
}
#endif
 
PIXMAN_EXPORT void
pixman_add_trapezoids (pixman_image_t * image,
int16_t x_off,
int y_off,
int ntraps,
const pixman_trapezoid_t *traps)
{
int i;
 
#if 0
dump_image (image, "before");
#endif
 
for (i = 0; i < ntraps; ++i)
{
const pixman_trapezoid_t *trap = &(traps[i]);
 
if (!pixman_trapezoid_valid (trap))
continue;
 
pixman_rasterize_trapezoid (image, trap, x_off, y_off);
}
 
#if 0
dump_image (image, "after");
#endif
}
 
PIXMAN_EXPORT void
pixman_rasterize_trapezoid (pixman_image_t * image,
const pixman_trapezoid_t *trap,
int x_off,
int y_off)
{
int bpp;
int height;
 
pixman_fixed_t y_off_fixed;
pixman_edge_t l, r;
pixman_fixed_t t, b;
 
return_if_fail (image->type == BITS);
 
_pixman_image_validate (image);
if (!pixman_trapezoid_valid (trap))
return;
 
height = image->bits.height;
bpp = PIXMAN_FORMAT_BPP (image->bits.format);
 
y_off_fixed = pixman_int_to_fixed (y_off);
 
t = trap->top + y_off_fixed;
if (t < 0)
t = 0;
t = pixman_sample_ceil_y (t, bpp);
 
b = trap->bottom + y_off_fixed;
if (pixman_fixed_to_int (b) >= height)
b = pixman_int_to_fixed (height) - 1;
b = pixman_sample_floor_y (b, bpp);
if (b >= t)
{
/* initialize edge walkers */
pixman_line_fixed_edge_init (&l, bpp, t, &trap->left, x_off, y_off);
pixman_line_fixed_edge_init (&r, bpp, t, &trap->right, x_off, y_off);
 
pixman_rasterize_edges (image, &l, &r, t, b);
}
}
 
static const pixman_bool_t zero_src_has_no_effect[PIXMAN_N_OPERATORS] =
{
FALSE, /* Clear 0 0 */
FALSE, /* Src 1 0 */
TRUE, /* Dst 0 1 */
TRUE, /* Over 1 1-Aa */
TRUE, /* OverReverse 1-Ab 1 */
FALSE, /* In Ab 0 */
FALSE, /* InReverse 0 Aa */
FALSE, /* Out 1-Ab 0 */
TRUE, /* OutReverse 0 1-Aa */
TRUE, /* Atop Ab 1-Aa */
FALSE, /* AtopReverse 1-Ab Aa */
TRUE, /* Xor 1-Ab 1-Aa */
TRUE, /* Add 1 1 */
};
 
static pixman_bool_t
get_trap_extents (pixman_op_t op, pixman_image_t *dest,
const pixman_trapezoid_t *traps, int n_traps,
pixman_box32_t *box)
{
int i;
 
/* When the operator is such that a zero source has an
* effect on the underlying image, we have to
* composite across the entire destination
*/
if (!zero_src_has_no_effect [op])
{
box->x1 = 0;
box->y1 = 0;
box->x2 = dest->bits.width;
box->y2 = dest->bits.height;
return TRUE;
}
box->x1 = INT32_MAX;
box->y1 = INT32_MAX;
box->x2 = INT32_MIN;
box->y2 = INT32_MIN;
for (i = 0; i < n_traps; ++i)
{
const pixman_trapezoid_t *trap = &(traps[i]);
int y1, y2;
if (!pixman_trapezoid_valid (trap))
continue;
y1 = pixman_fixed_to_int (trap->top);
if (y1 < box->y1)
box->y1 = y1;
y2 = pixman_fixed_to_int (pixman_fixed_ceil (trap->bottom));
if (y2 > box->y2)
box->y2 = y2;
#define EXTEND_MIN(x) \
if (pixman_fixed_to_int ((x)) < box->x1) \
box->x1 = pixman_fixed_to_int ((x));
#define EXTEND_MAX(x) \
if (pixman_fixed_to_int (pixman_fixed_ceil ((x))) > box->x2) \
box->x2 = pixman_fixed_to_int (pixman_fixed_ceil ((x)));
#define EXTEND(x) \
EXTEND_MIN(x); \
EXTEND_MAX(x);
EXTEND(trap->left.p1.x);
EXTEND(trap->left.p2.x);
EXTEND(trap->right.p1.x);
EXTEND(trap->right.p2.x);
}
if (box->x1 >= box->x2 || box->y1 >= box->y2)
return FALSE;
 
return TRUE;
}
 
/*
* pixman_composite_trapezoids()
*
* All the trapezoids are conceptually rendered to an infinitely big image.
* The (0, 0) coordinates of this image are then aligned with the (x, y)
* coordinates of the source image, and then both images are aligned with
* the (x, y) coordinates of the destination. Then these three images are
* composited across the entire destination.
*/
PIXMAN_EXPORT void
pixman_composite_trapezoids (pixman_op_t op,
pixman_image_t * src,
pixman_image_t * dst,
pixman_format_code_t mask_format,
int x_src,
int y_src,
int x_dst,
int y_dst,
int n_traps,
const pixman_trapezoid_t * traps)
{
int i;
 
return_if_fail (PIXMAN_FORMAT_TYPE (mask_format) == PIXMAN_TYPE_A);
if (n_traps <= 0)
return;
 
_pixman_image_validate (src);
_pixman_image_validate (dst);
 
if (op == PIXMAN_OP_ADD &&
(src->common.flags & FAST_PATH_IS_OPAQUE) &&
(mask_format == dst->common.extended_format_code) &&
!(dst->common.have_clip_region))
{
for (i = 0; i < n_traps; ++i)
{
const pixman_trapezoid_t *trap = &(traps[i]);
if (!pixman_trapezoid_valid (trap))
continue;
pixman_rasterize_trapezoid (dst, trap, x_dst, y_dst);
}
}
else
{
pixman_image_t *tmp;
pixman_box32_t box;
int i;
 
if (!get_trap_extents (op, dst, traps, n_traps, &box))
return;
if (!(tmp = pixman_image_create_bits (
mask_format, box.x2 - box.x1, box.y2 - box.y1, NULL, -1)))
return;
for (i = 0; i < n_traps; ++i)
{
const pixman_trapezoid_t *trap = &(traps[i]);
if (!pixman_trapezoid_valid (trap))
continue;
pixman_rasterize_trapezoid (tmp, trap, - box.x1, - box.y1);
}
pixman_image_composite (op, src, tmp, dst,
x_src + box.x1, y_src + box.y1,
0, 0,
x_dst + box.x1, y_dst + box.y1,
box.x2 - box.x1, box.y2 - box.y1);
pixman_image_unref (tmp);
}
}
 
static int
greater_y (const pixman_point_fixed_t *a, const pixman_point_fixed_t *b)
{
if (a->y == b->y)
return a->x > b->x;
return a->y > b->y;
}
 
/*
* Note that the definition of this function is a bit odd because
* of the X coordinate space (y increasing downwards).
*/
static int
clockwise (const pixman_point_fixed_t *ref,
const pixman_point_fixed_t *a,
const pixman_point_fixed_t *b)
{
pixman_point_fixed_t ad, bd;
 
ad.x = a->x - ref->x;
ad.y = a->y - ref->y;
bd.x = b->x - ref->x;
bd.y = b->y - ref->y;
 
return ((pixman_fixed_32_32_t) bd.y * ad.x -
(pixman_fixed_32_32_t) ad.y * bd.x) < 0;
}
 
static void
triangle_to_trapezoids (const pixman_triangle_t *tri, pixman_trapezoid_t *traps)
{
const pixman_point_fixed_t *top, *left, *right, *tmp;
 
top = &tri->p1;
left = &tri->p2;
right = &tri->p3;
 
if (greater_y (top, left))
{
tmp = left;
left = top;
top = tmp;
}
 
if (greater_y (top, right))
{
tmp = right;
right = top;
top = tmp;
}
 
if (clockwise (top, right, left))
{
tmp = right;
right = left;
left = tmp;
}
/*
* Two cases:
*
* + +
* / \ / \
* / \ / \
* / + + \
* / -- -- \
* / -- -- \
* / --- --- \
* +-- --+
*/
 
traps->top = top->y;
traps->left.p1 = *top;
traps->left.p2 = *left;
traps->right.p1 = *top;
traps->right.p2 = *right;
 
if (right->y < left->y)
traps->bottom = right->y;
else
traps->bottom = left->y;
 
traps++;
 
*traps = *(traps - 1);
if (right->y < left->y)
{
traps->top = right->y;
traps->bottom = left->y;
traps->right.p1 = *right;
traps->right.p2 = *left;
}
else
{
traps->top = left->y;
traps->bottom = right->y;
traps->left.p1 = *left;
traps->left.p2 = *right;
}
}
 
static pixman_trapezoid_t *
convert_triangles (int n_tris, const pixman_triangle_t *tris)
{
pixman_trapezoid_t *traps;
int i;
 
if (n_tris <= 0)
return NULL;
traps = pixman_malloc_ab (n_tris, 2 * sizeof (pixman_trapezoid_t));
if (!traps)
return NULL;
 
for (i = 0; i < n_tris; ++i)
triangle_to_trapezoids (&(tris[i]), traps + 2 * i);
 
return traps;
}
 
PIXMAN_EXPORT void
pixman_composite_triangles (pixman_op_t op,
pixman_image_t * src,
pixman_image_t * dst,
pixman_format_code_t mask_format,
int x_src,
int y_src,
int x_dst,
int y_dst,
int n_tris,
const pixman_triangle_t * tris)
{
pixman_trapezoid_t *traps;
 
if ((traps = convert_triangles (n_tris, tris)))
{
pixman_composite_trapezoids (op, src, dst, mask_format,
x_src, y_src, x_dst, y_dst,
n_tris * 2, traps);
free (traps);
}
}
 
PIXMAN_EXPORT void
pixman_add_triangles (pixman_image_t *image,
int32_t x_off,
int32_t y_off,
int n_tris,
const pixman_triangle_t *tris)
{
pixman_trapezoid_t *traps;
 
if ((traps = convert_triangles (n_tris, tris)))
{
pixman_add_trapezoids (image, x_off, y_off,
n_tris * 2, traps);
 
free (traps);
}
}
/contrib/sdk/sources/pixman/pixman-utils.c
0,0 → 1,310
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 1999 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Keith Packard, SuSE, Inc.
*/
 
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
 
#include "pixman-private.h"
 
pixman_bool_t
_pixman_multiply_overflows_size (size_t a, size_t b)
{
return a >= SIZE_MAX / b;
}
 
pixman_bool_t
_pixman_multiply_overflows_int (unsigned int a, unsigned int b)
{
return a >= INT32_MAX / b;
}
 
pixman_bool_t
_pixman_addition_overflows_int (unsigned int a, unsigned int b)
{
return a > INT32_MAX - b;
}
 
void *
pixman_malloc_ab (unsigned int a,
unsigned int b)
{
if (a >= INT32_MAX / b)
return NULL;
 
return malloc (a * b);
}
 
void *
pixman_malloc_abc (unsigned int a,
unsigned int b,
unsigned int c)
{
if (a >= INT32_MAX / b)
return NULL;
else if (a * b >= INT32_MAX / c)
return NULL;
else
return malloc (a * b * c);
}
 
static force_inline uint16_t
float_to_unorm (float f, int n_bits)
{
uint32_t u;
 
if (f > 1.0)
f = 1.0;
if (f < 0.0)
f = 0.0;
 
u = f * (1 << n_bits);
u -= (u >> n_bits);
 
return u;
}
 
static force_inline float
unorm_to_float (uint16_t u, int n_bits)
{
uint32_t m = ((1 << n_bits) - 1);
 
return (u & m) * (1.f / (float)m);
}
 
/*
* This function expands images from a8r8g8b8 to argb_t. To preserve
* precision, it needs to know from which source format the a8r8g8b8 pixels
* originally came.
*
* For example, if the source was PIXMAN_x1r5g5b5 and the red component
* contained bits 12345, then the 8-bit value is 12345123. To correctly
* expand this to floating point, it should be 12345 / 31.0 and not
* 12345123 / 255.0.
*/
void
pixman_expand_to_float (argb_t *dst,
const uint32_t *src,
pixman_format_code_t format,
int width)
{
static const float multipliers[16] = {
0.0f,
1.0f / ((1 << 1) - 1),
1.0f / ((1 << 2) - 1),
1.0f / ((1 << 3) - 1),
1.0f / ((1 << 4) - 1),
1.0f / ((1 << 5) - 1),
1.0f / ((1 << 6) - 1),
1.0f / ((1 << 7) - 1),
1.0f / ((1 << 8) - 1),
1.0f / ((1 << 9) - 1),
1.0f / ((1 << 10) - 1),
1.0f / ((1 << 11) - 1),
1.0f / ((1 << 12) - 1),
1.0f / ((1 << 13) - 1),
1.0f / ((1 << 14) - 1),
1.0f / ((1 << 15) - 1),
};
int a_size, r_size, g_size, b_size;
int a_shift, r_shift, g_shift, b_shift;
float a_mul, r_mul, g_mul, b_mul;
uint32_t a_mask, r_mask, g_mask, b_mask;
int i;
 
if (!PIXMAN_FORMAT_VIS (format))
format = PIXMAN_a8r8g8b8;
 
/*
* Determine the sizes of each component and the masks and shifts
* required to extract them from the source pixel.
*/
a_size = PIXMAN_FORMAT_A (format);
r_size = PIXMAN_FORMAT_R (format);
g_size = PIXMAN_FORMAT_G (format);
b_size = PIXMAN_FORMAT_B (format);
 
a_shift = 32 - a_size;
r_shift = 24 - r_size;
g_shift = 16 - g_size;
b_shift = 8 - b_size;
 
a_mask = ((1 << a_size) - 1);
r_mask = ((1 << r_size) - 1);
g_mask = ((1 << g_size) - 1);
b_mask = ((1 << b_size) - 1);
 
a_mul = multipliers[a_size];
r_mul = multipliers[r_size];
g_mul = multipliers[g_size];
b_mul = multipliers[b_size];
 
/* Start at the end so that we can do the expansion in place
* when src == dst
*/
for (i = width - 1; i >= 0; i--)
{
const uint32_t pixel = src[i];
 
dst[i].a = a_mask? ((pixel >> a_shift) & a_mask) * a_mul : 1.0f;
dst[i].r = ((pixel >> r_shift) & r_mask) * r_mul;
dst[i].g = ((pixel >> g_shift) & g_mask) * g_mul;
dst[i].b = ((pixel >> b_shift) & b_mask) * b_mul;
}
}
 
uint16_t
pixman_float_to_unorm (float f, int n_bits)
{
return float_to_unorm (f, n_bits);
}
 
float
pixman_unorm_to_float (uint16_t u, int n_bits)
{
return unorm_to_float (u, n_bits);
}
 
void
pixman_contract_from_float (uint32_t *dst,
const argb_t *src,
int width)
{
int i;
 
for (i = 0; i < width; ++i)
{
uint8_t a, r, g, b;
 
a = float_to_unorm (src[i].a, 8);
r = float_to_unorm (src[i].r, 8);
g = float_to_unorm (src[i].g, 8);
b = float_to_unorm (src[i].b, 8);
 
dst[i] = (a << 24) | (r << 16) | (g << 8) | (b << 0);
}
}
 
uint32_t *
_pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask)
{
return iter->buffer;
}
 
#define N_TMP_BOXES (16)
 
pixman_bool_t
pixman_region16_copy_from_region32 (pixman_region16_t *dst,
pixman_region32_t *src)
{
int n_boxes, i;
pixman_box32_t *boxes32;
pixman_box16_t *boxes16;
pixman_bool_t retval;
 
boxes32 = pixman_region32_rectangles (src, &n_boxes);
 
boxes16 = pixman_malloc_ab (n_boxes, sizeof (pixman_box16_t));
 
if (!boxes16)
return FALSE;
 
for (i = 0; i < n_boxes; ++i)
{
boxes16[i].x1 = boxes32[i].x1;
boxes16[i].y1 = boxes32[i].y1;
boxes16[i].x2 = boxes32[i].x2;
boxes16[i].y2 = boxes32[i].y2;
}
 
pixman_region_fini (dst);
retval = pixman_region_init_rects (dst, boxes16, n_boxes);
free (boxes16);
return retval;
}
 
pixman_bool_t
pixman_region32_copy_from_region16 (pixman_region32_t *dst,
pixman_region16_t *src)
{
int n_boxes, i;
pixman_box16_t *boxes16;
pixman_box32_t *boxes32;
pixman_box32_t tmp_boxes[N_TMP_BOXES];
pixman_bool_t retval;
 
boxes16 = pixman_region_rectangles (src, &n_boxes);
 
if (n_boxes > N_TMP_BOXES)
boxes32 = pixman_malloc_ab (n_boxes, sizeof (pixman_box32_t));
else
boxes32 = tmp_boxes;
 
if (!boxes32)
return FALSE;
 
for (i = 0; i < n_boxes; ++i)
{
boxes32[i].x1 = boxes16[i].x1;
boxes32[i].y1 = boxes16[i].y1;
boxes32[i].x2 = boxes16[i].x2;
boxes32[i].y2 = boxes16[i].y2;
}
 
pixman_region32_fini (dst);
retval = pixman_region32_init_rects (dst, boxes32, n_boxes);
 
if (boxes32 != tmp_boxes)
free (boxes32);
 
return retval;
}
 
/* This function is exported for the sake of the test suite and not part
* of the ABI.
*/
PIXMAN_EXPORT pixman_implementation_t *
_pixman_internal_only_get_implementation (void)
{
return get_implementation ();
}
 
void
_pixman_log_error (const char *function, const char *message)
{
static int n_messages = 0;
 
if (n_messages < 10)
{
fprintf (stderr,
"*** BUG ***\n"
"In %s: %s\n"
"Set a breakpoint on '_pixman_log_error' to debug\n\n",
function, message);
 
n_messages++;
}
}
/contrib/sdk/sources/pixman/pixman-version.h
0,0 → 1,50
/*
* Copyright © 2008 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation 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 AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Author: Carl D. Worth <cworth@cworth.org>
*/
 
#ifndef PIXMAN_VERSION_H__
#define PIXMAN_VERSION_H__
 
#ifndef PIXMAN_H__
# error pixman-version.h should only be included by pixman.h
#endif
 
#define PIXMAN_VERSION_MAJOR 0
#define PIXMAN_VERSION_MINOR 30
#define PIXMAN_VERSION_MICRO 2
 
#define PIXMAN_VERSION_STRING "0.30.2"
 
#define PIXMAN_VERSION_ENCODE(major, minor, micro) ( \
((major) * 10000) \
+ ((minor) * 100) \
+ ((micro) * 1))
 
#define PIXMAN_VERSION PIXMAN_VERSION_ENCODE( \
PIXMAN_VERSION_MAJOR, \
PIXMAN_VERSION_MINOR, \
PIXMAN_VERSION_MICRO)
 
#endif /* PIXMAN_VERSION_H__ */
/contrib/sdk/sources/pixman/pixman-x86.c
0,0 → 1,237
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
 
#include "pixman-private.h"
 
#if defined(USE_X86_MMX) || defined (USE_SSE2)
 
/* The CPU detection code needs to be in a file not compiled with
* "-mmmx -msse", as gcc would generate CMOV instructions otherwise
* that would lead to SIGILL instructions on old CPUs that don't have
* it.
*/
 
typedef enum
{
X86_MMX = (1 << 0),
X86_MMX_EXTENSIONS = (1 << 1),
X86_SSE = (1 << 2) | X86_MMX_EXTENSIONS,
X86_SSE2 = (1 << 3),
X86_CMOV = (1 << 4)
} cpu_features_t;
 
#ifdef HAVE_GETISAX
 
#include <sys/auxv.h>
 
static cpu_features_t
detect_cpu_features (void)
{
cpu_features_t features = 0;
unsigned int result = 0;
 
if (getisax (&result, 1))
{
if (result & AV_386_CMOV)
features |= X86_CMOV;
if (result & AV_386_MMX)
features |= X86_MMX;
if (result & AV_386_AMD_MMX)
features |= X86_MMX_EXTENSIONS;
if (result & AV_386_SSE)
features |= X86_SSE;
if (result & AV_386_SSE2)
features |= X86_SSE2;
}
 
return features;
}
 
#else
 
#define _PIXMAN_X86_64 \
(defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64))
 
static pixman_bool_t
have_cpuid (void)
{
#if _PIXMAN_X86_64 || defined (_MSC_VER)
 
return TRUE;
 
#elif defined (__GNUC__)
uint32_t result;
 
__asm__ volatile (
"pushf" "\n\t"
"pop %%eax" "\n\t"
"mov %%eax, %%ecx" "\n\t"
"xor $0x00200000, %%eax" "\n\t"
"push %%eax" "\n\t"
"popf" "\n\t"
"pushf" "\n\t"
"pop %%eax" "\n\t"
"xor %%ecx, %%eax" "\n\t"
"mov %%eax, %0" "\n\t"
: "=r" (result)
:
: "%eax", "%ecx");
 
return !!result;
 
#else
#error "Unknown compiler"
#endif
}
 
static void
pixman_cpuid (uint32_t feature,
uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
{
#if defined (__GNUC__)
 
#if _PIXMAN_X86_64
__asm__ volatile (
"cpuid" "\n\t"
: "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
: "a" (feature));
#else
/* On x86-32 we need to be careful about the handling of %ebx
* and %esp. We can't declare either one as clobbered
* since they are special registers (%ebx is the "PIC
* register" holding an offset to global data, %esp the
* stack pointer), so we need to make sure that %ebx is
* preserved, and that %esp has its original value when
* accessing the output operands.
*/
__asm__ volatile (
"xchg %%ebx, %1" "\n\t"
"cpuid" "\n\t"
"xchg %%ebx, %1" "\n\t"
: "=a" (*a), "=r" (*b), "=c" (*c), "=d" (*d)
: "a" (feature));
#endif
 
#elif defined (_MSC_VER)
int info[4];
 
__cpuid (info, feature);
 
*a = info[0];
*b = info[1];
*c = info[2];
*d = info[3];
#else
#error Unknown compiler
#endif
}
 
static cpu_features_t
detect_cpu_features (void)
{
uint32_t a, b, c, d;
cpu_features_t features = 0;
 
if (!have_cpuid())
return features;
 
/* Get feature bits */
pixman_cpuid (0x01, &a, &b, &c, &d);
if (d & (1 << 15))
features |= X86_CMOV;
if (d & (1 << 23))
features |= X86_MMX;
if (d & (1 << 25))
features |= X86_SSE;
if (d & (1 << 26))
features |= X86_SSE2;
 
/* Check for AMD specific features */
if ((features & X86_MMX) && !(features & X86_SSE))
{
char vendor[13];
 
/* Get vendor string */
memset (vendor, 0, sizeof vendor);
 
pixman_cpuid (0x00, &a, &b, &c, &d);
memcpy (vendor + 0, &b, 4);
memcpy (vendor + 4, &d, 4);
memcpy (vendor + 8, &c, 4);
 
if (strcmp (vendor, "AuthenticAMD") == 0 ||
strcmp (vendor, "Geode by NSC") == 0)
{
pixman_cpuid (0x80000000, &a, &b, &c, &d);
if (a >= 0x80000001)
{
pixman_cpuid (0x80000001, &a, &b, &c, &d);
 
if (d & (1 << 22))
features |= X86_MMX_EXTENSIONS;
}
}
}
 
return features;
}
 
#endif
 
static pixman_bool_t
have_feature (cpu_features_t feature)
{
static pixman_bool_t initialized;
static cpu_features_t features;
 
if (!initialized)
{
features = detect_cpu_features();
initialized = TRUE;
}
 
return (features & feature) == feature;
}
 
#endif
 
pixman_implementation_t *
_pixman_x86_get_implementations (pixman_implementation_t *imp)
{
#define MMX_BITS (X86_MMX | X86_MMX_EXTENSIONS)
#define SSE2_BITS (X86_MMX | X86_MMX_EXTENSIONS | X86_SSE | X86_SSE2)
 
#ifdef USE_X86_MMX
if (!_pixman_disabled ("mmx") && have_feature (MMX_BITS))
imp = _pixman_implementation_create_mmx (imp);
#endif
 
#ifdef USE_SSE2
if (!_pixman_disabled ("sse2") && have_feature (SSE2_BITS))
imp = _pixman_implementation_create_sse2 (imp);
#endif
 
return imp;
}
/contrib/sdk/sources/pixman/pixman.c
0,0 → 1,1135
/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Keith Packard, SuSE, Inc.
*/
 
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "pixman-private.h"
 
#include <stdlib.h>
 
pixman_implementation_t *global_implementation;
 
#ifdef TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR
static void __attribute__((constructor))
pixman_constructor (void)
{
global_implementation = _pixman_choose_implementation ();
}
#endif
 
typedef struct operator_info_t operator_info_t;
 
struct operator_info_t
{
uint8_t opaque_info[4];
};
 
#define PACK(neither, src, dest, both) \
{{ (uint8_t)PIXMAN_OP_ ## neither, \
(uint8_t)PIXMAN_OP_ ## src, \
(uint8_t)PIXMAN_OP_ ## dest, \
(uint8_t)PIXMAN_OP_ ## both }}
 
static const operator_info_t operator_table[] =
{
/* Neither Opaque Src Opaque Dst Opaque Both Opaque */
PACK (CLEAR, CLEAR, CLEAR, CLEAR),
PACK (SRC, SRC, SRC, SRC),
PACK (DST, DST, DST, DST),
PACK (OVER, SRC, OVER, SRC),
PACK (OVER_REVERSE, OVER_REVERSE, DST, DST),
PACK (IN, IN, SRC, SRC),
PACK (IN_REVERSE, DST, IN_REVERSE, DST),
PACK (OUT, OUT, CLEAR, CLEAR),
PACK (OUT_REVERSE, CLEAR, OUT_REVERSE, CLEAR),
PACK (ATOP, IN, OVER, SRC),
PACK (ATOP_REVERSE, OVER_REVERSE, IN_REVERSE, DST),
PACK (XOR, OUT, OUT_REVERSE, CLEAR),
PACK (ADD, ADD, ADD, ADD),
PACK (SATURATE, OVER_REVERSE, DST, DST),
 
{{ 0 /* 0x0e */ }},
{{ 0 /* 0x0f */ }},
 
PACK (CLEAR, CLEAR, CLEAR, CLEAR),
PACK (SRC, SRC, SRC, SRC),
PACK (DST, DST, DST, DST),
PACK (DISJOINT_OVER, DISJOINT_OVER, DISJOINT_OVER, DISJOINT_OVER),
PACK (DISJOINT_OVER_REVERSE, DISJOINT_OVER_REVERSE, DISJOINT_OVER_REVERSE, DISJOINT_OVER_REVERSE),
PACK (DISJOINT_IN, DISJOINT_IN, DISJOINT_IN, DISJOINT_IN),
PACK (DISJOINT_IN_REVERSE, DISJOINT_IN_REVERSE, DISJOINT_IN_REVERSE, DISJOINT_IN_REVERSE),
PACK (DISJOINT_OUT, DISJOINT_OUT, DISJOINT_OUT, DISJOINT_OUT),
PACK (DISJOINT_OUT_REVERSE, DISJOINT_OUT_REVERSE, DISJOINT_OUT_REVERSE, DISJOINT_OUT_REVERSE),
PACK (DISJOINT_ATOP, DISJOINT_ATOP, DISJOINT_ATOP, DISJOINT_ATOP),
PACK (DISJOINT_ATOP_REVERSE, DISJOINT_ATOP_REVERSE, DISJOINT_ATOP_REVERSE, DISJOINT_ATOP_REVERSE),
PACK (DISJOINT_XOR, DISJOINT_XOR, DISJOINT_XOR, DISJOINT_XOR),
 
{{ 0 /* 0x1c */ }},
{{ 0 /* 0x1d */ }},
{{ 0 /* 0x1e */ }},
{{ 0 /* 0x1f */ }},
 
PACK (CLEAR, CLEAR, CLEAR, CLEAR),
PACK (SRC, SRC, SRC, SRC),
PACK (DST, DST, DST, DST),
PACK (CONJOINT_OVER, CONJOINT_OVER, CONJOINT_OVER, CONJOINT_OVER),
PACK (CONJOINT_OVER_REVERSE, CONJOINT_OVER_REVERSE, CONJOINT_OVER_REVERSE, CONJOINT_OVER_REVERSE),
PACK (CONJOINT_IN, CONJOINT_IN, CONJOINT_IN, CONJOINT_IN),
PACK (CONJOINT_IN_REVERSE, CONJOINT_IN_REVERSE, CONJOINT_IN_REVERSE, CONJOINT_IN_REVERSE),
PACK (CONJOINT_OUT, CONJOINT_OUT, CONJOINT_OUT, CONJOINT_OUT),
PACK (CONJOINT_OUT_REVERSE, CONJOINT_OUT_REVERSE, CONJOINT_OUT_REVERSE, CONJOINT_OUT_REVERSE),
PACK (CONJOINT_ATOP, CONJOINT_ATOP, CONJOINT_ATOP, CONJOINT_ATOP),
PACK (CONJOINT_ATOP_REVERSE, CONJOINT_ATOP_REVERSE, CONJOINT_ATOP_REVERSE, CONJOINT_ATOP_REVERSE),
PACK (CONJOINT_XOR, CONJOINT_XOR, CONJOINT_XOR, CONJOINT_XOR),
 
{{ 0 /* 0x2c */ }},
{{ 0 /* 0x2d */ }},
{{ 0 /* 0x2e */ }},
{{ 0 /* 0x2f */ }},
 
PACK (MULTIPLY, MULTIPLY, MULTIPLY, MULTIPLY),
PACK (SCREEN, SCREEN, SCREEN, SCREEN),
PACK (OVERLAY, OVERLAY, OVERLAY, OVERLAY),
PACK (DARKEN, DARKEN, DARKEN, DARKEN),
PACK (LIGHTEN, LIGHTEN, LIGHTEN, LIGHTEN),
PACK (COLOR_DODGE, COLOR_DODGE, COLOR_DODGE, COLOR_DODGE),
PACK (COLOR_BURN, COLOR_BURN, COLOR_BURN, COLOR_BURN),
PACK (HARD_LIGHT, HARD_LIGHT, HARD_LIGHT, HARD_LIGHT),
PACK (SOFT_LIGHT, SOFT_LIGHT, SOFT_LIGHT, SOFT_LIGHT),
PACK (DIFFERENCE, DIFFERENCE, DIFFERENCE, DIFFERENCE),
PACK (EXCLUSION, EXCLUSION, EXCLUSION, EXCLUSION),
PACK (HSL_HUE, HSL_HUE, HSL_HUE, HSL_HUE),
PACK (HSL_SATURATION, HSL_SATURATION, HSL_SATURATION, HSL_SATURATION),
PACK (HSL_COLOR, HSL_COLOR, HSL_COLOR, HSL_COLOR),
PACK (HSL_LUMINOSITY, HSL_LUMINOSITY, HSL_LUMINOSITY, HSL_LUMINOSITY),
};
 
/*
* Optimize the current operator based on opacity of source or destination
* The output operator should be mathematically equivalent to the source.
*/
static pixman_op_t
optimize_operator (pixman_op_t op,
uint32_t src_flags,
uint32_t mask_flags,
uint32_t dst_flags)
{
pixman_bool_t is_source_opaque, is_dest_opaque;
 
#define OPAQUE_SHIFT 13
COMPILE_TIME_ASSERT (FAST_PATH_IS_OPAQUE == (1 << OPAQUE_SHIFT));
is_dest_opaque = (dst_flags & FAST_PATH_IS_OPAQUE);
is_source_opaque = ((src_flags & mask_flags) & FAST_PATH_IS_OPAQUE);
 
is_dest_opaque >>= OPAQUE_SHIFT - 1;
is_source_opaque >>= OPAQUE_SHIFT;
 
return operator_table[op].opaque_info[is_dest_opaque | is_source_opaque];
}
 
/*
* Computing composite region
*/
static inline pixman_bool_t
clip_general_image (pixman_region32_t * region,
pixman_region32_t * clip,
int dx,
int dy)
{
if (pixman_region32_n_rects (region) == 1 &&
pixman_region32_n_rects (clip) == 1)
{
pixman_box32_t * rbox = pixman_region32_rectangles (region, NULL);
pixman_box32_t * cbox = pixman_region32_rectangles (clip, NULL);
int v;
 
if (rbox->x1 < (v = cbox->x1 + dx))
rbox->x1 = v;
if (rbox->x2 > (v = cbox->x2 + dx))
rbox->x2 = v;
if (rbox->y1 < (v = cbox->y1 + dy))
rbox->y1 = v;
if (rbox->y2 > (v = cbox->y2 + dy))
rbox->y2 = v;
if (rbox->x1 >= rbox->x2 || rbox->y1 >= rbox->y2)
{
pixman_region32_init (region);
return FALSE;
}
}
else if (!pixman_region32_not_empty (clip))
{
return FALSE;
}
else
{
if (dx || dy)
pixman_region32_translate (region, -dx, -dy);
 
if (!pixman_region32_intersect (region, region, clip))
return FALSE;
 
if (dx || dy)
pixman_region32_translate (region, dx, dy);
}
 
return pixman_region32_not_empty (region);
}
 
static inline pixman_bool_t
clip_source_image (pixman_region32_t * region,
pixman_image_t * image,
int dx,
int dy)
{
/* Source clips are ignored, unless they are explicitly turned on
* and the clip in question was set by an X client. (Because if
* the clip was not set by a client, then it is a hierarchy
* clip and those should always be ignored for sources).
*/
if (!image->common.clip_sources || !image->common.client_clip)
return TRUE;
 
return clip_general_image (region,
&image->common.clip_region,
dx, dy);
}
 
/*
* returns FALSE if the final region is empty. Indistinguishable from
* an allocation failure, but rendering ignores those anyways.
*/
pixman_bool_t
_pixman_compute_composite_region32 (pixman_region32_t * region,
pixman_image_t * src_image,
pixman_image_t * mask_image,
pixman_image_t * dest_image,
int32_t src_x,
int32_t src_y,
int32_t mask_x,
int32_t mask_y,
int32_t dest_x,
int32_t dest_y,
int32_t width,
int32_t height)
{
region->extents.x1 = dest_x;
region->extents.x2 = dest_x + width;
region->extents.y1 = dest_y;
region->extents.y2 = dest_y + height;
 
region->extents.x1 = MAX (region->extents.x1, 0);
region->extents.y1 = MAX (region->extents.y1, 0);
region->extents.x2 = MIN (region->extents.x2, dest_image->bits.width);
region->extents.y2 = MIN (region->extents.y2, dest_image->bits.height);
 
region->data = 0;
 
/* Check for empty operation */
if (region->extents.x1 >= region->extents.x2 ||
region->extents.y1 >= region->extents.y2)
{
region->extents.x1 = 0;
region->extents.x2 = 0;
region->extents.y1 = 0;
region->extents.y2 = 0;
return FALSE;
}
 
if (dest_image->common.have_clip_region)
{
if (!clip_general_image (region, &dest_image->common.clip_region, 0, 0))
return FALSE;
}
 
if (dest_image->common.alpha_map)
{
if (!pixman_region32_intersect_rect (region, region,
dest_image->common.alpha_origin_x,
dest_image->common.alpha_origin_y,
dest_image->common.alpha_map->width,
dest_image->common.alpha_map->height))
{
return FALSE;
}
if (!pixman_region32_not_empty (region))
return FALSE;
if (dest_image->common.alpha_map->common.have_clip_region)
{
if (!clip_general_image (region, &dest_image->common.alpha_map->common.clip_region,
-dest_image->common.alpha_origin_x,
-dest_image->common.alpha_origin_y))
{
return FALSE;
}
}
}
 
/* clip against src */
if (src_image->common.have_clip_region)
{
if (!clip_source_image (region, src_image, dest_x - src_x, dest_y - src_y))
return FALSE;
}
if (src_image->common.alpha_map && src_image->common.alpha_map->common.have_clip_region)
{
if (!clip_source_image (region, (pixman_image_t *)src_image->common.alpha_map,
dest_x - (src_x - src_image->common.alpha_origin_x),
dest_y - (src_y - src_image->common.alpha_origin_y)))
{
return FALSE;
}
}
/* clip against mask */
if (mask_image && mask_image->common.have_clip_region)
{
if (!clip_source_image (region, mask_image, dest_x - mask_x, dest_y - mask_y))
return FALSE;
 
if (mask_image->common.alpha_map && mask_image->common.alpha_map->common.have_clip_region)
{
if (!clip_source_image (region, (pixman_image_t *)mask_image->common.alpha_map,
dest_x - (mask_x - mask_image->common.alpha_origin_x),
dest_y - (mask_y - mask_image->common.alpha_origin_y)))
{
return FALSE;
}
}
}
 
return TRUE;
}
 
typedef struct
{
pixman_fixed_48_16_t x1;
pixman_fixed_48_16_t y1;
pixman_fixed_48_16_t x2;
pixman_fixed_48_16_t y2;
} box_48_16_t;
 
static pixman_bool_t
compute_transformed_extents (pixman_transform_t *transform,
const pixman_box32_t *extents,
box_48_16_t *transformed)
{
pixman_fixed_48_16_t tx1, ty1, tx2, ty2;
pixman_fixed_t x1, y1, x2, y2;
int i;
 
x1 = pixman_int_to_fixed (extents->x1) + pixman_fixed_1 / 2;
y1 = pixman_int_to_fixed (extents->y1) + pixman_fixed_1 / 2;
x2 = pixman_int_to_fixed (extents->x2) - pixman_fixed_1 / 2;
y2 = pixman_int_to_fixed (extents->y2) - pixman_fixed_1 / 2;
 
if (!transform)
{
transformed->x1 = x1;
transformed->y1 = y1;
transformed->x2 = x2;
transformed->y2 = y2;
 
return TRUE;
}
 
tx1 = ty1 = INT64_MAX;
tx2 = ty2 = INT64_MIN;
 
for (i = 0; i < 4; ++i)
{
pixman_fixed_48_16_t tx, ty;
pixman_vector_t v;
 
v.vector[0] = (i & 0x01)? x1 : x2;
v.vector[1] = (i & 0x02)? y1 : y2;
v.vector[2] = pixman_fixed_1;
 
if (!pixman_transform_point (transform, &v))
return FALSE;
 
tx = (pixman_fixed_48_16_t)v.vector[0];
ty = (pixman_fixed_48_16_t)v.vector[1];
 
if (tx < tx1)
tx1 = tx;
if (ty < ty1)
ty1 = ty;
if (tx > tx2)
tx2 = tx;
if (ty > ty2)
ty2 = ty;
}
 
transformed->x1 = tx1;
transformed->y1 = ty1;
transformed->x2 = tx2;
transformed->y2 = ty2;
 
return TRUE;
}
 
#define IS_16BIT(x) (((x) >= INT16_MIN) && ((x) <= INT16_MAX))
#define ABS(f) (((f) < 0)? (-(f)) : (f))
#define IS_16_16(f) (((f) >= pixman_min_fixed_48_16 && ((f) <= pixman_max_fixed_48_16)))
 
static pixman_bool_t
analyze_extent (pixman_image_t *image,
const pixman_box32_t *extents,
uint32_t *flags)
{
pixman_transform_t *transform;
pixman_fixed_t x_off, y_off;
pixman_fixed_t width, height;
pixman_fixed_t *params;
box_48_16_t transformed;
pixman_box32_t exp_extents;
 
if (!image)
return TRUE;
 
/* Some compositing functions walk one step
* outside the destination rectangle, so we
* check here that the expanded-by-one source
* extents in destination space fits in 16 bits
*/
if (!IS_16BIT (extents->x1 - 1) ||
!IS_16BIT (extents->y1 - 1) ||
!IS_16BIT (extents->x2 + 1) ||
!IS_16BIT (extents->y2 + 1))
{
return FALSE;
}
 
transform = image->common.transform;
if (image->common.type == BITS)
{
/* During repeat mode calculations we might convert the
* width/height of an image to fixed 16.16, so we need
* them to be smaller than 16 bits.
*/
if (image->bits.width >= 0x7fff || image->bits.height >= 0x7fff)
return FALSE;
 
if ((image->common.flags & FAST_PATH_ID_TRANSFORM) == FAST_PATH_ID_TRANSFORM &&
extents->x1 >= 0 &&
extents->y1 >= 0 &&
extents->x2 <= image->bits.width &&
extents->y2 <= image->bits.height)
{
*flags |= FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
return TRUE;
}
 
switch (image->common.filter)
{
case PIXMAN_FILTER_CONVOLUTION:
params = image->common.filter_params;
x_off = - pixman_fixed_e - ((params[0] - pixman_fixed_1) >> 1);
y_off = - pixman_fixed_e - ((params[1] - pixman_fixed_1) >> 1);
width = params[0];
height = params[1];
break;
 
case PIXMAN_FILTER_SEPARABLE_CONVOLUTION:
params = image->common.filter_params;
x_off = - pixman_fixed_e - ((params[0] - pixman_fixed_1) >> 1);
y_off = - pixman_fixed_e - ((params[1] - pixman_fixed_1) >> 1);
width = params[0];
height = params[1];
break;
case PIXMAN_FILTER_GOOD:
case PIXMAN_FILTER_BEST:
case PIXMAN_FILTER_BILINEAR:
x_off = - pixman_fixed_1 / 2;
y_off = - pixman_fixed_1 / 2;
width = pixman_fixed_1;
height = pixman_fixed_1;
break;
 
case PIXMAN_FILTER_FAST:
case PIXMAN_FILTER_NEAREST:
x_off = - pixman_fixed_e;
y_off = - pixman_fixed_e;
width = 0;
height = 0;
break;
 
default:
return FALSE;
}
}
else
{
x_off = 0;
y_off = 0;
width = 0;
height = 0;
}
 
if (!compute_transformed_extents (transform, extents, &transformed))
return FALSE;
 
/* Expand the source area by a tiny bit so account of different rounding that
* may happen during sampling. Note that (8 * pixman_fixed_e) is very far from
* 0.5 so this won't cause the area computed to be overly pessimistic.
*/
transformed.x1 -= 8 * pixman_fixed_e;
transformed.y1 -= 8 * pixman_fixed_e;
transformed.x2 += 8 * pixman_fixed_e;
transformed.y2 += 8 * pixman_fixed_e;
 
if (image->common.type == BITS)
{
if (pixman_fixed_to_int (transformed.x1) >= 0 &&
pixman_fixed_to_int (transformed.y1) >= 0 &&
pixman_fixed_to_int (transformed.x2) < image->bits.width &&
pixman_fixed_to_int (transformed.y2) < image->bits.height)
{
*flags |= FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
}
 
if (pixman_fixed_to_int (transformed.x1 - pixman_fixed_1 / 2) >= 0 &&
pixman_fixed_to_int (transformed.y1 - pixman_fixed_1 / 2) >= 0 &&
pixman_fixed_to_int (transformed.x2 + pixman_fixed_1 / 2) < image->bits.width &&
pixman_fixed_to_int (transformed.y2 + pixman_fixed_1 / 2) < image->bits.height)
{
*flags |= FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR;
}
}
 
/* Check we don't overflow when the destination extents are expanded by one.
* This ensures that compositing functions can simply walk the source space
* using 16.16 variables without worrying about overflow.
*/
exp_extents = *extents;
exp_extents.x1 -= 1;
exp_extents.y1 -= 1;
exp_extents.x2 += 1;
exp_extents.y2 += 1;
 
if (!compute_transformed_extents (transform, &exp_extents, &transformed))
return FALSE;
if (!IS_16_16 (transformed.x1 + x_off - 8 * pixman_fixed_e) ||
!IS_16_16 (transformed.y1 + y_off - 8 * pixman_fixed_e) ||
!IS_16_16 (transformed.x2 + x_off + 8 * pixman_fixed_e + width) ||
!IS_16_16 (transformed.y2 + y_off + 8 * pixman_fixed_e + height))
{
return FALSE;
}
 
return TRUE;
}
 
/*
* Work around GCC bug causing crashes in Mozilla with SSE2
*
* When using -msse, gcc generates movdqa instructions assuming that
* the stack is 16 byte aligned. Unfortunately some applications, such
* as Mozilla and Mono, end up aligning the stack to 4 bytes, which
* causes the movdqa instructions to fail.
*
* The __force_align_arg_pointer__ makes gcc generate a prologue that
* realigns the stack pointer to 16 bytes.
*
* On x86-64 this is not necessary because the standard ABI already
* calls for a 16 byte aligned stack.
*
* See https://bugs.freedesktop.org/show_bug.cgi?id=15693
*/
#if defined (USE_SSE2) && defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
__attribute__((__force_align_arg_pointer__))
#endif
PIXMAN_EXPORT void
pixman_image_composite32 (pixman_op_t op,
pixman_image_t * src,
pixman_image_t * mask,
pixman_image_t * dest,
int32_t src_x,
int32_t src_y,
int32_t mask_x,
int32_t mask_y,
int32_t dest_x,
int32_t dest_y,
int32_t width,
int32_t height)
{
pixman_format_code_t src_format, mask_format, dest_format;
pixman_region32_t region;
pixman_box32_t extents;
pixman_implementation_t *imp;
pixman_composite_func_t func;
pixman_composite_info_t info;
const pixman_box32_t *pbox;
int n;
 
_pixman_image_validate (src);
if (mask)
_pixman_image_validate (mask);
_pixman_image_validate (dest);
 
src_format = src->common.extended_format_code;
info.src_flags = src->common.flags;
 
if (mask && !(mask->common.flags & FAST_PATH_IS_OPAQUE))
{
mask_format = mask->common.extended_format_code;
info.mask_flags = mask->common.flags;
}
else
{
mask_format = PIXMAN_null;
info.mask_flags = FAST_PATH_IS_OPAQUE;
}
 
dest_format = dest->common.extended_format_code;
info.dest_flags = dest->common.flags;
 
/* Check for pixbufs */
if ((mask_format == PIXMAN_a8r8g8b8 || mask_format == PIXMAN_a8b8g8r8) &&
(src->type == BITS && src->bits.bits == mask->bits.bits) &&
(src->common.repeat == mask->common.repeat) &&
(info.src_flags & info.mask_flags & FAST_PATH_ID_TRANSFORM) &&
(src_x == mask_x && src_y == mask_y))
{
if (src_format == PIXMAN_x8b8g8r8)
src_format = mask_format = PIXMAN_pixbuf;
else if (src_format == PIXMAN_x8r8g8b8)
src_format = mask_format = PIXMAN_rpixbuf;
}
 
pixman_region32_init (&region);
 
if (!_pixman_compute_composite_region32 (
&region, src, mask, dest,
src_x, src_y, mask_x, mask_y, dest_x, dest_y, width, height))
{
goto out;
}
 
extents = *pixman_region32_extents (&region);
 
extents.x1 -= dest_x - src_x;
extents.y1 -= dest_y - src_y;
extents.x2 -= dest_x - src_x;
extents.y2 -= dest_y - src_y;
 
if (!analyze_extent (src, &extents, &info.src_flags))
goto out;
 
extents.x1 -= src_x - mask_x;
extents.y1 -= src_y - mask_y;
extents.x2 -= src_x - mask_x;
extents.y2 -= src_y - mask_y;
 
if (!analyze_extent (mask, &extents, &info.mask_flags))
goto out;
 
/* If the clip is within the source samples, and the samples are
* opaque, then the source is effectively opaque.
*/
#define NEAREST_OPAQUE (FAST_PATH_SAMPLES_OPAQUE | \
FAST_PATH_NEAREST_FILTER | \
FAST_PATH_SAMPLES_COVER_CLIP_NEAREST)
#define BILINEAR_OPAQUE (FAST_PATH_SAMPLES_OPAQUE | \
FAST_PATH_BILINEAR_FILTER | \
FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR)
 
if ((info.src_flags & NEAREST_OPAQUE) == NEAREST_OPAQUE ||
(info.src_flags & BILINEAR_OPAQUE) == BILINEAR_OPAQUE)
{
info.src_flags |= FAST_PATH_IS_OPAQUE;
}
 
if ((info.mask_flags & NEAREST_OPAQUE) == NEAREST_OPAQUE ||
(info.mask_flags & BILINEAR_OPAQUE) == BILINEAR_OPAQUE)
{
info.mask_flags |= FAST_PATH_IS_OPAQUE;
}
 
/*
* Check if we can replace our operator by a simpler one
* if the src or dest are opaque. The output operator should be
* mathematically equivalent to the source.
*/
info.op = optimize_operator (op, info.src_flags, info.mask_flags, info.dest_flags);
 
_pixman_implementation_lookup_composite (
get_implementation (), info.op,
src_format, info.src_flags,
mask_format, info.mask_flags,
dest_format, info.dest_flags,
&imp, &func);
 
info.src_image = src;
info.mask_image = mask;
info.dest_image = dest;
 
pbox = pixman_region32_rectangles (&region, &n);
 
while (n--)
{
info.src_x = pbox->x1 + src_x - dest_x;
info.src_y = pbox->y1 + src_y - dest_y;
info.mask_x = pbox->x1 + mask_x - dest_x;
info.mask_y = pbox->y1 + mask_y - dest_y;
info.dest_x = pbox->x1;
info.dest_y = pbox->y1;
info.width = pbox->x2 - pbox->x1;
info.height = pbox->y2 - pbox->y1;
 
func (imp, &info);
 
pbox++;
}
 
out:
pixman_region32_fini (&region);
}
 
PIXMAN_EXPORT void
pixman_image_composite (pixman_op_t op,
pixman_image_t * src,
pixman_image_t * mask,
pixman_image_t * dest,
int16_t src_x,
int16_t src_y,
int16_t mask_x,
int16_t mask_y,
int16_t dest_x,
int16_t dest_y,
uint16_t width,
uint16_t height)
{
pixman_image_composite32 (op, src, mask, dest, src_x, src_y,
mask_x, mask_y, dest_x, dest_y, width, height);
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_blt (uint32_t *src_bits,
uint32_t *dst_bits,
int src_stride,
int dst_stride,
int src_bpp,
int dst_bpp,
int src_x,
int src_y,
int dest_x,
int dest_y,
int width,
int height)
{
return _pixman_implementation_blt (get_implementation(),
src_bits, dst_bits, src_stride, dst_stride,
src_bpp, dst_bpp,
src_x, src_y,
dest_x, dest_y,
width, height);
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_fill (uint32_t *bits,
int stride,
int bpp,
int x,
int y,
int width,
int height,
uint32_t filler)
{
return _pixman_implementation_fill (
get_implementation(), bits, stride, bpp, x, y, width, height, filler);
}
 
static uint32_t
color_to_uint32 (const pixman_color_t *color)
{
return
(color->alpha >> 8 << 24) |
(color->red >> 8 << 16) |
(color->green & 0xff00) |
(color->blue >> 8);
}
 
static pixman_bool_t
color_to_pixel (const pixman_color_t *color,
uint32_t * pixel,
pixman_format_code_t format)
{
uint32_t c = color_to_uint32 (color);
 
if (!(format == PIXMAN_a8r8g8b8 ||
format == PIXMAN_x8r8g8b8 ||
format == PIXMAN_a8b8g8r8 ||
format == PIXMAN_x8b8g8r8 ||
format == PIXMAN_b8g8r8a8 ||
format == PIXMAN_b8g8r8x8 ||
format == PIXMAN_r8g8b8a8 ||
format == PIXMAN_r8g8b8x8 ||
format == PIXMAN_r5g6b5 ||
format == PIXMAN_b5g6r5 ||
format == PIXMAN_a8 ||
format == PIXMAN_a1))
{
return FALSE;
}
 
if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR)
{
c = ((c & 0xff000000) >> 0) |
((c & 0x00ff0000) >> 16) |
((c & 0x0000ff00) >> 0) |
((c & 0x000000ff) << 16);
}
if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA)
{
c = ((c & 0xff000000) >> 24) |
((c & 0x00ff0000) >> 8) |
((c & 0x0000ff00) << 8) |
((c & 0x000000ff) << 24);
}
if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_RGBA)
c = ((c & 0xff000000) >> 24) | (c << 8);
 
if (format == PIXMAN_a1)
c = c >> 31;
else if (format == PIXMAN_a8)
c = c >> 24;
else if (format == PIXMAN_r5g6b5 ||
format == PIXMAN_b5g6r5)
c = convert_8888_to_0565 (c);
 
#if 0
printf ("color: %x %x %x %x\n", color->alpha, color->red, color->green, color->blue);
printf ("pixel: %x\n", c);
#endif
 
*pixel = c;
return TRUE;
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_image_fill_rectangles (pixman_op_t op,
pixman_image_t * dest,
const pixman_color_t * color,
int n_rects,
const pixman_rectangle16_t *rects)
{
pixman_box32_t stack_boxes[6];
pixman_box32_t *boxes;
pixman_bool_t result;
int i;
 
if (n_rects > 6)
{
boxes = pixman_malloc_ab (sizeof (pixman_box32_t), n_rects);
if (boxes == NULL)
return FALSE;
}
else
{
boxes = stack_boxes;
}
 
for (i = 0; i < n_rects; ++i)
{
boxes[i].x1 = rects[i].x;
boxes[i].y1 = rects[i].y;
boxes[i].x2 = boxes[i].x1 + rects[i].width;
boxes[i].y2 = boxes[i].y1 + rects[i].height;
}
 
result = pixman_image_fill_boxes (op, dest, color, n_rects, boxes);
 
if (boxes != stack_boxes)
free (boxes);
return result;
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_image_fill_boxes (pixman_op_t op,
pixman_image_t * dest,
const pixman_color_t *color,
int n_boxes,
const pixman_box32_t *boxes)
{
pixman_image_t *solid;
pixman_color_t c;
int i;
 
_pixman_image_validate (dest);
if (color->alpha == 0xffff)
{
if (op == PIXMAN_OP_OVER)
op = PIXMAN_OP_SRC;
}
 
if (op == PIXMAN_OP_CLEAR)
{
c.red = 0;
c.green = 0;
c.blue = 0;
c.alpha = 0;
 
color = &c;
 
op = PIXMAN_OP_SRC;
}
 
if (op == PIXMAN_OP_SRC)
{
uint32_t pixel;
 
if (color_to_pixel (color, &pixel, dest->bits.format))
{
pixman_region32_t fill_region;
int n_rects, j;
pixman_box32_t *rects;
 
if (!pixman_region32_init_rects (&fill_region, boxes, n_boxes))
return FALSE;
 
if (dest->common.have_clip_region)
{
if (!pixman_region32_intersect (&fill_region,
&fill_region,
&dest->common.clip_region))
return FALSE;
}
 
rects = pixman_region32_rectangles (&fill_region, &n_rects);
for (j = 0; j < n_rects; ++j)
{
const pixman_box32_t *rect = &(rects[j]);
pixman_fill (dest->bits.bits, dest->bits.rowstride, PIXMAN_FORMAT_BPP (dest->bits.format),
rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1,
pixel);
}
 
pixman_region32_fini (&fill_region);
return TRUE;
}
}
 
solid = pixman_image_create_solid_fill (color);
if (!solid)
return FALSE;
 
for (i = 0; i < n_boxes; ++i)
{
const pixman_box32_t *box = &(boxes[i]);
 
pixman_image_composite32 (op, solid, NULL, dest,
0, 0, 0, 0,
box->x1, box->y1,
box->x2 - box->x1, box->y2 - box->y1);
}
 
pixman_image_unref (solid);
 
return TRUE;
}
 
/**
* pixman_version:
*
* Returns the version of the pixman library encoded in a single
* integer as per %PIXMAN_VERSION_ENCODE. The encoding ensures that
* later versions compare greater than earlier versions.
*
* A run-time comparison to check that pixman's version is greater than
* or equal to version X.Y.Z could be performed as follows:
*
* <informalexample><programlisting>
* if (pixman_version() >= PIXMAN_VERSION_ENCODE(X,Y,Z)) {...}
* </programlisting></informalexample>
*
* See also pixman_version_string() as well as the compile-time
* equivalents %PIXMAN_VERSION and %PIXMAN_VERSION_STRING.
*
* Return value: the encoded version.
**/
PIXMAN_EXPORT int
pixman_version (void)
{
return PIXMAN_VERSION;
}
 
/**
* pixman_version_string:
*
* Returns the version of the pixman library as a human-readable string
* of the form "X.Y.Z".
*
* See also pixman_version() as well as the compile-time equivalents
* %PIXMAN_VERSION_STRING and %PIXMAN_VERSION.
*
* Return value: a string containing the version.
**/
PIXMAN_EXPORT const char*
pixman_version_string (void)
{
return PIXMAN_VERSION_STRING;
}
 
/**
* pixman_format_supported_source:
* @format: A pixman_format_code_t format
*
* Return value: whether the provided format code is a supported
* format for a pixman surface used as a source in
* rendering.
*
* Currently, all pixman_format_code_t values are supported.
**/
PIXMAN_EXPORT pixman_bool_t
pixman_format_supported_source (pixman_format_code_t format)
{
switch (format)
{
/* 32 bpp formats */
case PIXMAN_a2b10g10r10:
case PIXMAN_x2b10g10r10:
case PIXMAN_a2r10g10b10:
case PIXMAN_x2r10g10b10:
case PIXMAN_a8r8g8b8:
case PIXMAN_a8r8g8b8_sRGB:
case PIXMAN_x8r8g8b8:
case PIXMAN_a8b8g8r8:
case PIXMAN_x8b8g8r8:
case PIXMAN_b8g8r8a8:
case PIXMAN_b8g8r8x8:
case PIXMAN_r8g8b8a8:
case PIXMAN_r8g8b8x8:
case PIXMAN_r8g8b8:
case PIXMAN_b8g8r8:
case PIXMAN_r5g6b5:
case PIXMAN_b5g6r5:
case PIXMAN_x14r6g6b6:
/* 16 bpp formats */
case PIXMAN_a1r5g5b5:
case PIXMAN_x1r5g5b5:
case PIXMAN_a1b5g5r5:
case PIXMAN_x1b5g5r5:
case PIXMAN_a4r4g4b4:
case PIXMAN_x4r4g4b4:
case PIXMAN_a4b4g4r4:
case PIXMAN_x4b4g4r4:
/* 8bpp formats */
case PIXMAN_a8:
case PIXMAN_r3g3b2:
case PIXMAN_b2g3r3:
case PIXMAN_a2r2g2b2:
case PIXMAN_a2b2g2r2:
case PIXMAN_c8:
case PIXMAN_g8:
case PIXMAN_x4a4:
/* Collides with PIXMAN_c8
case PIXMAN_x4c4:
*/
/* Collides with PIXMAN_g8
case PIXMAN_x4g4:
*/
/* 4bpp formats */
case PIXMAN_a4:
case PIXMAN_r1g2b1:
case PIXMAN_b1g2r1:
case PIXMAN_a1r1g1b1:
case PIXMAN_a1b1g1r1:
case PIXMAN_c4:
case PIXMAN_g4:
/* 1bpp formats */
case PIXMAN_a1:
case PIXMAN_g1:
/* YUV formats */
case PIXMAN_yuy2:
case PIXMAN_yv12:
return TRUE;
 
default:
return FALSE;
}
}
 
/**
* pixman_format_supported_destination:
* @format: A pixman_format_code_t format
*
* Return value: whether the provided format code is a supported
* format for a pixman surface used as a destination in
* rendering.
*
* Currently, all pixman_format_code_t values are supported
* except for the YUV formats.
**/
PIXMAN_EXPORT pixman_bool_t
pixman_format_supported_destination (pixman_format_code_t format)
{
/* YUV formats cannot be written to at the moment */
if (format == PIXMAN_yuy2 || format == PIXMAN_yv12)
return FALSE;
 
return pixman_format_supported_source (format);
}
 
PIXMAN_EXPORT pixman_bool_t
pixman_compute_composite_region (pixman_region16_t * region,
pixman_image_t * src_image,
pixman_image_t * mask_image,
pixman_image_t * dest_image,
int16_t src_x,
int16_t src_y,
int16_t mask_x,
int16_t mask_y,
int16_t dest_x,
int16_t dest_y,
uint16_t width,
uint16_t height)
{
pixman_region32_t r32;
pixman_bool_t retval;
 
pixman_region32_init (&r32);
 
retval = _pixman_compute_composite_region32 (
&r32, src_image, mask_image, dest_image,
src_x, src_y, mask_x, mask_y, dest_x, dest_y,
width, height);
 
if (retval)
{
if (!pixman_region16_copy_from_region32 (region, &r32))
retval = FALSE;
}
 
pixman_region32_fini (&r32);
return retval;
}
/contrib/sdk/sources/pixman/pixman.h
0,0 → 1,1111
/***********************************************************
 
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 © 1998, 2004 Keith Packard
* Copyright 2007 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
 
#ifndef PIXMAN_H__
#define PIXMAN_H__
 
#include <pixman-version.h>
 
#ifdef __cplusplus
#define PIXMAN_BEGIN_DECLS extern "C" {
#define PIXMAN_END_DECLS }
#else
#define PIXMAN_BEGIN_DECLS
#define PIXMAN_END_DECLS
#endif
 
PIXMAN_BEGIN_DECLS
 
/*
* Standard integers
*/
 
#if !defined (PIXMAN_DONT_DEFINE_STDINT)
 
#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || defined (_sgi) || defined (__sun) || defined (sun) || defined (__digital__) || defined (__HP_cc)
# include <inttypes.h>
/* VS 2010 (_MSC_VER 1600) has stdint.h */
#elif defined (_MSC_VER) && _MSC_VER < 1600
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#elif defined (_AIX)
# include <sys/inttypes.h>
#else
# include <stdint.h>
#endif
 
#endif
 
/*
* Boolean
*/
typedef int pixman_bool_t;
 
/*
* Fixpoint numbers
*/
typedef int64_t pixman_fixed_32_32_t;
typedef pixman_fixed_32_32_t pixman_fixed_48_16_t;
typedef uint32_t pixman_fixed_1_31_t;
typedef uint32_t pixman_fixed_1_16_t;
typedef int32_t pixman_fixed_16_16_t;
typedef pixman_fixed_16_16_t pixman_fixed_t;
 
#define pixman_fixed_e ((pixman_fixed_t) 1)
#define pixman_fixed_1 (pixman_int_to_fixed(1))
#define pixman_fixed_1_minus_e (pixman_fixed_1 - pixman_fixed_e)
#define pixman_fixed_minus_1 (pixman_int_to_fixed(-1))
#define pixman_fixed_to_int(f) ((int) ((f) >> 16))
#define pixman_int_to_fixed(i) ((pixman_fixed_t) ((i) << 16))
#define pixman_fixed_to_double(f) (double) ((f) / (double) pixman_fixed_1)
#define pixman_double_to_fixed(d) ((pixman_fixed_t) ((d) * 65536.0))
#define pixman_fixed_frac(f) ((f) & pixman_fixed_1_minus_e)
#define pixman_fixed_floor(f) ((f) & ~pixman_fixed_1_minus_e)
#define pixman_fixed_ceil(f) pixman_fixed_floor ((f) + pixman_fixed_1_minus_e)
#define pixman_fixed_fraction(f) ((f) & pixman_fixed_1_minus_e)
#define pixman_fixed_mod_2(f) ((f) & (pixman_fixed1 | pixman_fixed_1_minus_e))
#define pixman_max_fixed_48_16 ((pixman_fixed_48_16_t) 0x7fffffff)
#define pixman_min_fixed_48_16 (-((pixman_fixed_48_16_t) 1 << 31))
 
/*
* Misc structs
*/
typedef struct pixman_color pixman_color_t;
typedef struct pixman_point_fixed pixman_point_fixed_t;
typedef struct pixman_line_fixed pixman_line_fixed_t;
typedef struct pixman_vector pixman_vector_t;
typedef struct pixman_transform pixman_transform_t;
 
struct pixman_color
{
uint16_t red;
uint16_t green;
uint16_t blue;
uint16_t alpha;
};
 
struct pixman_point_fixed
{
pixman_fixed_t x;
pixman_fixed_t y;
};
 
struct pixman_line_fixed
{
pixman_point_fixed_t p1, p2;
};
 
/*
* Fixed point matrices
*/
 
struct pixman_vector
{
pixman_fixed_t vector[3];
};
 
struct pixman_transform
{
pixman_fixed_t matrix[3][3];
};
 
/* forward declaration (sorry) */
struct pixman_box16;
typedef union pixman_image pixman_image_t;
 
void pixman_transform_init_identity (struct pixman_transform *matrix);
pixman_bool_t pixman_transform_point_3d (const struct pixman_transform *transform,
struct pixman_vector *vector);
pixman_bool_t pixman_transform_point (const struct pixman_transform *transform,
struct pixman_vector *vector);
pixman_bool_t pixman_transform_multiply (struct pixman_transform *dst,
const struct pixman_transform *l,
const struct pixman_transform *r);
void pixman_transform_init_scale (struct pixman_transform *t,
pixman_fixed_t sx,
pixman_fixed_t sy);
pixman_bool_t pixman_transform_scale (struct pixman_transform *forward,
struct pixman_transform *reverse,
pixman_fixed_t sx,
pixman_fixed_t sy);
void pixman_transform_init_rotate (struct pixman_transform *t,
pixman_fixed_t cos,
pixman_fixed_t sin);
pixman_bool_t pixman_transform_rotate (struct pixman_transform *forward,
struct pixman_transform *reverse,
pixman_fixed_t c,
pixman_fixed_t s);
void pixman_transform_init_translate (struct pixman_transform *t,
pixman_fixed_t tx,
pixman_fixed_t ty);
pixman_bool_t pixman_transform_translate (struct pixman_transform *forward,
struct pixman_transform *reverse,
pixman_fixed_t tx,
pixman_fixed_t ty);
pixman_bool_t pixman_transform_bounds (const struct pixman_transform *matrix,
struct pixman_box16 *b);
pixman_bool_t pixman_transform_invert (struct pixman_transform *dst,
const struct pixman_transform *src);
pixman_bool_t pixman_transform_is_identity (const struct pixman_transform *t);
pixman_bool_t pixman_transform_is_scale (const struct pixman_transform *t);
pixman_bool_t pixman_transform_is_int_translate (const struct pixman_transform *t);
pixman_bool_t pixman_transform_is_inverse (const struct pixman_transform *a,
const struct pixman_transform *b);
 
/*
* Floating point matrices
*/
typedef struct pixman_f_transform pixman_f_transform_t;
typedef struct pixman_f_vector pixman_f_vector_t;
 
struct pixman_f_vector
{
double v[3];
};
 
struct pixman_f_transform
{
double m[3][3];
};
 
pixman_bool_t pixman_transform_from_pixman_f_transform (struct pixman_transform *t,
const struct pixman_f_transform *ft);
void pixman_f_transform_from_pixman_transform (struct pixman_f_transform *ft,
const struct pixman_transform *t);
pixman_bool_t pixman_f_transform_invert (struct pixman_f_transform *dst,
const struct pixman_f_transform *src);
pixman_bool_t pixman_f_transform_point (const struct pixman_f_transform *t,
struct pixman_f_vector *v);
void pixman_f_transform_point_3d (const struct pixman_f_transform *t,
struct pixman_f_vector *v);
void pixman_f_transform_multiply (struct pixman_f_transform *dst,
const struct pixman_f_transform *l,
const struct pixman_f_transform *r);
void pixman_f_transform_init_scale (struct pixman_f_transform *t,
double sx,
double sy);
pixman_bool_t pixman_f_transform_scale (struct pixman_f_transform *forward,
struct pixman_f_transform *reverse,
double sx,
double sy);
void pixman_f_transform_init_rotate (struct pixman_f_transform *t,
double cos,
double sin);
pixman_bool_t pixman_f_transform_rotate (struct pixman_f_transform *forward,
struct pixman_f_transform *reverse,
double c,
double s);
void pixman_f_transform_init_translate (struct pixman_f_transform *t,
double tx,
double ty);
pixman_bool_t pixman_f_transform_translate (struct pixman_f_transform *forward,
struct pixman_f_transform *reverse,
double tx,
double ty);
pixman_bool_t pixman_f_transform_bounds (const struct pixman_f_transform *t,
struct pixman_box16 *b);
void pixman_f_transform_init_identity (struct pixman_f_transform *t);
 
typedef enum
{
PIXMAN_REPEAT_NONE,
PIXMAN_REPEAT_NORMAL,
PIXMAN_REPEAT_PAD,
PIXMAN_REPEAT_REFLECT
} pixman_repeat_t;
 
typedef enum
{
PIXMAN_FILTER_FAST,
PIXMAN_FILTER_GOOD,
PIXMAN_FILTER_BEST,
PIXMAN_FILTER_NEAREST,
PIXMAN_FILTER_BILINEAR,
PIXMAN_FILTER_CONVOLUTION,
 
/* The SEPARABLE_CONVOLUTION filter takes the following parameters:
*
* width: integer given as 16.16 fixpoint number
* height: integer given as 16.16 fixpoint number
* x_phase_bits: integer given as 16.16 fixpoint
* y_phase_bits: integer given as 16.16 fixpoint
* xtables: (1 << x_phase_bits) tables of size width
* ytables: (1 << y_phase_bits) tables of size height
*
* When sampling at (x, y), the location is first rounded to one of
* n_x_phases * n_y_phases subpixel positions. These subpixel positions
* determine an xtable and a ytable to use.
*
* Conceptually a width x height matrix is then formed in which each entry
* is the product of the corresponding entries in the x and y tables.
* This matrix is then aligned with the image pixels such that its center
* is as close as possible to the subpixel location chosen earlier. Then
* the image is convolved with the matrix and the resulting pixel returned.
*/
PIXMAN_FILTER_SEPARABLE_CONVOLUTION
} pixman_filter_t;
 
typedef enum
{
PIXMAN_OP_CLEAR = 0x00,
PIXMAN_OP_SRC = 0x01,
PIXMAN_OP_DST = 0x02,
PIXMAN_OP_OVER = 0x03,
PIXMAN_OP_OVER_REVERSE = 0x04,
PIXMAN_OP_IN = 0x05,
PIXMAN_OP_IN_REVERSE = 0x06,
PIXMAN_OP_OUT = 0x07,
PIXMAN_OP_OUT_REVERSE = 0x08,
PIXMAN_OP_ATOP = 0x09,
PIXMAN_OP_ATOP_REVERSE = 0x0a,
PIXMAN_OP_XOR = 0x0b,
PIXMAN_OP_ADD = 0x0c,
PIXMAN_OP_SATURATE = 0x0d,
 
PIXMAN_OP_DISJOINT_CLEAR = 0x10,
PIXMAN_OP_DISJOINT_SRC = 0x11,
PIXMAN_OP_DISJOINT_DST = 0x12,
PIXMAN_OP_DISJOINT_OVER = 0x13,
PIXMAN_OP_DISJOINT_OVER_REVERSE = 0x14,
PIXMAN_OP_DISJOINT_IN = 0x15,
PIXMAN_OP_DISJOINT_IN_REVERSE = 0x16,
PIXMAN_OP_DISJOINT_OUT = 0x17,
PIXMAN_OP_DISJOINT_OUT_REVERSE = 0x18,
PIXMAN_OP_DISJOINT_ATOP = 0x19,
PIXMAN_OP_DISJOINT_ATOP_REVERSE = 0x1a,
PIXMAN_OP_DISJOINT_XOR = 0x1b,
 
PIXMAN_OP_CONJOINT_CLEAR = 0x20,
PIXMAN_OP_CONJOINT_SRC = 0x21,
PIXMAN_OP_CONJOINT_DST = 0x22,
PIXMAN_OP_CONJOINT_OVER = 0x23,
PIXMAN_OP_CONJOINT_OVER_REVERSE = 0x24,
PIXMAN_OP_CONJOINT_IN = 0x25,
PIXMAN_OP_CONJOINT_IN_REVERSE = 0x26,
PIXMAN_OP_CONJOINT_OUT = 0x27,
PIXMAN_OP_CONJOINT_OUT_REVERSE = 0x28,
PIXMAN_OP_CONJOINT_ATOP = 0x29,
PIXMAN_OP_CONJOINT_ATOP_REVERSE = 0x2a,
PIXMAN_OP_CONJOINT_XOR = 0x2b,
 
PIXMAN_OP_MULTIPLY = 0x30,
PIXMAN_OP_SCREEN = 0x31,
PIXMAN_OP_OVERLAY = 0x32,
PIXMAN_OP_DARKEN = 0x33,
PIXMAN_OP_LIGHTEN = 0x34,
PIXMAN_OP_COLOR_DODGE = 0x35,
PIXMAN_OP_COLOR_BURN = 0x36,
PIXMAN_OP_HARD_LIGHT = 0x37,
PIXMAN_OP_SOFT_LIGHT = 0x38,
PIXMAN_OP_DIFFERENCE = 0x39,
PIXMAN_OP_EXCLUSION = 0x3a,
PIXMAN_OP_HSL_HUE = 0x3b,
PIXMAN_OP_HSL_SATURATION = 0x3c,
PIXMAN_OP_HSL_COLOR = 0x3d,
PIXMAN_OP_HSL_LUMINOSITY = 0x3e
 
#ifdef PIXMAN_USE_INTERNAL_API
,
PIXMAN_N_OPERATORS,
PIXMAN_OP_NONE = PIXMAN_N_OPERATORS
#endif
} pixman_op_t;
 
/*
* Regions
*/
typedef struct pixman_region16_data pixman_region16_data_t;
typedef struct pixman_box16 pixman_box16_t;
typedef struct pixman_rectangle16 pixman_rectangle16_t;
typedef struct pixman_region16 pixman_region16_t;
 
struct pixman_region16_data {
long size;
long numRects;
/* pixman_box16_t rects[size]; in memory but not explicitly declared */
};
 
struct pixman_rectangle16
{
int16_t x, y;
uint16_t width, height;
};
 
struct pixman_box16
{
int16_t x1, y1, x2, y2;
};
 
struct pixman_region16
{
pixman_box16_t extents;
pixman_region16_data_t *data;
};
 
typedef enum
{
PIXMAN_REGION_OUT,
PIXMAN_REGION_IN,
PIXMAN_REGION_PART
} pixman_region_overlap_t;
 
/* This function exists only to make it possible to preserve
* the X ABI - it should go away at first opportunity.
*/
void pixman_region_set_static_pointers (pixman_box16_t *empty_box,
pixman_region16_data_t *empty_data,
pixman_region16_data_t *broken_data);
 
/* creation/destruction */
void pixman_region_init (pixman_region16_t *region);
void pixman_region_init_rect (pixman_region16_t *region,
int x,
int y,
unsigned int width,
unsigned int height);
pixman_bool_t pixman_region_init_rects (pixman_region16_t *region,
const pixman_box16_t *boxes,
int count);
void pixman_region_init_with_extents (pixman_region16_t *region,
pixman_box16_t *extents);
void pixman_region_init_from_image (pixman_region16_t *region,
pixman_image_t *image);
void pixman_region_fini (pixman_region16_t *region);
 
 
/* manipulation */
void pixman_region_translate (pixman_region16_t *region,
int x,
int y);
pixman_bool_t pixman_region_copy (pixman_region16_t *dest,
pixman_region16_t *source);
pixman_bool_t pixman_region_intersect (pixman_region16_t *new_reg,
pixman_region16_t *reg1,
pixman_region16_t *reg2);
pixman_bool_t pixman_region_union (pixman_region16_t *new_reg,
pixman_region16_t *reg1,
pixman_region16_t *reg2);
pixman_bool_t pixman_region_union_rect (pixman_region16_t *dest,
pixman_region16_t *source,
int x,
int y,
unsigned int width,
unsigned int height);
pixman_bool_t pixman_region_intersect_rect (pixman_region16_t *dest,
pixman_region16_t *source,
int x,
int y,
unsigned int width,
unsigned int height);
pixman_bool_t pixman_region_subtract (pixman_region16_t *reg_d,
pixman_region16_t *reg_m,
pixman_region16_t *reg_s);
pixman_bool_t pixman_region_inverse (pixman_region16_t *new_reg,
pixman_region16_t *reg1,
pixman_box16_t *inv_rect);
pixman_bool_t pixman_region_contains_point (pixman_region16_t *region,
int x,
int y,
pixman_box16_t *box);
pixman_region_overlap_t pixman_region_contains_rectangle (pixman_region16_t *region,
pixman_box16_t *prect);
pixman_bool_t pixman_region_not_empty (pixman_region16_t *region);
pixman_box16_t * pixman_region_extents (pixman_region16_t *region);
int pixman_region_n_rects (pixman_region16_t *region);
pixman_box16_t * pixman_region_rectangles (pixman_region16_t *region,
int *n_rects);
pixman_bool_t pixman_region_equal (pixman_region16_t *region1,
pixman_region16_t *region2);
pixman_bool_t pixman_region_selfcheck (pixman_region16_t *region);
void pixman_region_reset (pixman_region16_t *region,
pixman_box16_t *box);
void pixman_region_clear (pixman_region16_t *region);
/*
* 32 bit regions
*/
typedef struct pixman_region32_data pixman_region32_data_t;
typedef struct pixman_box32 pixman_box32_t;
typedef struct pixman_rectangle32 pixman_rectangle32_t;
typedef struct pixman_region32 pixman_region32_t;
 
struct pixman_region32_data {
long size;
long numRects;
/* pixman_box32_t rects[size]; in memory but not explicitly declared */
};
 
struct pixman_rectangle32
{
int32_t x, y;
uint32_t width, height;
};
 
struct pixman_box32
{
int32_t x1, y1, x2, y2;
};
 
struct pixman_region32
{
pixman_box32_t extents;
pixman_region32_data_t *data;
};
 
/* creation/destruction */
void pixman_region32_init (pixman_region32_t *region);
void pixman_region32_init_rect (pixman_region32_t *region,
int x,
int y,
unsigned int width,
unsigned int height);
pixman_bool_t pixman_region32_init_rects (pixman_region32_t *region,
const pixman_box32_t *boxes,
int count);
void pixman_region32_init_with_extents (pixman_region32_t *region,
pixman_box32_t *extents);
void pixman_region32_init_from_image (pixman_region32_t *region,
pixman_image_t *image);
void pixman_region32_fini (pixman_region32_t *region);
 
 
/* manipulation */
void pixman_region32_translate (pixman_region32_t *region,
int x,
int y);
pixman_bool_t pixman_region32_copy (pixman_region32_t *dest,
pixman_region32_t *source);
pixman_bool_t pixman_region32_intersect (pixman_region32_t *new_reg,
pixman_region32_t *reg1,
pixman_region32_t *reg2);
pixman_bool_t pixman_region32_union (pixman_region32_t *new_reg,
pixman_region32_t *reg1,
pixman_region32_t *reg2);
pixman_bool_t pixman_region32_intersect_rect (pixman_region32_t *dest,
pixman_region32_t *source,
int x,
int y,
unsigned int width,
unsigned int height);
pixman_bool_t pixman_region32_union_rect (pixman_region32_t *dest,
pixman_region32_t *source,
int x,
int y,
unsigned int width,
unsigned int height);
pixman_bool_t pixman_region32_subtract (pixman_region32_t *reg_d,
pixman_region32_t *reg_m,
pixman_region32_t *reg_s);
pixman_bool_t pixman_region32_inverse (pixman_region32_t *new_reg,
pixman_region32_t *reg1,
pixman_box32_t *inv_rect);
pixman_bool_t pixman_region32_contains_point (pixman_region32_t *region,
int x,
int y,
pixman_box32_t *box);
pixman_region_overlap_t pixman_region32_contains_rectangle (pixman_region32_t *region,
pixman_box32_t *prect);
pixman_bool_t pixman_region32_not_empty (pixman_region32_t *region);
pixman_box32_t * pixman_region32_extents (pixman_region32_t *region);
int pixman_region32_n_rects (pixman_region32_t *region);
pixman_box32_t * pixman_region32_rectangles (pixman_region32_t *region,
int *n_rects);
pixman_bool_t pixman_region32_equal (pixman_region32_t *region1,
pixman_region32_t *region2);
pixman_bool_t pixman_region32_selfcheck (pixman_region32_t *region);
void pixman_region32_reset (pixman_region32_t *region,
pixman_box32_t *box);
void pixman_region32_clear (pixman_region32_t *region);
 
 
/* Copy / Fill / Misc */
pixman_bool_t pixman_blt (uint32_t *src_bits,
uint32_t *dst_bits,
int src_stride,
int dst_stride,
int src_bpp,
int dst_bpp,
int src_x,
int src_y,
int dest_x,
int dest_y,
int width,
int height);
pixman_bool_t pixman_fill (uint32_t *bits,
int stride,
int bpp,
int x,
int y,
int width,
int height,
uint32_t _xor);
 
int pixman_version (void);
const char* pixman_version_string (void);
 
/*
* Images
*/
typedef struct pixman_indexed pixman_indexed_t;
typedef struct pixman_gradient_stop pixman_gradient_stop_t;
 
typedef uint32_t (* pixman_read_memory_func_t) (const void *src, int size);
typedef void (* pixman_write_memory_func_t) (void *dst, uint32_t value, int size);
 
typedef void (* pixman_image_destroy_func_t) (pixman_image_t *image, void *data);
 
struct pixman_gradient_stop {
pixman_fixed_t x;
pixman_color_t color;
};
 
#define PIXMAN_MAX_INDEXED 256 /* XXX depth must be <= 8 */
 
#if PIXMAN_MAX_INDEXED <= 256
typedef uint8_t pixman_index_type;
#endif
 
struct pixman_indexed
{
pixman_bool_t color;
uint32_t rgba[PIXMAN_MAX_INDEXED];
pixman_index_type ent[32768];
};
 
/*
* While the protocol is generous in format support, the
* sample implementation allows only packed RGB and GBR
* representations for data to simplify software rendering,
*/
#define PIXMAN_FORMAT(bpp,type,a,r,g,b) (((bpp) << 24) | \
((type) << 16) | \
((a) << 12) | \
((r) << 8) | \
((g) << 4) | \
((b)))
 
#define PIXMAN_FORMAT_BPP(f) (((f) >> 24) )
#define PIXMAN_FORMAT_TYPE(f) (((f) >> 16) & 0xff)
#define PIXMAN_FORMAT_A(f) (((f) >> 12) & 0x0f)
#define PIXMAN_FORMAT_R(f) (((f) >> 8) & 0x0f)
#define PIXMAN_FORMAT_G(f) (((f) >> 4) & 0x0f)
#define PIXMAN_FORMAT_B(f) (((f) ) & 0x0f)
#define PIXMAN_FORMAT_RGB(f) (((f) ) & 0xfff)
#define PIXMAN_FORMAT_VIS(f) (((f) ) & 0xffff)
#define PIXMAN_FORMAT_DEPTH(f) (PIXMAN_FORMAT_A(f) + \
PIXMAN_FORMAT_R(f) + \
PIXMAN_FORMAT_G(f) + \
PIXMAN_FORMAT_B(f))
 
#define PIXMAN_TYPE_OTHER 0
#define PIXMAN_TYPE_A 1
#define PIXMAN_TYPE_ARGB 2
#define PIXMAN_TYPE_ABGR 3
#define PIXMAN_TYPE_COLOR 4
#define PIXMAN_TYPE_GRAY 5
#define PIXMAN_TYPE_YUY2 6
#define PIXMAN_TYPE_YV12 7
#define PIXMAN_TYPE_BGRA 8
#define PIXMAN_TYPE_RGBA 9
#define PIXMAN_TYPE_ARGB_SRGB 10
 
#define PIXMAN_FORMAT_COLOR(f) \
(PIXMAN_FORMAT_TYPE(f) == PIXMAN_TYPE_ARGB || \
PIXMAN_FORMAT_TYPE(f) == PIXMAN_TYPE_ABGR || \
PIXMAN_FORMAT_TYPE(f) == PIXMAN_TYPE_BGRA || \
PIXMAN_FORMAT_TYPE(f) == PIXMAN_TYPE_RGBA)
 
/* 32bpp formats */
typedef enum {
PIXMAN_a8r8g8b8 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ARGB,8,8,8,8),
PIXMAN_x8r8g8b8 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ARGB,0,8,8,8),
PIXMAN_a8b8g8r8 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ABGR,8,8,8,8),
PIXMAN_x8b8g8r8 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ABGR,0,8,8,8),
PIXMAN_b8g8r8a8 = PIXMAN_FORMAT(32,PIXMAN_TYPE_BGRA,8,8,8,8),
PIXMAN_b8g8r8x8 = PIXMAN_FORMAT(32,PIXMAN_TYPE_BGRA,0,8,8,8),
PIXMAN_r8g8b8a8 = PIXMAN_FORMAT(32,PIXMAN_TYPE_RGBA,8,8,8,8),
PIXMAN_r8g8b8x8 = PIXMAN_FORMAT(32,PIXMAN_TYPE_RGBA,0,8,8,8),
PIXMAN_x14r6g6b6 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ARGB,0,6,6,6),
PIXMAN_x2r10g10b10 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ARGB,0,10,10,10),
PIXMAN_a2r10g10b10 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ARGB,2,10,10,10),
PIXMAN_x2b10g10r10 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ABGR,0,10,10,10),
PIXMAN_a2b10g10r10 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ABGR,2,10,10,10),
 
/* sRGB formats */
PIXMAN_a8r8g8b8_sRGB = PIXMAN_FORMAT(32,PIXMAN_TYPE_ARGB_SRGB,8,8,8,8),
 
/* 24bpp formats */
PIXMAN_r8g8b8 = PIXMAN_FORMAT(24,PIXMAN_TYPE_ARGB,0,8,8,8),
PIXMAN_b8g8r8 = PIXMAN_FORMAT(24,PIXMAN_TYPE_ABGR,0,8,8,8),
 
/* 16bpp formats */
PIXMAN_r5g6b5 = PIXMAN_FORMAT(16,PIXMAN_TYPE_ARGB,0,5,6,5),
PIXMAN_b5g6r5 = PIXMAN_FORMAT(16,PIXMAN_TYPE_ABGR,0,5,6,5),
 
PIXMAN_a1r5g5b5 = PIXMAN_FORMAT(16,PIXMAN_TYPE_ARGB,1,5,5,5),
PIXMAN_x1r5g5b5 = PIXMAN_FORMAT(16,PIXMAN_TYPE_ARGB,0,5,5,5),
PIXMAN_a1b5g5r5 = PIXMAN_FORMAT(16,PIXMAN_TYPE_ABGR,1,5,5,5),
PIXMAN_x1b5g5r5 = PIXMAN_FORMAT(16,PIXMAN_TYPE_ABGR,0,5,5,5),
PIXMAN_a4r4g4b4 = PIXMAN_FORMAT(16,PIXMAN_TYPE_ARGB,4,4,4,4),
PIXMAN_x4r4g4b4 = PIXMAN_FORMAT(16,PIXMAN_TYPE_ARGB,0,4,4,4),
PIXMAN_a4b4g4r4 = PIXMAN_FORMAT(16,PIXMAN_TYPE_ABGR,4,4,4,4),
PIXMAN_x4b4g4r4 = PIXMAN_FORMAT(16,PIXMAN_TYPE_ABGR,0,4,4,4),
 
/* 8bpp formats */
PIXMAN_a8 = PIXMAN_FORMAT(8,PIXMAN_TYPE_A,8,0,0,0),
PIXMAN_r3g3b2 = PIXMAN_FORMAT(8,PIXMAN_TYPE_ARGB,0,3,3,2),
PIXMAN_b2g3r3 = PIXMAN_FORMAT(8,PIXMAN_TYPE_ABGR,0,3,3,2),
PIXMAN_a2r2g2b2 = PIXMAN_FORMAT(8,PIXMAN_TYPE_ARGB,2,2,2,2),
PIXMAN_a2b2g2r2 = PIXMAN_FORMAT(8,PIXMAN_TYPE_ABGR,2,2,2,2),
 
PIXMAN_c8 = PIXMAN_FORMAT(8,PIXMAN_TYPE_COLOR,0,0,0,0),
PIXMAN_g8 = PIXMAN_FORMAT(8,PIXMAN_TYPE_GRAY,0,0,0,0),
 
PIXMAN_x4a4 = PIXMAN_FORMAT(8,PIXMAN_TYPE_A,4,0,0,0),
 
PIXMAN_x4c4 = PIXMAN_FORMAT(8,PIXMAN_TYPE_COLOR,0,0,0,0),
PIXMAN_x4g4 = PIXMAN_FORMAT(8,PIXMAN_TYPE_GRAY,0,0,0,0),
 
/* 4bpp formats */
PIXMAN_a4 = PIXMAN_FORMAT(4,PIXMAN_TYPE_A,4,0,0,0),
PIXMAN_r1g2b1 = PIXMAN_FORMAT(4,PIXMAN_TYPE_ARGB,0,1,2,1),
PIXMAN_b1g2r1 = PIXMAN_FORMAT(4,PIXMAN_TYPE_ABGR,0,1,2,1),
PIXMAN_a1r1g1b1 = PIXMAN_FORMAT(4,PIXMAN_TYPE_ARGB,1,1,1,1),
PIXMAN_a1b1g1r1 = PIXMAN_FORMAT(4,PIXMAN_TYPE_ABGR,1,1,1,1),
 
PIXMAN_c4 = PIXMAN_FORMAT(4,PIXMAN_TYPE_COLOR,0,0,0,0),
PIXMAN_g4 = PIXMAN_FORMAT(4,PIXMAN_TYPE_GRAY,0,0,0,0),
 
/* 1bpp formats */
PIXMAN_a1 = PIXMAN_FORMAT(1,PIXMAN_TYPE_A,1,0,0,0),
 
PIXMAN_g1 = PIXMAN_FORMAT(1,PIXMAN_TYPE_GRAY,0,0,0,0),
 
/* YUV formats */
PIXMAN_yuy2 = PIXMAN_FORMAT(16,PIXMAN_TYPE_YUY2,0,0,0,0),
PIXMAN_yv12 = PIXMAN_FORMAT(12,PIXMAN_TYPE_YV12,0,0,0,0)
} pixman_format_code_t;
 
/* Querying supported format values. */
pixman_bool_t pixman_format_supported_destination (pixman_format_code_t format);
pixman_bool_t pixman_format_supported_source (pixman_format_code_t format);
 
/* Constructors */
pixman_image_t *pixman_image_create_solid_fill (const pixman_color_t *color);
pixman_image_t *pixman_image_create_linear_gradient (const pixman_point_fixed_t *p1,
const pixman_point_fixed_t *p2,
const pixman_gradient_stop_t *stops,
int n_stops);
pixman_image_t *pixman_image_create_radial_gradient (const pixman_point_fixed_t *inner,
const pixman_point_fixed_t *outer,
pixman_fixed_t inner_radius,
pixman_fixed_t outer_radius,
const pixman_gradient_stop_t *stops,
int n_stops);
pixman_image_t *pixman_image_create_conical_gradient (const pixman_point_fixed_t *center,
pixman_fixed_t angle,
const pixman_gradient_stop_t *stops,
int n_stops);
pixman_image_t *pixman_image_create_bits (pixman_format_code_t format,
int width,
int height,
uint32_t *bits,
int rowstride_bytes);
pixman_image_t *pixman_image_create_bits_no_clear (pixman_format_code_t format,
int width,
int height,
uint32_t * bits,
int rowstride_bytes);
 
/* Destructor */
pixman_image_t *pixman_image_ref (pixman_image_t *image);
pixman_bool_t pixman_image_unref (pixman_image_t *image);
 
void pixman_image_set_destroy_function (pixman_image_t *image,
pixman_image_destroy_func_t function,
void *data);
void * pixman_image_get_destroy_data (pixman_image_t *image);
 
/* Set properties */
pixman_bool_t pixman_image_set_clip_region (pixman_image_t *image,
pixman_region16_t *region);
pixman_bool_t pixman_image_set_clip_region32 (pixman_image_t *image,
pixman_region32_t *region);
void pixman_image_set_has_client_clip (pixman_image_t *image,
pixman_bool_t clien_clip);
pixman_bool_t pixman_image_set_transform (pixman_image_t *image,
const pixman_transform_t *transform);
void pixman_image_set_repeat (pixman_image_t *image,
pixman_repeat_t repeat);
pixman_bool_t pixman_image_set_filter (pixman_image_t *image,
pixman_filter_t filter,
const pixman_fixed_t *filter_params,
int n_filter_params);
void pixman_image_set_source_clipping (pixman_image_t *image,
pixman_bool_t source_clipping);
void pixman_image_set_alpha_map (pixman_image_t *image,
pixman_image_t *alpha_map,
int16_t x,
int16_t y);
void pixman_image_set_component_alpha (pixman_image_t *image,
pixman_bool_t component_alpha);
pixman_bool_t pixman_image_get_component_alpha (pixman_image_t *image);
void pixman_image_set_accessors (pixman_image_t *image,
pixman_read_memory_func_t read_func,
pixman_write_memory_func_t write_func);
void pixman_image_set_indexed (pixman_image_t *image,
const pixman_indexed_t *indexed);
uint32_t *pixman_image_get_data (pixman_image_t *image);
int pixman_image_get_width (pixman_image_t *image);
int pixman_image_get_height (pixman_image_t *image);
int pixman_image_get_stride (pixman_image_t *image); /* in bytes */
int pixman_image_get_depth (pixman_image_t *image);
pixman_format_code_t pixman_image_get_format (pixman_image_t *image);
 
typedef enum
{
PIXMAN_KERNEL_IMPULSE,
PIXMAN_KERNEL_BOX,
PIXMAN_KERNEL_LINEAR,
PIXMAN_KERNEL_CUBIC,
PIXMAN_KERNEL_GAUSSIAN,
PIXMAN_KERNEL_LANCZOS2,
PIXMAN_KERNEL_LANCZOS3,
PIXMAN_KERNEL_LANCZOS3_STRETCHED /* Jim Blinn's 'nice' filter */
} pixman_kernel_t;
 
/* Create the parameter list for a SEPARABLE_CONVOLUTION filter
* with the given kernels and scale parameters.
*/
pixman_fixed_t *
pixman_filter_create_separable_convolution (int *n_values,
pixman_fixed_t scale_x,
pixman_fixed_t scale_y,
pixman_kernel_t reconstruct_x,
pixman_kernel_t reconstruct_y,
pixman_kernel_t sample_x,
pixman_kernel_t sample_y,
int subsample_bits_x,
int subsample_bits_y);
 
pixman_bool_t pixman_image_fill_rectangles (pixman_op_t op,
pixman_image_t *image,
const pixman_color_t *color,
int n_rects,
const pixman_rectangle16_t *rects);
pixman_bool_t pixman_image_fill_boxes (pixman_op_t op,
pixman_image_t *dest,
const pixman_color_t *color,
int n_boxes,
const pixman_box32_t *boxes);
 
/* Composite */
pixman_bool_t pixman_compute_composite_region (pixman_region16_t *region,
pixman_image_t *src_image,
pixman_image_t *mask_image,
pixman_image_t *dest_image,
int16_t src_x,
int16_t src_y,
int16_t mask_x,
int16_t mask_y,
int16_t dest_x,
int16_t dest_y,
uint16_t width,
uint16_t height);
void pixman_image_composite (pixman_op_t op,
pixman_image_t *src,
pixman_image_t *mask,
pixman_image_t *dest,
int16_t src_x,
int16_t src_y,
int16_t mask_x,
int16_t mask_y,
int16_t dest_x,
int16_t dest_y,
uint16_t width,
uint16_t height);
void pixman_image_composite32 (pixman_op_t op,
pixman_image_t *src,
pixman_image_t *mask,
pixman_image_t *dest,
int32_t src_x,
int32_t src_y,
int32_t mask_x,
int32_t mask_y,
int32_t dest_x,
int32_t dest_y,
int32_t width,
int32_t height);
 
/* Executive Summary: This function is a no-op that only exists
* for historical reasons.
*
* There used to be a bug in the X server where it would rely on
* out-of-bounds accesses when it was asked to composite with a
* window as the source. It would create a pixman image pointing
* to some bogus position in memory, but then set a clip region
* to the position where the actual bits were.
*
* Due to a bug in old versions of pixman, where it would not clip
* against the image bounds when a clip region was set, this would
* actually work. So when the pixman bug was fixed, a workaround was
* added to allow certain out-of-bound accesses. This function disabled
* those workarounds.
*
* Since 0.21.2, pixman doesn't do these workarounds anymore, so now this
* function is a no-op.
*/
void pixman_disable_out_of_bounds_workaround (void);
 
/*
* Glyphs
*/
typedef struct pixman_glyph_cache_t pixman_glyph_cache_t;
typedef struct
{
int x, y;
const void *glyph;
} pixman_glyph_t;
 
pixman_glyph_cache_t *pixman_glyph_cache_create (void);
void pixman_glyph_cache_destroy (pixman_glyph_cache_t *cache);
void pixman_glyph_cache_freeze (pixman_glyph_cache_t *cache);
void pixman_glyph_cache_thaw (pixman_glyph_cache_t *cache);
const void * pixman_glyph_cache_lookup (pixman_glyph_cache_t *cache,
void *font_key,
void *glyph_key);
const void * pixman_glyph_cache_insert (pixman_glyph_cache_t *cache,
void *font_key,
void *glyph_key,
int origin_x,
int origin_y,
pixman_image_t *glyph_image);
void pixman_glyph_cache_remove (pixman_glyph_cache_t *cache,
void *font_key,
void *glyph_key);
void pixman_glyph_get_extents (pixman_glyph_cache_t *cache,
int n_glyphs,
pixman_glyph_t *glyphs,
pixman_box32_t *extents);
pixman_format_code_t pixman_glyph_get_mask_format (pixman_glyph_cache_t *cache,
int n_glyphs,
const pixman_glyph_t *glyphs);
void pixman_composite_glyphs (pixman_op_t op,
pixman_image_t *src,
pixman_image_t *dest,
pixman_format_code_t mask_format,
int32_t src_x,
int32_t src_y,
int32_t mask_x,
int32_t mask_y,
int32_t dest_x,
int32_t dest_y,
int32_t width,
int32_t height,
pixman_glyph_cache_t *cache,
int n_glyphs,
const pixman_glyph_t *glyphs);
void pixman_composite_glyphs_no_mask (pixman_op_t op,
pixman_image_t *src,
pixman_image_t *dest,
int32_t src_x,
int32_t src_y,
int32_t dest_x,
int32_t dest_y,
pixman_glyph_cache_t *cache,
int n_glyphs,
const pixman_glyph_t *glyphs);
 
/*
* Trapezoids
*/
typedef struct pixman_edge pixman_edge_t;
typedef struct pixman_trapezoid pixman_trapezoid_t;
typedef struct pixman_trap pixman_trap_t;
typedef struct pixman_span_fix pixman_span_fix_t;
typedef struct pixman_triangle pixman_triangle_t;
 
/*
* An edge structure. This represents a single polygon edge
* and can be quickly stepped across small or large gaps in the
* sample grid
*/
struct pixman_edge
{
pixman_fixed_t x;
pixman_fixed_t e;
pixman_fixed_t stepx;
pixman_fixed_t signdx;
pixman_fixed_t dy;
pixman_fixed_t dx;
 
pixman_fixed_t stepx_small;
pixman_fixed_t stepx_big;
pixman_fixed_t dx_small;
pixman_fixed_t dx_big;
};
 
struct pixman_trapezoid
{
pixman_fixed_t top, bottom;
pixman_line_fixed_t left, right;
};
 
struct pixman_triangle
{
pixman_point_fixed_t p1, p2, p3;
};
 
/* whether 't' is a well defined not obviously empty trapezoid */
#define pixman_trapezoid_valid(t) \
((t)->left.p1.y != (t)->left.p2.y && \
(t)->right.p1.y != (t)->right.p2.y && \
(int) ((t)->bottom - (t)->top) > 0)
 
struct pixman_span_fix
{
pixman_fixed_t l, r, y;
};
 
struct pixman_trap
{
pixman_span_fix_t top, bot;
};
 
pixman_fixed_t pixman_sample_ceil_y (pixman_fixed_t y,
int bpp);
pixman_fixed_t pixman_sample_floor_y (pixman_fixed_t y,
int bpp);
void pixman_edge_step (pixman_edge_t *e,
int n);
void pixman_edge_init (pixman_edge_t *e,
int bpp,
pixman_fixed_t y_start,
pixman_fixed_t x_top,
pixman_fixed_t y_top,
pixman_fixed_t x_bot,
pixman_fixed_t y_bot);
void pixman_line_fixed_edge_init (pixman_edge_t *e,
int bpp,
pixman_fixed_t y,
const pixman_line_fixed_t *line,
int x_off,
int y_off);
void pixman_rasterize_edges (pixman_image_t *image,
pixman_edge_t *l,
pixman_edge_t *r,
pixman_fixed_t t,
pixman_fixed_t b);
void pixman_add_traps (pixman_image_t *image,
int16_t x_off,
int16_t y_off,
int ntrap,
const pixman_trap_t *traps);
void pixman_add_trapezoids (pixman_image_t *image,
int16_t x_off,
int y_off,
int ntraps,
const pixman_trapezoid_t *traps);
void pixman_rasterize_trapezoid (pixman_image_t *image,
const pixman_trapezoid_t *trap,
int x_off,
int y_off);
void pixman_composite_trapezoids (pixman_op_t op,
pixman_image_t * src,
pixman_image_t * dst,
pixman_format_code_t mask_format,
int x_src,
int y_src,
int x_dst,
int y_dst,
int n_traps,
const pixman_trapezoid_t * traps);
void pixman_composite_triangles (pixman_op_t op,
pixman_image_t * src,
pixman_image_t * dst,
pixman_format_code_t mask_format,
int x_src,
int y_src,
int x_dst,
int y_dst,
int n_tris,
const pixman_triangle_t * tris);
void pixman_add_triangles (pixman_image_t *image,
int32_t x_off,
int32_t y_off,
int n_tris,
const pixman_triangle_t *tris);
 
PIXMAN_END_DECLS
 
#endif /* PIXMAN_H__ */
/contrib/sdk/sources/pixman/test/window-test.c
0,0 → 1,173
#include <stdio.h>
#include <stdlib.h>
#include <config.h>
#include "pixman-private.h"
#include "pixman.h"
 
#define FALSE 0
#define TRUE 1
 
/* Randomly decide between 32 and 16 bit
*
* Allocate bits with random width, stride and height
*
* Then make up some random offset (dx, dy)
*
* Then make an image with those values.
*
* Do this for both source and destination
*
* Composite them together using OVER.
*
* The bits in the source and the destination should have
* recognizable colors so that the result can be verified.
*
* Ie., walk the bits and verify that they have been composited.
*/
 
static int
get_rand (int bound)
{
return rand () % bound;
}
 
static pixman_image_t *
make_image (int width, int height, pixman_bool_t src, int *rx, int *ry)
{
pixman_format_code_t format;
pixman_image_t *image;
pixman_region32_t region;
uint8_t *bits;
int stride;
int bpp;
int dx, dy;
int i, j;
 
if (src)
format = PIXMAN_a8r8g8b8;
else
format = PIXMAN_r5g6b5;
 
bpp = PIXMAN_FORMAT_BPP (format) / 8;
 
stride = width + get_rand (width);
stride += (stride & 1); /* Make it an even number */
 
bits = malloc (height * stride * bpp);
 
for (j = 0; j < height; ++j)
{
for (i = 0; i < width; ++i)
{
uint8_t *pixel = bits + (stride * j + i) * bpp;
 
if (src)
*(uint32_t *)pixel = 0x7f00007f;
else
*(uint16_t *)pixel = 0xf100;
}
}
 
dx = dy = 0;
 
dx = get_rand (500);
dy = get_rand (500);
 
if (!src)
{
/* Now simulate the bogus X server translations */
bits -= (dy * stride + dx) * bpp;
}
 
image = pixman_image_create_bits (
format, width, height, (uint32_t *)bits, stride * bpp);
 
if (!src)
{
/* And add the bogus clip region */
pixman_region32_init_rect (&region, dx, dy, dx + width, dy + height);
 
pixman_image_set_clip_region32 (image, &region);
}
 
pixman_image_set_source_clipping (image, TRUE);
 
if (src)
{
pixman_transform_t trans;
 
pixman_transform_init_identity (&trans);
 
pixman_transform_translate (&trans,
NULL,
- pixman_int_to_fixed (width / 2),
- pixman_int_to_fixed (height / 2));
 
pixman_transform_scale (&trans,
NULL,
pixman_double_to_fixed (0.5),
pixman_double_to_fixed (0.5));
 
pixman_transform_translate (&trans,
NULL,
pixman_int_to_fixed (width / 2),
pixman_int_to_fixed (height / 2));
 
pixman_image_set_transform (image, &trans);
pixman_image_set_filter (image, PIXMAN_FILTER_BILINEAR, NULL, 0);
pixman_image_set_repeat (image, PIXMAN_REPEAT_PAD);
}
 
if (!src)
{
*rx = dx;
*ry = dy;
}
else
{
*rx = *ry = 0;
}
 
return image;
}
 
int
main ()
{
pixman_image_t *src, *dest;
int src_x, src_y, dest_x, dest_y;
int i, j;
int width = get_rand (499) + 1;
int height = get_rand (499) + 1;
 
src = make_image (width, height, TRUE, &src_x, &src_y);
dest = make_image (width, height, FALSE, &dest_x, &dest_y);
 
pixman_image_composite (
PIXMAN_OP_OVER, src, NULL, dest,
src_x, src_y,
-1, -1,
dest_x, dest_y,
width, height);
 
for (i = 0; i < height; ++i)
{
for (j = 0; j < width; ++j)
{
uint8_t *bits = (uint8_t *)dest->bits.bits;
int bpp = PIXMAN_FORMAT_BPP (dest->bits.format) / 8;
int stride = dest->bits.rowstride * 4;
 
uint8_t *pixel =
bits + (i + dest_y) * stride + (j + dest_x) * bpp;
 
if (*(uint16_t *)pixel != 0x788f)
{
printf ("bad pixel %x\n", *(uint16_t *)pixel);
assert (*(uint16_t *)pixel == 0x788f);
}
}
}
 
return 0;
}