mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
parent
186ab5aa24
commit
9333f028e8
5 changed files with 133 additions and 80 deletions
|
@ -93,13 +93,17 @@ struct CornerOrigin {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PaintContext<'a> {
|
impl<'a> PaintContext<'a> {
|
||||||
|
pub fn screen_pixels_per_px(&self) -> f32 {
|
||||||
|
self.screen_rect.size.width as f32 / self.page_rect.size.width
|
||||||
|
}
|
||||||
|
|
||||||
pub fn draw_target(&self) -> &DrawTarget {
|
pub fn draw_target(&self) -> &DrawTarget {
|
||||||
&self.draw_target
|
&self.draw_target
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_solid_color(&self, bounds: &Rect<Au>, color: Color) {
|
pub fn draw_solid_color(&self, bounds: &Rect<Au>, color: Color) {
|
||||||
self.draw_target.make_current();
|
self.draw_target.make_current();
|
||||||
self.draw_target.fill_rect(&bounds.to_nearest_azure_rect(),
|
self.draw_target.fill_rect(&bounds.to_nearest_azure_rect(self.screen_pixels_per_px()),
|
||||||
PatternRef::Color(&ColorPattern::new(color)),
|
PatternRef::Color(&ColorPattern::new(color)),
|
||||||
None);
|
None);
|
||||||
}
|
}
|
||||||
|
@ -110,8 +114,9 @@ impl<'a> PaintContext<'a> {
|
||||||
radius: &BorderRadii<Au>,
|
radius: &BorderRadii<Au>,
|
||||||
color: &SideOffsets2D<Color>,
|
color: &SideOffsets2D<Color>,
|
||||||
style: &SideOffsets2D<border_style::T>) {
|
style: &SideOffsets2D<border_style::T>) {
|
||||||
let border = border.to_float_px();
|
let scale = self.screen_pixels_per_px();
|
||||||
let radius = radius.to_radii_px();
|
let border = border.to_float_pixels(scale);
|
||||||
|
let radius = radius.to_radii_pixels(scale);
|
||||||
|
|
||||||
self.draw_border_segment(Direction::Top, bounds, &border, &radius, color, style);
|
self.draw_border_segment(Direction::Top, bounds, &border, &radius, color, style);
|
||||||
self.draw_border_segment(Direction::Right, bounds, &border, &radius, color, style);
|
self.draw_border_segment(Direction::Right, bounds, &border, &radius, color, style);
|
||||||
|
@ -126,7 +131,7 @@ impl<'a> PaintContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_push_clip(&self, bounds: &Rect<Au>) {
|
pub fn draw_push_clip(&self, bounds: &Rect<Au>) {
|
||||||
let rect = bounds.to_nearest_azure_rect();
|
let rect = bounds.to_nearest_azure_rect(self.screen_pixels_per_px());
|
||||||
let path_builder = self.draw_target.create_path_builder();
|
let path_builder = self.draw_target.create_path_builder();
|
||||||
|
|
||||||
let left_top = Point2D::new(rect.origin.x, rect.origin.y);
|
let left_top = Point2D::new(rect.origin.x, rect.origin.y);
|
||||||
|
@ -161,6 +166,7 @@ impl<'a> PaintContext<'a> {
|
||||||
PixelFormat::KA8 => panic!("KA8 color type not supported"),
|
PixelFormat::KA8 => panic!("KA8 color type not supported"),
|
||||||
};
|
};
|
||||||
let stride = image.width * pixel_width;
|
let stride = image.width * pixel_width;
|
||||||
|
let scale = self.screen_pixels_per_px();
|
||||||
|
|
||||||
self.draw_target.make_current();
|
self.draw_target.make_current();
|
||||||
let draw_target_ref = &self.draw_target;
|
let draw_target_ref = &self.draw_target;
|
||||||
|
@ -170,7 +176,7 @@ impl<'a> PaintContext<'a> {
|
||||||
source_format);
|
source_format);
|
||||||
let source_rect = Rect::new(Point2D::new(0.0, 0.0),
|
let source_rect = Rect::new(Point2D::new(0.0, 0.0),
|
||||||
Size2D::new(image.width as AzFloat, image.height as AzFloat));
|
Size2D::new(image.width as AzFloat, image.height as AzFloat));
|
||||||
let dest_rect = bounds.to_nearest_azure_rect();
|
let dest_rect = bounds.to_nearest_azure_rect(scale);
|
||||||
|
|
||||||
// TODO(pcwalton): According to CSS-IMAGES-3 § 5.3, nearest-neighbor interpolation is a
|
// TODO(pcwalton): According to CSS-IMAGES-3 § 5.3, nearest-neighbor interpolation is a
|
||||||
// conforming implementation of `crisp-edges`, but it is not the best we could do.
|
// conforming implementation of `crisp-edges`, but it is not the best we could do.
|
||||||
|
@ -198,7 +204,7 @@ impl<'a> PaintContext<'a> {
|
||||||
// Annoyingly, surface patterns in Azure/Skia are relative to the top left of the *canvas*,
|
// Annoyingly, surface patterns in Azure/Skia are relative to the top left of the *canvas*,
|
||||||
// not the rectangle we're drawing to. So we need to translate it explicitly.
|
// not the rectangle we're drawing to. So we need to translate it explicitly.
|
||||||
let matrix = Matrix2D::identity().translate(dest_rect.origin.x, dest_rect.origin.y);
|
let matrix = Matrix2D::identity().translate(dest_rect.origin.x, dest_rect.origin.y);
|
||||||
let stretch_size = stretch_size.to_nearest_azure_size();
|
let stretch_size = stretch_size.to_nearest_azure_size(scale);
|
||||||
if source_rect.size == stretch_size {
|
if source_rect.size == stretch_size {
|
||||||
let pattern = SurfacePattern::new(azure_surface.azure_source_surface,
|
let pattern = SurfacePattern::new(azure_surface.azure_source_surface,
|
||||||
true,
|
true,
|
||||||
|
@ -306,7 +312,8 @@ impl<'a> PaintContext<'a> {
|
||||||
radius: &BorderRadii<AzFloat>,
|
radius: &BorderRadii<AzFloat>,
|
||||||
color: Color,
|
color: Color,
|
||||||
style: border_style::T) {
|
style: border_style::T) {
|
||||||
let border = SideOffsets2D::new_all_same(bounds.size.width).to_float_px();
|
let scale = self.screen_pixels_per_px();
|
||||||
|
let border = SideOffsets2D::new_all_same(bounds.size.width).to_float_pixels(scale);
|
||||||
match style {
|
match style {
|
||||||
border_style::T::none | border_style::T::hidden => {}
|
border_style::T::none | border_style::T::hidden => {}
|
||||||
border_style::T::dotted => {
|
border_style::T::dotted => {
|
||||||
|
@ -1027,7 +1034,7 @@ impl<'a> PaintContext<'a> {
|
||||||
radius: &BorderRadii<AzFloat>,
|
radius: &BorderRadii<AzFloat>,
|
||||||
color: Color,
|
color: Color,
|
||||||
dash_size: DashSize) {
|
dash_size: DashSize) {
|
||||||
let rect = bounds.to_nearest_azure_rect();
|
let rect = bounds.to_nearest_azure_rect(self.screen_pixels_per_px());
|
||||||
let draw_opts = DrawOptions::new(1.0, CompositionOp::Over, AntialiasMode::None);
|
let draw_opts = DrawOptions::new(1.0, CompositionOp::Over, AntialiasMode::None);
|
||||||
let border_width = match direction {
|
let border_width = match direction {
|
||||||
Direction::Top => border.top,
|
Direction::Top => border.top,
|
||||||
|
@ -1095,7 +1102,7 @@ impl<'a> PaintContext<'a> {
|
||||||
border: &SideOffsets2D<f32>,
|
border: &SideOffsets2D<f32>,
|
||||||
radius: &BorderRadii<AzFloat>,
|
radius: &BorderRadii<AzFloat>,
|
||||||
color: Color) {
|
color: Color) {
|
||||||
let rect = bounds.to_nearest_azure_rect();
|
let rect = bounds.to_nearest_azure_rect(self.screen_pixels_per_px());
|
||||||
self.draw_border_path(&rect, direction, border, radius, color);
|
self.draw_border_path(&rect, direction, border, radius, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1103,7 +1110,7 @@ impl<'a> PaintContext<'a> {
|
||||||
bounds: &Rect<Au>,
|
bounds: &Rect<Au>,
|
||||||
border: &SideOffsets2D<f32>,
|
border: &SideOffsets2D<f32>,
|
||||||
shrink_factor: f32) -> Rect<f32> {
|
shrink_factor: f32) -> Rect<f32> {
|
||||||
let rect = bounds.to_nearest_azure_rect();
|
let rect = bounds.to_nearest_azure_rect(self.screen_pixels_per_px());
|
||||||
let scaled_border = SideOffsets2D::new(shrink_factor * border.top,
|
let scaled_border = SideOffsets2D::new(shrink_factor * border.top,
|
||||||
shrink_factor * border.right,
|
shrink_factor * border.right,
|
||||||
shrink_factor * border.bottom,
|
shrink_factor * border.bottom,
|
||||||
|
@ -1302,11 +1309,12 @@ impl<'a> PaintContext<'a> {
|
||||||
self.draw_target.make_current();
|
self.draw_target.make_current();
|
||||||
|
|
||||||
let stops = self.draw_target.create_gradient_stops(stops, ExtendMode::Clamp);
|
let stops = self.draw_target.create_gradient_stops(stops, ExtendMode::Clamp);
|
||||||
let pattern = LinearGradientPattern::new(&start_point.to_nearest_azure_point(),
|
let scale = self.screen_pixels_per_px();
|
||||||
&end_point.to_nearest_azure_point(),
|
let pattern = LinearGradientPattern::new(&start_point.to_nearest_azure_point(scale),
|
||||||
|
&end_point.to_nearest_azure_point(scale),
|
||||||
stops,
|
stops,
|
||||||
&Matrix2D::identity());
|
&Matrix2D::identity());
|
||||||
self.draw_target.fill_rect(&bounds.to_nearest_azure_rect(),
|
self.draw_target.fill_rect(&bounds.to_nearest_azure_rect(scale),
|
||||||
PatternRef::LinearGradient(&pattern),
|
PatternRef::LinearGradient(&pattern),
|
||||||
None);
|
None);
|
||||||
}
|
}
|
||||||
|
@ -1328,8 +1336,8 @@ impl<'a> PaintContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(pcwalton): This surface might be bigger than necessary and waste memory.
|
// FIXME(pcwalton): This surface might be bigger than necessary and waste memory.
|
||||||
let size = self.draw_target.get_size(); //Az size.
|
let size: AzIntSize = self.draw_target.get_size();
|
||||||
let mut size = Size2D::new(size.width, size.height); //Geom::Size.
|
let mut size = Size2D::new(size.width, size.height);
|
||||||
|
|
||||||
// Pre-calculate if there is a blur expansion need.
|
// Pre-calculate if there is a blur expansion need.
|
||||||
let accum_blur = filters::calculate_accumulated_blur(filters);
|
let accum_blur = filters::calculate_accumulated_blur(filters);
|
||||||
|
@ -1424,6 +1432,7 @@ impl<'a> PaintContext<'a> {
|
||||||
self.pop_clip_if_applicable();
|
self.pop_clip_if_applicable();
|
||||||
|
|
||||||
// If we have blur, create a new draw target.
|
// If we have blur, create a new draw target.
|
||||||
|
let pixels_per_px = self.screen_pixels_per_px();
|
||||||
let shadow_bounds = box_bounds.translate(offset).inflate(spread_radius, spread_radius);
|
let shadow_bounds = box_bounds.translate(offset).inflate(spread_radius, spread_radius);
|
||||||
let side_inflation = blur_radius * BLUR_INFLATION_FACTOR;
|
let side_inflation = blur_radius * BLUR_INFLATION_FACTOR;
|
||||||
let inflated_shadow_bounds = shadow_bounds.inflate(side_inflation, side_inflation);
|
let inflated_shadow_bounds = shadow_bounds.inflate(side_inflation, side_inflation);
|
||||||
|
@ -1435,17 +1444,21 @@ impl<'a> PaintContext<'a> {
|
||||||
BoxShadowClipMode::Inset => {
|
BoxShadowClipMode::Inset => {
|
||||||
path = temporary_draw_target.draw_target
|
path = temporary_draw_target.draw_target
|
||||||
.create_rectangular_border_path(&MAX_RECT,
|
.create_rectangular_border_path(&MAX_RECT,
|
||||||
&shadow_bounds);
|
&shadow_bounds,
|
||||||
self.draw_target.push_clip(&self.draw_target.create_rectangular_path(box_bounds))
|
pixels_per_px);
|
||||||
|
self.draw_target.push_clip(
|
||||||
|
&self.draw_target.create_rectangular_path(box_bounds, pixels_per_px))
|
||||||
}
|
}
|
||||||
BoxShadowClipMode::Outset => {
|
BoxShadowClipMode::Outset => {
|
||||||
path = temporary_draw_target.draw_target.create_rectangular_path(&shadow_bounds);
|
path = temporary_draw_target.draw_target.create_rectangular_path(&shadow_bounds,
|
||||||
self.draw_target.push_clip(&self.draw_target
|
pixels_per_px);
|
||||||
.create_rectangular_border_path(&MAX_RECT,
|
self.draw_target.push_clip(
|
||||||
box_bounds))
|
&self.draw_target.create_rectangular_border_path(&MAX_RECT, box_bounds,
|
||||||
|
pixels_per_px))
|
||||||
}
|
}
|
||||||
BoxShadowClipMode::None => {
|
BoxShadowClipMode::None => {
|
||||||
path = temporary_draw_target.draw_target.create_rectangular_path(&shadow_bounds)
|
path = temporary_draw_target.draw_target.create_rectangular_path(&shadow_bounds,
|
||||||
|
pixels_per_px)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1521,26 +1534,28 @@ impl<'a> PaintContext<'a> {
|
||||||
/// Sets a new transient clipping region. Automatically calls
|
/// Sets a new transient clipping region. Automatically calls
|
||||||
/// `remove_transient_clip_if_applicable()` first.
|
/// `remove_transient_clip_if_applicable()` first.
|
||||||
pub fn push_transient_clip(&mut self, clip_region: ClippingRegion) {
|
pub fn push_transient_clip(&mut self, clip_region: ClippingRegion) {
|
||||||
|
let scale = self.screen_pixels_per_px();
|
||||||
self.remove_transient_clip_if_applicable();
|
self.remove_transient_clip_if_applicable();
|
||||||
|
|
||||||
self.draw_push_clip(&clip_region.main);
|
self.draw_push_clip(&clip_region.main);
|
||||||
for complex_region in &clip_region.complex {
|
for complex_region in &clip_region.complex {
|
||||||
// FIXME(pcwalton): Actually draw a rounded rect.
|
// FIXME(pcwalton): Actually draw a rounded rect.
|
||||||
self.push_rounded_rect_clip(&complex_region.rect.to_nearest_azure_rect(),
|
self.push_rounded_rect_clip(&complex_region.rect.to_nearest_azure_rect(scale),
|
||||||
&complex_region.radii.to_radii_px())
|
&complex_region.radii.to_radii_pixels(scale))
|
||||||
}
|
}
|
||||||
self.transient_clip = Some(clip_region)
|
self.transient_clip = Some(clip_region)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToAzurePoint {
|
pub trait ToAzurePoint {
|
||||||
fn to_nearest_azure_point(&self) -> Point2D<AzFloat>;
|
fn to_nearest_azure_point(&self, pixels_per_px: f32) -> Point2D<AzFloat>;
|
||||||
fn to_azure_point(&self) -> Point2D<AzFloat>;
|
fn to_azure_point(&self) -> Point2D<AzFloat>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToAzurePoint for Point2D<Au> {
|
impl ToAzurePoint for Point2D<Au> {
|
||||||
fn to_nearest_azure_point(&self) -> Point2D<AzFloat> {
|
fn to_nearest_azure_point(&self, pixels_per_px: f32) -> Point2D<AzFloat> {
|
||||||
Point2D::new(self.x.to_nearest_px() as AzFloat, self.y.to_nearest_px() as AzFloat)
|
Point2D::new(self.x.to_nearest_pixel(pixels_per_px) as AzFloat,
|
||||||
|
self.y.to_nearest_pixel(pixels_per_px) as AzFloat)
|
||||||
}
|
}
|
||||||
fn to_azure_point(&self) -> Point2D<AzFloat> {
|
fn to_azure_point(&self) -> Point2D<AzFloat> {
|
||||||
Point2D::new(self.x.to_f32_px(), self.y.to_f32_px())
|
Point2D::new(self.x.to_f32_px(), self.y.to_f32_px())
|
||||||
|
@ -1548,8 +1563,8 @@ impl ToAzurePoint for Point2D<Au> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToAzureRect {
|
pub trait ToAzureRect {
|
||||||
fn to_nearest_azure_rect(&self) -> Rect<AzFloat>;
|
fn to_nearest_azure_rect(&self, pixels_per_px: f32) -> Rect<AzFloat>;
|
||||||
fn to_nearest_non_empty_azure_rect(&self) -> Rect<AzFloat>;
|
fn to_nearest_non_empty_azure_rect(&self, pixels_per_px: f32) -> Rect<AzFloat>;
|
||||||
fn to_azure_rect(&self) -> Rect<AzFloat>;
|
fn to_azure_rect(&self) -> Rect<AzFloat>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1557,7 +1572,7 @@ impl ToAzureRect for Rect<Au> {
|
||||||
|
|
||||||
/// Round rects to pixel coordinates, maintaining the invariant of non-overlap,
|
/// Round rects to pixel coordinates, maintaining the invariant of non-overlap,
|
||||||
/// assuming that before rounding rects don't overlap.
|
/// assuming that before rounding rects don't overlap.
|
||||||
fn to_nearest_azure_rect(&self) -> Rect<AzFloat> {
|
fn to_nearest_azure_rect(&self, pixels_per_px: f32) -> Rect<AzFloat> {
|
||||||
// Rounding the top left corner to the nearest pixel with the size rounded
|
// Rounding the top left corner to the nearest pixel with the size rounded
|
||||||
// to the nearest pixel multiple would violate the non-overlap condition,
|
// to the nearest pixel multiple would violate the non-overlap condition,
|
||||||
// e.g.
|
// e.g.
|
||||||
|
@ -1566,8 +1581,8 @@ impl ToAzureRect for Rect<Au> {
|
||||||
// 10px×10.0px at (0px,7.0px) & 10px×10.0px at (0px,16.0px), which overlap.
|
// 10px×10.0px at (0px,7.0px) & 10px×10.0px at (0px,16.0px), which overlap.
|
||||||
//
|
//
|
||||||
// Instead round each corner to the nearest pixel.
|
// Instead round each corner to the nearest pixel.
|
||||||
let top_left = self.origin.to_nearest_azure_point();
|
let top_left = self.origin.to_nearest_azure_point(pixels_per_px);
|
||||||
let bottom_right = self.bottom_right().to_nearest_azure_point();
|
let bottom_right = self.bottom_right().to_nearest_azure_point(pixels_per_px);
|
||||||
Rect::new(top_left, Size2D::new((bottom_right.x - top_left.x) as AzFloat,
|
Rect::new(top_left, Size2D::new((bottom_right.x - top_left.x) as AzFloat,
|
||||||
(bottom_right.y - top_left.y) as AzFloat))
|
(bottom_right.y - top_left.y) as AzFloat))
|
||||||
}
|
}
|
||||||
|
@ -1577,8 +1592,9 @@ impl ToAzureRect for Rect<Au> {
|
||||||
/// 10px×0.6px at 0px,28.56px -> 10px×0px at 0px,29px
|
/// 10px×0.6px at 0px,28.56px -> 10px×0px at 0px,29px
|
||||||
/// Instead round the top left to the nearest pixel and the size to the nearest pixel
|
/// Instead round the top left to the nearest pixel and the size to the nearest pixel
|
||||||
/// multiple. It's possible for non-overlapping rects after this rounding to overlap.
|
/// multiple. It's possible for non-overlapping rects after this rounding to overlap.
|
||||||
fn to_nearest_non_empty_azure_rect(&self) -> Rect<AzFloat> {
|
fn to_nearest_non_empty_azure_rect(&self, pixels_per_px: f32) -> Rect<AzFloat> {
|
||||||
Rect::new(self.origin.to_nearest_azure_point(), self.size.to_nearest_azure_size())
|
Rect::new(self.origin.to_nearest_azure_point(pixels_per_px),
|
||||||
|
self.size.to_nearest_azure_size(pixels_per_px))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_azure_rect(&self) -> Rect<AzFloat> {
|
fn to_azure_rect(&self) -> Rect<AzFloat> {
|
||||||
|
@ -1586,24 +1602,28 @@ impl ToAzureRect for Rect<Au> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait ToNearestAzureSize {
|
||||||
|
fn to_nearest_azure_size(&self, pixels_per_px: f32) -> Size2D<AzFloat>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToNearestAzureSize for Size2D<Au> {
|
||||||
|
fn to_nearest_azure_size(&self, pixels_per_px: f32) -> Size2D<AzFloat> {
|
||||||
|
Size2D::new(self.width.to_nearest_pixel(pixels_per_px) as AzFloat,
|
||||||
|
self.height.to_nearest_pixel(pixels_per_px) as AzFloat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ToAzureSize {
|
pub trait ToAzureSize {
|
||||||
fn to_nearest_azure_size(&self) -> Size2D<AzFloat>;
|
|
||||||
fn to_azure_size(&self) -> Size2D<AzFloat>;
|
fn to_azure_size(&self) -> Size2D<AzFloat>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToAzureSize for Size2D<Au> {
|
impl ToAzureSize for Size2D<Au> {
|
||||||
fn to_nearest_azure_size(&self) -> Size2D<AzFloat> {
|
|
||||||
Size2D::new(self.width.to_nearest_px() as AzFloat, self.height.to_nearest_px() as AzFloat)
|
|
||||||
}
|
|
||||||
fn to_azure_size(&self) -> Size2D<AzFloat> {
|
fn to_azure_size(&self) -> Size2D<AzFloat> {
|
||||||
Size2D::new(self.width.to_f32_px(), self.height.to_f32_px())
|
Size2D::new(self.width.to_f32_px(), self.height.to_f32_px())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToAzureSize for AzIntSize {
|
impl ToAzureSize for AzIntSize {
|
||||||
fn to_nearest_azure_size(&self) -> Size2D<AzFloat> {
|
|
||||||
Size2D::new(self.width as AzFloat, self.height as AzFloat)
|
|
||||||
}
|
|
||||||
fn to_azure_size(&self) -> Size2D<AzFloat> {
|
fn to_azure_size(&self) -> Size2D<AzFloat> {
|
||||||
Size2D::new(self.width as AzFloat, self.height as AzFloat)
|
Size2D::new(self.width as AzFloat, self.height as AzFloat)
|
||||||
}
|
}
|
||||||
|
@ -1613,46 +1633,34 @@ trait ToAzureIntSize {
|
||||||
fn to_azure_int_size(&self) -> Size2D<i32>;
|
fn to_azure_int_size(&self) -> Size2D<i32>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToAzureIntSize for Size2D<Au> {
|
|
||||||
fn to_azure_int_size(&self) -> Size2D<i32> {
|
|
||||||
Size2D::new(self.width.to_nearest_px() as i32, self.height.to_nearest_px() as i32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToAzureIntSize for Size2D<AzFloat> {
|
impl ToAzureIntSize for Size2D<AzFloat> {
|
||||||
fn to_azure_int_size(&self) -> Size2D<i32> {
|
fn to_azure_int_size(&self) -> Size2D<i32> {
|
||||||
Size2D::new(self.width as i32, self.height as i32)
|
Size2D::new(self.width as i32, self.height as i32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToAzureIntSize for Size2D<i32> {
|
trait ToSideOffsetsPixels {
|
||||||
fn to_azure_int_size(&self) -> Size2D<i32> {
|
fn to_float_pixels(&self, pixels_per_px: f32) -> SideOffsets2D<AzFloat>;
|
||||||
Size2D::new(self.width, self.height)
|
}
|
||||||
|
|
||||||
|
impl ToSideOffsetsPixels for SideOffsets2D<Au> {
|
||||||
|
fn to_float_pixels(&self, pixels_per_px: f32) -> SideOffsets2D<AzFloat> {
|
||||||
|
SideOffsets2D::new(self.top.to_nearest_pixel(pixels_per_px) as AzFloat,
|
||||||
|
self.right.to_nearest_pixel(pixels_per_px) as AzFloat,
|
||||||
|
self.bottom.to_nearest_pixel(pixels_per_px) as AzFloat,
|
||||||
|
self.left.to_nearest_pixel(pixels_per_px) as AzFloat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait ToSideOffsetsPx {
|
trait ToRadiiPixels {
|
||||||
fn to_float_px(&self) -> SideOffsets2D<AzFloat>;
|
fn to_radii_pixels(&self, pixels_per_px: f32) -> BorderRadii<AzFloat>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToSideOffsetsPx for SideOffsets2D<Au> {
|
impl ToRadiiPixels for BorderRadii<Au> {
|
||||||
fn to_float_px(&self) -> SideOffsets2D<AzFloat> {
|
fn to_radii_pixels(&self, pixels_per_px: f32) -> BorderRadii<AzFloat> {
|
||||||
SideOffsets2D::new(self.top.to_nearest_px() as AzFloat,
|
let to_nearest_px = |x: Au| -> AzFloat {
|
||||||
self.right.to_nearest_px() as AzFloat,
|
x.to_nearest_pixel(pixels_per_px) as AzFloat
|
||||||
self.bottom.to_nearest_px() as AzFloat,
|
};
|
||||||
self.left.to_nearest_px() as AzFloat)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait ToRadiiPx {
|
|
||||||
fn to_radii_px(&self) -> BorderRadii<AzFloat>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToRadiiPx for BorderRadii<Au> {
|
|
||||||
fn to_radii_px(&self) -> BorderRadii<AzFloat> {
|
|
||||||
fn to_nearest_px(x: Au) -> AzFloat {
|
|
||||||
x.to_nearest_px() as AzFloat
|
|
||||||
}
|
|
||||||
|
|
||||||
BorderRadii {
|
BorderRadii {
|
||||||
top_left: Size2D { width: to_nearest_px(self.top_left.width),
|
top_left: Size2D { width: to_nearest_px(self.top_left.width),
|
||||||
|
@ -1748,18 +1756,20 @@ trait DrawTargetExtensions {
|
||||||
/// |################################|
|
/// |################################|
|
||||||
/// +--------------------------------+
|
/// +--------------------------------+
|
||||||
/// ```
|
/// ```
|
||||||
fn create_rectangular_border_path<T>(&self, outer_rect: &T, inner_rect: &T)
|
fn create_rectangular_border_path(&self,
|
||||||
-> Path
|
outer_rect: &Rect<Au>,
|
||||||
where T: ToAzureRect;
|
inner_rect: &Rect<Au>,
|
||||||
|
pixels_per_px: f32) -> Path;
|
||||||
|
|
||||||
/// Creates and returns a path that represents a rectangle.
|
/// Creates and returns a path that represents a rectangle.
|
||||||
fn create_rectangular_path(&self, rect: &Rect<Au>) -> Path;
|
fn create_rectangular_path(&self, rect: &Rect<Au>, pixels_per_px: f32) -> Path;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrawTargetExtensions for DrawTarget {
|
impl DrawTargetExtensions for DrawTarget {
|
||||||
fn create_rectangular_border_path<T>(&self, outer_rect: &T, inner_rect: &T)
|
fn create_rectangular_border_path(&self,
|
||||||
-> Path
|
outer_rect: &Rect<Au>,
|
||||||
where T: ToAzureRect {
|
inner_rect: &Rect<Au>,
|
||||||
|
pixels_per_px: f32) -> Path {
|
||||||
// +-----------+
|
// +-----------+
|
||||||
// |2 |1
|
// |2 |1
|
||||||
// | |
|
// | |
|
||||||
|
@ -1772,7 +1782,8 @@ impl DrawTargetExtensions for DrawTarget {
|
||||||
// +-----------+
|
// +-----------+
|
||||||
// 3 4
|
// 3 4
|
||||||
|
|
||||||
let (outer_rect, inner_rect) = (outer_rect.to_nearest_azure_rect(), inner_rect.to_nearest_azure_rect());
|
let outer_rect = outer_rect.to_nearest_azure_rect(pixels_per_px);
|
||||||
|
let inner_rect = inner_rect.to_nearest_azure_rect(pixels_per_px);
|
||||||
let path_builder = self.create_path_builder();
|
let path_builder = self.create_path_builder();
|
||||||
path_builder.move_to(Point2D::new(outer_rect.max_x(), outer_rect.origin.y)); // 1
|
path_builder.move_to(Point2D::new(outer_rect.max_x(), outer_rect.origin.y)); // 1
|
||||||
path_builder.line_to(Point2D::new(outer_rect.origin.x, outer_rect.origin.y)); // 2
|
path_builder.line_to(Point2D::new(outer_rect.origin.x, outer_rect.origin.y)); // 2
|
||||||
|
@ -1787,11 +1798,11 @@ impl DrawTargetExtensions for DrawTarget {
|
||||||
path_builder.finish()
|
path_builder.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_rectangular_path(&self, rect: &Rect<Au>) -> Path {
|
fn create_rectangular_path(&self, rect: &Rect<Au>, pixels_per_px: f32) -> Path {
|
||||||
// Explicitly round to the nearest non-empty rect because when drawing
|
// Explicitly round to the nearest non-empty rect because when drawing
|
||||||
// box-shadow the rect height can be between 0.5px & 1px and could
|
// box-shadow the rect height can be between 0.5px & 1px and could
|
||||||
// otherwise round to an empty rect.
|
// otherwise round to an empty rect.
|
||||||
let rect = rect.to_nearest_non_empty_azure_rect();
|
let rect = rect.to_nearest_non_empty_azure_rect(pixels_per_px);
|
||||||
|
|
||||||
let path_builder = self.create_path_builder();
|
let path_builder = self.create_path_builder();
|
||||||
path_builder.move_to(rect.origin);
|
path_builder.move_to(rect.origin);
|
||||||
|
|
|
@ -236,6 +236,11 @@ impl Au {
|
||||||
((self.0 as f64) / (AU_PER_PX as f64)).round() as i32
|
((self.0 as f64) / (AU_PER_PX as f64)).round() as i32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_nearest_pixel(self, pixels_per_px: f32) -> f32 {
|
||||||
|
((self.0 as f32) / (AU_PER_PX as f32) * pixels_per_px).round() / pixels_per_px
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_f32_px(self) -> f32 {
|
pub fn to_f32_px(self) -> f32 {
|
||||||
(self.0 as f32) / (AU_PER_PX as f32)
|
(self.0 as f32) / (AU_PER_PX as f32)
|
||||||
|
|
|
@ -285,6 +285,7 @@ flaky_cpu == linebreak_simple_a.html linebreak_simple_b.html
|
||||||
== percentage_height_float_a.html percentage_height_float_ref.html
|
== percentage_height_float_a.html percentage_height_float_ref.html
|
||||||
== percentage_height_root.html percentage_height_root_ref.html
|
== percentage_height_root.html percentage_height_root_ref.html
|
||||||
== percentage_width_inline_block_a.html percentage_width_inline_block_ref.html
|
== percentage_width_inline_block_a.html percentage_width_inline_block_ref.html
|
||||||
|
device-pixel-ratio=2 != pixel_snapping_border_a.html pixel_snapping_border_ref.html
|
||||||
== png_rgba_colorspace_a.html png_rgba_colorspace_b.html
|
== png_rgba_colorspace_a.html png_rgba_colorspace_b.html
|
||||||
== position_abs_cb_with_non_cb_kid_a.html position_abs_cb_with_non_cb_kid_b.html
|
== position_abs_cb_with_non_cb_kid_a.html position_abs_cb_with_non_cb_kid_b.html
|
||||||
== position_abs_height_width_a.html position_abs_height_width_b.html
|
== position_abs_height_width_a.html position_abs_height_width_b.html
|
||||||
|
|
18
tests/ref/pixel_snapping_border_a.html
Normal file
18
tests/ref/pixel_snapping_border_a.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Pixel snapping border test</title>
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
height: 101px;
|
||||||
|
width: 101px;
|
||||||
|
border: 0.5px solid black;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
18
tests/ref/pixel_snapping_border_ref.html
Normal file
18
tests/ref/pixel_snapping_border_ref.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Pixel snapping border reference</title>
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
height: 100px;
|
||||||
|
width: 100px;
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue