Skip to content

Commit 5b155d4

Browse files
committed
Document Context, source and stack functions
1 parent 5e0be5c commit 5b155d4

File tree

1 file changed

+218
-0
lines changed

1 file changed

+218
-0
lines changed

cairo/src/context.rs

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,27 @@ impl fmt::Display for RectangleList {
5959
}
6060
}
6161

62+
/// A drawing context, used to draw on [`Surface`]s.
63+
///
64+
/// [`Context`] is the main entry point for all drawing operations. To acquire a [`Context`], you
65+
/// can create any kind of [`Surface`] (such as [`ImageSurface`] or [`PdfSurface`]), and call
66+
/// [`Context::new`] with the target surface:
67+
///
68+
/// ```
69+
/// use cairo::{Context, Format, ImageSurface};
70+
///
71+
/// let surface = ImageSurface::create(Format::ARgb32, 100, 100).unwrap();
72+
/// let ctx = Context::new(&surface).unwrap();
73+
///
74+
/// // paint the background black
75+
/// ctx.set_source_rgb(0.0, 0.0, 0.0);
76+
/// ctx.paint();
77+
///
78+
/// // etc.
79+
/// ```
80+
///
81+
/// [`ImageSurface`]: crate::ImageSurface
82+
/// [`PdfSurface`]: crate::PdfSurface
6283
#[derive(Debug)]
6384
#[repr(transparent)]
6485
pub struct Context(ptr::NonNull<cairo_t>);
@@ -163,74 +184,270 @@ impl Context {
163184
self.0.as_ptr()
164185
}
165186

187+
/// Checks whether an error has previously occurred for this context.
188+
///
189+
/// Refer to [`Error`] for an exhaustive list of error codes.
166190
#[doc(alias = "cairo_status")]
167191
#[inline]
168192
pub fn status(&self) -> Result<(), Error> {
169193
let status = unsafe { ffi::cairo_status(self.0.as_ptr()) };
170194
status_to_result(status)
171195
}
172196

197+
/// Creates a new [`Context`] with default graphics state parameters, for drawing to a target
198+
/// [`Surface`].
173199
pub fn new(target: impl AsRef<Surface>) -> Result<Context, Error> {
174200
let ctx = unsafe { Self::from_raw_full(ffi::cairo_create(target.as_ref().to_raw_none())) };
175201
ctx.status().map(|_| ctx)
176202
}
177203

204+
/// Makes a copy of the current state of the [`Context`], saving it in an internal stack of
205+
/// saved states for the [`Context`]. When [`Context::restore`] is called, this context will be
206+
/// restored to the saved state.
207+
///
208+
/// Multiple calls to [`Context::save`] and [`Context::restore`] can be nested; each call to
209+
/// [`Context::restore`] restores the state from the matching paired [`Context::save`].
210+
///
211+
/// # Examples
212+
///
213+
/// ```
214+
/// # fn main() -> Result<(), cairo::Error> {
215+
/// use cairo::{Context, Format, ImageSurface};
216+
///
217+
/// let surface = ImageSurface::create(Format::ARgb32, 100, 100).unwrap();
218+
/// let ctx = Context::new(&surface).unwrap();
219+
///
220+
/// // set source to red
221+
/// ctx.set_source_rgb(1.0, 0.0, 0.0);
222+
///
223+
/// // this block scope is not necessary, but can help with visualizing what happens
224+
/// {
225+
/// // save current state
226+
/// ctx.save()?;
227+
///
228+
/// // set source to white
229+
/// ctx.set_source_rgb(1.0, 1.0, 1.0);
230+
///
231+
/// // shift origin in canvas space, to (50, 50)
232+
/// ctx.translate(50.0, 50.0);
233+
///
234+
/// // draw a white square with its upper-left corner at (0, 0) in canvas space
235+
/// // (i.e. at (50, 50) in device space)
236+
/// ctx.rectangle(0.0, 0.0, 20.0, 20.0);
237+
/// ctx.fill()?;
238+
///
239+
/// // restore state, origin back at (0, 0) in canvas space
240+
/// ctx.restore()?;
241+
/// }
242+
///
243+
/// // draw a red square at (0, 0) in canvas and device space
244+
/// ctx.rectangle(0.0, 0.0, 20.0, 20.0);
245+
/// ctx.fill()?;
246+
/// # Ok(())
247+
/// # }
248+
/// ```
178249
#[doc(alias = "cairo_save")]
179250
pub fn save(&self) -> Result<(), Error> {
180251
unsafe { ffi::cairo_save(self.0.as_ptr()) }
181252
self.status()
182253
}
183254

255+
/// Restores the [`Context`] to the state saved by a preceding call to [`Context::save`],
256+
/// removing that state from the stack of saved states.
257+
///
258+
/// See [`Context::save`] for example usage.
184259
#[doc(alias = "cairo_restore")]
185260
pub fn restore(&self) -> Result<(), Error> {
186261
unsafe { ffi::cairo_restore(self.0.as_ptr()) }
187262
self.status()
188263
}
189264

265+
/// Returns the target [`Surface`] for this [`Context`].
190266
#[doc(alias = "get_target")]
191267
#[doc(alias = "cairo_get_target")]
192268
pub fn target(&self) -> Surface {
193269
unsafe { Surface::from_raw_none(ffi::cairo_get_target(self.0.as_ptr())) }
194270
}
195271

272+
/// Temporarily redirects drawing to an intermediate surface, known as a group, with a default
273+
/// content type of [`Content::ColorAlpha`]. The redirection lasts until the group is completed
274+
/// by a call to [`Context::pop_group`] / [`Context::pop_group_to_source`].
275+
///
276+
/// This can be convenient for performing intermediate compositing. A common use of a group is
277+
/// to render objects as opaque within the group (so that they occlude each other), and then
278+
/// blend the result with translucence onto the destination.
279+
///
280+
/// Groups can be nested arbitrarily deep by making balanced calls to [`Context::push_group`] /
281+
/// [`Context::pop_group`]. Each call pushes / pops the new target group onto / from a stack.
282+
///
283+
/// This function calls [`Context::save`] so that any changes to the graphics state will not be
284+
/// visible outside the group. ([`Context::pop_group`] functions call [`Context::restore`])
285+
///
286+
/// # Examples
287+
///
288+
/// TODO: make a nice example here
196289
#[doc(alias = "cairo_push_group")]
197290
pub fn push_group(&self) {
198291
unsafe { ffi::cairo_push_group(self.0.as_ptr()) }
199292
}
200293

294+
/// Temporarily redirects drawing to an intermediate surface, known as a group, with the given
295+
/// content type. The redirection lasts until the group is completed by a call to
296+
/// [`Context::pop_group`] / [`Context::pop_group_to_source`].
297+
///
298+
/// See [`Context::push_group`] for more details.
201299
#[doc(alias = "cairo_push_group_with_content")]
202300
pub fn push_group_with_content(&self, content: Content) {
203301
unsafe { ffi::cairo_push_group_with_content(self.0.as_ptr(), content.into()) }
204302
}
205303

304+
/// Terminates the redirection begun by a call to [`Context::push_group`] or
305+
/// [`Context::push_group_with_content`] and returns a new [`Pattern`] containing the results
306+
/// of all drawing operations performed on the group.
307+
///
308+
/// This function calls [`Context::restore`] so that any changes to the graphics state will not
309+
/// be visible outside the group.
310+
///
311+
/// # Examples
312+
///
313+
/// TODO: make a nice example here
206314
#[doc(alias = "cairo_pop_group")]
207315
pub fn pop_group(&self) -> Result<Pattern, Error> {
208316
let pattern = unsafe { Pattern::from_raw_full(ffi::cairo_pop_group(self.0.as_ptr())) };
209317
self.status().map(|_| pattern)
210318
}
211319

320+
/// Terminates the redirection begun by a call to [`Context::push_group`] or
321+
/// [`Context::push_group_with_content`]. The results of the drawing operations are then used
322+
/// as the source pattern for this [`Context`].
323+
///
324+
/// This function calls [`Context::restore`] so that any changes to the graphics state will not
325+
/// be visible outside the group.
326+
///
327+
/// # Examples
328+
///
329+
/// TODO: make a nice example here
212330
#[doc(alias = "cairo_pop_group_to_source")]
213331
pub fn pop_group_to_source(&self) -> Result<(), Error> {
214332
unsafe { ffi::cairo_pop_group_to_source(self.0.as_ptr()) };
215333
self.status()
216334
}
217335

336+
/// Gets the current destination surface for the [`Context`].
337+
///
338+
/// This is either the original target surface as passed to [`Context::new`], or the target
339+
/// surface for the current group as started by the most recent call to [`Context::push_group`]
340+
/// / [`Context::push_group_with_content`].
218341
#[doc(alias = "get_group_target")]
219342
#[doc(alias = "cairo_get_group_target")]
220343
pub fn group_target(&self) -> Surface {
221344
unsafe { Surface::from_raw_none(ffi::cairo_get_group_target(self.0.as_ptr())) }
222345
}
223346

347+
/// Sets this [`Context`]'s source pattern to an opaque color. This opaque color will be used
348+
/// for any subsequent drawing operation.
349+
///
350+
/// The color components are floating point numbers in the range `0.0..=1.0`. If the given
351+
/// values are outside that range, they will be clamped.
352+
///
353+
/// The default source pattern is an opaque black `(0.0, 0.0, 0.0)`.
354+
///
355+
/// # Examples
356+
///
357+
/// ```
358+
/// # fn main() -> Result<(), cairo::Error> {
359+
/// use cairo::{Context, Format, ImageSurface};
360+
///
361+
/// let surface = ImageSurface::create(Format::ARgb32, 100, 100).unwrap();
362+
/// let ctx = Context::new(&surface).unwrap();
363+
///
364+
/// // paint the background black
365+
/// ctx.paint()?;
366+
///
367+
/// // draw a red circle centered at (50, 50)
368+
/// ctx.set_source_rgb(1.0, 0.0, 0.0);
369+
/// ctx.arc(50.0, 50.0, 20.0, 0.0, std::f64::consts::TAU);
370+
/// ctx.fill()?;
371+
/// # Ok(())
372+
/// # }
373+
/// ```
224374
#[doc(alias = "cairo_set_source_rgb")]
225375
pub fn set_source_rgb(&self, red: f64, green: f64, blue: f64) {
226376
unsafe { ffi::cairo_set_source_rgb(self.0.as_ptr(), red, green, blue) }
227377
}
228378

379+
/// Sets this [`Context`]'s source pattern to a translucent color. This translucent color will
380+
/// be used for any subsequent drawing operation.
381+
///
382+
/// The color and alpha components are floating point numbers in the range `0.0..=1.0`. If the
383+
/// given values are outside that range, they will be clamped.
384+
///
385+
/// The default source pattern is an opaque black `(0.0, 0.0, 0.0, 1.0)`.
386+
///
387+
/// # Examples
388+
///
389+
/// ```
390+
/// # fn main() -> Result<(), cairo::Error> {
391+
/// use cairo::{Context, Format, ImageSurface};
392+
///
393+
/// let surface = ImageSurface::create(Format::ARgb32, 100, 100).unwrap();
394+
/// let ctx = Context::new(&surface).unwrap();
395+
///
396+
/// // paint the background black
397+
/// ctx.paint()?;
398+
///
399+
/// // draw a red circle centered at (50, 50)
400+
/// ctx.set_source_rgb(1.0, 0.0, 0.0);
401+
/// ctx.arc(50.0, 50.0, 20.0, 0.0, std::f64::consts::TAU);
402+
/// ctx.fill()?;
403+
///
404+
/// // draw a translucent blue square on top of the circle
405+
/// ctx.set_source_rgba(0.0, 0.0, 1.0, 0.5);
406+
/// ctx.rectangle(30.0, 30.0, 40.0, 40.0);
407+
/// ctx.fill()?;
408+
/// # Ok(())
409+
/// # }
410+
/// ```
229411
#[doc(alias = "cairo_set_source_rgba")]
230412
pub fn set_source_rgba(&self, red: f64, green: f64, blue: f64, alpha: f64) {
231413
unsafe { ffi::cairo_set_source_rgba(self.0.as_ptr(), red, green, blue, alpha) }
232414
}
233415

416+
/// Sets this [`Context`]'s source pattern. This source pattern will be used for any subsequent
417+
/// drawing operation.
418+
///
419+
/// **Note**: The pattern's transformation matrix will be locked to the user space when
420+
/// [`Context::set_source`] is called. Any subsequent modification of the current transformation
421+
/// matrix **will not** affect the source pattern.
422+
///
423+
/// The default source pattern is an opaque black `(0.0, 0.0, 0.0, 1.0)`.
424+
///
425+
/// # Examples
426+
///
427+
/// ```
428+
/// # fn main() -> Result<(), cairo::Error> {
429+
/// use cairo::{Context, Format, ImageSurface, RadialGradient};
430+
///
431+
/// let surface = ImageSurface::create(Format::ARgb32, 100, 100).unwrap();
432+
/// let ctx = Context::new(&surface).unwrap();
433+
///
434+
/// // creates a radial gradient from red to blue
435+
///
436+
/// // gradient will begin at (50, 50) with radius 0
437+
/// // ends at (50, 50) with radius 50
438+
/// let pattern = RadialGradient::new(50.0, 50.0, 0.0, 50.0, 50.0, 50.0);
439+
///
440+
/// // first color stop: at offset=0, draw with red=(1, 0, 0)
441+
/// pattern.add_color_stop_rgb(0.0, 1.0, 0.0, 0.0);
442+
///
443+
/// // second color stop: at offset=1, draw with blue=(0, 0, 1)
444+
/// pattern.add_color_stop_rgb(1.0, 0.0, 0.0, 1.0);
445+
///
446+
/// // paints the canvas with the gradient
447+
/// ctx.set_source(&pattern)?;
448+
/// ctx.paint()?;
449+
/// # Ok(())
450+
/// # }
234451
#[doc(alias = "cairo_set_source")]
235452
pub fn set_source(&self, source: impl AsRef<Pattern>) -> Result<(), Error> {
236453
let source = source.as_ref();
@@ -509,6 +726,7 @@ impl Context {
509726
self.status()
510727
}
511728

729+
/// Paints the current source color everywhere within the current clip region.
512730
#[doc(alias = "cairo_paint")]
513731
pub fn paint(&self) -> Result<(), Error> {
514732
unsafe { ffi::cairo_paint(self.0.as_ptr()) };

0 commit comments

Comments
 (0)