mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
Make media queries work with resize and page zoom.
This commit is contained in:
parent
e483a189a3
commit
11cf538ff4
5 changed files with 134 additions and 86 deletions
|
@ -25,6 +25,7 @@ use encoding::all::UTF_8;
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
|
use geom::scale_factor::ScaleFactor;
|
||||||
use gfx::display_list::{ContentStackingLevel, DisplayItem, DisplayList};
|
use gfx::display_list::{ContentStackingLevel, DisplayItem, DisplayList};
|
||||||
use gfx::display_list::{OpaqueNode};
|
use gfx::display_list::{OpaqueNode};
|
||||||
use gfx::render_task::{RenderInitMsg, RenderChan, RenderLayer};
|
use gfx::render_task::{RenderInitMsg, RenderChan, RenderLayer};
|
||||||
|
@ -93,10 +94,6 @@ pub struct LayoutTaskData {
|
||||||
/// This can be used to easily check for invalid stale data.
|
/// This can be used to easily check for invalid stale data.
|
||||||
pub generation: uint,
|
pub generation: uint,
|
||||||
|
|
||||||
/// True if a style sheet was added since the last reflow. Currently, this causes all nodes to
|
|
||||||
/// be dirtied at the next reflow.
|
|
||||||
pub stylesheet_dirty: bool,
|
|
||||||
|
|
||||||
/// A queued response for the union of the content boxes of a node.
|
/// A queued response for the union of the content boxes of a node.
|
||||||
pub content_box_response: Rect<Au>,
|
pub content_box_response: Rect<Au>,
|
||||||
|
|
||||||
|
@ -147,10 +144,6 @@ pub struct LayoutTask {
|
||||||
///
|
///
|
||||||
/// All the other elements of this struct are read-only.
|
/// All the other elements of this struct are read-only.
|
||||||
pub rw_data: Arc<Mutex<LayoutTaskData>>,
|
pub rw_data: Arc<Mutex<LayoutTaskData>>,
|
||||||
|
|
||||||
/// The media queries device state.
|
|
||||||
/// TODO: Handle updating this when window size changes etc.
|
|
||||||
pub device: Device,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LayoutImageResponder {
|
struct LayoutImageResponder {
|
||||||
|
@ -259,7 +252,7 @@ impl LayoutTask {
|
||||||
let local_image_cache =
|
let local_image_cache =
|
||||||
Arc::new(Mutex::new(LocalImageCache::new(image_cache_task.clone())));
|
Arc::new(Mutex::new(LocalImageCache::new(image_cache_task.clone())));
|
||||||
let screen_size = Size2D(Au(0), Au(0));
|
let screen_size = Size2D(Au(0), Au(0));
|
||||||
let device = Device::new(Screen, opts::get().initial_window_size.as_f32());
|
let device = Device::new(Screen, opts::get().initial_window_size.as_f32() * ScaleFactor(1.0));
|
||||||
let parallel_traversal = if opts::get().layout_threads != 1 {
|
let parallel_traversal = if opts::get().layout_threads != 1 {
|
||||||
Some(WorkQueue::new("LayoutWorker", task_state::Layout,
|
Some(WorkQueue::new("LayoutWorker", task_state::Layout,
|
||||||
opts::get().layout_threads, ptr::null()))
|
opts::get().layout_threads, ptr::null()))
|
||||||
|
@ -280,17 +273,15 @@ impl LayoutTask {
|
||||||
image_cache_task: image_cache_task.clone(),
|
image_cache_task: image_cache_task.clone(),
|
||||||
font_cache_task: font_cache_task,
|
font_cache_task: font_cache_task,
|
||||||
first_reflow: Cell::new(true),
|
first_reflow: Cell::new(true),
|
||||||
device: device,
|
|
||||||
rw_data: Arc::new(Mutex::new(
|
rw_data: Arc::new(Mutex::new(
|
||||||
LayoutTaskData {
|
LayoutTaskData {
|
||||||
local_image_cache: local_image_cache,
|
local_image_cache: local_image_cache,
|
||||||
screen_size: screen_size,
|
screen_size: screen_size,
|
||||||
display_list: None,
|
display_list: None,
|
||||||
stylist: box Stylist::new(&device),
|
stylist: box Stylist::new(device),
|
||||||
parallel_traversal: parallel_traversal,
|
parallel_traversal: parallel_traversal,
|
||||||
dirty: Rect::zero(),
|
dirty: Rect::zero(),
|
||||||
generation: 0,
|
generation: 0,
|
||||||
stylesheet_dirty: false,
|
|
||||||
content_box_response: Rect::zero(),
|
content_box_response: Rect::zero(),
|
||||||
content_boxes_response: Vec::new(),
|
content_boxes_response: Vec::new(),
|
||||||
})),
|
})),
|
||||||
|
@ -491,7 +482,8 @@ impl LayoutTask {
|
||||||
let sheet = Stylesheet::from_bytes_iter(iter,
|
let sheet = Stylesheet::from_bytes_iter(iter,
|
||||||
final_url,
|
final_url,
|
||||||
protocol_encoding_label,
|
protocol_encoding_label,
|
||||||
Some(environment_encoding));
|
Some(environment_encoding),
|
||||||
|
AuthorOrigin);
|
||||||
self.handle_add_stylesheet(sheet, possibly_locked_rw_data);
|
self.handle_add_stylesheet(sheet, possibly_locked_rw_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,12 +493,11 @@ impl LayoutTask {
|
||||||
&mut Option<MutexGuard<'a, LayoutTaskData>>) {
|
&mut Option<MutexGuard<'a, LayoutTaskData>>) {
|
||||||
// Find all font-face rules and notify the font cache of them.
|
// Find all font-face rules and notify the font cache of them.
|
||||||
// GWTODO: Need to handle unloading web fonts (when we handle unloading stylesheets!)
|
// GWTODO: Need to handle unloading web fonts (when we handle unloading stylesheets!)
|
||||||
iter_font_face_rules(&sheet, &self.device, |family, src| {
|
let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
|
||||||
|
iter_font_face_rules(&sheet, &rw_data.stylist.device, |family, src| {
|
||||||
self.font_cache_task.add_web_font(family.to_string(), (*src).clone());
|
self.font_cache_task.add_web_font(family.to_string(), (*src).clone());
|
||||||
});
|
});
|
||||||
let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
|
rw_data.stylist.add_stylesheet(sheet);
|
||||||
rw_data.stylist.add_stylesheet(sheet, AuthorOrigin, &self.device);
|
|
||||||
rw_data.stylesheet_dirty = true;
|
|
||||||
LayoutTask::return_rw_data(possibly_locked_rw_data, rw_data);
|
LayoutTask::return_rw_data(possibly_locked_rw_data, rw_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -757,12 +748,17 @@ impl LayoutTask {
|
||||||
&data.url);
|
&data.url);
|
||||||
|
|
||||||
// Handle conditions where the entire flow tree is invalid.
|
// Handle conditions where the entire flow tree is invalid.
|
||||||
let needs_dirtying = rw_data.stylesheet_dirty;
|
let screen_size_changed = current_screen_size != old_screen_size;
|
||||||
|
|
||||||
let mut needs_reflow = current_screen_size != old_screen_size;
|
if screen_size_changed {
|
||||||
|
let device = Device::new(Screen, data.window_size.initial_viewport);
|
||||||
|
rw_data.stylist.set_device(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
let needs_dirtying = rw_data.stylist.update();
|
||||||
|
|
||||||
// If the entire flow tree is invalid, then it will be reflowed anyhow.
|
// If the entire flow tree is invalid, then it will be reflowed anyhow.
|
||||||
needs_reflow &= !needs_dirtying;
|
let needs_reflow = screen_size_changed && !needs_dirtying;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if needs_dirtying {
|
if needs_dirtying {
|
||||||
|
@ -775,8 +771,6 @@ impl LayoutTask {
|
||||||
|mut flow| LayoutTask::reflow_all_nodes(flow.deref_mut()));
|
|mut flow| LayoutTask::reflow_all_nodes(flow.deref_mut()));
|
||||||
}
|
}
|
||||||
|
|
||||||
rw_data.stylesheet_dirty = false;
|
|
||||||
|
|
||||||
let mut layout_root = profile(time::LayoutStyleRecalcCategory,
|
let mut layout_root = profile(time::LayoutStyleRecalcCategory,
|
||||||
Some((&data.url,
|
Some((&data.url,
|
||||||
data.iframe,
|
data.iframe,
|
||||||
|
|
|
@ -15,7 +15,7 @@ use dom::node::{Node, NodeHelpers, ElementNodeTypeId, window_from_node};
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
use layout_interface::{AddStylesheetMsg, LayoutChan};
|
use layout_interface::{AddStylesheetMsg, LayoutChan};
|
||||||
use servo_util::str::DOMString;
|
use servo_util::str::DOMString;
|
||||||
use style::Stylesheet;
|
use style::{AuthorOrigin, Stylesheet};
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct HTMLStyleElement {
|
pub struct HTMLStyleElement {
|
||||||
|
@ -55,7 +55,7 @@ impl<'a> StyleElementHelpers for JSRef<'a, HTMLStyleElement> {
|
||||||
let url = win.page().get_url();
|
let url = win.page().get_url();
|
||||||
|
|
||||||
let data = node.GetTextContent().expect("Element.textContent must be a string");
|
let data = node.GetTextContent().expect("Element.textContent must be a string");
|
||||||
let sheet = Stylesheet::from_str(data.as_slice(), url);
|
let sheet = Stylesheet::from_str(data.as_slice(), url, AuthorOrigin);
|
||||||
let LayoutChan(ref layout_chan) = win.page().layout_chan;
|
let LayoutChan(ref layout_chan) = win.page().layout_chan;
|
||||||
layout_chan.send(AddStylesheetMsg(sheet));
|
layout_chan.send(AddStylesheetMsg(sheet));
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use namespaces::NamespaceMap;
|
||||||
use parsing_utils::{BufferedIter, ParserIter};
|
use parsing_utils::{BufferedIter, ParserIter};
|
||||||
use properties::common_types::*;
|
use properties::common_types::*;
|
||||||
use properties::longhands;
|
use properties::longhands;
|
||||||
use servo_util::geometry::ScreenPx;
|
use servo_util::geometry::ViewportPx;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub struct MediaRule {
|
pub struct MediaRule {
|
||||||
|
@ -83,11 +83,11 @@ pub enum MediaType {
|
||||||
|
|
||||||
pub struct Device {
|
pub struct Device {
|
||||||
pub media_type: MediaType,
|
pub media_type: MediaType,
|
||||||
pub viewport_size: TypedSize2D<ScreenPx, f32>,
|
pub viewport_size: TypedSize2D<ViewportPx, f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device {
|
impl Device {
|
||||||
pub fn new(media_type: MediaType, viewport_size: TypedSize2D<ScreenPx, f32>) -> Device {
|
pub fn new(media_type: MediaType, viewport_size: TypedSize2D<ViewportPx, f32>) -> Device {
|
||||||
Device {
|
Device {
|
||||||
media_type: media_type,
|
media_type: media_type,
|
||||||
viewport_size: viewport_size,
|
viewport_size: viewport_size,
|
||||||
|
|
|
@ -24,7 +24,7 @@ use node::{TElement, TElementAttributes, TNode};
|
||||||
use properties::{PropertyDeclaration, PropertyDeclarationBlock, SpecifiedValue, WidthDeclaration};
|
use properties::{PropertyDeclaration, PropertyDeclarationBlock, SpecifiedValue, WidthDeclaration};
|
||||||
use properties::{specified};
|
use properties::{specified};
|
||||||
use selectors::*;
|
use selectors::*;
|
||||||
use stylesheets::{Stylesheet, iter_stylesheet_style_rules};
|
use stylesheets::{Stylesheet, iter_stylesheet_media_rules, iter_stylesheet_style_rules};
|
||||||
|
|
||||||
pub enum StylesheetOrigin {
|
pub enum StylesheetOrigin {
|
||||||
UserAgentOrigin,
|
UserAgentOrigin,
|
||||||
|
@ -264,6 +264,18 @@ impl SelectorMap {
|
||||||
pub static RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE: uint = 4096;
|
pub static RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE: uint = 4096;
|
||||||
|
|
||||||
pub struct Stylist {
|
pub struct Stylist {
|
||||||
|
// List of stylesheets (including all media rules)
|
||||||
|
stylesheets: Vec<Stylesheet>,
|
||||||
|
|
||||||
|
// Device that the stylist is currently evaluating against.
|
||||||
|
pub device: Device,
|
||||||
|
|
||||||
|
// If true, a stylesheet has been added or the device has
|
||||||
|
// changed, and the stylist needs to be updated.
|
||||||
|
is_dirty: bool,
|
||||||
|
|
||||||
|
// The current selector maps, after evaluating media
|
||||||
|
// rules against the current device.
|
||||||
element_map: PerPseudoElementSelectorMap,
|
element_map: PerPseudoElementSelectorMap,
|
||||||
before_map: PerPseudoElementSelectorMap,
|
before_map: PerPseudoElementSelectorMap,
|
||||||
after_map: PerPseudoElementSelectorMap,
|
after_map: PerPseudoElementSelectorMap,
|
||||||
|
@ -272,8 +284,12 @@ pub struct Stylist {
|
||||||
|
|
||||||
impl Stylist {
|
impl Stylist {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(device: &Device) -> Stylist {
|
pub fn new(device: Device) -> Stylist {
|
||||||
let mut stylist = Stylist {
|
let mut stylist = Stylist {
|
||||||
|
stylesheets: vec!(),
|
||||||
|
device: device,
|
||||||
|
is_dirty: true,
|
||||||
|
|
||||||
element_map: PerPseudoElementSelectorMap::new(),
|
element_map: PerPseudoElementSelectorMap::new(),
|
||||||
before_map: PerPseudoElementSelectorMap::new(),
|
before_map: PerPseudoElementSelectorMap::new(),
|
||||||
after_map: PerPseudoElementSelectorMap::new(),
|
after_map: PerPseudoElementSelectorMap::new(),
|
||||||
|
@ -288,63 +304,96 @@ impl Stylist {
|
||||||
read_resource_file([filename]).unwrap().as_slice(),
|
read_resource_file([filename]).unwrap().as_slice(),
|
||||||
Url::parse(format!("chrome:///{}", filename).as_slice()).unwrap(),
|
Url::parse(format!("chrome:///{}", filename).as_slice()).unwrap(),
|
||||||
None,
|
None,
|
||||||
None);
|
None,
|
||||||
stylist.add_stylesheet(ua_stylesheet, UserAgentOrigin, device);
|
UserAgentOrigin);
|
||||||
|
stylist.add_stylesheet(ua_stylesheet);
|
||||||
}
|
}
|
||||||
stylist
|
stylist
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_stylesheet(&mut self, stylesheet: Stylesheet, origin: StylesheetOrigin,
|
pub fn update(&mut self) -> bool {
|
||||||
device: &Device) {
|
if self.is_dirty {
|
||||||
let (mut element_map, mut before_map, mut after_map) = match origin {
|
self.element_map = PerPseudoElementSelectorMap::new();
|
||||||
UserAgentOrigin => (
|
self.before_map = PerPseudoElementSelectorMap::new();
|
||||||
&mut self.element_map.user_agent,
|
self.after_map = PerPseudoElementSelectorMap::new();
|
||||||
&mut self.before_map.user_agent,
|
self.rules_source_order = 0;
|
||||||
&mut self.after_map.user_agent,
|
|
||||||
),
|
|
||||||
AuthorOrigin => (
|
|
||||||
&mut self.element_map.author,
|
|
||||||
&mut self.before_map.author,
|
|
||||||
&mut self.after_map.author,
|
|
||||||
),
|
|
||||||
UserOrigin => (
|
|
||||||
&mut self.element_map.user,
|
|
||||||
&mut self.before_map.user,
|
|
||||||
&mut self.after_map.user,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
let mut rules_source_order = self.rules_source_order;
|
|
||||||
|
|
||||||
// Take apart the StyleRule into individual Rules and insert
|
for stylesheet in self.stylesheets.iter() {
|
||||||
// them into the SelectorMap of that priority.
|
let (mut element_map, mut before_map, mut after_map) = match stylesheet.origin {
|
||||||
macro_rules! append(
|
UserAgentOrigin => (
|
||||||
($style_rule: ident, $priority: ident) => {
|
&mut self.element_map.user_agent,
|
||||||
if $style_rule.declarations.$priority.len() > 0 {
|
&mut self.before_map.user_agent,
|
||||||
for selector in $style_rule.selectors.iter() {
|
&mut self.after_map.user_agent,
|
||||||
let map = match selector.pseudo_element {
|
),
|
||||||
None => &mut element_map,
|
AuthorOrigin => (
|
||||||
Some(Before) => &mut before_map,
|
&mut self.element_map.author,
|
||||||
Some(After) => &mut after_map,
|
&mut self.before_map.author,
|
||||||
};
|
&mut self.after_map.author,
|
||||||
map.$priority.insert(Rule {
|
),
|
||||||
selector: selector.compound_selectors.clone(),
|
UserOrigin => (
|
||||||
declarations: DeclarationBlock {
|
&mut self.element_map.user,
|
||||||
specificity: selector.specificity,
|
&mut self.before_map.user,
|
||||||
declarations: $style_rule.declarations.$priority.clone(),
|
&mut self.after_map.user,
|
||||||
source_order: rules_source_order,
|
),
|
||||||
},
|
};
|
||||||
});
|
let mut rules_source_order = self.rules_source_order;
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
);
|
|
||||||
|
|
||||||
iter_stylesheet_style_rules(&stylesheet, device, |style_rule| {
|
// Take apart the StyleRule into individual Rules and insert
|
||||||
append!(style_rule, normal);
|
// them into the SelectorMap of that priority.
|
||||||
append!(style_rule, important);
|
macro_rules! append(
|
||||||
rules_source_order += 1;
|
($style_rule: ident, $priority: ident) => {
|
||||||
|
if $style_rule.declarations.$priority.len() > 0 {
|
||||||
|
for selector in $style_rule.selectors.iter() {
|
||||||
|
let map = match selector.pseudo_element {
|
||||||
|
None => &mut element_map,
|
||||||
|
Some(Before) => &mut before_map,
|
||||||
|
Some(After) => &mut after_map,
|
||||||
|
};
|
||||||
|
map.$priority.insert(Rule {
|
||||||
|
selector: selector.compound_selectors.clone(),
|
||||||
|
declarations: DeclarationBlock {
|
||||||
|
specificity: selector.specificity,
|
||||||
|
declarations: $style_rule.declarations.$priority.clone(),
|
||||||
|
source_order: rules_source_order,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
);
|
||||||
|
|
||||||
|
iter_stylesheet_style_rules(stylesheet, &self.device, |style_rule| {
|
||||||
|
append!(style_rule, normal);
|
||||||
|
append!(style_rule, important);
|
||||||
|
rules_source_order += 1;
|
||||||
|
});
|
||||||
|
self.rules_source_order = rules_source_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.is_dirty = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_device(&mut self, device: Device) {
|
||||||
|
let is_dirty = self.stylesheets.iter().any(|stylesheet| {
|
||||||
|
let mut stylesheet_dirty = false;
|
||||||
|
iter_stylesheet_media_rules(stylesheet, |rule| {
|
||||||
|
stylesheet_dirty |= rule.media_queries.evaluate(&self.device) !=
|
||||||
|
rule.media_queries.evaluate(&device);
|
||||||
|
});
|
||||||
|
stylesheet_dirty
|
||||||
});
|
});
|
||||||
self.rules_source_order = rules_source_order;
|
|
||||||
|
self.device = device;
|
||||||
|
self.is_dirty |= is_dirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_stylesheet(&mut self, stylesheet: Stylesheet) {
|
||||||
|
self.stylesheets.push(stylesheet);
|
||||||
|
self.is_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the applicable CSS declarations for the given element. This corresponds to
|
/// Returns the applicable CSS declarations for the given element. This corresponds to
|
||||||
|
@ -364,6 +413,7 @@ impl Stylist {
|
||||||
where E: TElement<'a> + TElementAttributes,
|
where E: TElement<'a> + TElementAttributes,
|
||||||
N: TNode<'a,E>,
|
N: TNode<'a,E>,
|
||||||
V: VecLike<DeclarationBlock> {
|
V: VecLike<DeclarationBlock> {
|
||||||
|
assert!(!self.is_dirty);
|
||||||
assert!(element.is_element());
|
assert!(element.is_element());
|
||||||
assert!(style_attribute.is_none() || pseudo_element.is_none(),
|
assert!(style_attribute.is_none() || pseudo_element.is_none(),
|
||||||
"Style attributes do not apply to pseudo-elements");
|
"Style attributes do not apply to pseudo-elements");
|
||||||
|
|
|
@ -17,12 +17,14 @@ use namespaces::{NamespaceMap, parse_namespace_rule};
|
||||||
use media_queries::{Device, MediaRule, parse_media_rule};
|
use media_queries::{Device, MediaRule, parse_media_rule};
|
||||||
use media_queries;
|
use media_queries;
|
||||||
use font_face::{FontFaceRule, Source, parse_font_face_rule, iter_font_face_rules_inner};
|
use font_face::{FontFaceRule, Source, parse_font_face_rule, iter_font_face_rules_inner};
|
||||||
|
use selector_matching::StylesheetOrigin;
|
||||||
|
|
||||||
|
|
||||||
pub struct Stylesheet {
|
pub struct Stylesheet {
|
||||||
/// List of rules in the order they were found (important for
|
/// List of rules in the order they were found (important for
|
||||||
/// cascading order)
|
/// cascading order)
|
||||||
rules: Vec<CSSRule>,
|
rules: Vec<CSSRule>,
|
||||||
|
pub origin: StylesheetOrigin,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,25 +44,25 @@ pub struct StyleRule {
|
||||||
impl Stylesheet {
|
impl Stylesheet {
|
||||||
pub fn from_bytes_iter<I: Iterator<Vec<u8>>>(
|
pub fn from_bytes_iter<I: Iterator<Vec<u8>>>(
|
||||||
mut input: I, base_url: Url, protocol_encoding_label: Option<&str>,
|
mut input: I, base_url: Url, protocol_encoding_label: Option<&str>,
|
||||||
environment_encoding: Option<EncodingRef>) -> Stylesheet {
|
environment_encoding: Option<EncodingRef>, origin: StylesheetOrigin) -> Stylesheet {
|
||||||
let mut bytes = vec!();
|
let mut bytes = vec!();
|
||||||
// TODO: incremental decoding and tokinization/parsing
|
// TODO: incremental decoding and tokinization/parsing
|
||||||
for chunk in input {
|
for chunk in input {
|
||||||
bytes.push_all(chunk.as_slice())
|
bytes.push_all(chunk.as_slice())
|
||||||
}
|
}
|
||||||
Stylesheet::from_bytes(bytes.as_slice(), base_url, protocol_encoding_label, environment_encoding)
|
Stylesheet::from_bytes(bytes.as_slice(), base_url, protocol_encoding_label, environment_encoding, origin)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_bytes(
|
pub fn from_bytes(
|
||||||
bytes: &[u8], base_url: Url, protocol_encoding_label: Option<&str>,
|
bytes: &[u8], base_url: Url, protocol_encoding_label: Option<&str>,
|
||||||
environment_encoding: Option<EncodingRef>) -> Stylesheet {
|
environment_encoding: Option<EncodingRef>, origin: StylesheetOrigin) -> Stylesheet {
|
||||||
// TODO: bytes.as_slice could be bytes.container_as_bytes()
|
// TODO: bytes.as_slice could be bytes.container_as_bytes()
|
||||||
let (string, _) = decode_stylesheet_bytes(
|
let (string, _) = decode_stylesheet_bytes(
|
||||||
bytes.as_slice(), protocol_encoding_label, environment_encoding);
|
bytes.as_slice(), protocol_encoding_label, environment_encoding);
|
||||||
Stylesheet::from_str(string.as_slice(), base_url)
|
Stylesheet::from_str(string.as_slice(), base_url, origin)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_str(css: &str, base_url: Url) -> Stylesheet {
|
pub fn from_str(css: &str, base_url: Url, origin: StylesheetOrigin) -> Stylesheet {
|
||||||
static STATE_CHARSET: uint = 1;
|
static STATE_CHARSET: uint = 1;
|
||||||
static STATE_IMPORTS: uint = 2;
|
static STATE_IMPORTS: uint = 2;
|
||||||
static STATE_NAMESPACES: uint = 3;
|
static STATE_NAMESPACES: uint = 3;
|
||||||
|
@ -119,7 +121,10 @@ impl Stylesheet {
|
||||||
}
|
}
|
||||||
state = next_state;
|
state = next_state;
|
||||||
}
|
}
|
||||||
Stylesheet{ rules: rules }
|
Stylesheet {
|
||||||
|
rules: rules,
|
||||||
|
origin: origin,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +170,6 @@ pub fn iter_style_rules<'a>(rules: &[CSSRule], device: &media_queries::Device,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub fn iter_stylesheet_media_rules(stylesheet: &Stylesheet, callback: |&MediaRule|) {
|
pub fn iter_stylesheet_media_rules(stylesheet: &Stylesheet, callback: |&MediaRule|) {
|
||||||
for rule in stylesheet.rules.iter() {
|
for rule in stylesheet.rules.iter() {
|
||||||
match *rule {
|
match *rule {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue