upload sdk

git-svn-id: svn://kolibrios.org@4349 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Sergey Semyonov (Serge)
2013-12-15 08:09:20 +00:00
parent 6c6781f799
commit 754f9336f0
5801 changed files with 1688660 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
Cairo Library Source Code
=========================
This directory contains the source code of the cairo library.
Source Code Listing
-------------------
The canonical list of source files is the file Makefile.sources. See that
file for how it works.
New Backends
------------
The rule of the thumb for adding new backends is to see how other
backends are integrated. Pick one of the simpler, unsupported, backends
and search the entire tree for it, and go from there.
To add new backends you need to basically:
* Modify $(top_srcdir)/configure.in to add checks for your backend.
* Modify Makefile.sources to add source files for your backend,
* Modify $(top_srcdir)/boilerplate/ to add boilerplate code for
testing your new backend.
New API
-------
After adding new API, run "make check" in this directory and fix any
reported issues. Also add new API to the right location in
$(top_srcdir)/doc/public/cairo-sections.txt and run "make check"
in $(top_builddir)/doc/public to make sure that any newly added
documentation is correctly hooked up.
Do not forget to add tests for the new API. See next section.
Tests
-----
There are some tests in this directory that check the source code and
the build for various issues. The tests are very quick to run, and
particularly should be run after any documentation or API changes. It
does not hurt to run them after any source modification either. Run
them simply by calling:
make check
There are also extensive regression tests in $(top_srcdir)/test. It is
a good idea to run that test suite for any changes made to the source
code. Moreover, for any new feature, API, or bug fix, new tests should
be added to the regression test suite to test the new code.
Bibliography
------------
A detailed list of academic publications used in cairo code is available
in the file $(top_srcdir)/BIBLIOGRAPHY. Feel free to update as you
implement more papers.
For more technical publications (eg. Adobe technical reports) just
point them out in a comment in the header of the file implementing them.

View File

@@ -0,0 +1,74 @@
/*
* Copyright © 2005 Keith Packard
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Keith Packard
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
*/
#ifndef CAIRO_ANALYSIS_SURFACE_H
#define CAIRO_ANALYSIS_SURFACE_H
#include "cairoint.h"
cairo_private cairo_surface_t *
_cairo_analysis_surface_create (cairo_surface_t *target);
cairo_private void
_cairo_analysis_surface_set_ctm (cairo_surface_t *surface,
const cairo_matrix_t *ctm);
cairo_private void
_cairo_analysis_surface_get_ctm (cairo_surface_t *surface,
cairo_matrix_t *ctm);
cairo_private cairo_region_t *
_cairo_analysis_surface_get_supported (cairo_surface_t *surface);
cairo_private cairo_region_t *
_cairo_analysis_surface_get_unsupported (cairo_surface_t *surface);
cairo_private cairo_bool_t
_cairo_analysis_surface_has_supported (cairo_surface_t *surface);
cairo_private cairo_bool_t
_cairo_analysis_surface_has_unsupported (cairo_surface_t *surface);
cairo_private void
_cairo_analysis_surface_get_bounding_box (cairo_surface_t *surface,
cairo_box_t *bbox);
cairo_private cairo_int_status_t
_cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
cairo_int_status_t status_b);
cairo_private cairo_surface_t *
_cairo_null_surface_create (cairo_content_t content);
#endif /* CAIRO_ANALYSIS_SURFACE_H */

View File

@@ -0,0 +1,934 @@
/*
* Copyright © 2006 Keith Packard
* Copyright © 2007 Adrian Johnson
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Keith Packard
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Adrian Johnson <ajohnson@redneon.com>
*/
#include "cairoint.h"
#include "cairo-analysis-surface-private.h"
#include "cairo-box-inline.h"
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
#include "cairo-paginated-private.h"
#include "cairo-recording-surface-inline.h"
#include "cairo-surface-snapshot-inline.h"
#include "cairo-surface-subsurface-inline.h"
#include "cairo-region-private.h"
typedef struct {
cairo_surface_t base;
cairo_surface_t *target;
cairo_bool_t first_op;
cairo_bool_t has_supported;
cairo_bool_t has_unsupported;
cairo_region_t supported_region;
cairo_region_t fallback_region;
cairo_box_t page_bbox;
cairo_bool_t has_ctm;
cairo_matrix_t ctm;
} cairo_analysis_surface_t;
cairo_int_status_t
_cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
cairo_int_status_t status_b)
{
/* fatal errors should be checked and propagated at source */
assert (! _cairo_int_status_is_error (status_a));
assert (! _cairo_int_status_is_error (status_b));
/* return the most important status */
if (status_a == CAIRO_INT_STATUS_UNSUPPORTED ||
status_b == CAIRO_INT_STATUS_UNSUPPORTED)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (status_a == CAIRO_INT_STATUS_IMAGE_FALLBACK ||
status_b == CAIRO_INT_STATUS_IMAGE_FALLBACK)
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
if (status_a == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN ||
status_b == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
if (status_a == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
status_b == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
/* at this point we have checked all the valid internal codes, so... */
assert (status_a == CAIRO_INT_STATUS_SUCCESS &&
status_b == CAIRO_INT_STATUS_SUCCESS);
return CAIRO_INT_STATUS_SUCCESS;
}
struct proxy {
cairo_surface_t base;
cairo_surface_t *target;
};
static cairo_status_t
proxy_finish (void *abstract_surface)
{
return CAIRO_STATUS_SUCCESS;
}
static const cairo_surface_backend_t proxy_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
proxy_finish,
};
static cairo_surface_t *
attach_proxy (cairo_surface_t *source,
cairo_surface_t *target)
{
struct proxy *proxy;
proxy = malloc (sizeof (*proxy));
if (unlikely (proxy == NULL))
return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
_cairo_surface_init (&proxy->base, &proxy_backend, NULL, target->content);
proxy->target = target;
_cairo_surface_attach_snapshot (source, &proxy->base, NULL);
return &proxy->base;
}
static void
detach_proxy (cairo_surface_t *proxy)
{
cairo_surface_finish (proxy);
cairo_surface_destroy (proxy);
}
static cairo_int_status_t
_analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
const cairo_pattern_t *pattern)
{
const cairo_surface_pattern_t *surface_pattern;
cairo_analysis_surface_t *tmp;
cairo_surface_t *source, *proxy;
cairo_matrix_t p2d;
cairo_status_t status, analysis_status;
assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
surface_pattern = (const cairo_surface_pattern_t *) pattern;
assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING);
source = surface_pattern->surface;
proxy = _cairo_surface_has_snapshot (source, &proxy_backend);
if (proxy != NULL) {
/* nothing untoward found so far */
return CAIRO_STATUS_SUCCESS;
}
tmp = (cairo_analysis_surface_t *)
_cairo_analysis_surface_create (surface->target);
if (unlikely (tmp->base.status))
return tmp->base.status;
proxy = attach_proxy (source, &tmp->base);
p2d = pattern->matrix;
status = cairo_matrix_invert (&p2d);
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&tmp->ctm, &p2d, &surface->ctm);
tmp->has_ctm = ! _cairo_matrix_is_identity (&tmp->ctm);
source = _cairo_surface_get_source (source, NULL);
status = _cairo_recording_surface_replay_and_create_regions (source,
&tmp->base);
analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS;
detach_proxy (proxy);
cairo_surface_destroy (&tmp->base);
if (unlikely (status))
return status;
return analysis_status;
}
static cairo_int_status_t
_add_operation (cairo_analysis_surface_t *surface,
cairo_rectangle_int_t *rect,
cairo_int_status_t backend_status)
{
cairo_int_status_t status;
cairo_box_t bbox;
if (rect->width == 0 || rect->height == 0) {
/* Even though the operation is not visible we must be careful
* to not allow unsupported operations to be replayed to the
* backend during CAIRO_PAGINATED_MODE_RENDER */
if (backend_status == CAIRO_INT_STATUS_SUCCESS ||
backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
backend_status == CAIRO_INT_STATUS_NOTHING_TO_DO)
{
return CAIRO_INT_STATUS_SUCCESS;
}
else
{
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
}
}
_cairo_box_from_rectangle (&bbox, rect);
if (surface->has_ctm) {
int tx, ty;
if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) {
rect->x += tx;
rect->y += ty;
tx = _cairo_fixed_from_int (tx);
bbox.p1.x += tx;
bbox.p2.x += tx;
ty = _cairo_fixed_from_int (ty);
bbox.p1.y += ty;
bbox.p2.y += ty;
} else {
_cairo_matrix_transform_bounding_box_fixed (&surface->ctm,
&bbox, NULL);
if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
/* Even though the operation is not visible we must be
* careful to not allow unsupported operations to be
* replayed to the backend during
* CAIRO_PAGINATED_MODE_RENDER */
if (backend_status == CAIRO_INT_STATUS_SUCCESS ||
backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
backend_status == CAIRO_INT_STATUS_NOTHING_TO_DO)
{
return CAIRO_INT_STATUS_SUCCESS;
}
else
{
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
}
}
_cairo_box_round_to_rectangle (&bbox, rect);
}
}
if (surface->first_op) {
surface->first_op = FALSE;
surface->page_bbox = bbox;
} else
_cairo_box_add_box(&surface->page_bbox, &bbox);
/* If the operation is completely enclosed within the fallback
* region there is no benefit in emitting a native operation as
* the fallback image will be painted on top.
*/
if (cairo_region_contains_rectangle (&surface->fallback_region, rect) == CAIRO_REGION_OVERLAP_IN)
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) {
/* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates
* that the backend only supports this operation if the
* transparency removed. If the extents of this operation does
* not intersect any other native operation, the operation is
* natively supported and the backend will blend the
* transparency into the white background.
*/
if (cairo_region_contains_rectangle (&surface->supported_region, rect) == CAIRO_REGION_OVERLAP_OUT)
backend_status = CAIRO_INT_STATUS_SUCCESS;
}
if (backend_status == CAIRO_INT_STATUS_SUCCESS) {
/* Add the operation to the supported region. Operations in
* this region will be emitted as native operations.
*/
surface->has_supported = TRUE;
return cairo_region_union_rectangle (&surface->supported_region, rect);
}
/* Add the operation to the unsupported region. This region will
* be painted as an image after all native operations have been
* emitted.
*/
surface->has_unsupported = TRUE;
status = cairo_region_union_rectangle (&surface->fallback_region, rect);
/* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
* unsupported operations to the recording surface as using
* CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to
* invoke the cairo-surface-fallback path then return
* CAIRO_STATUS_SUCCESS.
*/
if (status == CAIRO_INT_STATUS_SUCCESS)
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
else
return status;
}
static cairo_status_t
_cairo_analysis_surface_finish (void *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
_cairo_region_fini (&surface->supported_region);
_cairo_region_fini (&surface->fallback_region);
cairo_surface_destroy (surface->target);
return CAIRO_STATUS_SUCCESS;
}
static cairo_bool_t
_cairo_analysis_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_analysis_surface_t *surface = abstract_surface;
return _cairo_surface_get_extents (surface->target, rectangle);
}
static void
_rectangle_intersect_clip (cairo_rectangle_int_t *extents, const cairo_clip_t *clip)
{
if (clip != NULL)
_cairo_rectangle_intersect (extents, _cairo_clip_get_extents (clip));
}
static void
_cairo_analysis_surface_operation_extents (cairo_analysis_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip,
cairo_rectangle_int_t *extents)
{
cairo_bool_t is_empty;
is_empty = _cairo_surface_get_extents (&surface->base, extents);
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
_cairo_pattern_get_extents (source, &source_extents);
_cairo_rectangle_intersect (extents, &source_extents);
}
_rectangle_intersect_clip (extents, clip);
}
static cairo_int_status_t
_cairo_analysis_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t backend_status;
cairo_rectangle_int_t extents;
if (surface->target->backend->paint == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
backend_status =
surface->target->backend->paint (surface->target,
op, source, clip);
if (_cairo_int_status_is_error (backend_status))
return backend_status;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
backend_status = _analyze_recording_surface_pattern (surface, source);
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
return _add_operation (surface, &extents, backend_status);
}
static cairo_int_status_t
_cairo_analysis_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
const cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t backend_status;
cairo_rectangle_int_t extents;
if (surface->target->backend->mask == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
backend_status =
surface->target->backend->mask (surface->target,
op, source, mask, clip);
if (_cairo_int_status_is_error (backend_status))
return backend_status;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS;
cairo_int_status_t backend_mask_status = CAIRO_STATUS_SUCCESS;
if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_t *src_surface = ((cairo_surface_pattern_t *)source)->surface;
src_surface = _cairo_surface_get_source (src_surface, NULL);
if (_cairo_surface_is_recording (src_surface)) {
backend_source_status =
_analyze_recording_surface_pattern (surface, source);
if (_cairo_int_status_is_error (backend_source_status))
return backend_source_status;
}
}
if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_t *mask_surface = ((cairo_surface_pattern_t *)mask)->surface;
mask_surface = _cairo_surface_get_source (mask_surface, NULL);
if (_cairo_surface_is_recording (mask_surface)) {
backend_mask_status =
_analyze_recording_surface_pattern (surface, mask);
if (_cairo_int_status_is_error (backend_mask_status))
return backend_mask_status;
}
}
backend_status =
_cairo_analysis_surface_merge_status (backend_source_status,
backend_mask_status);
}
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
_cairo_pattern_get_extents (mask, &mask_extents);
_cairo_rectangle_intersect (&extents, &mask_extents);
}
return _add_operation (surface, &extents, backend_status);
}
static cairo_int_status_t
_cairo_analysis_surface_stroke (void *abstract_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)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t backend_status;
cairo_rectangle_int_t extents;
if (surface->target->backend->stroke == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
backend_status =
surface->target->backend->stroke (surface->target, op,
source, path, style,
ctm, ctm_inverse,
tolerance, antialias,
clip);
if (_cairo_int_status_is_error (backend_status))
return backend_status;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
backend_status = _analyze_recording_surface_pattern (surface, source);
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
cairo_int_status_t status;
status = _cairo_path_fixed_stroke_extents (path, style,
ctm, ctm_inverse,
tolerance,
&mask_extents);
if (unlikely (status))
return status;
_cairo_rectangle_intersect (&extents, &mask_extents);
}
return _add_operation (surface, &extents, backend_status);
}
static cairo_int_status_t
_cairo_analysis_surface_fill (void *abstract_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)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t backend_status;
cairo_rectangle_int_t extents;
if (surface->target->backend->fill == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
backend_status =
surface->target->backend->fill (surface->target, op,
source, path, fill_rule,
tolerance, antialias,
clip);
if (_cairo_int_status_is_error (backend_status))
return backend_status;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
backend_status = _analyze_recording_surface_pattern (surface, source);
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
_cairo_path_fixed_fill_extents (path, fill_rule, tolerance,
&mask_extents);
_cairo_rectangle_intersect (&extents, &mask_extents);
}
return _add_operation (surface, &extents, backend_status);
}
static cairo_int_status_t
_cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
const cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t status, backend_status;
cairo_rectangle_int_t extents, glyph_extents;
/* Adapted from _cairo_surface_show_glyphs */
if (surface->target->backend->show_glyphs != NULL) {
backend_status =
surface->target->backend->show_glyphs (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
clip);
if (_cairo_int_status_is_error (backend_status))
return backend_status;
}
else if (surface->target->backend->show_text_glyphs != NULL)
{
backend_status =
surface->target->backend->show_text_glyphs (surface->target, op,
source,
NULL, 0,
glyphs, num_glyphs,
NULL, 0,
FALSE,
scaled_font,
clip);
if (_cairo_int_status_is_error (backend_status))
return backend_status;
}
else
{
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
backend_status = _analyze_recording_surface_pattern (surface, source);
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
if (_cairo_operator_bounded_by_mask (op)) {
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs,
num_glyphs,
&glyph_extents,
NULL);
if (unlikely (status))
return status;
_cairo_rectangle_intersect (&extents, &glyph_extents);
}
return _add_operation (surface, &extents, backend_status);
}
static cairo_bool_t
_cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface)
{
cairo_analysis_surface_t *surface = abstract_surface;
return cairo_surface_has_show_text_glyphs (surface->target);
}
static cairo_int_status_t
_cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
const cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t status, backend_status;
cairo_rectangle_int_t extents, glyph_extents;
/* Adapted from _cairo_surface_show_glyphs */
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->target->backend->show_text_glyphs != NULL) {
backend_status =
surface->target->backend->show_text_glyphs (surface->target, op,
source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags,
scaled_font,
clip);
if (_cairo_int_status_is_error (backend_status))
return backend_status;
}
if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED &&
surface->target->backend->show_glyphs != NULL)
{
backend_status =
surface->target->backend->show_glyphs (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
clip);
if (_cairo_int_status_is_error (backend_status))
return backend_status;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
backend_status = _analyze_recording_surface_pattern (surface, source);
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
if (_cairo_operator_bounded_by_mask (op)) {
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs,
num_glyphs,
&glyph_extents,
NULL);
if (unlikely (status))
return status;
_cairo_rectangle_intersect (&extents, &glyph_extents);
}
return _add_operation (surface, &extents, backend_status);
}
static const cairo_surface_backend_t cairo_analysis_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
_cairo_analysis_surface_finish,
NULL,
NULL, /* create_similar */
NULL, /* create_similar_image */
NULL, /* map_to_image */
NULL, /* unmap */
NULL, /* source */
NULL, /* acquire_source_image */
NULL, /* release_source_image */
NULL, /* snapshot */
NULL, /* copy_page */
NULL, /* show_page */
_cairo_analysis_surface_get_extents,
NULL, /* get_font_options */
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
_cairo_analysis_surface_paint,
_cairo_analysis_surface_mask,
_cairo_analysis_surface_stroke,
_cairo_analysis_surface_fill,
NULL, /* fill_stroke */
_cairo_analysis_surface_show_glyphs,
_cairo_analysis_surface_has_show_text_glyphs,
_cairo_analysis_surface_show_text_glyphs
};
cairo_surface_t *
_cairo_analysis_surface_create (cairo_surface_t *target)
{
cairo_analysis_surface_t *surface;
cairo_status_t status;
status = target->status;
if (unlikely (status))
return _cairo_surface_create_in_error (status);
surface = malloc (sizeof (cairo_analysis_surface_t));
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
/* I believe the content type here is truly arbitrary. I'm quite
* sure nothing will ever use this value. */
_cairo_surface_init (&surface->base,
&cairo_analysis_surface_backend,
NULL, /* device */
CAIRO_CONTENT_COLOR_ALPHA);
cairo_matrix_init_identity (&surface->ctm);
surface->has_ctm = FALSE;
surface->target = cairo_surface_reference (target);
surface->first_op = TRUE;
surface->has_supported = FALSE;
surface->has_unsupported = FALSE;
_cairo_region_init (&surface->supported_region);
_cairo_region_init (&surface->fallback_region);
surface->page_bbox.p1.x = 0;
surface->page_bbox.p1.y = 0;
surface->page_bbox.p2.x = 0;
surface->page_bbox.p2.y = 0;
return &surface->base;
}
void
_cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
const cairo_matrix_t *ctm)
{
cairo_analysis_surface_t *surface;
if (abstract_surface->status)
return;
surface = (cairo_analysis_surface_t *) abstract_surface;
surface->ctm = *ctm;
surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
}
void
_cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface,
cairo_matrix_t *ctm)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
*ctm = surface->ctm;
}
cairo_region_t *
_cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
return &surface->supported_region;
}
cairo_region_t *
_cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
return &surface->fallback_region;
}
cairo_bool_t
_cairo_analysis_surface_has_supported (cairo_surface_t *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
return surface->has_supported;
}
cairo_bool_t
_cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
return surface->has_unsupported;
}
void
_cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface,
cairo_box_t *bbox)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
*bbox = surface->page_bbox;
}
/* null surface type: a surface that does nothing (has no side effects, yay!) */
static cairo_int_status_t
_return_success (void)
{
return CAIRO_STATUS_SUCCESS;
}
/* These typedefs are just to silence the compiler... */
typedef cairo_int_status_t
(*_paint_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip);
typedef cairo_int_status_t
(*_mask_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
const cairo_clip_t *clip);
typedef cairo_int_status_t
(*_stroke_func) (void *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);
typedef cairo_int_status_t
(*_fill_func) (void *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);
typedef cairo_int_status_t
(*_show_glyphs_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
const cairo_clip_t *clip);
static const cairo_surface_backend_t cairo_null_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
NULL, /* finish */
NULL, /* only accessed through the surface functions */
NULL, /* create_similar */
NULL, /* create similar image */
NULL, /* map to image */
NULL, /* unmap image*/
NULL, /* source */
NULL, /* acquire_source_image */
NULL, /* release_source_image */
NULL, /* snapshot */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* get_extents */
NULL, /* get_font_options */
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
(_paint_func) _return_success, /* paint */
(_mask_func) _return_success, /* mask */
(_stroke_func) _return_success, /* stroke */
(_fill_func) _return_success, /* fill */
NULL, /* fill_stroke */
(_show_glyphs_func) _return_success, /* show_glyphs */
NULL, /* has_show_text_glyphs */
NULL /* show_text_glyphs */
};
cairo_surface_t *
_cairo_null_surface_create (cairo_content_t content)
{
cairo_surface_t *surface;
surface = malloc (sizeof (cairo_surface_t));
if (unlikely (surface == NULL)) {
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
_cairo_surface_init (surface,
&cairo_null_surface_backend,
NULL, /* device */
content);
return surface;
}

View File

@@ -0,0 +1,61 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@redhat.com>
*/
#ifndef CAIRO_ARC_PRIVATE_H
#define CAIRO_ARC_PRIVATE_H
#include "cairoint.h"
CAIRO_BEGIN_DECLS
cairo_private void
_cairo_arc_path (cairo_t *cr,
double xc,
double yc,
double radius,
double angle1,
double angle2);
cairo_private void
_cairo_arc_path_negative (cairo_t *cr,
double xc,
double yc,
double radius,
double angle1,
double angle2);
CAIRO_END_DECLS
#endif /* CAIRO_ARC_PRIVATE_H */

View File

@@ -0,0 +1,308 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* 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.
*
* 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>
*/
#include "cairoint.h"
#include "cairo-arc-private.h"
#define MAX_FULL_CIRCLES 65536
/* Spline deviation from the circle in radius would be given by:
error = sqrt (x**2 + y**2) - 1
A simpler error function to work with is:
e = x**2 + y**2 - 1
From "Good approximation of circles by curvature-continuous Bezier
curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
Design 8 (1990) 22-41, we learn:
abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4)
and
abs (error) =~ 1/2 * e
Of course, this error value applies only for the particular spline
approximation that is used in _cairo_gstate_arc_segment.
*/
static double
_arc_error_normalized (double angle)
{
return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
}
static double
_arc_max_angle_for_tolerance_normalized (double tolerance)
{
double angle, error;
int i;
/* Use table lookup to reduce search time in most cases. */
struct {
double angle;
double error;
} table[] = {
{ M_PI / 1.0, 0.0185185185185185036127 },
{ M_PI / 2.0, 0.000272567143730179811158 },
{ M_PI / 3.0, 2.38647043651461047433e-05 },
{ M_PI / 4.0, 4.2455377443222443279e-06 },
{ M_PI / 5.0, 1.11281001494389081528e-06 },
{ M_PI / 6.0, 3.72662000942734705475e-07 },
{ M_PI / 7.0, 1.47783685574284411325e-07 },
{ M_PI / 8.0, 6.63240432022601149057e-08 },
{ M_PI / 9.0, 3.2715520137536980553e-08 },
{ M_PI / 10.0, 1.73863223499021216974e-08 },
{ M_PI / 11.0, 9.81410988043554039085e-09 },
};
int table_size = ARRAY_LENGTH (table);
for (i = 0; i < table_size; i++)
if (table[i].error < tolerance)
return table[i].angle;
++i;
do {
angle = M_PI / i++;
error = _arc_error_normalized (angle);
} while (error > tolerance);
return angle;
}
static int
_arc_segments_needed (double angle,
double radius,
cairo_matrix_t *ctm,
double tolerance)
{
double major_axis, max_angle;
/* the error is amplified by at most the length of the
* major axis of the circle; see cairo-pen.c for a more detailed analysis
* of this. */
major_axis = _cairo_matrix_transformed_circle_major_axis (ctm, radius);
max_angle = _arc_max_angle_for_tolerance_normalized (tolerance / major_axis);
return ceil (fabs (angle) / max_angle);
}
/* We want to draw a single spline approximating a circular arc radius
R from angle A to angle B. Since we want a symmetric spline that
matches the endpoints of the arc in position and slope, we know
that the spline control points must be:
(R * cos(A), R * sin(A))
(R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
(R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
(R * cos(B), R * sin(B))
for some value of h.
"Approximation of circular arcs by cubic polynomials", Michael
Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides
various values of h along with error analysis for each.
From that paper, a very practical value of h is:
h = 4/3 * R * tan(angle/4)
This value does not give the spline with minimal error, but it does
provide a very good approximation, (6th-order convergence), and the
error expression is quite simple, (see the comment for
_arc_error_normalized).
*/
static void
_cairo_arc_segment (cairo_t *cr,
double xc,
double yc,
double radius,
double angle_A,
double angle_B)
{
double r_sin_A, r_cos_A;
double r_sin_B, r_cos_B;
double h;
r_sin_A = radius * sin (angle_A);
r_cos_A = radius * cos (angle_A);
r_sin_B = radius * sin (angle_B);
r_cos_B = radius * cos (angle_B);
h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
cairo_curve_to (cr,
xc + r_cos_A - h * r_sin_A,
yc + r_sin_A + h * r_cos_A,
xc + r_cos_B + h * r_sin_B,
yc + r_sin_B - h * r_cos_B,
xc + r_cos_B,
yc + r_sin_B);
}
static void
_cairo_arc_in_direction (cairo_t *cr,
double xc,
double yc,
double radius,
double angle_min,
double angle_max,
cairo_direction_t dir)
{
if (cairo_status (cr))
return;
assert (angle_max >= angle_min);
if (angle_max - angle_min > 2 * M_PI * MAX_FULL_CIRCLES) {
angle_max = fmod (angle_max - angle_min, 2 * M_PI);
angle_min = fmod (angle_min, 2 * M_PI);
angle_max += angle_min + 2 * M_PI * MAX_FULL_CIRCLES;
}
/* Recurse if drawing arc larger than pi */
if (angle_max - angle_min > M_PI) {
double angle_mid = angle_min + (angle_max - angle_min) / 2.0;
if (dir == CAIRO_DIRECTION_FORWARD) {
_cairo_arc_in_direction (cr, xc, yc, radius,
angle_min, angle_mid,
dir);
_cairo_arc_in_direction (cr, xc, yc, radius,
angle_mid, angle_max,
dir);
} else {
_cairo_arc_in_direction (cr, xc, yc, radius,
angle_mid, angle_max,
dir);
_cairo_arc_in_direction (cr, xc, yc, radius,
angle_min, angle_mid,
dir);
}
} else if (angle_max != angle_min) {
cairo_matrix_t ctm;
int i, segments;
double step;
cairo_get_matrix (cr, &ctm);
segments = _arc_segments_needed (angle_max - angle_min,
radius, &ctm,
cairo_get_tolerance (cr));
step = (angle_max - angle_min) / segments;
segments -= 1;
if (dir == CAIRO_DIRECTION_REVERSE) {
double t;
t = angle_min;
angle_min = angle_max;
angle_max = t;
step = -step;
}
for (i = 0; i < segments; i++, angle_min += step) {
_cairo_arc_segment (cr, xc, yc, radius,
angle_min, angle_min + step);
}
_cairo_arc_segment (cr, xc, yc, radius,
angle_min, angle_max);
} else {
cairo_line_to (cr,
xc + radius * cos (angle_min),
yc + radius * sin (angle_min));
}
}
/**
* _cairo_arc_path:
* @cr: a cairo context
* @xc: X position of the center of the arc
* @yc: Y position of the center of the arc
* @radius: the radius of the arc
* @angle1: the start angle, in radians
* @angle2: the end angle, in radians
*
* Compute a path for the given arc and append it onto the current
* path within @cr. The arc will be accurate within the current
* tolerance and given the current transformation.
**/
void
_cairo_arc_path (cairo_t *cr,
double xc,
double yc,
double radius,
double angle1,
double angle2)
{
_cairo_arc_in_direction (cr, xc, yc,
radius,
angle1, angle2,
CAIRO_DIRECTION_FORWARD);
}
/**
* _cairo_arc_path_negative:
* @xc: X position of the center of the arc
* @yc: Y position of the center of the arc
* @radius: the radius of the arc
* @angle1: the start angle, in radians
* @angle2: the end angle, in radians
* @ctm: the current transformation matrix
* @tolerance: the current tolerance value
* @path: the path onto which the arc will be appended
*
* Compute a path for the given arc (defined in the negative
* direction) and append it onto the current path within @cr. The arc
* will be accurate within the current tolerance and given the current
* transformation.
**/
void
_cairo_arc_path_negative (cairo_t *cr,
double xc,
double yc,
double radius,
double angle1,
double angle2)
{
_cairo_arc_in_direction (cr, xc, yc,
radius,
angle2, angle1,
CAIRO_DIRECTION_REVERSE);
}

View File

@@ -0,0 +1,90 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* 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.
*
* 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>
*/
#ifndef CAIRO_ARRAY_PRIVATE_H
#define CAIRO_ARRAY_PRIVATE_H
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
CAIRO_BEGIN_DECLS
/* cairo-array.c structures and functions */
cairo_private void
_cairo_array_init (cairo_array_t *array, unsigned int element_size);
cairo_private void
_cairo_array_fini (cairo_array_t *array);
cairo_private cairo_status_t
_cairo_array_grow_by (cairo_array_t *array, unsigned int additional);
cairo_private void
_cairo_array_truncate (cairo_array_t *array, unsigned int num_elements);
cairo_private cairo_status_t
_cairo_array_append (cairo_array_t *array, const void *element);
cairo_private cairo_status_t
_cairo_array_append_multiple (cairo_array_t *array,
const void *elements,
unsigned int num_elements);
cairo_private cairo_status_t
_cairo_array_allocate (cairo_array_t *array,
unsigned int num_elements,
void **elements);
cairo_private void *
_cairo_array_index (cairo_array_t *array, unsigned int index);
cairo_private const void *
_cairo_array_index_const (const cairo_array_t *array, unsigned int index);
cairo_private void
_cairo_array_copy_element (const cairo_array_t *array, unsigned int index, void *dst);
cairo_private unsigned int
_cairo_array_num_elements (const cairo_array_t *array);
cairo_private unsigned int
_cairo_array_size (const cairo_array_t *array);
CAIRO_END_DECLS
#endif /* CAIRO_ARRAY_PRIVATE_H */

View File

@@ -0,0 +1,526 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Carl Worth <cworth@cworth.org>
*/
#include "cairoint.h"
#include "cairo-array-private.h"
#include "cairo-error-private.h"
/**
* _cairo_array_init:
*
* Initialize a new #cairo_array_t object to store objects each of size
* @element_size.
*
* The #cairo_array_t object provides grow-by-doubling storage. It
* never interprets the data passed to it, nor does it provide any
* sort of callback mechanism for freeing resources held onto by
* stored objects.
*
* When finished using the array, _cairo_array_fini() should be
* called to free resources allocated during use of the array.
**/
void
_cairo_array_init (cairo_array_t *array, unsigned int element_size)
{
array->size = 0;
array->num_elements = 0;
array->element_size = element_size;
array->elements = NULL;
}
/**
* _cairo_array_fini:
* @array: A #cairo_array_t
*
* Free all resources associated with @array. After this call, @array
* should not be used again without a subsequent call to
* _cairo_array_init() again first.
**/
void
_cairo_array_fini (cairo_array_t *array)
{
free (array->elements);
}
/**
* _cairo_array_grow_by:
* @array: a #cairo_array_t
*
* Increase the size of @array (if needed) so that there are at least
* @additional free spaces in the array. The actual size of the array
* is always increased by doubling as many times as necessary.
**/
cairo_status_t
_cairo_array_grow_by (cairo_array_t *array, unsigned int additional)
{
char *new_elements;
unsigned int old_size = array->size;
unsigned int required_size = array->num_elements + additional;
unsigned int new_size;
/* check for integer overflow */
if (required_size > INT_MAX || required_size < array->num_elements)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (required_size <= old_size)
return CAIRO_STATUS_SUCCESS;
if (old_size == 0)
new_size = 1;
else
new_size = old_size * 2;
while (new_size < required_size)
new_size = new_size * 2;
array->size = new_size;
new_elements = _cairo_realloc_ab (array->elements,
array->size, array->element_size);
if (unlikely (new_elements == NULL)) {
array->size = old_size;
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
array->elements = new_elements;
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_array_truncate:
* @array: a #cairo_array_t
*
* Truncate size of the array to @num_elements if less than the
* current size. No memory is actually freed. The stored objects
* beyond @num_elements are simply "forgotten".
**/
void
_cairo_array_truncate (cairo_array_t *array, unsigned int num_elements)
{
if (num_elements < array->num_elements)
array->num_elements = num_elements;
}
/**
* _cairo_array_index:
* @array: a #cairo_array_t
* Returns: A pointer to the object stored at @index.
*
* If the resulting value is assigned to a pointer to an object of the same
* element_size as initially passed to _cairo_array_init() then that
* pointer may be used for further direct indexing with []. For
* example:
*
* <informalexample><programlisting>
* cairo_array_t array;
* double *values;
*
* _cairo_array_init (&array, sizeof(double));
* ... calls to _cairo_array_append() here ...
*
* values = _cairo_array_index (&array, 0);
* for (i = 0; i < _cairo_array_num_elements (&array); i++)
* ... use values[i] here ...
* </programlisting></informalexample>
**/
void *
_cairo_array_index (cairo_array_t *array, unsigned int index)
{
/* We allow an index of 0 for the no-elements case.
* This makes for cleaner calling code which will often look like:
*
* elements = _cairo_array_index (array, 0);
* for (i=0; i < num_elements; i++) {
* ... use elements[i] here ...
* }
*
* which in the num_elements==0 case gets the NULL pointer here,
* but never dereferences it.
*/
if (index == 0 && array->num_elements == 0)
return NULL;
assert (index < array->num_elements);
return array->elements + index * array->element_size;
}
/**
* _cairo_array_index_const:
* @array: a #cairo_array_t
* Returns: A pointer to the object stored at @index.
*
* If the resulting value is assigned to a pointer to an object of the same
* element_size as initially passed to _cairo_array_init() then that
* pointer may be used for further direct indexing with []. For
* example:
*
* <informalexample><programlisting>
* cairo_array_t array;
* const double *values;
*
* _cairo_array_init (&array, sizeof(double));
* ... calls to _cairo_array_append() here ...
*
* values = _cairo_array_index_const (&array, 0);
* for (i = 0; i < _cairo_array_num_elements (&array); i++)
* ... read values[i] here ...
* </programlisting></informalexample>
**/
const void *
_cairo_array_index_const (const cairo_array_t *array, unsigned int index)
{
/* We allow an index of 0 for the no-elements case.
* This makes for cleaner calling code which will often look like:
*
* elements = _cairo_array_index_const (array, 0);
* for (i=0; i < num_elements; i++) {
* ... read elements[i] here ...
* }
*
* which in the num_elements==0 case gets the NULL pointer here,
* but never dereferences it.
*/
if (index == 0 && array->num_elements == 0)
return NULL;
assert (index < array->num_elements);
return array->elements + index * array->element_size;
}
/**
* _cairo_array_copy_element:
* @array: a #cairo_array_t
*
* Copy a single element out of the array from index @index into the
* location pointed to by @dst.
**/
void
_cairo_array_copy_element (const cairo_array_t *array,
unsigned int index,
void *dst)
{
memcpy (dst, _cairo_array_index_const (array, index), array->element_size);
}
/**
* _cairo_array_append:
* @array: a #cairo_array_t
*
* Append a single item onto the array by growing the array by at
* least one element, then copying element_size bytes from @element
* into the array. The address of the resulting object within the
* array can be determined with:
*
* _cairo_array_index (array, _cairo_array_num_elements (array) - 1);
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* operation.
**/
cairo_status_t
_cairo_array_append (cairo_array_t *array,
const void *element)
{
return _cairo_array_append_multiple (array, element, 1);
}
/**
* _cairo_array_append_multiple:
* @array: a #cairo_array_t
*
* Append one or more items onto the array by growing the array by
* @num_elements, then copying @num_elements * element_size bytes from
* @elements into the array.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* operation.
**/
cairo_status_t
_cairo_array_append_multiple (cairo_array_t *array,
const void *elements,
unsigned int num_elements)
{
cairo_status_t status;
void *dest;
status = _cairo_array_allocate (array, num_elements, &dest);
if (unlikely (status))
return status;
memcpy (dest, elements, num_elements * array->element_size);
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_array_allocate:
* @array: a #cairo_array_t
*
* Allocate space at the end of the array for @num_elements additional
* elements, providing the address of the new memory chunk in
* @elements. This memory will be unitialized, but will be accounted
* for in the return value of _cairo_array_num_elements().
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* operation.
**/
cairo_status_t
_cairo_array_allocate (cairo_array_t *array,
unsigned int num_elements,
void **elements)
{
cairo_status_t status;
status = _cairo_array_grow_by (array, num_elements);
if (unlikely (status))
return status;
assert (array->num_elements + num_elements <= array->size);
*elements = array->elements + array->num_elements * array->element_size;
array->num_elements += num_elements;
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_array_num_elements:
* @array: a #cairo_array_t
* Returns: The number of elements stored in @array.
*
* This space was left intentionally blank, but gtk-doc filled it.
**/
unsigned int
_cairo_array_num_elements (const cairo_array_t *array)
{
return array->num_elements;
}
/**
* _cairo_array_size:
* @array: a #cairo_array_t
* Returns: The number of elements for which there is currently space
* allocated in @array.
*
* This space was left intentionally blank, but gtk-doc filled it.
**/
unsigned int
_cairo_array_size (const cairo_array_t *array)
{
return array->size;
}
/**
* _cairo_user_data_array_init:
* @array: a #cairo_user_data_array_t
*
* Initializes a #cairo_user_data_array_t structure for future
* use. After initialization, the array has no keys. Call
* _cairo_user_data_array_fini() to free any allocated memory
* when done using the array.
**/
void
_cairo_user_data_array_init (cairo_user_data_array_t *array)
{
_cairo_array_init (array, sizeof (cairo_user_data_slot_t));
}
/**
* _cairo_user_data_array_fini:
* @array: a #cairo_user_data_array_t
*
* Destroys all current keys in the user data array and deallocates
* any memory allocated for the array itself.
**/
void
_cairo_user_data_array_fini (cairo_user_data_array_t *array)
{
unsigned int num_slots;
num_slots = array->num_elements;
if (num_slots) {
cairo_user_data_slot_t *slots;
slots = _cairo_array_index (array, 0);
while (num_slots--) {
cairo_user_data_slot_t *s = &slots[num_slots];
if (s->user_data != NULL && s->destroy != NULL)
s->destroy (s->user_data);
}
}
_cairo_array_fini (array);
}
/**
* _cairo_user_data_array_get_data:
* @array: a #cairo_user_data_array_t
* @key: the address of the #cairo_user_data_key_t the user data was
* attached to
*
* Returns user data previously attached using the specified
* key. If no user data has been attached with the given key this
* function returns %NULL.
*
* Return value: the user data previously attached or %NULL.
**/
void *
_cairo_user_data_array_get_data (cairo_user_data_array_t *array,
const cairo_user_data_key_t *key)
{
int i, num_slots;
cairo_user_data_slot_t *slots;
/* We allow this to support degenerate objects such as cairo_surface_nil. */
if (array == NULL)
return NULL;
num_slots = array->num_elements;
slots = _cairo_array_index (array, 0);
for (i = 0; i < num_slots; i++) {
if (slots[i].key == key)
return slots[i].user_data;
}
return NULL;
}
/**
* _cairo_user_data_array_set_data:
* @array: a #cairo_user_data_array_t
* @key: the address of a #cairo_user_data_key_t to attach the user data to
* @user_data: the user data to attach
* @destroy: a #cairo_destroy_func_t which will be called when the
* user data array is destroyed or when new user data is attached using the
* same key.
*
* Attaches user data to a user data array. To remove user data,
* call this function with the key that was used to set it and %NULL
* for @data.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
**/
cairo_status_t
_cairo_user_data_array_set_data (cairo_user_data_array_t *array,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy)
{
cairo_status_t status;
int i, num_slots;
cairo_user_data_slot_t *slots, *slot, new_slot;
if (user_data) {
new_slot.key = key;
new_slot.user_data = user_data;
new_slot.destroy = destroy;
} else {
new_slot.key = NULL;
new_slot.user_data = NULL;
new_slot.destroy = NULL;
}
slot = NULL;
num_slots = array->num_elements;
slots = _cairo_array_index (array, 0);
for (i = 0; i < num_slots; i++) {
if (slots[i].key == key) {
slot = &slots[i];
if (slot->destroy && slot->user_data)
slot->destroy (slot->user_data);
break;
}
if (user_data && slots[i].user_data == NULL) {
slot = &slots[i]; /* Have to keep searching for an exact match */
}
}
if (slot) {
*slot = new_slot;
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_array_append (array, &new_slot);
if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_user_data_array_copy (cairo_user_data_array_t *dst,
const cairo_user_data_array_t *src)
{
/* discard any existing user-data */
if (dst->num_elements != 0) {
_cairo_user_data_array_fini (dst);
_cairo_user_data_array_init (dst);
}
return _cairo_array_append_multiple (dst,
_cairo_array_index_const (src, 0),
src->num_elements);
}
void
_cairo_user_data_array_foreach (cairo_user_data_array_t *array,
void (*func) (const void *key,
void *elt,
void *closure),
void *closure)
{
cairo_user_data_slot_t *slots;
int i, num_slots;
num_slots = array->num_elements;
slots = _cairo_array_index (array, 0);
for (i = 0; i < num_slots; i++) {
if (slots[i].user_data != NULL)
func (slots[i].key, slots[i].user_data, closure);
}
}

View File

@@ -0,0 +1,272 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Chris Wilson
* Copyright © 2010 Andrea Canciani
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
* Andrea Canciani <ranma42@gmail.com>
*/
#ifndef CAIRO_ATOMIC_PRIVATE_H
#define CAIRO_ATOMIC_PRIVATE_H
# include "cairo-compiler-private.h"
#if HAVE_CONFIG_H
#include "config.h"
#endif
/* The autoconf on OpenBSD 4.5 produces the malformed constant name
* SIZEOF_VOID__ rather than SIZEOF_VOID_P. Work around that here. */
#if !defined(SIZEOF_VOID_P) && defined(SIZEOF_VOID__)
# define SIZEOF_VOID_P SIZEOF_VOID__
#endif
CAIRO_BEGIN_DECLS
#if HAVE_INTEL_ATOMIC_PRIMITIVES
#define HAS_ATOMIC_OPS 1
typedef int cairo_atomic_int_t;
#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
static cairo_always_inline cairo_atomic_int_t
_cairo_atomic_int_get (cairo_atomic_int_t *x)
{
__sync_synchronize ();
return *x;
}
static cairo_always_inline void *
_cairo_atomic_ptr_get (void **x)
{
__sync_synchronize ();
return *x;
}
#else
# define _cairo_atomic_int_get(x) (*x)
# define _cairo_atomic_ptr_get(x) (*x)
#endif
# define _cairo_atomic_int_inc(x) ((void) __sync_fetch_and_add(x, 1))
# define _cairo_atomic_int_dec(x) ((void) __sync_fetch_and_add(x, -1))
# define _cairo_atomic_int_dec_and_test(x) (__sync_fetch_and_add(x, -1) == 1)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_bool_compare_and_swap (x, oldv, newv)
# define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv)
#if SIZEOF_VOID_P==SIZEOF_INT
typedef int cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG
typedef long cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG_LONG
typedef long long cairo_atomic_intptr_t;
#else
#error No matching integer pointer type
#endif
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
__sync_bool_compare_and_swap ((cairo_atomic_intptr_t*)x, (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
# define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) \
_cairo_atomic_intptr_to_voidptr (__sync_val_compare_and_swap ((cairo_atomic_intptr_t*)x, (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv))
#endif
#if HAVE_LIB_ATOMIC_OPS
#include <atomic_ops.h>
#define HAS_ATOMIC_OPS 1
typedef AO_t cairo_atomic_int_t;
# define _cairo_atomic_int_get(x) (AO_load_full (x))
# define _cairo_atomic_int_inc(x) ((void) AO_fetch_and_add1_full(x))
# define _cairo_atomic_int_dec(x) ((void) AO_fetch_and_sub1_full(x))
# define _cairo_atomic_int_dec_and_test(x) (AO_fetch_and_sub1_full(x) == 1)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) AO_compare_and_swap_full(x, oldv, newv)
#if SIZEOF_VOID_P==SIZEOF_INT
typedef unsigned int cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG
typedef unsigned long cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG_LONG
typedef unsigned long long cairo_atomic_intptr_t;
#else
#error No matching integer pointer type
#endif
# define _cairo_atomic_ptr_get(x) _cairo_atomic_intptr_to_voidptr (AO_load_full (x))
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
_cairo_atomic_int_cmpxchg ((cairo_atomic_intptr_t*)(x), (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
#endif
#if HAVE_OS_ATOMIC_OPS
#include <libkern/OSAtomic.h>
#define HAS_ATOMIC_OPS 1
typedef int32_t cairo_atomic_int_t;
# define _cairo_atomic_int_get(x) (OSMemoryBarrier(), *(x))
# define _cairo_atomic_int_inc(x) ((void) OSAtomicIncrement32Barrier (x))
# define _cairo_atomic_int_dec(x) ((void) OSAtomicDecrement32Barrier (x))
# define _cairo_atomic_int_dec_and_test(x) (OSAtomicDecrement32Barrier (x) == 0)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) OSAtomicCompareAndSwap32Barrier(oldv, newv, x)
#if SIZEOF_VOID_P==4
typedef int32_t cairo_atomic_intptr_t;
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
OSAtomicCompareAndSwap32Barrier((cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv, (cairo_atomic_intptr_t *)x)
#elif SIZEOF_VOID_P==8
typedef int64_t cairo_atomic_intptr_t;
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
OSAtomicCompareAndSwap64Barrier((cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv, (cairo_atomic_intptr_t *)x)
#else
#error No matching integer pointer type
#endif
# define _cairo_atomic_ptr_get(x) (OSMemoryBarrier(), *(x))
#endif
#ifndef HAS_ATOMIC_OPS
#if SIZEOF_VOID_P==SIZEOF_INT
typedef unsigned int cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG
typedef unsigned long cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG_LONG
typedef unsigned long long cairo_atomic_intptr_t;
#else
#error No matching integer pointer type
#endif
typedef cairo_atomic_intptr_t cairo_atomic_int_t;
cairo_private void
_cairo_atomic_int_inc (cairo_atomic_int_t *x);
#define _cairo_atomic_int_dec(x) _cairo_atomic_int_dec_and_test(x)
cairo_private cairo_bool_t
_cairo_atomic_int_dec_and_test (cairo_atomic_int_t *x);
cairo_private cairo_atomic_int_t
_cairo_atomic_int_cmpxchg_return_old_impl (cairo_atomic_int_t *x, cairo_atomic_int_t oldv, cairo_atomic_int_t newv);
cairo_private void *
_cairo_atomic_ptr_cmpxchg_return_old_impl (void **x, void *oldv, void *newv);
#define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_int_cmpxchg_return_old_impl (x, oldv, newv)
#define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_ptr_cmpxchg_return_old_impl (x, oldv, newv)
#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
cairo_private cairo_atomic_int_t
_cairo_atomic_int_get (cairo_atomic_int_t *x);
# define _cairo_atomic_ptr_get(x) (void *) _cairo_atomic_int_get((cairo_atomic_int_t *) x)
#else
# define _cairo_atomic_int_get(x) (*x)
# define _cairo_atomic_ptr_get(x) (*x)
#endif
#else
/* Workaround GCC complaining about casts */
static cairo_always_inline void *
_cairo_atomic_intptr_to_voidptr (cairo_atomic_intptr_t x)
{
return (void *) x;
}
static cairo_always_inline cairo_atomic_int_t
_cairo_atomic_int_cmpxchg_return_old_fallback(cairo_atomic_int_t *x, cairo_atomic_int_t oldv, cairo_atomic_int_t newv)
{
cairo_atomic_int_t curr;
do {
curr = _cairo_atomic_int_get (x);
} while (curr == oldv && !_cairo_atomic_int_cmpxchg (x, oldv, newv));
return curr;
}
static cairo_always_inline void *
_cairo_atomic_ptr_cmpxchg_return_old_fallback(void **x, void *oldv, void *newv)
{
void *curr;
do {
curr = _cairo_atomic_ptr_get (x);
} while (curr == oldv && !_cairo_atomic_ptr_cmpxchg (x, oldv, newv));
return curr;
}
#endif
#ifndef _cairo_atomic_int_cmpxchg_return_old
#define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_int_cmpxchg_return_old_fallback (x, oldv, newv)
#endif
#ifndef _cairo_atomic_ptr_cmpxchg_return_old
#define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_ptr_cmpxchg_return_old_fallback (x, oldv, newv)
#endif
#ifndef _cairo_atomic_int_cmpxchg
#define _cairo_atomic_int_cmpxchg(x, oldv, newv) (_cairo_atomic_int_cmpxchg_return_old (x, oldv, newv) == oldv)
#endif
#ifndef _cairo_atomic_ptr_cmpxchg
#define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) (_cairo_atomic_ptr_cmpxchg_return_old (x, oldv, newv) == oldv)
#endif
#define _cairo_atomic_uint_get(x) _cairo_atomic_int_get(x)
#define _cairo_atomic_uint_cmpxchg(x, oldv, newv) \
_cairo_atomic_int_cmpxchg((cairo_atomic_int_t *)x, oldv, newv)
#define _cairo_status_set_error(status, err) do { \
int ret__; \
assert (err < CAIRO_STATUS_LAST_STATUS); \
/* hide compiler warnings about cairo_status_t != int (gcc treats its as \
* an unsigned integer instead, and about ignoring the return value. */ \
ret__ = _cairo_atomic_int_cmpxchg ((cairo_atomic_int_t *) status, CAIRO_STATUS_SUCCESS, err); \
(void) ret__; \
} while (0)
CAIRO_END_DECLS
#endif

View File

@@ -0,0 +1,106 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Chris Wilson
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-atomic-private.h"
#include "cairo-mutex-private.h"
#ifdef HAS_ATOMIC_OPS
COMPILE_TIME_ASSERT(sizeof(void*) == sizeof(int) ||
sizeof(void*) == sizeof(long) ||
sizeof(void*) == sizeof(long long));
#else
void
_cairo_atomic_int_inc (cairo_atomic_intptr_t *x)
{
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
*x += 1;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
}
cairo_bool_t
_cairo_atomic_int_dec_and_test (cairo_atomic_intptr_t *x)
{
cairo_bool_t ret;
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = --*x == 0;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
return ret;
}
cairo_atomic_intptr_t
_cairo_atomic_int_cmpxchg_return_old_impl (cairo_atomic_intptr_t *x, cairo_atomic_intptr_t oldv, cairo_atomic_intptr_t newv)
{
cairo_atomic_intptr_t ret;
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = *x;
if (ret == oldv)
*x = newv;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
return ret;
}
void *
_cairo_atomic_ptr_cmpxchg_return_old_impl (void **x, void *oldv, void *newv)
{
void *ret;
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = *x;
if (ret == oldv)
*x = newv;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
return ret;
}
#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
cairo_atomic_intptr_t
_cairo_atomic_int_get (cairo_atomic_intptr_t *x)
{
cairo_atomic_intptr_t ret;
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = *x;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
return ret;
}
#endif
#endif

View File

@@ -0,0 +1,201 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2010 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Intel Corporation
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_BACKEND_PRIVATE_H
#define CAIRO_BACKEND_PRIVATE_H
#include "cairo-types-private.h"
#include "cairo-private.h"
typedef enum _cairo_backend_type {
CAIRO_TYPE_DEFAULT,
CAIRO_TYPE_SKIA,
} cairo_backend_type_t;
struct _cairo_backend {
cairo_backend_type_t type;
void (*destroy) (void *cr);
cairo_surface_t *(*get_original_target) (void *cr);
cairo_surface_t *(*get_current_target) (void *cr);
cairo_status_t (*save) (void *cr);
cairo_status_t (*restore) (void *cr);
cairo_status_t (*push_group) (void *cr, cairo_content_t content);
cairo_pattern_t *(*pop_group) (void *cr);
cairo_status_t (*set_source_rgba) (void *cr, double red, double green, double blue, double alpha);
cairo_status_t (*set_source_surface) (void *cr, cairo_surface_t *surface, double x, double y);
cairo_status_t (*set_source) (void *cr, cairo_pattern_t *source);
cairo_pattern_t *(*get_source) (void *cr);
cairo_status_t (*set_antialias) (void *cr, cairo_antialias_t antialias);
cairo_status_t (*set_dash) (void *cr, const double *dashes, int num_dashes, double offset);
cairo_status_t (*set_fill_rule) (void *cr, cairo_fill_rule_t fill_rule);
cairo_status_t (*set_line_cap) (void *cr, cairo_line_cap_t line_cap);
cairo_status_t (*set_line_join) (void *cr, cairo_line_join_t line_join);
cairo_status_t (*set_line_width) (void *cr, double line_width);
cairo_status_t (*set_miter_limit) (void *cr, double limit);
cairo_status_t (*set_opacity) (void *cr, double opacity);
cairo_status_t (*set_operator) (void *cr, cairo_operator_t op);
cairo_status_t (*set_tolerance) (void *cr, double tolerance);
cairo_antialias_t (*get_antialias) (void *cr);
void (*get_dash) (void *cr, double *dashes, int *num_dashes, double *offset);
cairo_fill_rule_t (*get_fill_rule) (void *cr);
cairo_line_cap_t (*get_line_cap) (void *cr);
cairo_line_join_t (*get_line_join) (void *cr);
double (*get_line_width) (void *cr);
double (*get_miter_limit) (void *cr);
double (*get_opacity) (void *cr);
cairo_operator_t (*get_operator) (void *cr);
double (*get_tolerance) (void *cr);
cairo_status_t (*translate) (void *cr, double tx, double ty);
cairo_status_t (*scale) (void *cr, double sx, double sy);
cairo_status_t (*rotate) (void *cr, double theta);
cairo_status_t (*transform) (void *cr, const cairo_matrix_t *matrix);
cairo_status_t (*set_matrix) (void *cr, const cairo_matrix_t *matrix);
cairo_status_t (*set_identity_matrix) (void *cr);
void (*get_matrix) (void *cr, cairo_matrix_t *matrix);
void (*user_to_device) (void *cr, double *x, double *y);
void (*user_to_device_distance) (void *cr, double *x, double *y);
void (*device_to_user) (void *cr, double *x, double *y);
void (*device_to_user_distance) (void *cr, double *x, double *y);
void (*user_to_backend) (void *cr, double *x, double *y);
void (*user_to_backend_distance) (void *cr, double *x, double *y);
void (*backend_to_user) (void *cr, double *x, double *y);
void (*backend_to_user_distance) (void *cr, double *x, double *y);
cairo_status_t (*new_path) (void *cr);
cairo_status_t (*new_sub_path) (void *cr);
cairo_status_t (*move_to) (void *cr, double x, double y);
cairo_status_t (*rel_move_to) (void *cr, double dx, double dy);
cairo_status_t (*line_to) (void *cr, double x, double y);
cairo_status_t (*rel_line_to) (void *cr, double dx, double dy);
cairo_status_t (*curve_to) (void *cr, double x1, double y1, double x2, double y2, double x3, double y3);
cairo_status_t (*rel_curve_to) (void *cr, double dx1, double dy1, double dx2, double dy2, double dx3, double dy3);
cairo_status_t (*arc_to) (void *cr, double x1, double y1, double x2, double y2, double radius);
cairo_status_t (*rel_arc_to) (void *cr, double dx1, double dy1, double dx2, double dy2, double radius);
cairo_status_t (*close_path) (void *cr);
cairo_status_t (*arc) (void *cr, double xc, double yc, double radius, double angle1, double angle2, cairo_bool_t forward);
cairo_status_t (*rectangle) (void *cr, double x, double y, double width, double height);
void (*path_extents) (void *cr, double *x1, double *y1, double *x2, double *y2);
cairo_bool_t (*has_current_point) (void *cr);
cairo_bool_t (*get_current_point) (void *cr, double *x, double *y);
cairo_path_t *(*copy_path) (void *cr);
cairo_path_t *(*copy_path_flat) (void *cr);
cairo_status_t (*append_path) (void *cr, const cairo_path_t *path);
cairo_status_t (*stroke_to_path) (void *cr);
cairo_status_t (*clip) (void *cr);
cairo_status_t (*clip_preserve) (void *cr);
cairo_status_t (*in_clip) (void *cr, double x, double y, cairo_bool_t *inside);
cairo_status_t (*clip_extents) (void *cr, double *x1, double *y1, double *x2, double *y2);
cairo_status_t (*reset_clip) (void *cr);
cairo_rectangle_list_t *(*clip_copy_rectangle_list) (void *cr);
cairo_status_t (*paint) (void *cr);
cairo_status_t (*paint_with_alpha) (void *cr, double opacity);
cairo_status_t (*mask) (void *cr, cairo_pattern_t *pattern);
cairo_status_t (*stroke) (void *cr);
cairo_status_t (*stroke_preserve) (void *cr);
cairo_status_t (*in_stroke) (void *cr, double x, double y, cairo_bool_t *inside);
cairo_status_t (*stroke_extents) (void *cr, double *x1, double *y1, double *x2, double *y2);
cairo_status_t (*fill) (void *cr);
cairo_status_t (*fill_preserve) (void *cr);
cairo_status_t (*in_fill) (void *cr, double x, double y, cairo_bool_t *inside);
cairo_status_t (*fill_extents) (void *cr, double *x1, double *y1, double *x2, double *y2);
cairo_status_t (*set_font_face) (void *cr, cairo_font_face_t *font_face);
cairo_font_face_t *(*get_font_face) (void *cr);
cairo_status_t (*set_font_size) (void *cr, double size);
cairo_status_t (*set_font_matrix) (void *cr, const cairo_matrix_t *matrix);
void (*get_font_matrix) (void *cr, cairo_matrix_t *matrix);
cairo_status_t (*set_font_options) (void *cr, const cairo_font_options_t *options);
void (*get_font_options) (void *cr, cairo_font_options_t *options);
cairo_status_t (*set_scaled_font) (void *cr, cairo_scaled_font_t *scaled_font);
cairo_scaled_font_t *(*get_scaled_font) (void *cr);
cairo_status_t (*font_extents) (void *cr, cairo_font_extents_t *extents);
cairo_status_t (*glyphs) (void *cr,
const cairo_glyph_t *glyphs, int num_glyphs,
cairo_glyph_text_info_t *info);
cairo_status_t (*glyph_path) (void *cr,
const cairo_glyph_t *glyphs, int num_glyphs);
cairo_status_t (*glyph_extents) (void *cr,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents);
cairo_status_t (*copy_page) (void *cr);
cairo_status_t (*show_page) (void *cr);
};
static inline void
_cairo_backend_to_user (cairo_t *cr, double *x, double *y)
{
cr->backend->backend_to_user (cr, x, y);
}
static inline void
_cairo_backend_to_user_distance (cairo_t *cr, double *x, double *y)
{
cr->backend->backend_to_user_distance (cr, x, y);
}
static inline void
_cairo_user_to_backend (cairo_t *cr, double *x, double *y)
{
cr->backend->user_to_backend (cr, x, y);
}
static inline void
_cairo_user_to_backend_distance (cairo_t *cr, double *x, double *y)
{
cr->backend->user_to_backend_distance (cr, x, y);
}
#endif /* CAIRO_BACKEND_PRIVATE_H */

View File

@@ -0,0 +1,144 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005-2007 Emmanuel Pacaud <emmanuel.pacaud@free.fr>
* Copyright © 2009 Chris Wilson
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Author(s):
* Kristian Høgsberg <krh@redhat.com>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-output-stream-private.h"
typedef struct _cairo_base64_stream {
cairo_output_stream_t base;
cairo_output_stream_t *output;
unsigned int in_mem;
unsigned int trailing;
unsigned char src[3];
} cairo_base64_stream_t;
static char const base64_table[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static cairo_status_t
_cairo_base64_stream_write (cairo_output_stream_t *base,
const unsigned char *data,
unsigned int length)
{
cairo_base64_stream_t * stream = (cairo_base64_stream_t *) base;
unsigned char *src = stream->src;
unsigned int i;
if (stream->in_mem + length < 3) {
for (i = 0; i < length; i++) {
src[i + stream->in_mem] = *data++;
}
stream->in_mem += length;
return CAIRO_STATUS_SUCCESS;
}
do {
unsigned char dst[4];
for (i = stream->in_mem; i < 3; i++) {
src[i] = *data++;
length--;
}
stream->in_mem = 0;
dst[0] = base64_table[src[0] >> 2];
dst[1] = base64_table[(src[0] & 0x03) << 4 | src[1] >> 4];
dst[2] = base64_table[(src[1] & 0x0f) << 2 | src[2] >> 6];
dst[3] = base64_table[src[2] & 0xfc >> 2];
/* Special case for the last missing bits */
switch (stream->trailing) {
case 2:
dst[2] = '=';
case 1:
dst[3] = '=';
default:
break;
}
_cairo_output_stream_write (stream->output, dst, 4);
} while (length >= 3);
for (i = 0; i < length; i++) {
src[i] = *data++;
}
stream->in_mem = length;
return _cairo_output_stream_get_status (stream->output);
}
static cairo_status_t
_cairo_base64_stream_close (cairo_output_stream_t *base)
{
cairo_base64_stream_t *stream = (cairo_base64_stream_t *) base;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
if (stream->in_mem > 0) {
memset (stream->src + stream->in_mem, 0, 3 - stream->in_mem);
stream->trailing = 3 - stream->in_mem;
stream->in_mem = 3;
status = _cairo_base64_stream_write (base, NULL, 0);
}
return status;
}
cairo_output_stream_t *
_cairo_base64_stream_create (cairo_output_stream_t *output)
{
cairo_base64_stream_t *stream;
if (output->status)
return _cairo_output_stream_create_in_error (output->status);
stream = malloc (sizeof (cairo_base64_stream_t));
if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base,
_cairo_base64_stream_write,
NULL,
_cairo_base64_stream_close);
stream->output = output;
stream->in_mem = 0;
stream->trailing = 0;
return &stream->base;
}

View File

@@ -0,0 +1,131 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Author(s):
* Kristian Høgsberg <krh@redhat.com>
*/
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-output-stream-private.h"
typedef struct _cairo_base85_stream {
cairo_output_stream_t base;
cairo_output_stream_t *output;
unsigned char four_tuple[4];
int pending;
} cairo_base85_stream_t;
static void
_expand_four_tuple_to_five (unsigned char four_tuple[4],
unsigned char five_tuple[5],
cairo_bool_t *all_zero)
{
uint32_t value;
int digit, i;
value = four_tuple[0] << 24 | four_tuple[1] << 16 | four_tuple[2] << 8 | four_tuple[3];
if (all_zero)
*all_zero = TRUE;
for (i = 0; i < 5; i++) {
digit = value % 85;
if (digit != 0 && all_zero)
*all_zero = FALSE;
five_tuple[4-i] = digit + 33;
value = value / 85;
}
}
static cairo_status_t
_cairo_base85_stream_write (cairo_output_stream_t *base,
const unsigned char *data,
unsigned int length)
{
cairo_base85_stream_t *stream = (cairo_base85_stream_t *) base;
const unsigned char *ptr = data;
unsigned char five_tuple[5];
cairo_bool_t is_zero;
while (length) {
stream->four_tuple[stream->pending++] = *ptr++;
length--;
if (stream->pending == 4) {
_expand_four_tuple_to_five (stream->four_tuple, five_tuple, &is_zero);
if (is_zero)
_cairo_output_stream_write (stream->output, "z", 1);
else
_cairo_output_stream_write (stream->output, five_tuple, 5);
stream->pending = 0;
}
}
return _cairo_output_stream_get_status (stream->output);
}
static cairo_status_t
_cairo_base85_stream_close (cairo_output_stream_t *base)
{
cairo_base85_stream_t *stream = (cairo_base85_stream_t *) base;
unsigned char five_tuple[5];
if (stream->pending) {
memset (stream->four_tuple + stream->pending, 0, 4 - stream->pending);
_expand_four_tuple_to_five (stream->four_tuple, five_tuple, NULL);
_cairo_output_stream_write (stream->output, five_tuple, stream->pending + 1);
}
return _cairo_output_stream_get_status (stream->output);
}
cairo_output_stream_t *
_cairo_base85_stream_create (cairo_output_stream_t *output)
{
cairo_base85_stream_t *stream;
if (output->status)
return _cairo_output_stream_create_in_error (output->status);
stream = malloc (sizeof (cairo_base85_stream_t));
if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base,
_cairo_base85_stream_write,
NULL,
_cairo_base85_stream_close);
stream->output = output;
stream->pending = 0;
return &stream->base;
}

View File

@@ -0,0 +1,884 @@
/*
* Copyright © 2004 Carl Worth
* Copyright © 2006 Red Hat, Inc.
* Copyright © 2009 Chris Wilson
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Carl Worth
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
/* Provide definitions for standalone compilation */
#include "cairoint.h"
#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-combsort-inline.h"
#include "cairo-list-private.h"
#include "cairo-traps-private.h"
#include <setjmp.h>
typedef struct _rectangle rectangle_t;
typedef struct _edge edge_t;
struct _edge {
edge_t *next, *prev;
edge_t *right;
cairo_fixed_t x, top;
int dir;
};
struct _rectangle {
edge_t left, right;
int32_t top, bottom;
};
#define UNROLL3(x) x x x
/* the parent is always given by index/2 */
#define PQ_PARENT_INDEX(i) ((i) >> 1)
#define PQ_FIRST_ENTRY 1
/* left and right children are index * 2 and (index * 2) +1 respectively */
#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
typedef struct _sweep_line {
rectangle_t **rectangles;
rectangle_t **stop;
edge_t head, tail, *insert, *cursor;
int32_t current_y;
int32_t last_y;
int stop_size;
int32_t insert_x;
cairo_fill_rule_t fill_rule;
cairo_bool_t do_traps;
void *container;
jmp_buf unwind;
} sweep_line_t;
#define DEBUG_TRAPS 0
#if DEBUG_TRAPS
static void
dump_traps (cairo_traps_t *traps, const char *filename)
{
FILE *file;
int n;
if (getenv ("CAIRO_DEBUG_TRAPS") == NULL)
return;
file = fopen (filename, "a");
if (file != NULL) {
for (n = 0; n < traps->num_traps; n++) {
fprintf (file, "%d %d L:(%d, %d), (%d, %d) R:(%d, %d), (%d, %d)\n",
traps->traps[n].top,
traps->traps[n].bottom,
traps->traps[n].left.p1.x,
traps->traps[n].left.p1.y,
traps->traps[n].left.p2.x,
traps->traps[n].left.p2.y,
traps->traps[n].right.p1.x,
traps->traps[n].right.p1.y,
traps->traps[n].right.p2.x,
traps->traps[n].right.p2.y);
}
fprintf (file, "\n");
fclose (file);
}
}
#else
#define dump_traps(traps, filename)
#endif
static inline int
rectangle_compare_start (const rectangle_t *a,
const rectangle_t *b)
{
return a->top - b->top;
}
static inline int
rectangle_compare_stop (const rectangle_t *a,
const rectangle_t *b)
{
return a->bottom - b->bottom;
}
static inline void
pqueue_push (sweep_line_t *sweep, rectangle_t *rectangle)
{
rectangle_t **elements;
int i, parent;
elements = sweep->stop;
for (i = ++sweep->stop_size;
i != PQ_FIRST_ENTRY &&
rectangle_compare_stop (rectangle,
elements[parent = PQ_PARENT_INDEX (i)]) < 0;
i = parent)
{
elements[i] = elements[parent];
}
elements[i] = rectangle;
}
static inline void
rectangle_pop_stop (sweep_line_t *sweep)
{
rectangle_t **elements = sweep->stop;
rectangle_t *tail;
int child, i;
tail = elements[sweep->stop_size--];
if (sweep->stop_size == 0) {
elements[PQ_FIRST_ENTRY] = NULL;
return;
}
for (i = PQ_FIRST_ENTRY;
(child = PQ_LEFT_CHILD_INDEX (i)) <= sweep->stop_size;
i = child)
{
if (child != sweep->stop_size &&
rectangle_compare_stop (elements[child+1],
elements[child]) < 0)
{
child++;
}
if (rectangle_compare_stop (elements[child], tail) >= 0)
break;
elements[i] = elements[child];
}
elements[i] = tail;
}
static inline rectangle_t *
rectangle_pop_start (sweep_line_t *sweep_line)
{
return *sweep_line->rectangles++;
}
static inline rectangle_t *
rectangle_peek_stop (sweep_line_t *sweep_line)
{
return sweep_line->stop[PQ_FIRST_ENTRY];
}
CAIRO_COMBSORT_DECLARE (_rectangle_sort,
rectangle_t *,
rectangle_compare_start)
static void
sweep_line_init (sweep_line_t *sweep_line,
rectangle_t **rectangles,
int num_rectangles,
cairo_fill_rule_t fill_rule,
cairo_bool_t do_traps,
void *container)
{
rectangles[-2] = NULL;
rectangles[-1] = NULL;
rectangles[num_rectangles] = NULL;
sweep_line->rectangles = rectangles;
sweep_line->stop = rectangles - 2;
sweep_line->stop_size = 0;
sweep_line->insert = NULL;
sweep_line->insert_x = INT_MAX;
sweep_line->cursor = &sweep_line->tail;
sweep_line->head.dir = 0;
sweep_line->head.x = INT32_MIN;
sweep_line->head.right = NULL;
sweep_line->head.prev = NULL;
sweep_line->head.next = &sweep_line->tail;
sweep_line->tail.prev = &sweep_line->head;
sweep_line->tail.next = NULL;
sweep_line->tail.right = NULL;
sweep_line->tail.x = INT32_MAX;
sweep_line->tail.dir = 0;
sweep_line->current_y = INT32_MIN;
sweep_line->last_y = INT32_MIN;
sweep_line->fill_rule = fill_rule;
sweep_line->container = container;
sweep_line->do_traps = do_traps;
}
static void
edge_end_box (sweep_line_t *sweep_line, edge_t *left, int32_t bot)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
/* Only emit (trivial) non-degenerate trapezoids with positive height. */
if (likely (left->top < bot)) {
if (sweep_line->do_traps) {
cairo_line_t _left = {
{ left->x, left->top },
{ left->x, bot },
}, _right = {
{ left->right->x, left->top },
{ left->right->x, bot },
};
_cairo_traps_add_trap (sweep_line->container, left->top, bot, &_left, &_right);
status = _cairo_traps_status ((cairo_traps_t *) sweep_line->container);
} else {
cairo_box_t box;
box.p1.x = left->x;
box.p1.y = left->top;
box.p2.x = left->right->x;
box.p2.y = bot;
status = _cairo_boxes_add (sweep_line->container,
CAIRO_ANTIALIAS_DEFAULT,
&box);
}
}
if (unlikely (status))
longjmp (sweep_line->unwind, status);
left->right = NULL;
}
/* Start a new trapezoid at the given top y coordinate, whose edges
* are `edge' and `edge->next'. If `edge' already has a trapezoid,
* then either add it to the traps in `traps', if the trapezoid's
* right edge differs from `edge->next', or do nothing if the new
* trapezoid would be a continuation of the existing one. */
static inline void
edge_start_or_continue_box (sweep_line_t *sweep_line,
edge_t *left,
edge_t *right,
int top)
{
if (left->right == right)
return;
if (left->right != NULL) {
if (left->right->x == right->x) {
/* continuation on right, so just swap edges */
left->right = right;
return;
}
edge_end_box (sweep_line, left, top);
}
if (left->x != right->x) {
left->top = top;
left->right = right;
}
}
/*
* Merge two sorted edge lists.
* Input:
* - head_a: The head of the first list.
* - head_b: The head of the second list; head_b cannot be NULL.
* Output:
* Returns the head of the merged list.
*
* Implementation notes:
* To make it fast (in particular, to reduce to an insertion sort whenever
* one of the two input lists only has a single element) we iterate through
* a list until its head becomes greater than the head of the other list,
* then we switch their roles. As soon as one of the two lists is empty, we
* just attach the other one to the current list and exit.
* Writes to memory are only needed to "switch" lists (as it also requires
* attaching to the output list the list which we will be iterating next) and
* to attach the last non-empty list.
*/
static edge_t *
merge_sorted_edges (edge_t *head_a, edge_t *head_b)
{
edge_t *head, *prev;
int32_t x;
prev = head_a->prev;
if (head_a->x <= head_b->x) {
head = head_a;
} else {
head_b->prev = prev;
head = head_b;
goto start_with_b;
}
do {
x = head_b->x;
while (head_a != NULL && head_a->x <= x) {
prev = head_a;
head_a = head_a->next;
}
head_b->prev = prev;
prev->next = head_b;
if (head_a == NULL)
return head;
start_with_b:
x = head_a->x;
while (head_b != NULL && head_b->x <= x) {
prev = head_b;
head_b = head_b->next;
}
head_a->prev = prev;
prev->next = head_a;
if (head_b == NULL)
return head;
} while (1);
}
/*
* Sort (part of) a list.
* Input:
* - list: The list to be sorted; list cannot be NULL.
* - limit: Recursion limit.
* Output:
* - head_out: The head of the sorted list containing the first 2^(level+1) elements of the
* input list; if the input list has fewer elements, head_out be a sorted list
* containing all the elements of the input list.
* Returns the head of the list of unprocessed elements (NULL if the sorted list contains
* all the elements of the input list).
*
* Implementation notes:
* Special case single element list, unroll/inline the sorting of the first two elements.
* Some tail recursion is used since we iterate on the bottom-up solution of the problem
* (we start with a small sorted list and keep merging other lists of the same size to it).
*/
static edge_t *
sort_edges (edge_t *list,
unsigned int level,
edge_t **head_out)
{
edge_t *head_other, *remaining;
unsigned int i;
head_other = list->next;
if (head_other == NULL) {
*head_out = list;
return NULL;
}
remaining = head_other->next;
if (list->x <= head_other->x) {
*head_out = list;
head_other->next = NULL;
} else {
*head_out = head_other;
head_other->prev = list->prev;
head_other->next = list;
list->prev = head_other;
list->next = NULL;
}
for (i = 0; i < level && remaining; i++) {
remaining = sort_edges (remaining, i, &head_other);
*head_out = merge_sorted_edges (*head_out, head_other);
}
return remaining;
}
static edge_t *
merge_unsorted_edges (edge_t *head, edge_t *unsorted)
{
sort_edges (unsorted, UINT_MAX, &unsorted);
return merge_sorted_edges (head, unsorted);
}
static void
active_edges_insert (sweep_line_t *sweep)
{
edge_t *prev;
int x;
x = sweep->insert_x;
prev = sweep->cursor;
if (prev->x > x) {
do {
prev = prev->prev;
} while (prev->x > x);
} else {
while (prev->next->x < x)
prev = prev->next;
}
prev->next = merge_unsorted_edges (prev->next, sweep->insert);
sweep->cursor = sweep->insert;
sweep->insert = NULL;
sweep->insert_x = INT_MAX;
}
static inline void
active_edges_to_traps (sweep_line_t *sweep)
{
int top = sweep->current_y;
edge_t *pos;
if (sweep->last_y == sweep->current_y)
return;
if (sweep->insert)
active_edges_insert (sweep);
pos = sweep->head.next;
if (pos == &sweep->tail)
return;
if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING) {
do {
edge_t *left, *right;
int winding;
left = pos;
winding = left->dir;
right = left->next;
/* Check if there is a co-linear edge with an existing trap */
while (right->x == left->x) {
if (right->right != NULL) {
assert (left->right == NULL);
/* continuation on left */
left->top = right->top;
left->right = right->right;
right->right = NULL;
}
winding += right->dir;
right = right->next;
}
if (winding == 0) {
if (left->right != NULL)
edge_end_box (sweep, left, top);
pos = right;
continue;
}
do {
/* End all subsumed traps */
if (unlikely (right->right != NULL))
edge_end_box (sweep, right, top);
/* Greedily search for the closing edge, so that we generate
* the * maximal span width with the minimal number of
* boxes.
*/
winding += right->dir;
if (winding == 0 && right->x != right->next->x)
break;
right = right->next;
} while (TRUE);
edge_start_or_continue_box (sweep, left, right, top);
pos = right->next;
} while (pos != &sweep->tail);
} else {
do {
edge_t *right = pos->next;
int count = 0;
do {
/* End all subsumed traps */
if (unlikely (right->right != NULL))
edge_end_box (sweep, right, top);
/* skip co-linear edges */
if (++count & 1 && right->x != right->next->x)
break;
right = right->next;
} while (TRUE);
edge_start_or_continue_box (sweep, pos, right, top);
pos = right->next;
} while (pos != &sweep->tail);
}
sweep->last_y = sweep->current_y;
}
static inline void
sweep_line_delete_edge (sweep_line_t *sweep, edge_t *edge)
{
if (edge->right != NULL) {
edge_t *next = edge->next;
if (next->x == edge->x) {
next->top = edge->top;
next->right = edge->right;
} else
edge_end_box (sweep, edge, sweep->current_y);
}
if (sweep->cursor == edge)
sweep->cursor = edge->prev;
edge->prev->next = edge->next;
edge->next->prev = edge->prev;
}
static inline cairo_bool_t
sweep_line_delete (sweep_line_t *sweep, rectangle_t *rectangle)
{
cairo_bool_t update;
update = TRUE;
if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING &&
rectangle->left.prev->dir == rectangle->left.dir)
{
update = rectangle->left.next != &rectangle->right;
}
sweep_line_delete_edge (sweep, &rectangle->left);
sweep_line_delete_edge (sweep, &rectangle->right);
rectangle_pop_stop (sweep);
return update;
}
static inline void
sweep_line_insert (sweep_line_t *sweep, rectangle_t *rectangle)
{
if (sweep->insert)
sweep->insert->prev = &rectangle->right;
rectangle->right.next = sweep->insert;
rectangle->right.prev = &rectangle->left;
rectangle->left.next = &rectangle->right;
rectangle->left.prev = NULL;
sweep->insert = &rectangle->left;
if (rectangle->left.x < sweep->insert_x)
sweep->insert_x = rectangle->left.x;
pqueue_push (sweep, rectangle);
}
static cairo_status_t
_cairo_bentley_ottmann_tessellate_rectangular (rectangle_t **rectangles,
int num_rectangles,
cairo_fill_rule_t fill_rule,
cairo_bool_t do_traps,
void *container)
{
sweep_line_t sweep_line;
rectangle_t *rectangle;
cairo_status_t status;
cairo_bool_t update = FALSE;
sweep_line_init (&sweep_line,
rectangles, num_rectangles,
fill_rule,
do_traps, container);
if ((status = setjmp (sweep_line.unwind)))
return status;
rectangle = rectangle_pop_start (&sweep_line);
do {
if (rectangle->top != sweep_line.current_y) {
rectangle_t *stop;
stop = rectangle_peek_stop (&sweep_line);
while (stop != NULL && stop->bottom < rectangle->top) {
if (stop->bottom != sweep_line.current_y) {
if (update) {
active_edges_to_traps (&sweep_line);
update = FALSE;
}
sweep_line.current_y = stop->bottom;
}
update |= sweep_line_delete (&sweep_line, stop);
stop = rectangle_peek_stop (&sweep_line);
}
if (update) {
active_edges_to_traps (&sweep_line);
update = FALSE;
}
sweep_line.current_y = rectangle->top;
}
do {
sweep_line_insert (&sweep_line, rectangle);
} while ((rectangle = rectangle_pop_start (&sweep_line)) != NULL &&
sweep_line.current_y == rectangle->top);
update = TRUE;
} while (rectangle);
while ((rectangle = rectangle_peek_stop (&sweep_line)) != NULL) {
if (rectangle->bottom != sweep_line.current_y) {
if (update) {
active_edges_to_traps (&sweep_line);
update = FALSE;
}
sweep_line.current_y = rectangle->bottom;
}
update |= sweep_line_delete (&sweep_line, rectangle);
}
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule)
{
rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)];
rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 3];
rectangle_t *rectangles, **rectangles_ptrs;
cairo_status_t status;
int i;
if (unlikely (traps->num_traps <= 1))
return CAIRO_STATUS_SUCCESS;
assert (traps->is_rectangular);
dump_traps (traps, "bo-rects-traps-in.txt");
rectangles = stack_rectangles;
rectangles_ptrs = stack_rectangles_ptrs;
if (traps->num_traps > ARRAY_LENGTH (stack_rectangles)) {
rectangles = _cairo_malloc_ab_plus_c (traps->num_traps,
sizeof (rectangle_t) +
sizeof (rectangle_t *),
3*sizeof (rectangle_t *));
if (unlikely (rectangles == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
rectangles_ptrs = (rectangle_t **) (rectangles + traps->num_traps);
}
for (i = 0; i < traps->num_traps; i++) {
if (traps->traps[i].left.p1.x < traps->traps[i].right.p1.x) {
rectangles[i].left.x = traps->traps[i].left.p1.x;
rectangles[i].left.dir = 1;
rectangles[i].right.x = traps->traps[i].right.p1.x;
rectangles[i].right.dir = -1;
} else {
rectangles[i].right.x = traps->traps[i].left.p1.x;
rectangles[i].right.dir = 1;
rectangles[i].left.x = traps->traps[i].right.p1.x;
rectangles[i].left.dir = -1;
}
rectangles[i].left.right = NULL;
rectangles[i].right.right = NULL;
rectangles[i].top = traps->traps[i].top;
rectangles[i].bottom = traps->traps[i].bottom;
rectangles_ptrs[i+2] = &rectangles[i];
}
/* XXX incremental sort */
_rectangle_sort (rectangles_ptrs+2, i);
_cairo_traps_clear (traps);
status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs+2, i,
fill_rule,
TRUE, traps);
traps->is_rectilinear = TRUE;
traps->is_rectangular = TRUE;
if (rectangles != stack_rectangles)
free (rectangles);
dump_traps (traps, "bo-rects-traps-out.txt");
return status;
}
cairo_status_t
_cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
cairo_fill_rule_t fill_rule,
cairo_boxes_t *out)
{
rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)];
rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 3];
rectangle_t *rectangles, **rectangles_ptrs;
rectangle_t *stack_rectangles_chain[CAIRO_STACK_ARRAY_LENGTH (rectangle_t *) ];
rectangle_t **rectangles_chain = NULL;
const struct _cairo_boxes_chunk *chunk;
cairo_status_t status;
int i, j, y_min, y_max;
if (unlikely (in->num_boxes == 0)) {
_cairo_boxes_clear (out);
return CAIRO_STATUS_SUCCESS;
}
if (in->num_boxes == 1) {
if (in == out) {
cairo_box_t *box = &in->chunks.base[0];
if (box->p1.x > box->p2.x) {
cairo_fixed_t tmp = box->p1.x;
box->p1.x = box->p2.x;
box->p2.x = tmp;
}
} else {
cairo_box_t box = in->chunks.base[0];
if (box.p1.x > box.p2.x) {
cairo_fixed_t tmp = box.p1.x;
box.p1.x = box.p2.x;
box.p2.x = tmp;
}
_cairo_boxes_clear (out);
status = _cairo_boxes_add (out, CAIRO_ANTIALIAS_DEFAULT, &box);
assert (status == CAIRO_STATUS_SUCCESS);
}
return CAIRO_STATUS_SUCCESS;
}
y_min = INT_MAX; y_max = INT_MIN;
for (chunk = &in->chunks; chunk != NULL; chunk = chunk->next) {
const cairo_box_t *box = chunk->base;
for (i = 0; i < chunk->count; i++) {
if (box[i].p1.y < y_min)
y_min = box[i].p1.y;
if (box[i].p1.y > y_max)
y_max = box[i].p1.y;
}
}
y_min = _cairo_fixed_integer_floor (y_min);
y_max = _cairo_fixed_integer_floor (y_max) + 1;
y_max -= y_min;
if (y_max < in->num_boxes) {
rectangles_chain = stack_rectangles_chain;
if (y_max > ARRAY_LENGTH (stack_rectangles_chain)) {
rectangles_chain = _cairo_malloc_ab (y_max, sizeof (rectangle_t *));
if (unlikely (rectangles_chain == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
memset (rectangles_chain, 0, y_max * sizeof (rectangle_t*));
}
rectangles = stack_rectangles;
rectangles_ptrs = stack_rectangles_ptrs;
if (in->num_boxes > ARRAY_LENGTH (stack_rectangles)) {
rectangles = _cairo_malloc_ab_plus_c (in->num_boxes,
sizeof (rectangle_t) +
sizeof (rectangle_t *),
3*sizeof (rectangle_t *));
if (unlikely (rectangles == NULL)) {
if (rectangles_chain != stack_rectangles_chain)
free (rectangles_chain);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
rectangles_ptrs = (rectangle_t **) (rectangles + in->num_boxes);
}
j = 0;
for (chunk = &in->chunks; chunk != NULL; chunk = chunk->next) {
const cairo_box_t *box = chunk->base;
for (i = 0; i < chunk->count; i++) {
int h;
if (box[i].p1.x < box[i].p2.x) {
rectangles[j].left.x = box[i].p1.x;
rectangles[j].left.dir = 1;
rectangles[j].right.x = box[i].p2.x;
rectangles[j].right.dir = -1;
} else {
rectangles[j].right.x = box[i].p1.x;
rectangles[j].right.dir = 1;
rectangles[j].left.x = box[i].p2.x;
rectangles[j].left.dir = -1;
}
rectangles[j].left.right = NULL;
rectangles[j].right.right = NULL;
rectangles[j].top = box[i].p1.y;
rectangles[j].bottom = box[i].p2.y;
if (rectangles_chain) {
h = _cairo_fixed_integer_floor (box[i].p1.y) - y_min;
rectangles[j].left.next = (edge_t *)rectangles_chain[h];
rectangles_chain[h] = &rectangles[j];
} else {
rectangles_ptrs[j+2] = &rectangles[j];
}
j++;
}
}
if (rectangles_chain) {
j = 2;
for (y_min = 0; y_min < y_max; y_min++) {
rectangle_t *r;
int start = j;
for (r = rectangles_chain[y_min]; r; r = (rectangle_t *)r->left.next)
rectangles_ptrs[j++] = r;
if (j > start + 1)
_rectangle_sort (rectangles_ptrs + start, j - start);
}
if (rectangles_chain != stack_rectangles_chain)
free (rectangles_chain);
j -= 2;
} else {
_rectangle_sort (rectangles_ptrs + 2, j);
}
_cairo_boxes_clear (out);
status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs+2, j,
fill_rule,
FALSE, out);
if (rectangles != stack_rectangles)
free (rectangles);
return status;
}

View File

@@ -0,0 +1,600 @@
/*
* Copyright © 2004 Carl Worth
* Copyright © 2006 Red Hat, Inc.
* Copyright © 2008 Chris Wilson
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Carl Worth
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
/* Provide definitions for standalone compilation */
#include "cairoint.h"
#include "cairo-boxes-private.h"
#include "cairo-combsort-inline.h"
#include "cairo-error-private.h"
#include "cairo-traps-private.h"
typedef struct _cairo_bo_edge cairo_bo_edge_t;
typedef struct _cairo_bo_trap cairo_bo_trap_t;
/* A deferred trapezoid of an edge */
struct _cairo_bo_trap {
cairo_bo_edge_t *right;
int32_t top;
};
struct _cairo_bo_edge {
cairo_edge_t edge;
cairo_bo_edge_t *prev;
cairo_bo_edge_t *next;
cairo_bo_trap_t deferred_trap;
};
typedef enum {
CAIRO_BO_EVENT_TYPE_START,
CAIRO_BO_EVENT_TYPE_STOP
} cairo_bo_event_type_t;
typedef struct _cairo_bo_event {
cairo_bo_event_type_t type;
cairo_point_t point;
cairo_bo_edge_t *edge;
} cairo_bo_event_t;
typedef struct _cairo_bo_sweep_line {
cairo_bo_event_t **events;
cairo_bo_edge_t *head;
cairo_bo_edge_t *stopped;
int32_t current_y;
cairo_bo_edge_t *current_edge;
} cairo_bo_sweep_line_t;
static inline int
_cairo_point_compare (const cairo_point_t *a,
const cairo_point_t *b)
{
int cmp;
cmp = a->y - b->y;
if (likely (cmp))
return cmp;
return a->x - b->x;
}
static inline int
_cairo_bo_edge_compare (const cairo_bo_edge_t *a,
const cairo_bo_edge_t *b)
{
int cmp;
cmp = a->edge.line.p1.x - b->edge.line.p1.x;
if (likely (cmp))
return cmp;
return b->edge.bottom - a->edge.bottom;
}
static inline int
cairo_bo_event_compare (const cairo_bo_event_t *a,
const cairo_bo_event_t *b)
{
int cmp;
cmp = _cairo_point_compare (&a->point, &b->point);
if (likely (cmp))
return cmp;
cmp = a->type - b->type;
if (cmp)
return cmp;
return a - b;
}
static inline cairo_bo_event_t *
_cairo_bo_event_dequeue (cairo_bo_sweep_line_t *sweep_line)
{
return *sweep_line->events++;
}
CAIRO_COMBSORT_DECLARE (_cairo_bo_event_queue_sort,
cairo_bo_event_t *,
cairo_bo_event_compare)
static void
_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_event_t **events,
int num_events)
{
_cairo_bo_event_queue_sort (events, num_events);
events[num_events] = NULL;
sweep_line->events = events;
sweep_line->head = NULL;
sweep_line->current_y = INT32_MIN;
sweep_line->current_edge = NULL;
}
static void
_cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t *edge)
{
if (sweep_line->current_edge != NULL) {
cairo_bo_edge_t *prev, *next;
int cmp;
cmp = _cairo_bo_edge_compare (sweep_line->current_edge, edge);
if (cmp < 0) {
prev = sweep_line->current_edge;
next = prev->next;
while (next != NULL && _cairo_bo_edge_compare (next, edge) < 0)
prev = next, next = prev->next;
prev->next = edge;
edge->prev = prev;
edge->next = next;
if (next != NULL)
next->prev = edge;
} else if (cmp > 0) {
next = sweep_line->current_edge;
prev = next->prev;
while (prev != NULL && _cairo_bo_edge_compare (prev, edge) > 0)
next = prev, prev = next->prev;
next->prev = edge;
edge->next = next;
edge->prev = prev;
if (prev != NULL)
prev->next = edge;
else
sweep_line->head = edge;
} else {
prev = sweep_line->current_edge;
edge->prev = prev;
edge->next = prev->next;
if (prev->next != NULL)
prev->next->prev = edge;
prev->next = edge;
}
} else {
sweep_line->head = edge;
}
sweep_line->current_edge = edge;
}
static void
_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t *edge)
{
if (edge->prev != NULL)
edge->prev->next = edge->next;
else
sweep_line->head = edge->next;
if (edge->next != NULL)
edge->next->prev = edge->prev;
if (sweep_line->current_edge == edge)
sweep_line->current_edge = edge->prev ? edge->prev : edge->next;
}
static inline cairo_bool_t
edges_collinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
{
return a->edge.line.p1.x == b->edge.line.p1.x;
}
static cairo_status_t
_cairo_bo_edge_end_trap (cairo_bo_edge_t *left,
int32_t bot,
cairo_bool_t do_traps,
void *container)
{
cairo_bo_trap_t *trap = &left->deferred_trap;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
/* Only emit (trivial) non-degenerate trapezoids with positive height. */
if (likely (trap->top < bot)) {
if (do_traps) {
_cairo_traps_add_trap (container,
trap->top, bot,
&left->edge.line, &trap->right->edge.line);
status = _cairo_traps_status ((cairo_traps_t *) container);
} else {
cairo_box_t box;
box.p1.x = left->edge.line.p1.x;
box.p1.y = trap->top;
box.p2.x = trap->right->edge.line.p1.x;
box.p2.y = bot;
status = _cairo_boxes_add (container, CAIRO_ANTIALIAS_DEFAULT, &box);
}
}
trap->right = NULL;
return status;
}
/* Start a new trapezoid at the given top y coordinate, whose edges
* are `edge' and `edge->next'. If `edge' already has a trapezoid,
* then either add it to the traps in `traps', if the trapezoid's
* right edge differs from `edge->next', or do nothing if the new
* trapezoid would be a continuation of the existing one. */
static inline cairo_status_t
_cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
cairo_bo_edge_t *right,
int top,
cairo_bool_t do_traps,
void *container)
{
cairo_status_t status;
if (left->deferred_trap.right == right)
return CAIRO_STATUS_SUCCESS;
if (left->deferred_trap.right != NULL) {
if (right != NULL && edges_collinear (left->deferred_trap.right, right))
{
/* continuation on right, so just swap edges */
left->deferred_trap.right = right;
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_bo_edge_end_trap (left, top, do_traps, container);
if (unlikely (status))
return status;
}
if (right != NULL && ! edges_collinear (left, right)) {
left->deferred_trap.top = top;
left->deferred_trap.right = right;
}
return CAIRO_STATUS_SUCCESS;
}
static inline cairo_status_t
_active_edges_to_traps (cairo_bo_edge_t *left,
int32_t top,
cairo_fill_rule_t fill_rule,
cairo_bool_t do_traps,
void *container)
{
cairo_bo_edge_t *right;
cairo_status_t status;
if (fill_rule == CAIRO_FILL_RULE_WINDING) {
while (left != NULL) {
int in_out;
/* Greedily search for the closing edge, so that we generate the
* maximal span width with the minimal number of trapezoids.
*/
in_out = left->edge.dir;
/* Check if there is a co-linear edge with an existing trap */
right = left->next;
if (left->deferred_trap.right == NULL) {
while (right != NULL && right->deferred_trap.right == NULL)
right = right->next;
if (right != NULL && edges_collinear (left, right)) {
/* continuation on left */
left->deferred_trap = right->deferred_trap;
right->deferred_trap.right = NULL;
}
}
/* End all subsumed traps */
right = left->next;
while (right != NULL) {
if (right->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (right, top, do_traps, container);
if (unlikely (status))
return status;
}
in_out += right->edge.dir;
if (in_out == 0) {
/* skip co-linear edges */
if (right->next == NULL ||
! edges_collinear (right, right->next))
{
break;
}
}
right = right->next;
}
status = _cairo_bo_edge_start_or_continue_trap (left, right, top,
do_traps, container);
if (unlikely (status))
return status;
left = right;
if (left != NULL)
left = left->next;
}
} else {
while (left != NULL) {
int in_out = 0;
right = left->next;
while (right != NULL) {
if (right->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (right, top, do_traps, container);
if (unlikely (status))
return status;
}
if ((in_out++ & 1) == 0) {
cairo_bo_edge_t *next;
cairo_bool_t skip = FALSE;
/* skip co-linear edges */
next = right->next;
if (next != NULL)
skip = edges_collinear (right, next);
if (! skip)
break;
}
right = right->next;
}
status = _cairo_bo_edge_start_or_continue_trap (left, right, top,
do_traps, container);
if (unlikely (status))
return status;
left = right;
if (left != NULL)
left = left->next;
}
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t **start_events,
int num_events,
cairo_fill_rule_t fill_rule,
cairo_bool_t do_traps,
void *container)
{
cairo_bo_sweep_line_t sweep_line;
cairo_bo_event_t *event;
cairo_status_t status;
_cairo_bo_sweep_line_init (&sweep_line, start_events, num_events);
while ((event = _cairo_bo_event_dequeue (&sweep_line))) {
if (event->point.y != sweep_line.current_y) {
status = _active_edges_to_traps (sweep_line.head,
sweep_line.current_y,
fill_rule, do_traps, container);
if (unlikely (status))
return status;
sweep_line.current_y = event->point.y;
}
switch (event->type) {
case CAIRO_BO_EVENT_TYPE_START:
_cairo_bo_sweep_line_insert (&sweep_line, event->edge);
break;
case CAIRO_BO_EVENT_TYPE_STOP:
_cairo_bo_sweep_line_delete (&sweep_line, event->edge);
if (event->edge->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (event->edge,
sweep_line.current_y,
do_traps, container);
if (unlikely (status))
return status;
}
break;
}
}
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (const cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule,
cairo_boxes_t *boxes)
{
cairo_status_t status;
cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)];
cairo_bo_event_t *events;
cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
cairo_bo_event_t **event_ptrs;
cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)];
cairo_bo_edge_t *edges;
int num_events;
int i, j;
if (unlikely (polygon->num_edges == 0))
return CAIRO_STATUS_SUCCESS;
num_events = 2 * polygon->num_edges;
events = stack_events;
event_ptrs = stack_event_ptrs;
edges = stack_edges;
if (num_events > ARRAY_LENGTH (stack_events)) {
events = _cairo_malloc_ab_plus_c (num_events,
sizeof (cairo_bo_event_t) +
sizeof (cairo_bo_edge_t) +
sizeof (cairo_bo_event_t *),
sizeof (cairo_bo_event_t *));
if (unlikely (events == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
event_ptrs = (cairo_bo_event_t **) (events + num_events);
edges = (cairo_bo_edge_t *) (event_ptrs + num_events + 1);
}
for (i = j = 0; i < polygon->num_edges; i++) {
edges[i].edge = polygon->edges[i];
edges[i].deferred_trap.right = NULL;
edges[i].prev = NULL;
edges[i].next = NULL;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_START;
events[j].point.y = polygon->edges[i].top;
events[j].point.x = polygon->edges[i].line.p1.x;
events[j].edge = &edges[i];
j++;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
events[j].point.y = polygon->edges[i].bottom;
events[j].point.x = polygon->edges[i].line.p1.x;
events[j].edge = &edges[i];
j++;
}
status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
fill_rule,
FALSE, boxes);
if (events != stack_events)
free (events);
return status;
}
cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule)
{
cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)];
cairo_bo_event_t *events;
cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
cairo_bo_event_t **event_ptrs;
cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)];
cairo_bo_edge_t *edges;
cairo_status_t status;
int i, j, k;
if (unlikely (traps->num_traps == 0))
return CAIRO_STATUS_SUCCESS;
assert (traps->is_rectilinear);
i = 4 * traps->num_traps;
events = stack_events;
event_ptrs = stack_event_ptrs;
edges = stack_edges;
if (i > ARRAY_LENGTH (stack_events)) {
events = _cairo_malloc_ab_plus_c (i,
sizeof (cairo_bo_event_t) +
sizeof (cairo_bo_edge_t) +
sizeof (cairo_bo_event_t *),
sizeof (cairo_bo_event_t *));
if (unlikely (events == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
event_ptrs = (cairo_bo_event_t **) (events + i);
edges = (cairo_bo_edge_t *) (event_ptrs + i + 1);
}
for (i = j = k = 0; i < traps->num_traps; i++) {
edges[k].edge.top = traps->traps[i].top;
edges[k].edge.bottom = traps->traps[i].bottom;
edges[k].edge.line = traps->traps[i].left;
edges[k].edge.dir = 1;
edges[k].deferred_trap.right = NULL;
edges[k].prev = NULL;
edges[k].next = NULL;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_START;
events[j].point.y = traps->traps[i].top;
events[j].point.x = traps->traps[i].left.p1.x;
events[j].edge = &edges[k];
j++;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
events[j].point.y = traps->traps[i].bottom;
events[j].point.x = traps->traps[i].left.p1.x;
events[j].edge = &edges[k];
j++;
k++;
edges[k].edge.top = traps->traps[i].top;
edges[k].edge.bottom = traps->traps[i].bottom;
edges[k].edge.line = traps->traps[i].right;
edges[k].edge.dir = -1;
edges[k].deferred_trap.right = NULL;
edges[k].prev = NULL;
edges[k].next = NULL;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_START;
events[j].point.y = traps->traps[i].top;
events[j].point.x = traps->traps[i].right.p1.x;
events[j].edge = &edges[k];
j++;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
events[j].point.y = traps->traps[i].bottom;
events[j].point.x = traps->traps[i].right.p1.x;
events[j].edge = &edges[k];
j++;
k++;
}
_cairo_traps_clear (traps);
status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
fill_rule,
TRUE, traps);
traps->is_rectilinear = TRUE;
if (events != stack_events)
free (events);
return status;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,984 @@
/* vim:set ts=8 sw=4 noet cin: */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Christian Biesinger <cbiesinger@web.de>
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Christian Biesinger
* <cbiesinger@web.de>
*
* Contributor(s):
*/
// This is a C++ file in order to use the C++ BeOS API
#include "cairoint.h"
#include "cairo-beos.h"
#include "cairo-error-private.h"
#include "cairo-image-surface-inline.h"
#include <new>
#include <Bitmap.h>
#include <Region.h>
#if 0
#include <DirectWindow.h>
#endif
#include <Screen.h>
#include <Window.h>
#include <Locker.h>
/**
* SECTION:beos-surface
* @Title: BeOS Surfaces
* @Short_Description: BeOS surface support
* @See_Also: #cairo_surface_t
*
* The BeOS surface is used to render cairo graphics to BeOS views
* and bitmaps.
**/
#define CAIRO_INT_STATUS_SUCCESS (cairo_int_status_t)(CAIRO_STATUS_SUCCESS)
struct cairo_beos_surface_t {
cairo_surface_t base;
cairo_region_t *clip_region;
BView* view;
/*
* A view is either attached to a bitmap, a window, or unattached.
* If it is attached to a window, we can copy data out of it using BScreen.
* If it is attached to a bitmap, we can read the bitmap data.
* If it is not attached, it doesn't draw anything, we need not bother.
*
* Since there doesn't seem to be a way to get the bitmap from a view if it
* is attached to one, we have to use a special surface creation function.
*/
BBitmap* bitmap;
// If true, surface and view should be deleted when this surface is
// destroyed
bool owns_bitmap_view;
};
class AutoLockView {
public:
AutoLockView(BView* view) : mView(view) {
mOK = mView->LockLooper();
}
~AutoLockView() {
if (mOK)
mView->UnlockLooper();
}
operator bool() {
return mOK;
}
private:
BView* mView;
bool mOK;
};
static cairo_surface_t *
_cairo_beos_surface_create_internal (BView* view,
BBitmap* bmp,
bool owns_bitmap_view = false);
static inline BRect
_cairo_rectangle_to_brect (const cairo_rectangle_int_t* rect)
{
// A BRect is one pixel wider than you'd think
return BRect (rect->x, rect->y,
rect->x + rect->width - 1,
rect->y + rect->height - 1);
}
static inline cairo_rectangle_int_t
_brect_to_cairo_rectangle (const BRect &rect)
{
cairo_rectangle_int_t retval;
retval.x = floor (rect.left);
retval.y = floor (rect.top);
retval.width = ceil (rect.right) - retval.x + 1;
retval.height = ceil (rect.bottom) - rectval.y + 1;
return retval;
}
static inline rgb_color
_cairo_color_to_be_color (const cairo_color_t *color)
{
// This factor ensures a uniform distribution of numbers
const float factor = 256 - 1e-5;
// Using doubles to have non-premultiplied colors
rgb_color be_color = { uint8(color->red * factor),
uint8(color->green * factor),
uint8(color->blue * factor),
uint8(color->alpha * factor) };
return be_color;
}
enum ViewCopyStatus {
OK,
NOT_VISIBLE, // The view or the interest rect is not visible on screen
ERROR // The view was visible, but the rect could not be copied. Probably OOM
};
/**
* _cairo_beos_view_to_bitmap:
* @bitmap: [out] The resulting bitmap.
* @rect: [out] The rectangle that was copied, in the view's coordinate system
* @interestRect: If non-null, only this part of the view will be copied (view's coord system).
*
* Gets the contents of the view as a BBitmap*. Caller must delete the bitmap.
**/
static ViewCopyStatus
_cairo_beos_view_to_bitmap (BView* view,
BBitmap** bitmap,
BRect* rect = NULL,
const BRect* interestRect = NULL)
{
*bitmap = NULL;
BWindow* wnd = view->Window();
// If we have no window, can't do anything
if (!wnd)
return NOT_VISIBLE;
view->Sync();
wnd->Sync();
#if 0
// Is it a direct window?
BDirectWindow* directWnd = dynamic_cast<BDirectWindow*>(wnd);
if (directWnd) {
// WRITEME
}
#endif
// Is it visible? If so, we can copy the content off the screen
if (wnd->IsHidden())
return NOT_VISIBLE;
BRect rectToCopy(view->Bounds());
if (interestRect)
rectToCopy = rectToCopy & *interestRect;
if (!rectToCopy.IsValid())
return NOT_VISIBLE;
BScreen screen(wnd);
BRect screenRect(view->ConvertToScreen(rectToCopy));
screenRect = screenRect & screen.Frame();
if (!screen.IsValid())
return NOT_VISIBLE;
if (rect)
*rect = view->ConvertFromScreen(screenRect);
if (screen.GetBitmap(bitmap, false, &screenRect) == B_OK)
return OK;
return ERROR;
}
static void
unpremultiply_bgra (unsigned char* data,
int width,
int height,
int stride,
unsigned char* retdata)
{
unsigned char* end = data + stride * height;
for (unsigned char* in = data, *out = retdata;
in < end;
in += stride, out += stride)
{
for (int i = 0; i < width; i ++) {
uint8_t *b = &out[4*i];
uint32_t pixel;
uint8_t alpha;
memcpy (&pixel, &data[4*i], sizeof (uint32_t));
alpha = pixel & 0xff;
if (alpha == 0) {
b[0] = b[1] = b[2] = b[3] = 0;
} else {
b[0] = (((pixel >> 24) & 0xff) * 255 + alpha / 2) / alpha;
b[1] = (((pixel >> 16) & 0xff) * 255 + alpha / 2) / alpha;
b[2] = (((pixel >> 8) & 0xff) * 255 + alpha / 2) / alpha;
b[3] = alpha;
}
}
}
}
static inline int
multiply_alpha (int alpha, int color)
{
int temp = (alpha * color) + 0x80;
return ((temp + (temp >> 8)) >> 8);
}
static unsigned char*
premultiply_bgra (unsigned char* data,
int width,
int height,
int stride)
{
uint8_t * retdata = reinterpret_cast<unsigned char*>(_cairo_malloc_ab(height, stride));
if (!retdata)
return NULL;
uint8_t * end = data + stride * height;
for (uint8_t * in = data, *out = retdata;
in < end;
in += stride, out += stride)
{
for (int i = 0; i < width; i ++) {
uint8_t *base = &in[4*i];
uint8_t alpha = base[3];
uint32_t p;
if (alpha == 0) {
p = 0;
} else {
uint8_t blue = base[0];
uint8_t green = base[1];
uint8_t red = base[2];
if (alpha != 0xff) {
blue = multiply_alpha (alpha, blue);
green = multiply_alpha (alpha, green);
red = multiply_alpha (alpha, red);
}
p = (alpha << 0) | (red << 8) | (green << 16) | (blue << 24);
}
memcpy (&out[4*i], &p, sizeof (uint32_t));
}
}
return retdata;
}
static cairo_int_status_t
_cairo_beos_surface_set_clip_region (cairo_beos_surface_t *surface,
cairo_region_t *region)
{
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
AutoLockView locker(surface->view);
assert (locker);
if (region == surface->clip_region)
return CAIRO_INT_STATUS_SUCCESS;
cairo_region_destroy (surface->clip_region);
surface->clip_region = cairo_region_reference (region);
if (region == NULL) {
// No clipping
surface->view->ConstrainClippingRegion(NULL);
return CAIRO_INT_STATUS_SUCCESS;
}
int count = cairo_region_num_rectangles (region);
BRegion bregion;
for (int i = 0; i < count; ++i) {
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
// Have to subtract one, because for pixman, the second coordinate
// lies outside the rectangle.
bregion.Include (_cairo_rectangle_to_brect (&rect));
}
surface->view->ConstrainClippingRegion(&bregion);
return CAIRO_INT_STATUS_SUCCESS;
}
/**
* _cairo_beos_bitmap_to_surface:
*
* Returns an addrefed image surface for a BBitmap. The bitmap need not outlive
* the surface.
**/
static cairo_image_surface_t*
_cairo_beos_bitmap_to_surface (BBitmap* bitmap)
{
color_space format = bitmap->ColorSpace();
if (format != B_RGB32 && format != B_RGBA32) {
BBitmap bmp(bitmap->Bounds(), B_RGB32, true);
BView view(bitmap->Bounds(), "Cairo bitmap drawing view",
B_FOLLOW_ALL_SIDES, 0);
bmp.AddChild(&view);
view.LockLooper();
view.DrawBitmap(bitmap, BPoint(0.0, 0.0));
view.Sync();
cairo_image_surface_t* imgsurf = _cairo_beos_bitmap_to_surface(&bmp);
view.UnlockLooper();
bmp.RemoveChild(&view);
return imgsurf;
}
cairo_format_t cformat = format == B_RGB32 ?
CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32;
BRect bounds(bitmap->Bounds());
unsigned char* bits = reinterpret_cast<unsigned char*>(bitmap->Bits());
int width = bounds.IntegerWidth() + 1;
int height = bounds.IntegerHeight() + 1;
unsigned char* premultiplied;
if (cformat == CAIRO_FORMAT_ARGB32) {
premultiplied = premultiply_bgra (bits, width, height,
bitmap->BytesPerRow());
} else {
premultiplied = reinterpret_cast<unsigned char*>(
_cairo_malloc_ab(bitmap->BytesPerRow(), height));
if (premultiplied)
memcpy(premultiplied, bits, bitmap->BytesPerRow() * height);
}
if (!premultiplied)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
cairo_image_surface_t* surf = reinterpret_cast<cairo_image_surface_t*>
(cairo_image_surface_create_for_data(premultiplied,
cformat,
width,
height,
bitmap->BytesPerRow()));
if (surf->base.status)
free(premultiplied);
else
_cairo_image_surface_assume_ownership_of_data(surf);
return surf;
}
/**
* _cairo_image_surface_to_bitmap:
*
* Converts an image surface to a BBitmap. The return value must be freed with
* delete.
**/
static BBitmap*
_cairo_image_surface_to_bitmap (cairo_image_surface_t* surface)
{
BRect size(0.0, 0.0, surface->width - 1, surface->height - 1);
switch (surface->format) {
case CAIRO_FORMAT_ARGB32: {
BBitmap* data = new BBitmap(size, B_RGBA32);
unpremultiply_bgra (surface->data,
surface->width,
surface->height,
surface->stride,
reinterpret_cast<unsigned char*>(data->Bits()));
return data;
}
case CAIRO_FORMAT_RGB24: {
BBitmap* data = new BBitmap(size, B_RGB32);
memcpy(data->Bits(), surface->data, surface->height * surface->stride);
return data;
}
default:
assert(0);
return NULL;
}
}
/**
* _cairo_op_to_be_op:
*
* Converts a cairo drawing operator to a beos drawing_mode. Returns true if
* the operator could be converted, false otherwise.
**/
static bool
_cairo_op_to_be_op (cairo_operator_t cairo_op,
drawing_mode* beos_op)
{
switch (cairo_op) {
case CAIRO_OPERATOR_SOURCE:
*beos_op = B_OP_COPY;
return true;
case CAIRO_OPERATOR_OVER:
*beos_op = B_OP_ALPHA;
return true;
case CAIRO_OPERATOR_ADD:
// Does not actually work
// XXX This is a fundamental compositing operator, it has to work!
#if 1
return false;
#else
*beos_op = B_OP_ADD;
return true;
#endif
case CAIRO_OPERATOR_CLEAR:
// Does not map to B_OP_ERASE - it replaces the dest with the low
// color, instead of transparency; could be done by setting low
// color appropriately.
case CAIRO_OPERATOR_IN:
case CAIRO_OPERATOR_OUT:
case CAIRO_OPERATOR_ATOP:
case CAIRO_OPERATOR_DEST:
case CAIRO_OPERATOR_DEST_OVER:
case CAIRO_OPERATOR_DEST_IN:
case CAIRO_OPERATOR_DEST_OUT:
case CAIRO_OPERATOR_DEST_ATOP:
case CAIRO_OPERATOR_XOR:
case CAIRO_OPERATOR_SATURATE:
default:
return false;
}
}
static cairo_surface_t *
_cairo_beos_surface_create_similar (void *abstract_surface,
cairo_content_t content,
int width,
int height)
{
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
if (width <= 0)
width = 1;
if (height <= 0)
height = 1;
BRect rect(0.0, 0.0, width - 1, height - 1);
BBitmap* bmp;
switch (content) {
case CAIRO_CONTENT_ALPHA:
return NULL;
case CAIRO_CONTENT_COLOR_ALPHA:
bmp = new BBitmap(rect, B_RGBA32, true);
break;
case CAIRO_CONTENT_COLOR:
// Match the color depth
if (surface->bitmap) {
color_space space = surface->bitmap->ColorSpace();
// No alpha was requested -> make sure not to return
// a surface with alpha
if (space == B_RGBA32)
space = B_RGB32;
if (space == B_RGBA15)
space = B_RGB15;
bmp = new BBitmap(rect, space, true);
} else {
BScreen scr(surface->view->Window());
color_space space = B_RGB32;
if (scr.IsValid())
space = scr.ColorSpace();
bmp = new BBitmap(rect, space, true);
}
break;
default:
ASSERT_NOT_REACHED;
return NULL;
}
BView* view = new BView(rect, "Cairo bitmap view", B_FOLLOW_ALL_SIDES, 0);
bmp->AddChild(view);
return _cairo_beos_surface_create_internal(view, bmp, true);
}
static cairo_status_t
_cairo_beos_surface_finish (void *abstract_surface)
{
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
if (surface->owns_bitmap_view) {
if (surface->bitmap)
surface->bitmap->RemoveChild(surface->view);
delete surface->view;
delete surface->bitmap;
surface->view = NULL;
surface->bitmap = NULL;
}
cairo_region_destroy (surface->clip_region);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_beos_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
void **image_extra)
{
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
AutoLockView locker(surface->view);
if (!locker)
return CAIRO_STATUS_NO_MEMORY; /// XXX not exactly right, but what can we do?
surface->view->Sync();
if (surface->bitmap) {
*image_out = _cairo_beos_bitmap_to_surface (surface->bitmap);
if (unlikely ((*image_out)->base.status))
return (*image_out)->base.status;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
BBitmap* bmp;
if (_cairo_beos_view_to_bitmap(surface->view, &bmp) != OK)
return CAIRO_STATUS_NO_MEMORY; /// XXX incorrect if the error was NOT_VISIBLE
*image_out = _cairo_beos_bitmap_to_surface (bmp);
if (unlikely ((*image_out)->base.status)) {
delete bmp;
return (*image_out)->base.status;
}
*image_extra = bmp;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_beos_surface_release_source_image (void *abstract_surface,
cairo_image_surface_t *image,
void *image_extra)
{
cairo_surface_destroy (&image->base);
if (image_extra != NULL) {
BBitmap* bmp = static_cast<BBitmap*>(image_extra);
delete bmp;
}
}
static cairo_status_t
_cairo_beos_surface_acquire_dest_image (void *abstract_surface,
cairo_rectangle_int_t *interest_rect,
cairo_image_surface_t **image_out,
cairo_rectangle_int_t *image_rect,
void **image_extra)
{
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
AutoLockView locker(surface->view);
if (!locker) {
*image_out = NULL;
*image_extra = NULL;
return (cairo_status_t) CAIRO_INT_STATUS_NOTHING_TO_DO;
}
if (surface->bitmap) {
surface->view->Sync();
*image_out = _cairo_beos_bitmap_to_surface(surface->bitmap);
if (unlikely ((*image_out)->base.status))
return (*image_out)->base.status;
image_rect->x = 0;
image_rect->y = 0;
image_rect->width = (*image_out)->width;
image_rect->height = (*image_out)->height;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
BRect b_interest_rect (_cairo_rectangle_to_brect (interest_rect));
BRect rect;
BBitmap* bitmap;
ViewCopyStatus status = _cairo_beos_view_to_bitmap(surface->view, &bitmap,
&rect, &b_interest_rect);
if (status == NOT_VISIBLE) {
*image_out = NULL;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
if (status == ERROR)
return CAIRO_STATUS_NO_MEMORY;
*image_rect = _brect_to_cairo_rectangle(rect);
*image_out = _cairo_beos_bitmap_to_surface(bitmap);
delete bitmap;
if (unlikely ((*image_out)->base.status))
return (*image_out)->base.status;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_beos_surface_release_dest_image (void *abstract_surface,
cairo_rectangle_int_t *intersect_rect,
cairo_image_surface_t *image,
cairo_rectangle_int_t *image_rect,
void *image_extra)
{
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
AutoLockView locker(surface->view);
if (!locker)
return;
BBitmap* bitmap_to_draw = _cairo_image_surface_to_bitmap(image);
surface->view->PushState();
surface->view->SetDrawingMode(B_OP_COPY);
surface->view->DrawBitmap (bitmap_to_draw,
_cairo_rectangle_to_brect (image_rect));
surface->view->PopState();
delete bitmap_to_draw;
cairo_surface_destroy(&image->base);
}
static cairo_int_status_t
_cairo_beos_surface_composite (cairo_operator_t op,
cairo_pattern_t *src,
cairo_pattern_t *mask,
void *dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_region_t *clip_region)
{
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
dst);
cairo_int_status_t status;
AutoLockView locker(surface->view);
if (!locker)
return CAIRO_INT_STATUS_SUCCESS;
drawing_mode mode;
if (!_cairo_op_to_be_op(op, &mode))
return CAIRO_INT_STATUS_UNSUPPORTED;
// XXX Masks are not yet supported
if (mask)
return CAIRO_INT_STATUS_UNSUPPORTED;
// XXX should eventually support the others
if (src->type != CAIRO_PATTERN_TYPE_SURFACE ||
src->extend != CAIRO_EXTEND_NONE)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
// Can we maybe support other matrices as well? (scale? if the filter is right)
int itx, ity;
if (!_cairo_matrix_is_integer_translation(&src->matrix, &itx, &ity))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_beos_surface_set_clip_region (surface, clip_region);
if (unlikely (status))
return status;
BRect srcRect(src_x + itx,
src_y + ity,
src_x + itx + width - 1,
src_y + ity + height - 1);
BRect dstRect(dst_x, dst_y, dst_x + width - 1, dst_y + height - 1);
cairo_surface_t* src_surface = reinterpret_cast<cairo_surface_pattern_t*>(src)->
surface;
// Get a bitmap
BBitmap* bmp = NULL;
bool free_bmp = false;
if (_cairo_surface_is_image(src_surface)) {
cairo_image_surface_t* img_surface =
reinterpret_cast<cairo_image_surface_t*>(src_surface);
bmp = _cairo_image_surface_to_bitmap(img_surface);
free_bmp = true;
} else if (src_surface->backend == surface->base.backend) {
cairo_beos_surface_t *beos_surface =
reinterpret_cast<cairo_beos_surface_t*>(src_surface);
if (beos_surface->bitmap) {
AutoLockView locker(beos_surface->view);
if (locker)
beos_surface->view->Sync();
bmp = beos_surface->bitmap;
} else {
_cairo_beos_view_to_bitmap(surface->view, &bmp);
free_bmp = true;
}
}
if (!bmp)
return CAIRO_INT_STATUS_UNSUPPORTED;
// So, BeOS seems to screw up painting an opaque bitmap onto a
// translucent one (it makes them partly transparent). Just return
// unsupported.
if (bmp->ColorSpace() == B_RGB32 && surface->bitmap &&
surface->bitmap->ColorSpace() == B_RGBA32 &&
(mode == B_OP_COPY || mode == B_OP_ALPHA))
{
if (free_bmp)
delete bmp;
return CAIRO_INT_STATUS_UNSUPPORTED;
}
// Draw it on screen.
surface->view->PushState();
// If our image rect is only a subrect of the desired size, and we
// aren't using B_OP_ALPHA, then we need to fill the rect first.
if (mode == B_OP_COPY && !bmp->Bounds().Contains(srcRect)) {
rgb_color black = { 0, 0, 0, 0 };
surface->view->SetDrawingMode(mode);
surface->view->SetHighColor(black);
surface->view->FillRect(dstRect);
}
if (mode == B_OP_ALPHA && bmp->ColorSpace() == B_RGB32) {
mode = B_OP_COPY;
}
surface->view->SetDrawingMode(mode);
if (surface->bitmap && surface->bitmap->ColorSpace() == B_RGBA32)
surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
else
surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
surface->view->DrawBitmap(bmp, srcRect, dstRect);
surface->view->PopState();
if (free_bmp)
delete bmp;
return CAIRO_INT_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_beos_surface_fill_rectangles (void *abstract_surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_rectangle_int_t *rects,
int num_rects,
cairo_region_t *clip_region)
{
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
cairo_int_status_t status;
if (num_rects <= 0)
return CAIRO_INT_STATUS_SUCCESS;
AutoLockView locker(surface->view);
if (!locker)
return CAIRO_INT_STATUS_SUCCESS;
drawing_mode mode;
if (!_cairo_op_to_be_op(op, &mode))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_beos_surface_set_clip_region (surface, clip_region);
if (unlikely (status))
return status;
rgb_color be_color = _cairo_color_to_be_color(color);
if (mode == B_OP_ALPHA && be_color.alpha == 0xFF)
mode = B_OP_COPY;
// For CAIRO_OPERATOR_SOURCE, cairo expects us to use the premultiplied
// color info. This is only relevant when drawing into an rgb24 buffer
// (as for others, we can convert when asked for the image)
if (mode == B_OP_COPY && be_color.alpha != 0xFF &&
(!surface->bitmap || surface->bitmap->ColorSpace() != B_RGBA32))
{
be_color.red = color->red_short >> 8;
be_color.green = color->green_short >> 8;
be_color.blue = color->blue_short >> 8;
}
surface->view->PushState();
surface->view->SetDrawingMode(mode);
surface->view->SetHighColor(be_color);
if (surface->bitmap && surface->bitmap->ColorSpace() == B_RGBA32)
surface->view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
else
surface->view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
for (int i = 0; i < num_rects; ++i)
surface->view->FillRect (_cairo_rectangle_to_brect (&rects[i]));
surface->view->PopState();
return CAIRO_INT_STATUS_SUCCESS;
}
static cairo_bool_t
_cairo_beos_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
AutoLockView locker(surface->view);
if (!locker)
return FALSE;
*rectangle = _brect_to_cairo_rectangle (surface->view->Bounds());
return TRUE;
}
static const struct _cairo_surface_backend cairo_beos_surface_backend = {
CAIRO_SURFACE_TYPE_BEOS,
_cairo_beos_surface_create_similar,
_cairo_beos_surface_finish,
_cairo_beos_surface_acquire_source_image,
_cairo_beos_surface_release_source_image,
_cairo_beos_surface_acquire_dest_image,
_cairo_beos_surface_release_dest_image,
NULL, /* clone_similar */
_cairo_beos_surface_composite, /* composite */
_cairo_beos_surface_fill_rectangles,
NULL, /* composite_trapezoids */
NULL, /* create_span_renderer */
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
_cairo_beos_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
NULL, /* paint */
NULL, /* mask */
NULL, /* stroke */
NULL, /* fill */
NULL /* show_glyphs */
};
static cairo_surface_t *
_cairo_beos_surface_create_internal (BView* view,
BBitmap* bmp,
bool owns_bitmap_view)
{
// Must use malloc, because cairo code will use free() on the surface
cairo_beos_surface_t *surface = static_cast<cairo_beos_surface_t*>(
malloc(sizeof(cairo_beos_surface_t)));
if (surface == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
return const_cast<cairo_surface_t*>(&_cairo_surface_nil);
}
cairo_content_t content = CAIRO_CONTENT_COLOR;
if (bmp && (bmp->ColorSpace() == B_RGBA32 || bmp->ColorSpace() == B_RGBA15))
content = CAIRO_CONTENT_COLOR_ALPHA;
_cairo_surface_init (&surface->base,
&cairo_beos_surface_backend,
NULL, /* device */
content);
surface->view = view;
surface->bitmap = bmp;
surface->owns_bitmap_view = owns_bitmap_view;
surface->clip_region = NULL;
return &surface->base;
}
/**
* cairo_beos_surface_create:
* @view: The view to draw on
*
* Creates a Cairo surface that draws onto a BeOS BView.
* The caller must ensure that the view does not get deleted before the surface.
* If the view is attached to a bitmap rather than an on-screen window, use
* cairo_beos_surface_create_for_bitmap() instead of this function.
*
* Since: TBD
**/
cairo_surface_t *
cairo_beos_surface_create (BView* view)
{
return cairo_beos_surface_create_for_bitmap(view, NULL);
}
/**
* cairo_beos_surface_create_for_bitmap:
* @view: The view to draw on
* @bmp: The bitmap to which the view is attached
*
* Creates a Cairo surface that draws onto a BeOS BView which is attached to a
* BBitmap.
* The caller must ensure that the view and the bitmap do not get deleted
* before the surface.
*
* For views that draw to a bitmap (as opposed to a screen), use this function
* rather than cairo_beos_surface_create(). Not using this function WILL lead to
* incorrect behaviour.
*
* For now, only views that draw to the entire area of bmp are supported.
* The view must already be attached to the bitmap.
*
* Since: TBD
**/
cairo_surface_t *
cairo_beos_surface_create_for_bitmap (BView* view,
BBitmap* bmp)
{
return _cairo_beos_surface_create_internal(view, bmp);
}

View File

@@ -0,0 +1,60 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Christian Biesinger <cbiesinger@web.de>
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Christian Biesinger
* <cbiesinger@web.de>
*
* Contributor(s):
*/
#ifndef CAIRO_BEOS_H
#define CAIRO_BEOS_H
#include "cairo.h"
#if CAIRO_HAS_BEOS_SURFACE
#include <View.h>
CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
cairo_beos_surface_create (BView* view);
cairo_public cairo_surface_t *
cairo_beos_surface_create_for_bitmap (BView* view,
BBitmap* bmp);
CAIRO_END_DECLS
#else /* CAIRO_HAS_BEOS_SURFACE */
# error Cairo was not compiled with support for the beos backend
#endif /* CAIRO_HAS_BEOS_SURFACE */
#endif /* CAIRO_BEOS_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,121 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2010 Andrea Canciani
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Andrea Canciani <ranma42@gmail.com>
*/
#ifndef CAIRO_BOX_H
#define CAIRO_BOX_H
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
#include "cairo-fixed-private.h"
static inline void
_cairo_box_set (cairo_box_t *box,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
box->p1 = *p1;
box->p2 = *p2;
}
static inline void
_cairo_box_from_integers (cairo_box_t *box, int x, int y, int w, int h)
{
box->p1.x = _cairo_fixed_from_int (x);
box->p1.y = _cairo_fixed_from_int (y);
box->p2.x = _cairo_fixed_from_int (x + w);
box->p2.y = _cairo_fixed_from_int (y + h);
}
/* assumes box->p1 is top-left, p2 bottom-right */
static inline void
_cairo_box_add_point (cairo_box_t *box,
const cairo_point_t *point)
{
if (point->x < box->p1.x)
box->p1.x = point->x;
else if (point->x > box->p2.x)
box->p2.x = point->x;
if (point->y < box->p1.y)
box->p1.y = point->y;
else if (point->y > box->p2.y)
box->p2.y = point->y;
}
static inline void
_cairo_box_add_box (cairo_box_t *box,
const cairo_box_t *add)
{
if (add->p1.x < box->p1.x)
box->p1.x = add->p1.x;
if (add->p2.x > box->p2.x)
box->p2.x = add->p2.x;
if (add->p1.y < box->p1.y)
box->p1.y = add->p1.y;
if (add->p2.y > box->p2.y)
box->p2.y = add->p2.y;
}
/* assumes box->p1 is top-left, p2 bottom-right */
static inline cairo_bool_t
_cairo_box_contains_point (const cairo_box_t *box,
const cairo_point_t *point)
{
return box->p1.x <= point->x && point->x <= box->p2.x &&
box->p1.y <= point->y && point->y <= box->p2.y;
}
static inline cairo_bool_t
_cairo_box_is_pixel_aligned (const cairo_box_t *box)
{
#if CAIRO_FIXED_FRAC_BITS <= 8 && 0
return ((box->p1.x & CAIRO_FIXED_FRAC_MASK) << 24 |
(box->p1.y & CAIRO_FIXED_FRAC_MASK) << 16 |
(box->p2.x & CAIRO_FIXED_FRAC_MASK) << 8 |
(box->p2.y & CAIRO_FIXED_FRAC_MASK) << 0) == 0;
#else /* GCC on i7 prefers this variant (bizarrely according to the profiler) */
cairo_fixed_t f;
f = 0;
f |= box->p1.x & CAIRO_FIXED_FRAC_MASK;
f |= box->p1.y & CAIRO_FIXED_FRAC_MASK;
f |= box->p2.x & CAIRO_FIXED_FRAC_MASK;
f |= box->p2.y & CAIRO_FIXED_FRAC_MASK;
return f == 0;
#endif
}
#endif /* CAIRO_BOX_H */

View File

@@ -0,0 +1,690 @@
/*
* Copyright © 2004 Carl Worth
* Copyright © 2006 Red Hat, Inc.
* Copyright © 2009 Chris Wilson
* Copyright © 2011 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Carl Worth
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
/* Provide definitions for standalone compilation */
#include "cairoint.h"
#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-combsort-inline.h"
#include "cairo-list-private.h"
#include <setjmp.h>
typedef struct _rectangle rectangle_t;
typedef struct _edge edge_t;
struct _edge {
edge_t *next, *prev;
edge_t *right;
cairo_fixed_t x, top;
int a_or_b;
int dir;
};
struct _rectangle {
edge_t left, right;
int32_t top, bottom;
};
#define UNROLL3(x) x x x
/* the parent is always given by index/2 */
#define PQ_PARENT_INDEX(i) ((i) >> 1)
#define PQ_FIRST_ENTRY 1
/* left and right children are index * 2 and (index * 2) +1 respectively */
#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
typedef struct _pqueue {
int size, max_size;
rectangle_t **elements;
rectangle_t *elements_embedded[1024];
} pqueue_t;
typedef struct _sweep_line {
rectangle_t **rectangles;
pqueue_t pq;
edge_t head, tail;
edge_t *insert_left, *insert_right;
int32_t current_y;
int32_t last_y;
jmp_buf unwind;
} sweep_line_t;
#define DEBUG_TRAPS 0
#if DEBUG_TRAPS
static void
dump_traps (cairo_traps_t *traps, const char *filename)
{
FILE *file;
int n;
if (getenv ("CAIRO_DEBUG_TRAPS") == NULL)
return;
file = fopen (filename, "a");
if (file != NULL) {
for (n = 0; n < traps->num_traps; n++) {
fprintf (file, "%d %d L:(%d, %d), (%d, %d) R:(%d, %d), (%d, %d)\n",
traps->traps[n].top,
traps->traps[n].bottom,
traps->traps[n].left.p1.x,
traps->traps[n].left.p1.y,
traps->traps[n].left.p2.x,
traps->traps[n].left.p2.y,
traps->traps[n].right.p1.x,
traps->traps[n].right.p1.y,
traps->traps[n].right.p2.x,
traps->traps[n].right.p2.y);
}
fprintf (file, "\n");
fclose (file);
}
}
#else
#define dump_traps(traps, filename)
#endif
static inline int
rectangle_compare_start (const rectangle_t *a,
const rectangle_t *b)
{
return a->top - b->top;
}
static inline int
rectangle_compare_stop (const rectangle_t *a,
const rectangle_t *b)
{
return a->bottom - b->bottom;
}
static inline void
pqueue_init (pqueue_t *pq)
{
pq->max_size = ARRAY_LENGTH (pq->elements_embedded);
pq->size = 0;
pq->elements = pq->elements_embedded;
pq->elements[PQ_FIRST_ENTRY] = NULL;
}
static inline void
pqueue_fini (pqueue_t *pq)
{
if (pq->elements != pq->elements_embedded)
free (pq->elements);
}
static cairo_bool_t
pqueue_grow (pqueue_t *pq)
{
rectangle_t **new_elements;
pq->max_size *= 2;
if (pq->elements == pq->elements_embedded) {
new_elements = _cairo_malloc_ab (pq->max_size,
sizeof (rectangle_t *));
if (unlikely (new_elements == NULL))
return FALSE;
memcpy (new_elements, pq->elements_embedded,
sizeof (pq->elements_embedded));
} else {
new_elements = _cairo_realloc_ab (pq->elements,
pq->max_size,
sizeof (rectangle_t *));
if (unlikely (new_elements == NULL))
return FALSE;
}
pq->elements = new_elements;
return TRUE;
}
static inline void
pqueue_push (sweep_line_t *sweep, rectangle_t *rectangle)
{
rectangle_t **elements;
int i, parent;
if (unlikely (sweep->pq.size + 1 == sweep->pq.max_size)) {
if (unlikely (! pqueue_grow (&sweep->pq))) {
longjmp (sweep->unwind,
_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
}
elements = sweep->pq.elements;
for (i = ++sweep->pq.size;
i != PQ_FIRST_ENTRY &&
rectangle_compare_stop (rectangle,
elements[parent = PQ_PARENT_INDEX (i)]) < 0;
i = parent)
{
elements[i] = elements[parent];
}
elements[i] = rectangle;
}
static inline void
pqueue_pop (pqueue_t *pq)
{
rectangle_t **elements = pq->elements;
rectangle_t *tail;
int child, i;
tail = elements[pq->size--];
if (pq->size == 0) {
elements[PQ_FIRST_ENTRY] = NULL;
return;
}
for (i = PQ_FIRST_ENTRY;
(child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
i = child)
{
if (child != pq->size &&
rectangle_compare_stop (elements[child+1],
elements[child]) < 0)
{
child++;
}
if (rectangle_compare_stop (elements[child], tail) >= 0)
break;
elements[i] = elements[child];
}
elements[i] = tail;
}
static inline rectangle_t *
rectangle_pop_start (sweep_line_t *sweep_line)
{
return *sweep_line->rectangles++;
}
static inline rectangle_t *
rectangle_peek_stop (sweep_line_t *sweep_line)
{
return sweep_line->pq.elements[PQ_FIRST_ENTRY];
}
CAIRO_COMBSORT_DECLARE (_rectangle_sort,
rectangle_t *,
rectangle_compare_start)
static void
sweep_line_init (sweep_line_t *sweep_line,
rectangle_t **rectangles,
int num_rectangles)
{
_rectangle_sort (rectangles, num_rectangles);
rectangles[num_rectangles] = NULL;
sweep_line->rectangles = rectangles;
sweep_line->head.x = INT32_MIN;
sweep_line->head.right = NULL;
sweep_line->head.dir = 0;
sweep_line->head.next = &sweep_line->tail;
sweep_line->tail.x = INT32_MAX;
sweep_line->tail.right = NULL;
sweep_line->tail.dir = 0;
sweep_line->tail.prev = &sweep_line->head;
sweep_line->insert_left = &sweep_line->tail;
sweep_line->insert_right = &sweep_line->tail;
sweep_line->current_y = INT32_MIN;
sweep_line->last_y = INT32_MIN;
pqueue_init (&sweep_line->pq);
}
static void
sweep_line_fini (sweep_line_t *sweep_line)
{
pqueue_fini (&sweep_line->pq);
}
static void
end_box (sweep_line_t *sweep_line, edge_t *left, int32_t bot, cairo_boxes_t *out)
{
if (likely (left->top < bot)) {
cairo_status_t status;
cairo_box_t box;
box.p1.x = left->x;
box.p1.y = left->top;
box.p2.x = left->right->x;
box.p2.y = bot;
status = _cairo_boxes_add (out, CAIRO_ANTIALIAS_DEFAULT, &box);
if (unlikely (status))
longjmp (sweep_line->unwind, status);
}
left->right = NULL;
}
/* Start a new trapezoid at the given top y coordinate, whose edges
* are `edge' and `edge->next'. If `edge' already has a trapezoid,
* then either add it to the traps in `traps', if the trapezoid's
* right edge differs from `edge->next', or do nothing if the new
* trapezoid would be a continuation of the existing one. */
static inline void
start_or_continue_box (sweep_line_t *sweep_line,
edge_t *left,
edge_t *right,
int top,
cairo_boxes_t *out)
{
if (left->right == right)
return;
if (left->right != NULL) {
if (right != NULL && left->right->x == right->x) {
/* continuation on right, so just swap edges */
left->right = right;
return;
}
end_box (sweep_line, left, top, out);
}
if (right != NULL && left->x != right->x) {
left->top = top;
left->right = right;
}
}
static inline int is_zero(const int *winding)
{
return winding[0] == 0 || winding[1] == 0;
}
static inline void
active_edges (sweep_line_t *sweep, cairo_boxes_t *out)
{
int top = sweep->current_y;
int winding[2] = { 0 };
edge_t *pos;
if (sweep->last_y == sweep->current_y)
return;
pos = sweep->head.next;
if (pos == &sweep->tail)
return;
do {
edge_t *left, *right;
left = pos;
do {
winding[left->a_or_b] += left->dir;
if (!is_zero (winding))
break;
if (left->next == &sweep->tail)
goto out;
if (unlikely (left->right != NULL))
end_box (sweep, left, top, out);
left = left->next;
} while (1);
right = left->next;
do {
if (unlikely (right->right != NULL))
end_box (sweep, right, top, out);
winding[right->a_or_b] += right->dir;
if (is_zero (winding)) {
/* skip co-linear edges */
if (likely (right->x != right->next->x))
break;
}
right = right->next;
} while (TRUE);
start_or_continue_box (sweep, left, right, top, out);
pos = right->next;
} while (pos != &sweep->tail);
out:
sweep->last_y = sweep->current_y;
}
static inline void
sweep_line_delete_edge (sweep_line_t *sweep_line, edge_t *edge, cairo_boxes_t *out)
{
if (edge->right != NULL) {
edge_t *next = edge->next;
if (next->x == edge->x) {
next->top = edge->top;
next->right = edge->right;
} else {
end_box (sweep_line, edge, sweep_line->current_y, out);
}
}
if (sweep_line->insert_left == edge)
sweep_line->insert_left = edge->next;
if (sweep_line->insert_right == edge)
sweep_line->insert_right = edge->next;
edge->prev->next = edge->next;
edge->next->prev = edge->prev;
}
static inline void
sweep_line_delete (sweep_line_t *sweep,
rectangle_t *rectangle,
cairo_boxes_t *out)
{
sweep_line_delete_edge (sweep, &rectangle->left, out);
sweep_line_delete_edge (sweep, &rectangle->right, out);
pqueue_pop (&sweep->pq);
}
static inline void
insert_edge (edge_t *edge, edge_t *pos)
{
if (pos->x != edge->x) {
if (pos->x > edge->x) {
do {
UNROLL3({
if (pos->prev->x <= edge->x)
break;
pos = pos->prev;
})
} while (TRUE);
} else {
do {
UNROLL3({
pos = pos->next;
if (pos->x >= edge->x)
break;
})
} while (TRUE);
}
}
pos->prev->next = edge;
edge->prev = pos->prev;
edge->next = pos;
pos->prev = edge;
}
static inline void
sweep_line_insert (sweep_line_t *sweep, rectangle_t *rectangle)
{
edge_t *pos;
/* right edge */
pos = sweep->insert_right;
insert_edge (&rectangle->right, pos);
sweep->insert_right = &rectangle->right;
/* left edge */
pos = sweep->insert_left;
if (pos->x > sweep->insert_right->x)
pos = sweep->insert_right->prev;
insert_edge (&rectangle->left, pos);
sweep->insert_left = &rectangle->left;
pqueue_push (sweep, rectangle);
}
static cairo_status_t
intersect (rectangle_t **rectangles, int num_rectangles, cairo_boxes_t *out)
{
sweep_line_t sweep_line;
rectangle_t *rectangle;
cairo_status_t status;
sweep_line_init (&sweep_line, rectangles, num_rectangles);
if ((status = setjmp (sweep_line.unwind)))
goto unwind;
rectangle = rectangle_pop_start (&sweep_line);
do {
if (rectangle->top != sweep_line.current_y) {
rectangle_t *stop;
stop = rectangle_peek_stop (&sweep_line);
while (stop != NULL && stop->bottom < rectangle->top) {
if (stop->bottom != sweep_line.current_y) {
active_edges (&sweep_line, out);
sweep_line.current_y = stop->bottom;
}
sweep_line_delete (&sweep_line, stop, out);
stop = rectangle_peek_stop (&sweep_line);
}
active_edges (&sweep_line, out);
sweep_line.current_y = rectangle->top;
}
sweep_line_insert (&sweep_line, rectangle);
} while ((rectangle = rectangle_pop_start (&sweep_line)) != NULL);
while ((rectangle = rectangle_peek_stop (&sweep_line)) != NULL) {
if (rectangle->bottom != sweep_line.current_y) {
active_edges (&sweep_line, out);
sweep_line.current_y = rectangle->bottom;
}
sweep_line_delete (&sweep_line, rectangle, out);
}
unwind:
sweep_line_fini (&sweep_line);
return status;
}
static cairo_status_t
_cairo_boxes_intersect_with_box (const cairo_boxes_t *boxes,
const cairo_box_t *box,
cairo_boxes_t *out)
{
cairo_status_t status;
int i, j;
if (out == boxes) { /* inplace update */
struct _cairo_boxes_chunk *chunk;
out->num_boxes = 0;
for (chunk = &out->chunks; chunk != NULL; chunk = chunk->next) {
for (i = j = 0; i < chunk->count; i++) {
cairo_box_t *b = &chunk->base[i];
b->p1.x = MAX (b->p1.x, box->p1.x);
b->p1.y = MAX (b->p1.y, box->p1.y);
b->p2.x = MIN (b->p2.x, box->p2.x);
b->p2.y = MIN (b->p2.y, box->p2.y);
if (b->p1.x < b->p2.x && b->p1.y < b->p2.y) {
if (i != j)
chunk->base[j] = *b;
j++;
}
}
/* XXX unlink empty chains? */
chunk->count = j;
out->num_boxes += j;
}
} else {
const struct _cairo_boxes_chunk *chunk;
_cairo_boxes_clear (out);
_cairo_boxes_limit (out, box, 1);
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
status = _cairo_boxes_add (out,
CAIRO_ANTIALIAS_DEFAULT,
&chunk->base[i]);
if (unlikely (status))
return status;
}
}
}
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_boxes_intersect (const cairo_boxes_t *a,
const cairo_boxes_t *b,
cairo_boxes_t *out)
{
rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)];
rectangle_t *rectangles;
rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 1];
rectangle_t **rectangles_ptrs;
const struct _cairo_boxes_chunk *chunk;
cairo_status_t status;
int i, j, count;
if (unlikely (a->num_boxes == 0 || b->num_boxes == 0)) {
_cairo_boxes_clear (out);
return CAIRO_STATUS_SUCCESS;
}
if (a->num_boxes == 1) {
cairo_box_t box = a->chunks.base[0];
return _cairo_boxes_intersect_with_box (b, &box, out);
}
if (b->num_boxes == 1) {
cairo_box_t box = b->chunks.base[0];
return _cairo_boxes_intersect_with_box (a, &box, out);
}
rectangles = stack_rectangles;
rectangles_ptrs = stack_rectangles_ptrs;
count = a->num_boxes + b->num_boxes;
if (count > ARRAY_LENGTH (stack_rectangles)) {
rectangles = _cairo_malloc_ab_plus_c (count,
sizeof (rectangle_t) +
sizeof (rectangle_t *),
sizeof (rectangle_t *));
if (unlikely (rectangles == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
rectangles_ptrs = (rectangle_t **) (rectangles + count);
}
j = 0;
for (chunk = &a->chunks; chunk != NULL; chunk = chunk->next) {
const cairo_box_t *box = chunk->base;
for (i = 0; i < chunk->count; i++) {
if (box[i].p1.x < box[i].p2.x) {
rectangles[j].left.x = box[i].p1.x;
rectangles[j].left.dir = 1;
rectangles[j].right.x = box[i].p2.x;
rectangles[j].right.dir = -1;
} else {
rectangles[j].right.x = box[i].p1.x;
rectangles[j].right.dir = 1;
rectangles[j].left.x = box[i].p2.x;
rectangles[j].left.dir = -1;
}
rectangles[j].left.a_or_b = 0;
rectangles[j].left.right = NULL;
rectangles[j].right.a_or_b = 0;
rectangles[j].right.right = NULL;
rectangles[j].top = box[i].p1.y;
rectangles[j].bottom = box[i].p2.y;
rectangles_ptrs[j] = &rectangles[j];
j++;
}
}
for (chunk = &b->chunks; chunk != NULL; chunk = chunk->next) {
const cairo_box_t *box = chunk->base;
for (i = 0; i < chunk->count; i++) {
if (box[i].p1.x < box[i].p2.x) {
rectangles[j].left.x = box[i].p1.x;
rectangles[j].left.dir = 1;
rectangles[j].right.x = box[i].p2.x;
rectangles[j].right.dir = -1;
} else {
rectangles[j].right.x = box[i].p1.x;
rectangles[j].right.dir = 1;
rectangles[j].left.x = box[i].p2.x;
rectangles[j].left.dir = -1;
}
rectangles[j].left.a_or_b = 1;
rectangles[j].left.right = NULL;
rectangles[j].right.a_or_b = 1;
rectangles[j].right.right = NULL;
rectangles[j].top = box[i].p1.y;
rectangles[j].bottom = box[i].p2.y;
rectangles_ptrs[j] = &rectangles[j];
j++;
}
}
assert (j == count);
_cairo_boxes_clear (out);
status = intersect (rectangles_ptrs, j, out);
if (rectangles != stack_rectangles)
free (rectangles);
return status;
}

View File

@@ -0,0 +1,123 @@
/* 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.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_BOXES_H
#define CAIRO_BOXES_H
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
#include <stdio.h>
#include <stdlib.h>
struct _cairo_boxes_t {
cairo_status_t status;
cairo_box_t limit;
const cairo_box_t *limits;
int num_limits;
int num_boxes;
unsigned int is_pixel_aligned;
struct _cairo_boxes_chunk {
struct _cairo_boxes_chunk *next;
cairo_box_t *base;
int count;
int size;
} chunks, *tail;
cairo_box_t boxes_embedded[32];
};
cairo_private void
_cairo_boxes_init (cairo_boxes_t *boxes);
cairo_private void
_cairo_boxes_init_with_clip (cairo_boxes_t *boxes,
cairo_clip_t *clip);
cairo_private void
_cairo_boxes_init_for_array (cairo_boxes_t *boxes,
cairo_box_t *array,
int num_boxes);
cairo_private void
_cairo_boxes_init_from_rectangle (cairo_boxes_t *boxes,
int x, int y, int w, int h);
cairo_private void
_cairo_boxes_limit (cairo_boxes_t *boxes,
const cairo_box_t *limits,
int num_limits);
cairo_private cairo_status_t
_cairo_boxes_add (cairo_boxes_t *boxes,
cairo_antialias_t antialias,
const cairo_box_t *box);
cairo_private void
_cairo_boxes_extents (const cairo_boxes_t *boxes,
cairo_box_t *box);
cairo_private cairo_box_t *
_cairo_boxes_to_array (const cairo_boxes_t *boxes,
int *num_boxes,
cairo_bool_t force_allocation);
cairo_private cairo_status_t
_cairo_boxes_intersect (const cairo_boxes_t *a,
const cairo_boxes_t *b,
cairo_boxes_t *out);
cairo_private void
_cairo_boxes_clear (cairo_boxes_t *boxes);
cairo_private_no_warn cairo_bool_t
_cairo_boxes_for_each_box (cairo_boxes_t *boxes,
cairo_bool_t (*func) (cairo_box_t *box, void *data),
void *data);
cairo_private cairo_status_t
_cairo_rasterise_polygon_to_boxes (cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule,
cairo_boxes_t *boxes);
cairo_private void
_cairo_boxes_fini (cairo_boxes_t *boxes);
cairo_private void
_cairo_debug_print_boxes (FILE *stream,
const cairo_boxes_t *boxes);
#endif /* CAIRO_BOXES_H */

View File

@@ -0,0 +1,460 @@
/* 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.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-box-inline.h"
#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
void
_cairo_boxes_init (cairo_boxes_t *boxes)
{
boxes->status = CAIRO_STATUS_SUCCESS;
boxes->num_limits = 0;
boxes->num_boxes = 0;
boxes->tail = &boxes->chunks;
boxes->chunks.next = NULL;
boxes->chunks.base = boxes->boxes_embedded;
boxes->chunks.size = ARRAY_LENGTH (boxes->boxes_embedded);
boxes->chunks.count = 0;
boxes->is_pixel_aligned = TRUE;
}
void
_cairo_boxes_init_from_rectangle (cairo_boxes_t *boxes,
int x, int y, int w, int h)
{
_cairo_boxes_init (boxes);
_cairo_box_from_integers (&boxes->chunks.base[0], x, y, w, h);
boxes->num_boxes = 1;
}
void
_cairo_boxes_init_with_clip (cairo_boxes_t *boxes,
cairo_clip_t *clip)
{
_cairo_boxes_init (boxes);
if (clip)
_cairo_boxes_limit (boxes, clip->boxes, clip->num_boxes);
}
void
_cairo_boxes_init_for_array (cairo_boxes_t *boxes,
cairo_box_t *array,
int num_boxes)
{
int n;
boxes->status = CAIRO_STATUS_SUCCESS;
boxes->num_limits = 0;
boxes->num_boxes = num_boxes;
boxes->tail = &boxes->chunks;
boxes->chunks.next = NULL;
boxes->chunks.base = array;
boxes->chunks.size = num_boxes;
boxes->chunks.count = num_boxes;
for (n = 0; n < num_boxes; n++) {
if (! _cairo_fixed_is_integer (array[n].p1.x) ||
! _cairo_fixed_is_integer (array[n].p1.y) ||
! _cairo_fixed_is_integer (array[n].p2.x) ||
! _cairo_fixed_is_integer (array[n].p2.y))
{
break;
}
}
boxes->is_pixel_aligned = n == num_boxes;
}
void
_cairo_boxes_limit (cairo_boxes_t *boxes,
const cairo_box_t *limits,
int num_limits)
{
int n;
boxes->limits = limits;
boxes->num_limits = num_limits;
if (boxes->num_limits) {
boxes->limit = limits[0];
for (n = 1; n < num_limits; n++) {
if (limits[n].p1.x < boxes->limit.p1.x)
boxes->limit.p1.x = limits[n].p1.x;
if (limits[n].p1.y < boxes->limit.p1.y)
boxes->limit.p1.y = limits[n].p1.y;
if (limits[n].p2.x > boxes->limit.p2.x)
boxes->limit.p2.x = limits[n].p2.x;
if (limits[n].p2.y > boxes->limit.p2.y)
boxes->limit.p2.y = limits[n].p2.y;
}
}
}
static void
_cairo_boxes_add_internal (cairo_boxes_t *boxes,
const cairo_box_t *box)
{
struct _cairo_boxes_chunk *chunk;
if (unlikely (boxes->status))
return;
chunk = boxes->tail;
if (unlikely (chunk->count == chunk->size)) {
int size;
size = chunk->size * 2;
chunk->next = _cairo_malloc_ab_plus_c (size,
sizeof (cairo_box_t),
sizeof (struct _cairo_boxes_chunk));
if (unlikely (chunk->next == NULL)) {
boxes->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return;
}
chunk = chunk->next;
boxes->tail = chunk;
chunk->next = NULL;
chunk->count = 0;
chunk->size = size;
chunk->base = (cairo_box_t *) (chunk + 1);
}
chunk->base[chunk->count++] = *box;
boxes->num_boxes++;
if (boxes->is_pixel_aligned)
boxes->is_pixel_aligned = _cairo_box_is_pixel_aligned (box);
}
cairo_status_t
_cairo_boxes_add (cairo_boxes_t *boxes,
cairo_antialias_t antialias,
const cairo_box_t *box)
{
cairo_box_t b;
if (antialias == CAIRO_ANTIALIAS_NONE) {
b.p1.x = _cairo_fixed_round_down (box->p1.x);
b.p1.y = _cairo_fixed_round_down (box->p1.y);
b.p2.x = _cairo_fixed_round_down (box->p2.x);
b.p2.y = _cairo_fixed_round_down (box->p2.y);
box = &b;
}
if (box->p1.y == box->p2.y)
return CAIRO_STATUS_SUCCESS;
if (box->p1.x == box->p2.x)
return CAIRO_STATUS_SUCCESS;
if (boxes->num_limits) {
cairo_point_t p1, p2;
cairo_bool_t reversed = FALSE;
int n;
/* support counter-clockwise winding for rectangular tessellation */
if (box->p1.x < box->p2.x) {
p1.x = box->p1.x;
p2.x = box->p2.x;
} else {
p2.x = box->p1.x;
p1.x = box->p2.x;
reversed = ! reversed;
}
if (p1.x >= boxes->limit.p2.x || p2.x <= boxes->limit.p1.x)
return CAIRO_STATUS_SUCCESS;
if (box->p1.y < box->p2.y) {
p1.y = box->p1.y;
p2.y = box->p2.y;
} else {
p2.y = box->p1.y;
p1.y = box->p2.y;
reversed = ! reversed;
}
if (p1.y >= boxes->limit.p2.y || p2.y <= boxes->limit.p1.y)
return CAIRO_STATUS_SUCCESS;
for (n = 0; n < boxes->num_limits; n++) {
const cairo_box_t *limits = &boxes->limits[n];
cairo_box_t _box;
cairo_point_t _p1, _p2;
if (p1.x >= limits->p2.x || p2.x <= limits->p1.x)
continue;
if (p1.y >= limits->p2.y || p2.y <= limits->p1.y)
continue;
/* Otherwise, clip the box to the limits. */
_p1 = p1;
if (_p1.x < limits->p1.x)
_p1.x = limits->p1.x;
if (_p1.y < limits->p1.y)
_p1.y = limits->p1.y;
_p2 = p2;
if (_p2.x > limits->p2.x)
_p2.x = limits->p2.x;
if (_p2.y > limits->p2.y)
_p2.y = limits->p2.y;
if (_p2.y <= _p1.y || _p2.x <= _p1.x)
continue;
_box.p1.y = _p1.y;
_box.p2.y = _p2.y;
if (reversed) {
_box.p1.x = _p2.x;
_box.p2.x = _p1.x;
} else {
_box.p1.x = _p1.x;
_box.p2.x = _p2.x;
}
_cairo_boxes_add_internal (boxes, &_box);
}
} else {
_cairo_boxes_add_internal (boxes, box);
}
return boxes->status;
}
void
_cairo_boxes_extents (const cairo_boxes_t *boxes,
cairo_box_t *box)
{
const struct _cairo_boxes_chunk *chunk;
cairo_box_t b;
int i;
if (boxes->num_boxes == 0) {
box->p1.x = box->p1.y = box->p2.x = box->p2.y = 0;
return;
}
b = boxes->chunks.base[0];
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
if (chunk->base[i].p1.x < b.p1.x)
b.p1.x = chunk->base[i].p1.x;
if (chunk->base[i].p1.y < b.p1.y)
b.p1.y = chunk->base[i].p1.y;
if (chunk->base[i].p2.x > b.p2.x)
b.p2.x = chunk->base[i].p2.x;
if (chunk->base[i].p2.y > b.p2.y)
b.p2.y = chunk->base[i].p2.y;
}
}
*box = b;
}
void
_cairo_boxes_clear (cairo_boxes_t *boxes)
{
struct _cairo_boxes_chunk *chunk, *next;
for (chunk = boxes->chunks.next; chunk != NULL; chunk = next) {
next = chunk->next;
free (chunk);
}
boxes->tail = &boxes->chunks;
boxes->chunks.next = 0;
boxes->chunks.count = 0;
boxes->chunks.base = boxes->boxes_embedded;
boxes->chunks.size = ARRAY_LENGTH (boxes->boxes_embedded);
boxes->num_boxes = 0;
boxes->is_pixel_aligned = TRUE;
}
cairo_box_t *
_cairo_boxes_to_array (const cairo_boxes_t *boxes,
int *num_boxes,
cairo_bool_t force_allocation)
{
const struct _cairo_boxes_chunk *chunk;
cairo_box_t *box;
int i, j;
*num_boxes = boxes->num_boxes;
if (boxes->chunks.next == NULL && ! force_allocation)
return boxes->chunks.base;
box = _cairo_malloc_ab (boxes->num_boxes, sizeof (cairo_box_t));
if (box == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
j = 0;
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++)
box[j++] = chunk->base[i];
}
return box;
}
void
_cairo_boxes_fini (cairo_boxes_t *boxes)
{
struct _cairo_boxes_chunk *chunk, *next;
for (chunk = boxes->chunks.next; chunk != NULL; chunk = next) {
next = chunk->next;
free (chunk);
}
}
cairo_bool_t
_cairo_boxes_for_each_box (cairo_boxes_t *boxes,
cairo_bool_t (*func) (cairo_box_t *box, void *data),
void *data)
{
struct _cairo_boxes_chunk *chunk;
int i;
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++)
if (! func (&chunk->base[i], data))
return FALSE;
}
return TRUE;
}
struct cairo_box_renderer {
cairo_span_renderer_t base;
cairo_boxes_t *boxes;
};
static cairo_status_t
span_to_boxes (void *abstract_renderer, int y, int h,
const cairo_half_open_span_t *spans, unsigned num_spans)
{
struct cairo_box_renderer *r = abstract_renderer;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_box_t box;
if (num_spans == 0)
return CAIRO_STATUS_SUCCESS;
box.p1.y = _cairo_fixed_from_int (y);
box.p2.y = _cairo_fixed_from_int (y + h);
do {
if (spans[0].coverage) {
box.p1.x = _cairo_fixed_from_int(spans[0].x);
box.p2.x = _cairo_fixed_from_int(spans[1].x);
status = _cairo_boxes_add (r->boxes, CAIRO_ANTIALIAS_DEFAULT, &box);
}
spans++;
} while (--num_spans > 1 && status == CAIRO_STATUS_SUCCESS);
return status;
}
cairo_status_t
_cairo_rasterise_polygon_to_boxes (cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule,
cairo_boxes_t *boxes)
{
struct cairo_box_renderer renderer;
cairo_scan_converter_t *converter;
cairo_int_status_t status;
cairo_rectangle_int_t r;
TRACE ((stderr, "%s: fill_rule=%d\n", __FUNCTION__, fill_rule));
_cairo_box_round_to_rectangle (&polygon->extents, &r);
converter = _cairo_mono_scan_converter_create (r.x, r.y,
r.x + r.width,
r.y + r.height,
fill_rule);
status = _cairo_mono_scan_converter_add_polygon (converter, polygon);
if (unlikely (status))
goto cleanup_converter;
renderer.boxes = boxes;
renderer.base.render_rows = span_to_boxes;
status = converter->generate (converter, &renderer.base);
cleanup_converter:
converter->destroy (converter);
return status;
}
void
_cairo_debug_print_boxes (FILE *stream, const cairo_boxes_t *boxes)
{
const struct _cairo_boxes_chunk *chunk;
cairo_box_t extents;
int i;
_cairo_boxes_extents (boxes, &extents);
fprintf (stream, "boxes x %d: (%f, %f) x (%f, %f)\n",
boxes->num_boxes,
_cairo_fixed_to_double (extents.p1.x),
_cairo_fixed_to_double (extents.p1.y),
_cairo_fixed_to_double (extents.p2.x),
_cairo_fixed_to_double (extents.p2.y));
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
fprintf (stderr, " box[%d]: (%f, %f), (%f, %f)\n", i,
_cairo_fixed_to_double (chunk->base[i].p1.x),
_cairo_fixed_to_double (chunk->base[i].p1.y),
_cairo_fixed_to_double (chunk->base[i].p2.x),
_cairo_fixed_to_double (chunk->base[i].p2.y));
}
}
}

View File

@@ -0,0 +1,145 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc.
* Copyright © 2005 Red Hat, Inc.
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Graydon Hoare <graydon@redhat.com>
* Carl Worth <cworth@cworth.org>
*/
#ifndef CAIRO_CACHE_PRIVATE_H
#define CAIRO_CACHE_PRIVATE_H
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
/**
* cairo_cache_entry_t:
*
* A #cairo_cache_entry_t contains both a key and a value for
* #cairo_cache_t. User-derived types for #cairo_cache_entry_t must
* have a #cairo_cache_entry_t as their first field. For example:
*
* typedef _my_entry {
* cairo_cache_entry_t base;
* ... Remainder of key and value fields here ..
* } my_entry_t;
*
* which then allows a pointer to my_entry_t to be passed to any of
* the #cairo_cache_t functions as follows without requiring a cast:
*
* _cairo_cache_insert (cache, &my_entry->base, size);
*
* IMPORTANT: The caller is responsible for initializing
* my_entry->base.hash with a hash code derived from the key. The
* essential property of the hash code is that keys_equal must never
* return %TRUE for two keys that have different hashes. The best hash
* code will reduce the frequency of two keys with the same code for
* which keys_equal returns %FALSE.
*
* The user must also initialize my_entry->base.size to indicate
* the size of the current entry. What units to use for size is
* entirely up to the caller, (though the same units must be used for
* the max_size parameter passed to _cairo_cache_create()). If all
* entries are close to the same size, the simplest thing to do is to
* just use units of "entries", (eg. set size==1 in all entries and
* set max_size to the number of entries which you want to be saved
* in the cache).
*
* Which parts of the entry make up the "key" and which part make up
* the value are entirely up to the caller, (as determined by the
* computation going into base.hash as well as the keys_equal
* function). A few of the #cairo_cache_t functions accept an entry which
* will be used exclusively as a "key", (indicated by a parameter name
* of key). In these cases, the value-related fields of the entry need
* not be initialized if so desired.
**/
typedef struct _cairo_cache_entry {
unsigned long hash;
unsigned long size;
} cairo_cache_entry_t;
typedef cairo_bool_t (*cairo_cache_predicate_func_t) (const void *entry);
struct _cairo_cache {
cairo_hash_table_t *hash_table;
cairo_cache_predicate_func_t predicate;
cairo_destroy_func_t entry_destroy;
unsigned long max_size;
unsigned long size;
int freeze_count;
};
typedef cairo_bool_t
(*cairo_cache_keys_equal_func_t) (const void *key_a, const void *key_b);
typedef void
(*cairo_cache_callback_func_t) (void *entry,
void *closure);
cairo_private cairo_status_t
_cairo_cache_init (cairo_cache_t *cache,
cairo_cache_keys_equal_func_t keys_equal,
cairo_cache_predicate_func_t predicate,
cairo_destroy_func_t entry_destroy,
unsigned long max_size);
cairo_private void
_cairo_cache_fini (cairo_cache_t *cache);
cairo_private void
_cairo_cache_freeze (cairo_cache_t *cache);
cairo_private void
_cairo_cache_thaw (cairo_cache_t *cache);
cairo_private void *
_cairo_cache_lookup (cairo_cache_t *cache,
cairo_cache_entry_t *key);
cairo_private cairo_status_t
_cairo_cache_insert (cairo_cache_t *cache,
cairo_cache_entry_t *entry);
cairo_private void
_cairo_cache_remove (cairo_cache_t *cache,
cairo_cache_entry_t *entry);
cairo_private void
_cairo_cache_foreach (cairo_cache_t *cache,
cairo_cache_callback_func_t cache_callback,
void *closure);
#endif

View File

@@ -0,0 +1,338 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc.
* Copyright © 2005 Red Hat, Inc.
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Graydon Hoare <graydon@redhat.com>
* Carl Worth <cworth@cworth.org>
*/
#include "cairoint.h"
#include "cairo-error-private.h"
static void
_cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
unsigned long additional);
static cairo_bool_t
_cairo_cache_entry_is_non_zero (const void *entry)
{
return ((const cairo_cache_entry_t *) entry)->size;
}
/**
* _cairo_cache_init:
* @cache: the #cairo_cache_t to initialise
* @keys_equal: a function to return %TRUE if two keys are equal
* @entry_destroy: destroy notifier for cache entries
* @max_size: the maximum size for this cache
* Returns: the newly created #cairo_cache_t
*
* Creates a new cache using the keys_equal() function to determine
* the equality of entries.
*
* Data is provided to the cache in the form of user-derived version
* of #cairo_cache_entry_t. A cache entry must be able to hold hash
* code, a size, and the key/value pair being stored in the
* cache. Sometimes only the key will be necessary, (as in
* _cairo_cache_lookup()), and in these cases the value portion of the
* entry need not be initialized.
*
* The units for max_size can be chosen by the caller, but should be
* consistent with the units of the size field of cache entries. When
* adding an entry with _cairo_cache_insert() if the total size of
* entries in the cache would exceed max_size then entries will be
* removed at random until the new entry would fit or the cache is
* empty. Then the new entry is inserted.
*
* There are cases in which the automatic removal of entries is
* undesired. If the cache entries have reference counts, then it is a
* simple matter to use the reference counts to ensure that entries
* continue to live even after being ejected from the cache. However,
* in some cases the memory overhead of adding a reference count to
* the entry would be objectionable. In such cases, the
* _cairo_cache_freeze() and _cairo_cache_thaw() calls can be
* used to establish a window during which no automatic removal of
* entries will occur.
**/
cairo_status_t
_cairo_cache_init (cairo_cache_t *cache,
cairo_cache_keys_equal_func_t keys_equal,
cairo_cache_predicate_func_t predicate,
cairo_destroy_func_t entry_destroy,
unsigned long max_size)
{
cache->hash_table = _cairo_hash_table_create (keys_equal);
if (unlikely (cache->hash_table == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (predicate == NULL)
predicate = _cairo_cache_entry_is_non_zero;
cache->predicate = predicate;
cache->entry_destroy = entry_destroy;
cache->max_size = max_size;
cache->size = 0;
cache->freeze_count = 0;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_cache_pluck (void *entry, void *closure)
{
_cairo_cache_remove (closure, entry);
}
/**
* _cairo_cache_fini:
* @cache: a cache to destroy
*
* Immediately destroys the given cache, freeing all resources
* associated with it. As part of this process, the entry_destroy()
* function, (as passed to _cairo_cache_init()), will be called for
* each entry in the cache.
**/
void
_cairo_cache_fini (cairo_cache_t *cache)
{
_cairo_hash_table_foreach (cache->hash_table,
_cairo_cache_pluck,
cache);
assert (cache->size == 0);
_cairo_hash_table_destroy (cache->hash_table);
}
/**
* _cairo_cache_freeze:
* @cache: a cache with some precious entries in it (or about to be
* added)
*
* Disable the automatic ejection of entries from the cache. For as
* long as the cache is "frozen", calls to _cairo_cache_insert() will
* add new entries to the cache regardless of how large the cache
* grows. See _cairo_cache_thaw().
*
* Note: Multiple calls to _cairo_cache_freeze() will stack, in that
* the cache will remain "frozen" until a corresponding number of
* calls are made to _cairo_cache_thaw().
**/
void
_cairo_cache_freeze (cairo_cache_t *cache)
{
assert (cache->freeze_count >= 0);
cache->freeze_count++;
}
/**
* _cairo_cache_thaw:
* @cache: a cache, just after the entries in it have become less
* precious
*
* Cancels the effects of _cairo_cache_freeze().
*
* When a number of calls to _cairo_cache_thaw() is made corresponding
* to the number of calls to _cairo_cache_freeze() the cache will no
* longer be "frozen". If the cache had grown larger than max_size
* while frozen, entries will immediately be ejected (by random) from
* the cache until the cache is smaller than max_size. Also, the
* automatic ejection of entries on _cairo_cache_insert() will resume.
**/
void
_cairo_cache_thaw (cairo_cache_t *cache)
{
assert (cache->freeze_count > 0);
if (--cache->freeze_count == 0)
_cairo_cache_shrink_to_accommodate (cache, 0);
}
/**
* _cairo_cache_lookup:
* @cache: a cache
* @key: the key of interest
* @entry_return: pointer for return value
*
* Performs a lookup in @cache looking for an entry which has a key
* that matches @key, (as determined by the keys_equal() function
* passed to _cairo_cache_init()).
*
* Return value: %TRUE if there is an entry in the cache that matches
* @key, (which will now be in *entry_return). %FALSE otherwise, (in
* which case *entry_return will be %NULL).
**/
void *
_cairo_cache_lookup (cairo_cache_t *cache,
cairo_cache_entry_t *key)
{
return _cairo_hash_table_lookup (cache->hash_table,
(cairo_hash_entry_t *) key);
}
/**
* _cairo_cache_remove_random:
* @cache: a cache
*
* Remove a random entry from the cache.
*
* Return value: %TRUE if an entry was successfully removed.
* %FALSE if there are no entries that can be removed.
**/
static cairo_bool_t
_cairo_cache_remove_random (cairo_cache_t *cache)
{
cairo_cache_entry_t *entry;
entry = _cairo_hash_table_random_entry (cache->hash_table,
cache->predicate);
if (unlikely (entry == NULL))
return FALSE;
_cairo_cache_remove (cache, entry);
return TRUE;
}
/**
* _cairo_cache_shrink_to_accommodate:
* @cache: a cache
* @additional: additional size requested in bytes
*
* If cache is not frozen, eject entries randomly until the size of
* the cache is at least @additional bytes less than
* cache->max_size. That is, make enough room to accommodate a new
* entry of size @additional.
**/
static void
_cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
unsigned long additional)
{
while (cache->size + additional > cache->max_size) {
if (! _cairo_cache_remove_random (cache))
return;
}
}
/**
* _cairo_cache_insert:
* @cache: a cache
* @entry: an entry to be inserted
*
* Insert @entry into the cache. If an entry exists in the cache with
* a matching key, then the old entry will be removed first, (and the
* entry_destroy() callback will be called on it).
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
**/
cairo_status_t
_cairo_cache_insert (cairo_cache_t *cache,
cairo_cache_entry_t *entry)
{
cairo_status_t status;
if (entry->size && ! cache->freeze_count)
_cairo_cache_shrink_to_accommodate (cache, entry->size);
status = _cairo_hash_table_insert (cache->hash_table,
(cairo_hash_entry_t *) entry);
if (unlikely (status))
return status;
cache->size += entry->size;
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_cache_remove:
* @cache: a cache
* @entry: an entry that exists in the cache
*
* Remove an existing entry from the cache.
**/
void
_cairo_cache_remove (cairo_cache_t *cache,
cairo_cache_entry_t *entry)
{
cache->size -= entry->size;
_cairo_hash_table_remove (cache->hash_table,
(cairo_hash_entry_t *) entry);
if (cache->entry_destroy)
cache->entry_destroy (entry);
}
/**
* _cairo_cache_foreach:
* @cache: a cache
* @cache_callback: function to be called for each entry
* @closure: additional argument to be passed to @cache_callback
*
* Call @cache_callback for each entry in the cache, in a
* non-specified order.
**/
void
_cairo_cache_foreach (cairo_cache_t *cache,
cairo_cache_callback_func_t cache_callback,
void *closure)
{
_cairo_hash_table_foreach (cache->hash_table,
cache_callback,
closure);
}
unsigned long
_cairo_hash_string (const char *c)
{
/* This is the djb2 hash. */
unsigned long hash = _CAIRO_HASH_INIT_VALUE;
while (c && *c)
hash = ((hash << 5) + hash) + *c++;
return hash;
}
unsigned long
_cairo_hash_bytes (unsigned long hash,
const void *ptr,
unsigned int length)
{
const uint8_t *bytes = ptr;
/* This is the djb2 hash. */
while (length--)
hash = ((hash << 5) + hash) + *bytes++;
return hash;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,594 @@
/* -*- 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 © 2005 Red Hat, Inc.
* Copyright © 2009 Chris Wilson
*
* 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.
*
* 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>
* Kristian Høgsberg <krh@redhat.com>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-box-inline.h"
#include "cairo-clip-inline.h"
#include "cairo-clip-private.h"
#include "cairo-error-private.h"
#include "cairo-freed-pool-private.h"
#include "cairo-gstate-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-pattern-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-region-private.h"
static inline int
pot (int v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
static cairo_bool_t
_cairo_clip_contains_rectangle_box (const cairo_clip_t *clip,
const cairo_rectangle_int_t *rect,
const cairo_box_t *box)
{
int i;
/* clip == NULL means no clip, so the clip contains everything */
if (clip == NULL)
return TRUE;
if (_cairo_clip_is_all_clipped (clip))
return FALSE;
/* If we have a non-trivial path, just say no */
if (clip->path)
return FALSE;
if (! _cairo_rectangle_contains_rectangle (&clip->extents, rect))
return FALSE;
if (clip->num_boxes == 0)
return TRUE;
/* Check for a clip-box that wholly contains the rectangle */
for (i = 0; i < clip->num_boxes; i++) {
if (box->p1.x >= clip->boxes[i].p1.x &&
box->p1.y >= clip->boxes[i].p1.y &&
box->p2.x <= clip->boxes[i].p2.x &&
box->p2.y <= clip->boxes[i].p2.y)
{
return TRUE;
}
}
return FALSE;
}
cairo_bool_t
_cairo_clip_contains_box (const cairo_clip_t *clip,
const cairo_box_t *box)
{
cairo_rectangle_int_t rect;
_cairo_box_round_to_rectangle (box, &rect);
return _cairo_clip_contains_rectangle_box(clip, &rect, box);
}
cairo_bool_t
_cairo_clip_contains_rectangle (const cairo_clip_t *clip,
const cairo_rectangle_int_t *rect)
{
cairo_box_t box;
box.p1.x = _cairo_fixed_from_int (rect->x);
box.p1.y = _cairo_fixed_from_int (rect->y);
box.p2.x = _cairo_fixed_from_int (rect->x + rect->width);
box.p2.y = _cairo_fixed_from_int (rect->y + rect->height);
return _cairo_clip_contains_rectangle_box (clip, rect, &box);
}
cairo_clip_t *
_cairo_clip_intersect_rectilinear_path (cairo_clip_t *clip,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_antialias_t antialias)
{
cairo_status_t status;
cairo_boxes_t boxes;
_cairo_boxes_init (&boxes);
status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
fill_rule,
antialias,
&boxes);
if (likely (status == CAIRO_STATUS_SUCCESS && boxes.num_boxes))
clip = _cairo_clip_intersect_boxes (clip, &boxes);
else
clip = _cairo_clip_set_all_clipped (clip);
_cairo_boxes_fini (&boxes);
return clip;
}
static cairo_clip_t *
_cairo_clip_intersect_rectangle_box (cairo_clip_t *clip,
const cairo_rectangle_int_t *r,
const cairo_box_t *box)
{
cairo_box_t extents_box;
cairo_bool_t changed = FALSE;
int i, j;
if (clip == NULL) {
clip = _cairo_clip_create ();
if (clip == NULL)
return _cairo_clip_set_all_clipped (clip);
}
if (clip->num_boxes == 0) {
clip->boxes = &clip->embedded_box;
clip->boxes[0] = *box;
clip->num_boxes = 1;
if (clip->path == NULL) {
clip->extents = *r;
} else {
if (! _cairo_rectangle_intersect (&clip->extents, r))
clip = _cairo_clip_set_all_clipped (clip);
}
if (clip->path == NULL)
clip->is_region = _cairo_box_is_pixel_aligned (box);
return clip;
}
/* Does the new box wholly subsume the clip? Perform a cheap check
* for the common condition of a single clip rectangle.
*/
if (clip->num_boxes == 1 &&
clip->boxes[0].p1.x >= box->p1.x &&
clip->boxes[0].p1.y >= box->p1.y &&
clip->boxes[0].p2.x <= box->p2.x &&
clip->boxes[0].p2.y <= box->p2.y)
{
return clip;
}
for (i = j = 0; i < clip->num_boxes; i++) {
cairo_box_t *b = &clip->boxes[j];
if (j != i)
*b = clip->boxes[i];
if (box->p1.x > b->p1.x)
b->p1.x = box->p1.x, changed = TRUE;
if (box->p2.x < b->p2.x)
b->p2.x = box->p2.x, changed = TRUE;
if (box->p1.y > b->p1.y)
b->p1.y = box->p1.y, changed = TRUE;
if (box->p2.y < b->p2.y)
b->p2.y = box->p2.y, changed = TRUE;
j += b->p2.x > b->p1.x && b->p2.y > b->p1.y;
}
clip->num_boxes = j;
if (clip->num_boxes == 0)
return _cairo_clip_set_all_clipped (clip);
if (! changed)
return clip;
extents_box = clip->boxes[0];
for (i = 1; i < clip->num_boxes; i++) {
if (clip->boxes[i].p1.x < extents_box.p1.x)
extents_box.p1.x = clip->boxes[i].p1.x;
if (clip->boxes[i].p1.y < extents_box.p1.y)
extents_box.p1.y = clip->boxes[i].p1.y;
if (clip->boxes[i].p2.x > extents_box.p2.x)
extents_box.p2.x = clip->boxes[i].p2.x;
if (clip->boxes[i].p2.y > extents_box.p2.y)
extents_box.p2.y = clip->boxes[i].p2.y;
}
if (clip->path == NULL) {
_cairo_box_round_to_rectangle (&extents_box, &clip->extents);
} else {
cairo_rectangle_int_t extents_rect;
_cairo_box_round_to_rectangle (&extents_box, &extents_rect);
if (! _cairo_rectangle_intersect (&clip->extents, &extents_rect))
return _cairo_clip_set_all_clipped (clip);
}
if (clip->region) {
cairo_region_destroy (clip->region);
clip->region = NULL;
}
clip->is_region = FALSE;
return clip;
}
cairo_clip_t *
_cairo_clip_intersect_box (cairo_clip_t *clip,
const cairo_box_t *box)
{
cairo_rectangle_int_t r;
_cairo_box_round_to_rectangle (box, &r);
if (r.width == 0 || r.height == 0)
return _cairo_clip_set_all_clipped (clip);
return _cairo_clip_intersect_rectangle_box (clip, &r, box);
}
cairo_clip_t *
_cairo_clip_intersect_boxes (cairo_clip_t *clip,
const cairo_boxes_t *boxes)
{
cairo_boxes_t clip_boxes;
cairo_box_t limits;
cairo_rectangle_int_t extents;
if (_cairo_clip_is_all_clipped (clip))
return clip;
if (boxes->num_boxes == 0)
return _cairo_clip_set_all_clipped (clip);
if (boxes->num_boxes == 1)
return _cairo_clip_intersect_box (clip, boxes->chunks.base);
if (clip == NULL)
clip = _cairo_clip_create ();
if (clip->num_boxes) {
_cairo_boxes_init_for_array (&clip_boxes, clip->boxes, clip->num_boxes);
if (unlikely (_cairo_boxes_intersect (&clip_boxes, boxes, &clip_boxes))) {
clip = _cairo_clip_set_all_clipped (clip);
goto out;
}
if (clip->boxes != &clip->embedded_box)
free (clip->boxes);
clip->boxes = NULL;
boxes = &clip_boxes;
}
if (boxes->num_boxes == 0) {
clip = _cairo_clip_set_all_clipped (clip);
goto out;
} else if (boxes->num_boxes == 1) {
clip->boxes = &clip->embedded_box;
clip->boxes[0] = boxes->chunks.base[0];
clip->num_boxes = 1;
} else {
clip->boxes = _cairo_boxes_to_array (boxes, &clip->num_boxes, TRUE);
}
_cairo_boxes_extents (boxes, &limits);
_cairo_box_round_to_rectangle (&limits, &extents);
if (clip->path == NULL)
clip->extents = extents;
else if (! _cairo_rectangle_intersect (&clip->extents, &extents))
clip = _cairo_clip_set_all_clipped (clip);
if (clip->region) {
cairo_region_destroy (clip->region);
clip->region = NULL;
}
clip->is_region = FALSE;
out:
if (boxes == &clip_boxes)
_cairo_boxes_fini (&clip_boxes);
return clip;
}
cairo_clip_t *
_cairo_clip_intersect_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *r)
{
cairo_box_t box;
if (_cairo_clip_is_all_clipped (clip))
return clip;
if (r->width == 0 || r->height == 0)
return _cairo_clip_set_all_clipped (clip);
box.p1.x = _cairo_fixed_from_int (r->x);
box.p1.y = _cairo_fixed_from_int (r->y);
box.p2.x = _cairo_fixed_from_int (r->x + r->width);
box.p2.y = _cairo_fixed_from_int (r->y + r->height);
return _cairo_clip_intersect_rectangle_box (clip, r, &box);
}
struct reduce {
cairo_clip_t *clip;
cairo_box_t limit;
cairo_box_t extents;
cairo_bool_t inside;
cairo_point_t current_point;
cairo_point_t last_move_to;
};
static void
_add_clipped_edge (struct reduce *r,
const cairo_point_t *p1,
const cairo_point_t *p2,
int y1, int y2)
{
cairo_fixed_t x;
x = _cairo_edge_compute_intersection_x_for_y (p1, p2, y1);
if (x < r->extents.p1.x)
r->extents.p1.x = x;
x = _cairo_edge_compute_intersection_x_for_y (p1, p2, y2);
if (x > r->extents.p2.x)
r->extents.p2.x = x;
if (y1 < r->extents.p1.y)
r->extents.p1.y = y1;
if (y2 > r->extents.p2.y)
r->extents.p2.y = y2;
r->inside = TRUE;
}
static void
_add_edge (struct reduce *r,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
int top, bottom;
int top_y, bot_y;
int n;
if (p1->y < p2->y) {
top = p1->y;
bottom = p2->y;
} else {
top = p2->y;
bottom = p1->y;
}
if (bottom < r->limit.p1.y || top > r->limit.p2.y)
return;
if (p1->x > p2->x) {
const cairo_point_t *t = p1;
p1 = p2;
p2 = t;
}
if (p2->x <= r->limit.p1.x || p1->x >= r->limit.p2.x)
return;
for (n = 0; n < r->clip->num_boxes; n++) {
const cairo_box_t *limits = &r->clip->boxes[n];
if (bottom < limits->p1.y || top > limits->p2.y)
continue;
if (p2->x <= limits->p1.x || p1->x >= limits->p2.x)
continue;
if (p1->x >= limits->p1.x && p2->x <= limits->p1.x) {
top_y = top;
bot_y = bottom;
} else {
int p1_y, p2_y;
p1_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
limits->p1.x);
p2_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
limits->p2.x);
if (p1_y < p2_y) {
top_y = p1_y;
bot_y = p2_y;
} else {
top_y = p2_y;
bot_y = p1_y;
}
if (top_y < top)
top_y = top;
if (bot_y > bottom)
bot_y = bottom;
}
if (top_y < limits->p1.y)
top_y = limits->p1.y;
if (bot_y > limits->p2.y)
bot_y = limits->p2.y;
if (bot_y > top_y)
_add_clipped_edge (r, p1, p2, top_y, bot_y);
}
}
static cairo_status_t
_reduce_line_to (void *closure,
const cairo_point_t *point)
{
struct reduce *r = closure;
_add_edge (r, &r->current_point, point);
r->current_point = *point;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_reduce_close (void *closure)
{
struct reduce *r = closure;
return _reduce_line_to (r, &r->last_move_to);
}
static cairo_status_t
_reduce_move_to (void *closure,
const cairo_point_t *point)
{
struct reduce *r = closure;
cairo_status_t status;
/* close current subpath */
status = _reduce_close (closure);
/* make sure that the closure represents a degenerate path */
r->current_point = *point;
r->last_move_to = *point;
return status;
}
static cairo_clip_t *
_cairo_clip_reduce_to_boxes (cairo_clip_t *clip)
{
struct reduce r;
cairo_clip_path_t *clip_path;
cairo_status_t status;
return clip;
if (clip->path == NULL)
return clip;
r.clip = clip;
r.extents.p1.x = r.extents.p1.y = INT_MAX;
r.extents.p2.x = r.extents.p2.y = INT_MIN;
r.inside = FALSE;
r.limit.p1.x = _cairo_fixed_from_int (clip->extents.x);
r.limit.p1.y = _cairo_fixed_from_int (clip->extents.y);
r.limit.p2.x = _cairo_fixed_from_int (clip->extents.x + clip->extents.width);
r.limit.p2.y = _cairo_fixed_from_int (clip->extents.y + clip->extents.height);
clip_path = clip->path;
do {
r.current_point.x = 0;
r.current_point.y = 0;
r.last_move_to = r.current_point;
status = _cairo_path_fixed_interpret_flat (&clip_path->path,
_reduce_move_to,
_reduce_line_to,
_reduce_close,
&r,
clip_path->tolerance);
assert (status == CAIRO_STATUS_SUCCESS);
_reduce_close (&r);
} while ((clip_path = clip_path->prev));
if (! r.inside) {
_cairo_clip_path_destroy (clip->path);
clip->path = NULL;
}
return _cairo_clip_intersect_box (clip, &r.extents);
}
cairo_clip_t *
_cairo_clip_reduce_to_rectangle (const cairo_clip_t *clip,
const cairo_rectangle_int_t *r)
{
cairo_clip_t *copy;
if (_cairo_clip_is_all_clipped (clip))
return (cairo_clip_t *) clip;
if (_cairo_clip_contains_rectangle (clip, r))
return _cairo_clip_intersect_rectangle (NULL, r);
copy = _cairo_clip_copy_intersect_rectangle (clip, r);
if (_cairo_clip_is_all_clipped (copy))
return copy;
return _cairo_clip_reduce_to_boxes (copy);
}
cairo_clip_t *
_cairo_clip_reduce_for_composite (const cairo_clip_t *clip,
cairo_composite_rectangles_t *extents)
{
const cairo_rectangle_int_t *r;
r = extents->is_bounded ? &extents->bounded : &extents->unbounded;
return _cairo_clip_reduce_to_rectangle (clip, r);
}
cairo_clip_t *
_cairo_clip_from_boxes (const cairo_boxes_t *boxes)
{
cairo_box_t extents;
cairo_clip_t *clip = _cairo_clip_create ();
if (clip == NULL)
return _cairo_clip_set_all_clipped (clip);
/* XXX cow-boxes? */
if(boxes->num_boxes == 1) {
clip->boxes = &clip->embedded_box;
clip->boxes[0] = boxes->chunks.base[0];
clip->num_boxes = 1;
} else {
clip->boxes = _cairo_boxes_to_array (boxes, &clip->num_boxes, TRUE);
if (clip->boxes == NULL)
return _cairo_clip_set_all_clipped (clip);
}
_cairo_boxes_extents (boxes, &extents);
_cairo_box_round_to_rectangle (&extents, &clip->extents);
return clip;
}

View File

@@ -0,0 +1,83 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_CLIP_INLINE_H
#define CAIRO_CLIP_INLINE_H
#include "cairo-clip-private.h"
static inline cairo_bool_t _cairo_clip_is_all_clipped(const cairo_clip_t *clip)
{
return clip == &__cairo_clip_all;
}
static inline cairo_clip_t *
_cairo_clip_set_all_clipped (cairo_clip_t *clip)
{
_cairo_clip_destroy (clip);
return (cairo_clip_t *) &__cairo_clip_all;
}
static inline cairo_clip_t *
_cairo_clip_copy_intersect_rectangle (const cairo_clip_t *clip,
const cairo_rectangle_int_t *r)
{
return _cairo_clip_intersect_rectangle (_cairo_clip_copy (clip), r);
}
static inline cairo_clip_t *
_cairo_clip_copy_intersect_clip (const cairo_clip_t *clip,
const cairo_clip_t *other)
{
return _cairo_clip_intersect_clip (_cairo_clip_copy (clip), other);
}
static inline void
_cairo_clip_steal_boxes (cairo_clip_t *clip, cairo_boxes_t *boxes)
{
_cairo_boxes_init_for_array (boxes, clip->boxes, clip->num_boxes);
clip->boxes = NULL;
clip->num_boxes = 0;
}
static inline void
_cairo_clip_unsteal_boxes (cairo_clip_t *clip, cairo_boxes_t *boxes)
{
clip->boxes = boxes->chunks.base;
clip->num_boxes = boxes->num_boxes;
}
#endif /* CAIRO_CLIP_INLINE_H */

View File

@@ -0,0 +1,156 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2011 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-clip-inline.h"
#include "cairo-clip-private.h"
#include "cairo-error-private.h"
#include "cairo-freed-pool-private.h"
#include "cairo-gstate-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-pattern-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-region-private.h"
static cairo_bool_t
can_convert_to_polygon (const cairo_clip_t *clip)
{
cairo_clip_path_t *clip_path = clip->path;
cairo_antialias_t antialias = clip_path->antialias;
while ((clip_path = clip_path->prev) != NULL) {
if (clip_path->antialias != antialias)
return FALSE;
}
return TRUE;
}
cairo_int_status_t
_cairo_clip_get_polygon (const cairo_clip_t *clip,
cairo_polygon_t *polygon,
cairo_fill_rule_t *fill_rule,
cairo_antialias_t *antialias)
{
cairo_status_t status;
cairo_clip_path_t *clip_path;
if (_cairo_clip_is_all_clipped (clip)) {
_cairo_polygon_init (polygon, NULL, 0);
return CAIRO_INT_STATUS_SUCCESS;
}
/* If there is no clip, we need an infinite polygon */
assert (clip && (clip->path || clip->num_boxes));
if (clip->path == NULL) {
*fill_rule = CAIRO_FILL_RULE_WINDING;
*antialias = CAIRO_ANTIALIAS_DEFAULT;
return _cairo_polygon_init_box_array (polygon,
clip->boxes,
clip->num_boxes);
}
/* check that residual is all of the same type/tolerance */
if (! can_convert_to_polygon (clip))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (clip->num_boxes < 2)
_cairo_polygon_init_with_clip (polygon, clip);
else
_cairo_polygon_init_with_clip (polygon, NULL);
clip_path = clip->path;
*fill_rule = clip_path->fill_rule;
*antialias = clip_path->antialias;
status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
clip_path->tolerance,
polygon);
if (unlikely (status))
goto err;
if (clip->num_boxes > 1) {
status = _cairo_polygon_intersect_with_boxes (polygon, fill_rule,
clip->boxes, clip->num_boxes);
if (unlikely (status))
goto err;
}
polygon->limits = NULL;
polygon->num_limits = 0;
while ((clip_path = clip_path->prev) != NULL) {
cairo_polygon_t next;
_cairo_polygon_init (&next, NULL, 0);
status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
clip_path->tolerance,
&next);
if (likely (status == CAIRO_STATUS_SUCCESS))
status = _cairo_polygon_intersect (polygon, *fill_rule,
&next, clip_path->fill_rule);
_cairo_polygon_fini (&next);
if (unlikely (status))
goto err;
*fill_rule = CAIRO_FILL_RULE_WINDING;
}
return CAIRO_STATUS_SUCCESS;
err:
_cairo_polygon_fini (polygon);
return status;
}
cairo_bool_t
_cairo_clip_is_polygon (const cairo_clip_t *clip)
{
if (_cairo_clip_is_all_clipped (clip))
return TRUE;
/* If there is no clip, we need an infinite polygon */
if (clip == NULL)
return FALSE;
if (clip->path == NULL)
return TRUE;
/* check that residual is all of the same type/tolerance */
return can_convert_to_polygon (clip);
}

View File

@@ -0,0 +1,198 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_CLIP_PRIVATE_H
#define CAIRO_CLIP_PRIVATE_H
#include "cairo-types-private.h"
#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-compiler-private.h"
#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-reference-count-private.h"
extern const cairo_private cairo_rectangle_list_t _cairo_rectangles_nil;
struct _cairo_clip_path {
cairo_reference_count_t ref_count;
cairo_path_fixed_t path;
cairo_fill_rule_t fill_rule;
double tolerance;
cairo_antialias_t antialias;
cairo_clip_path_t *prev;
};
struct _cairo_clip {
cairo_rectangle_int_t extents;
cairo_clip_path_t *path;
cairo_box_t *boxes;
int num_boxes;
cairo_region_t *region;
cairo_bool_t is_region;
cairo_box_t embedded_box;
};
cairo_private cairo_clip_t *
_cairo_clip_create (void);
cairo_private cairo_clip_path_t *
_cairo_clip_path_reference (cairo_clip_path_t *clip_path);
cairo_private void
_cairo_clip_path_destroy (cairo_clip_path_t *clip_path);
cairo_private void
_cairo_clip_destroy (cairo_clip_t *clip);
cairo_private extern const cairo_clip_t __cairo_clip_all;
cairo_private cairo_clip_t *
_cairo_clip_copy (const cairo_clip_t *clip);
cairo_private cairo_clip_t *
_cairo_clip_copy_region (const cairo_clip_t *clip);
cairo_private cairo_clip_t *
_cairo_clip_copy_path (const cairo_clip_t *clip);
cairo_private cairo_clip_t *
_cairo_clip_translate (cairo_clip_t *clip, int tx, int ty);
cairo_private cairo_clip_t *
_cairo_clip_transform (cairo_clip_t *clip, const cairo_matrix_t *m);
cairo_private cairo_clip_t *
_cairo_clip_copy_with_translation (const cairo_clip_t *clip, int tx, int ty);
cairo_private cairo_bool_t
_cairo_clip_equal (const cairo_clip_t *clip_a,
const cairo_clip_t *clip_b);
cairo_private cairo_clip_t *
_cairo_clip_intersect_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rectangle);
cairo_private cairo_clip_t *
_cairo_clip_intersect_clip (cairo_clip_t *clip,
const cairo_clip_t *other);
cairo_private cairo_clip_t *
_cairo_clip_intersect_box (cairo_clip_t *clip,
const cairo_box_t *box);
cairo_private cairo_clip_t *
_cairo_clip_intersect_boxes (cairo_clip_t *clip,
const cairo_boxes_t *boxes);
cairo_private cairo_clip_t *
_cairo_clip_intersect_rectilinear_path (cairo_clip_t *clip,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_antialias_t antialias);
cairo_private cairo_clip_t *
_cairo_clip_intersect_path (cairo_clip_t *clip,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias);
cairo_private const cairo_rectangle_int_t *
_cairo_clip_get_extents (const cairo_clip_t *clip);
cairo_private cairo_surface_t *
_cairo_clip_get_surface (const cairo_clip_t *clip, cairo_surface_t *dst, int *tx, int *ty);
cairo_private cairo_surface_t *
_cairo_clip_get_image (const cairo_clip_t *clip,
cairo_surface_t *target,
const cairo_rectangle_int_t *extents);
cairo_private cairo_status_t
_cairo_clip_combine_with_surface (const cairo_clip_t *clip,
cairo_surface_t *dst,
int dst_x, int dst_y);
cairo_private cairo_clip_t *
_cairo_clip_from_boxes (const cairo_boxes_t *boxes);
cairo_private cairo_region_t *
_cairo_clip_get_region (const cairo_clip_t *clip);
cairo_private cairo_bool_t
_cairo_clip_is_region (const cairo_clip_t *clip);
cairo_private cairo_clip_t *
_cairo_clip_reduce_to_rectangle (const cairo_clip_t *clip,
const cairo_rectangle_int_t *r);
cairo_private cairo_clip_t *
_cairo_clip_reduce_for_composite (const cairo_clip_t *clip,
cairo_composite_rectangles_t *extents);
cairo_private cairo_bool_t
_cairo_clip_contains_rectangle (const cairo_clip_t *clip,
const cairo_rectangle_int_t *rect);
cairo_private cairo_bool_t
_cairo_clip_contains_box (const cairo_clip_t *clip,
const cairo_box_t *box);
cairo_private cairo_bool_t
_cairo_clip_contains_extents (const cairo_clip_t *clip,
const cairo_composite_rectangles_t *extents);
cairo_private cairo_rectangle_list_t*
_cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate);
cairo_private cairo_rectangle_list_t *
_cairo_rectangle_list_create_in_error (cairo_status_t status);
cairo_private cairo_bool_t
_cairo_clip_is_polygon (const cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_clip_get_polygon (const cairo_clip_t *clip,
cairo_polygon_t *polygon,
cairo_fill_rule_t *fill_rule,
cairo_antialias_t *antialias);
#endif /* CAIRO_CLIP_PRIVATE_H */

View File

@@ -0,0 +1,123 @@
/* -*- 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 © 2005 Red Hat, Inc.
* Copyright © 2009 Chris Wilson
*
* 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.
*
* 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>
* Kristian Høgsberg <krh@redhat.com>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-clip-private.h"
#include "cairo-error-private.h"
#include "cairo-freed-pool-private.h"
#include "cairo-gstate-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-pattern-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-region-private.h"
static void
_cairo_clip_extract_region (cairo_clip_t *clip)
{
cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
cairo_rectangle_int_t *r = stack_rects;
cairo_bool_t is_region;
int i;
if (clip->num_boxes == 0)
return;
if (clip->num_boxes > ARRAY_LENGTH (stack_rects)) {
r = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_rectangle_int_t));
if (r == NULL){
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return;
}
}
is_region = clip->path == NULL;
for (i = 0; i < clip->num_boxes; i++) {
cairo_box_t *b = &clip->boxes[i];
if (is_region)
is_region =
_cairo_fixed_is_integer (b->p1.x | b->p1.y | b->p2.x | b->p2.y);
r[i].x = _cairo_fixed_integer_floor (b->p1.x);
r[i].y = _cairo_fixed_integer_floor (b->p1.y);
r[i].width = _cairo_fixed_integer_ceil (b->p2.x) - r[i].x;
r[i].height = _cairo_fixed_integer_ceil (b->p2.y) - r[i].y;
}
clip->is_region = is_region;
clip->region = cairo_region_create_rectangles (r, i);
if (r != stack_rects)
free (r);
}
cairo_region_t *
_cairo_clip_get_region (const cairo_clip_t *clip)
{
if (clip == NULL)
return NULL;
if (clip->region == NULL)
_cairo_clip_extract_region ((cairo_clip_t *) clip);
return clip->region;
}
cairo_bool_t
_cairo_clip_is_region (const cairo_clip_t *clip)
{
if (clip == NULL)
return TRUE;
if (clip->is_region)
return TRUE;
/* XXX Geometric reduction? */
if (clip->path)
return FALSE;
if (clip->num_boxes == 0)
return TRUE;
if (clip->region == NULL)
_cairo_clip_extract_region ((cairo_clip_t *) clip);
return clip->is_region;
}

View File

@@ -0,0 +1,240 @@
/* -*- 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 © 2005 Red Hat, Inc.
* Copyright © 2009 Chris Wilson
*
* 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.
*
* 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>
* Kristian Høgsberg <krh@redhat.com>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-clip-private.h"
#include "cairo-error-private.h"
#include "cairo-freed-pool-private.h"
#include "cairo-gstate-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-pattern-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-region-private.h"
cairo_status_t
_cairo_clip_combine_with_surface (const cairo_clip_t *clip,
cairo_surface_t *dst,
int dst_x, int dst_y)
{
cairo_clip_path_t *copy_path;
cairo_clip_path_t *clip_path;
cairo_clip_t *copy;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
copy = _cairo_clip_copy_with_translation (clip, -dst_x, -dst_y);
copy_path = copy->path;
copy->path = NULL;
if (copy->boxes) {
status = _cairo_surface_paint (dst,
CAIRO_OPERATOR_IN,
&_cairo_pattern_white.base,
copy);
}
clip = NULL;
if (_cairo_clip_is_region (copy))
clip = copy;
clip_path = copy_path;
while (status == CAIRO_STATUS_SUCCESS && clip_path) {
status = _cairo_surface_fill (dst,
CAIRO_OPERATOR_IN,
&_cairo_pattern_white.base,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias,
clip);
clip_path = clip_path->prev;
}
copy->path = copy_path;
_cairo_clip_destroy (copy);
return status;
}
static cairo_status_t
_cairo_path_fixed_add_box (cairo_path_fixed_t *path,
const cairo_box_t *box,
cairo_fixed_t fx,
cairo_fixed_t fy)
{
cairo_status_t status;
status = _cairo_path_fixed_move_to (path, box->p1.x + fx, box->p1.y + fy);
if (unlikely (status))
return status;
status = _cairo_path_fixed_line_to (path, box->p2.x + fx, box->p1.y + fy);
if (unlikely (status))
return status;
status = _cairo_path_fixed_line_to (path, box->p2.x + fx, box->p2.y + fy);
if (unlikely (status))
return status;
status = _cairo_path_fixed_line_to (path, box->p1.x + fx, box->p2.y + fy);
if (unlikely (status))
return status;
return _cairo_path_fixed_close_path (path);
}
cairo_surface_t *
_cairo_clip_get_surface (const cairo_clip_t *clip,
cairo_surface_t *target,
int *tx, int *ty)
{
cairo_surface_t *surface;
cairo_status_t status;
cairo_clip_t *copy, *region;
cairo_clip_path_t *copy_path, *clip_path;
if (clip->num_boxes) {
cairo_path_fixed_t path;
int i;
surface = _cairo_surface_create_similar_solid (target,
CAIRO_CONTENT_ALPHA,
clip->extents.width,
clip->extents.height,
CAIRO_COLOR_TRANSPARENT);
if (unlikely (surface->status))
return surface;
_cairo_path_fixed_init (&path);
status = CAIRO_STATUS_SUCCESS;
for (i = 0; status == CAIRO_STATUS_SUCCESS && i < clip->num_boxes; i++) {
status = _cairo_path_fixed_add_box (&path, &clip->boxes[i],
-_cairo_fixed_from_int (clip->extents.x),
-_cairo_fixed_from_int (clip->extents.y));
}
if (status == CAIRO_STATUS_SUCCESS)
status = _cairo_surface_fill (surface,
CAIRO_OPERATOR_ADD,
&_cairo_pattern_white.base,
&path,
CAIRO_FILL_RULE_WINDING,
1.,
CAIRO_ANTIALIAS_DEFAULT,
NULL);
_cairo_path_fixed_fini (&path);
if (unlikely (status)) {
cairo_surface_destroy (surface);
return _cairo_surface_create_in_error (status);
}
} else {
surface = _cairo_surface_create_similar_solid (target,
CAIRO_CONTENT_ALPHA,
clip->extents.width,
clip->extents.height,
CAIRO_COLOR_WHITE);
if (unlikely (surface->status))
return surface;
}
copy = _cairo_clip_copy_with_translation (clip,
-clip->extents.x,
-clip->extents.y);
copy_path = copy->path;
copy->path = NULL;
region = copy;
if (! _cairo_clip_is_region (copy))
region = _cairo_clip_copy_region (copy);
status = CAIRO_STATUS_SUCCESS;
clip_path = copy_path;
while (status == CAIRO_STATUS_SUCCESS && clip_path) {
status = _cairo_surface_fill (surface,
CAIRO_OPERATOR_IN,
&_cairo_pattern_white.base,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias,
region);
clip_path = clip_path->prev;
}
copy->path = copy_path;
_cairo_clip_destroy (copy);
if (region != copy)
_cairo_clip_destroy (region);
if (unlikely (status)) {
cairo_surface_destroy (surface);
return _cairo_surface_create_in_error (status);
}
*tx = clip->extents.x;
*ty = clip->extents.y;
return surface;
}
cairo_surface_t *
_cairo_clip_get_image (const cairo_clip_t *clip,
cairo_surface_t *target,
const cairo_rectangle_int_t *extents)
{
cairo_surface_t *surface;
cairo_status_t status;
surface = cairo_surface_create_similar_image (target,
CAIRO_FORMAT_A8,
extents->width,
extents->height);
if (unlikely (surface->status))
return surface;
status = _cairo_surface_paint (surface, CAIRO_OPERATOR_SOURCE,
&_cairo_pattern_white.base, NULL);
if (likely (status == CAIRO_STATUS_SUCCESS))
status = _cairo_clip_combine_with_surface (clip, surface,
extents->x, extents->y);
if (unlikely (status)) {
cairo_surface_destroy (surface);
surface = _cairo_surface_create_in_error (status);
}
return surface;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,838 @@
/* -*- 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 © 2005 Red Hat, Inc.
* Copyright © 2009 Chris Wilson
*
* 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.
*
* 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>
* Kristian Høgsberg <krh@redhat.com>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-clip-inline.h"
#include "cairo-clip-private.h"
#include "cairo-error-private.h"
#include "cairo-freed-pool-private.h"
#include "cairo-gstate-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-pattern-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-region-private.h"
static freed_pool_t clip_path_pool;
static freed_pool_t clip_pool;
const cairo_clip_t __cairo_clip_all;
static cairo_clip_path_t *
_cairo_clip_path_create (cairo_clip_t *clip)
{
cairo_clip_path_t *clip_path;
clip_path = _freed_pool_get (&clip_path_pool);
if (unlikely (clip_path == NULL)) {
clip_path = malloc (sizeof (cairo_clip_path_t));
if (unlikely (clip_path == NULL))
return NULL;
}
CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1);
clip_path->prev = clip->path;
clip->path = clip_path;
return clip_path;
}
cairo_clip_path_t *
_cairo_clip_path_reference (cairo_clip_path_t *clip_path)
{
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
_cairo_reference_count_inc (&clip_path->ref_count);
return clip_path;
}
void
_cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
{
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count))
return;
_cairo_path_fixed_fini (&clip_path->path);
if (clip_path->prev != NULL)
_cairo_clip_path_destroy (clip_path->prev);
_freed_pool_put (&clip_path_pool, clip_path);
}
cairo_clip_t *
_cairo_clip_create (void)
{
cairo_clip_t *clip;
clip = _freed_pool_get (&clip_pool);
if (unlikely (clip == NULL)) {
clip = malloc (sizeof (cairo_clip_t));
if (unlikely (clip == NULL))
return NULL;
}
clip->extents = _cairo_unbounded_rectangle;
clip->path = NULL;
clip->boxes = NULL;
clip->num_boxes = 0;
clip->region = NULL;
clip->is_region = FALSE;
return clip;
}
void
_cairo_clip_destroy (cairo_clip_t *clip)
{
if (clip == NULL || _cairo_clip_is_all_clipped (clip))
return;
if (clip->path != NULL)
_cairo_clip_path_destroy (clip->path);
if (clip->boxes != &clip->embedded_box)
free (clip->boxes);
cairo_region_destroy (clip->region);
_freed_pool_put (&clip_pool, clip);
}
cairo_clip_t *
_cairo_clip_copy (const cairo_clip_t *clip)
{
cairo_clip_t *copy;
if (clip == NULL || _cairo_clip_is_all_clipped (clip))
return (cairo_clip_t *) clip;
copy = _cairo_clip_create ();
if (clip->path)
copy->path = _cairo_clip_path_reference (clip->path);
if (clip->num_boxes) {
if (clip->num_boxes == 1) {
copy->boxes = &copy->embedded_box;
} else {
copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
if (unlikely (copy->boxes == NULL))
return _cairo_clip_set_all_clipped (copy);
}
memcpy (copy->boxes, clip->boxes,
clip->num_boxes * sizeof (cairo_box_t));
copy->num_boxes = clip->num_boxes;
}
copy->extents = clip->extents;
copy->region = cairo_region_reference (clip->region);
copy->is_region = clip->is_region;
return copy;
}
cairo_clip_t *
_cairo_clip_copy_path (const cairo_clip_t *clip)
{
cairo_clip_t *copy;
if (clip == NULL || _cairo_clip_is_all_clipped (clip))
return (cairo_clip_t *) clip;
assert (clip->num_boxes);
copy = _cairo_clip_create ();
copy->extents = clip->extents;
if (clip->path)
copy->path = _cairo_clip_path_reference (clip->path);
return copy;
}
cairo_clip_t *
_cairo_clip_copy_region (const cairo_clip_t *clip)
{
cairo_clip_t *copy;
int i;
if (clip == NULL || _cairo_clip_is_all_clipped (clip))
return (cairo_clip_t *) clip;
assert (clip->num_boxes);
copy = _cairo_clip_create ();
copy->extents = clip->extents;
if (clip->num_boxes == 1) {
copy->boxes = &copy->embedded_box;
} else {
copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
if (unlikely (copy->boxes == NULL))
return _cairo_clip_set_all_clipped (copy);
}
for (i = 0; i < clip->num_boxes; i++) {
copy->boxes[i].p1.x = _cairo_fixed_floor (clip->boxes[i].p1.x);
copy->boxes[i].p1.y = _cairo_fixed_floor (clip->boxes[i].p1.y);
copy->boxes[i].p2.x = _cairo_fixed_ceil (clip->boxes[i].p2.x);
copy->boxes[i].p2.y = _cairo_fixed_ceil (clip->boxes[i].p2.y);
}
copy->num_boxes = clip->num_boxes;
copy->region = cairo_region_reference (clip->region);
copy->is_region = TRUE;
return copy;
}
cairo_clip_t *
_cairo_clip_intersect_path (cairo_clip_t *clip,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_clip_path_t *clip_path;
cairo_status_t status;
cairo_rectangle_int_t extents;
cairo_box_t box;
if (_cairo_clip_is_all_clipped (clip))
return clip;
/* catch the empty clip path */
if (_cairo_path_fixed_fill_is_empty (path))
return _cairo_clip_set_all_clipped (clip);
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_clip_intersect_box (clip, &box);
}
if (_cairo_path_fixed_fill_is_rectilinear (path))
return _cairo_clip_intersect_rectilinear_path (clip, path,
fill_rule, antialias);
_cairo_path_fixed_approximate_clip_extents (path, &extents);
if (extents.width == 0 || extents.height == 0)
return _cairo_clip_set_all_clipped (clip);
clip = _cairo_clip_intersect_rectangle (clip, &extents);
if (_cairo_clip_is_all_clipped (clip))
return clip;
clip_path = _cairo_clip_path_create (clip);
if (unlikely (clip_path == NULL))
return _cairo_clip_set_all_clipped (clip);
status = _cairo_path_fixed_init_copy (&clip_path->path, path);
if (unlikely (status))
return _cairo_clip_set_all_clipped (clip);
clip_path->fill_rule = fill_rule;
clip_path->tolerance = tolerance;
clip_path->antialias = antialias;
if (clip->region) {
cairo_region_destroy (clip->region);
clip->region = NULL;
}
clip->is_region = FALSE;
return clip;
}
static cairo_clip_t *
_cairo_clip_intersect_clip_path (cairo_clip_t *clip,
const cairo_clip_path_t *clip_path)
{
if (clip_path->prev)
clip = _cairo_clip_intersect_clip_path (clip, clip_path->prev);
return _cairo_clip_intersect_path (clip,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias);
}
cairo_clip_t *
_cairo_clip_intersect_clip (cairo_clip_t *clip,
const cairo_clip_t *other)
{
if (_cairo_clip_is_all_clipped (clip))
return clip;
if (other == NULL)
return clip;
if (clip == NULL)
return _cairo_clip_copy (other);
if (_cairo_clip_is_all_clipped (other))
return _cairo_clip_set_all_clipped (clip);
if (! _cairo_rectangle_intersect (&clip->extents, &other->extents))
return _cairo_clip_set_all_clipped (clip);
if (other->num_boxes) {
cairo_boxes_t boxes;
_cairo_boxes_init_for_array (&boxes, other->boxes, other->num_boxes);
clip = _cairo_clip_intersect_boxes (clip, &boxes);
}
if (! _cairo_clip_is_all_clipped (clip)) {
if (other->path) {
if (clip->path == NULL)
clip->path = _cairo_clip_path_reference (other->path);
else
clip = _cairo_clip_intersect_clip_path (clip, other->path);
}
}
if (clip->region) {
cairo_region_destroy (clip->region);
clip->region = NULL;
}
clip->is_region = FALSE;
return clip;
}
cairo_bool_t
_cairo_clip_equal (const cairo_clip_t *clip_a,
const cairo_clip_t *clip_b)
{
const cairo_clip_path_t *cp_a, *cp_b;
/* are both all-clipped or no-clip? */
if (clip_a == clip_b)
return TRUE;
/* or just one of them? */
if (clip_a == NULL || clip_b == NULL ||
_cairo_clip_is_all_clipped (clip_a) ||
_cairo_clip_is_all_clipped (clip_b))
{
return FALSE;
}
/* We have a pair of normal clips, check their contents */
if (clip_a->num_boxes != clip_b->num_boxes)
return FALSE;
if (memcmp (clip_a->boxes, clip_b->boxes,
sizeof (cairo_box_t) * clip_a->num_boxes))
return FALSE;
cp_a = clip_a->path;
cp_b = clip_b->path;
while (cp_a && cp_b) {
if (cp_a == cp_b)
return TRUE;
/* XXX compare reduced polygons? */
if (cp_a->antialias != cp_b->antialias)
return FALSE;
if (cp_a->tolerance != cp_b->tolerance)
return FALSE;
if (cp_a->fill_rule != cp_b->fill_rule)
return FALSE;
if (! _cairo_path_fixed_equal (&cp_a->path,
&cp_b->path))
return FALSE;
cp_a = cp_a->prev;
cp_b = cp_b->prev;
}
return cp_a == NULL && cp_b == NULL;
}
static cairo_clip_t *
_cairo_clip_path_copy_with_translation (cairo_clip_t *clip,
cairo_clip_path_t *other_path,
int fx, int fy)
{
cairo_status_t status;
cairo_clip_path_t *clip_path;
if (other_path->prev != NULL)
clip = _cairo_clip_path_copy_with_translation (clip, other_path->prev,
fx, fy);
if (_cairo_clip_is_all_clipped (clip))
return clip;
clip_path = _cairo_clip_path_create (clip);
if (unlikely (clip_path == NULL))
return _cairo_clip_set_all_clipped (clip);
status = _cairo_path_fixed_init_copy (&clip_path->path,
&other_path->path);
if (unlikely (status))
return _cairo_clip_set_all_clipped (clip);
_cairo_path_fixed_translate (&clip_path->path, fx, fy);
clip_path->fill_rule = other_path->fill_rule;
clip_path->tolerance = other_path->tolerance;
clip_path->antialias = other_path->antialias;
return clip;
}
cairo_clip_t *
_cairo_clip_translate (cairo_clip_t *clip, int tx, int ty)
{
int fx, fy, i;
cairo_clip_path_t *clip_path;
if (clip == NULL || _cairo_clip_is_all_clipped (clip))
return clip;
if (tx == 0 && ty == 0)
return clip;
fx = _cairo_fixed_from_int (tx);
fy = _cairo_fixed_from_int (ty);
for (i = 0; i < clip->num_boxes; i++) {
clip->boxes[i].p1.x += fx;
clip->boxes[i].p2.x += fx;
clip->boxes[i].p1.y += fy;
clip->boxes[i].p2.y += fy;
}
clip->extents.x += tx;
clip->extents.y += ty;
if (clip->path == NULL)
return clip;
clip_path = clip->path;
clip->path = NULL;
clip = _cairo_clip_path_copy_with_translation (clip, clip_path, fx, fy);
_cairo_clip_path_destroy (clip_path);
return clip;
}
static cairo_status_t
_cairo_path_fixed_add_box (cairo_path_fixed_t *path,
const cairo_box_t *box)
{
cairo_status_t status;
status = _cairo_path_fixed_move_to (path, box->p1.x, box->p1.y);
if (unlikely (status))
return status;
status = _cairo_path_fixed_line_to (path, box->p2.x, box->p1.y);
if (unlikely (status))
return status;
status = _cairo_path_fixed_line_to (path, box->p2.x, box->p2.y);
if (unlikely (status))
return status;
status = _cairo_path_fixed_line_to (path, box->p1.x, box->p2.y);
if (unlikely (status))
return status;
return _cairo_path_fixed_close_path (path);
}
static cairo_status_t
_cairo_path_fixed_init_from_boxes (cairo_path_fixed_t *path,
const cairo_boxes_t *boxes)
{
cairo_status_t status;
const struct _cairo_boxes_chunk *chunk;
int i;
_cairo_path_fixed_init (path);
if (boxes->num_boxes == 0)
return CAIRO_STATUS_SUCCESS;
for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
status = _cairo_path_fixed_add_box (path, &chunk->base[i]);
if (unlikely (status)) {
_cairo_path_fixed_fini (path);
return status;
}
}
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_clip_t *
_cairo_clip_intersect_clip_path_transformed (cairo_clip_t *clip,
const cairo_clip_path_t *clip_path,
const cairo_matrix_t *m)
{
cairo_path_fixed_t path;
if (clip_path->prev)
clip = _cairo_clip_intersect_clip_path_transformed (clip,
clip_path->prev,
m);
if (_cairo_path_fixed_init_copy (&path, &clip_path->path))
return _cairo_clip_set_all_clipped (clip);
_cairo_path_fixed_transform (&path, m);
clip = _cairo_clip_intersect_path (clip,
&path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias);
_cairo_path_fixed_fini (&path);
return clip;
}
cairo_clip_t *
_cairo_clip_transform (cairo_clip_t *clip, const cairo_matrix_t *m)
{
cairo_clip_t *copy;
if (clip == NULL || _cairo_clip_is_all_clipped (clip))
return clip;
if (_cairo_matrix_is_translation (m))
return _cairo_clip_translate (clip, m->x0, m->y0);
copy = _cairo_clip_create ();
if (clip->num_boxes) {
cairo_path_fixed_t path;
cairo_boxes_t boxes;
_cairo_boxes_init_for_array (&boxes, clip->boxes, clip->num_boxes);
_cairo_path_fixed_init_from_boxes (&path, &boxes);
_cairo_path_fixed_transform (&path, m);
copy = _cairo_clip_intersect_path (copy, &path,
CAIRO_FILL_RULE_WINDING,
0.1,
CAIRO_ANTIALIAS_DEFAULT);
_cairo_path_fixed_fini (&path);
}
if (clip->path)
copy = _cairo_clip_intersect_clip_path_transformed (copy, clip->path,m);
_cairo_clip_destroy (clip);
return copy;
}
cairo_clip_t *
_cairo_clip_copy_with_translation (const cairo_clip_t *clip, int tx, int ty)
{
cairo_clip_t *copy;
int fx, fy, i;
if (clip == NULL || _cairo_clip_is_all_clipped (clip))
return (cairo_clip_t *)clip;
if (tx == 0 && ty == 0)
return _cairo_clip_copy (clip);
copy = _cairo_clip_create ();
if (copy == NULL)
return _cairo_clip_set_all_clipped (copy);
fx = _cairo_fixed_from_int (tx);
fy = _cairo_fixed_from_int (ty);
if (clip->num_boxes) {
if (clip->num_boxes == 1) {
copy->boxes = &copy->embedded_box;
} else {
copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
if (unlikely (copy->boxes == NULL))
return _cairo_clip_set_all_clipped (copy);
}
for (i = 0; i < clip->num_boxes; i++) {
copy->boxes[i].p1.x = clip->boxes[i].p1.x + fx;
copy->boxes[i].p2.x = clip->boxes[i].p2.x + fx;
copy->boxes[i].p1.y = clip->boxes[i].p1.y + fy;
copy->boxes[i].p2.y = clip->boxes[i].p2.y + fy;
}
copy->num_boxes = clip->num_boxes;
}
copy->extents = clip->extents;
copy->extents.x += tx;
copy->extents.y += ty;
if (clip->path == NULL)
return copy;
return _cairo_clip_path_copy_with_translation (copy, clip->path, fx, fy);
}
cairo_bool_t
_cairo_clip_contains_extents (const cairo_clip_t *clip,
const cairo_composite_rectangles_t *extents)
{
const cairo_rectangle_int_t *rect;
rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
return _cairo_clip_contains_rectangle (clip, rect);
}
void
_cairo_debug_print_clip (FILE *stream, const cairo_clip_t *clip)
{
int i;
if (clip == NULL) {
fprintf (stream, "no clip\n");
return;
}
if (_cairo_clip_is_all_clipped (clip)) {
fprintf (stream, "clip: all-clipped\n");
return;
}
fprintf (stream, "clip:\n");
fprintf (stream, " extents: (%d, %d) x (%d, %d), is-region? %d",
clip->extents.x, clip->extents.y,
clip->extents.width, clip->extents.height,
clip->is_region);
fprintf (stream, " num_boxes = %d\n", clip->num_boxes);
for (i = 0; i < clip->num_boxes; i++) {
fprintf (stream, " [%d] = (%f, %f), (%f, %f)\n", i,
_cairo_fixed_to_double (clip->boxes[i].p1.x),
_cairo_fixed_to_double (clip->boxes[i].p1.y),
_cairo_fixed_to_double (clip->boxes[i].p2.x),
_cairo_fixed_to_double (clip->boxes[i].p2.y));
}
if (clip->path) {
cairo_clip_path_t *clip_path = clip->path;
do {
fprintf (stream, "path: aa=%d, tolerance=%f, rule=%d: ",
clip_path->antialias,
clip_path->tolerance,
clip_path->fill_rule);
_cairo_debug_print_path (stream, &clip_path->path);
fprintf (stream, "\n");
} while ((clip_path = clip_path->prev) != NULL);
}
}
const cairo_rectangle_int_t *
_cairo_clip_get_extents (const cairo_clip_t *clip)
{
if (clip == NULL)
return &_cairo_unbounded_rectangle;
if (_cairo_clip_is_all_clipped (clip))
return &_cairo_empty_rectangle;
return &clip->extents;
}
const cairo_rectangle_list_t _cairo_rectangles_nil =
{ CAIRO_STATUS_NO_MEMORY, NULL, 0 };
static const cairo_rectangle_list_t _cairo_rectangles_not_representable =
{ CAIRO_STATUS_CLIP_NOT_REPRESENTABLE, NULL, 0 };
static cairo_bool_t
_cairo_clip_int_rect_to_user (cairo_gstate_t *gstate,
cairo_rectangle_int_t *clip_rect,
cairo_rectangle_t *user_rect)
{
cairo_bool_t is_tight;
double x1 = clip_rect->x;
double y1 = clip_rect->y;
double x2 = clip_rect->x + (int) clip_rect->width;
double y2 = clip_rect->y + (int) clip_rect->height;
_cairo_gstate_backend_to_user_rectangle (gstate,
&x1, &y1, &x2, &y2,
&is_tight);
user_rect->x = x1;
user_rect->y = y1;
user_rect->width = x2 - x1;
user_rect->height = y2 - y1;
return is_tight;
}
cairo_rectangle_list_t *
_cairo_rectangle_list_create_in_error (cairo_status_t status)
{
cairo_rectangle_list_t *list;
if (status == CAIRO_STATUS_NO_MEMORY)
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
if (status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
list = malloc (sizeof (*list));
if (unlikely (list == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
}
list->status = status;
list->rectangles = NULL;
list->num_rectangles = 0;
return list;
}
cairo_rectangle_list_t *
_cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
{
#define ERROR_LIST(S) _cairo_rectangle_list_create_in_error (_cairo_error (S))
cairo_rectangle_list_t *list;
cairo_rectangle_t *rectangles = NULL;
cairo_region_t *region = NULL;
int n_rects = 0;
int i;
if (clip == NULL)
return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
if (_cairo_clip_is_all_clipped (clip))
goto DONE;
if (! _cairo_clip_is_region (clip))
return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
region = _cairo_clip_get_region (clip);
if (region == NULL)
return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
n_rects = cairo_region_num_rectangles (region);
if (n_rects) {
rectangles = _cairo_malloc_ab (n_rects, sizeof (cairo_rectangle_t));
if (unlikely (rectangles == NULL)) {
return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
}
for (i = 0; i < n_rects; ++i) {
cairo_rectangle_int_t clip_rect;
cairo_region_get_rectangle (region, i, &clip_rect);
if (! _cairo_clip_int_rect_to_user (gstate,
&clip_rect,
&rectangles[i]))
{
free (rectangles);
return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
}
}
}
DONE:
list = malloc (sizeof (cairo_rectangle_list_t));
if (unlikely (list == NULL)) {
free (rectangles);
return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
}
list->status = CAIRO_STATUS_SUCCESS;
list->rectangles = rectangles;
list->num_rectangles = n_rects;
return list;
#undef ERROR_LIST
}
/**
* cairo_rectangle_list_destroy:
* @rectangle_list: a rectangle list, as obtained from cairo_copy_clip_rectangle_list()
*
* Unconditionally frees @rectangle_list and all associated
* references. After this call, the @rectangle_list pointer must not
* be dereferenced.
*
* Since: 1.4
**/
void
cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list)
{
if (rectangle_list == NULL || rectangle_list == &_cairo_rectangles_nil ||
rectangle_list == &_cairo_rectangles_not_representable)
return;
free (rectangle_list->rectangles);
free (rectangle_list);
}
void
_cairo_clip_reset_static_data (void)
{
_freed_pool_reset (&clip_path_pool);
_freed_pool_reset (&clip_pool);
}

View File

@@ -0,0 +1,52 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2011 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.og/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):
* Robert Bragg <robert@linux.intel.com>
*/
#ifndef CAIRO_COGL_CONTEXT_PRIVATE_H
#define CAIRO_COGL_CONTEXT_PRIVATE_H
#include "cairo-default-context-private.h"
#include "cairo-cogl-private.h"
typedef struct _cairo_cogl_context {
cairo_default_context_t base;
cairo_cogl_device_t *dev;
int path_ctm_age;
cairo_path_fixed_t user_path;
cairo_bool_t path_is_rectangle;
double x, y, width, height;
} cairo_cogl_context_t;
cairo_t *
_cairo_cogl_context_create (void *target);
#endif /* CAIRO_COGL_CONTEXT_PRIVATE_H */

View File

@@ -0,0 +1,822 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2011 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.og/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):
* Robert Bragg <robert@linux.intel.com>
*/
/* so long as we can verify that the ctm doesn't change multiple times
* during the construction of a path we can build a shadow
* #cairo_path_fixed_t in user coordinates that we can use to create a
* hash value for caching tessellations of that path.
*
* We need to hook into all the points where the ctm can be changed
* so we can bump a cr->path_ctm_age counter.
*
* We need to hook into all the points where the path can be modified
* so we can catch the start of a path and reset the cr->path_ctm_age
* counter at that point.
*
* When a draw operation is hit we can then check that the
* path_ctm_age == 0 and if so we create a hash of the path.
*
* We use this hash to lookup a #cairo_cogl_path_meta_t struct which
* may contain tessellated triangles for the path or may just contain
* a count of how many times the path has been re-seen (we only cache
* tessellated triangles if there is evidence that the path is being
* used multiple times because there is a cost involved in allocating
* a separate buffer for the triangles).
*/
#include "cairoint.h"
#include "cairo-cogl-context-private.h"
#include "cairo-freed-pool-private.h"
#include "cairo-arc-private.h"
#include "cairo-path-fixed-private.h"
#include <glib.h>
static freed_pool_t context_pool;
void
_cairo_cogl_context_reset_static_data (void)
{
_freed_pool_reset (&context_pool);
}
static cairo_status_t
_cairo_cogl_context_rectangle_real (cairo_cogl_context_t *cr,
double x, double y,
double width, double height)
{
cairo_status_t status;
status = cr->dev->backend_parent.rectangle (cr, x, y, width, height);
if (unlikely (status))
return status;
return _cairo_cogl_path_fixed_rectangle (&cr->user_path,
_cairo_fixed_from_double (x),
_cairo_fixed_from_double (y),
_cairo_fixed_from_double (width),
_cairo_fixed_from_double (height));
}
/* The idea here is that we have a simplified way of tracking rectangle paths
* because rectangles are perhaps the most common shape drawn with cairo.
*
* Basically we have a speculative store for a rectangle path that doesn't
* need to use the #cairo_path_fixed_t api to describe a rectangle in terms of
* (move_to,rel_line_to,rel_line_to,_rel_line_to,close) because if you profile
* heavy rectangle drawing with Cairo that process can be overly expensive.
*
* If the user asks to add more than just a rectangle to their current path
* then we "flush" any speculative rectangle stored into the current path
* before continuing to append their operations.
*
* In addition to the speculative store cairo-cogl also has a fast-path
* fill_rectangle drawing operation that further aims to minimize the cost
* of drawing rectangles.
*/
static cairo_status_t
_flush_cr_rectangle (cairo_cogl_context_t *cr)
{
if (!cr->path_is_rectangle)
return CAIRO_STATUS_SUCCESS;
cr->path_is_rectangle = FALSE;
return _cairo_cogl_context_rectangle_real (cr, cr->x, cr->y, cr->width, cr->height);
}
static cairo_status_t
_cairo_cogl_context_restore (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
if (cr->path_is_rectangle) {
cairo_status_t status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
cr->path_ctm_age++;
return cr->dev->backend_parent.restore (abstract_cr);
}
static cairo_status_t
_cairo_cogl_context_translate (void *abstract_cr, double tx, double ty)
{
cairo_cogl_context_t *cr = abstract_cr;
if (cr->path_is_rectangle) {
cairo_status_t status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
cr->path_ctm_age++;
return cr->dev->backend_parent.translate (abstract_cr, tx, ty);
}
static cairo_status_t
_cairo_cogl_context_scale (void *abstract_cr, double sx, double sy)
{
cairo_cogl_context_t *cr = abstract_cr;
if (cr->path_is_rectangle) {
cairo_status_t status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
cr->path_ctm_age++;
return cr->dev->backend_parent.scale (abstract_cr, sx, sy);
}
static cairo_status_t
_cairo_cogl_context_rotate (void *abstract_cr, double theta)
{
cairo_cogl_context_t *cr = abstract_cr;
if (cr->path_is_rectangle) {
cairo_status_t status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
cr->path_ctm_age++;
return cr->dev->backend_parent.rotate (abstract_cr, theta);
}
static cairo_status_t
_cairo_cogl_context_transform (void *abstract_cr, const cairo_matrix_t *matrix)
{
cairo_cogl_context_t *cr = abstract_cr;
if (cr->path_is_rectangle) {
cairo_status_t status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
cr->path_ctm_age++;
return cr->dev->backend_parent.transform (abstract_cr, matrix);
}
static cairo_status_t
_cairo_cogl_context_set_matrix (void *abstract_cr, const cairo_matrix_t *matrix)
{
cairo_cogl_context_t *cr = abstract_cr;
if (cr->path_is_rectangle) {
cairo_status_t status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
cr->path_ctm_age++;
return cr->dev->backend_parent.set_matrix (abstract_cr, matrix);
}
static cairo_status_t
_cairo_cogl_context_set_identity_matrix (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
if (cr->path_is_rectangle) {
cairo_status_t status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
cr->path_ctm_age++;
return cr->dev->backend_parent.set_identity_matrix (abstract_cr);
}
static cairo_status_t
_cairo_cogl_context_new_path (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
status = cr->dev->backend_parent.new_path (abstract_cr);
if (unlikely (status))
return status;
_cairo_path_fixed_fini (&cr->user_path);
_cairo_path_fixed_init (&cr->user_path);
cr->path_is_rectangle = FALSE;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_cogl_context_new_sub_path (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
status = cr->dev->backend_parent.new_sub_path (abstract_cr);
if (unlikely (status))
return status;
_cairo_path_fixed_new_sub_path (&cr->user_path);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_cogl_context_move_to (void *abstract_cr, double x, double y)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
cairo_fixed_t x_fixed, y_fixed;
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
status = cr->dev->backend_parent.move_to (abstract_cr, x, y);
if (unlikely (status))
return status;
x_fixed = _cairo_fixed_from_double (x);
y_fixed = _cairo_fixed_from_double (y);
return _cairo_path_fixed_move_to (&cr->user_path, x_fixed, y_fixed);
}
static cairo_status_t
_cairo_cogl_context_line_to (void *abstract_cr, double x, double y)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
cairo_fixed_t x_fixed, y_fixed;
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
status = cr->dev->backend_parent.line_to (abstract_cr, x, y);
if (unlikely (status))
return status;
x_fixed = _cairo_fixed_from_double (x);
y_fixed = _cairo_fixed_from_double (y);
if (cr->user_path.buf.base.num_ops == 0)
cr->path_ctm_age = 0;
return _cairo_path_fixed_line_to (&cr->user_path, x_fixed, y_fixed);
}
static cairo_status_t
_cairo_cogl_context_curve_to (void *abstract_cr,
double x1, double y1,
double x2, double y2,
double x3, double y3)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
cairo_fixed_t x1_fixed, y1_fixed;
cairo_fixed_t x2_fixed, y2_fixed;
cairo_fixed_t x3_fixed, y3_fixed;
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
status = cr->dev->backend_parent.curve_to (abstract_cr, x1, y1, x2, y2, x3, y3);
if (unlikely (status))
return status;
x1_fixed = _cairo_fixed_from_double (x1);
y1_fixed = _cairo_fixed_from_double (y1);
x2_fixed = _cairo_fixed_from_double (x2);
y2_fixed = _cairo_fixed_from_double (y2);
x3_fixed = _cairo_fixed_from_double (x3);
y3_fixed = _cairo_fixed_from_double (y3);
if (cr->user_path.buf.base.num_ops == 0)
cr->path_ctm_age = 0;
return _cairo_path_fixed_curve_to (&cr->user_path,
x1_fixed, y1_fixed,
x2_fixed, y2_fixed,
x3_fixed, y3_fixed);
}
static cairo_status_t
_cairo_cogl_context_arc (void *abstract_cr,
double xc, double yc, double radius,
double angle1, double angle2,
cairo_bool_t forward)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
status = cr->dev->backend_parent.arc (abstract_cr, xc, yc, radius, angle1, angle2, forward);
if (unlikely (status))
return status;
if (cr->user_path.buf.base.num_ops == 0)
cr->path_ctm_age = 0;
/* Do nothing, successfully, if radius is <= 0 */
if (radius <= 0.0) {
cairo_fixed_t x_fixed, y_fixed;
x_fixed = _cairo_fixed_from_double (xc);
y_fixed = _cairo_fixed_from_double (yc);
status = _cairo_path_fixed_line_to (&cr->user_path, x_fixed, y_fixed);
if (unlikely (status))
return status;
status = _cairo_path_fixed_line_to (&cr->user_path, x_fixed, y_fixed);
if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_cogl_context_line_to (cr,
xc + radius * cos (angle1),
yc + radius * sin (angle1));
if (unlikely (status))
return status;
if (forward)
_cairo_arc_path (&cr->base.base, xc, yc, radius, angle1, angle2);
else
_cairo_arc_path_negative (&cr->base.base, xc, yc, radius, angle1, angle2);
return CAIRO_STATUS_SUCCESS; /* any error will have already been set on cr */
}
static cairo_status_t
_cairo_cogl_context_rel_move_to (void *abstract_cr, double dx, double dy)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
cairo_fixed_t dx_fixed, dy_fixed;
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
status = cr->dev->backend_parent.rel_move_to (abstract_cr, dx, dy);
if (unlikely (status))
return status;
dx_fixed = _cairo_fixed_from_double (dx);
dy_fixed = _cairo_fixed_from_double (dy);
return _cairo_path_fixed_rel_move_to (&cr->user_path, dx_fixed, dy_fixed);
}
static cairo_status_t
_cairo_cogl_context_rel_line_to (void *abstract_cr, double dx, double dy)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
cairo_fixed_t dx_fixed, dy_fixed;
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
status = cr->dev->backend_parent.rel_line_to (abstract_cr, dx, dy);
if (unlikely (status))
return status;
dx_fixed = _cairo_fixed_from_double (dx);
dy_fixed = _cairo_fixed_from_double (dy);
if (cr->user_path.buf.base.num_ops == 0)
cr->path_ctm_age = 0;
return _cairo_path_fixed_rel_line_to (&cr->user_path, dx_fixed, dy_fixed);
}
static cairo_status_t
_cairo_cogl_context_rel_curve_to (void *abstract_cr,
double dx1, double dy1,
double dx2, double dy2,
double dx3, double dy3)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
cairo_fixed_t dx1_fixed, dy1_fixed;
cairo_fixed_t dx2_fixed, dy2_fixed;
cairo_fixed_t dx3_fixed, dy3_fixed;
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
status = cr->dev->backend_parent.rel_curve_to (abstract_cr, dx1, dy1, dx2, dy2, dx3, dy3);
if (unlikely (status))
return status;
dx1_fixed = _cairo_fixed_from_double (dx1);
dy1_fixed = _cairo_fixed_from_double (dy1);
dx2_fixed = _cairo_fixed_from_double (dx2);
dy2_fixed = _cairo_fixed_from_double (dy2);
dx3_fixed = _cairo_fixed_from_double (dx3);
dy3_fixed = _cairo_fixed_from_double (dy3);
if (cr->user_path.buf.base.num_ops == 0)
cr->path_ctm_age = 0;
return _cairo_path_fixed_rel_curve_to (&cr->user_path,
dx1_fixed, dy1_fixed,
dx2_fixed, dy2_fixed,
dx3_fixed, dy3_fixed);
}
#if 0
static cairo_status_t
_cairo_cogl_context_arc_to (void *abstract_cr,
double x1, double y1,
double x2, double y2,
double radius)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
status = cr->dev->backend_parent.arc_to (abstract_cr, x1, y1, x2, y2, radius);
if (unlikely (status))
return status;
#warning "FIXME"
}
static cairo_status_t
_cairo_cogl_rel_arc_to (void *cr,
double dx1, double dy1,
double dx2, double dy2,
double radius)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
status = cr->dev->backend_parent.rel_arc_to (abstract_cr, dx1, dy2, dx2, dy2, radius);
if (unlikely (status))
return status;
#warning "FIXME"
}
#endif
static cairo_status_t
_cairo_cogl_context_close_path (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
if (cr->path_is_rectangle) {
status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
status = cr->dev->backend_parent.close_path (abstract_cr);
if (unlikely (status))
return status;
if (cr->user_path.buf.base.num_ops == 0)
cr->path_ctm_age = 0;
return _cairo_path_fixed_close_path (&cr->user_path);
}
static cairo_status_t
_cairo_cogl_context_rectangle (void *abstract_cr,
double x, double y,
double width, double height)
{
cairo_cogl_context_t *cr = abstract_cr;
if (cr->user_path.buf.base.num_ops == 0) {
cr->path_ctm_age = 0;
#if 1
/* XXX: Since drawing rectangles is so common we have a
* fast-path for drawing a single rectangle. */
cr->x = x;
cr->y = y;
cr->width = width;
cr->height = height;
cr->path_is_rectangle = TRUE;
return CAIRO_STATUS_SUCCESS;
#endif
}
if (cr->path_is_rectangle) {
cairo_status_t status = _flush_cr_rectangle (cr);
if (unlikely (status))
return status;
}
return _cairo_cogl_context_rectangle_real (cr, x, y, width, height);
}
/* Since the surface backend drawing operator functions don't get
* passed the current #cairo_t context we don't have a good way
* to get our user-coordinates path into our surface operator
* functions.
*
* For now we use this function to set side band data on the surface
* itself.
*/
static void
_cairo_cogl_surface_set_side_band_state (cairo_cogl_surface_t *surface,
cairo_cogl_context_t *cr)
{
if (cr->path_ctm_age <= 1) {
surface->user_path = &cr->user_path;
surface->ctm = &cr->base.gstate->ctm;
surface->ctm_inverse = &cr->base.gstate->ctm_inverse;
surface->path_is_rectangle = cr->path_is_rectangle;
if (surface->path_is_rectangle) {
surface->path_rectangle_x = cr->x;
surface->path_rectangle_y = cr->y;
surface->path_rectangle_width = cr->width;
surface->path_rectangle_height = cr->height;
}
} else {
surface->user_path = NULL;
surface->path_is_rectangle = FALSE;
}
}
static cairo_status_t
_cairo_cogl_context_fill (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)cr->base.gstate->target;
if (cr->path_is_rectangle) {
status = _cairo_cogl_surface_fill_rectangle (cr->base.gstate->target,
cr->base.gstate->op,
cr->base.gstate->source,
cr->x,
cr->y,
cr->width,
cr->height,
&cr->base.gstate->ctm,
cr->base.gstate->clip);
if (status == CAIRO_STATUS_SUCCESS)
goto DONE;
_flush_cr_rectangle (cr);
}
_cairo_cogl_surface_set_side_band_state (surface, cr);
status = cr->dev->backend_parent.fill (abstract_cr);
if (unlikely (status))
return status;
DONE:
_cairo_path_fixed_fini (&cr->user_path);
_cairo_path_fixed_init (&cr->user_path);
cr->path_is_rectangle = FALSE;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_cogl_context_fill_preserve (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)cr->base.gstate->target;
_cairo_cogl_surface_set_side_band_state (surface, cr);
status = cr->dev->backend_parent.fill_preserve (abstract_cr);
if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_cogl_context_stroke (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)cr->base.gstate->target;
_cairo_cogl_surface_set_side_band_state (surface, cr);
status = cr->dev->backend_parent.stroke (abstract_cr);
if (unlikely (status))
return status;
_cairo_path_fixed_fini (&cr->user_path);
_cairo_path_fixed_init (&cr->user_path);
cr->path_is_rectangle = FALSE;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_cogl_context_stroke_preserve (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)cr->base.gstate->target;
_cairo_cogl_surface_set_side_band_state (surface, cr);
status = cr->dev->backend_parent.stroke_preserve (abstract_cr);
if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_cogl_context_clip (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
cairo_status_t status;
status = cr->dev->backend_parent.clip (abstract_cr);
if (unlikely (status))
return status;
_cairo_path_fixed_fini (&cr->user_path);
_cairo_path_fixed_init (&cr->user_path);
cr->path_is_rectangle = FALSE;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_cogl_context_destroy (void *abstract_cr)
{
cairo_cogl_context_t *cr = abstract_cr;
_cairo_default_context_fini (&cr->base);
_cairo_path_fixed_fini (&cr->user_path);
/* mark the context as invalid to protect against misuse */
cr->base.base.status = CAIRO_STATUS_NULL_POINTER;
_freed_pool_put (&context_pool, cr);
}
/* We want to hook into the frontend of the path construction APIs so
* we can build up a path description in user coordinates instead of
* backend coordinates so that we can recognize user coordinate
* rectangles and so we can hash a user path independent of its
* transform. (With some care to catch unusual cases where the ctm
* changes mid-path) */
cairo_t *
_cairo_cogl_context_create (void *target)
{
cairo_cogl_surface_t *surface = target;
cairo_cogl_context_t *cr;
cairo_status_t status;
cr = _freed_pool_get (&context_pool);
if (unlikely (cr == NULL)) {
cr = malloc (sizeof (cairo_cogl_context_t));
if (unlikely (cr == NULL))
return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
status = _cairo_default_context_init (&cr->base, target);
if (unlikely (status)) {
_freed_pool_put (&context_pool, cr);
return _cairo_create_in_error (status);
}
cr->dev = (cairo_cogl_device_t *)surface->base.device;
if (unlikely (cr->dev->backend_vtable_initialized == FALSE)) {
cairo_backend_t *backend = &cr->dev->backend;
memcpy (backend, cr->base.base.backend, sizeof (cairo_backend_t));
memcpy (&cr->dev->backend_parent, cr->base.base.backend, sizeof (cairo_backend_t));
backend->destroy = _cairo_cogl_context_destroy;
backend->restore = _cairo_cogl_context_restore;
backend->translate = _cairo_cogl_context_translate;
backend->scale = _cairo_cogl_context_scale;
backend->rotate = _cairo_cogl_context_rotate;
backend->transform = _cairo_cogl_context_transform;
backend->set_matrix = _cairo_cogl_context_set_matrix;
backend->set_identity_matrix = _cairo_cogl_context_set_identity_matrix;
backend->new_path = _cairo_cogl_context_new_path;
backend->new_sub_path = _cairo_cogl_context_new_sub_path;
backend->move_to = _cairo_cogl_context_move_to;
backend->rel_move_to = _cairo_cogl_context_rel_move_to;
backend->line_to = _cairo_cogl_context_line_to;
backend->rel_line_to = _cairo_cogl_context_rel_line_to;
backend->curve_to = _cairo_cogl_context_curve_to;
backend->rel_curve_to = _cairo_cogl_context_rel_curve_to;
#if 0
backend->arc_to = _cairo_cogl_context_arc_to;
backend->rel_arc_to = _cairo_cogl_context_rel_arc_to;
#endif
backend->close_path = _cairo_cogl_context_close_path;
//backend->arc = _cairo_cogl_context_arc;
backend->rectangle = _cairo_cogl_context_rectangle;
/* Try to automatically catch if any new path APIs are added that mean
* we may need to overload more functions... */
assert (((char *)&backend->path_extents - (char *)&backend->device_to_user_distance)
== (sizeof (void *) * 14));
backend->fill = _cairo_cogl_context_fill;
backend->fill_preserve = _cairo_cogl_context_fill_preserve;
backend->stroke = _cairo_cogl_context_stroke;
backend->stroke_preserve = _cairo_cogl_context_stroke_preserve;
backend->clip = _cairo_cogl_context_clip;
cr->dev->backend_vtable_initialized = TRUE;
}
cr->base.base.backend = &cr->dev->backend;
_cairo_path_fixed_init (&cr->user_path);
cr->path_is_rectangle = FALSE;
return &cr->base.base;
}

View File

@@ -0,0 +1,89 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2011 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.og/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):
* Robert Bragg <robert@linux.intel.com>
*/
#ifndef CAIRO_COGL_GRADIENT_PRIVATE_H
#define CAIRO_COGL_GRADIENT_PRIVATE_H
#include "cairoint.h"
#include "cairo-pattern-private.h"
#include <cogl/cogl2-experimental.h>
#define CAIRO_COGL_LINEAR_GRADIENT_CACHE_SIZE (1024 * 1024)
typedef enum _cairo_cogl_gradient_compatibility {
CAIRO_COGL_GRADIENT_CAN_EXTEND_PAD = 1<<0,
CAIRO_COGL_GRADIENT_CAN_EXTEND_REPEAT = 1<<1,
CAIRO_COGL_GRADIENT_CAN_EXTEND_REFLECT = 1<<2,
CAIRO_COGL_GRADIENT_CAN_EXTEND_NONE = 1<<3
} cairo_cogl_gradient_compatibility_t;
#define CAIRO_COGL_GRADIENT_CAN_EXTEND_ALL (CAIRO_COGL_GRADIENT_CAN_EXTEND_PAD |\
CAIRO_COGL_GRADIENT_CAN_EXTEND_REPEAT|\
CAIRO_COGL_GRADIENT_CAN_EXTEND_REFLECT|\
CAIRO_COGL_GRADIENT_CAN_EXTEND_NONE)
typedef struct _cairo_cogl_linear_texture_entry {
cairo_cogl_gradient_compatibility_t compatibility;
CoglTexture *texture;
float translate_x;
float scale_x;
} cairo_cogl_linear_texture_entry_t;
typedef struct _cairo_cogl_linear_gradient {
cairo_cache_entry_t cache_entry;
cairo_reference_count_t ref_count;
GList *textures;
int n_stops;
const cairo_gradient_stop_t *stops;
cairo_gradient_stop_t stops_embedded[1];
} cairo_cogl_linear_gradient_t;
cairo_int_status_t
_cairo_cogl_get_linear_gradient (cairo_cogl_device_t *context,
cairo_extend_t extend_mode,
int n_stops,
const cairo_gradient_stop_t *stops,
cairo_cogl_linear_gradient_t **gradient_out);
cairo_cogl_linear_texture_entry_t *
_cairo_cogl_linear_gradient_texture_for_extend (cairo_cogl_linear_gradient_t *gradient,
cairo_extend_t extend_mode);
cairo_cogl_linear_gradient_t *
_cairo_cogl_linear_gradient_reference (cairo_cogl_linear_gradient_t *gradient);
void
_cairo_cogl_linear_gradient_destroy (cairo_cogl_linear_gradient_t *gradient);
cairo_bool_t
_cairo_cogl_linear_gradient_equal (const void *key_a, const void *key_b);
#endif /* CAIRO_COGL_GRADIENT_PRIVATE_H */

View File

@@ -0,0 +1,642 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2011 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.og/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):
* Robert Bragg <robert@linux.intel.com>
*/
//#include "cairoint.h"
#include "cairo-cogl-private.h"
#include "cairo-cogl-gradient-private.h"
#include "cairo-image-surface-private.h"
#include <cogl/cogl2-experimental.h>
#include <glib.h>
#define DUMP_GRADIENTS_TO_PNG
static unsigned long
_cairo_cogl_linear_gradient_hash (unsigned int n_stops,
const cairo_gradient_stop_t *stops)
{
return _cairo_hash_bytes (n_stops, stops,
sizeof (cairo_gradient_stop_t) * n_stops);
}
static cairo_cogl_linear_gradient_t *
_cairo_cogl_linear_gradient_lookup (cairo_cogl_device_t *ctx,
unsigned long hash,
unsigned int n_stops,
const cairo_gradient_stop_t *stops)
{
cairo_cogl_linear_gradient_t lookup;
lookup.cache_entry.hash = hash,
lookup.n_stops = n_stops;
lookup.stops = stops;
return _cairo_cache_lookup (&ctx->linear_cache, &lookup.cache_entry);
}
cairo_bool_t
_cairo_cogl_linear_gradient_equal (const void *key_a, const void *key_b)
{
const cairo_cogl_linear_gradient_t *a = key_a;
const cairo_cogl_linear_gradient_t *b = key_b;
if (a->n_stops != b->n_stops)
return FALSE;
return memcmp (a->stops, b->stops, a->n_stops * sizeof (cairo_gradient_stop_t)) == 0;
}
cairo_cogl_linear_gradient_t *
_cairo_cogl_linear_gradient_reference (cairo_cogl_linear_gradient_t *gradient)
{
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&gradient->ref_count));
_cairo_reference_count_inc (&gradient->ref_count);
return gradient;
}
void
_cairo_cogl_linear_gradient_destroy (cairo_cogl_linear_gradient_t *gradient)
{
GList *l;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&gradient->ref_count));
if (! _cairo_reference_count_dec_and_test (&gradient->ref_count))
return;
for (l = gradient->textures; l; l = l->next) {
cairo_cogl_linear_texture_entry_t *entry = l->data;
cogl_object_unref (entry->texture);
free (entry);
}
g_list_free (gradient->textures);
free (gradient);
}
static int
_cairo_cogl_util_next_p2 (int a)
{
int rval = 1;
while (rval < a)
rval <<= 1;
return rval;
}
static float
get_max_color_component_range (const cairo_color_stop_t *color0, const cairo_color_stop_t *color1)
{
float range;
float max = 0;
range = fabs (color0->red - color1->red);
max = MAX (range, max);
range = fabs (color0->green - color1->green);
max = MAX (range, max);
range = fabs (color0->blue - color1->blue);
max = MAX (range, max);
range = fabs (color0->alpha - color1->alpha);
max = MAX (range, max);
return max;
}
static int
_cairo_cogl_linear_gradient_width_for_stops (cairo_extend_t extend,
unsigned int n_stops,
const cairo_gradient_stop_t *stops)
{
unsigned int n;
float max_texels_per_unit_offset = 0;
float total_offset_range;
/* Find the stop pair demanding the most precision because we are
* interpolating the largest color-component range.
*
* From that we can define the relative sizes of all the other
* stop pairs within our texture and thus the overall size.
*
* To determine the maximum number of texels for a given gap we
* look at the range of colors we are expected to interpolate (so
* long as the stop offsets are not degenerate) and we simply
* assume we want one texel for each unique color value possible
* for a one byte-per-component representation.
* XXX: maybe this is overkill and just allowing 128 levels
* instead of 256 would be enough and then we'd rely on the
* bilinear filtering to give the full range.
*
* XXX: potentially we could try and map offsets to pixels to come
* up with a more precise mapping, but we are aiming to cache
* the gradients so we can't make assumptions about how it will be
* scaled in the future.
*/
for (n = 1; n < n_stops; n++) {
float color_range;
float offset_range;
float texels;
float texels_per_unit_offset;
/* note: degenerate stops don't need to be represented in the
* texture but we want to be sure that solid gaps get at least
* one texel and all other gaps get at least 2 texels.
*/
if (stops[n].offset == stops[n-1].offset)
continue;
color_range = get_max_color_component_range (&stops[n].color, &stops[n-1].color);
if (color_range == 0)
texels = 1;
else
texels = MAX (2, 256.0f * color_range);
/* So how many texels would we need to map over the full [0,1]
* gradient range so this gap would have enough texels? ... */
offset_range = stops[n].offset - stops[n - 1].offset;
texels_per_unit_offset = texels / offset_range;
if (texels_per_unit_offset > max_texels_per_unit_offset)
max_texels_per_unit_offset = texels_per_unit_offset;
}
total_offset_range = fabs (stops[n_stops - 1].offset - stops[0].offset);
return max_texels_per_unit_offset * total_offset_range;
}
/* Aim to create gradient textures without an alpha component so we can avoid
* needing to use blending... */
static CoglPixelFormat
_cairo_cogl_linear_gradient_format_for_stops (cairo_extend_t extend,
unsigned int n_stops,
const cairo_gradient_stop_t *stops)
{
unsigned int n;
/* We have to add extra transparent texels to the end of the gradient to
* handle CAIRO_EXTEND_NONE... */
if (extend == CAIRO_EXTEND_NONE)
return COGL_PIXEL_FORMAT_BGRA_8888_PRE;
for (n = 1; n < n_stops; n++) {
if (stops[n].color.alpha != 1.0)
return COGL_PIXEL_FORMAT_BGRA_8888_PRE;
}
return COGL_PIXEL_FORMAT_BGR_888;
}
static cairo_cogl_gradient_compatibility_t
_cairo_cogl_compatibility_from_extend_mode (cairo_extend_t extend_mode)
{
switch (extend_mode)
{
case CAIRO_EXTEND_NONE:
return CAIRO_COGL_GRADIENT_CAN_EXTEND_NONE;
case CAIRO_EXTEND_PAD:
return CAIRO_COGL_GRADIENT_CAN_EXTEND_PAD;
case CAIRO_EXTEND_REPEAT:
return CAIRO_COGL_GRADIENT_CAN_EXTEND_REPEAT;
case CAIRO_EXTEND_REFLECT:
return CAIRO_COGL_GRADIENT_CAN_EXTEND_REFLECT;
}
assert (0); /* not reached */
return CAIRO_EXTEND_NONE;
}
cairo_cogl_linear_texture_entry_t *
_cairo_cogl_linear_gradient_texture_for_extend (cairo_cogl_linear_gradient_t *gradient,
cairo_extend_t extend_mode)
{
GList *l;
cairo_cogl_gradient_compatibility_t compatibility =
_cairo_cogl_compatibility_from_extend_mode (extend_mode);
for (l = gradient->textures; l; l = l->next) {
cairo_cogl_linear_texture_entry_t *entry = l->data;
if (entry->compatibility & compatibility)
return entry;
}
return NULL;
}
static void
color_stop_lerp (const cairo_color_stop_t *c0,
const cairo_color_stop_t *c1,
float factor,
cairo_color_stop_t *dest)
{
/* NB: we always ignore the short members in this file so we don't need to
* worry about initializing them here. */
dest->red = c0->red * (1.0f-factor) + c1->red * factor;
dest->green = c0->green * (1.0f-factor) + c1->green * factor;
dest->blue = c0->blue * (1.0f-factor) + c1->blue * factor;
dest->alpha = c0->alpha * (1.0f-factor) + c1->alpha * factor;
}
static size_t
_cairo_cogl_linear_gradient_size (cairo_cogl_linear_gradient_t *gradient)
{
GList *l;
size_t size = 0;
for (l = gradient->textures; l; l = l->next) {
cairo_cogl_linear_texture_entry_t *entry = l->data;
size += cogl_texture_get_width (entry->texture) * 4;
}
return size;
}
static void
emit_stop (CoglVertexP2C4 **position,
float left,
float right,
const cairo_color_stop_t *left_color,
const cairo_color_stop_t *right_color)
{
CoglVertexP2C4 *p = *position;
guint8 lr = left_color->red * 255;
guint8 lg = left_color->green * 255;
guint8 lb = left_color->blue * 255;
guint8 la = left_color->alpha * 255;
guint8 rr = right_color->red * 255;
guint8 rg = right_color->green * 255;
guint8 rb = right_color->blue * 255;
guint8 ra = right_color->alpha * 255;
p[0].x = left;
p[0].y = 0;
p[0].r = lr; p[0].g = lg; p[0].b = lb; p[0].a = la;
p[1].x = left;
p[1].y = 1;
p[1].r = lr; p[1].g = lg; p[1].b = lb; p[1].a = la;
p[2].x = right;
p[2].y = 1;
p[2].r = rr; p[2].g = rg; p[2].b = rb; p[2].a = ra;
p[3].x = left;
p[3].y = 0;
p[3].r = lr; p[3].g = lg; p[3].b = lb; p[3].a = la;
p[4].x = right;
p[4].y = 1;
p[4].r = rr; p[4].g = rg; p[4].b = rb; p[4].a = ra;
p[5].x = right;
p[5].y = 0;
p[5].r = rr; p[5].g = rg; p[5].b = rb; p[5].a = ra;
*position = &p[6];
}
#ifdef DUMP_GRADIENTS_TO_PNG
static void
dump_gradient_to_png (CoglTexture *texture)
{
cairo_image_surface_t *image = (cairo_image_surface_t *)
cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
cogl_texture_get_width (texture),
cogl_texture_get_height (texture));
CoglPixelFormat format;
static int gradient_id = 0;
char *gradient_name;
if (image->base.status)
return;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
#else
format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
#endif
cogl_texture_get_data (texture,
format,
0,
image->data);
gradient_name = g_strdup_printf ("./gradient%d.png", gradient_id++);
g_print ("writing gradient: %s\n", gradient_name);
cairo_surface_write_to_png ((cairo_surface_t *)image, gradient_name);
g_free (gradient_name);
}
#endif
cairo_int_status_t
_cairo_cogl_get_linear_gradient (cairo_cogl_device_t *device,
cairo_extend_t extend_mode,
int n_stops,
const cairo_gradient_stop_t *stops,
cairo_cogl_linear_gradient_t **gradient_out)
{
unsigned long hash;
cairo_cogl_linear_gradient_t *gradient;
cairo_cogl_linear_texture_entry_t *entry;
cairo_gradient_stop_t *internal_stops;
int stop_offset;
int n_internal_stops;
int n;
cairo_cogl_gradient_compatibility_t compatibilities;
int width;
int left_padding = 0;
cairo_color_stop_t left_padding_color;
int right_padding = 0;
cairo_color_stop_t right_padding_color;
CoglPixelFormat format;
CoglTexture2D *tex;
GError *error = NULL;
int un_padded_width;
CoglHandle offscreen;
cairo_int_status_t status;
int n_quads;
int n_vertices;
float prev;
float right;
CoglVertexP2C4 *vertices;
CoglVertexP2C4 *p;
CoglPrimitive *prim;
hash = _cairo_cogl_linear_gradient_hash (n_stops, stops);
gradient = _cairo_cogl_linear_gradient_lookup (device, hash, n_stops, stops);
if (gradient) {
cairo_cogl_linear_texture_entry_t *entry =
_cairo_cogl_linear_gradient_texture_for_extend (gradient, extend_mode);
if (entry) {
*gradient_out = _cairo_cogl_linear_gradient_reference (gradient);
return CAIRO_INT_STATUS_SUCCESS;
}
}
if (!gradient) {
gradient = malloc (sizeof (cairo_cogl_linear_gradient_t) +
sizeof (cairo_gradient_stop_t) * (n_stops - 1));
if (!gradient)
return CAIRO_INT_STATUS_NO_MEMORY;
CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 1);
/* NB: we update the cache_entry size at the end before
* [re]adding it to the cache. */
gradient->cache_entry.hash = hash;
gradient->textures = NULL;
gradient->n_stops = n_stops;
gradient->stops = gradient->stops_embedded;
memcpy (gradient->stops_embedded, stops, sizeof (cairo_gradient_stop_t) * n_stops);
} else
_cairo_cogl_linear_gradient_reference (gradient);
entry = malloc (sizeof (cairo_cogl_linear_texture_entry_t));
if (!entry) {
status = CAIRO_INT_STATUS_NO_MEMORY;
goto BAIL;
}
compatibilities = _cairo_cogl_compatibility_from_extend_mode (extend_mode);
n_internal_stops = n_stops;
stop_offset = 0;
/* We really need stops covering the full [0,1] range for repeat/reflect
* if we want to use sampler REPEAT/MIRROR wrap modes so we may need
* to add some extra stops... */
if (extend_mode == CAIRO_EXTEND_REPEAT || extend_mode == CAIRO_EXTEND_REFLECT)
{
/* If we don't need any extra stops then actually the texture
* will be shareable for repeat and reflect... */
compatibilities = (CAIRO_COGL_GRADIENT_CAN_EXTEND_REPEAT |
CAIRO_COGL_GRADIENT_CAN_EXTEND_REFLECT);
if (stops[0].offset != 0) {
n_internal_stops++;
stop_offset++;
}
if (stops[n_stops - 1].offset != 1)
n_internal_stops++;
}
internal_stops = alloca (n_internal_stops * sizeof (cairo_gradient_stop_t));
memcpy (&internal_stops[stop_offset], stops, sizeof (cairo_gradient_stop_t) * n_stops);
/* cairo_color_stop_t values are all unpremultiplied but we need to
* interpolate premultiplied colors so we premultiply all the double
* components now. (skipping any extra stops added for repeat/reflect)
*
* Anothing thing to note is that by premultiplying the colors
* early we'll also reduce the range of colors to interpolate
* which can result in smaller gradient textures.
*/
for (n = stop_offset; n < n_stops; n++) {
cairo_color_stop_t *color = &internal_stops[n].color;
color->red *= color->alpha;
color->green *= color->alpha;
color->blue *= color->alpha;
}
if (n_internal_stops != n_stops)
{
if (extend_mode == CAIRO_EXTEND_REPEAT) {
compatibilities &= ~CAIRO_COGL_GRADIENT_CAN_EXTEND_REFLECT;
if (stops[0].offset != 0) {
/* what's the wrap-around distance between the user's end-stops? */
double dx = (1.0 - stops[n_stops - 1].offset) + stops[0].offset;
internal_stops[0].offset = 0;
color_stop_lerp (&stops[0].color,
&stops[n_stops - 1].color,
stops[0].offset / dx,
&internal_stops[0].color);
}
if (stops[n_stops - 1].offset != 1) {
internal_stops[n_internal_stops - 1].offset = 1;
internal_stops[n_internal_stops - 1].color = internal_stops[0].color;
}
} else if (extend_mode == CAIRO_EXTEND_REFLECT) {
compatibilities &= ~CAIRO_COGL_GRADIENT_CAN_EXTEND_REPEAT;
if (stops[0].offset != 0) {
internal_stops[0].offset = 0;
internal_stops[0].color = stops[n_stops - 1].color;
}
if (stops[n_stops - 1].offset != 1) {
internal_stops[n_internal_stops - 1].offset = 1;
internal_stops[n_internal_stops - 1].color = stops[0].color;
}
}
}
stops = internal_stops;
n_stops = n_internal_stops;
width = _cairo_cogl_linear_gradient_width_for_stops (extend_mode, n_stops, stops);
if (extend_mode == CAIRO_EXTEND_PAD) {
/* Here we need to guarantee that the edge texels of our
* texture correspond to the desired padding color so we
* can use CLAMP_TO_EDGE.
*
* For short stop-gaps and especially for degenerate stops
* it's possible that without special consideration the
* user's end stop colors would not be present in our final
* texture.
*
* To handle this we forcibly add two extra padding texels
* at the edges which extend beyond the [0,1] range of the
* gradient itself and we will later report a translate and
* scale transform to compensate for this.
*/
/* XXX: If we consider generating a mipmap for our 1d texture
* at some point then we also need to consider how much
* padding to add to be sure lower mipmap levels still have
* the desired edge color (as opposed to a linear blend with
* other colors of the gradient).
*/
left_padding = 1;
left_padding_color = stops[0].color;
right_padding = 1;
right_padding_color = stops[n_stops - 1].color;
} else if (extend_mode == CAIRO_EXTEND_NONE) {
/* We handle EXTEND_NONE by adding two extra, transparent, texels at
* the ends of the texture and use CLAMP_TO_EDGE.
*
* We add a scale and translate transform so to account for our texels
* extending beyond the [0,1] range. */
left_padding = 1;
left_padding_color.red = 0;
left_padding_color.green = 0;
left_padding_color.blue = 0;
left_padding_color.alpha = 0;
right_padding = 1;
right_padding_color = left_padding_color;
}
/* If we still have stops that don't cover the full [0,1] range
* then we need to define a texture-coordinate scale + translate
* transform to account for that... */
if (stops[n_stops - 1].offset - stops[0].offset < 1) {
float range = stops[n_stops - 1].offset - stops[0].offset;
entry->scale_x = 1.0 / range;
entry->translate_x = -(stops[0].offset * entry->scale_x);
}
width += left_padding + right_padding;
width = _cairo_cogl_util_next_p2 (width);
width = MIN (4096, width); /* lets not go too stupidly big! */
format = _cairo_cogl_linear_gradient_format_for_stops (extend_mode, n_stops, stops);
do {
tex = cogl_texture_2d_new_with_size (device->cogl_context,
width,
1,
format,
&error);
if (!tex)
g_error_free (error);
} while (tex == NULL && width >> 1);
if (!tex) {
status = CAIRO_INT_STATUS_NO_MEMORY;
goto BAIL;
}
entry->texture = COGL_TEXTURE (tex);
entry->compatibility = compatibilities;
un_padded_width = width - left_padding - right_padding;
/* XXX: only when we know the final texture width can we calculate the
* scale and translate factors needed to account for padding... */
if (un_padded_width != width)
entry->scale_x *= (float)un_padded_width / (float)width;
if (left_padding)
entry->translate_x += (entry->scale_x / (float)un_padded_width) * (float)left_padding;
offscreen = cogl_offscreen_new_to_texture (tex);
cogl_push_framebuffer (COGL_FRAMEBUFFER (offscreen));
cogl_ortho (0, width, 1, 0, -1, 100);
cogl_framebuffer_clear4f (COGL_FRAMEBUFFER (offscreen),
COGL_BUFFER_BIT_COLOR,
0, 0, 0, 0);
n_quads = n_stops - 1 + !!left_padding + !!right_padding;
n_vertices = 6 * n_quads;
vertices = alloca (sizeof (CoglVertexP2C4) * n_vertices);
p = vertices;
if (left_padding)
emit_stop (&p, 0, left_padding, &left_padding_color, &left_padding_color);
prev = (float)left_padding;
for (n = 1; n < n_stops; n++) {
right = (float)left_padding + (float)un_padded_width * stops[n].offset;
emit_stop (&p, prev, right, &stops[n-1].color, &stops[n].color);
prev = right;
}
if (right_padding)
emit_stop (&p, prev, width, &right_padding_color, &right_padding_color);
prim = cogl_primitive_new_p2c4 (COGL_VERTICES_MODE_TRIANGLES,
n_vertices,
vertices);
/* Just use this as the simplest way to setup a default pipeline... */
cogl_set_source_color4f (0, 0, 0, 0);
cogl_primitive_draw (prim);
cogl_object_unref (prim);
cogl_pop_framebuffer ();
cogl_object_unref (offscreen);
gradient->textures = g_list_prepend (gradient->textures, entry);
gradient->cache_entry.size = _cairo_cogl_linear_gradient_size (gradient);
#ifdef DUMP_GRADIENTS_TO_PNG
dump_gradient_to_png (COGL_TEXTURE (tex));
#endif
#warning "FIXME:"
/* XXX: it seems the documentation of _cairo_cache_insert isn't true - it
* doesn't handle re-adding the same entry gracefully - the cache will
* just keep on growing and then it will start randomly evicting things
* pointlessly */
/* we ignore errors here and just return an uncached gradient */
if (likely (! _cairo_cache_insert (&device->linear_cache, &gradient->cache_entry)))
_cairo_cogl_linear_gradient_reference (gradient);
*gradient_out = gradient;
return CAIRO_INT_STATUS_SUCCESS;
BAIL:
free (entry);
if (gradient)
_cairo_cogl_linear_gradient_destroy (gradient);
return status;
}

View File

@@ -0,0 +1,164 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2011 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.og/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):
* Robert Bragg <robert@linux.intel.com>
*/
#ifndef CAIRO_COGL_PRIVATE_H
#define CAIRO_COGL_PRIVATE_H
#include "cairo-device-private.h"
#include "cairo-cache-private.h"
#include "cairo-backend-private.h"
#include "cairo-default-context-private.h"
#include "cairo-surface-private.h"
#include <cogl/cogl2-experimental.h>
typedef enum _cairo_cogl_template_type {
CAIRO_COGL_TEMPLATE_TYPE_SOLID,
CAIRO_COGL_TEMPLATE_TYPE_TEXTURE,
CAIRO_COGL_TEMPLATE_TYPE_MASK_SOLID,
CAIRO_COGL_TEMPLATE_TYPE_MASK_TEXTURE,
CAIRO_COGL_TEMPLATE_TYPE_COUNT
} cairo_cogl_template_type;
typedef struct _cairo_cogl_device {
cairo_device_t base;
cairo_bool_t backend_vtable_initialized;
cairo_backend_t backend;
/* We save a copy of all the original backend methods that we override so
* we can chain up...
*/
cairo_backend_t backend_parent;
CoglContext *cogl_context;
CoglTexture *dummy_texture;
/* This is a sparsely filled set of templates because we don't support
* the full range of operators that cairo has. All entries corresponding
* to unsupported operators are NULL.
*
* The CAIRO_OPERATOR_ADD is the operator enum with the highest value that
* we support so we at least cap the size of the array by that.
*
* For each operator we have a template for when we have a solid source
* and another for each texture format that could be used as a source.
*/
CoglPipeline *template_pipelines[CAIRO_OPERATOR_ADD + 1][CAIRO_COGL_TEMPLATE_TYPE_COUNT];
CoglMatrix identity;
/* Caches 1d linear gradient textures */
cairo_cache_t linear_cache;
cairo_cache_t path_fill_staging_cache;
cairo_cache_t path_fill_prim_cache;
cairo_cache_t path_stroke_staging_cache;
cairo_cache_t path_stroke_prim_cache;
} cairo_cogl_device_t;
typedef struct _cairo_cogl_clip_primitives {
cairo_t *clip;
CoglPrimitive **primitives;
} cairo_cogl_clip_primitives_t;
typedef struct _cairo_cogl_surface {
cairo_surface_t base;
CoglPixelFormat cogl_format;
cairo_bool_t ignore_alpha;
/* We currently have 3 basic kinds of Cogl surfaces:
* 1) A light surface simply wrapping a CoglTexture
* 2) A CoglOffscreen framebuffer that implicitly also wraps a CoglTexture
* 3) A CoglOnscreen framebuffer which could potentially be mapped to
* a CoglTexture (e.g. via tfp on X11) but we don't currently do
* that.
*/
CoglTexture *texture;
CoglFramebuffer *framebuffer;
int width;
int height;
GQueue *journal;
CoglAttributeBuffer *buffer_stack;
size_t buffer_stack_size;
size_t buffer_stack_offset;
guint8 *buffer_stack_pointer;
cairo_clip_t *last_clip;
/* A small fifo of recently used cairo_clip_ts paired with CoglPrimitives
* that can be used to mask the stencil buffer. */
GList *clips_fifo;
int n_clip_updates_per_frame;
/* Since the surface backend drawing operator functions don't get
* passed the current cairo_t context we don't have a good way
* to get our user-coordinates path into our surface_fill function.
*
* For now we use our _cairo_cogl_context_fill() wrapper to set this
* side band data on the surface...
*/
cairo_path_fixed_t *user_path;
cairo_matrix_t *ctm;
cairo_matrix_t *ctm_inverse;
cairo_bool_t path_is_rectangle;
double path_rectangle_x;
double path_rectangle_y;
double path_rectangle_width;
double path_rectangle_height;
} cairo_cogl_surface_t;
cairo_status_t
_cairo_cogl_path_fixed_rectangle (cairo_path_fixed_t *path,
cairo_fixed_t x,
cairo_fixed_t y,
cairo_fixed_t width,
cairo_fixed_t height);
cairo_int_status_t
_cairo_cogl_surface_fill_rectangle (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
double x,
double y,
double width,
double height,
cairo_matrix_t *ctm,
const cairo_clip_t *clip);
#endif /* CAIRO_COGL_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,54 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2011 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.og/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):
* Robert Bragg <robert@linux.intel.com>
*/
#ifndef CAIRO_COGL_UTILS_PRIVATE_H
#define CAIRO_COGL_UTILS_PRIVATE_H
#include "cairo-path-fixed-private.h"
#include <cogl/cogl2-experimental.h>
CoglPath *
_cairo_cogl_util_path_from_cairo (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
float tolerance);
int
_cairo_cogl_util_next_p2 (int a);
#define CAIRO_FIXED_ONE_FLOAT ((float)(1 << CAIRO_FIXED_FRAC_BITS))
static inline float
_cairo_cogl_util_fixed_to_float (cairo_fixed_t f)
{
return ((float) f) / CAIRO_FIXED_ONE_FLOAT;
}
#endif /* CAIRO_COGL_UTILS_PRIVATE_H */

View File

@@ -0,0 +1,126 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2011 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.og/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):
* Robert Bragg <robert@linux.intel.com>
*/
#include "cairoint.h"
#include "cairo-cogl-utils-private.h"
#include <cogl/cogl.h>
#include <glib.h>
static cairo_status_t
_cogl_move_to (void *closure,
const cairo_point_t *point)
{
cogl_path_move_to (closure,
_cairo_cogl_util_fixed_to_float (point->x),
_cairo_cogl_util_fixed_to_float (point->y));
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cogl_line_to (void *closure,
const cairo_point_t *point)
{
cogl_path_line_to (closure,
_cairo_cogl_util_fixed_to_float (point->x),
_cairo_cogl_util_fixed_to_float (point->y));
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cogl_curve_to (void *closure,
const cairo_point_t *p0,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
cogl_path_curve_to (closure,
_cairo_cogl_util_fixed_to_float (p0->x),
_cairo_cogl_util_fixed_to_float (p0->y),
_cairo_cogl_util_fixed_to_float (p1->x),
_cairo_cogl_util_fixed_to_float (p1->y),
_cairo_cogl_util_fixed_to_float (p2->x),
_cairo_cogl_util_fixed_to_float (p2->y));
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cogl_close_path (void *closure)
{
cogl_path_close (closure);
return CAIRO_STATUS_SUCCESS;
}
CoglPath *
_cairo_cogl_util_path_from_cairo (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
float tolerance)
{
CoglPath *cogl_path = cogl_path_new ();
cairo_status_t status;
if (fill_rule == CAIRO_FILL_RULE_EVEN_ODD)
cogl_path_set_fill_rule (cogl_path, COGL_PATH_FILL_RULE_EVEN_ODD);
else
cogl_path_set_fill_rule (cogl_path, COGL_PATH_FILL_RULE_NON_ZERO);
#ifdef USE_CAIRO_PATH_FLATTENER
/* XXX: rely on cairo to do path flattening, since it seems Cogl's
* curve_to flattening is much slower */
status = _cairo_path_fixed_interpret_flat (path,
_cogl_move_to,
_cogl_line_to,
_cogl_close_path,
cogl_path,
tolerance);
#else
status = _cairo_path_fixed_interpret (path,
_cogl_move_to,
_cogl_line_to,
_cogl_curve_to,
_cogl_close_path,
cogl_path);
#endif
assert (status == CAIRO_STATUS_SUCCESS);
return cogl_path;
}
int
_cairo_cogl_util_next_p2 (int a)
{
int rval = 1;
while (rval < a)
rval <<= 1;
return rval;
}

View File

@@ -0,0 +1,69 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2011 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
*
* Contributor(s):
* Robert Bragg <robert@linux.intel.com>
*/
#ifndef CAIRO_VG_H
#define CAIRO_VG_H
#include "cairo.h"
#if CAIRO_HAS_COGL_SURFACE
#include <cogl/cogl2-experimental.h>
CAIRO_BEGIN_DECLS
cairo_public cairo_device_t *
cairo_cogl_device_create (CoglContext *context);
cairo_public cairo_surface_t *
cairo_cogl_surface_create (cairo_device_t *device,
CoglFramebuffer *framebuffer);
cairo_public CoglFramebuffer *
cairo_cogl_surface_get_framebuffer (cairo_surface_t *surface);
cairo_public CoglTexture *
cairo_cogl_surface_get_texture (cairo_surface_t *surface);
cairo_public void
cairo_cogl_surface_end_frame (cairo_surface_t *surface);
CAIRO_END_DECLS
#else /* CAIRO_HAS_COGL_SURFACE*/
# error Cairo was not compiled with support for the Cogl backend
#endif /* CAIRO_HAS_COGL_SURFACE*/
#endif /* CAIRO_COGL_H */

View File

@@ -0,0 +1,198 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* 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.
*
* 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>
*/
#include "cairoint.h"
static cairo_color_t const cairo_color_white = {
1.0, 1.0, 1.0, 1.0,
0xffff, 0xffff, 0xffff, 0xffff
};
static cairo_color_t const cairo_color_black = {
0.0, 0.0, 0.0, 1.0,
0x0, 0x0, 0x0, 0xffff
};
static cairo_color_t const cairo_color_transparent = {
0.0, 0.0, 0.0, 0.0,
0x0, 0x0, 0x0, 0x0
};
static cairo_color_t const cairo_color_magenta = {
1.0, 0.0, 1.0, 1.0,
0xffff, 0x0, 0xffff, 0xffff
};
const cairo_color_t *
_cairo_stock_color (cairo_stock_t stock)
{
switch (stock) {
case CAIRO_STOCK_WHITE:
return &cairo_color_white;
case CAIRO_STOCK_BLACK:
return &cairo_color_black;
case CAIRO_STOCK_TRANSPARENT:
return &cairo_color_transparent;
case CAIRO_STOCK_NUM_COLORS:
default:
ASSERT_NOT_REACHED;
/* If the user can get here somehow, give a color that indicates a
* problem. */
return &cairo_color_magenta;
}
}
/* Convert a double in [0.0, 1.0] to an integer in [0, 65535]
* The conversion is designed to divide the input range into 65536
* equally-sized regions. This is achieved by multiplying by 65536 and
* then special-casing the result of an input value of 1.0 so that it
* maps to 65535 instead of 65536.
*/
uint16_t
_cairo_color_double_to_short (double d)
{
uint32_t i;
i = (uint32_t) (d * 65536);
i -= (i >> 16);
return i;
}
static void
_cairo_color_compute_shorts (cairo_color_t *color)
{
color->red_short = _cairo_color_double_to_short (color->red * color->alpha);
color->green_short = _cairo_color_double_to_short (color->green * color->alpha);
color->blue_short = _cairo_color_double_to_short (color->blue * color->alpha);
color->alpha_short = _cairo_color_double_to_short (color->alpha);
}
void
_cairo_color_init_rgba (cairo_color_t *color,
double red, double green, double blue,
double alpha)
{
color->red = red;
color->green = green;
color->blue = blue;
color->alpha = alpha;
_cairo_color_compute_shorts (color);
}
void
_cairo_color_multiply_alpha (cairo_color_t *color,
double alpha)
{
color->alpha *= alpha;
_cairo_color_compute_shorts (color);
}
void
_cairo_color_get_rgba (cairo_color_t *color,
double *red,
double *green,
double *blue,
double *alpha)
{
*red = color->red;
*green = color->green;
*blue = color->blue;
*alpha = color->alpha;
}
void
_cairo_color_get_rgba_premultiplied (cairo_color_t *color,
double *red,
double *green,
double *blue,
double *alpha)
{
*red = color->red * color->alpha;
*green = color->green * color->alpha;
*blue = color->blue * color->alpha;
*alpha = color->alpha;
}
/* NB: This function works both for unmultiplied and premultiplied colors */
cairo_bool_t
_cairo_color_equal (const cairo_color_t *color_a,
const cairo_color_t *color_b)
{
if (color_a == color_b)
return TRUE;
if (color_a->alpha_short != color_b->alpha_short)
return FALSE;
if (color_a->alpha_short == 0)
return TRUE;
return color_a->red_short == color_b->red_short &&
color_a->green_short == color_b->green_short &&
color_a->blue_short == color_b->blue_short;
}
cairo_bool_t
_cairo_color_stop_equal (const cairo_color_stop_t *color_a,
const cairo_color_stop_t *color_b)
{
if (color_a == color_b)
return TRUE;
return color_a->alpha_short == color_b->alpha_short &&
color_a->red_short == color_b->red_short &&
color_a->green_short == color_b->green_short &&
color_a->blue_short == color_b->blue_short;
}
cairo_content_t
_cairo_color_get_content (const cairo_color_t *color)
{
if (CAIRO_COLOR_IS_OPAQUE (color))
return CAIRO_CONTENT_COLOR;
if (color->red_short == 0 &&
color->green_short == 0 &&
color->blue_short == 0)
{
return CAIRO_CONTENT_ALPHA;
}
return CAIRO_CONTENT_COLOR_ALPHA;
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright © 2008 Chris Wilson
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
/* This fragment implements a comb sort (specifically combsort11) */
#ifndef _HAVE_CAIRO_COMBSORT_NEWGAP
#define _HAVE_CAIRO_COMBSORT_NEWGAP
static inline unsigned int
_cairo_combsort_newgap (unsigned int gap)
{
gap = 10 * gap / 13;
if (gap == 9 || gap == 10)
gap = 11;
if (gap < 1)
gap = 1;
return gap;
}
#endif
#define CAIRO_COMBSORT_DECLARE(NAME, TYPE, CMP) \
static void \
NAME (TYPE *base, unsigned int nmemb) \
{ \
unsigned int gap = nmemb; \
unsigned int i, j; \
int swapped; \
do { \
gap = _cairo_combsort_newgap (gap); \
swapped = gap > 1; \
for (i = 0; i < nmemb-gap ; i++) { \
j = i + gap; \
if (CMP (base[i], base[j]) > 0 ) { \
TYPE tmp; \
tmp = base[i]; \
base[i] = base[j]; \
base[j] = tmp; \
swapped = 1; \
} \
} \
} while (swapped); \
}
#define CAIRO_COMBSORT_DECLARE_WITH_DATA(NAME, TYPE, CMP) \
static void \
NAME (TYPE *base, unsigned int nmemb, void *data) \
{ \
unsigned int gap = nmemb; \
unsigned int i, j; \
int swapped; \
do { \
gap = _cairo_combsort_newgap (gap); \
swapped = gap > 1; \
for (i = 0; i < nmemb-gap ; i++) { \
j = i + gap; \
if (CMP (base[i], base[j], data) > 0 ) { \
TYPE tmp; \
tmp = base[i]; \
base[i] = base[j]; \
base[j] = tmp; \
swapped = 1; \
} \
} \
} while (swapped); \
}

View File

@@ -0,0 +1,246 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* 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.
*
* 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>
*/
#ifndef CAIRO_COMPILER_PRIVATE_H
#define CAIRO_COMPILER_PRIVATE_H
#include "cairo.h"
#if HAVE_CONFIG_H
#include "config.h"
#endif
/* Size in bytes of buffer to use off the stack per functions.
* Mostly used by text functions. For larger allocations, they'll
* malloc(). */
#ifndef CAIRO_STACK_BUFFER_SIZE
#define CAIRO_STACK_BUFFER_SIZE (512 * sizeof (int))
#endif
#define CAIRO_STACK_ARRAY_LENGTH(T) (CAIRO_STACK_BUFFER_SIZE / sizeof(T))
/*
* The goal of this block is to define the following macros for
* providing faster linkage to functions in the public API for calls
* from within cairo.
*
* slim_hidden_proto(f)
* slim_hidden_proto_no_warn(f)
*
* Declares `f' as a library internal function and hides the
* function from the global symbol table. This macro must be
* expanded after `f' has been declared with a prototype but before
* any calls to the function are seen by the compiler. The no_warn
* variant inhibits warnings about the return value being unused at
* call sites. The macro works by renaming `f' to an internal name
* in the symbol table and hiding that. As far as cairo internal
* calls are concerned they're calling a library internal function
* and thus don't need to bounce via the PLT.
*
* slim_hidden_def(f)
*
* Exports `f' back to the global symbol table. This macro must be
* expanded right after the function definition and only for symbols
* hidden previously with slim_hidden_proto(). The macro works by
* adding a global entry to the symbol table which points at the
* internal name of `f' created by slim_hidden_proto().
*
* Functions in the public API which aren't called by the library
* don't need to be hidden and re-exported using the slim hidden
* macros.
*/
#if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun)
# define slim_hidden_proto(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private
# define slim_hidden_proto_no_warn(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private_no_warn
# define slim_hidden_def(name) slim_hidden_def1(name, slim_hidden_int_name(name))
# define slim_hidden_int_name(name) INT_##name
# define slim_hidden_proto1(name, internal) \
extern __typeof (name) name \
__asm__ (slim_hidden_asmname (internal))
# define slim_hidden_def1(name, internal) \
extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name)) \
__attribute__((__alias__(slim_hidden_asmname(internal))))
# define slim_hidden_ulp slim_hidden_ulp1(__USER_LABEL_PREFIX__)
# define slim_hidden_ulp1(x) slim_hidden_ulp2(x)
# define slim_hidden_ulp2(x) #x
# define slim_hidden_asmname(name) slim_hidden_asmname1(name)
# define slim_hidden_asmname1(name) slim_hidden_ulp #name
#else
# define slim_hidden_proto(name) int _cairo_dummy_prototype(void)
# define slim_hidden_proto_no_warn(name) int _cairo_dummy_prototype(void)
# define slim_hidden_def(name) int _cairo_dummy_prototype(void)
#endif
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
#define CAIRO_PRINTF_FORMAT(fmt_index, va_index) \
__attribute__((__format__(__printf__, fmt_index, va_index)))
#else
#define CAIRO_PRINTF_FORMAT(fmt_index, va_index)
#endif
/* slim_internal.h */
#define CAIRO_HAS_HIDDEN_SYMBOLS 1
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && \
(defined(__ELF__) || defined(__APPLE__)) && \
!defined(__sun)
#define cairo_private_no_warn __attribute__((__visibility__("hidden")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
#define cairo_private_no_warn __hidden
#else /* not gcc >= 3.3 and not Sun Studio >= 8 */
#define cairo_private_no_warn
#undef CAIRO_HAS_HIDDEN_SYMBOLS
#endif
#ifndef WARN_UNUSED_RESULT
#define WARN_UNUSED_RESULT
#endif
/* Add attribute(warn_unused_result) if supported */
#define cairo_warn WARN_UNUSED_RESULT
#define cairo_private cairo_private_no_warn cairo_warn
/* This macro allow us to deprecate a function by providing an alias
for the old function name to the new function name. With this
macro, binary compatibility is preserved. The macro only works on
some platforms --- tough.
Meanwhile, new definitions in the public header file break the
source code so that it will no longer link against the old
symbols. Instead it will give a descriptive error message
indicating that the old function has been deprecated by the new
function.
*/
#if __GNUC__ >= 2 && defined(__ELF__)
# define CAIRO_FUNCTION_ALIAS(old, new) \
extern __typeof (new) old \
__asm__ ("" #old) \
__attribute__((__alias__("" #new)))
#else
# define CAIRO_FUNCTION_ALIAS(old, new)
#endif
/*
* Cairo uses the following function attributes in order to improve the
* generated code (effectively by manual inter-procedural analysis).
*
* 'cairo_pure': The function is only allowed to read from its arguments
* and global memory (i.e. following a pointer argument or
* accessing a shared variable). The return value should
* only depend on its arguments, and for an identical set of
* arguments should return the same value.
*
* 'cairo_const': The function is only allowed to read from its arguments.
* It is not allowed to access global memory. The return
* value should only depend its arguments, and for an
* identical set of arguments should return the same value.
* This is currently the most strict function attribute.
*
* Both these function attributes allow gcc to perform CSE and
* constant-folding, with 'cairo_const 'also guaranteeing that pointer contents
* do not change across the function call.
*/
#if __GNUC__ >= 3
#define cairo_pure __attribute__((pure))
#define cairo_const __attribute__((const))
#define cairo_always_inline inline __attribute__((always_inline))
#else
#define cairo_pure
#define cairo_const
#define cairo_always_inline inline
#endif
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
#define likely(expr) (__builtin_expect (!!(expr), 1))
#define unlikely(expr) (__builtin_expect (!!(expr), 0))
#else
#define likely(expr) (expr)
#define unlikely(expr) (expr)
#endif
#ifndef __GNUC__
#undef __attribute__
#define __attribute__(x)
#endif
#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
#define access _access
#define fdopen _fdopen
#define hypot _hypot
#define pclose _pclose
#define popen _popen
#define snprintf _snprintf
#define strdup _strdup
#define unlink _unlink
#define vsnprintf _vsnprintf
#endif
#ifdef _MSC_VER
#ifndef __cplusplus
#undef inline
#define inline __inline
#endif
#endif
#if defined(_MSC_VER) && defined(_M_IX86)
/* When compiling with /Gy and /OPT:ICF identical functions will be folded in together.
The CAIRO_ENSURE_UNIQUE macro ensures that a function is always unique and
will never be folded into another one. Something like this might eventually
be needed for GCC but it seems fine for now. */
#define CAIRO_ENSURE_UNIQUE \
do { \
char func[] = __FUNCTION__; \
char file[] = __FILE__; \
__asm { \
__asm jmp __internal_skip_line_no \
__asm _emit (__LINE__ & 0xff) \
__asm _emit ((__LINE__>>8) & 0xff) \
__asm _emit ((__LINE__>>16) & 0xff) \
__asm _emit ((__LINE__>>24) & 0xff) \
__asm lea eax, func \
__asm lea eax, file \
__asm __internal_skip_line_no: \
}; \
} while (0)
#else
#define CAIRO_ENSURE_UNIQUE do { } while (0)
#endif
#ifdef __STRICT_ANSI__
#undef inline
#define inline __inline__
#endif
#endif

View File

@@ -0,0 +1,159 @@
/* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.u>
*/
#ifndef CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H
#define CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H
#include "cairo-types-private.h"
#include "cairo-error-private.h"
#include "cairo-pattern-private.h"
CAIRO_BEGIN_DECLS
/* Rectangles that take part in a composite operation.
*
* The source and mask track the extents of the respective patterns in device
* space. The unbounded rectangle is essentially the clip rectangle. And the
* intersection of all is the bounded rectangle, which is the minimum extents
* the operation may require. Whether or not the operation is actually bounded
* is tracked in the is_bounded boolean.
*
*/
struct _cairo_composite_rectangles {
cairo_surface_t *surface;
cairo_operator_t op;
cairo_rectangle_int_t source;
cairo_rectangle_int_t mask;
cairo_rectangle_int_t destination;
cairo_rectangle_int_t bounded; /* source? IN mask? IN unbounded */
cairo_rectangle_int_t unbounded; /* destination IN clip */
uint32_t is_bounded;
cairo_rectangle_int_t source_sample_area;
cairo_rectangle_int_t mask_sample_area;
cairo_pattern_union_t source_pattern;
cairo_pattern_union_t mask_pattern;
const cairo_pattern_t *original_source_pattern;
const cairo_pattern_t *original_mask_pattern;
cairo_clip_t *clip; /* clip will be reduced to the minimal container */
};
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
const cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
cairo_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_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_path_fixed_t *path,
const cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_boxes (cairo_composite_rectangles_t *extents,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_boxes_t *boxes,
const cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_polygon (cairo_composite_rectangles_t *extents,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_polygon_t *polygon,
const cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
cairo_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,
cairo_bool_t *overlap);
cairo_private cairo_int_status_t
_cairo_composite_rectangles_intersect_source_extents (cairo_composite_rectangles_t *extents,
const cairo_box_t *box);
cairo_private cairo_int_status_t
_cairo_composite_rectangles_intersect_mask_extents (cairo_composite_rectangles_t *extents,
const cairo_box_t *box);
cairo_private cairo_bool_t
_cairo_composite_rectangles_can_reduce_clip (cairo_composite_rectangles_t *composite,
cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_composite_rectangles_add_to_damage (cairo_composite_rectangles_t *composite,
cairo_boxes_t *damage);
cairo_private void
_cairo_composite_rectangles_fini (cairo_composite_rectangles_t *extents);
CAIRO_END_DECLS
#endif /* CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H */

View File

@@ -0,0 +1,500 @@
/* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-clip-inline.h"
#include "cairo-error-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-pattern-private.h"
/* A collection of routines to facilitate writing compositors. */
void _cairo_composite_rectangles_fini (cairo_composite_rectangles_t *extents)
{
_cairo_clip_destroy (extents->clip);
}
static void
_cairo_composite_reduce_pattern (const cairo_pattern_t *src,
cairo_pattern_union_t *dst)
{
int tx, ty;
_cairo_pattern_init_static_copy (&dst->base, src);
if (dst->base.type == CAIRO_PATTERN_TYPE_SOLID)
return;
dst->base.filter = _cairo_pattern_analyze_filter (&dst->base, NULL),
tx = ty = 0;
if (_cairo_matrix_is_pixman_translation (&dst->base.matrix,
dst->base.filter,
&tx, &ty))
{
dst->base.matrix.x0 = tx;
dst->base.matrix.y0 = ty;
}
}
static inline cairo_bool_t
_cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip)
{
if (_cairo_clip_is_all_clipped (clip))
return FALSE;
extents->surface = surface;
extents->op = op;
_cairo_surface_get_extents (surface, &extents->destination);
extents->clip = NULL;
extents->unbounded = extents->destination;
if (clip && ! _cairo_rectangle_intersect (&extents->unbounded,
_cairo_clip_get_extents (clip)))
return FALSE;
extents->bounded = extents->unbounded;
extents->is_bounded = _cairo_operator_bounded_by_either (op);
extents->original_source_pattern = source;
_cairo_composite_reduce_pattern (source, &extents->source_pattern);
_cairo_pattern_get_extents (&extents->source_pattern.base,
&extents->source);
if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE) {
if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source))
return FALSE;
}
extents->original_mask_pattern = NULL;
extents->mask_pattern.base.type = CAIRO_PATTERN_TYPE_SOLID;
extents->mask_pattern.solid.color.alpha = 1.; /* XXX full initialisation? */
extents->mask_pattern.solid.color.alpha_short = 0xffff;
return TRUE;
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip)
{
if (! _cairo_composite_rectangles_init (extents,
surface, op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
extents->mask = extents->destination;
extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
if (_cairo_clip_is_all_clipped (extents->clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (! _cairo_rectangle_intersect (&extents->unbounded,
_cairo_clip_get_extents (extents->clip)))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
_cairo_pattern_sampled_area (&extents->source_pattern.base,
&extents->bounded,
&extents->source_sample_area);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents,
const cairo_clip_t *clip)
{
cairo_bool_t ret;
ret = _cairo_rectangle_intersect (&extents->bounded, &extents->mask);
if (! ret && extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (extents->is_bounded == (CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE)) {
extents->unbounded = extents->bounded;
} else if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) {
if (!_cairo_rectangle_intersect (&extents->unbounded, &extents->mask))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
if (_cairo_clip_is_all_clipped (extents->clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (! _cairo_rectangle_intersect (&extents->unbounded,
_cairo_clip_get_extents (extents->clip)))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (! _cairo_rectangle_intersect (&extents->bounded,
_cairo_clip_get_extents (extents->clip)) &&
extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
_cairo_pattern_sampled_area (&extents->source_pattern.base,
&extents->bounded,
&extents->source_sample_area);
if (extents->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) {
_cairo_pattern_sampled_area (&extents->mask_pattern.base,
&extents->bounded,
&extents->mask_sample_area);
if (extents->mask_sample_area.width == 0 ||
extents->mask_sample_area.height == 0) {
_cairo_composite_rectangles_fini (extents);
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
}
return CAIRO_STATUS_SUCCESS;
}
cairo_int_status_t
_cairo_composite_rectangles_intersect_source_extents (cairo_composite_rectangles_t *extents,
const cairo_box_t *box)
{
cairo_rectangle_int_t rect;
cairo_clip_t *clip;
_cairo_box_round_to_rectangle (box, &rect);
if (rect.x == extents->source.x &&
rect.y == extents->source.y &&
rect.width == extents->source.width &&
rect.height == extents->source.height)
{
return CAIRO_INT_STATUS_SUCCESS;
}
_cairo_rectangle_intersect (&extents->source, &rect);
rect = extents->bounded;
if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source) &&
extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (rect.width == extents->bounded.width &&
rect.height == extents->bounded.height)
return CAIRO_INT_STATUS_SUCCESS;
if (extents->is_bounded == (CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE)) {
extents->unbounded = extents->bounded;
} else if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) {
if (!_cairo_rectangle_intersect (&extents->unbounded, &extents->mask))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
clip = extents->clip;
extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
if (clip != extents->clip)
_cairo_clip_destroy (clip);
if (_cairo_clip_is_all_clipped (extents->clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (! _cairo_rectangle_intersect (&extents->unbounded,
_cairo_clip_get_extents (extents->clip)))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
_cairo_pattern_sampled_area (&extents->source_pattern.base,
&extents->bounded,
&extents->source_sample_area);
if (extents->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) {
_cairo_pattern_sampled_area (&extents->mask_pattern.base,
&extents->bounded,
&extents->mask_sample_area);
if (extents->mask_sample_area.width == 0 ||
extents->mask_sample_area.height == 0)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
return CAIRO_INT_STATUS_SUCCESS;
}
cairo_int_status_t
_cairo_composite_rectangles_intersect_mask_extents (cairo_composite_rectangles_t *extents,
const cairo_box_t *box)
{
cairo_rectangle_int_t mask;
cairo_clip_t *clip;
_cairo_box_round_to_rectangle (box, &mask);
if (mask.x == extents->mask.x &&
mask.y == extents->mask.y &&
mask.width == extents->mask.width &&
mask.height == extents->mask.height)
{
return CAIRO_INT_STATUS_SUCCESS;
}
_cairo_rectangle_intersect (&extents->mask, &mask);
mask = extents->bounded;
if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask) &&
extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (mask.width == extents->bounded.width &&
mask.height == extents->bounded.height)
return CAIRO_INT_STATUS_SUCCESS;
if (extents->is_bounded == (CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE)) {
extents->unbounded = extents->bounded;
} else if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) {
if (!_cairo_rectangle_intersect (&extents->unbounded, &extents->mask))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
clip = extents->clip;
extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
if (clip != extents->clip)
_cairo_clip_destroy (clip);
if (_cairo_clip_is_all_clipped (extents->clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (! _cairo_rectangle_intersect (&extents->unbounded,
_cairo_clip_get_extents (extents->clip)))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
_cairo_pattern_sampled_area (&extents->source_pattern.base,
&extents->bounded,
&extents->source_sample_area);
if (extents->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) {
_cairo_pattern_sampled_area (&extents->mask_pattern.base,
&extents->bounded,
&extents->mask_sample_area);
if (extents->mask_sample_area.width == 0 ||
extents->mask_sample_area.height == 0)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
return CAIRO_INT_STATUS_SUCCESS;
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
cairo_surface_t*surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
const cairo_clip_t *clip)
{
if (! _cairo_composite_rectangles_init (extents,
surface, op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
extents->original_mask_pattern = mask;
_cairo_composite_reduce_pattern (mask, &extents->mask_pattern);
_cairo_pattern_get_extents (&extents->mask_pattern.base, &extents->mask);
return _cairo_composite_rectangles_intersect (extents, clip);
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
cairo_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_clip_t *clip)
{
if (! _cairo_composite_rectangles_init (extents,
surface, op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
_cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &extents->mask);
return _cairo_composite_rectangles_intersect (extents, clip);
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_path_fixed_t *path,
const cairo_clip_t *clip)
{
if (! _cairo_composite_rectangles_init (extents,
surface, op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
_cairo_path_fixed_approximate_fill_extents (path, &extents->mask);
return _cairo_composite_rectangles_intersect (extents, clip);
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_polygon (cairo_composite_rectangles_t *extents,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_polygon_t *polygon,
const cairo_clip_t *clip)
{
if (! _cairo_composite_rectangles_init (extents,
surface, op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
_cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
return _cairo_composite_rectangles_intersect (extents, clip);
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_boxes (cairo_composite_rectangles_t *extents,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_boxes_t *boxes,
const cairo_clip_t *clip)
{
cairo_box_t box;
if (! _cairo_composite_rectangles_init (extents,
surface, op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
_cairo_boxes_extents (boxes, &box);
_cairo_box_round_to_rectangle (&box, &extents->mask);
return _cairo_composite_rectangles_intersect (extents, clip);
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
cairo_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,
cairo_bool_t *overlap)
{
cairo_status_t status;
if (! _cairo_composite_rectangles_init (extents, surface, op, source, clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
/* Computing the exact bbox and the overlap is expensive.
* First perform a cheap test to see if the glyphs are all clipped out.
*/
if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK &&
_cairo_scaled_font_glyph_approximate_extents (scaled_font,
glyphs, num_glyphs,
&extents->mask))
{
if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs, num_glyphs,
&extents->mask,
overlap);
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);
}
cairo_bool_t
_cairo_composite_rectangles_can_reduce_clip (cairo_composite_rectangles_t *composite,
cairo_clip_t *clip)
{
cairo_rectangle_int_t extents;
cairo_box_t box;
if (clip == NULL)
return TRUE;
extents = composite->destination;
if (composite->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE)
_cairo_rectangle_intersect (&extents, &composite->source);
if (composite->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
_cairo_rectangle_intersect (&extents, &composite->mask);
_cairo_box_from_rectangle (&box, &extents);
return _cairo_clip_contains_box (clip, &box);
}
cairo_int_status_t
_cairo_composite_rectangles_add_to_damage (cairo_composite_rectangles_t *composite,
cairo_boxes_t *damage)
{
cairo_int_status_t status;
int n;
for (n = 0; n < composite->clip->num_boxes; n++) {
status = _cairo_boxes_add (damage,
CAIRO_ANTIALIAS_NONE,
&composite->clip->boxes[n]);
if (unlikely (status))
return status;
}
return CAIRO_INT_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,365 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2011 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_COMPOSITOR_PRIVATE_H
#define CAIRO_COMPOSITOR_PRIVATE_H
#include "cairo-composite-rectangles-private.h"
CAIRO_BEGIN_DECLS
typedef struct {
cairo_scaled_font_t *font;
cairo_glyph_t *glyphs;
int num_glyphs;
cairo_bool_t use_mask;
cairo_rectangle_int_t extents;
} cairo_composite_glyphs_info_t;
struct cairo_compositor {
const cairo_compositor_t *delegate;
cairo_warn cairo_int_status_t
(*paint) (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *extents);
cairo_warn cairo_int_status_t
(*mask) (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *extents);
cairo_warn cairo_int_status_t
(*stroke) (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *extents,
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);
cairo_warn cairo_int_status_t
(*fill) (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *extents,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias);
cairo_warn cairo_int_status_t
(*glyphs) (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *extents,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_bool_t overlap);
};
struct cairo_mask_compositor {
cairo_compositor_t base;
cairo_int_status_t (*acquire) (void *surface);
cairo_int_status_t (*release) (void *surface);
cairo_int_status_t (*set_clip_region) (void *surface,
cairo_region_t *clip_region);
cairo_surface_t * (*pattern_to_surface) (cairo_surface_t *dst,
const cairo_pattern_t *pattern,
cairo_bool_t is_mask,
const cairo_rectangle_int_t *extents,
const cairo_rectangle_int_t *sample,
int *src_x, int *src_y);
cairo_int_status_t (*draw_image_boxes) (void *surface,
cairo_image_surface_t *image,
cairo_boxes_t *boxes,
int dx, int dy);
cairo_int_status_t (*copy_boxes) (void *surface,
cairo_surface_t *src,
cairo_boxes_t *boxes,
const cairo_rectangle_int_t *extents,
int dx, int dy);
cairo_int_status_t
(*fill_rectangles) (void *surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_rectangle_int_t *rectangles,
int num_rects);
cairo_int_status_t
(*fill_boxes) (void *surface,
cairo_operator_t op,
const cairo_color_t *color,
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_surface_t *mask,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height);
cairo_int_status_t
(*composite_boxes) (void *surface,
cairo_operator_t op,
cairo_surface_t *source,
cairo_surface_t *mask,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
cairo_boxes_t *boxes,
const cairo_rectangle_int_t *extents);
cairo_int_status_t
(*check_composite_glyphs) (const cairo_composite_rectangles_t *extents,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int *num_glyphs);
cairo_int_status_t
(*composite_glyphs) (void *surface,
cairo_operator_t op,
cairo_surface_t *src,
int src_x,
int src_y,
int dst_x,
int dst_y,
cairo_composite_glyphs_info_t *info);
};
struct cairo_traps_compositor {
cairo_compositor_t base;
cairo_int_status_t
(*acquire) (void *surface);
cairo_int_status_t
(*release) (void *surface);
cairo_int_status_t
(*set_clip_region) (void *surface,
cairo_region_t *clip_region);
cairo_surface_t *
(*pattern_to_surface) (cairo_surface_t *dst,
const cairo_pattern_t *pattern,
cairo_bool_t is_mask,
const cairo_rectangle_int_t *extents,
const cairo_rectangle_int_t *sample,
int *src_x, int *src_y);
cairo_int_status_t (*draw_image_boxes) (void *surface,
cairo_image_surface_t *image,
cairo_boxes_t *boxes,
int dx, int dy);
cairo_int_status_t (*copy_boxes) (void *surface,
cairo_surface_t *src,
cairo_boxes_t *boxes,
const cairo_rectangle_int_t *extents,
int dx, int dy);
cairo_int_status_t
(*fill_boxes) (void *surface,
cairo_operator_t op,
const cairo_color_t *color,
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_surface_t *mask,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height);
cairo_int_status_t
(*lerp) (void *_dst,
cairo_surface_t *abstract_src,
cairo_surface_t *abstract_mask,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height);
cairo_int_status_t
(*composite_boxes) (void *surface,
cairo_operator_t op,
cairo_surface_t *source,
cairo_surface_t *mask,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
cairo_boxes_t *boxes,
const cairo_rectangle_int_t *extents);
cairo_int_status_t
(*composite_traps) (void *dst,
cairo_operator_t op,
cairo_surface_t *source,
int src_x,
int src_y,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
cairo_antialias_t antialias,
cairo_traps_t *traps);
cairo_int_status_t
(*composite_tristrip) (void *dst,
cairo_operator_t op,
cairo_surface_t *source,
int src_x,
int src_y,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
cairo_antialias_t antialias,
cairo_tristrip_t *tristrip);
cairo_int_status_t
(*check_composite_glyphs) (const cairo_composite_rectangles_t *extents,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int *num_glyphs);
cairo_int_status_t
(*composite_glyphs) (void *surface,
cairo_operator_t op,
cairo_surface_t *src,
int src_x,
int src_y,
int dst_x,
int dst_y,
cairo_composite_glyphs_info_t *info);
};
cairo_private extern const cairo_compositor_t __cairo_no_compositor;
cairo_private extern const cairo_compositor_t _cairo_fallback_compositor;
cairo_private void
_cairo_mask_compositor_init (cairo_mask_compositor_t *compositor,
const cairo_compositor_t *delegate);
cairo_private void
_cairo_shape_mask_compositor_init (cairo_compositor_t *compositor,
const cairo_compositor_t *delegate);
cairo_private void
_cairo_traps_compositor_init (cairo_traps_compositor_t *compositor,
const cairo_compositor_t *delegate);
cairo_private cairo_int_status_t
_cairo_compositor_paint (const cairo_compositor_t *compositor,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_compositor_mask (const cairo_compositor_t *compositor,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
const cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_compositor_stroke (const cairo_compositor_t *compositor,
cairo_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);
cairo_private cairo_int_status_t
_cairo_compositor_fill (const cairo_compositor_t *compositor,
cairo_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);
cairo_private cairo_int_status_t
_cairo_compositor_glyphs (const cairo_compositor_t *compositor,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
const cairo_clip_t *clip);
CAIRO_END_DECLS
#endif /* CAIRO_COMPOSITOR_PRIVATE_H */

View File

@@ -0,0 +1,268 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2011 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-compositor-private.h"
#include "cairo-damage-private.h"
#include "cairo-error-private.h"
cairo_int_status_t
_cairo_compositor_paint (const cairo_compositor_t *compositor,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip)
{
cairo_composite_rectangles_t extents;
cairo_int_status_t status;
TRACE ((stderr, "%s\n", __FUNCTION__));
status = _cairo_composite_rectangles_init_for_paint (&extents, surface,
op, source,
clip);
if (unlikely (status))
return status;
do {
while (compositor->paint == NULL)
compositor = compositor->delegate;
status = compositor->paint (compositor, &extents);
compositor = compositor->delegate;
} while (status == CAIRO_INT_STATUS_UNSUPPORTED);
if (status == CAIRO_INT_STATUS_SUCCESS && surface->damage) {
TRACE ((stderr, "%s: applying damage (%d,%d)x(%d, %d)\n",
__FUNCTION__,
extents.unbounded.x, extents.unbounded.y,
extents.unbounded.width, extents.unbounded.height));
surface->damage = _cairo_damage_add_rectangle (surface->damage,
&extents.unbounded);
}
_cairo_composite_rectangles_fini (&extents);
return status;
}
cairo_int_status_t
_cairo_compositor_mask (const cairo_compositor_t *compositor,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
const cairo_clip_t *clip)
{
cairo_composite_rectangles_t extents;
cairo_int_status_t status;
TRACE ((stderr, "%s\n", __FUNCTION__));
status = _cairo_composite_rectangles_init_for_mask (&extents, surface,
op, source, mask,
clip);
if (unlikely (status))
return status;
do {
while (compositor->mask == NULL)
compositor = compositor->delegate;
status = compositor->mask (compositor, &extents);
compositor = compositor->delegate;
} while (status == CAIRO_INT_STATUS_UNSUPPORTED);
if (status == CAIRO_INT_STATUS_SUCCESS && surface->damage) {
TRACE ((stderr, "%s: applying damage (%d,%d)x(%d, %d)\n",
__FUNCTION__,
extents.unbounded.x, extents.unbounded.y,
extents.unbounded.width, extents.unbounded.height));
surface->damage = _cairo_damage_add_rectangle (surface->damage,
&extents.unbounded);
}
_cairo_composite_rectangles_fini (&extents);
return status;
}
cairo_int_status_t
_cairo_compositor_stroke (const cairo_compositor_t *compositor,
cairo_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)
{
cairo_composite_rectangles_t extents;
cairo_int_status_t status;
TRACE ((stderr, "%s\n", __FUNCTION__));
if (_cairo_pen_vertices_needed (tolerance, style->line_width/2, ctm) <= 1)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
status = _cairo_composite_rectangles_init_for_stroke (&extents, surface,
op, source,
path, style, ctm,
clip);
if (unlikely (status))
return status;
do {
while (compositor->stroke == NULL)
compositor = compositor->delegate;
status = compositor->stroke (compositor, &extents,
path, style, ctm, ctm_inverse,
tolerance, antialias);
compositor = compositor->delegate;
} while (status == CAIRO_INT_STATUS_UNSUPPORTED);
if (status == CAIRO_INT_STATUS_SUCCESS && surface->damage) {
TRACE ((stderr, "%s: applying damage (%d,%d)x(%d, %d)\n",
__FUNCTION__,
extents.unbounded.x, extents.unbounded.y,
extents.unbounded.width, extents.unbounded.height));
surface->damage = _cairo_damage_add_rectangle (surface->damage,
&extents.unbounded);
}
_cairo_composite_rectangles_fini (&extents);
return status;
}
cairo_int_status_t
_cairo_compositor_fill (const cairo_compositor_t *compositor,
cairo_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)
{
cairo_composite_rectangles_t extents;
cairo_int_status_t status;
TRACE ((stderr, "%s\n", __FUNCTION__));
status = _cairo_composite_rectangles_init_for_fill (&extents, surface,
op, source, path,
clip);
if (unlikely (status))
return status;
do {
while (compositor->fill == NULL)
compositor = compositor->delegate;
status = compositor->fill (compositor, &extents,
path, fill_rule, tolerance, antialias);
compositor = compositor->delegate;
} while (status == CAIRO_INT_STATUS_UNSUPPORTED);
if (status == CAIRO_INT_STATUS_SUCCESS && surface->damage) {
TRACE ((stderr, "%s: applying damage (%d,%d)x(%d, %d)\n",
__FUNCTION__,
extents.unbounded.x, extents.unbounded.y,
extents.unbounded.width, extents.unbounded.height));
surface->damage = _cairo_damage_add_rectangle (surface->damage,
&extents.unbounded);
}
_cairo_composite_rectangles_fini (&extents);
return status;
}
cairo_int_status_t
_cairo_compositor_glyphs (const cairo_compositor_t *compositor,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
const cairo_clip_t *clip)
{
cairo_composite_rectangles_t extents;
cairo_bool_t overlap;
cairo_int_status_t status;
TRACE ((stderr, "%s\n", __FUNCTION__));
status = _cairo_composite_rectangles_init_for_glyphs (&extents, surface,
op, source,
scaled_font,
glyphs, num_glyphs,
clip, &overlap);
if (unlikely (status))
return status;
do {
while (compositor->glyphs == NULL)
compositor = compositor->delegate;
status = compositor->glyphs (compositor, &extents,
scaled_font, glyphs, num_glyphs, overlap);
compositor = compositor->delegate;
} while (status == CAIRO_INT_STATUS_UNSUPPORTED);
if (status == CAIRO_INT_STATUS_SUCCESS && surface->damage) {
TRACE ((stderr, "%s: applying damage (%d,%d)x(%d, %d)\n",
__FUNCTION__,
extents.unbounded.x, extents.unbounded.y,
extents.unbounded.width, extents.unbounded.height));
surface->damage = _cairo_damage_add_rectangle (surface->damage,
&extents.unbounded);
}
_cairo_composite_rectangles_fini (&extents);
return status;
}

View File

@@ -0,0 +1,80 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2011 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Intel Corporation
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_CONTOUR_INLINE_H
#define CAIRO_CONTOUR_INLINE_H
#include "cairo-contour-private.h"
CAIRO_BEGIN_DECLS
static inline cairo_int_status_t
_cairo_contour_add_point (cairo_contour_t *contour,
const cairo_point_t *point)
{
struct _cairo_contour_chain *tail = contour->tail;
if (unlikely (tail->num_points == tail->size_points))
return __cairo_contour_add_point (contour, point);
tail->points[tail->num_points++] = *point;
return CAIRO_INT_STATUS_SUCCESS;
}
static inline cairo_point_t *
_cairo_contour_first_point (cairo_contour_t *c)
{
return &c->chain.points[0];
}
static inline cairo_point_t *
_cairo_contour_last_point (cairo_contour_t *c)
{
return &c->tail->points[c->tail->num_points-1];
}
static inline void
_cairo_contour_remove_last_point (cairo_contour_t *contour)
{
if (contour->chain.num_points == 0)
return;
if (--contour->tail->num_points == 0)
__cairo_contour_remove_last_chain (contour);
}
CAIRO_END_DECLS
#endif /* CAIRO_CONTOUR_INLINE_H */

View File

@@ -0,0 +1,124 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2011 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Intel Corporation
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_CONTOUR_PRIVATE_H
#define CAIRO_CONTOUR_PRIVATE_H
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
#include "cairo-error-private.h"
#include "cairo-list-private.h"
#include <stdio.h>
CAIRO_BEGIN_DECLS
/* A contour is simply a closed chain of points that divide the infinite plane
* into inside and outside. Each contour is a simple polygon, that is it
* contains no holes or self-intersections, but maybe either concave or convex.
*/
struct _cairo_contour_chain {
cairo_point_t *points;
int num_points, size_points;
struct _cairo_contour_chain *next;
};
struct _cairo_contour_iter {
cairo_point_t *point;
cairo_contour_chain_t *chain;
};
struct _cairo_contour {
cairo_list_t next;
int direction;
cairo_contour_chain_t chain, *tail;
cairo_point_t embedded_points[64];
};
/* Initial definition of a shape is a set of contours (some representing holes) */
struct _cairo_shape {
cairo_list_t contours;
};
typedef struct _cairo_shape cairo_shape_t;
#if 0
cairo_private cairo_status_t
_cairo_shape_init_from_polygon (cairo_shape_t *shape,
const cairo_polygon_t *polygon);
cairo_private cairo_status_t
_cairo_shape_reduce (cairo_shape_t *shape, double tolerance);
#endif
cairo_private void
_cairo_contour_init (cairo_contour_t *contour,
int direction);
cairo_private cairo_int_status_t
__cairo_contour_add_point (cairo_contour_t *contour,
const cairo_point_t *point);
cairo_private void
_cairo_contour_simplify (cairo_contour_t *contour, double tolerance);
cairo_private void
_cairo_contour_reverse (cairo_contour_t *contour);
cairo_private cairo_int_status_t
_cairo_contour_add (cairo_contour_t *dst,
const cairo_contour_t *src);
cairo_private cairo_int_status_t
_cairo_contour_add_reversed (cairo_contour_t *dst,
const cairo_contour_t *src);
cairo_private void
__cairo_contour_remove_last_chain (cairo_contour_t *contour);
cairo_private void
_cairo_contour_reset (cairo_contour_t *contour);
cairo_private void
_cairo_contour_fini (cairo_contour_t *contour);
cairo_private void
_cairo_debug_print_contour (FILE *file, cairo_contour_t *contour);
CAIRO_END_DECLS
#endif /* CAIRO_CONTOUR_PRIVATE_H */

View File

@@ -0,0 +1,456 @@
/*
* Copyright © 2004 Carl Worth
* Copyright © 2006 Red Hat, Inc.
* Copyright © 2008 Chris Wilson
* Copyright © 2011 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Carl Worth
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
typedef unsigned long long uint64_t;
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-freelist-private.h"
#include "cairo-combsort-inline.h"
#include "cairo-contour-inline.h"
#include "cairo-contour-private.h"
void
_cairo_contour_init (cairo_contour_t *contour,
int direction)
{
contour->direction = direction;
contour->chain.points = contour->embedded_points;
contour->chain.next = NULL;
contour->chain.num_points = 0;
contour->chain.size_points = ARRAY_LENGTH (contour->embedded_points);
contour->tail = &contour->chain;
}
cairo_int_status_t
__cairo_contour_add_point (cairo_contour_t *contour,
const cairo_point_t *point)
{
cairo_contour_chain_t *tail = contour->tail;
cairo_contour_chain_t *next;
assert (tail->next == NULL);
next = _cairo_malloc_ab_plus_c (tail->size_points*2,
sizeof (cairo_point_t),
sizeof (cairo_contour_chain_t));
if (unlikely (next == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
next->size_points = tail->size_points*2;
next->num_points = 1;
next->points = (cairo_point_t *)(next+1);
next->next = NULL;
tail->next = next;
contour->tail = next;
next->points[0] = *point;
return CAIRO_INT_STATUS_SUCCESS;
}
static void
first_inc (cairo_contour_t *contour,
cairo_point_t **p,
cairo_contour_chain_t **chain)
{
if (*p == (*chain)->points + (*chain)->num_points) {
assert ((*chain)->next);
*chain = (*chain)->next;
*p = &(*chain)->points[0];
} else
++*p;
}
static void
last_dec (cairo_contour_t *contour,
cairo_point_t **p,
cairo_contour_chain_t **chain)
{
if (*p == (*chain)->points) {
cairo_contour_chain_t *prev;
assert (*chain != &contour->chain);
for (prev = &contour->chain; prev->next != *chain; prev = prev->next)
;
*chain = prev;
*p = &(*chain)->points[(*chain)->num_points-1];
} else
--*p;
}
void
_cairo_contour_reverse (cairo_contour_t *contour)
{
cairo_contour_chain_t *first_chain, *last_chain;
cairo_point_t *first, *last;
contour->direction = -contour->direction;
if (contour->chain.num_points <= 1)
return;
first_chain = &contour->chain;
last_chain = contour->tail;
first = &first_chain->points[0];
last = &last_chain->points[last_chain->num_points-1];
while (first != last) {
cairo_point_t p;
p = *first;
*first = *last;
*last = p;
first_inc (contour, &first, &first_chain);
last_dec (contour, &last, &last_chain);
}
}
cairo_int_status_t
_cairo_contour_add (cairo_contour_t *dst,
const cairo_contour_t *src)
{
const cairo_contour_chain_t *chain;
cairo_int_status_t status;
int i;
for (chain = &src->chain; chain; chain = chain->next) {
for (i = 0; i < chain->num_points; i++) {
status = _cairo_contour_add_point (dst, &chain->points[i]);
if (unlikely (status))
return status;
}
}
return CAIRO_INT_STATUS_SUCCESS;
}
static inline cairo_bool_t
iter_next (cairo_contour_iter_t *iter)
{
if (iter->point == &iter->chain->points[iter->chain->size_points-1]) {
iter->chain = iter->chain->next;
if (iter->chain == NULL)
return FALSE;
iter->point = &iter->chain->points[0];
return TRUE;
} else {
iter->point++;
return TRUE;
}
}
static cairo_bool_t
iter_equal (const cairo_contour_iter_t *i1,
const cairo_contour_iter_t *i2)
{
return i1->chain == i2->chain && i1->point == i2->point;
}
static void
iter_init (cairo_contour_iter_t *iter, cairo_contour_t *contour)
{
iter->chain = &contour->chain;
iter->point = &contour->chain.points[0];
}
static void
iter_init_last (cairo_contour_iter_t *iter, cairo_contour_t *contour)
{
iter->chain = contour->tail;
iter->point = &contour->tail->points[contour->tail->num_points-1];
}
static const cairo_contour_chain_t *prev_const_chain(const cairo_contour_t *contour,
const cairo_contour_chain_t *chain)
{
const cairo_contour_chain_t *prev;
if (chain == &contour->chain)
return NULL;
for (prev = &contour->chain; prev->next != chain; prev = prev->next)
;
return prev;
}
cairo_int_status_t
_cairo_contour_add_reversed (cairo_contour_t *dst,
const cairo_contour_t *src)
{
const cairo_contour_chain_t *last;
cairo_int_status_t status;
int i;
if (src->chain.num_points == 0)
return CAIRO_INT_STATUS_SUCCESS;
for (last = src->tail; last; last = prev_const_chain (src, last)) {
for (i = last->num_points-1; i >= 0; i--) {
status = _cairo_contour_add_point (dst, &last->points[i]);
if (unlikely (status))
return status;
}
}
return CAIRO_INT_STATUS_SUCCESS;
}
static cairo_uint64_t
point_distance_sq (const cairo_point_t *p1,
const cairo_point_t *p2)
{
int32_t dx = p1->x - p2->x;
int32_t dy = p1->y - p2->y;
return _cairo_int64_add(_cairo_int32x32_64_mul (dx, dx), _cairo_int32x32_64_mul (dy, dy));
}
#define DELETED(p) ((p)->x == INT_MIN && (p)->y == INT_MAX)
#define MARK_DELETED(p) ((p)->x = INT_MIN, (p)->y = INT_MAX)
static cairo_bool_t
_cairo_contour_simplify_chain (cairo_contour_t *contour, const double tolerance,
const cairo_contour_iter_t *first,
const cairo_contour_iter_t *last)
{
cairo_contour_iter_t iter, furthest;
uint64_t max_error;
int x0, y0;
int nx, ny;
int count;
iter = *first;
iter_next (&iter);
if (iter_equal (&iter, last))
return FALSE;
x0 = first->point->x;
y0 = first->point->y;
nx = last->point->y - y0;
ny = x0 - last->point->x;
count = 0;
max_error = 0;
do {
cairo_point_t *p = iter.point;
if (! DELETED(p)) {
uint64_t d = (uint64_t)nx * (x0 - p->x) + (uint64_t)ny * (y0 - p->y);
if (d * d > max_error) {
max_error = d * d;
furthest = iter;
}
count++;
}
iter_next (&iter);
} while (! iter_equal (&iter, last));
if (count == 0)
return FALSE;
if (max_error > tolerance * ((uint64_t)nx * nx + (uint64_t)ny * ny)) {
cairo_bool_t simplified;
simplified = FALSE;
simplified |= _cairo_contour_simplify_chain (contour, tolerance,
first, &furthest);
simplified |= _cairo_contour_simplify_chain (contour, tolerance,
&furthest, last);
return simplified;
} else {
iter = *first;
iter_next (&iter);
do {
MARK_DELETED (iter.point);
iter_next (&iter);
} while (! iter_equal (&iter, last));
return TRUE;
}
}
void
_cairo_contour_simplify (cairo_contour_t *contour, double tolerance)
{
cairo_contour_chain_t *chain;
cairo_point_t *last = NULL;
cairo_contour_iter_t iter, furthest;
cairo_bool_t simplified;
uint64_t max = 0;
int i;
if (contour->chain.num_points <= 2)
return;
tolerance = tolerance * CAIRO_FIXED_ONE;
tolerance *= tolerance;
/* stage 1: vertex reduction */
for (chain = &contour->chain; chain; chain = chain->next) {
for (i = 0; i < chain->num_points; i++) {
if (last == NULL ||
_cairo_uint64_to_double(point_distance_sq (last, &chain->points[i])) > tolerance) {
last = &chain->points[i];
} else {
MARK_DELETED (&chain->points[i]);
}
}
}
/* stage2: polygon simplification using Douglas-Peucker */
simplified = FALSE;
do {
last = &contour->chain.points[0];
iter_init (&furthest, contour);
max = 0;
for (chain = &contour->chain; chain; chain = chain->next) {
for (i = 0; i < chain->num_points; i++) {
uint64_t d;
if (DELETED (&chain->points[i]))
continue;
d = point_distance_sq (last, &chain->points[i]);
if (d > max) {
furthest.chain = chain;
furthest.point = &chain->points[i];
max = d;
}
}
}
assert (max);
simplified = FALSE;
iter_init (&iter, contour);
simplified |= _cairo_contour_simplify_chain (contour, tolerance,
&iter, &furthest);
iter_init_last (&iter, contour);
if (! iter_equal (&furthest, &iter))
simplified |= _cairo_contour_simplify_chain (contour, tolerance,
&furthest, &iter);
} while (simplified);
iter_init (&iter, contour);
for (chain = &contour->chain; chain; chain = chain->next) {
int num_points = chain->num_points;
chain->num_points = 0;
for (i = 0; i < num_points; i++) {
if (! DELETED(&chain->points[i])) {
if (iter.point != &chain->points[i])
*iter.point = chain->points[i];
iter.chain->num_points++;
iter_next (&iter);
}
}
}
if (iter.chain) {
cairo_contour_chain_t *next;
for (chain = iter.chain->next; chain; chain = next) {
next = chain->next;
free (chain);
}
iter.chain->next = NULL;
contour->tail = iter.chain;
}
}
void
_cairo_contour_reset (cairo_contour_t *contour)
{
_cairo_contour_fini (contour);
_cairo_contour_init (contour, contour->direction);
}
void
_cairo_contour_fini (cairo_contour_t *contour)
{
cairo_contour_chain_t *chain, *next;
for (chain = contour->chain.next; chain; chain = next) {
next = chain->next;
free (chain);
}
}
void
_cairo_debug_print_contour (FILE *file, cairo_contour_t *contour)
{
cairo_contour_chain_t *chain;
int num_points, size_points;
int i;
num_points = 0;
size_points = 0;
for (chain = &contour->chain; chain; chain = chain->next) {
num_points += chain->num_points;
size_points += chain->size_points;
}
fprintf (file, "contour: direction=%d, num_points=%d / %d\n",
contour->direction, num_points, size_points);
num_points = 0;
for (chain = &contour->chain; chain; chain = chain->next) {
for (i = 0; i < chain->num_points; i++) {
fprintf (file, " [%d] = (%f, %f)\n",
num_points++,
_cairo_fixed_to_double (chain->points[i].x),
_cairo_fixed_to_double (chain->points[i].y));
}
}
}
void
__cairo_contour_remove_last_chain (cairo_contour_t *contour)
{
cairo_contour_chain_t *chain;
if (contour->tail == &contour->chain)
return;
for (chain = &contour->chain; chain->next != contour->tail; chain = chain->next)
;
free (contour->tail);
contour->tail = chain;
chain->next = NULL;
}

View File

@@ -0,0 +1,85 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2012 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 Chris Wilson
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_DAMAGE_PRIVATE_H
#define CAIRO_DAMAGE_PRIVATE_H
#include "cairo-types-private.h"
#include <pixman.h>
CAIRO_BEGIN_DECLS
struct _cairo_damage {
cairo_status_t status;
cairo_region_t *region;
int dirty, remain;
struct _cairo_damage_chunk {
struct _cairo_damage_chunk *next;
cairo_box_t *base;
int count;
int size;
} chunks, *tail;
cairo_box_t boxes[32];
};
cairo_private cairo_damage_t *
_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);
cairo_private cairo_damage_t *
_cairo_damage_add_rectangle (cairo_damage_t *damage,
const cairo_rectangle_int_t *rect);
cairo_private cairo_damage_t *
_cairo_damage_add_region (cairo_damage_t *damage,
const cairo_region_t *region);
cairo_private cairo_damage_t *
_cairo_damage_reduce (cairo_damage_t *damage);
cairo_private void
_cairo_damage_destroy (cairo_damage_t *damage);
CAIRO_END_DECLS
#endif /* CAIRO_DAMAGE_PRIVATE_H */

View File

@@ -0,0 +1,241 @@
/*
* Copyright © 2012 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-damage-private.h"
#include "cairo-region-private.h"
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;
damage = malloc (sizeof (*damage));
if (unlikely (damage == NULL)) {
_cairo_error_throw(CAIRO_STATUS_NO_MEMORY);
return (cairo_damage_t *) &__cairo_damage__nil;
}
damage->status = CAIRO_STATUS_SUCCESS;
damage->region = NULL;
damage->dirty = 0;
damage->tail = &damage->chunks;
damage->chunks.base = damage->boxes;
damage->chunks.size = ARRAY_LENGTH(damage->boxes);
damage->chunks.count = 0;
damage->chunks.next = NULL;
damage->remain = damage->chunks.size;
return damage;
}
void
_cairo_damage_destroy (cairo_damage_t *damage)
{
struct _cairo_damage_chunk *chunk, *next;
if (damage == (cairo_damage_t *) &__cairo_damage__nil)
return;
for (chunk = damage->chunks.next; chunk != NULL; chunk = next) {
next = chunk->next;
free (chunk);
}
cairo_region_destroy (damage->region);
free (damage);
}
static cairo_damage_t *
_cairo_damage_add_boxes(cairo_damage_t *damage,
const cairo_box_t *boxes,
int count)
{
struct _cairo_damage_chunk *chunk;
int n, size;
TRACE ((stderr, "%s x%d\n", __FUNCTION__, count));
if (damage == NULL)
damage = _cairo_damage_create ();
if (damage->status)
return damage;
damage->dirty += count;
n = count;
if (n > damage->remain)
n = damage->remain;
memcpy (damage->tail->base + damage->tail->count, boxes,
n * sizeof (cairo_box_t));
count -= n;
damage->tail->count += n;
damage->remain -= n;
if (count == 0)
return damage;
size = 2 * damage->tail->size;
if (size < count)
size = (count + 64) & ~63;
chunk = malloc (sizeof (*chunk) + sizeof (cairo_box_t) * size);
if (unlikely (chunk == NULL)) {
_cairo_damage_destroy (damage);
return (cairo_damage_t *) &__cairo_damage__nil;
}
chunk->next = NULL;
chunk->base = (cairo_box_t *) (chunk + 1);
chunk->size = size;
chunk->count = count;
damage->tail->next = chunk;
damage->tail = chunk;
memcpy (damage->tail->base, boxes + n,
count * sizeof (cairo_box_t));
damage->remain = size - count;
return damage;
}
cairo_damage_t *
_cairo_damage_add_box(cairo_damage_t *damage,
const cairo_box_t *box)
{
TRACE ((stderr, "%s: (%d, %d),(%d, %d)\n", __FUNCTION__,
box->p1.x, box->p1.y, box->p2.x, box->p2.y));
return _cairo_damage_add_boxes(damage, box, 1);
}
cairo_damage_t *
_cairo_damage_add_rectangle(cairo_damage_t *damage,
const cairo_rectangle_int_t *r)
{
cairo_box_t box;
TRACE ((stderr, "%s: (%d, %d)x(%d, %d)\n", __FUNCTION__,
r->x, r->y, r->width, r->height));
box.p1.x = r->x;
box.p1.y = r->y;
box.p2.x = r->x + r->width;
box.p2.y = r->y + r->height;
return _cairo_damage_add_boxes(damage, &box, 1);
}
cairo_damage_t *
_cairo_damage_add_region (cairo_damage_t *damage,
const cairo_region_t *region)
{
cairo_box_t *boxes;
int nbox;
TRACE ((stderr, "%s\n", __FUNCTION__));
boxes = _cairo_region_get_boxes (region, &nbox);
return _cairo_damage_add_boxes(damage, boxes, nbox);
}
cairo_damage_t *
_cairo_damage_reduce (cairo_damage_t *damage)
{
cairo_box_t *free_boxes = NULL;
cairo_box_t *boxes, *b;
struct _cairo_damage_chunk *chunk, *last;
TRACE ((stderr, "%s: dirty=%d\n", __FUNCTION__,
damage ? damage->dirty : -1));
if (damage == NULL || damage->status || !damage->dirty)
return damage;
if (damage->region) {
cairo_region_t *region;
region = damage->region;
damage->region = NULL;
damage = _cairo_damage_add_region (damage, region);
cairo_region_destroy (region);
if (unlikely (damage->status))
return damage;
}
boxes = damage->tail->base;
if (damage->dirty > damage->tail->size) {
boxes = free_boxes = malloc (damage->dirty * sizeof (cairo_box_t));
if (unlikely (boxes == NULL)) {
_cairo_damage_destroy (damage);
return (cairo_damage_t *) &__cairo_damage__nil;
}
b = boxes;
last = NULL;
} else {
b = boxes + damage->tail->count;
last = damage->tail;
}
for (chunk = &damage->chunks; chunk != last; chunk = chunk->next) {
memcpy (b, chunk->base, chunk->count * sizeof (cairo_box_t));
b += chunk->count;
}
damage->region = _cairo_region_create_from_boxes (boxes, damage->dirty);
free (free_boxes);
if (unlikely (damage->region->status)) {
_cairo_damage_destroy (damage);
return (cairo_damage_t *) &__cairo_damage__nil;
}
damage->dirty = 0;
return damage;
}

View File

@@ -0,0 +1,304 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
#include "cairo-image-surface-private.h"
/**
* cairo_debug_reset_static_data:
*
* Resets all static data within cairo to its original state,
* (ie. identical to the state at the time of program invocation). For
* example, all caches within cairo will be flushed empty.
*
* This function is intended to be useful when using memory-checking
* tools such as valgrind. When valgrind's memcheck analyzes a
* cairo-using program without a call to cairo_debug_reset_static_data(),
* it will report all data reachable via cairo's static objects as
* "still reachable". Calling cairo_debug_reset_static_data() just prior
* to program termination will make it easier to get squeaky clean
* reports from valgrind.
*
* WARNING: It is only safe to call this function when there are no
* active cairo objects remaining, (ie. the appropriate destroy
* functions have been called as necessary). If there are active cairo
* objects, this call is likely to cause a crash, (eg. an assertion
* failure due to a hash table being destroyed when non-empty).
*
* Since: 1.0
**/
void
cairo_debug_reset_static_data (void)
{
CAIRO_MUTEX_INITIALIZE ();
_cairo_scaled_font_map_destroy ();
_cairo_toy_font_face_reset_static_data ();
#if CAIRO_HAS_FT_FONT
_cairo_ft_font_reset_static_data ();
#endif
#if CAIRO_HAS_WIN32_FONT
_cairo_win32_font_reset_static_data ();
#endif
_cairo_intern_string_reset_static_data ();
_cairo_scaled_font_reset_static_data ();
_cairo_pattern_reset_static_data ();
_cairo_clip_reset_static_data ();
_cairo_image_reset_static_data ();
#if CAIRO_HAS_DRM_SURFACE
_cairo_drm_device_reset_static_data ();
#endif
_cairo_default_context_reset_static_data ();
#if CAIRO_HAS_COGL_SURFACE
_cairo_cogl_context_reset_static_data ();
#endif
CAIRO_MUTEX_FINALIZE ();
}
#if HAVE_VALGRIND
void
_cairo_debug_check_image_surface_is_defined (const cairo_surface_t *surface)
{
const cairo_image_surface_t *image = (cairo_image_surface_t *) surface;
const uint8_t *bits;
int row, width;
if (surface == NULL)
return;
if (! RUNNING_ON_VALGRIND)
return;
bits = image->data;
switch (image->format) {
case CAIRO_FORMAT_A1:
width = (image->width + 7)/8;
break;
case CAIRO_FORMAT_A8:
width = image->width;
break;
case CAIRO_FORMAT_RGB16_565:
width = image->width*2;
break;
case CAIRO_FORMAT_RGB24:
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_ARGB32:
width = image->width*4;
break;
case CAIRO_FORMAT_INVALID:
default:
/* XXX compute width from pixman bpp */
return;
}
for (row = 0; row < image->height; row++) {
VALGRIND_CHECK_MEM_IS_DEFINED (bits, width);
/* and then silence any future valgrind warnings */
VALGRIND_MAKE_MEM_DEFINED (bits, width);
bits += image->stride;
}
}
#endif
#if 0
void
_cairo_image_surface_write_to_ppm (cairo_image_surface_t *isurf, const char *fn)
{
char *fmt;
if (isurf->format == CAIRO_FORMAT_ARGB32 || isurf->format == CAIRO_FORMAT_RGB24)
fmt = "P6";
else if (isurf->format == CAIRO_FORMAT_A8)
fmt = "P5";
else
return;
FILE *fp = fopen(fn, "wb");
if (!fp)
return;
fprintf (fp, "%s %d %d 255\n", fmt,isurf->width, isurf->height);
for (int j = 0; j < isurf->height; j++) {
unsigned char *row = isurf->data + isurf->stride * j;
for (int i = 0; i < isurf->width; i++) {
if (isurf->format == CAIRO_FORMAT_ARGB32 || isurf->format == CAIRO_FORMAT_RGB24) {
unsigned char r = *row++;
unsigned char g = *row++;
unsigned char b = *row++;
*row++;
putc(r, fp);
putc(g, fp);
putc(b, fp);
} else {
unsigned char a = *row++;
putc(a, fp);
}
}
}
fclose (fp);
fprintf (stderr, "Wrote %s\n", fn);
}
#endif
static cairo_status_t
_print_move_to (void *closure,
const cairo_point_t *point)
{
fprintf (closure,
" %f %f m",
_cairo_fixed_to_double (point->x),
_cairo_fixed_to_double (point->y));
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_print_line_to (void *closure,
const cairo_point_t *point)
{
fprintf (closure,
" %f %f l",
_cairo_fixed_to_double (point->x),
_cairo_fixed_to_double (point->y));
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_print_curve_to (void *closure,
const cairo_point_t *p1,
const cairo_point_t *p2,
const cairo_point_t *p3)
{
fprintf (closure,
" %f %f %f %f %f %f c",
_cairo_fixed_to_double (p1->x),
_cairo_fixed_to_double (p1->y),
_cairo_fixed_to_double (p2->x),
_cairo_fixed_to_double (p2->y),
_cairo_fixed_to_double (p3->x),
_cairo_fixed_to_double (p3->y));
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_print_close (void *closure)
{
fprintf (closure, " h");
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_debug_print_path (FILE *stream, cairo_path_fixed_t *path)
{
cairo_status_t status;
cairo_box_t box;
fprintf (stream,
"path: extents=(%f, %f), (%f, %f)\n",
_cairo_fixed_to_double (path->extents.p1.x),
_cairo_fixed_to_double (path->extents.p1.y),
_cairo_fixed_to_double (path->extents.p2.x),
_cairo_fixed_to_double (path->extents.p2.y));
status = _cairo_path_fixed_interpret (path,
_print_move_to,
_print_line_to,
_print_curve_to,
_print_close,
stream);
assert (status == CAIRO_STATUS_SUCCESS);
if (_cairo_path_fixed_is_box (path, &box)) {
fprintf (stream, "[box (%d, %d), (%d, %d)]",
box.p1.x, box.p1.y, box.p2.x, box.p2.y);
}
printf ("\n");
}
void
_cairo_debug_print_polygon (FILE *stream, cairo_polygon_t *polygon)
{
int n;
fprintf (stream,
"polygon: extents=(%f, %f), (%f, %f)\n",
_cairo_fixed_to_double (polygon->extents.p1.x),
_cairo_fixed_to_double (polygon->extents.p1.y),
_cairo_fixed_to_double (polygon->extents.p2.x),
_cairo_fixed_to_double (polygon->extents.p2.y));
if (polygon->num_limits) {
fprintf (stream,
" : limit=(%f, %f), (%f, %f) x %d\n",
_cairo_fixed_to_double (polygon->limit.p1.x),
_cairo_fixed_to_double (polygon->limit.p1.y),
_cairo_fixed_to_double (polygon->limit.p2.x),
_cairo_fixed_to_double (polygon->limit.p2.y),
polygon->num_limits);
}
for (n = 0; n < polygon->num_edges; n++) {
cairo_edge_t *edge = &polygon->edges[n];
fprintf (stream,
" [%d] = [(%f, %f), (%f, %f)], top=%f, bottom=%f, dir=%d\n",
n,
_cairo_fixed_to_double (edge->line.p1.x),
_cairo_fixed_to_double (edge->line.p1.y),
_cairo_fixed_to_double (edge->line.p2.x),
_cairo_fixed_to_double (edge->line.p2.y),
_cairo_fixed_to_double (edge->top),
_cairo_fixed_to_double (edge->bottom),
edge->dir);
}
}

View File

@@ -0,0 +1,68 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@redhat.com>
*/
#ifndef CAIRO_DEFAULT_CONTEXT_PRIVATE_H
#define CAIRO_DEFAULT_CONTEXT_PRIVATE_H
#include "cairo-private.h"
#include "cairo-gstate-private.h"
#include "cairo-path-fixed-private.h"
CAIRO_BEGIN_DECLS
typedef struct _cairo_default_context cairo_default_context_t;
struct _cairo_default_context {
cairo_t base;
cairo_gstate_t *gstate;
cairo_gstate_t gstate_tail[2];
cairo_gstate_t *gstate_freelist;
cairo_path_fixed_t path[1];
};
cairo_private cairo_t *
_cairo_default_context_create (void *target);
cairo_private cairo_status_t
_cairo_default_context_init (cairo_default_context_t *cr, void *target);
cairo_private void
_cairo_default_context_fini (cairo_default_context_t *cr);
CAIRO_END_DECLS
#endif /* CAIRO_DEFAULT_CONTEXT_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,156 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006 Adrian Johnson
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Adrian Johnson.
*
* Author(s):
* Adrian Johnson <ajohnson@redneon.com>
*/
#include "cairoint.h"
#if CAIRO_HAS_DEFLATE_STREAM
#include "cairo-error-private.h"
#include "cairo-output-stream-private.h"
#include <zlib.h>
#define BUFFER_SIZE 16384
typedef struct _cairo_deflate_stream {
cairo_output_stream_t base;
cairo_output_stream_t *output;
z_stream zlib_stream;
unsigned char input_buf[BUFFER_SIZE];
unsigned char output_buf[BUFFER_SIZE];
} cairo_deflate_stream_t;
static void
cairo_deflate_stream_deflate (cairo_deflate_stream_t *stream, cairo_bool_t flush)
{
int ret;
cairo_bool_t finished;
do {
ret = deflate (&stream->zlib_stream, flush ? Z_FINISH : Z_NO_FLUSH);
if (flush || stream->zlib_stream.avail_out == 0)
{
_cairo_output_stream_write (stream->output,
stream->output_buf,
BUFFER_SIZE - stream->zlib_stream.avail_out);
stream->zlib_stream.next_out = stream->output_buf;
stream->zlib_stream.avail_out = BUFFER_SIZE;
}
finished = TRUE;
if (stream->zlib_stream.avail_in != 0)
finished = FALSE;
if (flush && ret != Z_STREAM_END)
finished = FALSE;
} while (!finished);
stream->zlib_stream.next_in = stream->input_buf;
}
static cairo_status_t
_cairo_deflate_stream_write (cairo_output_stream_t *base,
const unsigned char *data,
unsigned int length)
{
cairo_deflate_stream_t *stream = (cairo_deflate_stream_t *) base;
unsigned int count;
const unsigned char *p = data;
while (length) {
count = length;
if (count > BUFFER_SIZE - stream->zlib_stream.avail_in)
count = BUFFER_SIZE - stream->zlib_stream.avail_in;
memcpy (stream->input_buf + stream->zlib_stream.avail_in, p, count);
p += count;
stream->zlib_stream.avail_in += count;
length -= count;
if (stream->zlib_stream.avail_in == BUFFER_SIZE)
cairo_deflate_stream_deflate (stream, FALSE);
}
return _cairo_output_stream_get_status (stream->output);
}
static cairo_status_t
_cairo_deflate_stream_close (cairo_output_stream_t *base)
{
cairo_deflate_stream_t *stream = (cairo_deflate_stream_t *) base;
cairo_deflate_stream_deflate (stream, TRUE);
deflateEnd (&stream->zlib_stream);
return _cairo_output_stream_get_status (stream->output);
}
cairo_output_stream_t *
_cairo_deflate_stream_create (cairo_output_stream_t *output)
{
cairo_deflate_stream_t *stream;
if (output->status)
return _cairo_output_stream_create_in_error (output->status);
stream = malloc (sizeof (cairo_deflate_stream_t));
if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base,
_cairo_deflate_stream_write,
NULL,
_cairo_deflate_stream_close);
stream->output = output;
stream->zlib_stream.zalloc = Z_NULL;
stream->zlib_stream.zfree = Z_NULL;
stream->zlib_stream.opaque = Z_NULL;
if (deflateInit (&stream->zlib_stream, Z_DEFAULT_COMPRESSION) != Z_OK) {
free (stream);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
stream->zlib_stream.next_in = stream->input_buf;
stream->zlib_stream.avail_in = 0;
stream->zlib_stream.next_out = stream->output_buf;
stream->zlib_stream.avail_out = BUFFER_SIZE;
return &stream->base;
}
#endif /* CAIRO_HAS_DEFLATE_STREAM */

View File

@@ -0,0 +1,123 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006 Red Hat, Inc.
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#ifndef CAIRO_DEPRECATED_H
#define CAIRO_DEPRECATED_H
#define CAIRO_FONT_TYPE_ATSUI CAIRO_FONT_TYPE_QUARTZ
/* Obsolete functions. These definitions exist to coerce the compiler
* into providing a little bit of guidance with its error
* messages. The idea is to help users port their old code without
* having to dig through lots of documentation.
*
* The first set of REPLACED_BY functions is for functions whose names
* have just been changed. So fixing these up is mechanical, (and
* automated by means of the cairo/util/cairo-api-update script.
*
* The second set of DEPRECATED_BY functions is for functions where
* the replacement is used in a different way, (ie. different
* arguments, multiple functions instead of one, etc). Fixing these up
* will require a bit more work on the user's part, (and hopefully we
* can get cairo-api-update to find these and print some guiding
* information).
*/
#define cairo_current_font_extents cairo_current_font_extents_REPLACED_BY_cairo_font_extents
#define cairo_get_font_extents cairo_get_font_extents_REPLACED_BY_cairo_font_extents
#define cairo_current_operator cairo_current_operator_REPLACED_BY_cairo_get_operator
#define cairo_current_tolerance cairo_current_tolerance_REPLACED_BY_cairo_get_tolerance
#define cairo_current_point cairo_current_point_REPLACED_BY_cairo_get_current_point
#define cairo_current_fill_rule cairo_current_fill_rule_REPLACED_BY_cairo_get_fill_rule
#define cairo_current_line_width cairo_current_line_width_REPLACED_BY_cairo_get_line_width
#define cairo_current_line_cap cairo_current_line_cap_REPLACED_BY_cairo_get_line_cap
#define cairo_current_line_join cairo_current_line_join_REPLACED_BY_cairo_get_line_join
#define cairo_current_miter_limit cairo_current_miter_limit_REPLACED_BY_cairo_get_miter_limit
#define cairo_current_matrix cairo_current_matrix_REPLACED_BY_cairo_get_matrix
#define cairo_current_target_surface cairo_current_target_surface_REPLACED_BY_cairo_get_target
#define cairo_get_status cairo_get_status_REPLACED_BY_cairo_status
#define cairo_concat_matrix cairo_concat_matrix_REPLACED_BY_cairo_transform
#define cairo_scale_font cairo_scale_font_REPLACED_BY_cairo_set_font_size
#define cairo_select_font cairo_select_font_REPLACED_BY_cairo_select_font_face
#define cairo_transform_font cairo_transform_font_REPLACED_BY_cairo_set_font_matrix
#define cairo_transform_point cairo_transform_point_REPLACED_BY_cairo_user_to_device
#define cairo_transform_distance cairo_transform_distance_REPLACED_BY_cairo_user_to_device_distance
#define cairo_inverse_transform_point cairo_inverse_transform_point_REPLACED_BY_cairo_device_to_user
#define cairo_inverse_transform_distance cairo_inverse_transform_distance_REPLACED_BY_cairo_device_to_user_distance
#define cairo_init_clip cairo_init_clip_REPLACED_BY_cairo_reset_clip
#define cairo_surface_create_for_image cairo_surface_create_for_image_REPLACED_BY_cairo_image_surface_create_for_data
#define cairo_default_matrix cairo_default_matrix_REPLACED_BY_cairo_identity_matrix
#define cairo_matrix_set_affine cairo_matrix_set_affine_REPLACED_BY_cairo_matrix_init
#define cairo_matrix_set_identity cairo_matrix_set_identity_REPLACED_BY_cairo_matrix_init_identity
#define cairo_pattern_add_color_stop cairo_pattern_add_color_stop_REPLACED_BY_cairo_pattern_add_color_stop_rgba
#define cairo_set_rgb_color cairo_set_rgb_color_REPLACED_BY_cairo_set_source_rgb
#define cairo_set_pattern cairo_set_pattern_REPLACED_BY_cairo_set_source
#define cairo_xlib_surface_create_for_pixmap_with_visual cairo_xlib_surface_create_for_pixmap_with_visual_REPLACED_BY_cairo_xlib_surface_create
#define cairo_xlib_surface_create_for_window_with_visual cairo_xlib_surface_create_for_window_with_visual_REPLACED_BY_cairo_xlib_surface_create
#define cairo_xcb_surface_create_for_pixmap_with_visual cairo_xcb_surface_create_for_pixmap_with_visual_REPLACED_BY_cairo_xcb_surface_create
#define cairo_xcb_surface_create_for_window_with_visual cairo_xcb_surface_create_for_window_with_visual_REPLACED_BY_cairo_xcb_surface_create
#define cairo_ps_surface_set_dpi cairo_ps_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution
#define cairo_pdf_surface_set_dpi cairo_pdf_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution
#define cairo_svg_surface_set_dpi cairo_svg_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution
#define cairo_atsui_font_face_create_for_atsu_font_id cairo_atsui_font_face_create_for_atsu_font_id_REPLACED_BY_cairo_quartz_font_face_create_for_atsu_font_id
#define cairo_current_path cairo_current_path_DEPRECATED_BY_cairo_copy_path
#define cairo_current_path_flat cairo_current_path_flat_DEPRECATED_BY_cairo_copy_path_flat
#define cairo_get_path cairo_get_path_DEPRECATED_BY_cairo_copy_path
#define cairo_get_path_flat cairo_get_path_flat_DEPRECATED_BY_cairo_get_path_flat
#define cairo_set_alpha cairo_set_alpha_DEPRECATED_BY_cairo_set_source_rgba_OR_cairo_paint_with_alpha
#define cairo_show_surface cairo_show_surface_DEPRECATED_BY_cairo_set_source_surface_AND_cairo_paint
#define cairo_copy cairo_copy_DEPRECATED_BY_cairo_create_AND_MANY_INDIVIDUAL_FUNCTIONS
#define cairo_surface_set_repeat cairo_surface_set_repeat_DEPRECATED_BY_cairo_pattern_set_extend
#define cairo_surface_set_matrix cairo_surface_set_matrix_DEPRECATED_BY_cairo_pattern_set_matrix
#define cairo_surface_get_matrix cairo_surface_get_matrix_DEPRECATED_BY_cairo_pattern_get_matrix
#define cairo_surface_set_filter cairo_surface_set_filter_DEPRECATED_BY_cairo_pattern_set_filter
#define cairo_surface_get_filter cairo_surface_get_filter_DEPRECATED_BY_cairo_pattern_get_filter
#define cairo_matrix_create cairo_matrix_create_DEPRECATED_BY_cairo_matrix_t
#define cairo_matrix_destroy cairo_matrix_destroy_DEPRECATED_BY_cairo_matrix_t
#define cairo_matrix_copy cairo_matrix_copy_DEPRECATED_BY_cairo_matrix_t
#define cairo_matrix_get_affine cairo_matrix_get_affine_DEPRECATED_BY_cairo_matrix_t
#define cairo_set_target_surface cairo_set_target_surface_DEPRECATED_BY_cairo_create
#define cairo_set_target_image cairo_set_target_image_DEPRECATED_BY_cairo_image_surface_create_for_data
#define cairo_set_target_pdf cairo_set_target_pdf_DEPRECATED_BY_cairo_pdf_surface_create
#define cairo_set_target_png cairo_set_target_png_DEPRECATED_BY_cairo_surface_write_to_png
#define cairo_set_target_ps cairo_set_target_ps_DEPRECATED_BY_cairo_ps_surface_create
#define cairo_set_target_quartz cairo_set_target_quartz_DEPRECATED_BY_cairo_quartz_surface_create
#define cairo_set_target_win32 cairo_set_target_win32_DEPRECATED_BY_cairo_win32_surface_create
#define cairo_set_target_xcb cairo_set_target_xcb_DEPRECATED_BY_cairo_xcb_surface_create
#define cairo_set_target_drawable cairo_set_target_drawable_DEPRECATED_BY_cairo_xlib_surface_create
#define cairo_get_status_string cairo_get_status_string_DEPRECATED_BY_cairo_status_AND_cairo_status_to_string
#define cairo_status_string cairo_status_string_DEPRECATED_BY_cairo_status_AND_cairo_status_to_string
#endif /* CAIRO_DEPRECATED_H */

View File

@@ -0,0 +1,86 @@
/* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Intel Corporation.
*
* Contributors(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef _CAIRO_DEVICE_PRIVATE_H_
#define _CAIRO_DEVICE_PRIVATE_H_
#include "cairo-compiler-private.h"
#include "cairo-mutex-private.h"
#include "cairo-reference-count-private.h"
#include "cairo-types-private.h"
struct _cairo_device {
cairo_reference_count_t ref_count;
cairo_status_t status;
cairo_user_data_array_t user_data;
const cairo_device_backend_t *backend;
cairo_recursive_mutex_t mutex;
unsigned mutex_depth;
cairo_bool_t finished;
};
struct _cairo_device_backend {
cairo_device_type_t type;
void (*lock) (void *device);
void (*unlock) (void *device);
cairo_warn cairo_status_t (*flush) (void *device);
void (*finish) (void *device);
void (*destroy) (void *device);
};
cairo_private cairo_device_t *
_cairo_device_create_in_error (cairo_status_t status);
cairo_private void
_cairo_device_init (cairo_device_t *device,
const cairo_device_backend_t *backend);
cairo_private cairo_status_t
_cairo_device_set_error (cairo_device_t *device,
cairo_status_t error);
slim_hidden_proto_no_warn (cairo_device_reference);
slim_hidden_proto (cairo_device_acquire);
slim_hidden_proto (cairo_device_release);
slim_hidden_proto (cairo_device_flush);
slim_hidden_proto (cairo_device_finish);
slim_hidden_proto (cairo_device_destroy);
#endif /* _CAIRO_DEVICE_PRIVATE_H_ */

View File

@@ -0,0 +1,540 @@
/* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Intel Corporation.
*
* Contributors(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-device-private.h"
#include "cairo-error-private.h"
/**
* SECTION:cairo-device
* @Title: cairo_device_t
* @Short_Description: interface to underlying rendering system
* @See_Also: #cairo_surface_t
*
* Devices are the abstraction Cairo employs for the rendering system
* used by a #cairo_surface_t. You can get the device of a surface using
* cairo_surface_get_device().
*
* Devices are created using custom functions specific to the rendering
* system you want to use. See the documentation for the surface types
* for those functions.
*
* An important function that devices fulfill is sharing access to the
* rendering system between Cairo and your application. If you want to
* access a device directly that you used to draw to with Cairo, you must
* first call cairo_device_flush() to ensure that Cairo finishes all
* operations on the device and resets it to a clean state.
*
* Cairo also provides the functions cairo_device_acquire() and
* cairo_device_release() to synchronize access to the rendering system
* in a multithreaded environment. This is done internally, but can also
* be used by applications.
*
* Putting this all together, a function that works with devices should
* look something like this:
* <informalexample><programlisting>
* void
* my_device_modifying_function (cairo_device_t *device)
* {
* cairo_status_t status;
*
* // Ensure the device is properly reset
* cairo_device_flush (device);
* // Try to acquire the device
* status = cairo_device_acquire (device);
* if (status != CAIRO_STATUS_SUCCESS) {
* printf ("Failed to acquire the device: %s\n", cairo_status_to_string (status));
* return;
* }
*
* // Do the custom operations on the device here.
* // But do not call any Cairo functions that might acquire devices.
*
* // Release the device when done.
* cairo_device_release (device);
* }
* </programlisting></informalexample>
*
* <note><para>Please refer to the documentation of each backend for
* additional usage requirements, guarantees provided, and
* interactions with existing surface API of the device functions for
* surfaces of that type.
* </para></note>
**/
static const cairo_device_t _nil_device = {
CAIRO_REFERENCE_COUNT_INVALID,
CAIRO_STATUS_NO_MEMORY,
};
static const cairo_device_t _mismatch_device = {
CAIRO_REFERENCE_COUNT_INVALID,
CAIRO_STATUS_DEVICE_TYPE_MISMATCH,
};
static const cairo_device_t _invalid_device = {
CAIRO_REFERENCE_COUNT_INVALID,
CAIRO_STATUS_DEVICE_ERROR,
};
cairo_device_t *
_cairo_device_create_in_error (cairo_status_t status)
{
switch (status) {
case CAIRO_STATUS_NO_MEMORY:
return (cairo_device_t *) &_nil_device;
case CAIRO_STATUS_DEVICE_ERROR:
return (cairo_device_t *) &_invalid_device;
case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
return (cairo_device_t *) &_mismatch_device;
case CAIRO_STATUS_SUCCESS:
case CAIRO_STATUS_LAST_STATUS:
ASSERT_NOT_REACHED;
/* fall-through */
case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
case CAIRO_STATUS_INVALID_STATUS:
case CAIRO_STATUS_INVALID_FORMAT:
case CAIRO_STATUS_INVALID_VISUAL:
case CAIRO_STATUS_READ_ERROR:
case CAIRO_STATUS_WRITE_ERROR:
case CAIRO_STATUS_FILE_NOT_FOUND:
case CAIRO_STATUS_TEMP_FILE_ERROR:
case CAIRO_STATUS_INVALID_STRIDE:
case CAIRO_STATUS_INVALID_SIZE:
case CAIRO_STATUS_INVALID_RESTORE:
case CAIRO_STATUS_INVALID_POP_GROUP:
case CAIRO_STATUS_NO_CURRENT_POINT:
case CAIRO_STATUS_INVALID_MATRIX:
case CAIRO_STATUS_NULL_POINTER:
case CAIRO_STATUS_INVALID_STRING:
case CAIRO_STATUS_INVALID_PATH_DATA:
case CAIRO_STATUS_SURFACE_FINISHED:
case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
case CAIRO_STATUS_INVALID_DASH:
case CAIRO_STATUS_INVALID_DSC_COMMENT:
case CAIRO_STATUS_INVALID_INDEX:
case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
case CAIRO_STATUS_FONT_TYPE_MISMATCH:
case CAIRO_STATUS_USER_FONT_IMMUTABLE:
case CAIRO_STATUS_USER_FONT_ERROR:
case CAIRO_STATUS_NEGATIVE_COUNT:
case CAIRO_STATUS_INVALID_CLUSTERS:
case CAIRO_STATUS_INVALID_SLANT:
case CAIRO_STATUS_INVALID_WEIGHT:
case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
case CAIRO_STATUS_INVALID_CONTENT:
case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION:
case CAIRO_STATUS_DEVICE_FINISHED:
default:
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_device_t *) &_nil_device;
}
}
void
_cairo_device_init (cairo_device_t *device,
const cairo_device_backend_t *backend)
{
CAIRO_REFERENCE_COUNT_INIT (&device->ref_count, 1);
device->status = CAIRO_STATUS_SUCCESS;
device->backend = backend;
CAIRO_RECURSIVE_MUTEX_INIT (device->mutex);
device->mutex_depth = 0;
device->finished = FALSE;
_cairo_user_data_array_init (&device->user_data);
}
/**
* cairo_device_reference:
* @device: a #cairo_device_t
*
* Increases the reference count on @device by one. This prevents
* @device from being destroyed until a matching call to
* cairo_device_destroy() is made.
*
* The number of references to a #cairo_device_t can be get using
* cairo_device_get_reference_count().
*
* Return value: the referenced #cairo_device_t.
*
* Since: 1.10
**/
cairo_device_t *
cairo_device_reference (cairo_device_t *device)
{
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
{
return device;
}
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
_cairo_reference_count_inc (&device->ref_count);
return device;
}
slim_hidden_def (cairo_device_reference);
/**
* cairo_device_status:
* @device: a #cairo_device_t
*
* Checks whether an error has previously occurred for this
* device.
*
* Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
* the device is in an error state.
*
* Since: 1.10
**/
cairo_status_t
cairo_device_status (cairo_device_t *device)
{
if (device == NULL)
return CAIRO_STATUS_NULL_POINTER;
return device->status;
}
/**
* cairo_device_flush:
* @device: a #cairo_device_t
*
* Finish any pending operations for the device and also restore any
* temporary modifications cairo has made to the device's state.
* This function must be called before switching from using the
* device with Cairo to operating on it directly with native APIs.
* If the device doesn't support direct access, then this function
* does nothing.
*
* This function may acquire devices.
*
* Since: 1.10
**/
void
cairo_device_flush (cairo_device_t *device)
{
cairo_status_t status;
if (device == NULL || device->status)
return;
if (device->finished)
return;
if (device->backend->flush != NULL) {
status = device->backend->flush (device);
if (unlikely (status))
status = _cairo_device_set_error (device, status);
}
}
slim_hidden_def (cairo_device_flush);
/**
* cairo_device_finish:
* @device: the #cairo_device_t to finish
*
* This function finishes the device and drops all references to
* external resources. All surfaces, fonts and other objects created
* for this @device will be finished, too.
* Further operations on the @device will not affect the @device but
* will instead trigger a %CAIRO_STATUS_DEVICE_FINISHED error.
*
* When the last call to cairo_device_destroy() decreases the
* reference count to zero, cairo will call cairo_device_finish() if
* it hasn't been called already, before freeing the resources
* associated with the device.
*
* This function may acquire devices.
*
* Since: 1.10
**/
void
cairo_device_finish (cairo_device_t *device)
{
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
{
return;
}
if (device->finished)
return;
cairo_device_flush (device);
if (device->backend->finish != NULL)
device->backend->finish (device);
/* We only finish the device after the backend's callback returns because
* the device might still be needed during the callback
* (e.g. for cairo_device_acquire ()).
*/
device->finished = TRUE;
}
slim_hidden_def (cairo_device_finish);
/**
* cairo_device_destroy:
* @device: a #cairo_device_t
*
* Decreases the reference count on @device by one. If the result is
* zero, then @device and all associated resources are freed. See
* cairo_device_reference().
*
* This function may acquire devices if the last reference was dropped.
*
* Since: 1.10
**/
void
cairo_device_destroy (cairo_device_t *device)
{
cairo_user_data_array_t user_data;
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
{
return;
}
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
if (! _cairo_reference_count_dec_and_test (&device->ref_count))
return;
cairo_device_finish (device);
assert (device->mutex_depth == 0);
CAIRO_MUTEX_FINI (device->mutex);
user_data = device->user_data;
device->backend->destroy (device);
_cairo_user_data_array_fini (&user_data);
}
slim_hidden_def (cairo_device_destroy);
/**
* cairo_device_get_type:
* @device: a #cairo_device_t
*
* This function returns the type of the device. See #cairo_device_type_t
* for available types.
*
* Return value: The type of @device.
*
* Since: 1.10
**/
cairo_device_type_t
cairo_device_get_type (cairo_device_t *device)
{
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
{
return CAIRO_DEVICE_TYPE_INVALID;
}
return device->backend->type;
}
/**
* cairo_device_acquire:
* @device: a #cairo_device_t
*
* Acquires the @device for the current thread. This function will block
* until no other thread has acquired the device.
*
* If the return value is %CAIRO_STATUS_SUCCESS, you successfully acquired the
* device. From now on your thread owns the device and no other thread will be
* able to acquire it until a matching call to cairo_device_release(). It is
* allowed to recursively acquire the device multiple times from the same
* thread.
*
* <note><para>You must never acquire two different devices at the same time
* unless this is explicitly allowed. Otherwise the possibility of deadlocks
* exist.
*
* As various Cairo functions can acquire devices when called, these functions
* may also cause deadlocks when you call them with an acquired device. So you
* must not have a device acquired when calling them. These functions are
* marked in the documentation.
* </para></note>
*
* Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
* the device is in an error state and could not be
* acquired. After a successful call to cairo_device_acquire(),
* a matching call to cairo_device_release() is required.
*
* Since: 1.10
**/
cairo_status_t
cairo_device_acquire (cairo_device_t *device)
{
if (device == NULL)
return CAIRO_STATUS_SUCCESS;
if (unlikely (device->status))
return device->status;
if (unlikely (device->finished))
return _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_FINISHED);
CAIRO_MUTEX_LOCK (device->mutex);
if (device->mutex_depth++ == 0) {
if (device->backend->lock != NULL)
device->backend->lock (device);
}
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def (cairo_device_acquire);
/**
* cairo_device_release:
* @device: a #cairo_device_t
*
* Releases a @device previously acquired using cairo_device_acquire(). See
* that function for details.
*
* Since: 1.10
**/
void
cairo_device_release (cairo_device_t *device)
{
if (device == NULL)
return;
assert (device->mutex_depth > 0);
if (--device->mutex_depth == 0) {
if (device->backend->unlock != NULL)
device->backend->unlock (device);
}
CAIRO_MUTEX_UNLOCK (device->mutex);
}
slim_hidden_def (cairo_device_release);
cairo_status_t
_cairo_device_set_error (cairo_device_t *device,
cairo_status_t status)
{
if (status == CAIRO_STATUS_SUCCESS)
return CAIRO_STATUS_SUCCESS;
_cairo_status_set_error (&device->status, status);
return _cairo_error (status);
}
/**
* cairo_device_get_reference_count:
* @device: a #cairo_device_t
*
* Returns the current reference count of @device.
*
* Return value: the current reference count of @device. If the
* object is a nil object, 0 will be returned.
*
* Since: 1.10
**/
unsigned int
cairo_device_get_reference_count (cairo_device_t *device)
{
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
return 0;
return CAIRO_REFERENCE_COUNT_GET_VALUE (&device->ref_count);
}
/**
* cairo_device_get_user_data:
* @device: a #cairo_device_t
* @key: the address of the #cairo_user_data_key_t the user data was
* attached to
*
* Return user data previously attached to @device using the
* specified key. If no user data has been attached with the given
* key this function returns %NULL.
*
* Return value: the user data previously attached or %NULL.
*
* Since: 1.10
**/
void *
cairo_device_get_user_data (cairo_device_t *device,
const cairo_user_data_key_t *key)
{
return _cairo_user_data_array_get_data (&device->user_data,
key);
}
/**
* cairo_device_set_user_data:
* @device: a #cairo_device_t
* @key: the address of a #cairo_user_data_key_t to attach the user data to
* @user_data: the user data to attach to the #cairo_device_t
* @destroy: a #cairo_destroy_func_t which will be called when the
* #cairo_t is destroyed or when new user data is attached using the
* same key.
*
* Attach user data to @device. To remove user data from a surface,
* call this function with the key that was used to set it and %NULL
* for @data.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
*
* Since: 1.10
**/
cairo_status_t
cairo_device_set_user_data (cairo_device_t *device,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy)
{
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
return device->status;
return _cairo_user_data_array_set_data (&device->user_data,
key, user_data, destroy);
}

View File

@@ -0,0 +1,544 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2012 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-directfb.h"
#include "cairo-clip-private.h"
#include "cairo-compositor-private.h"
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
#include "cairo-image-surface-inline.h"
#include "cairo-pattern-private.h"
#include "cairo-surface-backend-private.h"
#include "cairo-surface-fallback-private.h"
#include <pixman.h>
#include <directfb.h>
#include <direct/types.h>
#include <direct/debug.h>
#include <direct/memcpy.h>
#include <direct/util.h>
slim_hidden_proto(cairo_directfb_surface_create);
typedef struct _cairo_dfb_surface {
cairo_image_surface_t image;
IDirectFB *dfb;
IDirectFBSurface *dfb_surface;
unsigned blit_premultiplied : 1;
} cairo_dfb_surface_t;
static cairo_content_t
_directfb_format_to_content (DFBSurfacePixelFormat format)
{
cairo_content_t content = 0;
if (DFB_PIXELFORMAT_HAS_ALPHA (format))
content |= CAIRO_CONTENT_ALPHA;
if (DFB_COLOR_BITS_PER_PIXEL (format))
content |= CAIRO_CONTENT_COLOR_ALPHA;
assert(content);
return content;
}
static inline pixman_format_code_t
_directfb_to_pixman_format (DFBSurfacePixelFormat format)
{
switch (format) {
case DSPF_UNKNOWN: return 0;
case DSPF_ARGB1555: return PIXMAN_a1r5g5b5;
case DSPF_RGB16: return PIXMAN_r5g6b5;
case DSPF_RGB24: return PIXMAN_r8g8b8;
case DSPF_RGB32: return PIXMAN_x8r8g8b8;
case DSPF_ARGB: return PIXMAN_a8r8g8b8;
case DSPF_A8: return PIXMAN_a8;
case DSPF_YUY2: return PIXMAN_yuy2;
case DSPF_RGB332: return PIXMAN_r3g3b2;
case DSPF_UYVY: return 0;
case DSPF_I420: return 0;
case DSPF_YV12: return PIXMAN_yv12;
case DSPF_LUT8: return 0;
case DSPF_ALUT44: return 0;
case DSPF_AiRGB: return 0;
case DSPF_A1: return 0; /* bit reversed, oops */
case DSPF_NV12: return 0;
case DSPF_NV16: return 0;
case DSPF_ARGB2554: return 0;
case DSPF_ARGB4444: return PIXMAN_a4r4g4b4;
case DSPF_NV21: return 0;
case DSPF_AYUV: return 0;
case DSPF_A4: return PIXMAN_a4;
case DSPF_ARGB1666: return 0;
case DSPF_ARGB6666: return 0;
case DSPF_RGB18: return 0;
case DSPF_LUT2: return 0;
case DSPF_RGB444: return PIXMAN_x4r4g4b4;
case DSPF_RGB555: return PIXMAN_x1r5g5b5;
#if DFB_NUM_PIXELFORMATS >= 29
case DSPF_BGR555: return PIXMAN_x1b5g5r5;
#endif
}
return 0;
}
static cairo_surface_t *
_cairo_dfb_surface_create_similar (void *abstract_src,
cairo_content_t content,
int width,
int height)
{
cairo_dfb_surface_t *other = abstract_src;
DFBSurfacePixelFormat format;
IDirectFBSurface *buffer;
DFBSurfaceDescription dsc;
cairo_surface_t *surface;
if (width <= 0 || height <= 0)
return _cairo_image_surface_create_with_content (content, width, height);
switch (content) {
default:
ASSERT_NOT_REACHED;
case CAIRO_CONTENT_COLOR_ALPHA:
format = DSPF_ARGB;
break;
case CAIRO_CONTENT_COLOR:
format = DSPF_RGB32;
break;
case CAIRO_CONTENT_ALPHA:
format = DSPF_A8;
break;
}
dsc.flags = DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT;
dsc.caps = DSCAPS_PREMULTIPLIED;
dsc.width = width;
dsc.height = height;
dsc.pixelformat = format;
if (other->dfb->CreateSurface (other->dfb, &dsc, &buffer))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_DEVICE_ERROR));
surface = cairo_directfb_surface_create (other->dfb, buffer);
buffer->Release (buffer);
return surface;
}
static cairo_status_t
_cairo_dfb_surface_finish (void *abstract_surface)
{
cairo_dfb_surface_t *surface = abstract_surface;
surface->dfb_surface->Release (surface->dfb_surface);
return _cairo_image_surface_finish (abstract_surface);
}
static cairo_image_surface_t *
_cairo_dfb_surface_map_to_image (void *abstract_surface,
const cairo_rectangle_int_t *extents)
{
cairo_dfb_surface_t *surface = abstract_surface;
if (surface->image.pixman_image == NULL) {
IDirectFBSurface *buffer = surface->dfb_surface;
pixman_image_t *image;
void *data;
int pitch;
if (buffer->Lock (buffer, DSLF_READ | DSLF_WRITE, &data, &pitch))
return _cairo_image_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
image = pixman_image_create_bits (surface->image.pixman_format,
surface->image.width,
surface->image.height,
data, pitch);
if (image == NULL) {
buffer->Unlock (buffer);
return _cairo_image_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
_cairo_image_surface_init (&surface->image, image, surface->image.pixman_format);
}
return _cairo_image_surface_map_to_image (&surface->image.base, extents);
}
static cairo_int_status_t
_cairo_dfb_surface_unmap_image (void *abstract_surface,
cairo_image_surface_t *image)
{
cairo_dfb_surface_t *surface = abstract_surface;
return _cairo_image_surface_unmap_image (&surface->image.base, image);
}
static cairo_status_t
_cairo_dfb_surface_flush (void *abstract_surface,
unsigned flags)
{
cairo_dfb_surface_t *surface = abstract_surface;
if (flags)
return CAIRO_STATUS_SUCCESS;
if (surface->image.pixman_image) {
surface->dfb_surface->Unlock (surface->dfb_surface);
pixman_image_unref (surface->image.pixman_image);
surface->image.pixman_image = NULL;
surface->image.data = NULL;
}
return CAIRO_STATUS_SUCCESS;
}
#if 0
static inline DFBSurfacePixelFormat
_directfb_from_pixman_format (pixman_format_code_t format)
{
switch ((int) format) {
case PIXMAN_a1r5g5b5: return DSPF_ARGB1555;
case PIXMAN_r5g6b5: return DSPF_RGB16;
case PIXMAN_r8g8b8: return DSPF_RGB24;
case PIXMAN_x8r8g8b8: return DSPF_RGB32;
case PIXMAN_a8r8g8b8: return DSPF_ARGB;
case PIXMAN_a8: return DSPF_A8;
case PIXMAN_yuy2: return DSPF_YUY2;
case PIXMAN_r3g3b2: return DSPF_RGB332;
case PIXMAN_yv12: return DSPF_YV12;
case PIXMAN_a1: return DSPF_A1; /* bit reversed, oops */
case PIXMAN_a4r4g4b4: return DSPF_ARGB4444;
case PIXMAN_a4: return DSPF_A4;
case PIXMAN_x4r4g4b4: return DSPF_RGB444;
case PIXMAN_x1r5g5b5: return DSPF_RGB555;
#if DFB_NUM_PIXELFORMATS >= 29
case PIXMAN_x1b5g5r5: return DSPF_BGR555;
#endif
default: return 0;
}
}
static cairo_bool_t
_directfb_get_operator (cairo_operator_t operator,
DFBSurfaceBlendFunction *ret_srcblend,
DFBSurfaceBlendFunction *ret_dstblend)
{
DFBSurfaceBlendFunction srcblend = DSBF_ONE;
DFBSurfaceBlendFunction dstblend = DSBF_ZERO;
switch (operator) {
case CAIRO_OPERATOR_CLEAR:
srcblend = DSBF_ZERO;
dstblend = DSBF_ZERO;
break;
case CAIRO_OPERATOR_SOURCE:
srcblend = DSBF_ONE;
dstblend = DSBF_ZERO;
break;
case CAIRO_OPERATOR_OVER:
srcblend = DSBF_ONE;
dstblend = DSBF_INVSRCALPHA;
break;
case CAIRO_OPERATOR_IN:
srcblend = DSBF_DESTALPHA;
dstblend = DSBF_ZERO;
break;
case CAIRO_OPERATOR_OUT:
srcblend = DSBF_INVDESTALPHA;
dstblend = DSBF_ZERO;
break;
case CAIRO_OPERATOR_ATOP:
srcblend = DSBF_DESTALPHA;
dstblend = DSBF_INVSRCALPHA;
break;
case CAIRO_OPERATOR_DEST:
srcblend = DSBF_ZERO;
dstblend = DSBF_ONE;
break;
case CAIRO_OPERATOR_DEST_OVER:
srcblend = DSBF_INVDESTALPHA;
dstblend = DSBF_ONE;
break;
case CAIRO_OPERATOR_DEST_IN:
srcblend = DSBF_ZERO;
dstblend = DSBF_SRCALPHA;
break;
case CAIRO_OPERATOR_DEST_OUT:
srcblend = DSBF_ZERO;
dstblend = DSBF_INVSRCALPHA;
break;
case CAIRO_OPERATOR_DEST_ATOP:
srcblend = DSBF_INVDESTALPHA;
dstblend = DSBF_SRCALPHA;
break;
case CAIRO_OPERATOR_XOR:
srcblend = DSBF_INVDESTALPHA;
dstblend = DSBF_INVSRCALPHA;
break;
case CAIRO_OPERATOR_ADD:
srcblend = DSBF_ONE;
dstblend = DSBF_ONE;
break;
case CAIRO_OPERATOR_SATURATE:
/* XXX This does not work. */
#if 0
srcblend = DSBF_SRCALPHASAT;
dstblend = DSBF_ONE;
break;
#endif
case CAIRO_OPERATOR_MULTIPLY:
case CAIRO_OPERATOR_SCREEN:
case CAIRO_OPERATOR_OVERLAY:
case CAIRO_OPERATOR_DARKEN:
case CAIRO_OPERATOR_LIGHTEN:
case CAIRO_OPERATOR_COLOR_DODGE:
case CAIRO_OPERATOR_COLOR_BURN:
case CAIRO_OPERATOR_HARD_LIGHT:
case CAIRO_OPERATOR_SOFT_LIGHT:
case CAIRO_OPERATOR_DIFFERENCE:
case CAIRO_OPERATOR_EXCLUSION:
case CAIRO_OPERATOR_HSL_HUE:
case CAIRO_OPERATOR_HSL_SATURATION:
case CAIRO_OPERATOR_HSL_COLOR:
case CAIRO_OPERATOR_HSL_LUMINOSITY:
default:
return FALSE;
}
*ret_srcblend = srcblend;
*ret_dstblend = dstblend;
return TRUE;
}
#define RUN_CLIPPED(surface, clip_region, clip, func) {\
if ((clip_region) != NULL) {\
int n_clips = cairo_region_num_rectangles (clip_region), n; \
for (n = 0; n < n_clips; n++) {\
if (clip) {\
DFBRegion reg, *cli = (clip); \
cairo_rectangle_int_t rect; \
cairo_region_get_rectangle (clip_region, n, &rect); \
reg.x1 = rect.x; \
reg.y1 = rect.y; \
reg.x2 = rect.x + rect.width - 1; \
reg.y2 = rect.y + rect.height - 1; \
if (reg.x2 < cli->x1 || reg.y2 < cli->y1 ||\
reg.x1 > cli->x2 || reg.y1 > cli->y2)\
continue;\
if (reg.x1 < cli->x1)\
reg.x1 = cli->x1;\
if (reg.y1 < cli->y1)\
reg.y1 = cli->y1;\
if (reg.x2 > cli->x2)\
reg.x2 = cli->x2;\
if (reg.y2 > cli->y2)\
reg.y2 = cli->y2;\
(surface)->dfbsurface->SetClip ((surface)->dfbsurface, &reg);\
} else {\
DFBRegion reg; \
cairo_rectangle_int_t rect; \
cairo_region_get_rectangle (clip_region, n, &rect); \
reg.x1 = rect.x; \
reg.y1 = rect.y; \
reg.x2 = rect.x + rect.width - 1; \
reg.y2 = rect.y + rect.height - 1; \
(surface)->dfbsurface->SetClip ((surface)->dfbsurface, &reg); \
}\
func;\
}\
} else {\
(surface)->dfbsurface->SetClip ((surface)->dfbsurface, clip);\
func;\
}\
}
static cairo_int_status_t
_cairo_dfb_surface_fill_rectangles (void *abstract_surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_rectangle_int_t *rects,
int n_rects)
{
cairo_dfb_surface_t *dst = abstract_surface;
DFBSurfaceDrawingFlags flags;
DFBSurfaceBlendFunction sblend;
DFBSurfaceBlendFunction dblend;
DFBRectangle r[n_rects];
int i;
D_DEBUG_AT (CairoDFB_Render,
"%s( dst=%p, op=%d, color=%p, rects=%p, n_rects=%d ).\n",
__FUNCTION__, dst, op, color, rects, n_rects);
if (! dst->supported_destination)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (! _directfb_get_operator (op, &sblend, &dblend))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (CAIRO_COLOR_IS_OPAQUE (color)) {
if (sblend == DSBF_SRCALPHA)
sblend = DSBF_ONE;
else if (sblend == DSBF_INVSRCALPHA)
sblend = DSBF_ZERO;
if (dblend == DSBF_SRCALPHA)
dblend = DSBF_ONE;
else if (dblend == DSBF_INVSRCALPHA)
dblend = DSBF_ZERO;
}
if ((dst->base.content & CAIRO_CONTENT_ALPHA) == 0) {
if (sblend == DSBF_DESTALPHA)
sblend = DSBF_ONE;
else if (sblend == DSBF_INVDESTALPHA)
sblend = DSBF_ZERO;
if (dblend == DSBF_DESTALPHA)
dblend = DSBF_ONE;
else if (dblend == DSBF_INVDESTALPHA)
dblend = DSBF_ZERO;
}
flags = (sblend == DSBF_ONE && dblend == DSBF_ZERO) ? DSDRAW_NOFX : DSDRAW_BLEND;
dst->dfbsurface->SetDrawingFlags (dst->dfbsurface, flags);
if (flags & DSDRAW_BLEND) {
dst->dfbsurface->SetSrcBlendFunction (dst->dfbsurface, sblend);
dst->dfbsurface->SetDstBlendFunction (dst->dfbsurface, dblend);
}
dst->dfbsurface->SetColor (dst->dfbsurface,
color->red_short >> 8,
color->green_short >> 8,
color->blue_short >> 8,
color->alpha_short >> 8);
for (i = 0; i < n_rects; i++) {
r[i].x = rects[i].x;
r[i].y = rects[i].y;
r[i].w = rects[i].width;
r[i].h = rects[i].height;
}
RUN_CLIPPED (dst, NULL, NULL,
dst->dfbsurface->FillRectangles (dst->dfbsurface, r, n_rects));
return CAIRO_STATUS_SUCCESS;
}
#endif
static cairo_surface_backend_t
_cairo_dfb_surface_backend = {
CAIRO_SURFACE_TYPE_DIRECTFB, /*type*/
_cairo_dfb_surface_finish, /*finish*/
_cairo_default_context_create,
_cairo_dfb_surface_create_similar,/*create_similar*/
NULL, /* create similar image */
_cairo_dfb_surface_map_to_image,
_cairo_dfb_surface_unmap_image,
_cairo_surface_default_source,
_cairo_surface_default_acquire_source_image,
_cairo_surface_default_release_source_image,
NULL,
NULL, /* copy_page */
NULL, /* show_page */
_cairo_image_surface_get_extents,
_cairo_image_surface_get_font_options,
_cairo_dfb_surface_flush,
NULL, /* mark_dirty_rectangle */
_cairo_surface_fallback_paint,
_cairo_surface_fallback_mask,
_cairo_surface_fallback_stroke,
_cairo_surface_fallback_fill,
NULL, /* fill-stroke */
_cairo_surface_fallback_glyphs,
};
cairo_surface_t *
cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *dfbsurface)
{
cairo_dfb_surface_t *surface;
DFBSurfacePixelFormat format;
DFBSurfaceCapabilities caps;
pixman_format_code_t pixman_format;
int width, height;
D_ASSERT (dfb != NULL);
D_ASSERT (dfbsurface != NULL);
dfbsurface->GetPixelFormat (dfbsurface, &format);
dfbsurface->GetSize (dfbsurface, &width, &height);
pixman_format = _directfb_to_pixman_format (format);
if (! pixman_format_supported_destination (pixman_format))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
surface = calloc (1, sizeof (cairo_dfb_surface_t));
if (surface == NULL)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
/* XXX dfb -> device */
_cairo_surface_init (&surface->image.base,
&_cairo_dfb_surface_backend,
NULL, /* device */
_directfb_format_to_content (format));
surface->image.pixman_format = pixman_format;
surface->image.format = _cairo_format_from_pixman_format (pixman_format);
surface->image.width = width;
surface->image.height = height;
surface->image.depth = PIXMAN_FORMAT_DEPTH(pixman_format);
surface->dfb = dfb;
surface->dfb_surface = dfbsurface;
dfbsurface->AddRef (dfbsurface);
dfbsurface->GetCapabilities (dfbsurface, &caps);
if (caps & DSCAPS_PREMULTIPLIED)
surface->blit_premultiplied = TRUE;
return &surface->image.base;
}
slim_hidden_def(cairo_directfb_surface_create);

View File

@@ -0,0 +1,67 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
*
* 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.
*
* 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@isi.edu>
*/
/*
* Environment variables affecting the backend:
*
* %CAIRO_DIRECTFB_NO_ACCEL (boolean)
* if found, disables acceleration at all
*
* %CAIRO_DIRECTFB_ARGB_FONT (boolean)
* if found, enables using ARGB fonts instead of A8
*/
#ifndef CAIRO_DIRECTFB_H
#define CAIRO_DIRECTFB_H
#include "cairo.h"
#if CAIRO_HAS_DIRECTFB_SURFACE
#include <directfb.h>
CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *surface);
CAIRO_END_DECLS
#else /*CAIRO_HAS_DIRECTFB_SURFACE*/
# error Cairo was not compiled with support for the directfb backend
#endif /*CAIRO_HAS_DIRECTFB_SURFACE*/
#endif /*CAIRO_DIRECTFB_H*/

View File

@@ -0,0 +1,120 @@
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson.
*/
#ifndef CAIRO_DRM_H
#define CAIRO_DRM_H
#include "cairo.h"
#if CAIRO_HAS_DRM_SURFACE
CAIRO_BEGIN_DECLS
struct udev_device;
cairo_public cairo_device_t *
cairo_drm_device_get (struct udev_device *device);
cairo_public cairo_device_t *
cairo_drm_device_get_for_fd (int fd);
cairo_public cairo_device_t *
cairo_drm_device_default (void);
cairo_public int
cairo_drm_device_get_fd (cairo_device_t *device);
cairo_public void
cairo_drm_device_throttle (cairo_device_t *device);
cairo_public cairo_surface_t *
cairo_drm_surface_create (cairo_device_t *device,
cairo_format_t format,
int width, int height);
cairo_public cairo_surface_t *
cairo_drm_surface_create_for_name (cairo_device_t *device,
unsigned int name,
cairo_format_t format,
int width, int height, int stride);
cairo_public cairo_surface_t *
cairo_drm_surface_create_from_cacheable_image (cairo_device_t *device,
cairo_surface_t *surface);
cairo_public cairo_status_t
cairo_drm_surface_enable_scan_out (cairo_surface_t *surface);
cairo_public unsigned int
cairo_drm_surface_get_handle (cairo_surface_t *surface);
cairo_public unsigned int
cairo_drm_surface_get_name (cairo_surface_t *surface);
cairo_public cairo_format_t
cairo_drm_surface_get_format (cairo_surface_t *surface);
cairo_public int
cairo_drm_surface_get_width (cairo_surface_t *surface);
cairo_public int
cairo_drm_surface_get_height (cairo_surface_t *surface);
cairo_public int
cairo_drm_surface_get_stride (cairo_surface_t *surface);
/* XXX map/unmap, general surface layer? */
/* Rough outline, culled from a conversation on IRC:
* map() returns an image-surface representation of the drm-surface,
* which you unmap() when you are finished, i.e. map() pulls the buffer back
* from the GPU, maps it into the CPU domain and gives you direct access to
* the pixels. With the unmap(), the buffer is ready to be used again by the
* GPU and *until* the unmap(), all operations will be done in software.
*
* (Technically calling cairo_surface_flush() on the underlying drm-surface
* will also disassociate the mapping.)
*/
cairo_public cairo_surface_t *
cairo_drm_surface_map_to_image (cairo_surface_t *surface);
cairo_public void
cairo_drm_surface_unmap (cairo_surface_t *drm_surface,
cairo_surface_t *image_surface);
CAIRO_END_DECLS
#else /* CAIRO_HAS_DRM_SURFACE */
# error Cairo was not compiled with support for the DRM backend
#endif /* CAIRO_HAS_DRM_SURFACE */
#endif /* CAIRO_DRM_H */

View File

@@ -0,0 +1,311 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Eric Anholt
* Copyright © 2009 Chris Wilson
* Copyright © 2005 Red Hat, Inc
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-gl-private.h"
#include "cairo-error-private.h"
typedef struct _cairo_egl_context {
cairo_gl_context_t base;
EGLDisplay display;
EGLContext context;
EGLSurface dummy_surface;
EGLContext previous_context;
EGLSurface previous_surface;
} cairo_egl_context_t;
typedef struct _cairo_egl_surface {
cairo_gl_surface_t base;
EGLSurface egl;
} cairo_egl_surface_t;
static cairo_bool_t
_context_acquisition_changed_egl_state (cairo_egl_context_t *ctx,
EGLSurface current_surface)
{
return ctx->previous_context != ctx->context ||
ctx->previous_surface != current_surface;
}
static EGLSurface
_egl_get_current_surface (cairo_egl_context_t *ctx)
{
if (ctx->base.current_target == NULL ||
_cairo_gl_surface_is_texture (ctx->base.current_target)) {
return ctx->dummy_surface;
}
return ((cairo_egl_surface_t *) ctx->base.current_target)->egl;
}
static void
_egl_query_current_state (cairo_egl_context_t *ctx)
{
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_context == EGL_NO_CONTEXT) {
ctx->previous_surface = EGL_NO_SURFACE;
ctx->previous_context = EGL_NO_CONTEXT;
}
}
static void
_egl_acquire (void *abstract_ctx)
{
cairo_egl_context_t *ctx = abstract_ctx;
EGLSurface current_surface = _egl_get_current_surface (ctx);
_egl_query_current_state (ctx);
if (!_context_acquisition_changed_egl_state (ctx, current_surface))
return;
eglMakeCurrent (ctx->display,
current_surface, current_surface, ctx->context);
}
static void
_egl_release (void *abstract_ctx)
{
cairo_egl_context_t *ctx = abstract_ctx;
if (!ctx->base.thread_aware ||
!_context_acquisition_changed_egl_state (ctx,
_egl_get_current_surface (ctx))) {
return;
}
eglMakeCurrent (ctx->display,
EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
static void
_egl_make_current (void *abstract_ctx,
cairo_gl_surface_t *abstract_surface)
{
cairo_egl_context_t *ctx = abstract_ctx;
cairo_egl_surface_t *surface = (cairo_egl_surface_t *) abstract_surface;
eglMakeCurrent(ctx->display, surface->egl, surface->egl, ctx->context);
}
static void
_egl_swap_buffers (void *abstract_ctx,
cairo_gl_surface_t *abstract_surface)
{
cairo_egl_context_t *ctx = abstract_ctx;
cairo_egl_surface_t *surface = (cairo_egl_surface_t *) abstract_surface;
eglSwapBuffers (ctx->display, surface->egl);
}
static void
_egl_destroy (void *abstract_ctx)
{
cairo_egl_context_t *ctx = abstract_ctx;
eglMakeCurrent (ctx->display,
EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (ctx->dummy_surface != EGL_NO_SURFACE)
eglDestroySurface (ctx->display, ctx->dummy_surface);
}
static cairo_bool_t
_egl_make_current_surfaceless(cairo_egl_context_t *ctx)
{
const char *extensions;
extensions = eglQueryString(ctx->display, EGL_EXTENSIONS);
if (strstr(extensions, "EGL_KHR_surfaceless_context") == NULL &&
strstr(extensions, "EGL_KHR_surfaceless_opengl") == NULL)
return FALSE;
if (!eglMakeCurrent(ctx->display,
EGL_NO_SURFACE, EGL_NO_SURFACE, ctx->context))
return FALSE;
return TRUE;
}
cairo_device_t *
cairo_egl_device_create (EGLDisplay dpy, EGLContext egl)
{
cairo_egl_context_t *ctx;
cairo_status_t status;
int attribs[] = {
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_NONE,
};
EGLConfig config;
EGLint numConfigs;
ctx = calloc (1, sizeof (cairo_egl_context_t));
if (unlikely (ctx == NULL))
return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
ctx->display = dpy;
ctx->context = egl;
ctx->base.acquire = _egl_acquire;
ctx->base.release = _egl_release;
ctx->base.make_current = _egl_make_current;
ctx->base.swap_buffers = _egl_swap_buffers;
ctx->base.destroy = _egl_destroy;
/* We are about the change the current state of EGL, so we should
* query the pre-existing surface now instead of later. */
_egl_query_current_state (ctx);
if (!_egl_make_current_surfaceless (ctx)) {
/* Fall back to dummy surface, meh. */
EGLint config_attribs[] = {
EGL_CONFIG_ID, 0,
EGL_NONE
};
/*
* In order to be able to make an egl context current when using a
* pbuffer surface, that surface must have been created with a config
* that is compatible with the context config. For Mesa, this means
* that the configs must be the same.
*/
eglQueryContext (dpy, egl, EGL_CONFIG_ID, &config_attribs[1]);
eglChooseConfig (dpy, config_attribs, &config, 1, &numConfigs);
ctx->dummy_surface = eglCreatePbufferSurface (dpy, config, attribs);
if (ctx->dummy_surface == NULL) {
free (ctx);
return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
}
if (!eglMakeCurrent (dpy, ctx->dummy_surface, ctx->dummy_surface, egl)) {
free (ctx);
return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
}
}
status = _cairo_gl_dispatch_init (&ctx->base.dispatch, eglGetProcAddress);
if (unlikely (status)) {
free (ctx);
return _cairo_gl_context_create_in_error (status);
}
status = _cairo_gl_context_init (&ctx->base);
if (unlikely (status)) {
if (ctx->dummy_surface != EGL_NO_SURFACE)
eglDestroySurface (dpy, ctx->dummy_surface);
free (ctx);
return _cairo_gl_context_create_in_error (status);
}
eglMakeCurrent (dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
return &ctx->base.base;
}
cairo_surface_t *
cairo_gl_surface_create_for_egl (cairo_device_t *device,
EGLSurface egl,
int width,
int height)
{
cairo_egl_surface_t *surface;
if (unlikely (device->status))
return _cairo_surface_create_in_error (device->status);
if (device->backend->type != CAIRO_DEVICE_TYPE_GL)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
if (width <= 0 || height <= 0)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
surface = calloc (1, sizeof (cairo_egl_surface_t));
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_gl_surface_init (device, &surface->base,
CAIRO_CONTENT_COLOR_ALPHA, width, height);
surface->egl = egl;
return &surface->base.base;
}
static cairo_bool_t is_egl_device (cairo_device_t *device)
{
return (device->backend != NULL &&
device->backend->type == CAIRO_DEVICE_TYPE_GL);
}
static cairo_egl_context_t *to_egl_context (cairo_device_t *device)
{
return (cairo_egl_context_t *) device;
}
EGLDisplay
cairo_egl_device_get_display (cairo_device_t *device)
{
if (! is_egl_device (device)) {
_cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
return EGL_NO_DISPLAY;
}
return to_egl_context (device)->display;
}
cairo_public EGLContext
cairo_egl_device_get_context (cairo_device_t *device)
{
if (! is_egl_device (device)) {
_cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
return EGL_NO_CONTEXT;
}
return to_egl_context (device)->context;
}

View File

@@ -0,0 +1,52 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* 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.
*
* 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>
*/
#ifndef _CAIRO_ERROR_INLINE_H_
#define _CAIRO_ERROR_INLINE_H_
#include "cairo-error-private.h"
CAIRO_BEGIN_DECLS
static inline cairo_status_t
_cairo_public_status (cairo_int_status_t status)
{
assert (status <= CAIRO_INT_STATUS_LAST_STATUS);
return (cairo_status_t) status;
}
#endif /* _CAIRO_ERROR_INLINE_H_ */

View File

@@ -0,0 +1,123 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* 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.
*
* 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>
*/
#ifndef _CAIRO_ERROR_PRIVATE_H_
#define _CAIRO_ERROR_PRIVATE_H_
#include "cairo.h"
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
#include <assert.h>
CAIRO_BEGIN_DECLS
/* Sure wish C had a real enum type so that this would be distinct
* from #cairo_status_t. Oh well, without that, I'll use this bogus 100
* offset. We want to keep it fit in int8_t as the compiler may choose
* that for #cairo_status_t */
enum _cairo_int_status {
CAIRO_INT_STATUS_SUCCESS = 0,
CAIRO_INT_STATUS_NO_MEMORY,
CAIRO_INT_STATUS_INVALID_RESTORE,
CAIRO_INT_STATUS_INVALID_POP_GROUP,
CAIRO_INT_STATUS_NO_CURRENT_POINT,
CAIRO_INT_STATUS_INVALID_MATRIX,
CAIRO_INT_STATUS_INVALID_STATUS,
CAIRO_INT_STATUS_NULL_POINTER,
CAIRO_INT_STATUS_INVALID_STRING,
CAIRO_INT_STATUS_INVALID_PATH_DATA,
CAIRO_INT_STATUS_READ_ERROR,
CAIRO_INT_STATUS_WRITE_ERROR,
CAIRO_INT_STATUS_SURFACE_FINISHED,
CAIRO_INT_STATUS_SURFACE_TYPE_MISMATCH,
CAIRO_INT_STATUS_PATTERN_TYPE_MISMATCH,
CAIRO_INT_STATUS_INVALID_CONTENT,
CAIRO_INT_STATUS_INVALID_FORMAT,
CAIRO_INT_STATUS_INVALID_VISUAL,
CAIRO_INT_STATUS_FILE_NOT_FOUND,
CAIRO_INT_STATUS_INVALID_DASH,
CAIRO_INT_STATUS_INVALID_DSC_COMMENT,
CAIRO_INT_STATUS_INVALID_INDEX,
CAIRO_INT_STATUS_CLIP_NOT_REPRESENTABLE,
CAIRO_INT_STATUS_TEMP_FILE_ERROR,
CAIRO_INT_STATUS_INVALID_STRIDE,
CAIRO_INT_STATUS_FONT_TYPE_MISMATCH,
CAIRO_INT_STATUS_USER_FONT_IMMUTABLE,
CAIRO_INT_STATUS_USER_FONT_ERROR,
CAIRO_INT_STATUS_NEGATIVE_COUNT,
CAIRO_INT_STATUS_INVALID_CLUSTERS,
CAIRO_INT_STATUS_INVALID_SLANT,
CAIRO_INT_STATUS_INVALID_WEIGHT,
CAIRO_INT_STATUS_INVALID_SIZE,
CAIRO_INT_STATUS_USER_FONT_NOT_IMPLEMENTED,
CAIRO_INT_STATUS_DEVICE_TYPE_MISMATCH,
CAIRO_INT_STATUS_DEVICE_ERROR,
CAIRO_INT_STATUS_INVALID_MESH_CONSTRUCTION,
CAIRO_INT_STATUS_DEVICE_FINISHED,
CAIRO_INT_STATUS_LAST_STATUS,
CAIRO_INT_STATUS_UNSUPPORTED = 100,
CAIRO_INT_STATUS_DEGENERATE,
CAIRO_INT_STATUS_NOTHING_TO_DO,
CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY,
CAIRO_INT_STATUS_IMAGE_FALLBACK,
CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN,
};
typedef enum _cairo_int_status cairo_int_status_t;
#define _cairo_status_is_error(status) \
(status != CAIRO_STATUS_SUCCESS && status < CAIRO_STATUS_LAST_STATUS)
#define _cairo_int_status_is_error(status) \
(status != CAIRO_INT_STATUS_SUCCESS && status < CAIRO_INT_STATUS_LAST_STATUS)
cairo_private cairo_status_t
_cairo_error (cairo_status_t status);
/* hide compiler warnings when discarding the return value */
#define _cairo_error_throw(status) do { \
cairo_status_t status__ = _cairo_error (status); \
(void) status__; \
} while (0)
CAIRO_END_DECLS
#endif /* _CAIRO_ERROR_PRIVATE_H_ */

View File

@@ -0,0 +1,73 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* 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.
*
* 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>
*/
#include "cairoint.h"
#include "cairo-private.h"
#include "cairo-compiler-private.h"
#include "cairo-error-private.h"
#include <assert.h>
/**
* _cairo_error:
* @status: a status value indicating an error, (eg. not
* %CAIRO_STATUS_SUCCESS)
*
* Checks that status is an error status, but does nothing else.
*
* All assignments of an error status to any user-visible object
* within the cairo application should result in a call to
* _cairo_error().
*
* The purpose of this function is to allow the user to set a
* breakpoint in _cairo_error() to generate a stack trace for when the
* user causes cairo to detect an error.
*
* Return value: the error status.
**/
cairo_status_t
_cairo_error (cairo_status_t status)
{
CAIRO_ENSURE_UNIQUE;
assert (_cairo_status_is_error (status));
return status;
}
COMPILE_TIME_ASSERT ((int)CAIRO_INT_STATUS_LAST_STATUS == (int)CAIRO_STATUS_LAST_STATUS);

View File

@@ -0,0 +1,185 @@
/* -*- 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 © 2005 Red Hat, Inc.
* Copyright © 2011 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.
*
* 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>
* Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-compositor-private.h"
#include "cairo-image-surface-private.h"
#include "cairo-surface-offset-private.h"
/* high-level compositor interface */
static cairo_int_status_t
_cairo_fallback_compositor_paint (const cairo_compositor_t *_compositor,
cairo_composite_rectangles_t *extents)
{
cairo_image_surface_t *image;
cairo_int_status_t status;
TRACE ((stderr, "%s\n", __FUNCTION__));
image = _cairo_surface_map_to_image (extents->surface, &extents->unbounded);
status = _cairo_surface_offset_paint (&image->base,
extents->unbounded.x,
extents->unbounded.y,
extents->op,
&extents->source_pattern.base,
extents->clip);
return _cairo_surface_unmap_image (extents->surface, image);
}
static cairo_int_status_t
_cairo_fallback_compositor_mask (const cairo_compositor_t *_compositor,
cairo_composite_rectangles_t *extents)
{
cairo_image_surface_t *image;
cairo_int_status_t status;
TRACE ((stderr, "%s\n", __FUNCTION__));
image = _cairo_surface_map_to_image (extents->surface, &extents->unbounded);
status = _cairo_surface_offset_mask (&image->base,
extents->unbounded.x,
extents->unbounded.y,
extents->op,
&extents->source_pattern.base,
&extents->mask_pattern.base,
extents->clip);
return _cairo_surface_unmap_image (extents->surface, image);
}
static cairo_int_status_t
_cairo_fallback_compositor_stroke (const cairo_compositor_t *_compositor,
cairo_composite_rectangles_t *extents,
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)
{
cairo_image_surface_t *image;
cairo_int_status_t status;
TRACE ((stderr, "%s\n", __FUNCTION__));
image = _cairo_surface_map_to_image (extents->surface, &extents->unbounded);
status = _cairo_surface_offset_stroke (&image->base,
extents->unbounded.x,
extents->unbounded.y,
extents->op,
&extents->source_pattern.base,
path, style,
ctm, ctm_inverse,
tolerance,
antialias,
extents->clip);
return _cairo_surface_unmap_image (extents->surface, image);
}
static cairo_int_status_t
_cairo_fallback_compositor_fill (const cairo_compositor_t *_compositor,
cairo_composite_rectangles_t *extents,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_image_surface_t *image;
cairo_int_status_t status;
TRACE ((stderr, "%s\n", __FUNCTION__));
image = _cairo_surface_map_to_image (extents->surface, &extents->unbounded);
status = _cairo_surface_offset_fill (&image->base,
extents->unbounded.x,
extents->unbounded.y,
extents->op,
&extents->source_pattern.base,
path,
fill_rule, tolerance, antialias,
extents->clip);
return _cairo_surface_unmap_image (extents->surface, image);
}
static cairo_int_status_t
_cairo_fallback_compositor_glyphs (const cairo_compositor_t *_compositor,
cairo_composite_rectangles_t *extents,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_bool_t overlap)
{
cairo_image_surface_t *image;
cairo_int_status_t status;
TRACE ((stderr, "%s\n", __FUNCTION__));
image = _cairo_surface_map_to_image (extents->surface, &extents->unbounded);
status = _cairo_surface_offset_glyphs (&image->base,
extents->unbounded.x,
extents->unbounded.y,
extents->op,
&extents->source_pattern.base,
scaled_font, glyphs, num_glyphs,
extents->clip);
return _cairo_surface_unmap_image (extents->surface, image);
}
const cairo_compositor_t _cairo_fallback_compositor = {
&__cairo_no_compositor,
_cairo_fallback_compositor_paint,
_cairo_fallback_compositor_mask,
_cairo_fallback_compositor_stroke,
_cairo_fallback_compositor_fill,
_cairo_fallback_compositor_glyphs,
};

View File

@@ -0,0 +1,15 @@
/* Generated by configure. Do not edit. */
#ifndef CAIRO_FEATURES_H
#define CAIRO_FEATURES_H
#define CAIRO_HAS_FT_FONT 1
#define CAIRO_HAS_PNG_FUNCTIONS 1
#define CAIRO_HAS_IMAGE_SURFACE 1
#define CAIRO_HAS_SCRIPT_SURFACE 1
#define CAIRO_HAS_PDF_SURFACE 1
#define CAIRO_HAS_PS_SURFACE 1
//#define CAIRO_HAS_RECORDING_SURFACE 1
#define CAIRO_HAS_SVG_SURFACE 1
#define CAIRO_HAS_USER_FONT 1
#endif

View File

@@ -0,0 +1,394 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Mozilla 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Foundation
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
*/
#ifndef CAIRO_FIXED_PRIVATE_H
#define CAIRO_FIXED_PRIVATE_H
#include "cairo-fixed-type-private.h"
#include "cairo-wideint-private.h"
#include "cairoint.h"
/* Implementation */
#if (CAIRO_FIXED_BITS != 32)
# error CAIRO_FIXED_BITS must be 32, and the type must be a 32-bit type.
# error To remove this limitation, you will have to fix the tesselator.
#endif
#define CAIRO_FIXED_ONE ((cairo_fixed_t)(1 << CAIRO_FIXED_FRAC_BITS))
#define CAIRO_FIXED_ONE_DOUBLE ((double)(1 << CAIRO_FIXED_FRAC_BITS))
#define CAIRO_FIXED_EPSILON ((cairo_fixed_t)(1))
#define CAIRO_FIXED_ERROR_DOUBLE (1. / (2 * CAIRO_FIXED_ONE_DOUBLE))
#define CAIRO_FIXED_FRAC_MASK ((cairo_fixed_t)(((cairo_fixed_unsigned_t)(-1)) >> (CAIRO_FIXED_BITS - CAIRO_FIXED_FRAC_BITS)))
#define CAIRO_FIXED_WHOLE_MASK (~CAIRO_FIXED_FRAC_MASK)
static inline cairo_fixed_t
_cairo_fixed_from_int (int i)
{
return i << CAIRO_FIXED_FRAC_BITS;
}
/* This is the "magic number" approach to converting a double into fixed
* point as described here:
*
* http://www.stereopsis.com/sree/fpu2006.html (an overview)
* http://www.d6.com/users/checker/pdfs/gdmfp.pdf (in detail)
*
* The basic idea is to add a large enough number to the double that the
* literal floating point is moved up to the extent that it forces the
* double's value to be shifted down to the bottom of the mantissa (to make
* room for the large number being added in). Since the mantissa is, at a
* given moment in time, a fixed point integer itself, one can convert a
* float to various fixed point representations by moving around the point
* of a floating point number through arithmetic operations. This behavior
* is reliable on most modern platforms as it is mandated by the IEEE-754
* standard for floating point arithmetic.
*
* For our purposes, a "magic number" must be carefully selected that is
* both large enough to produce the desired point-shifting effect, and also
* has no lower bits in its representation that would interfere with our
* value at the bottom of the mantissa. The magic number is calculated as
* follows:
*
* (2 ^ (MANTISSA_SIZE - FRACTIONAL_SIZE)) * 1.5
*
* where in our case:
* - MANTISSA_SIZE for 64-bit doubles is 52
* - FRACTIONAL_SIZE for 16.16 fixed point is 16
*
* Although this approach provides a very large speedup of this function
* on a wide-array of systems, it does come with two caveats:
*
* 1) It uses banker's rounding as opposed to arithmetic rounding.
* 2) It doesn't function properly if the FPU is in single-precision
* mode.
*/
/* The 16.16 number must always be available */
#define CAIRO_MAGIC_NUMBER_FIXED_16_16 (103079215104.0)
#if CAIRO_FIXED_BITS <= 32
#define CAIRO_MAGIC_NUMBER_FIXED ((1LL << (52 - CAIRO_FIXED_FRAC_BITS)) * 1.5)
/* For 32-bit fixed point numbers */
static inline cairo_fixed_t
_cairo_fixed_from_double (double d)
{
union {
double d;
int32_t i[2];
} u;
u.d = d + CAIRO_MAGIC_NUMBER_FIXED;
#ifdef FLOAT_WORDS_BIGENDIAN
return u.i[1];
#else
return u.i[0];
#endif
}
#else
# error Please define a magic number for your fixed point type!
# error See cairo-fixed-private.h for details.
#endif
static inline cairo_fixed_t
_cairo_fixed_from_26_6 (uint32_t i)
{
#if CAIRO_FIXED_FRAC_BITS > 6
return i << (CAIRO_FIXED_FRAC_BITS - 6);
#else
return i >> (6 - CAIRO_FIXED_FRAC_BITS);
#endif
}
static inline cairo_fixed_t
_cairo_fixed_from_16_16 (uint32_t i)
{
#if CAIRO_FIXED_FRAC_BITS > 16
return i << (CAIRO_FIXED_FRAC_BITS - 16);
#else
return i >> (16 - CAIRO_FIXED_FRAC_BITS);
#endif
}
static inline double
_cairo_fixed_to_double (cairo_fixed_t f)
{
return ((double) f) / CAIRO_FIXED_ONE_DOUBLE;
}
static inline int
_cairo_fixed_is_integer (cairo_fixed_t f)
{
return (f & CAIRO_FIXED_FRAC_MASK) == 0;
}
static inline cairo_fixed_t
_cairo_fixed_floor (cairo_fixed_t f)
{
return f & ~CAIRO_FIXED_FRAC_MASK;
}
static inline cairo_fixed_t
_cairo_fixed_ceil (cairo_fixed_t f)
{
return _cairo_fixed_floor (f + CAIRO_FIXED_FRAC_MASK);
}
static inline cairo_fixed_t
_cairo_fixed_round (cairo_fixed_t f)
{
return _cairo_fixed_floor (f + (CAIRO_FIXED_FRAC_MASK+1)/2);
}
static inline cairo_fixed_t
_cairo_fixed_round_down (cairo_fixed_t f)
{
return _cairo_fixed_floor (f + CAIRO_FIXED_FRAC_MASK/2);
}
static inline int
_cairo_fixed_integer_part (cairo_fixed_t f)
{
return f >> CAIRO_FIXED_FRAC_BITS;
}
static inline int
_cairo_fixed_integer_round (cairo_fixed_t f)
{
return _cairo_fixed_integer_part (f + (CAIRO_FIXED_FRAC_MASK+1)/2);
}
static inline int
_cairo_fixed_integer_round_down (cairo_fixed_t f)
{
return _cairo_fixed_integer_part (f + CAIRO_FIXED_FRAC_MASK/2);
}
static inline int
_cairo_fixed_fractional_part (cairo_fixed_t f)
{
return f & CAIRO_FIXED_FRAC_MASK;
}
static inline int
_cairo_fixed_integer_floor (cairo_fixed_t f)
{
if (f >= 0)
return f >> CAIRO_FIXED_FRAC_BITS;
else
return -((-f - 1) >> CAIRO_FIXED_FRAC_BITS) - 1;
}
static inline int
_cairo_fixed_integer_ceil (cairo_fixed_t f)
{
if (f > 0)
return ((f - 1)>>CAIRO_FIXED_FRAC_BITS) + 1;
else
return - (-f >> CAIRO_FIXED_FRAC_BITS);
}
/* A bunch of explicit 16.16 operators; we need these
* to interface with pixman and other backends that require
* 16.16 fixed point types.
*/
static inline cairo_fixed_16_16_t
_cairo_fixed_to_16_16 (cairo_fixed_t f)
{
#if (CAIRO_FIXED_FRAC_BITS == 16) && (CAIRO_FIXED_BITS == 32)
return f;
#elif CAIRO_FIXED_FRAC_BITS > 16
/* We're just dropping the low bits, so we won't ever got over/underflow here */
return f >> (CAIRO_FIXED_FRAC_BITS - 16);
#else
cairo_fixed_16_16_t x;
/* Handle overflow/underflow by clamping to the lowest/highest
* value representable as 16.16
*/
if ((f >> CAIRO_FIXED_FRAC_BITS) < INT16_MIN) {
x = INT32_MIN;
} else if ((f >> CAIRO_FIXED_FRAC_BITS) > INT16_MAX) {
x = INT32_MAX;
} else {
x = f << (16 - CAIRO_FIXED_FRAC_BITS);
}
return x;
#endif
}
static inline cairo_fixed_16_16_t
_cairo_fixed_16_16_from_double (double d)
{
union {
double d;
int32_t i[2];
} u;
u.d = d + CAIRO_MAGIC_NUMBER_FIXED_16_16;
#ifdef FLOAT_WORDS_BIGENDIAN
return u.i[1];
#else
return u.i[0];
#endif
}
static inline int
_cairo_fixed_16_16_floor (cairo_fixed_16_16_t f)
{
if (f >= 0)
return f >> 16;
else
return -((-f - 1) >> 16) - 1;
}
static inline double
_cairo_fixed_16_16_to_double (cairo_fixed_16_16_t f)
{
return ((double) f) / (double) (1 << 16);
}
#if CAIRO_FIXED_BITS == 32
static inline cairo_fixed_t
_cairo_fixed_mul (cairo_fixed_t a, cairo_fixed_t b)
{
cairo_int64_t temp = _cairo_int32x32_64_mul (a, b);
return _cairo_int64_to_int32(_cairo_int64_rsl (temp, CAIRO_FIXED_FRAC_BITS));
}
/* computes round (a * b / c) */
static inline cairo_fixed_t
_cairo_fixed_mul_div (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
{
cairo_int64_t ab = _cairo_int32x32_64_mul (a, b);
cairo_int64_t c64 = _cairo_int32_to_int64 (c);
return _cairo_int64_to_int32 (_cairo_int64_divrem (ab, c64).quo);
}
/* computes floor (a * b / c) */
static inline cairo_fixed_t
_cairo_fixed_mul_div_floor (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
{
return _cairo_int64_32_div (_cairo_int32x32_64_mul (a, b), c);
}
static inline cairo_fixed_t
_cairo_edge_compute_intersection_y_for_x (const cairo_point_t *p1,
const cairo_point_t *p2,
cairo_fixed_t x)
{
cairo_fixed_t y, dx;
if (x == p1->x)
return p1->y;
if (x == p2->x)
return p2->y;
y = p1->y;
dx = p2->x - p1->x;
if (dx != 0)
y += _cairo_fixed_mul_div_floor (x - p1->x, p2->y - p1->y, dx);
return y;
}
static inline cairo_fixed_t
_cairo_edge_compute_intersection_x_for_y (const cairo_point_t *p1,
const cairo_point_t *p2,
cairo_fixed_t y)
{
cairo_fixed_t x, dy;
if (y == p1->y)
return p1->x;
if (y == p2->y)
return p2->x;
x = p1->x;
dy = p2->y - p1->y;
if (dy != 0)
x += _cairo_fixed_mul_div_floor (y - p1->y, p2->x - p1->x, dy);
return x;
}
/* Intersect two segments based on the algorithm described at
* http://paulbourke.net/geometry/pointlineplane/. This implementation
* uses floating point math. */
static inline cairo_bool_t
_slow_segment_intersection (const cairo_point_t *seg1_p1,
const cairo_point_t *seg1_p2,
const cairo_point_t *seg2_p1,
const cairo_point_t *seg2_p2,
cairo_point_t *intersection)
{
double denominator, u_a, u_b;
double seg1_dx, seg1_dy, seg2_dx, seg2_dy, seg_start_dx, seg_start_dy;
seg1_dx = _cairo_fixed_to_double (seg1_p2->x - seg1_p1->x);
seg1_dy = _cairo_fixed_to_double (seg1_p2->y - seg1_p1->y);
seg2_dx = _cairo_fixed_to_double (seg2_p2->x - seg2_p1->x);
seg2_dy = _cairo_fixed_to_double (seg2_p2->y - seg2_p1->y);
denominator = (seg2_dy * seg1_dx) - (seg2_dx * seg1_dy);
if (denominator == 0)
return FALSE;
seg_start_dx = _cairo_fixed_to_double (seg1_p1->x - seg2_p1->x);
seg_start_dy = _cairo_fixed_to_double (seg1_p1->y - seg2_p1->y);
u_a = ((seg2_dx * seg_start_dy) - (seg2_dy * seg_start_dx)) / denominator;
u_b = ((seg1_dx * seg_start_dy) - (seg1_dy * seg_start_dx)) / denominator;
if (u_a <= 0 || u_a >= 1 || u_b <= 0 || u_b >= 1)
return FALSE;
intersection->x = seg1_p1->x + _cairo_fixed_from_double ((u_a * seg1_dx));
intersection->y = seg1_p1->y + _cairo_fixed_from_double ((u_a * seg1_dy));
return TRUE;
}
#else
# error Please define multiplication and other operands for your fixed-point type size
#endif
#endif /* CAIRO_FIXED_PRIVATE_H */

View File

@@ -0,0 +1,75 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Mozilla 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Foundation
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
*/
#ifndef CAIRO_FIXED_TYPE_PRIVATE_H
#define CAIRO_FIXED_TYPE_PRIVATE_H
#include "cairo-wideint-type-private.h"
/*
* Fixed-point configuration
*/
typedef int32_t cairo_fixed_16_16_t;
typedef cairo_int64_t cairo_fixed_32_32_t;
typedef cairo_int64_t cairo_fixed_48_16_t;
typedef cairo_int128_t cairo_fixed_64_64_t;
typedef cairo_int128_t cairo_fixed_96_32_t;
/* Eventually, we should allow changing this, but I think
* there are some assumptions in the tesselator about the
* size of a fixed type. For now, it must be 32.
*/
#define CAIRO_FIXED_BITS 32
/* The number of fractional bits. Changing this involves
* making sure that you compute a double-to-fixed magic number.
* (see below).
*/
#define CAIRO_FIXED_FRAC_BITS 8
/* A signed type %CAIRO_FIXED_BITS in size; the main fixed point type */
typedef int32_t cairo_fixed_t;
/* An unsigned type of the same size as #cairo_fixed_t */
typedef uint32_t cairo_fixed_unsigned_t;
typedef struct _cairo_point {
cairo_fixed_t x;
cairo_fixed_t y;
} cairo_point_t;
#endif /* CAIRO_FIXED_TYPE_PRIVATE_H */

View File

@@ -0,0 +1,39 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
*
* 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.
*
* 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>
*/
#include "cairoint.h"
#include "cairo-fixed-private.h"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,752 @@
/*
* Copyright © 2004 Keith Packard
* Copyright © 2008 Red Hat, Inc.
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Keith Packard
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Behdad Esfahbod <behdad@behdad.org>
*/
#include "cairoint.h"
#include "cairo-error-private.h"
#include <math.h>
/*
* This file implements a user-font rendering the descendant of the Hershey
* font coded by Keith Packard for use in the Twin window system.
* The actual font data is in cairo-font-face-twin-data.c
*
* Ported to cairo user font and extended by Behdad Esfahbod.
*/
static cairo_user_data_key_t twin_properties_key;
/*
* Face properties
*/
/* We synthesize multiple faces from the twin data. Here is the parameters. */
/* The following tables and matching code are copied from Pango */
/* CSS weight */
typedef enum {
TWIN_WEIGHT_THIN = 100,
TWIN_WEIGHT_ULTRALIGHT = 200,
TWIN_WEIGHT_LIGHT = 300,
TWIN_WEIGHT_BOOK = 380,
TWIN_WEIGHT_NORMAL = 400,
TWIN_WEIGHT_MEDIUM = 500,
TWIN_WEIGHT_SEMIBOLD = 600,
TWIN_WEIGHT_BOLD = 700,
TWIN_WEIGHT_ULTRABOLD = 800,
TWIN_WEIGHT_HEAVY = 900,
TWIN_WEIGHT_ULTRAHEAVY = 1000
} twin_face_weight_t;
/* CSS stretch */
typedef enum {
TWIN_STRETCH_ULTRA_CONDENSED,
TWIN_STRETCH_EXTRA_CONDENSED,
TWIN_STRETCH_CONDENSED,
TWIN_STRETCH_SEMI_CONDENSED,
TWIN_STRETCH_NORMAL,
TWIN_STRETCH_SEMI_EXPANDED,
TWIN_STRETCH_EXPANDED,
TWIN_STRETCH_EXTRA_EXPANDED,
TWIN_STRETCH_ULTRA_EXPANDED
} twin_face_stretch_t;
typedef struct
{
int value;
const char str[16];
} FieldMap;
static const FieldMap slant_map[] = {
{ CAIRO_FONT_SLANT_NORMAL, "" },
{ CAIRO_FONT_SLANT_NORMAL, "Roman" },
{ CAIRO_FONT_SLANT_OBLIQUE, "Oblique" },
{ CAIRO_FONT_SLANT_ITALIC, "Italic" }
};
static const FieldMap smallcaps_map[] = {
{ FALSE, "" },
{ TRUE, "Small-Caps" }
};
static const FieldMap weight_map[] = {
{ TWIN_WEIGHT_THIN, "Thin" },
{ TWIN_WEIGHT_ULTRALIGHT, "Ultra-Light" },
{ TWIN_WEIGHT_ULTRALIGHT, "Extra-Light" },
{ TWIN_WEIGHT_LIGHT, "Light" },
{ TWIN_WEIGHT_BOOK, "Book" },
{ TWIN_WEIGHT_NORMAL, "" },
{ TWIN_WEIGHT_NORMAL, "Regular" },
{ TWIN_WEIGHT_MEDIUM, "Medium" },
{ TWIN_WEIGHT_SEMIBOLD, "Semi-Bold" },
{ TWIN_WEIGHT_SEMIBOLD, "Demi-Bold" },
{ TWIN_WEIGHT_BOLD, "Bold" },
{ TWIN_WEIGHT_ULTRABOLD, "Ultra-Bold" },
{ TWIN_WEIGHT_ULTRABOLD, "Extra-Bold" },
{ TWIN_WEIGHT_HEAVY, "Heavy" },
{ TWIN_WEIGHT_HEAVY, "Black" },
{ TWIN_WEIGHT_ULTRAHEAVY, "Ultra-Heavy" },
{ TWIN_WEIGHT_ULTRAHEAVY, "Extra-Heavy" },
{ TWIN_WEIGHT_ULTRAHEAVY, "Ultra-Black" },
{ TWIN_WEIGHT_ULTRAHEAVY, "Extra-Black" }
};
static const FieldMap stretch_map[] = {
{ TWIN_STRETCH_ULTRA_CONDENSED, "Ultra-Condensed" },
{ TWIN_STRETCH_EXTRA_CONDENSED, "Extra-Condensed" },
{ TWIN_STRETCH_CONDENSED, "Condensed" },
{ TWIN_STRETCH_SEMI_CONDENSED, "Semi-Condensed" },
{ TWIN_STRETCH_NORMAL, "" },
{ TWIN_STRETCH_SEMI_EXPANDED, "Semi-Expanded" },
{ TWIN_STRETCH_EXPANDED, "Expanded" },
{ TWIN_STRETCH_EXTRA_EXPANDED, "Extra-Expanded" },
{ TWIN_STRETCH_ULTRA_EXPANDED, "Ultra-Expanded" }
};
static const FieldMap monospace_map[] = {
{ FALSE, "" },
{ TRUE, "Mono" },
{ TRUE, "Monospace" }
};
typedef struct _twin_face_properties {
cairo_font_slant_t slant;
twin_face_weight_t weight;
twin_face_stretch_t stretch;
/* lets have some fun */
cairo_bool_t monospace;
cairo_bool_t smallcaps;
} twin_face_properties_t;
static cairo_bool_t
field_matches (const char *s1,
const char *s2,
int len)
{
int c1, c2;
while (len && *s1 && *s2)
{
#define TOLOWER(c) \
(((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
c1 = TOLOWER (*s1);
c2 = TOLOWER (*s2);
if (c1 != c2) {
if (c1 == '-') {
s1++;
continue;
}
return FALSE;
}
s1++; s2++;
len--;
}
return len == 0 && *s1 == '\0';
}
static cairo_bool_t
parse_int (const char *word,
size_t wordlen,
int *out)
{
char *end;
long val = strtol (word, &end, 10);
int i = val;
if (end != word && (end == word + wordlen) && val >= 0 && val == i)
{
if (out)
*out = i;
return TRUE;
}
return FALSE;
}
static cairo_bool_t
find_field (const char *what,
const FieldMap *map,
int n_elements,
const char *str,
int len,
int *val)
{
int i;
cairo_bool_t had_prefix = FALSE;
if (what)
{
i = strlen (what);
if (len > i && 0 == strncmp (what, str, i) && str[i] == '=')
{
str += i + 1;
len -= i + 1;
had_prefix = TRUE;
}
}
for (i=0; i<n_elements; i++)
{
if (map[i].str[0] && field_matches (map[i].str, str, len))
{
if (val)
*val = map[i].value;
return TRUE;
}
}
if (!what || had_prefix)
return parse_int (str, len, val);
return FALSE;
}
static void
parse_field (twin_face_properties_t *props,
const char *str,
int len)
{
if (field_matches ("Normal", str, len))
return;
#define FIELD(NAME) \
if (find_field (STRINGIFY (NAME), NAME##_map, ARRAY_LENGTH (NAME##_map), str, len, \
(int *)(void *)&props->NAME)) \
return; \
FIELD (weight);
FIELD (slant);
FIELD (stretch);
FIELD (smallcaps);
FIELD (monospace);
#undef FIELD
}
static void
face_props_parse (twin_face_properties_t *props,
const char *s)
{
const char *start, *end;
for (start = end = s; *end; end++) {
if (*end != ' ' && *end != ':')
continue;
if (start < end)
parse_field (props, start, end - start);
start = end + 1;
}
if (start < end)
parse_field (props, start, end - start);
}
static twin_face_properties_t *
twin_font_face_create_properties (cairo_font_face_t *twin_face)
{
twin_face_properties_t *props;
props = malloc (sizeof (twin_face_properties_t));
if (unlikely (props == NULL))
return NULL;
props->stretch = TWIN_STRETCH_NORMAL;
props->slant = CAIRO_FONT_SLANT_NORMAL;
props->weight = TWIN_WEIGHT_NORMAL;
props->monospace = FALSE;
props->smallcaps = FALSE;
if (unlikely (cairo_font_face_set_user_data (twin_face,
&twin_properties_key,
props, free))) {
free (props);
return NULL;
}
return props;
}
static cairo_status_t
twin_font_face_set_properties_from_toy (cairo_font_face_t *twin_face,
cairo_toy_font_face_t *toy_face)
{
twin_face_properties_t *props;
props = twin_font_face_create_properties (twin_face);
if (unlikely (props == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
props->slant = toy_face->slant;
props->weight = toy_face->weight == CAIRO_FONT_WEIGHT_NORMAL ?
TWIN_WEIGHT_NORMAL : TWIN_WEIGHT_BOLD;
face_props_parse (props, toy_face->family);
return CAIRO_STATUS_SUCCESS;
}
/*
* Scaled properties
*/
typedef struct _twin_scaled_properties {
twin_face_properties_t *face_props;
cairo_bool_t snap; /* hint outlines */
double weight; /* unhinted pen width */
double penx, peny; /* hinted pen width */
double marginl, marginr; /* hinted side margins */
double stretch; /* stretch factor */
} twin_scaled_properties_t;
static void
compute_hinting_scale (cairo_t *cr,
double x, double y,
double *scale, double *inv)
{
cairo_user_to_device_distance (cr, &x, &y);
*scale = x == 0 ? y : y == 0 ? x :sqrt (x*x + y*y);
*inv = 1 / *scale;
}
static void
compute_hinting_scales (cairo_t *cr,
double *x_scale, double *x_scale_inv,
double *y_scale, double *y_scale_inv)
{
double x, y;
x = 1; y = 0;
compute_hinting_scale (cr, x, y, x_scale, x_scale_inv);
x = 0; y = 1;
compute_hinting_scale (cr, x, y, y_scale, y_scale_inv);
}
#define SNAPXI(p) (_cairo_round ((p) * x_scale) * x_scale_inv)
#define SNAPYI(p) (_cairo_round ((p) * y_scale) * y_scale_inv)
/* This controls the global font size */
#define F(g) ((g) / 72.)
static void
twin_hint_pen_and_margins(cairo_t *cr,
double *penx, double *peny,
double *marginl, double *marginr)
{
double x_scale, x_scale_inv;
double y_scale, y_scale_inv;
double margin;
compute_hinting_scales (cr,
&x_scale, &x_scale_inv,
&y_scale, &y_scale_inv);
*penx = SNAPXI (*penx);
if (*penx < x_scale_inv)
*penx = x_scale_inv;
*peny = SNAPYI (*peny);
if (*peny < y_scale_inv)
*peny = y_scale_inv;
margin = *marginl + *marginr;
*marginl = SNAPXI (*marginl);
if (*marginl < x_scale_inv)
*marginl = x_scale_inv;
*marginr = margin - *marginl;
if (*marginr < 0)
*marginr = 0;
*marginr = SNAPXI (*marginr);
}
static cairo_status_t
twin_scaled_font_compute_properties (cairo_scaled_font_t *scaled_font,
cairo_t *cr)
{
cairo_status_t status;
twin_scaled_properties_t *props;
props = malloc (sizeof (twin_scaled_properties_t));
if (unlikely (props == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
props->face_props = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
&twin_properties_key);
props->snap = scaled_font->options.hint_style > CAIRO_HINT_STYLE_NONE;
/* weight */
props->weight = props->face_props->weight * (F (4) / TWIN_WEIGHT_NORMAL);
/* pen & margins */
props->penx = props->peny = props->weight;
props->marginl = props->marginr = F (4);
if (scaled_font->options.hint_style > CAIRO_HINT_STYLE_SLIGHT)
twin_hint_pen_and_margins(cr,
&props->penx, &props->peny,
&props->marginl, &props->marginr);
/* stretch */
props->stretch = 1 + .1 * ((int) props->face_props->stretch - (int) TWIN_STRETCH_NORMAL);
/* Save it */
status = cairo_scaled_font_set_user_data (scaled_font,
&twin_properties_key,
props, free);
if (unlikely (status))
goto FREE_PROPS;
return CAIRO_STATUS_SUCCESS;
FREE_PROPS:
free (props);
return status;
}
/*
* User-font implementation
*/
static cairo_status_t
twin_scaled_font_init (cairo_scaled_font_t *scaled_font,
cairo_t *cr,
cairo_font_extents_t *metrics)
{
metrics->ascent = F (54);
metrics->descent = 1 - metrics->ascent;
return twin_scaled_font_compute_properties (scaled_font, cr);
}
#define TWIN_GLYPH_MAX_SNAP_X 4
#define TWIN_GLYPH_MAX_SNAP_Y 7
typedef struct {
int n_snap_x;
int8_t snap_x[TWIN_GLYPH_MAX_SNAP_X];
double snapped_x[TWIN_GLYPH_MAX_SNAP_X];
int n_snap_y;
int8_t snap_y[TWIN_GLYPH_MAX_SNAP_Y];
double snapped_y[TWIN_GLYPH_MAX_SNAP_Y];
} twin_snap_info_t;
#define twin_glyph_left(g) ((g)[0])
#define twin_glyph_right(g) ((g)[1])
#define twin_glyph_ascent(g) ((g)[2])
#define twin_glyph_descent(g) ((g)[3])
#define twin_glyph_n_snap_x(g) ((g)[4])
#define twin_glyph_n_snap_y(g) ((g)[5])
#define twin_glyph_snap_x(g) (&g[6])
#define twin_glyph_snap_y(g) (twin_glyph_snap_x(g) + twin_glyph_n_snap_x(g))
#define twin_glyph_draw(g) (twin_glyph_snap_y(g) + twin_glyph_n_snap_y(g))
static void
twin_compute_snap (cairo_t *cr,
twin_snap_info_t *info,
const signed char *b)
{
int s, n;
const signed char *snap;
double x_scale, x_scale_inv;
double y_scale, y_scale_inv;
compute_hinting_scales (cr,
&x_scale, &x_scale_inv,
&y_scale, &y_scale_inv);
snap = twin_glyph_snap_x (b);
n = twin_glyph_n_snap_x (b);
info->n_snap_x = n;
assert (n <= TWIN_GLYPH_MAX_SNAP_X);
for (s = 0; s < n; s++) {
info->snap_x[s] = snap[s];
info->snapped_x[s] = SNAPXI (F (snap[s]));
}
snap = twin_glyph_snap_y (b);
n = twin_glyph_n_snap_y (b);
info->n_snap_y = n;
assert (n <= TWIN_GLYPH_MAX_SNAP_Y);
for (s = 0; s < n; s++) {
info->snap_y[s] = snap[s];
info->snapped_y[s] = SNAPYI (F (snap[s]));
}
}
static double
twin_snap (int8_t v, int n, int8_t *snap, double *snapped)
{
int s;
if (!n)
return F(v);
if (snap[0] == v)
return snapped[0];
for (s = 0; s < n - 1; s++)
{
if (snap[s+1] == v)
return snapped[s+1];
if (snap[s] <= v && v <= snap[s+1])
{
int before = snap[s];
int after = snap[s+1];
int dist = after - before;
double snap_before = snapped[s];
double snap_after = snapped[s+1];
double dist_before = v - before;
return snap_before + (snap_after - snap_before) * dist_before / dist;
}
}
return F(v);
}
#define SNAPX(p) twin_snap (p, info.n_snap_x, info.snap_x, info.snapped_x)
#define SNAPY(p) twin_snap (p, info.n_snap_y, info.snap_y, info.snapped_y)
static cairo_status_t
twin_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font,
unsigned long glyph,
cairo_t *cr,
cairo_text_extents_t *metrics)
{
double x1, y1, x2, y2, x3, y3;
double marginl;
twin_scaled_properties_t *props;
twin_snap_info_t info;
const int8_t *b;
const int8_t *g;
int8_t w;
double gw;
props = cairo_scaled_font_get_user_data (scaled_font, &twin_properties_key);
/* Save glyph space, we need it when stroking */
cairo_save (cr);
/* center the pen */
cairo_translate (cr, props->penx * .5, -props->peny * .5);
/* small-caps */
if (props->face_props->smallcaps && glyph >= 'a' && glyph <= 'z') {
glyph += 'A' - 'a';
/* 28 and 42 are small and capital letter heights of the glyph data */
cairo_scale (cr, 1, 28. / 42);
}
/* slant */
if (props->face_props->slant != CAIRO_FONT_SLANT_NORMAL) {
cairo_matrix_t shear = { 1, 0, -.2, 1, 0, 0};
cairo_transform (cr, &shear);
}
b = _cairo_twin_outlines +
_cairo_twin_charmap[unlikely (glyph >= ARRAY_LENGTH (_cairo_twin_charmap)) ? 0 : glyph];
g = twin_glyph_draw(b);
w = twin_glyph_right(b);
gw = F(w);
marginl = props->marginl;
/* monospace */
if (props->face_props->monospace) {
double monow = F(24);
double extra = props->penx + props->marginl + props->marginr;
cairo_scale (cr, (monow + extra) / (gw + extra), 1);
gw = monow;
/* resnap margin for new transform */
{
double x, y, x_scale, x_scale_inv;
x = 1; y = 0;
compute_hinting_scale (cr, x, y, &x_scale, &x_scale_inv);
marginl = SNAPXI (marginl);
}
}
cairo_translate (cr, marginl, 0);
/* stretch */
cairo_scale (cr, props->stretch, 1);
if (props->snap)
twin_compute_snap (cr, &info, b);
else
info.n_snap_x = info.n_snap_y = 0;
/* advance width */
metrics->x_advance = gw * props->stretch + props->penx + props->marginl + props->marginr;
/* glyph shape */
for (;;) {
switch (*g++) {
case 'M':
cairo_close_path (cr);
/* fall through */
case 'm':
x1 = SNAPX(*g++);
y1 = SNAPY(*g++);
cairo_move_to (cr, x1, y1);
continue;
case 'L':
cairo_close_path (cr);
/* fall through */
case 'l':
x1 = SNAPX(*g++);
y1 = SNAPY(*g++);
cairo_line_to (cr, x1, y1);
continue;
case 'C':
cairo_close_path (cr);
/* fall through */
case 'c':
x1 = SNAPX(*g++);
y1 = SNAPY(*g++);
x2 = SNAPX(*g++);
y2 = SNAPY(*g++);
x3 = SNAPX(*g++);
y3 = SNAPY(*g++);
cairo_curve_to (cr, x1, y1, x2, y2, x3, y3);
continue;
case 'E':
cairo_close_path (cr);
/* fall through */
case 'e':
cairo_restore (cr); /* restore glyph space */
cairo_set_tolerance (cr, 0.01);
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
cairo_set_line_width (cr, 1);
cairo_scale (cr, props->penx, props->peny);
cairo_stroke (cr);
break;
case 'X':
/* filler */
continue;
}
break;
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
twin_scaled_font_unicode_to_glyph (cairo_scaled_font_t *scaled_font,
unsigned long unicode,
unsigned long *glyph)
{
/* We use an identity charmap. Which means we could live
* with no unicode_to_glyph method too. But we define this
* to map all unknown chars to a single unknown glyph to
* reduce pressure on cache. */
if (likely (unicode < ARRAY_LENGTH (_cairo_twin_charmap)))
*glyph = unicode;
else
*glyph = 0;
return CAIRO_STATUS_SUCCESS;
}
/*
* Face constructor
*/
static cairo_font_face_t *
_cairo_font_face_twin_create_internal (void)
{
cairo_font_face_t *twin_font_face;
twin_font_face = cairo_user_font_face_create ();
cairo_user_font_face_set_init_func (twin_font_face, twin_scaled_font_init);
cairo_user_font_face_set_render_glyph_func (twin_font_face, twin_scaled_font_render_glyph);
cairo_user_font_face_set_unicode_to_glyph_func (twin_font_face, twin_scaled_font_unicode_to_glyph);
return twin_font_face;
}
cairo_font_face_t *
_cairo_font_face_twin_create_fallback (void)
{
cairo_font_face_t *twin_font_face;
twin_font_face = _cairo_font_face_twin_create_internal ();
if (! twin_font_face_create_properties (twin_font_face)) {
cairo_font_face_destroy (twin_font_face);
return (cairo_font_face_t *) &_cairo_font_face_nil;
}
return twin_font_face;
}
cairo_status_t
_cairo_font_face_twin_create_for_toy (cairo_toy_font_face_t *toy_face,
cairo_font_face_t **font_face)
{
cairo_status_t status;
cairo_font_face_t *twin_font_face;
twin_font_face = _cairo_font_face_twin_create_internal ();
status = twin_font_face_set_properties_from_toy (twin_font_face, toy_face);
if (status) {
cairo_font_face_destroy (twin_font_face);
return status;
}
*font_face = twin_font_face;
return CAIRO_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,318 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat Inc.
*
* 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.
*
* 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>
* Graydon Hoare <graydon@redhat.com>
* Owen Taylor <otaylor@redhat.com>
*/
#include "cairoint.h"
#include "cairo-error-private.h"
/**
* SECTION:cairo-font-face
* @Title: cairo_font_face_t
* @Short_Description: Base class for font faces
* @See_Also: #cairo_scaled_font_t
*
* #cairo_font_face_t represents a particular font at a particular weight,
* slant, and other characteristic but no size, transformation, or size.
*
* Font faces are created using <firstterm>font-backend</firstterm>-specific
* constructors, typically of the form
* <function>cairo_<emphasis>backend</emphasis>_font_face_create(<!-- -->)</function>,
* or implicitly using the <firstterm>toy</firstterm> text API by way of
* cairo_select_font_face(). The resulting face can be accessed using
* cairo_get_font_face().
**/
/* #cairo_font_face_t */
const cairo_font_face_t _cairo_font_face_nil = {
{ 0 }, /* hash_entry */
CAIRO_STATUS_NO_MEMORY, /* status */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
{ 0, 0, 0, NULL }, /* user_data */
NULL
};
cairo_status_t
_cairo_font_face_set_error (cairo_font_face_t *font_face,
cairo_status_t status)
{
if (status == CAIRO_STATUS_SUCCESS)
return status;
/* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. */
_cairo_status_set_error (&font_face->status, status);
return _cairo_error (status);
}
void
_cairo_font_face_init (cairo_font_face_t *font_face,
const cairo_font_face_backend_t *backend)
{
CAIRO_MUTEX_INITIALIZE ();
font_face->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&font_face->ref_count, 1);
font_face->backend = backend;
_cairo_user_data_array_init (&font_face->user_data);
}
/**
* cairo_font_face_reference:
* @font_face: a #cairo_font_face_t, (may be %NULL in which case this
* function does nothing).
*
* Increases the reference count on @font_face by one. This prevents
* @font_face from being destroyed until a matching call to
* cairo_font_face_destroy() is made.
*
* The number of references to a #cairo_font_face_t can be get using
* cairo_font_face_get_reference_count().
*
* Return value: the referenced #cairo_font_face_t.
*
* Since: 1.0
**/
cairo_font_face_t *
cairo_font_face_reference (cairo_font_face_t *font_face)
{
if (font_face == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return font_face;
/* We would normally assert that we have a reference here but we
* can't get away with that due to the zombie case as documented
* in _cairo_ft_font_face_destroy. */
_cairo_reference_count_inc (&font_face->ref_count);
return font_face;
}
slim_hidden_def (cairo_font_face_reference);
/**
* cairo_font_face_destroy:
* @font_face: a #cairo_font_face_t
*
* Decreases the reference count on @font_face by one. If the result
* is zero, then @font_face and all associated resources are freed.
* See cairo_font_face_reference().
*
* Since: 1.0
**/
void
cairo_font_face_destroy (cairo_font_face_t *font_face)
{
if (font_face == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->ref_count));
if (! _cairo_reference_count_dec_and_test (&font_face->ref_count))
return;
if (font_face->backend->destroy)
font_face->backend->destroy (font_face);
/* We allow resurrection to deal with some memory management for the
* FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t
* need to effectively mutually reference each other
*/
if (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->ref_count))
return;
_cairo_user_data_array_fini (&font_face->user_data);
free (font_face);
}
slim_hidden_def (cairo_font_face_destroy);
/**
* cairo_font_face_get_type:
* @font_face: a font face
*
* This function returns the type of the backend used to create
* a font face. See #cairo_font_type_t for available types.
*
* Return value: The type of @font_face.
*
* Since: 1.2
**/
cairo_font_type_t
cairo_font_face_get_type (cairo_font_face_t *font_face)
{
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return CAIRO_FONT_TYPE_TOY;
return font_face->backend->type;
}
/**
* cairo_font_face_get_reference_count:
* @font_face: a #cairo_font_face_t
*
* Returns the current reference count of @font_face.
*
* Return value: the current reference count of @font_face. If the
* object is a nil object, 0 will be returned.
*
* Since: 1.4
**/
unsigned int
cairo_font_face_get_reference_count (cairo_font_face_t *font_face)
{
if (font_face == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return 0;
return CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->ref_count);
}
/**
* cairo_font_face_status:
* @font_face: a #cairo_font_face_t
*
* Checks whether an error has previously occurred for this
* font face
*
* Return value: %CAIRO_STATUS_SUCCESS or another error such as
* %CAIRO_STATUS_NO_MEMORY.
*
* Since: 1.0
**/
cairo_status_t
cairo_font_face_status (cairo_font_face_t *font_face)
{
return font_face->status;
}
/**
* cairo_font_face_get_user_data:
* @font_face: a #cairo_font_face_t
* @key: the address of the #cairo_user_data_key_t the user data was
* attached to
*
* Return user data previously attached to @font_face using the specified
* key. If no user data has been attached with the given key this
* function returns %NULL.
*
* Return value: the user data previously attached or %NULL.
*
* Since: 1.0
**/
void *
cairo_font_face_get_user_data (cairo_font_face_t *font_face,
const cairo_user_data_key_t *key)
{
return _cairo_user_data_array_get_data (&font_face->user_data,
key);
}
slim_hidden_def (cairo_font_face_get_user_data);
/**
* cairo_font_face_set_user_data:
* @font_face: a #cairo_font_face_t
* @key: the address of a #cairo_user_data_key_t to attach the user data to
* @user_data: the user data to attach to the font face
* @destroy: a #cairo_destroy_func_t which will be called when the
* font face is destroyed or when new user data is attached using the
* same key.
*
* Attach user data to @font_face. To remove user data from a font face,
* call this function with the key that was used to set it and %NULL
* for @data.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
*
* Since: 1.0
**/
cairo_status_t
cairo_font_face_set_user_data (cairo_font_face_t *font_face,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy)
{
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return font_face->status;
return _cairo_user_data_array_set_data (&font_face->user_data,
key, user_data, destroy);
}
slim_hidden_def (cairo_font_face_set_user_data);
void
_cairo_unscaled_font_init (cairo_unscaled_font_t *unscaled_font,
const cairo_unscaled_font_backend_t *backend)
{
CAIRO_REFERENCE_COUNT_INIT (&unscaled_font->ref_count, 1);
unscaled_font->backend = backend;
}
cairo_unscaled_font_t *
_cairo_unscaled_font_reference (cairo_unscaled_font_t *unscaled_font)
{
if (unscaled_font == NULL)
return NULL;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled_font->ref_count));
_cairo_reference_count_inc (&unscaled_font->ref_count);
return unscaled_font;
}
void
_cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font)
{
if (unscaled_font == NULL)
return;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled_font->ref_count));
if (! _cairo_reference_count_dec_and_test (&unscaled_font->ref_count))
return;
unscaled_font->backend->destroy (unscaled_font);
free (unscaled_font);
}

View File

@@ -0,0 +1,535 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat Inc.
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Owen Taylor <otaylor@redhat.com>
*/
#include "cairoint.h"
#include "cairo-error-private.h"
/**
* SECTION:cairo-font-options
* @Title: cairo_font_options_t
* @Short_Description: How a font should be rendered
* @See_Also: #cairo_scaled_font_t
*
* The font options specify how fonts should be rendered. Most of the
* time the font options implied by a surface are just right and do not
* need any changes, but for pixel-based targets tweaking font options
* may result in superior output on a particular display.
**/
static const cairo_font_options_t _cairo_font_options_nil = {
CAIRO_ANTIALIAS_DEFAULT,
CAIRO_SUBPIXEL_ORDER_DEFAULT,
CAIRO_LCD_FILTER_DEFAULT,
CAIRO_HINT_STYLE_DEFAULT,
CAIRO_HINT_METRICS_DEFAULT,
CAIRO_ROUND_GLYPH_POS_DEFAULT
};
/**
* _cairo_font_options_init_default:
* @options: a #cairo_font_options_t
*
* Initializes all fields of the font options object to default values.
**/
void
_cairo_font_options_init_default (cairo_font_options_t *options)
{
options->antialias = CAIRO_ANTIALIAS_DEFAULT;
options->subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
options->lcd_filter = CAIRO_LCD_FILTER_DEFAULT;
options->hint_style = CAIRO_HINT_STYLE_DEFAULT;
options->hint_metrics = CAIRO_HINT_METRICS_DEFAULT;
options->round_glyph_positions = CAIRO_ROUND_GLYPH_POS_DEFAULT;
}
void
_cairo_font_options_init_copy (cairo_font_options_t *options,
const cairo_font_options_t *other)
{
options->antialias = other->antialias;
options->subpixel_order = other->subpixel_order;
options->lcd_filter = other->lcd_filter;
options->hint_style = other->hint_style;
options->hint_metrics = other->hint_metrics;
options->round_glyph_positions = other->round_glyph_positions;
}
/**
* cairo_font_options_create:
*
* Allocates a new font options object with all options initialized
* to default values.
*
* Return value: a newly allocated #cairo_font_options_t. Free with
* cairo_font_options_destroy(). This function always returns a
* valid pointer; if memory cannot be allocated, then a special
* error object is returned where all operations on the object do nothing.
* You can check for this with cairo_font_options_status().
*
* Since: 1.0
**/
cairo_font_options_t *
cairo_font_options_create (void)
{
cairo_font_options_t *options;
options = malloc (sizeof (cairo_font_options_t));
if (!options) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_options_t *) &_cairo_font_options_nil;
}
_cairo_font_options_init_default (options);
return options;
}
/**
* cairo_font_options_copy:
* @original: a #cairo_font_options_t
*
* Allocates a new font options object copying the option values from
* @original.
*
* Return value: a newly allocated #cairo_font_options_t. Free with
* cairo_font_options_destroy(). This function always returns a
* valid pointer; if memory cannot be allocated, then a special
* error object is returned where all operations on the object do nothing.
* You can check for this with cairo_font_options_status().
*
* Since: 1.0
**/
cairo_font_options_t *
cairo_font_options_copy (const cairo_font_options_t *original)
{
cairo_font_options_t *options;
if (cairo_font_options_status ((cairo_font_options_t *) original))
return (cairo_font_options_t *) &_cairo_font_options_nil;
options = malloc (sizeof (cairo_font_options_t));
if (!options) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_options_t *) &_cairo_font_options_nil;
}
_cairo_font_options_init_copy (options, original);
return options;
}
/**
* cairo_font_options_destroy:
* @options: a #cairo_font_options_t
*
* Destroys a #cairo_font_options_t object created with
* cairo_font_options_create() or cairo_font_options_copy().
*
* Since: 1.0
**/
void
cairo_font_options_destroy (cairo_font_options_t *options)
{
if (cairo_font_options_status (options))
return;
free (options);
}
/**
* cairo_font_options_status:
* @options: a #cairo_font_options_t
*
* Checks whether an error has previously occurred for this
* font options object
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
*
* Since: 1.0
**/
cairo_status_t
cairo_font_options_status (cairo_font_options_t *options)
{
if (options == NULL)
return CAIRO_STATUS_NULL_POINTER;
else if (options == (cairo_font_options_t *) &_cairo_font_options_nil)
return CAIRO_STATUS_NO_MEMORY;
else
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def (cairo_font_options_status);
/**
* cairo_font_options_merge:
* @options: a #cairo_font_options_t
* @other: another #cairo_font_options_t
*
* Merges non-default options from @other into @options, replacing
* existing values. This operation can be thought of as somewhat
* similar to compositing @other onto @options with the operation
* of %CAIRO_OPERATOR_OVER.
*
* Since: 1.0
**/
void
cairo_font_options_merge (cairo_font_options_t *options,
const cairo_font_options_t *other)
{
if (cairo_font_options_status (options))
return;
if (cairo_font_options_status ((cairo_font_options_t *) other))
return;
if (other->antialias != CAIRO_ANTIALIAS_DEFAULT)
options->antialias = other->antialias;
if (other->subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT)
options->subpixel_order = other->subpixel_order;
if (other->lcd_filter != CAIRO_LCD_FILTER_DEFAULT)
options->lcd_filter = other->lcd_filter;
if (other->hint_style != CAIRO_HINT_STYLE_DEFAULT)
options->hint_style = other->hint_style;
if (other->hint_metrics != CAIRO_HINT_METRICS_DEFAULT)
options->hint_metrics = other->hint_metrics;
if (other->round_glyph_positions != CAIRO_ROUND_GLYPH_POS_DEFAULT)
options->round_glyph_positions = other->round_glyph_positions;
}
slim_hidden_def (cairo_font_options_merge);
/**
* cairo_font_options_equal:
* @options: a #cairo_font_options_t
* @other: another #cairo_font_options_t
*
* Compares two font options objects for equality.
*
* Return value: %TRUE if all fields of the two font options objects match.
* Note that this function will return %FALSE if either object is in
* error.
*
* Since: 1.0
**/
cairo_bool_t
cairo_font_options_equal (const cairo_font_options_t *options,
const cairo_font_options_t *other)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return FALSE;
if (cairo_font_options_status ((cairo_font_options_t *) other))
return FALSE;
if (options == other)
return TRUE;
return (options->antialias == other->antialias &&
options->subpixel_order == other->subpixel_order &&
options->lcd_filter == other->lcd_filter &&
options->hint_style == other->hint_style &&
options->hint_metrics == other->hint_metrics &&
options->round_glyph_positions == other->round_glyph_positions);
}
slim_hidden_def (cairo_font_options_equal);
/**
* cairo_font_options_hash:
* @options: a #cairo_font_options_t
*
* Compute a hash for the font options object; this value will
* be useful when storing an object containing a #cairo_font_options_t
* in a hash table.
*
* Return value: the hash value for the font options object.
* The return value can be cast to a 32-bit type if a
* 32-bit hash value is needed.
*
* Since: 1.0
**/
unsigned long
cairo_font_options_hash (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
options = &_cairo_font_options_nil; /* force default values */
return ((options->antialias) |
(options->subpixel_order << 4) |
(options->lcd_filter << 8) |
(options->hint_style << 12) |
(options->hint_metrics << 16));
}
slim_hidden_def (cairo_font_options_hash);
/**
* cairo_font_options_set_antialias:
* @options: a #cairo_font_options_t
* @antialias: the new antialiasing mode
*
* Sets the antialiasing mode for the font options object. This
* specifies the type of antialiasing to do when rendering text.
*
* Since: 1.0
**/
void
cairo_font_options_set_antialias (cairo_font_options_t *options,
cairo_antialias_t antialias)
{
if (cairo_font_options_status (options))
return;
options->antialias = antialias;
}
slim_hidden_def (cairo_font_options_set_antialias);
/**
* cairo_font_options_get_antialias:
* @options: a #cairo_font_options_t
*
* Gets the antialiasing mode for the font options object.
*
* Return value: the antialiasing mode
*
* Since: 1.0
**/
cairo_antialias_t
cairo_font_options_get_antialias (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_ANTIALIAS_DEFAULT;
return options->antialias;
}
/**
* cairo_font_options_set_subpixel_order:
* @options: a #cairo_font_options_t
* @subpixel_order: the new subpixel order
*
* Sets the subpixel order for the font options object. The subpixel
* order specifies the order of color elements within each pixel on
* the display device when rendering with an antialiasing mode of
* %CAIRO_ANTIALIAS_SUBPIXEL. See the documentation for
* #cairo_subpixel_order_t for full details.
*
* Since: 1.0
**/
void
cairo_font_options_set_subpixel_order (cairo_font_options_t *options,
cairo_subpixel_order_t subpixel_order)
{
if (cairo_font_options_status (options))
return;
options->subpixel_order = subpixel_order;
}
slim_hidden_def (cairo_font_options_set_subpixel_order);
/**
* cairo_font_options_get_subpixel_order:
* @options: a #cairo_font_options_t
*
* Gets the subpixel order for the font options object.
* See the documentation for #cairo_subpixel_order_t for full details.
*
* Return value: the subpixel order for the font options object
*
* Since: 1.0
**/
cairo_subpixel_order_t
cairo_font_options_get_subpixel_order (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_SUBPIXEL_ORDER_DEFAULT;
return options->subpixel_order;
}
/**
* _cairo_font_options_set_lcd_filter:
* @options: a #cairo_font_options_t
* @lcd_filter: the new LCD filter
*
* Sets the LCD filter for the font options object. The LCD filter
* specifies how pixels are filtered when rendered with an antialiasing
* mode of %CAIRO_ANTIALIAS_SUBPIXEL. See the documentation for
* #cairo_lcd_filter_t for full details.
**/
void
_cairo_font_options_set_lcd_filter (cairo_font_options_t *options,
cairo_lcd_filter_t lcd_filter)
{
if (cairo_font_options_status (options))
return;
options->lcd_filter = lcd_filter;
}
/**
* _cairo_font_options_get_lcd_filter:
* @options: a #cairo_font_options_t
*
* Gets the LCD filter for the font options object.
* See the documentation for #cairo_lcd_filter_t for full details.
*
* Return value: the LCD filter for the font options object
**/
cairo_lcd_filter_t
_cairo_font_options_get_lcd_filter (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_LCD_FILTER_DEFAULT;
return options->lcd_filter;
}
/**
* _cairo_font_options_set_round_glyph_positions:
* @options: a #cairo_font_options_t
* @round: the new rounding value
*
* Sets the rounding options for the font options object. If rounding is set, a
* glyph's position will be rounded to integer values.
**/
void
_cairo_font_options_set_round_glyph_positions (cairo_font_options_t *options,
cairo_round_glyph_positions_t round)
{
if (cairo_font_options_status (options))
return;
options->round_glyph_positions = round;
}
/**
* _cairo_font_options_get_round_glyph_positions:
* @options: a #cairo_font_options_t
*
* Gets the glyph position rounding option for the font options object.
*
* Return value: The round glyph posistions flag for the font options object.
**/
cairo_round_glyph_positions_t
_cairo_font_options_get_round_glyph_positions (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_ROUND_GLYPH_POS_DEFAULT;
return options->round_glyph_positions;
}
/**
* cairo_font_options_set_hint_style:
* @options: a #cairo_font_options_t
* @hint_style: the new hint style
*
* Sets the hint style for font outlines for the font options object.
* This controls whether to fit font outlines to the pixel grid,
* and if so, whether to optimize for fidelity or contrast.
* See the documentation for #cairo_hint_style_t for full details.
*
* Since: 1.0
**/
void
cairo_font_options_set_hint_style (cairo_font_options_t *options,
cairo_hint_style_t hint_style)
{
if (cairo_font_options_status (options))
return;
options->hint_style = hint_style;
}
slim_hidden_def (cairo_font_options_set_hint_style);
/**
* cairo_font_options_get_hint_style:
* @options: a #cairo_font_options_t
*
* Gets the hint style for font outlines for the font options object.
* See the documentation for #cairo_hint_style_t for full details.
*
* Return value: the hint style for the font options object
*
* Since: 1.0
**/
cairo_hint_style_t
cairo_font_options_get_hint_style (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_HINT_STYLE_DEFAULT;
return options->hint_style;
}
/**
* cairo_font_options_set_hint_metrics:
* @options: a #cairo_font_options_t
* @hint_metrics: the new metrics hinting mode
*
* Sets the metrics hinting mode for the font options object. This
* controls whether metrics are quantized to integer values in
* device units.
* See the documentation for #cairo_hint_metrics_t for full details.
*
* Since: 1.0
**/
void
cairo_font_options_set_hint_metrics (cairo_font_options_t *options,
cairo_hint_metrics_t hint_metrics)
{
if (cairo_font_options_status (options))
return;
options->hint_metrics = hint_metrics;
}
slim_hidden_def (cairo_font_options_set_hint_metrics);
/**
* cairo_font_options_get_hint_metrics:
* @options: a #cairo_font_options_t
*
* Gets the metrics hinting mode for the font options object.
* See the documentation for #cairo_hint_metrics_t for full details.
*
* Return value: the metrics hinting mode for the font options object
*
* Since: 1.0
**/
cairo_hint_metrics_t
cairo_font_options_get_hint_metrics (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_HINT_METRICS_DEFAULT;
return options->hint_metrics;
}

View File

@@ -0,0 +1,78 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2000 Keith Packard
* Copyright © 2005 Red Hat, Inc
* Copyright © 2010 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Graydon Hoare <graydon@redhat.com>
* Owen Taylor <otaylor@redhat.com>
* Keith Packard <keithp@keithp.com>
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef _CAIRO_FONTCONFIG_PRIVATE_H
#define _CAIRO_FONTCONFIG_PRIVATE_H
#include "cairo.h"
#if CAIRO_HAS_FC_FONT
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
#endif
/* sub-pixel order */
#ifndef FC_RGBA_UNKNOWN
#define FC_RGBA_UNKNOWN 0
#define FC_RGBA_RGB 1
#define FC_RGBA_BGR 2
#define FC_RGBA_VRGB 3
#define FC_RGBA_VBGR 4
#define FC_RGBA_NONE 5
#endif
/* hinting style */
#ifndef FC_HINT_NONE
#define FC_HINT_NONE 0
#define FC_HINT_SLIGHT 1
#define FC_HINT_MEDIUM 2
#define FC_HINT_FULL 3
#endif
/* LCD filter */
#ifndef FC_LCD_NONE
#define FC_LCD_NONE 0
#define FC_LCD_DEFAULT 1
#define FC_LCD_LIGHT 2
#define FC_LCD_LEGACY 3
#endif
#endif /* _CAIRO_FONTCONFIG_PRIVATE_H */

View File

@@ -0,0 +1,139 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_FREED_POOL_H
#define CAIRO_FREED_POOL_H
#include "cairoint.h"
#include "cairo-atomic-private.h"
CAIRO_BEGIN_DECLS
#define DISABLE_FREED_POOLS 0
#if HAS_ATOMIC_OPS && ! DISABLE_FREED_POOLS
/* Keep a stash of recently freed clip_paths, since we need to
* reallocate them frequently.
*/
#define MAX_FREED_POOL_SIZE 16
typedef struct {
void *pool[MAX_FREED_POOL_SIZE];
int top;
} freed_pool_t;
static cairo_always_inline void *
_atomic_fetch (void **slot)
{
void *ptr;
do {
ptr = _cairo_atomic_ptr_get (slot);
} while (! _cairo_atomic_ptr_cmpxchg (slot, ptr, NULL));
return ptr;
}
static cairo_always_inline cairo_bool_t
_atomic_store (void **slot, void *ptr)
{
return _cairo_atomic_ptr_cmpxchg (slot, NULL, ptr);
}
cairo_private void *
_freed_pool_get_search (freed_pool_t *pool);
static inline void *
_freed_pool_get (freed_pool_t *pool)
{
void *ptr;
int i;
i = pool->top - 1;
if (i < 0)
i = 0;
ptr = _atomic_fetch (&pool->pool[i]);
if (likely (ptr != NULL)) {
pool->top = i;
return ptr;
}
/* either empty or contended */
return _freed_pool_get_search (pool);
}
cairo_private void
_freed_pool_put_search (freed_pool_t *pool, void *ptr);
static inline void
_freed_pool_put (freed_pool_t *pool, void *ptr)
{
int i;
i = pool->top;
if (likely (i < ARRAY_LENGTH (pool->pool) &&
_atomic_store (&pool->pool[i], ptr)))
{
pool->top = i + 1;
return;
}
/* either full or contended */
_freed_pool_put_search (pool, ptr);
}
cairo_private void
_freed_pool_reset (freed_pool_t *pool);
#define HAS_FREED_POOL 1
#else
/* A warning about an unused freed-pool in a build without atomics
* enabled usually indicates a missing _freed_pool_reset() in the
* static reset function */
typedef int freed_pool_t;
#define _freed_pool_get(pool) NULL
#define _freed_pool_put(pool, ptr) free(ptr)
#define _freed_pool_reset(ptr)
#endif
CAIRO_END_DECLS
#endif /* CAIRO_FREED_POOL_PRIVATE_H */

View File

@@ -0,0 +1,93 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-freed-pool-private.h"
#if HAS_FREED_POOL
void *
_freed_pool_get_search (freed_pool_t *pool)
{
void *ptr;
int i;
for (i = ARRAY_LENGTH (pool->pool); i--;) {
ptr = _atomic_fetch (&pool->pool[i]);
if (ptr != NULL) {
pool->top = i;
return ptr;
}
}
/* empty */
pool->top = 0;
return NULL;
}
void
_freed_pool_put_search (freed_pool_t *pool, void *ptr)
{
int i;
for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
if (_atomic_store (&pool->pool[i], ptr)) {
pool->top = i + 1;
return;
}
}
/* full */
pool->top = i;
free (ptr);
}
void
_freed_pool_reset (freed_pool_t *pool)
{
int i;
for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
free (pool->pool[i]);
pool->pool[i] = NULL;
}
pool->top = 0;
}
#endif

View File

@@ -0,0 +1,139 @@
/*
* Copyright © 2006 Joonas Pihlaja
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef CAIRO_FREELIST_H
#define CAIRO_FREELIST_H
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
#include "cairo-freelist-type-private.h"
/* for stand-alone compilation*/
#ifndef VG
#define VG(x)
#endif
#ifndef NULL
#define NULL (void *) 0
#endif
/* Initialise a freelist that will be responsible for allocating
* nodes of size nodesize. */
cairo_private void
_cairo_freelist_init (cairo_freelist_t *freelist, unsigned nodesize);
/* Deallocate any nodes in the freelist. */
cairo_private void
_cairo_freelist_fini (cairo_freelist_t *freelist);
/* Allocate a new node from the freelist. If the freelist contains no
* nodes, a new one will be allocated using malloc(). The caller is
* responsible for calling _cairo_freelist_free() or free() on the
* returned node. Returns %NULL on memory allocation error. */
cairo_private void *
_cairo_freelist_alloc (cairo_freelist_t *freelist);
/* Allocate a new node from the freelist. If the freelist contains no
* nodes, a new one will be allocated using calloc(). The caller is
* responsible for calling _cairo_freelist_free() or free() on the
* returned node. Returns %NULL on memory allocation error. */
cairo_private void *
_cairo_freelist_calloc (cairo_freelist_t *freelist);
/* Return a node to the freelist. This does not deallocate the memory,
* but makes it available for later reuse by
* _cairo_freelist_alloc(). */
cairo_private void
_cairo_freelist_free (cairo_freelist_t *freelist, void *node);
cairo_private void
_cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize);
cairo_private void
_cairo_freepool_fini (cairo_freepool_t *freepool);
static inline void
_cairo_freepool_reset (cairo_freepool_t *freepool)
{
while (freepool->pools != &freepool->embedded_pool) {
cairo_freelist_pool_t *pool = freepool->pools;
freepool->pools = pool->next;
pool->next = freepool->freepools;
freepool->freepools = pool;
}
freepool->embedded_pool.rem = sizeof (freepool->embedded_data);
freepool->embedded_pool.data = freepool->embedded_data;
}
cairo_private void *
_cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool);
static inline void *
_cairo_freepool_alloc_from_pool (cairo_freepool_t *freepool)
{
cairo_freelist_pool_t *pool;
uint8_t *ptr;
pool = freepool->pools;
if (unlikely (freepool->nodesize > pool->rem))
return _cairo_freepool_alloc_from_new_pool (freepool);
ptr = pool->data;
pool->data += freepool->nodesize;
pool->rem -= freepool->nodesize;
VG (VALGRIND_MAKE_MEM_UNDEFINED (ptr, freepool->nodesize));
return ptr;
}
static inline void *
_cairo_freepool_alloc (cairo_freepool_t *freepool)
{
cairo_freelist_node_t *node;
node = freepool->first_free_node;
if (node == NULL)
return _cairo_freepool_alloc_from_pool (freepool);
VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
freepool->first_free_node = node->next;
VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freepool->nodesize));
return node;
}
cairo_private cairo_status_t
_cairo_freepool_alloc_array (cairo_freepool_t *freepool,
int count,
void **array);
static inline void
_cairo_freepool_free (cairo_freepool_t *freepool, void *ptr)
{
cairo_freelist_node_t *node = ptr;
node->next = freepool->first_free_node;
freepool->first_free_node = node;
VG (VALGRIND_MAKE_MEM_NOACCESS (node, freepool->nodesize));
}
#endif /* CAIRO_FREELIST_H */

View File

@@ -0,0 +1,54 @@
/*
* Copyright © 2010 Joonas Pihlaja
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef CAIRO_FREELIST_TYPE_H
#define CAIRO_FREELIST_TYPE_H
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
typedef struct _cairo_freelist_node cairo_freelist_node_t;
struct _cairo_freelist_node {
cairo_freelist_node_t *next;
};
typedef struct _cairo_freelist {
cairo_freelist_node_t *first_free_node;
unsigned nodesize;
} cairo_freelist_t;
typedef struct _cairo_freelist_pool cairo_freelist_pool_t;
struct _cairo_freelist_pool {
cairo_freelist_pool_t *next;
unsigned size, rem;
uint8_t *data;
};
typedef struct _cairo_freepool {
cairo_freelist_node_t *first_free_node;
cairo_freelist_pool_t *pools;
cairo_freelist_pool_t *freepools;
unsigned nodesize;
cairo_freelist_pool_t embedded_pool;
uint8_t embedded_data[1000];
} cairo_freepool_t;
#endif /* CAIRO_FREELIST_TYPE_H */

View File

@@ -0,0 +1,191 @@
/*
* Copyright © 2006 Joonas Pihlaja
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-freelist-private.h"
void
_cairo_freelist_init (cairo_freelist_t *freelist, unsigned nodesize)
{
memset (freelist, 0, sizeof (cairo_freelist_t));
freelist->nodesize = nodesize;
}
void
_cairo_freelist_fini (cairo_freelist_t *freelist)
{
cairo_freelist_node_t *node = freelist->first_free_node;
while (node) {
cairo_freelist_node_t *next;
VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
next = node->next;
free (node);
node = next;
}
}
void *
_cairo_freelist_alloc (cairo_freelist_t *freelist)
{
if (freelist->first_free_node) {
cairo_freelist_node_t *node;
node = freelist->first_free_node;
VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
freelist->first_free_node = node->next;
VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freelist->nodesize));
return node;
}
return malloc (freelist->nodesize);
}
void *
_cairo_freelist_calloc (cairo_freelist_t *freelist)
{
void *node = _cairo_freelist_alloc (freelist);
if (node)
memset (node, 0, freelist->nodesize);
return node;
}
void
_cairo_freelist_free (cairo_freelist_t *freelist, void *voidnode)
{
cairo_freelist_node_t *node = voidnode;
if (node) {
node->next = freelist->first_free_node;
freelist->first_free_node = node;
VG (VALGRIND_MAKE_MEM_NOACCESS (node, freelist->nodesize));
}
}
void
_cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize)
{
freepool->first_free_node = NULL;
freepool->pools = &freepool->embedded_pool;
freepool->freepools = NULL;
freepool->nodesize = nodesize;
freepool->embedded_pool.next = NULL;
freepool->embedded_pool.size = sizeof (freepool->embedded_data);
freepool->embedded_pool.rem = sizeof (freepool->embedded_data);
freepool->embedded_pool.data = freepool->embedded_data;
VG (VALGRIND_MAKE_MEM_NOACCESS (freepool->embedded_data, sizeof (freepool->embedded_data)));
}
void
_cairo_freepool_fini (cairo_freepool_t *freepool)
{
cairo_freelist_pool_t *pool;
pool = freepool->pools;
while (pool != &freepool->embedded_pool) {
cairo_freelist_pool_t *next = pool->next;
free (pool);
pool = next;
}
pool = freepool->freepools;
while (pool != NULL) {
cairo_freelist_pool_t *next = pool->next;
free (pool);
pool = next;
}
VG (VALGRIND_MAKE_MEM_NOACCESS (freepool, sizeof (freepool)));
}
void *
_cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool)
{
cairo_freelist_pool_t *pool;
int poolsize;
if (freepool->freepools != NULL) {
pool = freepool->freepools;
freepool->freepools = pool->next;
poolsize = pool->size;
} else {
if (freepool->pools != &freepool->embedded_pool)
poolsize = 2 * freepool->pools->size;
else
poolsize = (128 * freepool->nodesize + 8191) & -8192;
pool = malloc (sizeof (cairo_freelist_pool_t) + poolsize);
if (unlikely (pool == NULL))
return pool;
pool->size = poolsize;
}
pool->next = freepool->pools;
freepool->pools = pool;
pool->rem = poolsize - freepool->nodesize;
pool->data = (uint8_t *) (pool + 1) + freepool->nodesize;
VG (VALGRIND_MAKE_MEM_NOACCESS (pool->data, pool->rem));
return pool + 1;
}
cairo_status_t
_cairo_freepool_alloc_array (cairo_freepool_t *freepool,
int count,
void **array)
{
int i;
for (i = 0; i < count; i++) {
cairo_freelist_node_t *node;
node = freepool->first_free_node;
if (likely (node != NULL)) {
VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
freepool->first_free_node = node->next;
VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freepool->nodesize));
} else {
node = _cairo_freepool_alloc_from_pool (freepool);
if (unlikely (node == NULL))
goto CLEANUP;
}
array[i] = node;
}
return CAIRO_STATUS_SUCCESS;
CLEANUP:
while (i--)
_cairo_freepool_free (freepool, array[i]);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,61 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Graydon Hoare <graydon@redhat.com>
* Owen Taylor <otaylor@redhat.com>
*/
#ifndef CAIRO_FT_PRIVATE_H
#define CAIRO_FT_PRIVATE_H
#include "cairo-ft.h"
#include "cairoint.h"
#if CAIRO_HAS_FT_FONT
CAIRO_BEGIN_DECLS
typedef struct _cairo_ft_unscaled_font cairo_ft_unscaled_font_t;
cairo_private cairo_bool_t
_cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font);
/* These functions are needed by the PDF backend, which needs to keep track of the
* the different fonts-on-disk used by a document, so it can embed them
*/
cairo_private unsigned int
_cairo_ft_scaled_font_get_load_flags (cairo_scaled_font_t *scaled_font);
CAIRO_END_DECLS
#endif /* CAIRO_HAS_FT_FONT */
#endif /* CAIRO_FT_PRIVATE_H */

View File

@@ -0,0 +1,118 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Graydon Hoare <graydon@redhat.com>
* Owen Taylor <otaylor@redhat.com>
*/
#ifndef CAIRO_FT_H
#define CAIRO_FT_H
#include "cairo.h"
#if CAIRO_HAS_FT_FONT
/* Fontconfig/Freetype platform-specific font interface */
#include <ft2build.h>
#include FT_FREETYPE_H
#if CAIRO_HAS_FC_FONT
#include <fontconfig/fontconfig.h>
#endif
CAIRO_BEGIN_DECLS
cairo_public cairo_font_face_t *
cairo_ft_font_face_create_for_ft_face (FT_Face face,
int load_flags);
/**
* cairo_ft_synthesize_t:
* @CAIRO_FT_SYNTHESIZE_BOLD: Embolden the glyphs (redraw with a pixel offset)
* @CAIRO_FT_SYNTHESIZE_OBLIQUE: Slant the glyph outline by 12 degrees to the
* right.
*
* A set of synthesis options to control how FreeType renders the glyphs
* for a particular font face.
*
* Individual synthesis features of a #cairo_ft_font_face_t can be set
* using cairo_ft_font_face_set_synthesize(), or disabled using
* cairo_ft_font_face_unset_synthesize(). The currently enabled set of
* synthesis options can be queried with cairo_ft_font_face_get_synthesize().
*
* Note: that when synthesizing glyphs, the font metrics returned will only
* be estimates.
*
* Since: 1.12
**/
typedef enum {
CAIRO_FT_SYNTHESIZE_BOLD = 1 << 0,
CAIRO_FT_SYNTHESIZE_OBLIQUE = 1 << 1
} cairo_ft_synthesize_t;
cairo_public void
cairo_ft_font_face_set_synthesize (cairo_font_face_t *font_face,
unsigned int synth_flags);
cairo_public void
cairo_ft_font_face_unset_synthesize (cairo_font_face_t *font_face,
unsigned int synth_flags);
cairo_public unsigned int
cairo_ft_font_face_get_synthesize (cairo_font_face_t *font_face);
cairo_public FT_Face
cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *scaled_font);
cairo_public void
cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *scaled_font);
#if CAIRO_HAS_FC_FONT
cairo_public cairo_font_face_t *
cairo_ft_font_face_create_for_pattern (FcPattern *pattern);
cairo_public void
cairo_ft_font_options_substitute (const cairo_font_options_t *options,
FcPattern *pattern);
#endif
CAIRO_END_DECLS
#else /* CAIRO_HAS_FT_FONT */
# error Cairo was not compiled with support for the freetype font backend
#endif /* CAIRO_HAS_FT_FONT */
#endif /* CAIRO_FT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,802 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Eric Anholt
* Copyright © 2009 Chris Wilson
* Copyright © 2005,2010 Red Hat, Inc
* Copyright © 2010 Linaro Limited
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Benjamin Otte <otte@gnome.org>
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
* Eric Anholt <eric@anholt.net>
* Alexandros Frantzis <alexandros.frantzis@linaro.org>
*/
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-gl-private.h"
#define MAX_MSAA_SAMPLES 4
static void
_gl_lock (void *device)
{
cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
ctx->acquire (ctx);
}
static void
_gl_unlock (void *device)
{
cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
ctx->release (ctx);
}
static cairo_status_t
_gl_flush (void *device)
{
cairo_gl_context_t *ctx;
cairo_status_t status;
status = _cairo_gl_context_acquire (device, &ctx);
if (unlikely (status))
return status;
_cairo_gl_composite_flush (ctx);
_cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
_cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
if (ctx->clip_region) {
cairo_region_destroy (ctx->clip_region);
ctx->clip_region = NULL;
}
ctx->current_target = NULL;
ctx->current_operator = -1;
ctx->vertex_size = 0;
ctx->pre_shader = NULL;
_cairo_gl_set_shader (ctx, NULL);
ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, 0);
glDisable (GL_SCISSOR_TEST);
glDisable (GL_BLEND);
return _cairo_gl_context_release (ctx, status);
}
static void
_gl_finish (void *device)
{
cairo_gl_context_t *ctx = device;
int n;
_gl_lock (device);
_cairo_cache_fini (&ctx->gradients);
_cairo_gl_context_fini_shaders (ctx);
for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
_cairo_gl_glyph_cache_fini (ctx, &ctx->glyph_cache[n]);
_gl_unlock (device);
}
static void
_gl_destroy (void *device)
{
cairo_gl_context_t *ctx = device;
ctx->acquire (ctx);
while (! cairo_list_is_empty (&ctx->fonts)) {
cairo_gl_font_t *font;
font = cairo_list_first_entry (&ctx->fonts,
cairo_gl_font_t,
link);
cairo_list_del (&font->base.link);
cairo_list_del (&font->link);
free (font);
}
_cairo_array_fini (&ctx->tristrip_indices);
cairo_region_destroy (ctx->clip_region);
_cairo_clip_destroy (ctx->clip);
free (ctx->vb);
ctx->destroy (ctx);
free (ctx);
}
static const cairo_device_backend_t _cairo_gl_device_backend = {
CAIRO_DEVICE_TYPE_GL,
_gl_lock,
_gl_unlock,
_gl_flush, /* flush */
_gl_finish,
_gl_destroy,
};
static cairo_bool_t
_cairo_gl_msaa_compositor_enabled (void)
{
const char *env = getenv ("CAIRO_GL_COMPOSITOR");
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_status_t status;
cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
int gl_version = _cairo_gl_get_version ();
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.
* However, it is useful to force one particular compositor whilst
* testing.
*/
if (_cairo_gl_msaa_compositor_enabled ())
ctx->compositor = _cairo_gl_msaa_compositor_get ();
else
ctx->compositor = _cairo_gl_span_compositor_get ();
ctx->thread_aware = TRUE;
memset (ctx->glyph_cache, 0, sizeof (ctx->glyph_cache));
cairo_list_init (&ctx->fonts);
/* Support only GL version >= 1.3 */
if (gl_version < CAIRO_GL_VERSION_ENCODE (1, 3))
return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
/* Check for required extensions */
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;
} else if (_cairo_gl_has_extension ("GL_ARB_texture_rectangle")) {
ctx->tex_target = GL_TEXTURE_RECTANGLE;
ctx->has_npot_repeat = FALSE;
} else
return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
} else {
ctx->tex_target = GL_TEXTURE_2D;
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 (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 (is_gles && ! _cairo_gl_has_extension ("GL_EXT_texture_format_BGRA8888"))
return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
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 =
(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 (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 (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 (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);
}
#endif
ctx->supports_msaa = ctx->num_samples > 1;
if (ctx->num_samples > MAX_MSAA_SAMPLES)
ctx->num_samples = MAX_MSAA_SAMPLES;
ctx->current_operator = -1;
ctx->gl_flavor = gl_flavor;
status = _cairo_gl_context_init_shaders (ctx);
if (unlikely (status))
return status;
status = _cairo_cache_init (&ctx->gradients,
_cairo_gl_gradient_equal,
NULL,
(cairo_destroy_func_t) _cairo_gl_gradient_destroy,
CAIRO_GL_GRADIENT_CACHE_SIZE);
if (unlikely (status))
return status;
ctx->vb = malloc (CAIRO_GL_VBO_SIZE);
if (unlikely (ctx->vb == NULL)) {
_cairo_cache_fini (&ctx->gradients);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
ctx->primitive_type = CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES;
_cairo_array_init (&ctx->tristrip_indices, sizeof (unsigned short));
/* PBO for any sort of texture upload */
dispatch->GenBuffers (1, &ctx->texture_load_pbo);
ctx->max_framebuffer_size = 0;
glGetIntegerv (GL_MAX_RENDERBUFFER_SIZE, &ctx->max_framebuffer_size);
ctx->max_texture_size = 0;
glGetIntegerv (GL_MAX_TEXTURE_SIZE, &ctx->max_texture_size);
ctx->max_textures = 0;
glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &ctx->max_textures);
for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
_cairo_gl_glyph_cache_init (&ctx->glyph_cache[n]);
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_gl_context_activate (cairo_gl_context_t *ctx,
cairo_gl_tex_t tex_unit)
{
if (ctx->max_textures <= (GLint) tex_unit) {
if (tex_unit < 2) {
_cairo_gl_composite_flush (ctx);
_cairo_gl_context_destroy_operand (ctx, ctx->max_textures - 1);
}
glActiveTexture (ctx->max_textures - 1);
} else {
glActiveTexture (GL_TEXTURE0 + tex_unit);
}
}
static GLenum
_get_depth_stencil_format (cairo_gl_context_t *ctx)
{
/* This is necessary to properly handle the situation where both
OpenGL and OpenGLES are active and returning a sane default. */
#if CAIRO_HAS_GL_SURFACE
if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
return GL_DEPTH_STENCIL;
#endif
#if CAIRO_HAS_GLESV2_SURFACE
if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
return GL_DEPTH24_STENCIL8_OES;
#endif
#if CAIRO_HAS_GL_SURFACE
return GL_DEPTH_STENCIL;
#elif CAIRO_HAS_GLESV2_SURFACE
return GL_DEPTH24_STENCIL8_OES;
#endif
}
#if CAIRO_HAS_GLESV2_SURFACE
static void
_cairo_gl_ensure_msaa_gles_framebuffer (cairo_gl_context_t *ctx,
cairo_gl_surface_t *surface)
{
if (surface->msaa_active)
return;
ctx->dispatch.FramebufferTexture2DMultisample(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
ctx->tex_target,
surface->tex,
0,
ctx->num_samples);
/* From now on MSAA will always be active on this surface. */
surface->msaa_active = TRUE;
}
#endif
static void
_cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
cairo_gl_surface_t *surface)
{
GLenum status;
cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
if (likely (surface->fb))
return;
/* Create a framebuffer object wrapping the texture so that we can render
* to it.
*/
dispatch->GenFramebuffers (1, &surface->fb);
dispatch->BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
/* Unlike for desktop GL we only maintain one multisampling framebuffer
for OpenGLES since the EXT_multisampled_render_to_texture extension
does not require an explicit multisample resolution. */
#if CAIRO_HAS_GLESV2_SURFACE
if (surface->supports_msaa && _cairo_gl_msaa_compositor_enabled () &&
ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
_cairo_gl_ensure_msaa_gles_framebuffer (ctx, surface);
} else
#endif
dispatch->FramebufferTexture2D (GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
ctx->tex_target,
surface->tex,
0);
#if CAIRO_HAS_GL_SURFACE
glDrawBuffer (GL_COLOR_ATTACHMENT0);
glReadBuffer (GL_COLOR_ATTACHMENT0);
#endif
status = dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
const char *str;
switch (status) {
//case GL_FRAMEBUFFER_UNDEFINED: str= "undefined"; break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: str= "incomplete attachment"; break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: str= "incomplete/missing attachment"; break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: str= "incomplete draw buffer"; break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: str= "incomplete read buffer"; break;
case GL_FRAMEBUFFER_UNSUPPORTED: str= "unsupported"; break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: str= "incomplete multiple"; break;
default: str = "unknown error"; break;
}
fprintf (stderr,
"destination is framebuffer incomplete: %s [%#x]\n",
str, status);
}
}
#if CAIRO_HAS_GL_SURFACE
static void
_cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx,
cairo_gl_surface_t *surface)
{
assert (surface->supports_msaa);
assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
if (surface->msaa_fb)
return;
/* We maintain a separate framebuffer for multisampling operations.
This allows us to do a fast paint to the non-multisampling framebuffer
when mulitsampling is disabled. */
ctx->dispatch.GenFramebuffers (1, &surface->msaa_fb);
ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
ctx->dispatch.GenRenderbuffers (1, &surface->msaa_rb);
ctx->dispatch.BindRenderbuffer (GL_RENDERBUFFER, surface->msaa_rb);
/* FIXME: For now we assume that textures passed from the outside have GL_RGBA
format, but eventually we need to expose a way for the API consumer to pass
this information. */
ctx->dispatch.RenderbufferStorageMultisample (GL_RENDERBUFFER,
ctx->num_samples,
GL_RGBA,
surface->width,
surface->height);
ctx->dispatch.FramebufferRenderbuffer (GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
surface->msaa_rb);
/* Cairo surfaces start out initialized to transparent (black) */
glDisable (GL_SCISSOR_TEST);
glClearColor (0, 0, 0, 0);
glClear (GL_COLOR_BUFFER_BIT);
}
#endif
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
dispatch->GenRenderbuffers (1, &surface->msaa_depth_stencil);
dispatch->BindRenderbuffer (GL_RENDERBUFFER,
surface->msaa_depth_stencil);
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,
surface->msaa_depth_stencil);
}
#endif
#if CAIRO_HAS_GLESV2_SURFACE
if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER,
surface->msaa_depth_stencil);
dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER,
surface->msaa_depth_stencil);
}
#endif
if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
dispatch->DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
surface->msaa_depth_stencil = 0;
return FALSE;
}
return TRUE;
}
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;
if (surface->depth_stencil)
return TRUE;
_cairo_gl_ensure_framebuffer (ctx, surface);
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, surface->depth_stencil);
dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, surface->depth_stencil);
if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
dispatch->DeleteRenderbuffers (1, &surface->depth_stencil);
surface->depth_stencil = 0;
return FALSE;
}
return TRUE;
}
cairo_bool_t
_cairo_gl_ensure_stencil (cairo_gl_context_t *ctx,
cairo_gl_surface_t *surface)
{
if (! _cairo_gl_surface_is_texture (surface))
return TRUE; /* best guess for now, will check later */
if (! ctx->has_packed_depth_stencil)
return FALSE;
if (surface->msaa_active)
return _cairo_gl_ensure_msaa_depth_stencil_buffer (ctx, surface);
else
return _cairo_gl_ensure_depth_stencil_buffer (ctx, surface);
}
/*
* Stores a parallel projection transformation in matrix 'm',
* using column-major order.
*
* This is equivalent to:
*
* glLoadIdentity()
* gluOrtho2D()
*
* The calculation for the ortho tranformation was taken from the
* mesa source code.
*/
static void
_gl_identity_ortho (GLfloat *m,
GLfloat left, GLfloat right,
GLfloat bottom, GLfloat top)
{
#define M(row,col) m[col*4+row]
M(0,0) = 2.f / (right - left);
M(0,1) = 0.f;
M(0,2) = 0.f;
M(0,3) = -(right + left) / (right - left);
M(1,0) = 0.f;
M(1,1) = 2.f / (top - bottom);
M(1,2) = 0.f;
M(1,3) = -(top + bottom) / (top - bottom);
M(2,0) = 0.f;
M(2,1) = 0.f;
M(2,2) = -1.f;
M(2,3) = 0.f;
M(3,0) = 0.f;
M(3,1) = 0.f;
M(3,2) = 0.f;
M(3,3) = 1.f;
#undef M
}
#if CAIRO_HAS_GL_SURFACE
static void
bind_multisample_framebuffer (cairo_gl_context_t *ctx,
cairo_gl_surface_t *surface)
{
cairo_bool_t stencil_test_enabled;
cairo_bool_t scissor_test_enabled;
assert (surface->supports_msaa);
assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
_cairo_gl_ensure_framebuffer (ctx, surface);
_cairo_gl_ensure_multisampling (ctx, surface);
if (surface->msaa_active) {
glEnable (GL_MULTISAMPLE);
ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
return;
}
_cairo_gl_composite_flush (ctx);
stencil_test_enabled = glIsEnabled (GL_STENCIL_TEST);
scissor_test_enabled = glIsEnabled (GL_SCISSOR_TEST);
glDisable (GL_STENCIL_TEST);
glDisable (GL_SCISSOR_TEST);
glEnable (GL_MULTISAMPLE);
/* 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. */
ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->msaa_fb);
ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->fb);
ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height,
0, 0, surface->width, surface->height,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
if (stencil_test_enabled)
glEnable (GL_STENCIL_TEST);
if (scissor_test_enabled)
glEnable (GL_SCISSOR_TEST);
}
#endif
#if CAIRO_HAS_GL_SURFACE
static void
bind_singlesample_framebuffer (cairo_gl_context_t *ctx,
cairo_gl_surface_t *surface)
{
cairo_bool_t stencil_test_enabled;
cairo_bool_t scissor_test_enabled;
assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
_cairo_gl_ensure_framebuffer (ctx, surface);
if (! surface->msaa_active) {
glDisable (GL_MULTISAMPLE);
ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
return;
}
_cairo_gl_composite_flush (ctx);
stencil_test_enabled = glIsEnabled (GL_STENCIL_TEST);
scissor_test_enabled = glIsEnabled (GL_SCISSOR_TEST);
glDisable (GL_STENCIL_TEST);
glDisable (GL_SCISSOR_TEST);
glDisable (GL_MULTISAMPLE);
/* 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->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->fb);
ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->msaa_fb);
ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height,
0, 0, surface->width, surface->height,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
if (stencil_test_enabled)
glEnable (GL_STENCIL_TEST);
if (scissor_test_enabled)
glEnable (GL_SCISSOR_TEST);
}
#endif
void
_cairo_gl_context_bind_framebuffer (cairo_gl_context_t *ctx,
cairo_gl_surface_t *surface,
cairo_bool_t multisampling)
{
if (_cairo_gl_surface_is_texture (surface)) {
/* OpenGL ES surfaces only have either a multisample framebuffer or a
* singlesample framebuffer, so we cannot switch back and forth. */
if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
_cairo_gl_ensure_framebuffer (ctx, surface);
ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
return;
}
#if CAIRO_HAS_GL_SURFACE
if (multisampling)
bind_multisample_framebuffer (ctx, surface);
else
bind_singlesample_framebuffer (ctx, surface);
#endif
} else {
ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0);
#if CAIRO_HAS_GL_SURFACE
if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
if (multisampling)
glEnable (GL_MULTISAMPLE);
else
glDisable (GL_MULTISAMPLE);
}
#endif
}
surface->msaa_active = multisampling;
}
void
_cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
cairo_gl_surface_t *surface,
cairo_bool_t multisampling)
{
cairo_bool_t changing_surface, changing_sampling;
/* The decision whether or not to use multisampling happens when
* we create an OpenGL ES surface, so we can never switch modes. */
if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES)
multisampling = surface->msaa_active;
changing_surface = ctx->current_target != surface || surface->needs_update;
changing_sampling = surface->msaa_active != multisampling;
if (! changing_surface && ! changing_sampling)
return;
if (! changing_surface) {
_cairo_gl_composite_flush (ctx);
_cairo_gl_context_bind_framebuffer (ctx, surface, multisampling);
return;
}
_cairo_gl_composite_flush (ctx);
ctx->current_target = surface;
surface->needs_update = FALSE;
if (! _cairo_gl_surface_is_texture (surface)) {
ctx->make_current (ctx, surface);
}
_cairo_gl_context_bind_framebuffer (ctx, surface, multisampling);
if (! _cairo_gl_surface_is_texture (surface)) {
#if CAIRO_HAS_GL_SURFACE
glDrawBuffer (GL_BACK_LEFT);
glReadBuffer (GL_BACK_LEFT);
#endif
}
glDisable (GL_DITHER);
glViewport (0, 0, surface->width, surface->height);
if (_cairo_gl_surface_is_texture (surface))
_gl_identity_ortho (ctx->modelviewprojection_matrix,
0, surface->width, 0, surface->height);
else
_gl_identity_ortho (ctx->modelviewprojection_matrix,
0, surface->width, surface->height, 0);
}
void
cairo_gl_device_set_thread_aware (cairo_device_t *device,
cairo_bool_t thread_aware)
{
if (device->backend->type != CAIRO_DEVICE_TYPE_GL) {
_cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
return;
}
((cairo_gl_context_t *) device)->thread_aware = thread_aware;
}

View File

@@ -0,0 +1,129 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2010 Linaro Limited
*
* 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):
* Alexandros Frantzis <alexandros.frantzis@linaro.org>
*/
#ifndef CAIRO_GL_DISPATCH_PRIVATE_H
#define CAIRO_GL_DISPATCH_PRIVATE_H
#include "cairo-gl-private.h"
#include <stddef.h>
typedef enum _cairo_gl_dispatch_name {
CAIRO_GL_DISPATCH_NAME_CORE,
CAIRO_GL_DISPATCH_NAME_EXT,
CAIRO_GL_DISPATCH_NAME_ES,
CAIRO_GL_DISPATCH_NAME_COUNT
} cairo_gl_dispatch_name_t;
typedef struct _cairo_gl_dispatch_entry {
const char *name[CAIRO_GL_DISPATCH_NAME_COUNT];
size_t offset;
} cairo_gl_dispatch_entry_t;
#define DISPATCH_ENTRY_ARB(name) { { "gl"#name, "gl"#name"ARB", "gl"#name }, \
offsetof(cairo_gl_dispatch_t, name) }
#define DISPATCH_ENTRY_EXT(name) { { "gl"#name, "gl"#name"EXT", "gl"#name }, \
offsetof(cairo_gl_dispatch_t, name) }
#define DISPATCH_ENTRY_ARB_OES(name) { { "gl"#name, "gl"#name"ARB", "gl"#name"OES" }, \
offsetof(cairo_gl_dispatch_t, name) }
#define DISPATCH_ENTRY_EXT_IMG(name) { { "gl"#name, "gl"#name"EXT", "gl"#name"IMG" }, \
offsetof(cairo_gl_dispatch_t, name) }
#define DISPATCH_ENTRY_CUSTOM(name, name2) { { "gl"#name, "gl"#name2, "gl"#name }, \
offsetof(cairo_gl_dispatch_t, name)}
#define DISPATCH_ENTRY_LAST { { NULL, NULL, NULL }, 0 }
cairo_private cairo_gl_dispatch_entry_t dispatch_buffers_entries[] = {
DISPATCH_ENTRY_ARB (GenBuffers),
DISPATCH_ENTRY_ARB (BindBuffer),
DISPATCH_ENTRY_ARB (BufferData),
DISPATCH_ENTRY_ARB_OES (MapBuffer),
DISPATCH_ENTRY_ARB_OES (UnmapBuffer),
DISPATCH_ENTRY_LAST
};
cairo_private cairo_gl_dispatch_entry_t dispatch_shaders_entries[] = {
/* Shaders */
DISPATCH_ENTRY_CUSTOM (CreateShader, CreateShaderObjectARB),
DISPATCH_ENTRY_ARB (ShaderSource),
DISPATCH_ENTRY_ARB (CompileShader),
DISPATCH_ENTRY_CUSTOM (GetShaderiv, GetObjectParameterivARB),
DISPATCH_ENTRY_CUSTOM (GetShaderInfoLog, GetInfoLogARB),
DISPATCH_ENTRY_CUSTOM (DeleteShader, DeleteObjectARB),
/* Programs */
DISPATCH_ENTRY_CUSTOM (CreateProgram, CreateProgramObjectARB),
DISPATCH_ENTRY_CUSTOM (AttachShader, AttachObjectARB),
DISPATCH_ENTRY_CUSTOM (DeleteProgram, DeleteObjectARB),
DISPATCH_ENTRY_ARB (LinkProgram),
DISPATCH_ENTRY_CUSTOM (UseProgram, UseProgramObjectARB),
DISPATCH_ENTRY_CUSTOM (GetProgramiv, GetObjectParameterivARB),
DISPATCH_ENTRY_CUSTOM (GetProgramInfoLog, GetInfoLogARB),
/* Uniforms */
DISPATCH_ENTRY_ARB (GetUniformLocation),
DISPATCH_ENTRY_ARB (Uniform1f),
DISPATCH_ENTRY_ARB (Uniform2f),
DISPATCH_ENTRY_ARB (Uniform3f),
DISPATCH_ENTRY_ARB (Uniform4f),
DISPATCH_ENTRY_ARB (UniformMatrix3fv),
DISPATCH_ENTRY_ARB (UniformMatrix4fv),
DISPATCH_ENTRY_ARB (Uniform1i),
/* Attributes */
DISPATCH_ENTRY_ARB (BindAttribLocation),
DISPATCH_ENTRY_ARB (VertexAttribPointer),
DISPATCH_ENTRY_ARB (EnableVertexAttribArray),
DISPATCH_ENTRY_ARB (DisableVertexAttribArray),
DISPATCH_ENTRY_LAST
};
cairo_private cairo_gl_dispatch_entry_t dispatch_fbo_entries[] = {
DISPATCH_ENTRY_EXT (GenFramebuffers),
DISPATCH_ENTRY_EXT (BindFramebuffer),
DISPATCH_ENTRY_EXT (FramebufferTexture2D),
DISPATCH_ENTRY_EXT (CheckFramebufferStatus),
DISPATCH_ENTRY_EXT (DeleteFramebuffers),
DISPATCH_ENTRY_EXT (GenRenderbuffers),
DISPATCH_ENTRY_EXT (BindRenderbuffer),
DISPATCH_ENTRY_EXT (RenderbufferStorage),
DISPATCH_ENTRY_EXT (FramebufferRenderbuffer),
DISPATCH_ENTRY_EXT (DeleteRenderbuffers),
DISPATCH_ENTRY_EXT (BlitFramebuffer),
DISPATCH_ENTRY_LAST
};
cairo_private cairo_gl_dispatch_entry_t dispatch_multisampling_entries[] = {
DISPATCH_ENTRY_EXT_IMG (RenderbufferStorageMultisample),
DISPATCH_ENTRY_EXT_IMG (FramebufferTexture2DMultisample),
DISPATCH_ENTRY_LAST
};
#endif /* CAIRO_GL_DISPATCH_PRIVATE_H */

View File

@@ -0,0 +1,261 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2010 Linaro Limited
*
* 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):
* Alexandros Frantzis <alexandros.frantzis@linaro.org>
*/
#include "cairoint.h"
#include "cairo-gl-private.h"
#include "cairo-gl-dispatch-private.h"
#if CAIRO_HAS_DLSYM
#include <dlfcn.h>
#endif
#if CAIRO_HAS_DLSYM
static void *
_cairo_gl_dispatch_open_lib (void)
{
return dlopen (NULL, RTLD_LAZY);
}
static void
_cairo_gl_dispatch_close_lib (void *handle)
{
dlclose (handle);
}
static cairo_gl_generic_func_t
_cairo_gl_dispatch_get_proc_addr (void *handle, const char *name)
{
return (cairo_gl_generic_func_t) dlsym (handle, name);
}
#else
static void *
_cairo_gl_dispatch_open_lib (void)
{
return NULL;
}
static void
_cairo_gl_dispatch_close_lib (void *handle)
{
return;
}
static cairo_gl_generic_func_t
_cairo_gl_dispatch_get_proc_addr (void *handle, const char *name)
{
return NULL;
}
#endif /* CAIRO_HAS_DLSYM */
static void
_cairo_gl_dispatch_init_entries (cairo_gl_dispatch_t *dispatch,
cairo_gl_get_proc_addr_func_t get_proc_addr,
cairo_gl_dispatch_entry_t *entries,
cairo_gl_dispatch_name_t dispatch_name)
{
cairo_gl_dispatch_entry_t *entry = entries;
void *handle = _cairo_gl_dispatch_open_lib ();
while (entry->name[CAIRO_GL_DISPATCH_NAME_CORE] != NULL) {
void *dispatch_ptr = &((char *) dispatch)[entry->offset];
const char *name = entry->name[dispatch_name];
/*
* In strictly conforming EGL implementations, eglGetProcAddress() can
* be used only to get extension functions, but some of the functions
* we want belong to core GL(ES). If the *GetProcAddress function
* provided by the context fails, try to get the address of the wanted
* GL function using standard system facilities (eg dlsym() in *nix
* systems).
*/
cairo_gl_generic_func_t func = get_proc_addr (name);
if (func == NULL)
func = _cairo_gl_dispatch_get_proc_addr (handle, name);
*((cairo_gl_generic_func_t *) dispatch_ptr) = func;
++entry;
}
_cairo_gl_dispatch_close_lib (handle);
}
static cairo_status_t
_cairo_gl_dispatch_init_buffers (cairo_gl_dispatch_t *dispatch,
cairo_gl_get_proc_addr_func_t get_proc_addr,
int gl_version, cairo_gl_flavor_t gl_flavor)
{
cairo_gl_dispatch_name_t dispatch_name;
if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
{
if (gl_version >= CAIRO_GL_VERSION_ENCODE (1, 5))
dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
else if (_cairo_gl_has_extension ("GL_ARB_vertex_buffer_object"))
dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
else
return CAIRO_STATUS_DEVICE_ERROR;
}
else if (gl_flavor == CAIRO_GL_FLAVOR_ES &&
gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
{
dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
}
else
{
return CAIRO_STATUS_DEVICE_ERROR;
}
_cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
dispatch_buffers_entries, dispatch_name);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_gl_dispatch_init_shaders (cairo_gl_dispatch_t *dispatch,
cairo_gl_get_proc_addr_func_t get_proc_addr,
int gl_version, cairo_gl_flavor_t gl_flavor)
{
cairo_gl_dispatch_name_t dispatch_name;
if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
{
if (gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
else if (_cairo_gl_has_extension ("GL_ARB_shader_objects"))
dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
else
return CAIRO_STATUS_DEVICE_ERROR;
}
else if (gl_flavor == CAIRO_GL_FLAVOR_ES &&
gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
{
dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
}
else
{
return CAIRO_STATUS_DEVICE_ERROR;
}
_cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
dispatch_shaders_entries, dispatch_name);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_gl_dispatch_init_fbo (cairo_gl_dispatch_t *dispatch,
cairo_gl_get_proc_addr_func_t get_proc_addr,
int gl_version, cairo_gl_flavor_t gl_flavor)
{
cairo_gl_dispatch_name_t dispatch_name;
if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
{
if (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) ||
_cairo_gl_has_extension ("GL_ARB_framebuffer_object"))
dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
else if (_cairo_gl_has_extension ("GL_EXT_framebuffer_object"))
dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
else
return CAIRO_STATUS_DEVICE_ERROR;
}
else if (gl_flavor == CAIRO_GL_FLAVOR_ES &&
gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
{
dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
}
else
{
return CAIRO_STATUS_DEVICE_ERROR;
}
_cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
dispatch_fbo_entries, dispatch_name);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_gl_dispatch_init_multisampling (cairo_gl_dispatch_t *dispatch,
cairo_gl_get_proc_addr_func_t get_proc_addr,
int gl_version,
cairo_gl_flavor_t gl_flavor)
{
/* 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"))
dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
else if (_cairo_gl_has_extension ("GL_IMG_multisampled_render_to_texture"))
dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
}
_cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
dispatch_multisampling_entries,
dispatch_name);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_gl_dispatch_init (cairo_gl_dispatch_t *dispatch,
cairo_gl_get_proc_addr_func_t get_proc_addr)
{
cairo_status_t status;
int gl_version;
cairo_gl_flavor_t gl_flavor;
gl_version = _cairo_gl_get_version ();
gl_flavor = _cairo_gl_get_flavor ();
status = _cairo_gl_dispatch_init_buffers (dispatch, get_proc_addr,
gl_version, gl_flavor);
if (status != CAIRO_STATUS_SUCCESS)
return status;
status = _cairo_gl_dispatch_init_shaders (dispatch, get_proc_addr,
gl_version, gl_flavor);
if (status != CAIRO_STATUS_SUCCESS)
return status;
status = _cairo_gl_dispatch_init_fbo (dispatch, get_proc_addr,
gl_version, gl_flavor);
if (status != CAIRO_STATUS_SUCCESS)
return status;
status = _cairo_gl_dispatch_init_multisampling (dispatch, get_proc_addr,
gl_version, gl_flavor);
if (status != CAIRO_STATUS_SUCCESS)
return status;
return CAIRO_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,143 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2010 Linaro Limited
*
* 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):
* Alexandros Frantzis <alexandros.frantzis@linaro.org>
*/
#ifndef CAIRO_GL_EXT_DEF_PRIVATE_H
#define CAIRO_GL_EXT_DEF_PRIVATE_H
#ifndef GL_TEXTURE_RECTANGLE
#define GL_TEXTURE_RECTANGLE 0x84F5
#endif
#ifndef GL_ARRAY_BUFFER
#define GL_ARRAY_BUFFER 0x8892
#endif
#ifndef GL_STREAM_DRAW
#define GL_STREAM_DRAW 0x88E0
#endif
#ifndef GL_WRITE_ONLY
#define GL_WRITE_ONLY 0x88B9
#endif
#ifndef GL_PIXEL_UNPACK_BUFFER
#define GL_PIXEL_UNPACK_BUFFER 0x88EC
#endif
#ifndef GL_FRAMEBUFFER
#define GL_FRAMEBUFFER 0x8D40
#endif
#ifndef GL_COLOR_ATTACHMENT0
#define GL_COLOR_ATTACHMENT0 0x8CE0
#endif
#ifndef GL_FRAMEBUFFER_COMPLETE
#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_FORMATS
#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS 0x8CDA
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC
#endif
#ifndef GL_FRAMEBUFFER_UNSUPPORTED
#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
#endif
#ifndef GL_PACK_INVERT_MESA
#define GL_PACK_INVERT_MESA 0x8758
#endif
#ifndef GL_CLAMP_TO_BORDER
#define GL_CLAMP_TO_BORDER 0x812D
#endif
#ifndef GL_BGR
#define GL_BGR 0x80E0
#endif
#ifndef GL_BGRA
#define GL_BGRA 0x80E1
#endif
#ifndef GL_RGBA8
#define GL_RGBA8 0x8058
#endif
#ifndef GL_UNSIGNED_INT_8_8_8_8
#define GL_UNSIGNED_INT_8_8_8_8 0x8035
#endif
#ifndef GL_UNSIGNED_SHORT_5_6_5_REV
#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
#endif
#ifndef GL_UNSIGNED_SHORT_1_5_5_5_REV
#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
#endif
#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
#endif
#ifndef GL_PACK_ROW_LENGTH
#define GL_PACK_ROW_LENGTH 0x0D02
#endif
#ifndef GL_UNPACK_ROW_LENGTH
#define GL_UNPACK_ROW_LENGTH 0x0CF2
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
#endif
#endif /* CAIRO_GL_EXT_DEF_PRIVATE_H */

View File

@@ -0,0 +1,503 @@
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
* Copyright © 2010 Intel Corporation
* Copyright © 2010 Red Hat, Inc
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson.
*
* Contributors:
* Benjamin Otte <otte@gnome.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-gl-private.h"
#include "cairo-compositor-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
#include "cairo-rtree-private.h"
#define GLYPH_CACHE_WIDTH 1024
#define GLYPH_CACHE_HEIGHT 1024
#define GLYPH_CACHE_MIN_SIZE 4
#define GLYPH_CACHE_MAX_SIZE 128
typedef struct _cairo_gl_glyph {
cairo_rtree_node_t node;
cairo_scaled_glyph_private_t base;
cairo_scaled_glyph_t *glyph;
cairo_gl_glyph_cache_t *cache;
struct { float x, y; } p1, p2;
} cairo_gl_glyph_t;
static void
_cairo_gl_node_destroy (cairo_rtree_node_t *node)
{
cairo_gl_glyph_t *priv = cairo_container_of (node, cairo_gl_glyph_t, node);
cairo_scaled_glyph_t *glyph;
glyph = priv->glyph;
if (glyph == NULL)
return;
if (glyph->dev_private_key == priv->cache) {
glyph->dev_private = NULL;
glyph->dev_private_key = NULL;
}
cairo_list_del (&priv->base.link);
priv->glyph = NULL;
}
static void
_cairo_gl_glyph_fini (cairo_scaled_glyph_private_t *glyph_private,
cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font)
{
cairo_gl_glyph_t *priv = cairo_container_of (glyph_private,
cairo_gl_glyph_t,
base);
assert (priv->glyph);
_cairo_gl_node_destroy (&priv->node);
/* XXX thread-safety? Probably ok due to the frozen scaled-font. */
if (! priv->node.pinned)
_cairo_rtree_node_remove (&priv->cache->rtree, &priv->node);
assert (priv->glyph == NULL);
}
static cairo_int_status_t
_cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
cairo_gl_glyph_cache_t *cache,
cairo_scaled_glyph_t *scaled_glyph)
{
cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
cairo_gl_glyph_t *glyph_private;
cairo_rtree_node_t *node = NULL;
cairo_int_status_t status;
int width, height;
width = glyph_surface->width;
if (width < GLYPH_CACHE_MIN_SIZE)
width = GLYPH_CACHE_MIN_SIZE;
height = glyph_surface->height;
if (height < GLYPH_CACHE_MIN_SIZE)
height = GLYPH_CACHE_MIN_SIZE;
/* search for an available slot */
status = _cairo_rtree_insert (&cache->rtree, width, height, &node);
/* search for an unlocked slot */
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
status = _cairo_rtree_evict_random (&cache->rtree,
width, height, &node);
if (status == CAIRO_INT_STATUS_SUCCESS) {
status = _cairo_rtree_node_insert (&cache->rtree,
node, width, height, &node);
}
}
if (status)
return status;
/* XXX: Make sure we use the mask texture. This should work automagically somehow */
glActiveTexture (GL_TEXTURE1);
status = _cairo_gl_surface_draw_image (cache->surface, glyph_surface,
0, 0,
glyph_surface->width, glyph_surface->height,
node->x, node->y, FALSE);
if (unlikely (status))
return status;
glyph_private = (cairo_gl_glyph_t *) node;
glyph_private->cache = cache;
glyph_private->glyph = scaled_glyph;
_cairo_scaled_glyph_attach_private (scaled_glyph,
&glyph_private->base,
cache,
_cairo_gl_glyph_fini);
scaled_glyph->dev_private = glyph_private;
scaled_glyph->dev_private_key = cache;
/* compute tex coords */
glyph_private->p1.x = node->x;
glyph_private->p1.y = node->y;
glyph_private->p2.x = node->x + glyph_surface->width;
glyph_private->p2.y = node->y + glyph_surface->height;
if (! _cairo_gl_device_requires_power_of_two_textures (&ctx->base)) {
glyph_private->p1.x /= GLYPH_CACHE_WIDTH;
glyph_private->p2.x /= GLYPH_CACHE_WIDTH;
glyph_private->p1.y /= GLYPH_CACHE_HEIGHT;
glyph_private->p2.y /= GLYPH_CACHE_HEIGHT;
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_gl_glyph_t *
_cairo_gl_glyph_cache_lock (cairo_gl_glyph_cache_t *cache,
cairo_scaled_glyph_t *scaled_glyph)
{
return _cairo_rtree_pin (&cache->rtree, scaled_glyph->dev_private);
}
static cairo_status_t
cairo_gl_context_get_glyph_cache (cairo_gl_context_t *ctx,
cairo_format_t format,
cairo_gl_glyph_cache_t **cache_out)
{
cairo_gl_glyph_cache_t *cache;
cairo_content_t content;
switch (format) {
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_RGB16_565:
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
cache = &ctx->glyph_cache[0];
content = CAIRO_CONTENT_COLOR_ALPHA;
break;
case CAIRO_FORMAT_A8:
case CAIRO_FORMAT_A1:
cache = &ctx->glyph_cache[1];
content = CAIRO_CONTENT_ALPHA;
break;
default:
case CAIRO_FORMAT_INVALID:
ASSERT_NOT_REACHED;
return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
}
if (unlikely (cache->surface == NULL)) {
cairo_surface_t *surface;
surface = _cairo_gl_surface_create_scratch_for_caching (ctx,
content,
GLYPH_CACHE_WIDTH,
GLYPH_CACHE_HEIGHT);
if (unlikely (surface->status))
return surface->status;
_cairo_surface_release_device_reference (surface);
cache->surface = (cairo_gl_surface_t *)surface;
cache->surface->operand.texture.attributes.has_component_alpha =
content == CAIRO_CONTENT_COLOR_ALPHA;
}
*cache_out = cache;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
render_glyphs (cairo_gl_surface_t *dst,
int dst_x, int dst_y,
cairo_operator_t op,
cairo_surface_t *source,
cairo_composite_glyphs_info_t *info,
cairo_bool_t *has_component_alpha,
cairo_clip_t *clip)
{
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 = NULL;
cairo_gl_composite_t setup;
cairo_int_status_t status;
int i = 0;
TRACE ((stderr, "%s (%d, %d)x(%d, %d)\n", __FUNCTION__,
info->extents.x, info->extents.y,
info->extents.width, info->extents.height));
*has_component_alpha = FALSE;
status = _cairo_gl_context_acquire (dst->base.device, &ctx);
if (unlikely (status))
return status;
status = _cairo_gl_composite_init (&setup, op, dst, TRUE);
if (unlikely (status))
goto FINISH;
if (source == NULL) {
_cairo_gl_composite_set_solid_source (&setup, CAIRO_COLOR_WHITE);
} else {
_cairo_gl_composite_set_source_operand (&setup,
source_to_operand (source));
}
_cairo_gl_composite_set_clip (&setup, clip);
for (i = 0; i < info->num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph;
cairo_gl_glyph_t *glyph;
double x_offset, y_offset;
double x1, x2, y1, y2;
status = _cairo_scaled_glyph_lookup (info->font,
info->glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
if (unlikely (status))
goto FINISH;
if (scaled_glyph->surface->width == 0 ||
scaled_glyph->surface->height == 0)
{
continue;
}
if (scaled_glyph->surface->format != last_format) {
status = cairo_gl_context_get_glyph_cache (ctx,
scaled_glyph->surface->format,
&cache);
if (unlikely (status))
goto FINISH;
last_format = scaled_glyph->surface->format;
_cairo_gl_composite_set_mask_operand (&setup, &cache->surface->operand);
*has_component_alpha |= cache->surface->operand.texture.attributes.has_component_alpha;
/* XXX Shoot me. */
status = _cairo_gl_composite_begin (&setup, &ctx);
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) {
cairo_scaled_glyph_private_t *priv;
priv = _cairo_scaled_glyph_find_private (scaled_glyph, cache);
if (priv) {
scaled_glyph->dev_private_key = cache;
scaled_glyph->dev_private = cairo_container_of (priv,
cairo_gl_glyph_t,
base);
} else {
status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
/* Cache is full, so flush existing prims and try again. */
_cairo_gl_composite_flush (ctx);
_cairo_gl_glyph_cache_unlock (cache);
status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
}
if (unlikely (_cairo_int_status_is_error (status)))
goto FINISH;
}
}
x_offset = scaled_glyph->surface->base.device_transform.x0;
y_offset = scaled_glyph->surface->base.device_transform.y0;
x1 = _cairo_lround (info->glyphs[i].x - x_offset - dst_x);
y1 = _cairo_lround (info->glyphs[i].y - y_offset - dst_y);
x2 = x1 + scaled_glyph->surface->width;
y2 = y1 + scaled_glyph->surface->height;
glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph);
assert (emit);
emit (ctx,
x1, y1, x2, y2,
glyph->p1.x, glyph->p1.y,
glyph->p2.x, glyph->p2.y);
}
status = CAIRO_STATUS_SUCCESS;
FINISH:
status = _cairo_gl_context_release (ctx, status);
_cairo_gl_composite_fini (&setup);
return status;
}
static cairo_int_status_t
render_glyphs_via_mask (cairo_gl_surface_t *dst,
int dst_x, int dst_y,
cairo_operator_t op,
cairo_surface_t *source,
cairo_composite_glyphs_info_t *info,
cairo_clip_t *clip)
{
cairo_surface_t *mask;
cairo_status_t status;
cairo_bool_t has_component_alpha;
TRACE ((stderr, "%s\n", __FUNCTION__));
/* XXX: For non-CA, this should be CAIRO_CONTENT_ALPHA to save memory */
mask = cairo_gl_surface_create (dst->base.device,
CAIRO_CONTENT_COLOR_ALPHA,
info->extents.width,
info->extents.height);
if (unlikely (mask->status))
return mask->status;
status = render_glyphs ((cairo_gl_surface_t *) mask,
info->extents.x, info->extents.y,
CAIRO_OPERATOR_ADD, NULL,
info, &has_component_alpha, NULL);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
cairo_surface_pattern_t mask_pattern;
cairo_surface_pattern_t source_pattern;
cairo_rectangle_int_t clip_extents;
mask->is_clear = FALSE;
_cairo_pattern_init_for_surface (&mask_pattern, mask);
mask_pattern.base.has_component_alpha = has_component_alpha;
mask_pattern.base.filter = CAIRO_FILTER_NEAREST;
mask_pattern.base.extend = CAIRO_EXTEND_NONE;
cairo_matrix_init_translate (&mask_pattern.base.matrix,
dst_x-info->extents.x, dst_y-info->extents.y);
_cairo_pattern_init_for_surface (&source_pattern, source);
cairo_matrix_init_translate (&source_pattern.base.matrix,
dst_x-info->extents.x, dst_y-info->extents.y);
clip = _cairo_clip_copy (clip);
clip_extents.x = info->extents.x - dst_x;
clip_extents.y = info->extents.y - dst_y;
clip_extents.width = info->extents.width;
clip_extents.height = info->extents.height;
clip = _cairo_clip_intersect_rectangle (clip, &clip_extents);
status = _cairo_surface_mask (&dst->base, op,
&source_pattern.base,
&mask_pattern.base,
clip);
_cairo_clip_destroy (clip);
_cairo_pattern_fini (&mask_pattern.base);
_cairo_pattern_fini (&source_pattern.base);
}
cairo_surface_destroy (mask);
return status;
}
cairo_int_status_t
_cairo_gl_check_composite_glyphs (const cairo_composite_rectangles_t *extents,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int *num_glyphs)
{
if (! _cairo_gl_operator_is_supported (extents->op))
return UNSUPPORTED ("unsupported operator");
/* XXX use individual masks for large glyphs? */
if (ceil (scaled_font->max_scale) >= GLYPH_CACHE_MAX_SIZE)
return UNSUPPORTED ("glyphs too large");
return CAIRO_STATUS_SUCCESS;
}
cairo_int_status_t
_cairo_gl_composite_glyphs_with_clip (void *_dst,
cairo_operator_t op,
cairo_surface_t *_src,
int src_x,
int src_y,
int dst_x,
int dst_y,
cairo_composite_glyphs_info_t *info,
cairo_clip_t *clip)
{
cairo_gl_surface_t *dst = _dst;
cairo_bool_t has_component_alpha;
TRACE ((stderr, "%s\n", __FUNCTION__));
/* If any of the glyphs require component alpha, we have to go through
* a mask, since only _cairo_gl_surface_composite() currently supports
* component alpha.
*/
if (!dst->base.is_clear && ! info->use_mask && op != CAIRO_OPERATOR_OVER &&
(info->font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL ||
info->font->options.antialias == CAIRO_ANTIALIAS_BEST))
{
info->use_mask = TRUE;
}
if (info->use_mask) {
return render_glyphs_via_mask (dst, dst_x, dst_y,
op, _src, info, clip);
} else {
return render_glyphs (dst, dst_x, dst_y,
op, _src, info,
&has_component_alpha,
clip);
}
}
cairo_int_status_t
_cairo_gl_composite_glyphs (void *_dst,
cairo_operator_t op,
cairo_surface_t *_src,
int src_x,
int src_y,
int dst_x,
int dst_y,
cairo_composite_glyphs_info_t *info)
{
return _cairo_gl_composite_glyphs_with_clip (_dst, op, _src, src_x, src_y,
dst_x, dst_y, info, NULL);
}
void
_cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache)
{
_cairo_rtree_init (&cache->rtree,
GLYPH_CACHE_WIDTH,
GLYPH_CACHE_HEIGHT,
GLYPH_CACHE_MIN_SIZE,
sizeof (cairo_gl_glyph_t),
_cairo_gl_node_destroy);
}
void
_cairo_gl_glyph_cache_fini (cairo_gl_context_t *ctx,
cairo_gl_glyph_cache_t *cache)
{
_cairo_rtree_fini (&cache->rtree);
cairo_surface_destroy (&cache->surface->base);
}

View File

@@ -0,0 +1,93 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Eric Anholt
* Copyright © 2009 Chris Wilson
* Copyright © 2005,2010 Red Hat, Inc
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Benjamin Otte <otte@gnome.org>
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
* Eric Anholt <eric@anholt.net>
*/
#ifndef CAIRO_GL_GRADIENT_PRIVATE_H
#define CAIRO_GL_GRADIENT_PRIVATE_H
#define GL_GLEXT_PROTOTYPES
#include "cairo-cache-private.h"
#include "cairo-device-private.h"
#include "cairo-reference-count-private.h"
#include "cairo-pattern-private.h"
#include "cairo-types-private.h"
#include "cairo-gl.h"
#if CAIRO_HAS_GL_SURFACE
#include <GL/gl.h>
#include <GL/glext.h>
#elif CAIRO_HAS_GLESV2_SURFACE
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#endif
#define CAIRO_GL_GRADIENT_CACHE_SIZE 4096
/* XXX: Declare in a better place */
typedef struct _cairo_gl_context cairo_gl_context_t;
typedef struct _cairo_gl_gradient {
cairo_cache_entry_t cache_entry;
cairo_reference_count_t ref_count;
cairo_device_t *device; /* NB: we don't hold a reference */
GLuint tex;
unsigned int n_stops;
const cairo_gradient_stop_t *stops;
cairo_gradient_stop_t stops_embedded[1];
} cairo_gl_gradient_t;
cairo_private cairo_int_status_t
_cairo_gl_gradient_create (cairo_gl_context_t *ctx,
unsigned int n_stops,
const cairo_gradient_stop_t *stops,
cairo_gl_gradient_t **gradient_out);
cairo_private_no_warn cairo_gl_gradient_t *
_cairo_gl_gradient_reference (cairo_gl_gradient_t *gradient);
cairo_private void
_cairo_gl_gradient_destroy (cairo_gl_gradient_t *gradient);
cairo_private cairo_bool_t
_cairo_gl_gradient_equal (const void *key_a, const void *key_b);
#endif /* CAIRO_GL_GRADIENT_PRIVATE_H */

View File

@@ -0,0 +1,338 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Eric Anholt
* Copyright © 2009 Chris Wilson
* Copyright © 2005,2010 Red Hat, Inc
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Benjamin Otte <otte@gnome.org>
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
* Eric Anholt <eric@anholt.net>
*/
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-gl-gradient-private.h"
#include "cairo-gl-private.h"
static int
_cairo_gl_gradient_sample_width (unsigned int n_stops,
const cairo_gradient_stop_t *stops)
{
unsigned int n;
int width;
width = 8;
for (n = 1; n < n_stops; n++) {
double dx = stops[n].offset - stops[n-1].offset;
double delta, max;
int ramp;
if (dx == 0)
return 1024; /* we need to emulate an infinitely sharp step */
max = fabs (stops[n].color.red - stops[n-1].color.red);
delta = fabs (stops[n].color.green - stops[n-1].color.green);
if (delta > max)
max = delta;
delta = fabs (stops[n].color.blue - stops[n-1].color.blue);
if (delta > max)
max = delta;
delta = fabs (stops[n].color.alpha - stops[n-1].color.alpha);
if (delta > max)
max = delta;
ramp = 128 * max / dx;
if (ramp > width)
width = ramp;
}
return (width + 7) & -8;
}
static uint8_t premultiply(double c, double a)
{
int v = c * a * 256;
return v - (v >> 8);
}
static uint32_t color_stop_to_pixel(const cairo_gradient_stop_t *stop)
{
uint8_t a, r, g, b;
a = stop->color.alpha_short >> 8;
r = premultiply(stop->color.red, stop->color.alpha);
g = premultiply(stop->color.green, stop->color.alpha);
b = premultiply(stop->color.blue, stop->color.alpha);
if (_cairo_is_little_endian ())
return a << 24 | r << 16 | g << 8 | b << 0;
else
return a << 0 | r << 8 | g << 16 | b << 24;
}
static cairo_status_t
_cairo_gl_gradient_render (const cairo_gl_context_t *ctx,
unsigned int n_stops,
const cairo_gradient_stop_t *stops,
void *bytes,
int width)
{
pixman_image_t *gradient, *image;
pixman_gradient_stop_t pixman_stops_stack[32];
pixman_gradient_stop_t *pixman_stops;
pixman_point_fixed_t p1, p2;
unsigned int i;
pixman_format_code_t gradient_pixman_format;
/*
* Ensure that the order of the gradient's components in memory is BGRA.
* This is done so that the gradient's pixel data is always suitable for
* texture upload using format=GL_BGRA and type=GL_UNSIGNED_BYTE.
*/
if (_cairo_is_little_endian ())
gradient_pixman_format = PIXMAN_a8r8g8b8;
else
gradient_pixman_format = PIXMAN_b8g8r8a8;
pixman_stops = pixman_stops_stack;
if (unlikely (n_stops > ARRAY_LENGTH (pixman_stops_stack))) {
pixman_stops = _cairo_malloc_ab (n_stops,
sizeof (pixman_gradient_stop_t));
if (unlikely (pixman_stops == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
for (i = 0; i < n_stops; i++) {
pixman_stops[i].x = _cairo_fixed_16_16_from_double (stops[i].offset);
pixman_stops[i].color.red = stops[i].color.red_short;
pixman_stops[i].color.green = stops[i].color.green_short;
pixman_stops[i].color.blue = stops[i].color.blue_short;
pixman_stops[i].color.alpha = stops[i].color.alpha_short;
}
p1.x = _cairo_fixed_16_16_from_double (0.5);
p1.y = 0;
p2.x = _cairo_fixed_16_16_from_double (width - 0.5);
p2.y = 0;
gradient = pixman_image_create_linear_gradient (&p1, &p2,
pixman_stops,
n_stops);
if (pixman_stops != pixman_stops_stack)
free (pixman_stops);
if (unlikely (gradient == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
pixman_image_set_filter (gradient, PIXMAN_FILTER_BILINEAR, NULL, 0);
pixman_image_set_repeat (gradient, PIXMAN_REPEAT_PAD);
image = pixman_image_create_bits (gradient_pixman_format, width, 1,
bytes, sizeof(uint32_t)*width);
if (unlikely (image == NULL)) {
pixman_image_unref (gradient);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
pixman_image_composite32 (PIXMAN_OP_SRC,
gradient, NULL, image,
0, 0,
0, 0,
0, 0,
width, 1);
pixman_image_unref (gradient);
pixman_image_unref (image);
/* We need to fudge pixel 0 to hold the left-most color stop and not
* the neareset stop to the zeroth pixel centre in order to correctly
* populate the border color. For completeness, do both edges.
*/
((uint32_t*)bytes)[0] = color_stop_to_pixel(&stops[0]);
((uint32_t*)bytes)[width-1] = color_stop_to_pixel(&stops[n_stops-1]);
return CAIRO_STATUS_SUCCESS;
}
static unsigned long
_cairo_gl_gradient_hash (unsigned int n_stops,
const cairo_gradient_stop_t *stops)
{
return _cairo_hash_bytes (n_stops,
stops,
sizeof (cairo_gradient_stop_t) * n_stops);
}
static cairo_gl_gradient_t *
_cairo_gl_gradient_lookup (cairo_gl_context_t *ctx,
unsigned long hash,
unsigned int n_stops,
const cairo_gradient_stop_t *stops)
{
cairo_gl_gradient_t lookup;
lookup.cache_entry.hash = hash,
lookup.n_stops = n_stops;
lookup.stops = stops;
return _cairo_cache_lookup (&ctx->gradients, &lookup.cache_entry);
}
cairo_bool_t
_cairo_gl_gradient_equal (const void *key_a, const void *key_b)
{
const cairo_gl_gradient_t *a = key_a;
const cairo_gl_gradient_t *b = key_b;
if (a->n_stops != b->n_stops)
return FALSE;
return memcmp (a->stops, b->stops, a->n_stops * sizeof (cairo_gradient_stop_t)) == 0;
}
cairo_int_status_t
_cairo_gl_gradient_create (cairo_gl_context_t *ctx,
unsigned int n_stops,
const cairo_gradient_stop_t *stops,
cairo_gl_gradient_t **gradient_out)
{
unsigned long hash;
cairo_gl_gradient_t *gradient;
cairo_status_t status;
int tex_width;
GLint internal_format;
void *data;
if ((unsigned int) ctx->max_texture_size / 2 <= n_stops)
return CAIRO_INT_STATUS_UNSUPPORTED;
hash = _cairo_gl_gradient_hash (n_stops, stops);
gradient = _cairo_gl_gradient_lookup (ctx, hash, n_stops, stops);
if (gradient) {
*gradient_out = _cairo_gl_gradient_reference (gradient);
return CAIRO_STATUS_SUCCESS;
}
gradient = malloc (sizeof (cairo_gl_gradient_t) + sizeof (cairo_gradient_stop_t) * (n_stops - 1));
if (gradient == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
tex_width = _cairo_gl_gradient_sample_width (n_stops, stops);
if (tex_width > ctx->max_texture_size)
tex_width = ctx->max_texture_size;
CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 2);
gradient->cache_entry.hash = hash;
gradient->cache_entry.size = tex_width;
gradient->device = &ctx->base;
gradient->n_stops = n_stops;
gradient->stops = gradient->stops_embedded;
memcpy (gradient->stops_embedded, stops, n_stops * sizeof (cairo_gradient_stop_t));
glGenTextures (1, &gradient->tex);
_cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
glBindTexture (ctx->tex_target, gradient->tex);
data = _cairo_malloc_ab (tex_width, sizeof (uint32_t));
if (unlikely (data == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto cleanup_gradient;
}
status = _cairo_gl_gradient_render (ctx, n_stops, stops, data, tex_width);
if (unlikely (status))
goto cleanup_data;
/*
* In OpenGL ES 2.0 no format conversion is allowed i.e. 'internalFormat'
* must match 'format' in glTexImage2D.
*/
if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES)
internal_format = GL_BGRA;
else
internal_format = GL_RGBA;
glTexImage2D (ctx->tex_target, 0, internal_format, tex_width, 1, 0,
GL_BGRA, GL_UNSIGNED_BYTE, data);
free (data);
/* we ignore errors here and just return an uncached gradient */
if (unlikely (_cairo_cache_insert (&ctx->gradients, &gradient->cache_entry)))
CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 1);
*gradient_out = gradient;
return CAIRO_STATUS_SUCCESS;
cleanup_data:
free (data);
cleanup_gradient:
free (gradient);
return status;
}
cairo_gl_gradient_t *
_cairo_gl_gradient_reference (cairo_gl_gradient_t *gradient)
{
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&gradient->ref_count));
_cairo_reference_count_inc (&gradient->ref_count);
return gradient;
}
void
_cairo_gl_gradient_destroy (cairo_gl_gradient_t *gradient)
{
cairo_gl_context_t *ctx;
cairo_status_t ignore;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&gradient->ref_count));
if (! _cairo_reference_count_dec_and_test (&gradient->ref_count))
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);
}
free (gradient);
}

View File

@@ -0,0 +1,91 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2010 Linaro Limited
*
* 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):
* Alexandros Frantzis <alexandros.frantzis@linaro.org>
*/
#include "cairoint.h"
#include "cairo-gl-private.h"
int
_cairo_gl_get_version (void)
{
int major, minor;
const char *version = (const char *) glGetString (GL_VERSION);
const char *dot = version == NULL ? NULL : strchr (version, '.');
const char *major_start = dot;
/* Sanity check */
if (dot == NULL || dot == version || *(dot + 1) == '\0') {
major = 0;
minor = 0;
} else {
/* Find the start of the major version in the string */
while (major_start > version && *major_start != ' ')
--major_start;
major = strtol (major_start, NULL, 10);
minor = strtol (dot + 1, NULL, 10);
}
return CAIRO_GL_VERSION_ENCODE (major, minor);
}
cairo_gl_flavor_t
_cairo_gl_get_flavor (void)
{
const char *version = (const char *) glGetString (GL_VERSION);
cairo_gl_flavor_t flavor;
if (version == NULL)
flavor = CAIRO_GL_FLAVOR_NONE;
else if (strstr (version, "OpenGL ES") != NULL)
flavor = CAIRO_GL_FLAVOR_ES;
else
flavor = CAIRO_GL_FLAVOR_DESKTOP;
return flavor;
}
cairo_bool_t
_cairo_gl_has_extension (const char *ext)
{
const char *extensions = (const char *) glGetString (GL_EXTENSIONS);
size_t len = strlen (ext);
const char *ext_ptr = extensions;
if (unlikely (ext_ptr == NULL))
return 0;
while ((ext_ptr = strstr (ext_ptr, ext)) != NULL) {
if (ext_ptr[len] == ' ' || ext_ptr[len] == '\0')
break;
ext_ptr += len;
}
return (ext_ptr != NULL);
}

View File

@@ -0,0 +1,944 @@
/* -*- 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 © 2005 Red Hat, Inc.
* Copyright © 2011 Intel Corporation
* Copyright © 2011 Samsung Electronics
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Henry Song <hsong@sisa.samsung.com>
* Martin Robinson <mrobinson@igalia.com>
*/
#include "cairoint.h"
#include "cairo-clip-inline.h"
#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"
static cairo_bool_t
can_use_msaa_compositor (cairo_gl_surface_t *surface,
cairo_antialias_t antialias);
static void
query_surface_capabilities (cairo_gl_surface_t *surface);
struct _tristrip_composite_info {
cairo_gl_composite_t setup;
cairo_gl_context_t *ctx;
};
static cairo_int_status_t
_draw_trap (cairo_gl_context_t *ctx,
cairo_gl_composite_t *setup,
cairo_trapezoid_t *trap)
{
cairo_point_t quad[4];
quad[0].x = _cairo_edge_compute_intersection_x_for_y (&trap->left.p1,
&trap->left.p2,
trap->top);
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);
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
_draw_traps (cairo_gl_context_t *ctx,
cairo_gl_composite_t *setup,
cairo_traps_t *traps)
{
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
int i;
for (i = 0; i < traps->num_traps; i++) {
cairo_trapezoid_t *trap = traps->traps + i;
if (unlikely ((status = _draw_trap (ctx, setup, trap))))
return status;
}
return status;
}
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_composite_emit_quad_as_tristrip (ctx, setup, quad);
}
static cairo_int_status_t
_draw_triangle_fan (cairo_gl_context_t *ctx,
cairo_gl_composite_t *setup,
const cairo_point_t *midpt,
const cairo_point_t *points,
int npoints)
{
int i;
/* Our strategy here is to not even try to build a triangle fan, but to
draw each triangle as if it was an unconnected member of a triangle strip. */
for (i = 1; i < npoints; i++) {
cairo_int_status_t status;
cairo_point_t triangle[3];
triangle[0] = *midpt;
triangle[1] = points[i - 1];
triangle[2] = points[i];
status = _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
if (unlikely (status))
return status;
}
return CAIRO_STATUS_SUCCESS;
}
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;
_cairo_traps_init (traps);
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);
}
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
* based rendering of the clip to be a reasonable approximation to
* the intersection between that clip and the path.
*
* In other words, what the user expects when they try to perform
* a geometric intersection between an unantialiased polygon and an
* antialiased polygon is open to interpretation. And we choose the fast
* option.
*/
_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;
}
static cairo_bool_t
_should_use_unbounded_surface (cairo_composite_rectangles_t *composite)
{
cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
cairo_rectangle_int_t *source = &composite->source;
if (composite->is_bounded)
return FALSE;
/* This isn't just an optimization. It also detects when painting is used
to paint back the unbounded surface, preventing infinite recursion. */
return ! (source->x <= 0 && source->y <= 0 &&
source->height + source->y >= dst->height &&
source->width + source->x >= dst->width);
}
static cairo_surface_t*
_prepare_unbounded_surface (cairo_gl_surface_t *dst)
{
cairo_surface_t* surface = cairo_gl_surface_create (dst->base.device,
dst->base.content,
dst->width,
dst->height);
if (surface == NULL)
return NULL;
if (unlikely (surface->status)) {
cairo_surface_destroy (surface);
return NULL;
}
return surface;
}
static cairo_int_status_t
_paint_back_unbounded_surface (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *composite,
cairo_surface_t *surface)
{
cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
cairo_int_status_t status;
cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
if (unlikely (pattern->status)) {
status = pattern->status;
goto finish;
}
status = _cairo_compositor_paint (compositor, &dst->base,
composite->op, pattern,
composite->clip);
finish:
cairo_pattern_destroy (pattern);
cairo_surface_destroy (surface);
return status;
}
static cairo_bool_t
can_use_msaa_compositor (cairo_gl_surface_t *surface,
cairo_antialias_t antialias)
{
query_surface_capabilities (surface);
if (! surface->supports_stencil)
return FALSE;
/* Multisampling OpenGL ES surfaces only maintain one multisampling
framebuffer and thus must use the spans compositor to do non-antialiased
rendering. */
if (((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES
&& surface->supports_msaa
&& antialias == CAIRO_ANTIALIAS_NONE)
return FALSE;
/* The MSAA compositor has a single-sample mode, so we can
support non-antialiased rendering. */
if (antialias == CAIRO_ANTIALIAS_NONE)
return TRUE;
if (antialias == CAIRO_ANTIALIAS_FAST || antialias == CAIRO_ANTIALIAS_DEFAULT)
return surface->supports_msaa;
return FALSE;
}
static void
_cairo_gl_msaa_compositor_set_clip (cairo_composite_rectangles_t *composite,
cairo_gl_composite_t *setup)
{
if (_cairo_composite_rectangles_can_reduce_clip (composite, composite->clip))
return;
_cairo_gl_composite_set_clip (setup, composite->clip);
}
/* 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_msaa_compositor_mask_source_operator (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *composite)
{
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_clip_t *clip = composite->clip;
cairo_traps_t 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))
return status;
status = _cairo_gl_composite_set_source (&setup,
&composite->mask_pattern.base,
&composite->mask_sample_area,
&composite->bounded,
FALSE);
if (unlikely (status))
goto finish;
_cairo_gl_composite_set_multisample (&setup);
status = _cairo_gl_composite_begin (&setup, &ctx);
if (unlikely (status))
goto finish;
if (! clip)
status = _draw_int_rect (ctx, &setup, &composite->bounded);
else
status = _draw_traps (ctx, &setup, &traps);
if (unlikely (status))
goto finish;
/* Now draw the second pass. */
status = _cairo_gl_composite_set_operator (&setup, CAIRO_OPERATOR_ADD,
FALSE /* assume_component_alpha */);
if (unlikely (status))
goto finish;
status = _cairo_gl_composite_set_source (&setup,
&composite->source_pattern.base,
&composite->source_sample_area,
&composite->bounded,
FALSE);
if (unlikely (status))
goto finish;
status = _cairo_gl_composite_set_mask (&setup,
&composite->mask_pattern.base,
&composite->source_sample_area,
&composite->bounded,
FALSE);
if (unlikely (status))
goto finish;
status = _cairo_gl_set_operands_and_operator (&setup, ctx);
if (unlikely (status))
goto finish;
if (! clip)
status = _draw_int_rect (ctx, &setup, &composite->bounded);
else
status = _draw_traps (ctx, &setup, &traps);
finish:
_cairo_gl_composite_fini (&setup);
if (ctx)
status = _cairo_gl_context_release (ctx, status);
if (clip)
_cairo_traps_fini (&traps);
return status;
}
static cairo_int_status_t
_cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *composite)
{
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_operator_t op = composite->op;
cairo_clip_t *clip = composite->clip;
if (! can_use_msaa_compositor (dst, CAIRO_ANTIALIAS_DEFAULT))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (composite->op == CAIRO_OPERATOR_CLEAR &&
composite->original_mask_pattern != NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
/* GL compositing operators cannot properly represent a mask operation
using the SOURCE compositing operator in one pass. This only matters if
there actually is a mask (there isn't in a paint operation) and if the
mask isn't totally opaque. */
if (op == CAIRO_OPERATOR_SOURCE &&
composite->original_mask_pattern != NULL &&
! _cairo_pattern_is_opaque (&composite->mask_pattern.base,
&composite->mask_sample_area)) {
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)) {
cairo_surface_t* surface = _prepare_unbounded_surface (dst);
if (unlikely (surface == NULL))
return CAIRO_INT_STATUS_UNSUPPORTED;
/* This may be a paint operation. */
if (composite->original_mask_pattern == NULL) {
status = _cairo_compositor_paint (compositor, surface,
CAIRO_OPERATOR_SOURCE,
&composite->source_pattern.base,
NULL);
} else {
status = _cairo_compositor_mask (compositor, surface,
CAIRO_OPERATOR_SOURCE,
&composite->source_pattern.base,
&composite->mask_pattern.base,
NULL);
}
if (unlikely (status)) {
cairo_surface_destroy (surface);
return status;
}
return _paint_back_unbounded_surface (compositor, composite, surface);
}
status = _cairo_gl_composite_init (&setup,
op,
dst,
FALSE /* assume_component_alpha */);
if (unlikely (status))
return status;
status = _cairo_gl_composite_set_source (&setup,
&composite->source_pattern.base,
&composite->source_sample_area,
&composite->bounded,
FALSE);
if (unlikely (status))
goto finish;
if (composite->original_mask_pattern != NULL) {
status = _cairo_gl_composite_set_mask (&setup,
&composite->mask_pattern.base,
&composite->mask_sample_area,
&composite->bounded,
FALSE);
}
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. */
_cairo_gl_composite_set_multisample (&setup);
status = _cairo_gl_composite_begin (&setup, &ctx);
if (unlikely (status))
goto finish;
if (! clip)
status = _draw_int_rect (ctx, &setup, &composite->bounded);
else
status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, clip);
finish:
_cairo_gl_composite_fini (&setup);
if (ctx)
status = _cairo_gl_context_release (ctx, status);
return status;
}
static cairo_int_status_t
_cairo_gl_msaa_compositor_paint (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *composite)
{
return _cairo_gl_msaa_compositor_mask (compositor, composite);
}
static cairo_status_t
_stroke_shaper_add_triangle (void *closure,
const cairo_point_t triangle[3])
{
struct _tristrip_composite_info *info = closure;
return _cairo_gl_composite_emit_triangle_as_tristrip (info->ctx,
&info->setup,
triangle);
}
static cairo_status_t
_stroke_shaper_add_triangle_fan (void *closure,
const cairo_point_t *midpoint,
const cairo_point_t *points,
int npoints)
{
struct _tristrip_composite_info *info = closure;
return _draw_triangle_fan (info->ctx, &info->setup,
midpoint, points, npoints);
}
static cairo_status_t
_stroke_shaper_add_quad (void *closure,
const cairo_point_t quad[4])
{
struct _tristrip_composite_info *info = closure;
return _cairo_gl_composite_emit_quad_as_tristrip (info->ctx, &info->setup,
quad);
}
static cairo_int_status_t
_prevent_overlapping_strokes (cairo_gl_context_t *ctx,
cairo_gl_composite_t *setup,
cairo_composite_rectangles_t *composite,
const cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm)
{
cairo_rectangle_int_t stroke_extents;
if (! _cairo_gl_ensure_stencil (ctx, setup->dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (_cairo_pattern_is_opaque (&composite->source_pattern.base,
&composite->source_sample_area))
return CAIRO_INT_STATUS_SUCCESS;
if (glIsEnabled (GL_STENCIL_TEST) == FALSE) {
cairo_bool_t scissor_was_enabled;
/* In case we have pending operations we have to flush before
adding the stencil buffer. */
_cairo_gl_composite_flush (ctx);
/* Enable the stencil buffer, even if we are not using it for clipping,
so we can use it below to prevent overlapping shapes. We initialize
it all to one here which represents infinite clip. */
glDepthMask (GL_TRUE);
glEnable (GL_STENCIL_TEST);
/* 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. */
scissor_was_enabled = glIsEnabled (GL_SCISSOR_TEST);
if (! scissor_was_enabled) {
_cairo_path_fixed_approximate_stroke_extents (path, style, ctm,
&stroke_extents);
_cairo_gl_scissor_to_rectangle (setup->dst, &stroke_extents);
}
glClearStencil (1);
glClear (GL_STENCIL_BUFFER_BIT);
if (! scissor_was_enabled)
glDisable (GL_SCISSOR_TEST);
glStencilFunc (GL_EQUAL, 1, 1);
}
/* This means that once we draw to a particular pixel nothing else can
be drawn there until the stencil buffer is reset or the stencil test
is disabled. */
glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO);
_cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
setup->dst->clip_on_stencil_buffer = NULL;
return CAIRO_INT_STATUS_SUCCESS;
}
static void
query_surface_capabilities (cairo_gl_surface_t *surface)
{
GLint samples, stencil_bits;
cairo_gl_context_t *ctx;
cairo_int_status_t status;
/* Texture surfaces are create in such a way that they always
have stencil and multisample bits if possible, so we don't
need to query their capabilities lazily. */
if (_cairo_gl_surface_is_texture (surface))
return;
if (surface->stencil_and_msaa_caps_initialized)
return;
surface->stencil_and_msaa_caps_initialized = TRUE;
surface->supports_stencil = FALSE;
surface->supports_msaa = FALSE;
status = _cairo_gl_context_acquire (surface->base.device, &ctx);
if (unlikely (status))
return;
_cairo_gl_context_set_destination (ctx, surface, FALSE);
glGetIntegerv(GL_SAMPLES, &samples);
glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);
surface->supports_stencil = stencil_bits > 0;
surface->supports_msaa = samples > 1;
status = _cairo_gl_context_release (ctx, status);
}
static cairo_int_status_t
_cairo_gl_msaa_compositor_stroke (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *composite,
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)
{
cairo_int_status_t status;
cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
struct _tristrip_composite_info info;
if (! can_use_msaa_compositor (dst, antialias))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (composite->is_bounded == FALSE) {
cairo_surface_t* surface = _prepare_unbounded_surface (dst);
if (unlikely (surface == NULL))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_compositor_stroke (compositor, surface,
CAIRO_OPERATOR_SOURCE,
&composite->source_pattern.base,
path, style, ctm, ctm_inverse,
tolerance, antialias, NULL);
if (unlikely (status)) {
cairo_surface_destroy (surface);
return status;
}
return _paint_back_unbounded_surface (compositor, composite, surface);
}
status = _cairo_gl_composite_init (&info.setup,
composite->op,
dst,
FALSE /* assume_component_alpha */);
if (unlikely (status))
return status;
info.ctx = NULL;
status = _cairo_gl_composite_set_source (&info.setup,
&composite->source_pattern.base,
&composite->source_sample_area,
&composite->bounded,
FALSE);
if (unlikely (status))
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 (&info.setup, &info.ctx);
if (unlikely (status))
goto finish;
status = _prevent_overlapping_strokes (info.ctx, &info.setup,
composite, path, style, ctm);
if (unlikely (status))
goto finish;
status = _cairo_path_fixed_stroke_to_shaper ((cairo_path_fixed_t *) path,
style,
ctm,
ctm_inverse,
tolerance,
_stroke_shaper_add_triangle,
_stroke_shaper_add_triangle_fan,
_stroke_shaper_add_quad,
&info);
if (unlikely (status))
goto finish;
finish:
_cairo_gl_composite_fini (&info.setup);
if (info.ctx)
status = _cairo_gl_context_release (info.ctx, status);
return status;
}
static cairo_int_status_t
_draw_simple_quad_path (cairo_gl_context_t *ctx,
cairo_gl_composite_t *setup,
const cairo_path_fixed_t *path)
{
cairo_point_t triangle[3];
cairo_int_status_t 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;
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_msaa_compositor_fill (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_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_traps_t traps;
cairo_bool_t draw_path_with_traps;
if (! can_use_msaa_compositor (dst, antialias))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (composite->is_bounded == FALSE) {
cairo_surface_t* surface = _prepare_unbounded_surface (dst);
if (unlikely (surface == NULL))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_compositor_fill (compositor, surface,
CAIRO_OPERATOR_SOURCE,
&composite->source_pattern.base,
path, fill_rule, tolerance,
antialias, NULL);
if (unlikely (status)) {
cairo_surface_destroy (surface);
return status;
}
return _paint_back_unbounded_surface (compositor, composite, surface);
}
draw_path_with_traps = ! _cairo_path_fixed_is_simple_quad (path);
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))
goto cleanup_traps;
status = _cairo_gl_composite_set_source (&setup,
&composite->source_pattern.base,
&composite->source_sample_area,
&composite->bounded,
FALSE);
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 (&setup, &ctx);
if (unlikely (status))
goto cleanup_setup;
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;
cleanup_setup:
_cairo_gl_composite_fini (&setup);
if (ctx)
status = _cairo_gl_context_release (ctx, status);
cleanup_traps:
if (draw_path_with_traps)
_cairo_traps_fini (&traps);
return status;
}
static cairo_int_status_t
_cairo_gl_msaa_compositor_glyphs (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *composite,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_bool_t overlap)
{
cairo_int_status_t status;
cairo_surface_t *src = NULL;
int src_x, src_y;
cairo_composite_glyphs_info_t info;
cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
query_surface_capabilities (dst);
if (! dst->supports_stencil)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (composite->op == CAIRO_OPERATOR_CLEAR)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (composite->is_bounded == FALSE) {
cairo_surface_t* surface = _prepare_unbounded_surface (dst);
if (unlikely (surface == NULL))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_compositor_glyphs (compositor, surface,
CAIRO_OPERATOR_SOURCE,
&composite->source_pattern.base,
glyphs, num_glyphs,
scaled_font, composite->clip);
if (unlikely (status)) {
cairo_surface_destroy (surface);
return status;
}
return _paint_back_unbounded_surface (compositor, composite, surface);
}
src = _cairo_gl_pattern_to_source (&dst->base,
&composite->source_pattern.base,
FALSE,
&composite->bounded,
&composite->source_sample_area,
&src_x, &src_y);
if (unlikely (src->status)) {
status = src->status;
goto finish;
}
status = _cairo_gl_check_composite_glyphs (composite,
scaled_font, glyphs,
&num_glyphs);
if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
goto finish;
info.font = scaled_font;
info.glyphs = glyphs;
info.num_glyphs = num_glyphs;
info.use_mask = overlap || ! composite->is_bounded ||
composite->op == CAIRO_OPERATOR_SOURCE;
info.extents = composite->bounded;
_cairo_scaled_font_freeze_cache (scaled_font);
status = _cairo_gl_composite_glyphs_with_clip (dst, composite->op,
src, src_x, src_y,
0, 0, &info,
composite->clip);
_cairo_scaled_font_thaw_cache (scaled_font);
finish:
if (src)
cairo_surface_destroy (src);
return status;
}
static void
_cairo_gl_msaa_compositor_init (cairo_compositor_t *compositor,
const cairo_compositor_t *delegate)
{
compositor->delegate = delegate;
compositor->paint = _cairo_gl_msaa_compositor_paint;
compositor->mask = _cairo_gl_msaa_compositor_mask;
compositor->fill = _cairo_gl_msaa_compositor_fill;
compositor->stroke = _cairo_gl_msaa_compositor_stroke;
compositor->glyphs = _cairo_gl_msaa_compositor_glyphs;
}
const cairo_compositor_t *
_cairo_gl_msaa_compositor_get (void)
{
static cairo_compositor_t compositor;
if (compositor.delegate == NULL)
_cairo_gl_msaa_compositor_init (&compositor,
_cairo_gl_span_compositor_get ());
return &compositor;
}

View File

@@ -0,0 +1,788 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Eric Anholt
* Copyright © 2009 Chris Wilson
* Copyright © 2005,2010 Red Hat, Inc
* Copyright © 2011 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Benjamin Otte <otte@gnome.org>
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
* Eric Anholt <eric@anholt.net>
*/
#include "cairoint.h"
#include "cairo-gl-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-compositor-private.h"
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
#include "cairo-surface-backend-private.h"
#include "cairo-surface-offset-private.h"
#include "cairo-surface-subsurface-inline.h"
static cairo_int_status_t
_cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
const cairo_gradient_pattern_t *pattern,
cairo_gl_gradient_t **gradient)
{
cairo_gl_context_t *ctx;
cairo_status_t status;
status = _cairo_gl_context_acquire (dst->base.device, &ctx);
if (unlikely (status))
return status;
status = _cairo_gl_gradient_create (ctx, pattern->n_stops, pattern->stops, gradient);
return _cairo_gl_context_release (ctx, status);
}
static cairo_status_t
_cairo_gl_subsurface_clone_operand_init (cairo_gl_operand_t *operand,
const cairo_pattern_t *_src,
cairo_gl_surface_t *dst,
const cairo_rectangle_int_t *sample,
const cairo_rectangle_int_t *extents,
cairo_bool_t use_texgen)
{
const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
cairo_surface_pattern_t local_pattern;
cairo_surface_subsurface_t *sub;
cairo_gl_surface_t *surface;
cairo_gl_context_t *ctx;
cairo_surface_attributes_t *attributes;
cairo_status_t status;
sub = (cairo_surface_subsurface_t *) src->surface;
if (sub->snapshot &&
sub->snapshot->type == CAIRO_SURFACE_TYPE_GL &&
sub->snapshot->device == dst->base.device)
{
surface = (cairo_gl_surface_t *)
cairo_surface_reference (sub->snapshot);
}
else
{
status = _cairo_gl_context_acquire (dst->base.device, &ctx);
if (unlikely (status))
return status;
/* XXX Trim surface to the sample area within the subsurface? */
surface = (cairo_gl_surface_t *)
_cairo_gl_surface_create_scratch (ctx,
sub->target->content,
sub->extents.width,
sub->extents.height);
if (surface->base.status)
return _cairo_gl_context_release (ctx, surface->base.status);
_cairo_pattern_init_for_surface (&local_pattern, sub->target);
cairo_matrix_init_translate (&local_pattern.base.matrix,
sub->extents.x, sub->extents.y);
local_pattern.base.filter = CAIRO_FILTER_NEAREST;
status = _cairo_surface_paint (&surface->base,
CAIRO_OPERATOR_SOURCE,
&local_pattern.base,
NULL);
_cairo_pattern_fini (&local_pattern.base);
status = _cairo_gl_context_release (ctx, status);
if (unlikely (status)) {
cairo_surface_destroy (&surface->base);
return status;
}
_cairo_surface_subsurface_set_snapshot (&sub->base, &surface->base);
}
status = _cairo_gl_surface_resolve_multisampling (surface);
if (unlikely (status))
return status;
attributes = &operand->texture.attributes;
operand->type = CAIRO_GL_OPERAND_TEXTURE;
operand->texture.surface = surface;
operand->texture.owns_surface = surface;
operand->texture.tex = surface->tex;
if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device)) {
attributes->matrix = src->base.matrix;
} else {
cairo_matrix_t m;
cairo_matrix_init_scale (&m,
1.0 / surface->width,
1.0 / surface->height);
cairo_matrix_multiply (&attributes->matrix, &src->base.matrix, &m);
}
attributes->extend = src->base.extend;
attributes->filter = src->base.filter;
attributes->has_component_alpha = src->base.has_component_alpha;
operand->texture.texgen = use_texgen;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_gl_subsurface_operand_init (cairo_gl_operand_t *operand,
const cairo_pattern_t *_src,
cairo_gl_surface_t *dst,
const cairo_rectangle_int_t *sample,
const cairo_rectangle_int_t *extents,
cairo_bool_t use_texgen)
{
const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
cairo_surface_subsurface_t *sub;
cairo_gl_surface_t *surface;
cairo_surface_attributes_t *attributes;
cairo_int_status_t status;
sub = (cairo_surface_subsurface_t *) src->surface;
if (sample->x < 0 || sample->y < 0 ||
sample->x + sample->width > sub->extents.width ||
sample->y + sample->height > sub->extents.height)
{
return _cairo_gl_subsurface_clone_operand_init (operand, _src,
dst, sample, extents,
use_texgen);
}
surface = (cairo_gl_surface_t *) sub->target;
if (surface->base.device && surface->base.device != dst->base.device)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (! _cairo_gl_surface_is_texture (surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_gl_surface_resolve_multisampling (surface);
if (unlikely (status))
return status;
/* Translate the matrix from
* (unnormalized src -> unnormalized src) to
* (unnormalized dst -> unnormalized src)
*/
_cairo_gl_operand_copy(operand, &surface->operand);
attributes = &operand->texture.attributes;
attributes->matrix = src->base.matrix;
attributes->matrix.x0 += sub->extents.x;
attributes->matrix.y0 += sub->extents.y;
cairo_matrix_multiply (&attributes->matrix,
&attributes->matrix,
&surface->operand.texture.attributes.matrix);
attributes->extend = src->base.extend;
attributes->filter = src->base.filter;
attributes->has_component_alpha = src->base.has_component_alpha;
operand->texture.texgen = use_texgen;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_gl_surface_operand_init (cairo_gl_operand_t *operand,
const cairo_pattern_t *_src,
cairo_gl_surface_t *dst,
const cairo_rectangle_int_t *sample,
const cairo_rectangle_int_t *extents,
cairo_bool_t use_texgen)
{
const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
cairo_gl_surface_t *surface;
cairo_surface_attributes_t *attributes;
cairo_int_status_t status;
surface = (cairo_gl_surface_t *) src->surface;
if (surface->base.type != CAIRO_SURFACE_TYPE_GL)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->base.backend->type != CAIRO_SURFACE_TYPE_GL) {
if (_cairo_surface_is_subsurface (&surface->base))
return _cairo_gl_subsurface_operand_init (operand, _src, dst,
sample, extents,
use_texgen);
return CAIRO_INT_STATUS_UNSUPPORTED;
}
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))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_gl_surface_resolve_multisampling (surface);
if (unlikely (status))
return status;
_cairo_gl_operand_copy(operand, &surface->operand);
attributes = &operand->texture.attributes;
cairo_matrix_multiply (&attributes->matrix,
&src->base.matrix,
&attributes->matrix);
attributes->extend = src->base.extend;
attributes->filter = src->base.filter;
attributes->has_component_alpha = src->base.has_component_alpha;
operand->texture.texgen = use_texgen;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand,
const cairo_pattern_t *_src,
cairo_gl_surface_t *dst,
const cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_gl_surface_t *surface;
cairo_gl_context_t *ctx;
cairo_image_surface_t *image;
cairo_bool_t src_is_gl_surface = FALSE;
cairo_rectangle_int_t map_extents;
if (_src->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_t* src_surface = ((cairo_surface_pattern_t *) _src)->surface;
src_is_gl_surface = src_surface->type == CAIRO_SURFACE_TYPE_GL;
}
status = _cairo_gl_context_acquire (dst->base.device, &ctx);
if (unlikely (status))
return status;
surface = (cairo_gl_surface_t *)
_cairo_gl_surface_create_scratch (ctx,
CAIRO_CONTENT_COLOR_ALPHA,
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. */
if (src_is_gl_surface) {
status = _cairo_gl_context_release (ctx, status);
if (unlikely (status))
goto fail;
}
status = _cairo_surface_offset_paint (&image->base, extents->x, extents->y,
CAIRO_OPERATOR_SOURCE, _src, NULL);
if (src_is_gl_surface) {
status = _cairo_gl_context_acquire (dst->base.device, &ctx);
if (unlikely (status))
goto fail;
}
status = _cairo_surface_unmap_image (&surface->base, image);
status = _cairo_gl_context_release (ctx, status);
if (unlikely (status))
goto fail;
*operand = surface->operand;
operand->texture.owns_surface = surface;
operand->texture.attributes.matrix.x0 -= extents->x * operand->texture.attributes.matrix.xx;
operand->texture.attributes.matrix.y0 -= extents->y * operand->texture.attributes.matrix.yy;
return CAIRO_STATUS_SUCCESS;
fail:
cairo_surface_destroy (&surface->base);
return status;
}
void
_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
const cairo_color_t *color)
{
operand->type = CAIRO_GL_OPERAND_CONSTANT;
operand->constant.color[0] = color->red * color->alpha;
operand->constant.color[1] = color->green * color->alpha;
operand->constant.color[2] = color->blue * color->alpha;
operand->constant.color[3] = color->alpha;
}
void
_cairo_gl_operand_translate (cairo_gl_operand_t *operand,
double tx, double ty)
{
switch (operand->type) {
case CAIRO_GL_OPERAND_TEXTURE:
operand->texture.attributes.matrix.x0 -= tx * operand->texture.attributes.matrix.xx;
operand->texture.attributes.matrix.y0 -= ty * operand->texture.attributes.matrix.yy;
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:
operand->gradient.m.x0 -= tx * operand->gradient.m.xx;
operand->gradient.m.y0 -= ty * operand->gradient.m.yy;
break;
case CAIRO_GL_OPERAND_NONE:
case CAIRO_GL_OPERAND_CONSTANT:
case CAIRO_GL_OPERAND_COUNT:
default:
break;
}
}
static cairo_status_t
_cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
const cairo_pattern_t *pattern,
cairo_gl_surface_t *dst,
cairo_bool_t use_texgen)
{
const cairo_gradient_pattern_t *gradient = (const cairo_gradient_pattern_t *)pattern;
cairo_status_t status;
assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
if (! _cairo_gl_device_has_glsl (dst->base.device))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_gl_create_gradient_texture (dst,
gradient,
&operand->gradient.gradient);
if (unlikely (status))
return status;
if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
double x0, y0, dx, dy, sf, offset;
dx = linear->pd2.x - linear->pd1.x;
dy = linear->pd2.y - linear->pd1.y;
sf = 1.0 / (dx * dx + dy * dy);
dx *= sf;
dy *= sf;
x0 = linear->pd1.x;
y0 = linear->pd1.y;
offset = dx * x0 + dy * y0;
operand->type = CAIRO_GL_OPERAND_LINEAR_GRADIENT;
cairo_matrix_init (&operand->gradient.m, dx, 0, dy, 1, -offset, 0);
if (! _cairo_matrix_is_identity (&pattern->matrix)) {
cairo_matrix_multiply (&operand->gradient.m,
&pattern->matrix,
&operand->gradient.m);
}
} else {
cairo_matrix_t m;
cairo_circle_double_t circles[2];
double x0, y0, r0, dx, dy, dr;
/*
* Some fragment shader implementations use half-floats to
* represent numbers, so the maximum number they can represent
* is about 2^14. Some intermediate computations used in the
* radial gradient shaders can produce results of up to 2*k^4.
* Setting k=8 makes the maximum result about 8192 (assuming
* that the extreme circles are not much smaller than the
* destination image).
*/
_cairo_gradient_pattern_fit_to_range (gradient, 8.,
&operand->gradient.m, circles);
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;
operand->gradient.a = dx * dx + dy * dy - dr * dr;
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;
if (operand->gradient.a == 0)
operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0;
else if (pattern->extend == CAIRO_EXTEND_NONE)
operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE;
else
operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT;
cairo_matrix_init_translate (&m, -x0, -y0);
cairo_matrix_multiply (&operand->gradient.m,
&operand->gradient.m,
&m);
}
operand->gradient.extend = pattern->extend;
operand->gradient.texgen = use_texgen;
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_gl_operand_copy (cairo_gl_operand_t *dst,
const cairo_gl_operand_t *src)
{
*dst = *src;
switch (dst->type) {
case CAIRO_GL_OPERAND_CONSTANT:
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 (dst->gradient.gradient);
break;
case CAIRO_GL_OPERAND_TEXTURE:
cairo_surface_reference (&dst->texture.owns_surface->base);
break;
default:
case CAIRO_GL_OPERAND_COUNT:
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
break;
}
}
void
_cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
{
switch (operand->type) {
case CAIRO_GL_OPERAND_CONSTANT:
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_destroy (operand->gradient.gradient);
break;
case CAIRO_GL_OPERAND_TEXTURE:
cairo_surface_destroy (&operand->texture.owns_surface->base);
break;
default:
case CAIRO_GL_OPERAND_COUNT:
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
break;
}
operand->type = CAIRO_GL_OPERAND_NONE;
}
cairo_int_status_t
_cairo_gl_operand_init (cairo_gl_operand_t *operand,
const cairo_pattern_t *pattern,
cairo_gl_surface_t *dst,
const cairo_rectangle_int_t *sample,
const cairo_rectangle_int_t *extents,
cairo_bool_t use_texgen)
{
cairo_int_status_t status;
TRACE ((stderr, "%s: type=%d\n", __FUNCTION__, pattern->type));
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
_cairo_gl_solid_operand_init (operand,
&((cairo_solid_pattern_t *) pattern)->color);
return CAIRO_STATUS_SUCCESS;
case CAIRO_PATTERN_TYPE_SURFACE:
status = _cairo_gl_surface_operand_init (operand, pattern, dst,
sample, extents, use_texgen);
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
break;
return status;
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
status = _cairo_gl_gradient_operand_init (operand, pattern, dst,
use_texgen);
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
break;
return status;
default:
case CAIRO_PATTERN_TYPE_MESH:
case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
break;
}
return _cairo_gl_pattern_texture_setup (operand, pattern, dst, extents);
}
cairo_filter_t
_cairo_gl_operand_get_filter (cairo_gl_operand_t *operand)
{
cairo_filter_t filter;
switch ((int) operand->type) {
case CAIRO_GL_OPERAND_TEXTURE:
filter = operand->texture.attributes.filter;
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:
filter = CAIRO_FILTER_BILINEAR;
break;
default:
filter = CAIRO_FILTER_DEFAULT;
break;
}
return filter;
}
GLint
_cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand)
{
cairo_filter_t filter = _cairo_gl_operand_get_filter (operand);
return filter != CAIRO_FILTER_FAST && filter != CAIRO_FILTER_NEAREST ?
GL_LINEAR :
GL_NEAREST;
}
cairo_extend_t
_cairo_gl_operand_get_extend (cairo_gl_operand_t *operand)
{
cairo_extend_t extend;
switch ((int) operand->type) {
case CAIRO_GL_OPERAND_TEXTURE:
extend = operand->texture.attributes.extend;
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:
extend = operand->gradient.extend;
break;
default:
extend = CAIRO_EXTEND_NONE;
break;
}
return extend;
}
void
_cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
cairo_gl_operand_t *operand,
cairo_gl_tex_t tex_unit)
{
const cairo_matrix_t *texgen = NULL;
switch (operand->type) {
default:
case CAIRO_GL_OPERAND_COUNT:
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
return;
case CAIRO_GL_OPERAND_CONSTANT:
_cairo_gl_shader_bind_vec4 (ctx,
ctx->current_shader->constant_location[tex_unit],
operand->constant.color[0],
operand->constant.color[1],
operand->constant.color[2],
operand->constant.color[3]);
return;
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
_cairo_gl_shader_bind_float (ctx,
ctx->current_shader->a_location[tex_unit],
operand->gradient.a);
/* fall through */
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
_cairo_gl_shader_bind_vec3 (ctx,
ctx->current_shader->circle_d_location[tex_unit],
operand->gradient.circle_d.center.x,
operand->gradient.circle_d.center.y,
operand->gradient.circle_d.radius);
_cairo_gl_shader_bind_float (ctx,
ctx->current_shader->radius_0_location[tex_unit],
operand->gradient.radius_0);
/* fall through */
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
case CAIRO_GL_OPERAND_TEXTURE:
/*
* For GLES2 we use shaders to implement GL_CLAMP_TO_BORDER (used
* with CAIRO_EXTEND_NONE). When bilinear filtering is enabled,
* these shaders need the texture dimensions for their calculations.
*/
if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
_cairo_gl_operand_get_extend (operand) == CAIRO_EXTEND_NONE &&
_cairo_gl_operand_get_gl_filter (operand) == GL_LINEAR)
{
float width, height;
if (operand->type == CAIRO_GL_OPERAND_TEXTURE) {
width = operand->texture.surface->width;
height = operand->texture.surface->height;
}
else {
width = operand->gradient.gradient->cache_entry.size,
height = 1;
}
_cairo_gl_shader_bind_vec2 (ctx,
ctx->current_shader->texdims_location[tex_unit],
width, height);
}
break;
}
if (operand->type == CAIRO_GL_OPERAND_TEXTURE) {
if (operand->texture.texgen)
texgen = &operand->texture.attributes.matrix;
} else {
if (operand->gradient.texgen)
texgen = &operand->gradient.m;
}
if (texgen) {
_cairo_gl_shader_bind_matrix(ctx,
ctx->current_shader->texgen_location[tex_unit],
texgen);
}
}
cairo_bool_t
_cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
cairo_gl_operand_t *source,
unsigned int vertex_offset)
{
if (dest->type != source->type)
return TRUE;
if (dest->vertex_offset != vertex_offset)
return TRUE;
switch (source->type) {
case CAIRO_GL_OPERAND_NONE:
return FALSE;
case CAIRO_GL_OPERAND_CONSTANT:
return dest->constant.color[0] != source->constant.color[0] ||
dest->constant.color[1] != source->constant.color[1] ||
dest->constant.color[2] != source->constant.color[2] ||
dest->constant.color[3] != source->constant.color[3];
case CAIRO_GL_OPERAND_TEXTURE:
return dest->texture.surface != source->texture.surface ||
dest->texture.attributes.extend != source->texture.attributes.extend ||
dest->texture.attributes.filter != source->texture.attributes.filter ||
dest->texture.attributes.has_component_alpha != source->texture.attributes.has_component_alpha;
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:
/* XXX: improve this */
return TRUE;
default:
case CAIRO_GL_OPERAND_COUNT:
ASSERT_NOT_REACHED;
break;
}
return TRUE;
}
unsigned int
_cairo_gl_operand_get_vertex_size (const cairo_gl_operand_t *operand)
{
switch (operand->type) {
default:
case CAIRO_GL_OPERAND_COUNT:
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
case CAIRO_GL_OPERAND_CONSTANT:
return 0;
case CAIRO_GL_OPERAND_TEXTURE:
return operand->texture.texgen ? 0 : 2 * sizeof (GLfloat);
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:
return operand->gradient.texgen ? 0 : 2 * sizeof (GLfloat);
}
}
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:
case CAIRO_GL_OPERAND_CONSTANT:
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:
if (! operand->gradient.texgen) {
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:
if (! operand->texture.texgen) {
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;
}
break;
}
}

View File

@@ -0,0 +1,848 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Eric Anholt
* Copyright © 2009 Chris Wilson
* Copyright © 2005,2010 Red Hat, Inc
* Copyright © 2011 Linaro Limited
*
* 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Benjamin Otte <otte@gnome.org>
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
* Eric Anholt <eric@anholt.net>
* T. Zachary Laine <whatwasthataddress@gmail.com>
* Alexandros Frantzis <alexandros.frantzis@linaro.org>
*/
#ifndef CAIRO_GL_PRIVATE_H
#define CAIRO_GL_PRIVATE_H
#define GL_GLEXT_PROTOTYPES
#include "cairoint.h"
#include "cairo-gl.h"
#include "cairo-gl-gradient-private.h"
#include "cairo-device-private.h"
#include "cairo-error-private.h"
#include "cairo-rtree-private.h"
#include "cairo-scaled-font-private.h"
#include "cairo-spans-compositor-private.h"
#include "cairo-array-private.h"
#include <assert.h>
#if CAIRO_HAS_GL_SURFACE
#include <GL/gl.h>
#include <GL/glext.h>
#elif CAIRO_HAS_GLESV2_SURFACE
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#endif
#include "cairo-gl-ext-def-private.h"
#define DEBUG_GL 0
#if DEBUG_GL && __GNUC__
#define UNSUPPORTED(reason) ({ \
fprintf (stderr, \
"cairo-gl: hit unsupported operation in %s(), line %d: %s\n", \
__FUNCTION__, __LINE__, reason); \
CAIRO_INT_STATUS_UNSUPPORTED; \
})
#else
#define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED
#endif
#define CAIRO_GL_VERSION_ENCODE(major, minor) ( \
((major) * 256) \
+ ((minor) * 1))
/* maximal number of shaders we keep in the cache.
* 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,
* but larger means hogging more memory and can cause trouble for drivers
* (especially on embedded devices). */
#define CAIRO_GL_VBO_SIZE (16*1024)
typedef struct _cairo_gl_surface cairo_gl_surface_t;
/* GL flavor */
typedef enum cairo_gl_flavor {
CAIRO_GL_FLAVOR_NONE = 0,
CAIRO_GL_FLAVOR_DESKTOP = 1,
CAIRO_GL_FLAVOR_ES = 2
} cairo_gl_flavor_t;
/* Indices for vertex attributes used by BindAttribLocation etc */
enum {
CAIRO_GL_VERTEX_ATTRIB_INDEX = 0,
CAIRO_GL_COLOR_ATTRIB_INDEX = 1,
CAIRO_GL_TEXCOORD0_ATTRIB_INDEX = 2,
CAIRO_GL_TEXCOORD1_ATTRIB_INDEX = CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + 1
};
typedef enum cairo_gl_operand_type {
CAIRO_GL_OPERAND_NONE,
CAIRO_GL_OPERAND_CONSTANT,
CAIRO_GL_OPERAND_TEXTURE,
CAIRO_GL_OPERAND_LINEAR_GRADIENT,
CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0,
CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE,
CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT,
CAIRO_GL_OPERAND_COUNT
} cairo_gl_operand_type_t;
/* This union structure describes a potential source or mask operand to the
* compositing equation.
*/
typedef struct cairo_gl_operand {
cairo_gl_operand_type_t type;
union {
struct {
GLuint tex;
cairo_gl_surface_t *surface;
cairo_gl_surface_t *owns_surface;
cairo_surface_attributes_t attributes;
int texgen;
} texture;
struct {
GLfloat color[4];
} constant;
struct {
cairo_gl_gradient_t *gradient;
cairo_matrix_t m;
cairo_circle_double_t circle_d;
double radius_0, a;
cairo_extend_t extend;
int texgen;
} gradient;
};
unsigned int vertex_offset;
} cairo_gl_operand_t;
typedef struct cairo_gl_source {
cairo_surface_t base;
cairo_gl_operand_t operand;
} cairo_gl_source_t;
struct _cairo_gl_surface {
cairo_surface_t base;
cairo_gl_operand_t operand;
int width, height;
GLuint tex; /* GL texture object containing our data. */
GLuint fb; /* GL framebuffer object wrapping our data. */
GLuint depth_stencil; /* GL renderbuffer object for holding stencil buffer clip. */
#if CAIRO_HAS_GL_SURFACE
GLuint msaa_rb; /* The ARB MSAA path uses a renderbuffer. */
GLuint msaa_fb;
#endif
GLuint msaa_depth_stencil;
cairo_bool_t stencil_and_msaa_caps_initialized;
cairo_bool_t supports_stencil; /* Stencil support for for non-texture surfaces. */
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;
cairo_region_t *clip_region;
};
typedef struct cairo_gl_glyph_cache {
cairo_rtree_t rtree;
cairo_gl_surface_t *surface;
} cairo_gl_glyph_cache_t;
typedef enum cairo_gl_tex {
CAIRO_GL_TEX_SOURCE = 0,
CAIRO_GL_TEX_MASK = 1,
CAIRO_GL_TEX_TEMP = 2
} cairo_gl_tex_t;
typedef struct cairo_gl_shader {
GLuint fragment_shader;
GLuint program;
GLint mvp_location;
GLint constant_location[2];
GLint a_location[2];
GLint circle_d_location[2];
GLint radius_0_location[2];
GLint texdims_location[2];
GLint texgen_location[2];
} cairo_gl_shader_t;
typedef enum cairo_gl_shader_in {
CAIRO_GL_SHADER_IN_NORMAL,
CAIRO_GL_SHADER_IN_CA_SOURCE,
CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
CAIRO_GL_SHADER_IN_COUNT
} cairo_gl_shader_in_t;
typedef enum cairo_gl_var_type {
CAIRO_GL_VAR_NONE,
CAIRO_GL_VAR_TEXCOORDS,
CAIRO_GL_VAR_TEXGEN,
} cairo_gl_var_type_t;
typedef enum cairo_gl_primitive_type {
CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES,
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,spans,dest) ((spans) << 5) | ((mask) << 3 | (src << 1) | (dest))
#define CAIRO_GL_VAR_TYPE_MAX (1 << 6)
typedef void (*cairo_gl_generic_func_t)(void);
typedef cairo_gl_generic_func_t (*cairo_gl_get_proc_addr_func_t)(const char *procname);
typedef struct _cairo_gl_dispatch {
/* Buffers */
void (*GenBuffers) (GLsizei n, GLuint *buffers);
void (*BindBuffer) (GLenum target, GLuint buffer);
void (*BufferData) (GLenum target, GLsizeiptr size,
const GLvoid* data, GLenum usage);
GLvoid *(*MapBuffer) (GLenum target, GLenum access);
GLboolean (*UnmapBuffer) (GLenum target);
/* Shaders */
GLuint (*CreateShader) (GLenum type);
void (*ShaderSource) (GLuint shader, GLsizei count,
const GLchar** string, const GLint* length);
void (*CompileShader) (GLuint shader);
void (*GetShaderiv) (GLuint shader, GLenum pname, GLint *params);
void (*GetShaderInfoLog) (GLuint shader, GLsizei bufSize,
GLsizei *length, GLchar *infoLog);
void (*DeleteShader) (GLuint shader);
/* Programs */
GLuint (*CreateProgram) (void);
void (*AttachShader) (GLuint program, GLuint shader);
void (*DeleteProgram) (GLuint program);
void (*LinkProgram) (GLuint program);
void (*UseProgram) (GLuint program);
void (*GetProgramiv) (GLuint program, GLenum pname, GLint *params);
void (*GetProgramInfoLog) (GLuint program, GLsizei bufSize,
GLsizei *length, GLchar *infoLog);
/* Uniforms */
GLint (*GetUniformLocation) (GLuint program, const GLchar* name);
void (*Uniform1f) (GLint location, GLfloat x);
void (*Uniform2f) (GLint location, GLfloat x, GLfloat y);
void (*Uniform3f) (GLint location, GLfloat x, GLfloat y, GLfloat z);
void (*Uniform4f) (GLint location, GLfloat x, GLfloat y, GLfloat z,
GLfloat w);
void (*UniformMatrix3fv) (GLint location, GLsizei count,
GLboolean transpose, const GLfloat *value);
void (*UniformMatrix4fv) (GLint location, GLsizei count,
GLboolean transpose, const GLfloat *value);
void (*Uniform1i) (GLint location, GLint x);
/* Attributes */
void (*BindAttribLocation) (GLuint program, GLuint index,
const GLchar *name);
void (*VertexAttribPointer) (GLuint index, GLint size, GLenum type,
GLboolean normalized, GLsizei stride,
const GLvoid *pointer);
void (*EnableVertexAttribArray) (GLuint index);
void (*DisableVertexAttribArray) (GLuint index);
/* Framebuffer objects */
void (*GenFramebuffers) (GLsizei n, GLuint* framebuffers);
void (*BindFramebuffer) (GLenum target, GLuint framebuffer);
void (*FramebufferTexture2D) (GLenum target, GLenum attachment,
GLenum textarget, GLuint texture,
GLint level);
GLenum (*CheckFramebufferStatus) (GLenum target);
void (*DeleteFramebuffers) (GLsizei n, const GLuint* framebuffers);
void (*GenRenderbuffers) (GLsizei n, GLuint *renderbuffers);
void (*BindRenderbuffer) (GLenum target, GLuint renderbuffer);
void (*RenderbufferStorage) (GLenum target, GLenum internal_format,
GLsizei width, GLsizei height);
void (*FramebufferRenderbuffer) (GLenum target, GLenum attachment,
GLenum renderbuffer_ttarget, GLuint renderbuffer);
void (*DeleteRenderbuffers) (GLsizei n, GLuint *renderbuffers);
void (*BlitFramebuffer) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
void (*RenderbufferStorageMultisample) (GLenum target, GLsizei samples,
GLenum internalformat,
GLsizei width, GLsizei height);
void (*FramebufferTexture2DMultisample) (GLenum target, GLenum attachment,
GLenum textarget, GLuint texture,
GLint level, GLsizei samples);
} cairo_gl_dispatch_t;
struct _cairo_gl_context {
cairo_device_t base;
const cairo_compositor_t *compositor;
GLuint texture_load_pbo;
GLint max_framebuffer_size;
GLint max_texture_size;
GLint max_textures;
GLenum tex_target;
GLint num_samples;
cairo_bool_t supports_msaa;
char *vb;
cairo_bool_t has_shader_support;
GLuint vertex_shaders[CAIRO_GL_VAR_TYPE_MAX];
cairo_gl_shader_t fill_rectangles_shader;
cairo_cache_t shaders;
cairo_cache_t gradients;
cairo_gl_glyph_cache_t glyph_cache[2];
cairo_list_t fonts;
cairo_gl_surface_t *current_target;
cairo_operator_t current_operator;
cairo_gl_shader_t *pre_shader; /* for component alpha */
cairo_gl_shader_t *current_shader;
cairo_gl_operand_t operands[2];
cairo_bool_t spans;
unsigned int vb_offset;
unsigned int vertex_size;
cairo_region_t *clip_region;
cairo_clip_t *clip;
cairo_gl_primitive_type_t primitive_type;
cairo_array_t tristrip_indices;
cairo_bool_t has_mesa_pack_invert;
cairo_gl_dispatch_t dispatch;
GLfloat modelviewprojection_matrix[16];
cairo_gl_flavor_t gl_flavor;
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;
void (*acquire) (void *ctx);
void (*release) (void *ctx);
void (*make_current) (void *ctx, cairo_gl_surface_t *surface);
void (*swap_buffers)(void *ctx, cairo_gl_surface_t *surface);
void (*destroy) (void *ctx);
};
typedef struct _cairo_gl_composite {
cairo_gl_surface_t *dst;
cairo_operator_t op;
cairo_region_t *clip_region;
cairo_gl_operand_t src;
cairo_gl_operand_t mask;
cairo_bool_t spans;
cairo_clip_t *clip;
cairo_bool_t multisample;
} cairo_gl_composite_t;
typedef struct _cairo_gl_font {
cairo_scaled_font_private_t base;
cairo_device_t *device;
cairo_list_t link;
} cairo_gl_font_t;
static cairo_always_inline GLenum
_cairo_gl_get_error (void)
{
GLenum err = glGetError();
if (unlikely (err))
while (glGetError ());
return err;
}
static inline cairo_device_t *
_cairo_gl_context_create_in_error (cairo_status_t status)
{
return (cairo_device_t *) _cairo_device_create_in_error (status);
}
cairo_private cairo_status_t
_cairo_gl_context_init (cairo_gl_context_t *ctx);
cairo_private void
_cairo_gl_surface_init (cairo_device_t *device,
cairo_gl_surface_t *surface,
cairo_content_t content,
int width, int height);
static cairo_always_inline cairo_bool_t cairo_warn
_cairo_gl_surface_is_texture (cairo_gl_surface_t *surface)
{
return surface->tex != 0;
}
cairo_private cairo_status_t
_cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
cairo_image_surface_t *src,
int src_x, int src_y,
int width, int height,
int dst_x, int dst_y,
cairo_bool_t force_flush);
cairo_private cairo_int_status_t
_cairo_gl_surface_resolve_multisampling (cairo_gl_surface_t *surface);
static cairo_always_inline cairo_bool_t
_cairo_gl_device_has_glsl (cairo_device_t *device)
{
return ((cairo_gl_context_t *) device)->has_shader_support;
}
static cairo_always_inline cairo_bool_t
_cairo_gl_device_requires_power_of_two_textures (cairo_device_t *device)
{
return ((cairo_gl_context_t *) device)->tex_target == GL_TEXTURE_RECTANGLE;
}
static cairo_always_inline cairo_status_t cairo_warn
_cairo_gl_context_acquire (cairo_device_t *device,
cairo_gl_context_t **ctx)
{
cairo_status_t status;
status = cairo_device_acquire (device);
if (unlikely (status))
return status;
/* clear potential previous GL errors */
_cairo_gl_get_error ();
*ctx = (cairo_gl_context_t *) device;
return CAIRO_STATUS_SUCCESS;
}
static cairo_always_inline cairo_warn cairo_status_t
_cairo_gl_context_release (cairo_gl_context_t *ctx, cairo_status_t status)
{
GLenum err;
err = _cairo_gl_get_error ();
if (unlikely (err)) {
cairo_status_t new_status;
new_status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
if (status == CAIRO_STATUS_SUCCESS)
status = new_status;
}
cairo_device_release (&(ctx)->base);
return status;
}
cairo_private void
_cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
cairo_gl_surface_t *surface,
cairo_bool_t multisampling);
cairo_private void
_cairo_gl_context_bind_framebuffer (cairo_gl_context_t *ctx,
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_private cairo_bool_t
_cairo_gl_operator_is_supported (cairo_operator_t op);
cairo_private cairo_bool_t
_cairo_gl_ensure_stencil (cairo_gl_context_t *ctx,
cairo_gl_surface_t *surface);
cairo_private cairo_status_t
_cairo_gl_composite_init (cairo_gl_composite_t *setup,
cairo_operator_t op,
cairo_gl_surface_t *dst,
cairo_bool_t has_component_alpha);
cairo_private void
_cairo_gl_composite_fini (cairo_gl_composite_t *setup);
cairo_private 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_clip(cairo_gl_composite_t *setup,
cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
const cairo_pattern_t *pattern,
const cairo_rectangle_int_t *sample,
const cairo_rectangle_int_t *extents,
cairo_bool_t use_texgen);
cairo_private void
_cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
const cairo_color_t *color);
cairo_private void
_cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
const cairo_gl_operand_t *source);
cairo_private cairo_int_status_t
_cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
const cairo_pattern_t *pattern,
const cairo_rectangle_int_t *sample,
const cairo_rectangle_int_t *extents,
cairo_bool_t use_texgen);
cairo_private void
_cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
const cairo_gl_operand_t *mask);
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_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 cairo_int_status_t
_cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t *ctx,
cairo_gl_composite_t *setup,
const cairo_point_t quad[4]);
cairo_private cairo_int_status_t
_cairo_gl_composite_emit_triangle_as_tristrip (cairo_gl_context_t *ctx,
cairo_gl_composite_t *setup,
const cairo_point_t triangle[3]);
cairo_private void
_cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
cairo_gl_tex_t tex_unit);
cairo_private cairo_bool_t
_cairo_gl_get_image_format_and_type (cairo_gl_flavor_t flavor,
pixman_format_code_t pixman_format,
GLenum *internal_format, GLenum *format,
GLenum *type, cairo_bool_t *has_alpha,
cairo_bool_t *needs_swap);
cairo_private void
_cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache);
cairo_private void
_cairo_gl_glyph_cache_fini (cairo_gl_context_t *ctx,
cairo_gl_glyph_cache_t *cache);
cairo_private cairo_int_status_t
_cairo_gl_surface_show_glyphs (void *abstract_dst,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
const cairo_clip_t *clip,
int *remaining_glyphs);
cairo_private cairo_status_t
_cairo_gl_context_init_shaders (cairo_gl_context_t *ctx);
cairo_private void
_cairo_gl_context_fini_shaders (cairo_gl_context_t *ctx);
static cairo_always_inline cairo_bool_t
_cairo_gl_context_is_flushed (cairo_gl_context_t *ctx)
{
return ctx->vb_offset == 0;
}
cairo_private cairo_status_t
_cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
cairo_gl_operand_t *source,
cairo_gl_operand_t *mask,
cairo_bool_t use_coverage,
cairo_gl_shader_in_t in,
cairo_gl_shader_t **shader);
cairo_private void
_cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
GLint location,
float value);
cairo_private void
_cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
GLint location,
float value0, float value1);
cairo_private void
_cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
GLint location,
float value0,
float value1,
float value2);
cairo_private void
_cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
GLint location,
float value0, float value1,
float value2, float value3);
cairo_private void
_cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
GLint location,
const cairo_matrix_t* m);
cairo_private void
_cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx,
GLint location,
GLfloat* gl_m);
cairo_private void
_cairo_gl_set_shader (cairo_gl_context_t *ctx,
cairo_gl_shader_t *shader);
cairo_private void
_cairo_gl_shader_fini (cairo_gl_context_t *ctx, cairo_gl_shader_t *shader);
cairo_private int
_cairo_gl_get_version (void);
cairo_private cairo_gl_flavor_t
_cairo_gl_get_flavor (void);
cairo_private cairo_bool_t
_cairo_gl_has_extension (const char *ext);
cairo_private cairo_status_t
_cairo_gl_dispatch_init(cairo_gl_dispatch_t *dispatch,
cairo_gl_get_proc_addr_func_t get_proc_addr);
cairo_private cairo_int_status_t
_cairo_gl_operand_init (cairo_gl_operand_t *operand,
const cairo_pattern_t *pattern,
cairo_gl_surface_t *dst,
const cairo_rectangle_int_t *sample,
const cairo_rectangle_int_t *extents,
cairo_bool_t use_texgen);
cairo_private void
_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
const cairo_color_t *color);
cairo_private cairo_filter_t
_cairo_gl_operand_get_filter (cairo_gl_operand_t *operand);
cairo_private GLint
_cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand);
cairo_private cairo_extend_t
_cairo_gl_operand_get_extend (cairo_gl_operand_t *operand);
cairo_private unsigned int
_cairo_gl_operand_get_vertex_size (const cairo_gl_operand_t *operand);
cairo_private cairo_bool_t
_cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
cairo_gl_operand_t *source,
unsigned int vertex_offset);
cairo_private void
_cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
cairo_gl_operand_t *operand,
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_private void
_cairo_gl_operand_translate (cairo_gl_operand_t *operand,
double tx, double ty);
cairo_private void
_cairo_gl_operand_destroy (cairo_gl_operand_t *operand);
cairo_private const cairo_compositor_t *
_cairo_gl_msaa_compositor_get (void);
cairo_private const cairo_compositor_t *
_cairo_gl_span_compositor_get (void);
cairo_private const cairo_compositor_t *
_cairo_gl_traps_compositor_get (void);
cairo_private cairo_int_status_t
_cairo_gl_check_composite_glyphs (const cairo_composite_rectangles_t *extents,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int *num_glyphs);
cairo_private cairo_int_status_t
_cairo_gl_composite_glyphs (void *_dst,
cairo_operator_t op,
cairo_surface_t *_src,
int src_x,
int src_y,
int dst_x,
int dst_y,
cairo_composite_glyphs_info_t *info);
cairo_private cairo_int_status_t
_cairo_gl_composite_glyphs_with_clip (void *_dst,
cairo_operator_t op,
cairo_surface_t *_src,
int src_x,
int src_y,
int dst_x,
int dst_y,
cairo_composite_glyphs_info_t *info,
cairo_clip_t *clip);
cairo_private cairo_surface_t *
_cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
cairo_content_t content,
int width,
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,
const cairo_pattern_t *pattern,
cairo_bool_t is_mask,
const cairo_rectangle_int_t *extents,
const cairo_rectangle_int_t *sample,
int *src_x, int *src_y);
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_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_gl_source_t *source = (cairo_gl_source_t *)surface;
return source ? &source->operand : NULL;
}
static inline void
_cairo_gl_glyph_cache_unlock (cairo_gl_glyph_cache_t *cache)
{
_cairo_rtree_unpin (&cache->rtree);
}
slim_hidden_proto (cairo_gl_surface_create);
slim_hidden_proto (cairo_gl_surface_create_for_texture);
#endif /* CAIRO_GL_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,111 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2011 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.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-gl-private.h"
#include "cairo-surface-backend-private.h"
static cairo_status_t
_cairo_gl_source_finish (void *abstract_surface)
{
cairo_gl_source_t *source = abstract_surface;
_cairo_gl_operand_destroy (&source->operand);
return CAIRO_STATUS_SUCCESS;
}
static const cairo_surface_backend_t cairo_gl_source_backend = {
CAIRO_SURFACE_TYPE_GL,
_cairo_gl_source_finish,
NULL, /* read-only wrapper */
};
cairo_surface_t *
_cairo_gl_pattern_to_source (cairo_surface_t *dst,
const cairo_pattern_t *pattern,
cairo_bool_t is_mask,
const cairo_rectangle_int_t *extents,
const cairo_rectangle_int_t *sample,
int *src_x, int *src_y)
{
cairo_gl_source_t *source;
cairo_int_status_t status;
TRACE ((stderr, "%s\n", __FUNCTION__));
if (pattern == NULL)
return _cairo_gl_white_source ();
source = malloc (sizeof (*source));
if (unlikely (source == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&source->base,
&cairo_gl_source_backend,
NULL, /* device */
CAIRO_CONTENT_COLOR_ALPHA);
*src_x = *src_y = 0;
status = _cairo_gl_operand_init (&source->operand, pattern,
(cairo_gl_surface_t *)dst,
sample, extents,
FALSE);
if (unlikely (status)) {
cairo_surface_destroy (&source->base);
return _cairo_surface_create_in_error (status);
}
return &source->base;
}
cairo_surface_t *
_cairo_gl_white_source (void)
{
cairo_gl_source_t *source;
source = malloc (sizeof (*source));
if (unlikely (source == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&source->base,
&cairo_gl_source_backend,
NULL, /* device */
CAIRO_CONTENT_COLOR_ALPHA);
_cairo_gl_solid_operand_init (&source->operand, CAIRO_COLOR_WHITE);
return &source->base;
}

Some files were not shown because too many files have changed in this diff Show More