pixman-0.30.2

git-svn-id: svn://kolibrios.org@3931 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Sergey Semyonov (Serge) 2013-09-22 20:55:51 +00:00
parent 4e370891be
commit 40a47213e6
43 changed files with 17951 additions and 9898 deletions

View File

@ -0,0 +1,148 @@
import pixman-1,\
_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'

View File

@ -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.
*/

View File

@ -2,45 +2,52 @@
LIBRARY = pixman-1
CC = gcc
CFLAGS = -U_Win32 -U_WIN32 -U__MINGW32__ -c -O2 -Wall -Winline -fomit-frame-pointer
CFLAGS = -c -O2 -mmmx -Winline -fomit-frame-pointer
LD = ld
LDFLAGS = -shared -s -nostdlib -T ../newlib/dll.lds --entry _DllStartup --image-base=0 --out-implib $(LIBRARY).dll.a
LDIMPORT:= -nostdlib --out-implib libpiximp.a --exclude-libs libamz.a
LDFLAGS:= -shared -s -T ../newlib/dll.lds --image-base 0
STRIP = $(PREFIX)strip
DEFINES = -DHAVE_CONFIG_H -DPIXMAN_NO_TLS -DUSE_MMX
INCLUDES = -I../pixman -I../newlib/include
INCLUDES= -I. -I../newlib/include
LIBPATH:= -L../newlib
LIBS:= -lamz -lgcc -lcimp
LIBS:= -ldll -lc.dll -lgcc
DEFINES = -DHAVE_CONFIG_H
SOURCES = \
pixman-image.c \
pixman.c \
pixman-access.c \
pixman-access-accessors.c \
pixman-region16.c \
pixman-region32.c \
pixman-bits-image.c \
pixman-combine32.c \
pixman-combine64.c \
pixman-utils.c \
pixman-combine-float.c \
pixman-conical-gradient.c \
pixman-edge.c \
pixman-edge-accessors.c \
pixman-trap.c \
pixman-timer.c \
pixman-matrix.c \
pixman-gradient-walker.c \
pixman-linear-gradient.c \
pixman-radial-gradient.c \
pixman-bits-image.c \
pixman.c \
pixman-cpu.c \
pixman-fast-path.c \
pixman-implementation.c \
pixman-solid-fill.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))
@ -53,13 +60,21 @@ all:$(LIBRARY).a $(LIBRARY).dll
$(LIBRARY).a: $(OBJECTS) Makefile
ar cvrs $(LIBRARY).a $(OBJECTS)
$(LIBRARY).dll: $(OBJECTS) Makefile
ld $(LDFLAGS) $(LDIMPORT) $(LIBPATH) -o $@ $(OBJECTS) $(LIBS)
$(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
%.o: %.c $(SOURCES) Makefile
%.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

View File

@ -1,22 +1,116 @@
pixman is a library that provides low-level pixel manipulation
Pixman is a library that provides low-level pixel manipulation
features such as image compositing and trapezoid rasterization.
All questions regarding this software should be directed to the pixman
Questions, bug reports and patches should be directed to the pixman
mailing list:
http://lists.freedesktop.org/mailman/listinfo/pixman
Please send patches and bug reports either to the mailing list above,
or file them at the freedesktop bug tracker:
You can also file bugs at
https://bugs.freedesktop.org/enter_bug.cgi?product=pixman
The master development code repository can be found at:
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
http://gitweb.freedesktop.org/?p=pixman;a=summary
and browsed on the web here:
For more information on the git code manager, see:
http://cgit.freedesktop.org/pixman/
http://wiki.x.org/wiki/GitPage
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.

View File

@ -10,6 +10,15 @@
/* 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 */
@ -25,9 +34,15 @@
/* Define to 1 if you have the `pixman-1' library (-lpixman-1). */
/* #undef HAVE_LIBPIXMAN_1 */
/* Whether we have libpng */
/* #undef HAVE_LIBPNG */
/* 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
@ -72,13 +87,13 @@
#define PACKAGE "pixman"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""pixman@lists.freedesktop.org""
#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.20.2"
#define PACKAGE_STRING "pixman 0.30.2"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "pixman"
@ -87,7 +102,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "0.20.2"
#define PACKAGE_VERSION "0.30.2"
/* enable TIMER_BEGIN/TIMER_END macros */
/* #undef PIXMAN_TIMERS */
@ -98,8 +113,14 @@
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Whether the tool chain supports __thread */
//#define TOOLCHAIN_SUPPORTS__THREAD /**/
/* 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 */
@ -110,20 +131,26 @@
/* use GNU-style inline assembler */
#define USE_GCC_INLINE_ASM 1
/* use MMX compiler intrinsics */
#define USE_MMX 1
/* use Loongson Multimedia Instructions */
/* #undef USE_LOONGSON_MMI */
/* use MIPS DSPr2 assembly optimizations */
/* #undef USE_MIPS_DSPR2 */
/* use OpenMP in the test suite */
//#define USE_OPENMP 1
/* #undef USE_OPENMP */
/* use SSE2 compiler intrinsics */
//#define USE_SSE2 1
#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.20.2"
#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). */
@ -142,3 +169,6 @@
#ifndef __cplusplus
/* #undef inline */
#endif
/* Define to sqrt if you do not have the `sqrtf' function. */
/* #undef sqrtf */

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +1,10 @@
#ifdef PIXMAN_FB_ACCESSORS
#define ACCESS(sym) sym##_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 MEMCPY_WRAPPED(img, dst, src, size) \
do { \
size_t _i; \
uint8_t *_dst = (uint8_t*)(dst), *_src = (uint8_t*)(src); \
for(_i = 0; _i < size; _i++) { \
WRITE((img), _dst +_i, READ((img), _src + _i)); \
} \
} while (0)
#define MEMSET_WRAPPED(img, dst, val, size) \
do { \
size_t _i; \
@ -27,12 +16,8 @@
#else
#define ACCESS(sym) sym
#define READ(img, ptr) (*(ptr))
#define WRITE(img, ptr, val) (*(ptr) = (val))
#define MEMCPY_WRAPPED(img, dst, src, size) \
memcpy(dst, src, size)
#define MEMSET_WRAPPED(img, dst, val, size) \
memset(dst, val, size)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,26 @@
/* WARNING: This file is generated by combine.pl from combine.inc.
Please edit one of those files rather than this one. */
#line 1 "pixman-combine.c.template"
/*
* 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
@ -10,10 +29,9 @@
#include <string.h>
#include "pixman-private.h"
#include "pixman-combine32.h"
/*** per channel helper functions ***/
/* component alpha helper functions */
static void
combine_mask_ca (uint32_t *src, uint32_t *mask)
@ -95,15 +113,11 @@ combine_mask_alpha_ca (const uint32_t *src, uint32_t *mask)
/*
* 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 'C'. Similarly, functions which deal with
* 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.
*/
/*
* All of the composing functions
*/
static force_inline uint32_t
combine_mask (const uint32_t *src, const uint32_t *mask, int i)
{
@ -158,7 +172,9 @@ combine_src_u (pixman_implementation_t *imp,
int i;
if (!mask)
{
memcpy (dest, src, width * sizeof (uint32_t));
}
else
{
for (i = 0; i < width; ++i)
@ -170,7 +186,6 @@ combine_src_u (pixman_implementation_t *imp,
}
}
/* if the Src is opaque, call combine_src_u */
static void
combine_over_u (pixman_implementation_t *imp,
pixman_op_t op,
@ -181,18 +196,61 @@ combine_over_u (pixman_implementation_t *imp,
{
int i;
for (i = 0; i < width; ++i)
if (!mask)
{
uint32_t s = combine_mask (src, mask, i);
uint32_t d = *(dest + i);
uint32_t ia = ALPHA_8 (~s);
UN8x4_MUL_UN8_ADD_UN8x4 (d, ia, s);
*(dest + i) = d;
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;
}
}
}
}
}
/* if the Dst is opaque, this is a noop */
static void
combine_over_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
@ -213,7 +271,6 @@ combine_over_reverse_u (pixman_implementation_t *imp,
}
}
/* if the Dst is opaque, call combine_src_u */
static void
combine_in_u (pixman_implementation_t *imp,
pixman_op_t op,
@ -233,7 +290,6 @@ combine_in_u (pixman_implementation_t *imp,
}
}
/* if the Src is opaque, this is a noop */
static void
combine_in_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
@ -254,7 +310,6 @@ combine_in_reverse_u (pixman_implementation_t *imp,
}
}
/* if the Dst is opaque, call combine_clear */
static void
combine_out_u (pixman_implementation_t *imp,
pixman_op_t op,
@ -274,7 +329,6 @@ combine_out_u (pixman_implementation_t *imp,
}
}
/* if the Src is opaque, call combine_clear */
static void
combine_out_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
@ -295,9 +349,6 @@ combine_out_reverse_u (pixman_implementation_t *imp,
}
}
/* if the Src is opaque, call combine_in_u */
/* if the Dst is opaque, call combine_over_u */
/* if both the Src and Dst are opaque, call combine_src_u */
static void
combine_atop_u (pixman_implementation_t *imp,
pixman_op_t op,
@ -320,9 +371,6 @@ combine_atop_u (pixman_implementation_t *imp,
}
}
/* if the Src is opaque, call combine_over_reverse_u */
/* if the Dst is opaque, call combine_in_reverse_u */
/* if both the Src and Dst are opaque, call combine_dst_u */
static void
combine_atop_reverse_u (pixman_implementation_t *imp,
pixman_op_t op,
@ -345,9 +393,6 @@ combine_atop_reverse_u (pixman_implementation_t *imp,
}
}
/* if the Src is opaque, call combine_over_u */
/* if the Dst is opaque, call combine_over_reverse_u */
/* if both the Src and Dst are opaque, call combine_clear */
static void
combine_xor_u (pixman_implementation_t *imp,
pixman_op_t op,
@ -389,9 +434,6 @@ combine_add_u (pixman_implementation_t *imp,
}
}
/* if the Src is opaque, call combine_add_u */
/* if the Dst is opaque, call combine_add_u */
/* if both the Src and Dst are opaque, call combine_add_u */
static void
combine_saturate_u (pixman_implementation_t *imp,
pixman_op_t op,
@ -441,14 +483,13 @@ combine_saturate_u (pixman_implementation_t *imp,
* 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)
* 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,
@ -493,7 +534,7 @@ combine_multiply_ca (pixman_implementation_t *imp,
uint32_t r = d;
uint32_t dest_ia = ALPHA_8 (~d);
combine_mask_value_ca (&s, &m);
combine_mask_ca (&s, &m);
UN8x4_MUL_UN8x4_ADD_UN8x4_MUL_UN8 (r, ~m, s, dest_ia);
UN8x4_MUL_UN8x4 (d, s);
@ -526,7 +567,7 @@ combine_multiply_ca (pixman_implementation_t *imp,
UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (result, isa, s, ida); \
\
*(dest + i) = result + \
(DIV_ONE_UN8 (sa * da) << A_SHIFT) + \
(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)); \
@ -550,13 +591,13 @@ combine_multiply_ca (pixman_implementation_t *imp,
uint8_t ida = ~da; \
uint32_t result; \
\
combine_mask_value_ca (&s, &m); \
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) * da) << A_SHIFT) + \
(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))); \
@ -853,7 +894,7 @@ PDF_SEPARABLE_BLEND_MODE (exclusion)
*
* 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
* 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)
@ -889,8 +930,7 @@ PDF_SEPARABLE_BLEND_MODE (exclusion)
*
* 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)
* = a_s * a_d * set_lum (set_sat (a_d * S, a_s * SAT (D)),
* a_s * LUM (D), a_s * a_d)
* = set_lum (set_sat (a_d * S, a_s * SAT (D)), a_s * LUM (D), a_s * a_d)
*
*/
@ -931,7 +971,7 @@ PDF_SEPARABLE_BLEND_MODE (exclusion)
blend_ ## name (c, dc, da, sc, sa); \
\
*(dest + i) = result + \
(DIV_ONE_UN8 (sa * da) << A_SHIFT) + \
(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])); \
@ -1148,9 +1188,7 @@ PDF_NON_SEPARABLE_BLEND_MODE (hsl_luminosity)
#undef CH_MIN
#undef PDF_NON_SEPARABLE_BLEND_MODE
/* Overlay
*
* All of the disjoint composing functions
/* 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
@ -1171,6 +1209,9 @@ PDF_NON_SEPARABLE_BLEND_MODE (hsl_luminosity)
* (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
@ -1583,9 +1624,8 @@ combine_conjoint_xor_u (pixman_implementation_t *imp,
combine_conjoint_general_u (dest, src, mask, width, COMBINE_XOR);
}
/************************************************************************/
/*********************** Per Channel functions **************************/
/************************************************************************/
/* Component alpha combiners */
static void
combine_clear_ca (pixman_implementation_t *imp,
@ -2462,4 +2502,3 @@ _pixman_setup_combiner_functions_32 (pixman_implementation_t *imp)
imp->combine_32_ca[PIXMAN_OP_HSL_COLOR] = combine_dst;
imp->combine_32_ca[PIXMAN_OP_HSL_LUMINOSITY] = combine_dst;
}

View File

@ -1,8 +1,3 @@
/* WARNING: This file is generated by combine.pl from combine.inc.
Please edit one of those files rather than this one. */
#line 1 "pixman-combine.c.template"
#define COMPONENT_SIZE 8
#define MASK 0xff
#define ONE_HALF 0x80
@ -24,19 +19,62 @@
#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) * (b) + ONE_HALF, ((((t) >> G_SHIFT ) + (t) ) >> G_SHIFT ))
((t) = (a) * (uint16_t)(b) + ONE_HALF, ((((t) >> G_SHIFT ) + (t) ) >> G_SHIFT ))
#define DIV_UN8(a, b) \
(((uint16_t) (a) * MASK) / (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)
@ -61,6 +99,7 @@
/*
* x_rb = min (x_rb + y_rb, 255)
*/
#ifndef UN8_rb_ADD_UN8_rb
#define UN8_rb_ADD_UN8_rb(x, y, t) \
do \
{ \
@ -68,6 +107,7 @@
t |= RB_MASK_PLUS_ONE - ((t >> G_SHIFT) & RB_MASK); \
x = (t & RB_MASK); \
} while (0)
#endif
/*
* x_rb = (x_rb * a_rb) / 255
@ -213,6 +253,7 @@
/*
x_c = min(x_c + y_c, 255)
*/
#ifndef UN8x4_ADD_UN8x4
#define UN8x4_ADD_UN8x4(x, y) \
do \
{ \
@ -228,3 +269,4 @@
\
x = r1__ | (r2__ << G_SHIFT); \
} while (0)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,230 +0,0 @@
/* WARNING: This file is generated by combine.pl from combine.inc.
Please edit one of those files rather than this one. */
#line 1 "pixman-combine.c.template"
#define COMPONENT_SIZE 16
#define MASK 0xffffULL
#define ONE_HALF 0x8000ULL
#define A_SHIFT 16 * 3
#define R_SHIFT 16 * 2
#define G_SHIFT 16
#define A_MASK 0xffff000000000000ULL
#define R_MASK 0xffff00000000ULL
#define G_MASK 0xffff0000ULL
#define RB_MASK 0xffff0000ffffULL
#define AG_MASK 0xffff0000ffff0000ULL
#define RB_ONE_HALF 0x800000008000ULL
#define RB_MASK_PLUS_ONE 0x10000000010000ULL
#define ALPHA_16(x) ((x) >> A_SHIFT)
#define RED_16(x) (((x) >> R_SHIFT) & MASK)
#define GREEN_16(x) (((x) >> G_SHIFT) & MASK)
#define BLUE_16(x) ((x) & MASK)
/*
* Helper macros.
*/
#define MUL_UN16(a, b, t) \
((t) = (a) * (b) + ONE_HALF, ((((t) >> G_SHIFT ) + (t) ) >> G_SHIFT ))
#define DIV_UN16(a, b) \
(((uint32_t) (a) * MASK) / (b))
#define ADD_UN16(x, y, t) \
((t) = (x) + (y), \
(uint64_t) (uint16_t) ((t) | (0 - ((t) >> G_SHIFT))))
#define DIV_ONE_UN16(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 UN16_rb_MUL_UN16(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)
*/
#define UN16_rb_ADD_UN16_rb(x, y, t) \
do \
{ \
t = ((x) + (y)); \
t |= RB_MASK_PLUS_ONE - ((t >> G_SHIFT) & RB_MASK); \
x = (t & RB_MASK); \
} while (0)
/*
* x_rb = (x_rb * a_rb) / 255
*/
#define UN16_rb_MUL_UN16_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 UN16x4_MUL_UN16(x, a) \
do \
{ \
uint64_t r1__, r2__, t__; \
\
r1__ = (x); \
UN16_rb_MUL_UN16 (r1__, (a), t__); \
\
r2__ = (x) >> G_SHIFT; \
UN16_rb_MUL_UN16 (r2__, (a), t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a) / 255 + y_c
*/
#define UN16x4_MUL_UN16_ADD_UN16x4(x, a, y) \
do \
{ \
uint64_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (y) & RB_MASK; \
UN16_rb_MUL_UN16 (r1__, (a), t__); \
UN16_rb_ADD_UN16_rb (r1__, r2__, t__); \
\
r2__ = (x) >> G_SHIFT; \
r3__ = ((y) >> G_SHIFT) & RB_MASK; \
UN16_rb_MUL_UN16 (r2__, (a), t__); \
UN16_rb_ADD_UN16_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a + y_c * b) / 255
*/
#define UN16x4_MUL_UN16_ADD_UN16x4_MUL_UN16(x, a, y, b) \
do \
{ \
uint64_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (y); \
UN16_rb_MUL_UN16 (r1__, (a), t__); \
UN16_rb_MUL_UN16 (r2__, (b), t__); \
UN16_rb_ADD_UN16_rb (r1__, r2__, t__); \
\
r2__ = ((x) >> G_SHIFT); \
r3__ = ((y) >> G_SHIFT); \
UN16_rb_MUL_UN16 (r2__, (a), t__); \
UN16_rb_MUL_UN16 (r3__, (b), t__); \
UN16_rb_ADD_UN16_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a_c) / 255
*/
#define UN16x4_MUL_UN16x4(x, a) \
do \
{ \
uint64_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (a); \
UN16_rb_MUL_UN16_rb (r1__, r2__, t__); \
\
r2__ = (x) >> G_SHIFT; \
r3__ = (a) >> G_SHIFT; \
UN16_rb_MUL_UN16_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a_c) / 255 + y_c
*/
#define UN16x4_MUL_UN16x4_ADD_UN16x4(x, a, y) \
do \
{ \
uint64_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (a); \
UN16_rb_MUL_UN16_rb (r1__, r2__, t__); \
r2__ = (y) & RB_MASK; \
UN16_rb_ADD_UN16_rb (r1__, r2__, t__); \
\
r2__ = ((x) >> G_SHIFT); \
r3__ = ((a) >> G_SHIFT); \
UN16_rb_MUL_UN16_rb (r2__, r3__, t__); \
r3__ = ((y) >> G_SHIFT) & RB_MASK; \
UN16_rb_ADD_UN16_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a_c + y_c * b) / 255
*/
#define UN16x4_MUL_UN16x4_ADD_UN16x4_MUL_UN16(x, a, y, b) \
do \
{ \
uint64_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (a); \
UN16_rb_MUL_UN16_rb (r1__, r2__, t__); \
r2__ = (y); \
UN16_rb_MUL_UN16 (r2__, (b), t__); \
UN16_rb_ADD_UN16_rb (r1__, r2__, t__); \
\
r2__ = (x) >> G_SHIFT; \
r3__ = (a) >> G_SHIFT; \
UN16_rb_MUL_UN16_rb (r2__, r3__, t__); \
r3__ = (y) >> G_SHIFT; \
UN16_rb_MUL_UN16 (r3__, (b), t__); \
UN16_rb_ADD_UN16_rb (r2__, r3__, t__); \
\
x = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
x_c = min(x_c + y_c, 255)
*/
#define UN16x4_ADD_UN16x4(x, y) \
do \
{ \
uint64_t r1__, r2__, r3__, t__; \
\
r1__ = (x) & RB_MASK; \
r2__ = (y) & RB_MASK; \
UN16_rb_ADD_UN16_rb (r1__, r2__, t__); \
\
r2__ = ((x) >> G_SHIFT) & RB_MASK; \
r3__ = ((y) >> G_SHIFT) & RB_MASK; \
UN16_rb_ADD_UN16_rb (r2__, r3__, t__); \
\
x = r1__ | (r2__ << G_SHIFT); \
} while (0)

View File

@ -18,6 +18,18 @@
# 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
@ -42,6 +54,19 @@
# 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
@ -74,6 +99,10 @@
# 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)
@ -82,10 +111,10 @@
# define PIXMAN_GET_THREAD_LOCAL(name) \
(&name)
#elif defined(TOOLCHAIN_SUPPORTS__THREAD)
#elif defined(TLS)
# define PIXMAN_DEFINE_THREAD_LOCAL(type, name) \
static __thread type name
static TLS type name
# define PIXMAN_GET_THREAD_LOCAL(name) \
(&name)
@ -191,8 +220,7 @@
value = tls_ ## name ## _alloc (); \
} \
return value; \
} \
extern int no_such_variable
}
# define PIXMAN_GET_THREAD_LOCAL(name) \
tls_ ## name ## _get ()

View File

@ -50,16 +50,16 @@ coordinates_to_parameter (double x, double y, double angle)
*/
}
static void
conical_gradient_get_scanline_32 (pixman_image_t *image,
int x,
int y,
int width,
uint32_t * buffer,
const uint32_t *mask)
static uint32_t *
conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
{
source_image_t *source = (source_image_t *)image;
gradient_t *gradient = (gradient_t *)source;
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;
@ -71,9 +71,9 @@ conical_gradient_get_scanline_32 (pixman_image_t *image,
double ry = y + 0.5;
double rz = 1.;
_pixman_gradient_walker_init (&walker, gradient, source->common.repeat);
_pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
if (source->common.transform)
if (image->common.transform)
{
pixman_vector_t v;
@ -82,19 +82,19 @@ conical_gradient_get_scanline_32 (pixman_image_t *image,
v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
if (!pixman_transform_point_3d (source->common.transform, &v))
return;
if (!pixman_transform_point_3d (image->common.transform, &v))
return iter->buffer;
cx = source->common.transform->matrix[0][0] / 65536.;
cy = source->common.transform->matrix[1][0] / 65536.;
cz = source->common.transform->matrix[2][0] / 65536.;
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 =
source->common.transform->matrix[2][0] == 0 &&
image->common.transform->matrix[2][0] == 0 &&
v.vector[2] == pixman_fixed_1;
}
@ -155,17 +155,33 @@ conical_gradient_get_scanline_32 (pixman_image_t *image,
rz += cz;
}
}
iter->y++;
return iter->buffer;
}
static void
conical_gradient_property_changed (pixman_image_t *image)
static uint32_t *
conical_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
{
image->common.get_scanline_32 = conical_gradient_get_scanline_32;
image->common.get_scanline_64 = _pixman_image_get_scanline_generic_64;
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 (pixman_point_fixed_t * center,
pixman_image_create_conical_gradient (const pixman_point_fixed_t * center,
pixman_fixed_t angle,
const pixman_gradient_stop_t *stops,
int n_stops)
@ -191,8 +207,6 @@ pixman_image_create_conical_gradient (pixman_point_fixed_t * center,
conical->center = *center;
conical->angle = (pixman_fixed_to_double (angle) / 180.0) * M_PI;
image->common.property_changed = conical_gradient_property_changed;
return image;
}

View File

@ -1,598 +0,0 @@
/*
* 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 <string.h>
#if defined(USE_ARM_SIMD) && defined(_MSC_VER)
/* Needed for EXCEPTION_ILLEGAL_INSTRUCTION */
#include <windows.h>
#endif
#include "pixman-private.h"
#ifdef USE_VMX
/* The CPU detection code needs to be in a file not compiled with
* "-maltivec -mabi=altivec", as gcc would try to save vector register
* across function calls causing SIGILL on cpus without Altivec/vmx.
*/
static pixman_bool_t initialized = FALSE;
static volatile pixman_bool_t have_vmx = TRUE;
#ifdef __APPLE__
#include <sys/sysctl.h>
static pixman_bool_t
pixman_have_vmx (void)
{
if (!initialized)
{
size_t length = sizeof(have_vmx);
int error =
sysctlbyname ("hw.optional.altivec", &have_vmx, &length, NULL, 0);
if (error)
have_vmx = FALSE;
initialized = TRUE;
}
return have_vmx;
}
#elif defined (__OpenBSD__)
#include <sys/param.h>
#include <sys/sysctl.h>
#include <machine/cpu.h>
static pixman_bool_t
pixman_have_vmx (void)
{
if (!initialized)
{
int mib[2] = { CTL_MACHDEP, CPU_ALTIVEC };
size_t length = sizeof(have_vmx);
int error =
sysctl (mib, 2, &have_vmx, &length, NULL, 0);
if (error != 0)
have_vmx = FALSE;
initialized = TRUE;
}
return have_vmx;
}
#elif defined (__linux__)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <linux/auxvec.h>
#include <asm/cputable.h>
static pixman_bool_t
pixman_have_vmx (void)
{
if (!initialized)
{
char fname[64];
unsigned long buf[64];
ssize_t count = 0;
pid_t pid;
int fd, i;
pid = getpid ();
snprintf (fname, sizeof(fname) - 1, "/proc/%d/auxv", pid);
fd = open (fname, O_RDONLY);
if (fd >= 0)
{
for (i = 0; i <= (count / sizeof(unsigned long)); i += 2)
{
/* Read more if buf is empty... */
if (i == (count / sizeof(unsigned long)))
{
count = read (fd, buf, sizeof(buf));
if (count <= 0)
break;
i = 0;
}
if (buf[i] == AT_HWCAP)
{
have_vmx = !!(buf[i + 1] & PPC_FEATURE_HAS_ALTIVEC);
initialized = TRUE;
break;
}
else if (buf[i] == AT_NULL)
{
break;
}
}
close (fd);
}
}
if (!initialized)
{
/* Something went wrong. Assume 'no' rather than playing
fragile tricks with catching SIGILL. */
have_vmx = FALSE;
initialized = TRUE;
}
return have_vmx;
}
#else /* !__APPLE__ && !__OpenBSD__ && !__linux__ */
#include <signal.h>
#include <setjmp.h>
static jmp_buf jump_env;
static void
vmx_test (int sig,
siginfo_t *si,
void * unused)
{
longjmp (jump_env, 1);
}
static pixman_bool_t
pixman_have_vmx (void)
{
struct sigaction sa, osa;
int jmp_result;
if (!initialized)
{
sa.sa_flags = SA_SIGINFO;
sigemptyset (&sa.sa_mask);
sa.sa_sigaction = vmx_test;
sigaction (SIGILL, &sa, &osa);
jmp_result = setjmp (jump_env);
if (jmp_result == 0)
{
asm volatile ( "vor 0, 0, 0" );
}
sigaction (SIGILL, &osa, NULL);
have_vmx = (jmp_result == 0);
initialized = TRUE;
}
return have_vmx;
}
#endif /* __APPLE__ */
#endif /* USE_VMX */
#if defined(USE_ARM_SIMD) || defined(USE_ARM_NEON)
#if defined(_MSC_VER)
#if defined(USE_ARM_SIMD)
extern int pixman_msvc_try_arm_simd_op ();
pixman_bool_t
pixman_have_arm_simd (void)
{
static pixman_bool_t initialized = FALSE;
static pixman_bool_t have_arm_simd = FALSE;
if (!initialized)
{
__try {
pixman_msvc_try_arm_simd_op ();
have_arm_simd = TRUE;
} __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION) {
have_arm_simd = FALSE;
}
initialized = TRUE;
}
return have_arm_simd;
}
#endif /* USE_ARM_SIMD */
#if defined(USE_ARM_NEON)
extern int pixman_msvc_try_arm_neon_op ();
pixman_bool_t
pixman_have_arm_neon (void)
{
static pixman_bool_t initialized = FALSE;
static pixman_bool_t have_arm_neon = FALSE;
if (!initialized)
{
__try
{
pixman_msvc_try_arm_neon_op ();
have_arm_neon = TRUE;
}
__except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION)
{
have_arm_neon = FALSE;
}
initialized = TRUE;
}
return have_arm_neon;
}
#endif /* USE_ARM_NEON */
#else /* linux ELF */
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <elf.h>
static pixman_bool_t arm_has_v7 = FALSE;
static pixman_bool_t arm_has_v6 = FALSE;
static pixman_bool_t arm_has_vfp = FALSE;
static pixman_bool_t arm_has_neon = FALSE;
static pixman_bool_t arm_has_iwmmxt = FALSE;
static pixman_bool_t arm_tests_initialized = FALSE;
static void
pixman_arm_read_auxv ()
{
int fd;
Elf32_auxv_t aux;
fd = open ("/proc/self/auxv", O_RDONLY);
if (fd >= 0)
{
while (read (fd, &aux, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t))
{
if (aux.a_type == AT_HWCAP)
{
uint32_t hwcap = aux.a_un.a_val;
/* hardcode these values to avoid depending on specific
* versions of the hwcap header, e.g. HWCAP_NEON
*/
arm_has_vfp = (hwcap & 64) != 0;
arm_has_iwmmxt = (hwcap & 512) != 0;
/* this flag is only present on kernel 2.6.29 */
arm_has_neon = (hwcap & 4096) != 0;
}
else if (aux.a_type == AT_PLATFORM)
{
const char *plat = (const char*) aux.a_un.a_val;
if (strncmp (plat, "v7l", 3) == 0)
{
arm_has_v7 = TRUE;
arm_has_v6 = TRUE;
}
else if (strncmp (plat, "v6l", 3) == 0)
{
arm_has_v6 = TRUE;
}
}
}
close (fd);
}
arm_tests_initialized = TRUE;
}
#if defined(USE_ARM_SIMD)
pixman_bool_t
pixman_have_arm_simd (void)
{
if (!arm_tests_initialized)
pixman_arm_read_auxv ();
return arm_has_v6;
}
#endif /* USE_ARM_SIMD */
#if defined(USE_ARM_NEON)
pixman_bool_t
pixman_have_arm_neon (void)
{
if (!arm_tests_initialized)
pixman_arm_read_auxv ();
return arm_has_neon;
}
#endif /* USE_ARM_NEON */
#endif /* linux */
#endif /* USE_ARM_SIMD || USE_ARM_NEON */
#if defined(USE_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.
*/
#if !defined(__amd64__) && !defined(__x86_64__) && !defined(_M_AMD64)
#ifdef HAVE_GETISAX
#include <sys/auxv.h>
#endif
typedef enum
{
NO_FEATURES = 0,
MMX = 0x1,
MMX_EXTENSIONS = 0x2,
SSE = 0x6,
SSE2 = 0x8,
CMOV = 0x10
} cpu_features_t;
static unsigned int
detect_cpu_features (void)
{
unsigned int features = 0;
unsigned int result = 0;
#ifdef HAVE_GETISAX
if (getisax (&result, 1))
{
if (result & AV_386_CMOV)
features |= CMOV;
if (result & AV_386_MMX)
features |= MMX;
if (result & AV_386_AMD_MMX)
features |= MMX_EXTENSIONS;
if (result & AV_386_SSE)
features |= SSE;
if (result & AV_386_SSE2)
features |= SSE2;
}
#else
char vendor[13];
#ifdef _MSC_VER
int vendor0 = 0, vendor1, vendor2;
#endif
vendor[0] = 0;
vendor[12] = 0;
#ifdef __GNUC__
/* see p. 118 of amd64 instruction set manual Vol3 */
/* We need to be careful about the handling of %ebx and
* %esp here. 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 they have their
* original values when we access the output operands.
*/
__asm__ (
"pushf\n"
"pop %%eax\n"
"mov %%eax, %%ecx\n"
"xor $0x00200000, %%eax\n"
"push %%eax\n"
"popf\n"
"pushf\n"
"pop %%eax\n"
"mov $0x0, %%edx\n"
"xor %%ecx, %%eax\n"
"jz 1f\n"
"mov $0x00000000, %%eax\n"
"push %%ebx\n"
"cpuid\n"
"mov %%ebx, %%eax\n"
"pop %%ebx\n"
"mov %%eax, %1\n"
"mov %%edx, %2\n"
"mov %%ecx, %3\n"
"mov $0x00000001, %%eax\n"
"push %%ebx\n"
"cpuid\n"
"pop %%ebx\n"
"1:\n"
"mov %%edx, %0\n"
: "=r" (result),
"=m" (vendor[0]),
"=m" (vendor[4]),
"=m" (vendor[8])
:
: "%eax", "%ecx", "%edx"
);
#elif defined (_MSC_VER)
_asm {
pushfd
pop eax
mov ecx, eax
xor eax, 00200000h
push eax
popfd
pushfd
pop eax
mov edx, 0
xor eax, ecx
jz nocpuid
mov eax, 0
push ebx
cpuid
mov eax, ebx
pop ebx
mov vendor0, eax
mov vendor1, edx
mov vendor2, ecx
mov eax, 1
push ebx
cpuid
pop ebx
nocpuid:
mov result, edx
}
memmove (vendor + 0, &vendor0, 4);
memmove (vendor + 4, &vendor1, 4);
memmove (vendor + 8, &vendor2, 4);
#else
# error unsupported compiler
#endif
features = 0;
if (result)
{
/* result now contains the standard feature bits */
if (result & (1 << 15))
features |= CMOV;
if (result & (1 << 23))
features |= MMX;
if (result & (1 << 25))
features |= SSE;
if (result & (1 << 26))
features |= SSE2;
if ((features & MMX) && !(features & SSE) &&
(strcmp (vendor, "AuthenticAMD") == 0 ||
strcmp (vendor, "Geode by NSC") == 0))
{
/* check for AMD MMX extensions */
#ifdef __GNUC__
__asm__ (
" push %%ebx\n"
" mov $0x80000000, %%eax\n"
" cpuid\n"
" xor %%edx, %%edx\n"
" cmp $0x1, %%eax\n"
" jge 2f\n"
" mov $0x80000001, %%eax\n"
" cpuid\n"
"2:\n"
" pop %%ebx\n"
" mov %%edx, %0\n"
: "=r" (result)
:
: "%eax", "%ecx", "%edx"
);
#elif defined _MSC_VER
_asm {
push ebx
mov eax, 80000000h
cpuid
xor edx, edx
cmp eax, 1
jge notamd
mov eax, 80000001h
cpuid
notamd:
pop ebx
mov result, edx
}
#endif
if (result & (1 << 22))
features |= MMX_EXTENSIONS;
}
}
#endif /* HAVE_GETISAX */
return features;
}
static pixman_bool_t
pixman_have_mmx (void)
{
static pixman_bool_t initialized = FALSE;
static pixman_bool_t mmx_present;
if (!initialized)
{
unsigned int features = detect_cpu_features ();
mmx_present = (features & (MMX | MMX_EXTENSIONS)) == (MMX | MMX_EXTENSIONS);
initialized = TRUE;
}
return mmx_present;
}
#ifdef USE_SSE2
static pixman_bool_t
pixman_have_sse2 (void)
{
static pixman_bool_t initialized = FALSE;
static pixman_bool_t sse2_present;
if (!initialized)
{
unsigned int features = detect_cpu_features ();
sse2_present = (features & (MMX | MMX_EXTENSIONS | SSE | SSE2)) == (MMX | MMX_EXTENSIONS | SSE | SSE2);
initialized = TRUE;
}
return sse2_present;
}
#endif
#else /* __amd64__ */
#ifdef USE_MMX
#define pixman_have_mmx() TRUE
#endif
#ifdef USE_SSE2
#define pixman_have_sse2() TRUE
#endif
#endif /* __amd64__ */
#endif
pixman_implementation_t *
_pixman_choose_implementation (void)
{
#ifdef USE_SSE2
if (pixman_have_sse2 ())
return _pixman_implementation_create_sse2 ();
#endif
#ifdef USE_MMX
if (pixman_have_mmx ())
return _pixman_implementation_create_mmx ();
#endif
#ifdef USE_ARM_NEON
if (pixman_have_arm_neon ())
return _pixman_implementation_create_arm_neon ();
#endif
#ifdef USE_ARM_SIMD
if (pixman_have_arm_simd ())
return _pixman_implementation_create_arm_simd ();
#endif
#ifdef USE_VMX
if (pixman_have_vmx ())
return _pixman_implementation_create_vmx ();
#endif
return _pixman_implementation_create_fast_path ();
}

View File

@ -374,6 +374,7 @@ pixman_rasterize_edges (pixman_image_t *image,
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);

File diff suppressed because it is too large Load Diff

View File

@ -1,451 +0,0 @@
/* -*- 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
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;
}
/*
* 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 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, \
src_type_t *src, \
int32_t w, \
pixman_fixed_t vx, \
pixman_fixed_t unit_x, \
pixman_fixed_t max_vx) \
{ \
uint32_t d; \
src_type_t s1, s2; \
uint8_t a1, a2; \
int x1, x2; \
\
if (PIXMAN_OP_ ## OP != PIXMAN_OP_SRC && PIXMAN_OP_ ## OP != PIXMAN_OP_OVER) \
abort(); \
\
while ((w -= 2) >= 0) \
{ \
x1 = vx >> 16; \
vx += unit_x; \
if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
{ \
/* This works because we know that unit_x is positive */ \
while (vx >= max_vx) \
vx -= max_vx; \
} \
s1 = src[x1]; \
\
x2 = vx >> 16; \
vx += unit_x; \
if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
{ \
/* This works because we know that unit_x is positive */ \
while (vx >= max_vx) \
vx -= max_vx; \
} \
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 = vx >> 16; \
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, dst_type_t, \
repeat_mode) \
static void \
fast_composite_scaled_nearest ## scale_func_name (pixman_implementation_t *imp, \
pixman_op_t op, \
pixman_image_t * src_image, \
pixman_image_t * mask_image, \
pixman_image_t * dst_image, \
int32_t src_x, \
int32_t src_y, \
int32_t mask_x, \
int32_t mask_y, \
int32_t dst_x, \
int32_t dst_y, \
int32_t width, \
int32_t height) \
{ \
dst_type_t *dst_line; \
src_type_t *src_first_line; \
int y; \
pixman_fixed_t max_vx = max_vx; /* suppress uninitialized variable warning */ \
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; \
int src_stride, dst_stride; \
\
PIXMAN_IMAGE_GET_LINE (dst_image, dst_x, dst_y, dst_type_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, 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) \
{ \
/* Clamp repeating positions inside the actual samples */ \
max_vx = src_image->bits.width << 16; \
max_vy = src_image->bits.height << 16; \
\
repeat (PIXMAN_REPEAT_NORMAL, &vx, max_vx); \
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; \
\
y = vy >> 16; \
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 (dst, src, left_pad, 0, 0, 0); \
} \
if (width > 0) \
{ \
scanline_func (dst + left_pad, src, width, vx, unit_x, 0); \
} \
if (right_pad > 0) \
{ \
scanline_func (dst + left_pad + width, src + src_image->bits.width - 1, \
right_pad, 0, 0, 0); \
} \
} \
else if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \
{ \
static src_type_t zero = 0; \
if (y < 0 || y >= src_image->bits.height) \
{ \
scanline_func (dst, &zero, left_pad + width + right_pad, 0, 0, 0); \
continue; \
} \
src = src_first_line + src_stride * y; \
if (left_pad > 0) \
{ \
scanline_func (dst, &zero, left_pad, 0, 0, 0); \
} \
if (width > 0) \
{ \
scanline_func (dst + left_pad, src, width, vx, unit_x, 0); \
} \
if (right_pad > 0) \
{ \
scanline_func (dst + left_pad + width, &zero, right_pad, 0, 0, 0); \
} \
} \
else \
{ \
src = src_first_line + src_stride * y; \
scanline_func (dst, src, width, vx, unit_x, max_vx); \
} \
} \
}
/* A workaround for old sun studio, see: https://bugs.freedesktop.org/show_bug.cgi?id=32764 */
#define FAST_NEAREST_MAINLOOP(scale_func_name, scanline_func, src_type_t, dst_type_t, \
repeat_mode) \
FAST_NEAREST_MAINLOOP_INT(_ ## 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_INT(_ ## scale_func_name ## _ ## OP, \
scaled_nearest_scanline_ ## scale_func_name ## _ ## OP, \
src_type_t, dst_type_t, repeat_mode) \
\
extern int no_such_variable
#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, \
PIXMAN_null, 0, \
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)
#endif

View File

@ -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;
}

View File

@ -36,44 +36,102 @@
#include <stdlib.h>
#include <string.h>
#include "pixman-private.h"
#include "pixman-combine32.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_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_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;
fetch_scanline_t fetch_src = NULL, fetch_mask = NULL, fetch_dest = NULL;
pixman_iter_t src_iter, mask_iter, dest_iter;
pixman_combine_32_func_t compose;
store_scanline_t store;
source_image_class_t src_class, mask_class;
pixman_bool_t component_alpha;
uint32_t *bits;
int32_t stride;
int narrow, Bpp;
iter_flags_t narrow, src_iter_flags;
int Bpp;
int i;
narrow =
(src->common.flags & FAST_PATH_NARROW_FORMAT) &&
(!mask || mask->common.flags & FAST_PATH_NARROW_FORMAT) &&
(dest->common.flags & FAST_PATH_NARROW_FORMAT);
Bpp = narrow ? 4 : 8;
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)
{
@ -87,172 +145,60 @@ general_composite_rect (pixman_implementation_t *imp,
mask_buffer = src_buffer + width * Bpp;
dest_buffer = mask_buffer + width * Bpp;
src_class = _pixman_image_classify (src,
src_x, src_y,
width, height);
mask_class = SOURCE_IMAGE_CLASS_UNKNOWN;
if (mask)
if (!narrow)
{
mask_class = _pixman_image_classify (mask,
src_x, src_y,
width, height);
/* 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;
if (op == PIXMAN_OP_CLEAR)
fetch_src = NULL;
else if (narrow)
fetch_src = _pixman_image_get_scanline_32;
else
fetch_src = _pixman_image_get_scanline_64;
_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);
if (!mask || op == PIXMAN_OP_CLEAR)
fetch_mask = NULL;
else if (narrow)
fetch_mask = _pixman_image_get_scanline_32;
else
fetch_mask = _pixman_image_get_scanline_64;
if (op == PIXMAN_OP_CLEAR || op == PIXMAN_OP_SRC)
fetch_dest = NULL;
else if (narrow)
fetch_dest = _pixman_image_get_scanline_32;
else
fetch_dest = _pixman_image_get_scanline_64;
if (narrow)
store = _pixman_image_store_scanline_32;
else
store = _pixman_image_store_scanline_64;
/* Skip the store step and composite directly into the
* destination if the output format of the compose func matches
* the destination format.
*
* If the destination format is a8r8g8b8 then we can always do
* this. If it is x8r8g8b8, then we can only do it if the
* operator doesn't make use of destination alpha.
*/
if ((dest->bits.format == PIXMAN_a8r8g8b8) ||
(dest->bits.format == PIXMAN_x8r8g8b8 &&
(op == PIXMAN_OP_OVER ||
op == PIXMAN_OP_ADD ||
op == PIXMAN_OP_SRC ||
op == PIXMAN_OP_CLEAR ||
op == PIXMAN_OP_IN_REVERSE ||
op == PIXMAN_OP_OUT_REVERSE ||
op == PIXMAN_OP_DST)))
/* mask iter */
if ((src_iter_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) ==
(ITER_IGNORE_ALPHA | ITER_IGNORE_RGB))
{
if (narrow &&
!dest->common.alpha_map &&
!dest->bits.write_func)
{
store = NULL;
}
}
if (!store)
{
bits = dest->bits.bits;
stride = dest->bits.rowstride;
}
else
{
bits = NULL;
stride = 0;
/* If it doesn't matter what the source is, then it doesn't matter
* what the mask is
*/
mask_image = NULL;
}
component_alpha =
fetch_src &&
fetch_mask &&
mask &&
mask->common.type == BITS &&
mask->common.component_alpha &&
PIXMAN_FORMAT_RGB (mask->bits.format);
mask_image &&
mask_image->common.type == BITS &&
mask_image->common.component_alpha &&
PIXMAN_FORMAT_RGB (mask_image->bits.format);
if (narrow)
{
if (component_alpha)
compose = _pixman_implementation_combine_32_ca;
else
compose = _pixman_implementation_combine_32;
}
else
{
if (component_alpha)
compose = (pixman_combine_32_func_t)_pixman_implementation_combine_64_ca;
else
compose = (pixman_combine_32_func_t)_pixman_implementation_combine_64;
}
_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);
if (!compose)
return;
/* 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);
if (!fetch_mask)
mask_buffer = NULL;
compose = _pixman_implementation_lookup_combiner (
imp->toplevel, op, component_alpha, narrow);
for (i = 0; i < height; ++i)
{
/* fill first half of scanline with source */
if (fetch_src)
{
if (fetch_mask)
{
/* fetch mask before source so that fetching of
source can be optimized */
fetch_mask (mask, mask_x, mask_y + i,
width, (void *)mask_buffer, 0);
uint32_t *s, *m, *d;
if (mask_class == SOURCE_IMAGE_CLASS_HORIZONTAL)
fetch_mask = NULL;
}
m = mask_iter.get_scanline (&mask_iter, NULL);
s = src_iter.get_scanline (&src_iter, m);
d = dest_iter.get_scanline (&dest_iter, NULL);
if (src_class == SOURCE_IMAGE_CLASS_HORIZONTAL)
{
fetch_src (src, src_x, src_y + i,
width, (void *)src_buffer, 0);
fetch_src = NULL;
}
else
{
fetch_src (src, src_x, src_y + i,
width, (void *)src_buffer, (void *)mask_buffer);
}
}
else if (fetch_mask)
{
fetch_mask (mask, mask_x, mask_y + i,
width, (void *)mask_buffer, 0);
}
compose (imp->toplevel, op, d, s, m, width);
if (store)
{
/* fill dest into second half of scanline */
if (fetch_dest)
{
fetch_dest (dest, dest_x, dest_y + i,
width, (void *)dest_buffer, 0);
}
/* blend */
compose (imp->toplevel, op,
(void *)dest_buffer,
(void *)src_buffer,
(void *)mask_buffer,
width);
/* write back */
store (&(dest->bits), dest_x, dest_y + i, width,
(void *)dest_buffer);
}
else
{
/* blend */
compose (imp->toplevel, op,
bits + (dest_y + i) * stride + dest_x,
(void *)src_buffer, (void *)mask_buffer, width);
}
dest_iter.write_back (&dest_iter);
}
if (scanline_buffer != (uint8_t *) stack_scanline_buffer)
@ -265,50 +211,16 @@ static const pixman_fast_path_t general_fast_path[] =
{ PIXMAN_OP_NONE }
};
static pixman_bool_t
general_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 dst_x,
int dst_y,
int width,
int height)
{
/* We can't blit unless we have sse2 or mmx */
return FALSE;
}
static pixman_bool_t
general_fill (pixman_implementation_t *imp,
uint32_t * bits,
int stride,
int bpp,
int x,
int y,
int width,
int height,
uint32_t xor)
{
return FALSE;
}
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_64 (imp);
_pixman_setup_combiner_functions_float (imp);
imp->blt = general_blt;
imp->fill = general_fill;
imp->src_iter_init = general_src_iter_init;
imp->dest_iter_init = general_dest_iter_init;
return imp;
}

View File

@ -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);
}

View File

@ -31,123 +31,71 @@
void
_pixman_gradient_walker_init (pixman_gradient_walker_t *walker,
gradient_t * gradient,
unsigned int spread)
pixman_repeat_t repeat)
{
walker->num_stops = gradient->n_stops;
walker->stops = gradient->stops;
walker->left_x = 0;
walker->right_x = 0x10000;
walker->stepper = 0;
walker->left_ag = 0;
walker->left_rb = 0;
walker->right_ag = 0;
walker->right_rb = 0;
walker->spread = spread;
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;
}
void
_pixman_gradient_walker_reset (pixman_gradient_walker_t *walker,
pixman_fixed_32_32_t pos)
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;
pixman_color_t *left_c, *right_c;
int n, count = walker->num_stops;
pixman_gradient_stop_t * stops = walker->stops;
pixman_gradient_stop_t *stops = walker->stops;
float la, lr, lg, lb;
float ra, rr, rg, rb;
float lx, rx;
static const pixman_color_t transparent_black = { 0, 0, 0, 0 };
switch (walker->spread)
if (walker->repeat == PIXMAN_REPEAT_NORMAL)
{
case PIXMAN_REPEAT_NORMAL:
x = (int32_t)pos & 0xFFFF;
for (n = 0; n < count; n++)
if (x < stops[n].x)
break;
if (n == 0)
{
left_x = stops[count - 1].x - 0x10000;
left_c = &stops[count - 1].color;
}
else
{
left_x = stops[n - 1].x;
left_c = &stops[n - 1].color;
}
if (n == count)
{
right_x = stops[0].x + 0x10000;
right_c = &stops[0].color;
}
else
{
right_x = stops[n].x;
right_c = &stops[n].color;
}
left_x += (pos - x);
right_x += (pos - x);
break;
case PIXMAN_REPEAT_PAD:
for (n = 0; n < count; n++)
if (pos < stops[n].x)
break;
if (n == 0)
{
left_x = INT32_MIN;
left_c = &stops[0].color;
}
else
{
left_x = stops[n - 1].x;
left_c = &stops[n - 1].color;
}
if (n == count)
{
right_x = INT32_MAX;
right_c = &stops[n - 1].color;
}
else
{
right_x = stops[n].x;
right_c = &stops[n].color;
}
break;
case PIXMAN_REPEAT_REFLECT:
x = (int32_t)pos & 0xFFFF;
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;
for (n = 0; n < count; n++)
if (x < stops[n].x)
break;
if (n == 0)
{
left_x = -stops[0].x;
left_c = &stops[0].color;
}
else
{
left_x = stops[n - 1].x;
left_c = &stops[n - 1].color;
}
if (n == count)
{
right_x = 0x20000 - stops[n - 1].x;
right_c = &stops[n - 1].color;
}
else
{
right_x = stops[n].x;
right_c = &stops[n].color;
}
}
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;
@ -165,90 +113,90 @@ _pixman_gradient_walker_reset (pixman_gradient_walker_t *walker,
}
left_x += (pos - x);
right_x += (pos - x);
break;
default: /* REPEAT_NONE */
for (n = 0; n < count; n++)
if (pos < stops[n].x)
break;
}
else if (walker->repeat == PIXMAN_REPEAT_NONE)
{
if (n == 0)
{
left_x = INT32_MIN;
right_x = stops[0].x;
left_c = right_c = (pixman_color_t*) &transparent_black;
}
right_c = left_c;
else if (n == count)
{
left_x = stops[n - 1].x;
right_x = INT32_MAX;
left_c = right_c = (pixman_color_t*) &transparent_black;
}
else
{
left_x = stops[n - 1].x;
right_x = stops[n].x;
left_c = &stops[n - 1].color;
right_c = &stops[n].color;
}
left_c = right_c;
}
walker->left_x = left_x;
walker->right_x = right_x;
walker->left_ag = ((left_c->alpha >> 8) << 16) | (left_c->green >> 8);
walker->left_rb = ((left_c->red & 0xff00) << 8) | (left_c->blue >> 8);
walker->right_ag = ((right_c->alpha >> 8) << 16) | (right_c->green >> 8);
walker->right_rb = ((right_c->red & 0xff00) << 8) | (right_c->blue >> 8);
/* 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));
if (walker->left_x == walker->right_x ||
( walker->left_ag == walker->right_ag &&
walker->left_rb == walker->right_rb ) )
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->stepper = 0;
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
{
int32_t width = right_x - left_x;
walker->stepper = ((1 << 24) + width / 2) / width;
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;
}
#define PIXMAN_GRADIENT_WALKER_NEED_RESET(w, x) \
( (w)->need_reset || (x) < (w)->left_x || (x) >= (w)->right_x)
/* the following assumes that PIXMAN_GRADIENT_WALKER_NEED_RESET(w,x) is FALSE */
uint32_t
_pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker,
pixman_fixed_32_32_t x)
pixman_fixed_48_16_t x)
{
int dist, idist;
uint32_t t1, t2, a, color;
float a, r, g, b;
uint8_t a8, r8, g8, b8;
uint32_t v;
float y;
if (PIXMAN_GRADIENT_WALKER_NEED_RESET (walker, x))
_pixman_gradient_walker_reset (walker, x);
if (walker->need_reset || x < walker->left_x || x >= walker->right_x)
gradient_walker_reset (walker, x);
dist = ((int)(x - walker->left_x) * walker->stepper) >> 16;
idist = 256 - dist;
y = x * (1.0f / 65536.0f);
/* combined INTERPOLATE and premultiply */
t1 = walker->left_rb * idist + walker->right_rb * dist;
t1 = (t1 >> 8) & 0xff00ff;
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);
t2 = walker->left_ag * idist + walker->right_ag * dist;
t2 &= 0xff00ff00;
a8 = a + 0.5f;
r8 = r + 0.5f;
g8 = g + 0.5f;
b8 = b + 0.5f;
color = t2 & 0xff000000;
a = t2 >> 24;
v = ((a8 << 24) & 0xff000000) |
((r8 << 16) & 0x00ff0000) |
((g8 << 8) & 0x0000ff00) |
((b8 >> 0) & 0x000000ff);
t1 = t1 * a + 0x800080;
t1 = (t1 + ((t1 >> 8) & 0xff00ff)) >> 8;
t2 = (t2 >> 8) * a + 0x800080;
t2 = (t2 + ((t2 >> 8) & 0xff00ff));
return (color | (t1 & 0xff00ff) | (t2 & 0xff00));
return v;
}

View File

@ -30,7 +30,50 @@
#include <assert.h>
#include "pixman-private.h"
#include "pixman-combine32.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,
@ -39,54 +82,100 @@ _pixman_init_gradient (gradient_t * gradient,
{
return_val_if_fail (n_stops > 0, FALSE);
gradient->stops = pixman_malloc_ab (n_stops, sizeof (pixman_gradient_stop_t));
/* 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->stop_range = 0xffff;
gradient->common.property_changed = gradient_property_changed;
return TRUE;
}
/*
* By default, just evaluate the image at 32bpp and expand. Individual image
* types can plug in a better scanline getter if they want to. For example
* we could produce smoother gradients by evaluating them at higher color
* depth, but that's a project for the future.
*/
void
_pixman_image_get_scanline_generic_64 (pixman_image_t * image,
int x,
int y,
int width,
uint32_t * buffer,
const uint32_t * mask)
_pixman_image_init (pixman_image_t *image)
{
uint32_t *mask8 = NULL;
image_common_t *common = &image->common;
/* Contract the mask image, if one exists, so that the 32-bit fetch
* function can use it.
*/
if (mask)
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)
{
mask8 = pixman_malloc_ab (width, sizeof(uint32_t));
if (!mask8)
return;
if (image->common.destroy_func)
image->common.destroy_func (image, image->common.destroy_data);
pixman_contract (mask8, (uint64_t *)mask, width);
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;
}
/* Fetch the source image into the first half of buffer. */
_pixman_image_get_scanline_32 (image, x, y, width, (uint32_t*)buffer, mask8);
/* Expand from 32bpp to 64bpp in place. */
pixman_expand ((uint64_t *)buffer, buffer, PIXMAN_a8r8g8b8, width);
free (mask8);
return FALSE;
}
pixman_image_t *
@ -95,70 +184,11 @@ _pixman_image_allocate (void)
pixman_image_t *image = malloc (sizeof (pixman_image_t));
if (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->classify = NULL;
common->client_clip = FALSE;
common->destroy_func = NULL;
common->destroy_data = NULL;
common->dirty = TRUE;
}
_pixman_image_init (image);
return image;
}
source_image_class_t
_pixman_image_classify (pixman_image_t *image,
int x,
int y,
int width,
int height)
{
if (image->common.classify)
return image->common.classify (image, x, y, width, height);
else
return SOURCE_IMAGE_CLASS_UNKNOWN;
}
void
_pixman_image_get_scanline_32 (pixman_image_t *image,
int x,
int y,
int width,
uint32_t * buffer,
const uint32_t *mask)
{
image->common.get_scanline_32 (image, x, y, width, buffer, mask);
}
/* Even thought the type of buffer is uint32_t *, the function actually expects
* a uint64_t *buffer.
*/
void
_pixman_image_get_scanline_64 (pixman_image_t *image,
int x,
int y,
int width,
uint32_t * buffer,
const uint32_t *unused)
{
image->common.get_scanline_64 (image, x, y, width, buffer, unused);
}
static void
image_property_changed (pixman_image_t *image)
{
@ -178,39 +208,9 @@ pixman_image_ref (pixman_image_t *image)
PIXMAN_EXPORT pixman_bool_t
pixman_image_unref (pixman_image_t *image)
{
image_common_t *common = (image_common_t *)image;
common->ref_count--;
if (common->ref_count == 0)
if (_pixman_image_fini (image))
{
if (image->common.destroy_func)
image->common.destroy_func (image, image->common.destroy_data);
pixman_region32_fini (&common->clip_region);
if (common->transform)
free (common->transform);
if (common->filter_params)
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)
free (image->gradient.stops);
}
if (image->type == BITS && image->bits.free_me)
free (image->bits.free_me);
free (image);
return TRUE;
}
@ -238,54 +238,27 @@ _pixman_image_reset_clip_region (pixman_image_t *image)
image->common.have_clip_region = FALSE;
}
static pixman_bool_t out_of_bounds_workaround = TRUE;
/* Old X servers rely on out-of-bounds accesses when they are asked
* to composite with a window as the source. They create a pixman image
* pointing to some bogus position in memory, but then they set a clip
* region to the position where the actual bits are.
/* 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 by default we allow certain out-of-bound access
* to happen unless explicitly disabled.
* 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.
*
* Fixed X servers should call this function to disable the workaround.
* 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)
{
out_of_bounds_workaround = FALSE;
}
static pixman_bool_t
source_image_needs_out_of_bounds_workaround (bits_image_t *image)
{
if (image->common.clip_sources &&
image->common.repeat == PIXMAN_REPEAT_NONE &&
image->common.have_clip_region &&
out_of_bounds_workaround)
{
if (!image->common.client_clip)
{
/* There is no client clip, so if the clip region extends beyond the
* drawable geometry, it must be because the X server generated the
* bogus clip region.
*/
const pixman_box32_t *extents =
pixman_region32_extents (&image->common.clip_region);
if (extents->x1 >= 0 && extents->x2 <= image->width &&
extents->y1 >= 0 && extents->y2 <= image->height)
{
return FALSE;
}
}
return TRUE;
}
return FALSE;
}
static void
@ -315,8 +288,24 @@ compute_image_info (pixman_image_t *image)
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)
@ -338,11 +327,56 @@ compute_image_info (pixman_image_t *image)
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;
@ -408,6 +442,7 @@ compute_image_info (pixman_image_t *image)
else
{
code = image->bits.format;
flags |= FAST_PATH_BITS_IMAGE;
}
if (!PIXMAN_FORMAT_A (image->bits.format) &&
@ -420,9 +455,6 @@ compute_image_info (pixman_image_t *image)
flags |= FAST_PATH_IS_OPAQUE;
}
if (source_image_needs_out_of_bounds_workaround (&image->bits))
flags |= FAST_PATH_NEEDS_WORKAROUND;
if (image->bits.read_func || image->bits.write_func)
flags &= ~FAST_PATH_NO_ACCESSORS;
@ -445,6 +477,7 @@ compute_image_info (pixman_image_t *image)
/* Fall through */
case CONICAL:
case LINEAR:
code = PIXMAN_unknown;
@ -486,8 +519,9 @@ compute_image_info (pixman_image_t *image)
* 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 ||
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);
@ -509,7 +543,8 @@ _pixman_image_validate (pixman_image_t *image)
* property_changed() can make use of the flags
* to set up accessors etc.
*/
image->common.property_changed (image);
if (image->common.property_changed)
image->common.property_changed (image);
image->common.dirty = FALSE;
}
@ -590,7 +625,7 @@ pixman_image_set_transform (pixman_image_t * image,
if (common->transform == transform)
return TRUE;
if (memcmp (&id, transform, sizeof (pixman_transform_t)) == 0)
if (!transform || memcmp (&id, transform, sizeof (pixman_transform_t)) == 0)
{
free (common->transform);
common->transform = NULL;
@ -599,6 +634,12 @@ pixman_image_set_transform (pixman_image_t * image,
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));
@ -623,6 +664,9 @@ 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);
@ -640,6 +684,19 @@ pixman_image_set_filter (pixman_image_t * image,
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)
{
@ -667,6 +724,9 @@ 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);
@ -682,6 +742,9 @@ pixman_image_set_indexed (pixman_image_t * image,
{
bits_image_t *bits = (bits_image_t *)image;
if (bits->indexed == indexed)
return;
bits->indexed = indexed;
image_property_changed (image);
@ -744,6 +807,9 @@ 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);
@ -822,19 +888,47 @@ pixman_image_get_format (pixman_image_t *image)
if (image->type == BITS)
return image->bits.format;
return 0;
return PIXMAN_null;
}
uint32_t
_pixman_image_get_solid (pixman_image_t * image,
pixman_format_code_t format)
_pixman_image_get_solid (pixman_implementation_t *imp,
pixman_image_t * image,
pixman_format_code_t format)
{
uint32_t result;
_pixman_image_get_scanline_32 (image, 0, 0, 1, &result, NULL);
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)
if (PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB
&& PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB_SRGB)
{
result = (((result & 0xff000000) >> 0) |
((result & 0x00ff0000) >> 16) |

View File

@ -27,168 +27,206 @@
#include <stdlib.h>
#include "pixman-private.h"
static void
delegate_combine_32 (pixman_implementation_t * imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
_pixman_implementation_combine_32 (imp->delegate,
op, dest, src, mask, width);
}
static void
delegate_combine_64 (pixman_implementation_t * imp,
pixman_op_t op,
uint64_t * dest,
const uint64_t * src,
const uint64_t * mask,
int width)
{
_pixman_implementation_combine_64 (imp->delegate,
op, dest, src, mask, width);
}
static void
delegate_combine_32_ca (pixman_implementation_t * imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
_pixman_implementation_combine_32_ca (imp->delegate,
op, dest, src, mask, width);
}
static void
delegate_combine_64_ca (pixman_implementation_t * imp,
pixman_op_t op,
uint64_t * dest,
const uint64_t * src,
const uint64_t * mask,
int width)
{
_pixman_implementation_combine_64_ca (imp->delegate,
op, dest, src, mask, width);
}
static pixman_bool_t
delegate_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 dst_x,
int dst_y,
int width,
int height)
{
return _pixman_implementation_blt (
imp->delegate, src_bits, dst_bits, src_stride, dst_stride,
src_bpp, dst_bpp, src_x, src_y, dst_x, dst_y,
width, height);
}
static pixman_bool_t
delegate_fill (pixman_implementation_t *imp,
uint32_t * bits,
int stride,
int bpp,
int x,
int y,
int width,
int height,
uint32_t xor)
{
return _pixman_implementation_fill (
imp->delegate, bits, stride, bpp, x, y, width, height, xor);
}
pixman_implementation_t *
_pixman_implementation_create (pixman_implementation_t *delegate,
_pixman_implementation_create (pixman_implementation_t *fallback,
const pixman_fast_path_t *fast_paths)
{
pixman_implementation_t *imp = malloc (sizeof (pixman_implementation_t));
pixman_implementation_t *d;
int i;
if (!imp)
return NULL;
pixman_implementation_t *imp;
assert (fast_paths);
/* Make sure the whole delegate chain has the right toplevel */
imp->delegate = delegate;
for (d = imp; d != NULL; d = d->delegate)
d->toplevel = imp;
/* Fill out function pointers with ones that just delegate
*/
imp->blt = delegate_blt;
imp->fill = delegate_fill;
for (i = 0; i < PIXMAN_N_OPERATORS; ++i)
if ((imp = malloc (sizeof (pixman_implementation_t))))
{
imp->combine_32[i] = delegate_combine_32;
imp->combine_64[i] = delegate_combine_64;
imp->combine_32_ca[i] = delegate_combine_32_ca;
imp->combine_64_ca[i] = delegate_combine_64_ca;
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;
}
imp->fast_paths = fast_paths;
return imp;
}
void
_pixman_implementation_combine_32 (pixman_implementation_t * imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
#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)
{
(*imp->combine_32[op]) (imp, op, dest, src, mask, width);
}
void
_pixman_implementation_combine_64 (pixman_implementation_t * imp,
pixman_op_t op,
uint64_t * dest,
const uint64_t * src,
const uint64_t * mask,
int width)
_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)
{
(*imp->combine_64[op]) (imp, op, dest, src, mask, width);
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;
}
}
void
_pixman_implementation_combine_32_ca (pixman_implementation_t * imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
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)
{
(*imp->combine_32_ca[op]) (imp, op, dest, src, mask, width);
}
void
_pixman_implementation_combine_64_ca (pixman_implementation_t * imp,
pixman_op_t op,
uint64_t * dest,
const uint64_t * src,
const uint64_t * mask,
int width)
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)
{
(*imp->combine_64_ca[op]) (imp, op, dest, src, mask, width);
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
@ -201,14 +239,25 @@ _pixman_implementation_blt (pixman_implementation_t * imp,
int dst_bpp,
int src_x,
int src_y,
int dst_x,
int dst_y,
int dest_x,
int dest_y,
int width,
int height)
{
return (*imp->blt) (imp, src_bits, dst_bits, src_stride, dst_stride,
src_bpp, dst_bpp, src_x, src_y, dst_x, dst_y,
width, 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
@ -220,8 +269,130 @@ _pixman_implementation_fill (pixman_implementation_t *imp,
int y,
int width,
int height,
uint32_t xor)
uint32_t filler)
{
return (*imp->fill) (imp, bits, stride, bpp, x, y, width, height, xor);
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;
}

File diff suppressed because it is too large Load Diff

View File

@ -31,36 +31,32 @@
#include <stdlib.h>
#include "pixman-private.h"
static source_image_class_t
linear_gradient_classify (pixman_image_t *image,
int x,
int y,
int width,
int height)
static pixman_bool_t
linear_gradient_is_horizontal (pixman_image_t *image,
int x,
int y,
int width,
int height)
{
source_image_t *source = (source_image_t *)image;
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;
source_image_class_t class;
class = SOURCE_IMAGE_CLASS_UNKNOWN;
if (source->common.transform)
if (image->common.transform)
{
/* projective transformation */
if (source->common.transform->matrix[2][0] != 0 ||
source->common.transform->matrix[2][1] != 0 ||
source->common.transform->matrix[2][2] == 0)
if (image->common.transform->matrix[2][0] != 0 ||
image->common.transform->matrix[2][1] != 0 ||
image->common.transform->matrix[2][2] == 0)
{
return class;
return FALSE;
}
v.vector[0] = source->common.transform->matrix[0][1];
v.vector[1] = source->common.transform->matrix[1][1];
v.vector[2] = source->common.transform->matrix[2][2];
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
{
@ -75,7 +71,7 @@ linear_gradient_classify (pixman_image_t *image,
l = dx * dx + dy * dy;
if (l == 0)
return class;
return FALSE;
/*
* compute how much the input of the gradient walked changes
@ -87,43 +83,44 @@ linear_gradient_classify (pixman_image_t *image,
/* check that casting to integer would result in 0 */
if (-1 < inc && inc < 1)
class = SOURCE_IMAGE_CLASS_HORIZONTAL;
return TRUE;
return class;
return FALSE;
}
static void
linear_gradient_get_scanline_32 (pixman_image_t *image,
int x,
int y,
int width,
uint32_t * buffer,
const uint32_t *mask)
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;
source_image_t *source = (source_image_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, source->common.repeat);
_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 (source->common.transform)
if (image->common.transform)
{
if (!pixman_transform_point_3d (source->common.transform, &v))
return;
unit.vector[0] = source->common.transform->matrix[0][0];
unit.vector[1] = source->common.transform->matrix[1][0];
unit.vector[2] = source->common.transform->matrix[2][0];
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
{
@ -219,18 +216,48 @@ linear_gradient_get_scanline_32 (pixman_image_t *image,
v.vector[2] += unit.vector[2];
}
}
iter->y++;
return iter->buffer;
}
static void
linear_gradient_property_changed (pixman_image_t *image)
static uint32_t *
linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
{
image->common.get_scanline_32 = linear_gradient_get_scanline_32;
image->common.get_scanline_64 = _pixman_image_get_scanline_generic_64;
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 (pixman_point_fixed_t * p1,
pixman_point_fixed_t * p2,
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)
{
@ -254,8 +281,6 @@ pixman_image_create_linear_gradient (pixman_point_fixed_t * p1,
linear->p2 = *p2;
image->type = LINEAR;
image->common.classify = linear_gradient_classify;
image->common.property_changed = linear_gradient_property_changed;
return image;
}

View File

@ -25,7 +25,7 @@
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#include <math.h>
@ -34,6 +34,338 @@
#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)
{
@ -50,69 +382,41 @@ PIXMAN_EXPORT pixman_bool_t
pixman_transform_point_3d (const struct pixman_transform *transform,
struct pixman_vector * vector)
{
struct pixman_vector result;
pixman_fixed_32_32_t partial;
pixman_fixed_48_16_t v;
int i, j;
pixman_vector_48_16_t tmp;
tmp.v[0] = vector->vector[0];
tmp.v[1] = vector->vector[1];
tmp.v[2] = vector->vector[2];
for (j = 0; j < 3; j++)
{
v = 0;
for (i = 0; i < 3; i++)
{
partial = ((pixman_fixed_48_16_t) transform->matrix[j][i] *
(pixman_fixed_48_16_t) vector->vector[i]);
v += partial >> 16;
}
if (v > pixman_max_fixed_48_16 || v < pixman_min_fixed_48_16)
return FALSE;
result.vector[j] = (pixman_fixed_t) v;
}
*vector = result;
pixman_transform_point_31_16_3d (transform, &tmp, &tmp);
if (!result.vector[2])
return FALSE;
vector->vector[0] = tmp.v[0];
vector->vector[1] = tmp.v[1];
vector->vector[2] = tmp.v[2];
return TRUE;
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_fixed_32_32_t partial;
pixman_fixed_34_30_t v[3];
pixman_fixed_48_16_t quo;
int i, j;
pixman_vector_48_16_t tmp;
tmp.v[0] = vector->vector[0];
tmp.v[1] = vector->vector[1];
tmp.v[2] = vector->vector[2];
for (j = 0; j < 3; j++)
{
v[j] = 0;
for (i = 0; i < 3; i++)
{
partial = ((pixman_fixed_32_32_t) transform->matrix[j][i] *
(pixman_fixed_32_32_t) vector->vector[i]);
v[j] += partial >> 2;
}
}
if (!(v[2] >> 16))
return FALSE;
if (!pixman_transform_point_31_16 (transform, &tmp, &tmp))
return FALSE;
for (j = 0; j < 2; j++)
{
quo = v[j] / (v[2] >> 16);
if (quo > pixman_max_fixed_48_16 || quo < pixman_min_fixed_48_16)
return FALSE;
vector->vector[j] = (pixman_fixed_t) quo;
}
vector->vector[2] = pixman_fixed_1;
return TRUE;
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
@ -138,7 +442,7 @@ pixman_transform_multiply (struct pixman_transform * dst,
(pixman_fixed_32_32_t) l->matrix[dy][o] *
(pixman_fixed_32_32_t) r->matrix[o][dx];
v += partial >> 16;
v += (partial + 0x8000) >> 16;
}
if (v > pixman_max_fixed_48_16 || v < pixman_min_fixed_48_16)
@ -336,14 +640,14 @@ PIXMAN_EXPORT pixman_bool_t
pixman_transform_invert (struct pixman_transform * dst,
const struct pixman_transform *src)
{
struct pixman_f_transform m, r;
struct pixman_f_transform m;
pixman_f_transform_from_pixman_transform (&m, src);
if (!pixman_f_transform_invert (&r, &m))
if (!pixman_f_transform_invert (&m, &m))
return FALSE;
if (!pixman_transform_from_pixman_f_transform (dst, &r))
if (!pixman_transform_from_pixman_f_transform (dst, &m))
return FALSE;
return TRUE;
@ -425,7 +729,8 @@ pixman_transform_is_inverse (const struct pixman_transform *a,
{
struct pixman_transform t;
pixman_transform_multiply (&t, a, b);
if (!pixman_transform_multiply (&t, a, b))
return FALSE;
return pixman_transform_is_identity (&t);
}
@ -464,17 +769,15 @@ pixman_transform_from_pixman_f_transform (struct pixman_transform * t,
return TRUE;
}
static const int a[3] = { 3, 3, 2 };
static const int b[3] = { 2, 1, 1 };
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;
static int a[3] = { 2, 2, 1 };
static int b[3] = { 1, 0, 0 };
det = 0;
for (i = 0; i < 3; i++)
@ -509,10 +812,12 @@ pixman_f_transform_invert (struct pixman_f_transform * dst,
if (((i + j) & 1) != 0)
p = -p;
dst->m[j][i] = det * p;
d.m[j][i] = det * p;
}
}
*dst = d;
return TRUE;
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -78,11 +78,11 @@ radial_compute_color (double a,
{
/*
* In this function error propagation can lead to bad results:
* - det can have an unbound error (if b*b-a*c is very small),
* - 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 sqrtdet;
* if det has the wrong sign or b is very small, this can lead to bad
* 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
@ -92,7 +92,7 @@ radial_compute_color (double a,
*
* - the above problems are worse if a is small (as inva becomes bigger)
*/
double det;
double discr;
if (a == 0)
{
@ -109,22 +109,33 @@ radial_compute_color (double a,
}
else
{
if (t * dr > mindr)
if (t * dr >= mindr)
return _pixman_gradient_walker_pixel (walker, t);
}
return 0;
}
det = fdot (b, a, 0, b, -c, 0);
if (det >= 0)
discr = fdot (b, a, 0, b, -c, 0);
if (discr >= 0)
{
double sqrtdet, t0, t1;
double sqrtdiscr, t0, t1;
sqrtdet = sqrt (det);
t0 = (b + sqrtdet) * inva;
t1 = (b - sqrtdet) * inva;
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)
@ -134,9 +145,9 @@ radial_compute_color (double a,
}
else
{
if (t0 * dr > mindr)
if (t0 * dr >= mindr)
return _pixman_gradient_walker_pixel (walker, t0);
else if (t1 * dr > mindr)
else if (t1 * dr >= mindr)
return _pixman_gradient_walker_pixel (walker, t1);
}
}
@ -144,19 +155,14 @@ radial_compute_color (double a,
return 0;
}
static void
radial_gradient_get_scanline_32 (pixman_image_t *image,
int x,
int y,
int width,
uint32_t * buffer,
const uint32_t *mask)
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.
*
@ -173,7 +179,7 @@ radial_gradient_get_scanline_32 (pixman_image_t *image,
*
* 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 operatior composition.
* 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
@ -184,14 +190,14 @@ radial_gradient_get_scanline_32 (pixman_image_t *image,
* 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
* lenght(t·cd - pd) = r + t·dr
* length(t·cd - pd) = r + t·dr
*
* which actually means
*
@ -217,7 +223,7 @@ radial_gradient_get_scanline_32 (pixman_image_t *image,
* 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
@ -233,9 +239,13 @@ radial_gradient_get_scanline_32 (pixman_image_t *image,
* <=> 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;
source_image_t *source = (source_image_t *)image;
radial_gradient_t *radial = (radial_gradient_t *)image;
uint32_t *end = buffer + width;
pixman_gradient_walker_t walker;
@ -246,16 +256,16 @@ radial_gradient_get_scanline_32 (pixman_image_t *image,
v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
_pixman_gradient_walker_init (&walker, gradient, source->common.repeat);
_pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
if (source->common.transform)
if (image->common.transform)
{
if (!pixman_transform_point_3d (source->common.transform, &v))
return;
unit.vector[0] = source->common.transform->matrix[0][0];
unit.vector[1] = source->common.transform->matrix[1][0];
unit.vector[2] = source->common.transform->matrix[2][0];
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
{
@ -325,7 +335,7 @@ radial_gradient_get_scanline_32 (pixman_image_t *image,
radial->delta.radius,
radial->mindr,
&walker,
source->common.repeat);
image->common.repeat);
}
b += db;
@ -370,14 +380,14 @@ radial_gradient_get_scanline_32 (pixman_image_t *image,
radial->delta.radius,
radial->mindr,
&walker,
source->common.repeat);
image->common.repeat);
}
else
{
*buffer = 0;
}
}
++buffer;
v.vector[0] += unit.vector[0];
@ -385,18 +395,34 @@ radial_gradient_get_scanline_32 (pixman_image_t *image,
v.vector[2] += unit.vector[2];
}
}
iter->y++;
return iter->buffer;
}
static void
radial_gradient_property_changed (pixman_image_t *image)
static uint32_t *
radial_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
{
image->common.get_scanline_32 = radial_gradient_get_scanline_32;
image->common.get_scanline_64 = _pixman_image_get_scanline_generic_64;
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 (pixman_point_fixed_t * inner,
pixman_point_fixed_t * outer,
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,
@ -441,8 +467,5 @@ pixman_image_create_radial_gradient (pixman_point_fixed_t * inner,
radial->mindr = -1. * pixman_fixed_1 * radial->c1.radius;
image->common.property_changed = radial_gradient_property_changed;
return image;
}

View File

@ -102,7 +102,11 @@
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_);
@ -198,7 +202,7 @@ PIXREGION_SZOF (size_t n)
return size + sizeof(region_data_type_t);
}
static void *
static region_data_type_t *
alloc_data (size_t n)
{
size_t sz = PIXREGION_SZOF (n);
@ -738,8 +742,7 @@ typedef pixman_bool_t (*overlap_proc_ptr) (region_type_t *region,
box_type_t * r2,
box_type_t * r2_end,
int y1,
int y2,
int * overlap);
int y2);
static pixman_bool_t
pixman_op (region_type_t * new_reg, /* Place to store result */
@ -750,10 +753,10 @@ pixman_op (region_type_t * new_reg, /* Place to store result
int append_non1, /* Append non-overlapping bands
* in region 1 ?
*/
int append_non2, /* Append non-overlapping bands
int append_non2 /* Append non-overlapping bands
* in region 2 ?
*/
int * overlap)
)
{
box_type_t *r1; /* Pointer into first region */
box_type_t *r2; /* Pointer into 2d region */
@ -824,8 +827,7 @@ pixman_op (region_type_t * new_reg, /* Place to store result
{
if (!pixman_rect_alloc (new_reg, new_size))
{
if (old_data)
free (old_data);
free (old_data);
return FALSE;
}
}
@ -932,8 +934,7 @@ pixman_op (region_type_t * new_reg, /* Place to store result
if (!(*overlap_func)(new_reg,
r1, r1_band_end,
r2, r2_band_end,
ytop, ybot,
overlap))
ytop, ybot))
{
goto bail;
}
@ -1001,8 +1002,7 @@ pixman_op (region_type_t * new_reg, /* Place to store result
APPEND_REGIONS (new_reg, r2_band_end, r2_end);
}
if (old_data)
free (old_data);
free (old_data);
if (!(numRects = new_reg->data->numRects))
{
@ -1023,8 +1023,7 @@ pixman_op (region_type_t * new_reg, /* Place to store result
return TRUE;
bail:
if (old_data)
free (old_data);
free (old_data);
return pixman_break (new_reg);
}
@ -1112,8 +1111,7 @@ pixman_region_intersect_o (region_type_t *region,
box_type_t * r2,
box_type_t * r2_end,
int y1,
int y2,
int * overlap)
int y2)
{
int x1;
int x2;
@ -1209,13 +1207,9 @@ PREFIX (_intersect) (region_type_t * new_reg,
else
{
/* General purpose intersection */
int overlap; /* result ignored */
if (!pixman_op (new_reg, reg1, reg2, pixman_region_intersect_o, FALSE, FALSE,
&overlap))
{
if (!pixman_op (new_reg, reg1, reg2, pixman_region_intersect_o, FALSE, FALSE))
return FALSE;
}
pixman_set_extents (new_reg);
}
@ -1230,9 +1224,6 @@ PREFIX (_intersect) (region_type_t * new_reg,
if (r->x1 <= x2) \
{ \
/* Merge with current rectangle */ \
if (r->x1 < x2) \
*overlap = TRUE; \
\
if (x2 < r->x2) \
x2 = r->x2; \
} \
@ -1272,8 +1263,7 @@ pixman_region_union_o (region_type_t *region,
box_type_t * r2,
box_type_t * r2_end,
int y1,
int y2,
int * overlap)
int y2)
{
box_type_t *next_rect;
int x1; /* left and right side of current union */
@ -1382,8 +1372,6 @@ PREFIX (_union) (region_type_t *new_reg,
region_type_t *reg1,
region_type_t *reg2)
{
int overlap; /* result ignored */
/* Return TRUE if some overlap
* between reg1, reg2
*/
@ -1449,7 +1437,7 @@ PREFIX (_union) (region_type_t *new_reg,
return TRUE;
}
if (!pixman_op (new_reg, reg1, reg2, pixman_region_union_o, TRUE, TRUE, &overlap))
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);
@ -1516,9 +1504,7 @@ quick_sort_rects (
r++;
i++;
}
while (i != numRects && (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1)))
;
while (i != numRects && (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1)));
r = &(rects[j]);
do
@ -1579,8 +1565,7 @@ quick_sort_rects (
*/
static pixman_bool_t
validate (region_type_t * badreg,
int * overlap)
validate (region_type_t * badreg)
{
/* Descriptor for regions under construction in Step 2. */
typedef struct
@ -1605,7 +1590,6 @@ validate (region_type_t * badreg,
region_type_t *hreg; /* ri[j_half].reg */
pixman_bool_t ret = TRUE;
*overlap = FALSE;
if (!badreg->data)
{
GOOD (badreg);
@ -1679,9 +1663,6 @@ validate (region_type_t * badreg,
if (box->x1 <= ri_box->x2)
{
/* Merge it with ri_box */
if (box->x1 < ri_box->x2)
*overlap = TRUE;
if (box->x2 > ri_box->x2)
ri_box->x2 = box->x2;
}
@ -1785,7 +1766,7 @@ validate (region_type_t * badreg,
reg = &ri[j].reg;
hreg = &ri[j + half].reg;
if (!pixman_op (reg, reg, hreg, pixman_region_union_o, TRUE, TRUE, overlap))
if (!pixman_op (reg, reg, hreg, pixman_region_union_o, TRUE, TRUE))
ret = FALSE;
if (hreg->extents.x1 < reg->extents.x1)
@ -1853,8 +1834,7 @@ pixman_region_subtract_o (region_type_t * region,
box_type_t * r2,
box_type_t * r2_end,
int y1,
int y2,
int * overlap)
int y2)
{
box_type_t * next_rect;
int x1;
@ -1878,7 +1858,7 @@ pixman_region_subtract_o (region_type_t * region,
else if (r2->x1 <= x1)
{
/*
* Subtrahend preceeds minuend: nuke left edge of minuend.
* Subtrahend precedes minuend: nuke left edge of minuend.
*/
x1 = r2->x2;
if (x1 >= r1->x2)
@ -1978,8 +1958,6 @@ PREFIX (_subtract) (region_type_t *reg_d,
region_type_t *reg_m,
region_type_t *reg_s)
{
int overlap; /* result ignored */
GOOD (reg_m);
GOOD (reg_s);
GOOD (reg_d);
@ -2004,9 +1982,9 @@ PREFIX (_subtract) (region_type_t *reg_d,
}
/* Add those rectangles in region 1 that aren't in region 2,
do yucky substraction for overlaps, and
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, &overlap))
if (!pixman_op (reg_d, reg_m, reg_s, pixman_region_subtract_o, TRUE, FALSE))
return FALSE;
/*
@ -2040,15 +2018,13 @@ PREFIX (_subtract) (region_type_t *reg_d,
*
*-----------------------------------------------------------------------
*/
pixman_bool_t
PIXMAN_EXPORT 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 */
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 */
int overlap; /* result ignored */
GOOD (reg1);
GOOD (new_reg);
@ -2066,12 +2042,12 @@ PIXMAN_EXPORT PREFIX (_inverse) (region_type_t *new_reg, /* Destination region
}
/* Add those rectangles in region 1 that aren't in region 2,
* do yucky substraction for overlaps, and
* 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, &overlap))
if (!pixman_op (new_reg, &inv_reg, reg1, pixman_region_subtract_o, TRUE, FALSE))
return FALSE;
/*
@ -2086,6 +2062,40 @@ PIXMAN_EXPORT PREFIX (_inverse) (region_type_t *new_reg, /* Destination region
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
@ -2102,10 +2112,9 @@ PIXMAN_EXPORT PREFIX (_inverse) (region_type_t *new_reg, /* Destination region
* 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_region_overlap_t
PIXMAN_EXPORT PREFIX (_contains_rectangle) (region_type_t * region,
box_type_t * prect)
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;
@ -2139,12 +2148,15 @@ PIXMAN_EXPORT PREFIX (_contains_rectangle) (region_type_t * region,
/* 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++)
pbox != pbox_end;
pbox++)
{
if (pbox->y2 <= y)
continue; /* getting up to speed or skipping remainder of band */
/* 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)
{
@ -2319,6 +2331,16 @@ PREFIX (_reset) (region_type_t *region, box_type_t *box)
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,
@ -2342,13 +2364,13 @@ PREFIX (_contains_point) (region_type_t * region,
return(TRUE);
}
for (pbox = PIXREGION_BOXPTR (region), pbox_end = pbox + numRects;
pbox != pbox_end;
pbox++)
{
if (y >= pbox->y2)
continue; /* not there yet */
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 */
@ -2528,7 +2550,7 @@ PREFIX (_init_rects) (region_type_t *region,
/* Validate */
region->extents.x1 = region->extents.x2 = 0;
return validate (region, &i);
return validate (region);
}
#define READ(_ptr) (*(_ptr))
@ -2545,8 +2567,7 @@ bitmap_addrect (region_type_t *reg,
((r-1)->y1 == ry1) && ((r-1)->y2 == ry2) &&
((r-1)->x1 <= rx1) && ((r-1)->x2 >= rx2))))
{
if (!reg->data ||
reg->data->numRects == reg->data->size)
if (reg->data->numRects == reg->data->size)
{
if (!pixman_rect_alloc (reg, 1))
return NULL;
@ -2590,6 +2611,8 @@ PREFIX (_init_from_image) (region_type_t *region,
PREFIX(_init) (region);
critical_if_fail (region->data);
return_if_fail (image->type == BITS);
return_if_fail (image->bits.format == PIXMAN_a1);

View File

@ -26,56 +26,6 @@
#endif
#include "pixman-private.h"
static void
solid_fill_get_scanline_32 (pixman_image_t *image,
int x,
int y,
int width,
uint32_t * buffer,
const uint32_t *mask)
{
uint32_t *end = buffer + width;
uint32_t color = image->solid.color_32;
while (buffer < end)
*(buffer++) = color;
return;
}
static void
solid_fill_get_scanline_64 (pixman_image_t *image,
int x,
int y,
int width,
uint32_t * buffer,
const uint32_t *mask)
{
uint64_t *b = (uint64_t *)buffer;
uint64_t *e = b + width;
uint64_t color = image->solid.color_64;
while (b < e)
*(b++) = color;
}
static source_image_class_t
solid_fill_classify (pixman_image_t *image,
int x,
int y,
int width,
int height)
{
return SOURCE_IMAGE_CLASS_HORIZONTAL;
}
static void
solid_fill_property_changed (pixman_image_t *image)
{
image->common.get_scanline_32 = solid_fill_get_scanline_32;
image->common.get_scanline_64 = solid_fill_get_scanline_64;
}
static uint32_t
color_to_uint32 (const pixman_color_t *color)
{
@ -86,18 +36,21 @@ color_to_uint32 (const pixman_color_t *color)
(color->blue >> 8);
}
static uint64_t
color_to_uint64 (const pixman_color_t *color)
static argb_t
color_to_float (const pixman_color_t *color)
{
return
((uint64_t)color->alpha << 48) |
((uint64_t)color->red << 32) |
((uint64_t)color->green << 16) |
((uint64_t)color->blue);
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 (pixman_color_t *color)
pixman_image_create_solid_fill (const pixman_color_t *color)
{
pixman_image_t *img = _pixman_image_allocate ();
@ -107,10 +60,7 @@ pixman_image_create_solid_fill (pixman_color_t *color)
img->type = SOLID;
img->solid.color = *color;
img->solid.color_32 = color_to_uint32 (color);
img->solid.color_64 = color_to_uint64 (color);
img->common.classify = solid_fill_classify;
img->common.property_changed = solid_fill_property_changed;
img->solid.color_float = color_to_float (color);
return img;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
/*
* 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
@ -25,6 +26,7 @@
#endif
#include <stdio.h>
#include <stdlib.h>
#include "pixman-private.h"
/*
@ -137,7 +139,7 @@ _pixman_edge_multi_init (pixman_edge_t * e,
if (ne > 0)
{
int nx = ne / e->dy;
ne -= nx * e->dy;
ne -= nx * (pixman_fixed_48_16_t)e->dy;
stepx += nx * e->signdx;
}
@ -228,14 +230,13 @@ pixman_line_fixed_edge_init (pixman_edge_t * e,
}
PIXMAN_EXPORT void
pixman_add_traps (pixman_image_t * image,
int16_t x_off,
int16_t y_off,
int ntrap,
pixman_trap_t * traps)
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 width;
int height;
pixman_fixed_t x_off_fixed;
@ -245,7 +246,6 @@ pixman_add_traps (pixman_image_t * image,
_pixman_image_validate (image);
width = image->bits.width;
height = image->bits.height;
bpp = PIXMAN_FORMAT_BPP (image->bits.format);
@ -349,10 +349,8 @@ pixman_rasterize_trapezoid (pixman_image_t * image,
int y_off)
{
int bpp;
int width;
int height;
pixman_fixed_t x_off_fixed;
pixman_fixed_t y_off_fixed;
pixman_edge_t l, r;
pixman_fixed_t t, b;
@ -364,11 +362,9 @@ pixman_rasterize_trapezoid (pixman_image_t * image,
if (!pixman_trapezoid_valid (trap))
return;
width = image->bits.width;
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);
t = trap->top + y_off_fixed;
@ -390,3 +386,326 @@ pixman_rasterize_trapezoid (pixman_image_t * image,
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);
}
}

View File

@ -31,15 +31,19 @@
#include "pixman-private.h"
pixman_bool_t
pixman_multiply_overflows_int (unsigned int a,
unsigned int b)
_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)
_pixman_addition_overflows_int (unsigned int a, unsigned int b)
{
return a > INT32_MAX - b;
}
@ -67,61 +71,96 @@ pixman_malloc_abc (unsigned int a,
return malloc (a * b * c);
}
/*
* Helper routine to expand a color component from 0 < n <= 8 bits to 16
* bits by replication.
*/
static inline uint64_t
expand16 (const uint8_t val, int nbits)
static force_inline uint16_t
float_to_unorm (float f, int n_bits)
{
/* Start out with the high bit of val in the high bit of result. */
uint16_t result = (uint16_t)val << (16 - nbits);
uint32_t u;
if (nbits == 0)
return 0;
if (f > 1.0)
f = 1.0;
if (f < 0.0)
f = 0.0;
/* Copy the bits in result, doubling the number of bits each time, until
* we fill all 16 bits.
*/
while (nbits < 16)
{
result |= result >> nbits;
nbits *= 2;
}
u = f * (1 << n_bits);
u -= (u >> n_bits);
return result;
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 ARGB8 format to ARGB16. To preserve
* precision, it needs to know the original source format. For example, if the
* source was PIXMAN_x1r5g5b5 and the red component contained bits 12345, then
* the expanded value is 12345123. To correctly expand this to 16 bits, it
* should be 1234512345123451 and not 1234512312345123.
* 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 (uint64_t * dst,
const uint32_t * src,
pixman_format_code_t format,
int width)
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.
*/
const int a_size = PIXMAN_FORMAT_A (format),
r_size = PIXMAN_FORMAT_R (format),
g_size = PIXMAN_FORMAT_G (format),
b_size = PIXMAN_FORMAT_B (format);
const int a_shift = 32 - a_size,
r_shift = 24 - r_size,
g_shift = 16 - g_size,
b_shift = 8 - b_size;
const uint8_t a_mask = ~(~0 << a_size),
r_mask = ~(~0 << r_size),
g_mask = ~(~0 << g_size),
b_mask = ~(~0 << b_size);
int i;
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
@ -129,44 +168,52 @@ pixman_expand (uint64_t * dst,
for (i = width - 1; i >= 0; i--)
{
const uint32_t pixel = src[i];
const uint8_t a = (pixel >> a_shift) & a_mask,
r = (pixel >> r_shift) & r_mask,
g = (pixel >> g_shift) & g_mask,
b = (pixel >> b_shift) & b_mask;
const uint64_t a16 = a_size ? expand16 (a, a_size) : 0xffff,
r16 = expand16 (r, r_size),
g16 = expand16 (g, g_size),
b16 = expand16 (b, b_size);
dst[i] = a16 << 48 | r16 << 32 | g16 << 16 | b16;
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;
}
}
/*
* Contracting is easier than expanding. We just need to truncate the
* components.
*/
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 (uint32_t * dst,
const uint64_t *src,
int width)
pixman_contract_from_float (uint32_t *dst,
const argb_t *src,
int width)
{
int i;
/* Start at the beginning so that we can do the contraction in
* place when src == dst
*/
for (i = 0; i < width; i++)
for (i = 0; i < width; ++i)
{
const uint8_t a = src[i] >> 56,
r = src[i] >> 40,
g = src[i] >> 24,
b = src[i] >> 8;
uint8_t a, r, g, b;
dst[i] = a << 24 | r << 16 | g << 8 | 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
@ -236,7 +283,14 @@ pixman_region32_copy_from_region16 (pixman_region32_t *dst,
return retval;
}
#ifdef DEBUG
/* 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)
@ -254,5 +308,3 @@ _pixman_log_error (const char *function, const char *message)
n_messages++;
}
}
#endif

View File

@ -32,10 +32,10 @@
#endif
#define PIXMAN_VERSION_MAJOR 0
#define PIXMAN_VERSION_MINOR 20
#define PIXMAN_VERSION_MINOR 30
#define PIXMAN_VERSION_MICRO 2
#define PIXMAN_VERSION_STRING "0.20.2"
#define PIXMAN_VERSION_STRING "0.30.2"
#define PIXMAN_VERSION_ENCODE(major, minor, micro) ( \
((major) * 10000) \

View File

@ -1,263 +0,0 @@
#ifndef MMX_X64_H_INCLUDED
#define MMX_X64_H_INCLUDED
/* Implementation of x64 MMX substitition functions, before
* pixman is reimplemented not to use __m64 type on Visual C++
*
* Copyright (C)2009 by George Yohng
* Released in public domain.
*/
#include <intrin.h>
#define M64C(a) (*(const __m64 *)(&a))
#define M64U(a) (*(const unsigned long long *)(&a))
__inline __m64
_m_from_int (int a)
{
long long i64 = a;
return M64C (i64);
}
__inline __m64
_mm_setzero_si64 ()
{
long long i64 = 0;
return M64C (i64);
}
__inline __m64
_mm_set_pi32 (int i1, int i0)
{
unsigned long long i64 = ((unsigned)i0) + (((unsigned long long)(unsigned)i1) << 32);
return M64C (i64);
}
__inline void
_m_empty ()
{
}
__inline __m64
_mm_set1_pi16 (short w)
{
unsigned long long i64 = ((unsigned long long)(unsigned short)(w)) * 0x0001000100010001ULL;
return M64C (i64);
}
__inline int
_m_to_int (__m64 m)
{
return m.m64_i32[0];
}
__inline __m64
_mm_movepi64_pi64 (__m128i a)
{
return M64C (a.m128i_i64[0]);
}
__inline __m64
_m_pand (__m64 a, __m64 b)
{
unsigned long long i64 = M64U (a) & M64U (b);
return M64C (i64);
}
__inline __m64
_m_por (__m64 a, __m64 b)
{
unsigned long long i64 = M64U (a) | M64U (b);
return M64C (i64);
}
__inline __m64
_m_pxor (__m64 a, __m64 b)
{
unsigned long long i64 = M64U (a) ^ M64U (b);
return M64C (i64);
}
__inline __m64
_m_pmulhuw (__m64 a, __m64 b) /* unoptimized */
{
unsigned short d[4] =
{
(unsigned short)((((unsigned)a.m64_u16[0]) * b.m64_u16[0]) >> 16),
(unsigned short)((((unsigned)a.m64_u16[1]) * b.m64_u16[1]) >> 16),
(unsigned short)((((unsigned)a.m64_u16[2]) * b.m64_u16[2]) >> 16),
(unsigned short)((((unsigned)a.m64_u16[3]) * b.m64_u16[3]) >> 16)
};
return M64C (d[0]);
}
__inline __m64
_m_pmullw2 (__m64 a, __m64 b) /* unoptimized */
{
unsigned short d[4] =
{
(unsigned short)((((unsigned)a.m64_u16[0]) * b.m64_u16[0])),
(unsigned short)((((unsigned)a.m64_u16[1]) * b.m64_u16[1])),
(unsigned short)((((unsigned)a.m64_u16[2]) * b.m64_u16[2])),
(unsigned short)((((unsigned)a.m64_u16[3]) * b.m64_u16[3]))
};
return M64C (d[0]);
}
__inline __m64
_m_pmullw (__m64 a, __m64 b) /* unoptimized */
{
unsigned long long x =
((unsigned long long)(unsigned short)((((unsigned)a.m64_u16[0]) * b.m64_u16[0]))) +
(((unsigned long long)(unsigned short)((((unsigned)a.m64_u16[1]) * b.m64_u16[1]))) << 16) +
(((unsigned long long)(unsigned short)((((unsigned)a.m64_u16[2]) * b.m64_u16[2]))) << 32) +
(((unsigned long long)(unsigned short)((((unsigned)a.m64_u16[3]) * b.m64_u16[3]))) << 48);
return M64C (x);
}
__inline __m64
_m_paddusb (__m64 a, __m64 b) /* unoptimized */
{
unsigned long long x = (M64U (a) & 0x00FF00FF00FF00FFULL) +
(M64U (b) & 0x00FF00FF00FF00FFULL);
unsigned long long y = ((M64U (a) >> 8) & 0x00FF00FF00FF00FFULL) +
((M64U (b) >> 8) & 0x00FF00FF00FF00FFULL);
x |= ((x & 0xFF00FF00FF00FF00ULL) >> 8) * 0xFF;
y |= ((y & 0xFF00FF00FF00FF00ULL) >> 8) * 0xFF;
x = (x & 0x00FF00FF00FF00FFULL) | ((y & 0x00FF00FF00FF00FFULL) << 8);
return M64C (x);
}
__inline __m64
_m_paddusw (__m64 a, __m64 b) /* unoptimized */
{
unsigned long long x = (M64U (a) & 0x0000FFFF0000FFFFULL) +
(M64U (b) & 0x0000FFFF0000FFFFULL);
unsigned long long y = ((M64U (a) >> 16) & 0x0000FFFF0000FFFFULL) +
((M64U (b) >> 16) & 0x0000FFFF0000FFFFULL);
x |= ((x & 0xFFFF0000FFFF0000) >> 16) * 0xFFFF;
y |= ((y & 0xFFFF0000FFFF0000) >> 16) * 0xFFFF;
x = (x & 0x0000FFFF0000FFFFULL) | ((y & 0x0000FFFF0000FFFFULL) << 16);
return M64C (x);
}
__inline __m64
_m_pshufw (__m64 a, int n) /* unoptimized */
{
unsigned short d[4] =
{
a.m64_u16[n & 3],
a.m64_u16[(n >> 2) & 3],
a.m64_u16[(n >> 4) & 3],
a.m64_u16[(n >> 6) & 3]
};
return M64C (d[0]);
}
__inline unsigned char
sat16 (unsigned short d)
{
if (d > 0xFF) return 0xFF;
else return d & 0xFF;
}
__inline __m64
_m_packuswb (__m64 m1, __m64 m2) /* unoptimized */
{
unsigned char d[8] =
{
sat16 (m1.m64_u16[0]),
sat16 (m1.m64_u16[1]),
sat16 (m1.m64_u16[2]),
sat16 (m1.m64_u16[3]),
sat16 (m2.m64_u16[0]),
sat16 (m2.m64_u16[1]),
sat16 (m2.m64_u16[2]),
sat16 (m2.m64_u16[3])
};
return M64C (d[0]);
}
__inline __m64 _m_punpcklbw (__m64 m1, __m64 m2) /* unoptimized */
{
unsigned char d[8] =
{
m1.m64_u8[0],
m2.m64_u8[0],
m1.m64_u8[1],
m2.m64_u8[1],
m1.m64_u8[2],
m2.m64_u8[2],
m1.m64_u8[3],
m2.m64_u8[3],
};
return M64C (d[0]);
}
__inline __m64 _m_punpckhbw (__m64 m1, __m64 m2) /* unoptimized */
{
unsigned char d[8] =
{
m1.m64_u8[4],
m2.m64_u8[4],
m1.m64_u8[5],
m2.m64_u8[5],
m1.m64_u8[6],
m2.m64_u8[6],
m1.m64_u8[7],
m2.m64_u8[7],
};
return M64C (d[0]);
}
__inline __m64 _m_psrlwi (__m64 a, int n) /* unoptimized */
{
unsigned short d[4] =
{
a.m64_u16[0] >> n,
a.m64_u16[1] >> n,
a.m64_u16[2] >> n,
a.m64_u16[3] >> n
};
return M64C (d[0]);
}
__inline __m64 _m_psrlqi (__m64 m, int n)
{
unsigned long long x = M64U (m) >> n;
return M64C (x);
}
__inline __m64 _m_psllqi (__m64 m, int n)
{
unsigned long long x = M64U (m) << n;
return M64C (x);
}
#endif /* MMX_X64_H_INCLUDED */

View File

@ -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;
}

View File

@ -30,16 +30,15 @@
#include <stdlib.h>
static force_inline pixman_implementation_t *
get_implementation (void)
pixman_implementation_t *global_implementation;
#ifdef TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR
static void __attribute__((constructor))
pixman_constructor (void)
{
static pixman_implementation_t *global_implementation;
if (!global_implementation)
global_implementation = _pixman_choose_implementation ();
return global_implementation;
global_implementation = _pixman_choose_implementation ();
}
#endif
typedef struct operator_info_t operator_info_t;
@ -153,57 +152,6 @@ optimize_operator (pixman_op_t op,
return operator_table[op].opaque_info[is_dest_opaque | is_source_opaque];
}
static void
apply_workaround (pixman_image_t *image,
int32_t * x,
int32_t * y,
uint32_t ** save_bits,
int * save_dx,
int * save_dy)
{
if (image && (image->common.flags & FAST_PATH_NEEDS_WORKAROUND))
{
/* Some X servers generate images that point to the
* wrong place in memory, but then set the clip region
* to point to the right place. Because of an old bug
* in pixman, this would actually work.
*
* Here we try and undo the damage
*/
int bpp = PIXMAN_FORMAT_BPP (image->bits.format) / 8;
pixman_box32_t *extents;
uint8_t *t;
int dx, dy;
extents = pixman_region32_extents (&(image->common.clip_region));
dx = extents->x1;
dy = extents->y1;
*save_bits = image->bits.bits;
*x -= dx;
*y -= dy;
pixman_region32_translate (&(image->common.clip_region), -dx, -dy);
t = (uint8_t *)image->bits.bits;
t += dy * image->bits.rowstride * 4 + dx * bpp;
image->bits.bits = (uint32_t *)t;
*save_dx = dx;
*save_dy = dy;
}
}
static void
unapply_workaround (pixman_image_t *image, uint32_t *bits, int dx, int dy)
{
if (image && (image->common.flags & FAST_PATH_NEEDS_WORKAROUND))
{
image->bits.bits = bits;
pixman_region32_translate (&image->common.clip_region, dx, dy);
}
}
/*
* Computing composite region
*/
@ -276,19 +224,19 @@ clip_source_image (pixman_region32_t * region,
* returns FALSE if the final region is empty. Indistinguishable from
* an allocation failure, but rendering ignores those anyways.
*/
static pixman_bool_t
pixman_compute_composite_region32 (pixman_region32_t * region,
pixman_image_t * src_image,
pixman_image_t * mask_image,
pixman_image_t * dst_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)
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;
@ -297,8 +245,8 @@ pixman_compute_composite_region32 (pixman_region32_t * region,
region->extents.x1 = MAX (region->extents.x1, 0);
region->extents.y1 = MAX (region->extents.y1, 0);
region->extents.x2 = MIN (region->extents.x2, dst_image->bits.width);
region->extents.y2 = MIN (region->extents.y2, dst_image->bits.height);
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;
@ -313,29 +261,29 @@ pixman_compute_composite_region32 (pixman_region32_t * region,
return FALSE;
}
if (dst_image->common.have_clip_region)
if (dest_image->common.have_clip_region)
{
if (!clip_general_image (region, &dst_image->common.clip_region, 0, 0))
if (!clip_general_image (region, &dest_image->common.clip_region, 0, 0))
return FALSE;
}
if (dst_image->common.alpha_map)
if (dest_image->common.alpha_map)
{
if (!pixman_region32_intersect_rect (region, region,
dst_image->common.alpha_origin_x,
dst_image->common.alpha_origin_y,
dst_image->common.alpha_map->width,
dst_image->common.alpha_map->height))
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 (dst_image->common.alpha_map->common.have_clip_region)
if (dest_image->common.alpha_map->common.have_clip_region)
{
if (!clip_general_image (region, &dst_image->common.alpha_map->common.clip_region,
-dst_image->common.alpha_origin_x,
-dst_image->common.alpha_origin_y))
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;
}
@ -377,220 +325,89 @@ pixman_compute_composite_region32 (pixman_region32_t * region,
return TRUE;
}
#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_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;
PIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache);
static force_inline pixman_bool_t
lookup_composite_function (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)
static pixman_bool_t
compute_transformed_extents (pixman_transform_t *transform,
const pixman_box32_t *extents,
box_48_16_t *transformed)
{
pixman_implementation_t *imp;
cache_t *cache;
pixman_fixed_48_16_t tx1, ty1, tx2, ty2;
pixman_fixed_t x1, y1, x2, y2;
int i;
/* Check cache for fast paths */
cache = PIXMAN_GET_THREAD_LOCAL (fast_path_cache);
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;
for (i = 0; i < N_CACHED_FAST_PATHS; ++i)
if (!transform)
{
const pixman_fast_path_t *info = &(cache->cache[i].fast_path);
transformed->x1 = x1;
transformed->y1 = y1;
transformed->x2 = x2;
transformed->y2 = y2;
/* 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;
}
return TRUE;
}
for (imp = get_implementation (); imp != NULL; imp = imp->delegate)
tx1 = ty1 = INT64_MAX;
tx2 = ty2 = INT64_MIN;
for (i = 0; i < 4; ++i)
{
const pixman_fast_path_t *info = imp->fast_paths;
pixman_fixed_48_16_t tx, ty;
pixman_vector_t v;
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;
v.vector[0] = (i & 0x01)? x1 : x2;
v.vector[1] = (i & 0x02)? y1 : y2;
v.vector[2] = pixman_fixed_1;
/* 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;
if (!pixman_transform_point (transform, &v))
return FALSE;
goto update_cache;
}
tx = (pixman_fixed_48_16_t)v.vector[0];
ty = (pixman_fixed_48_16_t)v.vector[1];
++info;
}
if (tx < tx1)
tx1 = tx;
if (ty < ty1)
ty1 = ty;
if (tx > tx2)
tx2 = tx;
if (ty > ty2)
ty2 = ty;
}
return FALSE;
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;
}
transformed->x1 = tx1;
transformed->y1 = ty1;
transformed->x2 = tx2;
transformed->y2 = ty2;
return TRUE;
}
static pixman_bool_t
compute_sample_extents (pixman_transform_t *transform,
pixman_box32_t *extents, int x, int y,
pixman_fixed_t x_off, pixman_fixed_t y_off,
pixman_fixed_t width, pixman_fixed_t height)
{
pixman_fixed_t x1, y1, x2, y2;
pixman_fixed_48_16_t tx1, ty1, tx2, ty2;
/* We have checked earlier that (extents->x1 - x) etc. fit in a pixman_fixed_t */
x1 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->x1 - x) + pixman_fixed_1 / 2;
y1 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->y1 - y) + pixman_fixed_1 / 2;
x2 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->x2 - x) - pixman_fixed_1 / 2;
y2 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->y2 - y) - pixman_fixed_1 / 2;
if (!transform)
{
tx1 = (pixman_fixed_48_16_t)x1;
ty1 = (pixman_fixed_48_16_t)y1;
tx2 = (pixman_fixed_48_16_t)x2;
ty2 = (pixman_fixed_48_16_t)y2;
}
else
{
int i;
/* Silence GCC */
tx1 = ty1 = tx2 = ty2 = 0;
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 (i == 0)
{
tx1 = tx;
ty1 = ty;
tx2 = tx;
ty2 = ty;
}
else
{
if (tx < tx1)
tx1 = tx;
if (ty < ty1)
ty1 = ty;
if (tx > tx2)
tx2 = tx;
if (ty > ty2)
ty2 = ty;
}
}
}
/* 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.
*/
tx1 += x_off - 8 * pixman_fixed_e;
ty1 += y_off - 8 * pixman_fixed_e;
tx2 += x_off + width + 8 * pixman_fixed_e;
ty2 += y_off + height + 8 * pixman_fixed_e;
if (tx1 < pixman_min_fixed_48_16 || tx1 > pixman_max_fixed_48_16 ||
ty1 < pixman_min_fixed_48_16 || ty1 > pixman_max_fixed_48_16 ||
tx2 < pixman_min_fixed_48_16 || tx2 > pixman_max_fixed_48_16 ||
ty2 < pixman_min_fixed_48_16 || ty2 > pixman_max_fixed_48_16)
{
return FALSE;
}
else
{
extents->x1 = pixman_fixed_to_int (tx1);
extents->y1 = pixman_fixed_to_int (ty1);
extents->x2 = pixman_fixed_to_int (tx2) + 1;
extents->y2 = pixman_fixed_to_int (ty2) + 1;
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, int x, int y,
const pixman_box32_t *extents, uint32_t *flags)
analyze_extent (pixman_image_t *image,
const pixman_box32_t *extents,
uint32_t *flags)
{
pixman_transform_t *transform;
pixman_fixed_t *params;
pixman_fixed_t x_off, y_off;
pixman_fixed_t width, height;
pixman_box32_t ex;
pixman_fixed_t *params;
box_48_16_t transformed;
pixman_box32_t exp_extents;
if (!image)
return TRUE;
@ -600,10 +417,10 @@ analyze_extent (pixman_image_t *image, int x, int y,
* check here that the expanded-by-one source
* extents in destination space fits in 16 bits
*/
if (!IS_16BIT (extents->x1 - x - 1) ||
!IS_16BIT (extents->y1 - y - 1) ||
!IS_16BIT (extents->x2 - x + 1) ||
!IS_16BIT (extents->y2 - y + 1))
if (!IS_16BIT (extents->x1 - 1) ||
!IS_16BIT (extents->y1 - 1) ||
!IS_16BIT (extents->x2 + 1) ||
!IS_16BIT (extents->y2 + 1))
{
return FALSE;
}
@ -618,18 +435,16 @@ analyze_extent (pixman_image_t *image, int x, int y,
if (image->bits.width >= 0x7fff || image->bits.height >= 0x7fff)
return FALSE;
#define ID_AND_NEAREST (FAST_PATH_ID_TRANSFORM | FAST_PATH_NEAREST_FILTER)
if ((image->common.flags & ID_AND_NEAREST) == ID_AND_NEAREST &&
extents->x1 - x >= 0 &&
extents->y1 - y >= 0 &&
extents->x2 - x <= image->bits.width &&
extents->y2 - y <= image->bits.height)
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;
*flags |= FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
return TRUE;
}
switch (image->common.filter)
{
case PIXMAN_FILTER_CONVOLUTION:
@ -640,6 +455,14 @@ analyze_extent (pixman_image_t *image, int x, int y,
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:
@ -660,17 +483,6 @@ analyze_extent (pixman_image_t *image, int x, int y,
default:
return FALSE;
}
/* Check whether the non-expanded, transformed extent is entirely within
* the source image, and set the FAST_PATH_SAMPLES_COVER_CLIP if it is.
*/
ex = *extents;
if (compute_sample_extents (transform, &ex, x, y, x_off, y_off, width, height) &&
ex.x1 >= 0 && ex.y1 >= 0 &&
ex.x2 <= image->bits.width && ex.y2 <= image->bits.height)
{
*flags |= FAST_PATH_SAMPLES_COVER_CLIP;
}
}
else
{
@ -680,18 +492,58 @@ analyze_extent (pixman_image_t *image, int x, int y,
height = 0;
}
/* Check that the extents expanded by one don't overflow. This ensures that
* compositing functions can simply walk the source space using 16.16
* variables without worrying about overflow.
*/
ex.x1 = extents->x1 - 1;
ex.y1 = extents->y1 - 1;
ex.x2 = extents->x2 + 1;
ex.y2 = extents->y2 + 1;
if (!compute_sample_extents (transform, &ex, x, y, x_off, y_off, width, height))
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;
}
@ -729,18 +581,13 @@ pixman_image_composite32 (pixman_op_t op,
int32_t height)
{
pixman_format_code_t src_format, mask_format, dest_format;
uint32_t src_flags, mask_flags, dest_flags;
pixman_region32_t region;
pixman_box32_t *extents;
uint32_t *src_bits;
int src_dx, src_dy;
uint32_t *mask_bits;
int mask_dx, mask_dy;
uint32_t *dest_bits;
int dest_dx, dest_dy;
pixman_bool_t need_workaround;
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)
@ -748,26 +595,27 @@ pixman_image_composite32 (pixman_op_t op,
_pixman_image_validate (dest);
src_format = src->common.extended_format_code;
src_flags = src->common.flags;
info.src_flags = src->common.flags;
if (mask)
if (mask && !(mask->common.flags & FAST_PATH_IS_OPAQUE))
{
mask_format = mask->common.extended_format_code;
mask_flags = mask->common.flags;
info.mask_flags = mask->common.flags;
}
else
{
mask_format = PIXMAN_null;
mask_flags = FAST_PATH_IS_OPAQUE;
info.mask_flags = FAST_PATH_IS_OPAQUE;
}
dest_format = dest->common.extended_format_code;
dest_flags = dest->common.flags;
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)
@ -776,89 +624,92 @@ pixman_image_composite32 (pixman_op_t op,
src_format = mask_format = PIXMAN_rpixbuf;
}
/* Check for workaround */
need_workaround = (src_flags | mask_flags | dest_flags) & FAST_PATH_NEEDS_WORKAROUND;
if (need_workaround)
{
apply_workaround (src, &src_x, &src_y, &src_bits, &src_dx, &src_dy);
apply_workaround (mask, &mask_x, &mask_y, &mask_bits, &mask_dx, &mask_dy);
apply_workaround (dest, &dest_x, &dest_y, &dest_bits, &dest_dx, &dest_dy);
}
pixman_region32_init (&region);
if (!pixman_compute_composite_region32 (
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 = *pixman_region32_extents (&region);
if (!analyze_extent (src, dest_x - src_x, dest_y - src_y, extents, &src_flags))
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;
if (!analyze_extent (mask, dest_x - mask_x, dest_y - mask_y, extents, &mask_flags))
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.
/* If the clip is within the source samples, and the samples are
* opaque, then the source is effectively opaque.
*/
#define BOTH (FAST_PATH_SAMPLES_OPAQUE | FAST_PATH_SAMPLES_COVER_CLIP)
#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;
}
if ((src_flags & BOTH) == BOTH)
src_flags |= FAST_PATH_IS_OPAQUE;
if ((mask_flags & BOTH) == BOTH)
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.
*/
op = optimize_operator (op, src_flags, mask_flags, dest_flags);
if (op == PIXMAN_OP_DST)
goto out;
info.op = optimize_operator (op, info.src_flags, info.mask_flags, info.dest_flags);
if (lookup_composite_function (op,
src_format, src_flags,
mask_format, mask_flags,
dest_format, dest_flags,
&imp, &func))
_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--)
{
const pixman_box32_t *pbox;
int 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;
pbox = pixman_region32_rectangles (&region, &n);
while (n--)
{
func (imp, op,
src, mask, dest,
pbox->x1 + src_x - dest_x,
pbox->y1 + src_y - dest_y,
pbox->x1 + mask_x - dest_x,
pbox->y1 + mask_y - dest_y,
pbox->x1,
pbox->y1,
pbox->x2 - pbox->x1,
pbox->y2 - pbox->y1);
pbox++;
}
func (imp, &info);
pbox++;
}
out:
if (need_workaround)
{
unapply_workaround (src, src_bits, src_dx, src_dy);
unapply_workaround (mask, mask_bits, mask_dx, mask_dy);
unapply_workaround (dest, dest_bits, dest_dx, dest_dy);
}
pixman_region32_fini (&region);
}
@ -889,8 +740,8 @@ pixman_blt (uint32_t *src_bits,
int dst_bpp,
int src_x,
int src_y,
int dst_x,
int dst_y,
int dest_x,
int dest_y,
int width,
int height)
{
@ -898,7 +749,7 @@ pixman_blt (uint32_t *src_bits,
src_bits, dst_bits, src_stride, dst_stride,
src_bpp, dst_bpp,
src_x, src_y,
dst_x, dst_y,
dest_x, dest_y,
width, height);
}
@ -910,10 +761,10 @@ pixman_fill (uint32_t *bits,
int y,
int width,
int height,
uint32_t xor)
uint32_t filler)
{
return _pixman_implementation_fill (
get_implementation(), bits, stride, bpp, x, y, width, height, xor);
get_implementation(), bits, stride, bpp, x, y, width, height, filler);
}
static uint32_t
@ -927,9 +778,9 @@ color_to_uint32 (const pixman_color_t *color)
}
static pixman_bool_t
color_to_pixel (pixman_color_t * color,
uint32_t * pixel,
pixman_format_code_t format)
color_to_pixel (const pixman_color_t *color,
uint32_t * pixel,
pixman_format_code_t format)
{
uint32_t c = color_to_uint32 (color);
@ -939,9 +790,12 @@ color_to_pixel (pixman_color_t * color,
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_a8 ||
format == PIXMAN_a1))
{
return FALSE;
}
@ -960,12 +814,16 @@ color_to_pixel (pixman_color_t * color,
((c & 0x0000ff00) << 8) |
((c & 0x000000ff) << 24);
}
if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_RGBA)
c = ((c & 0xff000000) >> 24) | (c << 8);
if (format == PIXMAN_a8)
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);
c = convert_8888_to_0565 (c);
#if 0
printf ("color: %x %x %x %x\n", color->alpha, color->red, color->green, color->blue);
@ -979,7 +837,7 @@ color_to_pixel (pixman_color_t * color,
PIXMAN_EXPORT pixman_bool_t
pixman_image_fill_rectangles (pixman_op_t op,
pixman_image_t * dest,
pixman_color_t * color,
const pixman_color_t * color,
int n_rects,
const pixman_rectangle16_t *rects)
{
@ -1018,7 +876,7 @@ pixman_image_fill_rectangles (pixman_op_t op,
PIXMAN_EXPORT pixman_bool_t
pixman_image_fill_boxes (pixman_op_t op,
pixman_image_t * dest,
pixman_color_t * color,
const pixman_color_t *color,
int n_boxes,
const pixman_box32_t *boxes)
{
@ -1163,11 +1021,14 @@ pixman_format_supported_source (pixman_format_code_t format)
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:
@ -1243,7 +1104,7 @@ 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 * dst_image,
pixman_image_t * dest_image,
int16_t src_x,
int16_t src_y,
int16_t mask_x,
@ -1258,8 +1119,8 @@ pixman_compute_composite_region (pixman_region16_t * region,
pixman_region32_init (&r32);
retval = pixman_compute_composite_region32 (
&r32, src_image, mask_image, dst_image,
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);

View File

@ -226,6 +226,9 @@ pixman_bool_t pixman_transform_is_inverse (const struct pixman_transform *
/*
* 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];
@ -289,7 +292,28 @@ typedef enum
PIXMAN_FILTER_BEST,
PIXMAN_FILTER_NEAREST,
PIXMAN_FILTER_BILINEAR,
PIXMAN_FILTER_CONVOLUTION
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
@ -466,6 +490,7 @@ pixman_bool_t pixman_region_equal (pixman_region16_t *reg
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
*/
@ -560,6 +585,7 @@ pixman_bool_t pixman_region32_equal (pixman_region32_t *r
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 */
@ -571,8 +597,8 @@ pixman_bool_t pixman_blt (uint32_t *src_bits,
int dst_bpp,
int src_x,
int src_y,
int dst_x,
int dst_y,
int dest_x,
int dest_y,
int width,
int height);
pixman_bool_t pixman_fill (uint32_t *bits,
@ -650,11 +676,14 @@ struct pixman_indexed
#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_BGRA || \
PIXMAN_FORMAT_TYPE(f) == PIXMAN_TYPE_RGBA)
/* 32bpp formats */
typedef enum {
@ -664,12 +693,17 @@ typedef enum {
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),
@ -727,18 +761,18 @@ 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 (pixman_color_t *color);
pixman_image_t *pixman_image_create_linear_gradient (pixman_point_fixed_t *p1,
pixman_point_fixed_t *p2,
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 (pixman_point_fixed_t *inner,
pixman_point_fixed_t *outer,
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 (pixman_point_fixed_t *center,
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);
@ -747,6 +781,11 @@ pixman_image_t *pixman_image_create_bits (pixman_format_code_t
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);
@ -792,14 +831,41 @@ int pixman_image_get_height (pixman_image_t
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,
pixman_color_t *color,
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,
pixman_color_t *color,
const pixman_color_t *color,
int n_boxes,
const pixman_box32_t *boxes);
@ -807,7 +873,7 @@ pixman_bool_t pixman_image_fill_boxes (pixman_op_t
pixman_bool_t pixman_compute_composite_region (pixman_region16_t *region,
pixman_image_t *src_image,
pixman_image_t *mask_image,
pixman_image_t *dst_image,
pixman_image_t *dest_image,
int16_t src_x,
int16_t src_y,
int16_t mask_x,
@ -841,19 +907,84 @@ void pixman_image_composite32 (pixman_op_t op,
int32_t width,
int32_t height);
/* Old X servers rely on out-of-bounds accesses when they are asked
* to composite with a window as the source. They create a pixman image
* pointing to some bogus position in memory, but then they set a clip
* region to the position where the actual bits are.
/* 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 by default we allow certain out-of-bound access
* to happen unless explicitly disabled.
* 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.
*
* Fixed X servers should call this function to disable the workaround.
* 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);
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
@ -862,6 +993,7 @@ 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
@ -889,6 +1021,10 @@ struct pixman_trapezoid
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) \
@ -934,7 +1070,7 @@ void pixman_add_traps (pixman_image_t *image,
int16_t x_off,
int16_t y_off,
int ntrap,
pixman_trap_t *traps);
const pixman_trap_t *traps);
void pixman_add_trapezoids (pixman_image_t *image,
int16_t x_off,
int y_off,
@ -944,6 +1080,31 @@ 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