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: MaskBlurStyleWhich part of the blurred shape survives. Ignored without a mask blur.
image_filter: ImageFilterA 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: ColorFilterA 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: f32Blur 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: BlendModeHow 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: boolWhether 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
impl Paint
Sourcepub fn linear_gradient(
start: Vec2,
end: Vec2,
stops: Vec<GradientStop>,
) -> Paint
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.
Sourcepub fn radial_gradient(
center: Vec2,
radius: f32,
stops: Vec<GradientStop>,
) -> Paint
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.
Sourcepub fn sweep_gradient(
center: Vec2,
start_angle: f32,
end_angle: f32,
stops: Vec<GradientStop>,
) -> Paint
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.
Sourcepub fn runtime_effect(program: u32, uniforms: Vec<f32>) -> Paint
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.
Sourcepub fn with_effect_image(self, slot: u32) -> Paint
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.
Sourcepub fn with_effect_images(self, slots: &[u32]) -> Paint
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.
Sourcepub fn conical_gradient(
start_center: Vec2,
start_radius: f32,
end_center: Vec2,
end_radius: f32,
stops: Vec<GradientStop>,
) -> Paint
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.
Sourcepub fn with_sampling(self, sampling: Sampling) -> Paint
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.
Sourcepub fn with_mask_blur_style(self, style: MaskBlurStyle) -> Paint
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.
Sourcepub fn with_image_filter(self, filter: ImageFilter) -> Paint
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.
Sourcepub fn with_color_filter(self, filter: ColorFilter) -> Paint
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.
Sourcepub fn with_mask_blur(self, sigma: f32) -> Paint
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.
Sourcepub fn with_dash(self, dash: impl Into<Option<Dash>>) -> Paint
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.
Sourcepub fn image(slot: u32, rect: Rect) -> Paint
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.
Sourcepub fn with_tile_mode(self, tile: TileMode) -> Paint
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.
Sourcepub fn with_source(self, source: Rect) -> Paint
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.
Sourcepub fn with_source_pixels(self, source: Rect, size: Extent2D) -> Paint
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.
Sourcepub fn with_tint(self, tint: Color) -> Paint
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.
Sourcepub fn with_image_alpha(self, alpha: f32) -> Paint
pub fn with_image_alpha(self, alpha: f32) -> Paint
Scale an image paint’s sampled color. Ignored by other paints.
pub fn stroke(color: Color, width: f32) -> Paint
pub fn with_shader(self, shader: Shader) -> Paint
pub fn with_style(self, style: Style) -> Paint
pub fn with_blend(self, blend: BlendMode) -> Paint
Sourcepub fn with_tint_blend(self, tint_blend: BlendMode) -> Paint
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.
Sourcepub fn with_anti_alias(self, anti_alias: bool) -> Paint
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.
Sourcepub fn is_visible(&self) -> bool
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.