diff --git a/README.md b/README.md index bbc4e2a3da5..56c6ee6844d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # The Servo Parallel Browser Project Servo is a prototype web browser engine written in the -[Rust](https://github.com/mozilla/rust) language. It is currently developed on +[Rust](https://github.com/rust-lang/rust) language. It is currently developed on 64bit OS X, 64bit Linux, Android, and Gonk (Firefox OS). Servo welcomes contribution from everyone. See diff --git a/components/canvas/canvas_paint_task.rs b/components/canvas/canvas_paint_task.rs index 76af23fa44f..150240bc722 100644 --- a/components/canvas/canvas_paint_task.rs +++ b/components/canvas/canvas_paint_task.rs @@ -39,6 +39,7 @@ pub enum CanvasMsg { SetFillStyle(FillOrStrokeStyle), SetStrokeStyle(FillOrStrokeStyle), SetLineWidth(f32), + SetMiterLimit(f32), SetTransform(Matrix2D), SetGlobalAlpha(f32), Recreate(Size2D), @@ -202,7 +203,7 @@ impl<'a> CanvasPaintTask<'a> { draw_options: DrawOptions::new(1.0, 0), fill_style: Pattern::Color(ColorPattern::new(color::black())), stroke_style: Pattern::Color(ColorPattern::new(color::black())), - stroke_opts: StrokeOptions::new(1.0, JoinStyle::MiterOrBevel, CapStyle::Butt, 1.0, &[]), + stroke_opts: StrokeOptions::new(1.0, JoinStyle::MiterOrBevel, CapStyle::Butt, 10.0, &[]), path_builder: path_builder, transform: Matrix2D::identity(), } @@ -245,6 +246,7 @@ impl<'a> CanvasPaintTask<'a> { CanvasMsg::SetFillStyle(style) => painter.set_fill_style(style), CanvasMsg::SetStrokeStyle(style) => painter.set_stroke_style(style), CanvasMsg::SetLineWidth(width) => painter.set_line_width(width), + CanvasMsg::SetMiterLimit(limit) => painter.set_miter_limit(limit), CanvasMsg::SetTransform(ref matrix) => painter.set_transform(matrix), CanvasMsg::SetGlobalAlpha(alpha) => painter.set_global_alpha(alpha), CanvasMsg::Recreate(size) => painter.recreate(size), @@ -425,6 +427,10 @@ impl<'a> CanvasPaintTask<'a> { self.stroke_opts.line_width = width; } + fn set_miter_limit(&mut self, limit: f32) { + self.stroke_opts.miter_limit = limit; + } + fn set_transform(&mut self, transform: &Matrix2D) { self.transform = *transform; self.drawtarget.set_transform(transform) diff --git a/components/gfx/platform/freetype/font.rs b/components/gfx/platform/freetype/font.rs index 181c3569bab..60587acb297 100644 --- a/components/gfx/platform/freetype/font.rs +++ b/components/gfx/platform/freetype/font.rs @@ -76,8 +76,7 @@ impl FontHandleMethods for FontHandle { let ft_ctx: FT_Library = fctx.ctx.ctx; if ft_ctx.is_null() { return Err(()); } - let bytes = &template.bytes; - let face_result = create_face_from_buffer(ft_ctx, bytes.as_ptr(), bytes.len(), pt_size); + let face_result = create_face_from_buffer(ft_ctx, &template.bytes, pt_size); // TODO: this could be more simply written as result::chain // and moving buf into the struct ctor, but cant' move out of @@ -94,12 +93,12 @@ impl FontHandleMethods for FontHandle { Err(()) => Err(()) }; - fn create_face_from_buffer(lib: FT_Library, cbuf: *const u8, cbuflen: uint, pt_size: Option) + fn create_face_from_buffer(lib: FT_Library, buffer: &[u8], pt_size: Option) -> Result { unsafe { let mut face: FT_Face = ptr::null_mut(); let face_index = 0 as FT_Long; - let result = FT_New_Memory_Face(lib, cbuf, cbuflen as FT_Long, + let result = FT_New_Memory_Face(lib, buffer.as_ptr(), buffer.len() as FT_Long, face_index, &mut face); if !result.succeeded() || face.is_null() { diff --git a/components/gfx/platform/freetype/font_list.rs b/components/gfx/platform/freetype/font_list.rs index 3970efa92ec..9f939fa9391 100644 --- a/components/gfx/platform/freetype/font_list.rs +++ b/components/gfx/platform/freetype/font_list.rs @@ -36,7 +36,7 @@ pub fn get_available_families(mut callback: F) where F: FnMut(String) { unsafe { let config = FcConfigGetCurrent(); let fontSet = FcConfigGetFonts(config, FcSetSystem); - for i in 0..((*fontSet).nfont as int) { + for i in 0..((*fontSet).nfont as isize) { let font = (*fontSet).fonts.offset(i); let mut family: *mut FcChar8 = ptr::null_mut(); let mut v: c_int = 0; @@ -74,7 +74,7 @@ pub fn get_variations_for_family(family_name: &str, mut callback: F) debug!("found {} variations", (*matches).nfont); - for i in 0..((*matches).nfont as int) { + for i in 0..((*matches).nfont as isize) { let font = (*matches).fonts.offset(i); let mut file: *mut FcChar8 = ptr::null_mut(); let file = if FcPatternGetString(*font, FC_FILE.as_ptr() as *mut c_char, 0, &mut file) == FcResultMatch { diff --git a/components/gfx/text/text_run.rs b/components/gfx/text/text_run.rs index 93c4c6c50b9..4e963bf1b28 100644 --- a/components/gfx/text/text_run.rs +++ b/components/gfx/text/text_run.rs @@ -16,6 +16,7 @@ use text::glyph::{CharIndex, GlyphStore}; /// A single "paragraph" of text in one font size and style. #[derive(Clone)] pub struct TextRun { + /// The UTF-8 string represented by this text run. pub text: Arc, pub font_template: Arc, pub actual_pt_size: Au, @@ -310,7 +311,8 @@ impl<'a> TextRun { self.font_metrics.descent) } - pub fn metrics_for_slice(&self, glyphs: &GlyphStore, slice_range: &Range) -> RunMetrics { + pub fn metrics_for_slice(&self, glyphs: &GlyphStore, slice_range: &Range) + -> RunMetrics { RunMetrics::new(glyphs.advance_for_char_range(slice_range), self.font_metrics.ascent, self.font_metrics.descent) diff --git a/components/gfx/text/util.rs b/components/gfx/text/util.rs index 890069b401c..95654af9ce5 100644 --- a/components/gfx/text/util.rs +++ b/components/gfx/text/util.rs @@ -2,8 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use text::glyph::CharIndex; - #[derive(PartialEq, Eq, Copy)] pub enum CompressionMode { CompressNone, @@ -25,12 +23,10 @@ pub enum CompressionMode { pub fn transform_text(text: &str, mode: CompressionMode, incoming_whitespace: bool, - output_text: &mut String, - new_line_pos: &mut Vec) + output_text: &mut String) -> bool { let out_whitespace = match mode { CompressionMode::CompressNone | CompressionMode::DiscardNewline => { - let mut new_line_index = CharIndex(0); for ch in text.chars() { if is_discardable_char(ch, mode) { // TODO: record skipped char @@ -38,15 +34,6 @@ pub fn transform_text(text: &str, // TODO: record kept char if ch == '\t' { // TODO: set "has tab" flag - } else if ch == '\n' { - // Save new-line's position for line-break - // This value is relative(not absolute) - new_line_pos.push(new_line_index); - new_line_index = CharIndex(0); - } - - if ch != '\n' { - new_line_index = new_line_index + CharIndex(1); } output_text.push(ch); } @@ -124,6 +111,6 @@ pub fn fixed_to_rounded_int(before: isize, f: i32) -> isize { if f > 0i32 { ((half + f) >> before) as isize } else { - -((half - f) >> before) as isize + -((half - f) >> before as usize) as isize } } diff --git a/components/layout/block.rs b/components/layout/block.rs index 4b187082db7..580a81c2a4f 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -1994,7 +1994,8 @@ pub struct ISizeConstraintSolution { } impl ISizeConstraintSolution { - pub fn new(inline_size: Au, margin_inline_start: Au, margin_inline_end: Au) -> ISizeConstraintSolution { + pub fn new(inline_size: Au, margin_inline_start: Au, margin_inline_end: Au) + -> ISizeConstraintSolution { ISizeConstraintSolution { inline_start: Au(0), inline_end: Au(0), diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 4c3d3bdc4c6..b766b27752e 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -27,16 +27,11 @@ use geom::{Point2D, Rect, Size2D}; use gfx::display_list::{BLUR_INFLATION_FACTOR, OpaqueNode}; use gfx::text::glyph::CharIndex; use gfx::text::text_run::{TextRun, TextRunSlice}; -use script_traits::UntrustedNodeAddress; -use rustc_serialize::{Encodable, Encoder}; use msg::constellation_msg::{ConstellationChan, Msg, PipelineId, SubpageId}; use net_traits::image::holder::ImageHolder; use net_traits::local_image_cache::LocalImageCache; -use util::geometry::{self, Au, ZERO_POINT}; -use util::logical_geometry::{LogicalRect, LogicalSize, LogicalMargin, WritingMode}; -use util::range::*; -use util::smallvec::SmallVec; -use util::str::is_whitespace; +use rustc_serialize::{Encodable, Encoder}; +use script_traits::UntrustedNodeAddress; use std::borrow::ToOwned; use std::cmp::{max, min}; use std::collections::LinkedList; @@ -56,6 +51,12 @@ use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto}; use style::values::computed::{LengthOrPercentageOrNone}; use text::TextRunScanner; use url::Url; +use util::geometry::{self, Au, ZERO_POINT}; +use util::logical_geometry::{LogicalRect, LogicalSize, LogicalMargin, WritingMode}; +use util::range::*; +use util::smallvec::SmallVec; +use util::str::is_whitespace; +use util; /// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position /// themselves. In general, fragments do not have a simple correspondence with CSS fragments in the @@ -580,36 +581,27 @@ pub struct ScannedTextFragmentInfo { /// The text run that this represents. pub run: Arc>, + /// The intrinsic size of the text fragment. + pub content_size: LogicalSize, + /// The range within the above text run that this represents. pub range: Range, - /// The positions of newlines within this scanned text fragment. - /// - /// FIXME(#2260, pcwalton): Can't this go somewhere else, like in the text run or something? - /// Or can we just remove it? - pub new_line_pos: Vec, - - /// The new_line_pos is eaten during line breaking. If we need to re-merge - /// fragments, it will have to be restored. - pub original_new_line_pos: Option>, - - /// The intrinsic size of the text fragment. - pub content_size: LogicalSize, + /// The endpoint of the above range, including whitespace that was stripped out. This exists + /// so that we can restore the range to its original value (before line breaking occurred) when + /// performing incremental reflow. + pub range_end_including_stripped_whitespace: CharIndex, } impl ScannedTextFragmentInfo { /// Creates the information specific to a scanned text fragment from a range and a text run. - pub fn new(run: Arc>, - range: Range, - new_line_positions: Vec, - content_size: LogicalSize) + pub fn new(run: Arc>, range: Range, content_size: LogicalSize) -> ScannedTextFragmentInfo { ScannedTextFragmentInfo { run: run, range: range, - new_line_pos: new_line_positions, - original_new_line_pos: None, content_size: content_size, + range_end_including_stripped_whitespace: range.end(), } } } @@ -769,32 +761,6 @@ impl Fragment { self.margin = LogicalMargin::zero(self.style.writing_mode); } - /// Saves the new_line_pos vector into a `SpecificFragmentInfo::ScannedText`. This will fail - /// if called on any other type of fragment. - pub fn save_new_line_pos(&mut self) { - match &mut self.specific { - &mut SpecificFragmentInfo::ScannedText(ref mut info) => { - if !info.new_line_pos.is_empty() { - info.original_new_line_pos = Some(info.new_line_pos.clone()); - } - } - _ => {} - } - } - - pub fn restore_new_line_pos(&mut self) { - match &mut self.specific { - &mut SpecificFragmentInfo::ScannedText(ref mut info) => { - match info.original_new_line_pos.take() { - None => {} - Some(new_line_pos) => info.new_line_pos = new_line_pos, - } - return - } - _ => {} - } - } - /// Returns a debug ID of this fragment. This ID should not be considered stable across /// multiple layouts or fragment manipulations. pub fn debug_id(&self) -> u16 { @@ -823,14 +789,12 @@ impl Fragment { } /// Transforms this fragment using the given `SplitInfo`, preserving all the other data. - pub fn transform_with_split_info(&self, - split: &SplitInfo, - text_run: Arc>) + pub fn transform_with_split_info(&self, split: &SplitInfo, text_run: Arc>) -> Fragment { let size = LogicalSize::new(self.style.writing_mode, split.inline_size, self.border_box.size.block); - let info = box ScannedTextFragmentInfo::new(text_run, split.range, Vec::new(), size); + let info = box ScannedTextFragmentInfo::new(text_run, split.range, size); self.transform(size, SpecificFragmentInfo::ScannedText(info)) } @@ -857,7 +821,6 @@ impl Fragment { style: Arc, first_frag: bool, last_frag: bool) { - if self.inline_context.is_none() { self.inline_context = Some(InlineFragmentContext::new()); } @@ -1179,25 +1142,11 @@ impl Fragment { } } - /// Returns true if this element can be split. This is true for text fragments. + /// Returns true if this element can be split. This is true for text fragments, unless + /// `white-space: pre` is set. pub fn can_split(&self) -> bool { - self.is_scanned_text_fragment() - } - - /// Returns the newline positions of this fragment, if it's a scanned text fragment. - pub fn newline_positions(&self) -> Option<&Vec> { - match self.specific { - SpecificFragmentInfo::ScannedText(ref info) => Some(&info.new_line_pos), - _ => None, - } - } - - /// Returns the newline positions of this fragment, if it's a scanned text fragment. - pub fn newline_positions_mut(&mut self) -> Option<&mut Vec> { - match self.specific { - SpecificFragmentInfo::ScannedText(ref mut info) => Some(&mut info.new_line_pos), - _ => None, - } + self.is_scanned_text_fragment() && + self.style.get_inheritedtext().white_space != white_space::T::pre } /// Returns true if and only if this fragment is a generated content fragment. @@ -1359,64 +1308,6 @@ impl Fragment { self.border_box - self.border_padding } - /// Find the split of a fragment that includes a new-line character. - /// - /// A return value of `None` indicates that the fragment is not splittable. - /// Otherwise the split information is returned. The right information is - /// optional due to the possibility of it being whitespace. - // - // TODO(bjz): The text run should be removed in the future, but it is currently needed for - // the current method of fragment splitting in the `inline::try_append_*` functions. - pub fn find_split_info_by_new_line(&self) - -> Option<(SplitInfo, Option, Arc> /* TODO(bjz): remove */)> { - match self.specific { - SpecificFragmentInfo::Canvas(_) | - SpecificFragmentInfo::Generic | - SpecificFragmentInfo::GeneratedContent(_) | - SpecificFragmentInfo::Iframe(_) | - SpecificFragmentInfo::Image(_) | - SpecificFragmentInfo::Table | - SpecificFragmentInfo::TableCell | - SpecificFragmentInfo::TableRow | - SpecificFragmentInfo::TableWrapper => { - None - } - SpecificFragmentInfo::TableColumn(_) => { - panic!("Table column fragments do not need to split") - } - SpecificFragmentInfo::UnscannedText(_) => { - panic!("Unscanned text fragments should have been scanned by now!") - } - SpecificFragmentInfo::InlineBlock(_) | - SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => { - panic!("Inline blocks or inline absolute hypothetical fragments do not get split") - } - SpecificFragmentInfo::ScannedText(ref text_fragment_info) => { - let mut new_line_pos = text_fragment_info.new_line_pos.clone(); - let cur_new_line_pos = new_line_pos.remove(0); - - let inline_start_range = Range::new(text_fragment_info.range.begin(), - cur_new_line_pos); - let inline_end_range = Range::new( - text_fragment_info.range.begin() + cur_new_line_pos + CharIndex(1), - text_fragment_info.range.length() - (cur_new_line_pos + CharIndex(1))); - - // Left fragment is for inline-start text of first founded new-line character. - let inline_start_fragment = SplitInfo::new(inline_start_range, - &**text_fragment_info); - - // Right fragment is for inline-end text of first founded new-line character. - let inline_end_fragment = if inline_end_range.length() > CharIndex(0) { - Some(SplitInfo::new(inline_end_range, &**text_fragment_info)) - } else { - None - }; - - Some((inline_start_fragment, inline_end_fragment, text_fragment_info.run.clone())) - } - } - } - /// Attempts to find the split positions of a text fragment so that its inline-size is no more /// than `max_inline_size`. /// @@ -1495,13 +1386,13 @@ impl Fragment { /// A helper method that uses the breaking strategy described by `slice_iterator` (at present, /// either natural word breaking or character breaking) to split this fragment. - fn calculate_split_position_using_breaking_strategy<'a,I>(&self, - slice_iterator: I, - max_inline_size: Au, - flags: SplitOptions) - -> Option - where I: Iterator> { + fn calculate_split_position_using_breaking_strategy<'a,I>( + &self, + slice_iterator: I, + max_inline_size: Au, + flags: SplitOptions) + -> Option + where I: Iterator> { let text_fragment_info = if let SpecificFragmentInfo::ScannedText(ref text_fragment_info) = self.specific { text_fragment_info @@ -1515,31 +1406,35 @@ impl Fragment { let mut inline_end_range = None; let mut overflowing = false; - debug!("calculate_split_position: splitting text fragment (strlen={}, range={:?}, \ - max_inline_size={:?})", + debug!("calculate_split_position_using_breaking_strategy: splitting text fragment \ + (strlen={}, range={:?}, max_inline_size={:?})", text_fragment_info.run.text.len(), text_fragment_info.range, max_inline_size); for slice in slice_iterator { - debug!("calculate_split_position: considering slice (offset={:?}, slice range={:?}, \ - remaining_inline_size={:?})", + debug!("calculate_split_position_using_breaking_strategy: considering slice \ + (offset={:?}, slice range={:?}, remaining_inline_size={:?})", slice.offset, slice.range, remaining_inline_size); + // Use the `remaining_inline_size` to find a split point if possible. If not, go around + // the loop again with the next slice. let metrics = text_fragment_info.run.metrics_for_slice(slice.glyphs, &slice.range); let advance = metrics.advance_width; // Have we found the split point? if advance <= remaining_inline_size || slice.glyphs.is_whitespace() { // Keep going; we haven't found the split point yet. - if flags.contains(STARTS_LINE) && pieces_processed_count == 0 && + if flags.contains(STARTS_LINE) && + pieces_processed_count == 0 && slice.glyphs.is_whitespace() { - debug!("calculate_split_position: skipping leading trimmable whitespace"); + debug!("calculate_split_position_using_breaking_strategy: skipping \ + leading trimmable whitespace"); inline_start_range.shift_by(slice.range.length()); } else { - debug!("split_to_inline_size: enlarging span"); + debug!("calculate_split_position_using_breaking_strategy: enlarging span"); remaining_inline_size = remaining_inline_size - advance; inline_start_range.extend_by(slice.range.length()); } @@ -1570,60 +1465,31 @@ impl Fragment { inline_end); } - break - } + // If we failed to find a suitable split point, we're on the verge of overflowing the + // line. + if inline_start_range.is_empty() || overflowing { + // If we've been instructed to retry at character boundaries (probably via + // `overflow-wrap: break-word`), do so. + if flags.contains(RETRY_AT_CHARACTER_BOUNDARIES) { + let character_breaking_strategy = + text_fragment_info.run + .character_slices_in_range(&text_fragment_info.range); + let mut flags = flags; + flags.remove(RETRY_AT_CHARACTER_BOUNDARIES); + return self.calculate_split_position_using_breaking_strategy( + character_breaking_strategy, + max_inline_size, + flags) + } - // If we failed to find a suitable split point, we're on the verge of overflowing the line. - if inline_start_range.is_empty() || overflowing { - // If we've been instructed to retry at character boundaries (probably via - // `overflow-wrap: break-word`), do so. - if flags.contains(RETRY_AT_CHARACTER_BOUNDARIES) { - let character_breaking_strategy = - text_fragment_info.run.character_slices_in_range(&text_fragment_info.range); - let mut flags = flags; - flags.remove(RETRY_AT_CHARACTER_BOUNDARIES); - return self.calculate_split_position_using_breaking_strategy( - character_breaking_strategy, - max_inline_size, - flags) - } - - // We aren't at the start of the line, so don't overflow. Let inline layout wrap to the - // next line instead. - if !flags.contains(STARTS_LINE) { - return None - } - } - - // Remove trailing whitespace from the inline-start split, if necessary. - // - // FIXME(pcwalton): Is there a more clever (i.e. faster) way to do this? - strip_trailing_whitespace(&**text_fragment_info.run, &mut inline_start_range); - - // Remove leading whitespace from the inline-end split, if necessary. - // - // FIXME(pcwalton): Is there a more clever (i.e. faster) way to do this? - if let Some(ref mut inline_end_range) = inline_end_range { - let inline_end_fragment_text = - text_fragment_info.run.text.slice_chars(inline_end_range.begin().to_usize(), - inline_end_range.end().to_usize()); - let mut leading_whitespace_character_count = 0; - for ch in inline_end_fragment_text.chars() { - if ch.is_whitespace() { - leading_whitespace_character_count += 1 - } else { - break + // We aren't at the start of the line, so don't overflow. Let inline layout wrap to + // the next line instead. + if !flags.contains(STARTS_LINE) { + return None } } - inline_end_range.adjust_by(CharIndex(leading_whitespace_character_count), - -CharIndex(leading_whitespace_character_count)); - } - // Normalize our split so that the inline-end fragment will never be `Some` while the - // inline-start fragment is `None`. - if inline_start_range.is_empty() && inline_end_range.is_some() { - inline_start_range = inline_end_range.unwrap(); - inline_end_range = None + break } let inline_start = if !inline_start_range.is_empty() { @@ -1642,22 +1508,21 @@ impl Fragment { }) } - /// Attempts to strip trailing whitespace from this fragment by adjusting the text run range. - /// Returns true if any modifications were made. - pub fn strip_trailing_whitespace_if_necessary(&mut self) -> bool { - let text_fragment_info = - if let SpecificFragmentInfo::ScannedText(ref mut text_fragment_info) = self.specific { - text_fragment_info - } else { - return false - }; - - let run = text_fragment_info.run.clone(); - if strip_trailing_whitespace(&**run, &mut text_fragment_info.range) { - self.border_box.size.inline = run.advance_for_range(&text_fragment_info.range); - return true + /// The opposite of `calculate_split_position_using_breaking_strategy`: merges this fragment + /// with the next one. + pub fn merge_with(&mut self, next_fragment: Fragment) { + match (&mut self.specific, &next_fragment.specific) { + (&mut SpecificFragmentInfo::ScannedText(ref mut this_info), + &SpecificFragmentInfo::ScannedText(ref other_info)) => { + debug_assert!(util::arc_ptr_eq(&this_info.run, &other_info.run)); + this_info.range.extend_to(other_info.range_end_including_stripped_whitespace); + this_info.content_size.inline = + this_info.run.metrics_for_range(&this_info.range).advance_width; + self.border_box.size.inline = this_info.content_size.inline + + self.border_padding.inline_start_end(); + } + _ => panic!("Can only merge two scanned-text fragments!"), } - false } /// Returns true if this fragment is an unscanned text fragment that consists entirely of @@ -1669,7 +1534,7 @@ impl Fragment { } match self.specific { SpecificFragmentInfo::UnscannedText(ref text_fragment_info) => { - is_whitespace(text_fragment_info.text.as_slice()) + util::str::is_whitespace(text_fragment_info.text.as_slice()) } _ => false, } @@ -1890,11 +1755,14 @@ impl Fragment { /// Returns true if this fragment can merge with another adjacent fragment or false otherwise. pub fn can_merge_with_fragment(&self, other: &Fragment) -> bool { match (&self.specific, &other.specific) { - (&SpecificFragmentInfo::UnscannedText(_), &SpecificFragmentInfo::UnscannedText(_)) => { + (&SpecificFragmentInfo::UnscannedText(ref first_unscanned_text), + &SpecificFragmentInfo::UnscannedText(_)) => { // FIXME: Should probably use a whitelist of styles that can safely differ (#3165) + let length = first_unscanned_text.text.len(); self.style().get_font() == other.style().get_font() && self.text_decoration() == other.text_decoration() && - self.white_space() == other.white_space() + self.white_space() == other.white_space() && + (length == 0 || first_unscanned_text.text.char_at_reverse(length) != '\n') } _ => false, } @@ -2076,14 +1944,57 @@ impl Fragment { _ => {} } } + + pub fn requires_line_break_afterward_if_wrapping_on_newlines(&self) -> bool { + match self.specific { + SpecificFragmentInfo::ScannedText(ref scanned_text) => { + !scanned_text.range.is_empty() && + scanned_text.run.text.char_at_reverse(scanned_text.range + .end() + .get() as usize) == '\n' + } + _ => false, + } + } + + pub fn strip_leading_whitespace_if_necessary(&mut self) { + let mut scanned_text_fragment_info = match self.specific { + SpecificFragmentInfo::ScannedText(ref mut scanned_text_fragment_info) => { + scanned_text_fragment_info + } + _ => return, + }; + + if self.style.get_inheritedtext().white_space == white_space::T::pre { + return + } + + let mut leading_whitespace_character_count = 0; + { + let text = scanned_text_fragment_info.run.text.slice_chars( + scanned_text_fragment_info.range.begin().to_usize(), + scanned_text_fragment_info.range.end().to_usize()); + for character in text.chars() { + if util::str::char_is_whitespace(character) { + leading_whitespace_character_count += 1 + } else { + break + } + } + } + + scanned_text_fragment_info.range.adjust_by(CharIndex(leading_whitespace_character_count), + -CharIndex(leading_whitespace_character_count)); + } } impl fmt::Debug for Fragment { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "({} {} ", self.debug_id(), self.specific.get_type())); - try!(write!(f, "bp {:?}", self.border_padding)); - try!(write!(f, " ")); - try!(write!(f, "m {:?}", self.margin)); + try!(write!(f, "bb {:?} bp {:?} m {:?}", + self.border_box, + self.border_padding, + self.margin)); write!(f, ")") } } @@ -2105,7 +2016,7 @@ bitflags! { const STARTS_LINE = 0x01, #[doc="True if we should attempt to split at character boundaries if this split fails. \ This is used to implement `overflow-wrap: break-word`."] - const RETRY_AT_CHARACTER_BOUNDARIES = 0x02 + const RETRY_AT_CHARACTER_BOUNDARIES = 0x02, } } @@ -2129,25 +2040,3 @@ pub enum CoordinateSystem { Own, } -/// Given a range and a text run, adjusts the range to eliminate trailing whitespace. Returns true -/// if any modifications were made. -fn strip_trailing_whitespace(text_run: &TextRun, range: &mut Range) -> bool { - // FIXME(pcwalton): Is there a more clever (i.e. faster) way to do this? - let text = text_run.text.slice_chars(range.begin().to_usize(), range.end().to_usize()); - let mut trailing_whitespace_character_count = 0; - for ch in text.chars().rev() { - if ch.is_whitespace() { - trailing_whitespace_character_count += 1 - } else { - break - } - } - - if trailing_whitespace_character_count == 0 { - return false - } - - range.extend_by(-CharIndex(trailing_whitespace_character_count)); - return true -} - diff --git a/components/layout/inline.rs b/components/layout/inline.rs index 2c2625225b2..1f9e59dba2e 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -8,11 +8,9 @@ use css::node_style::StyledNode; use context::LayoutContext; use display_list_builder::{FragmentDisplayListBuilding, InlineFlowDisplayListBuilding}; use floats::{FloatKind, Floats, PlacementInfo}; -use flow::{BaseFlow, FlowClass, Flow, MutableFlowUtils, ForceNonfloatedFlag}; +use flow::{self, BaseFlow, FlowClass, Flow, MutableFlowUtils, ForceNonfloatedFlag}; use flow::{IS_ABSOLUTELY_POSITIONED}; -use flow; -use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, ScannedTextFragmentInfo}; -use fragment::{SpecificFragmentInfo, SplitInfo}; +use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo}; use incremental::{REFLOW, REFLOW_OUT_OF_FLOW, RESOLVE_GENERATED_CONTENT}; use layout_debug; use model::IntrinsicISizesContribution; @@ -23,20 +21,21 @@ use geom::{Point2D, Rect}; use gfx::font::FontMetrics; use gfx::font_context::FontContext; use gfx::text::glyph::CharIndex; -use util::arc_ptr_eq; -use util::geometry::{Au, ZERO_RECT}; -use util::logical_geometry::{LogicalRect, LogicalSize, WritingMode}; -use util::range::{Range, RangeIndex}; +use gfx::text::text_run::TextRun; use std::cmp::max; use std::fmt; use std::mem; use std::num::ToPrimitive; use std::ops::{Add, Sub, Mul, Div, Rem, Neg, Shl, Shr, Not, BitOr, BitAnd, BitXor}; +use std::sync::Arc; use std::u16; use style::computed_values::{overflow_x, text_align, text_justify, text_overflow, vertical_align}; use style::computed_values::{white_space}; use style::properties::ComputedValues; -use std::sync::Arc; +use util::geometry::{Au, MAX_AU, ZERO_RECT}; +use util::logical_geometry::{LogicalRect, LogicalSize, WritingMode}; +use util::range::{Range, RangeIndex}; +use util; // From gfxFontConstants.h in Firefox static FONT_SUBSCRIPT_OFFSET_RATIO: f64 = 0.20; @@ -160,7 +159,9 @@ int_range_index! { bitflags! { flags InlineReflowFlags: u8 { #[doc="The `white-space: nowrap` property from CSS 2.1 § 16.6 is in effect."] - const NO_WRAP_INLINE_REFLOW_FLAG = 0x01 + const NO_WRAP_INLINE_REFLOW_FLAG = 0x01, + #[doc="The `white-space: pre` property from CSS 2.1 § 16.6 is in effect."] + const WRAP_ON_NEWLINE_INLINE_REFLOW_FLAG = 0x02 } } @@ -191,7 +192,7 @@ impl LineBreaker { pending_line: Line { range: Range::empty(), bounds: LogicalRect::zero(float_context.writing_mode), - green_zone: LogicalSize::zero(float_context.writing_mode) + green_zone: LogicalSize::zero(float_context.writing_mode), }, floats: float_context, lines: Vec::new(), @@ -216,7 +217,7 @@ impl LineBreaker { self.cur_b, Au(0), Au(0)); - self.pending_line.green_zone = LogicalSize::zero(self.floats.writing_mode) + self.pending_line.green_zone = LogicalSize::zero(self.floats.writing_mode); } /// Reflows fragments for the given inline flow. @@ -226,23 +227,13 @@ impl LineBreaker { // Create our fragment iterator. debug!("LineBreaker: scanning for lines, {} fragments", flow.fragments.len()); let mut old_fragments = mem::replace(&mut flow.fragments, InlineFragments::new()); - let mut old_fragment_iter = old_fragments.fragments.into_iter(); + let old_fragment_iter = old_fragments.fragments.into_iter(); - // Set up our initial line state with the clean lines from a previous reflow. - // // TODO(pcwalton): This would likely be better as a list of dirty line indices. That way we // could resynchronize if we discover during reflow that all subsequent fragments must have // the same position as they had in the previous reflow. I don't know how common this case // really is in practice, but it's probably worth handling. - self.lines = mem::replace(&mut flow.lines, Vec::new()); - match self.lines.as_slice().last() { - None => {} - Some(last_line) => { - for _ in range(FragmentIndex(0), last_line.range.end()) { - self.new_fragments.push(old_fragment_iter.next().unwrap()) - } - } - } + self.lines = Vec::new(); // Do the reflow. self.reflow_fragments(old_fragment_iter, flow, layout_context); @@ -270,30 +261,14 @@ impl LineBreaker { // Set up our reflow flags. let flags = match fragment.style().get_inheritedtext().white_space { white_space::T::normal => InlineReflowFlags::empty(), - white_space::T::pre | white_space::T::nowrap => NO_WRAP_INLINE_REFLOW_FLAG, + white_space::T::nowrap => NO_WRAP_INLINE_REFLOW_FLAG, + white_space::T::pre => { + WRAP_ON_NEWLINE_INLINE_REFLOW_FLAG | NO_WRAP_INLINE_REFLOW_FLAG + } }; - // Try to append the fragment, and commit the line (so we can try again with the next - // line) if we couldn't. - match fragment.style().get_inheritedtext().white_space { - white_space::T::normal | white_space::T::nowrap => { - if !self.append_fragment_to_line_if_possible(fragment, - flow, - layout_context, - flags) { - self.flush_current_line() - } - } - white_space::T::pre => { - // FIXME(pcwalton): Surely we can unify - // `append_fragment_to_line_if_possible` and - // `try_append_to_line_by_new_line` by adding another bit in the reflow - // flags. - if !self.try_append_to_line_by_new_line(layout_context, fragment) { - self.flush_current_line() - } - } - } + // Try to append the fragment. + self.reflow_fragment(fragment, flow, layout_context, flags); } if !self.pending_line_is_empty() { @@ -301,37 +276,25 @@ impl LineBreaker { self.lines.len()); self.flush_current_line() } - - // Strip trailing whitespace from the last line if necessary. - if let Some(ref mut last_line) = self.lines.last_mut() { - if let Some(ref mut last_fragment) = self.new_fragments.last_mut() { - let previous_inline_size = last_line.bounds.size.inline - - last_fragment.border_box.size.inline; - if last_fragment.strip_trailing_whitespace_if_necessary() { - last_line.bounds.size.inline = previous_inline_size + - last_fragment.border_box.size.inline; - } - } - } } /// Acquires a new fragment to lay out from the work list or fragment list as appropriate. - /// Note that you probably don't want to call this method directly in order to be - /// incremental-reflow-safe; try `next_unbroken_fragment` instead. + /// If the fragment was at the end of an old line, undoes the line break for that fragment. + /// Note that you probably don't want to call this method directly in order to be incremental- + /// reflow-safe; try `next_unbroken_fragment` instead. fn next_fragment(&mut self, old_fragment_iter: &mut I) -> Option where I: Iterator { + let mut fragment; if self.work_list.is_empty() { - return match old_fragment_iter.next() { - None => None, - Some(fragment) => { - debug!("LineBreaker: working with fragment from flow: {:?}", fragment); - Some(fragment) - } + match old_fragment_iter.next() { + None => return None, + Some(this_fragment) => fragment = this_fragment, } + } else { + return self.work_list.pop_front() } - debug!("LineBreaker: working with fragment from work list: {:?}", self.work_list.front()); - self.work_list.pop_front() + Some(fragment) } /// Acquires a new fragment to lay out from the work list or fragment list, merging it with any @@ -346,10 +309,6 @@ impl LineBreaker { }; loop { - // FIXME(pcwalton): Yuck! I hate this `new_line_pos` stuff. Can we avoid having to do - // this? - result.restore_new_line_pos(); - let candidate = match self.next_fragment(old_fragment_iter) { None => return Some(result), Some(fragment) => fragment, @@ -357,31 +316,58 @@ impl LineBreaker { let need_to_merge = match (&mut result.specific, &candidate.specific) { (&mut SpecificFragmentInfo::ScannedText(ref mut result_info), - &SpecificFragmentInfo::ScannedText(ref candidate_info)) - if arc_ptr_eq(&result_info.run, &candidate_info.run) && - result_info.range.end() + CharIndex(1) == candidate_info.range.begin() => { - // We found a previously-broken fragment. Merge it up. - result_info.range.extend_by(candidate_info.range.length() + CharIndex(1)); - true + &SpecificFragmentInfo::ScannedText(ref candidate_info)) => { + util::arc_ptr_eq(&result_info.run, &candidate_info.run) && + inline_contexts_are_equal(&result.inline_context, + &candidate.inline_context) } _ => false, }; - if !need_to_merge { - self.work_list.push_front(candidate); - return Some(result) + + if need_to_merge { + result.merge_with(candidate); + continue } + + self.work_list.push_front(candidate); + return Some(result) } } /// Commits a line to the list. fn flush_current_line(&mut self) { debug!("LineBreaker: flushing line {}: {:?}", self.lines.len(), self.pending_line); + self.strip_trailing_whitespace_from_pending_line_if_necessary(); self.lines.push(self.pending_line); self.cur_b = self.pending_line.bounds.start.b + self.pending_line.bounds.size.block; self.reset_line(); } + /// Removes trailing whitespace from the pending line if necessary. This is done right before + /// flushing it. + fn strip_trailing_whitespace_from_pending_line_if_necessary(&mut self) { + if self.pending_line.range.is_empty() { + return + } + let last_fragment_index = self.pending_line.range.end() - FragmentIndex(1); + let mut fragment = &mut self.new_fragments[last_fragment_index.get() as usize]; + if let SpecificFragmentInfo::ScannedText(ref mut scanned_text_fragment_info) = + fragment.specific { + let scanned_text_fragment_info = &mut **scanned_text_fragment_info; + let mut range = &mut scanned_text_fragment_info.range; + strip_trailing_whitespace_if_necessary(&**scanned_text_fragment_info.run, range); + + let old_fragment_inline_size = fragment.border_box.size.inline; + scanned_text_fragment_info.content_size.inline = + scanned_text_fragment_info.run.metrics_for_range(range).advance_width; + fragment.border_box.size.inline = scanned_text_fragment_info.content_size.inline + + fragment.border_padding.inline_start_end(); + self.pending_line.bounds.size.inline = self.pending_line.bounds.size.inline - + (old_fragment_inline_size - fragment.border_box.size.inline) + } + } + // FIXME(eatkinson): this assumes that the tallest fragment in the line determines the line // block-size. This might not be the case with some weird text fonts. fn new_block_size_for_line(&self, new_fragment: &Fragment, layout_context: &LayoutContext) @@ -488,71 +474,16 @@ impl LineBreaker { false } - /// Tries to append the given fragment to the line for `pre`-formatted text, splitting it if - /// necessary. Returns true if we successfully pushed the fragment to the line or false if we - /// couldn't. - fn try_append_to_line_by_new_line(&mut self, - layout_context: &LayoutContext, - in_fragment: Fragment) - -> bool { - let should_push = match in_fragment.newline_positions() { - None => true, - Some(ref positions) => positions.is_empty(), - }; - if should_push { - debug!("LineBreaker: did not find a newline character; pushing the fragment to \ - the line without splitting"); - self.push_fragment_to_line(layout_context, in_fragment); - return true - } - - debug!("LineBreaker: Found a new-line character, so splitting the line."); - - let (inline_start, inline_end, run) = - in_fragment.find_split_info_by_new_line() - .expect("LineBreaker: this split case makes no sense!"); - let writing_mode = self.floats.writing_mode; - - let split_fragment = |split: SplitInfo| { - let size = LogicalSize::new(writing_mode, - split.inline_size, - in_fragment.border_box.size.block); - let info = box ScannedTextFragmentInfo::new(run.clone(), - split.range, - (*in_fragment.newline_positions() - .unwrap()).clone(), - size); - in_fragment.transform(size, SpecificFragmentInfo::ScannedText(info)) - }; - - debug!("LineBreaker: Pushing the fragment to the inline_start of the new-line character \ - to the line."); - let mut inline_start = split_fragment(inline_start); - inline_start.save_new_line_pos(); - *inline_start.newline_positions_mut().unwrap() = vec![]; - self.push_fragment_to_line(layout_context, inline_start); - - for inline_end in inline_end.into_iter() { - debug!("LineBreaker: Deferring the fragment to the inline_end of the new-line \ - character to the line."); - let mut inline_end = split_fragment(inline_end); - inline_end.newline_positions_mut().unwrap().remove(0); - self.work_list.push_front(inline_end); - } - - false - } - - /// Tries to append the given fragment to the line, splitting it if necessary. Returns true if - /// we successfully pushed the fragment to the line or false if we couldn't. - fn append_fragment_to_line_if_possible(&mut self, - fragment: Fragment, - flow: &InlineFlow, - layout_context: &LayoutContext, - flags: InlineReflowFlags) - -> bool { + /// Tries to append the given fragment to the line, splitting it if necessary. Commits the + /// current line if needed. + fn reflow_fragment(&mut self, + mut fragment: Fragment, + flow: &InlineFlow, + layout_context: &LayoutContext, + flags: InlineReflowFlags) { // Determine initial placement for the fragment if we need to. if self.pending_line_is_empty() { + fragment.strip_leading_whitespace_if_necessary(); let (line_bounds, _) = self.initial_line_placement(flow, &fragment, self.cur_b); self.pending_line.bounds.start = line_bounds.start; self.pending_line.green_zone = line_bounds.size; @@ -572,9 +503,22 @@ impl LineBreaker { let new_block_size = self.new_block_size_for_line(&fragment, layout_context); if new_block_size > green_zone.block { // Uh-oh. Float collision imminent. Enter the float collision avoider! - return self.avoid_floats(flow, fragment, new_block_size) + if !self.avoid_floats(flow, fragment, new_block_size) { + self.flush_current_line(); + } + return } + // If we must flush the line after finishing this fragment due to `white-space: pre`, + // detect that. + let line_flush_mode = + if flags.contains(WRAP_ON_NEWLINE_INLINE_REFLOW_FLAG) && + fragment.requires_line_break_afterward_if_wrapping_on_newlines() { + LineFlushMode::Flush + } else { + LineFlushMode::No + }; + // If we're not going to overflow the green zone vertically, we might still do so // horizontally. We'll try to place the whole fragment on this line and break somewhere if // it doesn't fit. @@ -583,23 +527,27 @@ impl LineBreaker { fragment.border_box.size.inline + indentation; if new_inline_size <= green_zone.inline { debug!("LineBreaker: fragment fits without splitting"); - self.push_fragment_to_line(layout_context, fragment); - return true + self.push_fragment_to_line(layout_context, fragment, line_flush_mode); + return } // If we can't split the fragment or aren't allowed to because of the wrapping mode, then // just overflow. if (!fragment.can_split() && self.pending_line_is_empty()) || - flags.contains(NO_WRAP_INLINE_REFLOW_FLAG) { + (flags.contains(NO_WRAP_INLINE_REFLOW_FLAG) && + !flags.contains(WRAP_ON_NEWLINE_INLINE_REFLOW_FLAG)) { debug!("LineBreaker: fragment can't split and line {} is empty, so overflowing", self.lines.len()); - self.push_fragment_to_line(layout_context, fragment); - return false + self.push_fragment_to_line(layout_context, fragment, LineFlushMode::No); + return } // Split it up! - let available_inline_size = green_zone.inline - self.pending_line.bounds.size.inline - - indentation; + let available_inline_size = if !flags.contains(NO_WRAP_INLINE_REFLOW_FLAG) { + green_zone.inline - self.pending_line.bounds.size.inline - indentation + } else { + MAX_AU + }; let inline_start_fragment; let inline_end_fragment; let split_result = match fragment.calculate_split_position(available_inline_size, @@ -607,7 +555,8 @@ impl LineBreaker { None => { debug!("LineBreaker: fragment was unsplittable; deferring to next line"); self.work_list.push_front(fragment); - return false + self.flush_current_line(); + return } Some(split_result) => split_result, }; @@ -623,23 +572,30 @@ impl LineBreaker { // the second fragment. If there's no second fragment, the next line will start off empty. match (inline_start_fragment, inline_end_fragment) { (Some(inline_start_fragment), Some(inline_end_fragment)) => { - self.push_fragment_to_line(layout_context, inline_start_fragment); - self.flush_current_line(); + self.push_fragment_to_line(layout_context, + inline_start_fragment, + LineFlushMode::Flush); self.work_list.push_front(inline_end_fragment) }, (Some(fragment), None) => { - self.push_fragment_to_line(layout_context, fragment); + self.push_fragment_to_line(layout_context, fragment, line_flush_mode); + } + (None, Some(fragment)) => { + // Yes, this can happen! + self.flush_current_line(); + self.work_list.push_front(fragment) } - (None, Some(_)) => debug_assert!(false, "un-normalized split result"), (None, None) => {} } - - true } /// Pushes a fragment to the current line unconditionally, possibly truncating it and placing - /// an ellipsis based on the value of `text-overflow`. - fn push_fragment_to_line(&mut self, layout_context: &LayoutContext, fragment: Fragment) { + /// an ellipsis based on the value of `text-overflow`. If `flush_line` is `Flush`, then flushes + /// the line afterward; + fn push_fragment_to_line(&mut self, + layout_context: &LayoutContext, + fragment: Fragment, + line_flush_mode: LineFlushMode) { let indentation = self.indentation_for_pending_fragment(); if self.pending_line_is_empty() { assert!(self.new_fragments.len() <= (u16::MAX as usize)); @@ -661,25 +617,27 @@ impl LineBreaker { if !need_ellipsis { self.push_fragment_to_line_ignoring_text_overflow(fragment); - return + } else { + let ellipsis = fragment.transform_into_ellipsis(layout_context); + if let Some(truncation_info) = + fragment.truncate_to_inline_size(available_inline_size - + ellipsis.border_box.size.inline) { + let fragment = fragment.transform_with_split_info(&truncation_info.split, + truncation_info.text_run); + self.push_fragment_to_line_ignoring_text_overflow(fragment); + } + self.push_fragment_to_line_ignoring_text_overflow(ellipsis); } - let ellipsis = fragment.transform_into_ellipsis(layout_context); - if let Some(truncation_info) = - fragment.truncate_to_inline_size(available_inline_size - - ellipsis.border_box.size.inline) { - let fragment = fragment.transform_with_split_info(&truncation_info.split, - truncation_info.text_run); - self.push_fragment_to_line_ignoring_text_overflow(fragment); + if line_flush_mode == LineFlushMode::Flush { + self.flush_current_line() } - self.push_fragment_to_line_ignoring_text_overflow(ellipsis); } /// Pushes a fragment to the current line unconditionally, without placing an ellipsis in the /// case of `text-overflow: ellipsis`. fn push_fragment_to_line_ignoring_text_overflow(&mut self, fragment: Fragment) { let indentation = self.indentation_for_pending_fragment(); - self.pending_line.range.extend_by(FragmentIndex(1)); self.pending_line.bounds.size.inline = self.pending_line.bounds.size.inline + fragment.border_box.size.inline + @@ -813,7 +771,7 @@ impl InlineFlow { /// /// The extra boolean is set if and only if `largest_block_size_for_top_fragments` and/or /// `largest_block_size_for_bottom_fragments` were updated. That is, if the box has a `top` or - /// `bottom` value for `vertical-align, true is returned. + /// `bottom` value for `vertical-align`, true is returned. fn distance_from_baseline(fragment: &Fragment, ascent: Au, parent_text_block_start: Au, @@ -1180,7 +1138,7 @@ impl Flow for InlineFlow { // Reset our state, so that we handle incremental reflow correctly. // // TODO(pcwalton): Do something smarter, like Gecko and WebKit? - self.lines = Vec::new(); + self.lines.clear(); // Determine how much indentation the first line wants. let mut indentation = if self.fragments.is_empty() { @@ -1431,6 +1389,30 @@ impl InlineFragmentContext { styles: vec!() } } + + fn ptr_eq(&self, other: &InlineFragmentContext) -> bool { + if self.styles.len() != other.styles.len() { + return false + } + for (this_style, other_style) in self.styles.iter().zip(other.styles.iter()) { + if !util::arc_ptr_eq(this_style, other_style) { + return false + } + } + true + } +} + +fn inline_contexts_are_equal(inline_context_a: &Option, + inline_context_b: &Option) + -> bool { + match (inline_context_a, inline_context_b) { + (&Some(ref inline_context_a), &Some(ref inline_context_b)) => { + inline_context_a.ptr_eq(inline_context_b) + } + (&None, &None) => true, + (&Some(_), &None) | (&None, &Some(_)) => false, + } } /// Block-size above the baseline, depth below the baseline, and ascent for a fragment. See CSS 2.1 @@ -1464,3 +1446,31 @@ impl InlineMetrics { } } } + +#[derive(Copy, Clone, PartialEq)] +enum LineFlushMode { + No, + Flush, +} + +/// Given a range and a text run, adjusts the range to eliminate trailing whitespace. +fn strip_trailing_whitespace_if_necessary(text_run: &TextRun, range: &mut Range) { + // FIXME(pcwalton): Is there a more clever (i.e. faster) way to do this? + debug!("stripping trailing whitespace: range={:?}, len={}", + range, + text_run.text.chars().count()); + let text = text_run.text.slice_chars(range.begin().to_usize(), range.end().to_usize()); + let mut trailing_whitespace_character_count = 0; + for ch in text.chars().rev() { + if util::str::char_is_whitespace(ch) { + trailing_whitespace_character_count += 1 + } else { + break + } + } + + if trailing_whitespace_character_count != 0 { + range.extend_by(CharIndex(-trailing_whitespace_character_count)); + } +} + diff --git a/components/layout/model.rs b/components/layout/model.rs index 64ba9a001d8..2479ab7cb47 100644 --- a/components/layout/model.rs +++ b/components/layout/model.rs @@ -174,7 +174,12 @@ impl MarginCollapseInfo { pub fn current_float_ceiling(&mut self) -> Au { match self.state { - MarginCollapseState::AccumulatingCollapsibleTopMargin => self.block_start_margin.collapse(), + MarginCollapseState::AccumulatingCollapsibleTopMargin => { + // We do not include the top margin in the float ceiling, because the float flow + // needs to be positioned relative to our *border box*, not our margin box. See + // `tests/ref/float_under_top_margin_a.html`. + Au(0) + } MarginCollapseState::AccumulatingMarginIn => self.margin_in.collapse(), } } @@ -182,18 +187,22 @@ impl MarginCollapseInfo { /// Adds the child's potentially collapsible block-start margin to the current margin state and /// advances the Y offset by the appropriate amount to handle that margin. Returns the amount /// that should be added to the Y offset during block layout. - pub fn advance_block_start_margin(&mut self, child_collapsible_margins: &CollapsibleMargins) -> Au { + pub fn advance_block_start_margin(&mut self, child_collapsible_margins: &CollapsibleMargins) + -> Au { match (self.state, *child_collapsible_margins) { - (MarginCollapseState::AccumulatingCollapsibleTopMargin, CollapsibleMargins::None(block_start, _)) => { + (MarginCollapseState::AccumulatingCollapsibleTopMargin, + CollapsibleMargins::None(block_start, _)) => { self.state = MarginCollapseState::AccumulatingMarginIn; block_start } - (MarginCollapseState::AccumulatingCollapsibleTopMargin, CollapsibleMargins::Collapse(block_start, _)) => { + (MarginCollapseState::AccumulatingCollapsibleTopMargin, + CollapsibleMargins::Collapse(block_start, _)) => { self.block_start_margin.union(block_start); self.state = MarginCollapseState::AccumulatingMarginIn; Au(0) } - (MarginCollapseState::AccumulatingMarginIn, CollapsibleMargins::None(block_start, _)) => { + (MarginCollapseState::AccumulatingMarginIn, + CollapsibleMargins::None(block_start, _)) => { let previous_margin_value = self.margin_in.collapse(); self.margin_in = AdjoiningMargins::new(); previous_margin_value + block_start diff --git a/components/layout/text.rs b/components/layout/text.rs index 6380a4fe6ce..0844eadb359 100644 --- a/components/layout/text.rs +++ b/components/layout/text.rs @@ -6,7 +6,7 @@ #![deny(unsafe_code)] -use fragment::{Fragment, SpecificFragmentInfo, ScannedTextFragmentInfo}; +use fragment::{Fragment, SpecificFragmentInfo, ScannedTextFragmentInfo, UnscannedTextFragmentInfo}; use inline::InlineFragments; use gfx::font::{DISABLE_KERNING_SHAPING_FLAG, FontMetrics, IGNORE_LIGATURES_SHAPING_FLAG}; @@ -15,18 +15,19 @@ use gfx::font_context::FontContext; use gfx::text::glyph::CharIndex; use gfx::text::text_run::TextRun; use gfx::text::util::{self, CompressionMode}; -use util::linked_list::split_off_head; -use util::geometry::Au; -use util::logical_geometry::{LogicalSize, WritingMode}; -use util::range::Range; -use util::smallvec::{SmallVec, SmallVec1}; +use std::borrow::ToOwned; use std::collections::LinkedList; use std::mem; +use std::sync::Arc; use style::computed_values::{line_height, text_orientation, text_rendering, text_transform}; use style::computed_values::{white_space}; use style::properties::ComputedValues; use style::properties::style_structs::Font as FontStyle; -use std::sync::Arc; +use util::geometry::Au; +use util::linked_list::split_off_head; +use util::logical_geometry::{LogicalSize, WritingMode}; +use util::range::Range; +use util::smallvec::{SmallVec, SmallVec1}; /// A stack-allocated object for scanning an inline flow into `TextRun`-containing `TextFragment`s. pub struct TextRunScanner { @@ -40,7 +41,9 @@ impl TextRunScanner { } } - pub fn scan_for_runs(&mut self, font_context: &mut FontContext, mut fragments: LinkedList) + pub fn scan_for_runs(&mut self, + font_context: &mut FontContext, + mut fragments: LinkedList) -> InlineFragments { debug!("TextRunScanner: scanning {} fragments for text runs...", fragments.len()); @@ -50,12 +53,14 @@ impl TextRunScanner { let mut last_whitespace = true; while !fragments.is_empty() { // Create a clump. + split_first_fragment_at_newline_if_necessary(&mut fragments); self.clump.append(&mut split_off_head(&mut fragments)); while !fragments.is_empty() && self.clump .back() .unwrap() .can_merge_with_fragment(fragments.front() .unwrap()) { + split_first_fragment_at_newline_if_necessary(&mut fragments); self.clump.append(&mut split_off_head(&mut fragments)); } @@ -101,7 +106,6 @@ impl TextRunScanner { // // Concatenate all of the transformed strings together, saving the new character indices. let mut new_ranges: SmallVec1> = SmallVec1::new(); - let mut new_line_positions: SmallVec1 = SmallVec1::new(); let mut char_total = CharIndex(0); let run = { let fontgroup; @@ -137,14 +141,11 @@ impl TextRunScanner { _ => panic!("Expected an unscanned text fragment!"), }; - let mut new_line_pos = Vec::new(); let old_length = CharIndex(run_text.chars().count() as isize); last_whitespace = util::transform_text(in_fragment.as_slice(), compression, last_whitespace, - &mut run_text, - &mut new_line_pos); - new_line_positions.push(NewLinePositions(new_line_pos)); + &mut run_text); let added_chars = CharIndex(run_text.chars().count() as isize) - old_length; new_ranges.push(Range::new(char_total, added_chars)); @@ -200,13 +201,8 @@ impl TextRunScanner { } let text_size = old_fragment.border_box.size; - let &mut NewLinePositions(ref mut new_line_positions) = - new_line_positions.get_mut(logical_offset); let mut new_text_fragment_info = - box ScannedTextFragmentInfo::new(run.clone(), - range, - mem::replace(new_line_positions, Vec::new()), - text_size); + box ScannedTextFragmentInfo::new(run.clone(), range, text_size); let new_metrics = new_text_fragment_info.run.metrics_for_range(&range); let bounding_box_size = bounding_box_for_run_metrics(&new_metrics, old_fragment.style.writing_mode); @@ -270,8 +266,6 @@ impl TextRunScanner { } } -struct NewLinePositions(Vec); - #[inline] fn bounding_box_for_run_metrics(metrics: &RunMetrics, writing_mode: WritingMode) -> LogicalSize { @@ -318,3 +312,45 @@ pub fn line_height_from_style(style: &ComputedValues, metrics: &FontMetrics) -> line_height::T::Length(l) => l } } + +fn split_first_fragment_at_newline_if_necessary(fragments: &mut LinkedList) { + if fragments.len() < 1 { + return + } + + let new_fragment = { + let mut first_fragment = fragments.front_mut().unwrap(); + let string_before; + { + let unscanned_text_fragment_info = match first_fragment.specific { + SpecificFragmentInfo::UnscannedText(ref mut unscanned_text_fragment_info) => { + unscanned_text_fragment_info + } + _ => return, + }; + + if first_fragment.style.get_inheritedtext().white_space != white_space::T::pre { + return + } + + let position = match unscanned_text_fragment_info.text.find('\n') { + Some(position) if position < unscanned_text_fragment_info.text.len() - 1 => { + position + } + Some(_) | None => return, + }; + + string_before = + box unscanned_text_fragment_info.text[..(position + 1)].to_owned(); + unscanned_text_fragment_info.text = + box unscanned_text_fragment_info.text[(position + 1)..].to_owned(); + } + first_fragment.transform(first_fragment.border_box.size, + SpecificFragmentInfo::UnscannedText(UnscannedTextFragmentInfo { + text: string_before, + })) + }; + + fragments.push_front(new_fragment); +} + diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index b599e75d745..137a2e469b6 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -41,11 +41,12 @@ use opaque_node::OpaqueNodeMethods; use cssparser::RGBA; use gfx::display_list::OpaqueNode; -use script::dom::bindings::codegen::InheritTypes::{ElementCast, HTMLIFrameElementCast}; -use script::dom::bindings::codegen::InheritTypes::{HTMLCanvasElementCast, HTMLImageElementCast}; -use script::dom::bindings::codegen::InheritTypes::{HTMLInputElementCast, HTMLTextAreaElementCast}; -use script::dom::bindings::codegen::InheritTypes::{NodeCast, TextCast}; +use script::dom::bindings::codegen::InheritTypes::{CharacterDataCast, ElementCast}; +use script::dom::bindings::codegen::InheritTypes::{HTMLIFrameElementCast, HTMLCanvasElementCast}; +use script::dom::bindings::codegen::InheritTypes::{HTMLImageElementCast, HTMLInputElementCast}; +use script::dom::bindings::codegen::InheritTypes::{HTMLTextAreaElementCast, NodeCast, TextCast}; use script::dom::bindings::js::LayoutJS; +use script::dom::characterdata::LayoutCharacterDataHelpers; use script::dom::element::{Element, ElementTypeId}; use script::dom::element::{LayoutElementHelpers, RawLayoutElementHelpers}; use script::dom::htmlelement::HTMLElementTypeId; @@ -222,9 +223,8 @@ impl<'ln> TLayoutNode for LayoutNode<'ln> { let text: Option> = TextCast::to_layout_js(self.get_jsmanaged()); if let Some(text) = text { return vec![ - ContentItem::String((*text.unsafe_get()).characterdata() - .data_for_layout() - .to_owned()) + ContentItem::String( + CharacterDataCast::from_layout_js(&text).data_for_layout().to_owned()) ]; } let input: Option> = @@ -961,7 +961,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { None => return false }; - if !is_whitespace((*text.unsafe_get()).characterdata().data_for_layout()) { + if !is_whitespace(CharacterDataCast::from_layout_js(&text).data_for_layout()) { return false } diff --git a/components/net/mime_classifier.rs b/components/net/mime_classifier.rs index 773436d92d9..6501abdb6bb 100644 --- a/components/net/mime_classifier.rs +++ b/components/net/mime_classifier.rs @@ -111,7 +111,7 @@ impl MIMEClassifier { self.binary_or_plaintext.classify(data) } fn is_xml(tp: &str, sub_tp: &str) -> bool { - let suffix = &sub_tp[(max((sub_tp.len() as int) - ("+xml".len() as int), 0i) as uint)..]; + let suffix = &sub_tp[(max(sub_tp.len() as isize - "+xml".len() as isize, 0) as usize)..]; match (tp, sub_tp, suffix) { (_, _, "+xml") | ("application", "xml",_) | ("text", "xml",_) => {true} _ => {false} @@ -170,13 +170,13 @@ struct ByteMatcher { } impl ByteMatcher { - fn matches(&self, data: &Vec) -> Option { + fn matches(&self, data: &Vec) -> Option { if data.len() < self.pattern.len() { return None; } //TODO replace with iterators if I ever figure them out... - let mut i = 0u; + let mut i: usize = 0; let max_i = data.len()-self.pattern.len(); loop { @@ -184,12 +184,12 @@ impl ByteMatcher { break; } - i=i + 1; + i = i + 1; if i > max_i { return None; } } - for j in range(0u,self.pattern.len()) { + for j in 0..self.pattern.len() { if (data[i] & self.mask[j]) != (self.pattern[j] & self.mask[j]) { return None; } @@ -231,7 +231,7 @@ impl Mp4Matcher { return false; } let box_size = ((data[0] as u32) << 3 | (data[1] as u32) << 2 | - (data[2] as u32) << 1 | (data[3] as u32)) as uint; + (data[2] as u32) << 1 | (data[3] as u32)) as usize; if (data.len() < box_size) || (box_size % 4 != 0) { return false; } @@ -239,14 +239,14 @@ impl Mp4Matcher { let ftyp = [0x66, 0x74, 0x79, 0x70]; let mp4 = [0x6D, 0x70, 0x34]; - for i in range(4u,8u) { + for i in 4..8 { if data[i] != ftyp[i - 4] { return false; } } let mut all_match = true; - for i in range(8u,11u) { - if data[i]!=mp4[i - 8u] { + for i in 8..11 { + if data[i]!=mp4[i - 8] { all_match = false; break; } @@ -255,11 +255,11 @@ impl Mp4Matcher { return true; } - let mut bytes_read = 16u; + let mut bytes_read: usize = 16; while bytes_read < box_size { all_match = true; - for i in range(0u,3u) { + for i in 0..3 { if mp4[i] != data[i + bytes_read] { all_match = false; break; diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 650d1507b77..dd788146acd 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5427,6 +5427,12 @@ impl ${name}Cast { unsafe { derived.transmute_borrowed() } } + #[inline(always)] + #[allow(unrooted_must_root)] + pub fn from_layout_js(derived: &LayoutJS) -> LayoutJS<${name}> { + unsafe { derived.transmute_copy() } + } + #[inline(always)] pub fn from_temporary(derived: Temporary) -> Temporary<${name}> { unsafe { derived.transmute() } diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index feba3941bf3..426bff64d95 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -71,10 +71,9 @@ pub type Fallible = Result; /// return `()`. pub type ErrorResult = Fallible<()>; -/// Set a pending DOM exception for the given `result` on `cx`. +/// Set a pending exception for the given `result` on `cx`. pub fn throw_dom_exception(cx: *mut JSContext, global: GlobalRef, result: Error) { - assert!(unsafe { JS_IsExceptionPending(cx) } == 0); let code = match result { Error::IndexSize => DOMErrorName::IndexSizeError, Error::NotFound => DOMErrorName::NotFoundError, @@ -93,11 +92,17 @@ pub fn throw_dom_exception(cx: *mut JSContext, global: GlobalRef, Error::DataClone => DOMErrorName::DataCloneError, Error::NoModificationAllowed => DOMErrorName::NoModificationAllowedError, Error::Type(message) => { + assert!(unsafe { JS_IsExceptionPending(cx) } == 0); throw_type_error(cx, &message); return; } - Error::JSFailed => panic!(), + Error::JSFailed => { + assert!(unsafe { JS_IsExceptionPending(cx) } == 1); + return; + } }; + + assert!(unsafe { JS_IsExceptionPending(cx) } == 0); let exception = DOMException::new(global, code).root(); let thrown = exception.to_jsval(cx); unsafe { diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index 7faca76b6c6..c8a4e6a9da7 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -7,14 +7,17 @@ use dom::bindings::codegen::PrototypeList; use dom::bindings::codegen::PrototypeList::MAX_PROTO_CHAIN_LENGTH; use dom::bindings::conversions::{native_from_reflector_jsmanaged, is_dom_class}; -use dom::bindings::error::throw_type_error; +use dom::bindings::error::{Error, ErrorResult, Fallible, throw_type_error}; use dom::bindings::global::GlobalRef; use dom::bindings::js::{Temporary, Root}; use dom::browsercontext; use dom::window; +use util::namespace; +use util::str::DOMString; use libc; use libc::c_uint; +use std::borrow::ToOwned; use std::boxed; use std::cell::Cell; use std::ffi::CString; @@ -43,6 +46,7 @@ use js::rust::with_compartment; use js::{JSPROP_ENUMERATE, JSPROP_READONLY, JSPROP_PERMANENT}; use js::JSFUN_CONSTRUCTOR; use js; +use string_cache::{Atom, Namespace}; /// Proxy handler for a WindowProxy. pub struct WindowProxyHandler(pub *const libc::c_void); @@ -604,6 +608,68 @@ pub unsafe fn delete_property_by_id(cx: *mut JSContext, object: *mut JSObject, return true; } +/// Validate a qualified name. See https://dom.spec.whatwg.org/#validate for details. +pub fn validate_qualified_name(qualified_name: &str) -> ErrorResult { + match xml_name_type(qualified_name) { + XMLName::InvalidXMLName => { + // Step 1. + return Err(Error::InvalidCharacter); + }, + XMLName::Name => { + // Step 2. + return Err(Error::Namespace); + }, + XMLName::QName => Ok(()) + } +} + +/// Validate a namespace and qualified name and extract their parts. +/// See https://dom.spec.whatwg.org/#validate-and-extract for details. +pub fn validate_and_extract(namespace: Option, qualified_name: &str) + -> Fallible<(Namespace, Option, Atom)> { + // Step 1. + let namespace = namespace::from_domstring(namespace); + + // Step 2. + try!(validate_qualified_name(qualified_name)); + + let (prefix, local_name) = if qualified_name.contains(":") { + // Step 5. + let mut parts = qualified_name.splitn(1, ':'); + let prefix = parts.next().unwrap(); + debug_assert!(!prefix.is_empty()); + let local_name = parts.next().unwrap(); + debug_assert!(!local_name.contains(":")); + (Some(prefix), local_name) + } else { + (None, qualified_name) + }; + + match (namespace, prefix) { + (ns!(""), Some(_)) => { + // Step 6. + Err(Error::Namespace) + }, + (ref ns, Some("xml")) if ns != &ns!(XML) => { + // Step 7. + Err(Error::Namespace) + }, + (ref ns, p) if ns != &ns!(XMLNS) && + (qualified_name == "xmlns" || p == Some("xmlns")) => { + // Step 8. + Err(Error::Namespace) + }, + (ns!(XMLNS), p) if qualified_name != "xmlns" && p != Some("xmlns") => { + // Step 9. + Err(Error::Namespace) + }, + (ns, p) => { + // Step 10. + Ok((ns, p.map(|s| s.to_owned()), Atom::from_slice(local_name))) + } + } +} + /// Results of `xml_name_type`. #[derive(PartialEq)] #[allow(missing_docs)] diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 8213e7afc87..17dda025def 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -53,6 +53,7 @@ pub struct CanvasRenderingContext2D { image_smoothing_enabled: Cell, stroke_color: Cell, line_width: Cell, + miter_limit: Cell, fill_color: Cell, transform: Cell>, } @@ -75,6 +76,7 @@ impl CanvasRenderingContext2D { image_smoothing_enabled: Cell::new(true), stroke_color: Cell::new(black), line_width: Cell::new(1.0), + miter_limit: Cell::new(10.0), fill_color: Cell::new(black), transform: Cell::new(Matrix2D::identity()), } @@ -258,6 +260,18 @@ impl CanvasRenderingContext2D { _ => panic!("Image Cache: Unknown Result") } } + + fn create_drawable_rect(&self, x: f64, y: f64, w: f64, h: f64) -> Option> { + if !([x, y, w, h].iter().all(|val| val.is_finite())) { + return None; + } + + if w == 0.0 && h == 0.0 { + return None; + } + + Some(Rect(Point2D(x as f32, y as f32), Size2D(w as f32, h as f32))) + } } pub trait CanvasRenderingContext2DHelpers { @@ -358,33 +372,21 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D> } fn FillRect(self, x: f64, y: f64, width: f64, height: f64) { - if !(x.is_finite() && y.is_finite() && - width.is_finite() && height.is_finite()) { - return; + if let Some(rect) = self.create_drawable_rect(x, y, width, height) { + self.renderer.send(CanvasMsg::FillRect(rect)).unwrap(); } - - let rect = Rect(Point2D(x as f32, y as f32), Size2D(width as f32, height as f32)); - self.renderer.send(CanvasMsg::FillRect(rect)).unwrap(); } fn ClearRect(self, x: f64, y: f64, width: f64, height: f64) { - if !(x.is_finite() && y.is_finite() && - width.is_finite() && height.is_finite()) { - return; + if let Some(rect) = self.create_drawable_rect(x, y, width, height) { + self.renderer.send(CanvasMsg::ClearRect(rect)).unwrap(); } - - let rect = Rect(Point2D(x as f32, y as f32), Size2D(width as f32, height as f32)); - self.renderer.send(CanvasMsg::ClearRect(rect)).unwrap(); } fn StrokeRect(self, x: f64, y: f64, width: f64, height: f64) { - if !(x.is_finite() && y.is_finite() && - width.is_finite() && height.is_finite()) { - return; + if let Some(rect) = self.create_drawable_rect(x, y, width, height) { + self.renderer.send(CanvasMsg::StrokeRect(rect)).unwrap(); } - - let rect = Rect(Point2D(x as f32, y as f32), Size2D(width as f32, height as f32)); - self.renderer.send(CanvasMsg::StrokeRect(rect)).unwrap(); } fn BeginPath(self) { @@ -816,6 +818,19 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D> self.line_width.set(width); self.renderer.send(CanvasMsg::SetLineWidth(width as f32)).unwrap() } + + fn MiterLimit(self) -> f64 { + self.miter_limit.get() + } + + fn SetMiterLimit(self, limit: f64) { + if !limit.is_finite() || limit <= 0.0 { + return; + } + + self.miter_limit.set(limit); + self.renderer.send(CanvasMsg::SetMiterLimit(limit as f32)).unwrap() + } } #[unsafe_destructor] diff --git a/components/script/dom/characterdata.rs b/components/script/dom/characterdata.rs index 1f2b18f1b99..172fda96f47 100644 --- a/components/script/dom/characterdata.rs +++ b/components/script/dom/characterdata.rs @@ -6,11 +6,13 @@ use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods; -use dom::bindings::codegen::InheritTypes::{CharacterDataDerived, NodeCast}; +use dom::bindings::codegen::InheritTypes::{CharacterDataDerived, ElementCast}; +use dom::bindings::codegen::InheritTypes::NodeCast; use dom::bindings::error::{Fallible, ErrorResult}; use dom::bindings::error::Error::IndexSize; -use dom::bindings::js::JSRef; +use dom::bindings::js::{JSRef, LayoutJS, Temporary}; use dom::document::Document; +use dom::element::Element; use dom::eventtarget::{EventTarget, EventTargetTypeId}; use dom::node::{Node, NodeHelpers, NodeTypeId}; @@ -18,6 +20,7 @@ use util::str::DOMString; use std::borrow::ToOwned; use std::cell::Ref; +use std::cmp; #[dom_struct] pub struct CharacterData { @@ -43,67 +46,59 @@ impl CharacterData { data: DOMRefCell::new(data), } } - - #[inline] - pub fn node<'a>(&'a self) -> &'a Node { - &self.node - } - - #[inline] - pub fn data(&self) -> Ref { - self.data.borrow() - } - - #[inline] - pub fn set_data(&self, data: DOMString) { - *self.data.borrow_mut() = data; - } - - #[inline] - #[allow(unsafe_code)] - pub unsafe fn data_for_layout<'a>(&'a self) -> &'a str { - self.data.borrow_for_layout().as_slice() - } - } impl<'a> CharacterDataMethods for JSRef<'a, CharacterData> { + // https://dom.spec.whatwg.org/#dom-characterdata-data fn Data(self) -> DOMString { // FIXME(https://github.com/rust-lang/rust/issues/23338) let data = self.data.borrow(); data.clone() } - fn SetData(self, arg: DOMString) -> ErrorResult { - *self.data.borrow_mut() = arg; - Ok(()) + // https://dom.spec.whatwg.org/#dom-characterdata-data + fn SetData(self, data: DOMString) { + *self.data.borrow_mut() = data; } + // https://dom.spec.whatwg.org/#dom-characterdata-length fn Length(self) -> u32 { // FIXME(https://github.com/rust-lang/rust/issues/23338) let data = self.data.borrow(); data.chars().count() as u32 } + // https://dom.spec.whatwg.org/#dom-characterdata-substringdata fn SubstringData(self, offset: u32, count: u32) -> Fallible { - // FIXME(https://github.com/rust-lang/rust/issues/23338) let data = self.data.borrow(); - Ok(data.slice_chars(offset as usize, (offset + count) as usize).to_owned()) + // Step 1. + let len = data.chars().count(); + if len > offset as usize { + // Step 2. + return Err(IndexSize); + } + // Step 3. + let end = cmp::min((offset + count) as usize, len); + // Step 4. + Ok(data.slice_chars(offset as usize, end).to_owned()) } - fn AppendData(self, arg: DOMString) -> ErrorResult { - self.data.borrow_mut().push_str(arg.as_slice()); - Ok(()) + // https://dom.spec.whatwg.org/#dom-characterdata-appenddata + fn AppendData(self, data: DOMString) { + self.data.borrow_mut().push_str(&data); } + // https://dom.spec.whatwg.org/#dom-characterdata-insertdata fn InsertData(self, offset: u32, arg: DOMString) -> ErrorResult { self.ReplaceData(offset, 0, arg) } + // https://dom.spec.whatwg.org/#dom-characterdata-deletedata fn DeleteData(self, offset: u32, count: u32) -> ErrorResult { self.ReplaceData(offset, count, "".to_owned()) } + // https://dom.spec.whatwg.org/#dom-characterdata-replacedata fn ReplaceData(self, offset: u32, count: u32, arg: DOMString) -> ErrorResult { let length = self.data.borrow().chars().count() as u32; if offset > length { @@ -127,5 +122,40 @@ impl<'a> CharacterDataMethods for JSRef<'a, CharacterData> { let node: JSRef = NodeCast::from_ref(self); node.remove_self(); } + + // https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-previouselementsibling + fn GetPreviousElementSibling(self) -> Option> { + NodeCast::from_ref(self).preceding_siblings() + .filter_map(ElementCast::to_temporary).next() + } + + // https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-nextelementsibling + fn GetNextElementSibling(self) -> Option> { + NodeCast::from_ref(self).following_siblings() + .filter_map(ElementCast::to_temporary).next() + } } +pub trait CharacterDataHelpers<'a> { + fn data(self) -> Ref<'a, DOMString>; +} + +impl<'a> CharacterDataHelpers<'a> for JSRef<'a, CharacterData> { + #[inline] + fn data(self) -> Ref<'a, DOMString> { + self.extended_deref().data.borrow() + } +} + +#[allow(unsafe_code)] +pub trait LayoutCharacterDataHelpers { + unsafe fn data_for_layout<'a>(&'a self) -> &'a str; +} + +#[allow(unsafe_code)] +impl LayoutCharacterDataHelpers for LayoutJS { + #[inline] + unsafe fn data_for_layout<'a>(&'a self) -> &'a str { + &(*self.unsafe_get()).data.borrow_for_layout() + } +} diff --git a/components/script/dom/comment.rs b/components/script/dom/comment.rs index 85cca18b2b2..743e935db01 100644 --- a/components/script/dom/comment.rs +++ b/components/script/dom/comment.rs @@ -42,10 +42,5 @@ impl Comment { let document = global.as_window().Document().root(); Ok(Comment::new(data, document.r())) } - - #[inline] - pub fn characterdata<'a>(&'a self) -> &'a CharacterData { - &self.characterdata - } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index dad3cf7c96a..ca4182164d8 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -18,23 +18,24 @@ use dom::bindings::codegen::InheritTypes::{EventTargetCast, HTMLAnchorElementCas use dom::bindings::codegen::InheritTypes::{HTMLAnchorElementDerived, HTMLAppletElementDerived}; use dom::bindings::codegen::InheritTypes::{HTMLAreaElementDerived, HTMLEmbedElementDerived}; use dom::bindings::codegen::InheritTypes::{HTMLFormElementDerived, HTMLImageElementDerived}; -use dom::bindings::codegen::InheritTypes::{HTMLScriptElementDerived}; +use dom::bindings::codegen::InheritTypes::{HTMLScriptElementDerived, CharacterDataCast}; use dom::bindings::error::{ErrorResult, Fallible}; use dom::bindings::error::Error::{NotSupported, InvalidCharacter, Security}; -use dom::bindings::error::Error::{HierarchyRequest, Namespace}; +use dom::bindings::error::Error::HierarchyRequest; use dom::bindings::global::GlobalRef; use dom::bindings::js::{MutNullableJS, JS, JSRef, LayoutJS, Temporary, TemporaryPushable}; use dom::bindings::js::{OptionalRootable, RootedReference}; use dom::bindings::refcounted::Trusted; use dom::bindings::utils::reflect_dom_object; -use dom::bindings::utils::xml_name_type; -use dom::bindings::utils::XMLName::{QName, Name, InvalidXMLName}; +use dom::bindings::utils::{xml_name_type, validate_and_extract}; +use dom::bindings::utils::XMLName::InvalidXMLName; +use dom::characterdata::CharacterDataHelpers; use dom::comment::Comment; use dom::customevent::CustomEvent; use dom::documentfragment::DocumentFragment; use dom::documenttype::DocumentType; use dom::domimplementation::DOMImplementation; -use dom::element::{Element, ElementCreator, AttributeHandlers, get_attribute_parts}; +use dom::element::{Element, ElementCreator, AttributeHandlers}; use dom::element::{ElementTypeId, ActivationElementHelpers}; use dom::event::{Event, EventBubbles, EventCancelable, EventHelpers}; use dom::eventtarget::{EventTarget, EventTargetTypeId, EventTargetHelpers}; @@ -67,7 +68,7 @@ use net_traits::CookieSource::NonHTTP; use net_traits::ControlMsg::{SetCookiesForUrl, GetCookiesForUrl}; use script_task::Runnable; use script_traits::{MouseButton, UntrustedNodeAddress}; -use util::{opts, namespace}; +use util::opts; use util::str::{DOMString, split_html_space_chars}; use layout_interface::{ReflowGoal, ReflowQueryType}; @@ -975,45 +976,10 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { fn CreateElementNS(self, namespace: Option, qualified_name: DOMString) -> Fallible> { - let ns = namespace::from_domstring(namespace); - match xml_name_type(&qualified_name) { - InvalidXMLName => { - debug!("Not a valid element name"); - return Err(InvalidCharacter); - }, - Name => { - debug!("Not a valid qualified element name"); - return Err(Namespace); - }, - QName => {} - } - - let (prefix_from_qname, local_name_from_qname) = get_attribute_parts(&qualified_name); - match (&ns, prefix_from_qname, local_name_from_qname) { - // throw if prefix is not null and namespace is null - (&ns!(""), Some(_), _) => { - debug!("Namespace can't be null with a non-null prefix"); - return Err(Namespace); - }, - // throw if prefix is "xml" and namespace is not the XML namespace - (_, Some(ref prefix), _) if "xml" == *prefix && ns != ns!(XML) => { - debug!("Namespace must be the xml namespace if the prefix is 'xml'"); - return Err(Namespace); - }, - // throw if namespace is the XMLNS namespace and neither qualifiedName nor prefix is - // "xmlns" - (&ns!(XMLNS), Some(ref prefix), _) if "xmlns" == *prefix => {}, - (&ns!(XMLNS), _, "xmlns") => {}, - (&ns!(XMLNS), _, _) => { - debug!("The prefix or the qualified name must be 'xmlns' if namespace is the XMLNS namespace "); - return Err(Namespace); - }, - _ => {} - } - - let name = QualName::new(ns, Atom::from_slice(local_name_from_qname)); - Ok(Element::create(name, prefix_from_qname.map(|s| s.to_owned()), self, - ElementCreator::ScriptCreated)) + let (namespace, prefix, local_name) = + try!(validate_and_extract(namespace, &qualified_name)); + let name = QualName::new(namespace, local_name); + Ok(Element::create(name, prefix, self, ElementCreator::ScriptCreated)) } // http://dom.spec.whatwg.org/#dom-document-createattribute @@ -1032,6 +998,18 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { Ok(Attr::new(window.r(), name, value, l_name, ns!(""), None, None)) } + // http://dom.spec.whatwg.org/#dom-document-createattributens + fn CreateAttributeNS(self, namespace: Option, qualified_name: DOMString) + -> Fallible> { + let (namespace, prefix, local_name) = + try!(validate_and_extract(namespace, &qualified_name)); + let window = self.window.root(); + let value = AttrValue::String("".to_owned()); + let qualified_name = Atom::from_slice(&qualified_name); + Ok(Attr::new(window.r(), local_name, value, qualified_name, + namespace, prefix, None)) + } + // http://dom.spec.whatwg.org/#dom-document-createdocumentfragment fn CreateDocumentFragment(self) -> Temporary { DocumentFragment::new(self) @@ -1148,7 +1126,7 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { for child in title_element.children() { let child = child.root(); if let Some(text) = TextCast::to_ref(child.r()) { - title.push_str(&text.characterdata().data()); + title.push_str(&CharacterDataCast::from_ref(text).data()); } } } diff --git a/components/script/dom/domimplementation.rs b/components/script/dom/domimplementation.rs index 7e2a3dba03a..e5cac62f4e7 100644 --- a/components/script/dom/domimplementation.rs +++ b/components/script/dom/domimplementation.rs @@ -8,12 +8,10 @@ use dom::bindings::codegen::Bindings::DOMImplementationBinding::DOMImplementatio use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::InheritTypes::NodeCast; use dom::bindings::error::Fallible; -use dom::bindings::error::Error::{InvalidCharacter, Namespace}; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, JSRef, Root, Temporary, OptionalRootable}; use dom::bindings::utils::{Reflector, reflect_dom_object}; -use dom::bindings::utils::xml_name_type; -use dom::bindings::utils::XMLName::{QName, Name, InvalidXMLName}; +use dom::bindings::utils::validate_qualified_name; use dom::document::{Document, DocumentHelpers, IsHTMLDocument}; use dom::document::DocumentSource; use dom::documenttype::DocumentType; @@ -52,18 +50,11 @@ impl DOMImplementation { // http://dom.spec.whatwg.org/#domimplementation impl<'a> DOMImplementationMethods for JSRef<'a, DOMImplementation> { // http://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype - fn CreateDocumentType(self, qname: DOMString, pubid: DOMString, sysid: DOMString) -> Fallible> { - match xml_name_type(&qname) { - // Step 1. - InvalidXMLName => Err(InvalidCharacter), - // Step 2. - Name => Err(Namespace), - // Step 3. - QName => { - let document = self.document.root(); - Ok(DocumentType::new(qname, Some(pubid), Some(sysid), document.r())) - } - } + fn CreateDocumentType(self, qualified_name: DOMString, pubid: DOMString, sysid: DOMString) + -> Fallible> { + try!(validate_qualified_name(&qualified_name)); + let document = self.document.root(); + Ok(DocumentType::new(qualified_name, Some(pubid), Some(sysid), document.r())) } // http://dom.spec.whatwg.org/#dom-domimplementation-createdocument diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 9d25d2ad7b1..418dd124158 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -24,14 +24,13 @@ use dom::bindings::codegen::InheritTypes::{HTMLTableRowElementDerived, HTMLTextA use dom::bindings::codegen::InheritTypes::{HTMLTableSectionElementDerived, NodeCast}; use dom::bindings::codegen::InheritTypes::HTMLAnchorElementCast; use dom::bindings::error::{ErrorResult, Fallible}; -use dom::bindings::error::Error; use dom::bindings::error::Error::{InvalidCharacter, Syntax}; use dom::bindings::error::Error::NoModificationAllowed; use dom::bindings::js::{MutNullableJS, JS, JSRef, LayoutJS, Temporary, TemporaryPushable}; use dom::bindings::js::{OptionalRootable, RootedReference}; use dom::bindings::trace::RootedVec; -use dom::bindings::utils::xml_name_type; -use dom::bindings::utils::XMLName::{QName, Name, InvalidXMLName}; +use dom::bindings::utils::{xml_name_type, validate_and_extract}; +use dom::bindings::utils::XMLName::InvalidXMLName; use dom::create::create_element; use dom::domrect::DOMRect; use dom::domrectlist::DOMRectList; @@ -1037,58 +1036,14 @@ impl<'a> ElementMethods for JSRef<'a, Element> { // http://dom.spec.whatwg.org/#dom-element-setattributens fn SetAttributeNS(self, - namespace_url: Option, - name: DOMString, + namespace: Option, + qualified_name: DOMString, value: DOMString) -> ErrorResult { - // Step 1. - let namespace = namespace::from_domstring(namespace_url); - - let name_type = xml_name_type(&name); - match name_type { - // Step 2. - InvalidXMLName => return Err(InvalidCharacter), - // Step 3. - Name => return Err(Error::Namespace), - QName => {} - } - - // Step 4. - let (prefix, local_name) = get_attribute_parts(&name); - - if let Some(ref prefix_str) = prefix { - // Step 5. - if namespace == ns!("") { - return Err(Error::Namespace); - } - - // Step 6. - if "xml" == *prefix_str && namespace != ns!(XML) { - return Err(Error::Namespace); - } - - // Step 7b. - if "xmlns" == *prefix_str && namespace != ns!(XMLNS) { - return Err(Error::Namespace); - } - } - - let name = Atom::from_slice(&name); - let local_name = Atom::from_slice(local_name); - let xmlns = atom!("xmlns"); - - // Step 7a. - if xmlns == name && namespace != ns!(XMLNS) { - return Err(Error::Namespace); - } - - // Step 8. - if namespace == ns!(XMLNS) && xmlns != name && Some("xmlns") != prefix { - return Err(Error::Namespace); - } - - // Step 9. + let (namespace, prefix, local_name) = + try!(validate_and_extract(namespace, &qualified_name)); + let qualified_name = Atom::from_slice(&qualified_name); let value = self.parse_attribute(&namespace, &local_name, value); - self.do_set_attribute(local_name.clone(), value, name, + self.do_set_attribute(local_name.clone(), value, qualified_name, namespace.clone(), prefix.map(|s| s.to_owned()), |attr| { *attr.local_name() == local_name && @@ -1223,6 +1178,18 @@ impl<'a> ElementMethods for JSRef<'a, Element> { Ok(()) } + // https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-previouselementsibling + fn GetPreviousElementSibling(self) -> Option> { + NodeCast::from_ref(self).preceding_siblings() + .filter_map(ElementCast::to_temporary).next() + } + + // https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-nextelementsibling + fn GetNextElementSibling(self) -> Option> { + NodeCast::from_ref(self).following_siblings() + .filter_map(ElementCast::to_temporary).next() + } + // http://dom.spec.whatwg.org/#dom-parentnode-children fn Children(self) -> Temporary { let window = window_from_node(self).root(); @@ -1293,17 +1260,6 @@ impl<'a> ElementMethods for JSRef<'a, Element> { } } -pub fn get_attribute_parts<'a>(name: &'a str) -> (Option<&'a str>, &'a str) { - //FIXME: Throw for XML-invalid names - //FIXME: Throw for XMLNS-invalid names - if name.contains(":") { - let mut parts = name.splitn(1, ':'); - (Some(parts.next().unwrap()), parts.next().unwrap()) - } else { - (None, name) - } -} - impl<'a> VirtualMethods for JSRef<'a, Element> { fn super_type<'b>(&'b self) -> Option<&'b VirtualMethods> { let node: &JSRef = NodeCast::from_borrowed_ref(self); diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 7b4f7a8aea0..49cf5f257ed 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -524,8 +524,7 @@ impl<'a> HTMLScriptElementMethods for JSRef<'a, HTMLScriptElement> { // http://www.whatwg.org/html/#dom-script-text fn Text(self) -> DOMString { - let node: JSRef = NodeCast::from_ref(self); - Node::collect_text_contents(node.children().map(|c| c.root()).map(|c| c.get_unsound_ref_forever())) + Node::collect_text_contents(NodeCast::from_ref(self).children()) } // http://www.whatwg.org/html/#dom-script-text diff --git a/components/script/dom/htmltitleelement.rs b/components/script/dom/htmltitleelement.rs index df2592acef9..5fb9cd3b25f 100644 --- a/components/script/dom/htmltitleelement.rs +++ b/components/script/dom/htmltitleelement.rs @@ -6,8 +6,9 @@ use dom::bindings::codegen::Bindings::HTMLTitleElementBinding; use dom::bindings::codegen::Bindings::HTMLTitleElementBinding::HTMLTitleElementMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTitleElementDerived, NodeCast}; -use dom::bindings::codegen::InheritTypes::{TextCast}; +use dom::bindings::codegen::InheritTypes::{CharacterDataCast, TextCast}; use dom::bindings::js::{JSRef, Temporary}; +use dom::characterdata::CharacterDataHelpers; use dom::document::{Document, DocumentHelpers}; use dom::eventtarget::{EventTarget, EventTargetTypeId}; use dom::element::ElementTypeId; @@ -51,7 +52,7 @@ impl<'a> HTMLTitleElementMethods for JSRef<'a, HTMLTitleElement> { let child = child.root(); let text: Option> = TextCast::to_ref(child.r()); match text { - Some(text) => content.push_str(text.characterdata().data().as_slice()), + Some(text) => content.push_str(&CharacterDataCast::from_ref(text).data()), None => (), } } diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index d1dd72a30b6..6c7204f7765 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -315,6 +315,7 @@ pub mod servohtmlparser; pub mod storage; pub mod storageevent; pub mod text; +pub mod textdecoder; pub mod textencoder; pub mod treewalker; pub mod uievent; diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index b67056836e6..1249aec902a 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -13,12 +13,11 @@ use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods; use dom::bindings::codegen::Bindings::NodeBinding::{NodeConstants, NodeMethods}; use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods; use dom::bindings::codegen::Bindings::ProcessingInstructionBinding::ProcessingInstructionMethods; -use dom::bindings::codegen::InheritTypes::{CommentCast, DocumentCast, DocumentTypeCast}; -use dom::bindings::codegen::InheritTypes::{ElementCast, TextCast, NodeCast, ElementDerived}; -use dom::bindings::codegen::InheritTypes::{CharacterDataCast, NodeBase, NodeDerived}; -use dom::bindings::codegen::InheritTypes::{ProcessingInstructionCast, EventTargetCast}; +use dom::bindings::codegen::InheritTypes::{CharacterDataCast, DocumentCast, DocumentTypeCast}; +use dom::bindings::codegen::InheritTypes::{ElementCast, NodeCast, ElementDerived, EventTargetCast}; use dom::bindings::codegen::InheritTypes::{HTMLLegendElementDerived, HTMLFieldSetElementDerived}; -use dom::bindings::codegen::InheritTypes::HTMLOptGroupElementDerived; +use dom::bindings::codegen::InheritTypes::{HTMLOptGroupElementDerived, NodeBase, NodeDerived}; +use dom::bindings::codegen::InheritTypes::{ProcessingInstructionCast, TextCast}; use dom::bindings::conversions; use dom::bindings::error::Fallible; use dom::bindings::error::Error::{NotFound, HierarchyRequest, Syntax}; @@ -29,7 +28,7 @@ use dom::bindings::js::{ResultRootable, OptionalRootable, MutNullableJS}; use dom::bindings::trace::JSTraceable; use dom::bindings::trace::RootedVec; use dom::bindings::utils::{Reflectable, reflect_dom_object}; -use dom::characterdata::CharacterData; +use dom::characterdata::{CharacterData, CharacterDataHelpers}; use dom::comment::Comment; use dom::document::{Document, DocumentHelpers, IsHTMLDocument, DocumentSource}; use dom::documentfragment::DocumentFragment; @@ -415,6 +414,7 @@ pub trait NodeHelpers<'a> { fn rev_children(self) -> ReverseChildrenIterator; fn child_elements(self) -> ChildElementIterator; fn following_siblings(self) -> NodeSiblingIterator; + fn preceding_siblings(self) -> ReverseChildrenIterator; fn is_in_doc(self) -> bool; fn is_inclusive_ancestor_of(self, parent: JSRef) -> bool; fn is_parent_of(self, child: JSRef) -> bool; @@ -764,6 +764,12 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> { } } + fn preceding_siblings(self) -> ReverseChildrenIterator { + ReverseChildrenIterator { + current: self.prev_sibling(), + } + } + fn is_parent_of(self, child: JSRef) -> bool { match child.parent_node() { Some(ref parent) if parent == &Temporary::from_rooted(self) => true, @@ -1594,8 +1600,8 @@ impl Node { NodeCast::from_temporary(doc_fragment) }, NodeTypeId::Comment => { - let comment: JSRef = CommentCast::to_ref(node).unwrap(); - let comment = Comment::new(comment.characterdata().data().clone(), document.r()); + let cdata = CharacterDataCast::to_ref(node).unwrap(); + let comment = Comment::new(cdata.Data(), document.r()); NodeCast::from_temporary(comment) }, NodeTypeId::Document => { @@ -1622,14 +1628,14 @@ impl Node { NodeCast::from_temporary(element) }, NodeTypeId::Text => { - let text: JSRef = TextCast::to_ref(node).unwrap(); - let text = Text::new(text.characterdata().data().clone(), document.r()); + let cdata = CharacterDataCast::to_ref(node).unwrap(); + let text = Text::new(cdata.Data(), document.r()); NodeCast::from_temporary(text) }, NodeTypeId::ProcessingInstruction => { let pi: JSRef = ProcessingInstructionCast::to_ref(node).unwrap(); let pi = ProcessingInstruction::new(pi.target().clone(), - pi.characterdata().data().clone(), document.r()); + CharacterDataCast::from_ref(pi).Data(), document.r()); NodeCast::from_temporary(pi) }, }.root(); @@ -1683,12 +1689,13 @@ impl Node { Temporary::from_rooted(copy.r()) } - pub fn collect_text_contents<'a, T: Iterator>>(iterator: T) -> String { + pub fn collect_text_contents>>(iterator: T) -> String { let mut content = String::new(); for node in iterator { - let text: Option> = TextCast::to_ref(node); + let node = node.root(); + let text = TextCast::to_ref(node.r()); match text { - Some(text) => content.push_str(text.characterdata().data().as_slice()), + Some(text) => content.push_str(&CharacterDataCast::from_ref(text).Data()), None => (), } } @@ -1834,7 +1841,8 @@ impl<'a> NodeMethods for JSRef<'a, Node> { match self.type_id { NodeTypeId::DocumentFragment | NodeTypeId::Element(..) => { - let content = Node::collect_text_contents(self.traverse_preorder()); + let content = Node::collect_text_contents( + self.traverse_preorder().map(Temporary::from_rooted)); Some(content) } NodeTypeId::Comment | @@ -1871,7 +1879,7 @@ impl<'a> NodeMethods for JSRef<'a, Node> { NodeTypeId::Text | NodeTypeId::ProcessingInstruction => { let characterdata: JSRef = CharacterDataCast::to_ref(self).unwrap(); - characterdata.set_data(value); + characterdata.SetData(value); // Notify the document that the content of this node is different let document = self.owner_doc().root(); @@ -2114,7 +2122,7 @@ impl<'a> NodeMethods for JSRef<'a, Node> { let pi: JSRef = ProcessingInstructionCast::to_ref(node).unwrap(); let other_pi: JSRef = ProcessingInstructionCast::to_ref(other).unwrap(); (*pi.target() == *other_pi.target()) && - (*pi.characterdata().data() == *other_pi.characterdata().data()) + (*CharacterDataCast::from_ref(pi).data() == *CharacterDataCast::from_ref(other_pi).data()) } fn is_equal_characterdata(node: JSRef, other: JSRef) -> bool { let characterdata: JSRef = CharacterDataCast::to_ref(node).unwrap(); diff --git a/components/script/dom/processinginstruction.rs b/components/script/dom/processinginstruction.rs index 528c4cdd64a..c9d102b9862 100644 --- a/components/script/dom/processinginstruction.rs +++ b/components/script/dom/processinginstruction.rs @@ -38,10 +38,6 @@ impl ProcessingInstruction { document, ProcessingInstructionBinding::Wrap) } - pub fn characterdata<'a>(&'a self) -> &'a CharacterData { - &self.characterdata - } - pub fn target<'a>(&'a self) -> &'a DOMString { &self.target } diff --git a/components/script/dom/text.rs b/components/script/dom/text.rs index ea6c2791e96..c2e9c588665 100644 --- a/components/script/dom/text.rs +++ b/components/script/dom/text.rs @@ -42,10 +42,5 @@ impl Text { let document = global.as_window().Document().root(); Ok(Text::new(text, document.r())) } - - #[inline] - pub fn characterdata<'a>(&'a self) -> &'a CharacterData { - &self.characterdata - } } diff --git a/components/script/dom/textdecoder.rs b/components/script/dom/textdecoder.rs new file mode 100644 index 00000000000..714200f9a8f --- /dev/null +++ b/components/script/dom/textdecoder.rs @@ -0,0 +1,99 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use dom::bindings::codegen::Bindings::TextDecoderBinding; +use dom::bindings::codegen::Bindings::TextDecoderBinding::TextDecoderMethods; +use dom::bindings::error::{Error, Fallible}; +use dom::bindings::global::GlobalRef; +use dom::bindings::js::{JSRef, Temporary}; +use dom::bindings::str::USVString; +use dom::bindings::trace::JSTraceable; +use dom::bindings::utils::{Reflector, reflect_dom_object}; + +use util::str::DOMString; + +use encoding::Encoding; +use encoding::types::{EncodingRef, DecoderTrap}; +use encoding::label::encoding_from_whatwg_label; +use js::jsapi::{JSContext, JSObject}; +use js::jsfriendapi::bindgen::JS_GetObjectAsArrayBufferView; + +use std::borrow::ToOwned; +use std::ptr; +use std::slice; + +#[dom_struct] +pub struct TextDecoder { + reflector_: Reflector, + encoding: EncodingRef, + fatal: bool, +} + +impl TextDecoder { + fn new_inherited(encoding: EncodingRef, fatal: bool) -> TextDecoder { + TextDecoder { + reflector_: Reflector::new(), + encoding: encoding, + fatal: fatal, + } + } + + pub fn new(global: GlobalRef, encoding: EncodingRef, fatal: bool) -> Temporary { + reflect_dom_object(box TextDecoder::new_inherited(encoding, fatal), + global, + TextDecoderBinding::Wrap) + } + + /// https://encoding.spec.whatwg.org/#dom-textdecoder + pub fn Constructor(global: GlobalRef, + label: DOMString, + options: &TextDecoderBinding::TextDecoderOptions) + -> Fallible> { + let encoding = match encoding_from_whatwg_label(&label) { + Some(enc) => enc, + // FIXME: Should throw a RangeError as per spec + None => return Err(Error::Syntax), + }; + Ok(TextDecoder::new(global, encoding, options.fatal)) + } +} + +impl<'a> TextDecoderMethods for JSRef<'a, TextDecoder> { + fn Encoding(self) -> DOMString { + self.encoding.whatwg_name().unwrap().to_owned() + } + + fn Fatal(self) -> bool { + self.fatal + } + + #[allow(unsafe_code)] + fn Decode(self, cx: *mut JSContext, input: Option<*mut JSObject>) + -> Fallible { + let input = match input { + Some(input) => input, + None => return Ok(USVString("".to_owned())), + }; + + let mut length = 0; + let mut data = ptr::null_mut(); + if unsafe { JS_GetObjectAsArrayBufferView(cx, input, &mut length, &mut data).is_null() } { + return Err(Error::Type("Argument to TextDecoder.decode is not an ArrayBufferView".to_owned())); + } + + let buffer = unsafe { + slice::from_raw_parts(data as *const _, length as usize) + }; + let trap = if self.fatal { + DecoderTrap::Strict + } else { + DecoderTrap::Replace + }; + match self.encoding.decode(buffer, trap) { + Ok(s) => Ok(USVString(s)), + Err(_) => Err(Error::Type("Decoding failed".to_owned())), + } + } + +} diff --git a/components/script/dom/webidls/CanvasRenderingContext2D.webidl b/components/script/dom/webidls/CanvasRenderingContext2D.webidl index 6808e3c7d24..4c4b94374f2 100644 --- a/components/script/dom/webidls/CanvasRenderingContext2D.webidl +++ b/components/script/dom/webidls/CanvasRenderingContext2D.webidl @@ -136,7 +136,7 @@ interface CanvasDrawingStyles { attribute unrestricted double lineWidth; // (default 1) //attribute DOMString lineCap; // "butt", "round", "square" (default "butt") //attribute DOMString lineJoin; // "round", "bevel", "miter" (default "miter") - //attribute unrestricted double miterLimit; // (default 10) + attribute unrestricted double miterLimit; // (default 10) // dashed lines //void setLineDash(sequence segments); // default empty diff --git a/components/script/dom/webidls/CharacterData.webidl b/components/script/dom/webidls/CharacterData.webidl index d1b222bc168..e758adb4d30 100644 --- a/components/script/dom/webidls/CharacterData.webidl +++ b/components/script/dom/webidls/CharacterData.webidl @@ -11,11 +11,10 @@ */ interface CharacterData : Node { - [TreatNullAs=EmptyString,SetterThrows] attribute DOMString data; + [TreatNullAs=EmptyString] attribute DOMString data; readonly attribute unsigned long length; [Throws] DOMString substringData(unsigned long offset, unsigned long count); - [Throws] void appendData(DOMString data); [Throws] void insertData(unsigned long offset, DOMString data); @@ -26,3 +25,4 @@ interface CharacterData : Node { }; CharacterData implements ChildNode; +CharacterData implements NonDocumentTypeChildNode; diff --git a/components/script/dom/webidls/ChildNode.webidl b/components/script/dom/webidls/ChildNode.webidl index 16562fbafbf..fbcf8ea1208 100644 --- a/components/script/dom/webidls/ChildNode.webidl +++ b/components/script/dom/webidls/ChildNode.webidl @@ -16,10 +16,10 @@ interface ChildNode { void remove(); }; -// [NoInterfaceObject] -// interface NonDocumentTypeChildNode { -// [Pure] -// readonly attribute Element? previousElementSibling; -// [Pure] -// readonly attribute Element? nextElementSibling; -// }; +[NoInterfaceObject] +interface NonDocumentTypeChildNode { + [Pure] + readonly attribute Element? previousElementSibling; + [Pure] + readonly attribute Element? nextElementSibling; +}; diff --git a/components/script/dom/webidls/Document.webidl b/components/script/dom/webidls/Document.webidl index 984f79eb528..c57b09fff1b 100644 --- a/components/script/dom/webidls/Document.webidl +++ b/components/script/dom/webidls/Document.webidl @@ -27,27 +27,33 @@ interface Document : Node { HTMLCollection getElementsByClassName(DOMString classNames); Element? getElementById(DOMString elementId); - [Throws] + [NewObject, Throws] Element createElement(DOMString localName); - [Throws] + [NewObject, Throws] Element createElementNS(DOMString? namespace, DOMString qualifiedName); + [NewObject] DocumentFragment createDocumentFragment(); + [NewObject] Text createTextNode(DOMString data); + [NewObject] Comment createComment(DOMString data); - [Throws] + [NewObject, Throws] ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data); - [Throws] - Attr createAttribute(DOMString localName); - - [Throws] + [NewObject, Throws] Node importNode(Node node, optional boolean deep = false); [Throws] Node adoptNode(Node node); - [Throws] + [NewObject, Throws] + Attr createAttribute(DOMString localName); + [NewObject, Throws] + Attr createAttributeNS(DOMString? namespace, DOMString localName); + + [NewObject, Throws] Event createEvent(DOMString interface_); + [NewObject] Range createRange(); // NodeFilter.SHOW_ALL = 0xFFFFFFFF diff --git a/components/script/dom/webidls/Element.webidl b/components/script/dom/webidls/Element.webidl index 8d08717cd31..1090ad91588 100644 --- a/components/script/dom/webidls/Element.webidl +++ b/components/script/dom/webidls/Element.webidl @@ -70,4 +70,5 @@ partial interface Element { }; Element implements ChildNode; +Element implements NonDocumentTypeChildNode; Element implements ParentNode; diff --git a/components/script/dom/webidls/TextDecoder.webidl b/components/script/dom/webidls/TextDecoder.webidl new file mode 100644 index 00000000000..4ec66f07d7a --- /dev/null +++ b/components/script/dom/webidls/TextDecoder.webidl @@ -0,0 +1,21 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// https://encoding.spec.whatwg.org/#interface-textdecoder +dictionary TextDecoderOptions { + boolean fatal = false; + //boolean ignoreBOM = false; +}; + +[Constructor(optional DOMString label = "utf-8", optional TextDecoderOptions options)/*, + Exposed=Window,Worker*/] +interface TextDecoder { + readonly attribute DOMString encoding; + readonly attribute boolean fatal; + //readonly attribute boolean ignoreBOM; + //USVString decode(optional BufferSource input, optional TextDecodeOptions options); + [Throws] + USVString decode(optional object input); +}; diff --git a/components/script/parse/html.rs b/components/script/parse/html.rs index 66a95f2e879..d3e6b981783 100644 --- a/components/script/parse/html.rs +++ b/components/script/parse/html.rs @@ -7,13 +7,14 @@ use dom::attr::AttrHelpers; use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; -use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast, HTMLScriptElementCast}; -use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, TextCast, CommentCast}; +use dom::bindings::codegen::InheritTypes::{CharacterDataCast, DocumentTypeCast}; +use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLScriptElementCast}; +use dom::bindings::codegen::InheritTypes::{HTMLFormElementDerived, NodeCast}; use dom::bindings::codegen::InheritTypes::ProcessingInstructionCast; -use dom::bindings::codegen::InheritTypes::HTMLFormElementDerived; use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, Root}; use dom::bindings::js::RootedReference; use dom::bindings::trace::RootedVec; +use dom::characterdata::CharacterDataHelpers; use dom::comment::Comment; use dom::document::{Document, DocumentHelpers}; use dom::document::{DocumentSource, IsHTMLDocument}; @@ -234,22 +235,19 @@ impl<'a> Serializable for JSRef<'a, Node> { }, (IncludeNode, NodeTypeId::Text) => { - let text: JSRef = TextCast::to_ref(node).unwrap(); - let data = text.characterdata().data(); - serializer.write_text(data.as_slice()) + let cdata = CharacterDataCast::to_ref(node).unwrap(); + serializer.write_text(&cdata.data()) }, (IncludeNode, NodeTypeId::Comment) => { - let comment: JSRef = CommentCast::to_ref(node).unwrap(); - let data = comment.characterdata().data(); - serializer.write_comment(data.as_slice()) + let cdata = CharacterDataCast::to_ref(node).unwrap(); + serializer.write_comment(&cdata.data()) }, (IncludeNode, NodeTypeId::ProcessingInstruction) => { let pi: JSRef = ProcessingInstructionCast::to_ref(node).unwrap(); - let data = pi.characterdata().data(); - serializer.write_processing_instruction(pi.target().as_slice(), - data.as_slice()) + let data = CharacterDataCast::from_ref(pi).data(); + serializer.write_processing_instruction(&pi.target(), &data) }, (IncludeNode, NodeTypeId::DocumentFragment) => Ok(()), diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 83800fc7709..d61b2571292 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -479,7 +479,7 @@ dependencies = [ [[package]] name = "js" version = "0.1.0" -source = "git+https://github.com/servo/rust-mozjs#879b256e6bc5b38f792b68da130eb7a70633769b" +source = "git+https://github.com/servo/rust-mozjs#9512c3c770774ed73a2fdcc635eee178cbd02ab1" dependencies = [ "libc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mozjs_sys 0.0.0 (git+https://github.com/servo/mozjs)", @@ -617,7 +617,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mozjs_sys" version = "0.0.0" -source = "git+https://github.com/servo/mozjs#40e0680008cb129ddf9ccf40c6b0095e14d1cd97" +source = "git+https://github.com/servo/mozjs#19edb950930f03f0ad305ffbd9548b92fdb0a250" [[package]] name = "msg" diff --git a/components/util/str.rs b/components/util/str.rs index e763215633f..a400edb9572 100644 --- a/components/util/str.rs +++ b/components/util/str.rs @@ -39,7 +39,12 @@ pub fn null_str_as_empty_ref<'a>(s: &'a Option) -> &'a str { const WHITESPACE: &'static [char] = &[' ', '\t', '\x0a', '\x0c', '\x0d']; pub fn is_whitespace(s: &str) -> bool { - s.chars().all(|c| WHITESPACE.contains(&c)) + s.chars().all(char_is_whitespace) +} + +#[inline] +pub fn char_is_whitespace(c: char) -> bool { + WHITESPACE.contains(&c) } /// A "space character" according to: diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 7cd06499343..3fcab77d28b 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -482,7 +482,7 @@ dependencies = [ [[package]] name = "js" version = "0.1.0" -source = "git+https://github.com/servo/rust-mozjs#879b256e6bc5b38f792b68da130eb7a70633769b" +source = "git+https://github.com/servo/rust-mozjs#9512c3c770774ed73a2fdcc635eee178cbd02ab1" dependencies = [ "libc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mozjs_sys 0.0.0 (git+https://github.com/servo/mozjs)", @@ -620,7 +620,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mozjs_sys" version = "0.0.0" -source = "git+https://github.com/servo/mozjs#40e0680008cb129ddf9ccf40c6b0095e14d1cd97" +source = "git+https://github.com/servo/mozjs#19edb950930f03f0ad305ffbd9548b92fdb0a250" [[package]] name = "msg" diff --git a/ports/cef/wrappers.rs b/ports/cef/wrappers.rs index 3bfd1c27464..efc8ac8aaae 100644 --- a/ports/cef/wrappers.rs +++ b/ports/cef/wrappers.rs @@ -32,9 +32,11 @@ use types::{cef_window_info_t, cef_xml_encoding_type_t, cef_xml_node_type_t}; use unicode::str::Utf16Encoder; use libc::{self, c_char, c_int, c_ushort, c_void}; +use std::boxed; use std::collections::HashMap; use std::mem; use std::ptr; +use std::raw; pub trait CefWrap { fn to_c(rust_object: Self) -> CObject; @@ -61,7 +63,7 @@ macro_rules! cef_pointer_wrapper( rust_object } unsafe fn to_rust(c_object: *const $ty) -> &'a $ty { - mem::transmute::<*const $ty,&'a $ty>(c_object) + &*c_object } } impl<'a> CefWrap<*mut $ty> for &'a mut $ty { @@ -69,7 +71,7 @@ macro_rules! cef_pointer_wrapper( rust_object } unsafe fn to_rust(c_object: *mut $ty) -> &'a mut $ty { - mem::transmute::<*mut $ty,&'a mut $ty>(c_object) + &mut *c_object } } cef_noop_wrapper!(*const $ty); @@ -187,19 +189,18 @@ impl<'a> CefWrap<*const cef_string_t> for &'a [u16] { // FIXME(pcwalton): This leaks!! We should instead have the caller pass some scratch // stack space to create the object in. What a botch. - let boxed_string = box cef_string_utf16 { + boxed::into_raw(box cef_string_utf16 { str: ptr, length: buffer.len() as u64, dtor: Some(free_boxed_utf16_string as extern "C" fn(*mut c_ushort)), - }; - let result: *const cef_string_utf16 = &*boxed_string; - mem::forget(boxed_string); - result + }) as *const _ } } unsafe fn to_rust(cef_string: *const cef_string_t) -> &'a [u16] { - let (ptr, len): (*mut c_ushort, uint) = ((*cef_string).str, (*cef_string).length as uint); - mem::transmute((ptr, len)) + mem::transmute(raw::Slice { + data: (*cef_string).str, + len: (*cef_string).length as usize, + }) } } @@ -214,8 +215,7 @@ impl<'a> CefWrap<*mut cef_string_t> for &'a mut [u16] { panic!("unimplemented CEF type conversion: &'a str") } unsafe fn to_rust(_: *mut cef_string_t) -> &'a mut [u16] { - mem::transmute::<(int,int),_>(panic!("unimplemented CEF type conversion: *mut \ - cef_string_t")) + panic!("unimplemented CEF type conversion: *mut cef_string_t") } } @@ -245,19 +245,18 @@ impl<'a> CefWrap for String { let boxed_string; unsafe { - let buffer = libc::malloc((mem::size_of::() as u64) * - ((utf16_chars.len() + 1) as u64 + 1)) as *mut u16; + let buffer = libc::malloc((mem::size_of::() as libc::size_t) * + ((utf16_chars.len() + 1) as libc::size_t)) as *mut u16; for (i, ch) in utf16_chars.iter().enumerate() { *buffer.offset(i as int) = *ch } *buffer.offset(utf16_chars.len() as int) = 0; - boxed_string = libc::malloc(mem::size_of::() as u64) as + boxed_string = libc::malloc(mem::size_of::() as libc::size_t) as *mut cef_string_utf16; ptr::write(&mut (*boxed_string).str, buffer); ptr::write(&mut (*boxed_string).length, utf16_chars.len() as u64); ptr::write(&mut (*boxed_string).dtor, Some(free_utf16_buffer as extern "C" fn(*mut c_ushort))); - mem::forget(utf16_chars); } boxed_string } diff --git a/ports/gonk/Cargo.lock b/ports/gonk/Cargo.lock index ddc5afd7988..7de597c61f9 100644 --- a/ports/gonk/Cargo.lock +++ b/ports/gonk/Cargo.lock @@ -415,7 +415,7 @@ dependencies = [ [[package]] name = "js" version = "0.1.0" -source = "git+https://github.com/servo/rust-mozjs#879b256e6bc5b38f792b68da130eb7a70633769b" +source = "git+https://github.com/servo/rust-mozjs#9512c3c770774ed73a2fdcc635eee178cbd02ab1" dependencies = [ "libc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mozjs_sys 0.0.0 (git+https://github.com/servo/mozjs)", @@ -545,7 +545,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mozjs_sys" version = "0.0.0" -source = "git+https://github.com/servo/mozjs#40e0680008cb129ddf9ccf40c6b0095e14d1cd97" +source = "git+https://github.com/servo/mozjs#19edb950930f03f0ad305ffbd9548b92fdb0a250" [[package]] name = "msg" diff --git a/tests/ref/basic.list b/tests/ref/basic.list index f09177b5b2f..c1189069cc6 100644 --- a/tests/ref/basic.list +++ b/tests/ref/basic.list @@ -114,6 +114,7 @@ flaky_cpu == append_style_a.html append_style_b.html == float_intrinsic_width_a.html float_intrinsic_width_ref.html == float_right_intrinsic_width_a.html float_right_intrinsic_width_ref.html == float_table_a.html float_table_ref.html +== float_under_top_margin_a.html float_under_top_margin_ref.html == floated_generated_content_a.html floated_generated_content_b.html == floated_list_item_a.html floated_list_item_ref.html == floated_table_with_margin_a.html floated_table_with_margin_ref.html @@ -151,6 +152,7 @@ flaky_cpu == append_style_a.html append_style_b.html != img_simple.html img_simple_ref.html == img_size_a.html img_size_b.html == incremental_float_a.html incremental_float_ref.html +== incremental_inline_layout_a.html incremental_inline_layout_ref.html != inline_background_a.html inline_background_ref.html == inline_block_baseline_a.html inline_block_baseline_ref.html == inline_block_border_a.html inline_block_border_ref.html @@ -184,6 +186,7 @@ flaky_cpu == append_style_a.html append_style_b.html == legacy_td_bgcolor_attribute_a.html legacy_td_bgcolor_attribute_ref.html == legacy_td_width_attribute_a.html legacy_td_width_attribute_ref.html == letter_spacing_a.html letter_spacing_ref.html +== line_breaking_whitespace_collapse_a.html line_breaking_whitespace_collapse_ref.html == line_height_a.html line_height_ref.html != linear_gradients_corners_a.html linear_gradients_corners_ref.html == linear_gradients_lengths_a.html linear_gradients_lengths_ref.html diff --git a/tests/ref/float_intrinsic_height.html b/tests/ref/float_intrinsic_height.html index b6d9e7e302a..f349085d23c 100644 --- a/tests/ref/float_intrinsic_height.html +++ b/tests/ref/float_intrinsic_height.html @@ -19,6 +19,6 @@
-
+   diff --git a/tests/ref/float_under_top_margin_a.html b/tests/ref/float_under_top_margin_a.html new file mode 100644 index 00000000000..5cf1fdbdbd4 --- /dev/null +++ b/tests/ref/float_under_top_margin_a.html @@ -0,0 +1,29 @@ + + + + + + +
+ + + diff --git a/tests/ref/float_under_top_margin_ref.html b/tests/ref/float_under_top_margin_ref.html new file mode 100644 index 00000000000..904cbd5c66d --- /dev/null +++ b/tests/ref/float_under_top_margin_ref.html @@ -0,0 +1,29 @@ + + + + + + +
+ + + diff --git a/tests/ref/incremental_inline_layout_a.html b/tests/ref/incremental_inline_layout_a.html new file mode 100644 index 00000000000..cbd2d932071 --- /dev/null +++ b/tests/ref/incremental_inline_layout_a.html @@ -0,0 +1,32 @@ + + + + + + +

+Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +

+ + + + diff --git a/tests/ref/incremental_inline_layout_ref.html b/tests/ref/incremental_inline_layout_ref.html new file mode 100644 index 00000000000..7c42ff75bc5 --- /dev/null +++ b/tests/ref/incremental_inline_layout_ref.html @@ -0,0 +1,28 @@ + + + + + + +

+Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +Incremental Inline Layout +

+ + + diff --git a/tests/ref/line_breaking_whitespace_collapse_a.html b/tests/ref/line_breaking_whitespace_collapse_a.html new file mode 100644 index 00000000000..fdba44158de --- /dev/null +++ b/tests/ref/line_breaking_whitespace_collapse_a.html @@ -0,0 +1,19 @@ + + + + + + + +

xxxxx xxxxx xxxxx xxx xxxxx xxxxxxxxxxx

+ + diff --git a/tests/ref/line_breaking_whitespace_collapse_ref.html b/tests/ref/line_breaking_whitespace_collapse_ref.html new file mode 100644 index 00000000000..c36c0b4068d --- /dev/null +++ b/tests/ref/line_breaking_whitespace_collapse_ref.html @@ -0,0 +1,19 @@ + + + + + + + +

xxxxx xxxxx xxxxx xxx xxxxx
xxxxxxxxxxx

+ + diff --git a/tests/ref/margins_inside_floats_a.html b/tests/ref/margins_inside_floats_a.html index 139f12677df..9ad6aa576ed 100644 --- a/tests/ref/margins_inside_floats_a.html +++ b/tests/ref/margins_inside_floats_a.html @@ -4,7 +4,7 @@
Must be this tall
to write multi-threaded code.
-
+  diff --git a/tests/unit/gfx/text_util.rs b/tests/unit/gfx/text_util.rs index 6f63d18316f..f0253179145 100644 --- a/tests/unit/gfx/text_util.rs +++ b/tests/unit/gfx/text_util.rs @@ -18,9 +18,8 @@ fn test_transform_compress_none() { let mode = CompressionMode::CompressNone; for &test in test_strs.iter() { - let mut new_line_pos = vec![]; let mut trimmed_str = String::new(); - transform_text(test, mode, true, &mut trimmed_str, &mut new_line_pos); + transform_text(test, mode, true, &mut trimmed_str); assert_eq!(trimmed_str, test) } } @@ -52,9 +51,8 @@ fn test_transform_discard_newline() { let mode = CompressionMode::DiscardNewline; for &(test, oracle) in test_strs.iter() { - let mut new_line_pos = vec![]; let mut trimmed_str = String::new(); - transform_text(test, mode, true, &mut trimmed_str, &mut new_line_pos); + transform_text(test, mode, true, &mut trimmed_str); assert_eq!(trimmed_str, oracle) } } @@ -86,9 +84,8 @@ fn test_transform_compress_whitespace() { let mode = CompressionMode::CompressWhitespace; for &(test, oracle) in test_strs.iter() { - let mut new_line_pos = vec![]; let mut trimmed_str = String::new(); - transform_text(test, mode, true, &mut trimmed_str, &mut new_line_pos); + transform_text(test, mode, true, &mut trimmed_str); assert_eq!(&*trimmed_str, oracle) } } @@ -120,9 +117,8 @@ fn test_transform_compress_whitespace_newline() { let mode = CompressionMode::CompressWhitespaceNewline; for &(test, oracle) in test_strs.iter() { - let mut new_line_pos = vec![]; let mut trimmed_str = String::new(); - transform_text(test, mode, true, &mut trimmed_str, &mut new_line_pos); + transform_text(test, mode, true, &mut trimmed_str); assert_eq!(&*trimmed_str, oracle) } } @@ -157,9 +153,8 @@ fn test_transform_compress_whitespace_newline_no_incoming() { let mode = CompressionMode::CompressWhitespaceNewline; for &(test, oracle) in test_strs.iter() { - let mut new_line_pos = vec![]; let mut trimmed_str = String::new(); - transform_text(test, mode, false, &mut trimmed_str, &mut new_line_pos); + transform_text(test, mode, false, &mut trimmed_str); assert_eq!(trimmed_str, oracle) } } diff --git a/tests/wpt/README.md b/tests/wpt/README.md index 4637efe7058..20cb96beda2 100644 --- a/tests/wpt/README.md +++ b/tests/wpt/README.md @@ -64,7 +64,7 @@ first adding the following to the system's hosts file: 127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test 127.0.0.1 xn--lve-6lad.web-platform.test -and then running `python serve.py` from `tests/wpt/web-platform-tests`. +and then running `python serve` from `tests/wpt/web-platform-tests`. Then navigate Servo to `http://web-platform.test:8000/path/to/test`. Updating test expectations diff --git a/tests/wpt/metadata/2dcontext/drawing-rectangles-to-the-canvas/2d.strokeRect.zero.4.html.ini b/tests/wpt/metadata/2dcontext/drawing-rectangles-to-the-canvas/2d.strokeRect.zero.4.html.ini new file mode 100644 index 00000000000..31169ceaf88 --- /dev/null +++ b/tests/wpt/metadata/2dcontext/drawing-rectangles-to-the-canvas/2d.strokeRect.zero.4.html.ini @@ -0,0 +1,5 @@ +[2d.strokeRect.zero.4.html] + type: testharness + [strokeRect of Nx0 pixels draws a closed line with no caps] + expected: FAIL + diff --git a/tests/wpt/metadata/2dcontext/drawing-rectangles-to-the-canvas/2d.strokeRect.zero.5.html.ini b/tests/wpt/metadata/2dcontext/drawing-rectangles-to-the-canvas/2d.strokeRect.zero.5.html.ini deleted file mode 100644 index b08134d8578..00000000000 --- a/tests/wpt/metadata/2dcontext/drawing-rectangles-to-the-canvas/2d.strokeRect.zero.5.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.strokeRect.zero.5.html] - type: testharness - [strokeRect of Nx0 pixels draws a closed line with joins] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/line-styles/2d.line.cap.closed.html.ini b/tests/wpt/metadata/2dcontext/line-styles/2d.line.cap.closed.html.ini new file mode 100644 index 00000000000..20856efda4e --- /dev/null +++ b/tests/wpt/metadata/2dcontext/line-styles/2d.line.cap.closed.html.ini @@ -0,0 +1,5 @@ +[2d.line.cap.closed.html] + type: testharness + [Line caps are not drawn at the corners of an unclosed rectangle] + expected: FAIL + diff --git a/tests/wpt/metadata/2dcontext/line-styles/2d.line.join.bevel.html.ini b/tests/wpt/metadata/2dcontext/line-styles/2d.line.join.bevel.html.ini new file mode 100644 index 00000000000..4f618507159 --- /dev/null +++ b/tests/wpt/metadata/2dcontext/line-styles/2d.line.join.bevel.html.ini @@ -0,0 +1,5 @@ +[2d.line.join.bevel.html] + type: testharness + [lineJoin \'bevel\' is rendered correctly] + expected: FAIL + diff --git a/tests/wpt/metadata/2dcontext/line-styles/2d.line.join.closed.html.ini b/tests/wpt/metadata/2dcontext/line-styles/2d.line.join.closed.html.ini deleted file mode 100644 index 15f8a96aea1..00000000000 --- a/tests/wpt/metadata/2dcontext/line-styles/2d.line.join.closed.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.line.join.closed.html] - type: testharness - [Line joins are drawn at the corner of a closed rectangle] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/line-styles/2d.line.join.miter.html.ini b/tests/wpt/metadata/2dcontext/line-styles/2d.line.join.miter.html.ini deleted file mode 100644 index 9defd450bd7..00000000000 --- a/tests/wpt/metadata/2dcontext/line-styles/2d.line.join.miter.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.line.join.miter.html] - type: testharness - [lineJoin \'miter\' is rendered correctly] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/line-styles/2d.line.miter.acute.html.ini b/tests/wpt/metadata/2dcontext/line-styles/2d.line.miter.acute.html.ini deleted file mode 100644 index 8a4bb47701b..00000000000 --- a/tests/wpt/metadata/2dcontext/line-styles/2d.line.miter.acute.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.line.miter.acute.html] - type: testharness - [Miter joins are drawn correctly with acute angles] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/line-styles/2d.line.miter.invalid.html.ini b/tests/wpt/metadata/2dcontext/line-styles/2d.line.miter.invalid.html.ini deleted file mode 100644 index 90ea3c99711..00000000000 --- a/tests/wpt/metadata/2dcontext/line-styles/2d.line.miter.invalid.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.line.miter.invalid.html] - type: testharness - [Setting miterLimit to invalid values is ignored] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/line-styles/2d.line.miter.obtuse.html.ini b/tests/wpt/metadata/2dcontext/line-styles/2d.line.miter.obtuse.html.ini deleted file mode 100644 index 8e0a2db94f8..00000000000 --- a/tests/wpt/metadata/2dcontext/line-styles/2d.line.miter.obtuse.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.line.miter.obtuse.html] - type: testharness - [Miter joins are drawn correctly with obtuse angles] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/line-styles/2d.line.miter.valid.html.ini b/tests/wpt/metadata/2dcontext/line-styles/2d.line.miter.valid.html.ini deleted file mode 100644 index 1d0e60231c0..00000000000 --- a/tests/wpt/metadata/2dcontext/line-styles/2d.line.miter.valid.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.line.miter.valid.html] - type: testharness - [Setting miterLimit to valid values works] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/line-styles/2d.line.miter.within.html.ini b/tests/wpt/metadata/2dcontext/line-styles/2d.line.miter.within.html.ini deleted file mode 100644 index 2a555ab524e..00000000000 --- a/tests/wpt/metadata/2dcontext/line-styles/2d.line.miter.within.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.line.miter.within.html] - type: testharness - [Miter joins are drawn when the miter limit is not quite exceeded] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/shadows/2d.shadow.canvas.transparent.2.html.ini b/tests/wpt/metadata/2dcontext/shadows/2d.shadow.canvas.transparent.2.html.ini index f0485ad1623..b3623a00589 100644 --- a/tests/wpt/metadata/2dcontext/shadows/2d.shadow.canvas.transparent.2.html.ini +++ b/tests/wpt/metadata/2dcontext/shadows/2d.shadow.canvas.transparent.2.html.ini @@ -2,3 +2,4 @@ type: testharness [Shadows are not drawn for transparent parts of canvases] expected: FAIL + diff --git a/tests/wpt/metadata/2dcontext/shadows/2d.shadow.image.transparent.2.html.ini b/tests/wpt/metadata/2dcontext/shadows/2d.shadow.image.transparent.2.html.ini index c4f70567f88..4b5b797c037 100644 --- a/tests/wpt/metadata/2dcontext/shadows/2d.shadow.image.transparent.2.html.ini +++ b/tests/wpt/metadata/2dcontext/shadows/2d.shadow.image.transparent.2.html.ini @@ -2,3 +2,4 @@ type: testharness [Shadows are not drawn for transparent parts of images] expected: FAIL + diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index 77a963fdaee..0c4dc0c1164 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -8955,10 +8955,6 @@ "path": "IndexedDB/key_invalid.htm", "url": "/IndexedDB/key_invalid.htm" }, - { - "path": "IndexedDB/key_valid.html", - "url": "/IndexedDB/key_valid.html" - }, { "path": "IndexedDB/keygenerator-constrainterror.htm", "url": "/IndexedDB/keygenerator-constrainterror.htm" @@ -9819,38 +9815,6 @@ "path": "content-security-policy/img-src/img-src-4_1.html", "url": "/content-security-policy/img-src/img-src-4_1.html" }, - { - "path": "content-security-policy/media-src/media-src-7_1.html", - "url": "/content-security-policy/media-src/media-src-7_1.html" - }, - { - "path": "content-security-policy/media-src/media-src-7_1_2.html", - "url": "/content-security-policy/media-src/media-src-7_1_2.html" - }, - { - "path": "content-security-policy/media-src/media-src-7_2.html", - "url": "/content-security-policy/media-src/media-src-7_2.html" - }, - { - "path": "content-security-policy/media-src/media-src-7_2_2.html", - "url": "/content-security-policy/media-src/media-src-7_2_2.html" - }, - { - "path": "content-security-policy/media-src/media-src-7_3.html", - "url": "/content-security-policy/media-src/media-src-7_3.html" - }, - { - "path": "content-security-policy/media-src/media-src-7_3_2.html", - "url": "/content-security-policy/media-src/media-src-7_3_2.html" - }, - { - "path": "content-security-policy/object-src/object-src-2_1.html", - "url": "/content-security-policy/object-src/object-src-2_1.html" - }, - { - "path": "content-security-policy/object-src/object-src-2_2.html", - "url": "/content-security-policy/object-src/object-src-2_2.html" - }, { "path": "content-security-policy/script-src/script-src-1_1.html", "url": "/content-security-policy/script-src/script-src-1_1.html" @@ -10311,6 +10275,10 @@ "path": "dom/nodes/CharacterData-replaceData.html", "url": "/dom/nodes/CharacterData-replaceData.html" }, + { + "path": "dom/nodes/CharacterData-substringData.html", + "url": "/dom/nodes/CharacterData-substringData.html" + }, { "path": "dom/nodes/Comment-constructor.html", "url": "/dom/nodes/Comment-constructor.html" @@ -11271,6 +11239,30 @@ "path": "ext-xhtml-pubid/the-xhtml-syntax/parsing-xhtml-documents/xhtml-pubid-1.html", "url": "/ext-xhtml-pubid/the-xhtml-syntax/parsing-xhtml-documents/xhtml-pubid-1.html" }, + { + "path": "fetch/nosniff/image.html", + "url": "/fetch/nosniff/image.html" + }, + { + "path": "fetch/nosniff/importscripts.html", + "url": "/fetch/nosniff/importscripts.html" + }, + { + "path": "fetch/nosniff/parsing-nosniff.html", + "url": "/fetch/nosniff/parsing-nosniff.html" + }, + { + "path": "fetch/nosniff/script.html", + "url": "/fetch/nosniff/script.html" + }, + { + "path": "fetch/nosniff/stylesheet.html", + "url": "/fetch/nosniff/stylesheet.html" + }, + { + "path": "fetch/nosniff/worker.html", + "url": "/fetch/nosniff/worker.html" + }, { "path": "gamepad/idlharness.html", "url": "/gamepad/idlharness.html" @@ -18798,6 +18790,11 @@ "timeout": "long", "url": "/IndexedDB/idbobjectstore_createIndex8-valid_keys.htm" }, + { + "path": "IndexedDB/key_valid.html", + "timeout": "long", + "url": "/IndexedDB/key_valid.html" + }, { "path": "IndexedDB/keypath_maxsize.htm", "timeout": "long", @@ -18823,6 +18820,46 @@ "timeout": "long", "url": "/ambient-light/AmbientLight_tests.html" }, + { + "path": "content-security-policy/media-src/media-src-7_1.html", + "timeout": "long", + "url": "/content-security-policy/media-src/media-src-7_1.html" + }, + { + "path": "content-security-policy/media-src/media-src-7_1_2.html", + "timeout": "long", + "url": "/content-security-policy/media-src/media-src-7_1_2.html" + }, + { + "path": "content-security-policy/media-src/media-src-7_2.html", + "timeout": "long", + "url": "/content-security-policy/media-src/media-src-7_2.html" + }, + { + "path": "content-security-policy/media-src/media-src-7_2_2.html", + "timeout": "long", + "url": "/content-security-policy/media-src/media-src-7_2_2.html" + }, + { + "path": "content-security-policy/media-src/media-src-7_3.html", + "timeout": "long", + "url": "/content-security-policy/media-src/media-src-7_3.html" + }, + { + "path": "content-security-policy/media-src/media-src-7_3_2.html", + "timeout": "long", + "url": "/content-security-policy/media-src/media-src-7_3_2.html" + }, + { + "path": "content-security-policy/object-src/object-src-2_1.html", + "timeout": "long", + "url": "/content-security-policy/object-src/object-src-2_1.html" + }, + { + "path": "content-security-policy/object-src/object-src-2_2.html", + "timeout": "long", + "url": "/content-security-policy/object-src/object-src-2_2.html" + }, { "path": "cors/status-async.htm", "timeout": "long", @@ -25034,7 +25071,7 @@ } ] }, - "rev": "0d318188757a9c996e20b82db201fd04de5aa255", + "rev": "2a9fd810bb18610b422dbc3998ab74aa1bffae95", "url_base": "/", "version": 2 } \ No newline at end of file diff --git a/tests/wpt/metadata/XMLHttpRequest/getresponseheader-chunked-trailer.htm.ini b/tests/wpt/metadata/XMLHttpRequest/getresponseheader-chunked-trailer.htm.ini deleted file mode 100644 index 0ee1ddfee54..00000000000 --- a/tests/wpt/metadata/XMLHttpRequest/getresponseheader-chunked-trailer.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[getresponseheader-chunked-trailer.htm] - type: testharness - [XMLHttpRequest: getResponseHeader() and HTTP trailer] - expected: FAIL - diff --git a/tests/wpt/metadata/XMLHttpRequest/timeout-cors-async.htm.ini b/tests/wpt/metadata/XMLHttpRequest/timeout-cors-async.htm.ini index 4d37d487bfb..39ed4516c79 100644 --- a/tests/wpt/metadata/XMLHttpRequest/timeout-cors-async.htm.ini +++ b/tests/wpt/metadata/XMLHttpRequest/timeout-cors-async.htm.ini @@ -1,6 +1,5 @@ [timeout-cors-async.htm] type: testharness - expected: OK [XMLHttpRequest: timeout event and cross-origin request] expected: FAIL diff --git a/tests/wpt/metadata/dom/interfaces.html.ini b/tests/wpt/metadata/dom/interfaces.html.ini index 3b41ae6b502..e93857fa4ab 100644 --- a/tests/wpt/metadata/dom/interfaces.html.ini +++ b/tests/wpt/metadata/dom/interfaces.html.ini @@ -90,9 +90,6 @@ [Document interface: operation importNode(Node,boolean)] expected: FAIL - [Document interface: operation createAttributeNS(DOMString,DOMString)] - expected: FAIL - [Document interface: operation createNodeIterator(Node,unsigned long,NodeFilter)] expected: FAIL @@ -132,9 +129,6 @@ [Document interface: xmlDoc must inherit property "origin" with the proper type (3)] expected: FAIL - [Document interface: calling createAttributeNS(DOMString,DOMString) on xmlDoc with too few arguments must throw TypeError] - expected: FAIL - [Document interface: calling createNodeIterator(Node,unsigned long,NodeFilter) on xmlDoc with too few arguments must throw TypeError] expected: FAIL @@ -252,12 +246,6 @@ [Element interface: operation queryAll(DOMString)] expected: FAIL - [Element interface: attribute previousElementSibling] - expected: FAIL - - [Element interface: attribute nextElementSibling] - expected: FAIL - [Element interface: operation before([object Object\],[object Object\])] expected: FAIL @@ -321,12 +309,6 @@ [Element interface: calling queryAll(DOMString) on element with too few arguments must throw TypeError] expected: FAIL - [Element interface: element must inherit property "previousElementSibling" with the proper type (37)] - expected: FAIL - - [Element interface: element must inherit property "nextElementSibling" with the proper type (38)] - expected: FAIL - [Element interface: element must inherit property "before" with the proper type (39)] expected: FAIL @@ -345,12 +327,6 @@ [NamedNodeMap interface: operation setNamedItemNS(Attr)] expected: FAIL - [CharacterData interface: attribute previousElementSibling] - expected: FAIL - - [CharacterData interface: attribute nextElementSibling] - expected: FAIL - [CharacterData interface: operation before([object Object\],[object Object\])] expected: FAIL @@ -375,12 +351,6 @@ [Text interface: document.createTextNode("abc") must inherit property "wholeText" with the proper type (1)] expected: FAIL - [CharacterData interface: document.createTextNode("abc") must inherit property "previousElementSibling" with the proper type (7)] - expected: FAIL - - [CharacterData interface: document.createTextNode("abc") must inherit property "nextElementSibling" with the proper type (8)] - expected: FAIL - [CharacterData interface: document.createTextNode("abc") must inherit property "before" with the proper type (9)] expected: FAIL @@ -393,12 +363,6 @@ [CharacterData interface: calling after([object Object\],[object Object\]) on document.createTextNode("abc") with too few arguments must throw TypeError] expected: FAIL - [CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "previousElementSibling" with the proper type (7)] - expected: FAIL - - [CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "nextElementSibling" with the proper type (8)] - expected: FAIL - [CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "before" with the proper type (9)] expected: FAIL @@ -414,12 +378,6 @@ [Comment interface object length] expected: FAIL - [CharacterData interface: document.createComment("abc") must inherit property "previousElementSibling" with the proper type (7)] - expected: FAIL - - [CharacterData interface: document.createComment("abc") must inherit property "nextElementSibling" with the proper type (8)] - expected: FAIL - [CharacterData interface: document.createComment("abc") must inherit property "before" with the proper type (9)] expected: FAIL @@ -969,9 +927,6 @@ [DOMTokenList interface object length] expected: FAIL - [Document interface: xmlDoc must inherit property "createAttributeNS" with the proper type (22)] - expected: FAIL - [Document interface: xmlDoc must inherit property "createNodeIterator" with the proper type (25)] expected: FAIL diff --git a/tests/wpt/metadata/dom/nodes/CharacterData-substringData.html.ini b/tests/wpt/metadata/dom/nodes/CharacterData-substringData.html.ini new file mode 100644 index 00000000000..236aa95dfa3 --- /dev/null +++ b/tests/wpt/metadata/dom/nodes/CharacterData-substringData.html.ini @@ -0,0 +1,3 @@ +[CharacterData-substringData.html] + type: testharness + expected: CRASH diff --git a/tests/wpt/metadata/dom/nodes/DOMImplementation-createDocument.html.ini b/tests/wpt/metadata/dom/nodes/DOMImplementation-createDocument.html.ini deleted file mode 100644 index 8d02570c391..00000000000 --- a/tests/wpt/metadata/dom/nodes/DOMImplementation-createDocument.html.ini +++ /dev/null @@ -1,35 +0,0 @@ -[DOMImplementation-createDocument.html] - type: testharness - [createDocument test 23: null,"xmlns",null,"NAMESPACE_ERR"] - expected: FAIL - - [createDocument test 41: undefined,"xmlns",null,"NAMESPACE_ERR"] - expected: FAIL - - [createDocument test 64: "http://example.com/","xmlns",null,"NAMESPACE_ERR"] - expected: FAIL - - [createDocument test 69: "http://example.com/","xmlns:foo",null,"NAMESPACE_ERR"] - expected: FAIL - - [createDocument test 108: "/","xmlns",null,"NAMESPACE_ERR"] - expected: FAIL - - [createDocument test 111: "/","xmlns:foo",null,"NAMESPACE_ERR"] - expected: FAIL - - [createDocument test 121: "http://www.w3.org/XML/1998/namespace","xmlns",null,"NAMESPACE_ERR"] - expected: FAIL - - [createDocument test 124: "http://www.w3.org/XML/1998/namespace","xmlns:foo",null,"NAMESPACE_ERR"] - expected: FAIL - - [createDocument test 141: "http://www.w3.org/2000/xmlns/","foo:xmlns",null,"NAMESPACE_ERR"] - expected: FAIL - - [createDocument test 150: "foo:","xmlns",null,"NAMESPACE_ERR"] - expected: FAIL - - [createDocument test 153: "foo:","xmlns:foo",null,"NAMESPACE_ERR"] - expected: FAIL - diff --git a/tests/wpt/metadata/dom/nodes/Document-createElementNS.html.ini b/tests/wpt/metadata/dom/nodes/Document-createElementNS.html.ini deleted file mode 100644 index 69ab187bf8d..00000000000 --- a/tests/wpt/metadata/dom/nodes/Document-createElementNS.html.ini +++ /dev/null @@ -1,35 +0,0 @@ -[Document-createElementNS.html] - type: testharness - [createElementNS test 23: null,"xmlns","NAMESPACE_ERR"] - expected: FAIL - - [createElementNS test 41: undefined,"xmlns","NAMESPACE_ERR"] - expected: FAIL - - [createElementNS test 64: "http://example.com/","xmlns","NAMESPACE_ERR"] - expected: FAIL - - [createElementNS test 69: "http://example.com/","xmlns:foo","NAMESPACE_ERR"] - expected: FAIL - - [createElementNS test 108: "/","xmlns","NAMESPACE_ERR"] - expected: FAIL - - [createElementNS test 111: "/","xmlns:foo","NAMESPACE_ERR"] - expected: FAIL - - [createElementNS test 121: "http://www.w3.org/XML/1998/namespace","xmlns","NAMESPACE_ERR"] - expected: FAIL - - [createElementNS test 124: "http://www.w3.org/XML/1998/namespace","xmlns:foo","NAMESPACE_ERR"] - expected: FAIL - - [createElementNS test 141: "http://www.w3.org/2000/xmlns/","foo:xmlns","NAMESPACE_ERR"] - expected: FAIL - - [createElementNS test 150: "foo:","xmlns","NAMESPACE_ERR"] - expected: FAIL - - [createElementNS test 153: "foo:","xmlns:foo","NAMESPACE_ERR"] - expected: FAIL - diff --git a/tests/wpt/metadata/dom/nodes/Element-nextElementSibling.html.ini b/tests/wpt/metadata/dom/nodes/Element-nextElementSibling.html.ini deleted file mode 100644 index 500ad7ddfd9..00000000000 --- a/tests/wpt/metadata/dom/nodes/Element-nextElementSibling.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[Element-nextElementSibling.html] - type: testharness - [nextElementSibling] - expected: FAIL - diff --git a/tests/wpt/metadata/dom/nodes/Element-previousElementSibling.html.ini b/tests/wpt/metadata/dom/nodes/Element-previousElementSibling.html.ini deleted file mode 100644 index 9fc5b61136c..00000000000 --- a/tests/wpt/metadata/dom/nodes/Element-previousElementSibling.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[Element-previousElementSibling.html] - type: testharness - [previousElementSibling] - expected: FAIL - diff --git a/tests/wpt/metadata/dom/nodes/Element-siblingElement-null.html.ini b/tests/wpt/metadata/dom/nodes/Element-siblingElement-null.html.ini deleted file mode 100644 index 77c3ddfa89e..00000000000 --- a/tests/wpt/metadata/dom/nodes/Element-siblingElement-null.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[Element-siblingElement-null.html] - type: testharness - [Null test] - expected: FAIL - diff --git a/tests/wpt/metadata/dom/nodes/Node-properties.html.ini b/tests/wpt/metadata/dom/nodes/Node-properties.html.ini index 41bd3f2f43f..a286ce6e019 100644 --- a/tests/wpt/metadata/dom/nodes/Node-properties.html.ini +++ b/tests/wpt/metadata/dom/nodes/Node-properties.html.ini @@ -1,50 +1,5 @@ [Node-properties.html] type: testharness - [testDiv.previousElementSibling] - expected: FAIL - - [detachedDiv.previousElementSibling] - expected: FAIL - - [detachedDiv.nextElementSibling] - expected: FAIL - - [detachedPara1.previousElementSibling] - expected: FAIL - - [detachedPara1.nextElementSibling] - expected: FAIL - - [detachedPara2.previousElementSibling] - expected: FAIL - - [detachedPara2.nextElementSibling] - expected: FAIL - - [foreignPara1.previousElementSibling] - expected: FAIL - - [foreignPara1.nextElementSibling] - expected: FAIL - - [foreignPara2.previousElementSibling] - expected: FAIL - - [foreignPara2.nextElementSibling] - expected: FAIL - - [xmlElement.previousElementSibling] - expected: FAIL - - [xmlElement.nextElementSibling] - expected: FAIL - - [detachedXmlElement.previousElementSibling] - expected: FAIL - - [detachedXmlElement.nextElementSibling] - expected: FAIL - [detachedTextNode.wholeText] expected: FAIL @@ -60,32 +15,3 @@ [detachedXmlTextNode.wholeText] expected: FAIL - [paras[0\].previousElementSibling] - expected: FAIL - - [paras[0\].nextElementSibling] - expected: FAIL - - [paras[1\].previousElementSibling] - expected: FAIL - - [paras[1\].nextElementSibling] - expected: FAIL - - [paras[2\].previousElementSibling] - expected: FAIL - - [paras[2\].nextElementSibling] - expected: FAIL - - [paras[3\].previousElementSibling] - expected: FAIL - - [paras[3\].nextElementSibling] - expected: FAIL - - [paras[4\].previousElementSibling] - expected: FAIL - - [paras[4\].nextElementSibling] - expected: FAIL diff --git a/tests/wpt/metadata/encoding/api-basics.html.ini b/tests/wpt/metadata/encoding/api-basics.html.ini index 03947330276..0045f9e5794 100644 --- a/tests/wpt/metadata/encoding/api-basics.html.ini +++ b/tests/wpt/metadata/encoding/api-basics.html.ini @@ -1,8 +1,5 @@ [api-basics.html] type: testharness - [Default encodings] - expected: FAIL - [Default inputs] expected: FAIL diff --git a/tests/wpt/metadata/encoding/api-surrogates-utf8.html.ini b/tests/wpt/metadata/encoding/api-surrogates-utf8.html.ini deleted file mode 100644 index 76324a435ae..00000000000 --- a/tests/wpt/metadata/encoding/api-surrogates-utf8.html.ini +++ /dev/null @@ -1,20 +0,0 @@ -[api-surrogates-utf8.html] - type: testharness - [Invalid surrogates encoded into UTF-8: Sanity check] - expected: FAIL - - [Invalid surrogates encoded into UTF-8: Surrogate half (low)] - expected: FAIL - - [Invalid surrogates encoded into UTF-8: Surrogate half (high)] - expected: FAIL - - [Invalid surrogates encoded into UTF-8: Surrogate half (low), in a string] - expected: FAIL - - [Invalid surrogates encoded into UTF-8: Surrogate half (high), in a string] - expected: FAIL - - [Invalid surrogates encoded into UTF-8: Wrong order] - expected: FAIL - diff --git a/tests/wpt/metadata/encoding/idlharness.html.ini b/tests/wpt/metadata/encoding/idlharness.html.ini index 2c00e08d92e..28ad8fba868 100644 --- a/tests/wpt/metadata/encoding/idlharness.html.ini +++ b/tests/wpt/metadata/encoding/idlharness.html.ini @@ -1,50 +1,17 @@ [idlharness.html] type: testharness - [TextDecoder interface: existence and properties of interface object] - expected: FAIL - [TextDecoder interface object length] expected: FAIL - [TextDecoder interface: existence and properties of interface prototype object] - expected: FAIL - - [TextDecoder interface: existence and properties of interface prototype object\'s "constructor" property] - expected: FAIL - - [TextDecoder interface: attribute encoding] - expected: FAIL - - [TextDecoder interface: attribute fatal] - expected: FAIL - [TextDecoder interface: attribute ignoreBOM] expected: FAIL [TextDecoder interface: operation decode(BufferSource,TextDecodeOptions)] expected: FAIL - [TextDecoder must be primary interface of new TextDecoder()] - expected: FAIL - - [Stringification of new TextDecoder()] - expected: FAIL - - [TextDecoder interface: new TextDecoder() must inherit property "encoding" with the proper type (0)] - expected: FAIL - - [TextDecoder interface: new TextDecoder() must inherit property "fatal" with the proper type (1)] - expected: FAIL - [TextDecoder interface: new TextDecoder() must inherit property "ignoreBOM" with the proper type (2)] expected: FAIL - [TextDecoder interface: new TextDecoder() must inherit property "decode" with the proper type (3)] - expected: FAIL - - [TextDecoder interface: calling decode(BufferSource,TextDecodeOptions) on new TextDecoder() with too few arguments must throw TypeError] - expected: FAIL - [TextEncoder interface object length] expected: FAIL diff --git a/tests/wpt/metadata/encoding/iso-2022-jp-decoder.html.ini b/tests/wpt/metadata/encoding/iso-2022-jp-decoder.html.ini index 4651cfad0d9..ace8b904e2b 100644 --- a/tests/wpt/metadata/encoding/iso-2022-jp-decoder.html.ini +++ b/tests/wpt/metadata/encoding/iso-2022-jp-decoder.html.ini @@ -3,21 +3,12 @@ [iso-2022-jp decoder: Error ESC] expected: FAIL - [iso-2022-jp decoder: Error ESC, character] - expected: FAIL - [iso-2022-jp decoder: ASCII ESC, character] expected: FAIL [iso-2022-jp decoder: Double ASCII ESC, character] expected: FAIL - [iso-2022-jp decoder: character, ASCII ESC, character] - expected: FAIL - - [iso-2022-jp decoder: characters] - expected: FAIL - [iso-2022-jp decoder: SO / SI] expected: FAIL @@ -27,12 +18,6 @@ [iso-2022-jp decoder: Roman ESC, SO / SI] expected: FAIL - [iso-2022-jp decoder: Roman ESC, error ESC, Katakana ESC] - expected: FAIL - - [iso-2022-jp decoder: Katakana ESC, character] - expected: FAIL - [iso-2022-jp decoder: Katakana ESC, multibyte ESC, character] expected: FAIL @@ -42,18 +27,6 @@ [iso-2022-jp decoder: Katakana ESC, error ESC #2, character] expected: FAIL - [iso-2022-jp decoder: Katakana ESC, character, Katakana ESC, character] - expected: FAIL - - [iso-2022-jp decoder: Katakana ESC, SO / SI] - expected: FAIL - - [iso-2022-jp decoder: Multibyte ESC, character] - expected: FAIL - - [iso-2022-jp decoder: Multibyte ESC #2, character] - expected: FAIL - [iso-2022-jp decoder: Multibyte ESC, error ESC, character] expected: FAIL @@ -75,30 +48,6 @@ [iso-2022-jp decoder: Multibyte ESC, lead error byte] expected: FAIL - [iso-2022-jp decoder: Multibyte ESC, trail error byte] - expected: FAIL - - [iso-2022-jp decoder: character, error ESC] - expected: FAIL - [iso-2022-jp decoder: character, error ESC #2] expected: FAIL - [iso-2022-jp decoder: character, error ESC #3] - expected: FAIL - - [iso-2022-jp decoder: character, ASCII ESC] - expected: FAIL - - [iso-2022-jp decoder: character, Roman ESC] - expected: FAIL - - [iso-2022-jp decoder: character, Katakana ESC] - expected: FAIL - - [iso-2022-jp decoder: character, Multibyte ESC] - expected: FAIL - - [iso-2022-jp decoder: character, Multibyte ESC #2] - expected: FAIL - diff --git a/tests/wpt/metadata/encoding/textdecoder-fatal.html.ini b/tests/wpt/metadata/encoding/textdecoder-fatal.html.ini deleted file mode 100644 index 3f7dc6f45f6..00000000000 --- a/tests/wpt/metadata/encoding/textdecoder-fatal.html.ini +++ /dev/null @@ -1,107 +0,0 @@ -[textdecoder-fatal.html] - type: testharness - [Fatal flag: utf-8 - invalid code] - expected: FAIL - - [Fatal flag: utf-8 - ends early] - expected: FAIL - - [Fatal flag: utf-8 - ends early 2] - expected: FAIL - - [Fatal flag: utf-8 - invalid trail] - expected: FAIL - - [Fatal flag: utf-8 - invalid trail 2] - expected: FAIL - - [Fatal flag: utf-8 - invalid trail 3] - expected: FAIL - - [Fatal flag: utf-8 - invalid trail 4] - expected: FAIL - - [Fatal flag: utf-8 - invalid trail 5] - expected: FAIL - - [Fatal flag: utf-8 - invalid trail 6] - expected: FAIL - - [Fatal flag: utf-8 - > 0x10FFFF] - expected: FAIL - - [Fatal flag: utf-8 - obsolete lead byte] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+0000 - 2 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+0000 - 3 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+0000 - 4 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+0000 - 5 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+0000 - 6 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+007F - 2 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+007F - 3 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+007F - 4 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+007F - 5 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+007F - 6 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+07FF - 3 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+07FF - 4 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+07FF - 5 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+07FF - 6 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+FFFF - 4 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+FFFF - 5 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+FFFF - 6 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+10FFFF - 5 bytes] - expected: FAIL - - [Fatal flag: utf-8 - overlong U+10FFFF - 6 bytes] - expected: FAIL - - [Fatal flag: utf-8 - lead surrogate] - expected: FAIL - - [Fatal flag: utf-8 - trail surrogate] - expected: FAIL - - [Fatal flag: utf-8 - surrogate pair] - expected: FAIL - - [Fatal flag: utf-16le - truncated code unit] - expected: FAIL - - [The fatal attribute of TextDecoder] - expected: FAIL - diff --git a/tests/wpt/metadata/encoding/textdecoder-labels.html.ini b/tests/wpt/metadata/encoding/textdecoder-labels.html.ini index 61506476753..4f3fd8edbbf 100644 --- a/tests/wpt/metadata/encoding/textdecoder-labels.html.ini +++ b/tests/wpt/metadata/encoding/textdecoder-labels.html.ini @@ -1,515 +1,5 @@ [textdecoder-labels.html] type: testharness - [name=utf-8 label=unicode-1-1-utf-8] - expected: FAIL - - [name=utf-8 label=utf-8] - expected: FAIL - - [name=utf-8 label=utf8] - expected: FAIL - - [name=ibm866 label=866] - expected: FAIL - - [name=ibm866 label=cp866] - expected: FAIL - - [name=ibm866 label=csibm866] - expected: FAIL - - [name=ibm866 label=ibm866] - expected: FAIL - - [name=iso-8859-2 label=csisolatin2] - expected: FAIL - - [name=iso-8859-2 label=iso-8859-2] - expected: FAIL - - [name=iso-8859-2 label=iso-ir-101] - expected: FAIL - - [name=iso-8859-2 label=iso8859-2] - expected: FAIL - - [name=iso-8859-2 label=iso88592] - expected: FAIL - - [name=iso-8859-2 label=iso_8859-2] - expected: FAIL - - [name=iso-8859-2 label=iso_8859-2:1987] - expected: FAIL - - [name=iso-8859-2 label=l2] - expected: FAIL - - [name=iso-8859-2 label=latin2] - expected: FAIL - - [name=iso-8859-3 label=csisolatin3] - expected: FAIL - - [name=iso-8859-3 label=iso-8859-3] - expected: FAIL - - [name=iso-8859-3 label=iso-ir-109] - expected: FAIL - - [name=iso-8859-3 label=iso8859-3] - expected: FAIL - - [name=iso-8859-3 label=iso88593] - expected: FAIL - - [name=iso-8859-3 label=iso_8859-3] - expected: FAIL - - [name=iso-8859-3 label=iso_8859-3:1988] - expected: FAIL - - [name=iso-8859-3 label=l3] - expected: FAIL - - [name=iso-8859-3 label=latin3] - expected: FAIL - - [name=iso-8859-4 label=csisolatin4] - expected: FAIL - - [name=iso-8859-4 label=iso-8859-4] - expected: FAIL - - [name=iso-8859-4 label=iso-ir-110] - expected: FAIL - - [name=iso-8859-4 label=iso8859-4] - expected: FAIL - - [name=iso-8859-4 label=iso88594] - expected: FAIL - - [name=iso-8859-4 label=iso_8859-4] - expected: FAIL - - [name=iso-8859-4 label=iso_8859-4:1988] - expected: FAIL - - [name=iso-8859-4 label=l4] - expected: FAIL - - [name=iso-8859-4 label=latin4] - expected: FAIL - - [name=iso-8859-5 label=csisolatincyrillic] - expected: FAIL - - [name=iso-8859-5 label=cyrillic] - expected: FAIL - - [name=iso-8859-5 label=iso-8859-5] - expected: FAIL - - [name=iso-8859-5 label=iso-ir-144] - expected: FAIL - - [name=iso-8859-5 label=iso8859-5] - expected: FAIL - - [name=iso-8859-5 label=iso88595] - expected: FAIL - - [name=iso-8859-5 label=iso_8859-5] - expected: FAIL - - [name=iso-8859-5 label=iso_8859-5:1988] - expected: FAIL - - [name=iso-8859-6 label=arabic] - expected: FAIL - - [name=iso-8859-6 label=asmo-708] - expected: FAIL - - [name=iso-8859-6 label=csiso88596e] - expected: FAIL - - [name=iso-8859-6 label=csiso88596i] - expected: FAIL - - [name=iso-8859-6 label=csisolatinarabic] - expected: FAIL - - [name=iso-8859-6 label=ecma-114] - expected: FAIL - - [name=iso-8859-6 label=iso-8859-6] - expected: FAIL - - [name=iso-8859-6 label=iso-8859-6-e] - expected: FAIL - - [name=iso-8859-6 label=iso-8859-6-i] - expected: FAIL - - [name=iso-8859-6 label=iso-ir-127] - expected: FAIL - - [name=iso-8859-6 label=iso8859-6] - expected: FAIL - - [name=iso-8859-6 label=iso88596] - expected: FAIL - - [name=iso-8859-6 label=iso_8859-6] - expected: FAIL - - [name=iso-8859-6 label=iso_8859-6:1987] - expected: FAIL - - [name=iso-8859-7 label=csisolatingreek] - expected: FAIL - - [name=iso-8859-7 label=ecma-118] - expected: FAIL - - [name=iso-8859-7 label=elot_928] - expected: FAIL - - [name=iso-8859-7 label=greek] - expected: FAIL - - [name=iso-8859-7 label=greek8] - expected: FAIL - - [name=iso-8859-7 label=iso-8859-7] - expected: FAIL - - [name=iso-8859-7 label=iso-ir-126] - expected: FAIL - - [name=iso-8859-7 label=iso8859-7] - expected: FAIL - - [name=iso-8859-7 label=iso88597] - expected: FAIL - - [name=iso-8859-7 label=iso_8859-7] - expected: FAIL - - [name=iso-8859-7 label=iso_8859-7:1987] - expected: FAIL - - [name=iso-8859-7 label=sun_eu_greek] - expected: FAIL - - [name=iso-8859-8 label=csiso88598e] - expected: FAIL - - [name=iso-8859-8 label=csisolatinhebrew] - expected: FAIL - - [name=iso-8859-8 label=hebrew] - expected: FAIL - - [name=iso-8859-8 label=iso-8859-8] - expected: FAIL - - [name=iso-8859-8 label=iso-8859-8-e] - expected: FAIL - - [name=iso-8859-8 label=iso-ir-138] - expected: FAIL - - [name=iso-8859-8 label=iso8859-8] - expected: FAIL - - [name=iso-8859-8 label=iso88598] - expected: FAIL - - [name=iso-8859-8 label=iso_8859-8] - expected: FAIL - - [name=iso-8859-8 label=iso_8859-8:1988] - expected: FAIL - - [name=iso-8859-8 label=visual] - expected: FAIL - - [name=iso-8859-8-i label=csiso88598i] - expected: FAIL - - [name=iso-8859-8-i label=iso-8859-8-i] - expected: FAIL - - [name=iso-8859-8-i label=logical] - expected: FAIL - - [name=iso-8859-10 label=csisolatin6] - expected: FAIL - - [name=iso-8859-10 label=iso-8859-10] - expected: FAIL - - [name=iso-8859-10 label=iso-ir-157] - expected: FAIL - - [name=iso-8859-10 label=iso8859-10] - expected: FAIL - - [name=iso-8859-10 label=iso885910] - expected: FAIL - - [name=iso-8859-10 label=l6] - expected: FAIL - - [name=iso-8859-10 label=latin6] - expected: FAIL - - [name=iso-8859-13 label=iso-8859-13] - expected: FAIL - - [name=iso-8859-13 label=iso8859-13] - expected: FAIL - - [name=iso-8859-13 label=iso885913] - expected: FAIL - - [name=iso-8859-14 label=iso-8859-14] - expected: FAIL - - [name=iso-8859-14 label=iso8859-14] - expected: FAIL - - [name=iso-8859-14 label=iso885914] - expected: FAIL - - [name=iso-8859-15 label=csisolatin9] - expected: FAIL - - [name=iso-8859-15 label=iso-8859-15] - expected: FAIL - - [name=iso-8859-15 label=iso8859-15] - expected: FAIL - - [name=iso-8859-15 label=iso885915] - expected: FAIL - - [name=iso-8859-15 label=iso_8859-15] - expected: FAIL - - [name=iso-8859-15 label=l9] - expected: FAIL - - [name=iso-8859-16 label=iso-8859-16] - expected: FAIL - - [name=koi8-r label=cskoi8r] - expected: FAIL - - [name=koi8-r label=koi] - expected: FAIL - - [name=koi8-r label=koi8] - expected: FAIL - - [name=koi8-r label=koi8-r] - expected: FAIL - - [name=koi8-r label=koi8_r] - expected: FAIL - - [name=koi8-u label=koi8-u] - expected: FAIL - - [name=macintosh label=csmacintosh] - expected: FAIL - - [name=macintosh label=mac] - expected: FAIL - - [name=macintosh label=macintosh] - expected: FAIL - - [name=macintosh label=x-mac-roman] - expected: FAIL - - [name=windows-874 label=dos-874] - expected: FAIL - - [name=windows-874 label=iso-8859-11] - expected: FAIL - - [name=windows-874 label=iso8859-11] - expected: FAIL - - [name=windows-874 label=iso885911] - expected: FAIL - - [name=windows-874 label=tis-620] - expected: FAIL - - [name=windows-874 label=windows-874] - expected: FAIL - - [name=windows-1250 label=cp1250] - expected: FAIL - - [name=windows-1250 label=windows-1250] - expected: FAIL - - [name=windows-1250 label=x-cp1250] - expected: FAIL - - [name=windows-1251 label=cp1251] - expected: FAIL - - [name=windows-1251 label=windows-1251] - expected: FAIL - - [name=windows-1251 label=x-cp1251] - expected: FAIL - - [name=windows-1252 label=ansi_x3.4-1968] - expected: FAIL - - [name=windows-1252 label=ascii] - expected: FAIL - - [name=windows-1252 label=cp1252] - expected: FAIL - - [name=windows-1252 label=cp819] - expected: FAIL - - [name=windows-1252 label=csisolatin1] - expected: FAIL - - [name=windows-1252 label=ibm819] - expected: FAIL - - [name=windows-1252 label=iso-8859-1] - expected: FAIL - - [name=windows-1252 label=iso-ir-100] - expected: FAIL - - [name=windows-1252 label=iso8859-1] - expected: FAIL - - [name=windows-1252 label=iso88591] - expected: FAIL - - [name=windows-1252 label=iso_8859-1] - expected: FAIL - - [name=windows-1252 label=iso_8859-1:1987] - expected: FAIL - - [name=windows-1252 label=l1] - expected: FAIL - - [name=windows-1252 label=latin1] - expected: FAIL - - [name=windows-1252 label=us-ascii] - expected: FAIL - - [name=windows-1252 label=windows-1252] - expected: FAIL - - [name=windows-1252 label=x-cp1252] - expected: FAIL - - [name=windows-1253 label=cp1253] - expected: FAIL - - [name=windows-1253 label=windows-1253] - expected: FAIL - - [name=windows-1253 label=x-cp1253] - expected: FAIL - - [name=windows-1254 label=cp1254] - expected: FAIL - - [name=windows-1254 label=csisolatin5] - expected: FAIL - - [name=windows-1254 label=iso-8859-9] - expected: FAIL - - [name=windows-1254 label=iso-ir-148] - expected: FAIL - - [name=windows-1254 label=iso8859-9] - expected: FAIL - - [name=windows-1254 label=iso88599] - expected: FAIL - - [name=windows-1254 label=iso_8859-9] - expected: FAIL - - [name=windows-1254 label=iso_8859-9:1989] - expected: FAIL - - [name=windows-1254 label=l5] - expected: FAIL - - [name=windows-1254 label=latin5] - expected: FAIL - - [name=windows-1254 label=windows-1254] - expected: FAIL - - [name=windows-1254 label=x-cp1254] - expected: FAIL - - [name=windows-1255 label=cp1255] - expected: FAIL - - [name=windows-1255 label=windows-1255] - expected: FAIL - - [name=windows-1255 label=x-cp1255] - expected: FAIL - - [name=windows-1256 label=cp1256] - expected: FAIL - - [name=windows-1256 label=windows-1256] - expected: FAIL - - [name=windows-1256 label=x-cp1256] - expected: FAIL - - [name=windows-1257 label=cp1257] - expected: FAIL - - [name=windows-1257 label=windows-1257] - expected: FAIL - - [name=windows-1257 label=x-cp1257] - expected: FAIL - - [name=windows-1258 label=cp1258] - expected: FAIL - - [name=windows-1258 label=windows-1258] - expected: FAIL - - [name=windows-1258 label=x-cp1258] - expected: FAIL - - [name=x-mac-cyrillic label=x-mac-cyrillic] - expected: FAIL - - [name=x-mac-cyrillic label=x-mac-ukrainian] - expected: FAIL - [name=gbk label=chinese] expected: FAIL @@ -537,99 +27,9 @@ [name=gbk label=x-gbk] expected: FAIL - [name=gb18030 label=gb18030] - expected: FAIL - - [name=big5 label=big5] - expected: FAIL - - [name=big5 label=big5-hkscs] - expected: FAIL - - [name=big5 label=cn-big5] - expected: FAIL - - [name=big5 label=csbig5] - expected: FAIL - - [name=big5 label=x-x-big5] - expected: FAIL - - [name=euc-jp label=cseucpkdfmtjapanese] - expected: FAIL - - [name=euc-jp label=euc-jp] - expected: FAIL - - [name=euc-jp label=x-euc-jp] - expected: FAIL - - [name=iso-2022-jp label=csiso2022jp] - expected: FAIL - - [name=iso-2022-jp label=iso-2022-jp] - expected: FAIL - - [name=shift_jis label=csshiftjis] - expected: FAIL - - [name=shift_jis label=ms_kanji] - expected: FAIL - - [name=shift_jis label=shift-jis] - expected: FAIL - - [name=shift_jis label=shift_jis] - expected: FAIL - - [name=shift_jis label=sjis] - expected: FAIL - - [name=shift_jis label=windows-31j] - expected: FAIL - - [name=shift_jis label=x-sjis] - expected: FAIL - - [name=euc-kr label=cseuckr] - expected: FAIL - - [name=euc-kr label=csksc56011987] - expected: FAIL - - [name=euc-kr label=euc-kr] - expected: FAIL - - [name=euc-kr label=iso-ir-149] - expected: FAIL - - [name=euc-kr label=korean] - expected: FAIL - - [name=euc-kr label=ks_c_5601-1987] - expected: FAIL - - [name=euc-kr label=ks_c_5601-1989] - expected: FAIL - - [name=euc-kr label=ksc5601] - expected: FAIL - - [name=euc-kr label=ksc_5601] - expected: FAIL - - [name=euc-kr label=windows-949] - expected: FAIL - - [name=utf-16be label=utf-16be] - expected: FAIL - [name=utf-16le label=utf-16] expected: FAIL [name=utf-16le label=utf-16le] expected: FAIL - [name=x-user-defined label=x-user-defined] - expected: FAIL - diff --git a/tests/wpt/metadata/encoding/textdecoder-streaming.html.ini b/tests/wpt/metadata/encoding/textdecoder-streaming.html.ini index 8f34fafe58b..401997d8036 100644 --- a/tests/wpt/metadata/encoding/textdecoder-streaming.html.ini +++ b/tests/wpt/metadata/encoding/textdecoder-streaming.html.ini @@ -1,47 +1,20 @@ [textdecoder-streaming.html] type: testharness - [Streaming decode: utf-8, 1 byte window] - expected: FAIL - - [Streaming decode: utf-8, 2 byte window] - expected: FAIL - - [Streaming decode: utf-8, 3 byte window] - expected: FAIL - - [Streaming decode: utf-8, 4 byte window] - expected: FAIL - - [Streaming decode: utf-8, 5 byte window] - expected: FAIL - [Streaming decode: utf-16le, 1 byte window] expected: FAIL - [Streaming decode: utf-16le, 2 byte window] - expected: FAIL - [Streaming decode: utf-16le, 3 byte window] expected: FAIL - [Streaming decode: utf-16le, 4 byte window] - expected: FAIL - [Streaming decode: utf-16le, 5 byte window] expected: FAIL [Streaming decode: utf-16be, 1 byte window] expected: FAIL - [Streaming decode: utf-16be, 2 byte window] - expected: FAIL - [Streaming decode: utf-16be, 3 byte window] expected: FAIL - [Streaming decode: utf-16be, 4 byte window] - expected: FAIL - [Streaming decode: utf-16be, 5 byte window] expected: FAIL diff --git a/tests/wpt/metadata/encoding/textdecoder-utf16-surrogates.html.ini b/tests/wpt/metadata/encoding/textdecoder-utf16-surrogates.html.ini deleted file mode 100644 index 0630043c8c7..00000000000 --- a/tests/wpt/metadata/encoding/textdecoder-utf16-surrogates.html.ini +++ /dev/null @@ -1,32 +0,0 @@ -[textdecoder-utf16-surrogates.html] - type: testharness - [utf-16le - lone surrogate lead] - expected: FAIL - - [utf-16le - lone surrogate lead (fatal flag set)] - expected: FAIL - - [utf-16le - lone surrogate trail] - expected: FAIL - - [utf-16le - lone surrogate trail (fatal flag set)] - expected: FAIL - - [utf-16le - unmatched surrogate lead] - expected: FAIL - - [utf-16le - unmatched surrogate lead (fatal flag set)] - expected: FAIL - - [utf-16le - unmatched surrogate trail] - expected: FAIL - - [utf-16le - unmatched surrogate trail (fatal flag set)] - expected: FAIL - - [utf-16le - swapped surrogate pair] - expected: FAIL - - [utf-16le - swapped surrogate pair (fatal flag set)] - expected: FAIL - diff --git a/tests/wpt/metadata/encoding/textencoder-constructor-non-utf.html.ini b/tests/wpt/metadata/encoding/textencoder-constructor-non-utf.html.ini index 1af7e7f02b9..4d846b4443c 100644 --- a/tests/wpt/metadata/encoding/textencoder-constructor-non-utf.html.ini +++ b/tests/wpt/metadata/encoding/textencoder-constructor-non-utf.html.ini @@ -1,8 +1,5 @@ [textencoder-constructor-non-utf.html] type: testharness - [UTF encodings are supported for encode and decode: utf-8] - expected: FAIL - [Non-UTF encodings supported only for decode, not encode: ibm866] expected: FAIL @@ -108,9 +105,6 @@ [Non-UTF encodings supported only for decode, not encode: euc-kr] expected: FAIL - [UTF encodings are supported for encode and decode: utf-16be] - expected: FAIL - [UTF encodings are supported for encode and decode: utf-16le] expected: FAIL diff --git a/tests/wpt/metadata/encoding/textencoder-utf16-surrogates.html.ini b/tests/wpt/metadata/encoding/textencoder-utf16-surrogates.html.ini deleted file mode 100644 index 45d49ee6a37..00000000000 --- a/tests/wpt/metadata/encoding/textencoder-utf16-surrogates.html.ini +++ /dev/null @@ -1,20 +0,0 @@ -[textencoder-utf16-surrogates.html] - type: testharness - [USVString handling: lone surrogate lead] - expected: FAIL - - [USVString handling: lone surrogate trail] - expected: FAIL - - [USVString handling: unmatched surrogate lead] - expected: FAIL - - [USVString handling: unmatched surrogate trail] - expected: FAIL - - [USVString handling: swapped surrogate pair] - expected: FAIL - - [USVString handling: properly encoded MUSICAL SYMBOL G CLEF (U+1D11E)] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/windows/nested-browsing-contexts/frameElement.sub.html.ini b/tests/wpt/metadata/html/browsers/windows/nested-browsing-contexts/frameElement.sub.html.ini index 974579d1009..922f8a7b076 100644 --- a/tests/wpt/metadata/html/browsers/windows/nested-browsing-contexts/frameElement.sub.html.ini +++ b/tests/wpt/metadata/html/browsers/windows/nested-browsing-contexts/frameElement.sub.html.ini @@ -1,6 +1,5 @@ [frameElement.sub.html] type: testharness - expected: OK [The window\'s frameElement attribute must return its container element if it is a nested browsing context] expected: FAIL diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini index f4821d971af..7d8dde43332 100644 --- a/tests/wpt/metadata/html/dom/interfaces.html.ini +++ b/tests/wpt/metadata/html/dom/interfaces.html.ini @@ -1035,12 +1035,6 @@ [Document interface: document.implementation.createDocument(null, "", null) must inherit property "origin" with the proper type (3)] expected: FAIL - [Document interface: document.implementation.createDocument(null, "", null) must inherit property "createAttributeNS" with the proper type (22)] - expected: FAIL - - [Document interface: calling createAttributeNS(DOMString,DOMString) on document.implementation.createDocument(null, "", null) with too few arguments must throw TypeError] - expected: FAIL - [Document interface: document.implementation.createDocument(null, "", null) must inherit property "createNodeIterator" with the proper type (25)] expected: FAIL @@ -2220,12 +2214,6 @@ [Element interface: calling queryAll(DOMString) on document.createElement("noscript") with too few arguments must throw TypeError] expected: FAIL - [Element interface: document.createElement("noscript") must inherit property "previousElementSibling" with the proper type (37)] - expected: FAIL - - [Element interface: document.createElement("noscript") must inherit property "nextElementSibling" with the proper type (38)] - expected: FAIL - [Element interface: document.createElement("noscript") must inherit property "before" with the proper type (39)] expected: FAIL @@ -7011,9 +6999,6 @@ [CanvasRenderingContext2D interface: attribute lineJoin] expected: FAIL - [CanvasRenderingContext2D interface: attribute miterLimit] - expected: FAIL - [CanvasRenderingContext2D interface: operation setLineDash([object Object\])] expected: FAIL @@ -7221,9 +7206,6 @@ [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "lineJoin" with the proper type (61)] expected: FAIL - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "miterLimit" with the proper type (62)] - expected: FAIL - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "setLineDash" with the proper type (63)] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/disabled-elements/disabledElement.html.ini b/tests/wpt/metadata/html/semantics/disabled-elements/disabledElement.html.ini index f381b21bccb..52c221a1e49 100644 --- a/tests/wpt/metadata/html/semantics/disabled-elements/disabledElement.html.ini +++ b/tests/wpt/metadata/html/semantics/disabled-elements/disabledElement.html.ini @@ -20,3 +20,4 @@ [A disabled should not be focusable] expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html.ini index af450694b73..0f0eaf8d6f4 100644 --- a/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html.ini +++ b/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html.ini @@ -705,3 +705,6 @@ ["data:,a 1w \\x011h" (leading U+0001)] expected: FAIL + ["data:,a 1w"] + expected: FAIL + diff --git a/tests/wpt/metadata/workers/WorkerGlobalScope_importScripts_NetworkErr.htm.ini b/tests/wpt/metadata/workers/WorkerGlobalScope_importScripts_NetworkErr.htm.ini index 6e4caece23b..ddec84b7387 100644 --- a/tests/wpt/metadata/workers/WorkerGlobalScope_importScripts_NetworkErr.htm.ini +++ b/tests/wpt/metadata/workers/WorkerGlobalScope_importScripts_NetworkErr.htm.ini @@ -1,6 +1,5 @@ [WorkerGlobalScope_importScripts_NetworkErr.htm] type: testharness - expected: TIMEOUT [ importScripts() with non-existent script file ] - expected: TIMEOUT + expected: FAIL diff --git a/tests/wpt/metadata/workers/interfaces/WorkerGlobalScope/location/members.html.ini b/tests/wpt/metadata/workers/interfaces/WorkerGlobalScope/location/members.html.ini index 71d4aa447ea..d708f6da6f9 100644 --- a/tests/wpt/metadata/workers/interfaces/WorkerGlobalScope/location/members.html.ini +++ b/tests/wpt/metadata/workers/interfaces/WorkerGlobalScope/location/members.html.ini @@ -2,3 +2,4 @@ type: testharness [members of WorkerLocation] expected: FAIL + diff --git a/tests/wpt/web-platform-tests/IndexedDB/key_valid.html b/tests/wpt/web-platform-tests/IndexedDB/key_valid.html index e695d14c4cd..f45d4a903e3 100644 --- a/tests/wpt/web-platform-tests/IndexedDB/key_valid.html +++ b/tests/wpt/web-platform-tests/IndexedDB/key_valid.html @@ -1,6 +1,7 @@ + Valid key diff --git a/tests/wpt/web-platform-tests/README.md b/tests/wpt/web-platform-tests/README.md index 0c1c7165ca5..dbf82da9785 100644 --- a/tests/wpt/web-platform-tests/README.md +++ b/tests/wpt/web-platform-tests/README.md @@ -1,8 +1,16 @@ The Web Platform Tests Project [![IRC chat](https://goo.gl/6nCIks)](http://irc.w3.org/?channels=testing) ============================== -These are test suites for 60+ Web-platform specifications, along -with test-infrastructure code for running the tests. +The Web Platform Tests Project is a W3C-coordinated attempt to build a +cross-browser testsuite for the Web-platform stack. Writing tests in a +way that allows them to be run in all browsers gives browser projects +confidence that they are shipping software that is compatible with other +implementations, and that later implementations will be compatible with +their implementations. This in turn gives Web authors/developers +confidence that they can actually rely on the Web platform to deliver on +the promise of working across browsers and devices without needing extra +layers of abstraction to paper over the gaps left by specification +editors and implementors. Running the Tests ================= diff --git a/tests/wpt/web-platform-tests/XMLHttpRequest/resources/chunked.py b/tests/wpt/web-platform-tests/XMLHttpRequest/resources/chunked.py index 7adabbfd7f4..7e8433bd869 100644 --- a/tests/wpt/web-platform-tests/XMLHttpRequest/resources/chunked.py +++ b/tests/wpt/web-platform-tests/XMLHttpRequest/resources/chunked.py @@ -10,7 +10,7 @@ def main(request, response): response.write_status_headers() for value in chunks: - response.writer.write("%d\r\n" % len(value)) + response.writer.write("%x\r\n" % len(value)) response.writer.write(value) response.writer.write("\r\n") response.writer.write("0\r\n") diff --git a/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_1.html b/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_1.html index d912b86bb8b..bf6d32cf83e 100644 --- a/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_1.html +++ b/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_1.html @@ -2,6 +2,7 @@ Video element src attribute must match src list - positive test + diff --git a/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_1_2.html b/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_1_2.html index c1b9f72f48d..61d4b142579 100644 --- a/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_1_2.html +++ b/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_1_2.html @@ -2,6 +2,7 @@ Video element src attribute must match src list - negative test + diff --git a/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_2.html b/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_2.html index 7509d7b051a..771e389c8f2 100644 --- a/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_2.html +++ b/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_2.html @@ -2,6 +2,7 @@ Audio element src attribute must match src list - positive test + diff --git a/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_2_2.html b/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_2_2.html index 573b5389e2a..9b613429620 100644 --- a/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_2_2.html +++ b/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_2_2.html @@ -2,6 +2,7 @@ Audio element src attribute must match src list - negative test + diff --git a/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_3.html b/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_3.html index 32187708239..c645d9bec83 100644 --- a/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_3.html +++ b/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_3.html @@ -2,6 +2,7 @@ Video track src attribute must match src list - positive test + diff --git a/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_3_2.html b/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_3_2.html index 7ead63f88e8..f4488bb4475 100644 --- a/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_3_2.html +++ b/tests/wpt/web-platform-tests/content-security-policy/media-src/media-src-7_3_2.html @@ -2,6 +2,7 @@ Video track src attribute must match src list - negative test + diff --git a/tests/wpt/web-platform-tests/content-security-policy/object-src/object-src-2_1.html b/tests/wpt/web-platform-tests/content-security-policy/object-src/object-src-2_1.html index aaf67bf740a..a6cc8d49df0 100644 --- a/tests/wpt/web-platform-tests/content-security-policy/object-src/object-src-2_1.html +++ b/tests/wpt/web-platform-tests/content-security-policy/object-src/object-src-2_1.html @@ -2,6 +2,7 @@ Objects loaded using data attribute of <object> tag are blocked unless their host is listed as an allowed source in the object-src directive + @@ -34,19 +35,19 @@ function object_loaded() { var elem = document.getElementById("flashObject"); - var is_loaded = false; - try { - - var pct_loaded = elem.PercentLoaded(); - is_loaded = true; - } catch (e) {} + var is_loaded = false; + try { + + var pct_loaded = elem.PercentLoaded(); + is_loaded = true; + } catch (e) {} - if (hasMimeType) { - test1.step(function() {assert_false(is_loaded, "External object loaded.")}); - } else { - test1.step(function() {assert_true(hasMimeType, "No Flash Player, cannot run test.")}); - } - test1.done(); + if (hasMimeType) { + test1.step(function() {assert_false(is_loaded, "External object loaded.")}); + } else { + test1.step(function() {assert_true(hasMimeType, "No Flash Player, cannot run test.")}); + } + test1.done(); } diff --git a/tests/wpt/web-platform-tests/content-security-policy/object-src/object-src-2_2.html b/tests/wpt/web-platform-tests/content-security-policy/object-src/object-src-2_2.html index 63b85604f5e..5ad75f99b80 100644 --- a/tests/wpt/web-platform-tests/content-security-policy/object-src/object-src-2_2.html +++ b/tests/wpt/web-platform-tests/content-security-policy/object-src/object-src-2_2.html @@ -2,6 +2,7 @@ Objects loaded using src attribute of <embed> tag are blocked unless their host is listed as an allowed source in the object-src directive + @@ -34,19 +35,19 @@ function object_loaded() { var elem = document.getElementById("flashObject"); - var is_loaded = false; - try { - - var pct_loaded = elem.PercentLoaded(); - is_loaded = true; - } catch (e) {} + var is_loaded = false; + try { + + var pct_loaded = elem.PercentLoaded(); + is_loaded = true; + } catch (e) {} - if (hasMimeType) { - test1.step(function() {assert_false(is_loaded, "External object loaded.")}); - } else { - test1.step(function() {assert_true(hasMimeType, "No Flash Player, cannot run test.")}); - } - test1.done(); + if (hasMimeType) { + test1.step(function() {assert_false(is_loaded, "External object loaded.")}); + } else { + test1.step(function() {assert_true(hasMimeType, "No Flash Player, cannot run test.")}); + } + test1.done(); } diff --git a/tests/wpt/web-platform-tests/content-security-policy/support/checkReport.sub.js b/tests/wpt/web-platform-tests/content-security-policy/support/checkReport.sub.js index dfaec7ac54d..023ce471910 100644 --- a/tests/wpt/web-platform-tests/content-security-policy/support/checkReport.sub.js +++ b/tests/wpt/web-platform-tests/content-security-policy/support/checkReport.sub.js @@ -31,7 +31,8 @@ } } - var reportLocation = location.protocol + "//" + location.host + "/content-security-policy/support/report.py?op=take&timeout=5&reportID=" + reportID; + var timeout = document.querySelector("meta[name=timeout][content=long]") ? 50 : 5; + var reportLocation = location.protocol + "//" + location.host + "/content-security-policy/support/report.py?op=take&timeout=" + timeout + "&reportID=" + reportID; var reportTest = async_test("Violation report status OK."); reportTest.step(function () { diff --git a/tests/wpt/web-platform-tests/content-security-policy/support/report.py b/tests/wpt/web-platform-tests/content-security-policy/support/report.py index f8c0c463c03..455d46c6d1d 100644 --- a/tests/wpt/web-platform-tests/content-security-policy/support/report.py +++ b/tests/wpt/web-platform-tests/content-security-policy/support/report.py @@ -2,25 +2,22 @@ import time import json def main(request, response): - op = request.GET.first("op"); key = request.GET.first("reportID") if op == "take": - timeout = float(request.GET.first("timeout")) - value = request.server.stash.take(key=key) - if value is not None: - return [("Content-Type", "application/json")], value - else: - time.sleep(timeout) - value = request.server.stash.take(key=key) - if value is not None: - return [("Content-Type", "application/json")], value - else: - return [("Content-Type", "application/json")], json.dumps({'error': 'No such report.' , 'guid' : key}) - else: - report = request.body - report.rstrip() - request.server.stash.take(key=key) - request.server.stash.put(key=key, value=report) - return [("Content-Type", "text/plain")], "Recorded report " + report \ No newline at end of file + timeout = float(request.GET.first("timeout")) + t0 = time.time() + while time.time() - t0 < timeout: + time.sleep(0.5) + value = request.server.stash.take(key=key) + if value is not None: + return [("Content-Type", "application/json")], value + + return [("Content-Type", "application/json")], json.dumps({'error': 'No such report.' , 'guid' : key}) + + report = request.body + report.rstrip() + request.server.stash.take(key=key) + request.server.stash.put(key=key, value=report) + return [("Content-Type", "text/plain")], "Recorded report " + report diff --git a/tests/wpt/web-platform-tests/dom/nodes/CharacterData-appendData.html b/tests/wpt/web-platform-tests/dom/nodes/CharacterData-appendData.html index 5e84e970551..464a119a03d 100644 --- a/tests/wpt/web-platform-tests/dom/nodes/CharacterData-appendData.html +++ b/tests/wpt/web-platform-tests/dom/nodes/CharacterData-appendData.html @@ -7,15 +7,56 @@
diff --git a/tests/wpt/web-platform-tests/dom/nodes/CharacterData-substringData.html b/tests/wpt/web-platform-tests/dom/nodes/CharacterData-substringData.html new file mode 100644 index 00000000000..1d7288ab3f1 --- /dev/null +++ b/tests/wpt/web-platform-tests/dom/nodes/CharacterData-substringData.html @@ -0,0 +1,108 @@ + + +CharacterData.substringData + + + + +
+ diff --git a/tests/wpt/web-platform-tests/dom/nodes/attributes.html b/tests/wpt/web-platform-tests/dom/nodes/attributes.html index f4a993a252f..34be42a0a0d 100644 --- a/tests/wpt/web-platform-tests/dom/nodes/attributes.html +++ b/tests/wpt/web-platform-tests/dom/nodes/attributes.html @@ -385,4 +385,13 @@ test(function() { el.removeAttributeNS(null, "pre:fix") assert_equals(el.attributes[0], unprefixed) }, "Attribute with prefix in local name") + +test(function() { + var el = document.createElement("div") + el.setAttribute("foo", "bar") + var attr = el.attributes[0] + assert_equals(attr.ownerElement, el) + el.removeAttribute("foo") + assert_equals(attr.ownerElement, null) +}, "Attribute loses its owner when removed") diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/image.html b/tests/wpt/web-platform-tests/fetch/nosniff/image.html new file mode 100644 index 00000000000..e5869d94e60 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/image.html @@ -0,0 +1,29 @@ + + +
+ diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/importscripts.html b/tests/wpt/web-platform-tests/fetch/nosniff/importscripts.html new file mode 100644 index 00000000000..920b6bdd409 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/importscripts.html @@ -0,0 +1,14 @@ + + +
+ diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/importscripts.js b/tests/wpt/web-platform-tests/fetch/nosniff/importscripts.js new file mode 100644 index 00000000000..aeb6154870b --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/importscripts.js @@ -0,0 +1,17 @@ +// Testing importScripts() +function log(w) { this.postMessage(w) } +function f() { log("FAIL") } +function p() { log("PASS") } + +["", "?type=", "?type=x", "?type=x/x"].forEach(function(urlpart) { + try { + importScripts("resources/js.py" + urlpart) + } catch(e) { + (e.name == "NetworkError") ? p() : log("FAIL (no NetworkError exception): " + urlpart) + } + +}) +importScripts("resources/js.py?type=text/javascript&outcome=p") +importScripts("resources/js.py?type=text/ecmascript&outcome=p") +importScripts("resources/js.py?type=text/ecmascript;blah&outcome=p") +log("END") diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/parsing-nosniff.html b/tests/wpt/web-platform-tests/fetch/nosniff/parsing-nosniff.html new file mode 100644 index 00000000000..10c5cadfcaa --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/parsing-nosniff.html @@ -0,0 +1,28 @@ + + +
+ diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/resources/css.py b/tests/wpt/web-platform-tests/fetch/nosniff/resources/css.py new file mode 100644 index 00000000000..7c4c63b596a --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/resources/css.py @@ -0,0 +1,15 @@ +def main(request, response): + outcome = request.GET.first("outcome", "f") + type = request.GET.first("type", None) + + content = "/* nothing to see here */" + + response.add_required_headers = False + response.writer.write_status(200) + response.writer.write_header("x-content-type-options", "nosniff") + response.writer.write_header("content-length", len(content)) + if(type != None): + response.writer.write_header("content-type", type) + response.writer.end_headers() + + response.writer.write(content) diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/resources/image.py b/tests/wpt/web-platform-tests/fetch/nosniff/resources/image.py new file mode 100644 index 00000000000..32a07c197df --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/resources/image.py @@ -0,0 +1,16 @@ +import os.path + +def main(request, response): + type = request.GET.first("type", None) + + body = open(os.path.join(os.path.dirname(__file__), "../../../images/blue96x96.png")).read() + + response.add_required_headers = False + response.writer.write_status(200) + response.writer.write_header("x-content-type-options", "nosniff") + response.writer.write_header("content-length", len(body)) + if(type != None): + response.writer.write_header("content-type", type) + response.writer.end_headers() + + response.writer.write(body) diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/resources/js.py b/tests/wpt/web-platform-tests/fetch/nosniff/resources/js.py new file mode 100644 index 00000000000..0c06d9cd2e4 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/resources/js.py @@ -0,0 +1,17 @@ +def main(request, response): + outcome = request.GET.first("outcome", "f") + type = request.GET.first("type", "Content-Type missing") + + content = "// nothing to see here" + content += "\n" + content += "log('FAIL: " + type + "')" if (outcome == "f") else "p()" + + response.add_required_headers = False + response.writer.write_status(200) + response.writer.write_header("x-content-type-options", "nosniff") + response.writer.write_header("content-length", len(content)) + if(type != "Content-Type missing"): + response.writer.write_header("content-type", type) + response.writer.end_headers() + + response.writer.write(content) diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-first.asis b/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-first.asis new file mode 100644 index 00000000000..bccc53eef8a --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-first.asis @@ -0,0 +1,7 @@ +HTTP/1.1 200 YOU HAVE NO POWER HERE +Content-Length: 22 +Content-Type: x/x +X-Content-Type-options: nosniff +X-Content-Type-Options: no + +// nothing to see here diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-last.asis b/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-last.asis new file mode 100644 index 00000000000..e3de0733e4f --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-last.asis @@ -0,0 +1,7 @@ +HTTP/1.1 200 YOU HAVE NO POWER HERE +Content-Length: 22 +Content-Type: x/x +X-Content-Type-Options: no +X-Content-Type-options: nosniff + +// nothing to see here diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-no-x.asis b/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-no-x.asis new file mode 100644 index 00000000000..329d0f72143 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-no-x.asis @@ -0,0 +1,6 @@ +HTTP/1.1 200 YOU HAVE NO POWER HERE +Content-Length: 22 +Content-Type: x/x +Content-Type-Options: nosniff + +// nothing to see here diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-quoted-single.asis b/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-quoted-single.asis new file mode 100644 index 00000000000..501f18999d0 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-quoted-single.asis @@ -0,0 +1,6 @@ +HTTP/1.1 200 YOU HAVE NO POWER HERE +Content-Length: 22 +Content-Type: x/x +X-Content-Type-Options: 'NosniFF' + +// nothing to see here diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-quoted.asis b/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-quoted.asis new file mode 100644 index 00000000000..c6de62b689e --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-quoted.asis @@ -0,0 +1,6 @@ +HTTP/1.1 200 YOU HAVE NO POWER HERE +Content-Length: 22 +Content-Type: x/x +X-Content-Type-Options: "nosniFF" + +// nothing to see here diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-uppercase.asis b/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-uppercase.asis new file mode 100644 index 00000000000..8097fddce10 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/resources/nosniff-uppercase.asis @@ -0,0 +1,6 @@ +HTTP/1.1 200 YOU HAVE NO POWER HERE +Content-Length: 22 +Content-Type: x/x +X-Content-Type-Options: NOSNIFF + +// nothing to see here diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/resources/worker.py b/tests/wpt/web-platform-tests/fetch/nosniff/resources/worker.py new file mode 100644 index 00000000000..3903ba34947 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/resources/worker.py @@ -0,0 +1,16 @@ +def main(request, response): + type = request.GET.first("type", None) + + content = "// nothing to see here" + content += "\n" + content += "this.postMessage('hi')" + + response.add_required_headers = False + response.writer.write_status(200) + response.writer.write_header("x-content-type-options", "nosniff") + response.writer.write_header("content-length", len(content)) + if(type != None): + response.writer.write_header("content-type", type) + response.writer.end_headers() + + response.writer.write(content) diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/script.html b/tests/wpt/web-platform-tests/fetch/nosniff/script.html new file mode 100644 index 00000000000..667f3c99a6c --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/script.html @@ -0,0 +1,32 @@ + + +
+ diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/stylesheet.html b/tests/wpt/web-platform-tests/fetch/nosniff/stylesheet.html new file mode 100644 index 00000000000..07de819f8af --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/stylesheet.html @@ -0,0 +1,34 @@ + + + +
+ diff --git a/tests/wpt/web-platform-tests/fetch/nosniff/worker.html b/tests/wpt/web-platform-tests/fetch/nosniff/worker.html new file mode 100644 index 00000000000..466b2075e97 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/nosniff/worker.html @@ -0,0 +1,28 @@ + + +
+ diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html index 2ff9886e036..ce1e4cebe5f 100644 --- a/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html @@ -58,12 +58,13 @@ - - + + + diff --git a/tests/wpt/web-platform-tests/manifest b/tests/wpt/web-platform-tests/manifest index f5b0c9bade7..edebae62695 100755 --- a/tests/wpt/web-platform-tests/manifest +++ b/tests/wpt/web-platform-tests/manifest @@ -1,6 +1,8 @@ #!/usr/bin/env python +import os import sys from tools.manifest import update -update.main() +update.main(default_tests_root= + os.path.abspath(os.path.dirname(__file__))) diff --git a/tests/wpt/web-platform-tests/resources/docs/api.md b/tests/wpt/web-platform-tests/resources/docs/api.md index 4598a9b15a9..78c00a957a1 100644 --- a/tests/wpt/web-platform-tests/resources/docs/api.md +++ b/tests/wpt/web-platform-tests/resources/docs/api.md @@ -147,6 +147,42 @@ with a TypeError: return promise_rejects(t, new TypeError(), bar); }, "Another example"); +`EventWatcher` is a constructor function that allows DOM events to be handled +using Promises, which can make it a lot easier to test a very specific series +of events, including ensuring that unexpected events are not fired at any point. + +Here's an example of how to use `EventWatcher`: + + var t = async_test("Event order on animation start"); + + var animation = watchedNode.getAnimations()[0]; + var eventWatcher = new EventWatcher(watchedNode, ['animationstart', + 'animationiteration', + 'animationend']); + + eventWatcher.wait_for(t, 'animationstart').then(t.step_func(function() { + assertExpectedStateAtStartOfAnimation(); + animation.currentTime = END_TIME; // skip to end + // We expect two animationiteration events then an animationend event on + // skipping to the end of the animation. + return eventWatcher.wait_for(['animationiteration', + 'animationiteration', + 'animationend']); + })).then(t.step_func(function() { + assertExpectedStateAtEndOfAnimation(); + test.done(); + })); + +`wait_for` either takes the name of a single event and returns a Promise that +will resolve after that event is fired at the watched node, or else it takes an +array of the names of a series of events and returns a Promise that will +resolve after that specific series of events has been fired at the watched node. + +`EventWatcher` will assert if an event occurs while there is no `wait_for`() +created Promise waiting to be fulfilled, or if the event is of a different type +to the type currently expected. This ensures that only the events that are +expected occur, in the correct order, and with the correct timing. + ## Single Page Tests ## Sometimes, particularly when dealing with asynchronous behaviour, diff --git a/tests/wpt/web-platform-tests/resources/testharness.js b/tests/wpt/web-platform-tests/resources/testharness.js index ab88e541fcb..748010306c1 100644 --- a/tests/wpt/web-platform-tests/resources/testharness.js +++ b/tests/wpt/web-platform-tests/resources/testharness.js @@ -470,6 +470,74 @@ policies and contribution forms [3]. }); } + /** + * This constructor helper allows DOM events to be handled using Promises, + * which can make it a lot easier to test a very specific series of events, + * including ensuring that unexpected events are not fired at any point. + */ + function EventWatcher(test, watchedNode, eventTypes) + { + if (typeof eventTypes == 'string') { + eventTypes = [eventTypes]; + } + + var waitingFor = null; + + var eventHandler = test.step_func(function(evt) { + assert_true(!!waitingFor, + 'Not expecting event, but got ' + evt.type + ' event'); + assert_equals(evt.type, waitingFor.types[0], + 'Expected ' + waitingFor.types[0] + ' event, but got ' + + evt.type + ' event instead'); + if (waitingFor.types.length > 1) { + // Pop first event from array + waitingFor.types.shift(); + return; + } + // We need to null out waitingFor before calling the resolve function + // since the Promise's resolve handlers may call wait_for() which will + // need to set waitingFor. + var resolveFunc = waitingFor.resolve; + waitingFor = null; + resolveFunc(evt); + }); + + for (var i = 0; i < eventTypes.length; i++) { + watchedNode.addEventListener(eventTypes[i], eventHandler); + } + + /** + * Returns a Promise that will resolve after the specified event or + * series of events has occured. + */ + this.wait_for = function(types) { + if (waitingFor) { + return Promise.reject('Already waiting for an event or events'); + } + if (typeof types == 'string') { + types = [types]; + } + return new Promise(function(resolve, reject) { + waitingFor = { + types: types, + resolve: resolve, + reject: reject + }; + }); + }; + + function stop_watching() { + for (var i = 0; i < eventTypes.length; i++) { + watchedNode.removeEventListener(eventTypes[i], eventHandler); + } + }; + + test.add_cleanup(stop_watching); + + return this; + } + expose(EventWatcher, 'EventWatcher'); + function setup(func_or_properties, maybe_properties) { var func = null; diff --git a/tests/wpt/web-platform-tests/tools/.gitignore b/tests/wpt/web-platform-tests/tools/.gitignore new file mode 100644 index 00000000000..7a8ba560c9e --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/.gitignore @@ -0,0 +1,6 @@ +*# +*.py[co] +*.sw[po] +*~ +\#* + diff --git a/tests/wpt/web-platform-tests/tools/manifest/update.py b/tests/wpt/web-platform-tests/tools/manifest/update.py index 054e9ce7ab2..1c08c8850d4 100644 --- a/tests/wpt/web-platform-tests/tools/manifest/update.py +++ b/tests/wpt/web-platform-tests/tools/manifest/update.py @@ -2,6 +2,7 @@ import argparse import imp import os +import sys import manifest import vcs @@ -82,11 +83,32 @@ def create_parser(): return parser -def main(): +def find_top_repo(): + path = here + rv = None + while path != "/": + if vcs.is_git_repo(path): + rv = path + path = os.path.abspath(os.path.join(path, os.pardir)) + + return rv + +def main(default_tests_root=None): opts = create_parser().parse_args() if opts.tests_root is None: - opts.tests_root = vcs.get_repo_root() + tests_root = None + if default_tests_root is not None: + tests_root = default_tests_root + else: + tests_root = find_top_repo() + + if tests_root is None: + print >> sys.stderr, """No git repo found; could not determine test root. +Run again with --test-root""" + sys.exit(1) + + opts.tests_root = tests_root if opts.path is None: opts.path = os.path.join(opts.tests_root, "MANIFEST.json") diff --git a/tests/wpt/web-platform-tests/tools/manifest/vcs.py b/tests/wpt/web-platform-tests/tools/manifest/vcs.py index 7bf37949208..93bd445e1e8 100644 --- a/tests/wpt/web-platform-tests/tools/manifest/vcs.py +++ b/tests/wpt/web-platform-tests/tools/manifest/vcs.py @@ -13,9 +13,13 @@ def is_git_repo(tests_root): _repo_root = None -def get_repo_root(): +def get_repo_root(initial_dir=None): global _repo_root + + if initial_dir is None: + initial_dir = os.path.dirname(__file__) + if _repo_root is None: - git = get_git_func(os.path.dirname(__file__)) + git = get_git_func(initial_dir) _repo_root = git("rev-parse", "--show-toplevel").rstrip() return _repo_root diff --git a/tests/wpt/web-platform-tests/websockets/Close-undefined.htm b/tests/wpt/web-platform-tests/websockets/Close-undefined.htm index 4f67c067e74..3de1656561c 100644 --- a/tests/wpt/web-platform-tests/websockets/Close-undefined.htm +++ b/tests/wpt/web-platform-tests/websockets/Close-undefined.htm @@ -10,13 +10,13 @@
diff --git a/tests/wpt/web-platform-tests/websockets/Secure-Close-undefined.htm b/tests/wpt/web-platform-tests/websockets/Secure-Close-undefined.htm index ef4a874ea75..f6c77ba77ad 100644 --- a/tests/wpt/web-platform-tests/websockets/Secure-Close-undefined.htm +++ b/tests/wpt/web-platform-tests/websockets/Secure-Close-undefined.htm @@ -10,13 +10,13 @@
diff --git a/tests/wpt/web-platform-tests/websockets/cookies/001.html b/tests/wpt/web-platform-tests/websockets/cookies/001.html index b0701d0cd91..ed318456522 100644 --- a/tests/wpt/web-platform-tests/websockets/cookies/001.html +++ b/tests/wpt/web-platform-tests/websockets/cookies/001.html @@ -10,6 +10,10 @@ async_test(function(t) { if (window.WebSocket) { document.cookie = 'ws_test_'+cookie_id+'=test; Path=/'; } + t.add_cleanup(function() { + // remove cookie + document.cookie = 'ws_test_'+cookie_id+'=; Path=/; Expires=Sun, 06 Nov 1994 08:49:37 GMT'; + }); var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo-cookie'); ws.onmessage = t.step_func(function(e) { assert_regexp_match(e.data, new RegExp('ws_test_'+cookie_id+'=test')); @@ -18,6 +22,4 @@ async_test(function(t) { }); ws.onerror = ws.onclose = t.step_func(function(e) {assert_unreached(e.type)}); }); -// remove cookie -document.cookie = 'ws_test_'+cookie_id+'=; Path=/; Expires=Sun, 06 Nov 1994 08:49:37 GMT'; diff --git a/tests/wpt/web-platform-tests/websockets/cookies/002.html b/tests/wpt/web-platform-tests/websockets/cookies/002.html index 1e6a1dbeab2..fd174f2aefb 100644 --- a/tests/wpt/web-platform-tests/websockets/cookies/002.html +++ b/tests/wpt/web-platform-tests/websockets/cookies/002.html @@ -7,11 +7,13 @@ diff --git a/tests/wpt/web-platform-tests/websockets/cookies/004.html b/tests/wpt/web-platform-tests/websockets/cookies/004.html index 894ef2eff89..db6b3c1c214 100644 --- a/tests/wpt/web-platform-tests/websockets/cookies/004.html +++ b/tests/wpt/web-platform-tests/websockets/cookies/004.html @@ -10,6 +10,11 @@ var cookie_id = ((new Date())-0) + '.' + Math.random(); var t = async_test(function(t) { var iframe = document.createElement('iframe'); + t.add_cleanup(function() { + // remove cookie + iframe.src = 'support/set-cookie.py?'+encodeURIComponent('ws_test_'+cookie_id+'=; Path=/; HttpOnly; Expires=Sun, 06 Nov 1994 08:49:37 GMT'); + iframe.onload = done; + }); var url = SCHEME_DOMAIN_PORT+'/set-cookie_http?'+cookie_id; var ws = new WebSocket(url); ws.onopen = t.step_func(function(e) { @@ -17,13 +22,7 @@ var t = async_test(function(t) { assert_false(new RegExp('ws_test_'+cookie_id+'=test').test(document.cookie)); t.done(); }); - ws.onclose = t.step_func(function(e) {assert_unreached()}); - - - add_result_callback(function() { - iframe.src = 'support/set-cookie.py?'+encodeURIComponent('ws_test_'+cookie_id+'=; Path=/; HttpOnly; Expires=Sun, 06 Nov 1994 08:49:37 GMT'); - iframe.onload = done; - }); + ws.onerror = ws.onclose = t.step_func(function(e) {assert_unreached(e.type)}); document.body.appendChild(iframe); }, null, {timeout:9900}) diff --git a/tests/wpt/web-platform-tests/websockets/cookies/005.html b/tests/wpt/web-platform-tests/websockets/cookies/005.html index e7aefd5978e..7b3d80f129c 100644 --- a/tests/wpt/web-platform-tests/websockets/cookies/005.html +++ b/tests/wpt/web-platform-tests/websockets/cookies/005.html @@ -11,6 +11,11 @@ var cookie_id = ((new Date())-0) + '.' + Math.random(); var t = async_test(function(t) { var iframe = document.createElement('iframe'); + t.add_cleanup(function() { + // remove cookie + iframe.src = 'support/set-cookie.py?'+encodeURIComponent('ws_test_'+cookie_id+'=; Path=/; HttpOnly; Expires=Sun, 06 Nov 1994 08:49:37 GMT'); + iframe.onload = done; + }); var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/set-cookie_http?'+cookie_id); ws.onopen = t.step_func(function(e) { var ws2 = new WebSocket(SCHEME_DOMAIN_PORT+'/echo-cookie'); @@ -21,12 +26,7 @@ var t = async_test(function(t) { t.done(); }); }); - ws.onclose = t.step_func(function() {assert_unreached()}); - - add_result_callback(function() { - iframe.src = 'support/set-cookie.py?'+encodeURIComponent('ws_test_'+cookie_id+'=; Path=/; HttpOnly; Expires=Sun, 06 Nov 1994 08:49:37 GMT'); - iframe.onload = done; - }); + ws.onerror = ws.onclose = t.step_func(function(e) {assert_unreached(e.type)}); document.body.appendChild(iframe); }) diff --git a/tests/wpt/web-platform-tests/websockets/cookies/006.html b/tests/wpt/web-platform-tests/websockets/cookies/006.html index 05c848033b1..e14a90f7bdf 100644 --- a/tests/wpt/web-platform-tests/websockets/cookies/006.html +++ b/tests/wpt/web-platform-tests/websockets/cookies/006.html @@ -10,6 +10,10 @@ async_test(function(t) { if (window.WebSocket) { document.cookie = 'ws_test_'+cookie_id+'=test; Path=/; Secure'; } + t.add_cleanup(function() { + // remove cookie + document.cookie = 'ws_test_'+cookie_id+'=; Path=/; Secure; Expires=Sun, 06 Nov 1994 08:49:37 GMT'; + }); var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo-cookie'); ws.onmessage = t.step_func(function(e) { ws.close(); @@ -20,8 +24,6 @@ async_test(function(t) { } t.done(); }) - ws.onclose = t.step_func(function() {assert_unreached()}); + ws.onerror = ws.onclose = t.step_func(function(e) {assert_unreached(e.type)}); }); -// remove cookie -document.cookie = 'ws_test_'+cookie_id+'; Path=/; Secure; Expires=Sun, 06 Nov 1994 08:49:37 GMT'; diff --git a/tests/wpt/web-platform-tests/websockets/cookies/007.html b/tests/wpt/web-platform-tests/websockets/cookies/007.html index efea696a1e9..eba3139645a 100644 --- a/tests/wpt/web-platform-tests/websockets/cookies/007.html +++ b/tests/wpt/web-platform-tests/websockets/cookies/007.html @@ -8,15 +8,17 @@ diff --git a/tests/wpt/web-platform-tests/websockets/websocket.js b/tests/wpt/web-platform-tests/websockets/websocket.js index a7c2e201c4c..196a1b5c6a2 100644 --- a/tests/wpt/web-platform-tests/websockets/websocket.js +++ b/tests/wpt/web-platform-tests/websockets/websocket.js @@ -2,7 +2,7 @@ var __SERVER__NAME = "{{host}}"; var __PORT = {{ports[ws][0]}}; var __SECURE__PORT = null; //{{ports[ws][0]}}; //Should be wss var __NEW__PORT = __PORT; //All ports are non-default for now -var __NEW_SECURE_PORT = __PORT; //All ports are non-default for now +var __NEW__SECURE__PORT = __PORT; //All ports are non-default for now var __PATH = "echo"; var __CONTROLPATH = "control"; var __PROTOCOL = "echo";