+Release 1.12.12 (2013-01-31 Chris Wilson <chris@chris-wilson.co.uk>)
+===================================================================
+The goal of this release is to fix the synchronisation problems that
+were exhibited in the SHM transport for cairo-xlib. This cropped up
+any place that tried to rapidly push fresh pixel data to the X server
+through an ordinary image surface, such as gimp-2.9 and evince.
+
+Bug fixes
+---------
+
+ Avoid replacing the entire image when uploading subimages
+ https://bugs.freedesktop.org/show_bug.cgi?id=59635
+
+ Force synchronisation for scratch SHM image buffers, so that we do
+ not overwrite data as it is being read by X.
+ https://bugs.freedesktop.org/show_bug.cgi?id=59635 (also)
+
+ Fix typos in detecting multisampling for the GL (MSAA) backend.
+
+ Fix a memory leak in the GL (MSAA) backend.
+
+ Fix a reference counting bug when mapping a GL surface to an image.
+
+
+Release 1.12.10 (2013-01-16 Chris Wilson <chris@chris-wilson.co.uk>)
+===================================================================
+A heap of bug fixes everywhere, and the gradual completion of the MSAA
+backend for cairo-gl. Perhaps the most noteworthy set of the bugfixes
+was the crusage lead by Behdad Eshfabod to make font handling by
+pango/cairo/fontconfig fully threadsafe. This testing revealed a couple
+of races that needed fixing in Cairo's scaled-font and glyph cache.
+
+Bug fixes
+---------
+
+ Append coincident elements to the recording's surface bbtree so that
+ the list is not corrupted and the overlapping elements lost.
+
+ Fix cairo-trace to correctly record map-to-image/unmap-image and then
+ replay them.
+
+ Ignore MappingNotifies when running the XCB testsuite as they are sent
+ to all clients when the keyboard changes. The testsuite would detect
+ the unexpected event and complain.
+
+ Handle very large large images in the XCB backend.
+
+ Fix a memory leak in the xlib/shm layer, and prevent use of the SHM
+ surfaces after the display is closed.
+ https://bugs.freedesktop.org/show_bug.cgi
+
+ Handle resizing of bitmap fonts, in preparation for a fix to
+ fontconfig to correctly pass on the user request for scaling.
+
+ Always include subroutine 4 (hint replacement idion) when subsetting
+ type 1 fonts in order to prevent a crash in cgpdftops on Mac OS/X
+
+ Fix a couple of typos in the cairo-gobject.h header files for
+ introspection.
+
+ Prevent a mutex deadlock when freeing a scaled-glyph containing a
+ recording-surface that itself references another scaled-glyph.
+ https://bugs.freedesktop.org/show_bug.cgi?id=54950
+
+ Make scaled-font cache actually thread-safe and prevent
+ use-after-frees.
+
+ Restore support for older versions of XRender. A couple of typos and a
+ few forgotten chunks prevented the xlib compositor from running
+ correctly with XRender < 0.10. Note that there are still a few
+ regressions remaining.
+
+
+Release 1.12.8 (2012-11-24 Chris Wilson <chris@chris-wilson.co.uk>)
+===================================================================
+Another couple of weeks and a few more bugs have been found and fixed,
+it is time to push the next point release. Many thanks to everyone who
+reported their issues and helped us track down the bugs and helped
+testing the fixes.
+
+Bug fixes
+---------
+
+ Expand the sanity checking for broken combinations of XSendEvent and
+ ShmCompletionEvent.
+
+ Notice that "The X.Org Foundation" sometimes also identifies itself
+ as "The Xorg Foundation".
+
+ Handle various ages of libXext and its Shm headers.
+
+ Fix the invalid clipping of the source drawable when using SHM
+ transport to upload images.
+ https://bugs.freedesktop.org/show_bug.cgi?id=56547
+
+ Handle all Type1 postscript operators for better font compatibility.
+ https://bugs.freedesktop.org/show_bug.cgi?id=56265
+
+ Fix a couple of memory leaks in Type1 font subsetting
+ https://bugs.freedesktop.org/show_bug.cgi?id=56566
+
+ Tighten the evaluation of the start/stop pen vertices, and catch a few
+ instances where we would use a fan instead of a bevel.
+ https://bugs.freedesktop.org/show_bug.cgi?id=56432
+
+ Fix assumption that geometric clipping always succeeds with the
+ span-compositor.
+ https://bugs.freedesktop.org/show_bug.cgi?id=56574
+
+ Fix call to spline intersection when evaluating whether a stoke is
+ visible.
+
+ Remember to copy inferior sources when using SHM to readback the
+ surface for use as a source.
+
+Release 1.12.6 (2012-10-22 Chris Wilson <chris@chris-wilson.co.uk>)
+===================================================================
+Thanks to everyone who download cairo-1.12.4 and gave us their feedback.
+It truly was invaluable and has helped us to fix many portability issues
+that crept in with some of the new features. This release aims to fix
+those stability issues and run on a wider range of systems.
+
+Bug fixes
+---------
+
+ Fix the recording surface to actually snapshot the source and so fix
+ PDF drawing.
+
+ Calling XSendEvent with an XShmCompletionEvent is incompatabile with
+ older Xorg servers.
+
+ Reorder CloseDisplay chain so that XShm is not reinstantiated after
+ shutdown, causing a potential crash if the Display was immediately
+ recreated using the same memory address.
+
+ Make sure that the Xserver has attached to the SHM segment before
+ deleting it from the global namespace on systems that do not support
+ deferred deletion.
+
+ Type1 subsetting support for PDF (and PS) was once again improved to
+ work with a larger number of PDF readers.
+
+ GLESv2 build fixes and improved support for embedded GPUs.
+
+ Tweak the invisible pen detection for applications that are currently
+ using too large values for geometric tolerance.
+
+ A build fix for older freetype libraries.
+
+
Release 1.12.4 (2012-10-05 Chris Wilson <chris@chris-wilson.co.uk>)
===================================================================
More bugs, and more importantly, more fixes. On the cairo-gl side, we
+++ /dev/null
-CC = gcc
-
-all : fill stroke image
-
-fill: main.c common.c fill.c
- $(CC) main.c common.c fill.c -g -o fill `pkg-config --cflags --libs cairo elementary opengl-es-20` -lecore_x -levas -lecore
-
-stroke: main.c common.c stroke.c
- $(CC) main.c common.c stroke.c -g -o stroke `pkg-config --cflags --libs cairo elementary opengl-es-20` -lecore_x -levas -lecore
-
-image: main.c common.c image.c
- $(CC) main.c common.c image.c -g -o image `pkg-config --cflags --libs cairo elementary opengl-es-20` -lecore_x -levas -lecore
-
-clean:
- rm -rf *.0 fill stroke image
+++ /dev/null
-/*
- * Cairo Performance Test Framework
- * (c) 2012 Samsung Electronics, Inc.
- * All rights reserved.
- *
- * Measures rendering performance for image, gl backends
- *
- * This software is a confidential and proprietary information of Samsung
- * Electronics, Inc. ("Confidential Information"). You shall not disclose such
- * Confidential Information and shall use it only in accordance with the terms
- * of the license agreement you entered into with Samsung Electronics.
- *
- * Author: Dongyeon Kim <dy5.kim@samsung.com>
- */
-
-#include "common.h"
-
-void clearCairo(cairo_t *cr, double width, double height)
-{
- cairo_set_source_rgba(cr, 1, 1, 1, 1);
- cairo_rectangle(cr, 0.0, 0.0, width, height);
- cairo_fill(cr);
-}
-
-void cairoSquare(cairo_t *cr, double x, double y, double length)
-{
- cairo_rectangle(cr, x, y, length, length);
- cairo_fill(cr);
-}
-
-void cairoSquareStroke(cairo_t *cr, double x, double y, double length)
-{
- cairo_rectangle(cr, x, y, length, length);
- cairo_stroke(cr);
-}
-
-void cairoCircle(cairo_t *cr, double x, double y, double radius)
-{
- cairo_arc(cr, x, y, radius, 0.0, 2.0 * M_PI);
- cairo_fill(cr);
-}
-
-void cairoCircleStroke(cairo_t *cr, double x, double y, double radius)
-{
- cairo_arc(cr, x, y, radius, 0.0, 2.0 * M_PI);
- cairo_stroke(cr);
-}
-
-void cairoTriangle(cairo_t *cr, double x, double y, double side)
-{
- cairo_move_to(cr, x, y);
- cairo_line_to(cr, x + side, y + side);
- cairo_line_to(cr, x, y + side);
- cairo_close_path(cr);
- cairo_fill(cr);
-}
-
-void cairoTriangleStroke(cairo_t *cr, double x, double y, double side)
-{
- cairo_move_to(cr, x, y);
- cairo_line_to(cr, x + side, y);
- cairo_line_to(cr, x, y + side);
- cairo_close_path(cr);
- cairo_stroke(cr);
-}
+++ /dev/null
-/*
- * Cairo Performance Test Framework
- * (c) 2012 Samsung Electronics, Inc.
- * All rights reserved.
- *
- * Measures rendering performance for image, gl backends
- *
- * This software is a confidential and proprietary information of Samsung
- * Electronics, Inc. ("Confidential Information"). You shall not disclose such
- * Confidential Information and shall use it only in accordance with the terms
- * of the license agreement you entered into with Samsung Electronics.
- *
- * Author: Dongyeon Kim <dy5.kim@samsung.com>
- */
-
-#include <Ecore_X.h>
-#include <Elementary.h>
-#include <cairo.h>
-#include <cairo-gl.h>
-
-void clearCairo(cairo_t *cr, double width, double height);
-void cairoSquare(cairo_t *cr, double x, double y, double length);
-void cairoSquareStroke(cairo_t *cr, double x, double y, double length);
-void cairoCircle(cairo_t *cr, double x, double y, double radius);
-void cairoCircleStroke(cairo_t *cr, double x, double y, double radius);
-void cairoTriangle(cairo_t *cr, double x, double y, double side);
-void cairoTriangleStroke(cairo_t *cr, double x, double y, double side);
-
+++ /dev/null
-/*
- * Cairo Performance Test Framework
- * (c) 2012 Samsung Electronics, Inc.
- * All rights reserved.
- *
- * Measures rendering performance for image, gl backends
- *
- * This software is a confidential and proprietary information of Samsung
- * Electronics, Inc. ("Confidential Information"). You shall not disclose such
- * Confidential Information and shall use it only in accordance with the terms
- * of the license agreement you entered into with Samsung Electronics.
- *
- * Author: Dongyeon Kim <dy5.kim@samsung.com>
- */
-
-#include "common.h"
-
-#define RENDER_LOOP 100
-
-extern int WIDTH, HEIGHT;
-
-int preRender(cairo_t *cr)
-{
- return 1;
-}
-
-int render(cairo_t *cr)
-{
- int i;
- double r, g, b, a;
-
- clearCairo(cr, WIDTH, HEIGHT);
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-
- for(i = 0; i < RENDER_LOOP; i++)
- {
- r = drand48();
- g = drand48();
- b = drand48();
- a = drand48();
- float x = drand48() * WIDTH;
- float y = drand48() * HEIGHT;
- float side = drand48() * 300;
- int shape = drand48() * 3;
-
- cairo_set_source_rgba(cr, r, g, b, a);
-
- if(shape == 0)
- cairoSquare(cr, x, y, side);
- else if(shape == 1)
- cairoCircle(cr, x, y, side/2);
- else
- cairoTriangle(cr, x, y, side);
- }
-
- return 1;
-}
-
-int postRender(cairo_t *cr)
-{
- return 1;
-}
-
+++ /dev/null
-/*
- * Cairo Performance Test Framework
- * (c) 2012 Samsung Electronics, Inc.
- * All rights reserved.
- *
- * Measures rendering performance for image, gl backends
- *
- * This software is a confidential and proprietary information of Samsung
- * Electronics, Inc. ("Confidential Information"). You shall not disclose such
- * Confidential Information and shall use it only in accordance with the terms
- * of the license agreement you entered into with Samsung Electronics.
- *
- * Author: Dongyeon Kim <dy5.kim@samsung.com>
- */
-
-#include "common.h"
-
-#define RENDER_LOOP 100
-
-extern int WIDTH, HEIGHT;
-
-extern cairo_device_t *cairo_device;
-cairo_pattern_t *pattern1, *pattern2;
-int image_width, image_height;
-
-int preRender(cairo_t *cr)
-{
- { // Image 1
- cairo_surface_t *image_surface = cairo_image_surface_create_from_png("./image1.png");
- image_width = cairo_image_surface_get_width(image_surface);
- image_height = cairo_image_surface_get_height(image_surface);
-
- if(cairo_surface_get_type(cairo_get_target(cr)) == CAIRO_SURFACE_TYPE_IMAGE) {
- pattern1 = cairo_pattern_create_for_surface(image_surface);
- } else {
- cairo_surface_t *gl_surface = cairo_gl_surface_create(cairo_device, CAIRO_CONTENT_COLOR_ALPHA,
- image_width, image_height);
- cairo_t *cr_gl = cairo_create(gl_surface);
- cairo_set_source_surface(cr_gl, image_surface, 0, 0);
- cairo_paint(cr_gl);
-
- pattern1 = cairo_pattern_create_for_surface(gl_surface);
-
- cairo_surface_destroy(gl_surface);
- cairo_destroy(cr_gl);
- }
- cairo_surface_destroy(image_surface);
- }
- { // Image 2
- cairo_surface_t *image_surface = cairo_image_surface_create_from_png("./image2.png");
- image_width = cairo_image_surface_get_width(image_surface);
- image_height = cairo_image_surface_get_height(image_surface);
-
- if(cairo_surface_get_type(cairo_get_target(cr)) == CAIRO_SURFACE_TYPE_IMAGE) {
- pattern2 = cairo_pattern_create_for_surface(image_surface);
- } else {
- cairo_surface_t *gl_surface = cairo_gl_surface_create(cairo_device, CAIRO_CONTENT_COLOR_ALPHA,
- image_width, image_height);
- cairo_t *cr_gl = cairo_create(gl_surface);
- cairo_set_source_surface(cr_gl, image_surface, 0, 0);
- cairo_paint(cr_gl);
-
- pattern2 = cairo_pattern_create_for_surface(gl_surface);
-
- cairo_surface_destroy(gl_surface);
- cairo_destroy(cr_gl);
- }
- cairo_surface_destroy(image_surface);
- }
-
- return 1;
-}
-
-int render(cairo_t *cr)
-{
- int i;
-
- clearCairo(cr, WIDTH, HEIGHT);
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-
- for(i = 0; i < RENDER_LOOP; i++)
- {
- float x = drand48() * WIDTH - image_width / 2;
- float y = drand48() * HEIGHT - image_height / 2;
- int index = drand48() * 2;
-
- cairo_identity_matrix(cr);
- cairo_translate(cr, x, y);
- if(index == 0)
- cairo_set_source(cr, pattern1);
- else
- cairo_set_source(cr, pattern2);
- cairoSquare(cr, 0, 0, image_width);
- }
-
- return 1;
-}
-
-int postRender(cairo_t *cr)
-{
- cairo_pattern_destroy(pattern1);
- cairo_pattern_destroy(pattern2);
- return 1;
-}
-
+++ /dev/null
-/*
- * Cairo Performance Test Framework
- * (c) 2012 Samsung Electronics, Inc.
- * All rights reserved.
- *
- * Measures rendering performance for image, gl backends
- *
- * This software is a confidential and proprietary information of Samsung
- * Electronics, Inc. ("Confidential Information"). You shall not disclose such
- * Confidential Information and shall use it only in accordance with the terms
- * of the license agreement you entered into with Samsung Electronics.
- *
- * Author: Dongyeon Kim <dy5.kim@samsung.com>
- */
-
-#include <Ecore_X.h>
-#include <Elementary.h>
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <cairo.h>
-#include <cairo-gl.h>
-
-#define SURFACE_TYPE_IMAGE 0
-#define SURFACE_TYPE_GL 1
-#define TOTAL_TIME 100
-
-int WIDTH, HEIGHT;
-
-//Ecore Evas variables
-Ecore_X_Window window;
-Evas_Object *img;
-
-//EGL variables
-EGLDisplay egl_display;
-EGLSurface egl_surface;
-EGLContext egl_context;
-
-//Cairo variables
-cairo_device_t *cairo_device;
-cairo_surface_t *cairo_surface;
-cairo_t *cr;
-
-Eina_Bool renderMain(void *data)
-{
- static int counter = 0;
- static float totalTime = 0;
- static float totalPaint = 0;
- static float totalUpdate = 0;
- struct timeval paintStart, paintStop, updateStop;
-
- cairo_save(cr);
- gettimeofday(&paintStart, NULL);
- /* ########## PAINT : START ########## */
- render(cr);
- /* ########## PAINT : END ########## */
- gettimeofday(&paintStop, NULL);
- /* ########## UPDATE : START ########## */
- if(cairo_surface_get_type(cairo_get_target(cr)) == CAIRO_SURFACE_TYPE_GL) {
- cairo_gl_surface_swapbuffers(cairo_get_target(cr));
- } else {
- unsigned char *imageData = cairo_image_surface_get_data(cairo_get_target(cr));
- evas_object_image_data_set(img, imageData);
- evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT);
- ecore_x_sync();
- }
- /* ########## UPDATE : END ########## */
- gettimeofday(&updateStop, NULL);
- cairo_restore(cr);
-
- totalTime += updateStop.tv_usec - paintStart.tv_usec;
- totalTime += (updateStop.tv_sec - paintStart.tv_sec)*1000000;
- totalPaint += (paintStop.tv_usec - paintStart.tv_usec);
- totalPaint += (paintStop.tv_sec - paintStart.tv_sec)*1000000;
- totalUpdate += (updateStop.tv_usec - paintStop.tv_usec);
- totalUpdate += (updateStop.tv_sec - paintStop.tv_sec)*1000000;
- counter++;
-
- if(counter == TOTAL_TIME)
- {
- float fps = TOTAL_TIME / totalTime * 1000000.0f;
- printf("fps = %0.2f\n", fps);
- printf("average paint time = %0.1f usec, update time = %0.1f usec\n", totalPaint/TOTAL_TIME, totalUpdate/TOTAL_TIME);
-
- elm_exit();
- return 0;
- }
-}
-
-void initELMWindow(int surface_type)
-{
- Evas_Object *win = elm_win_add(NULL, "cairotest", ELM_WIN_BASIC);
- elm_win_autodel_set(win, EINA_TRUE);
- ecore_x_screen_size_get(ecore_x_default_screen_get(), &WIDTH, &HEIGHT);
- evas_object_resize(win, WIDTH, HEIGHT);
- evas_object_show(win);
-
- if (surface_type == SURFACE_TYPE_IMAGE) {
- Evas_Object *img_win = elm_image_add(win);
- img = evas_object_image_filled_add(evas_object_evas_get(img_win));
- elm_win_resize_object_add(win, img);
- evas_object_image_content_hint_set(img, EVAS_IMAGE_CONTENT_HINT_DYNAMIC);
- evas_object_image_size_set(img, WIDTH, HEIGHT);
- evas_object_image_colorspace_set(img, EVAS_COLORSPACE_ARGB8888);
- evas_object_image_alpha_set(img, 0);
- evas_object_show(img_win);
- evas_object_show(img);
- } else if(surface_type == SURFACE_TYPE_GL) {
- window = ecore_x_window_new(0, 0, 0, WIDTH, HEIGHT);
- ecore_x_icccm_title_set(window, "window");
- ecore_x_netwm_name_set(window, "window");
- ecore_x_input_multi_select(window);
- ecore_x_icccm_transient_for_set(window, elm_win_xwindow_get(win));
- ecore_x_window_show(window);
- }
-}
-
-void initEGL(int surface_type)
-{
- if(surface_type != SURFACE_TYPE_GL)
- return;
-
- setenv("ELM_ENGINE", "gl", 1);
-
- egl_display = eglGetDisplay((EGLNativeDisplayType) ecore_x_display_get());
- if(egl_display == EGL_NO_DISPLAY)
- {
- printf("cannot get egl display\n");
- exit(1);
- }
-
- EGLint major, minor;
- if(!eglInitialize(egl_display, &major, &minor))
- {
- printf("cannot initialize egl\n");
- exit(-1);
- }
-
- if(!eglBindAPI(EGL_OPENGL_ES_API))
- {
- printf("cannot bind egl to gles2 API\n");
- exit(-1);
- }
-
- EGLConfig egl_config;
- EGLint num;
-
- EGLint attr[] =
- {
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL_STENCIL_SIZE, 0,
- EGL_SAMPLES, 4,
- EGL_RED_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_BLUE_SIZE, 8,
- EGL_ALPHA_SIZE, 8,
- EGL_NONE
- };
-
-
- if(!eglChooseConfig(egl_display, attr, &egl_config, 1, &num))
- {
- printf("cannot choose config\n");
- exit(-1);
- }
-
- if(num != 1)
- {
- printf("did not get exactly one config = %d\n", num);
- exit(-1);
- }
-
- egl_surface = eglCreateWindowSurface(egl_display,
- egl_config, (NativeWindowType) window, NULL);
- if(egl_surface == EGL_NO_SURFACE)
- {
- printf("cannot create surface\n");
- exit(-1);
- }
-
- EGLint e = eglGetError();
- //printf("egl error = %x\n", e);
-
- EGLint ctxattr[] =
- {
- EGL_CONTEXT_CLIENT_VERSION, 2,
- EGL_NONE
- };
-
- egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, ctxattr);
- if(egl_context == EGL_NO_CONTEXT)
- {
- EGLint e = eglGetError();
- printf("cannot create context, error = %x\n", e);
- exit(-1);
- }
-
- EGLint value;
- EGLBoolean result = eglQueryContext(egl_display, egl_context, EGL_CONTEXT_CLIENT_VERSION, &value);
- //printf("Context version = %x, result = %d\n", value, result);
-
- eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
-}
-
-void destroyEGL(int surface_type)
-{
- if(surface_type != SURFACE_TYPE_GL)
- return;
-
- eglDestroyContext(egl_display, egl_context);
- eglDestroySurface(egl_display, egl_surface);
- eglTerminate(egl_display);
-}
-
-void initCairo(int surface_type)
-{
- if(surface_type == SURFACE_TYPE_IMAGE) {
- printf("== CREATE IMAGE SURFACE ==\n");
- cairo_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT);
- } else if(surface_type == SURFACE_TYPE_GL) {
- printf("== CREATE GL SURFACE ==\n");
- setenv("CAIRO_GL_COMPOSITOR", "msaa", 1);
- cairo_device = cairo_egl_device_create(egl_display, egl_context);
- cairo_gl_device_set_thread_aware(cairo_device, 0);
- cairo_surface = cairo_gl_surface_create_for_egl(cairo_device, egl_surface, WIDTH, HEIGHT);
- }
- cr = cairo_create(cairo_surface);
-}
-
-void destroyCairo(int surface_type)
-{
- cairo_surface_destroy(cairo_surface);
- cairo_destroy(cr);
-
- if(surface_type == SURFACE_TYPE_GL) {
- cairo_device_destroy(cairo_device);
- }
-}
-
-int main(int argc, char **argv)
-{
- int surface_type = SURFACE_TYPE_GL;
-
- if(argc == 2)
- surface_type = atoi(argv[1]);
-
- elm_init(argc, argv);
-
- initELMWindow(surface_type);
- initEGL(surface_type);
- initCairo(surface_type);
-
- preRender(cr);
- Ecore_Animator *animator = ecore_animator_add(renderMain, (void *)cr);
- elm_run();
- postRender(cr);
-
- destroyCairo(surface_type);
- destroyEGL(surface_type);
- elm_shutdown();
-
- return 0;
-}
-
+++ /dev/null
-/*
- * Cairo Performance Test Framework
- * (c) 2012 Samsung Electronics, Inc.
- * All rights reserved.
- *
- * Measures rendering performance for image, gl backends
- *
- * This software is a confidential and proprietary information of Samsung
- * Electronics, Inc. ("Confidential Information"). You shall not disclose such
- * Confidential Information and shall use it only in accordance with the terms
- * of the license agreement you entered into with Samsung Electronics.
- *
- * Author: Dongyeon Kim <dy5.kim@samsung.com>
- */
-
-#include "common.h"
-
-#define RENDER_LOOP 100
-
-extern int WIDTH, HEIGHT;
-
-int preRender(cairo_t *cr)
-{
- return 1;
-}
-
-int render(cairo_t *cr)
-{
- int i;
- double r, g, b, a;
-
- clearCairo(cr, WIDTH, HEIGHT);
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-
- for(i = 0; i < RENDER_LOOP; i++)
- {
- r = drand48();
- g = drand48();
- b = drand48();
- a = drand48();
- float x = drand48() * WIDTH;
- float y = drand48() * HEIGHT;
- float side = drand48() * 300;
- int shape = drand48() *3;
- float width = drand48() * 50 + 1;
- int line_cap = drand48() * 3;
- cairo_line_cap_t line_cap_style = CAIRO_LINE_CAP_BUTT;
- if(line_cap == 1)
- line_cap_style = CAIRO_LINE_CAP_ROUND;
- else if(line_cap == 2)
- line_cap_style = CAIRO_LINE_CAP_SQUARE;
- int line_join = drand48() * 3;
- cairo_line_join_t line_join_style = CAIRO_LINE_JOIN_MITER;
- if(line_join == 1)
- line_join_style = CAIRO_LINE_JOIN_ROUND;
- else if(line_join == 2)
- line_join_style = CAIRO_LINE_JOIN_BEVEL;
-
- double dash[] = {0.0, 0.0};
- dash[0] = drand48() * 50;
- dash[1] = drand48() * 50;
-
- cairo_set_dash(cr, dash, 2, 0);
- cairo_set_line_width(cr, width);
- cairo_set_line_join(cr, line_join_style);
- cairo_set_line_cap(cr, line_cap_style);
-
- cairo_set_source_rgba(cr, r, g, b, a);
-
- if(shape == 0)
- cairoSquareStroke(cr, x, y, side);
- else if(shape == 1)
- cairoCircleStroke(cr, x, y, side/2);
- else
- cairoTriangleStroke(cr, x, y, side);
- }
-
- return 1;
-}
-
-int postRender(cairo_t *cr)
-{
- return 1;
-}
-
/testcase/utc_big_little_triangle_image
#/testcase/utc_big_trap_image
/testcase/utc_bilevel_image_image
-/testcase/utc_bitmap_font_image
+#/testcase/utc_bitmap_font_image
/testcase/utc_bug_40410_image
/testcase/utc_bug_bo_rectangular_image
/testcase/utc_bug_bo_ricotz_image
/testcase/utc_big_little_triangle_gl
/testcase/utc_big_trap_gl
/testcase/utc_bilevel_image_gl
-/testcase/utc_bitmap_font_gl
+#/testcase/utc_bitmap_font_gl
/testcase/utc_bug_40410_gl
/testcase/utc_bug_bo_rectangular_gl
/testcase/utc_bug_bo_ricotz_gl
#elif CAIRO_HAS_GLESV2_SURFACE
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
#endif
+ EGL_SAMPLES, 4,
EGL_NONE
};
const EGLint ctx_attribs[] = {
}
gltc->device = cairo_egl_device_create (gltc->dpy, gltc->ctx);
+ cairo_gl_device_set_thread_aware (gltc->device, FALSE);
if (width < 1)
width = 1;
}
static cairo_surface_t *
-_cairo_boilerplate_gl_create_window (const char *name,
- cairo_content_t content,
- double width,
- double height,
- double max_width,
- double max_height,
- cairo_boilerplate_mode_t mode,
- void **closure)
+_cairo_boilerplate_gl_create_window_common (int rgba_attribs[],
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ gl_target_closure_t *gltc)
{
- int rgba_attribs[] = { GLX_RGBA,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_ALPHA_SIZE, 1,
- GLX_DOUBLEBUFFER,
- None };
-
- int msaa_attribs[] = { GLX_RGBA,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_ALPHA_SIZE, 1,
- GLX_STENCIL_SIZE, 1,
- GLX_SAMPLES, 4,
- GLX_SAMPLE_BUFFERS, 1,
- GLX_DOUBLEBUFFER,
- None };
-
XVisualInfo *vi;
GLXContext ctx;
- gl_target_closure_t *gltc;
cairo_surface_t *surface;
Display *dpy;
XSetWindowAttributes attr;
- gltc = calloc (1, sizeof (gl_target_closure_t));
- *closure = gltc;
-
width = ceil (width);
height = ceil (height);
if (mode == CAIRO_BOILERPLATE_MODE_TEST)
XSynchronize (gltc->dpy, 1);
- vi = glXChooseVisual (dpy, DefaultScreen (dpy), msaa_attribs);
-
- if (vi == NULL)
- vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
-
+ vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
if (vi == NULL) {
fprintf (stderr, "Failed to create RGBA, double-buffered visual\n");
XCloseDisplay (dpy);
gltc->surface = surface = cairo_gl_surface_create_for_window (gltc->device,
gltc->drawable,
width, height);
- if (cairo_surface_status (surface))
+ if (cairo_surface_status (surface)) {
_cairo_boilerplate_gl_cleanup (gltc);
-
+ return NULL;
+ }
return surface;
}
static cairo_surface_t *
-_cairo_boilerplate_gl_create_window_db (const char *name,
- cairo_content_t content,
- double width,
- double height,
- double max_width,
- double max_height,
- cairo_boilerplate_mode_t mode,
- void **closure)
+_cairo_boilerplate_gl_create_window (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ void **closure)
{
+ gl_target_closure_t *gltc;
+
int rgba_attribs[] = { GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_DOUBLEBUFFER,
None };
- int msaa_attribs[] = { GLX_RGBA,
+ gltc = calloc (1, sizeof (gl_target_closure_t));
+ *closure = gltc;
+
+ return _cairo_boilerplate_gl_create_window_common (rgba_attribs, content,
+ width, height,
+ max_width, max_height,
+ mode, gltc);
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_gl_create_window_msaa (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ void **closure)
+{
+ gl_target_closure_t *gltc;
+
+ int rgba_attribs[] = { GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DOUBLEBUFFER,
None };
- XVisualInfo *vi;
- GLXContext ctx;
- gl_target_closure_t *gltc;
- cairo_surface_t *surface;
- Display *dpy;
- XSetWindowAttributes attr;
- cairo_status_t status;
-
gltc = calloc (1, sizeof (gl_target_closure_t));
*closure = gltc;
+ return _cairo_boilerplate_gl_create_window_common (rgba_attribs, content,
+ width, height,
+ max_width, max_height,
+ mode, gltc);
- width = ceil (width);
- height = ceil (height);
-
- if (width == 0)
- width = 1;
- if (height == 0)
- height = 1;
+}
- dpy = XOpenDisplay (NULL);
- gltc->dpy = dpy;
- if (!gltc->dpy) {
- fprintf (stderr, "Failed to open display: %s\n", XDisplayName(0));
- free (gltc);
- return NULL;
- }
+static cairo_surface_t *
+_cairo_boilerplate_gl_create_window_db (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ void **closure)
+{
+ cairo_status_t status;
+ cairo_surface_t *surface;
+ gl_target_closure_t *gltc;
- if (mode == CAIRO_BOILERPLATE_MODE_TEST)
- XSynchronize (gltc->dpy, 1);
+ int rgba_attribs[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_ALPHA_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
- vi = glXChooseVisual (dpy, DefaultScreen (dpy), msaa_attribs);
+ gltc = calloc (1, sizeof (gl_target_closure_t));
+ *closure = gltc;
- if (vi == NULL)
- vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
+ surface = _cairo_boilerplate_gl_create_window_common (rgba_attribs, content,
+ width, height,
+ max_width, max_height,
+ mode, gltc);
- if (vi == NULL) {
- fprintf (stderr, "Failed to create RGBA, double-buffered visual\n");
- XCloseDisplay (dpy);
- free (gltc);
+ if (! surface)
return NULL;
- }
- attr.colormap = XCreateColormap (dpy,
- RootWindow (dpy, vi->screen),
- vi->visual,
- AllocNone);
- attr.border_pixel = 0;
- attr.override_redirect = True;
- gltc->drawable = XCreateWindow (dpy, DefaultRootWindow (dpy), 0, 0,
- width, height, 0, vi->depth,
- InputOutput, vi->visual,
- CWOverrideRedirect | CWBorderPixel | CWColormap,
- &attr);
- XMapWindow (dpy, gltc->drawable);
-
- ctx = glXCreateContext (dpy, vi, NULL, True);
- XFree (vi);
-
- gltc->ctx = ctx;
- gltc->device = cairo_glx_device_create (dpy, ctx);
-
- gltc->surface = cairo_gl_surface_create_for_window (gltc->device,
- gltc->drawable,
- width, height);
surface = cairo_surface_create_similar (gltc->surface, content, width, height);
status = cairo_surface_set_user_data (surface, &gl_closure_key, gltc, NULL);
if (status == CAIRO_STATUS_SUCCESS)
FALSE, FALSE, FALSE
},
{
+ "gl-window-msaa", "gl", NULL, NULL,
+ CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR_ALPHA, 1,
+ "cairo_gl_surface_create_for_window",
+ _cairo_boilerplate_gl_create_window_msaa,
+ cairo_surface_create_similar,
+ NULL,
+ _cairo_boilerplate_gl_finish_window,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_gl_cleanup,
+ _cairo_boilerplate_gl_synchronize,
+ _cairo_boilerplate_gl_describe,
+ FALSE, FALSE, FALSE
+ },
+ {
"gl-window&", "gl", NULL, NULL,
CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR_ALPHA, 1,
"cairo_gl_surface_create_for_window",
static cairo_status_t
_cairo_boilerplate_xcb_handle_errors (xcb_target_closure_t *xtc)
{
- xcb_generic_event_t *ev;
+ xcb_generic_event_t *ev = NULL;
- if ((ev = xcb_poll_for_event (xtc->c)) != NULL) {
+ /* Ignore all MappingNotify events; those might happen without us causing them */
+ do {
+ free(ev);
+ ev = xcb_poll_for_event(xtc->c);
+ } while (ev != NULL && ev->response_type == XCB_MAPPING_NOTIFY);
+
+ if (ev != NULL) {
if (ev->response_type == CAIRO_XCB_ERROR) {
xcb_generic_error_t *error = (xcb_generic_error_t *) ev;
#define CAIRO_VERSION_MAJOR 1
#define CAIRO_VERSION_MINOR 12
-#define CAIRO_VERSION_MICRO 4
+#define CAIRO_VERSION_MICRO 12
#endif
[have_libz="no (requires zlib http://www.gzip.org/zlib/)"])],
[have_libz="no (requires zlib http://www.gzip.org/zlib/)"])
+save_LIBS="$LIBS"
+AC_CHECK_LIB(lzo2, lzo2a_decompress,
+ [AC_CHECK_HEADER(lzo/lzo2a.h, [
+ have_lzo=yes
+ AC_DEFINE(HAVE_LZO, 1, [Define to 1 if you have lzo available])
+ lzo_LIBS="-llzo2"
+ ],
+ [have_lzo="no (requires lzpo http://www.oberhumer.com/opensource/lzo/)"])],
+ [have_lzo="no (requires lzpo http://www.oberhumer.com/opensource/lzo/)"])
+AC_SUBST(lzo_LIBS)
+LIBS="$save_LIBS"
+
AC_CHECK_LIB(dl, dlsym,
[have_dlsym=yes; have_dl=yes],
[have_dlsym=no; have_dl=no])
CAIRO_ENABLE_SURFACE_BACKEND(xlib, Xlib, auto, [
xlib_REQUIRES="x11 xext"
PKG_CHECK_MODULES(xlib, $xlib_REQUIRES, ,
- [AC_MSG_RESULT(no)
- xlib_REQUIRES=""
+ [xlib_REQUIRES=""
AC_PATH_XTRA
if test "x$no_x" = xyes; then
use_xlib="no (requires X development libraries)"
xlib_NONPKGCONFIG_LIBS="$X_PRE_LIBS $X_LIBS -lX11 -lXext $X_EXTRA_LIBS"
xlib_NONPKGCONFIG_CFLAGS=$X_CFLAGS
fi])
+
+ AC_CHECK_HEADER(sys/ipc.h)
+ AC_CHECK_HEADER(sys/shm.h)
+
+ if test "$ac_cv_header_sys_ipc_h" = "yes" -a "$ac_cv_header_sys_shm_h" = "yes"; then
+ AC_MSG_CHECKING(whether shmctl IPC_RMID allowes subsequent attaches)
+ AC_TRY_RUN([
+ #include <sys/types.h>
+ #include <sys/ipc.h>
+ #include <sys/shm.h>
+ int main()
+ {
+ char *shmaddr;
+ int id = shmget (IPC_PRIVATE, 4, IPC_CREAT | 0600);
+ if (id == -1) return 2;
+ shmaddr = shmat (id, 0, 0);
+ shmctl (id, IPC_RMID, 0);
+ if ((char*) shmat (id, 0, 0) == (char*) -1) {
+ shmdt (shmaddr);
+ return 1;
+ }
+ shmdt (shmaddr);
+ shmdt (shmaddr);
+ return 0;
+ }
+ ],
+ AC_DEFINE(IPC_RMID_DEFERRED_RELEASE, 1,
+ [Define to 1 if shared memory segments are released deferred.])
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no),
+ AC_MSG_RESULT(assuming no))
+ fi
+
+ AC_CHECK_HEADERS([X11/extensions/XShm.h X11/extensions/shmproto.h X11/extensions/shmstr.h], [], [],
+ [#include <X11/Xlibint.h>
+ #include <X11/Xproto.h>])
])
CAIRO_ENABLE_SURFACE_BACKEND(xlib_xrender, Xlib Xrender, auto, [
xlib_xrender_BASE=cairo-xlib
xlib_xrender_REQUIRES="xrender >= 0.6"
PKG_CHECK_MODULES(xlib_xrender, $xlib_xrender_REQUIRES, ,
- [AC_MSG_RESULT(no)
- xlib_xrender_REQUIRES=""
+ [xlib_xrender_REQUIRES=""
old_CPPFLAGS=$CPPFLAGS
CPPFLAGS="$CPPFLAGS $xlib_CFLAGS $xlib_NONPKGCONFIG_CFLAGS"
AC_CHECK_HEADER(X11/extensions/Xrender.h,
[xlib_xrender_NONPKGCONFIG_LIBS="-lXrender"],
- [use_xlib_xrender="no (requires $xlib_xrender_REQUIRES http://freedesktop.org/Software/xlibs)"])
+ [use_xlib_xrender="no (requires $xlib_xrender_REQUIRES http://freedesktop.org/Software/xlibs)"],
+ [#include <X11/X.h>])
CPPFLAGS=$old_CPPFLAGS
])
CAIRO_ENABLE_SURFACE_BACKEND(xcb, XCB, auto, [
xcb_REQUIRES="xcb >= 1.6 xcb-render >= 1.6"
PKG_CHECK_MODULES(xcb, $xcb_REQUIRES, ,
- [AC_MSG_RESULT(no)
- use_xcb="no (requires $xcb_REQUIRES http://xcb.freedesktop.org)"])
+ [use_xcb="no (requires $xcb_REQUIRES http://xcb.freedesktop.org)"])
])
CAIRO_ENABLE_FUNCTIONS(xlib_xcb, Xlib/XCB, no, [
if test "x$use_xcb" = "xyes" -a "x$use_xlib" = "xyes"; then
xlib_xcb_REQUIRES="x11-xcb"
PKG_CHECK_MODULES(xlib_xcb, $xlib_xcb_REQUIRES, ,
- [AC_MSG_RESULT(no)
- use_xlib_xcb="no (requires $xlib_xcb_REQUIRES http://xcb.freedesktop.org)"])
+ [use_xlib_xcb="no (requires $xlib_xcb_REQUIRES http://xcb.freedesktop.org)"])
else
use_xlib_xcb="no (requires both --enable-xlib and --enable-xcb)"
fi
if test "x$use_xcb" = "xyes"; then
xcb_shm_REQUIRES="xcb-shm"
PKG_CHECK_MODULES(xcb_shm, $xcb_shm_REQUIRES, ,
- [AC_MSG_RESULT(no)
- use_xcb_shm="no (requires $xcb_shm http://xcb.freedesktop.org)"])
+ [use_xcb_shm="no (requires $xcb_shm http://xcb.freedesktop.org)"])
else
use_xcb_shm="no (requires --enable-xcb)"
fi
CAIRO_ENABLE_SURFACE_BACKEND(qt, Qt, no, [
qt_REQUIRES="QtGui >= 4.4.0"
PKG_CHECK_MODULES(qt, $qt_REQUIRES, ,
- [AC_MSG_RESULT(no)
- qt_REQUIRES=""
+ [qt_REQUIRES=""
use_qt="no (requires Qt4 development libraries)"
])
])
CAIRO_ENABLE_SURFACE_BACKEND(drm, DRM, no, [
drm_REQUIRES="libudev >= 136"
- PKG_CHECK_MODULES(drm, $drm_REQUIRES, , [AC_MSG_RESULT(no)
- use_drm="no (requires $drm_REQUIRES, udev is available from git://git.kernel.org/pub/scm/linux/hotplug/udev.git)"])
+ PKG_CHECK_MODULES(drm, $drm_REQUIRES, ,
+ [use_drm="no (requires $drm_REQUIRES, udev is available from git://git.kernel.org/pub/scm/linux/hotplug/udev.git)"])
])
CAIRO_ENABLE_SURFACE_BACKEND(gallium, Gallium3D, no, [
fi
if test "x$use_png" = "xyes" ; then
- PKG_CHECK_MODULES(png, $png_REQUIRES, , AC_MSG_RESULT(no))
+ PKG_CHECK_MODULES(png, $png_REQUIRES, , : )
else
AC_MSG_WARN([Could not find libpng in the pkg-config search path])
fi
CAIRO_ENABLE_SURFACE_BACKEND(directfb, directfb, no, [
directfb_REQUIRES=directfb
- PKG_CHECK_MODULES(directfb, $directfb_REQUIRES, , AC_MSG_RESULT(no)
+ PKG_CHECK_MODULES(directfb, $directfb_REQUIRES, ,
[use_directfb="no (requires $directfb_REQUIRES http://www.directfb.org)"])
])
PKG_CHECK_MODULES(FREETYPE, freetype2 >= $FREETYPE_MIN_VERSION,
[freetype_pkgconfig=yes],
- [AC_MSG_RESULT(no)
- freetype_pkgconfig=no])
+ [freetype_pkgconfig=no])
if test "x$freetype_pkgconfig" = "xyes"; then
ft_REQUIRES="freetype2 >= $FREETYPE_MIN_VERSION $ft_REQUIRES"
if test "x$use_fc" = "xyes"; then
fc_REQUIRES="fontconfig >= $FONTCONFIG_MIN_VERSION"
PKG_CHECK_MODULES(FONTCONFIG, $fc_REQUIRES,,
- [AC_MSG_RESULT(no); use_fc="no (requires $fc_REQUIRES)"])
+ [use_fc="no (requires $fc_REQUIRES)"])
fi
fc_CFLAGS="$FONTCONFIG_CFLAGS"
fc_LIBS="$FONTCONFIG_LIBS"
_save_cflags="$CFLAGS"
LIBS="$LIBS $ft_LIBS"
CFLAGS="$CFLAGS $ft_CFLAGS"
- AC_CHECK_MEMBER(FT_Bitmap_Size.y_ppem,
- HAVE_FT_BITMAP_SIZE_Y_PPEM=1,
- HAVE_FT_BITMAP_SIZE_Y_PPEM=0,
- [#include <ft2build.h>
- #include FT_FREETYPE_H])
- AC_DEFINE_UNQUOTED(HAVE_FT_BITMAP_SIZE_Y_PPEM,$HAVE_FT_BITMAP_SIZE_Y_PPEM,
- [FT_Bitmap_Size structure includes y_ppem field])
- AC_CHECK_FUNCS(FT_GlyphSlot_Embolden FT_GlyphSlot_Oblique FT_Load_Sfnt_Table FT_Library_SetLcdFilter)
+ AC_CHECK_FUNCS(FT_Get_X11_Font_Format FT_GlyphSlot_Embolden FT_GlyphSlot_Oblique FT_Load_Sfnt_Table FT_Library_SetLcdFilter)
LIBS="$_save_libs"
CFLAGS="$_save_cflags"
CAIRO_ENABLE_SURFACE_BACKEND(image, image, always, [
pixman_REQUIRES="pixman-1 >= 0.22.0"
- PKG_CHECK_MODULES(pixman, $pixman_REQUIRES, , [AC_MSG_RESULT(no)
- use_image="no (requires $pixman_REQUIRES http://cairographics.org/releases/)"])
+ PKG_CHECK_MODULES(pixman, $pixman_REQUIRES, ,
+ [use_image="no (requires $pixman_REQUIRES http://cairographics.org/releases/)"])
image_REQUIRES=$pixman_REQUIRES
image_CFLAGS=$pixman_CFLAGS
image_LIBS=$pixman_LIBS
CAIRO_ENABLE_FUNCTIONS(gobject, gobject, auto, [
gobject_REQUIRES="gobject-2.0 glib-2.0"
- PKG_CHECK_MODULES(GOBJECT, $gobject_REQUIRES, , [AC_MSG_RESULT(no)
- use_gobject="no (requires $gobject_REQUIRES http://download.gnome.org/pub/GNOME/sources/glib/)"])
+ PKG_CHECK_MODULES(GOBJECT, $gobject_REQUIRES, ,
+ [use_gobject="no (requires $gobject_REQUIRES http://download.gnome.org/pub/GNOME/sources/glib/)"])
gobject_NONPKGCONFIG_EXTRA_LIBS="-L\${libdir} -lcairo-gobject"
])
dnl I'm too lazy to fix the caching properly
if test "x$use_gobject" = "xyes"; then
- PKG_CHECK_MODULES(GOBJECT, $gobject_REQUIRES)
+ PKG_CHECK_MODULES(GOBJECT, $gobject_REQUIRES, : )
fi
dnl ===========================================================================
+cairo (1.12.8-slp2+3) unstable; urgency=low
+
+ * Remove gobject, script-interpreter libraries from package
+ * Git: framework/graphics/cairo
+ * Tag: cairo_1.12.8+3
+
+ -- Dongyeon Kim <dy5.kim@samsung.com> Tue, 05 Feb 2013 14:00:47 +0900
+
+cairo (1.12.8-slp2+2) unstable; urgency=low
+
+ * gl: Bug fix of the clip handling
+ * Git: framework/graphics/cairo
+ * Tag: cairo_1.12.8+2
+
+ -- Dongyeon Kim <dy5.kim@samsung.com> Wed, 23 Jan 2013 16:28:17 +0900
+
+cairo (1.12.8-slp2+1) unstable; urgency=low
+
+ * Update cairo to 1.12.8
+ * Git: framework/graphics/cairo
+ * Tag: cairo_1.12.8+1
+
+ -- Dongyeon Kim <dy5.kim@samsung.com> Fri, 11 Jan 2013 18:09:24 +0900
+
+cairo (1.12.6-slp2+2) unstable; urgency=low
+
+ * Bug fixes for stroke and gradients
+ * Git: framework/graphics/cairo
+ * Tag: cairo_1.12.6-slp2+2
+
+ -- Dongyeon Kim <dy5.kim@samsung.com> Thu, 03 Jan 2013 11:35:33 +0900
+
+cairo (1.12.6-slp2+1) unstable; urgency=low
+
+ * Update cairo to 1.12.6
+ * Git: framework/graphics/cairo
+ * Tag: cairo_1.12.6-slp2+1
+
+ -- Dongyeon Kim <dy5.kim@samsung.com> Wed, 28 Nov 2012 10:13:41 +0900
+
+cairo (1.12.4-slp2+3) unstable; urgency=low
+
+ * gl: Fix gradient cache overflow
+ * Git: framework/graphics/cairo
+ * Tag: cairo_1.12.4-slp2+3
+
+ -- Dongyeon Kim <dy5.kim@samsung.com> Tue, 06 Nov 2012 10:22:48 +0900
+
+cairo (1.12.4-slp2+2) unstable; urgency=low
+
+ * Various bug fixes
+ * Git: framework/graphics/cairo
+ * Tag: cairo_1.12.4-slp2+2
+
+ -- Dongyeon Kim <dy5.kim@samsung.com> Wed, 24 Oct 2012 19:23:38 +0900
+
cairo (1.12.4-slp2+1) unstable; urgency=low
* Update cairo to 1.12.4
#sbs-git:slp/unmodified/cairo cairo 1.11.3 076a40b95caaadbc4a05b92a1a1d7840427e05b7
Name: cairo
Summary: A vector graphics library
-Version: 1.12.4
+Version: 1.12.12
Release: 1
Group: System/Libraries
License: LGPLv2 or MPLv1.1
%files
%manifest cairo.manifest
-%{_libdir}/libcairo*.so.*
+%{_libdir}/libcairo.so.*
/usr/share/license/%{name}
+%exclude %{_libdir}/libcairo-*.so.*
%files devel
%manifest cairo.manifest
%{_includedir}/*
%{_libdir}/libcairo*.so
+%{_libdir}/libcairo-*.so.*
%{_libdir}/pkgconfig/*
%exclude %{_bindir}/cairo-trace
%exclude %{_libdir}/cairo/libcairo-trace.so
int width, height;
int num_tests, num_reports;
double min_value, max_value;
+ double *average;
cairo_bool_t use_html;
cairo_bool_t relative;
int num_tests = 0;
double slow_sum = 0, fast_sum = 0, sum;
int slow_count = 0, fast_count = 0;
+ int *count;
int i;
num_values = 0;
size_values = 64;
values = xmalloc (size_values * sizeof (double));
+ chart->average = xmalloc(chart->num_reports * sizeof(double));
+ count = xmalloc(chart->num_reports * sizeof(int));
+ for (i = 0; i < chart->num_reports; i++) {
+ chart->average[i] = 0;
+ count[i] = 0;
+ }
+
tests = xmalloc (chart->num_reports * sizeof (test_report_t *));
for (i = 0; i < chart->num_reports; i++)
tests[i] = chart->reports[i].tests;
if (test_time == 0)
test_time = report_time;
+ chart->average[i] += report_time / test_time;
+ count[i]++;
+
if (chart->relative) {
if (test_time != report_time) {
double v = to_factor (test_time / report_time);
}
}
+ for (i = 0; i < chart->num_reports; i++) {
+ if (count[i])
+ chart->average[i] = count[i] / chart->average[i];
+ else
+ chart->average[i] = 1.;
+ }
+
if (chart->relative)
trim_outliers (values, num_values, &min, &max);
chart->min_value = min;
chart->max_value = max;
- chart->num_tests = num_tests;
+ chart->num_tests = num_tests + !!chart->relative;
free (values);
free (tests);
+ free (count);
printf ("%d: slow[%d] average: %f, fast[%d] average: %f, %f\n",
num_values, slow_count, slow_sum / slow_count, fast_count, fast_sum / fast_count, sum / num_values);
}
static void
+add_average (struct chart *c,
+ int test,
+ int report,
+ double value)
+{
+ double dx, dy, x;
+ cairo_text_extents_t extents;
+ char buf[80];
+ double y;
+
+ if (fabs (value) < 0.1)
+ return;
+
+ dy = (c->height/2. - PAD) / MAX (-c->min_value, c->max_value);
+ /* the first report is always skipped, as it is used as the baseline */
+ dx = c->width / (double) (c->num_tests * c->num_reports);
+ x = dx * (c->num_reports * test + report - .5);
+
+ cairo_rectangle (c->cr,
+ floor (x), c->height / 2.,
+ floor (x + dx) - floor (x),
+ ceil (-dy*value - c->height/2.) + c->height/2.);
+ if (dx < 5) {
+ set_report_color (c, report);
+ cairo_fill (c->cr);
+ } else {
+ set_report_gradient (c, report,
+ floor (x), c->height / 2.,
+ floor (x + dx) - floor (x),
+ ceil (-dy*value - c->height/2.) + c->height/2.);
+
+ cairo_fill_preserve (c->cr);
+ cairo_save (c->cr);
+ cairo_clip_preserve (c->cr);
+ set_report_color (c, report);
+ cairo_stroke (c->cr);
+ cairo_restore (c->cr);
+ }
+
+ /* Skip the label if the difference between the two is less than 0.1% */
+ if (fabs (value) < 0.1)
+ return;
+
+ cairo_save (c->cr);
+ cairo_set_font_size (c->cr, dx - 2);
+
+ if (value < 0) {
+ sprintf (buf, "%.1f", -value/100 + 1);
+ } else {
+ sprintf (buf, "%.1f", value/100 + 1);
+ }
+ cairo_text_extents (c->cr, buf, &extents);
+
+ /* will it be clipped? */
+ y = -dy * value;
+ if (y < -c->height/2) {
+ y = -c->height/2;
+ } else if (y > c->height/2) {
+ y = c->height/2;
+ }
+
+ if (y < 0) {
+ if (y > -extents.width - 6)
+ y -= extents.width + 6;
+ } else {
+ if (y < extents.width + 6)
+ y += extents.width + 6;
+ }
+
+ cairo_translate (c->cr,
+ floor (x) + (floor (x + dx) - floor (x))/2,
+ floor (y) + c->height/2.);
+ cairo_rotate (c->cr, -M_PI/2);
+ if (y < 0) {
+ cairo_move_to (c->cr, -extents.x_bearing -extents.width - 4, -extents.y_bearing/2);
+ } else {
+ cairo_move_to (c->cr, 2, -extents.y_bearing/2);
+ }
+
+ cairo_set_source_rgb (c->cr, .95, .95, .95);
+ cairo_show_text (c->cr, buf);
+ cairo_restore (c->cr);
+}
+
+static void
add_label (struct chart *c,
int test,
const char *label)
num_test++;
}
+ if (chart->relative) {
+ add_label (chart, num_test, "(geometric mean)");
+ for (i = 0; i < chart->num_reports; i++)
+ add_average (chart, num_test, i, to_factor (chart->average[i]));
+ }
free (tests);
if (print) {
add_legend (&chart);
cairo_surface_write_to_png (cairo_get_target (chart.cr),
- chart.relative ?
- "cairo-perf-chart-relative.png" :
- "cairo-perf-chart-absolute.png");
+ chart.relative ? "relative.png" : "absolute.png");
cairo_destroy (chart.cr);
}
}
static void
-clear_surface (cairo_surface_t *surface)
+fill_surface (cairo_surface_t *surface)
{
cairo_t *cr = cairo_create (surface);
- cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+ /* This needs to be an operation that the backends can't optimise away */
+ cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.5);
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_paint (cr);
cairo_destroy (cr);
}
return surface;
}
+static cairo_surface_t *
+_source_image_create (void *closure,
+ cairo_format_t format,
+ int width,
+ int height,
+ long uid)
+{
+ struct trace *args = closure;
+
+ return cairo_surface_create_similar_image (args->surface,
+ format, width, height);
+}
+
static cairo_t *
_context_create (void *closure,
cairo_surface_t *surface)
_context_create,
NULL, /* context_destroy */
NULL, /* show_page */
- NULL /* copy_page */
+ NULL, /* copy_page */
+ _source_image_create,
};
args.tile_size = perf->tile_size;
1, 1,
CAIRO_BOILERPLATE_MODE_PERF,
&args.closure);
+ fill_surface(args.surface); /* remove any clear flags */
+
if (perf->observe) {
cairo_surface_t *obs;
obs = cairo_surface_create_observer (args.surface,
fill[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_fill_elapsed (observer));
glyphs[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_glyphs_elapsed (observer));
} else {
- clear_surface (args.surface); /* queue a write to the sync'ed surface */
+ fill_surface (args.surface); /* queue a write to the sync'ed surface */
cairo_perf_timer_stop ();
times[i] = cairo_perf_timer_elapsed ();
}
void
cairo_perf_timer_stop (void)
{
+ if (cairo_perf_timer_synchronize)
+ cairo_perf_timer_synchronize (cairo_perf_timer_synchronize_closure);
+
timer = _cairo_time_get_delta (timer);
}
cairo-path-stroke.c \
cairo-path-stroke-boxes.c \
cairo-path-stroke-polygon.c \
+ cairo-path-stroke-traps.c \
cairo-path-stroke-tristrip.c \
cairo-pattern.c \
cairo-pen.c \
cairo-cogl-gradient.c \
cairo-cogl-context.c \
cairo-cogl-utils.c
+
if (backend->is_synthetic && backend->is_synthetic (scaled_font_subset->scaled_font))
return CAIRO_INT_STATUS_UNSUPPORTED;
- font = malloc (sizeof (cairo_cff_font_t));
+ font = calloc (1, sizeof (cairo_cff_font_t));
if (unlikely (font == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
fail3:
free (font->subset_font_name);
fail2:
- free (font->data);
- free (font->font_name);
free (font->ps_name);
_cairo_array_fini (&font->output);
fail1:
+ free (font->data);
+ free (font->font_name);
free (font);
return status;
_cairo_traps_init (&traps);
- status = _cairo_path_fixed_stroke_to_traps (path, style, ctm, ctm_inverse, tolerance,
- &traps);
+ status = _cairo_path_fixed_stroke_polygon_to_traps (path, style,
+ ctm, ctm_inverse,
+ tolerance,
+ &traps);
if (unlikely (status))
goto BAIL;
if (type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
- cairo_surface_t *pattern_surface = pattern_surface = surface_pattern->surface;
+ cairo_surface_t *pattern_surface = surface_pattern->surface;
/* XXX: both source and target are GL surface */
if (cairo_surface_get_type (pattern_surface) == CAIRO_SURFACE_TYPE_GL &&
if (unlikely (status))
return status;
+ if (overlap && *overlap &&
+ scaled_font->options.antialias == CAIRO_ANTIALIAS_NONE &&
+ _cairo_pattern_is_opaque_solid (&extents->source_pattern.base))
+ {
+ *overlap = FALSE;
+ }
+
return _cairo_composite_rectangles_intersect (extents, clip);
}
clip, &should_be_lazy))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE &&
+ _cairo_scaled_font_glyph_approximate_extents (scaled_font,
+ glyphs, num_glyphs,
+ &extents->source))
+ {
+ if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source))
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ }
+
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs, num_glyphs,
&extents->source,
if (unlikely (status))
return status;
+ if (*overlap &&
+ scaled_font->options.antialias == CAIRO_ANTIALIAS_NONE &&
+ _cairo_pattern_is_opaque_solid (extents->original_source_pattern))
+ {
+ *overlap = FALSE;
+ }
+
extents->clip = _cairo_clip_copy (clip);
return CAIRO_INT_STATUS_SUCCESS;
cairo_boxes_t *boxes);
cairo_int_status_t
+ (*check_composite) (const cairo_composite_rectangles_t *extents);
+
+ cairo_int_status_t
(*composite) (void *dst,
cairo_operator_t op,
cairo_surface_t *src,
_cairo_damage_create (void);
cairo_private cairo_damage_t *
+_cairo_damage_create_in_error (cairo_status_t status);
+
+cairo_private cairo_damage_t *
_cairo_damage_add_box (cairo_damage_t *damage,
const cairo_box_t *box);
static const cairo_damage_t __cairo_damage__nil = { CAIRO_STATUS_NO_MEMORY };
cairo_damage_t *
+_cairo_damage_create_in_error (cairo_status_t status)
+{
+ _cairo_error_throw (status);
+ return (cairo_damage_t *) &__cairo_damage__nil;
+}
+
+cairo_damage_t *
_cairo_damage_create (void)
{
cairo_damage_t *damage;
} else {
cairo_surface_t *parent_surface;
cairo_rectangle_int_t extents;
- cairo_bool_t is_empty;
+ cairo_bool_t bounded, is_empty;
parent_surface = _cairo_gstate_get_target (cr->gstate);
/* Get the extents that we'll use in creating our new group surface */
- is_empty = _cairo_surface_get_extents (parent_surface, &extents);
+ bounded = _cairo_surface_get_extents (parent_surface, &extents);
if (clip)
+ /* XXX: This assignment just fixes a compiler warning? */
is_empty = _cairo_rectangle_intersect (&extents,
_cairo_clip_get_extents (clip));
- /* XXX unbounded surface creation */
-
- group_surface = _cairo_surface_create_similar_solid (parent_surface,
- content,
- extents.width,
- extents.height,
- CAIRO_COLOR_TRANSPARENT);
+ if (!bounded) {
+ /* XXX: Generic solution? */
+ group_surface = cairo_recording_surface_create (content, NULL);
+ extents.x = extents.y = 0;
+ } else {
+ group_surface = _cairo_surface_create_similar_solid (parent_surface,
+ content,
+ extents.width,
+ extents.height,
+ CAIRO_COLOR_TRANSPARENT);
+ }
status = group_surface->status;
if (unlikely (status))
goto bail;
_cairo_default_context_set_source (cr, (cairo_pattern_t *) &_cairo_pattern_black);
pattern = cairo_pattern_create_rgba (red, green, blue, alpha);
- if (unlikely (pattern->status))
- return pattern->status;
+ if (unlikely (pattern->status)) {
+ status = pattern->status;
+ cairo_pattern_destroy (pattern);
+ return pattern->status;
+ }
status = _cairo_default_context_set_source (cr, pattern);
cairo_pattern_destroy (pattern);
_cairo_default_context_set_source (cr, (cairo_pattern_t *) &_cairo_pattern_black);
pattern = cairo_pattern_create_for_surface (surface);
- if (unlikely (pattern->status))
- return pattern->status;
+ if (unlikely (pattern->status)) {
+ status = pattern->status;
+ cairo_pattern_destroy (pattern);
+ return status;
+ }
cairo_matrix_init_translate (&matrix, -x, -y);
cairo_pattern_set_matrix (pattern, &matrix);
EGLSurface dummy_surface;
- EGLDisplay previous_display;
EGLContext previous_context;
- EGLSurface previous_surface;
} cairo_egl_context_t;
typedef struct _cairo_egl_surface {
_context_acquisition_changed_egl_state (cairo_egl_context_t *ctx,
EGLSurface current_surface)
{
- return !(ctx->previous_display == ctx->display &&
- ctx->previous_surface == current_surface &&
- ctx->previous_context == ctx->context);
+ return ctx->previous_context != ctx->context;
}
static EGLSurface
static void
_egl_query_current_state (cairo_egl_context_t *ctx)
{
- ctx->previous_display = eglGetCurrentDisplay ();
- ctx->previous_surface = eglGetCurrentSurface (EGL_DRAW);
ctx->previous_context = eglGetCurrentContext ();
-
- /* If any of the values were none, assume they are all none. Not all
- drivers seem well behaved when it comes to using these values across
- multiple threads. */
- if (ctx->previous_surface == EGL_NO_SURFACE
- || ctx->previous_display == EGL_NO_DISPLAY
- || ctx->previous_context == EGL_NO_CONTEXT) {
- ctx->previous_surface = EGL_NO_SURFACE;
- ctx->previous_display = EGL_NO_DISPLAY;
- ctx->previous_context = EGL_NO_CONTEXT;
- }
}
static void
return;
_cairo_gl_context_reset (&ctx->base);
-
eglMakeCurrent (ctx->display,
current_surface, current_surface, ctx->context);
}
static cairo_status_t
_compute_transform (cairo_ft_font_transform_t *sf,
- cairo_matrix_t *scale)
+ cairo_matrix_t *scale,
+ cairo_ft_unscaled_font_t *unscaled)
{
cairo_status_t status;
double x_scale, y_scale;
if (y_scale < 1.0)
y_scale = 1.0;
+ if (unscaled && (unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) == 0) {
+ double min_distance = DBL_MAX;
+ int i;
+ int best_i = 0;
+ double best_x_size = 0;
+ double best_y_size = 0;
+
+ for (i = 0; i < unscaled->face->num_fixed_sizes; i++) {
+ double x_size = unscaled->face->available_sizes[i].y_ppem / 64.;
+ double y_size = unscaled->face->available_sizes[i].y_ppem / 64.;
+ double distance = fabs (y_size - y_scale);
+
+ if (distance <= min_distance) {
+ min_distance = distance;
+ best_i = i;
+ best_x_size = x_size;
+ best_y_size = y_size;
+ }
+ }
+
+ x_scale = best_x_size;
+ y_scale = best_y_size;
+ }
+
sf->x_scale = x_scale;
sf->y_scale = y_scale;
unscaled->have_scale = TRUE;
unscaled->current_scale = *scale;
- status = _compute_transform (&sf, scale);
+ status = _compute_transform (&sf, scale, unscaled);
if (unlikely (status))
return status;
FT_Set_Transform(unscaled->face, &mat, NULL);
- if ((unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) != 0) {
- error = FT_Set_Char_Size (unscaled->face,
- sf.x_scale * 64.0 + .5,
- sf.y_scale * 64.0 + .5,
- 0, 0);
- if (error)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- } else {
- double min_distance = DBL_MAX;
- int i;
- int best_i = 0;
-
- for (i = 0; i < unscaled->face->num_fixed_sizes; i++) {
-#if HAVE_FT_BITMAP_SIZE_Y_PPEM
- double size = unscaled->face->available_sizes[i].y_ppem / 64.;
-#else
- double size = unscaled->face->available_sizes[i].height;
-#endif
- double distance = fabs (size - sf.y_scale);
-
- if (distance <= min_distance) {
- min_distance = distance;
- best_i = i;
- }
- }
-#if HAVE_FT_BITMAP_SIZE_Y_PPEM
- error = FT_Set_Char_Size (unscaled->face,
- unscaled->face->available_sizes[best_i].x_ppem,
- unscaled->face->available_sizes[best_i].y_ppem,
- 0, 0);
- if (error)
-#endif
- error = FT_Set_Pixel_Sizes (unscaled->face,
- unscaled->face->available_sizes[best_i].width,
- unscaled->face->available_sizes[best_i].height);
- if (error)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
+ error = FT_Set_Char_Size (unscaled->face,
+ sf.x_scale * 64.0 + .5,
+ sf.y_scale * 64.0 + .5,
+ 0, 0);
+ if (error)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS;
}
return CAIRO_INT_STATUS_UNSUPPORTED;
}
+static cairo_bool_t
+_ft_is_type1 (FT_Face face)
+{
+#if HAVE_FT_GET_X11_FONT_FORMAT
+ const char *font_format = FT_Get_X11_Font_Format (face);
+ if (font_format &&
+ (strcmp (font_format, "Type 1") == 0 ||
+ strcmp (font_format, "CFF") == 0))
+ {
+ return TRUE;
+ }
+#endif
+
+ return FALSE;
+}
+
static cairo_int_status_t
_cairo_ft_load_type1_data (void *abstract_font,
long offset,
cairo_status_t status = CAIRO_STATUS_SUCCESS;
unsigned long available_length;
unsigned long ret;
- const char *font_format;
assert (length != NULL);
}
#endif
- font_format = FT_Get_X11_Font_Format (face);
- if (!font_format ||
- !(strcmp (font_format, "Type 1") == 0 ||
- strcmp (font_format, "CFF") == 0))
- {
+ if (! _ft_is_type1 (face)) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto unlock;
}
font_matrix,
&scale);
- status = _compute_transform (&sf, &scale);
+ status = _compute_transform (&sf, &scale, NULL);
if (unlikely (status))
return (cairo_font_face_t *)&_cairo_font_face_nil;
#include "cairo-clip-private.h"
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
-#include "cairo-traps-private.h"
union fi {
float f;
}
void
+_cairo_gl_composite_set_multisample (cairo_gl_composite_t *setup)
+{
+ setup->multisample = TRUE;
+}
+
+void
_cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
cairo_region_t *clip_region)
{
_cairo_gl_composite_bind_to_shader (cairo_gl_context_t *ctx,
cairo_gl_composite_t *setup)
{
- _cairo_gl_shader_bind_matrix4f(ctx, "ModelViewProjectionMatrix",
+ _cairo_gl_shader_bind_matrix4f(ctx, CAIRO_GL_SHADER_SLOT_MVPMAT,
ctx->modelviewprojection_matrix);
_cairo_gl_operand_bind_to_shader (ctx, &setup->src, CAIRO_GL_TEX_SOURCE);
_cairo_gl_operand_bind_to_shader (ctx, &setup->mask, CAIRO_GL_TEX_MASK);
static void
_cairo_gl_context_setup_spans (cairo_gl_context_t *ctx,
+ cairo_bool_t spans_enabled,
unsigned int vertex_size,
unsigned int vertex_offset)
{
cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+ if (! spans_enabled) {
+ dispatch->DisableVertexAttribArray (CAIRO_GL_COVERAGE_ATTRIB_INDEX);
+ ctx->spans = FALSE;
+ return;
+ }
+
dispatch->VertexAttribPointer (CAIRO_GL_COVERAGE_ATTRIB_INDEX, 4,
GL_UNSIGNED_BYTE, GL_TRUE, vertex_size,
ctx->vb + vertex_offset);
return CAIRO_STATUS_SUCCESS;
}
-void
-_cairo_gl_scissor_to_extents (cairo_gl_surface_t *surface,
- const cairo_rectangle_int_t *extents)
-{
- int x1, y1, height;
-
- x1 = extents->x;
- y1 = extents->y;
- height = extents->height;
-
- if (_cairo_gl_surface_is_texture (surface) == FALSE)
- y1 = surface->height - (y1 + height);
- glScissor (x1, y1, extents->width, height);
- glEnable (GL_SCISSOR_TEST);
-}
-
static void
_scissor_to_doubles (cairo_gl_surface_t *surface,
double x1, double y1,
if (_cairo_gl_surface_is_texture (surface) == FALSE)
y1 = surface->height - (y1 + height);
glScissor (x1, y1, x2 - x1, height);
- glEnable (GL_SCISSOR_TEST);
}
-static void
-_scissor_to_rectangle (cairo_gl_surface_t *surface,
+void
+_cairo_gl_scissor_to_rectangle (cairo_gl_surface_t *surface,
const cairo_rectangle_int_t *r)
{
_scissor_to_doubles (surface, r->x, r->y, r->x+r->width, r->y+r->height);
ctx->vertex_size = size_per_vertex;
}
-void
-_disable_stencil_buffer (void)
-{
- if (glIsEnabled (GL_STENCIL_TEST))
- glDisable (GL_STENCIL_TEST);
-}
-
-void
-_disable_scissor_buffer (void)
-{
- if (glIsEnabled (GL_SCISSOR_TEST))
- glDisable (GL_SCISSOR_TEST);
-}
-
static cairo_int_status_t
_cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
cairo_gl_context_t *ctx,
- int vertex_size,
- cairo_bool_t equal_clip)
+ int vertex_size)
{
cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
cairo_gl_surface_t *dst = setup->dst;
cairo_clip_t *clip = setup->clip;
- cairo_traps_t traps;
- const cairo_rectangle_int_t *clip_extents;
if (clip->num_boxes == 1 && clip->path == NULL) {
- _scissor_to_box (dst, &clip->boxes[0]);
- goto disable_stencil_buffer_and_return;
+ _scissor_to_box (dst, &clip->boxes[0]);
+ _enable_scissor_buffer (ctx);
+ goto disable_stencil_buffer_and_return;
}
if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
goto disable_stencil_buffer_and_return;
}
+ /* The clip is not rectangular, so use the stencil buffer. */
if (! ctx->states_cache.depth_mask ) {
glDepthMask (GL_TRUE);
ctx->states_cache.depth_mask = TRUE;
}
- glEnable (GL_STENCIL_TEST);
- clip_extents = _cairo_clip_get_extents ((const cairo_clip_t *)clip);
- _cairo_gl_scissor_to_extents (dst, clip_extents);
- if (equal_clip)
- return CAIRO_INT_STATUS_SUCCESS;
+ _enable_stencil_buffer (ctx);
+
+ _disable_scissor_buffer (ctx);
+
+ cairo_clip_t *old_clip = setup->dst->clip_on_stencil_buffer;
+ if (_cairo_clip_equal (old_clip, setup->clip))
+ goto activate_stencil_buffer_and_return;
+
+ /* Clear the stencil buffer, but only the areas that we are
+ * going to be drawing to. */
+ if (old_clip)
+ _cairo_gl_scissor_to_rectangle (dst, _cairo_clip_get_extents (old_clip));
+ _enable_scissor_buffer (ctx);
+ setup->dst->clip_on_stencil_buffer = _cairo_clip_copy (setup->clip);
glClearStencil (0);
glClear (GL_STENCIL_BUFFER_BIT);
+ _disable_scissor_buffer (ctx);
+
glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
glStencilFunc (GL_EQUAL, 1, 0xffffffff);
glColorMask (0, 0, 0, 0);
- _cairo_traps_init (&traps);
- status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip, &traps);
- _cairo_traps_fini (&traps);
+ status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip);
if (unlikely (status)) {
glColorMask (1, 1, 1, 1);
_cairo_gl_composite_flush (ctx);
_cairo_gl_composite_setup_vbo (ctx, vertex_size);
+activate_stencil_buffer_and_return:
glColorMask (1, 1, 1, 1);
glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
glStencilFunc (GL_EQUAL, 1, 0xffffffff);
return CAIRO_INT_STATUS_SUCCESS;
disable_stencil_buffer_and_return:
- _disable_stencil_buffer ();
+ _disable_stencil_buffer (ctx);
return status;
}
cairo_gl_context_t *ctx,
int vertex_size)
{
- cairo_bool_t same_clip;
+ cairo_bool_t clip_changing = TRUE;
+ cairo_bool_t clip_region_changing = TRUE;
- if (! ctx->clip && ! setup->clip && ! ctx->clip_region)
- goto finish;
+ if (! ctx->clip && ! setup->clip && ! setup->clip_region && ! ctx->clip_region)
+ goto disable_all_clipping;
- same_clip = _cairo_clip_equal (ctx->clip, setup->clip);
+ clip_changing = ! _cairo_clip_equal (ctx->clip, setup->clip);
+ clip_region_changing = ! cairo_region_equal (ctx->clip_region, setup->clip_region);
if (! _cairo_gl_context_is_flushed (ctx) &&
- (! cairo_region_equal (ctx->clip_region, setup->clip_region) ||
- ! same_clip))
+ (clip_region_changing || clip_changing))
_cairo_gl_composite_flush (ctx);
- cairo_region_destroy (ctx->clip_region);
- ctx->clip_region = cairo_region_reference (setup->clip_region);
-
assert (!setup->clip_region || !setup->clip);
- if (! same_clip) {
+ /* setup->clip is only used by the msaa compositor and setup->clip_region
+ * only by the other compositors, so it's safe to wait to clean up obsolete
+ * clips. */
+ if (clip_region_changing) {
+ cairo_region_destroy (ctx->clip_region);
+ ctx->clip_region = cairo_region_reference (setup->clip_region);
+ }
+ if (clip_changing) {
_cairo_clip_destroy (ctx->clip);
ctx->clip = _cairo_clip_copy (setup->clip);
}
- if (ctx->clip_region) {
- _disable_stencil_buffer ();
- glEnable (GL_SCISSOR_TEST);
- return CAIRO_INT_STATUS_SUCCESS;
- }
+ /* For clip regions, we scissor right before drawing. */
+ if (setup->clip_region)
+ goto disable_all_clipping;
if (setup->clip)
- return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
- vertex_size,
- same_clip);
-
-finish:
- _disable_stencil_buffer ();
- _disable_scissor_buffer ();
+ return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
+ vertex_size);
+disable_all_clipping:
+ _disable_stencil_buffer (ctx);
+ _disable_scissor_buffer (ctx);
return CAIRO_INT_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
- cairo_gl_context_t **ctx_out,
- cairo_bool_t multisampling)
+_cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup,
+ cairo_gl_context_t *ctx)
{
unsigned int dst_size, src_size, mask_size, vertex_size;
- cairo_gl_context_t *ctx;
cairo_status_t status;
- cairo_bool_t component_alpha;
cairo_gl_shader_t *shader;
+ cairo_bool_t component_alpha;
cairo_operator_t op = setup->op;
cairo_surface_t *mask_surface = NULL;
- assert (setup->dst);
-
- status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
- if (unlikely (status))
- return status;
-
- _cairo_gl_context_set_destination (ctx, setup->dst, multisampling);
-
- if (ctx->states_cache.blend_enabled == FALSE) {
- glEnable (GL_BLEND);
- ctx->states_cache.blend_enabled = TRUE;
- }
-
component_alpha =
setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
setup->mask.texture.attributes.has_component_alpha;
/* Do various magic for component alpha */
if (component_alpha) {
- status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
- if (unlikely (status))
- goto FAIL;
- } else {
- if (ctx->pre_shader) {
- _cairo_gl_composite_flush (ctx);
- ctx->pre_shader = NULL;
- }
+ status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
+ if (unlikely (status))
+ return status;
+ } else {
+ if (ctx->pre_shader) {
+ _cairo_gl_composite_flush (ctx);
+ ctx->pre_shader = NULL;
+ }
}
status = _cairo_gl_get_shader_by_type (ctx,
&setup->src,
&setup->mask,
setup->spans,
- component_alpha ?
+ component_alpha ?
CAIRO_GL_SHADER_IN_CA_SOURCE :
CAIRO_GL_SHADER_IN_NORMAL,
&shader);
if (unlikely (status)) {
- ctx->pre_shader = NULL;
- goto FAIL;
+ ctx->pre_shader = NULL;
+ return status;
}
if (ctx->current_shader != shader)
_cairo_gl_composite_flush (ctx);
status = CAIRO_STATUS_SUCCESS;
- dst_size = 2 * sizeof (GLfloat);
- src_size = _cairo_gl_operand_get_vertex_size (&setup->src);
+ dst_size = 2 * sizeof (GLfloat);
+ src_size = _cairo_gl_operand_get_vertex_size (&setup->src);
mask_size = _cairo_gl_operand_get_vertex_size (&setup->mask);
vertex_size = dst_size + src_size + mask_size;
if (setup->spans)
- vertex_size += sizeof (GLfloat);
+ vertex_size += sizeof (GLfloat);
_cairo_gl_composite_setup_vbo (ctx, vertex_size);
_cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, vertex_size, dst_size);
_cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, vertex_size, dst_size + src_size);
- if (setup->spans)
- _cairo_gl_context_setup_spans (ctx, vertex_size, dst_size + src_size + mask_size);
- else {
- ctx->dispatch.DisableVertexAttribArray (CAIRO_GL_COVERAGE_ATTRIB_INDEX);
- ctx->spans = FALSE;
- }
+
+ _cairo_gl_context_setup_spans (ctx, setup->spans, vertex_size,
+ dst_size + src_size + mask_size);
/* XXX: Shoot me - we have converted CLEAR to DEST_OUT,
so the dst_factor would be GL_ONE_MINUS_SRC_ALPHA, if the
_cairo_gl_set_operator (ctx, setup->op, component_alpha);
if (_cairo_gl_context_is_flushed (ctx)) {
- if (ctx->pre_shader) {
- _cairo_gl_set_shader (ctx, ctx->pre_shader);
- _cairo_gl_composite_bind_to_shader (ctx, setup);
- }
- _cairo_gl_set_shader (ctx, shader);
- _cairo_gl_composite_bind_to_shader (ctx, setup);
+ if (ctx->pre_shader) {
+ _cairo_gl_set_shader (ctx, ctx->pre_shader);
+ _cairo_gl_composite_bind_to_shader (ctx, setup);
+ }
+ _cairo_gl_set_shader (ctx, shader);
+ _cairo_gl_composite_bind_to_shader (ctx, setup);
}
- status = _cairo_gl_composite_setup_clipping (setup, ctx, vertex_size);
+ return status;
+}
+
+cairo_status_t
+_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
+ cairo_gl_context_t **ctx_out)
+{
+ cairo_gl_context_t *ctx;
+ cairo_status_t status;
+
+ assert (setup->dst);
+
+ status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
+ if (unlikely (status))
+ return status;
+
+ _cairo_gl_context_set_destination (ctx, setup->dst, setup->multisample);
+ if (ctx->states_cache.blend_enabled == FALSE) {
+ glEnable (GL_BLEND);
+ ctx->states_cache.blend_enabled = TRUE;
+ }
+ _cairo_gl_set_operands_and_operator (setup, ctx);
+
+ status = _cairo_gl_composite_setup_clipping (setup, ctx, ctx->vertex_size);
if (unlikely (status))
goto FAIL;
return status;
}
-cairo_status_t
-_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
- cairo_gl_context_t **ctx_out)
-{
- return _cairo_gl_composite_begin_multisample (setup, ctx_out, FALSE);
-}
-
static inline void
_cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx)
{
cairo_region_get_rectangle (ctx->clip_region, i, &rect);
- _scissor_to_rectangle (ctx->current_target, &rect);
+ _cairo_gl_scissor_to_rectangle (ctx->current_target, &rect);
+ _enable_scissor_buffer (ctx);
_cairo_gl_composite_draw_triangles (ctx, count);
}
}
}
static inline void
-_cairo_gl_composite_operand_emit (cairo_gl_operand_t *operand,
- GLfloat ** vb,
- GLfloat x,
- GLfloat y)
+_cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
+ GLfloat x, GLfloat y)
{
- switch (operand->type) {
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_OPERAND_NONE:
- break;
- case CAIRO_GL_OPERAND_CONSTANT:
- if (operand->use_color_attribute) {
- fi.bytes[0] = operand->constant.color[0] * 255;
- fi.bytes[1] = operand->constant.color[1] * 255;
- fi.bytes[2] = operand->constant.color[2] * 255;
- fi.bytes[3] = operand->constant.color[3] * 255;
- *(*vb)++ = fi.f;
- }
- break;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- {
- double s = x;
- double t = y;
+ GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
- cairo_matrix_transform_point (&operand->gradient.m, &s, &t);
+ *vb++ = x;
+ *vb++ = y;
- *(*vb)++ = s;
- *(*vb)++ = t;
- }
- break;
- case CAIRO_GL_OPERAND_TEXTURE:
- {
- cairo_surface_attributes_t *src_attributes = &operand->texture.attributes;
- double s = x;
- double t = y;
-
- cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
- *(*vb)++ = s;
- *(*vb)++ = t;
-
- if (operand->texture.use_atlas) {
- *(*vb)++ = operand->texture.p1.x;
- *(*vb)++ = operand->texture.p1.y;
- *(*vb)++ = operand->texture.p2.x;
- *(*vb)++ = operand->texture.p2.y;
- }
- }
- break;
- }
+ _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
+ _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK ], &vb, x, y);
+
+ ctx->vb_offset += ctx->vertex_size;
}
static inline void
-_cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
- GLfloat x,
- GLfloat y,
- uint8_t alpha)
+_cairo_gl_composite_emit_alpha_vertex (cairo_gl_context_t *ctx,
+ GLfloat x, GLfloat y, uint8_t alpha)
{
GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
+ union fi {
+ float f;
+ GLbyte bytes[4];
+ } fi;
*vb++ = x;
*vb++ = y;
- _cairo_gl_composite_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
- _cairo_gl_composite_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK ], &vb, x, y);
+ _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
+ _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK ], &vb, x, y);
- if (ctx->spans) {
-
- fi.bytes[0] = 0;
- fi.bytes[1] = 0;
- fi.bytes[2] = 0;
- fi.bytes[3] = alpha;
- *vb++ = fi.f;
- }
+ fi.bytes[0] = 0;
+ fi.bytes[1] = 0;
+ fi.bytes[2] = 0;
+ fi.bytes[3] = alpha;
+ *vb++ = fi.f;
ctx->vb_offset += ctx->vertex_size;
}
-static inline void
+static void
_cairo_gl_composite_emit_point (cairo_gl_context_t *ctx,
- const cairo_point_t *point,
- uint8_t alpha)
+ const cairo_point_t *point)
{
_cairo_gl_composite_emit_vertex (ctx,
_cairo_fixed_to_double (point->x),
- _cairo_fixed_to_double (point->y),
- alpha);
+ _cairo_fixed_to_double (point->y));
}
-void
+static void
_cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
- GLfloat x1,
- GLfloat y1,
- GLfloat x2,
- GLfloat y2,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2)
+{
+ _cairo_gl_composite_prepare_buffer (ctx, 6,
+ CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
+
+ _cairo_gl_composite_emit_vertex (ctx, x1, y1);
+ _cairo_gl_composite_emit_vertex (ctx, x2, y1);
+ _cairo_gl_composite_emit_vertex (ctx, x1, y2);
+
+ _cairo_gl_composite_emit_vertex (ctx, x2, y1);
+ _cairo_gl_composite_emit_vertex (ctx, x2, y2);
+ _cairo_gl_composite_emit_vertex (ctx, x1, y2);
+}
+
+cairo_gl_emit_rect_t
+_cairo_gl_context_choose_emit_rect (cairo_gl_context_t *ctx)
+{
+ return _cairo_gl_composite_emit_rect;
+}
+
+void
+_cairo_gl_context_emit_rect (cairo_gl_context_t *ctx,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2)
+{
+ _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2);
+}
+
+static void
+_cairo_gl_composite_emit_span (cairo_gl_context_t *ctx,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2,
uint8_t alpha)
{
if (ctx->draw_mode != CAIRO_GL_VERTEX) {
_cairo_gl_composite_prepare_buffer (ctx, 6,
CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
- _cairo_gl_composite_emit_vertex (ctx, x1, y1, alpha);
- _cairo_gl_composite_emit_vertex (ctx, x2, y1, alpha);
- _cairo_gl_composite_emit_vertex (ctx, x1, y2, alpha);
+ _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y1, alpha);
+ _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
+ _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
+
+ _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
+ _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y2, alpha);
+ _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
+}
+
+static void
+_cairo_gl_composite_emit_solid_span (cairo_gl_context_t *ctx,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2,
+ uint8_t alpha)
+{
+ GLfloat *v;
+ union fi {
+ float f;
+ GLbyte bytes[4];
+ } fi;
+
+ _cairo_gl_composite_prepare_buffer (ctx, 6,
+ CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
+ v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
+
+ v[15] = v[ 6] = v[0] = x1;
+ v[10] = v[ 4] = v[1] = y1;
+ v[12] = v[ 9] = v[3] = x2;
+ v[16] = v[13] = v[7] = y2;
+
+ fi.bytes[0] = 0;
+ fi.bytes[1] = 0;
+ fi.bytes[2] = 0;
+ fi.bytes[3] = alpha;
+ v[17] =v[14] = v[11] = v[8] = v[5] = v[2] = fi.f;
+
+ ctx->vb_offset += 6*3 * sizeof(GLfloat);
+}
+
+cairo_gl_emit_span_t
+_cairo_gl_context_choose_emit_span (cairo_gl_context_t *ctx)
+{
+ if (ctx->operands[CAIRO_GL_TEX_MASK].type != CAIRO_GL_OPERAND_NONE)
+ return _cairo_gl_composite_emit_span;
- _cairo_gl_composite_emit_vertex (ctx, x2, y1, alpha);
- _cairo_gl_composite_emit_vertex (ctx, x2, y2, alpha);
- _cairo_gl_composite_emit_vertex (ctx, x1, y2, alpha);
+ switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
+ default:
+ case CAIRO_GL_OPERAND_COUNT:
+ ASSERT_NOT_REACHED;
+ case CAIRO_GL_OPERAND_NONE:
+ case CAIRO_GL_OPERAND_CONSTANT:
+ return _cairo_gl_composite_emit_solid_span;
+
+ case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+ case CAIRO_GL_OPERAND_TEXTURE:
+ return _cairo_gl_composite_emit_span;
+ }
}
static inline void
_cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
- GLfloat x,
- GLfloat y,
- GLfloat glyph_x,
- GLfloat glyph_y)
+ GLfloat x, GLfloat y,
+ GLfloat glyph_x, GLfloat glyph_y)
{
GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
*vb++ = x;
*vb++ = y;
- _cairo_gl_composite_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
+ _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
*vb++ = glyph_x;
*vb++ = glyph_y;
ctx->vb_offset += ctx->vertex_size;
}
-void
+static void
_cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
- GLfloat x1,
- GLfloat y1,
- GLfloat x2,
- GLfloat y2,
- GLfloat glyph_x1,
- GLfloat glyph_y1,
- GLfloat glyph_x2,
- GLfloat glyph_y2)
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2,
+ GLfloat glyph_x1, GLfloat glyph_y1,
+ GLfloat glyph_x2, GLfloat glyph_y2)
{
if (ctx->draw_mode != CAIRO_GL_VERTEX) {
_cairo_gl_composite_flush (ctx);
_cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
}
+static void
+_cairo_gl_composite_emit_solid_glyph (cairo_gl_context_t *ctx,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2,
+ GLfloat glyph_x1, GLfloat glyph_y1,
+ GLfloat glyph_x2, GLfloat glyph_y2)
+{
+ GLfloat *v;
+
+ _cairo_gl_composite_prepare_buffer (ctx, 6,
+ CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
+
+ v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
+
+ v[20] = v[ 8] = v[0] = x1;
+ v[13] = v[ 5] = v[1] = y1;
+ v[22] = v[10] = v[2] = glyph_x1;
+ v[15] = v[ 7] = v[3] = glyph_y1;
+
+ v[16] = v[12] = v[4] = x2;
+ v[18] = v[14] = v[6] = glyph_x2;
+
+ v[21] = v[17] = v[ 9] = y2;
+ v[23] = v[19] = v[11] = glyph_y2;
+
+ ctx->vb_offset += 4 * 6 * sizeof (GLfloat);
+}
+
+cairo_gl_emit_glyph_t
+_cairo_gl_context_choose_emit_glyph (cairo_gl_context_t *ctx)
+{
+ switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
+ default:
+ case CAIRO_GL_OPERAND_COUNT:
+ ASSERT_NOT_REACHED;
+ case CAIRO_GL_OPERAND_NONE:
+ case CAIRO_GL_OPERAND_CONSTANT:
+ if (! ctx->operands[CAIRO_GL_TEX_SOURCE].use_color_attribute)
+ return _cairo_gl_composite_emit_solid_glyph;
+
+ case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+ case CAIRO_GL_OPERAND_TEXTURE:
+ return _cairo_gl_composite_emit_glyph;
+ }
+}
+
void
_cairo_gl_composite_fini (cairo_gl_composite_t *setup)
{
}
cairo_status_t
-_cairo_gl_composite_init (cairo_gl_composite_t *setup,
- cairo_operator_t op,
- cairo_gl_surface_t *dst,
- cairo_bool_t assume_component_alpha)
+_cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
+ cairo_operator_t op,
+ cairo_bool_t assume_component_alpha)
{
- memset (setup, 0, sizeof (cairo_gl_composite_t));
-
if (assume_component_alpha) {
if (op != CAIRO_OPERATOR_CLEAR &&
op != CAIRO_OPERATOR_OVER &&
return UNSUPPORTED ("unsupported operator");
}
- setup->dst = dst;
setup->op = op;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_gl_composite_init (cairo_gl_composite_t *setup,
+ cairo_operator_t op,
+ cairo_gl_surface_t *dst,
+ cairo_bool_t assume_component_alpha)
+{
+ cairo_status_t status;
+
+ memset (setup, 0, sizeof (cairo_gl_composite_t));
+
+ status = _cairo_gl_composite_set_operator (setup, op,
+ assume_component_alpha);
+ if (status)
+ return status;
+
+ setup->dst = dst;
setup->clip_region = dst->clip_region;
return CAIRO_STATUS_SUCCESS;
_cairo_gl_composite_prepare_buffer (ctx, 4,
CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
- _cairo_gl_composite_emit_point (ctx, &quad[0], 0);
- _cairo_gl_composite_emit_point (ctx, &quad[1], 0);
+ _cairo_gl_composite_emit_point (ctx, &quad[0]);
+ _cairo_gl_composite_emit_point (ctx, &quad[1]);
/* Cairo stores quad vertices in counter-clockwise order, but we need to
emit them from top to bottom in the triangle strip, so we need to reverse
the order of the last two vertices. */
- _cairo_gl_composite_emit_point (ctx, &quad[3], 0);
- _cairo_gl_composite_emit_point (ctx, &quad[2], 0);
+ _cairo_gl_composite_emit_point (ctx, &quad[3]);
+ _cairo_gl_composite_emit_point (ctx, &quad[2]);
return _cairo_gl_composite_append_vertex_indices (ctx, 4, TRUE);
}
_cairo_gl_composite_prepare_buffer (ctx, 3,
CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
- _cairo_gl_composite_emit_point (ctx, &triangle[0], 0);
- _cairo_gl_composite_emit_point (ctx, &triangle[1], 0);
- _cairo_gl_composite_emit_point (ctx, &triangle[2], 0);
+ _cairo_gl_composite_emit_point (ctx, &triangle[0]);
+ _cairo_gl_composite_emit_point (ctx, &triangle[1]);
+ _cairo_gl_composite_emit_point (ctx, &triangle[2]);
return _cairo_gl_composite_append_vertex_indices (ctx, 3, TRUE);
}
_cairo_gl_composite_prepare_buffer (ctx, 2,
CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
- _cairo_gl_composite_emit_point (ctx, &point[0], 0);
- _cairo_gl_composite_emit_point (ctx, &point[1], 0);
+ _cairo_gl_composite_emit_point (ctx, &point[0]);
+ _cairo_gl_composite_emit_point (ctx, &point[1]);
return _cairo_gl_composite_append_vertex_indices (ctx, num_indices, FALSE);
}
cairo_surface_t *cache_surface = _cairo_gl_surface_create_scratch (ctx,
CAIRO_CONTENT_COLOR_ALPHA,
IMAGE_CACHE_WIDTH,
- IMAGE_CACHE_HEIGHT,
- FALSE);
+ IMAGE_CACHE_HEIGHT);
if (unlikely (cache_surface->status)) {
cairo_surface_destroy (cache_surface);
return CAIRO_INT_STATUS_UNSUPPORTED;
_cairo_gl_context_reset (ctx);
- _disable_scissor_buffer ();
+ _disable_scissor_buffer (ctx);
if (ctx->states_cache.blend_enabled == TRUE ) {
glDisable (GL_BLEND);
for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
_cairo_gl_glyph_cache_fini (ctx, &ctx->glyph_cache[n]);
- if (ctx->shared_depth_stencil)
- ctx->dispatch.DeleteRenderbuffers (1, &ctx->shared_depth_stencil);
- if (ctx->shared_msaa_depth_stencil)
- ctx->dispatch.DeleteRenderbuffers (1, &ctx->shared_msaa_depth_stencil);
_cairo_gl_image_cache_fini (ctx);
return env && strcmp(env, "msaa") == 0;
}
+static cairo_bool_t
+test_can_read_bgra (cairo_gl_flavor_t gl_flavor)
+{
+ /* Desktop GL always supports BGRA formats. */
+ if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+ return TRUE;
+
+ assert (gl_flavor == CAIRO_GL_FLAVOR_ES);
+
+ /* For OpenGL ES we have to look for the specific extension and BGRA only
+ * matches cairo's integer packed bytes on little-endian machines. */
+ if (!_cairo_is_little_endian())
+ return FALSE;
+ return _cairo_gl_has_extension ("EXT_read_format_bgra");
+}
+
cairo_status_t
_cairo_gl_context_init (cairo_gl_context_t *ctx)
{
cairo_gl_flavor_t gl_flavor = _cairo_gl_get_flavor ();
int n;
+ cairo_bool_t is_desktop = gl_flavor == CAIRO_GL_FLAVOR_DESKTOP;
+ cairo_bool_t is_gles = gl_flavor == CAIRO_GL_FLAVOR_ES;
+
_cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
/* XXX The choice of compositor should be made automatically at runtime.
return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
/* Check for required extensions */
- if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
+ if (is_desktop) {
if (_cairo_gl_has_extension ("GL_ARB_texture_non_power_of_two")) {
ctx->tex_target = GL_TEXTURE_2D;
ctx->has_npot_repeat = TRUE;
return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
} else {
ctx->tex_target = GL_TEXTURE_2D;
- if (_cairo_gl_has_extension ("GL_OES_texture_npot"))
+ if (_cairo_gl_has_extension ("GL_OES_texture_npot") ||
+ _cairo_gl_has_extension ("GL_IMG_texture_npot"))
ctx->has_npot_repeat = TRUE;
else
ctx->has_npot_repeat = FALSE;
}
- if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP &&
- gl_version < CAIRO_GL_VERSION_ENCODE (2, 1) &&
+ if (is_desktop && gl_version < CAIRO_GL_VERSION_ENCODE (2, 1) &&
! _cairo_gl_has_extension ("GL_ARB_pixel_buffer_object"))
return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
- if (gl_flavor == CAIRO_GL_FLAVOR_ES &&
- ! _cairo_gl_has_extension ("GL_EXT_texture_format_BGRA8888"))
+ if (is_gles && ! _cairo_gl_has_extension ("GL_EXT_texture_format_BGRA8888"))
return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
- ctx->has_map_buffer = (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
- (gl_flavor == CAIRO_GL_FLAVOR_ES &&
- _cairo_gl_has_extension ("GL_OES_mapbuffer")));
+ ctx->has_map_buffer =
+ is_desktop || (is_gles && _cairo_gl_has_extension ("GL_OES_mapbuffer"));
+
+ ctx->can_read_bgra = test_can_read_bgra (gl_flavor);
ctx->has_mesa_pack_invert =
_cairo_gl_has_extension ("GL_MESA_pack_invert");
ctx->has_packed_depth_stencil =
- ((gl_flavor == CAIRO_GL_FLAVOR_DESKTOP &&
- _cairo_gl_has_extension ("GL_EXT_packed_depth_stencil")) ||
- (gl_flavor == CAIRO_GL_FLAVOR_ES &&
- _cairo_gl_has_extension ("GL_OES_packed_depth_stencil")));
+ (is_desktop && _cairo_gl_has_extension ("GL_EXT_packed_depth_stencil")) ||
+ (is_gles && _cairo_gl_has_extension ("GL_OES_packed_depth_stencil"));
ctx->num_samples = 1;
#if CAIRO_HAS_GL_SURFACE
- if (ctx->has_packed_depth_stencil &&
- _cairo_gl_has_extension ("GL_ARB_framebuffer_object")) {
+ if (is_desktop && ctx->has_packed_depth_stencil &&
+ (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) ||
+ _cairo_gl_has_extension ("GL_ARB_framebuffer_object") ||
+ (_cairo_gl_has_extension ("GL_EXT_framebuffer_blit") &&
+ _cairo_gl_has_extension ("GL_EXT_framebuffer_multisample")))) {
glGetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
}
#endif
#if CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_EXT)
- if (ctx->has_packed_depth_stencil &&
+ if (is_gles && ctx->has_packed_depth_stencil &&
_cairo_gl_has_extension ("GL_EXT_multisampled_render_to_texture")) {
glGetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
}
#endif
#if CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_IMG)
- if (ctx->has_packed_depth_stencil &&
+ if (is_gles && ctx->has_packed_depth_stencil &&
_cairo_gl_has_extension ("GL_IMG_multisampled_render_to_texture")) {
glGetIntegerv(GL_MAX_SAMPLES_IMG, &ctx->num_samples);
}
surface->msaa_rb);
/* Cairo surfaces start out initialized to transparent (black) */
- _disable_scissor_buffer ();
+ _disable_scissor_buffer (ctx);
glClearColor (0, 0, 0, 0);
// reset cached clear colors
memset (&ctx->states_cache.clear_red, 0, sizeof (double) * 4);
}
#endif
-static void
-_cairo_gl_replace_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
- int width,
- int height)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-
- if (ctx->shared_msaa_depth_stencil)
- dispatch->DeleteRenderbuffers (1, &ctx->shared_msaa_depth_stencil);
-
- dispatch->GenRenderbuffers (1, &ctx->shared_msaa_depth_stencil);
- dispatch->BindRenderbuffer (GL_RENDERBUFFER, ctx->shared_msaa_depth_stencil);
- dispatch->RenderbufferStorageMultisample (GL_RENDERBUFFER, ctx->num_samples,
- _get_depth_stencil_format (ctx),
- width, height);
- ctx->shared_msaa_depth_stencil_width = width;
- ctx->shared_msaa_depth_stencil_height = height;
-}
-
static cairo_bool_t
_cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
cairo_gl_surface_t *surface)
{
cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+ if (surface->msaa_depth_stencil)
+ return TRUE;
+
_cairo_gl_ensure_framebuffer (ctx, surface);
#if CAIRO_HAS_GL_SURFACE
if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
_cairo_gl_ensure_multisampling (ctx, surface);
#endif
- if (! ctx->shared_msaa_depth_stencil ||
- ctx->shared_msaa_depth_stencil_width < surface->width ||
- ctx->shared_msaa_depth_stencil_height < surface->height) {
- _cairo_gl_replace_msaa_depth_stencil_buffer (ctx,
- surface->width,
- surface->height);
- }
+ dispatch->GenRenderbuffers (1, &surface->msaa_depth_stencil);
+ dispatch->BindRenderbuffer (GL_RENDERBUFFER,
+ surface->msaa_depth_stencil);
- assert (ctx->shared_msaa_depth_stencil);
- if (surface->msaa_depth_stencil == ctx->shared_msaa_depth_stencil)
- return TRUE;
+ dispatch->RenderbufferStorageMultisample (GL_RENDERBUFFER,
+ ctx->num_samples,
+ _get_depth_stencil_format (ctx),
+ surface->width,
+ surface->height);
#if CAIRO_HAS_GL_SURFACE
if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
GL_DEPTH_STENCIL_ATTACHMENT,
GL_RENDERBUFFER,
- ctx->shared_msaa_depth_stencil);
+ surface->msaa_depth_stencil);
}
#endif
dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER,
- ctx->shared_msaa_depth_stencil);
+ surface->msaa_depth_stencil);
dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER,
- ctx->shared_msaa_depth_stencil);
+ surface->msaa_depth_stencil);
}
#endif
- surface->msaa_depth_stencil = ctx->shared_msaa_depth_stencil;
-
if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
dispatch->DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
surface->msaa_depth_stencil = 0;
return TRUE;
}
-static void
-_cairo_gl_replace_depth_stencil_buffer (cairo_gl_context_t *ctx,
- int width,
- int height)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-
- if (ctx->shared_depth_stencil)
- dispatch->DeleteRenderbuffers (1, &ctx->shared_depth_stencil);
-
- dispatch->GenRenderbuffers (1, &ctx->shared_depth_stencil);
- dispatch->BindRenderbuffer (GL_RENDERBUFFER, ctx->shared_depth_stencil);
- dispatch->RenderbufferStorage (GL_RENDERBUFFER,
- _get_depth_stencil_format (ctx),
- width, height);
- ctx->shared_depth_stencil_width = width;
- ctx->shared_depth_stencil_height = height;
-}
-
static cairo_bool_t
_cairo_gl_ensure_depth_stencil_buffer (cairo_gl_context_t *ctx,
cairo_gl_surface_t *surface)
{
cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
- _cairo_gl_ensure_framebuffer (ctx, surface);
+ if (surface->depth_stencil)
+ return TRUE;
- if (! ctx->shared_depth_stencil ||
- ctx->shared_depth_stencil_width < surface->width ||
- ctx->shared_depth_stencil_height < surface->height) {
- _cairo_gl_replace_depth_stencil_buffer (ctx,
- surface->width,
- surface->height);
- }
+ _cairo_gl_ensure_framebuffer (ctx, surface);
- if (surface->depth_stencil == ctx->shared_depth_stencil)
- return TRUE;
+ dispatch->GenRenderbuffers (1, &surface->depth_stencil);
+ dispatch->BindRenderbuffer (GL_RENDERBUFFER, surface->depth_stencil);
+ dispatch->RenderbufferStorage (GL_RENDERBUFFER,
+ _get_depth_stencil_format (ctx),
+ surface->width, surface->height);
dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER, ctx->shared_depth_stencil);
+ GL_RENDERBUFFER, surface->depth_stencil);
dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- GL_RENDERBUFFER, ctx->shared_depth_stencil);
- surface->depth_stencil = ctx->shared_depth_stencil;
-
+ GL_RENDERBUFFER, surface->depth_stencil);
if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
dispatch->DeleteRenderbuffers (1, &surface->depth_stencil);
surface->depth_stencil = 0;
_cairo_gl_composite_flush (ctx);
glEnable (GL_MULTISAMPLE);
- _disable_scissor_buffer ();
-
/* The last time we drew to the surface, we were not using multisampling,
so we need to blit from the non-multisampling framebuffer into the
multisampling framebuffer. */
_cairo_gl_composite_flush (ctx);
glDisable (GL_MULTISAMPLE);
- _disable_scissor_buffer ();
-
/* The last time we drew to the surface, we were using multisampling,
so we need to blit from the multisampling framebuffer into the
non-multisampling framebuffer. */
ctx->states_cache.active_texture = CAIRO_GL_ENUM_UNINITIALIZED;
ctx->states_cache.depth_mask = FALSE;
+
+ /* FIXME: this is hack to fix mali driver */
+ glDisable (GL_DITHER);
}
int gl_version,
cairo_gl_flavor_t gl_flavor)
{
- /* For the multisampling table, the there are two GLES versions
- * of the extension, so we put one in the EXT slot and one in
- * the real ES slot.*/
+ /* For the multisampling table, there are two GLES versions of the
+ * extension, so we put one in the EXT slot and one in the real ES slot.*/
cairo_gl_dispatch_name_t dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
if (gl_flavor == CAIRO_GL_FLAVOR_ES) {
if (_cairo_gl_has_extension ("GL_EXT_multisampled_render_to_texture"))
{
cairo_gl_glyph_cache_t *cache;
cairo_content_t content;
- cairo_bool_t true_alpha = FALSE;
switch (format) {
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_A1:
cache = &ctx->glyph_cache[1];
content = CAIRO_CONTENT_ALPHA;
- true_alpha = TRUE;
break;
default:
case CAIRO_FORMAT_INVALID:
}
if (unlikely (cache->surface == NULL)) {
- cairo_surface_t *surface;
+ cairo_surface_t *surface;
- surface = _cairo_gl_surface_create_scratch (ctx,
- content,
- GLYPH_CACHE_WIDTH,
- GLYPH_CACHE_HEIGHT,
- true_alpha);
+ surface = _cairo_gl_surface_create_scratch_for_caching (ctx,
+ content,
+ GLYPH_CACHE_WIDTH,
+ GLYPH_CACHE_HEIGHT);
+ if (unlikely (surface->status))
+ return surface->status;
- if (unlikely (surface->status))
- return surface->status;
-
- _cairo_surface_release_device_reference (surface);
+ _cairo_surface_release_device_reference (surface);
cache->surface = (cairo_gl_surface_t *)surface;
cache->surface->operand.texture.attributes.has_component_alpha =
cairo_format_t last_format = CAIRO_FORMAT_INVALID;
cairo_gl_glyph_cache_t *cache = NULL;
cairo_gl_context_t *ctx;
+ cairo_gl_emit_glyph_t emit;
cairo_gl_composite_t setup;
cairo_int_status_t status;
int i = 0;
status = _cairo_gl_context_release (ctx, status);
if (unlikely (status))
goto FINISH;
+
+ emit = _cairo_gl_context_choose_emit_glyph (ctx);
}
if (scaled_glyph->dev_private_key != cache) {
y2 = y1 + scaled_glyph->surface->height;
glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph);
- _cairo_gl_composite_emit_glyph (ctx,
- x1, y1, x2, y2,
- glyph->p1.x, glyph->p1.y,
- glyph->p2.x, glyph->p2.y);
+ emit (ctx,
+ x1, y1, x2, y2,
+ glyph->p1.x, glyph->p1.y,
+ glyph->p2.x, glyph->p2.y);
}
status = CAIRO_STATUS_SUCCESS;
cairo_reference_count_t ref_count;
cairo_device_t *device; /* NB: we don't hold a reference */
GLuint tex;
+ int tex_width;
unsigned int n_stops;
const cairo_gradient_stop_t *stops;
cairo_gradient_stop_t stops_embedded[1];
CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 2);
gradient->cache_entry.hash = hash;
- gradient->cache_entry.size = tex_width;
+ gradient->cache_entry.size = sizeof (cairo_gl_gradient_t *);
+ gradient->tex_width = tex_width;
gradient->device = &ctx->base;
gradient->n_stops = n_stops;
gradient->stops = gradient->stops_embedded;
return;
if (_cairo_gl_context_acquire (gradient->device, &ctx) == CAIRO_STATUS_SUCCESS) {
+ /* The gradient my still be active in the last operation, so flush */
+ _cairo_gl_composite_flush (ctx);
glDeleteTextures (1, &gradient->tex);
ignore = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
}
#include "cairo-composite-rectangles-private.h"
#include "cairo-compositor-private.h"
#include "cairo-gl-private.h"
+#include "cairo-path-private.h"
#include "cairo-traps-private.h"
-#include "cairo-surface-subsurface-inline.h"
static cairo_bool_t
can_use_msaa_compositor (cairo_gl_surface_t *surface,
{
cairo_point_t quad[4];
- quad[0].x = _cairo_edge_compute_intersection_x_for_y (&trap->left.p1,
- &trap->left.p2,
- trap->top);
+ if (trap->left.p1.x == trap->left.p2.x) {
+ quad[0].x = trap->left.p1.x;
+ quad[1].x = trap->left.p1.x;
+ } else {
+ cairo_fixed_t x, dy;
+ x = trap->left.p1.x;
+ dy = trap->left.p2.y - trap->left.p1.y;
+
+ if (trap->top == trap->left.p1.y)
+ quad[0].x = x;
+ else if (trap->top == trap->left.p2.y)
+ quad[0].x = trap->left.p2.x;
+ else if (dy != 0)
+ quad[0].x = x + _cairo_fixed_mul_div_floor (trap->top - trap->left.p1.y,
+ trap->left.p2.x - trap->left.p1.x, dy);
+
+ if (trap->bottom == trap->left.p2.y)
+ quad[1].x = trap->left.p2.x;
+ else if (trap->bottom == trap->left.p1.y)
+ quad[1].x = x;
+ else if (dy != 0)
+ quad[1].x = x + _cairo_fixed_mul_div_floor (trap->bottom - trap->left.p1.y,
+ trap->left.p2.x - trap->left.p1.x, dy);
+ }
quad[0].y = trap->top;
-
- quad[1].x = _cairo_edge_compute_intersection_x_for_y (&trap->left.p1,
- &trap->left.p2,
- trap->bottom);
quad[1].y = trap->bottom;
- quad[2].x = _cairo_edge_compute_intersection_x_for_y (&trap->right.p1,
- &trap->right.p2,
- trap->bottom);
+ if (trap->right.p1.x == trap->right.p2.x) {
+ quad[2].x = trap->right.p1.x;
+ quad[3].x = trap->right.p1.x;
+ } else {
+ cairo_fixed_t x, dy;
+ x = trap->right.p1.x;
+ dy = trap->right.p2.y - trap->right.p1.y;
+
+ if (trap->bottom == trap->right.p2.y)
+ quad[2].x = trap->right.p2.x;
+ else if (trap->bottom == trap->right.p1.y)
+ quad[2].x = x;
+ else if (dy != 0)
+ quad[2].x = x + _cairo_fixed_mul_div_floor (trap->bottom - trap->right.p1.y,
+ trap->right.p2.x - trap->right.p1.x, dy);
+
+ if (trap->top == trap->right.p1.y)
+ quad[3].x = x;
+ else if (trap->top == trap->right.p2.y)
+ quad[3].x = trap->right.p2.x;
+ else if (dy != 0)
+ quad[3].x = x + _cairo_fixed_mul_div_floor (trap->top - trap->right.p1.y,
+ trap->right.p2.x - trap->right.p1.x, dy);
+ }
quad[2].y = trap->bottom;
-
- quad[3].x = _cairo_edge_compute_intersection_x_for_y (&trap->right.p1,
- &trap->right.p2,
- trap->top);
quad[3].y = trap->top;
+
return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
}
}
static cairo_int_status_t
-_cairo_gl_msaa_compositor_draw_quad (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- cairo_box_t *box)
-{
- cairo_point_t quad[4];
-
- quad[0].x = box->p1.x;
- quad[0].y = box->p1.y;
-
- quad[1].x = box->p1.x;
- quad[1].y = box->p2.y;
-
- quad[2].x = box->p2.x;
- quad[2].y = box->p2.y;
-
- quad[3].x = box->p2.x;
- quad[3].y = box->p1.y;
-
- return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
-}
-
-static cairo_int_status_t
_draw_int_rect (cairo_gl_context_t *ctx,
cairo_gl_composite_t *setup,
cairo_rectangle_int_t *rect)
{
cairo_box_t box;
+ cairo_point_t quad[4];
_cairo_box_from_rectangle (&box, rect);
+ quad[0].x = box.p1.x;
+ quad[0].y = box.p1.y;
+ quad[1].x = box.p1.x;
+ quad[1].y = box.p2.y;
+ quad[2].x = box.p2.x;
+ quad[2].y = box.p2.y;
+ quad[3].x = box.p2.x;
+ quad[3].y = box.p1.y;
- return _cairo_gl_msaa_compositor_draw_quad (ctx, setup, &box);
+ return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
}
static cairo_int_status_t
return CAIRO_STATUS_SUCCESS;
}
-cairo_int_status_t
-_cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- cairo_clip_t *clip,
- cairo_traps_t *traps)
+static cairo_int_status_t
+_clip_to_traps (cairo_clip_t *clip,
+ cairo_traps_t *traps)
{
cairo_int_status_t status;
-
cairo_polygon_t polygon;
cairo_antialias_t antialias;
cairo_fill_rule_t fill_rule;
- if (! clip)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ _cairo_traps_init (traps);
- if (clip->num_boxes == 1 && ! clip->path)
- return _cairo_gl_msaa_compositor_draw_quad (ctx, setup,
- &clip->boxes[0]);
+ if (clip->num_boxes == 1 && clip->path == NULL) {
+ cairo_boxes_t boxes;
+ _cairo_boxes_init_for_array (&boxes, clip->boxes, clip->num_boxes);
+ return _cairo_traps_init_boxes (traps, &boxes);
+ }
- if (traps->num_traps == 0) {
- status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule,
- &antialias);
- if (unlikely (status))
- return status;
+ status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &antialias);
+ if (unlikely (status))
+ return status;
/* We ignore the antialias mode of the clip here, since the user requested
* unantialiased rendering of their path and we expect that this stencil
* antialiased polygon is open to interpretation. And we choose the fast
* option.
*/
- status = _cairo_bentley_ottmann_tessellate_polygon (traps,
- &polygon,
- fill_rule);
- _cairo_polygon_fini (&polygon);
- if (unlikely (status))
- return status;
- }
- status = _draw_traps (ctx, setup, traps);
+ _cairo_traps_init (traps);
+ status = _cairo_bentley_ottmann_tessellate_polygon (traps,
+ &polygon,
+ fill_rule);
+ _cairo_polygon_fini (&polygon);
+
+ return status;
+}
+
+cairo_int_status_t
+_cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
+ cairo_gl_composite_t *setup,
+ cairo_clip_t *clip)
+{
+ cairo_int_status_t status;
+ cairo_traps_t traps;
+ status = _clip_to_traps (clip, &traps);
+ if (unlikely (status))
+ return status;
+ status = _draw_traps (ctx, setup, &traps);
+
+ _cairo_traps_fini (&traps);
return status;
}
{
uint32_t is_bounded;
- if (_cairo_clip_is_all_clipped (composite->clip))
- return;
-
/* We don't need to check CAIRO_OPERATOR_BOUND_BY_MASK in these
situations. */
is_bounded = composite->is_bounded;
composite->is_bounded = is_bounded;
}
-static void
-_gl_pattern_fix_reference_count (const cairo_pattern_t *pattern)
-{
- cairo_pattern_type_t pattern_type = cairo_pattern_get_type ((cairo_pattern_t *)pattern);
-
- /* We need to increase reference count on surface and gradient if
- the original_source_pattern is a cairo_gl_source_t type. */
- if (pattern_type == CAIRO_PATTERN_TYPE_SURFACE) {
-
- cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)pattern;
- cairo_surface_t *pattern_surface = surface_pattern->surface;
-
- if (cairo_surface_get_type (pattern_surface) == CAIRO_SURFACE_TYPE_GL &&
- ! pattern_surface->device &&
- ! _cairo_surface_is_subsurface (pattern_surface)) {
-
- cairo_gl_source_t *_source = (cairo_gl_source_t *)pattern_surface;
-
- switch (_source->operand.type) {
- case CAIRO_GL_OPERAND_TEXTURE:
- cairo_surface_reference (&(_source->operand.texture.owns_surface)->base);
- break;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- _cairo_gl_gradient_reference (_source->operand.gradient.gradient);
- break;
- default:
- case CAIRO_GL_OPERAND_NONE:
- case CAIRO_GL_OPERAND_CONSTANT:
- case CAIRO_GL_OPERAND_COUNT:
- break;
- }
- }
- }
-}
-
-/* We use two passes to paint with SOURCE operator */
-/* The first pass, we use mask as source, to get dst1 = (1 - ma) * dst) with
- * DEST_OUT operator. In the second pass, we use ADD operator to achieve
- * result = (src * ma) + dst1. Combining two passes, we have
+/* Masking with the SOURCE operator requires two passes. In the first
+ * pass we use the mask as the source to get:
+ * result = (1 - ma) * dst
+ * In the second pass we use the add operator to achieve:
+ * result = (src * ma) + dst
+ * Combined this produces:
* result = (src * ma) + (1 - ma) * dst
*/
static cairo_int_status_t
cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
cairo_gl_context_t *ctx = NULL;
cairo_int_status_t status;
+
+ cairo_clip_t *clip = composite->clip;
cairo_traps_t traps;
- _cairo_traps_init (&traps);
+ /* If we have a non-rectangular clip, we can avoid using the stencil buffer
+ * for clipping and just draw the clip polygon. */
+ if (clip) {
+ status = _clip_to_traps (clip, &traps);
+ if (unlikely (status)) {
+ _cairo_traps_fini (&traps);
+ return status;
+ }
+ }
status = _cairo_gl_composite_init (&setup,
CAIRO_OPERATOR_DEST_OUT,
dst,
FALSE /* assume_component_alpha */);
if (unlikely (status))
- goto finish;
-
- _gl_pattern_fix_reference_count (composite->original_mask_pattern);
-
+ return status;
status = _cairo_gl_composite_set_source (&setup,
- &composite->mask_pattern.base,
+ composite->original_mask_pattern,
&composite->mask_sample_area,
&composite->bounded,
FALSE);
if (unlikely (status))
goto finish;
-
- status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE);
+ _cairo_gl_composite_set_multisample (&setup);
+ status = _cairo_gl_composite_begin (&setup, &ctx);
if (unlikely (status))
goto finish;
- if (! composite->clip)
+ if (! clip)
status = _draw_int_rect (ctx, &setup, &composite->bounded);
else
- status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, composite->clip, &traps);
+ status = _draw_traps (ctx, &setup, &traps);
- _cairo_gl_composite_fini (&setup);
- status = _cairo_gl_context_release (ctx, status);
- ctx = NULL;
- if (unlikely (status))
- return status;
-
- /* second pass */
- status = _cairo_gl_composite_init (&setup,
- CAIRO_OPERATOR_ADD,
- dst,
- FALSE /* assume_component_alpha */);
+ /* Now draw the second pass. */
+ _cairo_gl_composite_set_operator (&setup, CAIRO_OPERATOR_ADD,
+ FALSE /* assume_component_alpha */);
if (unlikely (status))
- goto finish;
-
- _gl_pattern_fix_reference_count (composite->original_source_pattern);
-
+ goto finish;
status = _cairo_gl_composite_set_source (&setup,
- &composite->source_pattern.base,
+ composite->original_source_pattern,
&composite->source_sample_area,
&composite->bounded,
FALSE);
if (unlikely (status))
goto finish;
-
status = _cairo_gl_composite_set_mask (&setup,
- &composite->mask_pattern.base,
+ composite->original_mask_pattern,
&composite->source_sample_area,
&composite->bounded);
if (unlikely (status))
goto finish;
-
- /* We always use multisampling here, because we do not yet have the smarts
- to calculate when the clip or the source requires it. */
- status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE);
+ status = _cairo_gl_set_operands_and_operator (&setup, ctx);
if (unlikely (status))
goto finish;
- if (! composite->clip)
+ if (! clip)
status = _draw_int_rect (ctx, &setup, &composite->bounded);
else
- status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, composite->clip, &traps);
+ status = _draw_traps (ctx, &setup, &traps);
finish:
- _cairo_traps_fini (&traps);
_cairo_gl_composite_fini (&setup);
-
if (ctx)
status = _cairo_gl_context_release (ctx, status);
+ if (clip)
+ _cairo_traps_fini (&traps);
return status;
}
cairo_gl_context_t *ctx = NULL;
cairo_int_status_t status;
cairo_operator_t op = composite->op;
- cairo_traps_t traps;
cairo_bool_t use_color_attribute = FALSE;
+ cairo_clip_t *clip = composite->clip;
if (! can_use_msaa_compositor (dst, CAIRO_ANTIALIAS_DEFAULT))
return CAIRO_INT_STATUS_UNSUPPORTED;
! _cairo_pattern_is_opaque (&composite->mask_pattern.base,
&composite->mask_sample_area)) {
- /* If the source is opaque the operation reduces to OVER. */
- if (_cairo_pattern_is_opaque (&composite->source_pattern.base,
- &composite->source_sample_area))
- op = CAIRO_OPERATOR_OVER;
- else
+ if (! _cairo_pattern_is_opaque (&composite->source_pattern.base,
+ &composite->source_sample_area)) {
return _cairo_gl_msaa_compositor_mask_source_operator (compositor, composite);
+ }
+
+ /* If the source is opaque the operation reduces to OVER. */
+ op = CAIRO_OPERATOR_OVER;
}
if (_should_use_unbounded_surface (composite)) {
dst,
FALSE /* assume_component_alpha */);
if (unlikely (status))
- goto finish;
-
- _gl_pattern_fix_reference_count (composite->original_source_pattern);
+ return status;
if (! composite->clip ||
(composite->clip->num_boxes == 1 && ! composite->clip->path))
/* We always use multisampling here, because we do not yet have the smarts
to calculate when the clip or the source requires it. */
- status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE);
+ _cairo_gl_composite_set_multisample (&setup);
+
+ status = _cairo_gl_composite_begin (&setup, &ctx);
if (unlikely (status))
goto finish;
- _cairo_traps_init (&traps);
-
- if (! composite->clip)
+ if (! clip)
status = _draw_int_rect (ctx, &setup, &composite->bounded);
else
- status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, composite->clip, &traps);
-
- _cairo_traps_fini (&traps);
+ status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, clip);
finish:
_cairo_gl_composite_fini (&setup);
}
static cairo_int_status_t
-_prevent_overlapping_drawing (cairo_gl_context_t *ctx,
+_prevent_overlapping_strokes (cairo_gl_context_t *ctx,
cairo_gl_composite_t *setup,
cairo_composite_rectangles_t *composite,
const cairo_path_fixed_t *path,
_cairo_pattern_is_opaque_solid (pattern))
return CAIRO_INT_STATUS_SUCCESS;
- if (glIsEnabled (GL_STENCIL_TEST) == FALSE) {
+ if (ctx->states_cache.stencil_test_enabled == FALSE) {
/* In case we have pending operations we have to flush before
adding the stencil buffer. */
_cairo_gl_composite_flush (ctx);
ctx->states_cache.depth_mask = TRUE;
}
glEnable (GL_STENCIL_TEST);
+ ctx->states_cache.stencil_test_enabled = TRUE;
- /* If we don't have clip, then we will setup clip extents based on
- approximate stroke extent. */
- if (! setup->clip) {
+ /* We scissor here so that we don't have to clear the entire stencil
+ * buffer. If the scissor test is already enabled, it was enabled
+ * for clipping. In that case, instead of calculating an intersection,
+ * we just reuse it, and risk clearing too much. */
+ if (ctx->states_cache.scissor_test_enabled == FALSE) {
_cairo_path_fixed_approximate_stroke_extents (path, style, ctm,
&stroke_extents);
- _cairo_gl_scissor_to_extents (setup->dst, &stroke_extents);
+ _cairo_gl_scissor_to_rectangle (setup->dst, &stroke_extents);
+ glEnable (GL_SCISSOR_TEST);
+ ctx->states_cache.scissor_test_enabled = TRUE;
}
-
glClearStencil (1);
glClear (GL_STENCIL_BUFFER_BIT);
+ _disable_scissor_buffer (ctx);
+
glStencilFunc (GL_EQUAL, 1, 1);
}
is disabled. */
glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO);
- /* we need to clean up clip cache */
- _cairo_clip_destroy (ctx->clip);
- ctx->clip = NULL;
+ _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
+ setup->dst->clip_on_stencil_buffer = NULL;
return CAIRO_INT_STATUS_SUCCESS;
}
goto finish;
_cairo_gl_msaa_compositor_set_clip (composite, &info.setup);
+ if (antialias != CAIRO_ANTIALIAS_NONE)
+ _cairo_gl_composite_set_multisample (&info.setup);
- status = _cairo_gl_composite_begin_multisample (&info.setup, &info.ctx,
- antialias != CAIRO_ANTIALIAS_NONE);
+ status = _cairo_gl_composite_begin (&info.setup, &info.ctx);
if (unlikely (status))
goto finish;
if (! (_is_continuous_arc (path, style) ||
_is_continuous_single_line (path, style))) {
- status = _prevent_overlapping_drawing (info.ctx, &info.setup,
- composite, path,
+ status = _prevent_overlapping_strokes (info.ctx, &info.setup,
+ composite, path,
style, ctm);
if (unlikely (status))
goto finish;
_cairo_traps_fini (&traps);
} else {
if (!_is_continuous_single_line (path, style)) {
- status = _prevent_overlapping_drawing (info.ctx, &info.setup,
- composite, path,
- style, ctm);
+ status = _prevent_overlapping_strokes (info.ctx, &info.setup,
+ composite, path, style, ctm);
if (unlikely (status))
goto finish;
}
}
static cairo_int_status_t
-_cairo_gl_msaa_compositor_fill_rectilinear (const cairo_compositor_t *compositor,
- cairo_composite_rectangles_t *composite,
- const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- cairo_clip_t *clip)
+_draw_simple_quad_path (cairo_gl_context_t *ctx,
+ cairo_gl_composite_t *setup,
+ const cairo_path_fixed_t *path)
{
- cairo_gl_composite_t setup;
- cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
- cairo_gl_context_t *ctx = NULL;
+ cairo_point_t triangle[3];
cairo_int_status_t status;
- int i;
-
- status = _cairo_gl_composite_init (&setup,
- composite->op,
- dst,
- FALSE /* assume_component_alpha */);
- if (unlikely (status))
- goto cleanup_setup;
-
- status = _cairo_gl_composite_set_source (&setup,
- composite->original_source_pattern,
- &composite->source_sample_area,
- &composite->bounded,
- TRUE);
- if (unlikely (status))
- goto cleanup_setup;
-
- status = _cairo_gl_composite_begin_multisample (&setup, &ctx,
- antialias != CAIRO_ANTIALIAS_NONE);
- if (unlikely (status))
- goto cleanup_setup;
-
- for (i = 0; i < clip->num_boxes; i++) {
- status = _cairo_gl_msaa_compositor_draw_quad (ctx, &setup,
- &clip->boxes[i]);
- if (unlikely (status))
- goto cleanup_setup;
- }
-
-cleanup_setup:
- _cairo_gl_composite_fini (&setup);
-
- if (ctx)
- status = _cairo_gl_context_release (ctx, status);
+ const cairo_point_t *points;
+
+ points = cairo_path_head (path)->points;
+ triangle[0] = points[0];
+ triangle[1] = points[1];
+ triangle[2] = points[2];
+ status = _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
+ if (status)
+ return status;
- return status;
+ triangle[0] = points[2];
+ triangle[1] = points[3];
+ triangle[2] = points[0];
+ return _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
}
static cairo_int_status_t
cairo_gl_composite_t setup;
cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
cairo_gl_context_t *ctx = NULL;
- cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
+ cairo_int_status_t status;
cairo_traps_t traps;
- cairo_bool_t use_color_attr = FALSE;
+ cairo_bool_t draw_path_with_traps;
if (! can_use_msaa_compositor (dst, antialias))
return CAIRO_INT_STATUS_UNSUPPORTED;
return _paint_back_unbounded_surface (compositor, composite, surface);
}
- if (_cairo_path_fixed_fill_is_rectilinear (path) &&
- composite->clip != NULL &&
- composite->clip->num_boxes == 1 &&
- composite->clip->path == NULL) {
- cairo_clip_t *clip = _cairo_clip_copy (composite->clip);
- clip = _cairo_clip_intersect_rectilinear_path (clip,
- path,
- fill_rule,
- antialias);
- if (clip->num_boxes)
- status = _cairo_gl_msaa_compositor_fill_rectilinear (compositor,
- composite,
- path,
- fill_rule,
- tolerance,
- antialias,
- clip);
- _cairo_clip_destroy (clip);
+ draw_path_with_traps = ! _cairo_path_fixed_is_simple_quad (path);
- return status;
+ if (draw_path_with_traps) {
+ _cairo_traps_init (&traps);
+ status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps);
+ if (unlikely (status))
+ goto cleanup_traps;
}
status = _cairo_gl_composite_init (&setup,
composite->op,
dst,
FALSE /* assume_component_alpha */);
- if (unlikely (status)) {
- _cairo_gl_composite_fini (&setup);
- return status;
- }
-
- _cairo_traps_init (&traps);
-
- if (_cairo_path_fixed_fill_is_rectilinear (path)) {
- status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
- fill_rule,
- antialias,
- &traps);
- use_color_attr = TRUE;
- } else
- status = _cairo_path_fixed_fill_to_traps (path, fill_rule,
- tolerance, &traps);
if (unlikely (status))
goto cleanup_traps;
composite->original_source_pattern,
&composite->source_sample_area,
&composite->bounded,
- use_color_attr);
+ !draw_path_with_traps);
if (unlikely (status))
goto cleanup_setup;
_cairo_gl_msaa_compositor_set_clip (composite, &setup);
+ if (antialias != CAIRO_ANTIALIAS_NONE)
+ _cairo_gl_composite_set_multisample (&setup);
- status = _cairo_gl_composite_begin_multisample (&setup, &ctx,
- antialias != CAIRO_ANTIALIAS_NONE);
+ status = _cairo_gl_composite_begin (&setup, &ctx);
if (unlikely (status))
goto cleanup_setup;
- status = _draw_traps (ctx, &setup, &traps);
+ if (! draw_path_with_traps)
+ status = _draw_simple_quad_path (ctx, &setup, path);
+ else
+ status = _draw_traps (ctx, &setup, &traps);
if (unlikely (status))
goto cleanup_setup;
status = _cairo_gl_context_release (ctx, status);
cleanup_traps:
- _cairo_traps_fini (&traps);
+ if (draw_path_with_traps)
+ _cairo_traps_fini (&traps);
return status;
}
#include "cairo-image-surface-private.h"
#include "cairo-surface-backend-private.h"
#include "cairo-surface-offset-private.h"
-#include "cairo-surface-snapshot-inline.h"
#include "cairo-surface-subsurface-inline.h"
#include "cairo-rtree-private.h"
cairo_gl_dispatch_t *dispatch;
cairo_gl_surface_t *cache_surface;
cairo_gl_surface_t *target;
+ cairo_surface_pattern_t pattern;
if (! _cairo_gl_surface_is_texture (image))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (replace)
_cairo_gl_composite_flush (ctx_out);
- /* Bind framebuffer of source image. */
+ image->needs_to_cache = FALSE;
dispatch = &ctx_out->dispatch;
cache_surface = ctx_out->image_cache.surface;
target = ctx_out->current_target;
- _cairo_gl_ensure_framebuffer (ctx_out, image);
- dispatch->BindFramebuffer (GL_FRAMEBUFFER, image->fb);
- glBindTexture (ctx_out->tex_target, cache_surface->tex);
+ /* paint image to dst */
+ _cairo_pattern_init_for_surface (&pattern, &image->base);
+ cairo_matrix_init_translate (&pattern.base.matrix, -x, -y);
- glCopyTexSubImage2D (ctx_out->tex_target, 0, x, y, 0, 0, width, height);
+ status = _cairo_surface_paint (&cache_surface->base,
+ CAIRO_OPERATOR_SOURCE,
+ &pattern.base, NULL);
+
+ _cairo_gl_composite_flush (ctx_out);
+ _cairo_pattern_fini (&pattern.base);
+
+ /* restore ctx status */
dispatch->BindFramebuffer (GL_FRAMEBUFFER, target->fb);
ctx_out->current_target = target;
*ctx = ctx_out;
- return CAIRO_INT_STATUS_SUCCESS;
+ if (unlikely (status))
+ return _cairo_gl_context_release (ctx_out, status);
+
+ return status;
}
static cairo_int_status_t
(*image_node)->p1.y /= IMAGE_CACHE_HEIGHT;
(*image_node)->p2.y /= IMAGE_CACHE_HEIGHT;
}
+ (*image_node)->user_data_removed = FALSE;
image->content_changed = FALSE;
/* Set user data. */
status = cairo_surface_set_user_data (&image->base,
_cairo_gl_surface_create_scratch (ctx,
sub->target->content,
sub->extents.width,
- sub->extents.height,
- FALSE);
-
+ sub->extents.height);
if (surface->base.status)
return _cairo_gl_context_release (ctx, surface->base.status);
}
surface = (cairo_gl_surface_t *) sub->target;
- if (surface->base.device &&
- (surface->base.device != dst->base.device ||
- (! surface->tex && ! surface->bounded_tex)))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (! _cairo_gl_surface_is_texture (surface))
+ if (surface->base.device && (surface->base.device != dst->base.device ||
+ (! _cairo_gl_surface_is_texture (surface) && ! surface->bounded_tex)))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _resolve_multisampling (surface);
if (_cairo_surface_is_subsurface (&surface->base))
return _cairo_gl_subsurface_operand_init (operand, _src, dst,
sample, extents);
- else if (_cairo_surface_is_snapshot (src->surface)) {
- cairo_surface_snapshot_t *surface_snapshot;
- cairo_pattern_t *sub_pattern;
-
- surface_snapshot = (cairo_surface_snapshot_t *)src->surface;
- surface = (cairo_gl_surface_t *)surface_snapshot->target;
- if (surface->base.type != CAIRO_SURFACE_TYPE_GL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (_cairo_surface_is_subsurface (&surface->base)) {
- sub_pattern = cairo_pattern_create_for_surface (&surface->base);
- status = _cairo_gl_subsurface_operand_init (operand,
- sub_pattern,
- dst,
- sample,
- extents);
- cairo_pattern_destroy (sub_pattern);
- return status;
- }
- }
- else
- return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
- if (surface->base.device &&
- (surface->base.device != dst->base.device ||
- (! surface->tex && ! surface->bounded_tex)))
+ if (surface->base.device && surface->base.device != dst->base.device)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (surface->base.device && ! _cairo_gl_surface_is_texture (surface) &&
+ ! surface->bounded_tex)
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _resolve_multisampling (surface);
cairo_gl_context_t *ctx;
cairo_image_surface_t *image;
cairo_bool_t src_is_gl_surface = FALSE;
- pixman_format_code_t pixman_format;
+ cairo_rectangle_int_t map_extents;
if (_src->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_t* src_surface = ((cairo_surface_pattern_t *) _src)->surface;
surface = (cairo_gl_surface_t *)
_cairo_gl_surface_create_scratch (ctx,
CAIRO_CONTENT_COLOR_ALPHA,
- extents->width, extents->height,
- FALSE);
-
- /* XXX: This is a hack for driver that does not support PBO, we
- don't need an extra step of downloading newly created texture
- to image, we can create image directly. */
- if (! _cairo_is_little_endian ())
- pixman_format = PIXMAN_r8g8b8a8;
- else
- pixman_format = PIXMAN_a8b8g8r8;
- image = (cairo_image_surface_t*)
- _cairo_image_surface_create_with_pixman_format (NULL,
- pixman_format,
- extents->width,
- extents->height,
- -1);
- if (unlikely (image->base.status)) {
- status = _cairo_gl_context_release (ctx, status);
-
- /* The error status in the image is issue that caused the problem. */
- status = image->base.status;
-
- cairo_surface_destroy (&image->base);
- goto fail;
- }
+ extents->width, extents->height);
+ map_extents = *extents;
+ map_extents.x = map_extents.y = 0;
+ image = _cairo_surface_map_to_image (&surface->base, &map_extents);
/* If the pattern is a GL surface, it belongs to some other GL context,
so we need to release this device while we paint it to the image. */
cairo_matrix_t m;
cairo_circle_double_t circles[2];
double x0, y0, r0, dx, dy, dr;
+ double scale = 1.0;
+ cairo_radial_pattern_t *radial_pattern = (cairo_radial_pattern_t *)gradient;
/*
* Some fragment shader implementations use half-floats to
_cairo_gradient_pattern_fit_to_range (gradient, 8.,
&operand->gradient.m, circles);
+ /*
+ * Instead of using scaled data that might introducing rounding
+ * errors, we use original data directly
+ */
+ if (circles[0].center.x)
+ scale = radial_pattern->cd1.center.x / circles[0].center.x;
+ else if (circles[0].center.y)
+ scale = radial_pattern->cd1.center.y / circles[0].center.y;
+ else if (circles[0].radius)
+ scale = radial_pattern->cd1.radius / circles[0].radius;
+ else if (circles[1].center.x)
+ scale = radial_pattern->cd2.center.x / circles[1].center.x;
+ else if (circles[1].center.y)
+ scale = radial_pattern->cd2.center.y / circles[1].center.y;
+ else if (circles[1].radius)
+ scale = radial_pattern->cd2.radius / circles[1].radius;
+
x0 = circles[0].center.x;
y0 = circles[0].center.y;
r0 = circles[0].radius;
- dx = circles[1].center.x - x0;
- dy = circles[1].center.y - y0;
- dr = circles[1].radius - r0;
+ dx = radial_pattern->cd2.center.x - radial_pattern->cd1.center.x;
+ dy = radial_pattern->cd2.center.y - radial_pattern->cd1.center.y;
+ dr = radial_pattern->cd2.radius - radial_pattern->cd1.radius;
- operand->gradient.a = dx * dx + dy * dy - dr * dr;
+ operand->gradient.a = (dx * dx + dy * dy - dr * dr)/(scale * scale);
operand->gradient.radius_0 = r0;
- operand->gradient.circle_d.center.x = dx;
- operand->gradient.circle_d.center.y = dy;
- operand->gradient.circle_d.radius = dr;
+ operand->gradient.circle_d.center.x = dx / scale;
+ operand->gradient.circle_d.center.y = dy / scale;
+ operand->gradient.circle_d.radius = dr / scale;
if (operand->gradient.a == 0)
operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0;
cairo_gl_operand_t *operand,
cairo_gl_tex_t tex_unit)
{
- char uniform_name[50];
- char *custom_part;
- static const char *names[] = { "source", "mask" };
-
- strcpy (uniform_name, names[tex_unit]);
- custom_part = uniform_name + strlen (names[tex_unit]);
+ cairo_gl_shader_slot_t slot = CAIRO_GL_SHADER_SLOT_SOURCE_CONSTANT;
switch (operand->type) {
default:
break;
case CAIRO_GL_OPERAND_CONSTANT:
if (!operand->use_color_attribute) {
- strcpy (custom_part, "_constant");
+ slot = tex_unit == CAIRO_GL_TEX_SOURCE ? CAIRO_GL_SHADER_SLOT_SOURCE_CONSTANT : CAIRO_GL_SHADER_SLOT_MASK_CONSTANT;
_cairo_gl_shader_bind_vec4 (ctx,
- uniform_name,
+ slot,
operand->constant.color[0],
operand->constant.color[1],
operand->constant.color[2],
break;
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- strcpy (custom_part, "_a");
+ slot = tex_unit == CAIRO_GL_TEX_SOURCE ? CAIRO_GL_SHADER_SLOT_SOURCE_A : CAIRO_GL_SHADER_SLOT_MASK_A;
_cairo_gl_shader_bind_float (ctx,
- uniform_name,
+ slot,
operand->gradient.a);
/* fall through */
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- strcpy (custom_part, "_circle_d");
- _cairo_gl_shader_bind_vec3 (ctx,
- uniform_name,
+ slot = tex_unit == CAIRO_GL_TEX_SOURCE ? CAIRO_GL_SHADER_SLOT_SOURCE_CIRCLE_D : CAIRO_GL_SHADER_SLOT_MASK_CIRCLE_D;
+ _cairo_gl_shader_bind_vec3 (ctx,
+ slot,
operand->gradient.circle_d.center.x,
operand->gradient.circle_d.center.y,
operand->gradient.circle_d.radius);
- strcpy (custom_part, "_radius_0");
- _cairo_gl_shader_bind_float (ctx,
- uniform_name,
- operand->gradient.radius_0);
+ slot = tex_unit == CAIRO_GL_TEX_SOURCE ? CAIRO_GL_SHADER_SLOT_SOURCE_RADIUS_0 : CAIRO_GL_SHADER_SLOT_MASK_RADIUS_0;
+ _cairo_gl_shader_bind_float (ctx,
+ slot,
+ operand->gradient.radius_0);
/* fall through */
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
case CAIRO_GL_OPERAND_TEXTURE:
width = operand->gradient.gradient->cache_entry.size,
height = 1;
}
- strcpy (custom_part, "_texdims");
- _cairo_gl_shader_bind_vec2 (ctx, uniform_name, width, height);
+ slot = tex_unit == CAIRO_GL_TEX_SOURCE ? CAIRO_GL_SHADER_SLOT_SOURCE_TEXDIMS : CAIRO_GL_SHADER_SLOT_MASK_TEXDIMS;
+ _cairo_gl_shader_bind_vec2 (ctx, slot, width, height);
}
break;
}
}
}
+void
+_cairo_gl_operand_emit (cairo_gl_operand_t *operand,
+ GLfloat ** vb,
+ GLfloat x,
+ GLfloat y)
+{
+ switch (operand->type) {
+ default:
+ case CAIRO_GL_OPERAND_COUNT:
+ ASSERT_NOT_REACHED;
+ case CAIRO_GL_OPERAND_NONE:
+ break;
+ case CAIRO_GL_OPERAND_CONSTANT: {
+ union fi {
+ float f;
+ GLbyte bytes[4];
+ } fi;
+ if (operand->use_color_attribute) {
+ fi.bytes[0] = operand->constant.color[0] * 255;
+ fi.bytes[1] = operand->constant.color[1] * 255;
+ fi.bytes[2] = operand->constant.color[2] * 255;
+ fi.bytes[3] = operand->constant.color[3] * 255;
+ *(*vb)++ = fi.f;
+ }
+ break;
+ }
+ case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+ {
+ double s = x;
+ double t = y;
+
+ cairo_matrix_transform_point (&operand->gradient.m, &s, &t);
+
+ *(*vb)++ = s;
+ *(*vb)++ = t;
+ }
+ break;
+ case CAIRO_GL_OPERAND_TEXTURE:
+ {
+ cairo_surface_attributes_t *src_attributes = &operand->texture.attributes;
+ double s = x;
+ double t = y;
+
+ cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
+ *(*vb)++ = s;
+ *(*vb)++ = t;
+
+ if (operand->texture.use_atlas) {
+ *(*vb)++ = operand->texture.p1.x;
+ *(*vb)++ = operand->texture.p1.y;
+ *(*vb)++ = operand->texture.p2.x;
+ *(*vb)++ = operand->texture.p2.y;
+ }
+ }
+ break;
+ }
+}
+
static inline cairo_int_status_t
_cairo_gl_context_get_image_cache (cairo_gl_context_t *ctx,
cairo_gl_image_cache_t **cache_out)
* Random number that is hopefully big enough to not cause many cache evictions. */
#define CAIRO_GL_MAX_SHADERS_PER_CONTEXT 64
-/* VBO size that we allocate, smaller size means we gotta flush more often */
-#define CAIRO_GL_VBO_SIZE (256*1024)
+/* VBO size that we allocate, smaller size means we gotta flush more often,
+ * but larger means hogging more memory and can cause trouble for drivers
+ * (especially on embedded devices). */
+#define CAIRO_GL_VBO_SIZE (16*1024)
#define IMAGE_CACHE_WIDTH 2048
#define IMAGE_CACHE_HEIGHT 2048
CAIRO_GL_FLAVOR_ES = 2
} cairo_gl_flavor_t;
+/* Shortcuts for shader uniform locations. Table filled lazily on first access.
+ * Using these slots saves per-draw calls to glGetUniformLocation(). */
+typedef enum cairo_gl_shader_slot_t {
+ /* "ModelViewProjectionMatrix" */
+ CAIRO_GL_SHADER_SLOT_MVPMAT = 0,
+ /* "source_texdims" */
+ CAIRO_GL_SHADER_SLOT_SOURCE_TEXDIMS,
+ /* "source_constant" */
+ CAIRO_GL_SHADER_SLOT_SOURCE_CONSTANT,
+ /* "source_sampler" */
+ CAIRO_GL_SHADER_SLOT_SOURCE_SAMPLER,
+ /* "source_a" */
+ CAIRO_GL_SHADER_SLOT_SOURCE_A,
+ /* "source_circle_d" */
+ CAIRO_GL_SHADER_SLOT_SOURCE_CIRCLE_D,
+ /* "source_radius_0" */
+ CAIRO_GL_SHADER_SLOT_SOURCE_RADIUS_0,
+ /* "mask_texdims" */
+ CAIRO_GL_SHADER_SLOT_MASK_TEXDIMS,
+ /* "mask_constant" */
+ CAIRO_GL_SHADER_SLOT_MASK_CONSTANT,
+ /* "mask_sampler" */
+ CAIRO_GL_SHADER_SLOT_MASK_SAMPLER,
+ /* "mask_a" */
+ CAIRO_GL_SHADER_SLOT_MASK_A,
+ /* "mask_circle_d" */
+ CAIRO_GL_SHADER_SLOT_MASK_CIRCLE_D,
+ /* "mask_radius_0" */
+ CAIRO_GL_SHADER_SLOT_MASK_RADIUS_0,
+
+ CAIRO_GL_SHADER_SLOT_MAX
+
+} cairo_gl_shader_slot_t;
+
+
/* Indices for vertex attributes used by BindAttribLocation etc */
enum {
CAIRO_GL_VERTEX_ATTRIB_INDEX = 0,
cairo_bool_t supports_msaa;
cairo_bool_t msaa_active; /* Whether the multisampling
framebuffer is active or not. */
+ cairo_clip_t *clip_on_stencil_buffer;
int owns_tex;
cairo_bool_t needs_update;
typedef struct cairo_gl_shader {
GLuint fragment_shader;
GLuint program;
+ /* Storage table for uniform locations.*/
+ GLint uniforms[CAIRO_GL_SHADER_SLOT_MAX];
+ /* Validity table for the above: initially set at 0, set to
+ * nonzero once corresponding item in uniforms is looked up. */
+ char uniforms_valid[CAIRO_GL_SHADER_SLOT_MAX];
} cairo_gl_shader_t;
typedef struct cairo_gl_image_cache {
CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS
} cairo_gl_primitive_type_t;
+typedef void (*cairo_gl_emit_rect_t) (cairo_gl_context_t *ctx,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2);
+
+typedef void (*cairo_gl_emit_span_t) (cairo_gl_context_t *ctx,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2,
+ uint8_t alpha);
+
+typedef void (*cairo_gl_emit_glyph_t) (cairo_gl_context_t *ctx,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2,
+ GLfloat glyph_x1, GLfloat glyph_y1,
+ GLfloat glyph_x2, GLfloat glyph_y2);
+
#define cairo_gl_var_type_hash(src,mask,src_atlas_extend,mask_atlas_extend,src_use_atlas,mask_use_atlas, spans,dest) ((spans) << 11) | ((mask) << 9 | (src << 7) | (mask_atlas_extend << 5) | (src_atlas_extend << 3) | (mask_use_atlas << 2) | (src_use_atlas << 1) | (dest))
#define CAIRO_GL_VAR_TYPE_MAX ((CAIRO_GL_VAR_TEXCOORDS << 11) | (CAIRO_GL_VAR_TEXCOORDS << 9) | (CAIRO_GL_VAR_TEXCOORDS << 5) | CAIRO_GL_VAR_TEXCOORDS)
cairo_bool_t depth_mask;
+ cairo_bool_t scissor_test_enabled;
+ cairo_bool_t stencil_test_enabled;
+
} cairo_gl_states_t;
struct _cairo_gl_context {
cairo_bool_t has_map_buffer;
cairo_bool_t has_packed_depth_stencil;
cairo_bool_t has_npot_repeat;
+ cairo_bool_t can_read_bgra;
cairo_bool_t thread_aware;
- /* GL stencil and depth buffers are shared among all surfaces
- to preserve memory. In the future this could be a pool of renderbuffers
- with an eviction policy. */
- GLuint shared_depth_stencil;
- int shared_depth_stencil_width;
- int shared_depth_stencil_height;
- GLuint shared_msaa_depth_stencil;
- int shared_msaa_depth_stencil_width;
- int shared_msaa_depth_stencil_height;
-
cairo_gl_image_cache_t image_cache;
cairo_gl_draw_mode_t draw_mode;
cairo_gl_states_t states_cache;
cairo_bool_t spans;
cairo_clip_t *clip;
+ cairo_bool_t multisample;
} cairo_gl_composite_t;
typedef struct _cairo_gl_font {
cairo_gl_surface_t *surface,
cairo_bool_t multisampling);
+cairo_private cairo_gl_emit_rect_t
+_cairo_gl_context_choose_emit_rect (cairo_gl_context_t *ctx);
+
+cairo_private void
+_cairo_gl_context_emit_rect (cairo_gl_context_t *ctx,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2);
+
+cairo_private cairo_gl_emit_span_t
+_cairo_gl_context_choose_emit_span (cairo_gl_context_t *ctx);
+
+cairo_private cairo_gl_emit_glyph_t
+_cairo_gl_context_choose_emit_glyph (cairo_gl_context_t *ctx);
+
cairo_private void
_cairo_gl_context_activate (cairo_gl_context_t *ctx,
cairo_gl_tex_t tex_unit);
_cairo_gl_ensure_stencil (cairo_gl_context_t *ctx,
cairo_gl_surface_t *surface);
-cairo_private void
-_disable_scissor_buffer (void);
+static cairo_always_inline void
+_disable_stencil_buffer (cairo_gl_context_t *ctx)
+{
+ if (ctx->states_cache.stencil_test_enabled == TRUE) {
+ glDisable (GL_STENCIL_TEST);
+ ctx->states_cache.stencil_test_enabled = FALSE;
+ }
+}
-cairo_private void
-_disable_stencil_buffer (void);
+static cairo_always_inline void
+_disable_scissor_buffer (cairo_gl_context_t *ctx)
+{
+ if (ctx->states_cache.scissor_test_enabled == TRUE) {
+ glDisable (GL_SCISSOR_TEST);
+ ctx->states_cache.scissor_test_enabled = FALSE;
+ }
+}
+
+static cairo_always_inline void
+_enable_stencil_buffer (cairo_gl_context_t *ctx)
+{
+ if (ctx->states_cache.stencil_test_enabled == FALSE) {
+ glEnable (GL_STENCIL_TEST);
+ ctx->states_cache.stencil_test_enabled = TRUE;
+ }
+}
+
+static cairo_always_inline void
+_enable_scissor_buffer (cairo_gl_context_t *ctx)
+{
+ if (ctx->states_cache.scissor_test_enabled == FALSE) {
+ glEnable (GL_SCISSOR_TEST);
+ ctx->states_cache.scissor_test_enabled = TRUE;
+ }
+}
cairo_private cairo_status_t
_cairo_gl_composite_init (cairo_gl_composite_t *setup,
cairo_private void
_cairo_gl_composite_fini (cairo_gl_composite_t *setup);
+cairo_status_t
+_cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
+ cairo_operator_t op,
+ cairo_bool_t assume_component_alpha);
+
cairo_private void
_cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
cairo_region_t *clip_region);
cairo_private void
_cairo_gl_composite_set_spans (cairo_gl_composite_t *setup);
+cairo_private void
+_cairo_gl_composite_set_multisample (cairo_gl_composite_t *setup);
+
cairo_private cairo_status_t
_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
cairo_gl_context_t **ctx);
-cairo_private cairo_status_t
-_cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
- cairo_gl_context_t **ctx_out,
- cairo_bool_t multisampling);
-
-cairo_private void
-_cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
- GLfloat x1,
- GLfloat y1,
- GLfloat x2,
- GLfloat y2,
- uint8_t alpha);
-
-cairo_private void
-_cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
- GLfloat x1,
- GLfloat y1,
- GLfloat x2,
- GLfloat y2,
- GLfloat glyph_x1,
- GLfloat glyph_y1,
- GLfloat glyph_x2,
- GLfloat glyph_y2);
+cairo_status_t
+_cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup,
+ cairo_gl_context_t *ctx);
cairo_private void
_cairo_gl_composite_flush (cairo_gl_context_t *ctx);
cairo_private void
_cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
- const char *name,
+ cairo_gl_shader_slot_t slot,
float value);
cairo_private void
+_cairo_gl_shader_bind_float_name (cairo_gl_context_t *ctx,
+ const char *name,
+ float value);
+
+cairo_private void
_cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
- const char *name,
- float value0, float value1);
+ cairo_gl_shader_slot_t slot,
+ float value0,
+ float value1);
+
+cairo_private void
+_cairo_gl_shader_bind_vec2_name (cairo_gl_context_t *ctx,
+ const char *name,
+ float value0,
+ float value1);
cairo_private void
_cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
+ cairo_gl_shader_slot_t slot,
+ float value0,
+ float value1,
+ float value2);
+
+cairo_private void
+_cairo_gl_shader_bind_vec3_name (cairo_gl_context_t *ctx,
const char *name,
float value0,
float value1,
cairo_private void
_cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
+ cairo_gl_shader_slot_t slot,
+ float value0, float value1,
+ float value2, float value3);
+
+cairo_private void
+_cairo_gl_shader_bind_vec4_name (cairo_gl_context_t *ctx,
const char *name,
float value0, float value1,
float value2, float value3);
cairo_private void
_cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
+ cairo_gl_shader_slot_t slot,
+ cairo_matrix_t* m);
+
+cairo_private void
+_cairo_gl_shader_bind_matrix_name (cairo_gl_context_t *ctx,
const char *name,
cairo_matrix_t* m);
cairo_private void
_cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx,
+ cairo_gl_shader_slot_t slot,
+ GLfloat* gl_m);
+
+cairo_private void
+_cairo_gl_shader_bind_matrix4f_name (cairo_gl_context_t *ctx,
const char *name,
GLfloat* gl_m);
cairo_gl_tex_t tex_unit);
cairo_private void
+_cairo_gl_operand_emit (cairo_gl_operand_t *operand,
+ GLfloat ** vb,
+ GLfloat x,
+ GLfloat y);
+
+cairo_private void
_cairo_gl_operand_copy (cairo_gl_operand_t *dst,
const cairo_gl_operand_t *src);
_cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
cairo_content_t content,
int width,
- int height,
- cairo_bool_t true_alpha);
+ int height);
+
+cairo_private cairo_surface_t *
+_cairo_gl_surface_create_scratch_for_caching (cairo_gl_context_t *ctx,
+ cairo_content_t content,
+ int width,
+ int height);
cairo_private cairo_surface_t *
_cairo_gl_pattern_to_source (cairo_surface_t *dst,
cairo_private cairo_int_status_t
_cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
cairo_gl_composite_t *setup,
- cairo_clip_t *clip,
- cairo_traps_t *traps);
+ cairo_clip_t *clip);
cairo_private cairo_surface_t *
_cairo_gl_white_source (void);
+cairo_private void
+_cairo_gl_scissor_to_rectangle (cairo_gl_surface_t *surface,
+ const cairo_rectangle_int_t *r);
+
static inline cairo_gl_operand_t *
source_to_operand (cairo_surface_t *surface)
{
_cairo_rtree_unpin (&cache->rtree);
}
-cairo_private void
-_cairo_gl_scissor_to_extents (cairo_gl_surface_t *surface,
- const cairo_rectangle_int_t *extents);
cairo_private cairo_bool_t
#include "cairo-error-private.h"
#include "cairo-output-stream-private.h"
+/* Lookup table of shader slot names, must be in same order as cairo_gl_shader_t enum. */
+static const char * _cairo_gl_shader_slot_names[CAIRO_GL_SHADER_SLOT_MAX] =
+{
+ "ModelViewProjectionMatrix",
+ "source_texdims",
+ "source_constant",
+ "source_sampler",
+ "source_a",
+ "source_circle_d",
+ "source_radius_0",
+ "mask_texdims",
+ "mask_constant",
+ "mask_sampler",
+ "mask_a",
+ "mask_circle_d",
+ "mask_radius_0"
+};
+
+static GLint _cairo_gl_lookup_shader_uniform(cairo_gl_context_t *ctx, cairo_gl_shader_t *shader, cairo_gl_shader_slot_t slot)
+{
+ if(shader->uniforms_valid[slot] == 0)
+ {
+ shader->uniforms[slot] = ctx->dispatch.GetUniformLocation (shader->program, _cairo_gl_shader_slot_names[slot]);
+ shader->uniforms_valid[slot] = 1;
+ }
+ return shader->uniforms[slot];
+}
+
+
static cairo_status_t
_cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx,
cairo_gl_shader_t *shader,
{
shader->fragment_shader = 0;
shader->program = 0;
+ memset (shader->uniforms, 0, sizeof (shader->uniforms));
+ memset (shader->uniforms_valid, 0, sizeof (shader->uniforms_valid));
}
cairo_status_t
glGetIntegerv (GL_CURRENT_PROGRAM, &saved_program);
dispatch->UseProgram (shader->program);
- location = dispatch->GetUniformLocation (shader->program, "source_sampler");
+ location = _cairo_gl_lookup_shader_uniform (ctx, shader, CAIRO_GL_SHADER_SLOT_SOURCE_SAMPLER);
if (location != -1) {
dispatch->Uniform1i (location, CAIRO_GL_TEX_SOURCE);
}
- location = dispatch->GetUniformLocation (shader->program, "mask_sampler");
+ location = _cairo_gl_lookup_shader_uniform (ctx, shader, CAIRO_GL_SHADER_SLOT_MASK_SAMPLER);
if (location != -1) {
dispatch->Uniform1i (location, CAIRO_GL_TEX_MASK);
}
void
_cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
+ cairo_gl_shader_slot_t slot,
+ float value)
+{
+ cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+ GLint location = _cairo_gl_lookup_shader_uniform (ctx, ctx->current_shader, slot);
+ assert (location != -1);
+ dispatch->Uniform1f (location, value);
+}
+
+void
+_cairo_gl_shader_bind_float_name (cairo_gl_context_t *ctx,
const char *name,
float value)
{
void
_cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
+ cairo_gl_shader_slot_t slot,
+ float value0,
+ float value1)
+{
+ cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+ GLint location = _cairo_gl_lookup_shader_uniform (ctx, ctx->current_shader, slot);
+ assert (location != -1);
+ dispatch->Uniform2f (location, value0, value1);
+}
+
+void
+_cairo_gl_shader_bind_vec2_name (cairo_gl_context_t *ctx,
const char *name,
float value0,
float value1)
void
_cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
+ cairo_gl_shader_slot_t slot,
+ float value0,
+ float value1,
+ float value2)
+{
+ cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+ GLint location = _cairo_gl_lookup_shader_uniform (ctx, ctx->current_shader, slot);
+ assert (location != -1);
+ dispatch->Uniform3f (location, value0, value1, value2);
+}
+
+void
+_cairo_gl_shader_bind_vec3_name (cairo_gl_context_t *ctx,
const char *name,
float value0,
float value1,
void
_cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
+ cairo_gl_shader_slot_t slot,
+ float value0, float value1,
+ float value2, float value3)
+{
+ cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+ GLint location = _cairo_gl_lookup_shader_uniform (ctx, ctx->current_shader, slot);
+ assert (location != -1);
+ dispatch->Uniform4f (location, value0, value1, value2, value3);
+}
+
+void
+_cairo_gl_shader_bind_vec4_name (cairo_gl_context_t *ctx,
const char *name,
float value0, float value1,
float value2, float value3)
void
_cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
+ cairo_gl_shader_slot_t slot, cairo_matrix_t* m)
+{
+ cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+ GLint location = _cairo_gl_lookup_shader_uniform (ctx, ctx->current_shader, slot);
+
+ float gl_m[9] = {
+ m->xx, m->xy, m->x0,
+ m->yx, m->yy, m->y0,
+ 0, 0, 1};
+ assert (location != -1);
+ dispatch->UniformMatrix3fv (location, 1, GL_TRUE, gl_m);
+}
+
+void
+_cairo_gl_shader_bind_matrix_name (cairo_gl_context_t *ctx,
const char *name, cairo_matrix_t* m)
{
cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
float gl_m[9] = {
m->xx, m->xy, m->x0,
m->yx, m->yy, m->y0,
- 0, 0, 1
- };
+ 0, 0, 1};
assert (location != -1);
dispatch->UniformMatrix3fv (location, 1, GL_TRUE, gl_m);
}
void
_cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx,
+ cairo_gl_shader_slot_t slot, GLfloat* gl_m)
+{
+ cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+ GLint location = _cairo_gl_lookup_shader_uniform (ctx, ctx->current_shader, slot);
+ assert (location != -1);
+ dispatch->UniformMatrix4fv (location, 1, GL_FALSE, gl_m);
+}
+
+void
+_cairo_gl_shader_bind_matrix4f_name (cairo_gl_context_t *ctx,
const char *name, GLfloat* gl_m)
{
cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
cairo_gl_composite_t setup;
double opacity;
+ cairo_gl_emit_span_t emit;
+
int xmin, xmax;
int ymin, ymax;
unsigned num_spans)
{
cairo_gl_span_renderer_t *r = abstract_renderer;
+ cairo_gl_emit_span_t emit = r->emit;
if (num_spans == 0)
return CAIRO_STATUS_SUCCESS;
do {
if (spans[0].coverage) {
- _cairo_gl_composite_emit_rect (r->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- spans[0].coverage);
+ emit (r->ctx,
+ spans[0].x, y,
+ spans[1].x, y + height,
+ spans[0].coverage);
}
spans++;
unsigned num_spans)
{
cairo_gl_span_renderer_t *r = abstract_renderer;
+ cairo_gl_emit_span_t emit = r->emit;
if (num_spans == 0)
return CAIRO_STATUS_SUCCESS;
do {
if (spans[0].coverage) {
- _cairo_gl_composite_emit_rect (r->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- r->opacity * spans[0].coverage);
+ emit (r->ctx,
+ spans[0].x, y,
+ spans[1].x, y + height,
+ r->opacity * spans[0].coverage);
}
spans++;
unsigned num_spans)
{
cairo_gl_span_renderer_t *r = abstract_renderer;
+ cairo_gl_emit_span_t emit = r->emit;
if (y > r->ymin) {
- _cairo_gl_composite_emit_rect (r->ctx,
- r->xmin, r->ymin,
- r->xmax, y,
- 0);
+ emit (r->ctx,
+ r->xmin, r->ymin,
+ r->xmax, y,
+ 0);
}
if (num_spans == 0) {
- _cairo_gl_composite_emit_rect (r->ctx,
- r->xmin, y,
- r->xmax, y + height,
- 0);
+ emit (r->ctx,
+ r->xmin, y,
+ r->xmax, y + height,
+ 0);
} else {
if (spans[0].x != r->xmin) {
- _cairo_gl_composite_emit_rect (r->ctx,
- r->xmin, y,
- spans[0].x, y + height,
- 0);
+ emit (r->ctx,
+ r->xmin, y,
+ spans[0].x, y + height,
+ 0);
}
do {
- _cairo_gl_composite_emit_rect (r->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- r->opacity * spans[0].coverage);
+ emit (r->ctx,
+ spans[0].x, y,
+ spans[1].x, y + height,
+ r->opacity * spans[0].coverage);
spans++;
} while (--num_spans > 1);
if (spans[0].x != r->xmax) {
- _cairo_gl_composite_emit_rect (r->ctx,
- spans[0].x, y,
- r->xmax, y + height,
- 0);
+ emit (r->ctx,
+ spans[0].x, y,
+ r->xmax, y + height,
+ 0);
}
}
unsigned num_spans)
{
cairo_gl_span_renderer_t *r = abstract_renderer;
+ cairo_gl_emit_span_t emit = r->emit;
if (y > r->ymin) {
- _cairo_gl_composite_emit_rect (r->ctx,
- r->xmin, r->ymin,
- r->xmax, y,
- 0);
+ emit (r->ctx,
+ r->xmin, r->ymin,
+ r->xmax, y,
+ 0);
}
if (num_spans == 0) {
- _cairo_gl_composite_emit_rect (r->ctx,
- r->xmin, y,
- r->xmax, y + height,
- 0);
+ emit (r->ctx,
+ r->xmin, y,
+ r->xmax, y + height,
+ 0);
} else {
if (spans[0].x != r->xmin) {
- _cairo_gl_composite_emit_rect (r->ctx,
- r->xmin, y,
- spans[0].x, y + height,
- 0);
+ emit (r->ctx,
+ r->xmin, y,
+ spans[0].x, y + height,
+ 0);
}
do {
- _cairo_gl_composite_emit_rect (r->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- r->opacity * spans[0].coverage);
+ emit (r->ctx,
+ spans[0].x, y,
+ spans[1].x, y + height,
+ r->opacity * spans[0].coverage);
spans++;
} while (--num_spans > 1);
if (spans[0].x != r->xmax) {
- _cairo_gl_composite_emit_rect (r->ctx,
- spans[0].x, y,
- r->xmax, y + height,
- 0);
+ emit (r->ctx,
+ spans[0].x, y,
+ r->xmax, y + height,
+ 0);
}
}
_cairo_gl_finish_unbounded_spans (void *abstract_renderer)
{
cairo_gl_span_renderer_t *r = abstract_renderer;
+ cairo_gl_emit_span_t emit = r->emit;
if (r->ymax > r->ymin) {
- _cairo_gl_composite_emit_rect (r->ctx,
- r->xmin, r->ymin,
- r->xmax, r->ymax,
- 0);
+ emit (r->ctx,
+ r->xmin, r->ymin,
+ r->xmax, r->ymax,
+ 0);
}
return _cairo_gl_context_release (r->ctx, CAIRO_STATUS_SUCCESS);
const cairo_boxes_t *boxes)
{
const struct _cairo_boxes_chunk *chunk;
+ cairo_gl_emit_rect_t emit = _cairo_gl_context_choose_emit_rect (ctx);
int i;
TRACE ((stderr, "%s: num_boxes=%d\n", __FUNCTION__, boxes->num_boxes));
int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
- _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2, 255);
+ emit (ctx, x1, y1, x2, y2);
}
}
}
struct _cairo_boxes_chunk *chunk;
int i;
+ if (_cairo_gl_surface_is_texture (dst))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
cairo_box_t *b = &chunk->base[i];
if (unlikely (status))
goto FAIL;
+ r->emit = _cairo_gl_context_choose_emit_span (r->ctx);
if (composite->is_bounded) {
if (r->opacity == 1.)
r->base.render_rows = _cairo_gl_bounded_opaque_spans;
return &surface->base;
}
-cairo_surface_t *
-_cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
- cairo_content_t content,
- int width,
- int height,
- cairo_bool_t true_alpha)
+static cairo_surface_t *
+_create_scratch_internal (cairo_gl_context_t *ctx,
+ cairo_content_t content,
+ int width,
+ int height,
+ cairo_bool_t for_caching)
{
cairo_gl_surface_t *surface;
GLenum format;
format = GL_RGBA;
break;
case CAIRO_CONTENT_ALPHA:
- /* We want to be trying GL_ALPHA framebuffer objects here. */
- if (true_alpha)
+ /* When using GL_ALPHA, compositing doesn't work properly, but for
+ * caching surfaces, we are just uploading pixel data, so it isn't
+ * an issue. */
+ if (for_caching)
format = GL_ALPHA;
else
format = GL_RGBA;
return &surface->base;
}
+cairo_surface_t *
+_cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ return _create_scratch_internal (ctx, content, width, height, FALSE);
+}
+
+cairo_surface_t *
+_cairo_gl_surface_create_scratch_for_caching (cairo_gl_context_t *ctx,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ return _create_scratch_internal (ctx, content, width, height, TRUE);
+}
+
static cairo_status_t
_cairo_gl_surface_clear (cairo_gl_surface_t *surface,
const cairo_color_t *color)
a = 1.0;
}
+ _disable_scissor_buffer (ctx);
if (ctx->states_cache.clear_red != r ||
ctx->states_cache.clear_green != g ||
ctx->states_cache.clear_blue != b ||
glClearColor (r, g, b, a);
}
-
- _disable_scissor_buffer ();
glClear (GL_COLOR_BUFFER_BIT);
+ if (a == 0)
+ surface->base.is_clear = TRUE;
+
surface->content_changed = TRUE;
return _cairo_gl_context_release (ctx, status);
}
+static cairo_surface_t *
+_cairo_gl_surface_create_and_clear_scratch (cairo_gl_context_t *ctx,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ cairo_gl_surface_t *surface;
+ cairo_int_status_t status;
+
+ surface = (cairo_gl_surface_t *)
+ _cairo_gl_surface_create_scratch (ctx, content, width, height);
+ if (unlikely (surface->base.status))
+ return &surface->base;
+
+ /* Cairo surfaces start out initialized to transparent (black) */
+ status = _cairo_gl_surface_clear (surface, CAIRO_COLOR_TRANSPARENT);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&surface->base);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ return &surface->base;
+}
+
cairo_surface_t *
cairo_gl_surface_create (cairo_device_t *abstract_device,
cairo_content_t content,
return _cairo_surface_create_in_error (status);
surface = (cairo_gl_surface_t *)
- _cairo_gl_surface_create_scratch (ctx, content, width, height, FALSE);
+ _cairo_gl_surface_create_and_clear_scratch (ctx, content, width, height);
if (unlikely (surface->base.status)) {
status = _cairo_gl_context_release (ctx, surface->base.status);
cairo_surface_destroy (&surface->base);
return _cairo_surface_create_in_error (status);
}
- /* Cairo surfaces start out initialized to transparent (black) */
- status = _cairo_gl_surface_clear (surface, CAIRO_COLOR_TRANSPARENT);
-
status = _cairo_gl_context_release (ctx, status);
if (unlikely (status)) {
cairo_surface_destroy (&surface->base);
if (unlikely (status))
return _cairo_surface_create_in_error (status);
- surface = _cairo_gl_surface_create_scratch (ctx, content, width,
- height, FALSE);
+ surface = _cairo_gl_surface_create_and_clear_scratch (ctx, content, width, height);
status = _cairo_gl_context_release (ctx, status);
if (unlikely (status)) {
if (unlikely (status))
goto CLEANUP;
- _cairo_gl_composite_emit_rect (ctx, x, y, x + width, y + height, 0);
+ _cairo_gl_context_emit_rect (ctx, x, y, x + width, y + height);
status = _cairo_gl_context_release (ctx, status);
tmp = _cairo_gl_surface_create_scratch (ctx,
dst->base.content,
- width, height, FALSE);
+ width, height);
if (unlikely (tmp->status))
goto FAIL;
if (surface->fb)
ctx->dispatch.DeleteFramebuffers (1, &surface->fb);
+ if (surface->depth_stencil)
+ ctx->dispatch.DeleteRenderbuffers (1, &surface->depth_stencil);
if (surface->owns_tex)
glDeleteTextures (1, &surface->tex);
#if CAIRO_HAS_GL_SURFACE
+ if (surface->msaa_depth_stencil)
+ ctx->dispatch.DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
if (surface->msaa_fb)
ctx->dispatch.DeleteFramebuffers (1, &surface->msaa_fb);
if (surface->msaa_rb)
cairo_status_t status;
int y;
+ status = _cairo_gl_context_acquire (surface->base.device, &ctx);
+ if (unlikely (status)) {
+ return _cairo_image_surface_create_in_error (status);
+ }
+
/* Want to use a switch statement here but the compiler gets whiny. */
if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) {
format = GL_BGRA;
return NULL;
}
- /*
- * GLES2 supports only RGBA, UNSIGNED_BYTE so use that.
- * We are also using this format for ALPHA as GLES2 does not
- * support GL_PACK_ROW_LENGTH anyway, and this makes sure that the
- * pixman image that is created has row_stride = row_width * bpp.
- */
if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES) {
- format = GL_RGBA;
- if (! _cairo_is_little_endian ()) {
- if (surface->base.content == CAIRO_CONTENT_COLOR)
- pixman_format = PIXMAN_r8g8b8x8;
- else
- pixman_format = PIXMAN_r8g8b8a8;
- } else {
- if (surface->base.content == CAIRO_CONTENT_COLOR)
- pixman_format = PIXMAN_x8b8g8r8;
- else
- pixman_format = PIXMAN_a8b8g8r8;
+ /* If only RGBA is supported, we must download data in a compatible
+ * format. This means that pixman will convert the data on the CPU when
+ * interacting with other image surfaces. For ALPHA, GLES2 does not
+ * support GL_PACK_ROW_LENGTH anyway, and this makes sure that the
+ * pixman image that is created has row_stride = row_width * bpp. */
+ if (surface->base.content == CAIRO_CONTENT_ALPHA || !ctx->can_read_bgra) {
+ cairo_bool_t little_endian = _cairo_is_little_endian ();
+ format = GL_RGBA;
+
+ if (surface->base.content == CAIRO_CONTENT_COLOR) {
+ pixman_format = little_endian ?
+ PIXMAN_x8b8g8r8 : PIXMAN_r8g8b8x8;
+ } else {
+ pixman_format = little_endian ?
+ PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8;
+ }
}
+
+ /* GLES2 only supports GL_UNSIGNED_BYTE. */
type = GL_UNSIGNED_BYTE;
cpp = 4;
}
extents->width,
extents->height,
-1);
- if (unlikely (image->base.status))
- return image;
-
- if (surface->base.serial == 0)
+ if (unlikely (image->base.status)) {
+ status = _cairo_gl_context_release (ctx, status);
return image;
-
- status = _cairo_gl_context_acquire (surface->base.device, &ctx);
- if (unlikely (status)) {
- cairo_surface_destroy (&image->base);
- return _cairo_image_surface_create_in_error (status);
}
cairo_surface_set_device_offset (&image->base, -extents->x, -extents->y);
+ /* If the original surface has not been modified or
+ * is clear, we can avoid downloading data. */
+ if (surface->base.is_clear || surface->base.serial == 0) {
+ status = _cairo_gl_context_release (ctx, status);
+ return image;
+ }
+
/* This is inefficient, as we'd rather just read the thing without making
* it the destination. But then, this is the fallback path, so let's not
* fall back instead.
#include "cairo-image-surface-private.h"
#include "cairo-spans-compositor-private.h"
#include "cairo-surface-backend-private.h"
+#include "cairo-surface-offset-private.h"
static cairo_int_status_t
acquire (void *abstract_dst)
struct _cairo_boxes_chunk *chunk;
int i;
+ if (_cairo_gl_surface_is_texture (dst))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
cairo_box_t *b = &chunk->base[i];
const cairo_boxes_t *boxes)
{
const struct _cairo_boxes_chunk *chunk;
+ cairo_gl_emit_rect_t emit = _cairo_gl_context_choose_emit_rect (ctx);
int i;
for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
- _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2, 0);
+ emit (ctx, x1, y1, x2, y2);
}
}
}
goto FAIL;
/* XXX clip */
- _cairo_gl_composite_emit_rect (ctx, dst_x, dst_y, dst_x+width, dst_y+height, 0);
+ _cairo_gl_context_emit_rect (ctx, dst_x, dst_y, dst_x+width, dst_y+height);
status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
FAIL:
return image->status;
}
+ /* GLES2 only supports RGB/RGBA when uploading */
+ if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES) {
+ cairo_surface_pattern_t pattern;
+ cairo_surface_t *rgba_image;
+
+ /* XXX perform this fixup inside _cairo_gl_draw_image() */
+
+ rgba_image =
+ _cairo_image_surface_create_with_pixman_format (NULL,
+ _cairo_is_little_endian () ? PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8,
+ extents->width,
+ extents->height,
+ 0);
+ if (unlikely (rgba_image->status))
+ return rgba_image->status;
+
+ _cairo_pattern_init_for_surface (&pattern, image);
+ status = _cairo_surface_paint (rgba_image, CAIRO_OPERATOR_SOURCE,
+ &pattern.base, NULL);
+ _cairo_pattern_fini (&pattern.base);
+
+ cairo_surface_destroy (image);
+ image = rgba_image;
+
+ if (unlikely (status)) {
+ cairo_surface_destroy (image);
+ return status;
+ }
+ }
+
mask = _cairo_surface_create_similar_scratch (_dst,
CAIRO_CONTENT_COLOR_ALPHA,
extents->width,
extents->width, extents->height,
0, 0);
cairo_surface_destroy (image);
+
if (unlikely (status))
goto error;
goto FAIL;
/* XXX clip */
- _cairo_gl_composite_emit_rect (ctx,
- extents->x-dst_x, extents->y-dst_y,
- extents->x-dst_x+extents->width,
- extents->y-dst_y+extents->height, 0);
+ _cairo_gl_context_emit_rect (ctx,
+ extents->x-dst_x, extents->y-dst_y,
+ extents->x-dst_x+extents->width,
+ extents->y-dst_y+extents->height);
status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
FAIL:
goto FAIL;
/* XXX clip */
- _cairo_gl_composite_emit_rect (ctx,
- dst_x, dst_y,
- dst_x+extents->width,
- dst_y+extents->height, 0);
+ _cairo_gl_context_emit_rect (ctx,
+ dst_x, dst_y,
+ dst_x+extents->width,
+ dst_y+extents->height);
status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
FAIL:
Window dummy_window;
GLXContext context;
- Display *previous_display;
- GLXDrawable previous_drawable;
GLXContext previous_context;
cairo_bool_t has_multithread_makecurrent;
} cairo_glx_surface_t;
static cairo_bool_t
-_context_acquisition_changed_glx_state (cairo_glx_context_t *ctx,
- GLXDrawable current_drawable)
+_context_acquisition_changed_glx_state (cairo_glx_context_t *ctx)
{
- return !(ctx->previous_display == ctx->display &&
- ctx->previous_drawable == current_drawable &&
- ctx->previous_context == ctx->context);
+ return ctx->previous_context != ctx->context;
}
static GLXDrawable
static void
_glx_query_current_state (cairo_glx_context_t * ctx)
{
- ctx->previous_drawable = glXGetCurrentDrawable ();
- ctx->previous_display = glXGetCurrentDisplay ();
ctx->previous_context = glXGetCurrentContext ();
-
- /* If any of the values were none, assume they are all none. Not all
- drivers seem well behaved when it comes to using these values across
- multiple threads. */
- if (ctx->previous_drawable == None
- || ctx->previous_display == None
- || ctx->previous_context == None) {
- ctx->previous_drawable = None;
- ctx->previous_display = None;
- ctx->previous_context = None;
- }
}
static void
GLXDrawable current_drawable = _glx_get_current_drawable (ctx);
_glx_query_current_state (ctx);
- if (!_context_acquisition_changed_glx_state (ctx, current_drawable))
+ if (!_context_acquisition_changed_glx_state (ctx))
return;
_cairo_gl_context_reset (&ctx->base);
cairo_glx_context_t *ctx = abstract_ctx;
if (ctx->has_multithread_makecurrent || !ctx->base.thread_aware ||
- !_context_acquisition_changed_glx_state (ctx,
- _glx_get_current_drawable (ctx))) {
+ !_context_acquisition_changed_glx_state (ctx)) {
return;
}
_cairo_traps_init (&traps);
_cairo_traps_limit (&traps, &limit, 1);
- status = _cairo_path_fixed_stroke_to_traps (path,
- &gstate->stroke_style,
- &gstate->ctm,
- &gstate->ctm_inverse,
- gstate->tolerance,
- &traps);
+ status = _cairo_path_fixed_stroke_polygon_to_traps (path,
+ &gstate->stroke_style,
+ &gstate->ctm,
+ &gstate->ctm_inverse,
+ gstate->tolerance,
+ &traps);
if (unlikely (status))
goto BAIL;
cairo_traps_t traps;
_cairo_traps_init (&traps);
- status = _cairo_path_fixed_stroke_to_traps (path,
- &gstate->stroke_style,
- &gstate->ctm,
- &gstate->ctm_inverse,
- gstate->tolerance,
- &traps);
+ status = _cairo_path_fixed_stroke_polygon_to_traps (path,
+ &gstate->stroke_style,
+ &gstate->ctm,
+ &gstate->ctm_inverse,
+ gstate->tolerance,
+ &traps);
empty = traps.num_traps == 0;
if (! empty)
_cairo_traps_extents (&traps, &extents);
#include "cairo-traps-private.h"
#include "cairo-tristrip-private.h"
+#if CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
+#include "cairo-thread-local-private.h"
+#endif
+
static pixman_image_t *
to_pixman_image (cairo_surface_t *s)
{
}
#if HAS_PIXMAN_GLYPHS
-#error
+#if CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
+CAIRO_DEFINE_THREAD_LOCAL (pixman_glyph_cache_t *, per_thread_glyph_cache);
+#else
static pixman_glyph_cache_t *global_glyph_cache;
+#endif
static inline pixman_glyph_cache_t *
get_glyph_cache (void)
{
- if (!global_glyph_cache)
- global_glyph_cache = pixman_glyph_cache_create ();
+ pixman_glyph_cache_t **glyph_cache = NULL;
- return global_glyph_cache;
+#if CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
+ glyph_cache = CAIRO_GET_THREAD_LOCAL (per_thread_glyph_cache);
+#else
+ glyph_cache = &global_glyph_cache;
+#endif
+
+ if (! (*glyph_cache))
+ *glyph_cache = pixman_glyph_cache_create ();
+
+ return *glyph_cache;
}
void
_cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
cairo_scaled_glyph_t *scaled_glyph)
{
+ pixman_glyph_cache_t *glyph_cache = NULL;
+
+#if CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
+ glyph_cache = *CAIRO_GET_THREAD_LOCAL (per_thread_glyph_cache);
+#else
+ glyph_cache = global_glyph_cache;
CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
+#endif
- if (global_glyph_cache) {
+ if (glyph_cache) {
pixman_glyph_cache_remove (
- global_glyph_cache, scaled_font,
+ glyph_cache, scaled_font,
(void *)_cairo_scaled_glyph_index (scaled_glyph));
}
+#if ! CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
+#endif
}
static cairo_int_status_t
TRACE ((stderr, "%s\n", __FUNCTION__));
+#if ! CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
+#endif
glyph_cache = get_glyph_cache();
if (unlikely (glyph_cache == NULL)) {
cairo_scaled_glyph_t *scaled_glyph;
cairo_image_surface_t *glyph_surface;
+#if ! CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
/* This call can actually end up recursing, so we have to
* drop the mutex around it.
*/
CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
+#endif
+ _cairo_scaled_font_freeze_cache (info->font);
+
status = _cairo_scaled_glyph_lookup (info->font, index,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
+
+#if ! CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
+#endif
- if (unlikely (status))
+ if (unlikely (status)) {
+ _cairo_scaled_font_thaw_cache (info->font);
goto out_thaw;
+ }
glyph_surface = scaled_glyph->surface;
glyph = pixman_glyph_cache_insert (glyph_cache, info->font, (void *)index,
glyph_surface->base.device_transform.x0,
glyph_surface->base.device_transform.y0,
glyph_surface->pixman_image);
+
+ _cairo_scaled_font_thaw_cache (info->font);
+
if (unlikely (!glyph)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto out_thaw;
free(pglyphs);
out_unlock:
+#if ! CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
+#endif
+
return status;
}
#else
TRACE ((stderr, "%s\n", __FUNCTION__));
- if (info->num_glyphs == 1)
- return composite_one_glyph(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
+ _cairo_scaled_font_freeze_cache (info->font);
+
+ if (info->num_glyphs == 1) {
+ status = composite_one_glyph(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
+ goto out_thaw;
+ }
- if (info->use_mask)
- return composite_glyphs_via_mask(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
+ if (info->use_mask) {
+ status = composite_glyphs_via_mask(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
+ goto out_thaw;
+ }
op = _pixman_operator (op);
dst = to_pixman_image (_dst);
}
}
+out_thaw:
+ _cairo_scaled_font_thaw_cache (info->font);
+
return status;
}
#endif
pixman_image_t *dst;
int src_x, src_y;
int mask_x, mask_y;
+ int run_length;
} composite;
struct finish {
cairo_rectangle_int_t extents;
uint8_t *data;
} mask;
} u;
- uint8_t buf[sizeof(cairo_abstract_span_renderer_t)-128];
+ uint8_t _buf[0];
+#define SZ_BUF (sizeof (cairo_abstract_span_renderer_t) - sizeof (cairo_image_span_renderer_t))
} cairo_image_span_renderer_t;
COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t));
uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
if (a == 0xff) {
if (len > 31) {
- pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
+ pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), 32,
spans[0].x, y, len, 1, r->u.fill.pixel);
} else {
uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
if (a) {
if (a == 0xff) {
if (spans[1].x - spans[0].x > 16) {
- pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
+ pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), 32,
spans[0].x, y, spans[1].x - spans[0].x, h,
r->u.fill.pixel);
} else {
if (likely(h == 1)) {
do {
- uint8_t a = mul8_8 (spans[0].coverage, r->op);
+ uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
if (a) {
int len = spans[1].x - spans[0].x;
uint8_t *d = r->u.fill.data + r->u.fill.stride*y + spans[0].x;
} while (--num_spans > 1);
} else {
do {
- uint8_t a = mul8_8 (spans[0].coverage, r->op);
+ uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
if (a) {
int yy = y, hh = h;
uint16_t p = (uint16_t)a * r->u.fill.pixel + 0x7f;
if (likely(h == 1)) {
do {
- uint8_t a = mul8_8 (spans[0].coverage, r->op);
+ uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
if (a) {
int len = spans[1].x - spans[0].x;
uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
} while (--num_spans > 1);
} else {
do {
- uint8_t a = mul8_8 (spans[0].coverage, r->op);
+ uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
if (a) {
int yy = y, hh = h;
do {
uint8_t *src = r->u.blit.src_data + y*r->u.blit.src_stride;
uint8_t *dst = r->u.blit.data + y*r->u.blit.stride;
do {
- uint8_t a = mul8_8 (spans[0].coverage, r->op);
+ uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
if (a) {
uint32_t *s = (uint32_t*)src + spans[0].x;
uint32_t *d = (uint32_t*)dst + spans[0].x;
} while (--num_spans > 1);
} else {
do {
- uint8_t a = mul8_8 (spans[0].coverage, r->op);
+ uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
if (a) {
int yy = y, hh = h;
do {
}
mask = (uint8_t *)pixman_image_get_data (r->mask);
- x0 = spans[0].x;
+ x1 = x0 = spans[0].x;
do {
int len = spans[1].x - spans[0].x;
*mask++ = spans[0].coverage;
if (len > 1) {
- memset (mask, spans[0].coverage, --len);
- mask += len;
+ if (len >= r->u.composite.run_length && spans[0].coverage == 0xff) {
+ if (x1 != x0) {
+ pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ x1 - x0, h);
+ }
+ pixman_image_composite32 (r->op, r->src, NULL, r->u.composite.dst,
+ spans[0].x + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ spans[0].x, y,
+ len, h);
+ mask = (uint8_t *)pixman_image_get_data (r->mask);
+ x0 = spans[1].x;
+ } else if (spans[0].coverage == 0x0 &&
+ x1 - x0 > r->u.composite.run_length) {
+ pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ x1 - x0, h);
+ mask = (uint8_t *)pixman_image_get_data (r->mask);
+ x0 = spans[1].x;
+ }else {
+ memset (mask, spans[0].coverage, --len);
+ mask += len;
+ }
}
x1 = spans[1].x;
spans++;
} while (--num_spans > 1);
- pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
- x0 + r->u.composite.src_x,
- y + r->u.composite.src_y,
- 0, 0,
- x0, y,
- x1 - x0, h);
+ if (x1 != x0) {
+ pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ x1 - x0, h);
+ }
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_inplace_src_spans (void *abstract_renderer,
- int y, int h,
+_inplace_opacity_spans (void *abstract_renderer, int y, int h,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_image_span_renderer_t *r = abstract_renderer;
+ uint8_t *mask;
+ int x0, x1;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ mask = (uint8_t *)pixman_image_get_data (r->mask);
+ x1 = x0 = spans[0].x;
+ do {
+ int len = spans[1].x - spans[0].x;
+ uint8_t m = mul8_8(spans[0].coverage, r->bpp);
+ *mask++ = m;
+ if (len > 1) {
+ if (m == 0 &&
+ x1 - x0 > r->u.composite.run_length) {
+ pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ x1 - x0, h);
+ mask = (uint8_t *)pixman_image_get_data (r->mask);
+ x0 = spans[1].x;
+ }else {
+ memset (mask, m, --len);
+ mask += len;
+ }
+ }
+ x1 = spans[1].x;
+ spans++;
+ } while (--num_spans > 1);
+
+ if (x1 != x0) {
+ pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ x1 - x0, h);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_inplace_src_spans (void *abstract_renderer, int y, int h,
const cairo_half_open_span_t *spans,
unsigned num_spans)
{
return CAIRO_STATUS_SUCCESS;
x0 = spans[0].x;
- m = r->buf;
+ m = r->_buf;
do {
int len = spans[1].x - spans[0].x;
- if (spans[0].coverage == 0xff) {
+ if (len >= r->u.composite.run_length && spans[0].coverage == 0xff) {
if (spans[0].x != x0) {
#if PIXMAN_HAS_OP_LERP
pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
spans[0].x, y,
spans[1].x - spans[0].x, h);
- m = r->buf;
+ m = r->_buf;
x0 = spans[1].x;
} else if (spans[0].coverage == 0x0) {
if (spans[0].x != x0) {
#endif
}
- m = r->buf;
+ m = r->_buf;
x0 = spans[1].x;
} else {
*m++ = spans[0].coverage;
return CAIRO_STATUS_SUCCESS;
}
+static cairo_status_t
+_inplace_src_opacity_spans (void *abstract_renderer, int y, int h,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_image_span_renderer_t *r = abstract_renderer;
+ uint8_t *mask;
+ int x0;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ x0 = spans[0].x;
+ mask = (uint8_t *)pixman_image_get_data (r->mask);
+ do {
+ int len = spans[1].x - spans[0].x;
+ uint8_t m = mul8_8(spans[0].coverage, r->bpp);
+ if (m == 0) {
+ if (spans[0].x != x0) {
+#if PIXMAN_HAS_OP_LERP
+ pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
+ r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ spans[0].x - x0, h);
+#else
+ pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
+ r->mask, NULL, r->u.composite.dst,
+ 0, 0,
+ 0, 0,
+ x0, y,
+ spans[0].x - x0, h);
+ pixman_image_composite32 (PIXMAN_OP_ADD,
+ r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ spans[0].x - x0, h);
+#endif
+ }
+
+ mask = (uint8_t *)pixman_image_get_data (r->mask);
+ x0 = spans[1].x;
+ } else {
+ *mask++ = m;
+ if (len > 1) {
+ memset (mask, m, --len);
+ mask += len;
+ }
+ }
+ spans++;
+ } while (--num_spans > 1);
+
+ if (spans[0].x != x0) {
+#if PIXMAN_HAS_OP_LERP
+ pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
+ r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ spans[0].x - x0, h);
+#else
+ pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
+ r->mask, NULL, r->u.composite.dst,
+ 0, 0,
+ 0, 0,
+ x0, y,
+ spans[0].x - x0, h);
+ pixman_image_composite32 (PIXMAN_OP_ADD,
+ r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ spans[0].x - x0, h);
+#endif
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void free_pixels (pixman_image_t *image, void *data)
+{
+ free (data);
+}
+
static cairo_int_status_t
inplace_renderer_init (cairo_image_span_renderer_t *r,
const cairo_composite_rectangles_t *composite,
cairo_bool_t needs_clip)
{
cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
+ uint8_t *buf;
if (composite->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
return CAIRO_INT_STATUS_UNSUPPORTED;
r->base.render_rows = NULL;
- r->op = composite->mask_pattern.solid.color.alpha_short >> 8;
+ r->bpp = composite->mask_pattern.solid.color.alpha_short >> 8;
if (composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
const cairo_color_t *color;
* typically small, too small to payback the startup overheads of
* using SSE2 etc.
*/
- if (r->op == 0xff) {
+ if (r->bpp == 0xff) {
switch (dst->format) {
case CAIRO_FORMAT_A8:
r->base.render_rows = _fill_a8_lerp_opaque_spans;
}
}
if (r->base.render_rows == NULL) {
- unsigned int width;
const cairo_pattern_t *src = &composite->source_pattern.base;
-
- if (r->op != 0xff)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ unsigned int width;
if (composite->is_bounded == 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
+ r->base.render_rows = r->bpp == 0xff ? _inplace_spans : _inplace_opacity_spans;
width = (composite->bounded.width + 3) & ~3;
- r->base.render_rows = _inplace_spans;
+
+ r->u.composite.run_length = 8;
+ if (src->type == CAIRO_PATTERN_TYPE_LINEAR ||
+ src->type == CAIRO_PATTERN_TYPE_RADIAL)
+ r->u.composite.run_length = 256;
if (dst->base.is_clear &&
(composite->op == CAIRO_OPERATOR_SOURCE ||
composite->op == CAIRO_OPERATOR_OVER ||
composite->op == CAIRO_OPERATOR_ADD)) {
r->op = PIXMAN_OP_SRC;
} else if (composite->op == CAIRO_OPERATOR_SOURCE) {
- r->base.render_rows = _inplace_src_spans;
+ r->base.render_rows = r->bpp == 0xff ? _inplace_src_spans : _inplace_src_opacity_spans;
r->u.composite.mask_y = r->composite->unbounded.y;
width = (composite->unbounded.width + 3) & ~3;
} else if (composite->op == CAIRO_OPERATOR_CLEAR) {
r->op = _pixman_operator (composite->op);
}
- if (width > sizeof (r->buf))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
r->src = _pixman_image_for_pattern (dst, src, FALSE,
&composite->bounded,
&composite->source_sample_area,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
/* Create an effectively unbounded mask by repeating the single line */
+ buf = r->_buf;
+ if (width > SZ_BUF) {
+ buf = malloc (width);
+ if (unlikely (buf == NULL)) {
+ pixman_image_unref (r->src);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+ }
r->mask = pixman_image_create_bits (PIXMAN_a8,
width, composite->unbounded.height,
- (uint32_t *)r->buf, 0);
+ (uint32_t *)buf, 0);
if (unlikely (r->mask == NULL)) {
pixman_image_unref (r->src);
+ if (buf != r->_buf)
+ free (buf);
return _cairo_error(CAIRO_STATUS_NO_MEMORY);
}
+ if (buf != r->_buf)
+ pixman_image_set_destroy_function (r->mask, free_pixels, buf);
+
r->u.composite.dst = dst->pixman_image;
}
- r->bpp = PIXMAN_FORMAT_BPP(dst->pixman_format);
-
return CAIRO_INT_STATUS_SUCCESS;
}
cairo_operator_t op = composite->op;
cairo_int_status_t status;
- TRACE ((stderr, "%s\n", __FUNCTION__));
+ TRACE ((stderr, "%s: antialias=%d, needs_clip=%d\n", __FUNCTION__,
+ antialias, needs_clip));
if (needs_clip)
return CAIRO_INT_STATUS_UNSUPPORTED;
r->u.mask.extents = composite->unbounded;
r->u.mask.stride = (r->u.mask.extents.width + 3) & ~3;
- if (r->u.mask.extents.height * r->u.mask.stride > (int)sizeof (r->buf)) {
+ if (r->u.mask.extents.height * r->u.mask.stride > (int)sizeof (r->_buf)) {
r->mask = pixman_image_create_bits (PIXMAN_a8,
r->u.mask.extents.width,
r->u.mask.extents.height,
r->mask = pixman_image_create_bits (PIXMAN_a8,
r->u.mask.extents.width,
r->u.mask.extents.height,
- (uint32_t *)r->buf, r->u.mask.stride);
+ (uint32_t *)r->_buf, r->u.mask.stride);
r->base.render_rows = _cairo_image_spans_and_zero;
r->base.finish = _cairo_image_finish_spans_and_zero;
cairo_surface_t *parent)
{
image->parent = parent;
- cairo_surface_reference (parent);
}
static inline cairo_bool_t
if (unlikely (status))
goto error;
- _cairo_image_surface_set_parent (to_image_surface (image), surface);
+ /* We use the parent as a flag during map-to-image/umap-image that the
+ * resultant image came from a fallback rather than as direct call
+ * to the backend's map_to_image(). Whilst we use it as a simple flag,
+ * we need to make sure the parent surface obeys the reference counting
+ * semantics and is consistent for all callers.
+ */
+ _cairo_image_surface_set_parent (to_image_surface (image),
+ cairo_surface_reference (surface));
return to_image_surface (image);
status = compositor->acquire (surface);
if (unlikely (status)) {
cairo_surface_destroy (surface);
- return _cairo_surface_create_in_error (status);
+ return _cairo_int_surface_create_in_error (status);
}
if (!surface->is_clear) {
compositor->release (surface);
if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
cairo_surface_destroy (surface);
- surface = _cairo_surface_create_in_error (status);
+ surface = _cairo_int_surface_create_in_error (status);
}
return surface;
}
return CAIRO_STATUS_SUCCESS;
}
+static cairo_surface_t *
+get_clip_source (const cairo_mask_compositor_t *compositor,
+ cairo_clip_t *clip,
+ cairo_surface_t *dst,
+ const cairo_rectangle_int_t *bounds,
+ int *out_x, int *out_y)
+{
+ cairo_surface_pattern_t pattern;
+ cairo_rectangle_int_t r;
+ cairo_surface_t *surface;
+
+ surface = _cairo_clip_get_image (clip, dst, bounds);
+ if (unlikely (surface->status))
+ return surface;
+
+ _cairo_pattern_init_for_surface (&pattern, surface);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
+ cairo_surface_destroy (surface);
+
+ r.x = r.y = 0;
+ r.width = bounds->width;
+ r.height = bounds->height;
+
+ surface = compositor->pattern_to_surface (dst, &pattern.base, TRUE,
+ &r, &r, out_x, out_y);
+ _cairo_pattern_fini (&pattern.base);
+
+ *out_x += -bounds->x;
+ *out_y += -bounds->y;
+ return surface;
+}
+
/* Handles compositing with a clip surface when we have to do the operation
* in two pieces and combine them together.
*/
cairo_surface_t *dst = extents->surface;
cairo_surface_t *tmp, *clip;
cairo_status_t status;
+ int clip_x, clip_y;
tmp = _cairo_surface_create_similar_scratch (dst, dst->content,
extents->bounded.width,
if (unlikely (status))
goto cleanup;
- clip = _cairo_clip_get_image (extents->clip, dst, &extents->bounded);
+ clip = get_clip_source (compositor,
+ extents->clip, dst, &extents->bounded,
+ &clip_x, &clip_y);
if (unlikely ((status = clip->status)))
goto cleanup;
if (dst->is_clear) {
compositor->composite (dst, CAIRO_OPERATOR_SOURCE, tmp, clip,
0, 0,
- 0, 0,
+ clip_x, clip_y,
extents->bounded.x, extents->bounded.y,
extents->bounded.width, extents->bounded.height);
} else {
/* Punch the clip out of the destination */
compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, clip, NULL,
- 0, 0,
+ clip_x, clip_y,
0, 0,
extents->bounded.x, extents->bounded.y,
extents->bounded.width, extents->bounded.height);
/* Now add the two results together */
compositor->composite (dst, CAIRO_OPERATOR_ADD, tmp, clip,
0, 0,
- 0, 0,
+ clip_x, clip_y,
extents->bounded.x, extents->bounded.y,
extents->bounded.width, extents->bounded.height);
}
cairo_surface_t *dst,
const cairo_composite_rectangles_t *extents)
{
- cairo_clip_t *clip = extents->clip;
cairo_surface_t *mask;
int mask_x, mask_y;
- mask = _cairo_clip_get_image (clip, dst, &extents->unbounded);
+ mask = get_clip_source (compositor,
+ extents->clip, dst, &extents->unbounded,
+ &mask_x, &mask_y);
if (unlikely (mask->status))
return mask->status;
- mask_x = -extents->unbounded.x;
- mask_y = -extents->unbounded.y;
-
/* top */
if (extents->bounded.y != extents->unbounded.y) {
int x = extents->unbounded.x;
int mask_x = 0, mask_y = 0;
if (need_clip_mask) {
- mask = _cairo_clip_get_image (extents->clip, dst,
- &extents->bounded);
+ mask = get_clip_source (compositor,
+ extents->clip, dst, &extents->bounded,
+ &mask_x, &mask_y);
if (unlikely (mask->status))
return mask->status;
source = NULL;
op = CAIRO_OPERATOR_DEST_OUT;
}
-
- mask_x = -extents->bounded.x;
- mask_y = -extents->bounded.y;
}
if (source || mask == NULL) {
cairo_boxes_t boxes;
cairo_int_status_t status;
+ status = compositor->check_composite (extents);
+ if (unlikely (status))
+ return status;
+
_cairo_clip_steal_boxes (extents->clip, &boxes);
status = clip_and_composite_boxes (compositor, extents, &boxes);
_cairo_clip_unsteal_boxes (extents->clip, &boxes);
const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
+ status = compositor->check_composite (extents);
+ if (unlikely (status))
+ return status;
+
if (extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
extents->clip->path == NULL &&
- ! _cairo_clip_is_region (extents->clip)) {
+ _cairo_clip_is_region (extents->clip)) {
status = clip_and_composite (compositor,
composite_opacity_boxes,
composite_opacity_boxes,
const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
cairo_surface_t *mask;
cairo_surface_pattern_t pattern;
- cairo_int_status_t status;
+ cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = compositor->check_composite (extents);
+ if (unlikely (status))
+ return status;
- status = CAIRO_INT_STATUS_UNSUPPORTED;
if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
cairo_boxes_t boxes;
const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
cairo_surface_t *mask;
cairo_surface_pattern_t pattern;
- cairo_int_status_t status;
+ cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = compositor->check_composite (extents);
+ if (unlikely (status))
+ return status;
- status = CAIRO_INT_STATUS_UNSUPPORTED;
if (_cairo_path_fixed_fill_is_rectilinear (path)) {
cairo_boxes_t boxes;
int num_glyphs,
cairo_bool_t overlap)
{
+ const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
cairo_surface_t *mask;
cairo_surface_pattern_t pattern;
cairo_int_status_t status;
+ status = compositor->check_composite (extents);
+ if (unlikely (status))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
mask = cairo_surface_create_similar_image (extents->surface,
CAIRO_FORMAT_A8,
extents->bounded.width,
void *base, size_t bytes,
int min_bits, int num_sizes)
{
+ unsigned long tmp;
int num_blocks;
int i;
+ /* Align the start to an integral chunk */
+ tmp = ((unsigned long) base) & ((1 << min_bits) - 1);
+ if (tmp) {
+ tmp = (1 << min_bits) - tmp;
+ base = (char *)base + tmp;
+ bytes -= tmp;
+ }
+
assert ((((unsigned long) base) & ((1 << min_bits) - 1)) == 0);
assert (num_sizes < ARRAY_LENGTH (pool->free));
boxes);
}
-cairo_status_t
-_cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- cairo_antialias_t antialias,
- cairo_traps_t *traps)
-{
- cairo_box_t box;
- cairo_status_t status;
-
- traps->is_rectilinear = TRUE;
- traps->is_rectangular = TRUE;
-
- if (_cairo_path_fixed_is_box (path, &box)) {
- if (antialias == CAIRO_ANTIALIAS_NONE) {
- box.p1.x = _cairo_fixed_round_down (box.p1.x);
- box.p1.y = _cairo_fixed_round_down (box.p1.y);
- box.p2.x = _cairo_fixed_round_down (box.p2.x);
- box.p2.y = _cairo_fixed_round_down (box.p2.y);
- }
- return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2);
- } else {
- cairo_path_fixed_iter_t iter;
-
- _cairo_path_fixed_iter_init (&iter, path);
- while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
- if (box.p1.y > box.p2.y) {
- cairo_fixed_t t;
-
- t = box.p1.y;
- box.p1.y = box.p2.y;
- box.p2.y = t;
-
- t = box.p1.x;
- box.p1.x = box.p2.x;
- box.p2.x = t;
- }
-
- if (antialias == CAIRO_ANTIALIAS_NONE) {
- box.p1.x = _cairo_fixed_round_down (box.p1.x);
- box.p1.y = _cairo_fixed_round_down (box.p1.y);
- box.p2.x = _cairo_fixed_round_down (box.p2.x);
- box.p2.y = _cairo_fixed_round_down (box.p2.y);
- }
-
- status = _cairo_traps_tessellate_rectangle (traps,
- &box.p1, &box.p2);
- if (unlikely (status)) {
- _cairo_traps_clear (traps);
- return status;
- }
- }
-
- if (_cairo_path_fixed_iter_at_end (&iter))
- return _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, fill_rule);
-
- _cairo_traps_clear (traps);
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-}
#define CAIRO_PATH_BUF_SIZE ((512 - sizeof (cairo_path_buf_t)) \
/ (2 * sizeof (cairo_point_t) + sizeof (cairo_path_op_t)))
+#define cairo_path_head(path__) (&(path__)->buf.base)
+#define cairo_path_tail(path__) cairo_path_buf_prev (cairo_path_head (path__))
+
+#define cairo_path_buf_next(pos__) \
+ cairo_list_entry ((pos__)->link.next, cairo_path_buf_t, link)
+#define cairo_path_buf_prev(pos__) \
+ cairo_list_entry ((pos__)->link.prev, cairo_path_buf_t, link)
+
+#define cairo_path_foreach_buf_start(pos__, path__) \
+ pos__ = cairo_path_head (path__); do
+#define cairo_path_foreach_buf_end(pos__, path__) \
+ while ((pos__ = cairo_path_buf_next (pos__)) != cairo_path_head (path__))
+
+
typedef struct _cairo_path_buf {
cairo_list_t link;
unsigned int num_ops;
_cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t *path,
cairo_box_t *box);
+cairo_private cairo_bool_t
+_cairo_path_fixed_is_simple_quad (const cairo_path_fixed_t *path);
+
#endif /* CAIRO_PATH_FIXED_PRIVATE_H */
const cairo_point_t *points,
int num_points);
-#define cairo_path_head(path__) (&(path__)->buf.base)
-#define cairo_path_tail(path__) cairo_path_buf_prev (cairo_path_head (path__))
-
-#define cairo_path_buf_next(pos__) \
- cairo_list_entry ((pos__)->link.next, cairo_path_buf_t, link)
-#define cairo_path_buf_prev(pos__) \
- cairo_list_entry ((pos__)->link.prev, cairo_path_buf_t, link)
-
-#define cairo_path_foreach_buf_start(pos__, path__) \
- pos__ = cairo_path_head (path__); do
-#define cairo_path_foreach_buf_end(pos__, path__) \
- while ((pos__ = cairo_path_buf_next (pos__)) != cairo_path_head (path__))
-
void
_cairo_path_fixed_init (cairo_path_fixed_t *path)
{
}
}
-/*
- * Check whether the given path contains a single rectangle.
- */
-cairo_bool_t
-_cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
- cairo_box_t *box)
+static inline cairo_bool_t
+_path_is_quad (const cairo_path_fixed_t *path)
{
const cairo_path_buf_t *buf = cairo_path_head (path);
- if (! path->fill_is_rectilinear)
- return FALSE;
-
/* Do we have the right number of ops? */
if (buf->num_ops < 4 || buf->num_ops > 6)
return FALSE;
}
}
- /* Ok, we may have a box, if the points line up */
- if (buf->points[0].y == buf->points[1].y &&
- buf->points[1].x == buf->points[2].x &&
- buf->points[2].y == buf->points[3].y &&
- buf->points[3].x == buf->points[0].x)
- {
+ return TRUE;
+}
+
+static inline cairo_bool_t
+_points_form_rect (const cairo_point_t *points)
+{
+ if (points[0].y == points[1].y &&
+ points[1].x == points[2].x &&
+ points[2].y == points[3].y &&
+ points[3].x == points[0].x)
+ return TRUE;
+ if (points[0].x == points[1].x &&
+ points[1].y == points[2].y &&
+ points[2].x == points[3].x &&
+ points[3].y == points[0].y)
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Check whether the given path contains a single rectangle.
+ */
+cairo_bool_t
+_cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
+ cairo_box_t *box)
+{
+ const cairo_path_buf_t *buf;
+
+ if (! path->fill_is_rectilinear)
+ return FALSE;
+
+ if (! _path_is_quad (path))
+ return FALSE;
+
+ buf = cairo_path_head (path);
+ if (_points_form_rect (buf->points)) {
_canonical_box (box, &buf->points[0], &buf->points[2]);
return TRUE;
}
- if (buf->points[0].x == buf->points[1].x &&
- buf->points[1].y == buf->points[2].y &&
- buf->points[2].x == buf->points[3].x &&
- buf->points[3].y == buf->points[0].y)
- {
- _canonical_box (box, &buf->points[0], &buf->points[2]);
+ return FALSE;
+}
+
+/* Determine whether two lines A->B and C->D intersect based on the
+ * algorithm described here: http://paulbourke.net/geometry/lineline2d/ */
+static inline cairo_bool_t
+_lines_intersect_or_are_coincident (cairo_point_t a,
+ cairo_point_t b,
+ cairo_point_t c,
+ cairo_point_t d)
+{
+ cairo_int64_t numerator_a, numerator_b, denominator;
+
+ denominator = _cairo_int64_sub (_cairo_int32x32_64_mul (d.y - c.y, b.x - a.x),
+ _cairo_int32x32_64_mul (d.x - c.x, b.y - a.y));
+ numerator_a = _cairo_int64_sub (_cairo_int32x32_64_mul (d.x - c.x, a.y - c.y),
+ _cairo_int32x32_64_mul (d.y - c.y, a.x - c.x));
+ numerator_b = _cairo_int64_sub (_cairo_int32x32_64_mul (b.x - a.x, a.y - c.y),
+ _cairo_int32x32_64_mul (b.y - a.y, a.x - c.x));
+
+ if (_cairo_int64_is_zero (denominator)) {
+ /* If the denominator and numerators are both zero,
+ * the lines are coincident. */
+ if (_cairo_int64_is_zero (numerator_a) && _cairo_int64_is_zero (numerator_b))
+ return TRUE;
+
+ /* Otherwise, a zero denominator indicates the lines are
+ * parallel and never intersect. */
+ return FALSE;
+ }
+
+ /* If either division would produce a number between 0 and 1, i.e.
+ * the numerator is smaller than the denominator and their signs are
+ * the same, then the lines intersect. */
+ if (_cairo_int64_lt (numerator_a, denominator) &&
+ ! (_cairo_int64_negative (numerator_a) ^ _cairo_int64_negative(denominator))) {
+ return TRUE;
+ }
+
+ if (_cairo_int64_lt (numerator_b, denominator) &&
+ ! (_cairo_int64_negative (numerator_b) ^ _cairo_int64_negative(denominator))) {
return TRUE;
}
}
cairo_bool_t
+_cairo_path_fixed_is_simple_quad (const cairo_path_fixed_t *path)
+{
+ const cairo_point_t *points;
+
+ if (! _path_is_quad (path))
+ return FALSE;
+
+ points = cairo_path_head (path)->points;
+ if (_points_form_rect (points))
+ return TRUE;
+
+ if (_lines_intersect_or_are_coincident (points[0], points[1],
+ points[3], points[2]))
+ return FALSE;
+
+ if (_lines_intersect_or_are_coincident (points[0], points[3],
+ points[1], points[2]))
+ return FALSE;
+
+ return TRUE;
+}
+
+cairo_bool_t
_cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t *path,
cairo_box_t *box)
{
{
const cairo_path_buf_t *buf = cairo_path_head (path);
- if (buf->op[0] != CAIRO_PATH_OP_MOVE_TO ||
- buf->op[1] != CAIRO_PATH_OP_LINE_TO)
+ if (buf->num_ops > 2)
return FALSE;
+ if (buf->num_ops <= 1)
+ return TRUE;
- return TRUE;
+ return buf->op[0] == CAIRO_PATH_OP_MOVE_TO &&
+ buf->op[1] == CAIRO_PATH_OP_LINE_TO;
}
cairo_bool_t
cairo_stroke_face_t face;
if (stroker->has_bounds &&
- ! _cairo_spline_intersects (&stroker->current_face.point, b, c, b,
+ ! _cairo_spline_intersects (&stroker->current_face.point, b, c, d,
&stroker->bounds))
return line_to (closure, d);
--- /dev/null
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2013 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-box-inline.h"
+#include "cairo-path-fixed-private.h"
+#include "cairo-slope-private.h"
+#include "cairo-stroke-dash-private.h"
+#include "cairo-traps-private.h"
+
+#include <float.h>
+
+struct stroker {
+ const cairo_stroke_style_t *style;
+
+ const cairo_matrix_t *ctm;
+ const cairo_matrix_t *ctm_inverse;
+ double spline_cusp_tolerance;
+ double half_line_width;
+ double tolerance;
+ double ctm_determinant;
+ cairo_bool_t ctm_det_positive;
+ cairo_line_join_t line_join;
+
+ cairo_traps_t *traps;
+
+ cairo_pen_t pen;
+
+ cairo_point_t first_point;
+
+ cairo_bool_t has_initial_sub_path;
+
+ cairo_bool_t has_current_face;
+ cairo_stroke_face_t current_face;
+
+ cairo_bool_t has_first_face;
+ cairo_stroke_face_t first_face;
+
+ cairo_stroker_dash_t dash;
+
+ cairo_bool_t has_bounds;
+ cairo_box_t tight_bounds;
+ cairo_box_t line_bounds;
+ cairo_box_t join_bounds;
+};
+
+static cairo_status_t
+stroker_init (struct stroker *stroker,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_traps_t *traps)
+{
+ cairo_status_t status;
+
+ stroker->style = style;
+ stroker->ctm = ctm;
+ stroker->ctm_inverse = NULL;
+ if (! _cairo_matrix_is_identity (ctm_inverse))
+ stroker->ctm_inverse = ctm_inverse;
+ stroker->line_join = style->line_join;
+ stroker->half_line_width = style->line_width / 2.0;
+ stroker->tolerance = tolerance;
+ stroker->traps = traps;
+
+ /* To test whether we need to join two segments of a spline using
+ * a round-join or a bevel-join, we can inspect the angle between the
+ * two segments. If the difference between the chord distance
+ * (half-line-width times the cosine of the bisection angle) and the
+ * half-line-width itself is greater than tolerance then we need to
+ * inject a point.
+ */
+ stroker->spline_cusp_tolerance = 1 - tolerance / stroker->half_line_width;
+ stroker->spline_cusp_tolerance *= stroker->spline_cusp_tolerance;
+ stroker->spline_cusp_tolerance *= 2;
+ stroker->spline_cusp_tolerance -= 1;
+
+ stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
+ stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
+
+ status = _cairo_pen_init (&stroker->pen,
+ stroker->half_line_width,
+ tolerance, ctm);
+ if (unlikely (status))
+ return status;
+
+ stroker->has_current_face = FALSE;
+ stroker->has_first_face = FALSE;
+ stroker->has_initial_sub_path = FALSE;
+
+ _cairo_stroker_dash_init (&stroker->dash, style);
+
+ stroker->has_bounds = traps->num_limits;
+ if (stroker->has_bounds) {
+ /* Extend the bounds in each direction to account for the maximum area
+ * we might generate trapezoids, to capture line segments that are outside
+ * of the bounds but which might generate rendering that's within bounds.
+ */
+ double dx, dy;
+ cairo_fixed_t fdx, fdy;
+
+ stroker->tight_bounds = traps->bounds;
+
+ _cairo_stroke_style_max_distance_from_path (stroker->style, path,
+ stroker->ctm, &dx, &dy);
+
+ _cairo_stroke_style_max_line_distance_from_path (stroker->style, path,
+ stroker->ctm, &dx, &dy);
+
+ fdx = _cairo_fixed_from_double (dx);
+ fdy = _cairo_fixed_from_double (dy);
+
+ stroker->line_bounds = stroker->tight_bounds;
+ stroker->line_bounds.p1.x -= fdx;
+ stroker->line_bounds.p2.x += fdx;
+ stroker->line_bounds.p1.y -= fdy;
+ stroker->line_bounds.p2.y += fdy;
+
+ _cairo_stroke_style_max_join_distance_from_path (stroker->style, path,
+ stroker->ctm, &dx, &dy);
+
+ fdx = _cairo_fixed_from_double (dx);
+ fdy = _cairo_fixed_from_double (dy);
+
+ stroker->join_bounds = stroker->tight_bounds;
+ stroker->join_bounds.p1.x -= fdx;
+ stroker->join_bounds.p2.x += fdx;
+ stroker->join_bounds.p1.y -= fdy;
+ stroker->join_bounds.p2.y += fdy;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+stroker_fini (struct stroker *stroker)
+{
+ _cairo_pen_fini (&stroker->pen);
+}
+
+static void
+translate_point (cairo_point_t *point, cairo_point_t *offset)
+{
+ point->x += offset->x;
+ point->y += offset->y;
+}
+
+static int
+join_is_clockwise (const cairo_stroke_face_t *in,
+ const cairo_stroke_face_t *out)
+{
+ return _cairo_slope_compare (&in->dev_vector, &out->dev_vector) < 0;
+}
+
+static int
+slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
+{
+ double c = dx1 * dy2 - dx2 * dy1;
+ if (c > 0) return 1;
+ if (c < 0) return -1;
+ return 0;
+}
+
+static cairo_bool_t
+stroker_intersects_join (const struct stroker *stroker,
+ const cairo_point_t *in,
+ const cairo_point_t *out)
+{
+ cairo_line_t segment;
+
+ if (! stroker->has_bounds)
+ return TRUE;
+
+ segment.p1 = *in;
+ segment.p2 = *out;
+ return _cairo_box_intersects_line_segment (&stroker->join_bounds, &segment);
+}
+
+static void
+join (struct stroker *stroker,
+ cairo_stroke_face_t *in,
+ cairo_stroke_face_t *out)
+{
+ int clockwise = join_is_clockwise (out, in);
+ cairo_point_t *inpt, *outpt;
+
+ if (in->cw.x == out->cw.x &&
+ in->cw.y == out->cw.y &&
+ in->ccw.x == out->ccw.x &&
+ in->ccw.y == out->ccw.y)
+ {
+ return;
+ }
+
+ if (clockwise) {
+ inpt = &in->ccw;
+ outpt = &out->ccw;
+ } else {
+ inpt = &in->cw;
+ outpt = &out->cw;
+ }
+
+ if (! stroker_intersects_join (stroker, inpt, outpt))
+ return;
+
+ switch (stroker->line_join) {
+ case CAIRO_LINE_JOIN_ROUND:
+ /* construct a fan around the common midpoint */
+ if ((in->dev_slope.x * out->dev_slope.x +
+ in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance)
+ {
+ int start, stop;
+ cairo_point_t tri[3];
+ cairo_pen_t *pen = &stroker->pen;
+
+ tri[0] = in->point;
+ tri[1] = *inpt;
+ if (clockwise) {
+ _cairo_pen_find_active_ccw_vertices (pen,
+ &in->dev_vector, &out->dev_vector,
+ &start, &stop);
+ while (start != stop) {
+ tri[2] = in->point;
+ translate_point (&tri[2], &pen->vertices[start].point);
+ _cairo_traps_tessellate_triangle (stroker->traps, tri);
+ tri[1] = tri[2];
+
+ if (start-- == 0)
+ start += pen->num_vertices;
+ }
+ } else {
+ _cairo_pen_find_active_cw_vertices (pen,
+ &in->dev_vector, &out->dev_vector,
+ &start, &stop);
+ while (start != stop) {
+ tri[2] = in->point;
+ translate_point (&tri[2], &pen->vertices[start].point);
+ _cairo_traps_tessellate_triangle (stroker->traps, tri);
+ tri[1] = tri[2];
+
+ if (++start == pen->num_vertices)
+ start = 0;
+ }
+ }
+ tri[2] = *outpt;
+ _cairo_traps_tessellate_triangle (stroker->traps, tri);
+ break;
+ }
+
+ case CAIRO_LINE_JOIN_MITER:
+ default: {
+ /* dot product of incoming slope vector with outgoing slope vector */
+ double in_dot_out = (-in->usr_vector.x * out->usr_vector.x +
+ -in->usr_vector.y * out->usr_vector.y);
+ double ml = stroker->style->miter_limit;
+
+ /* Check the miter limit -- lines meeting at an acute angle
+ * can generate long miters, the limit converts them to bevel
+ *
+ * Consider the miter join formed when two line segments
+ * meet at an angle psi:
+ *
+ * /.\
+ * /. .\
+ * /./ \.\
+ * /./psi\.\
+ *
+ * We can zoom in on the right half of that to see:
+ *
+ * |\
+ * | \ psi/2
+ * | \
+ * | \
+ * | \
+ * | \
+ * miter \
+ * length \
+ * | \
+ * | .\
+ * | . \
+ * |. line \
+ * \ width \
+ * \ \
+ *
+ *
+ * The right triangle in that figure, (the line-width side is
+ * shown faintly with three '.' characters), gives us the
+ * following expression relating miter length, angle and line
+ * width:
+ *
+ * 1 /sin (psi/2) = miter_length / line_width
+ *
+ * The right-hand side of this relationship is the same ratio
+ * in which the miter limit (ml) is expressed. We want to know
+ * when the miter length is within the miter limit. That is
+ * when the following condition holds:
+ *
+ * 1/sin(psi/2) <= ml
+ * 1 <= ml sin(psi/2)
+ * 1 <= ml² sin²(psi/2)
+ * 2 <= ml² 2 sin²(psi/2)
+ * 2·sin²(psi/2) = 1-cos(psi)
+ * 2 <= ml² (1-cos(psi))
+ *
+ * in · out = |in| |out| cos (psi)
+ *
+ * in and out are both unit vectors, so:
+ *
+ * in · out = cos (psi)
+ *
+ * 2 <= ml² (1 - in · out)
+ *
+ */
+ if (2 <= ml * ml * (1 - in_dot_out)) {
+ double x1, y1, x2, y2;
+ double mx, my;
+ double dx1, dx2, dy1, dy2;
+ cairo_point_t outer;
+ cairo_point_t quad[4];
+ double ix, iy;
+ double fdx1, fdy1, fdx2, fdy2;
+ double mdx, mdy;
+
+ /*
+ * we've got the points already transformed to device
+ * space, but need to do some computation with them and
+ * also need to transform the slope from user space to
+ * device space
+ */
+ /* outer point of incoming line face */
+ x1 = _cairo_fixed_to_double (inpt->x);
+ y1 = _cairo_fixed_to_double (inpt->y);
+ dx1 = in->usr_vector.x;
+ dy1 = in->usr_vector.y;
+ cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
+
+ /* outer point of outgoing line face */
+ x2 = _cairo_fixed_to_double (outpt->x);
+ y2 = _cairo_fixed_to_double (outpt->y);
+ dx2 = out->usr_vector.x;
+ dy2 = out->usr_vector.y;
+ cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
+
+ /*
+ * Compute the location of the outer corner of the miter.
+ * That's pretty easy -- just the intersection of the two
+ * outer edges. We've got slopes and points on each
+ * of those edges. Compute my directly, then compute
+ * mx by using the edge with the larger dy; that avoids
+ * dividing by values close to zero.
+ */
+ my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
+ (dx1 * dy2 - dx2 * dy1));
+ if (fabs (dy1) >= fabs (dy2))
+ mx = (my - y1) * dx1 / dy1 + x1;
+ else
+ mx = (my - y2) * dx2 / dy2 + x2;
+
+ /*
+ * When the two outer edges are nearly parallel, slight
+ * perturbations in the position of the outer points of the lines
+ * caused by representing them in fixed point form can cause the
+ * intersection point of the miter to move a large amount. If
+ * that moves the miter intersection from between the two faces,
+ * then draw a bevel instead.
+ */
+
+ ix = _cairo_fixed_to_double (in->point.x);
+ iy = _cairo_fixed_to_double (in->point.y);
+
+ /* slope of one face */
+ fdx1 = x1 - ix; fdy1 = y1 - iy;
+
+ /* slope of the other face */
+ fdx2 = x2 - ix; fdy2 = y2 - iy;
+
+ /* slope from the intersection to the miter point */
+ mdx = mx - ix; mdy = my - iy;
+
+ /*
+ * Make sure the miter point line lies between the two
+ * faces by comparing the slopes
+ */
+ if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
+ slope_compare_sgn (fdx2, fdy2, mdx, mdy))
+ {
+ /*
+ * Draw the quadrilateral
+ */
+ outer.x = _cairo_fixed_from_double (mx);
+ outer.y = _cairo_fixed_from_double (my);
+
+ quad[0] = in->point;
+ quad[1] = *inpt;
+ quad[2] = outer;
+ quad[3] = *outpt;
+
+ _cairo_traps_tessellate_convex_quad (stroker->traps, quad);
+ break;
+ }
+ }
+ /* fall through ... */
+ }
+
+ case CAIRO_LINE_JOIN_BEVEL: {
+ cairo_point_t tri[3];
+ tri[0] = in->point;
+ tri[1] = *inpt;
+ tri[2] = *outpt;
+
+ _cairo_traps_tessellate_triangle (stroker->traps, tri);
+ break;
+ }
+ }
+}
+
+static void
+add_cap (struct stroker *stroker, cairo_stroke_face_t *f)
+{
+ switch (stroker->style->line_cap) {
+ case CAIRO_LINE_CAP_ROUND: {
+ int start, stop;
+ cairo_slope_t in_slope, out_slope;
+ cairo_point_t tri[3];
+ cairo_pen_t *pen = &stroker->pen;
+
+ in_slope = f->dev_vector;
+ out_slope.dx = -in_slope.dx;
+ out_slope.dy = -in_slope.dy;
+ _cairo_pen_find_active_cw_vertices (pen, &in_slope, &out_slope,
+ &start, &stop);
+ tri[0] = f->point;
+ tri[1] = f->cw;
+ while (start != stop) {
+ tri[2] = f->point;
+ translate_point (&tri[2], &pen->vertices[start].point);
+ _cairo_traps_tessellate_triangle (stroker->traps, tri);
+
+ tri[1] = tri[2];
+ if (++start == pen->num_vertices)
+ start = 0;
+ }
+ tri[2] = f->ccw;
+ _cairo_traps_tessellate_triangle (stroker->traps, tri);
+ break;
+ }
+
+ case CAIRO_LINE_CAP_SQUARE: {
+ double dx, dy;
+ cairo_slope_t fvector;
+ cairo_point_t quad[4];
+
+ dx = f->usr_vector.x;
+ dy = f->usr_vector.y;
+ dx *= stroker->half_line_width;
+ dy *= stroker->half_line_width;
+ cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
+ fvector.dx = _cairo_fixed_from_double (dx);
+ fvector.dy = _cairo_fixed_from_double (dy);
+
+ quad[0] = f->cw;
+ quad[1].x = f->cw.x + fvector.dx;
+ quad[1].y = f->cw.y + fvector.dy;
+ quad[2].x = f->ccw.x + fvector.dx;
+ quad[2].y = f->ccw.y + fvector.dy;
+ quad[3] = f->ccw;
+
+ _cairo_traps_tessellate_convex_quad (stroker->traps, quad);
+ break;
+ }
+
+ case CAIRO_LINE_CAP_BUTT:
+ default:
+ break;
+ }
+}
+
+static void
+add_leading_cap (struct stroker *stroker,
+ cairo_stroke_face_t *face)
+{
+ cairo_stroke_face_t reversed;
+ cairo_point_t t;
+
+ reversed = *face;
+
+ /* The initial cap needs an outward facing vector. Reverse everything */
+ reversed.usr_vector.x = -reversed.usr_vector.x;
+ reversed.usr_vector.y = -reversed.usr_vector.y;
+ reversed.dev_vector.dx = -reversed.dev_vector.dx;
+ reversed.dev_vector.dy = -reversed.dev_vector.dy;
+ t = reversed.cw;
+ reversed.cw = reversed.ccw;
+ reversed.ccw = t;
+
+ add_cap (stroker, &reversed);
+}
+
+static void
+add_trailing_cap (struct stroker *stroker, cairo_stroke_face_t *face)
+{
+ add_cap (stroker, face);
+}
+
+static inline double
+normalize_slope (double *dx, double *dy)
+{
+ double dx0 = *dx, dy0 = *dy;
+
+ if (dx0 == 0.0 && dy0 == 0.0)
+ return 0;
+
+ if (dx0 == 0.0) {
+ *dx = 0.0;
+ if (dy0 > 0.0) {
+ *dy = 1.0;
+ return dy0;
+ } else {
+ *dy = -1.0;
+ return -dy0;
+ }
+ } else if (dy0 == 0.0) {
+ *dy = 0.0;
+ if (dx0 > 0.0) {
+ *dx = 1.0;
+ return dx0;
+ } else {
+ *dx = -1.0;
+ return -dx0;
+ }
+ } else {
+ double mag = hypot (dx0, dy0);
+ *dx = dx0 / mag;
+ *dy = dy0 / mag;
+ return mag;
+ }
+}
+
+static void
+compute_face (const cairo_point_t *point,
+ const cairo_slope_t *dev_slope,
+ struct stroker *stroker,
+ cairo_stroke_face_t *face)
+{
+ double face_dx, face_dy;
+ cairo_point_t offset_ccw, offset_cw;
+ double slope_dx, slope_dy;
+
+ slope_dx = _cairo_fixed_to_double (dev_slope->dx);
+ slope_dy = _cairo_fixed_to_double (dev_slope->dy);
+ face->length = normalize_slope (&slope_dx, &slope_dy);
+ face->dev_slope.x = slope_dx;
+ face->dev_slope.y = slope_dy;
+
+ /*
+ * rotate to get a line_width/2 vector along the face, note that
+ * the vector must be rotated the right direction in device space,
+ * but by 90° in user space. So, the rotation depends on
+ * whether the ctm reflects or not, and that can be determined
+ * by looking at the determinant of the matrix.
+ */
+ if (stroker->ctm_inverse) {
+ cairo_matrix_transform_distance (stroker->ctm_inverse, &slope_dx, &slope_dy);
+ normalize_slope (&slope_dx, &slope_dy);
+
+ if (stroker->ctm_det_positive) {
+ face_dx = - slope_dy * stroker->half_line_width;
+ face_dy = slope_dx * stroker->half_line_width;
+ } else {
+ face_dx = slope_dy * stroker->half_line_width;
+ face_dy = - slope_dx * stroker->half_line_width;
+ }
+
+ /* back to device space */
+ cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
+ } else {
+ face_dx = - slope_dy * stroker->half_line_width;
+ face_dy = slope_dx * stroker->half_line_width;
+ }
+
+ offset_ccw.x = _cairo_fixed_from_double (face_dx);
+ offset_ccw.y = _cairo_fixed_from_double (face_dy);
+ offset_cw.x = -offset_ccw.x;
+ offset_cw.y = -offset_ccw.y;
+
+ face->ccw = *point;
+ translate_point (&face->ccw, &offset_ccw);
+
+ face->point = *point;
+
+ face->cw = *point;
+ translate_point (&face->cw, &offset_cw);
+
+ face->usr_vector.x = slope_dx;
+ face->usr_vector.y = slope_dy;
+
+ face->dev_vector = *dev_slope;
+}
+
+static void
+add_caps (struct stroker *stroker)
+{
+ /* check for a degenerative sub_path */
+ if (stroker->has_initial_sub_path &&
+ !stroker->has_first_face &&
+ !stroker->has_current_face &&
+ stroker->style->line_cap == CAIRO_LINE_CAP_ROUND)
+ {
+ /* pick an arbitrary slope to use */
+ cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
+ cairo_stroke_face_t face;
+
+ /* arbitrarily choose first_point
+ * first_point and current_point should be the same */
+ compute_face (&stroker->first_point, &slope, stroker, &face);
+
+ add_leading_cap (stroker, &face);
+ add_trailing_cap (stroker, &face);
+ }
+
+ if (stroker->has_first_face)
+ add_leading_cap (stroker, &stroker->first_face);
+
+ if (stroker->has_current_face)
+ add_trailing_cap (stroker, &stroker->current_face);
+}
+
+static cairo_bool_t
+stroker_intersects_edge (const struct stroker *stroker,
+ const cairo_stroke_face_t *start,
+ const cairo_stroke_face_t *end)
+{
+ cairo_box_t box;
+
+ if (! stroker->has_bounds)
+ return TRUE;
+
+ if (_cairo_box_contains_point (&stroker->tight_bounds, &start->cw))
+ return TRUE;
+ box.p2 = box.p1 = start->cw;
+
+ if (_cairo_box_contains_point (&stroker->tight_bounds, &start->ccw))
+ return TRUE;
+ _cairo_box_add_point (&box, &start->ccw);
+
+ if (_cairo_box_contains_point (&stroker->tight_bounds, &end->cw))
+ return TRUE;
+ _cairo_box_add_point (&box, &end->cw);
+
+ if (_cairo_box_contains_point (&stroker->tight_bounds, &end->ccw))
+ return TRUE;
+ _cairo_box_add_point (&box, &end->ccw);
+
+ return (box.p2.x > stroker->tight_bounds.p1.x &&
+ box.p1.x < stroker->tight_bounds.p2.x &&
+ box.p2.y > stroker->tight_bounds.p1.y &&
+ box.p1.y < stroker->tight_bounds.p2.y);
+}
+
+static void
+add_sub_edge (struct stroker *stroker,
+ const cairo_point_t *p1, const cairo_point_t *p2,
+ const cairo_slope_t *dev_slope,
+ cairo_stroke_face_t *start, cairo_stroke_face_t *end)
+{
+ cairo_point_t rectangle[4];
+
+ compute_face (p1, dev_slope, stroker, start);
+
+ *end = *start;
+ end->point = *p2;
+ rectangle[0].x = p2->x - p1->x;
+ rectangle[0].y = p2->y - p1->y;
+ translate_point (&end->ccw, &rectangle[0]);
+ translate_point (&end->cw, &rectangle[0]);
+
+ if (p1->x == p2->x && p1->y == p2->y)
+ return;
+
+ if (! stroker_intersects_edge (stroker, start, end))
+ return;
+
+ rectangle[0] = start->cw;
+ rectangle[1] = start->ccw;
+ rectangle[2] = end->ccw;
+ rectangle[3] = end->cw;
+
+ _cairo_traps_tessellate_convex_quad (stroker->traps, rectangle);
+}
+
+static cairo_status_t
+move_to (void *closure, const cairo_point_t *point)
+{
+ struct stroker *stroker = closure;
+
+ /* Cap the start and end of the previous sub path as needed */
+ add_caps (stroker);
+
+ stroker->first_point = *point;
+ stroker->current_face.point = *point;
+
+ stroker->has_first_face = FALSE;
+ stroker->has_current_face = FALSE;
+ stroker->has_initial_sub_path = FALSE;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+move_to_dashed (void *closure, const cairo_point_t *point)
+{
+ /* reset the dash pattern for new sub paths */
+ struct stroker *stroker = closure;
+
+ _cairo_stroker_dash_start (&stroker->dash);
+ return move_to (closure, point);
+}
+
+static cairo_status_t
+line_to (void *closure, const cairo_point_t *point)
+{
+ struct stroker *stroker = closure;
+ cairo_stroke_face_t start, end;
+ const cairo_point_t *p1 = &stroker->current_face.point;
+ const cairo_point_t *p2 = point;
+ cairo_slope_t dev_slope;
+
+ stroker->has_initial_sub_path = TRUE;
+
+ if (p1->x == p2->x && p1->y == p2->y)
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_slope_init (&dev_slope, p1, p2);
+ add_sub_edge (stroker, p1, p2, &dev_slope, &start, &end);
+
+ if (stroker->has_current_face) {
+ /* Join with final face from previous segment */
+ join (stroker, &stroker->current_face, &start);
+ } else if (!stroker->has_first_face) {
+ /* Save sub path's first face in case needed for closing join */
+ stroker->first_face = start;
+ stroker->has_first_face = TRUE;
+ }
+ stroker->current_face = end;
+ stroker->has_current_face = TRUE;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/*
+ * Dashed lines. Cap each dash end, join around turns when on
+ */
+static cairo_status_t
+line_to_dashed (void *closure, const cairo_point_t *point)
+{
+ struct stroker *stroker = closure;
+ double mag, remain, step_length = 0;
+ double slope_dx, slope_dy;
+ double dx2, dy2;
+ cairo_stroke_face_t sub_start, sub_end;
+ const cairo_point_t *p1 = &stroker->current_face.point;
+ const cairo_point_t *p2 = point;
+ cairo_slope_t dev_slope;
+ cairo_line_t segment;
+ cairo_bool_t fully_in_bounds;
+
+ stroker->has_initial_sub_path = stroker->dash.dash_starts_on;
+
+ if (p1->x == p2->x && p1->y == p2->y)
+ return CAIRO_STATUS_SUCCESS;
+
+ fully_in_bounds = TRUE;
+ if (stroker->has_bounds &&
+ (! _cairo_box_contains_point (&stroker->join_bounds, p1) ||
+ ! _cairo_box_contains_point (&stroker->join_bounds, p2)))
+ {
+ fully_in_bounds = FALSE;
+ }
+
+ _cairo_slope_init (&dev_slope, p1, p2);
+
+ slope_dx = _cairo_fixed_to_double (p2->x - p1->x);
+ slope_dy = _cairo_fixed_to_double (p2->y - p1->y);
+
+ if (stroker->ctm_inverse)
+ cairo_matrix_transform_distance (stroker->ctm_inverse, &slope_dx, &slope_dy);
+ mag = normalize_slope (&slope_dx, &slope_dy);
+ if (mag <= DBL_EPSILON)
+ return CAIRO_STATUS_SUCCESS;
+
+ remain = mag;
+ segment.p1 = *p1;
+ while (remain) {
+ step_length = MIN (stroker->dash.dash_remain, remain);
+ remain -= step_length;
+ dx2 = slope_dx * (mag - remain);
+ dy2 = slope_dy * (mag - remain);
+ cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
+ segment.p2.x = _cairo_fixed_from_double (dx2) + p1->x;
+ segment.p2.y = _cairo_fixed_from_double (dy2) + p1->y;
+
+ if (stroker->dash.dash_on &&
+ (fully_in_bounds ||
+ (! stroker->has_first_face && stroker->dash.dash_starts_on) ||
+ _cairo_box_intersects_line_segment (&stroker->join_bounds, &segment)))
+ {
+ add_sub_edge (stroker,
+ &segment.p1, &segment.p2,
+ &dev_slope,
+ &sub_start, &sub_end);
+
+ if (stroker->has_current_face) {
+ /* Join with final face from previous segment */
+ join (stroker, &stroker->current_face, &sub_start);
+
+ stroker->has_current_face = FALSE;
+ } else if (! stroker->has_first_face && stroker->dash.dash_starts_on) {
+ /* Save sub path's first face in case needed for closing join */
+ stroker->first_face = sub_start;
+ stroker->has_first_face = TRUE;
+ } else {
+ /* Cap dash start if not connecting to a previous segment */
+ add_leading_cap (stroker, &sub_start);
+ }
+
+ if (remain) {
+ /* Cap dash end if not at end of segment */
+ add_trailing_cap (stroker, &sub_end);
+ } else {
+ stroker->current_face = sub_end;
+ stroker->has_current_face = TRUE;
+ }
+ } else {
+ if (stroker->has_current_face) {
+ /* Cap final face from previous segment */
+ add_trailing_cap (stroker, &stroker->current_face);
+
+ stroker->has_current_face = FALSE;
+ }
+ }
+
+ _cairo_stroker_dash_step (&stroker->dash, step_length);
+ segment.p1 = segment.p2;
+ }
+
+ if (stroker->dash.dash_on && ! stroker->has_current_face) {
+ /* This segment ends on a transition to dash_on, compute a new face
+ * and add cap for the beginning of the next dash_on step.
+ *
+ * Note: this will create a degenerate cap if this is not the last line
+ * in the path. Whether this behaviour is desirable or not is debatable.
+ * On one side these degenerate caps can not be reproduced with regular
+ * path stroking.
+ * On the other hand, Acroread 7 also produces the degenerate caps.
+ */
+ compute_face (point, &dev_slope, stroker, &stroker->current_face);
+
+ add_leading_cap (stroker, &stroker->current_face);
+
+ stroker->has_current_face = TRUE;
+ } else
+ stroker->current_face.point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+spline_to (void *closure,
+ const cairo_point_t *point,
+ const cairo_slope_t *tangent)
+{
+ struct stroker *stroker = closure;
+ cairo_stroke_face_t face;
+
+ if ((tangent->dx | tangent->dy) == 0) {
+ cairo_point_t t;
+
+ face = stroker->current_face;
+
+ face.usr_vector.x = -face.usr_vector.x;
+ face.usr_vector.y = -face.usr_vector.y;
+ face.dev_slope.x = -face.dev_slope.x;
+ face.dev_slope.y = -face.dev_slope.y;
+ face.dev_vector.dx = -face.dev_vector.dx;
+ face.dev_vector.dy = -face.dev_vector.dy;
+
+ t = face.cw;
+ face.cw = face.ccw;
+ face.ccw = t;
+
+ join (stroker, &stroker->current_face, &face);
+ } else {
+ cairo_point_t rectangle[4];
+
+ compute_face (&stroker->current_face.point, tangent, stroker, &face);
+
+ join (stroker, &stroker->current_face, &face);
+
+ rectangle[0] = face.cw;
+ rectangle[1] = face.ccw;
+
+ rectangle[2].x = point->x - face.point.x;
+ rectangle[2].y = point->y - face.point.y;
+ face.point = *point;
+ translate_point (&face.ccw, &rectangle[2]);
+ translate_point (&face.cw, &rectangle[2]);
+
+ rectangle[2] = face.ccw;
+ rectangle[3] = face.cw;
+
+ _cairo_traps_tessellate_convex_quad (stroker->traps, rectangle);
+ }
+
+ stroker->current_face = face;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+curve_to (void *closure,
+ const cairo_point_t *b,
+ const cairo_point_t *c,
+ const cairo_point_t *d)
+{
+ struct stroker *stroker = closure;
+ cairo_line_join_t line_join_save;
+ cairo_spline_t spline;
+ cairo_stroke_face_t face;
+ cairo_status_t status;
+
+ if (stroker->has_bounds &&
+ ! _cairo_spline_intersects (&stroker->current_face.point, b, c, d,
+ &stroker->line_bounds))
+ return line_to (closure, d);
+
+ if (! _cairo_spline_init (&spline, spline_to, stroker,
+ &stroker->current_face.point, b, c, d))
+ return line_to (closure, d);
+
+ compute_face (&stroker->current_face.point, &spline.initial_slope,
+ stroker, &face);
+
+ if (stroker->has_current_face) {
+ /* Join with final face from previous segment */
+ join (stroker, &stroker->current_face, &face);
+ } else {
+ if (! stroker->has_first_face) {
+ /* Save sub path's first face in case needed for closing join */
+ stroker->first_face = face;
+ stroker->has_first_face = TRUE;
+ }
+ stroker->has_current_face = TRUE;
+ }
+ stroker->current_face = face;
+
+ /* Temporarily modify the stroker to use round joins to guarantee
+ * smooth stroked curves. */
+ line_join_save = stroker->line_join;
+ stroker->line_join = CAIRO_LINE_JOIN_ROUND;
+
+ status = _cairo_spline_decompose (&spline, stroker->tolerance);
+
+ stroker->line_join = line_join_save;
+
+ return status;
+}
+
+static cairo_status_t
+curve_to_dashed (void *closure,
+ const cairo_point_t *b,
+ const cairo_point_t *c,
+ const cairo_point_t *d)
+{
+ struct stroker *stroker = closure;
+ cairo_spline_t spline;
+ cairo_line_join_t line_join_save;
+ cairo_spline_add_point_func_t func;
+ cairo_status_t status;
+
+ func = (cairo_spline_add_point_func_t)line_to_dashed;
+
+ if (stroker->has_bounds &&
+ ! _cairo_spline_intersects (&stroker->current_face.point, b, c, b,
+ &stroker->line_bounds))
+ return func (closure, d, NULL);
+
+ if (! _cairo_spline_init (&spline, func, stroker,
+ &stroker->current_face.point, b, c, d))
+ return func (closure, d, NULL);
+
+ /* Temporarily modify the stroker to use round joins to guarantee
+ * smooth stroked curves. */
+ line_join_save = stroker->line_join;
+ stroker->line_join = CAIRO_LINE_JOIN_ROUND;
+
+ status = _cairo_spline_decompose (&spline, stroker->tolerance);
+
+ stroker->line_join = line_join_save;
+
+ return status;
+}
+
+static cairo_status_t
+_close_path (struct stroker *stroker)
+{
+ if (stroker->has_first_face && stroker->has_current_face) {
+ /* Join first and final faces of sub path */
+ join (stroker, &stroker->current_face, &stroker->first_face);
+ } else {
+ /* Cap the start and end of the sub path as needed */
+ add_caps (stroker);
+ }
+
+ stroker->has_initial_sub_path = FALSE;
+ stroker->has_first_face = FALSE;
+ stroker->has_current_face = FALSE;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+close_path (void *closure)
+{
+ struct stroker *stroker = closure;
+ cairo_status_t status;
+
+ status = line_to (stroker, &stroker->first_point);
+ if (unlikely (status))
+ return status;
+
+ return _close_path (stroker);
+}
+
+static cairo_status_t
+close_path_dashed (void *closure)
+{
+ struct stroker *stroker = closure;
+ cairo_status_t status;
+
+ status = line_to_dashed (stroker, &stroker->first_point);
+ if (unlikely (status))
+ return status;
+
+ return _close_path (stroker);
+}
+
+cairo_int_status_t
+_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_traps_t *traps)
+{
+ struct stroker stroker;
+ cairo_status_t status;
+
+ status = stroker_init (&stroker, path, style,
+ ctm, ctm_inverse, tolerance,
+ traps);
+ if (unlikely (status))
+ return status;
+
+ if (stroker.dash.dashed)
+ status = _cairo_path_fixed_interpret (path,
+ move_to_dashed,
+ line_to_dashed,
+ curve_to_dashed,
+ close_path_dashed,
+ &stroker);
+ else
+ status = _cairo_path_fixed_interpret (path,
+ move_to,
+ line_to,
+ curve_to,
+ close_path,
+ &stroker);
+ assert(status == CAIRO_STATUS_SUCCESS);
+ add_caps (&stroker);
+
+ stroker_fini (&stroker);
+
+ return traps->status;
+}
const cairo_matrix_t *ctm;
const cairo_matrix_t *ctm_inverse;
+ double half_line_width;
double tolerance;
double ctm_determinant;
cairo_bool_t ctm_det_positive;
cairo_box_t bounds;
} cairo_stroker_t;
+static cairo_bool_t
+_cairo_stroke_segment_intersect (cairo_point_t *p1, cairo_point_t *p2,
+ cairo_point_t *p3, cairo_point_t *p4,
+ cairo_point_t *p)
+{
+ double x1, y1, x2, y2, x3, y3, x4, y4;
+ double pre, post;
+ double x, y, d;
+
+ x1 = _cairo_fixed_to_double (p1->x);
+ y1 = _cairo_fixed_to_double (p1->y);
+ x2 = _cairo_fixed_to_double (p2->x);
+ y2 = _cairo_fixed_to_double (p2->y);
+ x3 = _cairo_fixed_to_double (p3->x);
+ y3 = _cairo_fixed_to_double (p3->y);
+ x4 = _cairo_fixed_to_double (p4->x);
+ y4 = _cairo_fixed_to_double (p4->y);
+
+ d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
+ if (d == 0)
+ return FALSE;
+
+ pre = x1 * y2 - y1 * x2;
+ post = x3 * y4 - y3 * x4;
+ x = (pre * (x3 - x4) - (x1 - x2) * post) / d;
+ y = (pre * (y3 - y4) - (y1 - y2) * post) / d;
+
+ /* check if x, y are within both segments */
+ if (x < MIN (x1, x2) || x > MAX (x1, x2) ||
+ x < MIN (x3, x4) || x > MAX (x3, x4))
+ return FALSE;
+ if (y < MIN (y1, y2) || y > MAX (y1, y2) ||
+ y < MIN (y1, y2) || y > MAX (y3, y4))
+ return FALSE;
+
+ p->x = _cairo_fixed_from_double (x);
+ p->y = _cairo_fixed_from_double (y);
+ return TRUE;
+}
+
static void
_cairo_stroker_limit (cairo_stroker_t *stroker,
const cairo_path_fixed_t *path,
stroker->ctm = ctm;
stroker->ctm_inverse = ctm_inverse;
stroker->tolerance = tolerance;
+ stroker->half_line_width = stroke_style->line_width / 2.0;
stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
status = _cairo_pen_init (&stroker->pen,
- stroke_style->line_width / 2.0,
- tolerance, ctm);
+ stroker->half_line_width, tolerance, ctm);
if (unlikely (status))
return status;
dx = f->usr_vector.x;
dy = f->usr_vector.y;
- dx *= stroker->style.line_width / 2.0;
- dy *= stroker->style.line_width / 2.0;
+ dx *= stroker->half_line_width;
+ dy *= stroker->half_line_width;
cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
fvector.dx = _cairo_fixed_from_double (dx);
fvector.dy = _cairo_fixed_from_double (dy);
*/
if (stroker->ctm_det_positive)
{
- face_dx = - slope_dy * (stroker->style.line_width / 2.0);
- face_dy = slope_dx * (stroker->style.line_width / 2.0);
+ face_dx = - slope_dy * stroker->half_line_width;
+ face_dy = slope_dx * stroker->half_line_width;
}
else
{
- face_dx = slope_dy * (stroker->style.line_width / 2.0);
- face_dy = - slope_dx * (stroker->style.line_width / 2.0);
+ face_dx = slope_dy * stroker->half_line_width;
+ face_dy = - slope_dx * stroker->half_line_width;
}
/* back to device space */
cairo_stroke_face_t new_face;
double slope_dx, slope_dy;
cairo_point_t points[3];
+ cairo_point_t intersect_point;
stroker->has_initial_sub_path = TRUE;
stroker, &new_face);
assert(stroker->has_current_face);
+
+ if (_cairo_stroke_segment_intersect (&stroker->current_face.cw,
+ &stroker->current_face.ccw,
+ &new_face.cw,
+ &new_face.ccw,
+ &intersect_point)) {
+ points[0] = stroker->current_face.ccw;
+ points[1] = new_face.ccw;
+ points[2] = intersect_point;
+ stroker->add_triangle (stroker->closure, points);
+
points[0] = stroker->current_face.cw;
- points[1] = stroker->current_face.ccw;
+ points[1] = new_face.cw;
+ stroker->add_triangle (stroker->closure, points);
+ }
+ else {
+ points[0] = stroker->current_face.ccw;
+ points[1] = stroker->current_face.cw;
points[2] = new_face.cw;
stroker->add_triangle (stroker->closure, points);
points[1] = new_face.cw;
points[2] = new_face.ccw;
stroker->add_triangle (stroker->closure, points);
+ }
stroker->current_face = new_face;
stroker->has_current_face = TRUE;
}
cairo_int_status_t
-_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *stroke_style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_traps_t *traps)
+_cairo_path_fixed_stroke_polygon_to_traps (const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_traps_t *traps)
{
cairo_int_status_t status;
cairo_polygon_t polygon;
radius);
int num_vertices;
- if (tolerance >= 2*major_axis) {
+ if (tolerance >= 4*major_axis) { /* XXX relaxed from 2*major for inkscape */
num_vertices = 1;
} else if (tolerance >= major_axis) {
num_vertices = 4;
i = 0;
*start = i;
- lo = i;
- hi = i + pen->num_vertices;
- i = (lo + hi) >> 1;
- do {
- int j = i;
- if (j >= pen->num_vertices)
- j -= pen->num_vertices;
- if (_cairo_slope_compare (&pen->vertices[j].slope_cw, out) > 0)
- hi = i;
- else
- lo = i;
+ if (_cairo_slope_compare (out, &pen->vertices[i].slope_ccw) >= 0) {
+ lo = i;
+ hi = i + pen->num_vertices;
i = (lo + hi) >> 1;
- } while (hi - lo > 1);
- if (i >= pen->num_vertices)
- i -= pen->num_vertices;
+ do {
+ int j = i;
+ if (j >= pen->num_vertices)
+ j -= pen->num_vertices;
+ if (_cairo_slope_compare (&pen->vertices[j].slope_cw, out) > 0)
+ hi = i;
+ else
+ lo = i;
+ i = (lo + hi) >> 1;
+ } while (hi - lo > 1);
+ if (i >= pen->num_vertices)
+ i -= pen->num_vertices;
+ }
*stop = i;
}
i = 0;
*start = i;
- lo = i;
- hi = i + pen->num_vertices;
- i = (lo + hi) >> 1;
- do {
- int j = i;
- if (j >= pen->num_vertices)
- j -= pen->num_vertices;
- if (_cairo_slope_compare (out, &pen->vertices[j].slope_ccw) > 0)
- hi = i;
- else
- lo = i;
+ if (_cairo_slope_compare (&pen->vertices[i].slope_cw, out) <= 0) {
+ lo = i;
+ hi = i + pen->num_vertices;
i = (lo + hi) >> 1;
- } while (hi - lo > 1);
- if (i >= pen->num_vertices)
- i -= pen->num_vertices;
+ do {
+ int j = i;
+ if (j >= pen->num_vertices)
+ j -= pen->num_vertices;
+ if (_cairo_slope_compare (out, &pen->vertices[j].slope_ccw) > 0)
+ hi = i;
+ else
+ lo = i;
+ i = (lo + hi) >> 1;
+ } while (hi - lo > 1);
+ if (i >= pen->num_vertices)
+ i -= pen->num_vertices;
+ }
*stop = i;
}
if (box->p1.x == bbt->extents.p1.x && box->p1.y == bbt->extents.p1.y &&
box->p2.x == bbt->extents.p2.x && box->p2.y == bbt->extents.p2.y)
{
- header->chain = bbt->chain;
+ cairo_command_header_t *last = header;
+ while (last->chain) /* expected to be infrequent */
+ last = last->chain;
+ last->chain = bbt->chain;
bbt->chain = header;
return CAIRO_STATUS_SUCCESS;
}
_cairo_traps_init (&traps);
/* XXX call cairo_stroke_to_path() when that is implemented */
- status = _cairo_path_fixed_stroke_to_traps (&command->stroke.path,
- &command->stroke.style,
- &command->stroke.ctm,
- &command->stroke.ctm_inverse,
- command->stroke.tolerance,
- &traps);
+ status = _cairo_path_fixed_stroke_polygon_to_traps (&command->stroke.path,
+ &command->stroke.style,
+ &command->stroke.ctm,
+ &command->stroke.ctm_inverse,
+ command->stroke.tolerance,
+ &traps);
if (status == CAIRO_INT_STATUS_SUCCESS)
status = _cairo_traps_path (&traps, path);
*/
cairo_bool_t
-_cairo_box_intersects_line_segment (cairo_box_t *box, cairo_line_t *line)
+_cairo_box_intersects_line_segment (const cairo_box_t *box, cairo_line_t *line)
{
cairo_fixed_t t1=0, t2=0, t3=0, t4=0;
cairo_int64_t t1y, t2y, t3x, t4x;
CLEANUP_MUTEX_LOCK:
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
}
+
static void
-_cairo_scaled_glyph_page_destroy (void *closure)
+_cairo_scaled_glyph_page_destroy (cairo_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_page_t *page)
{
- cairo_scaled_glyph_page_t *page = closure;
- cairo_scaled_font_t *scaled_font;
unsigned int n;
- assert (! cairo_list_is_empty (&page->link));
+ assert (!scaled_font->cache_frozen);
+ assert (!scaled_font->global_cache_frozen);
- scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash;
for (n = 0; n < page->num_glyphs; n++) {
_cairo_hash_table_remove (scaled_font->glyphs,
&page->glyphs[n].hash_entry);
}
cairo_list_del (&page->link);
-
free (page);
}
+static void
+_cairo_scaled_glyph_page_pluck (void *closure)
+{
+ cairo_scaled_glyph_page_t *page = closure;
+ cairo_scaled_font_t *scaled_font;
+
+ assert (! cairo_list_is_empty (&page->link));
+
+ scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash;
+
+ CAIRO_MUTEX_LOCK (scaled_font->mutex);
+ _cairo_scaled_glyph_page_destroy (scaled_font, page);
+ CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
+}
+
/* If a scaled font wants to unlock the font map while still being
* created (needed for user-fonts), we need to take extra care not
* ending up with multiple identical scaled fonts being created.
void
_cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font)
{
- scaled_font->cache_frozen = FALSE;
+ assert (scaled_font->cache_frozen);
if (scaled_font->global_cache_frozen) {
CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
_cairo_cache_thaw (&cairo_scaled_glyph_page_cache);
CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
-
scaled_font->global_cache_frozen = FALSE;
}
+ scaled_font->cache_frozen = FALSE;
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
}
void
_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font)
{
+ CAIRO_MUTEX_LOCK (scaled_font->mutex);
assert (! scaled_font->cache_frozen);
-
+ assert (! scaled_font->global_cache_frozen);
CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
while (! cairo_list_is_empty (&scaled_font->glyph_pages)) {
- _cairo_cache_remove (&cairo_scaled_glyph_page_cache,
- &cairo_list_first_entry (&scaled_font->glyph_pages,
- cairo_scaled_glyph_page_t,
- link)->cache_entry);
+ cairo_scaled_glyph_page_t *page =
+ cairo_list_first_entry (&scaled_font->glyph_pages,
+ cairo_scaled_glyph_page_t,
+ link);
+
+ cairo_scaled_glyph_page_cache.size -= page->cache_entry.size;
+ _cairo_hash_table_remove (cairo_scaled_glyph_page_cache.hash_table,
+ (cairo_hash_entry_t *) &page->cache_entry);
+
+ _cairo_scaled_glyph_page_destroy (scaled_font, page);
}
CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
+ CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
}
cairo_status_t
static void
_cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
{
+ assert (! scaled_font->cache_frozen);
+ assert (! scaled_font->global_cache_frozen);
scaled_font->finished = TRUE;
_cairo_scaled_font_reset_cache (scaled_font);
* ft-font-faces
*/
assert (scaled_font->font_face == font_face);
+ assert (! scaled_font->cache_frozen);
+ assert (! scaled_font->global_cache_frozen);
scaled_font->original_font_face =
cairo_font_face_reference (original_font_face);
if (! _cairo_reference_count_dec_and_test (&scaled_font->ref_count))
return;
+ assert (! scaled_font->cache_frozen);
+ assert (! scaled_font->global_cache_frozen);
+
font_map = _cairo_scaled_font_map_lock ();
assert (font_map != NULL);
const cairo_glyph_t *glyph,
cairo_rectangle_int_t *extents)
{
- cairo_round_glyph_positions_t round_xy;
cairo_scaled_glyph_t *scaled_glyph;
cairo_status_t status;
- cairo_box_t box;
- cairo_fixed_t v;
+ _cairo_scaled_font_freeze_cache (scaled_font);
status = _cairo_scaled_glyph_lookup (scaled_font,
glyph->index,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
- if (unlikely (status))
- return status;
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ cairo_bool_t round_xy = _cairo_font_options_get_round_glyph_positions (&scaled_font->options) == CAIRO_ROUND_GLYPH_POS_ON;
+ cairo_box_t box;
+ cairo_fixed_t v;
- round_xy = _cairo_font_options_get_round_glyph_positions (&scaled_font->options);
- if (round_xy == CAIRO_ROUND_GLYPH_POS_ON)
- v = _cairo_fixed_from_int (_cairo_lround (glyph->x));
- else
- v = _cairo_fixed_from_double (glyph->x);
- box.p1.x = v + scaled_glyph->bbox.p1.x;
- box.p2.x = v + scaled_glyph->bbox.p2.x;
+ if (round_xy)
+ v = _cairo_fixed_from_int (_cairo_lround (glyph->x));
+ else
+ v = _cairo_fixed_from_double (glyph->x);
+ box.p1.x = v + scaled_glyph->bbox.p1.x;
+ box.p2.x = v + scaled_glyph->bbox.p2.x;
- if (round_xy == CAIRO_ROUND_GLYPH_POS_ON)
- v = _cairo_fixed_from_int (_cairo_lround (glyph->y));
- else
- v = _cairo_fixed_from_double (glyph->y);
- box.p1.y = v + scaled_glyph->bbox.p1.y;
- box.p2.y = v + scaled_glyph->bbox.p2.y;
+ if (round_xy)
+ v = _cairo_fixed_from_int (_cairo_lround (glyph->y));
+ else
+ v = _cairo_fixed_from_double (glyph->y);
+ box.p1.y = v + scaled_glyph->bbox.p1.y;
+ box.p2.y = v + scaled_glyph->bbox.p2.y;
- _cairo_box_round_to_rectangle (&box, extents);
- return CAIRO_STATUS_SUCCESS;
+ _cairo_box_round_to_rectangle (&box, extents);
+ }
+ _cairo_scaled_font_thaw_cache (scaled_font);
+ return status;
}
/*
cairo_scaled_glyph_page_t *page;
cairo_status_t status;
+ assert (scaled_font->cache_frozen);
+
/* only the first page in the list may contain available slots */
if (! cairo_list_is_empty (&scaled_font->glyph_pages)) {
page = cairo_list_last_entry (&scaled_font->glyph_pages,
status = _cairo_cache_init (&cairo_scaled_glyph_page_cache,
NULL,
_cairo_scaled_glyph_page_can_remove,
- _cairo_scaled_glyph_page_destroy,
+ _cairo_scaled_glyph_page_pluck,
MAX_GLYPH_PAGES_CACHED);
if (unlikely (status)) {
CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
return scaled_font->status;
assert (CAIRO_MUTEX_IS_LOCKED(scaled_font->mutex));
+ assert (scaled_font->cache_frozen);
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
* hold true for all possible cases.
*
* Return value: The #cairo_font_face_t with which @scaled_font was
- * created.
+ * created. This object is owned by cairo. To keep a reference to it,
+ * you must call cairo_scaled_font_reference().
*
* Since: 1.2
**/
glyphs[n].index,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
- if (unlikely (status))
+ if (unlikely (status)) {
+ _cairo_scaled_font_thaw_cache (scaled_font);
goto BAIL;
+ }
if (fabs (glyphs[n].x - x) > 1e-5 || fabs (glyphs[n].y - y) > 1e-5) {
if (fabs (glyphs[n].y - y) < 1e-5) {
typedef struct _cairo_abstract_span_renderer {
cairo_span_renderer_t base;
- char data[2048];
+ char data[4096];
} cairo_abstract_span_renderer_t;
struct cairo_spans_compositor {
TRACE ((stderr, "%s: need_clip_mask=%d, is-bounded=%d\n",
__FUNCTION__, need_clip_mask, extents->is_bounded));
- if (need_clip_mask && ! extents->is_bounded)
+ if (need_clip_mask && ! extents->is_bounded) {
+ TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
no_mask = extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
CAIRO_COLOR_IS_OPAQUE (&extents->mask_pattern.solid.color);
if (op == CAIRO_OPERATOR_SOURCE && (need_clip_mask || ! no_mask)) {
/* SOURCE with a mask is actually a LERP in cairo semantics */
- if ((compositor->flags & CAIRO_SPANS_COMPOSITOR_HAS_LERP) == 0)
+ if ((compositor->flags & CAIRO_SPANS_COMPOSITOR_HAS_LERP) == 0) {
+ TRACE ((stderr, "%s: unsupported lerp\n", __FUNCTION__));
return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
}
/* Are we just copying a recording surface? */
TRACE ((stderr, "%s\n", __FUNCTION__));
_cairo_box_from_rectangle (&box, &extents->unbounded);
- if (composite_needs_clip (extents, &box))
+ if (composite_needs_clip (extents, &box)) {
+ TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
_cairo_rectangular_scan_converter_init (&converter, &extents->unbounded);
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
cairo_bool_t needs_clip;
cairo_int_status_t status;
- needs_clip = ! extents->is_bounded &&
- (! _clip_is_region (extents->clip) || extents->clip->num_boxes > 1);
+ if (extents->is_bounded)
+ needs_clip = extents->clip->path != NULL;
+ else
+ needs_clip = !_clip_is_region (extents->clip) || extents->clip->num_boxes > 1;
TRACE ((stderr, "%s - needs_clip=%d\n", __FUNCTION__, needs_clip));
if (needs_clip) {
+ TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
return CAIRO_INT_STATUS_UNSUPPORTED;
converter = _cairo_clip_tor_scan_converter_create (extents->clip,
polygon,
const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
cairo_int_status_t status;
+ TRACE ((stderr, "%s\n", __FUNCTION__));
TRACE_ (_cairo_debug_print_path (stderr, path));
+ TRACE_ (_cairo_debug_print_clip (stderr, extents->clip));
status = CAIRO_INT_STATUS_UNSUPPORTED;
if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
}
}
+void
+_cairo_stroke_style_max_line_distance_from_path (const cairo_stroke_style_t *style,
+ const cairo_path_fixed_t *path,
+ const cairo_matrix_t *ctm,
+ double *dx, double *dy)
+{
+ double style_expansion = 0.5 * style->line_width;
+ if (_cairo_matrix_has_unity_scale (ctm)) {
+ *dx = *dy = style_expansion;
+ } else {
+ *dx = style_expansion * hypot (ctm->xx, ctm->xy);
+ *dy = style_expansion * hypot (ctm->yy, ctm->yx);
+ }
+}
+
+void
+_cairo_stroke_style_max_join_distance_from_path (const cairo_stroke_style_t *style,
+ const cairo_path_fixed_t *path,
+ const cairo_matrix_t *ctm,
+ double *dx, double *dy)
+{
+ double style_expansion = 0.5;
+
+ if (style->line_join == CAIRO_LINE_JOIN_MITER &&
+ ! path->stroke_is_rectilinear &&
+ style_expansion < M_SQRT2 * style->miter_limit)
+ {
+ style_expansion = M_SQRT2 * style->miter_limit;
+ }
+
+ style_expansion *= style->line_width;
+
+ if (_cairo_matrix_has_unity_scale (ctm)) {
+ *dx = *dy = style_expansion;
+ } else {
+ *dx = style_expansion * hypot (ctm->xx, ctm->xy);
+ *dy = style_expansion * hypot (ctm->yy, ctm->yx);
+ }
+}
/*
* Computes the period of a dashed stroke style.
* Returns 0 for non-dashed styles.
* memory and disk space.
*
* The recognized MIME types are the following: %CAIRO_MIME_TYPE_JPEG,
- * %CAIRO_MIME_TYPE_PNG, %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_URI.
+ * %CAIRO_MIME_TYPE_PNG, %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_URI,
+ * %CAIRO_MIME_TYPE_UNIQUE_ID.
*
* See corresponding backend surface docs for details about which MIME
* types it can handle. Caution: the associated MIME data will be
* The clip will trim that overestimate to our expectations.
*/
if (! extents->is_bounded)
- flags |= FORCE_CLIP_REGION;
+ flags |= FORCE_CLIP_REGION;
traps.antialias = antialias;
status = clip_and_composite (compositor, extents,
static cairo_int_status_t
clip_and_composite_traps (const cairo_traps_compositor_t *compositor,
cairo_composite_rectangles_t *extents,
- composite_traps_info_t *info)
+ composite_traps_info_t *info,
+ unsigned flags)
{
cairo_int_status_t status;
if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
return status;
- status = composite_traps_as_boxes (compositor, extents, info);
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if ((flags & FORCE_CLIP_REGION) == 0)
+ status = composite_traps_as_boxes (compositor, extents, info);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- unsigned int flags = 0;
-
/* For unbounded operations, the X11 server will estimate the
* affected rectangle and apply the operation to that. However,
* there are cases where this is an overestimate (e.g. the
}
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ cairo_int_status_t (*func) (const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_traps_t *traps);
composite_traps_info_t info;
+ unsigned flags = 0;
+
+ if (antialias == CAIRO_ANTIALIAS_BEST || antialias == CAIRO_ANTIALIAS_GOOD) {
+ func = _cairo_path_fixed_stroke_polygon_to_traps;
+ } else {
+ func = _cairo_path_fixed_stroke_to_traps;
+ if (extents->clip->num_boxes > 1 ||
+ extents->mask.width > extents->unbounded.width ||
+ extents->mask.height > extents->unbounded.height)
+ {
+ flags = NEED_CLIP_REGION | FORCE_CLIP_REGION;
+ }
+ }
info.antialias = antialias;
_cairo_traps_init_with_clip (&info.traps, extents->clip);
- status = _cairo_path_fixed_stroke_to_traps (path, style,
- ctm, ctm_inverse,
- tolerance,
- &info.traps);
+ status = func (path, style, ctm, ctm_inverse, tolerance, &info.traps);
if (likely (status == CAIRO_INT_STATUS_SUCCESS))
- status = clip_and_composite_traps (compositor, extents, &info);
+ status = clip_and_composite_traps (compositor, extents, &info, flags);
_cairo_traps_fini (&info.traps);
}
if (unlikely (status))
return status;
- _cairo_scaled_font_freeze_cache (scaled_font);
status = compositor->check_composite_glyphs (extents,
scaled_font, glyphs,
&num_glyphs);
need_bounded_clip (extents) |
flags);
}
- _cairo_scaled_font_thaw_cache (scaled_font);
return status;
}
struct _cairo_traps {
cairo_status_t status;
+ cairo_box_t bounds;
const cairo_box_t *limits;
int num_limits;
cairo_private void
_cairo_traps_translate (cairo_traps_t *traps, int x, int y);
+cairo_private void
+_cairo_traps_tessellate_triangle (cairo_traps_t *traps,
+ const cairo_point_t t[3]);
+
+cairo_private void
+_cairo_traps_tessellate_convex_quad (cairo_traps_t *traps,
+ const cairo_point_t q[4]);
+
cairo_private cairo_status_t
_cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
const cairo_point_t *top_left,
#include "cairoint.h"
+#include "cairo-box-inline.h"
#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-region-private.h"
const cairo_box_t *limits,
int num_limits)
{
+ int i;
+
traps->limits = limits;
traps->num_limits = num_limits;
+
+ traps->bounds = limits[0];
+ for (i = 1; i < num_limits; i++)
+ _cairo_box_add_box (&traps->bounds, &limits[i]);
}
void
trap->right = *right;
}
+static void
+_cairo_traps_add_clipped_trap (cairo_traps_t *traps,
+ cairo_fixed_t _top, cairo_fixed_t _bottom,
+ cairo_line_t *_left, cairo_line_t *_right)
+{
+ /* Note: With the goofy trapezoid specification, (where an
+ * arbitrary two points on the lines can specified for the left
+ * and right edges), these limit checks would not work in
+ * general. For example, one can imagine a trapezoid entirely
+ * within the limits, but with two points used to specify the left
+ * edge entirely to the right of the limits. Fortunately, for our
+ * purposes, cairo will never generate such a crazy
+ * trapezoid. Instead, cairo always uses for its points the
+ * extreme positions of the edge that are visible on at least some
+ * trapezoid. With this constraint, it's impossible for both
+ * points to be outside the limits while the relevant edge is
+ * entirely inside the limits.
+ */
+ if (traps->num_limits) {
+ const cairo_box_t *b = &traps->bounds;
+ cairo_fixed_t top = _top, bottom = _bottom;
+ cairo_line_t left = *_left, right = *_right;
+
+ /* Trivially reject if trapezoid is entirely to the right or
+ * to the left of the limits. */
+ if (left.p1.x >= b->p2.x && left.p2.x >= b->p2.x)
+ return;
+
+ if (right.p1.x <= b->p1.x && right.p2.x <= b->p1.x)
+ return;
+
+ /* And reject if the trapezoid is entirely above or below */
+ if (top >= b->p2.y || bottom <= b->p1.y)
+ return;
+
+ /* Otherwise, clip the trapezoid to the limits. We only clip
+ * where an edge is entirely outside the limits. If we wanted
+ * to be more clever, we could handle cases where a trapezoid
+ * edge intersects the edge of the limits, but that would
+ * require slicing this trapezoid into multiple trapezoids,
+ * and I'm not sure the effort would be worth it. */
+ if (top < b->p1.y)
+ top = b->p1.y;
+
+ if (bottom > b->p2.y)
+ bottom = b->p2.y;
+
+ if (left.p1.x <= b->p1.x && left.p2.x <= b->p1.x)
+ left.p1.x = left.p2.x = b->p1.x;
+
+ if (right.p1.x >= b->p2.x && right.p2.x >= b->p2.x)
+ right.p1.x = right.p2.x = b->p2.x;
+
+ /* Trivial discards for empty trapezoids that are likely to
+ * be produced by our tessellators (most notably convex_quad
+ * when given a simple rectangle).
+ */
+ if (top >= bottom)
+ return;
+
+ /* cheap colinearity check */
+ if (right.p1.x <= left.p1.x && right.p1.y == left.p1.y &&
+ right.p2.x <= left.p2.x && right.p2.y == left.p2.y)
+ return;
+
+ _cairo_traps_add_trap (traps, top, bottom, &left, &right);
+ } else
+ _cairo_traps_add_trap (traps, _top, _bottom, _left, _right);
+}
+
+static int
+_compare_point_fixed_by_y (const void *av, const void *bv)
+{
+ const cairo_point_t *a = av, *b = bv;
+ int ret = a->y - b->y;
+ if (ret == 0)
+ ret = a->x - b->x;
+ return ret;
+}
+
+void
+_cairo_traps_tessellate_convex_quad (cairo_traps_t *traps,
+ const cairo_point_t q[4])
+{
+ int a, b, c, d;
+ int i;
+ cairo_slope_t ab, ad;
+ cairo_bool_t b_left_of_d;
+ cairo_line_t left;
+ cairo_line_t right;
+
+ /* Choose a as a point with minimal y */
+ a = 0;
+ for (i = 1; i < 4; i++)
+ if (_compare_point_fixed_by_y (&q[i], &q[a]) < 0)
+ a = i;
+
+ /* b and d are adjacent to a, while c is opposite */
+ b = (a + 1) % 4;
+ c = (a + 2) % 4;
+ d = (a + 3) % 4;
+
+ /* Choose between b and d so that b.y is less than d.y */
+ if (_compare_point_fixed_by_y (&q[d], &q[b]) < 0) {
+ b = (a + 3) % 4;
+ d = (a + 1) % 4;
+ }
+
+ /* Without freedom left to choose anything else, we have four
+ * cases to tessellate.
+ *
+ * First, we have to determine the Y-axis sort of the four
+ * vertices, (either abcd or abdc). After that we need to detemine
+ * which edges will be "left" and which will be "right" in the
+ * resulting trapezoids. This can be determined by computing a
+ * slope comparison of ab and ad to determine if b is left of d or
+ * not.
+ *
+ * Note that "left of" here is in the sense of which edges should
+ * be the left vs. right edges of the trapezoid. In particular, b
+ * left of d does *not* mean that b.x is less than d.x.
+ *
+ * This should hopefully be made clear in the lame ASCII art
+ * below. Since the same slope comparison is used in all cases, we
+ * compute it before testing for the Y-value sort. */
+
+ /* Note: If a == b then the ab slope doesn't give us any
+ * information. In that case, we can replace it with the ac (or
+ * equivalenly the bc) slope which gives us exactly the same
+ * information we need. At worst the names of the identifiers ab
+ * and b_left_of_d are inaccurate in this case, (would be ac, and
+ * c_left_of_d). */
+ if (q[a].x == q[b].x && q[a].y == q[b].y)
+ _cairo_slope_init (&ab, &q[a], &q[c]);
+ else
+ _cairo_slope_init (&ab, &q[a], &q[b]);
+
+ _cairo_slope_init (&ad, &q[a], &q[d]);
+
+ b_left_of_d = _cairo_slope_compare (&ab, &ad) > 0;
+
+ if (q[c].y <= q[d].y) {
+ if (b_left_of_d) {
+ /* Y-sort is abcd and b is left of d, (slope(ab) > slope (ad))
+ *
+ * top bot left right
+ * _a a a
+ * / / /| |\ a.y b.y ab ad
+ * b / b | b \
+ * / / | | \ \ b.y c.y bc ad
+ * c / c | c \
+ * | / \| \ \ c.y d.y cd ad
+ * d d d
+ */
+ left.p1 = q[a]; left.p2 = q[b];
+ right.p1 = q[a]; right.p2 = q[d];
+ _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
+ left.p1 = q[b]; left.p2 = q[c];
+ _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right);
+ left.p1 = q[c]; left.p2 = q[d];
+ _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right);
+ } else {
+ /* Y-sort is abcd and b is right of d, (slope(ab) <= slope (ad))
+ *
+ * a a a_
+ * /| |\ \ \ a.y b.y ad ab
+ * / b | b \ b
+ * / / | | \ \ b.y c.y ad bc
+ * / c | c \ c
+ * / / |/ \ | c.y d.y ad cd
+ * d d d
+ */
+ left.p1 = q[a]; left.p2 = q[d];
+ right.p1 = q[a]; right.p2 = q[b];
+ _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
+ right.p1 = q[b]; right.p2 = q[c];
+ _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right);
+ right.p1 = q[c]; right.p2 = q[d];
+ _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right);
+ }
+ } else {
+ if (b_left_of_d) {
+ /* Y-sort is abdc and b is left of d, (slope (ab) > slope (ad))
+ *
+ * a a a
+ * // / \ |\ a.y b.y ab ad
+ * /b/ b \ b \
+ * / / \ \ \ \ b.y d.y bc ad
+ * /d/ \ d \ d
+ * // \ / \| d.y c.y bc dc
+ * c c c
+ */
+ left.p1 = q[a]; left.p2 = q[b];
+ right.p1 = q[a]; right.p2 = q[d];
+ _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
+ left.p1 = q[b]; left.p2 = q[c];
+ _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right);
+ right.p1 = q[d]; right.p2 = q[c];
+ _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right);
+ } else {
+ /* Y-sort is abdc and b is right of d, (slope (ab) <= slope (ad))
+ *
+ * a a a
+ * /| / \ \\ a.y b.y ad ab
+ * / b / b \b\
+ * / / / / \ \ b.y d.y ad bc
+ * d / d / \d\
+ * |/ \ / \\ d.y c.y dc bc
+ * c c c
+ */
+ left.p1 = q[a]; left.p2 = q[d];
+ right.p1 = q[a]; right.p2 = q[b];
+ _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
+ right.p1 = q[b]; right.p2 = q[c];
+ _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right);
+ left.p1 = q[d]; left.p2 = q[c];
+ _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right);
+ }
+ }
+}
+
+/* A triangle is simply a degenerate case of a convex
+ * quadrilateral. We would not benefit from having any distinct
+ * implementation of triangle vs. quadrilateral tessellation here. */
+void
+_cairo_traps_tessellate_triangle (cairo_traps_t *traps,
+ const cairo_point_t t[3])
+{
+ cairo_point_t quad[4];
+
+ quad[0] = t[0];
+ quad[1] = t[0];
+ quad[2] = t[1];
+ quad[3] = t[2];
+
+ _cairo_traps_tessellate_convex_quad (traps, quad);
+}
+
+
/**
* _cairo_traps_init_boxes:
* @traps: a #cairo_traps_t
cairo_bool_t reversed;
int n;
+ if (top >= traps->bounds.p2.y || bottom <= traps->bounds.p1.y)
+ return CAIRO_STATUS_SUCCESS;
+
/* support counter-clockwise winding for rectangular tessellation */
reversed = top_left->x > bottom_right->x;
if (reversed) {
left.p1.x = left.p2.x = bottom_right->x;
}
+ if (left.p1.x >= traps->bounds.p2.x || right.p1.x <= traps->bounds.p1.x)
+ return CAIRO_STATUS_SUCCESS;
+
for (n = 0; n < traps->num_limits; n++) {
const cairo_box_t *limits = &traps->limits[n];
cairo_line_t _left, _right;
#include "cairo-output-stream-private.h"
#include <ctype.h>
+#include <locale.h>
#define TYPE1_STACKSIZE 24 /* Defined in Type 1 Font Format */
const char *rd, *nd, *np;
+ int lenIV;
+
char *type1_data;
unsigned int type1_length;
char *type1_end;
int hex_column;
struct {
- int stack[TYPE1_STACKSIZE], sp, top_value;
+ double stack[TYPE1_STACKSIZE];
+ int sp;
} build_stack;
struct {
- int other_subr_args[TYPE1_STACKSIZE], num_other_subr_args, cur_other_subr_arg;
+ int stack[TYPE1_STACKSIZE];
+ int sp;
} ps_stack;
double *d)
{
const char *start, *end, *segment_end;
- int ret;
+ int ret, s_max, i, j;
char *s;
+ struct lconv *locale_data;
+ const char *decimal_point;
+ int decimal_point_len;
+
+ locale_data = localeconv ();
+ decimal_point = locale_data->decimal_point;
+ decimal_point_len = strlen (decimal_point);
+
+ assert (decimal_point_len != 0);
segment_end = font->header_segment + font->header_segment_size;
start = find_token (font->header_segment, segment_end, name);
if (end == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
- s = malloc (end - start + 1);
+ s_max = end - start + 5*decimal_point_len + 1;
+ s = malloc (s_max);
if (unlikely (s == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- strncpy (s, start, end - start);
- s[end - start] = 0;
+ i = 0;
+ j = 0;
+ while (i < end - start && j < s_max - decimal_point_len) {
+ if (start[i] == '.') {
+ strncpy(s + j, decimal_point, decimal_point_len);
+ i++;
+ j += decimal_point_len;
+ } else {
+ s[j++] = start[i++];
+ }
+ }
+ s[j] = 0;
start = strpbrk (s, "{[");
if (!start) {
return CAIRO_INT_STATUS_UNSUPPORTED;
}
-#define TYPE1_CHARSTRING_COMMAND_ESCAPE 0x0c
-#define TYPE1_CHARSTRING_COMMAND_SEAC 0x0c06
-#define TYPE1_CHARSTRING_COMMAND_SBW 0x0c07
-#define TYPE1_CHARSTRING_COMMAND_HSBW 0x0d
-#define TYPE1_CHARSTRING_COMMAND_CALLSUBR 0x0a
-#define TYPE1_CHARSTRING_COMMAND_CALLOTHERSUBR 0x0c10
-#define TYPE1_CHARSTRING_COMMAND_POP 0x0c11
-
-
-/* Get glyph width and look for seac operatorParse charstring */
+#define TYPE1_CHARSTRING_COMMAND_HSTEM 0x01
+#define TYPE1_CHARSTRING_COMMAND_VSTEM 0x03
+#define TYPE1_CHARSTRING_COMMAND_VMOVETO 0x04
+#define TYPE1_CHARSTRING_COMMAND_RLINETO 0x05
+#define TYPE1_CHARSTRING_COMMAND_HLINETO 0x06
+#define TYPE1_CHARSTRING_COMMAND_VLINETO 0x07
+#define TYPE1_CHARSTRING_COMMAND_RRCURVETO 0x08
+#define TYPE1_CHARSTRING_COMMAND_CLOSEPATH 0x09
+#define TYPE1_CHARSTRING_COMMAND_CALLSUBR 0x0a
+#define TYPE1_CHARSTRING_COMMAND_RETURN 0x0b
+#define TYPE1_CHARSTRING_COMMAND_ESCAPE 0x0c
+#define TYPE1_CHARSTRING_COMMAND_HSBW 0x0d
+#define TYPE1_CHARSTRING_COMMAND_ENDCHAR 0x0e
+#define TYPE1_CHARSTRING_COMMAND_RMOVETO 0x15
+#define TYPE1_CHARSTRING_COMMAND_HMOVETO 0x16
+#define TYPE1_CHARSTRING_COMMAND_VHCURVETO 0x1e
+#define TYPE1_CHARSTRING_COMMAND_HVCURVETO 0x1f
+#define TYPE1_CHARSTRING_COMMAND_DOTSECTION 0x0c00
+#define TYPE1_CHARSTRING_COMMAND_VSTEM3 0x0c01
+#define TYPE1_CHARSTRING_COMMAND_HSTEM3 0x0c02
+#define TYPE1_CHARSTRING_COMMAND_SEAC 0x0c06
+#define TYPE1_CHARSTRING_COMMAND_SBW 0x0c07
+#define TYPE1_CHARSTRING_COMMAND_DIV 0x0c0c
+#define TYPE1_CHARSTRING_COMMAND_CALLOTHERSUBR 0x0c10
+#define TYPE1_CHARSTRING_COMMAND_POP 0x0c11
+#define TYPE1_CHARSTRING_COMMAND_SETCURRENTPOINT 0x0c21
+
+/* Parse the charstring, including recursing into subroutines. Find
+ * the glyph width, subroutines called, and glyphs required by the
+ * SEAC operator. */
static cairo_status_t
cairo_type1_font_subset_parse_charstring (cairo_type1_font_subset_t *font,
int glyph,
unsigned char *charstring;
const unsigned char *end;
const unsigned char *p;
- cairo_bool_t last_op_was_integer;
int command;
- int subr_num, i;
charstring = malloc (encrypted_charstring_length);
if (unlikely (charstring == NULL))
encrypted_charstring_length,
charstring);
end = charstring + encrypted_charstring_length;
-
- p = charstring + 4;
-
- last_op_was_integer = FALSE;
-
+ p = charstring + font->lenIV;
+ status = CAIRO_STATUS_SUCCESS;
while (p < end) {
if (*p < 32) {
command = *p++;
switch (command) {
- case TYPE1_CHARSTRING_COMMAND_HSBW:
- if (! last_op_was_integer)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- font->glyphs[glyph].width = font->build_stack.stack[1]/font->base.units_per_em;
+ case TYPE1_CHARSTRING_COMMAND_HSTEM:
+ case TYPE1_CHARSTRING_COMMAND_VSTEM:
+ case TYPE1_CHARSTRING_COMMAND_VMOVETO:
+ case TYPE1_CHARSTRING_COMMAND_RLINETO:
+ case TYPE1_CHARSTRING_COMMAND_HLINETO:
+ case TYPE1_CHARSTRING_COMMAND_VLINETO:
+ case TYPE1_CHARSTRING_COMMAND_RRCURVETO:
+ case TYPE1_CHARSTRING_COMMAND_CLOSEPATH:
+ case TYPE1_CHARSTRING_COMMAND_RMOVETO:
+ case TYPE1_CHARSTRING_COMMAND_HMOVETO:
+ case TYPE1_CHARSTRING_COMMAND_VHCURVETO:
+ case TYPE1_CHARSTRING_COMMAND_HVCURVETO:
+ case TYPE1_CHARSTRING_COMMAND_RETURN:
+ case TYPE1_CHARSTRING_COMMAND_ENDCHAR:
+ default:
+ /* stack clearing operator */
font->build_stack.sp = 0;
- last_op_was_integer = FALSE;
break;
case TYPE1_CHARSTRING_COMMAND_CALLSUBR:
- if (font->subset_subrs &&
- last_op_was_integer &&
- font->build_stack.top_value >= 0 &&
- font->build_stack.top_value < font->num_subrs)
- {
- subr_num = font->build_stack.top_value;
- font->subrs[subr_num].used = TRUE;
- last_op_was_integer = FALSE;
- status = cairo_type1_font_subset_parse_charstring (font,
- glyph,
- font->subrs[subr_num].subr_string,
- font->subrs[subr_num].subr_length);
- } else {
- font->subset_subrs = FALSE;
+ if (font->subset_subrs && font->build_stack.sp > 0) {
+ double int_val;
+ if (modf(font->build_stack.stack[--font->build_stack.sp], &int_val) == 0.0) {
+ int subr_num = int_val;
+ if (subr_num >= 0 && subr_num < font->num_subrs) {
+ font->subrs[subr_num].used = TRUE;
+ status = cairo_type1_font_subset_parse_charstring (
+ font,
+ glyph,
+ font->subrs[subr_num].subr_string,
+ font->subrs[subr_num].subr_length);
+ break;
+ }
+ }
}
+ font->subset_subrs = FALSE;
+ break;
+
+ case TYPE1_CHARSTRING_COMMAND_HSBW:
+ if (font->build_stack.sp < 2) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
+
+ font->glyphs[glyph].width = font->build_stack.stack[1]/font->base.units_per_em;
+ font->build_stack.sp = 0;
break;
case TYPE1_CHARSTRING_COMMAND_ESCAPE:
command = command << 8 | *p++;
switch (command) {
+ case TYPE1_CHARSTRING_COMMAND_DOTSECTION:
+ case TYPE1_CHARSTRING_COMMAND_VSTEM3:
+ case TYPE1_CHARSTRING_COMMAND_HSTEM3:
+ case TYPE1_CHARSTRING_COMMAND_SETCURRENTPOINT:
+ default:
+ /* stack clearing operator */
+ font->build_stack.sp = 0;
+ break;
+
case TYPE1_CHARSTRING_COMMAND_SEAC:
/* The seac command takes five integer arguments. The
* last two are glyph indices into the PS standard
* glyph is composed from. All we need to do is to
* make sure those glyphs are present in the subset
* under their standard names. */
+ if (font->build_stack.sp < 5) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
+
status = use_standard_encoding_glyph (font, font->build_stack.stack[3]);
if (unlikely (status))
- return status;
+ goto cleanup;
status = use_standard_encoding_glyph (font, font->build_stack.stack[4]);
if (unlikely (status))
- return status;
+ goto cleanup;
font->build_stack.sp = 0;
- last_op_was_integer = FALSE;
break;
case TYPE1_CHARSTRING_COMMAND_SBW:
- if (! last_op_was_integer)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (font->build_stack.sp < 4) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
font->glyphs[glyph].width = font->build_stack.stack[2]/font->base.units_per_em;
font->build_stack.sp = 0;
- last_op_was_integer = FALSE;
break;
- case TYPE1_CHARSTRING_COMMAND_CALLOTHERSUBR:
- for (i = 0; i < font->build_stack.sp; i++)
- font->ps_stack.other_subr_args[i] = font->build_stack.stack[i];
- font->ps_stack.num_other_subr_args = font->build_stack.sp;
- font->ps_stack.cur_other_subr_arg = 0;
- font->build_stack.sp = 0;
- last_op_was_integer = FALSE;
+ case TYPE1_CHARSTRING_COMMAND_DIV:
+ if (font->build_stack.sp < 2) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ } else {
+ double num1 = font->build_stack.stack[font->build_stack.sp - 2];
+ double num2 = font->build_stack.stack[font->build_stack.sp - 1];
+ font->build_stack.sp--;
+ if (num2 == 0.0) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
+ font->build_stack.stack[font->build_stack.sp - 1] = num1/num2;
+ }
break;
+ case TYPE1_CHARSTRING_COMMAND_CALLOTHERSUBR:
+ if (font->build_stack.sp < 1) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
+
+ font->build_stack.sp--;
+ font->ps_stack.sp = 0;
+ while (font->build_stack.sp)
+ font->ps_stack.stack[font->ps_stack.sp++] = font->build_stack.stack[--font->build_stack.sp];
+
+ break;
+
case TYPE1_CHARSTRING_COMMAND_POP:
- if (font->ps_stack.num_other_subr_args > font->ps_stack.cur_other_subr_arg) {
- font->build_stack.top_value = font->ps_stack.other_subr_args[font->ps_stack.cur_other_subr_arg++];
- last_op_was_integer = TRUE;
- } else {
- font->subset_subrs = FALSE;
+ if (font->ps_stack.sp < 1) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
}
- break;
- default:
- font->build_stack.sp = 0;
- last_op_was_integer = FALSE;
+ /* T1 spec states that if the interpreter does not
+ * support executing the callothersub, the results
+ * must be taken from the callothersub arguments. */
+ font->build_stack.stack[font->build_stack.sp++] = font->ps_stack.stack[--font->ps_stack.sp];
break;
}
break;
-
- default:
- font->build_stack.sp = 0;
- last_op_was_integer = FALSE;
- break;
}
- } else {
+ } else {
/* integer argument */
- p = cairo_type1_font_subset_decode_integer (p, &font->build_stack.top_value);
- last_op_was_integer = TRUE;
- if (font->build_stack.sp < TYPE1_STACKSIZE)
- font->build_stack.stack[font->build_stack.sp++] = font->build_stack.top_value;
- }
+ if (font->build_stack.sp < TYPE1_STACKSIZE) {
+ int val;
+ p = cairo_type1_font_subset_decode_integer (p, &val);
+ font->build_stack.stack[font->build_stack.sp++] = val;
+ } else {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
+ }
}
+cleanup:
free (charstring);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
static cairo_status_t
{
cairo_status_t status;
const char *p, *subrs, *charstrings, *array_start, *array_end, *dict_start, *dict_end;
- const char *closefile_token;
- char buffer[32], *subr_count_end, *glyph_count_end;
- int length;
+ const char *lenIV_start, *lenIV_end, *closefile_token;
+ char buffer[32], *lenIV_str, *subr_count_end, *glyph_count_end;
+ int ret, lenIV, length;
const cairo_scaled_font_backend_t *backend;
unsigned int i;
int glyph, j;
* subroutines and charstrings not required.
*/
+ /* Determine lenIV, the number of random characters at the start of
+ each encrypted charstring. The defaults is 4, but this can be
+ overridden in the private dict. */
+ font->lenIV = 4;
+ if ((lenIV_start = find_token (font->cleartext, font->cleartext_end, "/lenIV")) != NULL) {
+ lenIV_start += 6;
+ lenIV_end = find_token (lenIV_start, font->cleartext_end, "def");
+ if (lenIV_end == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ lenIV_str = malloc (lenIV_end - lenIV_start + 1);
+ if (unlikely (lenIV_str == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ strncpy (lenIV_str, lenIV_start, lenIV_end - lenIV_start);
+ lenIV_str[lenIV_end - lenIV_start] = 0;
+
+ ret = sscanf(lenIV_str, "%d", &lenIV);
+ free(lenIV_str);
+
+ if (unlikely (ret <= 0))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* Apparently some fonts signal unencrypted charstrings with a negative lenIV,
+ though this is not part of the Type 1 Font Format specification. See, e.g.
+ http://lists.gnu.org/archive/html/freetype-devel/2000-06/msg00064.html. */
+ if (unlikely (lenIV < 0))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ font->lenIV = lenIV;
+ }
+
/* Find start of Subrs */
subrs = find_token (font->cleartext, font->cleartext_end, "/Subrs");
if (subrs == NULL) {
for (j = 0; j < font->num_glyphs; j++) {
glyph = font->subset_index_to_glyphs[j];
font->build_stack.sp = 0;
- font->ps_stack.num_other_subr_args = 0;
+ font->ps_stack.sp = 0;
status = cairo_type1_font_subset_parse_charstring (font,
glyph,
font->glyphs[glyph].encrypted_charstring,
return status;
}
+ /* Always include the first five subroutines in case the Flex/hint mechanism is
+ * being used. */
+ for (j = 0; j < MIN (font->num_subrs, 5); j++) {
+ font->subrs[j].used = TRUE;
+ }
+
closefile_token = find_token (dict_end, font->cleartext_end, "closefile");
if (closefile_token == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
free (font->subset_index_to_glyphs);
+ free (font->cleartext);
+
return status;
}
}
}
-void
-_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
- xcb_drawable_t dst,
- xcb_gcontext_t gc,
- int16_t src_x,
- int16_t src_y,
- uint16_t width,
- uint16_t height,
- uint16_t cpp,
- int stride,
- int16_t dst_x,
- int16_t dst_y,
- uint8_t depth,
- void *_data)
+static void
+_cairo_xcb_connection_do_put_subimage (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ uint16_t cpp,
+ int stride,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint8_t depth,
+ void *_data)
{
xcb_protocol_request_t xcb_req = {
0 /* count */,
free (vec);
}
+void
+_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ uint16_t cpp,
+ int stride,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint8_t depth,
+ void *_data)
+{
+ const uint32_t req_size = sizeof(xcb_put_image_request_t);
+ uint32_t length = height * cpp * width;
+ uint32_t len = (req_size + length) >> 2;
+
+ if (len < connection->maximum_request_length) {
+ _cairo_xcb_connection_do_put_subimage (connection, dst, gc, src_x, src_y,
+ width, height, cpp, stride, dst_x, dst_y, depth, _data);
+ } else {
+ int rows = (connection->maximum_request_length - req_size - 4) / (cpp * width);
+ if (rows > 0) {
+ do {
+ if (rows > height)
+ rows = height;
+
+ length = rows * cpp * width;
+
+ _cairo_xcb_connection_do_put_subimage (connection, dst, gc, src_x, src_y,
+ width, rows, cpp, stride, dst_x, dst_y, depth, _data);
+
+ height -= rows;
+ dst_y += rows;
+ _data = (char *) _data + stride * rows;
+ } while (height);
+ } else {
+ ASSERT_NOT_REACHED;
+ }
+ }
+}
+
cairo_status_t
_cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection,
xcb_drawable_t src,
struct _cairo_xcb_shm_mem_pool {
int shmid;
uint32_t shmseg;
+ void *shm;
cairo_mempool_t mem;
{
cairo_list_del (&pool->link);
- shmdt (pool->mem.base);
+ shmdt (pool->shm);
_cairo_mempool_fini (&pool->mem);
free (pool);
size_t shm_allocated = 0;
void *mem = NULL;
cairo_status_t status;
- void *base;
assert (connection->flags & CAIRO_XCB_HAS_SHM);
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- base = shmat (pool->shmid, NULL, 0);
- if (unlikely (base == (char *) -1)) {
+ pool->shm = shmat (pool->shmid, NULL, 0);
+ if (unlikely (pool->shm == (char *) -1)) {
shmctl (pool->shmid, IPC_RMID, NULL);
free (pool);
CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
- status = _cairo_mempool_init (&pool->mem, base, bytes,
+ status = _cairo_mempool_init (&pool->mem, pool->shm, bytes,
minbits, maxbits - minbits + 1);
if (unlikely (status)) {
- shmdt (base);
+ shmdt (pool->shm);
free (pool);
CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
return status;
shm_info->pool = pool;
shm_info->shm = pool->shmseg;
shm_info->size = size;
- shm_info->offset = (char *) mem - (char *) pool->mem.base;
+ shm_info->offset = (char *) mem - (char *) pool->shm;
shm_info->mem = mem;
shm_info->sync.sequence = XCB_NONE;
+++ /dev/null
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Intel Corporation
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * Contributor(s):
- * Chris Wilson <chris@chris-wilson.co.uk>
- */
-
-#include "cairoint.h"
-
-#include "cairo-clip-private.h"
-#include "cairo-xcb-private.h"
-
-cairo_int_status_t
-_cairo_xcb_surface_cairo_paint (cairo_xcb_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_clip_t *clip)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-cairo_int_status_t
-_cairo_xcb_surface_cairo_mask (cairo_xcb_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_pattern_t *mask,
- const cairo_clip_t *clip)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-cairo_int_status_t
-_cairo_xcb_surface_cairo_stroke (cairo_xcb_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-cairo_int_status_t
-_cairo_xcb_surface_cairo_fill (cairo_xcb_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-cairo_int_status_t
-_cairo_xcb_surface_cairo_glyphs (cairo_xcb_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_scaled_font_t *scaled_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- const cairo_clip_t *clip)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
return status;
}
-static void
-_clear_image (cairo_surface_t *surface)
-{
- cairo_image_surface_t *image = (cairo_image_surface_t *) surface;
- memset (image->data, 0, image->stride * image->height);
- surface->is_clear = TRUE;
-}
-
static cairo_status_t
_cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t *dst,
cairo_operator_t op,
if (unlikely (image->status))
return image->status;
- _clear_image (image);
-
clip = _cairo_clip_copy_region (extents->clip);
status = _cairo_surface_offset_stroke (image, x, y,
CAIRO_OPERATOR_ADD,
if (unlikely (image->status))
return image->status;
- _clear_image (image);
-
clip = _cairo_clip_copy_region (extents->clip);
status = _cairo_surface_offset_fill (image, x, y,
CAIRO_OPERATOR_ADD,
if (unlikely (image->status))
return image->status;
- _clear_image (image);
-
clip = _cairo_clip_copy_region (extents->clip);
status = _cairo_surface_offset_glyphs (image, x, y,
CAIRO_OPERATOR_ADD,
scaled_font = font->scaled_font;
- CAIRO_MUTEX_LOCK (scaled_font->mutex);
//scaled_font->surface_private = NULL;
_cairo_scaled_font_reset_cache (scaled_font);
- CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
_cairo_xcb_font_destroy (font);
}
if (unlikely (status))
return _cairo_surface_create_in_error (status);
+ if (! image->base.is_clear) {
+ memset (image->data, 0, image->stride * image->height);
+ image->base.is_clear = TRUE;
+ }
+
return &image->base;
}
Display *dpy;
Drawable drawable;
GC gc;
+ //cairo_surface_t *dither = NULL;
};
static cairo_bool_t fill_box (cairo_box_t *box, void *closure)
}
static cairo_int_status_t
-fill_boxes (cairo_xlib_surface_t *dst,
- const cairo_color_t *color,
- cairo_boxes_t *boxes)
+_fill_box_init (struct _fill_box *fb,
+ cairo_xlib_surface_t *dst,
+ const cairo_color_t *color)
{
- cairo_surface_t *dither = NULL;
- cairo_status_t status;
- struct _fill_box fb;
+ cairo_int_status_t status;
- status = _cairo_xlib_surface_get_gc (dst->display, dst, &fb.gc);
+ status = _cairo_xlib_surface_get_gc (dst->display, dst, &fb->gc);
if (unlikely (status))
return status;
- fb.dpy = dst->display->display;
- fb.drawable = dst->drawable;
+ fb->dpy = dst->display->display;
+ fb->drawable = dst->drawable;
if (dst->visual && dst->visual->class != TrueColor && 0) {
+#if 0
cairo_solid_pattern_t solid;
cairo_surface_attributes_t attrs;
_cairo_pattern_init_solid (&solid, color);
-#if 0
status = _cairo_pattern_acquire_surface (&solid.base, &dst->base,
0, 0,
ARRAY_LENGTH (dither_pattern[0]),
_cairo_xlib_surface_put_gc (dst->display, dst, fb.gc);
return status;
}
-#endif
- XSetTSOrigin (fb.dpy, fb.gc,
+ XSetTSOrigin (fb->dpy, fb->gc,
- (dst->base.device_transform.x0 + attrs.x_offset),
- (dst->base.device_transform.y0 + attrs.y_offset));
- XSetTile (fb.dpy, fb.gc, ((cairo_xlib_surface_t *) dither)->drawable);
+ XSetTile (fb->dpy, fb->gc, ((cairo_xlib_surface_t *) dither)->drawable);
+#endif
} else {
XGCValues gcv;
gcv.foreground = color_to_pixel (dst, color);
gcv.fill_style = FillSolid;
- XChangeGC (fb.dpy, fb.gc, GCFillStyle | GCForeground, &gcv);
+ XChangeGC (fb->dpy, fb->gc, GCFillStyle | GCForeground, &gcv);
}
+ return CAIRO_INT_STATUS_SUCCESS;
+}
+
+static void
+_fill_box_fini (struct _fill_box *fb,
+ cairo_xlib_surface_t *dst)
+{
+ _cairo_xlib_surface_put_gc (dst->display, dst, fb->gc);
+ //cairo_surface_destroy (fb->dither);
+}
+
+cairo_int_status_t
+_cairo_xlib_core_fill_boxes (cairo_xlib_surface_t *dst,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes)
+{
+ cairo_int_status_t status;
+ struct _fill_box fb;
+
+ status = _fill_box_init (&fb, dst, color);
+ if (unlikely (status))
+ return status;
+
_cairo_boxes_for_each_box (boxes, fill_box, &fb);
- _cairo_xlib_surface_put_gc (dst->display, dst, fb.gc);
+ _fill_box_fini (&fb, dst);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_int_status_t
+_cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t *dst,
+ const cairo_color_t *color,
+ int num_rects,
+ cairo_rectangle_int_t *rects)
+{
+ cairo_int_status_t status;
+ struct _fill_box fb;
+ int i;
+
+ status = _fill_box_init (&fb, dst, color);
+ if (unlikely (status))
+ return status;
- cairo_surface_destroy (dither);
+ for (i = 0; i < num_rects; i++)
+ XFillRectangle (fb.dpy, fb.drawable, fb.gc,
+ rects[i].x, rects[i].y,
+ rects[i].width, rects[i].height);
+ _fill_box_fini (&fb, dst);
return CAIRO_STATUS_SUCCESS;
}
return status;
if (src->type == CAIRO_PATTERN_TYPE_SOLID) {
- status = fill_boxes (dst,
- &((cairo_solid_pattern_t *) src)->color,
- boxes);
+ status = _cairo_xlib_core_fill_boxes
+ (dst, &((cairo_solid_pattern_t *) src)->color, boxes);
} else {
status = upload_image_inplace (dst, src, boxes);
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
goto UNLOCK;
}
+ _cairo_device_init (&display->base, &_cairo_xlib_device_backend);
+
+ display->display = dpy;
+ cairo_list_init (&display->screens);
+ cairo_list_init (&display->fonts);
+ display->closed = FALSE;
+
/* Xlib calls out to the extension close_display hooks in LIFO
* order. So we have to ensure that all extensions that we depend
* on in our close_display hook are properly initialized before we
_cairo_xlib_display_select_compositor (display);
- codes = XAddExtension (dpy);
- if (unlikely (codes == NULL)) {
- device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
- free (display);
- goto UNLOCK;
- }
-
- _cairo_device_init (&display->base, &_cairo_xlib_device_backend);
-
- XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
-
- cairo_device_reference (&display->base); /* add one for the CloseDisplay */
- display->display = dpy;
- cairo_list_init (&display->screens);
- cairo_list_init (&display->fonts);
- display->closed = FALSE;
-
display->white = NULL;
memset (display->alpha, 0, sizeof (display->alpha));
memset (display->solid, 0, sizeof (display->solid));
* safest to just blacklist all old-versioning-scheme X servers,
* (just using VendorRelease < 70000000), as buggy_repeat=TRUE.
*/
- if (strstr (ServerVendor (dpy), "X.Org") != NULL) {
+ if (_cairo_xlib_vendor_is_xorg (dpy)) {
if (VendorRelease (dpy) >= 60700000) {
if (VendorRelease (dpy) < 70000000)
display->buggy_repeat = TRUE;
display->buggy_pad_reflect = TRUE;
}
+ codes = XAddExtension (dpy);
+ if (unlikely (codes == NULL)) {
+ device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
+ free (display);
+ goto UNLOCK;
+ }
+
+ XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
+ cairo_device_reference (&display->base); /* add one for the CloseDisplay */
+
display->next = _cairo_xlib_display_list;
_cairo_xlib_display_list = display;
#include "cairo-surface-private.h"
#include <pixman.h>
+#include <string.h>
typedef struct _cairo_xlib_display cairo_xlib_display_t;
typedef struct _cairo_xlib_shm_display cairo_xlib_shm_display_t;
cairo_surface_t base;
Picture picture;
+ Drawable drawable;
const cairo_compositor_t *compositor;
cairo_surface_t *shm;
cairo_list_t link;
Display *dpy; /* only valid between acquire/release */
- Drawable drawable;
cairo_bool_t owns_pixmap;
Visual *visual;
cairo_surface_t base;
Picture picture;
+ Pixmap pixmap;
Display *dpy;
unsigned int filter:3;
cairo_surface_t *owner;
};
+inline static cairo_bool_t
+_cairo_xlib_vendor_is_xorg (Display *dpy)
+{
+ const char *const vendor = ServerVendor (dpy);
+ return strstr (vendor, "X.Org") || strstr (vendor, "Xorg");
+}
+
cairo_private cairo_status_t
_cairo_xlib_surface_get_gc (cairo_xlib_display_t *display,
cairo_xlib_surface_t *surface,
return dst->screen == src->screen;
}
+cairo_private cairo_int_status_t
+_cairo_xlib_core_fill_boxes (cairo_xlib_surface_t *dst,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes);
+
+cairo_private cairo_int_status_t
+_cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t *dst,
+ const cairo_color_t *color,
+ int num_rects,
+ cairo_rectangle_int_t *rects);
+
static inline void
_cairo_xlib_surface_put_gc (cairo_xlib_display_t *display,
cairo_xlib_surface_t *surface,
cairo_private pixman_format_code_t
_pixman_format_for_xlib_surface (cairo_xlib_surface_t *surface);
-
#endif /* CAIRO_XLIB_PRIVATE_H */
#include "cairo-tristrip-private.h"
static cairo_int_status_t
+check_composite (const cairo_composite_rectangles_t *extents)
+{
+ cairo_xlib_display_t *display = ((cairo_xlib_surface_t *)extents->surface)->display;
+
+ if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
acquire (void *abstract_dst)
{
cairo_xlib_surface_t *dst = abstract_dst;
int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
+ _cairo_xlib_shm_surface_mark_active (&image->base);
XCopyArea (dst->dpy, src, dst->drawable, gc,
x1 + dx, y1 + dy,
x2 - x1, y2 - y1,
int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
- rects[j].x = x1;
- rects[j].y = y1;
- rects[j].width = x2 - x1;
- rects[j].height = y2 - y1;
- j++;
+ if (x2 > x1 && y2 > y1) {
+ rects[j].x = x1;
+ rects[j].y = y1;
+ rects[j].width = x2 - x1;
+ rects[j].height = y2 - y1;
+ j++;
+ }
}
}
- assert (j == boxes->num_boxes);
XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, Unsorted);
-
+ _cairo_xlib_shm_surface_mark_active (&image->base);
XCopyArea (dst->dpy, src, dst->drawable, gc,
- dx, dy,
- image->width, image->height,
- 0, 0);
-
+ 0, 0, image->width, image->height, -dx, -dy);
XSetClipMask (dst->dpy, gc, None);
if (rects != stack_rects)
free (rects);
}
- _cairo_xlib_shm_surface_mark_active (&image->base);
_cairo_xlib_surface_put_gc (dst->display, dst, gc);
release (dst);
return CAIRO_STATUS_SUCCESS;
{
cairo_xlib_surface_t *dst = _dst;
struct _cairo_boxes_chunk *chunk;
- cairo_image_surface_t *shm;
+ cairo_image_surface_t *shm = NULL;
cairo_int_status_t status;
int i;
- if (image->base.device == dst->base.device &&
- image->depth == dst->depth &&
- _cairo_xlib_shm_surface_get_pixmap (&image->base))
+ if (image->base.device == dst->base.device) {
+ if (image->depth != dst->depth)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (_cairo_xlib_shm_surface_get_pixmap (&image->base))
return copy_image_boxes (dst, image, boxes, dx, dy);
- shm = NULL;
+ goto draw_image_boxes;
+ }
+
if (boxes_cover_surface (boxes, dst))
shm = (cairo_image_surface_t *) _cairo_xlib_surface_get_shm (dst, TRUE);
if (shm) {
if (_cairo_xlib_shm_surface_get_pixmap (&image->base)) {
status = copy_image_boxes (dst, image, boxes, dx, dy);
- goto out;
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ goto out;
}
}
}
+draw_image_boxes:
status = CAIRO_STATUS_SUCCESS;
for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
int y1 = _cairo_fixed_integer_part (b->p1.y);
int x2 = _cairo_fixed_integer_part (b->p2.x);
int y2 = _cairo_fixed_integer_part (b->p2.y);
- if ( _cairo_xlib_surface_draw_image (dst, image,
- x1 + dx, y1 + dy,
- x2 - x1, y2 - y1,
- x1, y1)) {
+ if (_cairo_xlib_surface_draw_image (dst, image,
+ x1 + dx, y1 + dy,
+ x2 - x1, y2 - y1,
+ x1, y1)) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto out;
}
//X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
+ if (fill_reduces_to_source (op, color, dst))
+ op = CAIRO_OPERATOR_SOURCE;
+
+ if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
+ cairo_int_status_t status;
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (op == CAIRO_OPERATOR_SOURCE)
+ status = _cairo_xlib_core_fill_rectangles (dst, color, num_rects, rects);
+ return status;
+ }
+
render_color.red = color->red_short;
render_color.green = color->green_short;
render_color.blue = color->blue_short;
render_color.alpha = color->alpha_short;
- if (fill_reduces_to_source (op, color, dst))
- op = CAIRO_OPERATOR_SOURCE;
-
_cairo_xlib_surface_ensure_picture (dst);
if (num_rects == 1) {
/* Take advantage of the protocol compaction that libXrender performs
cairo_xlib_surface_t *dst = abstract_surface;
XRenderColor render_color;
+ if (fill_reduces_to_source (op, color, dst))
+ op = CAIRO_OPERATOR_SOURCE;
+
+ if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
+ cairo_int_status_t status;
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (op == CAIRO_OPERATOR_SOURCE)
+ status = _cairo_xlib_core_fill_boxes (dst, color, boxes);
+ return status;
+ }
+
render_color.red = color->red_short;
render_color.green = color->green_short;
render_color.blue = color->blue_short;
render_color.alpha = color->alpha_short;
- if (fill_reduces_to_source (op, color, dst))
- op = CAIRO_OPERATOR_SOURCE;
-
_cairo_xlib_surface_ensure_picture (dst);
if (boxes->num_boxes == 1) {
int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
cairo_xlib_display_t *display = dst->display;
int max_request_size, size;
+ TRACE ((stderr, "%s\n", __FUNCTION__));
+
if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
return CAIRO_INT_STATUS_UNSUPPORTED;
compositor.fill_rectangles = fill_rectangles;
compositor.fill_boxes = fill_boxes;
compositor.copy_boxes = copy_boxes;
- //compositor.check_composite = check_composite;
+ compositor.check_composite = check_composite;
compositor.composite = composite;
//compositor.check_composite_boxes = check_composite_boxes;
compositor.composite_boxes = composite_boxes;
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
-check_composite (const cairo_composite_rectangles_t *extents)
-{
- cairo_xlib_display_t *display = ((cairo_xlib_surface_t *)extents->surface)->display;
-
- if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
const cairo_compositor_t *
_cairo_xlib_traps_compositor_get (void)
{
#include "cairo-xlib-surface-private.h"
#include "cairo-error-private.h"
-#include "cairo-image-surface-private.h"
+#include "cairo-image-surface-inline.h"
#include "cairo-paginated-private.h"
#include "cairo-pattern-inline.h"
#include "cairo-recording-surface-private.h"
cairo_xlib_source_t *source = abstract_surface;
XRenderFreePicture (source->dpy, source->picture);
+ if (source->pixmap)
+ XFreePixmap (source->dpy, source->pixmap);
return CAIRO_STATUS_SUCCESS;
}
{
cairo_xlib_proxy_t *proxy = abstract_surface;
- XRenderFreePicture (proxy->source.dpy, proxy->source.picture);
_cairo_xlib_shm_surface_mark_active (proxy->owner);
+ XRenderFreePicture (proxy->source.dpy, proxy->source.picture);
+ if (proxy->source.pixmap)
+ XFreePixmap (proxy->source.dpy, proxy->source.pixmap);
cairo_surface_destroy (proxy->owner);
return CAIRO_STATUS_SUCCESS;
}
};
static cairo_surface_t *
-source (cairo_xlib_surface_t *dst, Picture picture)
+source (cairo_xlib_surface_t *dst, Picture picture, Pixmap pixmap)
{
cairo_xlib_source_t *source;
if (picture == None)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- source = malloc (sizeof (cairo_image_surface_t));
+ source = malloc (sizeof (*source));
if (unlikely (source == NULL)) {
XRenderFreePicture (dst->display->display, picture);
+ if (pixmap)
+ XFreePixmap (dst->display->display, pixmap);
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
/* The source exists only within an operation */
source->picture = picture;
+ source->pixmap = pixmap;
source->dpy = dst->display->display;
return &source->base;
return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y);
}
- return source (dst, picture);
+ return source (dst, picture, None);
}
static cairo_surface_t *
color_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
{
- XRenderColor xrender_color;
+ Display *dpy = dst->display->display;
+ XRenderColor xcolor;
+ Picture picture;
+ Pixmap pixmap = None;
+
+ xcolor.red = color->red_short;
+ xcolor.green = color->green_short;
+ xcolor.blue = color->blue_short;
+ xcolor.alpha = color->alpha_short;
- xrender_color.red = color->red_short;
- xrender_color.green = color->green_short;
- xrender_color.blue = color->blue_short;
- xrender_color.alpha = color->alpha_short;
+ if (CAIRO_RENDER_HAS_GRADIENTS(dst->display)) {
+ picture = XRenderCreateSolidFill (dpy, &xcolor);
+ } else {
+ XRenderPictureAttributes pa;
+ int mask = 0;
+
+ pa.repeat = RepeatNormal;
+ mask |= CPRepeat;
- return source (dst,
- XRenderCreateSolidFill (dst->display->display,
- &xrender_color));
+ pixmap = XCreatePixmap (dpy, dst->drawable, 1, 1, 32);
+ picture = XRenderCreatePicture (dpy, pixmap,
+ _cairo_xlib_display_get_xrender_format (dst->display, CAIRO_FORMAT_ARGB32),
+ mask, &pa);
+
+ if (CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
+ XRectangle r = { 0, 0, 1, 1};
+ XRenderFillRectangles (dpy, PictOpSrc, picture, &xcolor, &r, 1);
+ } else {
+ XGCValues gcv;
+ GC gc;
+
+ gc = _cairo_xlib_screen_get_gc (dst->display, dst->screen,
+ 32, pixmap);
+ if (unlikely (gc == NULL)) {
+ XFreePixmap (dpy, pixmap);
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+
+ gcv.foreground = 0;
+ gcv.foreground |= color->alpha_short >> 8 << 24;
+ gcv.foreground |= color->red_short >> 8 << 16;
+ gcv.foreground |= color->green_short >> 8 << 8;
+ gcv.foreground |= color->blue_short >> 8 << 0;
+ gcv.fill_style = FillSolid;
+
+ XChangeGC (dpy, gc, GCFillStyle | GCForeground, &gcv);
+ XFillRectangle (dpy, pixmap, gc, 0, 0, 1, 1);
+
+ _cairo_xlib_screen_put_gc (dst->display, dst->screen, 32, gc);
+ }
+ }
+
+ return source (dst, picture, pixmap);
}
static cairo_surface_t *
cairo_xlib_surface_t *xsrc;
cairo_surface_pattern_t local_pattern;
cairo_status_t status;
- cairo_rectangle_int_t upload, limit, map_extents;
- cairo_matrix_t m;
+ cairo_rectangle_int_t upload, limit;
src = pattern->surface;
if (src->type == CAIRO_SURFACE_TYPE_IMAGE &&
_cairo_xlib_shm_surface_get_pixmap (src)) {
cairo_xlib_proxy_t *proxy;
- cairo_surface_reference (src);
-
-prepare_shm_image:
proxy = malloc (sizeof(*proxy));
- if (unlikely (proxy == NULL)) {
- cairo_surface_destroy (src);
+ if (unlikely (proxy == NULL))
return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
- }
_cairo_surface_init (&proxy->source.base,
&cairo_xlib_proxy_backend,
dst->base.device,
- CAIRO_CONTENT_COLOR_ALPHA);
+ src->content);
proxy->source.dpy = dst->display->display;
proxy->source.picture = XRenderCreatePicture (proxy->source.dpy,
_cairo_xlib_shm_surface_get_pixmap (src),
_cairo_xlib_shm_surface_get_xrender_format (src),
0, NULL);
+ proxy->source.pixmap = None;
proxy->source.has_component_alpha = 0;
proxy->source.has_matrix = 0;
proxy->source.filter = CAIRO_FILTER_NEAREST;
proxy->source.extend = CAIRO_EXTEND_NONE;
- proxy->owner = src;
+ proxy->owner = cairo_surface_reference (src);
return embedded_source (dst, pattern, extents, src_x, src_y,
&proxy->source);
}
}
- src = _cairo_xlib_surface_create_similar_shm (&dst->base,
- _cairo_format_from_content (pattern->surface->content),
- upload.width,
- upload.height);
+ xsrc = (cairo_xlib_surface_t *)
+ _cairo_surface_create_similar_scratch (&dst->base,
+ src->content,
+ upload.width,
+ upload.height);
+ if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ cairo_surface_destroy (src);
+ cairo_surface_destroy (&xsrc->base);
+ return None;
+ }
- _cairo_pattern_init_for_surface (&local_pattern, pattern->surface);
- cairo_matrix_init_translate (&local_pattern.base.matrix,
- upload.x, upload.y);
+ if (_cairo_surface_is_image (src)) {
+ status = _cairo_xlib_surface_draw_image (xsrc, (cairo_image_surface_t *)src,
+ upload.x, upload.y,
+ upload.width, upload.height,
+ 0, 0);
+ } else {
+ cairo_image_surface_t *image;
+ cairo_rectangle_int_t map_extents = { 0,0, upload.width,upload.height };
- map_extents = upload;
- map_extents.x = map_extents.y = 0;
+ image = _cairo_surface_map_to_image (&xsrc->base, &map_extents);
- status = _cairo_surface_paint (src,
- CAIRO_OPERATOR_SOURCE,
- &local_pattern.base,
- NULL);
- _cairo_pattern_fini (&local_pattern.base);
+ _cairo_pattern_init_for_surface (&local_pattern, pattern->surface);
+ cairo_matrix_init_translate (&local_pattern.base.matrix,
+ upload.x, upload.y);
- if (unlikely (status)) {
- cairo_surface_destroy (src);
- return _cairo_surface_create_in_error (status);
+ status = _cairo_surface_paint (&image->base,
+ CAIRO_OPERATOR_SOURCE,
+ &local_pattern.base,
+ NULL);
+ _cairo_pattern_fini (&local_pattern.base);
+
+ status = _cairo_surface_unmap_image (&xsrc->base, image);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&xsrc->base);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ status = _cairo_xlib_surface_put_shm (xsrc);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&xsrc->base);
+ return _cairo_surface_create_in_error (status);
+ }
}
_cairo_pattern_init_static_copy (&local_pattern.base, &pattern->base);
if (upload.x | upload.y) {
+ cairo_matrix_t m;
cairo_matrix_init_translate (&m, -upload.x, -upload.y);
cairo_matrix_multiply (&local_pattern.base.matrix,
&local_pattern.base.matrix,
}
*src_x = *src_y = 0;
- if (src->device == dst->base.device &&
- _cairo_xlib_shm_surface_get_pixmap (src)) {
- pattern = &local_pattern;
- goto prepare_shm_image;
- }
-
- xsrc = (cairo_xlib_surface_t *)
- _cairo_surface_create_similar_scratch (&dst->base,
- src->content,
- upload.width,
- upload.height);
- if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) {
- cairo_surface_destroy (src);
- cairo_surface_destroy (&xsrc->base);
- return None;
- }
-
- status = _cairo_xlib_surface_draw_image (xsrc, (cairo_image_surface_t *)src,
- 0, 0,
- upload.width, upload.height,
- 0, 0);
- cairo_surface_destroy (src);
-
_cairo_xlib_surface_ensure_picture (xsrc);
if (! picture_set_properties (xsrc->display,
xsrc->picture,
#include "cairo-xlib-private.h"
#include "cairo-xlib-surface-private.h"
-#include "cairo-image-surface-private.h"
-#include "cairo-mempool-private.h"
+
+#if !HAVE_X11_EXTENSIONS_XSHM_H || !(HAVE_X11_EXTENSIONS_SHMPROTO_H || HAVE_X11_EXTENSIONS_SHMSTR_H)
+void _cairo_xlib_display_init_shm (cairo_xlib_display_t *display) {}
+
+cairo_surface_t *
+_cairo_xlib_surface_get_shm (cairo_xlib_surface_t *surface,
+ cairo_bool_t overwrite)
+{
+ return NULL;
+}
+
+cairo_int_status_t
+_cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
+{
+ assert (!surface->fallback);
+ return CAIRO_INT_STATUS_SUCCESS;
+}
+
+cairo_surface_t *
+_cairo_xlib_surface_create_shm (cairo_xlib_surface_t *other,
+ pixman_format_code_t format,
+ int width, int height)
+{
+ return NULL;
+}
+
+cairo_surface_t *
+_cairo_xlib_surface_create_shm__image (cairo_xlib_surface_t *surface,
+ pixman_format_code_t format,
+ int width, int height)
+{
+ return NULL;
+}
+
+cairo_surface_t *
+_cairo_xlib_surface_create_similar_shm (void *other,
+ cairo_format_t format,
+ int width, int height)
+{
+ return cairo_image_surface_create (format, width, height);
+}
+
+void
+_cairo_xlib_shm_surface_mark_active (cairo_surface_t *_shm)
+{
+ ASSERT_NOT_REACHED;
+}
+
+void
+_cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface,
+ XImage *ximage)
+{
+ ASSERT_NOT_REACHED;
+}
+
+void *
+_cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface)
+{
+ ASSERT_NOT_REACHED;
+ return NULL;
+}
+
+Pixmap
+_cairo_xlib_shm_surface_get_pixmap (cairo_surface_t *surface)
+{
+ ASSERT_NOT_REACHED;
+ return 0;
+}
+
+XRenderPictFormat *
+_cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface)
+{
+ ASSERT_NOT_REACHED;
+ return NULL;
+}
+
+cairo_bool_t
+_cairo_xlib_shm_surface_is_active (cairo_surface_t *surface)
+{
+ ASSERT_NOT_REACHED;
+ return FALSE;
+}
+
+cairo_bool_t
+_cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface)
+{
+ ASSERT_NOT_REACHED;
+ return TRUE;
+}
+
+void _cairo_xlib_display_fini_shm (cairo_xlib_display_t *display) {}
+
+#else
#include "cairo-damage-private.h"
#include "cairo-default-context-private.h"
+#include "cairo-image-surface-private.h"
#include "cairo-list-inline.h"
+#include "cairo-mempool-private.h"
#include <X11/Xlibint.h>
#include <X11/Xproto.h>
#include <X11/extensions/XShm.h>
+#if HAVE_X11_EXTENSIONS_SHMPROTO_H
#include <X11/extensions/shmproto.h>
+#elif HAVE_X11_EXTENSIONS_SHMSTR_H
+#include <X11/extensions/shmstr.h>
+#endif
#include <sys/ipc.h>
#include <sys/shm.h>
int event;
Window window;
+ unsigned long last_request;
+ unsigned long last_event;
cairo_list_t surfaces;
static inline cairo_bool_t
seqno_passed (unsigned long a, unsigned long b)
{
+ return (long)(b - a) >= 0;
+}
+
+static inline cairo_bool_t
+seqno_before (unsigned long a, unsigned long b)
+{
return (long)(b - a) > 0;
}
+static inline cairo_bool_t
+seqno_after (unsigned long a, unsigned long b)
+{
+ return (long)(a - b) > 0;
+}
+
static inline cairo_status_t
_pqueue_init (struct pqueue *pq)
{
return LastKnownRequestProcessed (peek_display(device));
}
-static unsigned next_request (cairo_device_t *device)
-{
- return NextRequest (peek_display (device));
-}
-
static void
_cairo_xlib_display_shm_pool_destroy (cairo_xlib_display_t *display,
cairo_xlib_shm_t *pool)
free (pool);
}
+static void send_event(cairo_xlib_display_t *display,
+ cairo_xlib_shm_info_t *info,
+ unsigned long seqno)
+{
+ XShmCompletionEvent ev;
+
+ if (! seqno_after (seqno, display->shm->last_event))
+ return;
+
+ ev.type = display->shm->event;
+ ev.send_event = 1; /* XXX or lie? */
+ ev.serial = NextRequest (display->display);
+ ev.drawable = display->shm->window;
+ ev.major_code = display->shm->opcode;
+ ev.minor_code = X_ShmPutImage;
+ ev.shmseg = info->pool->shm.shmid;
+ ev.offset = (char *)info->mem - (char *)info->pool->shm.shmaddr;
+
+ XSendEvent (display->display, ev.drawable, False, 0, (XEvent *)&ev);
+
+ display->shm->last_event = ev.serial;
+}
+
+static void sync (cairo_xlib_display_t *display)
+{
+ cairo_xlib_shm_info_t *info;
+ struct pqueue *pq = &display->shm->info;
+
+ XSync (display->display, False);
+
+ while ((info = PQ_TOP(pq))) {
+ _cairo_mempool_free (&info->pool->mem, info->mem);
+ _pqueue_pop (&display->shm->info);
+ free (info);
+ }
+}
+
static void
_cairo_xlib_shm_info_cleanup (cairo_xlib_display_t *display)
{
info = PQ_TOP(pq);
do {
- if (! seqno_passed (info->last_request, processed))
- break;
+ if (! seqno_passed (info->last_request, processed)) {
+ send_event (display, info, display->shm->last_request);
+ return;
+ }
_cairo_mempool_free (&info->pool->mem, info->mem);
_pqueue_pop (&display->shm->info);
} while ((info = PQ_TOP(pq)));
}
-static cairo_xlib_shm_info_t *
-_cairo_xlib_shm_info_find (cairo_xlib_display_t *display,
- size_t size, unsigned long *last_request)
+static cairo_xlib_shm_t *
+_cairo_xlib_shm_info_find (cairo_xlib_display_t *display, size_t size,
+ void **ptr, unsigned long *last_request)
{
cairo_xlib_shm_info_t *info;
struct pqueue *pq = &display->shm->info;
info = PQ_TOP(pq);
do {
- _pqueue_pop (&display->shm->info);
-
- if (info->size >= size && size <= 2*info->size)
- return info;
+ cairo_xlib_shm_t *pool = info->pool;
*last_request = info->last_request;
- _cairo_mempool_free (&info->pool->mem, info->mem);
+
+ _pqueue_pop (&display->shm->info);
+ _cairo_mempool_free (&pool->mem, info->mem);
free (info);
+
+ if (pool->mem.free_bytes >= size) {
+ void *mem = _cairo_mempool_alloc (&pool->mem, size);
+ if (mem != NULL) {
+ *ptr = mem;
+ return pool;
+ }
+ }
} while ((info = PQ_TOP(pq)));
return NULL;
pool->attached = NextRequest (dpy);
success = XShmAttach (dpy, &pool->shm);
+#if !IPC_RMID_DEFERRED_RELEASE
+ XSync (dpy, FALSE);
+#endif
shmctl (pool->shm.shmid, IPC_RMID, NULL);
if (! success)
unsigned long last_request = 0;
void *mem = NULL;
- if (will_sync) {
- info = _cairo_xlib_shm_info_find (display, size, &last_request);
- if (info)
- return info;
- }
-
_cairo_xlib_shm_info_cleanup (display);
pool = _cairo_xlib_shm_pool_find (display, size, &mem);
_cairo_xlib_shm_pool_cleanup (display);
+
+ if (pool == NULL && will_sync)
+ pool = _cairo_xlib_shm_info_find (display, size, &mem, &last_request);
if (pool == NULL)
pool = _cairo_xlib_shm_pool_create (display, size, &mem);
if (pool == NULL)
{
cairo_xlib_shm_surface_t *shm = abstract_surface;
cairo_xlib_display_t *display;
+ Display *dpy;
cairo_status_t status;
if (shm->active == 0)
if (unlikely (status))
return status;
- XEventsQueued (display->display, QueuedAfterReading);
- if (!seqno_passed (shm->active,
- LastKnownRequestProcessed (display->display)))
- XSync (display->display, False);
+ send_event (display, shm->info, shm->active);
+
+ dpy = display->display;
+ XEventsQueued (dpy, QueuedAfterReading);
+ while (! seqno_passed (shm->active, LastKnownRequestProcessed (dpy))) {
+ LockDisplay(dpy);
+ _XReadEvents(dpy);
+ UnlockDisplay(dpy);
+ }
cairo_device_release (&display->base);
shm->active = 0;
active (cairo_xlib_shm_surface_t *shm, Display *dpy)
{
return (shm->active &&
- !seqno_passed (shm->active, LastKnownRequestProcessed (dpy)));
+ ! seqno_passed (shm->active, LastKnownRequestProcessed (dpy)));
}
static cairo_status_t
cairo_xlib_display_t *display;
cairo_status_t status;
+ if (shm->image.base.damage) {
+ _cairo_damage_destroy (shm->image.base.damage);
+ shm->image.base.damage = _cairo_damage_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
+ }
+
status = _cairo_xlib_display_acquire (shm->image.base.device, &display);
if (unlikely (status))
return status;
if (active (shm, display->display)) {
shm->info->last_request = shm->active;
_pqueue_push (&display->shm->info, shm->info);
+ if (seqno_before (display->shm->last_request, shm->active))
+ display->shm->last_request = shm->active;
} else {
_cairo_mempool_free (&shm->info->pool->mem, shm->info->mem);
free (shm->info);
cairo_list_del (&shm->link);
cairo_device_release (&display->base);
- return CAIRO_STATUS_SUCCESS;
+ return _cairo_image_surface_finish (abstract_surface);
}
static const cairo_surface_backend_t cairo_xlib_shm_surface_backend = {
if (_cairo_xlib_surface_get_gc (display, surface, &gc))
goto cleanup_display;
+ if (! surface->owns_pixmap) {
+ XGCValues gcv;
+
+ gcv.subwindow_mode = IncludeInferiors;
+ XChangeGC (display->display, gc, GCSubwindowMode, &gcv);
+ }
+
if (damage->region) {
XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))];
XRectangle *rects = stack_rects;
0, 0);
}
- XSync (display->display, False);
+ if (! surface->owns_pixmap) {
+ XGCValues gcv;
+
+ gcv.subwindow_mode = ClipByChildren;
+ XChangeGC (display->display, gc, GCSubwindowMode, &gcv);
+ }
+
+ sync (display);
shm->active = 0;
shm->idle--;
damage = _cairo_damage_reduce (shm->image.base.damage);
shm->image.base.damage = _cairo_damage_create ();
- status = _cairo_xlib_surface_get_gc (display, surface, &gc);
- if (unlikely (status))
- goto out;
-
TRACE ((stderr, "%s: flushing damage x %d\n", __FUNCTION__,
damage->region ? cairo_region_num_rectangles (damage->region) : 0));
if (damage->status == CAIRO_STATUS_SUCCESS && damage->region) {
int n_rects, i;
n_rects = cairo_region_num_rectangles (damage->region);
- if (n_rects == 0) {
- } else if (n_rects == 1) {
+ if (n_rects == 0)
+ goto out;
+
+ status = _cairo_xlib_surface_get_gc (display, surface, &gc);
+ if (unlikely (status))
+ goto out;
+
+ if (n_rects == 1) {
cairo_region_get_rectangle (damage->region, 0, &r);
+ _cairo_xlib_shm_surface_mark_active (surface->shm);
XCopyArea (display->display,
shm->pixmap, surface->drawable, gc,
r.x, r.y,
rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
if (unlikely (rects == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ _cairo_xlib_surface_put_gc (display, surface, gc);
goto out;
}
}
}
XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded);
+ _cairo_xlib_shm_surface_mark_active (surface->shm);
XCopyArea (display->display,
shm->pixmap, surface->drawable, gc,
0, 0,
if (damage->status == CAIRO_STATUS_SUCCESS && damage->region)
XSetClipMask (display->display, gc, None);
}
+
+ _cairo_xlib_surface_put_gc (display, surface, gc);
}
- _cairo_damage_destroy (damage);
- _cairo_xlib_shm_surface_mark_active (surface->shm);
- _cairo_xlib_surface_put_gc (display, surface, gc);
out:
+ _cairo_damage_destroy (damage);
cairo_device_release (&display->base);
}
surface = NULL;
if (has_shm (other))
- surface = &_cairo_xlib_shm_surface_create (other, format,
- width, height, FALSE,
- has_shm_pixmaps (other))->image.base;
+ surface = &_cairo_xlib_shm_surface_create (other, format, width, height,
+ FALSE, has_shm_pixmaps (other))->image.base;
return surface;
}
if (! has_shm(surface))
return NULL;
- return &_cairo_xlib_shm_surface_create (surface, format,
- surface->width, surface->height,
- TRUE, 0)->image.base;
+ return &_cairo_xlib_shm_surface_create (surface, format, width, height,
+ FALSE, 0)->image.base;
}
cairo_surface_t *
{
cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) _shm;
cairo_xlib_display_t *display = (cairo_xlib_display_t *) _shm->device;
- XShmCompletionEvent ev;
-
- ev.type = display->shm->event;
- ev.drawable = display->shm->window;
- ev.major_code = display->shm->opcode;
- ev.minor_code = X_ShmPutImage;
- ev.shmseg = shm->info->pool->shm.shmid;
- ev.offset = (char *)shm->info->mem - (char *)shm->info->pool->shm.shmaddr;
shm->active = NextRequest (display->display);
- XSendEvent (display->display, ev.drawable, False, 0, (XEvent *)&ev);
}
void
void *
_cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface)
{
- cairo_xlib_shm_surface_t *shm;
+ cairo_xlib_display_t *display = (cairo_xlib_display_t *) surface->device;
+ cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface;
- shm = (cairo_xlib_shm_surface_t *) surface;
- shm->active = next_request (surface->device);
+ display->shm->last_event = shm->active = NextRequest (display->display);
return &shm->info->pool->shm;
}
return shm->idle > 0;
}
+#define XORG_VERSION_ENCODE(major,minor,patch,snap) \
+ (((major) * 10000000) + ((minor) * 100000) + ((patch) * 1000) + snap)
+
+static cairo_bool_t
+has_broken_send_shm_event (cairo_xlib_display_t *display,
+ cairo_xlib_shm_display_t *shm)
+{
+ Display *dpy = display->display;
+ int (*old_handler) (Display *display, XErrorEvent *event);
+ XShmCompletionEvent ev;
+ XShmSegmentInfo info;
+
+ info.shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
+ if (info.shmid == -1)
+ return TRUE;
+
+ info.readOnly = FALSE;
+ info.shmaddr = shmat (info.shmid, NULL, 0);
+ if (info.shmaddr == (char *) -1) {
+ shmctl (info.shmid, IPC_RMID, NULL);
+ return TRUE;
+ }
+
+ ev.type = shm->event;
+ ev.send_event = 1;
+ ev.serial = 1;
+ ev.drawable = shm->window;
+ ev.major_code = shm->opcode;
+ ev.minor_code = X_ShmPutImage;
+
+ ev.shmseg = info.shmid;
+ ev.offset = 0;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (_cairo_xlib_display_mutex));
+ _x_error_occurred = FALSE;
+
+ XLockDisplay (dpy);
+ XSync (dpy, False);
+ old_handler = XSetErrorHandler (_check_error_handler);
+
+ XShmAttach (dpy, &info);
+ XSendEvent (dpy, ev.drawable, False, 0, (XEvent *)&ev);
+ XShmDetach (dpy, &info);
+
+ XSync (dpy, False);
+ XSetErrorHandler (old_handler);
+ XUnlockDisplay (dpy);
+
+ shmctl (info.shmid, IPC_RMID, NULL);
+ shmdt (info.shmaddr);
+
+ return _x_error_occurred;
+}
+
+static cairo_bool_t
+xorg_has_buggy_send_shm_completion_event(cairo_xlib_display_t *display,
+ cairo_xlib_shm_display_t *shm)
+{
+ Display *dpy = display->display;
+
+ /* As libXext sets the SEND_EVENT bit in the ShmCompletionEvent,
+ * the Xserver may crash if it does not take care when processing
+ * the event type. For instance versions of Xorg prior to 1.11.1
+ * exhibited this bug, and was fixed by:
+ *
+ * commit 2d2dce558d24eeea0eb011ec9ebaa6c5c2273c39
+ * Author: Sam Spilsbury <sam.spilsbury@canonical.com>
+ * Date: Wed Sep 14 09:58:34 2011 +0800
+ *
+ * Remove the SendEvent bit (0x80) before doing range checks on event type.
+ */
+ if (_cairo_xlib_vendor_is_xorg (dpy) &&
+ VendorRelease (dpy) < XORG_VERSION_ENCODE(1,11,0,1))
+ return TRUE;
+
+ /* For everyone else check that no error is generated */
+ return has_broken_send_shm_event (display, shm);
+}
+
void
_cairo_xlib_display_init_shm (cairo_xlib_display_t *display)
{
if (unlikely (shm == NULL))
return;
+ codes = XInitExtension (display->display, SHMNAME);
+ if (codes == NULL) {
+ free (shm);
+ return;
+ }
+
+ shm->opcode = codes ->major_opcode;
+ shm->event = codes->first_event;
+
if (unlikely (_pqueue_init (&shm->info))) {
free (shm);
return;
InputOutput,
DefaultVisual (display->display, scr),
CWOverrideRedirect, &attr);
+ shm->last_event = 0;
+ shm->last_request = 0;
+
+ if (xorg_has_buggy_send_shm_completion_event(display, shm))
+ has_pixmap = 0;
shm->has_pixmaps = has_pixmap ? MIN_PIXMAP_SIZE : 0;
cairo_list_init (&shm->pool);
- codes = XInitExtension (display->display, SHMNAME);
- shm->opcode = codes ->major_opcode;
- shm->event = codes->first_event;
-
cairo_list_init (&shm->surfaces);
display->shm = shm;
free (shm);
display->shm = NULL;
}
-
+#endif
#endif
XImage ximage;
cairo_format_masks_t image_masks;
int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst;
+ cairo_surface_t *shm_image = NULL;
pixman_image_t *pixman_image = NULL;
cairo_status_t status;
- cairo_bool_t own_data;
+ cairo_bool_t own_data = FALSE;
cairo_bool_t is_rgb_image;
GC gc;
ximage.bits_per_pixel = image_masks.bpp;
ximage.bytes_per_line = image->stride;
ximage.data = (char *)image->data;
- if (image->base.device == surface->base.device)
+ if (image->base.device != surface->base.device) {
+ /* If PutImage will break the image up into chunks, prefer to
+ * send it all in one pass with ShmPutImage. For larger images,
+ * it is further advantageous to reduce the number of copies,
+ * albeit at the expense of more SHM bookkeeping.
+ */
+ int max_request_size = XExtendedMaxRequestSize (display->display);
+ if (max_request_size == 0)
+ max_request_size = XMaxRequestSize (display->display);
+ if (max_request_size > 8192)
+ max_request_size = 8192;
+ if (width * height * 4 > max_request_size) {
+ shm_image = _cairo_xlib_surface_create_shm__image (surface,
+ image->pixman_format,
+ width, height);
+ if (shm_image && shm_image->status == CAIRO_STATUS_SUCCESS) {
+ cairo_image_surface_t *clone = (cairo_image_surface_t *) shm_image;
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ image->pixman_image, NULL, clone->pixman_image,
+ src_x, src_y,
+ 0, 0,
+ 0, 0,
+ width, height);
+ ximage.obdata = _cairo_xlib_shm_surface_get_obdata (shm_image);
+ ximage.data = (char *)clone->data;
+ ximage.bytes_per_line = clone->stride;
+ ximage.width = width;
+ ximage.height = height;
+ src_x = src_y = 0;
+ }
+ }
+ } else
ximage.obdata = _cairo_xlib_shm_surface_get_obdata (&image->base);
- own_data = FALSE;
ret = XInitImage (&ximage);
assert (ret != 0);
ret = _pixman_format_from_masks (&image_masks, &intermediate_format);
assert (ret);
- own_data = FALSE;
-
- pixman_image = pixman_image_create_bits (intermediate_format,
- width, height, NULL, 0);
- if (pixman_image == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
+ shm_image = _cairo_xlib_surface_create_shm__image (surface,
+ intermediate_format,
+ width, height);
+ if (shm_image && shm_image->status == CAIRO_STATUS_SUCCESS) {
+ cairo_image_surface_t *clone = (cairo_image_surface_t *) shm_image;
+
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ image->pixman_image,
+ NULL,
+ clone->pixman_image,
+ src_x, src_y,
+ 0, 0,
+ 0, 0,
+ width, height);
+
+ ximage.data = (char *) clone->data;
+ ximage.obdata = _cairo_xlib_shm_surface_get_obdata (&clone->base);
+ ximage.bytes_per_line = clone->stride;
+ } else {
+ pixman_image = pixman_image_create_bits (intermediate_format,
+ width, height, NULL, 0);
+ if (pixman_image == NULL) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL;
+ }
- pixman_image_composite32 (PIXMAN_OP_SRC,
- image->pixman_image,
- NULL,
- pixman_image,
- src_x, src_y,
- 0, 0,
- 0, 0,
- width, height);
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ image->pixman_image,
+ NULL,
+ pixman_image,
+ src_x, src_y,
+ 0, 0,
+ 0, 0,
+ width, height);
+
+ ximage.data = (char *) pixman_image_get_data (pixman_image);
+ ximage.bytes_per_line = pixman_image_get_stride (pixman_image);
+ }
ximage.width = width;
ximage.height = height;
ximage.bits_per_pixel = image_masks.bpp;
- ximage.data = (char *) pixman_image_get_data (pixman_image);
- ximage.bytes_per_line = pixman_image_get_stride (pixman_image);
ret = XInitImage (&ximage);
assert (ret != 0);
ximage.bytes_per_line = stride;
ximage.data = _cairo_malloc_ab (stride, ximage.height);
if (unlikely (ximage.data == NULL)) {
- own_data = FALSE;
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
if (ximage.obdata)
XShmPutImage (display->display, surface->drawable, gc, &ximage,
- src_x, src_y, dst_x, dst_y, width, height, TRUE);
+ src_x, src_y, dst_x, dst_y, width, height, True);
else
XPutImage (display->display, surface->drawable, gc, &ximage,
src_x, src_y, dst_x, dst_y, width, height);
if (own_data)
free (ximage.data);
+ if (shm_image)
+ cairo_surface_destroy (shm_image);
if (pixman_image)
pixman_image_unref (pixman_image);
CAIRO_SURFACE_TYPE_XML,
CAIRO_SURFACE_TYPE_SKIA,
CAIRO_SURFACE_TYPE_SUBSURFACE,
- CAIRO_SURFACE_TYPE_COGL
+ CAIRO_SURFACE_TYPE_COGL,
} cairo_surface_type_t;
cairo_public cairo_surface_type_t
const cairo_rectangle_int_t *src);
cairo_private cairo_bool_t
-_cairo_box_intersects_line_segment (cairo_box_t *box,
+_cairo_box_intersects_line_segment (const cairo_box_t *box,
cairo_line_t *line) cairo_pure;
cairo_private cairo_bool_t
double tolerance,
cairo_traps_t *traps);
-cairo_private cairo_status_t
-_cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- cairo_antialias_t antialias,
- cairo_traps_t *traps);
-
/* cairo-path-stroke.c */
cairo_private cairo_status_t
_cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
double tolerance,
cairo_traps_t *traps);
+cairo_private cairo_int_status_t
+_cairo_path_fixed_stroke_polygon_to_traps (const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_traps_t *traps);
+
cairo_private cairo_status_t
_cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_path_fixed_t *path,
const cairo_matrix_t *ctm,
double *dx, double *dy);
+cairo_private void
+_cairo_stroke_style_max_line_distance_from_path (const cairo_stroke_style_t *style,
+ const cairo_path_fixed_t *path,
+ const cairo_matrix_t *ctm,
+ double *dx, double *dy);
+
+cairo_private void
+_cairo_stroke_style_max_join_distance_from_path (const cairo_stroke_style_t *style,
+ const cairo_path_fixed_t *path,
+ const cairo_matrix_t *ctm,
+ double *dx, double *dy);
cairo_private double
_cairo_stroke_style_dash_period (const cairo_stroke_style_t *style);
slim_hidden_proto (cairo_pop_group);
slim_hidden_proto (cairo_push_group_with_content);
slim_hidden_proto_no_warn (cairo_path_destroy);
+slim_hidden_proto (cairo_recording_surface_create);
slim_hidden_proto (cairo_rel_line_to);
slim_hidden_proto (cairo_restore);
slim_hidden_proto (cairo_save);
_cairo_debug_print_clip (FILE *stream, const cairo_clip_t *clip);
#if 0
-#define TRACE(x) fprintf x
+#define TRACE(x) fprintf (stderr, "%s: ", __FILE__), fprintf x
#define TRACE_(x) x
#else
#define TRACE(x)
info.antialias = antialias;
_cairo_traps_init_with_clip (&info.traps, extents->clip);
- status = _cairo_path_fixed_stroke_to_traps (path, style,
- ctm, ctm_inverse,
- tolerance,
- &info.traps);
+ status = _cairo_path_fixed_stroke_polygon_to_traps (path, style,
+ ctm, ctm_inverse,
+ tolerance,
+ &info.traps);
if (likely (status == CAIRO_INT_STATUS_SUCCESS))
status = trim_extents_to_traps (extents, &info.traps);
if (likely (status == CAIRO_INT_STATUS_SUCCESS))
__FUNCTION__, r.x, r.y, r.width, r.height));
surface->fallback->damage =
_cairo_damage_add_rectangle (surface->fallback->damage, &r);
+ surface = to_win32_display_surface (surface->fallback);
}
return _cairo_surface_unmap_image (surface->image, image);
scale-source-surface-paint.c \
scaled-font-zero-matrix.c \
stroke-ctm-caps.c \
+ stroke-clipped.c \
stroke-image.c \
stroke-open-box.c \
select-font-face.c \
world-map.c \
white-in-noop.c \
xcb-huge-image-shm.c \
+ xcb-huge-subimage.c \
xcb-stress-cache.c \
xcb-snapshot-assert.c \
xcomposite-projection.c \
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
-#if HAVE_FEENABLEEXCEPT
-#include <fenv.h>
-#endif
#include <assert.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
+#if HAVE_FENV_H
+# include <fenv.h>
+#endif
+/* The following are optional in C99, so define them if they aren't yet */
+#ifndef FE_DIVBYZERO
+#define FE_DIVBYZERO 0
+#endif
+#ifndef FE_INEXACT
+#define FE_INEXACT 0
+#endif
+#ifndef FE_INVALID
+#define FE_INVALID 0
+#endif
+#ifndef FE_OVERFLOW
+#define FE_OVERFLOW 0
+#endif
+#ifndef FE_UNDERFLOW
+#define FE_UNDERFLOW 0
+#endif
+
#include <math.h>
static inline double
#define INFINITY HUGE_VAL
#endif
-#if HAVE_FENV_H
-# include <fenv.h>
-#endif
-
static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
+++ /dev/null
-/*
- * Copyright © 2011 Intel 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 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: Chris Wilson <chris@chris-wilson.co.uk>
- */
-
-#include "cairo-test.h"
-
-#include <stdio.h>
-#include <errno.h>
-
-/* Basic test to exercise the new mime-surface callback. */
-
-#define WIDTH 200
-#define HEIGHT 80
-
-/* Lazy way of determining PNG dimensions... */
-static void
-png_dimensions (const char *filename,
- cairo_content_t *content, int *width, int *height)
-{
- cairo_surface_t *surface;
-
- surface = cairo_image_surface_create_from_png (filename);
- *content = cairo_surface_get_content (surface);
- *width = cairo_image_surface_get_width (surface);
- *height = cairo_image_surface_get_height (surface);
- cairo_surface_destroy (surface);
-}
-
-static cairo_surface_t *
-png_acquire (cairo_surface_t *mime_surface, void *closure,
- cairo_surface_t *target, const cairo_rectangle_int_t *roi,
- cairo_rectangle_int_t *extents)
-{
- cairo_surface_t *image;
-
- image = cairo_image_surface_create_from_png (closure);
- extents->x = extents->y = 0;
- extents->width = cairo_image_surface_get_width (image);
- extents->height = cairo_image_surface_get_height (image);
- return image;
-}
-
-static cairo_surface_t *
-red_acquire (cairo_surface_t *mime_surface, void *closure,
- cairo_surface_t *target, const cairo_rectangle_int_t *roi,
- cairo_rectangle_int_t *extents)
-{
- cairo_surface_t *image;
- cairo_t *cr;
-
- image = cairo_surface_create_similar_image (target,
- CAIRO_FORMAT_RGB24,
- roi->width, roi->height);
- cr = cairo_create (image);
- cairo_set_source_rgb (cr, 1, 0, 0);
- cairo_paint (cr);
- cairo_destroy (cr);
-
- *extents = *roi;
- return image;
-}
-
-static void
-release (cairo_surface_t *mime_surface, void *closure, cairo_surface_t *image)
-{
- cairo_surface_destroy (image);
-}
-
-static cairo_test_status_t
-draw (cairo_t *cr, int width, int height)
-{
- const char *png_filename = "png.png";
- cairo_surface_t *png, *red;
- cairo_content_t content;
- int png_width, png_height;
- int i, j;
-
- png_dimensions (png_filename, &content, &png_width, &png_height);
-
- png = cairo_mime_surface_create ((void*)png_filename, content, png_width, png_height);
- cairo_mime_surface_set_acquire (png, png_acquire, release);
-
- red = cairo_mime_surface_create (NULL, CAIRO_CONTENT_COLOR, WIDTH, HEIGHT);
- cairo_mime_surface_set_acquire (red, red_acquire, release);
-
- cairo_set_source_rgb (cr, 0, 0, 1);
- cairo_paint (cr);
-
- cairo_translate (cr, 0, (HEIGHT-png_height)/2);
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++) {
- cairo_surface_t *source;
- if ((i ^ j) & 1)
- source = red;
- else
- source = png;
- cairo_set_source_surface (cr, source, 0, 0);
- cairo_rectangle (cr, i * WIDTH/4, j * png_height/4, WIDTH/4, png_height/4);
- cairo_fill (cr);
- }
- }
-
- cairo_surface_destroy (red);
- cairo_surface_destroy (png);
-
- return CAIRO_TEST_SUCCESS;
-}
-
-static cairo_test_status_t
-check_status (const cairo_test_context_t *ctx,
- cairo_status_t status,
- cairo_status_t expected)
-{
- if (status == expected)
- return CAIRO_TEST_SUCCESS;
-
- cairo_test_log (ctx,
- "Error: Expected status value %d (%s), received %d (%s)\n",
- expected,
- cairo_status_to_string (expected),
- status,
- cairo_status_to_string (status));
- return CAIRO_TEST_FAILURE;
-}
-
-static cairo_test_status_t
-preamble (cairo_test_context_t *ctx)
-{
- cairo_surface_t *mime;
- cairo_status_t status;
- cairo_t *cr;
-
- /* drawing to a mime-surface is verboten */
-
- mime = cairo_mime_surface_create (NULL, CAIRO_CONTENT_COLOR, 0, 0);
- cr = cairo_create (mime);
- cairo_surface_destroy (mime);
- status = cairo_status (cr);
- cairo_destroy (cr);
- status = check_status (ctx, status, CAIRO_STATUS_WRITE_ERROR);
- if (status)
- return status;
-
- return CAIRO_TEST_SUCCESS;
-}
-
-CAIRO_TEST (mime_surface,
- "Check that the mime-surface embedding works",
- "api", /* keywords */
- NULL, /* requirements */
- WIDTH, HEIGHT,
- preamble, draw)
--- /dev/null
+/*
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "cairo-test.h"
+
+#define SIZE 200
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ int row;
+
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_paint(cr);
+
+ cairo_set_source_rgb(cr, 1, 0, 0);
+ for(row = 0; row < SIZE; row++) {
+ cairo_rectangle(cr, 0, row, SIZE, 1);
+ cairo_clip(cr);
+
+ cairo_arc(cr, SIZE/2, SIZE/2, SIZE/2-8, 0, 2*M_PI);
+ cairo_stroke(cr);
+
+ cairo_reset_clip(cr);
+ }
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (stroke_clipped,
+ "Check that the stroke is accurately drawn through smaller clips",
+ "stroke", /* keywords */
+ NULL, /* requirements */
+ SIZE, SIZE,
+ NULL, draw)
--- /dev/null
+/*
+ * Copyright © 2012 Uli Schlachter
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Uli Schlachter <psychon@znc.in>
+ */
+
+#include "cairo-test.h"
+
+#define WIDTH 6000
+#define HEIGHT 6000
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_surface_t *surface;
+ cairo_surface_t *image;
+ cairo_surface_t *subimage;
+ cairo_rectangle_int_t extents;
+ cairo_t *cr2;
+
+ extents.x = extents.y = 10;
+ extents.width = WIDTH - 20;
+ extents.height = HEIGHT - 20;
+
+ /* We use a similar surface to have way smaller ref images */
+ surface = cairo_surface_create_similar (cairo_get_target (cr),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ WIDTH, HEIGHT);
+
+ /* First we have to defeat xcb's deferred clear */
+ cr2 = cairo_create (surface);
+ cairo_test_paint_checkered (cr2);
+ cairo_destroy (cr2);
+
+ /* Get us an image surface with a non-natural stride */
+ image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ WIDTH, HEIGHT);
+ subimage = cairo_surface_map_to_image (image, &extents);
+
+ /* Paint the subimage to the similar surface and trigger the big upload */
+ cr2 = cairo_create (surface);
+ cairo_set_source_surface (cr2, subimage, 0, 0);
+ cairo_paint (cr2);
+ cairo_destroy (cr2);
+
+ /* Finally we make sure that errors aren't lost. */
+ cairo_surface_unmap_image (image, subimage);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+ cairo_surface_destroy (image);
+ cairo_surface_destroy (surface);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (xcb_huge_subimage,
+ "Test if the maximum request size is honored",
+ "xcb", /* keywords */
+ NULL, /* requirements */
+ 2, 2,
+ NULL, draw)
cairo_fdr_la_CPPFLAGS = $(AM_CPPFLAGS)
cairo_fdr_la_CFLAGS = $(CAIRO_CFLAGS)
cairo_fdr_la_LDFLAGS = -module -no-undefined
+if CAIRO_HAS_DL
cairo_fdr_la_LIBADD = -ldl
+endif
cairo_public GType
cairo_gobject_line_join_get_type (void);
-#define CAIRO_GOBJECT_TYPE_CLUSTER_FLAGS cairo_gobject_cluster_flags_get_type ()
+#define CAIRO_GOBJECT_TYPE_TEXT_CLUSTER_FLAGS cairo_gobject_text_cluster_flags_get_type ()
cairo_public GType
cairo_gobject_text_cluster_flags_get_type (void);
cairo_public GType
cairo_gobject_hint_style_get_type (void);
+/* historical accident */
#define CAIRO_GOBJECT_TYPE_HNT_METRICS cairo_gobject_hint_metrics_get_type ()
+#define CAIRO_GOBJECT_TYPE_HINT_METRICS cairo_gobject_hint_metrics_get_type ()
cairo_public GType
cairo_gobject_hint_metrics_get_type (void);
$(NULL)
libcairo_script_interpreter_la_CFLAGS = $(CAIRO_CFLAGS)
libcairo_script_interpreter_la_LDFLAGS = -version-info $(CAIRO_LIBTOOL_VERSION_INFO) -no-undefined $(export_symbols)
-libcairo_script_interpreter_la_LIBADD = $(top_builddir)/src/libcairo.la $(CAIRO_LIBS) -lz
+libcairo_script_interpreter_la_LIBADD = $(top_builddir)/src/libcairo.la $(CAIRO_LIBS) $(lzo_LIBS) -lz
csi_replay_SOURCES = csi-replay.c
csi_replay_CFLAGS = $(CAIRO_CFLAGS)
#include <string.h>
#include <zlib.h>
+#if HAVE_LZO
+#include <lzo/lzo2a.h>
+#endif
+
#define CHUNK_SIZE 32768
#define OWN_STREAM 0x1
return status;
tmp_str = tmp_obj.datum.string;
- if (uncompress ((Bytef *) tmp_str->string, &len,
- (Bytef *) src->string, src->len) != Z_OK)
- {
+ switch (src->method) {
+ case NONE:
+ default:
+ status = _csi_error (CAIRO_STATUS_NO_MEMORY);
+ break;
+
+#if HAVE_ZLIB
+ case ZLIB:
+ if (uncompress ((Bytef *) tmp_str->string, &len,
+ (Bytef *) src->string, src->len) != Z_OK)
+ status = _csi_error (CAIRO_STATUS_NO_MEMORY);
+ break;
+#endif
+#if HAVE_LZO
+ case LZO:
+ if (lzo2a_decompress ((lzo_bytep) src->string, src->len,
+ (lzo_bytep) tmp_str->string, &len,
+ NULL))
+ status = _csi_error (CAIRO_STATUS_NO_MEMORY);
+ break;
+#endif
+ }
+ if (_csi_unlikely (status)) {
csi_string_free (ctx, tmp_str);
_csi_slab_free (ctx, file, sizeof (csi_file_t));
- return _csi_error (CAIRO_STATUS_NO_MEMORY);
+ return status;
}
file->src = tmp_str;
(*csi_copy_page_func_t) (void *closure,
cairo_t *cr);
+typedef cairo_surface_t *
+(*csi_create_source_image_t) (void *closure,
+ cairo_format_t format,
+ int width, int height,
+ long uid);
+
typedef struct _cairo_script_interpreter_hooks {
void *closure;
csi_surface_create_func_t surface_create;
csi_destroy_func_t context_destroy;
csi_show_page_func_t show_page;
csi_copy_page_func_t copy_page;
+ csi_create_source_image_t create_source_image;
} cairo_script_interpreter_hooks_t;
cairo_public cairo_script_interpreter_t *
}
string->len = len;
string->deflate = 0;
+ string->method = NONE;
string->base.type = CSI_OBJECT_TYPE_STRING;
string->base.ref = 1;
string = obj->datum.string;
string->deflate = out_len;
+ string->method = ZLIB;
return CSI_STATUS_SUCCESS;
}
string->string = bytes;
string->len = len;
string->deflate = 0;
+ string->method = NONE;
string->base.type = CSI_OBJECT_TYPE_STRING;
string->base.ref = 1;
#include <math.h>
#include <limits.h> /* INT_MAX */
#include <assert.h>
+
+#if HAVE_ZLIB
#include <zlib.h>
+#endif
+
+#if HAVE_LZO
+#include <lzo/lzo2a.h>
+#endif
#ifdef HAVE_MMAP
# ifdef HAVE_UNISTD_H
if (bytes == NULL)
return NULL;
- if (uncompress ((Bytef *) bytes, &len,
- (Bytef *) src->string, src->len) != Z_OK)
- {
- _csi_free (ctx, bytes);
- bytes = NULL;
- }
- else
- {
- bytes[len] = '\0';
+ switch (src->method) {
+ default:
+ case NONE:
+ free (bytes);
+ return NULL;
+
+#if HAVE_ZLIB
+ case ZLIB:
+ if (uncompress ((Bytef *) bytes, &len,
+ (Bytef *) src->string, src->len) != Z_OK)
+ {
+ _csi_free (ctx, bytes);
+ return NULL;
+ }
+ break;
+#endif
+
+#if HAVE_LZO
+ case LZO:
+ if (lzo2a_decompress ((Bytef *) src->string, src->len,
+ (Bytef *) bytes, &len,
+ NULL))
+ {
+ _csi_free (ctx, bytes);
+ return NULL;
+ }
+ break;
+#endif
}
+ bytes[len] = '\0';
return bytes;
}
}
static csi_status_t
-_image_read_raw (csi_file_t *src,
+_image_read_raw (csi_t *ctx,
+ csi_object_t *src,
cairo_format_t format,
int width, int height,
cairo_surface_t **image_out)
int rem, len, ret, x, rowlen, instride, stride;
cairo_status_t status;
- stride = cairo_format_stride_for_width (format, width);
- data = malloc (stride * height);
- if (data == NULL)
- return CAIRO_STATUS_NO_MEMORY;
+ if (width == 0 || height == 0) {
+ *image_out = cairo_image_surface_create (format, 0, 0);
+ return CSI_STATUS_SUCCESS;
+ }
- image = cairo_image_surface_create_for_data (data, format,
- width, height, stride);
- status = cairo_surface_set_user_data (image,
- (const cairo_user_data_key_t *) image,
- data, free);
- if (status) {
- cairo_surface_destroy (image);
- free (image);
- return status;
+ if (ctx->hooks.create_source_image != NULL) {
+ image = ctx->hooks.create_source_image (ctx->hooks.closure,
+ format, width, height,
+ 0);
+
+ stride = cairo_image_surface_get_stride (image);
+ data = cairo_image_surface_get_data (image);
+ } else {
+ stride = cairo_format_stride_for_width (format, width);
+ data = malloc (stride * height);
+ if (data == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ image = cairo_image_surface_create_for_data (data, format,
+ width, height, stride);
+ status = cairo_surface_set_user_data (image,
+ (const cairo_user_data_key_t *) image,
+ data, free);
+ if (status) {
+ cairo_surface_destroy (image);
+ free (image);
+ return status;
+ }
}
switch (format) {
}
len = rowlen * height;
- bp = data;
- rem = len;
- while (rem) {
- ret = csi_file_read (src, bp, rem);
- if (_csi_unlikely (ret == 0)) {
+ if (rowlen == instride &&
+ src->type == CSI_OBJECT_TYPE_STRING &&
+ len == src->datum.string->deflate)
+ {
+ csi_string_t *s = src->datum.string;
+ unsigned long out = s->deflate;
+
+ switch (s->method) {
+ default:
+ case NONE:
+err_decompress:
cairo_surface_destroy (image);
return _csi_error (CSI_STATUS_READ_ERROR);
+
+#if HAVE_ZLIB
+ case ZLIB:
+ if (uncompress ((Bytef *) data, &out,
+ (Bytef *) s->string, s->len) != Z_OK)
+ goto err_decompress;
+ break;
+#endif
+
+#if HAVE_LZO
+ case LZO:
+ if (lzo2a_decompress ((Bytef *) s->string, s->len,
+ (Bytef *) data, &out,
+ NULL))
+ goto err_decompress;
+ break;
+#endif
}
- rem -= ret;
- bp += ret;
}
+ else
+ {
+ csi_object_t file;
+
+ status = csi_object_as_file (ctx, src, &file);
+ if (_csi_unlikely (status)) {
+ cairo_surface_destroy (image);
+ return status;
+ }
+
+ bp = data;
+ rem = len;
+ while (rem) {
+ ret = csi_file_read (file.datum.file, bp, rem);
+ if (_csi_unlikely (ret == 0)) {
+ cairo_surface_destroy (image);
+ return _csi_error (CSI_STATUS_READ_ERROR);
+ }
+ rem -= ret;
+ bp += ret;
+ }
+
+ if (len != height * stride) {
+ while (--height) {
+ uint8_t *row = data + height * stride;
+
+ /* XXX pixel conversion */
+ switch (format) {
+ case CAIRO_FORMAT_A1:
+ for (x = rowlen; x--; ) {
+ uint8_t byte = *--bp;
+ row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
+ }
+ break;
+ case CAIRO_FORMAT_A8:
+ for (x = width; x--; )
+ row[x] = *--bp;
+ break;
+ case CAIRO_FORMAT_RGB16_565:
+ for (x = width; x--; ) {
+#ifdef WORDS_BIGENDIAN
+ row[2*x + 1] = *--bp;
+ row[2*x + 0] = *--bp;
+#else
+ row[2*x + 0] = *--bp;
+ row[2*x + 1] = *--bp;
+#endif
+ }
+ break;
+ case CAIRO_FORMAT_RGB24:
+ for (x = width; x--; ) {
+#ifdef WORDS_BIGENDIAN
+ row[4*x + 3] = *--bp;
+ row[4*x + 2] = *--bp;
+ row[4*x + 1] = *--bp;
+ row[4*x + 0] = 0xff;
+#else
+ row[4*x + 0] = *--bp;
+ row[4*x + 1] = *--bp;
+ row[4*x + 2] = *--bp;
+ row[4*x + 3] = 0xff;
+#endif
+ }
+ break;
+ case CAIRO_FORMAT_RGB30:
+ case CAIRO_FORMAT_INVALID:
+ case CAIRO_FORMAT_ARGB32:
+ /* stride == width */
+ break;
+ }
- if (len != height * stride) {
- while (--height) {
- uint8_t *row = data + height * stride;
+ memset (row + instride, 0, stride - instride);
+ }
- /* XXX pixel conversion */
+ /* need to treat last row carefully */
switch (format) {
case CAIRO_FORMAT_A1:
for (x = rowlen; x--; ) {
uint8_t byte = *--bp;
- row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
+ data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
}
break;
case CAIRO_FORMAT_A8:
for (x = width; x--; )
- row[x] = *--bp;
+ data[x] = *--bp;
break;
case CAIRO_FORMAT_RGB16_565:
for (x = width; x--; ) {
#ifdef WORDS_BIGENDIAN
- row[2*x + 1] = *--bp;
- row[2*x + 0] = *--bp;
+ data[2*x + 1] = *--bp;
+ data[2*x + 0] = *--bp;
#else
- row[2*x + 0] = *--bp;
- row[2*x + 1] = *--bp;
+ data[2*x + 0] = *--bp;
+ data[2*x + 1] = *--bp;
#endif
}
break;
case CAIRO_FORMAT_RGB24:
- for (x = width; x--; ) {
+ for (x = width; --x>1; ) {
#ifdef WORDS_BIGENDIAN
- row[4*x + 3] = *--bp;
- row[4*x + 2] = *--bp;
- row[4*x + 1] = *--bp;
- row[4*x + 0] = 0xff;
+ data[4*x + 3] = *--bp;
+ data[4*x + 2] = *--bp;
+ data[4*x + 1] = *--bp;
+ data[4*x + 0] = 0xff;
#else
- row[4*x + 0] = *--bp;
- row[4*x + 1] = *--bp;
- row[4*x + 2] = *--bp;
- row[4*x + 3] = 0xff;
+ data[4*x + 0] = *--bp;
+ data[4*x + 1] = *--bp;
+ data[4*x + 2] = *--bp;
+ data[4*x + 3] = 0xff;
#endif
}
- break;
- case CAIRO_FORMAT_RGB30:
- case CAIRO_FORMAT_INVALID:
- case CAIRO_FORMAT_ARGB32:
- /* stride == width */
- break;
- }
-
- memset (row + instride, 0, stride - instride);
- }
-
- /* need to treat last row carefully */
- switch (format) {
- case CAIRO_FORMAT_A1:
- for (x = rowlen; x--; ) {
- uint8_t byte = *--bp;
- data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
- }
- break;
- case CAIRO_FORMAT_A8:
- for (x = width; x--; )
- data[x] = *--bp;
- break;
- case CAIRO_FORMAT_RGB16_565:
- for (x = width; x--; ) {
-#ifdef WORDS_BIGENDIAN
- data[2*x + 1] = *--bp;
- data[2*x + 0] = *--bp;
-#else
- data[2*x + 0] = *--bp;
- data[2*x + 1] = *--bp;
-#endif
- }
- break;
- case CAIRO_FORMAT_RGB24:
- for (x = width; --x>1; ) {
-#ifdef WORDS_BIGENDIAN
- data[4*x + 3] = *--bp;
- data[4*x + 2] = *--bp;
- data[4*x + 1] = *--bp;
- data[4*x + 0] = 0xff;
-#else
- data[4*x + 0] = *--bp;
- data[4*x + 1] = *--bp;
- data[4*x + 2] = *--bp;
- data[4*x + 3] = 0xff;
-#endif
- }
- if (width > 1) {
- uint8_t rgb[2][3];
- /* shuffle the last couple of overlapping pixels */
- rgb[1][0] = data[5];
- rgb[1][1] = data[4];
- rgb[1][2] = data[3];
- rgb[0][0] = data[2];
- rgb[0][1] = data[1];
- rgb[0][2] = data[0];
+ if (width > 1) {
+ uint8_t rgb[2][3];
+ /* shuffle the last couple of overlapping pixels */
+ rgb[1][0] = data[5];
+ rgb[1][1] = data[4];
+ rgb[1][2] = data[3];
+ rgb[0][0] = data[2];
+ rgb[0][1] = data[1];
+ rgb[0][2] = data[0];
#ifdef WORDS_BIGENDIAN
- data[4] = 0xff;
- data[5] = rgb[1][2];
- data[6] = rgb[1][1];
- data[7] = rgb[1][0];
- data[0] = 0xff;
- data[1] = rgb[0][2];
- data[2] = rgb[0][1];
- data[3] = rgb[0][0];
+ data[4] = 0xff;
+ data[5] = rgb[1][2];
+ data[6] = rgb[1][1];
+ data[7] = rgb[1][0];
+ data[0] = 0xff;
+ data[1] = rgb[0][2];
+ data[2] = rgb[0][1];
+ data[3] = rgb[0][0];
#else
- data[7] = 0xff;
- data[6] = rgb[1][2];
- data[5] = rgb[1][1];
- data[4] = rgb[1][0];
- data[3] = 0xff;
- data[2] = rgb[0][2];
- data[1] = rgb[0][1];
- data[0] = rgb[0][0];
+ data[7] = 0xff;
+ data[6] = rgb[1][2];
+ data[5] = rgb[1][1];
+ data[4] = rgb[1][0];
+ data[3] = 0xff;
+ data[2] = rgb[0][2];
+ data[1] = rgb[0][1];
+ data[0] = rgb[0][0];
#endif
- } else {
+ } else {
#ifdef WORDS_BIGENDIAN
- data[0] = 0xff;
- data[1] = data[0];
- data[2] = data[1];
- data[3] = data[2];
+ data[0] = 0xff;
+ data[1] = data[0];
+ data[2] = data[1];
+ data[3] = data[2];
#else
- data[3] = data[0];
- data[0] = data[2];
- data[2] = data[3];
- data[3] = 0xff;
+ data[3] = data[0];
+ data[0] = data[2];
+ data[2] = data[3];
+ data[3] = 0xff;
#endif
+ }
+ break;
+ case CAIRO_FORMAT_RGB30:
+ case CAIRO_FORMAT_INVALID:
+ case CAIRO_FORMAT_ARGB32:
+ /* stride == width */
+ break;
}
- break;
- case CAIRO_FORMAT_RGB30:
- case CAIRO_FORMAT_INVALID:
- case CAIRO_FORMAT_ARGB32:
- /* stride == width */
- break;
- }
- memset (data + instride, 0, stride - instride);
- } else {
+ memset (data + instride, 0, stride - instride);
+ } else {
#ifndef WORDS_BIGENDIAN
- switch (format) {
- case CAIRO_FORMAT_A1:
- for (x = 0; x < len; x++) {
- uint8_t byte = data[x];
- data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
- }
- break;
- case CAIRO_FORMAT_RGB16_565:
- {
- uint32_t *rgba = (uint32_t *) data;
- for (x = len/2; x--; rgba++) {
- *rgba = bswap_16 (*rgba);
+ switch (format) {
+ case CAIRO_FORMAT_A1:
+ for (x = 0; x < len; x++) {
+ uint8_t byte = data[x];
+ data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
}
- }
- break;
- case CAIRO_FORMAT_ARGB32:
- {
- uint32_t *rgba = (uint32_t *) data;
- for (x = len/4; x--; rgba++) {
- *rgba = bswap_32 (*rgba);
+ break;
+ case CAIRO_FORMAT_RGB16_565:
+ {
+ uint32_t *rgba = (uint32_t *) data;
+ for (x = len/2; x--; rgba++) {
+ *rgba = bswap_16 (*rgba);
+ }
}
- }
- break;
+ break;
+ case CAIRO_FORMAT_ARGB32:
+ {
+ uint32_t *rgba = (uint32_t *) data;
+ for (x = len/4; x--; rgba++) {
+ *rgba = bswap_32 (*rgba);
+ }
+ }
+ break;
- case CAIRO_FORMAT_A8:
- break;
+ case CAIRO_FORMAT_A8:
+ break;
- case CAIRO_FORMAT_RGB30:
- case CAIRO_FORMAT_RGB24:
- case CAIRO_FORMAT_INVALID:
- default:
- break;
- }
+ case CAIRO_FORMAT_RGB30:
+ case CAIRO_FORMAT_RGB24:
+ case CAIRO_FORMAT_INVALID:
+ default:
+ break;
+ }
#endif
+ }
+ csi_object_free (ctx, &file);
}
cairo_surface_mark_dirty (image);
mime_type = MIME_TYPE_PNG;
}
- status = csi_object_as_file (ctx, &obj, &file);
- if (_csi_unlikely (status))
- return status;
/* XXX hook for general mime-type decoder */
switch (mime_type) {
case MIME_TYPE_NONE:
- status = _image_read_raw (file.datum.file,
- format, width, height, &image);
+ status = _image_read_raw (ctx, &obj, format, width, height, &image);
break;
case MIME_TYPE_PNG:
+ status = csi_object_as_file (ctx, &obj, &file);
+ if (_csi_unlikely (status))
+ return status;
+
status = _image_read_png (file.datum.file, &image);
+ csi_object_free (ctx, &file);
break;
}
- csi_object_free (ctx, &file);
if (_csi_unlikely (status))
return status;
}
obj.type = CSI_OBJECT_TYPE_SURFACE;
- obj.datum.surface = cairo_surface_map_to_image (surface, r);
- pop (2);
+ obj.datum.surface = cairo_surface_reference (cairo_surface_map_to_image (surface, r));
+ pop (1);
return push (&obj);
}
cairo_surface_unmap_image (surface, image);
- pop (2);
+ pop (1);
return CSI_STATUS_SUCCESS;
}
* principally to remove the pixman ops from the profiles.
*/
if (_csi_likely (_matching_images (surface, source))) {
- cairo_surface_flush (surface);
- memcpy (cairo_image_surface_get_data (surface),
- cairo_image_surface_get_data (source),
- cairo_image_surface_get_height (source) * cairo_image_surface_get_stride (source));
- cairo_surface_mark_dirty (surface);
+ if (cairo_surface_get_reference_count (surface) == 1 &&
+ cairo_surface_get_reference_count (source) == 1)
+ {
+ _csi_peek_ostack (ctx, 0)->datum.surface = surface;
+ _csi_peek_ostack (ctx, 1)->datum.surface = source;
+ }
+ else
+ {
+ cairo_surface_flush (surface);
+ memcpy (cairo_image_surface_get_data (surface),
+ cairo_image_surface_get_data (source),
+ cairo_image_surface_get_height (source) * cairo_image_surface_get_stride (source));
+ cairo_surface_mark_dirty (surface);
+ }
} else {
cairo_t *cr;
csi_compound_object_t base;
csi_integer_t len;
csi_integer_t deflate;
+ enum {
+ NONE,
+ ZLIB,
+ LZO,
+ } method;
char *string;
};
#include <math.h> /* pow */
#include <stdio.h> /* EOF */
#include <stdint.h> /* for {INT,UINT}*_{MIN,MAX} */
+#include <stdlib.h> /* malloc/free */
#include <string.h> /* memset */
#include <assert.h>
#include <zlib.h>
+#if HAVE_LZO
+#include <lzo/lzo2a.h>
+#endif
+
#define DEBUG_SCAN 0
#if WORDS_BIGENDIAN
obj->datum.matrix->matrix.y0);
break;
case CSI_OBJECT_TYPE_STRING:
- fprintf (stream, "string: len=%ld\n", obj->datum.string->len);
+ fprintf (stream, "string: len=%ld, defate=%ld, method=%d\n",
+ obj->datum.string->len, obj->datum.string->deflate, obj->datum.string->method);
break;
/* cairo */
uint32_t u32;
scan_read (scan, src, &u32, 4);
obj->datum.string->deflate = be32 (u32);
+ obj->datum.string->method = compressed;
}
if (_csi_likely (len))
obj.type &= ~CSI_OBJECT_ATTR_EXECUTABLE;
break;
+#define STRING_LZO 154
+ case STRING_LZO:
+ scan_read (scan, src, &u.u32, 4);
+ string_read (ctx, scan, src, be32 (u.u32), LZO, &obj);
+ break;
+
/* unassigned */
- case 154:
case 155:
case 156:
case 157:
uint16_t u16;
uint32_t u32;
} u;
- int len;
+ void *buf;
+ unsigned long hdr_len, buf_len, deflate;
+ int method;
+
+ buf = string->string;
+ buf_len = string->len;
+ deflate = string->deflate;
+ method = string->method;
+
+#if HAVE_LZO
+ if (method == NONE && buf_len > 16) {
+ unsigned long mem_len = 2*string->len > LZO2A_999_MEM_COMPRESS ? 2*string->len : LZO2A_999_MEM_COMPRESS;
+ void *mem = malloc (mem_len);
+ void *work = malloc(LZO2A_999_MEM_COMPRESS);
+
+ if (lzo2a_999_compress ((lzo_bytep) buf, buf_len,
+ (lzo_bytep) mem, &mem_len,
+ work) == 0 &&
+ 8+2*mem_len < buf_len)
+ {
+ method = LZO;
+ deflate = buf_len;
+ buf_len = mem_len;
+ buf = mem;
+ }
+ else
+ {
+ free (mem);
+ }
-#if WORDS_BIGENDIAN
- if (string->len <= UINT8_MAX) {
- hdr = STRING_1;
- u.u8 = string->len;
- len = 1;
- } else if (string->len <= UINT16_MAX) {
- hdr = STRING_2_MSB;
- u.u16 = string->len;
- len = 2;
- } else {
- hdr = STRING_4_MSB;
- u.u32 = string->len;
- len = 4;
+ free (work);
}
-#else
- if (string->len <= UINT8_MAX) {
- hdr = STRING_1;
- u.u8 = string->len;
- len = 1;
- } else if (string->len <= UINT16_MAX) {
- hdr = STRING_2_LSB;
- u.u16 = string->len;
- len = 2;
- } else {
- hdr = STRING_4_LSB;
- u.u32 = string->len;
- len = 4;
+#if HAVE_ZLIB
+ if (method == ZLIB) {
+ buf_len = string->deflate;
+ buf = malloc (string->deflate);
+ if (uncompress ((Bytef *) buf, &buf_len,
+ (Bytef *) string->string, string->len) == Z_OK)
+ {
+ if (buf_len <= 8 + 2*string->len) {
+ method = NONE;
+ deflate = 0;
+ } else {
+ unsigned long mem_len = 2*string->deflate;
+ void *mem = malloc (mem_len);
+ void *work = malloc(LZO2A_999_MEM_COMPRESS);
+
+ if (lzo2a_999_compress ((lzo_bytep) buf, buf_len,
+ (lzo_bytep) mem, &mem_len,
+ work) == 0)
+ {
+ if (8 + mem_len > buf_len) {
+ method = NONE;
+ deflate = 0;
+ } else {
+ free (buf);
+ method = LZO;
+ deflate = buf_len;
+ buf_len = mem_len;
+ buf = mem;
+ assert(deflate);
+ }
+ }
+ else
+ {
+ free (buf);
+ buf = string->string;
+ buf_len = string->len;
+ }
+
+ free (work);
+ }
+ }
+ else
+ {
+ free (buf);
+ buf = string->string;
+ buf_len = string->len;
+ }
}
#endif
- if (string->deflate)
- hdr |= STRING_DEFLATE;
-
- closure->write_func (closure->closure,
- (unsigned char *) &hdr, 1);
- closure->write_func (closure->closure,
- (unsigned char *) &u, len);
- if (string->deflate) {
- uint32_t u32 = to_be32 (string->deflate);
- closure->write_func (closure->closure,
- (unsigned char *) &u32, 4);
+#endif
+
+ if (method == LZO) {
+ hdr = STRING_LZO;
+ u.u32 = to_be32 (buf_len);
+ hdr_len = 4;
+ } else {
+#if WORDS_BIGENDIAN
+ if (buf_len <= UINT8_MAX) {
+ hdr = STRING_1;
+ u.u8 = buf_len;
+ hdr_len = 1;
+ } else if (buf_len <= UINT16_MAX) {
+ hdr = STRING_2_MSB;
+ u.u16 = buf_len;
+ hdr_len = 2;
+ } else {
+ hdr = STRING_4_MSB;
+ u.u32 = buf_len;
+ hdr_len = 4;
+ }
+#else
+ if (buf_len <= UINT8_MAX) {
+ hdr = STRING_1;
+ u.u8 = buf_len;
+ hdr_len = 1;
+ } else if (buf_len <= UINT16_MAX) {
+ hdr = STRING_2_LSB;
+ u.u16 = buf_len;
+ hdr_len = 2;
+ } else {
+ hdr = STRING_4_LSB;
+ u.u32 = buf_len;
+ hdr_len = 4;
+ }
+#endif
+ if (deflate) {
+ assert (method == ZLIB);
+ hdr |= STRING_DEFLATE;
+ }
}
- closure->write_func (closure->closure,
- (unsigned char *) string->string, string->len);
+
+ closure->write_func (closure->closure, (unsigned char *) &hdr, 1);
+ closure->write_func (closure->closure, (unsigned char *) &u, hdr_len);
+ if (deflate) {
+ uint32_t u32 = to_be32 (deflate);
+ closure->write_func (closure->closure, (unsigned char *) &u32, 4);
+ }
+ closure->write_func (closure->closure, (unsigned char *) buf, buf_len);
+
+ if (buf != string->string)
+ free (buf);
return CSI_STATUS_SUCCESS;
}
cairo_sphinx_la_CPPFLAGS = $(AM_CPPFLAGS)
cairo_sphinx_la_CFLAGS = $(CAIRO_CFLAGS)
cairo_sphinx_la_LDFLAGS = -module -no-undefined
+if CAIRO_HAS_DL
cairo_sphinx_la_LIBADD = -ldl
+endif
cairo_sphinx_SOURCES = sphinx.c
cairo_sphinx_CPPFLAGS = $(AM_CPPFLAGS) -DLIBDIR="\"$(cairolibdir)\""
#include <dlfcn.h>
#include <stdint.h>
+#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
int width, height;
cairo_bool_t foreign;
cairo_bool_t defined;
+ cairo_bool_t unknown;
int operand;
void *data;
void (*destroy)(void *);
}
static void
-_consume_operand (void)
+_consume_operand (bool discard)
{
Object *obj;
ensure_operands (1);
obj = current_object[--current_stack_depth];
- if (! obj->defined) {
+ if (!discard && ! obj->defined) {
_trace_printf ("dup /%s%ld exch def\n",
obj->type->op_code,
obj->token);
}
static cairo_bool_t
-_pop_operands_to_object (Object *obj)
+_pop_operands_to_depth (int depth)
{
- if (obj->operand == -1)
- return FALSE;
-
- if (obj->operand == current_stack_depth - 2) {
- _exch_operands ();
- _trace_printf ("exch ");
- return TRUE;
- }
-
- while (current_stack_depth > obj->operand + 1) {
+ while (current_stack_depth > depth) {
Object *c_obj;
ensure_operands (1);
c_obj = current_object[--current_stack_depth];
c_obj->operand = -1;
if (! c_obj->defined) {
+ if (c_obj->unknown)
+ return FALSE;
+
_trace_printf ("/%s%ld exch def\n",
c_obj->type->op_code,
c_obj->token);
}
static cairo_bool_t
+_pop_operands_to_object (Object *obj)
+{
+ if (obj->operand == -1)
+ return FALSE;
+
+ if (obj->operand == current_stack_depth - 1)
+ return TRUE;
+
+ if (! _pop_operands_to_depth (obj->operand + 2))
+ return FALSE;
+
+ _exch_operands ();
+ _trace_printf ("exch ");
+ return TRUE;
+}
+
+static cairo_bool_t
_pop_operands_to (enum operand_type t, const void *ptr)
{
return _pop_operands_to_object (_get_object (t, ptr));
/* we presume that we will continue to use the context */
if (_pop_operands_to (SURFACE, target)){
- _consume_operand ();
+ _consume_operand (false);
} else {
_trace_printf ("s%ld ", surface_id);
}
if (_is_current (SURFACE, surface, 0) &&
_is_current (CONTEXT, cr, 1))
{
- _consume_operand ();
+ _consume_operand (false);
}
else if (_is_current (SURFACE, surface, 1) &&
_is_current (CONTEXT, cr, 0))
{
_trace_printf ("exch ");
_exch_operands ();
- _consume_operand ();
+ _consume_operand (false);
} else if (obj->defined) {
_emit_context (cr);
_trace_printf ("s%ld ", obj->token);
_is_current (CONTEXT, cr, 1))
{
if (obj->defined) {
- _consume_operand ();
+ _consume_operand (false);
need_context_and_pattern = FALSE;
}
}
if (obj->defined) {
_trace_printf ("exch ");
_exch_operands ();
- _consume_operand ();
+ _consume_operand (false);
need_context_and_pattern = FALSE;
}
}
_is_current (CONTEXT, cr, 1))
{
if (obj->defined) {
- _consume_operand ();
+ _consume_operand (false);
need_context_and_pattern = FALSE;
}
}
if (obj->defined) {
_trace_printf ("exch ");
_exch_operands ();
- _consume_operand ();
+ _consume_operand (false);
need_context_and_pattern = FALSE;
}
}
if (_is_current (SURFACE, surface, 0) &&
_is_current (CONTEXT, cr, 1))
{
- _consume_operand ();
+ _consume_operand (false);
}
else if (_is_current (SURFACE, surface, 1) &&
_is_current (CONTEXT, cr, 0))
{
_trace_printf ("exch ");
_exch_operands ();
- _consume_operand ();
+ _consume_operand (false);
} else if (obj->defined){
_emit_context (cr);
_trace_printf ("s%ld ", obj->token);
if (_is_current (FONT_FACE, font_face, 0) &&
_is_current (CONTEXT, cr, 1))
{
- _consume_operand ();
+ _consume_operand (false);
}
else if (_is_current (FONT_FACE, font_face, 1) &&
_is_current (CONTEXT, cr, 0))
{
_trace_printf ("exch ");
_exch_operands ();
- _consume_operand ();
+ _consume_operand (false);
}
else
{
if (_pop_operands_to (SCALED_FONT, scaled_font)) {
if (_is_current (CONTEXT, cr, 1)) {
if (_write_lock ()) {
- _consume_operand ();
+ _consume_operand (false);
_trace_printf ("set-scaled-font\n");
_write_unlock ();
}
} else {
if (_get_object (CONTEXT, cr)->defined) {
if (_write_lock ()) {
- _consume_operand ();
+ _consume_operand (false);
_trace_printf ("c%ld exch set-scaled-font pop\n",
_get_context_id (cr));
_write_unlock ();
&& _write_lock ())
{
if (_pop_operands_to (FONT_FACE, font_face))
- _consume_operand ();
+ _consume_operand (false);
else
_trace_printf ("f%ld ", _get_font_face_id (font_face));
if (_write_lock ()) {
Object *obj = _create_surface (ret);
+ _emit_surface (surface);
if (extents) {
- _trace_printf ("[%d %d %d %d] map-to-image\n",
+ _trace_printf ("[%d %d %d %d] map-to-image %% s%ld\n",
extents->x, extents->y,
- extents->width, extents->height);
+ extents->width, extents->height,
+ obj->token);
obj->width = extents->width;
obj->height = extents->height;
} else {
- _trace_printf ("[ ] map-to-image\n");
+ _trace_printf ("[ ] map-to-image %% s%ld\n", obj->token);
}
+
+ obj->unknown = TRUE;
_push_object (obj);
_write_unlock ();
}
_emit_line_info ();
if (_write_lock ()) {
- _trace_printf ("/s%ld /s%ld unmap-image\n",
- _get_surface_id (surface),
- _get_surface_id (image));
- _consume_operand ();
+ Object *s = _get_object (SURFACE, surface);
+ Object *i = _get_object (SURFACE, image);
+ if (!(s->operand == current_stack_depth - 2 &&
+ i->operand == current_stack_depth - 1)) {
+ if (i->operand != s->operand + 1 || ! _pop_operands_to_depth (i->operand + 1)) {
+ _emit_surface (surface);
+ _emit_surface (image);
+ }
+ }
+ _trace_printf ("unmap-image\n");
+ _consume_operand (true);
_write_unlock ();
}
surface_id = _get_surface_id (surface);
if (_pop_operands_to (SURFACE, surface)) {
- _consume_operand ();
+ _consume_operand (false);
} else {
_trace_printf ("s%ld ", surface_id);
}
{
int n;
+ if (dir < 0)
+ cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
+ else
+ cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
+
for (n = 0; n < p->num_edges; n++) {
const edge_t *e = &p->edges[n];
+ double dx, dy;
+ double x1, x2;
if (e->dir != dir)
continue;
- cairo_arc (cr, e->p1.x, e->p1.y, 2/sf, 0, 2*M_PI);
- cairo_arc (cr, e->p2.x, e->p2.y, 2/sf, 0, 2*M_PI);
+ dx = e->p2.x - e->p1.x;
+ dy = e->p2.y - e->p1.y;
+
+ x1 = e->p1.x + (e->top - e->p1.y) / dy * dx;
+ x2 = e->p1.x + (e->bot - e->p1.y) / dy * dx;
+
+ cairo_arc (cr, x1, e->top, 2/sf, 0, 2*M_PI);
+ cairo_arc (cr, x2, e->bot, 2/sf, 0, 2*M_PI);
cairo_fill (cr);
}
+ if (dir < 0)
+ cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 0.5);
+ else
+ cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.5);
+
for (n = 0; n < p->num_edges; n++) {
const edge_t *e = &p->edges[n];
cairo_set_line_width (cr, 1.);
cairo_stroke (cr);
} cairo_restore (cr);
+
+ if (dir < 0)
+ cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
+ else
+ cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
+
+ for (n = 0; n < p->num_edges; n++) {
+ const edge_t *e = &p->edges[n];
+ double dx, dy;
+ double x1, x2;
+
+ if (e->dir != dir)
+ continue;
+
+ dx = e->p2.x - e->p1.x;
+ dy = e->p2.y - e->p1.y;
+
+ x1 = e->p1.x + (e->top - e->p1.y) / dy * dx;
+ x2 = e->p1.x + (e->bot - e->p1.y) / dy * dx;
+
+ cairo_move_to (cr, x1, e->top);
+ cairo_line_to (cr, x2, e->bot);
+ }
+ cairo_save (cr); {
+ cairo_identity_matrix (cr);
+ cairo_set_line_width (cr, 1.);
+ cairo_stroke (cr);
+ } cairo_restore (cr);
}
static void draw_polygon (cairo_t *cr, polygon_t *p, gdouble sf)
{
- cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
draw_edges (cr, p, sf, -1);
- cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
draw_edges (cr, p, sf, +1);
}