1 // Copyright 2015 The Servo Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9 
10 use base::CGFloat;
11 use color_space::CGColorSpace;
12 use core_foundation::base::{CFTypeID, TCFType};
13 use font::{CGFont, CGGlyph};
14 use geometry::{CGPoint, CGSize};
15 use gradient::{CGGradient, CGGradientDrawingOptions};
16 use color::CGColor;
17 use path::CGPathRef;
18 use libc::{c_int, size_t};
19 use std::os::raw::c_void;
20 
21 use std::cmp;
22 use std::ptr;
23 use std::slice;
24 use geometry::{CGAffineTransform, CGRect};
25 use image::CGImage;
26 use foreign_types::{ForeignType, ForeignTypeRef};
27 
28 #[repr(C)]
29 #[derive(Clone, Copy, Debug)]
30 pub enum CGBlendMode {
31     Normal = 0,
32     Multiply,
33     Screen,
34     Overlay,
35     Darken,
36     Lighten,
37     ColorDodge,
38     ColorBurn,
39     SoftLight,
40     HardLight,
41     Difference,
42     Exclusion,
43     Hue,
44     Saturation,
45     Color,
46     Luminosity,
47     // 10.5 and up:
48     Clear,
49     Copy,
50     SourceIn,
51     SourceOut,
52     SourceAtop,
53     DestinationOver,
54     DestinationIn,
55     DestinationOut,
56     DestinationAtop,
57     Xor,
58     PlusDarker,
59     PlusLighter,
60 }
61 
62 #[repr(C)]
63 pub enum CGTextDrawingMode {
64     CGTextFill,
65     CGTextStroke,
66     CGTextFillStroke,
67     CGTextInvisible,
68     CGTextFillClip,
69     CGTextStrokeClip,
70     CGTextFillStrokeClip,
71     CGTextClip
72 }
73 
74 #[repr(C)]
75 #[derive(Clone, Copy, Debug)]
76 pub enum CGLineCap {
77     CGLineCapButt,
78     CGLineCapRound,
79     CGLineCapSquare,
80 }
81 
82 #[repr(C)]
83 #[derive(Clone, Copy, Debug)]
84 pub enum CGLineJoin {
85     CGLineJoinMiter,
86     CGLineJoinRound,
87     CGLineJoinBevel,
88 }
89 
90 #[repr(C)]
91 #[derive(Clone, Copy, Debug)]
92 pub enum CGPathDrawingMode {
93     CGPathFill,
94     CGPathEOFill,
95     CGPathStroke,
96     CGPathFillStroke,
97     CGPathEOFillStroke,
98 }
99 
100 #[repr(C)]
101 #[derive(Clone, Copy, Debug)]
102 pub enum CGInterpolationQuality {
103     CGInterpolationQualityDefault,
104     CGInterpolationQualityNone,
105     CGInterpolationQualityLow,
106     CGInterpolationQualityMedium,
107     CGInterpolationQualityHigh,
108 }
109 
110 foreign_type! {
111     #[doc(hidden)]
112     type CType = ::sys::CGContext;
113     fn drop = |cs| CGContextRelease(cs);
114     fn clone = |p| CGContextRetain(p);
115     pub struct CGContext;
116     pub struct CGContextRef;
117 }
118 
119 impl CGContext {
type_id() -> CFTypeID120     pub fn type_id() -> CFTypeID {
121         unsafe {
122             CGContextGetTypeID()
123         }
124     }
125 
126     /// Creates a `CGContext` instance from an existing [`CGContextRef`] pointer.
127     ///
128     /// This funtion will internally call [`CGRetain`] and hence there is no need to call it explicitly.
129     ///
130     /// This function is particularly useful for cases when the context is not instantiated/managed
131     /// by the caller, but it's retrieve via other means (e.g., by calling the method [`NSGraphicsContext::CGContext`]
132     /// in a cocoa application).
133     ///
134     /// [`CGContextRef`]: https://developer.apple.com/documentation/coregraphics/cgcontextref
135     /// [`CGRetain`]: https://developer.apple.com/documentation/coregraphics/1586506-cgcontextretain
136     /// [`NSGraphicsContext::CGContext`]: https://developer.apple.com/documentation/appkit/nsgraphicscontext/1535352-currentcontext
from_existing_context_ptr(ctx: *mut ::sys::CGContext) -> CGContext137     pub unsafe fn from_existing_context_ptr(ctx: *mut ::sys::CGContext) -> CGContext {
138         CGContextRetain(ctx);
139         Self::from_ptr(ctx)
140     }
141 
create_bitmap_context(data: Option<*mut c_void>, width: size_t, height: size_t, bits_per_component: size_t, bytes_per_row: size_t, space: &CGColorSpace, bitmap_info: u32) -> CGContext142     pub fn create_bitmap_context(data: Option<*mut c_void>,
143                                  width: size_t,
144                                  height: size_t,
145                                  bits_per_component: size_t,
146                                  bytes_per_row: size_t,
147                                  space: &CGColorSpace,
148                                  bitmap_info: u32)
149                                  -> CGContext {
150         unsafe {
151             let result = CGBitmapContextCreate(data.unwrap_or(ptr::null_mut()),
152                                                width,
153                                                height,
154                                                bits_per_component,
155                                                bytes_per_row,
156                                                space.as_ptr(),
157                                                bitmap_info);
158             assert!(!result.is_null());
159             Self::from_ptr(result)
160         }
161     }
162 
data(&mut self) -> &mut [u8]163     pub fn data(&mut self) -> &mut [u8] {
164         unsafe {
165             slice::from_raw_parts_mut(
166                     CGBitmapContextGetData(self.as_ptr()) as *mut u8,
167                     (self.height() * self.bytes_per_row()) as usize)
168         }
169     }
170 }
171 
172 impl CGContextRef {
flush(&self)173     pub fn flush(&self) {
174         unsafe {
175             CGContextFlush(self.as_ptr())
176         }
177     }
178 
width(&self) -> size_t179     pub fn width(&self) -> size_t {
180         unsafe {
181             CGBitmapContextGetWidth(self.as_ptr())
182         }
183     }
184 
height(&self) -> size_t185     pub fn height(&self) -> size_t {
186         unsafe {
187             CGBitmapContextGetHeight(self.as_ptr())
188         }
189     }
190 
bytes_per_row(&self) -> size_t191     pub fn bytes_per_row(&self) -> size_t {
192         unsafe {
193             CGBitmapContextGetBytesPerRow(self.as_ptr())
194         }
195     }
196 
clip_bounding_box(&self) -> CGRect197     pub fn clip_bounding_box(&self) -> CGRect {
198         unsafe {
199             CGContextGetClipBoundingBox(self.as_ptr())
200         }
201     }
202 
set_fill_color(&self, color: &CGColor)203     pub fn set_fill_color(&self, color: &CGColor) {
204         unsafe {
205             CGContextSetFillColorWithColor(self.as_ptr(), color.as_concrete_TypeRef());
206         }
207     }
208 
set_rgb_fill_color(&self, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)209     pub fn set_rgb_fill_color(&self, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
210         unsafe {
211             CGContextSetRGBFillColor(self.as_ptr(), red, green, blue, alpha)
212         }
213     }
214 
set_rgb_stroke_color(&self, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)215     pub fn set_rgb_stroke_color(&self, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
216         unsafe {
217             CGContextSetRGBStrokeColor(self.as_ptr(), red, green, blue, alpha)
218         }
219     }
220 
set_gray_fill_color(&self, gray: CGFloat, alpha: CGFloat)221     pub fn set_gray_fill_color(&self, gray: CGFloat, alpha: CGFloat) {
222         unsafe {
223             CGContextSetGrayFillColor(self.as_ptr(), gray, alpha)
224         }
225     }
226 
set_blend_mode(&self, blend_mode: CGBlendMode)227     pub fn set_blend_mode(&self, blend_mode: CGBlendMode) {
228         unsafe {
229             CGContextSetBlendMode(self.as_ptr(), blend_mode)
230         }
231     }
232 
set_allows_font_smoothing(&self, allows_font_smoothing: bool)233     pub fn set_allows_font_smoothing(&self, allows_font_smoothing: bool) {
234         unsafe {
235             CGContextSetAllowsFontSmoothing(self.as_ptr(), allows_font_smoothing)
236         }
237     }
238 
set_font_smoothing_style(&self, style: i32)239     pub fn set_font_smoothing_style(&self, style: i32) {
240         unsafe {
241             CGContextSetFontSmoothingStyle(self.as_ptr(), style as _);
242         }
243     }
244 
set_should_smooth_fonts(&self, should_smooth_fonts: bool)245     pub fn set_should_smooth_fonts(&self, should_smooth_fonts: bool) {
246         unsafe {
247             CGContextSetShouldSmoothFonts(self.as_ptr(), should_smooth_fonts)
248         }
249     }
250 
set_allows_antialiasing(&self, allows_antialiasing: bool)251     pub fn set_allows_antialiasing(&self, allows_antialiasing: bool) {
252         unsafe {
253             CGContextSetAllowsAntialiasing(self.as_ptr(), allows_antialiasing)
254         }
255     }
256 
set_should_antialias(&self, should_antialias: bool)257     pub fn set_should_antialias(&self, should_antialias: bool) {
258         unsafe {
259             CGContextSetShouldAntialias(self.as_ptr(), should_antialias)
260         }
261     }
262 
set_allows_font_subpixel_quantization(&self, allows_font_subpixel_quantization: bool)263     pub fn set_allows_font_subpixel_quantization(&self, allows_font_subpixel_quantization: bool) {
264         unsafe {
265             CGContextSetAllowsFontSubpixelQuantization(self.as_ptr(), allows_font_subpixel_quantization)
266         }
267     }
268 
set_should_subpixel_quantize_fonts(&self, should_subpixel_quantize_fonts: bool)269     pub fn set_should_subpixel_quantize_fonts(&self, should_subpixel_quantize_fonts: bool) {
270         unsafe {
271             CGContextSetShouldSubpixelQuantizeFonts(self.as_ptr(), should_subpixel_quantize_fonts)
272         }
273     }
274 
set_allows_font_subpixel_positioning(&self, allows_font_subpixel_positioning: bool)275     pub fn set_allows_font_subpixel_positioning(&self, allows_font_subpixel_positioning: bool) {
276         unsafe {
277             CGContextSetAllowsFontSubpixelPositioning(self.as_ptr(), allows_font_subpixel_positioning)
278         }
279     }
280 
set_should_subpixel_position_fonts(&self, should_subpixel_position_fonts: bool)281     pub fn set_should_subpixel_position_fonts(&self, should_subpixel_position_fonts: bool) {
282         unsafe {
283             CGContextSetShouldSubpixelPositionFonts(self.as_ptr(), should_subpixel_position_fonts)
284         }
285     }
286 
set_text_drawing_mode(&self, mode: CGTextDrawingMode)287     pub fn set_text_drawing_mode(&self, mode: CGTextDrawingMode) {
288         unsafe {
289             CGContextSetTextDrawingMode(self.as_ptr(), mode)
290         }
291     }
292 
set_line_cap(&self, cap: CGLineCap)293     pub fn set_line_cap(&self, cap: CGLineCap) {
294         unsafe {
295             CGContextSetLineCap(self.as_ptr(), cap)
296         }
297     }
298 
set_line_dash(&self, phase: CGFloat, lengths: &[CGFloat])299     pub fn set_line_dash(&self, phase: CGFloat, lengths: &[CGFloat]) {
300         unsafe {
301             CGContextSetLineDash(self.as_ptr(), phase, lengths.as_ptr(), lengths.len())
302         }
303     }
304 
set_line_join(&self, join: CGLineJoin)305     pub fn set_line_join(&self, join: CGLineJoin) {
306         unsafe {
307             CGContextSetLineJoin(self.as_ptr(), join)
308         }
309     }
310 
set_line_width(&self, width: CGFloat)311     pub fn set_line_width(&self, width: CGFloat) {
312         unsafe {
313             CGContextSetLineWidth(self.as_ptr(), width)
314         }
315     }
316 
set_miter_limit(&self, limit: CGFloat)317     pub fn set_miter_limit(&self, limit: CGFloat) {
318         unsafe {
319             CGContextSetMiterLimit(self.as_ptr(), limit)
320         }
321     }
322 
add_path(&self, path: &CGPathRef)323     pub fn add_path(&self, path: &CGPathRef) {
324         unsafe {
325             CGContextAddPath(self.as_ptr(), path.as_ptr());
326         }
327     }
328 
add_curve_to_point(&self, cp1x: CGFloat, cp1y: CGFloat, cp2x: CGFloat, cp2y: CGFloat, x: CGFloat, y: CGFloat)329     pub fn add_curve_to_point(&self,
330                               cp1x: CGFloat,
331                               cp1y: CGFloat,
332                               cp2x: CGFloat,
333                               cp2y: CGFloat,
334                               x: CGFloat,
335                               y: CGFloat) {
336         unsafe {
337             CGContextAddCurveToPoint(self.as_ptr(),
338                                      cp1x, cp1y,
339                                      cp2x, cp2y,
340                                      x, y);
341         }
342     }
343 
add_quad_curve_to_point(&self, cpx: CGFloat, cpy: CGFloat, x: CGFloat, y: CGFloat)344     pub fn add_quad_curve_to_point(&self,
345                                    cpx: CGFloat,
346                                    cpy: CGFloat,
347                                    x: CGFloat,
348                                    y: CGFloat) {
349         unsafe {
350             CGContextAddQuadCurveToPoint(self.as_ptr(),
351                                          cpx, cpy,
352                                          x, y);
353         }
354     }
355 
add_line_to_point(&self, x: CGFloat, y: CGFloat)356     pub fn add_line_to_point(&self, x: CGFloat, y: CGFloat) {
357         unsafe {
358             CGContextAddLineToPoint(self.as_ptr(), x, y);
359         }
360     }
361 
begin_path(&self)362     pub fn begin_path(&self) {
363          unsafe {
364             CGContextBeginPath(self.as_ptr());
365         }
366     }
367 
close_path(&self)368     pub fn close_path(&self) {
369         unsafe {
370             CGContextClosePath(self.as_ptr());
371         }
372     }
373 
move_to_point(&self, x: CGFloat, y: CGFloat)374     pub fn move_to_point(&self, x: CGFloat, y: CGFloat) {
375         unsafe {
376             CGContextMoveToPoint(self.as_ptr(), x, y);
377         }
378     }
379 
clip(&self)380     pub fn clip(&self) {
381         unsafe {
382             CGContextClip(self.as_ptr());
383         }
384     }
385 
eo_clip(&self)386     pub fn eo_clip(&self) {
387         unsafe {
388             CGContextEOClip(self.as_ptr());
389         }
390     }
391 
draw_path(&self, mode: CGPathDrawingMode)392     pub fn draw_path(&self, mode: CGPathDrawingMode) {
393         unsafe {
394             CGContextDrawPath(self.as_ptr(), mode);
395         }
396     }
397 
fill_path(&self)398     pub fn fill_path(&self) {
399         unsafe {
400             CGContextFillPath(self.as_ptr());
401         }
402     }
403 
eo_fill_path(&self)404     pub fn eo_fill_path(&self) {
405         unsafe {
406             CGContextEOFillPath(self.as_ptr());
407         }
408     }
409 
stroke_path(&self)410     pub fn stroke_path(&self) {
411         unsafe {
412             CGContextStrokePath(self.as_ptr());
413         }
414     }
415 
fill_rect(&self, rect: CGRect)416     pub fn fill_rect(&self, rect: CGRect) {
417         unsafe {
418             CGContextFillRect(self.as_ptr(), rect)
419         }
420     }
421 
fill_rects(&self, rects: &[CGRect])422     pub fn fill_rects(&self, rects: &[CGRect]) {
423         unsafe {
424             CGContextFillRects(self.as_ptr(), rects.as_ptr(), rects.len())
425         }
426     }
427 
clear_rect(&self, rect: CGRect)428     pub fn clear_rect(&self, rect: CGRect) {
429         unsafe {
430             CGContextClearRect(self.as_ptr(), rect)
431         }
432     }
433 
stroke_rect(&self, rect: CGRect)434     pub fn stroke_rect(&self, rect: CGRect) {
435         unsafe {
436             CGContextStrokeRect(self.as_ptr(), rect)
437         }
438     }
439 
stroke_rect_with_width(&self, rect: CGRect, width: CGFloat)440     pub fn stroke_rect_with_width(&self, rect: CGRect, width: CGFloat) {
441         unsafe {
442             CGContextStrokeRectWithWidth(self.as_ptr(), rect, width)
443         }
444     }
445 
clip_to_rect(&self, rect: CGRect)446     pub fn clip_to_rect(&self, rect: CGRect) {
447         unsafe {
448             CGContextClipToRect(self.as_ptr(), rect)
449         }
450     }
451 
clip_to_rects(&self, rects: &[CGRect])452     pub fn clip_to_rects(&self, rects: &[CGRect]) {
453         unsafe {
454             CGContextClipToRects(self.as_ptr(), rects.as_ptr(), rects.len())
455         }
456     }
457 
clip_to_mask(&self, rect: CGRect, image: &CGImage)458     pub fn clip_to_mask(&self, rect: CGRect, image: &CGImage) {
459         unsafe {
460             CGContextClipToMask(self.as_ptr(), rect, image.as_ptr())
461         }
462     }
463 
replace_path_with_stroked_path(&self)464     pub fn replace_path_with_stroked_path(&self) {
465         unsafe {
466             CGContextReplacePathWithStrokedPath(self.as_ptr())
467         }
468     }
469 
fill_ellipse_in_rect(&self, rect: CGRect)470     pub fn fill_ellipse_in_rect(&self, rect: CGRect) {
471         unsafe {
472             CGContextFillEllipseInRect(self.as_ptr(), rect)
473         }
474     }
475 
stroke_ellipse_in_rect(&self, rect: CGRect)476     pub fn stroke_ellipse_in_rect(&self, rect: CGRect) {
477         unsafe {
478             CGContextStrokeEllipseInRect(self.as_ptr(), rect)
479         }
480     }
481 
stroke_line_segments(&self, points: &[CGPoint])482     pub fn stroke_line_segments(&self, points: &[CGPoint]) {
483         unsafe {
484             CGContextStrokeLineSegments(self.as_ptr(), points.as_ptr(), points.len())
485         }
486     }
487 
set_interpolation_quality(&self, quality: CGInterpolationQuality)488     pub fn set_interpolation_quality(&self, quality: CGInterpolationQuality) {
489         unsafe {
490             CGContextSetInterpolationQuality(self.as_ptr(), quality);
491         }
492     }
493 
get_interpolation_quality(&self) -> CGInterpolationQuality494     pub fn get_interpolation_quality(&self) -> CGInterpolationQuality {
495         unsafe {
496             CGContextGetInterpolationQuality(self.as_ptr())
497 
498         }
499     }
500 
draw_image(&self, rect: CGRect, image: &CGImage)501     pub fn draw_image(&self, rect: CGRect, image: &CGImage) {
502         unsafe {
503             CGContextDrawImage(self.as_ptr(), rect, image.as_ptr());
504         }
505     }
506 
create_image(&self) -> Option<CGImage>507     pub fn create_image(&self) -> Option<CGImage> {
508         let image = unsafe { CGBitmapContextCreateImage(self.as_ptr()) };
509         if !image.is_null() {
510             Some(unsafe { CGImage::from_ptr(image) })
511         } else {
512             None
513         }
514     }
515 
set_font(&self, font: &CGFont)516     pub fn set_font(&self, font: &CGFont) {
517         unsafe {
518             CGContextSetFont(self.as_ptr(), font.as_ptr())
519         }
520     }
521 
set_font_size(&self, size: CGFloat)522     pub fn set_font_size(&self, size: CGFloat) {
523         unsafe {
524             CGContextSetFontSize(self.as_ptr(), size)
525         }
526     }
527 
set_text_matrix(&self, t: &CGAffineTransform)528     pub fn set_text_matrix(&self, t: &CGAffineTransform) {
529         unsafe {
530             CGContextSetTextMatrix(self.as_ptr(), *t)
531         }
532     }
533 
set_text_position(&self, x: CGFloat, y: CGFloat)534     pub fn set_text_position(&self, x: CGFloat, y: CGFloat) {
535         unsafe {
536             CGContextSetTextPosition(self.as_ptr(), x, y)
537         }
538     }
539 
show_glyphs_at_positions(&self, glyphs: &[CGGlyph], positions: &[CGPoint])540     pub fn show_glyphs_at_positions(&self, glyphs: &[CGGlyph], positions: &[CGPoint]) {
541         unsafe {
542             let count = cmp::min(glyphs.len(), positions.len());
543             CGContextShowGlyphsAtPositions(self.as_ptr(),
544                                            glyphs.as_ptr(),
545                                            positions.as_ptr(),
546                                            count)
547         }
548     }
549 
save(&self)550     pub fn save(&self) {
551         unsafe {
552             CGContextSaveGState(self.as_ptr());
553         }
554     }
555 
restore(&self)556     pub fn restore(&self) {
557         unsafe {
558             CGContextRestoreGState(self.as_ptr());
559         }
560     }
561 
translate(&self, tx: CGFloat, ty: CGFloat)562     pub fn translate(&self, tx: CGFloat, ty: CGFloat) {
563         unsafe {
564             CGContextTranslateCTM(self.as_ptr(), tx, ty);
565         }
566     }
567 
scale(&self, sx: CGFloat, sy: CGFloat)568     pub fn scale(&self, sx: CGFloat, sy: CGFloat) {
569         unsafe {
570             CGContextScaleCTM(self.as_ptr(), sx, sy);
571         }
572     }
573 
rotate(&self, angle: CGFloat)574     pub fn rotate(&self, angle: CGFloat) {
575         unsafe {
576             CGContextRotateCTM(self.as_ptr(), angle);
577         }
578     }
579 
get_ctm(&self) -> CGAffineTransform580     pub fn get_ctm(&self) -> CGAffineTransform {
581         unsafe {
582             CGContextGetCTM(self.as_ptr())
583         }
584     }
585 
concat_ctm(&self, transform: CGAffineTransform)586     pub fn concat_ctm(&self, transform: CGAffineTransform) {
587         unsafe {
588             CGContextConcatCTM(self.as_ptr(), transform)
589         }
590     }
591 
draw_linear_gradient(&self, gradient: &CGGradient, start_point: CGPoint, end_point: CGPoint, options: CGGradientDrawingOptions)592     pub fn draw_linear_gradient(&self, gradient: &CGGradient, start_point: CGPoint, end_point: CGPoint, options: CGGradientDrawingOptions) {
593         unsafe {
594             CGContextDrawLinearGradient(self.as_ptr(), gradient.as_ptr(), start_point, end_point, options);
595         }
596     }
597 
draw_radial_gradient(&self, gradient: &CGGradient, start_center: CGPoint, start_radius: CGFloat, end_center: CGPoint, end_radius: CGFloat, options: CGGradientDrawingOptions)598     pub fn draw_radial_gradient(&self, gradient: &CGGradient, start_center: CGPoint, start_radius: CGFloat, end_center: CGPoint, end_radius: CGFloat, options: CGGradientDrawingOptions) {
599         unsafe {
600             CGContextDrawRadialGradient(self.as_ptr(), gradient.as_ptr(), start_center, start_radius, end_center, end_radius, options);
601         }
602     }
603 
set_shadow(&self, offset: CGSize, blur: CGFloat)604     pub fn set_shadow(&self, offset: CGSize, blur: CGFloat) {
605         unsafe {
606             CGContextSetShadow(self.as_ptr(), offset, blur);
607         }
608     }
609 
set_shadow_with_color(&self, offset: CGSize, blur: CGFloat, color: &CGColor)610     pub fn set_shadow_with_color(&self, offset: CGSize, blur: CGFloat, color: &CGColor) {
611         unsafe {
612             CGContextSetShadowWithColor(self.as_ptr(), offset, blur, color.as_concrete_TypeRef());
613         }
614     }
615 }
616 
617 #[test]
create_bitmap_context_test()618 fn create_bitmap_context_test() {
619     use geometry::*;
620 
621     let cs = CGColorSpace::create_device_rgb();
622     let ctx = CGContext::create_bitmap_context(None,
623                                 16, 8,
624                                 8, 0,
625                                 &cs,
626                                 ::base::kCGImageAlphaPremultipliedLast);
627     ctx.set_rgb_fill_color(1.,0.,1.,1.);
628     ctx.set_miter_limit(4.);
629     ctx.fill_rect(CGRect::new(&CGPoint::new(0.,0.), &CGSize::new(8.,8.)));
630     let img = ctx.create_image().unwrap();
631     assert_eq!(16, img.width());
632     assert_eq!(8, img.height());
633     assert_eq!(8, img.bits_per_component());
634     assert_eq!(32, img.bits_per_pixel());
635     let data = img.data();
636     assert_eq!(255, data.bytes()[0]);
637     assert_eq!(0, data.bytes()[1]);
638     assert_eq!(255, data.bytes()[2]);
639     assert_eq!(255, data.bytes()[3]);
640 }
641 
642 #[link(name = "CoreGraphics", kind = "framework")]
643 extern {
CGContextRetain(c: ::sys::CGContextRef) -> ::sys::CGContextRef644     fn CGContextRetain(c: ::sys::CGContextRef) -> ::sys::CGContextRef;
CGContextRelease(c: ::sys::CGContextRef)645     fn CGContextRelease(c: ::sys::CGContextRef);
646 
CGBitmapContextCreate(data: *mut c_void, width: size_t, height: size_t, bitsPerComponent: size_t, bytesPerRow: size_t, space: ::sys::CGColorSpaceRef, bitmapInfo: u32) -> ::sys::CGContextRef647     fn CGBitmapContextCreate(data: *mut c_void,
648                              width: size_t,
649                              height: size_t,
650                              bitsPerComponent: size_t,
651                              bytesPerRow: size_t,
652                              space: ::sys::CGColorSpaceRef,
653                              bitmapInfo: u32)
654                              -> ::sys::CGContextRef;
CGBitmapContextGetData(context: ::sys::CGContextRef) -> *mut c_void655     fn CGBitmapContextGetData(context: ::sys::CGContextRef) -> *mut c_void;
CGBitmapContextGetWidth(context: ::sys::CGContextRef) -> size_t656     fn CGBitmapContextGetWidth(context: ::sys::CGContextRef) -> size_t;
CGBitmapContextGetHeight(context: ::sys::CGContextRef) -> size_t657     fn CGBitmapContextGetHeight(context: ::sys::CGContextRef) -> size_t;
CGBitmapContextGetBytesPerRow(context: ::sys::CGContextRef) -> size_t658     fn CGBitmapContextGetBytesPerRow(context: ::sys::CGContextRef) -> size_t;
CGBitmapContextCreateImage(context: ::sys::CGContextRef) -> ::sys::CGImageRef659     fn CGBitmapContextCreateImage(context: ::sys::CGContextRef) -> ::sys::CGImageRef;
CGContextGetTypeID() -> CFTypeID660     fn CGContextGetTypeID() -> CFTypeID;
CGContextGetClipBoundingBox(c: ::sys::CGContextRef) -> CGRect661     fn CGContextGetClipBoundingBox(c: ::sys::CGContextRef) -> CGRect;
CGContextFlush(c: ::sys::CGContextRef)662     fn CGContextFlush(c: ::sys::CGContextRef);
CGContextSetBlendMode(c: ::sys::CGContextRef, blendMode: CGBlendMode)663     fn CGContextSetBlendMode(c: ::sys::CGContextRef, blendMode: CGBlendMode);
CGContextSetAllowsFontSmoothing(c: ::sys::CGContextRef, allowsFontSmoothing: bool)664     fn CGContextSetAllowsFontSmoothing(c: ::sys::CGContextRef, allowsFontSmoothing: bool);
CGContextSetShouldSmoothFonts(c: ::sys::CGContextRef, shouldSmoothFonts: bool)665     fn CGContextSetShouldSmoothFonts(c: ::sys::CGContextRef, shouldSmoothFonts: bool);
CGContextSetFontSmoothingStyle(c: ::sys::CGContextRef, style: c_int)666     fn CGContextSetFontSmoothingStyle(c: ::sys::CGContextRef, style: c_int);
CGContextSetAllowsAntialiasing(c: ::sys::CGContextRef, allowsAntialiasing: bool)667     fn CGContextSetAllowsAntialiasing(c: ::sys::CGContextRef, allowsAntialiasing: bool);
CGContextSetShouldAntialias(c: ::sys::CGContextRef, shouldAntialias: bool)668     fn CGContextSetShouldAntialias(c: ::sys::CGContextRef, shouldAntialias: bool);
CGContextSetAllowsFontSubpixelQuantization(c: ::sys::CGContextRef, allowsFontSubpixelQuantization: bool)669     fn CGContextSetAllowsFontSubpixelQuantization(c: ::sys::CGContextRef,
670                                                   allowsFontSubpixelQuantization: bool);
CGContextSetShouldSubpixelQuantizeFonts(c: ::sys::CGContextRef, shouldSubpixelQuantizeFonts: bool)671     fn CGContextSetShouldSubpixelQuantizeFonts(c: ::sys::CGContextRef,
672                                                shouldSubpixelQuantizeFonts: bool);
CGContextSetAllowsFontSubpixelPositioning(c: ::sys::CGContextRef, allowsFontSubpixelPositioning: bool)673     fn CGContextSetAllowsFontSubpixelPositioning(c: ::sys::CGContextRef,
674                                                  allowsFontSubpixelPositioning: bool);
CGContextSetShouldSubpixelPositionFonts(c: ::sys::CGContextRef, shouldSubpixelPositionFonts: bool)675     fn CGContextSetShouldSubpixelPositionFonts(c: ::sys::CGContextRef,
676                                                shouldSubpixelPositionFonts: bool);
CGContextSetTextDrawingMode(c: ::sys::CGContextRef, mode: CGTextDrawingMode)677     fn CGContextSetTextDrawingMode(c: ::sys::CGContextRef, mode: CGTextDrawingMode);
CGContextSetFillColorWithColor(c: ::sys::CGContextRef, color: ::sys::CGColorRef)678     fn CGContextSetFillColorWithColor(c: ::sys::CGContextRef, color: ::sys::CGColorRef);
CGContextSetLineCap(c: ::sys::CGContextRef, cap: CGLineCap)679     fn CGContextSetLineCap(c: ::sys::CGContextRef, cap: CGLineCap);
CGContextSetLineDash(c: ::sys::CGContextRef, phase: CGFloat, lengths: *const CGFloat, count: size_t)680     fn CGContextSetLineDash(c: ::sys::CGContextRef, phase: CGFloat, lengths: *const CGFloat, count: size_t);
CGContextSetLineJoin(c: ::sys::CGContextRef, join: CGLineJoin)681     fn CGContextSetLineJoin(c: ::sys::CGContextRef, join: CGLineJoin);
CGContextSetLineWidth(c: ::sys::CGContextRef, width: CGFloat)682     fn CGContextSetLineWidth(c: ::sys::CGContextRef, width: CGFloat);
CGContextSetMiterLimit(c: ::sys::CGContextRef, limit: CGFloat)683     fn CGContextSetMiterLimit(c: ::sys::CGContextRef, limit: CGFloat);
684 
CGContextAddPath(c: ::sys::CGContextRef, path: ::sys::CGPathRef)685     fn CGContextAddPath(c: ::sys::CGContextRef, path: ::sys::CGPathRef);
CGContextAddCurveToPoint(c: ::sys::CGContextRef, cp1x: CGFloat, cp1y: CGFloat, cp2x: CGFloat, cp2y: CGFloat, x: CGFloat, y: CGFloat)686     fn CGContextAddCurveToPoint(c: ::sys::CGContextRef,
687                                 cp1x: CGFloat,
688                                 cp1y: CGFloat,
689                                 cp2x: CGFloat,
690                                 cp2y: CGFloat,
691                                 x: CGFloat,
692                                 y: CGFloat);
CGContextAddQuadCurveToPoint(c: ::sys::CGContextRef, cpx: CGFloat, cpy: CGFloat, x: CGFloat, y: CGFloat)693     fn CGContextAddQuadCurveToPoint(c: ::sys::CGContextRef,
694                                     cpx: CGFloat,
695                                     cpy: CGFloat,
696                                     x: CGFloat,
697                                     y: CGFloat);
CGContextAddLineToPoint(c: ::sys::CGContextRef, x: CGFloat, y: CGFloat)698     fn CGContextAddLineToPoint(c: ::sys::CGContextRef,
699                                x: CGFloat,
700                                y: CGFloat);
CGContextBeginPath(c: ::sys::CGContextRef)701     fn CGContextBeginPath(c: ::sys::CGContextRef);
CGContextClosePath(c: ::sys::CGContextRef)702     fn CGContextClosePath(c: ::sys::CGContextRef);
CGContextMoveToPoint(c: ::sys::CGContextRef, x: CGFloat, y: CGFloat)703     fn CGContextMoveToPoint(c: ::sys::CGContextRef,
704                             x: CGFloat,
705                             y: CGFloat);
CGContextDrawPath(c: ::sys::CGContextRef, mode: CGPathDrawingMode)706     fn CGContextDrawPath(c: ::sys::CGContextRef, mode: CGPathDrawingMode);
CGContextFillPath(c: ::sys::CGContextRef)707     fn CGContextFillPath(c: ::sys::CGContextRef);
CGContextEOFillPath(c: ::sys::CGContextRef)708     fn CGContextEOFillPath(c: ::sys::CGContextRef);
CGContextClip(c: ::sys::CGContextRef)709     fn CGContextClip(c: ::sys::CGContextRef);
CGContextEOClip(c: ::sys::CGContextRef)710     fn CGContextEOClip(c: ::sys::CGContextRef);
CGContextStrokePath(c: ::sys::CGContextRef)711     fn CGContextStrokePath(c: ::sys::CGContextRef);
CGContextSetRGBFillColor(context: ::sys::CGContextRef, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)712     fn CGContextSetRGBFillColor(context: ::sys::CGContextRef,
713                                 red: CGFloat,
714                                 green: CGFloat,
715                                 blue: CGFloat,
716                                 alpha: CGFloat);
CGContextSetRGBStrokeColor(context: ::sys::CGContextRef, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)717     fn CGContextSetRGBStrokeColor(context: ::sys::CGContextRef,
718                                   red: CGFloat,
719                                   green: CGFloat,
720                                   blue: CGFloat,
721                                   alpha: CGFloat);
CGContextSetGrayFillColor(context: ::sys::CGContextRef, gray: CGFloat, alpha: CGFloat)722     fn CGContextSetGrayFillColor(context: ::sys::CGContextRef, gray: CGFloat, alpha: CGFloat);
CGContextClearRect(context: ::sys::CGContextRef, rect: CGRect)723     fn CGContextClearRect(context: ::sys::CGContextRef,
724                           rect: CGRect);
CGContextFillRect(context: ::sys::CGContextRef, rect: CGRect)725     fn CGContextFillRect(context: ::sys::CGContextRef,
726                          rect: CGRect);
CGContextFillRects(context: ::sys::CGContextRef, rects: *const CGRect, count: size_t)727     fn CGContextFillRects(context: ::sys::CGContextRef,
728                           rects: *const CGRect,
729                           count: size_t);
CGContextStrokeRect(context: ::sys::CGContextRef, rect: CGRect)730     fn CGContextStrokeRect(context: ::sys::CGContextRef,
731                            rect: CGRect);
CGContextStrokeRectWithWidth(context: ::sys::CGContextRef, rect: CGRect, width: CGFloat)732     fn CGContextStrokeRectWithWidth(context: ::sys::CGContextRef,
733                                     rect: CGRect,
734                                     width: CGFloat);
CGContextClipToRect(context: ::sys::CGContextRef, rect: CGRect)735     fn CGContextClipToRect(context: ::sys::CGContextRef,
736                            rect: CGRect);
CGContextClipToRects(context: ::sys::CGContextRef, rects: *const CGRect, count: size_t)737     fn CGContextClipToRects(context: ::sys::CGContextRef,
738                             rects: *const CGRect,
739                             count: size_t);
CGContextClipToMask(ctx: ::sys::CGContextRef, rect: CGRect, mask: ::sys::CGImageRef)740     fn CGContextClipToMask(ctx: ::sys::CGContextRef, rect: CGRect, mask: ::sys::CGImageRef);
CGContextReplacePathWithStrokedPath(context: ::sys::CGContextRef)741     fn CGContextReplacePathWithStrokedPath(context: ::sys::CGContextRef);
CGContextFillEllipseInRect(context: ::sys::CGContextRef, rect: CGRect)742     fn CGContextFillEllipseInRect(context: ::sys::CGContextRef,
743                                   rect: CGRect);
CGContextStrokeEllipseInRect(context: ::sys::CGContextRef, rect: CGRect)744     fn CGContextStrokeEllipseInRect(context: ::sys::CGContextRef,
745                                     rect: CGRect);
CGContextStrokeLineSegments(context: ::sys::CGContextRef, points: *const CGPoint, count: size_t)746     fn CGContextStrokeLineSegments(context: ::sys::CGContextRef,
747                                     points: *const CGPoint,
748                                     count: size_t);
CGContextDrawImage(c: ::sys::CGContextRef, rect: CGRect, image: ::sys::CGImageRef)749     fn CGContextDrawImage(c: ::sys::CGContextRef, rect: CGRect, image: ::sys::CGImageRef);
CGContextSetInterpolationQuality(c: ::sys::CGContextRef, quality: CGInterpolationQuality)750     fn CGContextSetInterpolationQuality(c: ::sys::CGContextRef, quality: CGInterpolationQuality);
CGContextGetInterpolationQuality(c: ::sys::CGContextRef) -> CGInterpolationQuality751     fn CGContextGetInterpolationQuality(c: ::sys::CGContextRef) -> CGInterpolationQuality;
CGContextSetFont(c: ::sys::CGContextRef, font: ::sys::CGFontRef)752     fn CGContextSetFont(c: ::sys::CGContextRef, font: ::sys::CGFontRef);
CGContextSetFontSize(c: ::sys::CGContextRef, size: CGFloat)753     fn CGContextSetFontSize(c: ::sys::CGContextRef, size: CGFloat);
CGContextSetTextMatrix(c: ::sys::CGContextRef, t: CGAffineTransform)754     fn CGContextSetTextMatrix(c: ::sys::CGContextRef, t: CGAffineTransform);
CGContextSetTextPosition(c: ::sys::CGContextRef, x: CGFloat, y: CGFloat)755     fn CGContextSetTextPosition(c: ::sys::CGContextRef, x: CGFloat, y: CGFloat);
CGContextShowGlyphsAtPositions(c: ::sys::CGContextRef, glyphs: *const CGGlyph, positions: *const CGPoint, count: size_t)756     fn CGContextShowGlyphsAtPositions(c: ::sys::CGContextRef,
757                                       glyphs: *const CGGlyph,
758                                       positions: *const CGPoint,
759                                       count: size_t);
760 
CGContextSaveGState(c: ::sys::CGContextRef)761     fn CGContextSaveGState(c: ::sys::CGContextRef);
CGContextRestoreGState(c: ::sys::CGContextRef)762     fn CGContextRestoreGState(c: ::sys::CGContextRef);
CGContextTranslateCTM(c: ::sys::CGContextRef, tx: CGFloat, ty: CGFloat)763     fn CGContextTranslateCTM(c: ::sys::CGContextRef, tx: CGFloat, ty: CGFloat);
CGContextScaleCTM(c: ::sys::CGContextRef, sx: CGFloat, sy: CGFloat)764     fn CGContextScaleCTM(c: ::sys::CGContextRef, sx: CGFloat, sy: CGFloat);
CGContextRotateCTM(c: ::sys::CGContextRef, angle: CGFloat)765     fn CGContextRotateCTM(c: ::sys::CGContextRef, angle: CGFloat);
CGContextGetCTM(c: ::sys::CGContextRef) -> CGAffineTransform766     fn CGContextGetCTM(c: ::sys::CGContextRef) -> CGAffineTransform;
CGContextConcatCTM(c: ::sys::CGContextRef, transform: CGAffineTransform)767     fn CGContextConcatCTM(c: ::sys::CGContextRef, transform: CGAffineTransform);
768 
CGContextDrawLinearGradient(c: ::sys::CGContextRef, gradient: ::sys::CGGradientRef, startPoint: CGPoint, endPoint: CGPoint, options: CGGradientDrawingOptions)769     fn CGContextDrawLinearGradient(c: ::sys::CGContextRef, gradient: ::sys::CGGradientRef, startPoint: CGPoint, endPoint: CGPoint, options: CGGradientDrawingOptions);
CGContextDrawRadialGradient(c: ::sys::CGContextRef, gradient: ::sys::CGGradientRef, startCenter: CGPoint, startRadius: CGFloat, endCenter:CGPoint, endRadius:CGFloat, options: CGGradientDrawingOptions)770     fn CGContextDrawRadialGradient(c: ::sys::CGContextRef, gradient: ::sys::CGGradientRef,  startCenter: CGPoint, startRadius: CGFloat, endCenter:CGPoint, endRadius:CGFloat, options: CGGradientDrawingOptions);
771 
CGContextSetShadow(c: ::sys::CGContextRef, offset: CGSize, blur: CGFloat)772     fn CGContextSetShadow(c: ::sys::CGContextRef, offset: CGSize, blur: CGFloat);
CGContextSetShadowWithColor(c: ::sys::CGContextRef, offset: CGSize, blur: CGFloat, color: ::sys::CGColorRef)773     fn CGContextSetShadowWithColor(c: ::sys::CGContextRef, offset: CGSize, blur: CGFloat, color: ::sys::CGColorRef);
774 }
775 
776