Better rounding of rectangles with thin outlines (#5571)
Better positioning of rectangle outline when the stroke width is less than one pixel
This commit is contained in:
parent
46b58e5bcc
commit
4784136fee
|
|
@ -102,7 +102,7 @@ pub enum SnapshotError {
|
|||
}
|
||||
|
||||
const HOW_TO_UPDATE_SCREENSHOTS: &str =
|
||||
"Run `UPDATE_SNAPSHOTS=1 cargo test` to update the snapshots.";
|
||||
"Run `UPDATE_SNAPSHOTS=1 cargo test --all-features` to update the snapshots.";
|
||||
|
||||
impl Display for SnapshotError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
|
|
|
|||
|
|
@ -1291,29 +1291,6 @@ impl Tessellator {
|
|||
self.clip_rect = clip_rect;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn round_to_pixel(&self, point: f32) -> f32 {
|
||||
(point * self.pixels_per_point).round() / self.pixels_per_point
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn round_to_pixel_center(&self, point: f32) -> f32 {
|
||||
((point * self.pixels_per_point - 0.5).round() + 0.5) / self.pixels_per_point
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn round_pos_to_pixel(&self, pos: Pos2) -> Pos2 {
|
||||
pos2(self.round_to_pixel(pos.x), self.round_to_pixel(pos.y))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn round_pos_to_pixel_center(&self, pos: Pos2) -> Pos2 {
|
||||
pos2(
|
||||
self.round_to_pixel_center(pos.x),
|
||||
self.round_to_pixel_center(pos.y),
|
||||
)
|
||||
}
|
||||
|
||||
/// Tessellate a clipped shape into a list of primitives.
|
||||
pub fn tessellate_clipped_shape(
|
||||
&mut self,
|
||||
|
|
@ -1716,8 +1693,16 @@ impl Tessellator {
|
|||
// Since the stroke extends outside of the rectangle,
|
||||
// we can round the rectangle sides to the physical pixel edges,
|
||||
// and the filled rect will appear crisp, as will the inside of the stroke.
|
||||
let Stroke { .. } = stroke; // Make sure we remember to update this if we change `stroke` to `PathStroke`
|
||||
rect = rect.round_to_pixels(self.pixels_per_point);
|
||||
let Stroke { width, .. } = stroke; // Make sure we remember to update this if we change `stroke` to `PathStroke`
|
||||
if width <= self.feathering && !stroke.is_empty() {
|
||||
// If the stroke is thin, make sure its center is in the center of the pixel:
|
||||
rect = rect
|
||||
.expand(width / 2.0)
|
||||
.round_to_pixel_center(self.pixels_per_point)
|
||||
.shrink(width / 2.0);
|
||||
} else {
|
||||
rect = rect.round_to_pixels(self.pixels_per_point);
|
||||
}
|
||||
}
|
||||
|
||||
// It is common to (sometimes accidentally) create an infinitely sized rectangle.
|
||||
|
|
@ -1727,7 +1712,7 @@ impl Tessellator {
|
|||
|
||||
let old_feathering = self.feathering;
|
||||
|
||||
if old_feathering < blur_width {
|
||||
if self.feathering < blur_width {
|
||||
// We accomplish the blur by using a larger-than-normal feathering.
|
||||
// Feathering is usually used to make the edges of a shape softer for anti-aliasing.
|
||||
|
||||
|
|
@ -1836,10 +1821,7 @@ impl Tessellator {
|
|||
// The contents of the galley are already snapped to pixel coordinates,
|
||||
// but we need to make sure the galley ends up on the start of a physical pixel:
|
||||
let galley_pos = if self.options.round_text_to_pixels {
|
||||
pos2(
|
||||
self.round_to_pixel(galley_pos.x),
|
||||
self.round_to_pixel(galley_pos.y),
|
||||
)
|
||||
galley_pos.round_to_pixels(self.pixels_per_point)
|
||||
} else {
|
||||
*galley_pos
|
||||
};
|
||||
|
|
@ -1917,13 +1899,11 @@ impl Tessellator {
|
|||
);
|
||||
|
||||
if *underline != Stroke::NONE {
|
||||
self.scratchpad_path.clear();
|
||||
self.scratchpad_path.add_line_segment([
|
||||
self.round_pos_to_pixel_center(row_rect.left_bottom()),
|
||||
self.round_pos_to_pixel_center(row_rect.right_bottom()),
|
||||
]);
|
||||
self.scratchpad_path
|
||||
.stroke_open(0.0, &PathStroke::from(*underline), out);
|
||||
self.tessellate_line_segment(
|
||||
[row_rect.left_bottom(), row_rect.right_bottom()],
|
||||
*underline,
|
||||
out,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue