aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/compositing/compositor.rs12
-rw-r--r--components/compositing/compositor_thread.rs2
-rw-r--r--components/compositing/windowing.rs4
-rw-r--r--components/constellation/constellation.rs16
-rw-r--r--components/layout/Cargo.toml2
-rw-r--r--components/layout/display_list_builder.rs59
-rw-r--r--components/layout/traversal.rs2
-rw-r--r--components/script/Cargo.toml2
-rw-r--r--components/script/dom/bindings/str.rs11
-rw-r--r--components/script/dom/bindings/trace.rs2
-rw-r--r--components/script/dom/document.rs9
-rw-r--r--components/script/dom/element.rs53
-rw-r--r--components/script/dom/htmlimageelement.rs104
-rw-r--r--components/script/dom/keyboardevent.rs42
-rw-r--r--components/script/dom/webidls/CSSStyleDeclaration.webidl3
-rw-r--r--components/script/layout_wrapper.rs90
-rw-r--r--components/script/script_thread.rs4
-rw-r--r--components/script/task_source/dom_manipulation.rs6
-rw-r--r--components/script/textinput.rs68
-rw-r--r--components/script_layout_interface/Cargo.toml2
-rw-r--r--components/script_layout_interface/wrapper_traits.rs4
-rw-r--r--components/script_traits/lib.rs4
-rw-r--r--components/script_traits/script_msg.rs2
-rw-r--r--components/servo/Cargo.lock16
-rw-r--r--components/style/Cargo.toml4
-rw-r--r--components/style/dom.rs4
-rw-r--r--components/style/keyframes.rs18
-rw-r--r--components/style/matching.rs64
-rw-r--r--components/style/properties/helpers.mako.rs3
-rw-r--r--components/style/properties/helpers/animated_properties.mako.rs6
-rw-r--r--components/style/properties/longhand/box.mako.rs12
-rw-r--r--components/style/properties/longhand/position.mako.rs5
-rw-r--r--components/style/properties/properties.mako.rs3
-rw-r--r--components/style/properties/shorthand/position.mako.rs88
-rw-r--r--components/style/restyle_hints.rs117
-rw-r--r--components/style/selector_impl.rs3
-rw-r--r--components/style/selector_matching.rs34
-rw-r--r--components/style/stylesheets.rs3
38 files changed, 532 insertions, 351 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs
index 270a6b656d0..8041fd7f1df 100644
--- a/components/compositing/compositor.rs
+++ b/components/compositing/compositor.rs
@@ -701,9 +701,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.composition_request = CompositionRequest::CompositeNow(reason)
}
- (Msg::KeyEvent(key, state, modified), ShutdownState::NotShuttingDown) => {
+ (Msg::KeyEvent(ch, key, state, modified), ShutdownState::NotShuttingDown) => {
if state == KeyState::Pressed {
- self.window.handle_key(key, modified);
+ self.window.handle_key(ch, key, modified);
}
}
@@ -1348,8 +1348,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.on_touchpad_pressure_event(cursor, pressure, stage);
}
- WindowEvent::KeyEvent(key, state, modifiers) => {
- self.on_key_event(key, state, modifiers);
+ WindowEvent::KeyEvent(ch, key, state, modifiers) => {
+ self.on_key_event(ch, key, state, modifiers);
}
WindowEvent::Quit => {
@@ -1880,8 +1880,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
}
- fn on_key_event(&self, key: Key, state: KeyState, modifiers: KeyModifiers) {
- let msg = ConstellationMsg::KeyEvent(key, state, modifiers);
+ fn on_key_event(&self, ch: Option<char>, key: Key, state: KeyState, modifiers: KeyModifiers) {
+ let msg = ConstellationMsg::KeyEvent(ch, key, state, modifiers);
if let Err(e) = self.constellation_chan.send(msg) {
warn!("Sending key event to constellation failed ({}).", e);
}
diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs
index 24b9caba0a7..49d0692e6c8 100644
--- a/components/compositing/compositor_thread.rs
+++ b/components/compositing/compositor_thread.rs
@@ -151,7 +151,7 @@ pub enum Msg {
/// Composite.
Recomposite(CompositingReason),
/// Sends an unconsumed key event back to the compositor.
- KeyEvent(Key, KeyState, KeyModifiers),
+ KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
/// Script has handled a touch event, and either prevented or allowed default actions.
TouchEventProcessed(EventResult),
/// Changes the cursor.
diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs
index b67803b07c6..2da658a9661 100644
--- a/components/compositing/windowing.rs
+++ b/components/compositing/windowing.rs
@@ -76,7 +76,7 @@ pub enum WindowEvent {
/// Sent when the user quits the application
Quit,
/// Sent when a key input state changes
- KeyEvent(Key, KeyState, KeyModifiers),
+ KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
/// Sent when Ctr+R/Apple+R is called to reload the current page.
Reload,
}
@@ -159,7 +159,7 @@ pub trait WindowMethods {
fn set_cursor(&self, cursor: Cursor);
/// Process a key event.
- fn handle_key(&self, key: Key, mods: KeyModifiers);
+ fn handle_key(&self, ch: Option<char>, key: Key, mods: KeyModifiers);
/// Does this window support a clipboard
fn supports_clipboard(&self) -> bool;
diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs
index 7c3a95dbc54..0920a4a523f 100644
--- a/components/constellation/constellation.rs
+++ b/components/constellation/constellation.rs
@@ -574,9 +574,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
debug!("constellation got get-pipeline-title message");
self.handle_get_pipeline_title_msg(pipeline_id);
}
- FromCompositorMsg::KeyEvent(key, state, modifiers) => {
+ FromCompositorMsg::KeyEvent(ch, key, state, modifiers) => {
debug!("constellation got key event message");
- self.handle_key_msg(key, state, modifiers);
+ self.handle_key_msg(ch, key, state, modifiers);
}
// Load a new page from a typed url
// If there is already a pending page (self.pending_frames), it will not be overridden;
@@ -803,8 +803,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.compositor_proxy.send(ToCompositorMsg::ChangePageTitle(pipeline_id, title))
}
- FromScriptMsg::SendKeyEvent(key, key_state, key_modifiers) => {
- self.compositor_proxy.send(ToCompositorMsg::KeyEvent(key, key_state, key_modifiers))
+ FromScriptMsg::SendKeyEvent(ch, key, key_state, key_modifiers) => {
+ self.compositor_proxy.send(ToCompositorMsg::KeyEvent(ch, key, key_state, key_modifiers))
}
FromScriptMsg::TouchEventProcessed(result) => {
@@ -1396,7 +1396,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
}
- fn handle_key_msg(&mut self, key: Key, state: KeyState, mods: KeyModifiers) {
+ fn handle_key_msg(&mut self, ch: Option<char>, key: Key, state: KeyState, mods: KeyModifiers) {
// Send to the explicitly focused pipeline (if it exists), or the root
// frame's current pipeline. If neither exist, fall back to sending to
// the compositor below.
@@ -1407,7 +1407,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
match pipeline_id {
Some(pipeline_id) => {
- let event = CompositorEvent::KeyEvent(key, state, mods);
+ let event = CompositorEvent::KeyEvent(ch, key, state, mods);
let msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
let result = match self.pipelines.get(&pipeline_id) {
Some(pipeline) => pipeline.script_chan.send(msg),
@@ -1418,7 +1418,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
},
None => {
- let event = ToCompositorMsg::KeyEvent(key, state, mods);
+ let event = ToCompositorMsg::KeyEvent(ch, key, state, mods);
self.compositor_proxy.clone_compositor_proxy().send(event);
}
}
@@ -1629,7 +1629,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
None => return warn!("Pipeline {:?} SendKeys after closure.", pipeline_id),
};
for (key, mods, state) in cmd {
- let event = CompositorEvent::KeyEvent(key, state, mods);
+ let event = CompositorEvent::KeyEvent(None, key, state, mods);
let control_msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
if let Err(e) = script_channel.send(control_msg) {
return self.handle_send_error(pipeline_id, e);
diff --git a/components/layout/Cargo.toml b/components/layout/Cargo.toml
index 188b39e9207..05f9fcda82c 100644
--- a/components/layout/Cargo.toml
+++ b/components/layout/Cargo.toml
@@ -31,7 +31,7 @@ range = {path = "../range"}
rustc-serialize = "0.3"
script_layout_interface = {path = "../script_layout_interface"}
script_traits = {path = "../script_traits"}
-selectors = {version = "0.6", features = ["heap_size"]}
+selectors = {version = "0.7", features = ["heap_size"]}
serde_macros = "0.7.11"
smallvec = "0.1"
string_cache = {version = "0.2.20", features = ["heap_size"]}
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index 173a19196a5..4bc969b2e74 100644
--- a/components/layout/display_list_builder.rs
+++ b/components/layout/display_list_builder.rs
@@ -43,6 +43,7 @@ use std::default::Default;
use std::sync::Arc;
use std::{cmp, f32};
use style::computed_values::filter::Filter;
+use style::computed_values::text_shadow::TextShadow;
use style::computed_values::{_servo_overflow_clip_box as overflow_clip_box};
use style::computed_values::{background_attachment, background_clip, background_origin};
use style::computed_values::{background_repeat, background_size, border_style};
@@ -258,14 +259,12 @@ pub trait FragmentDisplayListBuilding {
/// Creates the text display item for one text fragment. This can be called multiple times for
/// one fragment if there are text shadows.
///
- /// `shadow_blur_radius` will be `Some` if this is a shadow, even if the blur radius is zero.
+ /// `text_shadow` will be `Some` if this is rendering a shadow.
fn build_display_list_for_text_fragment(&self,
state: &mut DisplayListBuildState,
text_fragment: &ScannedTextFragmentInfo,
- text_color: RGBA,
stacking_relative_content_box: &Rect<Au>,
- shadow_blur_radius: Option<Au>,
- offset: &Point2D<Au>,
+ text_shadow: Option<&TextShadow>,
clip: &ClippingRegion);
/// Creates the display item for a text decoration: underline, overline, or line-through.
@@ -1150,32 +1149,19 @@ impl FragmentDisplayListBuilding for Fragment {
// NB: According to CSS-BACKGROUNDS, text shadows render in *reverse* order (front
// to back).
- // TODO(emilio): Allow changing more properties by ::selection
- let text_color = if text_fragment.selected() {
- self.selected_style().get_color().color
- } else {
- self.style().get_color().color
- };
-
for text_shadow in self.style.get_inheritedtext().text_shadow.0.iter().rev() {
- let offset = &Point2D::new(text_shadow.offset_x, text_shadow.offset_y);
- let color = self.style().resolve_color(text_shadow.color);
self.build_display_list_for_text_fragment(state,
&**text_fragment,
- color,
&stacking_relative_content_box,
- Some(text_shadow.blur_radius),
- offset,
+ Some(text_shadow),
clip);
}
// Create the main text display item.
self.build_display_list_for_text_fragment(state,
&**text_fragment,
- text_color,
&stacking_relative_content_box,
None,
- &Point2D::new(Au(0), Au(0)),
clip);
if opts::get().show_debug_fragment_borders {
@@ -1539,11 +1525,22 @@ impl FragmentDisplayListBuilding for Fragment {
fn build_display_list_for_text_fragment(&self,
state: &mut DisplayListBuildState,
text_fragment: &ScannedTextFragmentInfo,
- text_color: RGBA,
stacking_relative_content_box: &Rect<Au>,
- shadow_blur_radius: Option<Au>,
- offset: &Point2D<Au>,
+ text_shadow: Option<&TextShadow>,
clip: &ClippingRegion) {
+ // TODO(emilio): Allow changing more properties by ::selection
+ let text_color = if let Some(shadow) = text_shadow {
+ // If we're painting a shadow, paint the text the same color as the shadow.
+ self.style().resolve_color(shadow.color)
+ } else if text_fragment.selected() {
+ // Otherwise, paint the text with the color as described in its styling.
+ self.selected_style().get_color().color
+ } else {
+ self.style().get_color().color
+ };
+ let offset = text_shadow.map(|s| Point2D::new(s.offset_x, s.offset_y)).unwrap_or_else(Point2D::zero);
+ let shadow_blur_radius = text_shadow.map(|s| s.blur_radius).unwrap_or(Au(0));
+
// Determine the orientation and cursor to use.
let (orientation, cursor) = if self.style.writing_mode.is_vertical() {
if self.style.writing_mode.is_sideways_left() {
@@ -1560,7 +1557,7 @@ impl FragmentDisplayListBuilding for Fragment {
// FIXME(pcwalton): Get the real container size.
let container_size = Size2D::zero();
let metrics = &text_fragment.run.font_metrics;
- let stacking_relative_content_box = stacking_relative_content_box.translate(offset);
+ let stacking_relative_content_box = stacking_relative_content_box.translate(&offset);
let baseline_origin = stacking_relative_content_box.origin +
LogicalPoint::new(self.style.writing_mode,
Au(0),
@@ -1580,19 +1577,17 @@ impl FragmentDisplayListBuilding for Fragment {
text_color: text_color.to_gfx_color(),
orientation: orientation,
baseline_origin: baseline_origin,
- blur_radius: shadow_blur_radius.unwrap_or(Au(0)),
+ blur_radius: shadow_blur_radius,
}));
// Create display items for text decorations.
let mut text_decorations = self.style()
.get_inheritedtext()
._servo_text_decorations_in_effect;
- if shadow_blur_radius.is_some() {
- // If we're painting a shadow, paint the decorations the same color as the shadow.
- text_decorations.underline = text_decorations.underline.map(|_| text_color);
- text_decorations.overline = text_decorations.overline.map(|_| text_color);
- text_decorations.line_through = text_decorations.line_through.map(|_| text_color);
- }
+ // Note that the text decoration colors are always the same as the text color.
+ text_decorations.underline = text_decorations.underline.map(|_| text_color);
+ text_decorations.overline = text_decorations.overline.map(|_| text_color);
+ text_decorations.line_through = text_decorations.line_through.map(|_| text_color);
let stacking_relative_content_box =
LogicalRect::from_physical(self.style.writing_mode,
@@ -1607,7 +1602,7 @@ impl FragmentDisplayListBuilding for Fragment {
underline_color,
&stacking_relative_box,
clip,
- shadow_blur_radius.unwrap_or(Au(0)));
+ shadow_blur_radius);
}
if let Some(ref overline_color) = text_decorations.overline {
@@ -1617,7 +1612,7 @@ impl FragmentDisplayListBuilding for Fragment {
overline_color,
&stacking_relative_box,
clip,
- shadow_blur_radius.unwrap_or(Au(0)));
+ shadow_blur_radius);
}
if let Some(ref line_through_color) = text_decorations.line_through {
@@ -1629,7 +1624,7 @@ impl FragmentDisplayListBuilding for Fragment {
line_through_color,
&stacking_relative_box,
clip,
- shadow_blur_radius.unwrap_or(Au(0)));
+ shadow_blur_radius);
}
}
diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs
index 5db766f68b5..581fee5e03d 100644
--- a/components/layout/traversal.rs
+++ b/components/layout/traversal.rs
@@ -28,7 +28,7 @@ pub struct RecalcStyleAndConstructFlows<'lc> {
impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc>
where N: LayoutNode + TNode<ConcreteComputedValues=ServoComputedValues>,
- N::ConcreteElement: ::selectors::Element<Impl=ServoSelectorImpl>
+ N::ConcreteElement: ::selectors::Element<Impl=ServoSelectorImpl, AttrString=String>
{
type SharedContext = SharedLayoutContext;
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml
index d9bdeac843b..fa2d75c633d 100644
--- a/components/script/Cargo.toml
+++ b/components/script/Cargo.toml
@@ -57,7 +57,7 @@ regex = "0.1.43"
rustc-serialize = "0.3"
script_layout_interface = {path = "../script_layout_interface"}
script_traits = {path = "../script_traits"}
-selectors = {version = "0.6", features = ["heap_size"]}
+selectors = {version = "0.7", features = ["heap_size"]}
serde = "0.7.11"
smallvec = "0.1"
string_cache = {version = "0.2.20", features = ["heap_size", "unstable"]}
diff --git a/components/script/dom/bindings/str.rs b/components/script/dom/bindings/str.rs
index 69565520899..310285a8bcd 100644
--- a/components/script/dom/bindings/str.rs
+++ b/components/script/dom/bindings/str.rs
@@ -5,7 +5,7 @@
//! The `ByteString` struct.
use std::ascii::AsciiExt;
-use std::borrow::ToOwned;
+use std::borrow::{ToOwned, Cow};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops;
@@ -204,6 +204,15 @@ impl<'a> From<&'a str> for DOMString {
}
}
+impl<'a> From<Cow<'a, str>> for DOMString {
+ fn from(contents: Cow<'a, str>) -> DOMString {
+ match contents {
+ Cow::Owned(s) => DOMString::from(s),
+ Cow::Borrowed(s) => DOMString::from(s),
+ }
+ }
+}
+
impl From<DOMString> for Atom {
fn from(contents: DOMString) -> Atom {
Atom::from(contents.0)
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index 7404e96b95d..e2c6e540a3d 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -276,7 +276,7 @@ impl<A: JSTraceable, B: JSTraceable, C: JSTraceable> JSTraceable for (A, B, C) {
}
}
-no_jsmanaged_fields!(bool, f32, f64, String, Url, AtomicBool, AtomicUsize, UrlOrigin, Uuid);
+no_jsmanaged_fields!(bool, f32, f64, String, Url, AtomicBool, AtomicUsize, UrlOrigin, Uuid, char);
no_jsmanaged_fields!(usize, u8, u16, u32, u64);
no_jsmanaged_fields!(isize, i8, i16, i32, i64);
no_jsmanaged_fields!(Sender<T>);
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 2160a3a4556..43a4473689e 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -1044,6 +1044,7 @@ impl Document {
/// The entry point for all key processing for web content
pub fn dispatch_key_event(&self,
+ ch: Option<char>,
key: Key,
state: KeyState,
modifiers: KeyModifiers,
@@ -1070,7 +1071,7 @@ impl Document {
}
.to_owned());
- let props = KeyboardEvent::key_properties(key, modifiers);
+ let props = KeyboardEvent::key_properties(ch, key, modifiers);
let keyevent = KeyboardEvent::new(&self.window,
ev_type,
@@ -1078,8 +1079,9 @@ impl Document {
true,
Some(&self.window),
0,
+ ch,
Some(key),
- DOMString::from(props.key_string),
+ DOMString::from(props.key_string.clone()),
DOMString::from(props.code),
props.location,
is_repeating,
@@ -1103,6 +1105,7 @@ impl Document {
true,
Some(&self.window),
0,
+ ch,
Some(key),
DOMString::from(props.key_string),
DOMString::from(props.code),
@@ -1122,7 +1125,7 @@ impl Document {
}
if !prevented {
- constellation.send(ConstellationMsg::SendKeyEvent(key, state, modifiers)).unwrap();
+ constellation.send(ConstellationMsg::SendKeyEvent(ch, key, state, modifiers)).unwrap();
}
// This behavior is unspecced
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index d9535663d46..e53f7dbb77b 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -2217,6 +2217,34 @@ impl VirtualMethods for Element {
}
}
+impl<'a> ::selectors::MatchAttrGeneric for Root<Element> {
+ fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool
+ where F: Fn(&str) -> bool
+ {
+ use ::selectors::Element;
+ let local_name = {
+ if self.is_html_element_in_html_document() {
+ &attr.lower_name
+ } else {
+ &attr.name
+ }
+ };
+ match attr.namespace {
+ NamespaceConstraint::Specific(ref ns) => {
+ self.get_attribute(ns, local_name)
+ .map_or(false, |attr| {
+ test(&attr.value())
+ })
+ },
+ NamespaceConstraint::Any => {
+ self.attrs.borrow().iter().any(|attr| {
+ attr.local_name() == local_name && test(&attr.value())
+ })
+ }
+ }
+ }
+}
+
impl<'a> ::selectors::Element for Root<Element> {
type Impl = ServoSelectorImpl;
@@ -2317,31 +2345,6 @@ impl<'a> ::selectors::Element for Root<Element> {
}
}
- fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool
- where F: Fn(&str) -> bool
- {
- let local_name = {
- if self.is_html_element_in_html_document() {
- &attr.lower_name
- } else {
- &attr.name
- }
- };
- match attr.namespace {
- NamespaceConstraint::Specific(ref ns) => {
- self.get_attribute(ns, local_name)
- .map_or(false, |attr| {
- test(&attr.value())
- })
- },
- NamespaceConstraint::Any => {
- self.attrs.borrow().iter().any(|attr| {
- attr.local_name() == local_name && test(&attr.value())
- })
- }
- }
- }
-
fn is_html_element_in_html_document(&self) -> bool {
self.html_element_in_html_document()
}
diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs
index 06a5bf93abf..2b61a800a1a 100644
--- a/components/script/dom/htmlimageelement.rs
+++ b/components/script/dom/htmlimageelement.rs
@@ -31,6 +31,8 @@ use script_thread::Runnable;
use std::sync::Arc;
use string_cache::Atom;
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
+use task_source::TaskSource;
+use task_source::dom_manipulation::DOMManipulationTask;
use url::Url;
#[derive(JSTraceable, HeapSizeOf)]
@@ -44,7 +46,8 @@ enum State {
#[derive(JSTraceable, HeapSizeOf)]
struct ImageRequest {
state: State,
- url: Option<Url>,
+ parsed_url: Option<Url>,
+ source_url: Option<DOMString>,
image: Option<Arc<Image>>,
metadata: Option<ImageMetadata>,
}
@@ -56,8 +59,8 @@ pub struct HTMLImageElement {
}
impl HTMLImageElement {
- pub fn get_url(&self) -> Option<Url>{
- self.current_request.borrow().url.clone()
+ pub fn get_url(&self) -> Option<Url> {
+ self.current_request.borrow().parsed_url.clone()
}
}
@@ -118,33 +121,70 @@ impl HTMLImageElement {
let image_cache = window.image_cache_thread();
match value {
None => {
- self.current_request.borrow_mut().url = None;
+ self.current_request.borrow_mut().parsed_url = None;
+ self.current_request.borrow_mut().source_url = None;
self.current_request.borrow_mut().image = None;
}
Some((src, base_url)) => {
let img_url = base_url.join(&src);
- // FIXME: handle URL parse errors more gracefully.
- let img_url = img_url.unwrap();
- self.current_request.borrow_mut().url = Some(img_url.clone());
-
- let trusted_node = Trusted::new(self);
- let (responder_sender, responder_receiver) = ipc::channel().unwrap();
- let script_chan = window.networking_task_source();
- let wrapper = window.get_runnable_wrapper();
- ROUTER.add_route(responder_receiver.to_opaque(), box move |message| {
- // Return the image via a message to the script thread, which marks the element
- // as dirty and triggers a reflow.
- let image_response = message.to().unwrap();
- let runnable = ImageResponseHandlerRunnable::new(
- trusted_node.clone(), image_response);
- let runnable = wrapper.wrap_runnable(runnable);
- let _ = script_chan.send(CommonScriptMsg::RunnableMsg(
- UpdateReplacedElement, runnable));
- });
-
- image_cache.request_image_and_metadata(img_url,
- window.image_cache_chan(),
- Some(ImageResponder::new(responder_sender)));
+ if let Ok(img_url) = img_url {
+ self.current_request.borrow_mut().parsed_url = Some(img_url.clone());
+ self.current_request.borrow_mut().source_url = Some(src);
+
+ let trusted_node = Trusted::new(self);
+ let (responder_sender, responder_receiver) = ipc::channel().unwrap();
+ let script_chan = window.networking_task_source();
+ let wrapper = window.get_runnable_wrapper();
+ ROUTER.add_route(responder_receiver.to_opaque(), box move |message| {
+ // Return the image via a message to the script thread, which marks the element
+ // as dirty and triggers a reflow.
+ let image_response = message.to().unwrap();
+ let runnable = ImageResponseHandlerRunnable::new(
+ trusted_node.clone(), image_response);
+ let runnable = wrapper.wrap_runnable(runnable);
+ let _ = script_chan.send(CommonScriptMsg::RunnableMsg(
+ UpdateReplacedElement, runnable));
+ });
+
+ image_cache.request_image_and_metadata(img_url,
+ window.image_cache_chan(),
+ Some(ImageResponder::new(responder_sender)));
+ } else {
+ // https://html.spec.whatwg.org/multipage/#update-the-image-data
+ // Step 11 (error substeps)
+ debug!("Failed to parse URL {} with base {}", src, base_url);
+ let mut req = self.current_request.borrow_mut();
+
+ // Substeps 1,2
+ req.image = None;
+ req.parsed_url = None;
+ req.state = State::Broken;
+ // todo: set pending request to null
+ // (pending requests aren't being used yet)
+
+
+ struct ImgParseErrorRunnable {
+ img: Trusted<HTMLImageElement>,
+ src: String,
+ }
+ impl Runnable for ImgParseErrorRunnable {
+ fn handler(self: Box<Self>) {
+ // https://html.spec.whatwg.org/multipage/#update-the-image-data
+ // Step 11, substep 5
+ let img = self.img.root();
+ img.current_request.borrow_mut().source_url = Some(self.src.into());
+ img.upcast::<EventTarget>().fire_simple_event("error");
+ img.upcast::<EventTarget>().fire_simple_event("loadend");
+ }
+ }
+
+ let runnable = Box::new(ImgParseErrorRunnable {
+ img: Trusted::new(self),
+ src: src.into(),
+ });
+ let task = window.dom_manipulation_task_source();
+ let _ = task.queue(DOMManipulationTask::Miscellaneous(runnable));
+ }
}
}
}
@@ -153,13 +193,15 @@ impl HTMLImageElement {
htmlelement: HTMLElement::new_inherited(localName, prefix, document),
current_request: DOMRefCell::new(ImageRequest {
state: State::Unavailable,
- url: None,
+ parsed_url: None,
+ source_url: None,
image: None,
metadata: None
}),
pending_request: DOMRefCell::new(ImageRequest {
state: State::Unavailable,
- url: None,
+ parsed_url: None,
+ source_url: None,
image: None,
metadata: None
}),
@@ -209,7 +251,7 @@ impl LayoutHTMLImageElementHelpers for LayoutJS<HTMLImageElement> {
#[allow(unsafe_code)]
unsafe fn image_url(&self) -> Option<Url> {
- (*self.unsafe_get()).current_request.borrow_for_layout().url.clone()
+ (*self.unsafe_get()).current_request.borrow_for_layout().parsed_url.clone()
}
#[allow(unsafe_code)]
@@ -313,9 +355,9 @@ impl HTMLImageElementMethods for HTMLImageElement {
// https://html.spec.whatwg.org/multipage/#dom-img-currentsrc
fn CurrentSrc(&self) -> DOMString {
- let ref url = self.current_request.borrow().url;
+ let ref url = self.current_request.borrow().source_url;
match *url {
- Some(ref url) => DOMString::from(url.as_str()),
+ Some(ref url) => url.clone(),
None => DOMString::from(""),
}
}
diff --git a/components/script/dom/keyboardevent.rs b/components/script/dom/keyboardevent.rs
index 4cfa1a61011..71b00767a8e 100644
--- a/components/script/dom/keyboardevent.rs
+++ b/components/script/dom/keyboardevent.rs
@@ -17,6 +17,7 @@ use dom::uievent::UIEvent;
use dom::window::Window;
use msg::constellation_msg;
use msg::constellation_msg::{Key, KeyModifiers};
+use std::borrow::Cow;
use std::cell::Cell;
no_jsmanaged_fields!(Key);
@@ -36,6 +37,7 @@ pub struct KeyboardEvent {
is_composing: Cell<bool>,
char_code: Cell<Option<u32>>,
key_code: Cell<u32>,
+ printable: Cell<Option<char>>,
}
impl KeyboardEvent {
@@ -54,6 +56,7 @@ impl KeyboardEvent {
is_composing: Cell::new(false),
char_code: Cell::new(None),
key_code: Cell::new(0),
+ printable: Cell::new(None),
}
}
@@ -69,6 +72,7 @@ impl KeyboardEvent {
cancelable: bool,
view: Option<&Window>,
_detail: i32,
+ ch: Option<char>,
key: Option<Key>,
key_string: DOMString,
code: DOMString,
@@ -91,6 +95,7 @@ impl KeyboardEvent {
ev.shift.set(shiftKey);
ev.meta.set(metaKey);
ev.char_code.set(char_code);
+ ev.printable.set(ch);
ev.key_code.set(key_code);
ev.is_composing.set(isComposing);
ev
@@ -103,7 +108,9 @@ impl KeyboardEvent {
init.parent.parent.parent.bubbles,
init.parent.parent.parent.cancelable,
init.parent.parent.view.r(),
- init.parent.parent.detail, key_from_string(&init.key, init.location),
+ init.parent.parent.detail,
+ None,
+ key_from_string(&init.key, init.location),
init.key.clone(), init.code.clone(), init.location,
init.repeat, init.isComposing, init.parent.ctrlKey,
init.parent.altKey, init.parent.shiftKey, init.parent.metaKey,
@@ -111,13 +118,13 @@ impl KeyboardEvent {
Ok(event)
}
- pub fn key_properties(key: Key, mods: KeyModifiers)
+ pub fn key_properties(ch: Option<char>, key: Key, mods: KeyModifiers)
-> KeyEventProperties {
KeyEventProperties {
- key_string: key_value(key, mods),
+ key_string: key_value(ch, key, mods),
code: code_value(key),
location: key_location(key),
- char_code: key_charcode(key, mods),
+ char_code: ch.map(|ch| ch as u32),
key_code: key_keycode(key),
}
}
@@ -125,6 +132,10 @@ impl KeyboardEvent {
impl KeyboardEvent {
+ pub fn printable(&self) -> Option<char> {
+ self.printable.get()
+ }
+
pub fn get_key(&self) -> Option<Key> {
self.key.get().clone()
}
@@ -147,11 +158,14 @@ impl KeyboardEvent {
}
}
-
// https://w3c.github.io/uievents-key/#key-value-tables
-pub fn key_value(key: Key, mods: KeyModifiers) -> &'static str {
+pub fn key_value(ch: Option<char>, key: Key, mods: KeyModifiers) -> Cow<'static, str> {
+ if let Some(ch) = ch {
+ return Cow::from(format!("{}", ch));
+ }
+
let shift = mods.contains(constellation_msg::SHIFT);
- match key {
+ Cow::from(match key {
Key::Space => " ",
Key::Apostrophe if shift => "\"",
Key::Apostrophe => "'",
@@ -321,7 +335,7 @@ pub fn key_value(key: Key, mods: KeyModifiers) -> &'static str {
Key::Menu => "ContextMenu",
Key::NavigateForward => "BrowserForward",
Key::NavigateBackward => "BrowserBack",
- }
+ })
}
fn key_from_string(key_string: &str, location: u32) -> Option<Key> {
@@ -647,16 +661,6 @@ fn key_location(key: Key) -> u32 {
}
}
-// https://w3c.github.io/uievents/#dom-keyboardevent-charcode
-fn key_charcode(key: Key, mods: KeyModifiers) -> Option<u32> {
- let key_string = key_value(key, mods);
- if key_string.len() == 1 {
- Some(key_string.chars().next().unwrap() as u32)
- } else {
- None
- }
-}
-
// https://w3c.github.io/uievents/#legacy-key-models
fn key_keycode(key: Key) -> u32 {
match key {
@@ -739,7 +743,7 @@ fn key_keycode(key: Key) -> u32 {
#[derive(HeapSizeOf)]
pub struct KeyEventProperties {
- pub key_string: &'static str,
+ pub key_string: Cow<'static, str>,
pub code: &'static str,
pub location: u32,
pub char_code: Option<u32>,
diff --git a/components/script/dom/webidls/CSSStyleDeclaration.webidl b/components/script/dom/webidls/CSSStyleDeclaration.webidl
index 8d587b9760a..02864d39a77 100644
--- a/components/script/dom/webidls/CSSStyleDeclaration.webidl
+++ b/components/script/dom/webidls/CSSStyleDeclaration.webidl
@@ -308,6 +308,9 @@ partial interface CSSStyleDeclaration {
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString transitionDelay;
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString transition-delay;
+ [SetterThrows, TreatNullAs=EmptyString] attribute DOMString flex;
+ [SetterThrows, TreatNullAs=EmptyString] attribute DOMString flexFlow;
+ [SetterThrows, TreatNullAs=EmptyString] attribute DOMString flex-flow;
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString flexDirection;
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString flex-direction;
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString flexWrap;
diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs
index 7085fcae002..ebc2da9c529 100644
--- a/components/script/layout_wrapper.rs
+++ b/components/script/layout_wrapper.rs
@@ -387,17 +387,13 @@ impl<'le> TElement for ServoLayoutElement<'le> {
}
#[inline]
- fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&str> {
- unsafe {
- (*self.element.unsafe_get()).get_attr_val_for_layout(namespace, name)
- }
+ fn has_attr(&self, namespace: &Namespace, attr: &Atom) -> bool {
+ self.get_attr(namespace, attr).is_some()
}
#[inline]
- fn get_attrs(&self, name: &Atom) -> Vec<&str> {
- unsafe {
- (*self.element.unsafe_get()).get_attr_vals_for_layout(name)
- }
+ fn attr_equals(&self, namespace: &Namespace, attr: &Atom, val: &Atom) -> bool {
+ self.get_attr(namespace, attr).map_or(false, |x| x == val)
}
}
@@ -409,12 +405,41 @@ impl<'le> ServoLayoutElement<'le> {
chain: PhantomData,
}
}
+
+ #[inline]
+ fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&str> {
+ unsafe {
+ (*self.element.unsafe_get()).get_attr_val_for_layout(namespace, name)
+ }
+ }
}
fn as_element<'le>(node: LayoutJS<Node>) -> Option<ServoLayoutElement<'le>> {
node.downcast().map(ServoLayoutElement::from_layout_js)
}
+impl<'le> ::selectors::MatchAttrGeneric for ServoLayoutElement<'le> {
+ fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool where F: Fn(&str) -> bool {
+ use ::selectors::Element;
+ let name = if self.is_html_element_in_html_document() {
+ &attr.lower_name
+ } else {
+ &attr.name
+ };
+ match attr.namespace {
+ NamespaceConstraint::Specific(ref ns) => {
+ self.get_attr(ns, name).map_or(false, |attr| test(attr))
+ },
+ NamespaceConstraint::Any => {
+ let attrs = unsafe {
+ (*self.element.unsafe_get()).get_attr_vals_for_layout(name)
+ };
+ attrs.iter().any(|attr| test(*attr))
+ }
+ }
+ }
+}
+
impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
type Impl = ServoSelectorImpl;
@@ -550,22 +575,6 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
}
}
- fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool where F: Fn(&str) -> bool {
- let name = if self.is_html_element_in_html_document() {
- &attr.lower_name
- } else {
- &attr.name
- };
- match attr.namespace {
- NamespaceConstraint::Specific(ref ns) => {
- self.get_attr(ns, name).map_or(false, |attr| test(attr))
- },
- NamespaceConstraint::Any => {
- self.get_attrs(name).iter().any(|attr| test(*attr))
- }
- }
- }
-
fn is_html_element_in_html_document(&self) -> bool {
unsafe {
self.element.html_element_in_html_document_for_layout()
@@ -900,7 +909,23 @@ impl<'le> ThreadSafeLayoutElement for ServoThreadSafeLayoutElement<'le> {
///
/// Note that the element implementation is needed only for selector matching,
/// not for inheritance (styles are inherited appropiately).
-impl <'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
+impl<'le> ::selectors::MatchAttrGeneric for ServoThreadSafeLayoutElement<'le> {
+ fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool
+ where F: Fn(&str) -> bool {
+ match attr.namespace {
+ NamespaceConstraint::Specific(ref ns) => {
+ self.get_attr(ns, &attr.name).map_or(false, |attr| test(attr))
+ },
+ NamespaceConstraint::Any => {
+ unsafe {
+ self.element.get_attr_vals_for_layout(&attr.name).iter()
+ .any(|attr| test(*attr))
+ }
+ }
+ }
+ }
+}
+impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
type Impl = ServoSelectorImpl;
fn parent_element(&self) -> Option<Self> {
@@ -962,21 +987,6 @@ impl <'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
false
}
- fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool
- where F: Fn(&str) -> bool {
- match attr.namespace {
- NamespaceConstraint::Specific(ref ns) => {
- self.get_attr(ns, &attr.name).map_or(false, |attr| test(attr))
- },
- NamespaceConstraint::Any => {
- unsafe {
- self.element.get_attr_vals_for_layout(&attr.name).iter()
- .any(|attr| test(*attr))
- }
- }
- }
- }
-
fn is_empty(&self) -> bool {
warn!("ServoThreadSafeLayoutElement::is_empty called");
false
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 2367ecc0fd9..05689baac39 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -1937,12 +1937,12 @@ impl ScriptThread {
document.r().handle_touchpad_pressure_event(self.js_runtime.rt(), point, pressure, phase);
}
- KeyEvent(key, state, modifiers) => {
+ KeyEvent(ch, key, state, modifiers) => {
let document = match self.root_browsing_context().find(pipeline_id) {
Some(browsing_context) => browsing_context.active_document(),
None => return warn!("Message sent to closed pipeline {}.", pipeline_id),
};
- document.dispatch_key_event(key, state, modifiers, &self.constellation_chan);
+ document.dispatch_key_event(ch, key, state, modifiers, &self.constellation_chan);
}
}
}
diff --git a/components/script/task_source/dom_manipulation.rs b/components/script/task_source/dom_manipulation.rs
index daf212d8c52..fbe864a9005 100644
--- a/components/script/task_source/dom_manipulation.rs
+++ b/components/script/task_source/dom_manipulation.rs
@@ -52,7 +52,8 @@ pub enum DOMManipulationTask {
// https://html.spec.whatwg.org/multipage/#planned-navigation
PlannedNavigation(Box<Runnable + Send>),
// https://html.spec.whatwg.org/multipage/#send-a-storage-notification
- SendStorageNotification(Box<MainThreadRunnable + Send>)
+ SendStorageNotification(Box<MainThreadRunnable + Send>),
+ Miscellaneous(Box<Runnable + Send>),
}
impl DOMManipulationTask {
@@ -72,7 +73,8 @@ impl DOMManipulationTask {
FireToggleEvent(runnable) => runnable.handler(),
MediaTask(runnable) => runnable.handler(),
PlannedNavigation(runnable) => runnable.handler(),
- SendStorageNotification(runnable) => runnable.handler(script_thread)
+ SendStorageNotification(runnable) => runnable.handler(script_thread),
+ Miscellaneous(runnable) => runnable.handler(),
}
}
}
diff --git a/components/script/textinput.rs b/components/script/textinput.rs
index a56bd983f34..871af9637c0 100644
--- a/components/script/textinput.rs
+++ b/components/script/textinput.rs
@@ -6,7 +6,7 @@
use clipboard_provider::ClipboardProvider;
use dom::bindings::str::DOMString;
-use dom::keyboardevent::{KeyboardEvent, key_value};
+use dom::keyboardevent::KeyboardEvent;
use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER};
use msg::constellation_msg::{Key, KeyModifiers};
use std::borrow::ToOwned;
@@ -120,24 +120,6 @@ fn is_control_key(mods: KeyModifiers) -> bool {
mods.contains(CONTROL) && !mods.contains(SUPER | ALT)
}
-fn is_printable_key(key: Key) -> bool {
- match key {
- Key::Space | Key::Apostrophe | Key::Comma | Key::Minus |
- Key::Period | Key::Slash | Key::GraveAccent | Key::Num0 |
- Key::Num1 | Key::Num2 | Key::Num3 | Key::Num4 | Key::Num5 |
- Key::Num6 | Key::Num7 | Key::Num8 | Key::Num9 | Key::Semicolon |
- Key::Equal | Key::A | Key::B | Key::C | Key::D | Key::E | Key::F |
- Key::G | Key::H | Key::I | Key::J | Key::K | Key::L | Key::M | Key::N |
- Key::O | Key::P | Key::Q | Key::R | Key::S | Key::T | Key::U | Key::V |
- Key::W | Key::X | Key::Y | Key::Z | Key::LeftBracket | Key::Backslash |
- Key::RightBracket | Key::Kp0 | Key::Kp1 | Key::Kp2 | Key::Kp3 |
- Key::Kp4 | Key::Kp5 | Key::Kp6 | Key::Kp7 | Key::Kp8 | Key::Kp9 |
- Key::KpDecimal | Key::KpDivide | Key::KpMultiply | Key::KpSubtract |
- Key::KpAdd | Key::KpEqual => true,
- _ => false,
- }
-}
-
/// The length in bytes of the first n characters in a UTF-8 string.
///
/// If the string has fewer than n characters, returns the length of the whole string.
@@ -486,80 +468,80 @@ impl<T: ClipboardProvider> TextInput<T> {
/// Process a given `KeyboardEvent` and return an action for the caller to execute.
pub fn handle_keydown(&mut self, event: &KeyboardEvent) -> KeyReaction {
if let Some(key) = event.get_key() {
- self.handle_keydown_aux(key, event.get_key_modifiers())
+ self.handle_keydown_aux(event.printable(), key, event.get_key_modifiers())
} else {
KeyReaction::Nothing
}
}
- pub fn handle_keydown_aux(&mut self, key: Key, mods: KeyModifiers) -> KeyReaction {
+
+ pub fn handle_keydown_aux(&mut self,
+ printable: Option<char>,
+ key: Key,
+ mods: KeyModifiers) -> KeyReaction {
let maybe_select = if mods.contains(SHIFT) { Selection::Selected } else { Selection::NotSelected };
- match key {
- Key::A if is_control_key(mods) => {
+ match (printable, key) {
+ (Some('a'), _) if is_control_key(mods) => {
self.select_all();
KeyReaction::RedrawSelection
},
- Key::C if is_control_key(mods) => {
+ (Some('c'), _) if is_control_key(mods) => {
if let Some(text) = self.get_selection_text() {
self.clipboard_provider.set_clipboard_contents(text);
}
KeyReaction::DispatchInput
},
- Key::V if is_control_key(mods) => {
+ (Some('v'), _) if is_control_key(mods) => {
let contents = self.clipboard_provider.clipboard_contents();
self.insert_string(contents);
KeyReaction::DispatchInput
},
- _ if is_printable_key(key) => {
- self.insert_string(key_value(key, mods));
- KeyReaction::DispatchInput
- }
- Key::Space => {
- self.insert_char(' ');
+ (Some(c), _) => {
+ self.insert_char(c);
KeyReaction::DispatchInput
}
- Key::Delete => {
+ (None, Key::Delete) => {
self.delete_char(Direction::Forward);
KeyReaction::DispatchInput
}
- Key::Backspace => {
+ (None, Key::Backspace) => {
self.delete_char(Direction::Backward);
KeyReaction::DispatchInput
}
- Key::Left => {
+ (None, Key::Left) => {
self.adjust_horizontal_by_one(Direction::Backward, maybe_select);
KeyReaction::RedrawSelection
}
- Key::Right => {
+ (None, Key::Right) => {
self.adjust_horizontal_by_one(Direction::Forward, maybe_select);
KeyReaction::RedrawSelection
}
- Key::Up => {
+ (None, Key::Up) => {
self.adjust_vertical(-1, maybe_select);
KeyReaction::RedrawSelection
}
- Key::Down => {
+ (None, Key::Down) => {
self.adjust_vertical(1, maybe_select);
KeyReaction::RedrawSelection
}
- Key::Enter | Key::KpEnter => self.handle_return(),
- Key::Home => {
+ (None, Key::Enter) | (None, Key::KpEnter) => self.handle_return(),
+ (None, Key::Home) => {
self.edit_point.index = 0;
KeyReaction::RedrawSelection
}
- Key::End => {
+ (None, Key::End) => {
self.edit_point.index = self.current_line_length();
self.assert_ok_selection();
KeyReaction::RedrawSelection
}
- Key::PageUp => {
+ (None, Key::PageUp) => {
self.adjust_vertical(-28, maybe_select);
KeyReaction::RedrawSelection
}
- Key::PageDown => {
+ (None, Key::PageDown) => {
self.adjust_vertical(28, maybe_select);
KeyReaction::RedrawSelection
}
- Key::Tab => KeyReaction::TriggerDefaultAction,
+ (None, Key::Tab) => KeyReaction::TriggerDefaultAction,
_ => KeyReaction::Nothing,
}
}
diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml
index 51b767c753f..41c1f6e2598 100644
--- a/components/script_layout_interface/Cargo.toml
+++ b/components/script_layout_interface/Cargo.toml
@@ -26,7 +26,7 @@ plugins = {path = "../plugins"}
profile_traits = {path = "../profile_traits"}
range = {path = "../range"}
script_traits = {path = "../script_traits"}
-selectors = {version = "0.6", features = ["heap_size"]}
+selectors = {version = "0.7", features = ["heap_size"]}
string_cache = {version = "0.2.20", features = ["heap_size"]}
style = {path = "../style"}
url = {version = "1.0.0", features = ["heap_size"]}
diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs
index a816321ec28..bdbf31c37c8 100644
--- a/components/script_layout_interface/wrapper_traits.rs
+++ b/components/script_layout_interface/wrapper_traits.rs
@@ -86,7 +86,7 @@ pub trait LayoutNode: TNode {
pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq {
type ConcreteThreadSafeLayoutElement:
ThreadSafeLayoutElement<ConcreteThreadSafeLayoutNode = Self>
- + ::selectors::Element<Impl=ServoSelectorImpl>;
+ + ::selectors::Element<Impl=ServoSelectorImpl, AttrString=String>;
type ChildrenIterator: Iterator<Item = Self> + Sized;
/// Creates a new `ThreadSafeLayoutNode` for the same `LayoutNode`
@@ -351,7 +351,7 @@ pub trait DangerousThreadSafeLayoutNode: ThreadSafeLayoutNode {
}
pub trait ThreadSafeLayoutElement: Clone + Copy + Sized +
- ::selectors::Element<Impl=ServoSelectorImpl> +
+ ::selectors::Element<Impl=ServoSelectorImpl, AttrString=String> +
PresentationalHintsSynthetizer {
type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<ConcreteThreadSafeLayoutElement = Self>;
diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs
index bd82a498d46..5c6064a3d3e 100644
--- a/components/script_traits/lib.rs
+++ b/components/script_traits/lib.rs
@@ -282,7 +282,7 @@ pub enum CompositorEvent {
/// Touchpad pressure event
TouchpadPressureEvent(Point2D<f32>, f32, TouchpadPressurePhase),
/// A key was pressed.
- KeyEvent(Key, KeyState, KeyModifiers),
+ KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
}
/// Touchpad pressure phase for TouchpadPressureEvent.
@@ -586,7 +586,7 @@ pub enum ConstellationMsg {
/// Query the constellation to see if the current compositor output is stable
IsReadyToSaveImage(HashMap<PipelineId, Epoch>),
/// Inform the constellation of a key event.
- KeyEvent(Key, KeyState, KeyModifiers),
+ KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
/// Request to load a page.
LoadUrl(PipelineId, LoadData),
/// Request to navigate a frame.
diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs
index 7fc871eb4cc..0ac5aeae4b4 100644
--- a/components/script_traits/script_msg.rs
+++ b/components/script_traits/script_msg.rs
@@ -103,7 +103,7 @@ pub enum ScriptMsg {
/// https://html.spec.whatwg.org/multipage/#document.title
SetTitle(PipelineId, Option<String>),
/// Send a key event
- SendKeyEvent(Key, KeyState, KeyModifiers),
+ SendKeyEvent(Option<char>, Key, KeyState, KeyModifiers),
/// Get Window Informations size and position
GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
/// Move the window to a point
diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock
index 3424416cead..030f19a5038 100644
--- a/components/servo/Cargo.lock
+++ b/components/servo/Cargo.lock
@@ -146,7 +146,7 @@ dependencies = [
[[package]]
name = "bincode"
-version = "0.5.7"
+version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1061,7 +1061,7 @@ name = "ipc-channel"
version = "0.2.3"
source = "git+https://github.com/servo/ipc-channel#48137d69955f5460da586c552de275ecdc3f4efe"
dependencies = [
- "bincode 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bincode 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1159,7 +1159,7 @@ dependencies = [
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"script_layout_interface 0.0.1",
"script_traits 0.0.1",
- "selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1942,7 +1942,7 @@ dependencies = [
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"script_layout_interface 0.0.1",
"script_traits 0.0.1",
- "selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1978,7 +1978,7 @@ dependencies = [
"profile_traits 0.0.1",
"range 0.0.1",
"script_traits 0.0.1",
- "selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1",
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2026,7 +2026,7 @@ dependencies = [
[[package]]
name = "selectors"
-version = "0.6.0"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2243,7 +2243,7 @@ dependencies = [
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2263,7 +2263,7 @@ dependencies = [
"cssparser 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1",
"style_traits 0.0.1",
diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml
index a90673b9e40..049dd560eeb 100644
--- a/components/style/Cargo.toml
+++ b/components/style/Cargo.toml
@@ -11,7 +11,7 @@ name = "style"
path = "lib.rs"
[features]
-gecko = ["gecko_bindings"]
+gecko = ["gecko_bindings", "selectors/gecko"]
servo = ["serde", "serde/nightly", "serde_macros", "heapsize", "heapsize_plugin",
"style_traits/servo", "app_units/plugins", "euclid/plugins",
"cssparser/heap_size", "cssparser/serde-serialization",
@@ -36,7 +36,7 @@ matches = "0.1"
num-traits = "0.1.32"
rand = "0.3"
rustc-serialize = "0.3"
-selectors = "0.6"
+selectors = "0.7"
serde = {version = "0.7.11", optional = true}
serde_macros = {version = "0.7.11", optional = true}
smallvec = "0.1"
diff --git a/components/style/dom.rs b/components/style/dom.rs
index 11cc5f93a0e..0e94c2c5c1d 100644
--- a/components/style/dom.rs
+++ b/components/style/dom.rs
@@ -207,8 +207,8 @@ pub trait TElement : Sized + Copy + Clone + ElementExt + PresentationalHintsSynt
fn get_state(&self) -> ElementState;
- fn get_attr<'a>(&'a self, namespace: &Namespace, attr: &Atom) -> Option<&'a str>;
- fn get_attrs<'a>(&'a self, attr: &Atom) -> Vec<&'a str>;
+ fn has_attr(&self, namespace: &Namespace, attr: &Atom) -> bool;
+ fn attr_equals(&self, namespace: &Namespace, attr: &Atom, value: &Atom) -> bool;
/// Properly marks nodes as dirty in response to restyle hints.
fn note_restyle_hint(&self, mut hint: RestyleHint) {
diff --git a/components/style/keyframes.rs b/components/style/keyframes.rs
index 7d219758848..82dc4c9200f 100644
--- a/components/style/keyframes.rs
+++ b/components/style/keyframes.rs
@@ -10,7 +10,8 @@ use std::sync::Arc;
/// A number from 1 to 100, indicating the percentage of the animation where
/// this keyframe should run.
-#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, HeapSizeOf)]
+#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframePercentage(pub f32);
impl ::std::cmp::Ord for KeyframePercentage {
@@ -49,7 +50,8 @@ impl KeyframePercentage {
/// A keyframes selector is a list of percentages or from/to symbols, which are
/// converted at parse time to percentages.
-#[derive(Debug, Clone, PartialEq, HeapSizeOf)]
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframeSelector(Vec<KeyframePercentage>);
impl KeyframeSelector {
#[inline]
@@ -64,7 +66,8 @@ impl KeyframeSelector {
}
/// A keyframe.
-#[derive(Debug, Clone, PartialEq, HeapSizeOf)]
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Keyframe {
pub selector: KeyframeSelector,
pub declarations: Arc<Vec<PropertyDeclaration>>,
@@ -95,14 +98,16 @@ impl Keyframe {
/// is, one autogenerated from the current computed values, or a list of
/// declarations to apply.
// TODO: Find a better name for this?
-#[derive(Debug, Clone, PartialEq, HeapSizeOf)]
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum KeyframesStepValue {
Declarations(Arc<Vec<PropertyDeclaration>>),
ComputedValues,
}
/// A single step from a keyframe animation.
-#[derive(Debug, Clone, PartialEq, HeapSizeOf)]
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframesStep {
/// The percentage of the animation duration when this step starts.
pub start_percentage: KeyframePercentage,
@@ -126,7 +131,8 @@ impl KeyframesStep {
/// of keyframes, in order.
///
/// It only takes into account animable properties.
-#[derive(Debug, Clone, PartialEq, HeapSizeOf)]
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframesAnimation {
pub steps: Vec<KeyframesStep>,
/// The properties that change in this animation.
diff --git a/components/style/matching.rs b/components/style/matching.rs
index d3dd3742d3d..5d4fa82b8ce 100644
--- a/components/style/matching.rs
+++ b/components/style/matching.rs
@@ -34,16 +34,13 @@ fn create_common_style_affecting_attributes_from_element<E: TElement>(element: &
for attribute_info in &common_style_affecting_attributes() {
match attribute_info.mode {
CommonStyleAffectingAttributeMode::IsPresent(flag) => {
- if element.get_attr(&ns!(), &attribute_info.atom).is_some() {
+ if element.has_attr(&ns!(), &attribute_info.atom) {
flags.insert(flag)
}
}
- CommonStyleAffectingAttributeMode::IsEqual(target_value, flag) => {
- match element.get_attr(&ns!(), &attribute_info.atom) {
- Some(element_value) if element_value == target_value => {
- flags.insert(flag)
- }
- _ => {}
+ CommonStyleAffectingAttributeMode::IsEqual(ref target_value, flag) => {
+ if element.attr_equals(&ns!(), &attribute_info.atom, target_value) {
+ flags.insert(flag)
}
}
}
@@ -189,8 +186,7 @@ pub struct StyleSharingCandidate<C: ComputedValues> {
pub style: Arc<C>,
pub parent_style: Arc<C>,
pub local_name: Atom,
- // FIXME(pcwalton): Should be a list of atoms instead.
- pub class: Option<String>,
+ pub classes: Vec<Atom>,
pub namespace: Namespace,
pub common_style_affecting_attributes: CommonStyleAffectingAttributes,
pub link: bool,
@@ -201,7 +197,7 @@ impl<C: ComputedValues> PartialEq for StyleSharingCandidate<C> {
arc_ptr_eq(&self.style, &other.style) &&
arc_ptr_eq(&self.parent_style, &other.parent_style) &&
self.local_name == other.local_name &&
- self.class == other.class &&
+ self.classes == other.classes &&
self.link == other.link &&
self.namespace == other.namespace &&
self.common_style_affecting_attributes == other.common_style_affecting_attributes
@@ -246,12 +242,13 @@ impl<C: ComputedValues> StyleSharingCandidate<C> {
return None
}
+ let mut classes = Vec::new();
+ element.each_class(|c| classes.push(c.clone()));
Some(StyleSharingCandidate {
style: style,
parent_style: parent_style,
local_name: element.get_local_name().clone(),
- class: element.get_attr(&ns!(), &atom!("class"))
- .map(|string| string.to_owned()),
+ classes: classes,
link: element.is_link(),
namespace: (*element.get_namespace()).clone(),
common_style_affecting_attributes:
@@ -264,14 +261,19 @@ impl<C: ComputedValues> StyleSharingCandidate<C> {
return false
}
- // FIXME(pcwalton): Use `each_class` here instead of slow string comparison.
- match (&self.class, element.get_attr(&ns!(), &atom!("class"))) {
- (&None, Some(_)) | (&Some(_), None) => return false,
- (&Some(ref this_class), Some(element_class)) if
- element_class != &**this_class => {
- return false
+ let mut num_classes = 0;
+ let mut classes_match = true;
+ element.each_class(|c| {
+ num_classes += 1;
+ // Note that we could do this check more cheaply if we decided to
+ // only consider class lists as equal if the orders match, since
+ // we could then index by num_classes instead of using .contains().
+ if classes_match && !self.classes.contains(c) {
+ classes_match = false;
}
- (&Some(_), Some(_)) | (&None, None) => {}
+ });
+ if !classes_match || num_classes != self.classes.len() {
+ return false;
}
if *element.get_namespace() != self.namespace {
@@ -291,31 +293,25 @@ impl<C: ComputedValues> StyleSharingCandidate<C> {
match attribute_info.mode {
CommonStyleAffectingAttributeMode::IsPresent(flag) => {
if self.common_style_affecting_attributes.contains(flag) !=
- element.get_attr(&ns!(), &attribute_info.atom).is_some() {
+ element.has_attr(&ns!(), &attribute_info.atom) {
return false
}
}
- CommonStyleAffectingAttributeMode::IsEqual(target_value, flag) => {
- match element.get_attr(&ns!(), &attribute_info.atom) {
- Some(ref element_value) if self.common_style_affecting_attributes
- .contains(flag) &&
- *element_value != target_value => {
+ CommonStyleAffectingAttributeMode::IsEqual(ref target_value, flag) => {
+ let contains = self.common_style_affecting_attributes.contains(flag);
+ if element.has_attr(&ns!(), &attribute_info.atom) {
+ if !contains || !element.attr_equals(&ns!(), &attribute_info.atom, target_value) {
return false
}
- Some(_) if !self.common_style_affecting_attributes.contains(flag) => {
- return false
- }
- None if self.common_style_affecting_attributes.contains(flag) => {
- return false
- }
- _ => {}
+ } else if contains {
+ return false
}
}
}
}
for attribute_name in &rare_style_affecting_attributes() {
- if element.get_attr(&ns!(), attribute_name).is_some() {
+ if element.has_attr(&ns!(), attribute_name) {
return false
}
}
@@ -601,7 +597,7 @@ pub trait ElementMatchMethods : TElement
if self.style_attribute().is_some() {
return StyleSharingResult::CannotShare
}
- if self.get_attr(&ns!(), &atom!("id")).is_some() {
+ if self.has_attr(&ns!(), &atom!("id")) {
return StyleSharingResult::CannotShare
}
diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs
index cd85567c856..81dff023605 100644
--- a/components/style/properties/helpers.mako.rs
+++ b/components/style/properties/helpers.mako.rs
@@ -206,7 +206,8 @@
use cssparser::ToCss;
use std::fmt;
- #[derive(Debug, Clone, PartialEq, HeapSizeOf)]
+ #[derive(Debug, Clone, PartialEq)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct T(pub Vec<${to_camel_case(name)}>);
impl ToCss for T {
diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs
index 504a72cf498..404698968b8 100644
--- a/components/style/properties/helpers/animated_properties.mako.rs
+++ b/components/style/properties/helpers/animated_properties.mako.rs
@@ -34,7 +34,8 @@ use values::computed::{CalcLengthOrPercentage, LengthOrPercentage};
// NB: This needs to be here because it needs all the longhands generated
// beforehand.
-#[derive(Copy, Clone, Debug, PartialEq, HeapSizeOf)]
+#[derive(Copy, Clone, Debug, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum TransitionProperty {
All,
% for prop in data.longhands:
@@ -92,7 +93,8 @@ impl ToCss for TransitionProperty {
}
}
-#[derive(Clone, Debug, PartialEq, HeapSizeOf)]
+#[derive(Clone, Debug, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum AnimatedProperty {
% for prop in data.longhands:
% if prop.animatable:
diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs
index d9195d00df2..381ca4df1d9 100644
--- a/components/style/properties/longhand/box.mako.rs
+++ b/components/style/properties/longhand/box.mako.rs
@@ -94,8 +94,7 @@ ${helpers.single_keyword("position", "static absolute relative fixed",
<%helpers:single_keyword_computed name="float"
values="none left right"
animatable="False"
- need_clone="True"
- gecko_ffi_name="mFloats">
+ need_clone="True">
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
@@ -618,7 +617,8 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
pub use string_cache::Atom as SingleComputedValue;
- #[derive(Debug, Clone, PartialEq, HeapSizeOf)]
+ #[derive(Debug, Clone, PartialEq)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct T(pub Vec<Atom>);
impl ToCss for T {
@@ -683,7 +683,8 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
pub use self::AnimationIterationCount as SingleComputedValue;
- #[derive(Debug, Clone, PartialEq, HeapSizeOf)]
+ #[derive(Debug, Clone, PartialEq)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum AnimationIterationCount {
Number(u32),
Infinite,
@@ -698,7 +699,8 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
}
}
- #[derive(Debug, Clone, PartialEq, HeapSizeOf)]
+ #[derive(Debug, Clone, PartialEq)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct T(pub Vec<AnimationIterationCount>);
impl ToCss for T {
diff --git a/components/style/properties/longhand/position.mako.rs b/components/style/properties/longhand/position.mako.rs
index a143dab44c5..3ad07a9c2c3 100644
--- a/components/style/properties/longhand/position.mako.rs
+++ b/components/style/properties/longhand/position.mako.rs
@@ -77,11 +77,14 @@ ${helpers.single_keyword("justify-content", "flex-start flex-end center space-be
products="servo",
animatable=False)}
+// FIXME(heycam): Disable align-items in geckolib since we don't support the Gecko initial value
+// 'normal' yet.
${helpers.single_keyword("align-items", "stretch flex-start flex-end center baseline",
experimental=True,
need_clone=True,
gecko_constant_prefix="NS_STYLE_ALIGN",
- animatable=False)}
+ animatable=False,
+ products="servo")}
${helpers.single_keyword("align-content", "stretch flex-start flex-end center space-between space-around",
experimental=True,
diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs
index d2d07c79a73..9bb65979f4e 100644
--- a/components/style/properties/properties.mako.rs
+++ b/components/style/properties/properties.mako.rs
@@ -129,6 +129,7 @@ pub mod shorthands {
<%include file="/shorthand/margin.mako.rs" />
<%include file="/shorthand/outline.mako.rs" />
<%include file="/shorthand/padding.mako.rs" />
+ <%include file="/shorthand/position.mako.rs" />
<%include file="/shorthand/text.mako.rs" />
}
@@ -1921,6 +1922,7 @@ pub fn cascade<C: ComputedValues>(
}
}
+ % if "align-items" in data.longhands_by_name:
{
use self::style_struct_traits::Position;
use computed_values::align_self::T as align_self;
@@ -1937,6 +1939,7 @@ pub fn cascade<C: ComputedValues>(
style.mutate_position().set_align_self(self_align);
}
}
+ % endif
// The initial value of border-*-width may be changed at computed value time.
% for side in ["top", "right", "bottom", "left"]:
diff --git a/components/style/properties/shorthand/position.mako.rs b/components/style/properties/shorthand/position.mako.rs
new file mode 100644
index 00000000000..4710afd121e
--- /dev/null
+++ b/components/style/properties/shorthand/position.mako.rs
@@ -0,0 +1,88 @@
+/* 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/. */
+
+<%namespace name="helpers" file="/helpers.mako.rs" />
+
+// https://drafts.csswg.org/css-flexbox/#flex-flow-property
+<%helpers:shorthand name="flex-flow" sub_properties="flex-direction flex-wrap"
+ experimental="True">
+ use properties::longhands::{flex_direction, flex_wrap};
+
+ let mut direction = None;
+ let mut wrap = None;
+ loop {
+ if direction.is_none() {
+ if let Ok(value) = input.try(|input| flex_direction::parse(context, input)) {
+ direction = Some(value);
+ continue
+ }
+ }
+ if wrap.is_none() {
+ if let Ok(value) = input.try(|input| flex_wrap::parse(context, input)) {
+ wrap = Some(value);
+ continue
+ }
+ }
+ break
+ }
+
+ if direction.is_none() && wrap.is_none() {
+ return Err(())
+ }
+ Ok(Longhands {
+ flex_direction: direction,
+ flex_wrap: wrap,
+ })
+</%helpers:shorthand>
+
+// https://drafts.csswg.org/css-flexbox/#flex-property
+<%helpers:shorthand name="flex" sub_properties="flex-grow flex-shrink flex-basis"
+ experimental="True">
+ use app_units::Au;
+ use values::specified::{Number, Length, LengthOrPercentageOrAutoOrContent};
+
+ pub fn parse_flexibility(input: &mut Parser)
+ -> Result<(Number, Option<Number>),()> {
+ let grow = try!(Number::parse_non_negative(input));
+ let shrink = input.try(Number::parse_non_negative).ok();
+ Ok((grow, shrink))
+ }
+
+ let mut grow = None;
+ let mut shrink = None;
+ let mut basis = None;
+
+ if input.try(|input| input.expect_ident_matching("none")).is_ok() {
+ return Ok(Longhands {
+ flex_grow: Some(Number(0.0)),
+ flex_shrink: Some(Number(0.0)),
+ flex_basis: Some(LengthOrPercentageOrAutoOrContent::Auto)
+ })
+ }
+ loop {
+ if grow.is_none() {
+ if let Ok((flex_grow, flex_shrink)) = input.try(parse_flexibility) {
+ grow = Some(flex_grow);
+ shrink = flex_shrink;
+ continue
+ }
+ }
+ if basis.is_none() {
+ if let Ok(value) = input.try(LengthOrPercentageOrAutoOrContent::parse) {
+ basis = Some(value);
+ continue
+ }
+ }
+ break
+ }
+
+ if grow.is_none() && basis.is_none() {
+ return Err(())
+ }
+ Ok(Longhands {
+ flex_grow: grow.or(Some(Number(1.0))),
+ flex_shrink: shrink.or(Some(Number(1.0))),
+ flex_basis: basis.or(Some(LengthOrPercentageOrAutoOrContent::Length(Length::Absolute(Au(0)))))
+ })
+</%helpers:shorthand>
diff --git a/components/style/restyle_hints.rs b/components/style/restyle_hints.rs
index c517a6f1a7b..cd9957322e4 100644
--- a/components/style/restyle_hints.rs
+++ b/components/style/restyle_hints.rs
@@ -7,9 +7,9 @@
use attr::{AttrIdentifier, AttrValue};
use element_state::*;
use selector_impl::SelectorImplExt;
-use selectors::Element;
use selectors::matching::matches_compound_selector;
use selectors::parser::{AttrSelector, Combinator, CompoundSelector, SelectorImpl, SimpleSelector};
+use selectors::{Element, MatchAttrGeneric};
use std::clone::Clone;
use std::sync::Arc;
use string_cache::{Atom, BorrowedAtom, BorrowedNamespace, Namespace};
@@ -81,15 +81,21 @@ impl ElementSnapshot {
static EMPTY_SNAPSHOT: ElementSnapshot = ElementSnapshot { state: None, attrs: None };
+// FIXME(bholley): This implementation isn't going to work for geckolib, because
+// it's fundamentally based on get_attr/match_attr, which we don't want to support
+// that configuration due to the overhead of converting between UTF-16 and UTF-8.
+// We'll need to figure something out when we start using restyle hints with
+// geckolib, but in the mean time we can just use the trait parameters to
+// specialize it to the Servo configuration.
struct ElementWrapper<'a, E>
- where E: Element,
+ where E: Element<AttrString=String>,
E::Impl: SelectorImplExt {
element: E,
snapshot: &'a ElementSnapshot,
}
impl<'a, E> ElementWrapper<'a, E>
- where E: Element,
+ where E: Element<AttrString=String>,
E::Impl: SelectorImplExt {
pub fn new(el: E) -> ElementWrapper<'a, E> {
ElementWrapper { element: el, snapshot: &EMPTY_SNAPSHOT }
@@ -100,8 +106,42 @@ impl<'a, E> ElementWrapper<'a, E>
}
}
+#[cfg(not(feature = "gecko"))]
+impl<'a, E> MatchAttrGeneric for ElementWrapper<'a, E>
+ where E: Element<AttrString=String>,
+ E: MatchAttrGeneric,
+ E::Impl: SelectorImplExt {
+ fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool
+ where F: Fn(&str) -> bool {
+ use selectors::parser::NamespaceConstraint;
+ match self.snapshot.attrs {
+ Some(_) => {
+ let html = self.is_html_element_in_html_document();
+ let local_name = if html { &attr.lower_name } else { &attr.name };
+ match attr.namespace {
+ NamespaceConstraint::Specific(ref ns) => self.snapshot.get_attr(ns, local_name),
+ NamespaceConstraint::Any => self.snapshot.get_attr_ignore_ns(local_name),
+ }.map_or(false, |v| test(v))
+ },
+ None => self.element.match_attr(attr, test)
+ }
+ }
+}
+
+#[cfg(feature = "gecko")]
+impl<'a, E> MatchAttrGeneric for ElementWrapper<'a, E>
+ where E: Element<AttrString=String>,
+ E: MatchAttrGeneric,
+ E::Impl: SelectorImplExt {
+ fn match_attr<F>(&self, _: &AttrSelector, _: F) -> bool
+ where F: Fn(&str) -> bool {
+ panic!("Not implemented for Gecko - this system will need to be redesigned");
+ }
+}
+
impl<'a, E> Element for ElementWrapper<'a, E>
- where E: Element,
+ where E: Element<AttrString=String>,
+ E: MatchAttrGeneric,
E::Impl: SelectorImplExt {
type Impl = E::Impl;
@@ -155,27 +195,6 @@ impl<'a, E> Element for ElementWrapper<'a, E>
None => self.element.has_class(name),
}
}
- #[cfg(feature = "gecko")]
- fn match_attr<F>(&self, _: &AttrSelector, _: F) -> bool
- where F: Fn(&str) -> bool {
- panic!("Gecko can't borrow atoms as UTF-8.");
- }
- #[cfg(not(feature = "gecko"))]
- fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool
- where F: Fn(&str) -> bool {
- use selectors::parser::NamespaceConstraint;
- match self.snapshot.attrs {
- Some(_) => {
- let html = self.is_html_element_in_html_document();
- let local_name = if html { &attr.lower_name } else { &attr.name };
- match attr.namespace {
- NamespaceConstraint::Specific(ref ns) => self.snapshot.get_attr(ns, local_name),
- NamespaceConstraint::Any => self.snapshot.get_attr_ignore_ns(local_name),
- }.map_or(false, |v| test(v))
- },
- None => self.element.match_attr(attr, test)
- }
- }
fn is_empty(&self) -> bool {
self.element.is_empty()
}
@@ -208,7 +227,7 @@ fn is_attr_selector<Impl: SelectorImpl>(sel: &SimpleSelector<Impl>) -> bool {
SimpleSelector::AttrExists(_) |
SimpleSelector::AttrEqual(_, _, _) |
SimpleSelector::AttrIncludes(_, _) |
- SimpleSelector::AttrDashMatch(_, _, _) |
+ SimpleSelector::AttrDashMatch(_, _) |
SimpleSelector::AttrPrefixMatch(_, _) |
SimpleSelector::AttrSubstringMatch(_, _) |
SimpleSelector::AttrSuffixMatch(_, _) => true,
@@ -285,28 +304,6 @@ impl<Impl: SelectorImplExt> DependencySet<Impl> {
DependencySet { deps: Vec::new() }
}
- pub fn compute_hint<E>(&self, el: &E, snapshot: &ElementSnapshot, current_state: ElementState)
- -> RestyleHint
- where E: Element<Impl=Impl> + Clone {
- let state_changes = snapshot.state.map_or(ElementState::empty(), |old_state| current_state ^ old_state);
- let attrs_changed = snapshot.attrs.is_some();
- let mut hint = RestyleHint::empty();
- for dep in &self.deps {
- if state_changes.intersects(dep.sensitivities.states) || (attrs_changed && dep.sensitivities.attrs) {
- let old_el: ElementWrapper<E> = ElementWrapper::new_with_snapshot(el.clone(), snapshot);
- let matched_then = matches_compound_selector(&*dep.selector, &old_el, None, &mut false);
- let matches_now = matches_compound_selector(&*dep.selector, el, None, &mut false);
- if matched_then != matches_now {
- hint.insert(combinator_to_restyle_hint(dep.combinator));
- if hint.is_all() {
- break
- }
- }
- }
- }
- hint
- }
-
pub fn note_selector(&mut self, selector: Arc<CompoundSelector<Impl>>) {
let mut cur = selector;
let mut combinator: Option<Combinator> = None;
@@ -340,3 +337,27 @@ impl<Impl: SelectorImplExt> DependencySet<Impl> {
self.deps.clear();
}
}
+
+impl<Impl: SelectorImplExt<AttrString=String>> DependencySet<Impl> {
+ pub fn compute_hint<E>(&self, el: &E, snapshot: &ElementSnapshot, current_state: ElementState)
+ -> RestyleHint
+ where E: Element<Impl=Impl, AttrString=Impl::AttrString> + Clone + MatchAttrGeneric {
+ let state_changes = snapshot.state.map_or(ElementState::empty(), |old_state| current_state ^ old_state);
+ let attrs_changed = snapshot.attrs.is_some();
+ let mut hint = RestyleHint::empty();
+ for dep in &self.deps {
+ if state_changes.intersects(dep.sensitivities.states) || (attrs_changed && dep.sensitivities.attrs) {
+ let old_el: ElementWrapper<E> = ElementWrapper::new_with_snapshot(el.clone(), snapshot);
+ let matched_then = matches_compound_selector(&*dep.selector, &old_el, None, &mut false);
+ let matches_now = matches_compound_selector(&*dep.selector, el, None, &mut false);
+ if matched_then != matches_now {
+ hint.insert(combinator_to_restyle_hint(dep.combinator));
+ if hint.is_all() {
+ break
+ }
+ }
+ }
+ }
+ hint
+ }
+}
diff --git a/components/style/selector_impl.rs b/components/style/selector_impl.rs
index cf95f4a9048..cd47d0dc7f5 100644
--- a/components/style/selector_impl.rs
+++ b/components/style/selector_impl.rs
@@ -181,6 +181,7 @@ impl NonTSPseudoClass {
pub struct ServoSelectorImpl;
impl SelectorImpl for ServoSelectorImpl {
+ type AttrString = String;
type PseudoElement = PseudoElement;
type NonTSPseudoClass = NonTSPseudoClass;
@@ -278,7 +279,7 @@ impl SelectorImplExt for ServoSelectorImpl {
}
}
-impl<E: Element<Impl=ServoSelectorImpl>> ElementExt for E {
+impl<E: Element<Impl=ServoSelectorImpl, AttrString=String>> ElementExt for E {
fn is_link(&self) -> bool {
self.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink)
}
diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs
index 74718d4b69b..b632d783e1e 100644
--- a/components/style/selector_matching.rs
+++ b/components/style/selector_matching.rs
@@ -13,11 +13,11 @@ use parser::ParserContextExtraData;
use properties::{self, PropertyDeclaration, PropertyDeclarationBlock};
use restyle_hints::{ElementSnapshot, RestyleHint, DependencySet};
use selector_impl::{SelectorImplExt, ServoSelectorImpl};
-use selectors::Element;
use selectors::bloom::BloomFilter;
use selectors::matching::DeclarationBlock as GenericDeclarationBlock;
use selectors::matching::{Rule, SelectorMap};
use selectors::parser::SelectorImpl;
+use selectors::{Element, MatchAttrGeneric};
use sink::Push;
use smallvec::VecLike;
use std::collections::HashMap;
@@ -311,7 +311,7 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
pseudo: &Impl::PseudoElement,
parent: &Arc<Impl::ComputedValues>)
-> Option<Arc<Impl::ComputedValues>>
- where E: Element<Impl=Impl> +
+ where E: Element<Impl=Impl, AttrString=Impl::AttrString> +
PresentationalHintsSynthetizer {
debug_assert!(Impl::pseudo_element_cascade_type(pseudo).is_lazy());
if self.pseudos_map.get(pseudo).is_none() {
@@ -336,18 +336,6 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
Some(Arc::new(computed))
}
- pub fn compute_restyle_hint<E>(&self, element: &E,
- snapshot: &ElementSnapshot,
- // NB: We need to pass current_state as an argument because
- // selectors::Element doesn't provide access to ElementState
- // directly, and computing it from the ElementState would be
- // more expensive than getting it directly from the caller.
- current_state: ElementState)
- -> RestyleHint
- where E: Element<Impl=Impl> + Clone {
- self.state_deps.compute_hint(element, snapshot, current_state)
- }
-
pub fn set_device(&mut self, mut device: Device, stylesheets: &[Arc<Stylesheet<Impl>>]) {
let cascaded_rule = stylesheets.iter()
.flat_map(|s| s.effective_rules(&self.device).viewport())
@@ -389,7 +377,8 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
pseudo_element: Option<&Impl::PseudoElement>,
applicable_declarations: &mut V)
-> bool
- where E: Element<Impl=Impl> + PresentationalHintsSynthetizer,
+ where E: Element<Impl=Impl, AttrString=Impl::AttrString> +
+ PresentationalHintsSynthetizer,
V: Push<DeclarationBlock> + VecLike<DeclarationBlock> {
assert!(!self.is_device_dirty);
assert!(style_attribute.is_none() || pseudo_element.is_none(),
@@ -474,6 +463,21 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
}
}
+impl<Impl: SelectorImplExt<AttrString=String>> Stylist<Impl> {
+ pub fn compute_restyle_hint<E>(&self, element: &E,
+ snapshot: &ElementSnapshot,
+ // NB: We need to pass current_state as an argument because
+ // selectors::Element doesn't provide access to ElementState
+ // directly, and computing it from the ElementState would be
+ // more expensive than getting it directly from the caller.
+ current_state: ElementState)
+ -> RestyleHint
+ where E: Element<Impl=Impl, AttrString=String> + Clone + MatchAttrGeneric {
+ self.state_deps.compute_hint(element, snapshot, current_state)
+ }
+}
+
+
/// Map that contains the CSS rules for a given origin.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
struct PerOriginSelectorMap<Impl: SelectorImpl> {
diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs
index 5307f226f4b..d371bf4144f 100644
--- a/components/style/stylesheets.rs
+++ b/components/style/stylesheets.rs
@@ -67,7 +67,8 @@ pub enum CSSRule<Impl: SelectorImpl> {
}
-#[derive(Debug, HeapSizeOf, PartialEq)]
+#[derive(Debug, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframesRule {
pub name: Atom,
pub keyframes: Vec<Keyframe>,