diff options
21 files changed, 196 insertions, 226 deletions
diff --git a/components/app_units/Cargo.toml b/components/app_units/Cargo.toml index d324f7cb27f..b019f842603 100644 --- a/components/app_units/Cargo.toml +++ b/components/app_units/Cargo.toml @@ -2,6 +2,10 @@ name = "app_units" version = "0.1.0" authors = ["The Servo Project Developers"] +description = "Servo app units type (Au)" +documentation = "http://doc.servo.org/app_units/" +repository = "https://github.com/servo/app_units" +license = "MIT / Apache-2.0" [dependencies] serde = "0.6" diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index ffd898934cc..540267cc408 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -271,7 +271,8 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { ScaleFactor::new(1.0), initial_viewport: opts::get().initial_window_size.as_f32() * ScaleFactor::new(1.0), - device_pixel_ratio: ScaleFactor::new(1.0), + device_pixel_ratio: + ScaleFactor::new(opts::get().device_pixels_per_px.unwrap_or(1.0)), }, phantom: PhantomData, clipboard_ctx: if state.supports_clipboard { diff --git a/components/compositing/headless.rs b/components/compositing/headless.rs index 92b445a4476..3a0ab67ea21 100644 --- a/components/compositing/headless.rs +++ b/components/compositing/headless.rs @@ -11,6 +11,7 @@ use msg::constellation_msg::Msg as ConstellationMsg; use msg::constellation_msg::{ConstellationChan, WindowSizeData}; use profile_traits::mem; use profile_traits::time; +use util::opts; use windowing::WindowEvent; /// Starts the compositor, which listens for messages on the specified port. @@ -45,9 +46,10 @@ impl NullCompositor { { let ConstellationChan(ref chan) = compositor.constellation_chan; chan.send(ConstellationMsg::ResizedWindow(WindowSizeData { - initial_viewport: Size2D::typed(640_f32, 480_f32), - visible_viewport: Size2D::typed(640_f32, 480_f32), - device_pixel_ratio: ScaleFactor::new(1.0), + initial_viewport: Size2D::typed(800_f32, 600_f32), + visible_viewport: Size2D::typed(800_f32, 600_f32), + device_pixel_ratio: + ScaleFactor::new(opts::get().device_pixels_per_px.unwrap_or(1.0)), })).unwrap(); } diff --git a/components/gfx/paint_context.rs b/components/gfx/paint_context.rs index 8ac75733061..d73d9013a05 100644 --- a/components/gfx/paint_context.rs +++ b/components/gfx/paint_context.rs @@ -1792,7 +1792,7 @@ impl ScaledFontExtensionMethods for ScaledFont { azglyphs.reserve(range.length().to_usize()); for slice in run.natural_word_slices_in_visual_order(range) { - for (_i, glyph) in slice.glyphs.iter_glyphs_for_char_range(&slice.range) { + for glyph in slice.glyphs.iter_glyphs_for_char_range(&slice.range) { let glyph_advance = glyph.advance(); let glyph_offset = glyph.offset().unwrap_or(Point2D::zero()); let azglyph = struct__AzGlyph { diff --git a/components/gfx/text/glyph.rs b/components/gfx/text/glyph.rs index 700a44e3d95..31a1c850d00 100644 --- a/components/gfx/text/glyph.rs +++ b/components/gfx/text/glyph.rs @@ -62,14 +62,6 @@ impl GlyphEntry { GlyphEntry::new(glyph_count as u32) } - /// Create a GlyphEntry for the case where glyphs couldn't be found for the specified - /// character. - fn missing(glyph_count: usize) -> GlyphEntry { - assert!(glyph_count <= u16::MAX as usize); - - GlyphEntry::new(glyph_count as u32) - } - fn is_initial(&self) -> bool { *self == GlyphEntry::initial() } @@ -129,8 +121,8 @@ impl GlyphEntry { } #[inline(always)] - fn set_char_is_space(&self) -> GlyphEntry { - GlyphEntry::new(self.value | FLAG_CHAR_IS_SPACE) + fn set_char_is_space(&mut self) { + self.value |= FLAG_CHAR_IS_SPACE; } fn glyph_count(&self) -> u16 { @@ -147,11 +139,6 @@ impl GlyphEntry { fn has_flag(&self, flag: u32) -> bool { (self.value & flag) != 0 } - - #[inline(always)] - fn adapt_character_flags_of_entry(&self, other: GlyphEntry) -> GlyphEntry { - GlyphEntry { value: self.value | other.value } - } } // Stores data for a detailed glyph, in the case that several glyphs @@ -322,7 +309,6 @@ pub struct GlyphData { id: GlyphId, advance: Au, offset: Point2D<Au>, - is_missing: bool, cluster_start: bool, ligature_start: bool, } @@ -332,7 +318,6 @@ impl GlyphData { pub fn new(id: GlyphId, advance: Au, offset: Option<Point2D<Au>>, - is_missing: bool, cluster_start: bool, ligature_start: bool) -> GlyphData { @@ -340,7 +325,6 @@ impl GlyphData { id: id, advance: advance, offset: offset.unwrap_or(Point2D::zero()), - is_missing: is_missing, cluster_start: cluster_start, ligature_start: ligature_start, } @@ -465,31 +449,27 @@ impl<'a> GlyphStore { /// otherwise, this glyph represents multiple characters. pub fn add_glyph_for_char_index(&mut self, i: CharIndex, - character: Option<char>, + character: char, data: &GlyphData) { - fn glyph_is_compressible(data: &GlyphData) -> bool { - is_simple_glyph_id(data.id) - && is_simple_advance(data.advance) + let glyph_is_compressible = is_simple_glyph_id(data.id) && + is_simple_advance(data.advance) && data.offset == Point2D::zero() - && data.cluster_start // others are stored in detail buffer - } + && data.cluster_start; // others are stored in detail buffer debug_assert!(data.ligature_start); // can't compress ligature continuation glyphs. debug_assert!(i < self.char_len()); - let mut entry = match (data.is_missing, glyph_is_compressible(data)) { - (true, _) => GlyphEntry::missing(1), - (false, true) => GlyphEntry::simple(data.id, data.advance), - (false, false) => { - let glyph = &[DetailedGlyph::new(data.id, data.advance, data.offset)]; - self.has_detailed_glyphs = true; - self.detail_store.add_detailed_glyphs_for_entry(i, glyph); - GlyphEntry::complex(data.cluster_start, data.ligature_start, 1) - } + let mut entry = if glyph_is_compressible { + GlyphEntry::simple(data.id, data.advance) + } else { + let glyph = &[DetailedGlyph::new(data.id, data.advance, data.offset)]; + self.has_detailed_glyphs = true; + self.detail_store.add_detailed_glyphs_for_entry(i, glyph); + GlyphEntry::complex(data.cluster_start, data.ligature_start, 1) }; - if character == Some(' ') { - entry = entry.set_char_is_space() + if character == ' ' { + entry.set_char_is_space() } self.entry_buffer[i.to_usize()] = entry; @@ -502,22 +482,18 @@ impl<'a> GlyphStore { let glyph_count = data_for_glyphs.len(); let first_glyph_data = data_for_glyphs[0]; - let entry = match first_glyph_data.is_missing { - true => GlyphEntry::missing(glyph_count), - false => { - let glyphs_vec: Vec<DetailedGlyph> = (0..glyph_count).map(|i| { - DetailedGlyph::new(data_for_glyphs[i].id, - data_for_glyphs[i].advance, - data_for_glyphs[i].offset) - }).collect(); - - self.has_detailed_glyphs = true; - self.detail_store.add_detailed_glyphs_for_entry(i, &glyphs_vec); - GlyphEntry::complex(first_glyph_data.cluster_start, - first_glyph_data.ligature_start, - glyph_count) - } - }.adapt_character_flags_of_entry(self.entry_buffer[i.to_usize()]); + let glyphs_vec: Vec<DetailedGlyph> = (0..glyph_count).map(|i| { + DetailedGlyph::new(data_for_glyphs[i].id, + data_for_glyphs[i].advance, + data_for_glyphs[i].offset) + }).collect(); + + self.has_detailed_glyphs = true; + self.detail_store.add_detailed_glyphs_for_entry(i, &glyphs_vec); + + let entry = GlyphEntry::complex(first_glyph_data.cluster_start, + first_glyph_data.ligature_start, + glyph_count); debug!("Adding multiple glyphs[idx={:?}, count={}]: {:?}", i, glyph_count, entry); @@ -566,7 +542,7 @@ impl<'a> GlyphStore { #[inline] pub fn advance_for_char_range_slow_path(&self, rang: &Range<CharIndex>) -> Au { self.iter_glyphs_for_char_range(rang) - .fold(Au(0), |advance, (_, glyph)| advance + glyph.advance()) + .fold(Au(0), |advance, glyph| advance + glyph.advance()) } #[inline] @@ -688,11 +664,10 @@ pub struct GlyphIterator<'a> { impl<'a> GlyphIterator<'a> { // Slow path when there is a glyph range. #[inline(never)] - fn next_glyph_range(&mut self) -> Option<(CharIndex, GlyphInfo<'a>)> { + fn next_glyph_range(&mut self) -> Option<GlyphInfo<'a>> { match self.glyph_range.as_mut().unwrap().next() { Some(j) => { - Some((self.char_index, - GlyphInfo::Detail(self.store, self.char_index, j.get() as u16 /* ??? */))) + Some(GlyphInfo::Detail(self.store, self.char_index, j.get() as u16 /* ??? */)) } None => { // No more glyphs for current character. Try to get another. @@ -704,8 +679,7 @@ impl<'a> GlyphIterator<'a> { // Slow path when there is a complex glyph. #[inline(never)] - fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: CharIndex) - -> Option<(CharIndex, GlyphInfo<'a>)> { + fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: CharIndex) -> Option<GlyphInfo<'a>> { let glyphs = self.store.detail_store.detailed_glyphs_for_entry(i, entry.glyph_count()); self.glyph_range = Some(range::each_index(CharIndex(0), CharIndex(glyphs.len() as isize))); self.next() @@ -713,7 +687,7 @@ impl<'a> GlyphIterator<'a> { } impl<'a> Iterator for GlyphIterator<'a> { - type Item = (CharIndex, GlyphInfo<'a>); + type Item = GlyphInfo<'a>; // I tried to start with something simpler and apply FlatMap, but the // inability to store free variables in the FlatMap struct was problematic. @@ -722,7 +696,7 @@ impl<'a> Iterator for GlyphIterator<'a> { // slow paths, which should not be inlined, are `next_glyph_range()` and // `next_complex_glyph()`. #[inline(always)] - fn next(&mut self) -> Option<(CharIndex, GlyphInfo<'a>)> { + fn next(&mut self) -> Option<GlyphInfo<'a>> { // Would use 'match' here but it borrows contents in a way that interferes with mutation. if self.glyph_range.is_some() { return self.next_glyph_range() @@ -741,7 +715,7 @@ impl<'a> Iterator for GlyphIterator<'a> { debug_assert!(i < self.store.char_len()); let entry = self.store.entry_buffer[i.to_usize()]; if entry.is_simple() { - Some((i, GlyphInfo::Simple(self.store, i))) + Some(GlyphInfo::Simple(self.store, i)) } else { // Fall back to the slow path. self.next_complex_glyph(&entry, i) diff --git a/components/gfx/text/shaping/harfbuzz.rs b/components/gfx/text/shaping/harfbuzz.rs index d4b05221be0..800ba9f2557 100644 --- a/components/gfx/text/shaping/harfbuzz.rs +++ b/components/gfx/text/shaping/harfbuzz.rs @@ -453,20 +453,18 @@ impl Shaper { let data = GlyphData::new(space_glyph_id, advance, Default::default(), - false, true, true); - glyphs.add_glyph_for_char_index(char_idx, Some(character), &data); + glyphs.add_glyph_for_char_index(char_idx, character, &data); } else { let shape = glyph_data.entry_for_glyph(glyph_span.begin(), &mut y_pos); let advance = self.advance_for_shaped_glyph(shape.advance, character, options); let data = GlyphData::new(shape.codepoint, advance, shape.offset, - false, true, true); - glyphs.add_glyph_for_char_index(char_idx, Some(character), &data); + glyphs.add_glyph_for_char_index(char_idx, character, &data); } } else { // collect all glyphs to be assigned to the first character. @@ -477,7 +475,6 @@ impl Shaper { datas.push(GlyphData::new(shape.codepoint, shape.advance, shape.offset, - false, // not missing true, // treat as cluster start glyph_i > glyph_span.begin())); // all but first are ligature continuations diff --git a/components/layout/block.rs b/components/layout/block.rs index 8203acaf850..a0768b9d9aa 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -51,7 +51,7 @@ use layout_debug; use layout_task::DISPLAY_PORT_SIZE_FACTOR; use model::{CollapsibleMargins, MaybeAuto, specified, specified_or_none}; use model::{IntrinsicISizes, MarginCollapseInfo}; -use msg::compositor_msg::{LayerId, LayerType}; +use msg::compositor_msg::LayerId; use rustc_serialize::{Encodable, Encoder}; use std::cmp::{max, min}; use std::fmt; @@ -64,7 +64,6 @@ use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto}; use util::geometry::MAX_RECT; use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode}; use util::opts; -use wrapper::PseudoElementType; /// Information specific to floated blocks. #[derive(Clone, RustcEncodable)] @@ -2077,16 +2076,11 @@ impl Flow for BlockFlow { } fn layer_id(&self) -> LayerId { - let layer_type = match self.fragment.pseudo { - PseudoElementType::Normal => LayerType::FragmentBody, - PseudoElementType::Before(_) => LayerType::BeforePseudoContent, - PseudoElementType::After(_) => LayerType::AfterPseudoContent - }; - LayerId::new_of_type(layer_type, self.fragment.node.id() as usize) + self.fragment.layer_id() } fn layer_id_for_overflow_scroll(&self) -> LayerId { - LayerId::new_of_type(LayerType::OverflowScroll, self.fragment.node.id() as usize) + self.fragment.layer_id_for_overflow_scroll() } fn is_absolute_containing_block(&self) -> bool { diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 94b911cae00..49c140cbedb 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -35,7 +35,7 @@ use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT}; use ipc_channel::ipc::{self, IpcSharedMemory}; use list_item::ListItemFlow; use model::{self, MaybeAuto, ToGfxMatrix}; -use msg::compositor_msg::{LayerId, ScrollPolicy, SubpageLayerInfo}; +use msg::compositor_msg::{ScrollPolicy, SubpageLayerInfo}; use net_traits::image::base::{Image, PixelFormat}; use net_traits::image_cache_task::UsePlaceholder; use std::default::Default; @@ -65,12 +65,6 @@ use util::range::Range; /// The logical width of an insertion point: at the moment, a one-pixel-wide line. const INSERTION_POINT_LOGICAL_WIDTH: Au = Au(1 * AU_PER_PX); -/// Whether a stacking context needs a layer or not. -pub enum StackingContextLayerNecessity { - Always(LayerId, ScrollPolicy), - IfCanvasOrIframe(LayerId), -} - /// The results of display list building for a single flow. pub enum DisplayListBuildingResult { None, @@ -258,7 +252,7 @@ pub trait FragmentDisplayListBuilding { base_flow: &BaseFlow, display_list: Box<DisplayList>, layout_context: &LayoutContext, - needs_layer: StackingContextLayerNecessity, + scroll_policy: ScrollPolicy, mode: StackingContextCreationMode) -> Arc<StackingContext>; } @@ -1172,7 +1166,7 @@ impl FragmentDisplayListBuilding for Fragment { base_flow: &BaseFlow, display_list: Box<DisplayList>, layout_context: &LayoutContext, - needs_layer: StackingContextLayerNecessity, + scroll_policy: ScrollPolicy, mode: StackingContextCreationMode) -> Arc<StackingContext> { let border_box = match mode { @@ -1285,24 +1279,23 @@ impl FragmentDisplayListBuilding for Fragment { filters.push(Filter::Opacity(effects.opacity)) } - // Ensure every canvas or iframe has a layer. - let (scroll_policy, layer_id) = match needs_layer { - StackingContextLayerNecessity::Always(layer_id, scroll_policy) => { - (scroll_policy, Some(layer_id)) - } - StackingContextLayerNecessity::IfCanvasOrIframe(layer_id) => { - // FIXME(pcwalton): So so bogus :( - match self.specific { - SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Iframe(_) => { - (ScrollPolicy::Scrollable, Some(layer_id)) - } - _ => (ScrollPolicy::Scrollable, None), - } - } + let canvas_or_iframe = match self.specific { + SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Iframe(_) => true, + _ => false + }; + + // There are three situations that need layers: when the fragment has the HAS_LAYER + // flag, when this is a canvas or iframe fragment, and when we are building a layer + // tree for overflow scrolling. + let layer_id = if mode == StackingContextCreationMode::InnerScrollWrapper { + Some(self.layer_id_for_overflow_scroll()) + } else if self.flags.contains(HAS_LAYER) || canvas_or_iframe { + Some(self.layer_id()) + } else { + None }; - // If it's a canvas we must propagate the layer and the renderer to the paint - // task + // If it's a canvas we must propagate the layer and the renderer to the paint task. if let SpecificFragmentInfo::Canvas(ref fragment_info) = self.specific { let layer_id = layer_id.unwrap(); if let Some(ref ipc_renderer) = fragment_info.ipc_renderer { @@ -1586,27 +1579,19 @@ impl BlockFlowDisplayListBuilding for BlockFlow { border_painting_mode, background_border_level); - self.base.display_list_building_result = if self.fragment.flags.contains(HAS_LAYER) { + self.base.display_list_building_result = if self.fragment.establishes_stacking_context() { let scroll_policy = if self.is_fixed() { ScrollPolicy::FixedPosition } else { ScrollPolicy::Scrollable }; - let stacking_context = self.fragment.create_stacking_context( - &self.base, - display_list, - layout_context, - StackingContextLayerNecessity::Always(self.layer_id(), scroll_policy), - StackingContextCreationMode::Normal); - DisplayListBuildingResult::StackingContext(stacking_context) - } else if self.fragment.establishes_stacking_context() { DisplayListBuildingResult::StackingContext( self.fragment.create_stacking_context( &self.base, display_list, layout_context, - StackingContextLayerNecessity::IfCanvasOrIframe(self.layer_id()), + scroll_policy, StackingContextCreationMode::Normal)) } else { match self.fragment.style.get_box().position { @@ -1671,22 +1656,11 @@ impl BlockFlowDisplayListBuilding for BlockFlow { } }; - if !self.fragment.flags.contains(HAS_LAYER) { - if !self.fragment.establishes_stacking_context() { - display_list.form_pseudo_stacking_context_for_positioned_content(); - self.base.display_list_building_result = - DisplayListBuildingResult::Normal(display_list); - } else { - self.base.display_list_building_result = - DisplayListBuildingResult::StackingContext( - self.fragment.create_stacking_context( - &self.base, - display_list, - layout_context, - StackingContextLayerNecessity::IfCanvasOrIframe(self.layer_id()), - StackingContextCreationMode::Normal)); - } - return + if !self.fragment.flags.contains(HAS_LAYER) && !self.fragment.establishes_stacking_context() { + display_list.form_pseudo_stacking_context_for_positioned_content(); + self.base.display_list_building_result = + DisplayListBuildingResult::Normal(display_list); + return; } // If we got here, then we need a new layer. @@ -1696,40 +1670,33 @@ impl BlockFlowDisplayListBuilding for BlockFlow { ScrollPolicy::Scrollable }; - let stacking_context_creation_mode = if outer_display_list_for_overflow_scroll.is_some() { - StackingContextCreationMode::InnerScrollWrapper - } else { - StackingContextCreationMode::Normal - }; - - let layer_id = if outer_display_list_for_overflow_scroll.is_some() { - self.layer_id_for_overflow_scroll() - } else { - self.layer_id() - }; - let stacking_context = self.fragment.create_stacking_context( - &self.base, - display_list, - layout_context, - StackingContextLayerNecessity::Always(layer_id, scroll_policy), - stacking_context_creation_mode); - - let outermost_stacking_context = match outer_display_list_for_overflow_scroll { - Some(mut outer_display_list_for_overflow_scroll) => { - outer_display_list_for_overflow_scroll.children.push_back(stacking_context); - + let stacking_context = match outer_display_list_for_overflow_scroll { + Some(mut outer_display_list) => { + outer_display_list.children.push_back(self.fragment.create_stacking_context( + &self.base, + display_list, + layout_context, + scroll_policy, + StackingContextCreationMode::InnerScrollWrapper)); self.fragment.create_stacking_context( &self.base, - outer_display_list_for_overflow_scroll, + outer_display_list, layout_context, - StackingContextLayerNecessity::Always(self.layer_id(), scroll_policy), + scroll_policy, StackingContextCreationMode::OuterScrollWrapper) } - None => stacking_context, + None => { + self.fragment.create_stacking_context( + &self.base, + display_list, + layout_context, + scroll_policy, + StackingContextCreationMode::Normal) + } }; self.base.display_list_building_result = - DisplayListBuildingResult::StackingContext(outermost_stacking_context) + DisplayListBuildingResult::StackingContext(stacking_context) } fn build_display_list_for_floating_block(&mut self, @@ -1744,12 +1711,11 @@ impl BlockFlowDisplayListBuilding for BlockFlow { self.base.display_list_building_result = if self.fragment.establishes_stacking_context() { DisplayListBuildingResult::StackingContext( - self.fragment.create_stacking_context( - &self.base, - display_list, - layout_context, - StackingContextLayerNecessity::IfCanvasOrIframe(self.layer_id()), - StackingContextCreationMode::Normal)) + self.fragment.create_stacking_context(&self.base, + display_list, + layout_context, + ScrollPolicy::Scrollable, + StackingContextCreationMode::Normal)) } else { DisplayListBuildingResult::Normal(display_list) } @@ -1852,8 +1818,7 @@ impl InlineFlowDisplayListBuilding for InlineFlow { &self.base, display_list, layout_context, - StackingContextLayerNecessity::Always(self.layer_id(), - ScrollPolicy::Scrollable), + ScrollPolicy::Scrollable, StackingContextCreationMode::Normal)) } else { DisplayListBuildingResult::Normal(display_list) diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 13cf107227e..63fec117a8c 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -23,6 +23,7 @@ use inline::{InlineMetrics, LAST_FRAGMENT_OF_ELEMENT}; use ipc_channel::ipc::IpcSender; use layout_debug; use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, specified}; +use msg::compositor_msg::{LayerId, LayerType}; use msg::constellation_msg::{PipelineId, SubpageId}; use net_traits::image::base::Image; use net_traits::image_cache_task::UsePlaceholder; @@ -2424,6 +2425,19 @@ impl Fragment { } } } + + pub fn layer_id(&self) -> LayerId { + let layer_type = match self.pseudo { + PseudoElementType::Normal => LayerType::FragmentBody, + PseudoElementType::Before(_) => LayerType::BeforePseudoContent, + PseudoElementType::After(_) => LayerType::AfterPseudoContent + }; + LayerId::new_of_type(layer_type, self.node.id() as usize) + } + + pub fn layer_id_for_overflow_scroll(&self) -> LayerId { + LayerId::new_of_type(LayerType::OverflowScroll, self.node.id() as usize) + } } impl fmt::Debug for Fragment { diff --git a/components/script/dom/htmlbuttonelement.rs b/components/script/dom/htmlbuttonelement.rs index 7023a8ffdfe..8406fa2f895 100644 --- a/components/script/dom/htmlbuttonelement.rs +++ b/components/script/dom/htmlbuttonelement.rs @@ -191,11 +191,7 @@ impl VirtualMethods for HTMLButtonElement { } } -impl<'a> FormControl<'a> for &'a HTMLButtonElement { - fn to_element(self) -> &'a Element { - ElementCast::from_ref(self) - } -} +impl FormControl for HTMLButtonElement {} impl<'a> Activatable for &'a HTMLButtonElement { fn as_element<'b>(&'b self) -> &'b Element { diff --git a/components/script/dom/htmlfieldsetelement.rs b/components/script/dom/htmlfieldsetelement.rs index a38c6e9a7b2..c4c2f5a86f9 100644 --- a/components/script/dom/htmlfieldsetelement.rs +++ b/components/script/dom/htmlfieldsetelement.rs @@ -5,7 +5,7 @@ use dom::attr::Attr; use dom::bindings::codegen::Bindings::HTMLFieldSetElementBinding; use dom::bindings::codegen::Bindings::HTMLFieldSetElementBinding::HTMLFieldSetElementMethods; -use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, HTMLLegendElementDerived}; +use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLLegendElementDerived}; use dom::bindings::codegen::InheritTypes::{HTMLFieldSetElementDerived, NodeCast}; use dom::bindings::js::{Root, RootedReference}; use dom::document::Document; @@ -157,8 +157,4 @@ impl VirtualMethods for HTMLFieldSetElement { } } -impl<'a> FormControl<'a> for &'a HTMLFieldSetElement { - fn to_element(self) -> &'a Element { - ElementCast::from_ref(self) - } -} +impl FormControl for HTMLFieldSetElement {} diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index b16b2ec5609..632b084c293 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -15,9 +15,11 @@ use dom::bindings::codegen::InheritTypes::HTMLElementCast; use dom::bindings::codegen::InheritTypes::HTMLFormElementCast; use dom::bindings::codegen::InheritTypes::HTMLFormElementDerived; use dom::bindings::codegen::InheritTypes::HTMLInputElementCast; +use dom::bindings::codegen::InheritTypes::{ElementBase, ElementCast}; use dom::bindings::codegen::InheritTypes::{HTMLTextAreaElementCast, NodeCast}; use dom::bindings::global::GlobalRef; use dom::bindings::js::{Root}; +use dom::bindings::utils::Reflectable; use dom::document::Document; use dom::element::{Element, ElementTypeId}; use dom::event::{Event, EventBubbles, EventCancelable}; @@ -515,10 +517,10 @@ impl<'a> FormSubmitter<'a> { } } -pub trait FormControl<'a> : Copy + Sized { +pub trait FormControl: ElementBase + Reflectable { // FIXME: This is wrong (https://github.com/servo/servo/issues/3553) // but we need html5ever to do it correctly - fn form_owner(self) -> Option<Root<HTMLFormElement>> { + fn form_owner(&self) -> Option<Root<HTMLFormElement>> { // https://html.spec.whatwg.org/multipage/#reset-the-form-owner let elem = self.to_element(); let owner = elem.get_string_attribute(&atom!("form")); @@ -544,12 +546,12 @@ pub trait FormControl<'a> : Copy + Sized { None } - fn get_form_attribute<InputFn, OwnerFn>(self, + fn get_form_attribute<InputFn, OwnerFn>(&self, attr: &Atom, input: InputFn, owner: OwnerFn) -> DOMString - where InputFn: Fn(Self) -> DOMString, + where InputFn: Fn(&Self) -> DOMString, OwnerFn: Fn(&HTMLFormElement) -> DOMString { if self.to_element().has_attribute(attr) { @@ -559,7 +561,9 @@ pub trait FormControl<'a> : Copy + Sized { } } - fn to_element(self) -> &'a Element; + fn to_element(&self) -> &Element { + ElementCast::from_ref(self) + } } impl VirtualMethods for HTMLFormElement { diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index a07529ebbec..1ae235ea316 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -633,11 +633,7 @@ impl VirtualMethods for HTMLInputElement { } } -impl<'a> FormControl<'a> for &'a HTMLInputElement { - fn to_element(self) -> &'a Element { - ElementCast::from_ref(self) - } -} +impl FormControl for HTMLInputElement {} impl Activatable for HTMLInputElement { fn as_element<'b>(&'b self) -> &'b Element { diff --git a/components/script/dom/htmllabelelement.rs b/components/script/dom/htmllabelelement.rs index ec3f1fa7865..624d0e3f722 100644 --- a/components/script/dom/htmllabelelement.rs +++ b/components/script/dom/htmllabelelement.rs @@ -4,11 +4,10 @@ use dom::bindings::codegen::Bindings::HTMLLabelElementBinding; use dom::bindings::codegen::Bindings::HTMLLabelElementBinding::HTMLLabelElementMethods; -use dom::bindings::codegen::InheritTypes::ElementCast; use dom::bindings::codegen::InheritTypes::HTMLLabelElementDerived; use dom::bindings::js::Root; use dom::document::Document; -use dom::element::{Element, ElementTypeId}; +use dom::element::ElementTypeId; use dom::eventtarget::{EventTarget, EventTargetTypeId}; use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; use dom::htmlformelement::{FormControl, HTMLFormElement}; @@ -54,8 +53,4 @@ impl HTMLLabelElementMethods for HTMLLabelElement { } } -impl<'a> FormControl<'a> for &'a HTMLLabelElement { - fn to_element(self) -> &'a Element { - ElementCast::from_ref(self) - } -} +impl FormControl for HTMLLabelElement {} diff --git a/components/script/dom/htmlobjectelement.rs b/components/script/dom/htmlobjectelement.rs index e197f1d60c4..fb6c7a39860 100644 --- a/components/script/dom/htmlobjectelement.rs +++ b/components/script/dom/htmlobjectelement.rs @@ -10,7 +10,7 @@ use dom::bindings::codegen::InheritTypes::HTMLObjectElementDerived; use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast}; use dom::bindings::js::Root; use dom::document::Document; -use dom::element::{AttributeMutation, Element, ElementTypeId}; +use dom::element::{AttributeMutation, ElementTypeId}; use dom::eventtarget::{EventTarget, EventTargetTypeId}; use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; use dom::htmlformelement::{FormControl, HTMLFormElement}; @@ -119,8 +119,4 @@ impl VirtualMethods for HTMLObjectElement { } } -impl<'a> FormControl<'a> for &'a HTMLObjectElement { - fn to_element(self) -> &'a Element { - ElementCast::from_ref(self) - } -} +impl FormControl for HTMLObjectElement {} diff --git a/components/script/dom/htmloutputelement.rs b/components/script/dom/htmloutputelement.rs index 781ba2f9e83..c0e98571358 100644 --- a/components/script/dom/htmloutputelement.rs +++ b/components/script/dom/htmloutputelement.rs @@ -4,11 +4,10 @@ use dom::bindings::codegen::Bindings::HTMLOutputElementBinding; use dom::bindings::codegen::Bindings::HTMLOutputElementBinding::HTMLOutputElementMethods; -use dom::bindings::codegen::InheritTypes::ElementCast; use dom::bindings::codegen::InheritTypes::HTMLOutputElementDerived; use dom::bindings::js::Root; use dom::document::Document; -use dom::element::{Element, ElementTypeId}; +use dom::element::ElementTypeId; use dom::eventtarget::{EventTarget, EventTargetTypeId}; use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; use dom::htmlformelement::{FormControl, HTMLFormElement}; @@ -61,8 +60,4 @@ impl HTMLOutputElementMethods for HTMLOutputElement { } } -impl<'a> FormControl<'a> for &'a HTMLOutputElement { - fn to_element(self) -> &'a Element { - ElementCast::from_ref(self) - } -} +impl FormControl for HTMLOutputElement {} diff --git a/components/script/dom/htmlselectelement.rs b/components/script/dom/htmlselectelement.rs index 48aea7422ee..8c6b73c564b 100644 --- a/components/script/dom/htmlselectelement.rs +++ b/components/script/dom/htmlselectelement.rs @@ -5,13 +5,13 @@ use dom::attr::{Attr, AttrValue}; use dom::bindings::codegen::Bindings::HTMLSelectElementBinding; use dom::bindings::codegen::Bindings::HTMLSelectElementBinding::HTMLSelectElementMethods; -use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, NodeCast}; +use dom::bindings::codegen::InheritTypes::{HTMLElementCast, NodeCast}; use dom::bindings::codegen::InheritTypes::{HTMLFieldSetElementDerived, HTMLSelectElementDerived}; use dom::bindings::codegen::UnionTypes::HTMLElementOrLong; use dom::bindings::codegen::UnionTypes::HTMLOptionElementOrHTMLOptGroupElement; use dom::bindings::js::Root; use dom::document::Document; -use dom::element::{AttributeMutation, Element, ElementTypeId}; +use dom::element::{AttributeMutation, ElementTypeId}; use dom::eventtarget::{EventTarget, EventTargetTypeId}; use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; use dom::htmlformelement::{FormControl, HTMLFormElement}; @@ -161,8 +161,4 @@ impl VirtualMethods for HTMLSelectElement { } } -impl<'a> FormControl<'a> for &'a HTMLSelectElement { - fn to_element(self) -> &'a Element { - ElementCast::from_ref(self) - } -} +impl FormControl for HTMLSelectElement {} diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index 9c20b4ad2b2..c2231b070b7 100644 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -15,7 +15,7 @@ use dom::bindings::global::GlobalRef; use dom::bindings::js::{LayoutJS, Root}; use dom::bindings::refcounted::Trusted; use dom::document::Document; -use dom::element::{AttributeMutation, Element, ElementTypeId}; +use dom::element::{AttributeMutation, ElementTypeId}; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::eventtarget::{EventTarget, EventTargetTypeId}; use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; @@ -363,11 +363,7 @@ impl VirtualMethods for HTMLTextAreaElement { } } -impl<'a> FormControl<'a> for &'a HTMLTextAreaElement { - fn to_element(self) -> &'a Element { - ElementCast::from_ref(self) - } -} +impl FormControl for HTMLTextAreaElement {} pub struct ChangeEventRunnable { element: Trusted<HTMLTextAreaElement>, diff --git a/components/util/str.rs b/components/util/str.rs index 78a444be094..e2759e936d6 100644 --- a/components/util/str.rs +++ b/components/util/str.rs @@ -329,8 +329,8 @@ pub unsafe fn c_str_to_string(s: *const c_char) -> String { pub fn str_join<I, T>(strs: I, join: &str) -> String where I: IntoIterator<Item=T>, T: AsRef<str>, { - strs.into_iter().fold(String::new(), |mut acc, s| { - if !acc.is_empty() { acc.push_str(join); } + strs.into_iter().enumerate().fold(String::new(), |mut acc, (i, s)| { + if i > 0 { acc.push_str(join); } acc.push_str(s.as_ref()); acc }) diff --git a/python/servo/testing_commands.py b/python/servo/testing_commands.py index a1f0899b7c3..e4c36236bd0 100644 --- a/python/servo/testing_commands.py +++ b/python/servo/testing_commands.py @@ -10,6 +10,7 @@ from __future__ import print_function, unicode_literals import argparse +import re import sys import os import os.path as path @@ -90,7 +91,9 @@ class MachCommands(CommandBase): ("css", {"kwargs": {"release": release}, "paths": [path.abspath(path.join("tests", "wpt", "css-tests"))], "include_arg": "include"}), - ("unit", {}), + ("unit", {"kwargs": {}, + "paths": [path.abspath(path.join("tests", "unit"))], + "include_arg": "test_name"}) ]) suites_by_prefix = {path: k for k, v in suites.iteritems() if "paths" in v for path in v["paths"]} @@ -138,7 +141,7 @@ class MachCommands(CommandBase): category='testing') @CommandArgument('--package', '-p', default=None, help="Specific package to test") @CommandArgument('test_name', nargs=argparse.REMAINDER, - help="Only run tests that match this pattern") + help="Only run tests that match this pattern or file path") def test_unit(self, test_name=None, package=None): if test_name is None: test_name = [] @@ -146,13 +149,35 @@ class MachCommands(CommandBase): self.ensure_bootstrapped() if package: - packages = [package] + packages = {package} else: - packages = os.listdir(path.join(self.context.topdir, "tests", "unit")) + packages = set() + + test_patterns = [] + for test in test_name: + # add package if 'tests/unit/<package>' + match = re.search("tests/unit/(\\w+)/?$", test) + if match: + packages.add(match.group(1)) + # add package & test if '<package>/<test>', 'tests/unit/<package>/<test>.rs', or similar + elif re.search("\\w/\\w", test): + tokens = test.split("/") + packages.add(tokens[-2]) + test_prefix = tokens[-1] + if test_prefix.endswith(".rs"): + test_prefix = test_prefix[:-3] + test_prefix += "::" + test_patterns.append(test_prefix) + # add test as-is otherwise + else: + test_patterns.append(test) + + if not packages: + packages = set(os.listdir(path.join(self.context.topdir, "tests", "unit"))) for crate in packages: result = subprocess.call( - ["cargo", "test", "-p", "%s_tests" % crate] + test_name, + ["cargo", "test", "-p", "%s_tests" % crate] + test_patterns, env=self.build_env(), cwd=self.servo_crate()) if result != 0: return result diff --git a/tests/unit/util/str.rs b/tests/unit/util/str.rs index 63f8fbd8881..c03d8c8086c 100644 --- a/tests/unit/util/str.rs +++ b/tests/unit/util/str.rs @@ -2,7 +2,7 @@ * 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 util::str::split_html_space_chars; +use util::str::{split_html_space_chars, str_join}; #[test] @@ -10,3 +10,27 @@ pub fn split_html_space_chars_whitespace() { assert!(split_html_space_chars("").collect::<Vec<_>>().is_empty()); assert!(split_html_space_chars("\u{0020}\u{0009}\u{000a}\u{000c}\u{000d}").collect::<Vec<_>>().is_empty()); } + +#[test] +pub fn test_str_join_empty() { + let slice = [] as [&str; 0]; + let actual = str_join(&slice, "-"); + let expected = ""; + assert_eq!(actual, expected); +} + +#[test] +pub fn test_str_join_one() { + let slice = ["alpha"]; + let actual = str_join(&slice, "-"); + let expected = "alpha"; + assert_eq!(actual, expected); +} + +#[test] +pub fn test_str_join_many() { + let slice = ["", "alpha", "", "beta", "gamma", ""]; + let actual = str_join(&slice, "-"); + let expected = "-alpha--beta-gamma-"; + assert_eq!(actual, expected); +} |