core_graphics/
context.rs

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