mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Merge pull request #3110 from SimonSapin/writing-modes-reftest
Add a basic CSS Writing Modes reftest
This commit is contained in:
commit
a0d70c4cfd
13 changed files with 554 additions and 86 deletions
|
@ -316,7 +316,6 @@ impl DisplayList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Appends the given item to the display list.
|
/// Appends the given item to the display list.
|
||||||
pub fn push(&mut self, item: DisplayItem) {
|
pub fn push(&mut self, item: DisplayItem) {
|
||||||
self.list.push(item)
|
self.list.push(item)
|
||||||
|
@ -328,6 +327,14 @@ impl DisplayList {
|
||||||
self.list.append(other.list)
|
self.list.append(other.list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn debug(&self) {
|
||||||
|
if log_enabled!(::log::DEBUG) {
|
||||||
|
for item in self.list.iter() {
|
||||||
|
item.debug_with_level(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Draws the display list into the given render context. The display list must be flattened
|
/// Draws the display list into the given render context. The display list must be flattened
|
||||||
/// first for correct painting.
|
/// first for correct painting.
|
||||||
pub fn draw_into_context(&self, render_context: &mut RenderContext) {
|
pub fn draw_into_context(&self, render_context: &mut RenderContext) {
|
||||||
|
@ -724,14 +731,14 @@ impl DisplayItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_with_level(&self, level: uint) {
|
pub fn debug_with_level(&self, level: uint) {
|
||||||
let mut indent = String::new();
|
let mut indent = String::new();
|
||||||
for _ in range(0, level) {
|
for _ in range(0, level) {
|
||||||
indent.push_str("| ")
|
indent.push_str("| ")
|
||||||
}
|
}
|
||||||
debug!("{}+ {}", indent, self);
|
debug!("{}+ {}", indent, self);
|
||||||
for child in self.children() {
|
for child in self.children() {
|
||||||
child.debug_with_level(level + 1);
|
child.debug_with_level(level + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1110,16 +1110,18 @@ impl BlockFlow {
|
||||||
.relative_containing_block_size,
|
.relative_containing_block_size,
|
||||||
None);
|
None);
|
||||||
|
|
||||||
|
// FIXME(#2795): Get the real container size
|
||||||
|
let container_size = Size2D::zero();
|
||||||
|
|
||||||
// Add the box that starts the block context.
|
// Add the box that starts the block context.
|
||||||
let mut display_list = DisplayList::new();
|
let mut display_list = DisplayList::new();
|
||||||
let mut accumulator =
|
let mut accumulator = self.fragment.build_display_list(
|
||||||
self.fragment.build_display_list(&mut display_list,
|
&mut display_list,
|
||||||
layout_context,
|
layout_context,
|
||||||
self.base.abs_position
|
self.base.abs_position + (offset + rel_offset).to_physical(
|
||||||
.add_point(&offset)
|
self.base.writing_mode, container_size),
|
||||||
+ rel_offset,
|
background_border_level,
|
||||||
background_border_level,
|
None);
|
||||||
None);
|
|
||||||
|
|
||||||
let mut child_layers = DList::new();
|
let mut child_layers = DList::new();
|
||||||
for kid in self.base.child_iter() {
|
for kid in self.base.child_iter() {
|
||||||
|
@ -1592,17 +1594,22 @@ impl Flow for BlockFlow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_absolute_position(&mut self) {
|
fn compute_absolute_position(&mut self) {
|
||||||
|
// FIXME(#2795): Get the real container size
|
||||||
|
let container_size = Size2D::zero();
|
||||||
|
|
||||||
if self.is_absolutely_positioned() {
|
if self.is_absolutely_positioned() {
|
||||||
|
let position_start = self.base.position.start.to_physical(
|
||||||
|
self.base.writing_mode, container_size);
|
||||||
self.base
|
self.base
|
||||||
.absolute_position_info
|
.absolute_position_info
|
||||||
.absolute_containing_block_position = if self.is_fixed() {
|
.absolute_containing_block_position = if self.is_fixed() {
|
||||||
// The viewport is initially at (0, 0).
|
// The viewport is initially at (0, 0).
|
||||||
self.base.position.start
|
position_start
|
||||||
} else {
|
} else {
|
||||||
// Absolute position of the containing block + position of absolute flow w/r/t the
|
// Absolute position of the containing block + position of absolute flow w/r/t the
|
||||||
// containing block.
|
// containing block.
|
||||||
self.base.absolute_position_info.absolute_containing_block_position
|
self.base.absolute_position_info.absolute_containing_block_position
|
||||||
.add_point(&self.base.position.start)
|
+ position_start
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set the absolute position, which will be passed down later as part
|
// Set the absolute position, which will be passed down later as part
|
||||||
|
@ -1622,8 +1629,8 @@ impl Flow for BlockFlow {
|
||||||
if self.is_positioned() {
|
if self.is_positioned() {
|
||||||
self.base.absolute_position_info.absolute_containing_block_position =
|
self.base.absolute_position_info.absolute_containing_block_position =
|
||||||
self.base.abs_position
|
self.base.abs_position
|
||||||
.add_point(&self.generated_containing_block_rect().start)
|
+ (self.generated_containing_block_rect().start
|
||||||
+ relative_offset
|
+ relative_offset).to_physical(self.base.writing_mode, container_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
let float_offset = if self.is_float() {
|
let float_offset = if self.is_float() {
|
||||||
|
@ -1640,14 +1647,14 @@ impl Flow for BlockFlow {
|
||||||
|
|
||||||
// Process children.
|
// Process children.
|
||||||
let this_position = self.base.abs_position;
|
let this_position = self.base.abs_position;
|
||||||
|
let writing_mode = self.base.writing_mode;
|
||||||
for kid in self.base.child_iter() {
|
for kid in self.base.child_iter() {
|
||||||
if !kid.is_absolutely_positioned() {
|
if !kid.is_absolutely_positioned() {
|
||||||
let kid_base = flow::mut_base(kid);
|
let kid_base = flow::mut_base(kid);
|
||||||
kid_base.abs_position =
|
kid_base.abs_position = this_position + (
|
||||||
this_position
|
kid_base.position.start
|
||||||
.add_point(&kid_base.position.start)
|
|
||||||
.add_point(&float_offset)
|
.add_point(&float_offset)
|
||||||
+ relative_offset;
|
+ relative_offset).to_physical(writing_mode, container_size);
|
||||||
kid_base.absolute_position_info = absolute_position_info
|
kid_base.absolute_position_info = absolute_position_info
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,13 +46,15 @@ use table_cell::TableCellFlow;
|
||||||
use wrapper::ThreadSafeLayoutNode;
|
use wrapper::ThreadSafeLayoutNode;
|
||||||
|
|
||||||
use collections::dlist::DList;
|
use collections::dlist::DList;
|
||||||
|
use geom::Point2D;
|
||||||
use gfx::display_list::DisplayList;
|
use gfx::display_list::DisplayList;
|
||||||
use gfx::render_task::RenderLayer;
|
use gfx::render_task::RenderLayer;
|
||||||
use servo_msg::compositor_msg::LayerId;
|
use servo_msg::compositor_msg::LayerId;
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use servo_util::logical_geometry::WritingMode;
|
use servo_util::logical_geometry::WritingMode;
|
||||||
use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
|
use servo_util::logical_geometry::{LogicalRect, LogicalSize};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::num::Zero;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::Zip;
|
use std::iter::Zip;
|
||||||
use std::sync::atomics::{AtomicUint, Relaxed, SeqCst};
|
use std::sync::atomics::{AtomicUint, Relaxed, SeqCst};
|
||||||
|
@ -596,7 +598,7 @@ pub struct AbsolutePositionInfo {
|
||||||
/// The size of the containing block for relatively-positioned descendants.
|
/// The size of the containing block for relatively-positioned descendants.
|
||||||
pub relative_containing_block_size: LogicalSize<Au>,
|
pub relative_containing_block_size: LogicalSize<Au>,
|
||||||
/// The position of the absolute containing block.
|
/// The position of the absolute containing block.
|
||||||
pub absolute_containing_block_position: LogicalPoint<Au>,
|
pub absolute_containing_block_position: Point2D<Au>,
|
||||||
/// Whether the absolute containing block forces positioned descendants to be layerized.
|
/// Whether the absolute containing block forces positioned descendants to be layerized.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): Move into `FlowFlags`.
|
/// FIXME(pcwalton): Move into `FlowFlags`.
|
||||||
|
@ -609,7 +611,7 @@ impl AbsolutePositionInfo {
|
||||||
// of the root layer.
|
// of the root layer.
|
||||||
AbsolutePositionInfo {
|
AbsolutePositionInfo {
|
||||||
relative_containing_block_size: LogicalSize::zero(writing_mode),
|
relative_containing_block_size: LogicalSize::zero(writing_mode),
|
||||||
absolute_containing_block_position: LogicalPoint::zero(writing_mode),
|
absolute_containing_block_position: Zero::zero(),
|
||||||
layers_needed_for_positioned_flows: false,
|
layers_needed_for_positioned_flows: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -660,7 +662,7 @@ pub struct BaseFlow {
|
||||||
pub collapsible_margins: CollapsibleMargins,
|
pub collapsible_margins: CollapsibleMargins,
|
||||||
|
|
||||||
/// The position of this flow in page coordinates, computed during display list construction.
|
/// The position of this flow in page coordinates, computed during display list construction.
|
||||||
pub abs_position: LogicalPoint<Au>,
|
pub abs_position: Point2D<Au>,
|
||||||
|
|
||||||
/// Details about descendants with position 'absolute' or 'fixed' for which we are the
|
/// Details about descendants with position 'absolute' or 'fixed' for which we are the
|
||||||
/// containing block. This is in tree order. This includes any direct children.
|
/// containing block. This is in tree order. This includes any direct children.
|
||||||
|
@ -724,7 +726,7 @@ impl BaseFlow {
|
||||||
|
|
||||||
floats: Floats::new(writing_mode),
|
floats: Floats::new(writing_mode),
|
||||||
collapsible_margins: CollapsibleMargins::new(),
|
collapsible_margins: CollapsibleMargins::new(),
|
||||||
abs_position: LogicalPoint::zero(writing_mode),
|
abs_position: Zero::zero(),
|
||||||
abs_descendants: Descendants::new(),
|
abs_descendants: Descendants::new(),
|
||||||
absolute_static_i_offset: Au::new(0),
|
absolute_static_i_offset: Au::new(0),
|
||||||
fixed_static_i_offset: Au::new(0),
|
fixed_static_i_offset: Au::new(0),
|
||||||
|
|
|
@ -37,7 +37,7 @@ use servo_net::image::holder::ImageHolder;
|
||||||
use servo_net::local_image_cache::LocalImageCache;
|
use servo_net::local_image_cache::LocalImageCache;
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use servo_util::geometry;
|
use servo_util::geometry;
|
||||||
use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, LogicalMargin};
|
use servo_util::logical_geometry::{LogicalRect, LogicalSize, LogicalMargin};
|
||||||
use servo_util::range::*;
|
use servo_util::range::*;
|
||||||
use servo_util::namespace;
|
use servo_util::namespace;
|
||||||
use servo_util::smallvec::SmallVec;
|
use servo_util::smallvec::SmallVec;
|
||||||
|
@ -776,15 +776,15 @@ impl Fragment {
|
||||||
|
|
||||||
fn build_debug_borders_around_text_fragments(&self,
|
fn build_debug_borders_around_text_fragments(&self,
|
||||||
display_list: &mut DisplayList,
|
display_list: &mut DisplayList,
|
||||||
flow_origin: LogicalPoint<Au>,
|
flow_origin: Point2D<Au>,
|
||||||
text_fragment: &ScannedTextFragmentInfo) {
|
text_fragment: &ScannedTextFragmentInfo) {
|
||||||
let mut fragment_bounds = self.border_box.clone();
|
|
||||||
fragment_bounds.start.i = fragment_bounds.start.i + flow_origin.i;
|
|
||||||
fragment_bounds.start.b = fragment_bounds.start.b + flow_origin.b;
|
|
||||||
// FIXME(#2795): Get the real container size
|
// FIXME(#2795): Get the real container size
|
||||||
let container_size = Size2D::zero();
|
let container_size = Size2D::zero();
|
||||||
let absolute_fragment_bounds = fragment_bounds.to_physical(
|
// Fragment position wrt to the owning flow.
|
||||||
self.style.writing_mode, container_size);
|
let fragment_bounds = self.border_box.to_physical(self.style.writing_mode, container_size);
|
||||||
|
let absolute_fragment_bounds = Rect(
|
||||||
|
fragment_bounds.origin + flow_origin,
|
||||||
|
fragment_bounds.size);
|
||||||
|
|
||||||
// Compute the text fragment bounds and draw a border surrounding them.
|
// Compute the text fragment bounds and draw a border surrounding them.
|
||||||
let border_display_item = box BorderDisplayItem {
|
let border_display_item = box BorderDisplayItem {
|
||||||
|
@ -797,13 +797,11 @@ impl Fragment {
|
||||||
|
|
||||||
// Draw a rectangle representing the baselines.
|
// Draw a rectangle representing the baselines.
|
||||||
let ascent = text_fragment.run.ascent();
|
let ascent = text_fragment.run.ascent();
|
||||||
let baseline = LogicalRect::new(
|
let mut baseline = self.border_box.clone();
|
||||||
self.style.writing_mode,
|
baseline.start.b = baseline.start.b + ascent;
|
||||||
fragment_bounds.start.i,
|
baseline.size.block = Au(0);
|
||||||
fragment_bounds.start.b + ascent,
|
let mut baseline = baseline.to_physical(self.style.writing_mode, container_size);
|
||||||
fragment_bounds.size.inline,
|
baseline.origin = baseline.origin + flow_origin;
|
||||||
Au(0)
|
|
||||||
).to_physical(self.style.writing_mode, container_size);
|
|
||||||
|
|
||||||
let line_display_item = box LineDisplayItem {
|
let line_display_item = box LineDisplayItem {
|
||||||
base: BaseDisplayItem::new(baseline, self.node, ContentStackingLevel),
|
base: BaseDisplayItem::new(baseline, self.node, ContentStackingLevel),
|
||||||
|
@ -815,14 +813,14 @@ impl Fragment {
|
||||||
|
|
||||||
fn build_debug_borders_around_fragment(&self,
|
fn build_debug_borders_around_fragment(&self,
|
||||||
display_list: &mut DisplayList,
|
display_list: &mut DisplayList,
|
||||||
flow_origin: LogicalPoint<Au>) {
|
flow_origin: Point2D<Au>) {
|
||||||
let mut fragment_bounds = self.border_box.clone();
|
|
||||||
fragment_bounds.start.i = fragment_bounds.start.i + flow_origin.i;
|
|
||||||
fragment_bounds.start.b = fragment_bounds.start.b + flow_origin.b;
|
|
||||||
// FIXME(#2795): Get the real container size
|
// FIXME(#2795): Get the real container size
|
||||||
let container_size = Size2D::zero();
|
let container_size = Size2D::zero();
|
||||||
let absolute_fragment_bounds = fragment_bounds.to_physical(
|
// Fragment position wrt to the owning flow.
|
||||||
self.style.writing_mode, container_size);
|
let fragment_bounds = self.border_box.to_physical(self.style.writing_mode, container_size);
|
||||||
|
let absolute_fragment_bounds = Rect(
|
||||||
|
fragment_bounds.origin + flow_origin,
|
||||||
|
fragment_bounds.size);
|
||||||
|
|
||||||
// This prints a debug border around the border of this fragment.
|
// This prints a debug border around the border of this fragment.
|
||||||
let border_display_item = box BorderDisplayItem {
|
let border_display_item = box BorderDisplayItem {
|
||||||
|
@ -845,18 +843,17 @@ impl Fragment {
|
||||||
pub fn build_display_list(&self,
|
pub fn build_display_list(&self,
|
||||||
display_list: &mut DisplayList,
|
display_list: &mut DisplayList,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
flow_origin: LogicalPoint<Au>,
|
flow_origin: Point2D<Au>,
|
||||||
background_and_border_level: BackgroundAndBorderLevel,
|
background_and_border_level: BackgroundAndBorderLevel,
|
||||||
inline_fragment_context: Option<InlineFragmentContext>)
|
inline_fragment_context: Option<InlineFragmentContext>)
|
||||||
-> ChildDisplayListAccumulator {
|
-> ChildDisplayListAccumulator {
|
||||||
// Fragment position wrt to the owning flow.
|
|
||||||
let mut fragment_bounds = self.border_box.clone();
|
|
||||||
fragment_bounds.start.i = fragment_bounds.start.i + flow_origin.i;
|
|
||||||
fragment_bounds.start.b = fragment_bounds.start.b + flow_origin.b;
|
|
||||||
// FIXME(#2795): Get the real container size
|
// FIXME(#2795): Get the real container size
|
||||||
let container_size = Size2D::zero();
|
let container_size = Size2D::zero();
|
||||||
let absolute_fragment_bounds = fragment_bounds.to_physical(
|
// Fragment position wrt to the owning flow.
|
||||||
self.style.writing_mode, container_size);
|
let fragment_bounds = self.border_box.to_physical(self.style.writing_mode, container_size);
|
||||||
|
let absolute_fragment_bounds = Rect(
|
||||||
|
fragment_bounds.origin + flow_origin,
|
||||||
|
fragment_bounds.size);
|
||||||
debug!("Fragment::build_display_list at rel={}, abs={}: {}",
|
debug!("Fragment::build_display_list at rel={}, abs={}: {}",
|
||||||
self.border_box,
|
self.border_box,
|
||||||
absolute_fragment_bounds,
|
absolute_fragment_bounds,
|
||||||
|
@ -1413,21 +1410,18 @@ impl Fragment {
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn finalize_position_and_size_of_iframe(&self,
|
fn finalize_position_and_size_of_iframe(&self,
|
||||||
iframe_fragment: &IframeFragmentInfo,
|
iframe_fragment: &IframeFragmentInfo,
|
||||||
offset: LogicalPoint<Au>,
|
offset: Point2D<Au>,
|
||||||
layout_context: &LayoutContext) {
|
layout_context: &LayoutContext) {
|
||||||
let inline_start = offset.i + self.margin.inline_start + self.border_padding.inline_start;
|
let mbp = (self.margin + self.border_padding).to_physical(self.style.writing_mode);
|
||||||
let block_start = offset.b + self.margin.block_start + self.border_padding.block_start;
|
let content_size = self.content_box().size.to_physical(self.style.writing_mode);
|
||||||
let inline_size = self.content_box().size.inline;
|
|
||||||
let block_size = self.content_box().size.block;
|
let left = offset.x + mbp.left;
|
||||||
// FIXME(#2795): Get the real container size
|
let top = offset.y + mbp.top;
|
||||||
let container_size = Size2D::zero();
|
let width = content_size.width;
|
||||||
let rect = LogicalRect::new(
|
let height = content_size.height;
|
||||||
self.style.writing_mode,
|
let origin = Point2D(geometry::to_frac_px(left) as f32, geometry::to_frac_px(top) as f32);
|
||||||
geometry::to_frac_px(inline_start) as f32,
|
let size = Size2D(geometry::to_frac_px(width) as f32, geometry::to_frac_px(height) as f32);
|
||||||
geometry::to_frac_px(block_start) as f32,
|
let rect = Rect(origin, size);
|
||||||
geometry::to_frac_px(inline_size) as f32,
|
|
||||||
geometry::to_frac_px(block_size) as f32
|
|
||||||
).to_physical(self.style.writing_mode, container_size);
|
|
||||||
|
|
||||||
debug!("finalizing position and size of iframe for {:?},{:?}",
|
debug!("finalizing position and size of iframe for {:?},{:?}",
|
||||||
iframe_fragment.pipeline_id,
|
iframe_fragment.pipeline_id,
|
||||||
|
|
|
@ -16,7 +16,7 @@ use text;
|
||||||
use wrapper::ThreadSafeLayoutNode;
|
use wrapper::ThreadSafeLayoutNode;
|
||||||
|
|
||||||
use collections::{Deque, RingBuf};
|
use collections::{Deque, RingBuf};
|
||||||
use geom::Size2D;
|
use geom::Rect;
|
||||||
use gfx::display_list::ContentLevel;
|
use gfx::display_list::ContentLevel;
|
||||||
use gfx::font::FontMetrics;
|
use gfx::font::FontMetrics;
|
||||||
use gfx::font_context::FontContext;
|
use gfx::font_context::FontContext;
|
||||||
|
@ -927,12 +927,8 @@ impl InlineFlow {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_display_list_inline(&mut self, layout_context: &LayoutContext) {
|
pub fn build_display_list_inline(&mut self, layout_context: &LayoutContext) {
|
||||||
let abs_rect = LogicalRect::from_point_size(
|
let size = self.base.position.size.to_physical(self.base.writing_mode);
|
||||||
self.base.writing_mode, self.base.abs_position, self.base.position.size);
|
if !Rect(self.base.abs_position, size).intersects(&layout_context.shared.dirty) {
|
||||||
// FIXME(#2795): Get the real container size
|
|
||||||
let container_size = Size2D::zero();
|
|
||||||
if !abs_rect.to_physical(self.base.writing_mode, container_size)
|
|
||||||
.intersects(&layout_context.shared.dirty) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -947,7 +943,8 @@ impl InlineFlow {
|
||||||
Some(context));
|
Some(context));
|
||||||
drop(fragment.build_display_list(&mut self.base.display_list,
|
drop(fragment.build_display_list(&mut self.base.display_list,
|
||||||
layout_context,
|
layout_context,
|
||||||
self.base.abs_position + rel_offset,
|
self.base.abs_position.add_size(
|
||||||
|
&rel_offset.to_physical(self.base.writing_mode)),
|
||||||
ContentLevel,
|
ContentLevel,
|
||||||
Some(context)));
|
Some(context)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ use gfx::font_cache_task::{FontCacheTask};
|
||||||
use servo_net::local_image_cache::{ImageResponder, LocalImageCache};
|
use servo_net::local_image_cache::{ImageResponder, LocalImageCache};
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use servo_util::geometry;
|
use servo_util::geometry;
|
||||||
|
use servo_util::logical_geometry::LogicalPoint;
|
||||||
use servo_util::opts::Opts;
|
use servo_util::opts::Opts;
|
||||||
use servo_util::smallvec::{SmallVec, SmallVec1};
|
use servo_util::smallvec::{SmallVec, SmallVec1};
|
||||||
use servo_util::time::{TimeProfilerChan, profile};
|
use servo_util::time::{TimeProfilerChan, profile};
|
||||||
|
@ -694,10 +695,10 @@ impl LayoutTask {
|
||||||
if data.goal == ReflowForDisplay {
|
if data.goal == ReflowForDisplay {
|
||||||
let writing_mode = flow::base(layout_root.get()).writing_mode;
|
let writing_mode = flow::base(layout_root.get()).writing_mode;
|
||||||
profile(time::LayoutDispListBuildCategory, self.time_profiler_chan.clone(), || {
|
profile(time::LayoutDispListBuildCategory, self.time_profiler_chan.clone(), || {
|
||||||
// FIXME(#2795): Get the real container size
|
|
||||||
let container_size = Size2D::zero();
|
|
||||||
shared_layout_ctx.dirty = flow::base(layout_root.get()).position.to_physical(
|
shared_layout_ctx.dirty = flow::base(layout_root.get()).position.to_physical(
|
||||||
writing_mode, container_size);
|
writing_mode, self.screen_size);
|
||||||
|
flow::mut_base(layout_root.get_mut()).abs_position =
|
||||||
|
LogicalPoint::zero(writing_mode).to_physical(writing_mode, self.screen_size);
|
||||||
|
|
||||||
match self.parallel_traversal {
|
match self.parallel_traversal {
|
||||||
None => {
|
None => {
|
||||||
|
@ -718,6 +719,7 @@ impl LayoutTask {
|
||||||
let root_display_list =
|
let root_display_list =
|
||||||
mem::replace(&mut flow::mut_base(layout_root.get_mut()).display_list,
|
mem::replace(&mut flow::mut_base(layout_root.get_mut()).display_list,
|
||||||
DisplayList::new());
|
DisplayList::new());
|
||||||
|
root_display_list.debug();
|
||||||
let display_list = Arc::new(root_display_list.flatten(ContentStackingLevel));
|
let display_list = Arc::new(root_display_list.flatten(ContentStackingLevel));
|
||||||
|
|
||||||
// FIXME(pcwalton): This is really ugly and can't handle overflow: scroll. Refactor
|
// FIXME(pcwalton): This is really ugly and can't handle overflow: scroll. Refactor
|
||||||
|
|
|
@ -79,8 +79,7 @@ impl Default for Au {
|
||||||
|
|
||||||
impl fmt::Show for Au {
|
impl fmt::Show for Au {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let Au(n) = *self;
|
write!(f, "{}px", to_frac_px(*self))
|
||||||
write!(f, "Au(au={} px={})", n, to_frac_px(*self))
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
impl Add<Au,Au> for Au {
|
impl Add<Au,Au> for Au {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit b41f144a3a8b6388d0956f341bcffa5bbaecc899
|
Subproject commit c733f78e06bd02f7498e93b391e0f6094d91786a
|
|
@ -114,6 +114,7 @@ struct Reftest {
|
||||||
servo_args: Vec<String>,
|
servo_args: Vec<String>,
|
||||||
render_mode: RenderMode,
|
render_mode: RenderMode,
|
||||||
is_flaky: bool,
|
is_flaky: bool,
|
||||||
|
experimental: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestLine<'a> {
|
struct TestLine<'a> {
|
||||||
|
@ -166,12 +167,14 @@ fn parse_lists(file: &str, servo_args: &[String], render_mode: RenderMode, id_of
|
||||||
|
|
||||||
let mut conditions_list = test_line.conditions.split(',');
|
let mut conditions_list = test_line.conditions.split(',');
|
||||||
let mut flakiness = RenderMode::empty();
|
let mut flakiness = RenderMode::empty();
|
||||||
|
let mut experimental = false;
|
||||||
for condition in conditions_list {
|
for condition in conditions_list {
|
||||||
match condition {
|
match condition {
|
||||||
"flaky_cpu" => flakiness.insert(CpuRendering),
|
"flaky_cpu" => flakiness.insert(CpuRendering),
|
||||||
"flaky_gpu" => flakiness.insert(GpuRendering),
|
"flaky_gpu" => flakiness.insert(GpuRendering),
|
||||||
"flaky_linux" => flakiness.insert(LinuxTarget),
|
"flaky_linux" => flakiness.insert(LinuxTarget),
|
||||||
"flaky_macos" => flakiness.insert(MacOsTarget),
|
"flaky_macos" => flakiness.insert(MacOsTarget),
|
||||||
|
"experimental" => experimental = true,
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,6 +187,7 @@ fn parse_lists(file: &str, servo_args: &[String], render_mode: RenderMode, id_of
|
||||||
render_mode: render_mode,
|
render_mode: render_mode,
|
||||||
servo_args: servo_args.iter().map(|x| x.clone()).collect(),
|
servo_args: servo_args.iter().map(|x| x.clone()).collect(),
|
||||||
is_flaky: render_mode.intersects(flakiness),
|
is_flaky: render_mode.intersects(flakiness),
|
||||||
|
experimental: experimental,
|
||||||
};
|
};
|
||||||
|
|
||||||
tests.push(make_test(reftest));
|
tests.push(make_test(reftest));
|
||||||
|
@ -212,7 +216,11 @@ fn capture(reftest: &Reftest, side: uint) -> png::Image {
|
||||||
if reftest.render_mode.contains(CpuRendering) {
|
if reftest.render_mode.contains(CpuRendering) {
|
||||||
args.push("-c".to_string());
|
args.push("-c".to_string());
|
||||||
}
|
}
|
||||||
args.push_all_move(vec!("-f".to_string(), "-o".to_string(), filename.clone(), reftest.files[side].clone()));
|
if reftest.experimental {
|
||||||
|
args.push("--experimental".to_string());
|
||||||
|
}
|
||||||
|
args.push_all(["-f".to_string(), "-o".to_string(), filename.clone(),
|
||||||
|
reftest.files[side].clone()]);
|
||||||
|
|
||||||
let retval = match Command::new("./servo").args(args.as_slice()).status() {
|
let retval = match Command::new("./servo").args(args.as_slice()).status() {
|
||||||
Ok(status) => status,
|
Ok(status) => status,
|
||||||
|
|
415
src/test/harness/reftest/reftest.rs.orig
Normal file
415
src/test/harness/reftest/reftest.rs.orig
Normal file
|
@ -0,0 +1,415 @@
|
||||||
|
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
extern crate png;
|
||||||
|
extern crate std;
|
||||||
|
extern crate test;
|
||||||
|
extern crate regex;
|
||||||
|
|
||||||
|
use std::ascii::StrAsciiExt;
|
||||||
|
use std::io;
|
||||||
|
use std::io::{File, Reader, Command};
|
||||||
|
use std::io::process::ExitStatus;
|
||||||
|
use std::os;
|
||||||
|
use test::{AutoColor, DynTestName, DynTestFn, TestDesc, TestOpts, TestDescAndFn};
|
||||||
|
use test::run_tests_console;
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
|
||||||
|
bitflags!(
|
||||||
|
flags RenderMode: u32 {
|
||||||
|
static CpuRendering = 0x00000001,
|
||||||
|
static GpuRendering = 0x00000010,
|
||||||
|
static LinuxTarget = 0x00000100,
|
||||||
|
static MacOsTarget = 0x00001000,
|
||||||
|
static AndroidTarget = 0x00010000
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = os::args();
|
||||||
|
let mut parts = args.tail().split(|e| "--" == e.as_slice());
|
||||||
|
|
||||||
|
let harness_args = parts.next().unwrap(); // .split() is never empty
|
||||||
|
let servo_args = parts.next().unwrap_or(&[]);
|
||||||
|
|
||||||
|
let (render_mode_string, base_path, testname) = match harness_args {
|
||||||
|
[] | [_] => fail!("USAGE: cpu|gpu base_path [testname regex]"),
|
||||||
|
[ref render_mode_string, ref base_path] => (render_mode_string, base_path, None),
|
||||||
|
[ref render_mode_string, ref base_path, ref testname, ..] => (render_mode_string, base_path, Some(Regex::new(testname.as_slice()).unwrap())),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut render_mode = match render_mode_string.as_slice() {
|
||||||
|
"cpu" => CpuRendering,
|
||||||
|
"gpu" => GpuRendering,
|
||||||
|
_ => fail!("First argument must specify cpu or gpu as rendering mode")
|
||||||
|
};
|
||||||
|
if cfg!(target_os = "linux") {
|
||||||
|
render_mode.insert(LinuxTarget);
|
||||||
|
}
|
||||||
|
if cfg!(target_os = "macos") {
|
||||||
|
render_mode.insert(MacOsTarget);
|
||||||
|
}
|
||||||
|
if cfg!(target_os = "android") {
|
||||||
|
render_mode.insert(AndroidTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut all_tests = vec!();
|
||||||
|
println!("Scanning {} for manifests\n", base_path);
|
||||||
|
|
||||||
|
for file in io::fs::walk_dir(&Path::new(base_path.as_slice())).unwrap() {
|
||||||
|
let maybe_extension = file.extension_str();
|
||||||
|
match maybe_extension {
|
||||||
|
Some(extension) => {
|
||||||
|
if extension.to_ascii_lower().as_slice() == "list" && file.is_file() {
|
||||||
|
let manifest = file.as_str().unwrap();
|
||||||
|
let tests = parse_lists(manifest, servo_args, render_mode);
|
||||||
|
println!("\t{} [{} tests]", manifest, tests.len());
|
||||||
|
all_tests.push_all_move(tests);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let test_opts = TestOpts {
|
||||||
|
filter: testname,
|
||||||
|
run_ignored: false,
|
||||||
|
logfile: None,
|
||||||
|
run_tests: true,
|
||||||
|
run_benchmarks: false,
|
||||||
|
ratchet_noise_percent: None,
|
||||||
|
ratchet_metrics: None,
|
||||||
|
save_metrics: None,
|
||||||
|
test_shard: None,
|
||||||
|
nocapture: false,
|
||||||
|
color: AutoColor
|
||||||
|
};
|
||||||
|
|
||||||
|
match run_tests_console(&test_opts, all_tests) {
|
||||||
|
Ok(false) => os::set_exit_status(1), // tests failed
|
||||||
|
Err(_) => os::set_exit_status(2), // I/O-related failure
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deriving(PartialEq)]
|
||||||
|
enum ReftestKind {
|
||||||
|
Same,
|
||||||
|
Different,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Reftest {
|
||||||
|
name: String,
|
||||||
|
kind: ReftestKind,
|
||||||
|
files: [String, ..2],
|
||||||
|
id: uint,
|
||||||
|
servo_args: Vec<String>,
|
||||||
|
render_mode: RenderMode,
|
||||||
|
<<<<<<< HEAD
|
||||||
|
is_flaky: bool,
|
||||||
|
||||||| merged common ancestors
|
||||||
|
flakiness: uint,
|
||||||
|
=======
|
||||||
|
flakiness: uint,
|
||||||
|
experimental: bool,
|
||||||
|
>>>>>>> Reftests can opt into --experimental
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TestLine<'a> {
|
||||||
|
conditions: &'a str,
|
||||||
|
kind: &'a str,
|
||||||
|
file_left: &'a str,
|
||||||
|
file_right: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_lists(file: &str, servo_args: &[String], render_mode: RenderMode) -> Vec<TestDescAndFn> {
|
||||||
|
let mut tests = Vec::new();
|
||||||
|
let mut next_id = 0;
|
||||||
|
let file_path = Path::new(file);
|
||||||
|
let contents = File::open_mode(&file_path, io::Open, io::Read)
|
||||||
|
.and_then(|mut f| f.read_to_string())
|
||||||
|
.ok().expect("Could not read file");
|
||||||
|
|
||||||
|
for line in contents.as_slice().lines() {
|
||||||
|
<<<<<<< HEAD
|
||||||
|
// ignore comments or empty lines
|
||||||
|
if line.starts_with("#") || line.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let parts: Vec<&str> = line.split(' ').filter(|p| !p.is_empty()).collect();
|
||||||
|
|
||||||
|
let test_line = match parts.len() {
|
||||||
|
3 => TestLine {
|
||||||
|
conditions: "",
|
||||||
|
kind: parts[0],
|
||||||
|
file_left: parts[1],
|
||||||
|
file_right: parts[2],
|
||||||
|
||||||| merged common ancestors
|
||||||
|
// ignore comments or empty lines
|
||||||
|
if line.starts_with("#") || line.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let parts: Vec<&str> = line.split(' ').filter(|p| !p.is_empty()).collect();
|
||||||
|
|
||||||
|
let test_line = match parts.len() {
|
||||||
|
3 => {
|
||||||
|
TestLine {
|
||||||
|
conditions: "",
|
||||||
|
kind: parts[0],
|
||||||
|
file_left: parts[1],
|
||||||
|
file_right: parts[2],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
4 => {
|
||||||
|
TestLine {
|
||||||
|
conditions: parts[0],
|
||||||
|
kind: parts[1],
|
||||||
|
file_left: parts[2],
|
||||||
|
file_right: parts[3],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
fail!("reftest line: '{:s}' doesn't match '[CONDITIONS] KIND LEFT RIGHT'", line);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let kind = match test_line.kind {
|
||||||
|
"==" => Same,
|
||||||
|
"!=" => Different,
|
||||||
|
part => fail!("reftest line: '{:s}' has invalid kind '{:s}'", line, part)
|
||||||
|
};
|
||||||
|
let src_path = file_path.dir_path();
|
||||||
|
let src_dir = src_path.display().to_string();
|
||||||
|
let file_left = src_dir.clone().append("/").append(test_line.file_left);
|
||||||
|
let file_right = src_dir.append("/").append(test_line.file_right);
|
||||||
|
|
||||||
|
let mut conditions_list = test_line.conditions.split(',');
|
||||||
|
let mut flakiness = 0;
|
||||||
|
for condition in conditions_list {
|
||||||
|
match condition {
|
||||||
|
"flaky_cpu" => {
|
||||||
|
flakiness |= CpuRendering as uint;
|
||||||
|
=======
|
||||||
|
// ignore comments or empty lines
|
||||||
|
if line.starts_with("#") || line.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let parts: Vec<&str> = line.split(' ').filter(|p| !p.is_empty()).collect();
|
||||||
|
|
||||||
|
let test_line = match parts.len() {
|
||||||
|
3 => {
|
||||||
|
TestLine {
|
||||||
|
conditions: "",
|
||||||
|
kind: parts[0],
|
||||||
|
file_left: parts[1],
|
||||||
|
file_right: parts[2],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
4 => {
|
||||||
|
TestLine {
|
||||||
|
conditions: parts[0],
|
||||||
|
kind: parts[1],
|
||||||
|
file_left: parts[2],
|
||||||
|
file_right: parts[3],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
fail!("reftest line: '{:s}' doesn't match '[CONDITIONS] KIND LEFT RIGHT'", line);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let kind = match test_line.kind {
|
||||||
|
"==" => Same,
|
||||||
|
"!=" => Different,
|
||||||
|
part => fail!("reftest line: '{:s}' has invalid kind '{:s}'", line, part)
|
||||||
|
};
|
||||||
|
let src_path = file_path.dir_path();
|
||||||
|
let src_dir = src_path.display().to_string();
|
||||||
|
let file_left = src_dir.clone().append("/").append(test_line.file_left);
|
||||||
|
let file_right = src_dir.append("/").append(test_line.file_right);
|
||||||
|
|
||||||
|
let mut conditions_list = test_line.conditions.split(',');
|
||||||
|
let mut flakiness = 0;
|
||||||
|
let mut experimental = false;
|
||||||
|
for condition in conditions_list {
|
||||||
|
match condition {
|
||||||
|
"flaky_cpu" => {
|
||||||
|
flakiness |= CpuRendering as uint;
|
||||||
|
>>>>>>> Reftests can opt into --experimental
|
||||||
|
},
|
||||||
|
4 => TestLine {
|
||||||
|
conditions: parts[0],
|
||||||
|
kind: parts[1],
|
||||||
|
file_left: parts[2],
|
||||||
|
file_right: parts[3],
|
||||||
|
},
|
||||||
|
<<<<<<< HEAD
|
||||||
|
_ => fail!("reftest line: '{:s}' doesn't match '[CONDITIONS] KIND LEFT RIGHT'", line),
|
||||||
|
};
|
||||||
|
|
||||||
|
let kind = match test_line.kind {
|
||||||
|
"==" => Same,
|
||||||
|
"!=" => Different,
|
||||||
|
part => fail!("reftest line: '{:s}' has invalid kind '{:s}'", line, part)
|
||||||
|
};
|
||||||
|
let src_path = file_path.dir_path();
|
||||||
|
let src_dir = src_path.display().to_string();
|
||||||
|
let file_left = src_dir.clone().append("/").append(test_line.file_left);
|
||||||
|
let file_right = src_dir.append("/").append(test_line.file_right);
|
||||||
|
|
||||||
|
let mut conditions_list = test_line.conditions.split(',');
|
||||||
|
let mut flakiness = RenderMode::empty();
|
||||||
|
for condition in conditions_list {
|
||||||
|
match condition {
|
||||||
|
"flaky_cpu" => flakiness.insert(CpuRendering),
|
||||||
|
"flaky_gpu" => flakiness.insert(GpuRendering),
|
||||||
|
"flaky_linux" => flakiness.insert(LinuxTarget),
|
||||||
|
"flaky_macos" => flakiness.insert(MacOsTarget),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let reftest = Reftest {
|
||||||
|
name: format!("{} {} {}", test_line.file_left, test_line.kind, test_line.file_right),
|
||||||
|
kind: kind,
|
||||||
|
files: [file_left, file_right],
|
||||||
|
id: next_id,
|
||||||
|
render_mode: render_mode,
|
||||||
|
servo_args: servo_args.iter().map(|x| x.clone()).collect(),
|
||||||
|
is_flaky: render_mode.intersects(flakiness),
|
||||||
|
};
|
||||||
|
|
||||||
|
next_id += 1;
|
||||||
|
|
||||||
|
tests.push(make_test(reftest));
|
||||||
|
||||||| merged common ancestors
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let reftest = Reftest {
|
||||||
|
name: test_line.file_left.to_string().append(" / ").append(test_line.file_right),
|
||||||
|
kind: kind,
|
||||||
|
files: [file_left, file_right],
|
||||||
|
id: next_id,
|
||||||
|
render_mode: render_mode,
|
||||||
|
servo_args: servo_args.iter().map(|x| x.clone()).collect(),
|
||||||
|
flakiness: flakiness,
|
||||||
|
};
|
||||||
|
|
||||||
|
next_id += 1;
|
||||||
|
|
||||||
|
tests.push(make_test(reftest));
|
||||||
|
=======
|
||||||
|
"experimental" => {
|
||||||
|
experimental = true;
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let reftest = Reftest {
|
||||||
|
name: test_line.file_left.to_string().append(" / ").append(test_line.file_right),
|
||||||
|
kind: kind,
|
||||||
|
files: [file_left, file_right],
|
||||||
|
id: next_id,
|
||||||
|
render_mode: render_mode,
|
||||||
|
servo_args: servo_args.iter().map(|x| x.clone()).collect(),
|
||||||
|
flakiness: flakiness,
|
||||||
|
experimental: experimental,
|
||||||
|
};
|
||||||
|
|
||||||
|
next_id += 1;
|
||||||
|
|
||||||
|
tests.push(make_test(reftest));
|
||||||
|
>>>>>>> Reftests can opt into --experimental
|
||||||
|
}
|
||||||
|
tests
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_test(reftest: Reftest) -> TestDescAndFn {
|
||||||
|
let name = reftest.name.clone();
|
||||||
|
TestDescAndFn {
|
||||||
|
desc: TestDesc {
|
||||||
|
name: DynTestName(name),
|
||||||
|
ignore: false,
|
||||||
|
should_fail: false,
|
||||||
|
},
|
||||||
|
testfn: DynTestFn(proc() {
|
||||||
|
check_reftest(reftest);
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn capture(reftest: &Reftest, side: uint) -> png::Image {
|
||||||
|
let filename = format!("/tmp/servo-reftest-{:06u}-{:u}.png", reftest.id, side);
|
||||||
|
let mut args = reftest.servo_args.clone();
|
||||||
|
// GPU rendering is the default
|
||||||
|
if reftest.render_mode.contains(CpuRendering) {
|
||||||
|
args.push("-c".to_string());
|
||||||
|
}
|
||||||
|
if reftest.experimental {
|
||||||
|
args.push("--experimental".to_string());
|
||||||
|
}
|
||||||
|
args.push_all(["-f".to_string(), "-o".to_string(), filename.clone(),
|
||||||
|
reftest.files[side].clone()]);
|
||||||
|
|
||||||
|
let retval = match Command::new("./servo").args(args.as_slice()).status() {
|
||||||
|
Ok(status) => status,
|
||||||
|
Err(e) => fail!("failed to execute process: {}", e),
|
||||||
|
};
|
||||||
|
assert!(retval == ExitStatus(0));
|
||||||
|
|
||||||
|
png::load_png(&from_str::<Path>(filename.as_slice()).unwrap()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_reftest(reftest: Reftest) {
|
||||||
|
let left = capture(&reftest, 0);
|
||||||
|
let right = capture(&reftest, 1);
|
||||||
|
|
||||||
|
let pixels = left.pixels.iter().zip(right.pixels.iter()).map(|(&a, &b)| {
|
||||||
|
if a as i8 - b as i8 == 0 {
|
||||||
|
// White for correct
|
||||||
|
0xFF
|
||||||
|
} else {
|
||||||
|
// "1100" in the RGBA channel with an error for an incorrect value
|
||||||
|
// This results in some number of C0 and FFs, which is much more
|
||||||
|
// readable (and distinguishable) than the previous difference-wise
|
||||||
|
// scaling but does not require reconstructing the actual RGBA pixel.
|
||||||
|
0xC0
|
||||||
|
}
|
||||||
|
}).collect::<Vec<u8>>();
|
||||||
|
|
||||||
|
if pixels.iter().any(|&a| a < 255) {
|
||||||
|
let output_str = format!("/tmp/servo-reftest-{:06u}-diff.png", reftest.id);
|
||||||
|
let output = from_str::<Path>(output_str.as_slice()).unwrap();
|
||||||
|
|
||||||
|
let mut img = png::Image {
|
||||||
|
width: left.width,
|
||||||
|
height: left.height,
|
||||||
|
color_type: png::RGBA8,
|
||||||
|
pixels: pixels,
|
||||||
|
};
|
||||||
|
let res = png::store_png(&mut img, &output);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
|
||||||
|
match (reftest.kind, reftest.is_flaky) {
|
||||||
|
(Same, true) => println!("flaky test - rendering difference: {}", output_str),
|
||||||
|
(Same, false) => fail!("rendering difference: {}", output_str),
|
||||||
|
(Different, _) => {} // Result was different and that's what was expected
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert!(reftest.is_flaky || reftest.kind == Same);
|
||||||
|
}
|
||||||
|
}
|
|
@ -86,6 +86,7 @@ flaky_cpu == linebreak_simple_a.html linebreak_simple_b.html
|
||||||
== position_fixed_overflow_a.html position_fixed_overflow_b.html
|
== position_fixed_overflow_a.html position_fixed_overflow_b.html
|
||||||
== noscript.html noscript_ref.html
|
== noscript.html noscript_ref.html
|
||||||
== pseudo_inherit.html pseudo_inherit_ref.html
|
== pseudo_inherit.html pseudo_inherit_ref.html
|
||||||
|
experimental == vertical-lr-blocks.html vertical-lr-blocks_ref.html
|
||||||
== float_intrinsic_height.html float_intrinsic_height_ref.html
|
== float_intrinsic_height.html float_intrinsic_height_ref.html
|
||||||
== table_auto_width.html table_auto_width_ref.html
|
== table_auto_width.html table_auto_width_ref.html
|
||||||
== inline_whitespace_b.html inline_whitespace_ref.html
|
== inline_whitespace_b.html inline_whitespace_ref.html
|
||||||
|
|
18
src/test/ref/vertical-lr-blocks.html
Normal file
18
src/test/ref/vertical-lr-blocks.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
html { writing-mode: vertical-rl }
|
||||||
|
body { margin: 10px }
|
||||||
|
div { border: blue solid 5px; line-height: 30px; height: 500px }
|
||||||
|
p { background: green; margin: 40px 20px }
|
||||||
|
p + p { margin-top: 60px }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<p> </p>
|
||||||
|
<p> </p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
18
src/test/ref/vertical-lr-blocks_ref.html
Normal file
18
src/test/ref/vertical-lr-blocks_ref.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
div { border: blue solid 5px; position: absolute;
|
||||||
|
top: 10px; right: 10px; bottom: 10px; width: 120px; height: 500px }
|
||||||
|
p { background: green; margin: 0; position: absolute;
|
||||||
|
top: 40px; right: 20px; bottom: 40px; width: 30px }
|
||||||
|
p + p { right: 70px; top: 60px }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<p> </p>
|
||||||
|
<p> </p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue