📄 cairo.c
字号:
/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. * * The Original Code is the cairo graphics library. * * The Initial Developer of the Original Code is University of Southern * California. * * Contributor(s): * Carl D. Worth <cworth@cworth.org> */#include "cairoint.h"#include "cairo-private.h"#include "cairo-arc-private.h"#include "cairo-path-data-private.h"#define CAIRO_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */static const cairo_t cairo_nil = { (unsigned int)-1, /* ref_count */ CAIRO_STATUS_NO_MEMORY, /* status */ { /* path */ NULL, NULL, /* op_buf_head, op_buf_tail */ NULL, NULL, /* arg_buf_head, arg_buf_tail */ { 0, 0 }, /* last_move_point */ { 0, 0 }, /* current point */ FALSE, /* has_current_point */ }, NULL /* gstate */};#include <assert.h>/* This has to be updated whenever cairo_status_t is extended. That's * a bit of a pain, but it should be easy to always catch as long as * one adds a new test case to test a trigger of the new status value. */#define CAIRO_STATUS_LAST_STATUS CAIRO_STATUS_INVALID_DSC_COMMENT/** * _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. **/void_cairo_error (cairo_status_t status){ assert (status > CAIRO_STATUS_SUCCESS && status <= CAIRO_STATUS_LAST_STATUS);}/** * _cairo_set_error: * @cr: a cairo context * @status: a status value indicating an error, (eg. not * CAIRO_STATUS_SUCCESS) * * Sets cr->status to @status and calls _cairo_error; * * All assignments of an error status to cr->status should happen * through _cairo_set_error() or else _cairo_error() should be * called immediately after the assignment. * * 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. **/static void_cairo_set_error (cairo_t *cr, cairo_status_t status){ /* Don't overwrite an existing error. This preserves the first * error, which is the most significant. It also avoids attempting * to write to read-only data (eg. from a nil cairo_t). */ if (cr->status == CAIRO_STATUS_SUCCESS) cr->status = status; _cairo_error (status);}/** * cairo_version: * * Returns the version of the cairo library encoded in a single * integer as per CAIRO_VERSION_ENCODE. The encoding ensures that * later versions compare greater than earlier versions. * * A run-time comparison to check that cairo's version is greater than * or equal to version X.Y.Z could be performed as follows: * * <informalexample><programlisting> * if (cairo_version() >= CAIRO_VERSION_ENCODE(X,Y,Z)) {...} * </programlisting></informalexample> * * See also cairo_version_string() as well as the compile-time * equivalents %CAIRO_VERSION and %CAIRO_VERSION_STRING. * * Return value: the encoded version. **/intcairo_version (void){ return CAIRO_VERSION;}/** * cairo_version_string: * * Returns the version of the cairo library as a human-readable string * of the form "X.Y.Z". * * See also cairo_version() as well as the compile-time equivalents * %CAIRO_VERSION_STRING and %CAIRO_VERSION. * * Return value: a string containing the version. **/const char*cairo_version_string (void){ return CAIRO_VERSION_STRING;}/** * cairo_create: * @target: target surface for the context * * Creates a new #cairo_t with all graphics state parameters set to * default values and with @target as a target surface. The target * surface should be constructed with a backend-specific function such * as cairo_image_surface_create() (or any other * <literal>cairo_<backend>_surface_create</literal> variant). * * This function references @target, so you can immediately * call cairo_surface_destroy() on it if you don't need to * maintain a separate reference to it. * * Return value: a newly allocated #cairo_t with a reference * count of 1. The initial reference count should be released * with cairo_destroy() when you are done using the #cairo_t. * This function never returns %NULL. If memory cannot be * allocated, a special #cairo_t object will be returned on * which cairo_status() returns %CAIRO_STATUS_NO_MEMORY. * You can use this object normally, but no drawing will * be done. **/cairo_t *cairo_create (cairo_surface_t *target){ cairo_t *cr; cr = malloc (sizeof (cairo_t)); if (cr == NULL) return (cairo_t *) &cairo_nil; cr->ref_count = 1; cr->status = CAIRO_STATUS_SUCCESS; _cairo_path_fixed_init (&cr->path); if (target == NULL) { cr->gstate = NULL; _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); return cr; } cr->gstate = _cairo_gstate_create (target); if (cr->gstate == NULL) _cairo_set_error (cr, CAIRO_STATUS_NO_MEMORY); return cr;}/** * cairo_reference: * @cr: a #cairo_t * * Increases the reference count on @cr by one. This prevents * @cr from being destroyed until a matching call to cairo_destroy() * is made. * * Return value: the referenced #cairo_t. **/cairo_t *cairo_reference (cairo_t *cr){ if (cr == NULL) return NULL; if (cr->ref_count == (unsigned int)-1) return cr; assert (cr->ref_count > 0); cr->ref_count++; return cr;}/** * cairo_destroy: * @cr: a #cairo_t * * Decreases the reference count on @cr by one. If the result * is zero, then @cr and all associated resources are freed. * See cairo_reference(). **/voidcairo_destroy (cairo_t *cr){ if (cr == NULL) return; if (cr->ref_count == (unsigned int)-1) return; assert (cr->ref_count > 0); cr->ref_count--; if (cr->ref_count) return; while (cr->gstate) { cairo_gstate_t *tmp = cr->gstate; cr->gstate = tmp->next; _cairo_gstate_destroy (tmp); } _cairo_path_fixed_fini (&cr->path); free (cr);}/** * cairo_save: * @cr: a #cairo_t * * Makes a copy of the current state of @cr and saves it * on an internal stack of saved states for @cr. When * cairo_restore() is called, @cr will be restored to * the saved state. Multiple calls to cairo_save() and * cairo_restore() can be nested; each call to cairo_restore() * restores the state from the matching paired cairo_save(). * * It isn't necessary to clear all saved states before * a #cairo_t is freed. If the reference count of a #cairo_t * drops to zero in response to a call to cairo_destroy(), * any saved states will be freed along with the #cairo_t. **/voidcairo_save (cairo_t *cr){ cairo_gstate_t *top; if (cr->status) return; top = _cairo_gstate_clone (cr->gstate); if (top == NULL) { _cairo_set_error (cr, CAIRO_STATUS_NO_MEMORY); return; } top->next = cr->gstate; cr->gstate = top;}slim_hidden_def(cairo_save);/** * cairo_restore: * @cr: a #cairo_t * * Restores @cr to the state saved by a preceding call to * cairo_save() and removes that state from the stack of * saved states. **/voidcairo_restore (cairo_t *cr){ cairo_gstate_t *top; if (cr->status) return; top = cr->gstate; cr->gstate = top->next; _cairo_gstate_destroy (top); if (cr->gstate == NULL) _cairo_set_error (cr, CAIRO_STATUS_INVALID_RESTORE);}slim_hidden_def(cairo_restore);/** * cairo_push_group: * @cr: a cairo context * * Temporarily redirects drawing to an intermediate surface known as a * group. The redirection lasts until the group is completed by a call * to cairo_pop_group() or cairo_pop_group_to_source(). These calls * provide the result of any drawing to the group as a pattern, * (either as an explicit object, or set as the source pattern). * * This group functionality can be convenient for performing * intermediate compositing. One common use of a group is to render * objects as opaque within the group, (so that they occlude each * other), and then blend the result with translucence onto the * destination. * * Groups can be nested arbitrarily deep by making balanced calls to * cairo_push_group()/cairo_pop_group(). Each call pushes/pops the new * target group onto/from a stack. * * The cairo_push_group() function calls cairo_save() so that any * changes to the graphics state will not be visible outside the * group, (the pop_group functions call cairo_restore()). * * By default the intermediate group will have a content type of * CAIRO_CONTENT_COLOR_ALPHA. Other content types can be chosen for * the group by using cairo_push_group_with_content() instead. * * As an example, here is how one might fill and stroke a path with * translucence, but without any portion of the fill being visible * under the stroke: * * <informalexample><programlisting> * cairo_push_group (cr); * cairo_set_source (cr, fill_pattern); * cairo_fill_preserve (cr); * cairo_set_source (cr, stroke_pattern); * cairo_stroke (cr); * cairo_pop_group_to_source (cr); * cairo_paint_with_alpha (cr, alpha); * </programlisting></informalexample> * * Since: 1.2 */voidcairo_push_group (cairo_t *cr){ cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);}slim_hidden_def(cairo_push_group);/** * cairo_push_group_with_content: * @cr: a cairo context * @content: a %cairo_content_t indicating the type of group that * will be created * * Temporarily redirects drawing to an intermediate surface known as a * group. The redirection lasts until the group is completed by a call * to cairo_pop_group() or cairo_pop_group_to_source(). These calls * provide the result of any drawing to the group as a pattern, * (either as an explicit object, or set as the source pattern). * * The group will have a content type of @content. The ability to * control this content type is the only distinction between this * function and cairo_push_group() which you should see for a more * detailed description of group rendering. * * Since: 1.2 */voidcairo_push_group_with_content (cairo_t *cr, cairo_content_t content){ cairo_status_t status; cairo_rectangle_int16_t extents; cairo_surface_t *group_surface = NULL; /* Get the extents that we'll use in creating our new group surface */ _cairo_surface_get_extents (_cairo_gstate_get_target (cr->gstate), &extents); status = _cairo_clip_intersect_to_rectangle (_cairo_gstate_get_clip (cr->gstate), &extents); if (status != CAIRO_STATUS_SUCCESS) goto bail; group_surface = cairo_surface_create_similar (_cairo_gstate_get_target (cr->gstate), content, extents.width, extents.height); status = cairo_surface_status (group_surface); if (status) goto bail; /* Set device offsets on the new surface so that logically it appears at * the same location on the parent surface -- when we pop_group this, * the source pattern will get fixed up for the appropriate target surface * device offsets, so we want to set our own surface offsets from /that/, * and not from the device origin. */ cairo_surface_set_device_offset (group_surface, cr->gstate->target->device_transform.x0 - extents.x, cr->gstate->target->device_transform.y0 - extents.y); /* create a new gstate for the redirect */ cairo_save (cr); if (cr->status) goto bail; _cairo_gstate_redirect_target (cr->gstate, group_surface);bail: cairo_surface_destroy (group_surface); if (status) _cairo_set_error (cr, status);}slim_hidden_def(cairo_push_group_with_content);/** * cairo_pop_group: * @cr: a cairo context * * Terminates the redirection begun by a call to cairo_push_group() or * cairo_push_group_with_content() and returns a new pattern * containing the results of all drawing operations performed to the * group. * * The cairo_pop_group() function calls cairo_restore(), (balancing a * call to cairo_save() by the push_group function), so that any * changes to the graphics state will not be visible outside the * group.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -