piet/
render_context.rs

1// Copyright 2019 the Piet Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4//! The main render context trait.
5
6use std::borrow::Cow;
7
8use kurbo::{Affine, Point, Rect, Shape};
9
10use crate::{
11    Color, Error, FixedGradient, FixedLinearGradient, FixedRadialGradient, Image, LinearGradient,
12    RadialGradient, StrokeStyle, Text, TextLayout,
13};
14
15/// A requested interpolation mode for drawing images.
16#[derive(Clone, Copy, PartialEq, Eq)]
17pub enum InterpolationMode {
18    /// Don't interpolate, use nearest neighbor.
19    NearestNeighbor,
20    /// Use bilinear interpolation.
21    Bilinear,
22}
23
24/// The pixel format for bitmap images.
25#[derive(Clone, Copy, Debug, PartialEq, Eq)]
26#[non_exhaustive]
27pub enum ImageFormat {
28    /// 1 byte per pixel.
29    ///
30    /// For example, a white pixel has value 0xff.
31    Grayscale,
32    /// 3 bytes per pixel, in RGB order.
33    ///
34    /// For example, a red pixel consists of three bytes `[0xff, 0, 0]` independent of the system's
35    /// endianness.
36    Rgb,
37    /// 4 bytes per pixel, in RGBA order, with separate alpha.
38    ///
39    /// For example, a full-intensity red pixel with 50% transparency consists of four bytes
40    /// `[0xff, 0, 0, 0x80]` independent of the system's endianness.
41    RgbaSeparate,
42    /// 4 bytes per pixel, in RGBA order, with premultiplied alpha.
43    ///
44    /// For example, a full-intensity red pixel with 50% transparency consists of four bytes
45    /// `[0x80, 0, 0, 0x80]` independent of the system's endianness.
46    RgbaPremul,
47}
48
49impl ImageFormat {
50    /// The number of bytes required to represent a pixel in this format.
51    pub fn bytes_per_pixel(self) -> usize {
52        match self {
53            ImageFormat::Grayscale => 1,
54            ImageFormat::Rgb => 3,
55            ImageFormat::RgbaPremul | ImageFormat::RgbaSeparate => 4,
56        }
57    }
58}
59
60/// The main trait for rendering graphics.
61///
62/// This trait provides an API for drawing 2D graphics. In basic usage, it
63/// wraps a surface of some kind, so that drawing commands paint onto the
64/// surface. It can also be a recording context, creating a display list for
65/// playback later.
66///
67/// The intent of the design is to be general so that any number of back-ends
68/// can implement this trait.
69///
70/// Code that draws graphics will in general take `&mut impl RenderContext`.
71pub trait RenderContext
72where
73    Self::Brush: IntoBrush<Self>,
74{
75    /// The type of a "brush".
76    ///
77    /// Represents solid colors and gradients.
78    type Brush: Clone;
79
80    /// An associated factory for creating text layouts and related resources.
81    type Text: Text<TextLayout = Self::TextLayout>;
82
83    /// The type use to represent text layout objects.
84    type TextLayout: TextLayout;
85
86    /// The associated type of an image.
87    type Image: Image;
88
89    /// Report an internal error.
90    ///
91    /// Drawing operations may cause internal errors, which may also occur
92    /// asynchronously after the drawing command was issued. This method reports
93    /// any such error that has been detected.
94    fn status(&mut self) -> Result<(), Error>;
95
96    /// Create a new brush resource.
97    ///
98    /// TODO: figure out how to document lifetime and rebuilding requirements. Should
99    /// that be the responsibility of the client, or should the back-end take
100    /// responsibility? We could have a cache that is flushed when the Direct2D
101    /// render target is rebuilt. Solid brushes are super lightweight, but
102    /// other potentially retained objects will be heavier.
103    fn solid_brush(&mut self, color: Color) -> Self::Brush;
104
105    /// Create a new gradient brush.
106    fn gradient(&mut self, gradient: impl Into<FixedGradient>) -> Result<Self::Brush, Error>;
107
108    /// Replace a region of the canvas with the provided [`Color`].
109    ///
110    /// The region can be omitted, in which case it will apply to the entire
111    /// canvas.
112    ///
113    /// This operation ignores any existing clipping and transformations.
114    ///
115    /// # Note:
116    ///
117    /// You probably don't want to call this. It is essentially a specialized
118    /// fill method that can be used in GUI contexts for things like clearing
119    /// damage regions. It does not have a good cross-platform implementation,
120    /// and eventually should be deprecated when support is added for blend
121    /// modes, at which point it will be easier to just use [`fill`] for
122    /// everything.
123    ///
124    /// [`fill`]: RenderContext::fill
125    fn clear(&mut self, region: impl Into<Option<Rect>>, color: Color);
126
127    /// Stroke a [`Shape`], using the default [`StrokeStyle`].
128    fn stroke(&mut self, shape: impl Shape, brush: &impl IntoBrush<Self>, width: f64);
129
130    /// Stroke a [`Shape`], providing a custom [`StrokeStyle`].
131    fn stroke_styled(
132        &mut self,
133        shape: impl Shape,
134        brush: &impl IntoBrush<Self>,
135        width: f64,
136        style: &StrokeStyle,
137    );
138
139    /// Fill a [`Shape`], using the [non-zero fill rule].
140    ///
141    /// [non-zero fill rule]: https://en.wikipedia.org/wiki/Nonzero-rule
142    fn fill(&mut self, shape: impl Shape, brush: &impl IntoBrush<Self>);
143
144    /// Fill a shape, using the [even-odd fill rule].
145    ///
146    /// [even-odd fill rule]: https://en.wikipedia.org/wiki/Even–odd_rule
147    fn fill_even_odd(&mut self, shape: impl Shape, brush: &impl IntoBrush<Self>);
148
149    /// Clip to a [`Shape`].
150    ///
151    /// All subsequent drawing operations up to the next [`restore`]
152    /// are clipped by the shape.
153    ///
154    /// [`restore`]: RenderContext::restore
155    fn clip(&mut self, shape: impl Shape);
156
157    /// Returns a reference to a shared [`Text`] object.
158    ///
159    /// This provides access to the text API.
160    fn text(&mut self) -> &mut Self::Text;
161
162    /// Draw a [`TextLayout`].
163    ///
164    /// The `pos` parameter specifies the upper-left corner of the layout object
165    /// (even for right-to-left text). To draw on a baseline, you can use
166    /// [`TextLayout::line_metric`] to get the baseline position of a specific line.
167    fn draw_text(&mut self, layout: &Self::TextLayout, pos: impl Into<Point>);
168
169    /// Save the context state.
170    ///
171    /// Pushes the current context state onto a stack, to be popped by
172    /// [`restore`].
173    ///
174    /// Prefer [`with_save`] if possible, as that statically
175    /// enforces balance of save/restore pairs.
176    ///
177    /// The context state currently consists of a clip region and an affine
178    /// transform, but is expected to grow in the near future.
179    ///
180    /// [`restore`]: RenderContext::restore
181    /// [`with_save`]: RenderContext::with_save
182    fn save(&mut self) -> Result<(), Error>;
183
184    /// Restore the context state.
185    ///
186    /// Pop a context state that was pushed by [`save`]. See
187    /// that method for details.
188    ///
189    /// [`save`]: RenderContext::save
190    fn restore(&mut self) -> Result<(), Error>;
191
192    /// Do graphics operations with the context state saved and then restored.
193    ///
194    /// Equivalent to [`save`], calling `f`, then
195    /// [`restore`]. See those methods for more details.
196    ///
197    /// [`restore`]: RenderContext::restore
198    /// [`save`]: RenderContext::save
199    fn with_save(&mut self, f: impl FnOnce(&mut Self) -> Result<(), Error>) -> Result<(), Error> {
200        self.save()?;
201        // Always try to restore the stack, even if `f` errored.
202        f(self).and(self.restore())
203    }
204
205    /// Finish any pending operations.
206    ///
207    /// This will generally be called by a shell after all user drawing
208    /// operations but before presenting. Not all back-ends will handle this
209    /// the same way.
210    fn finish(&mut self) -> Result<(), Error>;
211
212    /// Apply a transform.
213    ///
214    /// Apply an affine transformation. The transformation remains in effect
215    /// until a [`restore`] operation.
216    ///
217    /// [`restore`]: RenderContext::restore
218    fn transform(&mut self, transform: Affine);
219
220    /// Create a new [`Image`] from a pixel buffer.
221    ///
222    /// This takes raw pixel data and attempts create an object that the
223    /// platform knows how to draw.
224    ///
225    /// The generated image can be cached and reused. This is a good idea for
226    /// images that are used frequently, because creating the image type may
227    /// be expensive.
228    ///
229    /// To draw the generated image, pass it to [`draw_image`]. To draw a portion
230    /// of the image, use [`draw_image_area`].
231    ///
232    /// If you are trying to create an image from the contents of this
233    /// [`RenderContext`], see [`capture_image_area`].
234    ///
235    /// # Arguments
236    ///
237    /// * `width` - The width of the image in pixels.
238    /// * `height` - The height of the image in pixels.
239    /// * `buf` - The pixel data. The length of this buffer must be at least
240    ///   `width * height * format.bytes_per_pixel()`.
241    /// * `format` - The format of the pixel data.
242    ///
243    /// [`draw_image`]: RenderContext::draw_image
244    /// [`draw_image_area`]: RenderContext::draw_image_area
245    /// [`capture_image_area`]: RenderContext::capture_image_area
246    fn make_image(
247        &mut self,
248        width: usize,
249        height: usize,
250        buf: &[u8],
251        format: ImageFormat,
252    ) -> Result<Self::Image, Error> {
253        self.make_image_with_stride(width, height, width * format.bytes_per_pixel(), buf, format)
254    }
255
256    /// Create a new [`Image`] from a pixel buffer with a specified row stride.
257    ///
258    /// This has the same semantics as [`make_image`], but allows the caller to
259    /// specify the stride of the image data. It is useful for images that are
260    /// not tightly packed.
261    ///
262    /// # Arguments
263    ///
264    /// * `width` - The width of the image in pixels.
265    /// * `height` - The height of the image in pixels.
266    /// * `stride` - The number of bytes between the start of one row of pixels
267    ///   and the start of the next row of pixels.
268    /// * `buf` - The pixel data for the image. The length of this buffer must
269    ///   be at least `stride * height`.
270    /// * `format` - The format of the pixel data.
271    ///
272    /// [`make_image`]: RenderContext::make_image
273    fn make_image_with_stride(
274        &mut self,
275        width: usize,
276        height: usize,
277        stride: usize,
278        buf: &[u8],
279        format: ImageFormat,
280    ) -> Result<Self::Image, Error>;
281
282    /// Draw an [`Image`] into the provided [`Rect`].
283    ///
284    /// The image is scaled to fit the provided [`Rect`]; it will be squashed
285    /// if the aspect ratios don't match.
286    fn draw_image(
287        &mut self,
288        image: &Self::Image,
289        dst_rect: impl Into<Rect>,
290        interp: InterpolationMode,
291    );
292
293    /// Draw a specified area of an [`Image`].
294    ///
295    /// The `src_rect` area of `image` is scaled to the provided `dst_rect`.
296    /// It will be squashed if the aspect ratios don't match.
297    fn draw_image_area(
298        &mut self,
299        image: &Self::Image,
300        src_rect: impl Into<Rect>,
301        dst_rect: impl Into<Rect>,
302        interp: InterpolationMode,
303    );
304
305    /// Create an [`Image`] of the specified region of the context.
306    ///
307    /// The `src_rect` area of the current render context will be captured
308    /// as a copy and returned.
309    ///
310    /// This can be used for things like caching expensive drawing operations.
311    fn capture_image_area(&mut self, src_rect: impl Into<Rect>) -> Result<Self::Image, Error>;
312
313    /// Draw a rectangle with Gaussian blur.
314    ///
315    /// The blur radius is sometimes referred to as the "standard deviation" of
316    /// the blur.
317    fn blurred_rect(&mut self, rect: Rect, blur_radius: f64, brush: &impl IntoBrush<Self>);
318
319    /// Returns the transformations currently applied to the context.
320    fn current_transform(&self) -> Affine;
321}
322
323/// A trait for various types that can be used as brushes.
324///
325/// These include backend-independent types such [`Color`] and [`LinearGradient`],
326/// as well as the types used to represent these on a specific backend.
327///
328/// This is an internal trait that you should not have to implement or think about.
329pub trait IntoBrush<P: RenderContext>
330where
331    P: ?Sized,
332{
333    #[doc(hidden)]
334    fn make_brush<'a>(&'a self, piet: &mut P, bbox: impl FnOnce() -> Rect) -> Cow<'a, P::Brush>;
335}
336
337impl<P: RenderContext> IntoBrush<P> for Color {
338    fn make_brush<'a>(&'a self, piet: &mut P, _bbox: impl FnOnce() -> Rect) -> Cow<'a, P::Brush> {
339        Cow::Owned(piet.solid_brush(self.to_owned()))
340    }
341}
342
343/// A color or a gradient.
344///
345/// This type is provided as a convenience, so that library consumers can
346/// easily write methods and types that use or reference *something* that can
347/// be used as a brush, without needing to know what it is.
348///
349/// # Examples
350///
351/// ```no_run
352/// use piet::{Color, PaintBrush, RadialGradient};
353/// use piet::kurbo::Rect;
354///
355/// struct Widget {
356/// frame: Rect,
357/// background: PaintBrush,
358/// }
359///
360/// fn make_widget<T: Into<PaintBrush>>(frame: Rect, bg: T) -> Widget {
361///     Widget {
362///         frame,
363///         background: bg.into(),
364///     }
365/// }
366///
367/// let color_widget = make_widget(Rect::ZERO, Color::BLACK);
368/// let rad_grad = RadialGradient::new(0.8, (Color::WHITE, Color::BLACK));
369/// let gradient_widget = make_widget(Rect::ZERO, rad_grad);
370///
371/// ```
372#[derive(Debug, Clone)]
373pub enum PaintBrush {
374    /// A [`Color`].
375    Color(Color),
376    /// A [`LinearGradient`].
377    Linear(LinearGradient),
378    /// A [`RadialGradient`].
379    Radial(RadialGradient),
380    /// A [`FixedGradient`].
381    Fixed(FixedGradient),
382}
383
384impl<P: RenderContext> IntoBrush<P> for PaintBrush {
385    fn make_brush<'a>(&'a self, piet: &mut P, bbox: impl FnOnce() -> Rect) -> Cow<'a, P::Brush> {
386        match self {
387            PaintBrush::Color(color) => color.make_brush(piet, bbox),
388            PaintBrush::Linear(linear) => linear.make_brush(piet, bbox),
389            PaintBrush::Radial(radial) => radial.make_brush(piet, bbox),
390            PaintBrush::Fixed(fixed) => fixed.make_brush(piet, bbox),
391        }
392    }
393}
394
395impl From<Color> for PaintBrush {
396    fn from(src: Color) -> PaintBrush {
397        PaintBrush::Color(src)
398    }
399}
400
401impl From<LinearGradient> for PaintBrush {
402    fn from(src: LinearGradient) -> PaintBrush {
403        PaintBrush::Linear(src)
404    }
405}
406
407impl From<RadialGradient> for PaintBrush {
408    fn from(src: RadialGradient) -> PaintBrush {
409        PaintBrush::Radial(src)
410    }
411}
412
413impl From<FixedGradient> for PaintBrush {
414    fn from(src: FixedGradient) -> PaintBrush {
415        PaintBrush::Fixed(src)
416    }
417}
418
419impl From<FixedLinearGradient> for PaintBrush {
420    fn from(src: FixedLinearGradient) -> PaintBrush {
421        PaintBrush::Fixed(src.into())
422    }
423}
424
425impl From<FixedRadialGradient> for PaintBrush {
426    fn from(src: FixedRadialGradient) -> PaintBrush {
427        PaintBrush::Fixed(src.into())
428    }
429}