зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #12543 - Accumulate subpixels through stacking contexts (from mrobinson:off-by-one-ng); r=pcwalton
<!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [X] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Instead of simply rounding layer origins and discarding subpixel offsets, accumulate them by transforming them into the space of the next child stacking context. This is an attempt to eliminate subpixel differences that are caused by different stacking context boundaries in reference tests. Currently these accumulated subpixels are only used for text positioning, but the plan is that they can be used for all drawing in the future. Source-Repo: https://github.com/servo/servo Source-Revision: 4077ae7d04e64d66e2dfd1577dc4d337c45fecd4
This commit is contained in:
Родитель
325364ad0a
Коммит
849f2102d3
|
@ -382,7 +382,11 @@ impl DisplayList {
|
||||||
current_item_index: start,
|
current_item_index: start,
|
||||||
last_item_index: end,
|
last_item_index: end,
|
||||||
};
|
};
|
||||||
self.draw_stacking_context(stacking_context, &mut traversal, paint_context, transform);
|
self.draw_stacking_context(stacking_context,
|
||||||
|
&mut traversal,
|
||||||
|
paint_context,
|
||||||
|
transform,
|
||||||
|
&Point2D::zero());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_stacking_context_contents<'a>(&'a self,
|
fn draw_stacking_context_contents<'a>(&'a self,
|
||||||
|
@ -390,6 +394,7 @@ impl DisplayList {
|
||||||
traversal: &mut DisplayListTraversal<'a>,
|
traversal: &mut DisplayListTraversal<'a>,
|
||||||
paint_context: &mut PaintContext,
|
paint_context: &mut PaintContext,
|
||||||
transform: &Matrix4D<f32>,
|
transform: &Matrix4D<f32>,
|
||||||
|
subpixel_offset: &Point2D<Au>,
|
||||||
tile_rect: Option<Rect<Au>>) {
|
tile_rect: Option<Rect<Au>>) {
|
||||||
for child in stacking_context.children.iter() {
|
for child in stacking_context.children.iter() {
|
||||||
while let Some(item) = traversal.advance(stacking_context) {
|
while let Some(item) = traversal.advance(stacking_context) {
|
||||||
|
@ -399,7 +404,11 @@ impl DisplayList {
|
||||||
}
|
}
|
||||||
|
|
||||||
if child.intersects_rect_in_parent_context(tile_rect) {
|
if child.intersects_rect_in_parent_context(tile_rect) {
|
||||||
self.draw_stacking_context(child, traversal, paint_context, &transform);
|
self.draw_stacking_context(child,
|
||||||
|
traversal,
|
||||||
|
paint_context,
|
||||||
|
&transform,
|
||||||
|
subpixel_offset);
|
||||||
} else {
|
} else {
|
||||||
traversal.skip_past_stacking_context(child);
|
traversal.skip_past_stacking_context(child);
|
||||||
}
|
}
|
||||||
|
@ -417,12 +426,14 @@ impl DisplayList {
|
||||||
stacking_context: &StackingContext,
|
stacking_context: &StackingContext,
|
||||||
traversal: &mut DisplayListTraversal<'a>,
|
traversal: &mut DisplayListTraversal<'a>,
|
||||||
paint_context: &mut PaintContext,
|
paint_context: &mut PaintContext,
|
||||||
transform: &Matrix4D<f32>) {
|
transform: &Matrix4D<f32>,
|
||||||
|
subpixel_offset: &Point2D<Au>) {
|
||||||
if stacking_context.context_type != StackingContextType::Real {
|
if stacking_context.context_type != StackingContextType::Real {
|
||||||
self.draw_stacking_context_contents(stacking_context,
|
self.draw_stacking_context_contents(stacking_context,
|
||||||
traversal,
|
traversal,
|
||||||
paint_context,
|
paint_context,
|
||||||
transform,
|
transform,
|
||||||
|
subpixel_offset,
|
||||||
None);
|
None);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -431,18 +442,35 @@ impl DisplayList {
|
||||||
&stacking_context.filters,
|
&stacking_context.filters,
|
||||||
stacking_context.blend_mode);
|
stacking_context.blend_mode);
|
||||||
|
|
||||||
// If a layer is being used, the transform for this layer
|
|
||||||
// will be handled by the compositor.
|
|
||||||
let old_transform = paint_context.draw_target.get_transform();
|
let old_transform = paint_context.draw_target.get_transform();
|
||||||
let transform = match stacking_context.layer_info {
|
let pixels_per_px = paint_context.screen_pixels_per_px();
|
||||||
Some(..) => *transform,
|
let (transform, subpixel_offset) = match stacking_context.layer_info {
|
||||||
|
// If this stacking context starts a layer, the offset and transformation are handled
|
||||||
|
// by layer position within the compositor.
|
||||||
|
Some(..) => (*transform, *subpixel_offset),
|
||||||
None => {
|
None => {
|
||||||
let pixels_per_px = paint_context.screen_pixels_per_px();
|
let origin = stacking_context.bounds.origin + *subpixel_offset;
|
||||||
let origin = &stacking_context.bounds.origin;
|
let pixel_snapped_origin =
|
||||||
transform.translate(
|
Point2D::new(origin.x.to_nearest_pixel(pixels_per_px.get()),
|
||||||
origin.x.to_nearest_pixel(pixels_per_px.get()) as AzFloat,
|
origin.y.to_nearest_pixel(pixels_per_px.get()));
|
||||||
origin.y.to_nearest_pixel(pixels_per_px.get()) as AzFloat,
|
|
||||||
0.0).mul(&stacking_context.transform)
|
let transform = transform.translate(pixel_snapped_origin.x as AzFloat,
|
||||||
|
pixel_snapped_origin.y as AzFloat,
|
||||||
|
0.0).mul(&stacking_context.transform);
|
||||||
|
let inverse_transform = transform.invert();
|
||||||
|
|
||||||
|
// Here we are trying to accumulate any subpixel distances across transformed
|
||||||
|
// stacking contexts. This allows us transform stacking context with a
|
||||||
|
// pixel-snapped transform, but continue to propagate any subpixels from stacking
|
||||||
|
// context origins to children.
|
||||||
|
let subpixel_offset = Point2D::new(origin.x.to_f32_px() - pixel_snapped_origin.x,
|
||||||
|
origin.y.to_f32_px() - pixel_snapped_origin.y);
|
||||||
|
let subpixel_offset = inverse_transform.transform_point(&subpixel_offset) -
|
||||||
|
inverse_transform.transform_point(&Point2D::zero());;
|
||||||
|
let subpixel_offset = Point2D::new(Au::from_f32_px(subpixel_offset.x),
|
||||||
|
Au::from_f32_px(subpixel_offset.y));
|
||||||
|
|
||||||
|
(transform, subpixel_offset)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -455,6 +483,7 @@ impl DisplayList {
|
||||||
clip_rect: Some(stacking_context.overflow),
|
clip_rect: Some(stacking_context.overflow),
|
||||||
transient_clip: None,
|
transient_clip: None,
|
||||||
layer_kind: paint_context.layer_kind,
|
layer_kind: paint_context.layer_kind,
|
||||||
|
subpixel_offset: subpixel_offset,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set up our clip rect and transform.
|
// Set up our clip rect and transform.
|
||||||
|
@ -469,6 +498,7 @@ impl DisplayList {
|
||||||
traversal,
|
traversal,
|
||||||
&mut paint_subcontext,
|
&mut paint_subcontext,
|
||||||
&transform,
|
&transform,
|
||||||
|
&subpixel_offset,
|
||||||
Some(transformed_tile_rect(paint_context.screen_rect, &transform)));
|
Some(transformed_tile_rect(paint_context.screen_rect, &transform)));
|
||||||
|
|
||||||
paint_subcontext.remove_transient_clip_if_applicable();
|
paint_subcontext.remove_transient_clip_if_applicable();
|
||||||
|
|
|
@ -53,6 +53,10 @@ pub struct PaintContext<'a> {
|
||||||
pub transient_clip: Option<ClippingRegion>,
|
pub transient_clip: Option<ClippingRegion>,
|
||||||
/// A temporary hack to disable clipping optimizations on 3d layers.
|
/// A temporary hack to disable clipping optimizations on 3d layers.
|
||||||
pub layer_kind: LayerKind,
|
pub layer_kind: LayerKind,
|
||||||
|
/// The current subpixel offset, used to make pixel snapping aware of accumulated subpixels
|
||||||
|
/// from the StackingContext.
|
||||||
|
/// TODO: Eventually this should be added to all points handled by the PaintContext.
|
||||||
|
pub subpixel_offset: Point2D<Au>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
@ -1338,24 +1342,26 @@ impl<'a> PaintContext<'a> {
|
||||||
pub fn draw_text(&mut self, text: &TextDisplayItem) {
|
pub fn draw_text(&mut self, text: &TextDisplayItem) {
|
||||||
let draw_target_transform = self.draw_target.get_transform();
|
let draw_target_transform = self.draw_target.get_transform();
|
||||||
|
|
||||||
|
let origin = text.baseline_origin + self.subpixel_offset;
|
||||||
|
|
||||||
// Optimization: Don’t set a transform matrix for upright text, and pass a start point to
|
// Optimization: Don’t set a transform matrix for upright text, and pass a start point to
|
||||||
// `draw_text_into_context`.
|
// `draw_text_into_context`.
|
||||||
//
|
//
|
||||||
// For sideways text, it’s easier to do the rotation such that its center (the baseline’s
|
// For sideways text, it’s easier to do the rotation such that its center (the baseline’s
|
||||||
// start point) is at (0, 0) coordinates.
|
// start point) is at (0, 0) coordinates.
|
||||||
let baseline_origin = match text.orientation {
|
let baseline_origin = match text.orientation {
|
||||||
Upright => text.baseline_origin,
|
Upright => origin,
|
||||||
SidewaysLeft => {
|
SidewaysLeft => {
|
||||||
let x = text.baseline_origin.x.to_f32_px();
|
let x = origin.x.to_f32_px();
|
||||||
let y = text.baseline_origin.y.to_f32_px();
|
let y = origin.y.to_f32_px();
|
||||||
self.draw_target.set_transform(&draw_target_transform.mul(&Matrix2D::new(0., -1.,
|
self.draw_target.set_transform(&draw_target_transform.mul(&Matrix2D::new(0., -1.,
|
||||||
1., 0.,
|
1., 0.,
|
||||||
x, y)));
|
x, y)));
|
||||||
Point2D::zero()
|
Point2D::zero()
|
||||||
}
|
}
|
||||||
SidewaysRight => {
|
SidewaysRight => {
|
||||||
let x = text.baseline_origin.x.to_f32_px();
|
let x = origin.x.to_f32_px();
|
||||||
let y = text.baseline_origin.y.to_f32_px();
|
let y = origin.y.to_f32_px();
|
||||||
self.draw_target.set_transform(&draw_target_transform.mul(&Matrix2D::new(0., 1.,
|
self.draw_target.set_transform(&draw_target_transform.mul(&Matrix2D::new(0., 1.,
|
||||||
-1., 0.,
|
-1., 0.,
|
||||||
x, y)));
|
x, y)));
|
||||||
|
@ -1382,10 +1388,7 @@ impl<'a> PaintContext<'a> {
|
||||||
// Blur, if necessary.
|
// Blur, if necessary.
|
||||||
self.blur_if_necessary(temporary_draw_target, text.blur_radius);
|
self.blur_if_necessary(temporary_draw_target, text.blur_radius);
|
||||||
|
|
||||||
// Undo the transform, only when we did one.
|
self.draw_target.set_transform(&draw_target_transform)
|
||||||
if text.orientation != Upright {
|
|
||||||
self.draw_target.set_transform(&draw_target_transform)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws a linear gradient in the given boundaries from the given start point to the given end
|
/// Draws a linear gradient in the given boundaries from the given start point to the given end
|
||||||
|
|
|
@ -690,6 +690,7 @@ impl WorkerThread {
|
||||||
clip_rect: None,
|
clip_rect: None,
|
||||||
transient_clip: None,
|
transient_clip: None,
|
||||||
layer_kind: layer_kind,
|
layer_kind: layer_kind,
|
||||||
|
subpixel_offset: Point2D::zero(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Apply the translation to paint the tile we want.
|
// Apply the translation to paint the tile we want.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче