Skip to main content

Paint

Struct Paint 

Source
pub struct Paint {
    pub shader: Shader,
    pub style: Style,
    pub mask_blur_style: MaskBlurStyle,
    pub image_filter: ImageFilter,
    pub color_filter: ColorFilter,
    pub dash: Option<Dash>,
    pub mask_blur: f32,
    pub blend: BlendMode,
    pub tint_blend: BlendMode,
    pub anti_alias: bool,
}
Expand description

Everything about how a shape is painted.

Fields§

§shader: Shader§style: Style§mask_blur_style: MaskBlurStyle

Which part of the blurred shape survives. Ignored without a mask blur.

§image_filter: ImageFilter

A function applied to what this paint drew, after the shader and any color filter.

Costs a layer: what is drawn goes into a target of its own, is filtered, and is composited back. See ImageFilter for how this differs from a color filter and from a mask blur.

§color_filter: ColorFilter

A function applied to the color the shader produces, before blending.

Beside the shader rather than inside it because it applies to all of them, and after it rather than before because that is where dart:ui puts a color filter and where it is useful: what is being recolored is the result of the fill, not the inputs it was built from.

§dash: Option<Dash>

Cut a stroke into a dash pattern before drawing it.

On the paint rather than inside Style::Stroke for two reasons. It keeps the geometry crate’s stroke description a small copyable value, which the tessellator wants and a pattern of arbitrary length would end. And it says what it is: a dashed stroke is a stroke of a different path, so this describes what happens to the path on the way in rather than how the outline is built.

Ignored by a fill, which has no length to measure along.

§mask_blur: f32

Blur the shape’s coverage before filling it, in device pixels.

What a soft shadow is made of: the same shape, softened, drawn behind the thing casting it. Zero for none.

dart:ui states this as blurring the mask and then applying the paint through it, and that is what a shape gets. Two orders exist and they agree only where the fill does not vary, because a blur is linear: blur(C·α) is C·blur(α) for a constant C and for nothing else. A solid color therefore takes the cheaper route and is drawn through a blurred layer, which is that identity used; anything that varies is drawn the way the specification says, with the fill laid across everything the blur reaches and blurred coverage composited onto it.

Two things still take a solid color only, and neither is about blurring. A glyph run tints one color by its own nature, so a gradient over one is refused here exactly as it is when nothing is blurred. And a mesh carries a color per vertex, which is a second thing multiplying the coverage rather than a fill to lay down.

The three styles that combine a blurred mask with a sharp one need the coverage twice and are not built for a varying fill; they take a solid color, which is every use a shadow has.

§blend: BlendMode§tint_blend: BlendMode

How a color carried per vertex or per sprite combines with what this paint produced.

dart:ui passes this as an argument to drawVertices and drawAtlas rather than on the paint. It sits here instead because those are the only two calls that can carry such a color, and an argument every other call would have to pass and ignore is worse than a field they leave alone. BlendMode::Modulate multiplies, which is the identity for the white a caller who supplied no color gets.

Distinct from Self::blend, which decides how the result reaches the target. Both colors here are in the shader already, so every mode is available to this one without an extension.

§anti_alias: bool

Whether to antialias this shape’s edges.

Recorded per paint but applied per pass, because multisampling is a property of the target rather than of a draw: a canvas that mixes the two antialiases everything.

Implementations§

Source§

impl Paint

Source

pub fn fill(color: Color) -> Paint

A solid fill.

Source

pub fn linear_gradient( start: Vec2, end: Vec2, stops: Vec<GradientStop>, ) -> Paint

A fill that runs between colors along a line in user space.

Any number of them. Up to MAX_STOPS the colors travel with the material; beyond that the recorder tabulates them into a texture the shader samples, which costs one small upload per distinct gradient and is otherwise invisible. Ask Shader::stop_count if you want to know which will happen.

Source

pub fn radial_gradient( center: Vec2, radius: f32, stops: Vec<GradientStop>, ) -> Paint

A fill that runs outward from a center in user space.

Any number of stops; see Paint::linear_gradient.

Source

pub fn sweep_gradient( center: Vec2, start_angle: f32, end_angle: f32, stops: Vec<GradientStop>, ) -> Paint

A fill that runs around a center in user space.

Angles are in radians, counter-clockwise from the positive X axis. At any number of stops; see Paint::linear_gradient.

Source

pub fn runtime_effect(program: u32, uniforms: Vec<f32>) -> Paint

A fill computed by a program the caller supplied.

See Shader::RuntimeEffect. The program has to be registered with the context that will draw the recording, and the index it was given is what goes here.

Source

pub fn with_effect_image(self, slot: u32) -> Paint

Give a runtime effect a texture to sample.

Ignored by every other kind of paint, which either samples nothing or already names what it samples. Called more than once, the slots stack up in the order the program declares its bindings.

Source

pub fn with_effect_images(self, slots: &[u32]) -> Paint

Give a runtime effect every texture it samples at once.

The order is the order the program declares its bindings, which for a program written in WGSL is the order of the binding numbers rather than the order of the declarations.

Source

pub fn conical_gradient( start_center: Vec2, start_radius: f32, end_center: Vec2, end_radius: f32, stops: Vec<GradientStop>, ) -> Paint

A fill that runs between two circles in user space.

The general gradient: the first stop lands on the first circle and the last on the second, and every stop between them on a circle interpolated between the two. radial_gradient is the case where the first circle is a point at the second’s center, and is worth reaching for when that is what you mean – it does less work per fragment.

Any number of stops; see Paint::linear_gradient.

Source

pub fn with_sampling(self, sampling: Sampling) -> Paint

How to read a texture between its texels.

Linear by default, which is what an image drawn at any size but its own wants. Sampling::Nearest is for the cases where blending is the wrong answer: pixel art, and a sprite drawn at exactly its own size where certainty that no neighbor bled in matters more than smoothness.

Ignored by a paint with no texture.

Source

pub fn with_mask_blur_style(self, style: MaskBlurStyle) -> Paint

Keep only part of the blurred shape. See MaskBlurStyle.

Ignored unless a mask blur is set, since there is nothing to take a part of otherwise.

Source

pub fn with_image_filter(self, filter: ImageFilter) -> Paint

Filter what this paint draws, rather than the color it computes.

Unlike a mask blur this takes any shader, because blurring a result is defined whatever produced it. It is the more expensive of the two: a layer is allocated, drawn into and composited back, where a mask blur of a solid color reaches the same picture the same way but is only offered where that equivalence holds.

Source

pub fn with_color_filter(self, filter: ColorFilter) -> Paint

Apply a function to the color this paint produces, before it blends.

Works on any shader, which is the point: the image tint that came before it could only recolor an image. A gradient, a shape, a run of glyphs all take one now.

Source

pub fn with_mask_blur(self, sigma: f32) -> Paint

Blur the shape’s coverage, for a shadow or a glow.

Ignored unless finite and positive. Applies to a fill or a stroke alike – what is blurred is whatever coverage the shape produces.

Source

pub fn with_dash(self, dash: impl Into<Option<Dash>>) -> Paint

Dash this paint’s stroke, or clear an existing pattern with None.

The lengths are in the space the shape is drawn in, so a pattern scales with the canvas transform along with the line it cuts. A pattern that cannot be walked – empty, negative, or summing to zero – draws the line whole rather than drawing nothing, since an undashed line leads back to the pattern and an absent one leads nowhere.

Source

pub fn image(slot: u32, rect: Rect) -> Paint

A stroke of the given width, with default caps and joins. A fill that samples an image across a rectangle in user space.

slot indexes the table supplied when the recording is drawn, and rect is the region the image covers rather than the region drawn: the shape being filled decides what is painted, this decides where the image sits under it.

Source

pub fn with_tile_mode(self, tile: TileMode) -> Paint

What happens outside the paint’s own extent.

Means the same thing for a gradient as for an image, which is why it is one call rather than two: past the end of the ramp, past the radius, or outside the swept arc, the color either holds, or repeats, or stops. Ignored by a solid paint, which has no outside.

Source

pub fn with_source(self, source: Rect) -> Paint

Draw only part of the image, in coordinates from zero to one.

What a sprite sheet needs, and a nine-patch border. Normalized rather than in texels because a canvas records without touching a device and has never seen the image: it holds a slot, not a texture, and cannot ask how large it is. The caller who uploaded it can, which is what Paint::with_source_pixels is for.

Ignored by paints that are not images.

Source

pub fn with_source_pixels(self, source: Rect, size: Extent2D) -> Paint

The same, stated in texels of an image of the given size.

A degenerate size would divide by zero, so it leaves the paint alone – drawing the whole image, which is what the paint already said.

Source

pub fn with_tint(self, tint: Color) -> Paint

Multiply an image paint’s sampled color. Ignored by other paints.

What turns one monochrome icon sheet into every state a control has: upload the shapes once as white on transparent, and tint per draw. A white tint is the identity, which is what an image that never mentions one already carries.

Composes with everything else on the paint, so a tinted sprite from a sheet is one call for the piece and one for the color.

Source

pub fn with_image_alpha(self, alpha: f32) -> Paint

Scale an image paint’s sampled color. Ignored by other paints.

Source

pub fn stroke(color: Color, width: f32) -> Paint

Source

pub fn with_shader(self, shader: Shader) -> Paint

Source

pub fn with_style(self, style: Style) -> Paint

Source

pub fn with_blend(self, blend: BlendMode) -> Paint

Source

pub fn with_tint_blend(self, tint_blend: BlendMode) -> Paint

How a per-vertex or per-sprite color combines with this paint’s result.

Ignored by every call that carries no such color, there being nothing to combine.

Source

pub fn with_anti_alias(self, anti_alias: bool) -> Paint

Whether this paint’s edges are smoothed. On by default.

How that is paid for depends on the shape rather than on this flag. A rectangle, rounded rectangle, oval or circle is drawn from a distance field and antialiases itself inside its own fragment shader, costing a pass nothing. Anything that reaches the tessellator instead – an arbitrary path, a stroke, a line, a double rounded rectangle – has only triangles to work with, so its pass becomes multisampled.

That second case carries a requirement worth knowing before meeting it: a multisampled pass must clear, so the pass it lands in needs something to clear to. Drawn straight onto the frame, that means the canvas needs a background – see crate::Canvas::clear, which is where a caller refused for this reason should look. Drawn inside a layer it means nothing to the caller, the layer’s target clearing to transparent on its own.

Source

pub fn is_visible(&self) -> bool

Whether drawing with this paint would change anything.

A transparent fill and a zero-width stroke both draw nothing, and skipping them early keeps empty geometry out of the batch rather than tessellating it and discovering it was empty.

Trait Implementations§

Source§

impl Clone for Paint

Source§

fn clone(&self) -> Paint

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Paint

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Default for Paint

Source§

fn default() -> Paint

Returns the “default value” for a type. Read more
Source§

impl PartialEq for Paint

Source§

fn eq(&self, other: &Paint) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Paint

Auto Trait Implementations§

§

impl Freeze for Paint

§

impl RefUnwindSafe for Paint

§

impl Send for Paint

§

impl Sync for Paint

§

impl Unpin for Paint

§

impl UnsafeUnpin for Paint

§

impl UnwindSafe for Paint

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>