/* Some of these are present in earlier versions of the OS than where *theyarepublic;otherarenotpublicatall
*/ /* public since 10.5 */ staticvoid (*CGContextDrawTiledImagePtr) (CGContextRef, CGRect, CGImageRef) = NULL;
/* public since 10.6 */ static CGPathRef (*CGContextCopyPathPtr) (CGContextRef) = NULL; staticvoid (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL;
/* not yet public */ staticunsignedint (*CGContextGetTypePtr) (CGContextRef) = NULL; staticbool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
/* CTFontDrawGlyphs is not available until 10.7 */ staticvoid (*CTFontDrawGlyphsPtr) (CTFontRef, const CGGlyph[], const CGPoint[], size_t, CGContextRef) = NULL;
#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1050 static PrivateCGCompositeMode
_cairo_quartz_cairo_operator_to_quartz_composite (cairo_operator_t op)
{ switch (op) { case CAIRO_OPERATOR_CLEAR: return kPrivateCGCompositeClear; case CAIRO_OPERATOR_SOURCE: return kPrivateCGCompositeCopy; case CAIRO_OPERATOR_OVER: return kPrivateCGCompositeSourceOver; case CAIRO_OPERATOR_IN: return kPrivateCGCompositeSourceIn; case CAIRO_OPERATOR_OUT: return kPrivateCGCompositeSourceOut; case CAIRO_OPERATOR_ATOP: return kPrivateCGCompositeSourceAtop; case CAIRO_OPERATOR_DEST_OVER: return kPrivateCGCompositeDestinationOver; case CAIRO_OPERATOR_DEST_IN: return kPrivateCGCompositeDestinationIn; case CAIRO_OPERATOR_DEST_OUT: return kPrivateCGCompositeDestinationOut; case CAIRO_OPERATOR_DEST_ATOP: return kPrivateCGCompositeDestinationAtop; case CAIRO_OPERATOR_XOR: return kPrivateCGCompositeXOR; case CAIRO_OPERATOR_ADD: return kPrivateCGCompositePlusLighter;
case CAIRO_OPERATOR_DEST: case CAIRO_OPERATOR_SATURATE: 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:
ASSERT_NOT_REACHED;
}
} #endif
static CGBlendMode
_cairo_quartz_cairo_operator_to_quartz_blend (cairo_operator_t op)
{ switch (op) { case CAIRO_OPERATOR_MULTIPLY: return kCGBlendModeMultiply; case CAIRO_OPERATOR_SCREEN: return kCGBlendModeScreen; case CAIRO_OPERATOR_OVERLAY: return kCGBlendModeOverlay; case CAIRO_OPERATOR_DARKEN: return kCGBlendModeDarken; case CAIRO_OPERATOR_LIGHTEN: return kCGBlendModeLighten; case CAIRO_OPERATOR_COLOR_DODGE: return kCGBlendModeColorDodge; case CAIRO_OPERATOR_COLOR_BURN: return kCGBlendModeColorBurn; case CAIRO_OPERATOR_HARD_LIGHT: return kCGBlendModeHardLight; case CAIRO_OPERATOR_SOFT_LIGHT: return kCGBlendModeSoftLight; case CAIRO_OPERATOR_DIFFERENCE: return kCGBlendModeDifference; case CAIRO_OPERATOR_EXCLUSION: return kCGBlendModeExclusion; case CAIRO_OPERATOR_HSL_HUE: return kCGBlendModeHue; case CAIRO_OPERATOR_HSL_SATURATION: return kCGBlendModeSaturation; case CAIRO_OPERATOR_HSL_COLOR: return kCGBlendModeColor; case CAIRO_OPERATOR_HSL_LUMINOSITY: return kCGBlendModeLuminosity;
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 case CAIRO_OPERATOR_CLEAR: return kCGBlendModeClear; case CAIRO_OPERATOR_SOURCE: return kCGBlendModeCopy; case CAIRO_OPERATOR_OVER: return kCGBlendModeNormal; case CAIRO_OPERATOR_IN: return kCGBlendModeSourceIn; case CAIRO_OPERATOR_OUT: return kCGBlendModeSourceOut; case CAIRO_OPERATOR_ATOP: return kCGBlendModeSourceAtop; case CAIRO_OPERATOR_DEST_OVER: return kCGBlendModeDestinationOver; case CAIRO_OPERATOR_DEST_IN: return kCGBlendModeDestinationIn; case CAIRO_OPERATOR_DEST_OUT: return kCGBlendModeDestinationOut; case CAIRO_OPERATOR_DEST_ATOP: return kCGBlendModeDestinationAtop; case CAIRO_OPERATOR_XOR: return kCGBlendModeXOR; case CAIRO_OPERATOR_ADD: return kCGBlendModePlusLighter; #else case CAIRO_OPERATOR_CLEAR: case CAIRO_OPERATOR_SOURCE: case CAIRO_OPERATOR_OVER: case CAIRO_OPERATOR_IN: case CAIRO_OPERATOR_OUT: case CAIRO_OPERATOR_ATOP: 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_ADD: #endif
case CAIRO_OPERATOR_DEST: case CAIRO_OPERATOR_SATURATE: default:
ASSERT_NOT_REACHED;
} return kCGBlendModeNormal; /* just to silence clang warning [-Wreturn-type] */
}
/* Quartz doesn't support SATURATE at all. COLOR_DODGE and *COLOR_BURNinQuartzfollowtheISO32000definition,butcairo *usesthedefinitionfromtheAdobeSupplement.Alsofallback *onSOFT_LIGHTandHSL_HUE,becausetheirresultsare *significantlydifferentfromthoseprovidedbypixman.
*/ if (op == CAIRO_OPERATOR_SATURATE ||
op == CAIRO_OPERATOR_SOFT_LIGHT ||
op == CAIRO_OPERATOR_HSL_HUE ||
op == CAIRO_OPERATOR_COLOR_DODGE ||
op == CAIRO_OPERATOR_COLOR_BURN)
{ return CAIRO_INT_STATUS_UNSUPPORTED;
}
/* When the destination has no color components, we can avoid some *fallbacks,butwehavetoworkaroundoperatorswhichbehave
* differently in Quartz. */ if (surface->base.content == CAIRO_CONTENT_ALPHA) {
assert (op != CAIRO_OPERATOR_ATOP); /* filtered by surface layer */
if (op == CAIRO_OPERATOR_SOURCE ||
op == CAIRO_OPERATOR_IN ||
op == CAIRO_OPERATOR_OUT ||
op == CAIRO_OPERATOR_DEST_IN ||
op == CAIRO_OPERATOR_DEST_ATOP ||
op == CAIRO_OPERATOR_XOR)
{ return CAIRO_INT_STATUS_UNSUPPORTED;
}
if (op == CAIRO_OPERATOR_DEST_OVER)
op = CAIRO_OPERATOR_OVER; elseif (op == CAIRO_OPERATOR_SATURATE)
op = CAIRO_OPERATOR_ADD; elseif (op == CAIRO_OPERATOR_COLOR_DODGE)
op = CAIRO_OPERATOR_OVER; elseif (op == CAIRO_OPERATOR_COLOR_BURN)
op = CAIRO_OPERATOR_OVER;
}
case CAIRO_LINE_JOIN_MITER: return kCGLineJoinMiter;
case CAIRO_LINE_JOIN_ROUND: return kCGLineJoinRound;
case CAIRO_LINE_JOIN_BEVEL: return kCGLineJoinBevel;
}
}
staticinline CGInterpolationQuality
_cairo_quartz_filter_to_quartz (cairo_filter_t filter)
{ /* The CGInterpolationQuality enumeration values seem to have the *followingmeaning: *-kCGInterpolationNone:nearestneighbor *-kCGInterpolationLow:bilinear *-kCGInterpolationHigh:bicubic?Lanczos?
*/
switch (filter) { case CAIRO_FILTER_NEAREST: case CAIRO_FILTER_FAST: return kCGInterpolationNone;
case CAIRO_FILTER_BEST: return kCGInterpolationHigh;
case CAIRO_FILTER_GOOD: case CAIRO_FILTER_BILINEAR: return kCGInterpolationLow;
case CAIRO_FILTER_GAUSSIAN: return kCGInterpolationDefault;
/* Quartz computes a small number of samples of the gradient color *function.OnMacOSX10.5itapparentlycomputesonly1024
* samples. */ #define MAX_GRADIENT_RANGE 1024
if (gradient->base.extend == CAIRO_EXTEND_PAD) {
t[0] = MAX (t[0], -0.5);
t[1] = MIN (t[1], 1.5);
} elseif (t[1] - t[0] > MAX_GRADIENT_RANGE) return NULL;
/* set the input range for the function -- the function knows how
to map values outside of 0.0 .. 1.0 to the correct color */
input_value_range[0] = t[0];
input_value_range[1] = t[1];
} else {
input_value_range[0] = 0;
input_value_range[1] = 1;
}
image_data = _cairo_malloc_ab (image_surface->height, image_surface->stride); if (unlikely (!image_data))
{ if (acquired)
_cairo_surface_release_source_image (source, image_surface, image_extra); else
cairo_surface_destroy (&image_surface->base);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
// The last row of data may have less than stride bytes so make sure we // only copy the minimum amount required from that row.
memcpy (image_data, image_surface->data,
(image_surface->height - 1) * image_surface->stride +
cairo_format_stride_for_width (image_surface->format,
image_surface->width));
*image_out = CairoQuartzCreateCGImage (image_surface->format,
image_surface->width,
image_surface->height,
image_surface->stride,
image_data, TRUE,
NULL,
DataProviderReleaseCallback,
image_data);
/* TODO: differentiate memory error and unsupported surface type */ if (unlikely (*image_out == NULL))
status = CAIRO_INT_STATUS_UNSUPPORTED;
if (acquired)
_cairo_surface_release_source_image (source, image_surface, image_extra); else
cairo_surface_destroy (&image_surface->base);
return status;
}
/* Generic #cairo_pattern_t -> CGPattern function */
CGContextDrawImage (context, info->imageBounds, info->image); if (info->do_reflect) { /* draw 3 more copies of the image, flipped. *DrawImagedrawstheimageaccordingtothecurrentY-directionintotherectanglegiven *(imageBounds);atthetimeofthefirstDrawImageabove,theoriginisatthebottomleft *ofthebaseimageposition,andtheYaxisisextendingupwards.
*/
/* Make the y axis extend downwards, and draw a flipped image below */
CGContextScaleCTM (context, 1, -1);
CGContextDrawImage (context, info->imageBounds, info->image);
/* Shift over to the right, and flip vertically (translation is 2x, *sincewe'llbeflippingandthusrenderingtherectangle"backwards"
*/
CGContextTranslateCTM (context, 2 * info->imageBounds.size.width, 0);
CGContextScaleCTM (context, -1, 1);
CGContextDrawImage (context, info->imageBounds, info->image);
/* Then unflip the Y-axis again, and draw the image above the point. */
CGContextScaleCTM (context, 1, -1);
CGContextDrawImage (context, info->imageBounds, info->image);
}
}
/* The pattern matrix is relative to the bottom left, again; the *incomingcairopatternmatrixisrelativetotheupperleft. *Sowetakethepatternmatrixandtheoriginalcontextmatrix, *whichgivesusthecorrectbasetranslation/yflip.
*/
ptransform = CGAffineTransformConcat (stransform, dest->cgContextBaseCTM);
/* Source layer to be rendered when using DO_LAYER. Unlike'layer'above,thisisnotownedbythedrawingstate
but by the source surface. */
CGLayerRef sourceLayer;
} cairo_quartz_drawing_state_t;
/* Quartz seems to tile images at pixel-aligned regions only -- this *leadstoseamsiftheimagedoesn'tendupscalingtofillthe *spaceexactly.TheCGPatterntilingapproachdoesn'thavethis *problem.Checkifwe'regoingtofillupthespace(withinsome *epsilon),andifnot,fallbacktotheCGPatterntype.
*/
if ((fw & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON &&
(fh & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON)
{ /* We're good to use DrawTiledImage, but ensure that
* the math works out */
// let's hope they don't add YUV under us
colorspace = CGBitmapContextGetColorSpace (surface->cgContext);
color_comps = CGColorSpaceGetNumberOfComponents(colorspace);
// XXX TODO: We can handle all of these by converting to // pixman masks, including non-native-endian masks if (bpc != 8) return CAIRO_INT_STATUS_UNSUPPORTED;
if (bpp != 32 && bpp != 8) return CAIRO_INT_STATUS_UNSUPPORTED;
if (color_comps != 3 && color_comps != 1) return CAIRO_INT_STATUS_UNSUPPORTED;
if (IS_EMPTY (surface)) return CAIRO_STATUS_SUCCESS;
/* Restore our saved gstate that we use to reset clipping */
CGContextRestoreGState (surface->cgContext);
_cairo_surface_clipper_reset (&surface->clipper);
/* ClipToMask is essentially drawing an image, so we need to flip the CTM
* to get the image to appear oriented the right way */
CGContextConcatCTM (state.cgMaskContext, CGAffineTransformInvert (mask_matrix));
CGContextTranslateCTM (state.cgMaskContext, 0.0, rect.size.height);
CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
if (! need_temp) {
mask_surf = extents->mask_pattern.surface.surface;
/* When an opaque surface used as a mask in Quartz, its *luminosityisusedasthealphavalue,sowecononlyuse
* surfaces with alpha without creating a temporary mask. */
need_temp = ! (mask_surf->content & CAIRO_CONTENT_ALPHA);
}
if (! need_temp) {
CGInterpolationQuality mask_filter;
cairo_bool_t simple_transform;
/* Quartz only allows one interpolation to be set for mask and *source,sowecanskipthetempsurfaceonlyifthesource
* filtering makes the mask look correct. */ if (source->type == CAIRO_PATTERN_TYPE_SURFACE)
need_temp = ! (simple_transform || filter == mask_filter); else
filter = mask_filter;
}
if (need_temp) { /* Render the mask to a surface */
mask_surf = _cairo_quartz_surface_create_similar (surface,
CAIRO_CONTENT_ALPHA,
surface->extents.width,
surface->extents.height);
status = mask_surf->status; if (unlikely (status)) goto BAIL;
/* mask_surf is clear, so use OVER instead of SOURCE to avoid a
* temporary layer or fallback to cairo-image. */
status = _cairo_surface_paint (mask_surf, CAIRO_OPERATOR_OVER, mask, NULL); if (unlikely (status)) goto BAIL;
cairo_matrix_init_identity (&matrix);
}
status = _cairo_quartz_cg_mask_with_surface (extents,
mask_surf, &matrix, filter);
rv = _cairo_quartz_setup_state (&state, extents); if (unlikely (rv)) goto BAIL;
// Turning antialiasing off used to cause misrendering with // single-pixel lines (e.g. 20,10.5 -> 21,10.5 end up being rendered as 2 pixels). // That's been since fixed in at least 10.5, and in the latest 10.4 dot releases.
CGContextSetShouldAntialias (state.cgMaskContext, (antialias != CAIRO_ANTIALIAS_NONE));
CGContextSetLineWidth (state.cgMaskContext, style->line_width);
CGContextSetLineCap (state.cgMaskContext, _cairo_quartz_cairo_line_cap_to_quartz (style->line_cap));
CGContextSetLineJoin (state.cgMaskContext, _cairo_quartz_cairo_line_join_to_quartz (style->line_join));
CGContextSetMiterLimit (state.cgMaskContext, style->miter_limit);
/* Convert glyph positions to glyph advances. */
cg_glyphs[0] = glyphs[0].index; for (i = 1; i < num_glyphs; i++) {
CGSize advance = CGSizeMake (glyphs[i].x - glyphs[i-1].x,
glyphs[i].y - glyphs[i-1].y);
cg_advances[i] = CGSizeApplyAffineTransform (advance, invTextTransform);
cg_glyphs[i] = glyphs[i].index;
}
if (CTFontDrawGlyphsPtr) { /* If CTFontDrawGlyphs is available, we want to use that *insteadofthedeprecatedCGContextShowGlyphsWithAdvances *sothatcolored-bitmapfontslikeAppleColorEmojiwill
* render properly. */
/* Accumulate the glyph advances into glyph positions, *overwritingthem.Startat(0,0)becausetheCTMalready
* takes into account the position of the first glyph. */
CGPoint pos = CGPointMake (0, 0);
cg_positions = (CGPoint *) cg_advances;
cg_positions[0] = pos; for (i = 1; i < num_glyphs; i++) {
pos.x += cg_advances[i].width;
pos.y += cg_advances[i].height;
cg_positions[i] = pos;
}
/* Revert the changes to the CTM. This fragment cannot rely on
* CG{Save,Restore}GState, as that would reset the clip. */
CGContextConcatCTM (state.cgMaskContext, invTextTransform);
CGContextTranslateCTM (state.cgMaskContext, -glyphs[0].x, -glyphs[0].y);
if (state.action != DO_DIRECT)
_cairo_quartz_draw_source (&state, extents->op);
BAIL: if (didForceFontSmoothing)
CGContextSetAllowsFontSmoothingPtr (state.cgMaskContext, FALSE);
_cairo_quartz_teardown_state (&state, extents);
if (cg_advances != cg_advances_static)
free (cg_advances);
if (IS_EMPTY (surface))
return CAIRO_STATUS_SUCCESS;
if (path == NULL) {
/* If we're being asked to reset the clip, we can only do it
* by restoring the gstate to our previous saved one, and
* saving it again.
*
* Note that this assumes that ALL quartz surface creation
* functions will do a SaveGState first; we do this in create_internal.
*/
CGContextRestoreGState (surface->cgContext);
CGContextSaveGState (surface->cgContext);
} else {
CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
if (fill_rule == CAIRO_FILL_RULE_WINDING)
CGContextClip (surface->cgContext); else
CGContextEOClip (surface->cgContext);
}
ND ((stderr, "-- intersect_clip_path\n"));
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_quartz_surface_link (cairo_quartz_surface_t *surface,
cairo_bool_t begin,
const char *attributes)
{
cairo_link_attrs_t link_attrs;
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
int i, num_rects;
/* We only process the 'begin' tag, and expect a rect attribute;
using the extents of the drawing operations enclosed by the begin/end
link tags to define the clickable area is not implemented. */ if (!begin)
return status;
status = _cairo_tag_parse_link_attributes (attributes, &link_attrs); if (unlikely (status))
return status;
num_rects = _cairo_array_num_elements (&link_attrs.rects); if (num_rects > 0) {
/* Create either a named destination or a URL, depending which is present
in the link attributes. */
CFURLRef url = NULL;
CFStringRef name = NULL; if (link_attrs.dest && *link_attrs.dest)
name = CFStringCreateWithBytes (kCFAllocatorDefault,
(const UInt8 *) link_attrs.dest,
strlen (link_attrs.dest),
kCFStringEncodingUTF8,
FALSE); elseif (link_attrs.uri && *link_attrs.uri)
url = CFURLCreateWithBytes (NULL,
(const UInt8 *) link_attrs.uri,
strlen (link_attrs.uri),
kCFStringEncodingUTF8,
NULL); else /* silently ignore link that doesn't have a usable target */
goto cleanup;
for (i = 0; i < num_rects; i++) {
CGRect link_rect;
cairo_rectangle_t rectf;
_cairo_array_copy_element (&link_attrs.rects, i, &rectf);
/* Currently the only tags we support are CAIRO_TAG_LINK and CAIRO_TAG_DEST */ if (!strcmp (tag_name, CAIRO_TAG_LINK))
return _cairo_quartz_surface_link (surface, begin, attributes);
if (!strcmp (tag_name, CAIRO_TAG_DEST))
return _cairo_quartz_surface_dest (surface, begin, attributes);
/* Unknown tag names are silently ignored here. */
return CAIRO_INT_STATUS_SUCCESS;
}
// XXXtodo implement show_page; need to figure out how to handle begin/end
/* Save so we can always get back to a known-good CGContext -- this is
* required for proper behaviour of intersect_clip_path(NULL)
*/
CGContextSaveGState (cgContext);
/**
* cairo_quartz_surface_create_for_cg_context:
* @cgContext: the existing CGContext for which to create the surface
* @width: width of the surface, in pixels
* @height: height of the surface, in pixels
*
* Creates a Quartz surface that wraps the given CGContext. The
* CGContext is assumed to be in the standard Cairo coordinate space
* (that is, with the origin at the upper left and the Y axis
* increasing downward). If the CGContext is in the Quartz coordinate
* space (with the origin at the bottom left), then it should be
* flipped before this function is called. The flip can be accomplished
* using a translate and a scale; for example:
*
* <informalexample><programlisting>
* CGContextTranslateCTM (cgContext, 0.0, height);
* CGContextScaleCTM (cgContext, 1.0, -1.0);
* </programlisting></informalexample>
*
* All Cairo operations are implemented in terms of Quartz operations,
* as long as Quartz-compatible elements are used (such as Quartz fonts).
*
* Return value: the newly created Cairo surface.
*
* Since: 1.6
**/
cairo_surface_t *
cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext,
unsigned int width,
unsigned int height)
{
cairo_quartz_surface_t *surf;
/**
* cairo_quartz_surface_create_cg_layer
* @surface: The returned surface can be efficiently drawn into this
* destination surface (if tiling is not used)."
* @content: the content type of the surface
* @width: width of the surface, in pixels
* @height: height of the surface, in pixels
*
* Creates a Quartz surface backed by a CGLayer, if the given surface
* is a Quartz surface; the CGLayer is created to match the surface's
* Quartz context. Otherwise just calls cairo_surface_create_similar.
* The returned surface can be efficiently blitted to the given surface,
* but tiling and 'extend' modes other than NONE are not so efficient.
*
* Return value: the newly created surface.
*
* Since: 1.10
**/
cairo_surface_t *
cairo_quartz_surface_create_cg_layer (cairo_surface_t *surface,
cairo_content_t content,
unsigned int width,
unsigned int height)
{
cairo_quartz_surface_t *surf;
CGLayerRef layer;
CGContextRef ctx;
CGContextRef cgContext;
if (!_cairo_quartz_verify_surface_size(width, height))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
/* If we pass zero width or height into CGLayerCreateWithContext below,
* it will fail.
*/ if (width == 0 || height == 0) {
return (cairo_surface_t*)
_cairo_quartz_surface_create_internal (NULL, content,
width, height);
}
ctx = CGLayerGetContext (layer);
/* Flip it when we draw into it, so that when we finally composite it
* to a flipped target, the directions match and Quartz will optimize
* the composition properly
*/
CGContextTranslateCTM (ctx, 0, height);
CGContextScaleCTM (ctx, 1, -1);
CGContextRetain (ctx);
surf = _cairo_quartz_surface_create_internal (ctx, content,
width, height); if (surf->base.status) {
CGLayerRelease (layer);
// create_internal will have set an error
return (cairo_surface_t*) surf;
}
surf->cgLayer = layer;
return (cairo_surface_t *) surf;
}
/**
* cairo_quartz_surface_create:
* @format: format of pixels in the surface to create
* @width: width of the surface, in pixels
* @height: height of the surface, in pixels
*
* Creates a Quartz surface backed by a CGBitmap. The surface is
* created using the Device RGB (or Device Gray, for A8) color space.
* All Cairo operations, including those that require software
* rendering, will succeed on this surface.
*
* Return value: the newly created surface.
*
* Since: 1.6
**/
cairo_surface_t *
cairo_quartz_surface_create (cairo_format_t format,
unsigned int width,
unsigned int height)
{
cairo_quartz_surface_t *surf;
CGContextRef cgc;
CGColorSpaceRef cgColorspace;
CGBitmapInfo bitinfo;
void *imageData;
int stride;
int bitsPerComponent;
if (!_cairo_quartz_verify_surface_size (width, height))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
if (format == CAIRO_FORMAT_ARGB32 ||
format == CAIRO_FORMAT_RGB24)
{
cgColorspace = CGColorSpaceCreateDeviceRGB ();
bitinfo = kCGBitmapByteOrder32Host; if (format == CAIRO_FORMAT_ARGB32)
bitinfo |= kCGImageAlphaPremultipliedFirst; else
bitinfo |= kCGImageAlphaNoneSkipFirst;
bitsPerComponent = 8;
stride = width * 4;
} elseif (format == CAIRO_FORMAT_A8) {
cgColorspace = NULL;
stride = width;
bitinfo = kCGImageAlphaOnly;
bitsPerComponent = 8;
} elseif (format == CAIRO_FORMAT_A1) {
/* I don't think we can usefully support this, as defined by
* cairo_format_t -- these are 1-bit pixels stored in 32-bit
* quantities.
*/
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
} else {
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
}
/* The Apple docs say that for best performance, the stride and the data
* pointer should be 16-byte aligned. malloc already aligns to 16-bytes,
* so we don't have to anything special on allocation.
*/
stride = (stride + 15) & ~15;
if (!cgc) {
free (imageData);
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
/* flip the Y axis */
CGContextTranslateCTM (cgc, 0.0, height);
CGContextScaleCTM (cgc, 1.0, -1.0);
surf = _cairo_quartz_surface_create_internal (cgc, _cairo_content_from_format (format),
width, height); if (surf->base.status) {
CGContextRelease (cgc);
free (imageData);
// create_internal will have set an error
return &surf->base;
}
// We created this data, so we can delete it.
surf->ownsData = TRUE;
return &surf->base;
}
/**
* cairo_quartz_surface_get_cg_context:
* @surface: the Cairo Quartz surface
*
* Returns the CGContextRef that the given Quartz surface is backed
* by.
*
* A call to cairo_surface_flush() is required before using the
* CGContextRef to ensure that all pending drawing operations are
* finished and to restore any temporary modification cairo has made
* to its state. A call to cairo_surface_mark_dirty() is required
* after the state or the content of the CGContextRef has been
* modified.
*
* Return value: the CGContextRef for the given surface.
*
* Since: 1.6
**/
CGContextRef
cairo_quartz_surface_get_cg_context (cairo_surface_t *surface)
{ if (surface && _cairo_surface_is_quartz (surface)) {
cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t *) surface;
return quartz->cgContext;
} else
return NULL;
}
/**
* _cairo_surface_is_quartz:
* @surface: a #cairo_surface_t
*
* Checks if a surface is a #cairo_quartz_surface_t
*
* Return value: True if the surface is an quartz surface
**/
cairo_bool_t
_cairo_surface_is_quartz (const cairo_surface_t *surface)
{
return surface->backend == &cairo_quartz_surface_backend;
}
GraphicsExportComponent grex = 0;
unsigned long sizeWritten;
ComponentResult result;
// create the data reference
result = QTNewDataReferenceFromFullPathCFString (inPath, kQTNativeDefaultPathStyle, 0, &dataRef, &dataRefType);
if (NULL != dataRef && noErr == result) {
// get the PNG exporter
result = OpenADefaultComponent (GraphicsExporterComponentType, kQTFileTypePNG,
&grex);
if (grex) {
// tell the exporter where to find its source image
result = GraphicsExportSetInputCGImage (grex, inImageRef);
if (noErr == result) {
// tell the exporter where to save the exporter image
result = GraphicsExportSetOutputDataReference (grex, dataRef,
dataRefType);
if (noErr == result) {
// write the PNG file
result = GraphicsExportDoExport (grex, &sizeWritten);
}
}
// remember to close the component
CloseComponent (grex);
}
// remember to dispose of the data reference handle
DisposeHandle (dataRef);
}
}
if (dest == NULL) {
fprintf (stderr, "** Writing %p to foo%d\n", nq, sctr);
sprintf (sptr, "/Users/vladimir/Desktop/foo%d.png", sctr);
sctr++;
dest = sptr;
}
CGImageRef imgref = CGBitmapContextCreateImage (nq->cgContext); if (imgref == NULL) {
fprintf (stderr, "quartz surface at %p is not a bitmap context!\n", nq);
return;
}
ExportCGImageToPNGFile (imgref, dest);
CGImageRelease (imgref);
}
#endif /* QUARTZ_DEBUG */
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.118Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.