mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
auto merge of #4289 : pcwalton/servo/hacker-news, r=SimonSapin
This patch provides some of the groundwork for column spans greater than 1. It implements the column-span CSS property as well as the corresponding colspan attribute; although the former is not well-specified outside of CSS multi-column layout, INTRINSIC refers to it. Although width is distributed to spanning columns, they do not yet contribute minimum and preferred widths; this will be implemented in a follow-up. The parsing for the legacy bgcolor and border attributes is implemented according to the WHATWG HTML specification. Additionally, this patch cleans up some miscellaneous formatting issues, refactors layout/css somewhat to eliminate needless levels of indirection, and cleans up the handling of table rowgroups. New Hacker News screenshot: http://i.imgur.com/hnl2a7E.png
This commit is contained in:
commit
8e31e5f987
46 changed files with 1610 additions and 572 deletions
|
@ -31,6 +31,9 @@ path = "../net"
|
||||||
[dependencies.util]
|
[dependencies.util]
|
||||||
path = "../util"
|
path = "../util"
|
||||||
|
|
||||||
|
[dependencies.cssparser]
|
||||||
|
git = "https://github.com/servo/rust-cssparser"
|
||||||
|
|
||||||
[dependencies.encoding]
|
[dependencies.encoding]
|
||||||
git = "https://github.com/lifthrasiir/rust-encoding"
|
git = "https://github.com/lifthrasiir/rust-encoding"
|
||||||
|
|
||||||
|
|
|
@ -268,6 +268,9 @@ impl StyleSharingCandidate {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(pcwalton): It's probably faster to iterate over all the element's attributes and
|
||||||
|
// use the {common, rare}-style-affecting-attributes tables as lookup tables.
|
||||||
|
|
||||||
for attribute_info in style::common_style_affecting_attributes().iter() {
|
for attribute_info in style::common_style_affecting_attributes().iter() {
|
||||||
match attribute_info.mode {
|
match attribute_info.mode {
|
||||||
AttrIsPresentMode(flag) => {
|
AttrIsPresentMode(flag) => {
|
||||||
|
@ -295,6 +298,12 @@ impl StyleSharingCandidate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for attribute_name in style::rare_style_affecting_attributes().iter() {
|
||||||
|
if element.get_attr(&ns!(""), attribute_name).is_some() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if element.get_link().is_some() != self.link {
|
if element.get_link().is_some() != self.link {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,27 +2,75 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
// Style retrieval from DOM elements.
|
//! Style retrieval from DOM elements.
|
||||||
|
|
||||||
use css::node_util::NodeUtil;
|
use wrapper::{After, Before, Normal, ThreadSafeLayoutNode};
|
||||||
use wrapper::ThreadSafeLayoutNode;
|
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
use style::ComputedValues;
|
use style::ComputedValues;
|
||||||
use sync::Arc;
|
use sync::Arc;
|
||||||
|
|
||||||
/// Node mixin providing `style` method that returns a `NodeStyle`
|
/// Node mixin providing `style` method that returns a `NodeStyle`
|
||||||
pub trait StyledNode {
|
pub trait StyledNode {
|
||||||
|
/// Returns the style results for the given node. If CSS selector matching has not yet been
|
||||||
|
/// performed, fails.
|
||||||
fn style<'a>(&'a self) -> &'a Arc<ComputedValues>;
|
fn style<'a>(&'a self) -> &'a Arc<ComputedValues>;
|
||||||
|
/// Does this node have a computed style yet?
|
||||||
|
fn has_style(&self) -> bool;
|
||||||
|
/// Removes the style from this node.
|
||||||
fn unstyle(self);
|
fn unstyle(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ln> StyledNode for ThreadSafeLayoutNode<'ln> {
|
impl<'ln> StyledNode for ThreadSafeLayoutNode<'ln> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn style<'a>(&'a self) -> &'a Arc<ComputedValues> {
|
fn style<'a>(&'a self) -> &'a Arc<ComputedValues> {
|
||||||
self.get_css_select_results()
|
unsafe {
|
||||||
|
let layout_data_ref = self.borrow_layout_data();
|
||||||
|
match self.get_pseudo_element_type() {
|
||||||
|
Before(_) => {
|
||||||
|
mem::transmute(layout_data_ref.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.data
|
||||||
|
.before_style
|
||||||
|
.as_ref()
|
||||||
|
.unwrap())
|
||||||
|
}
|
||||||
|
After(_) => {
|
||||||
|
mem::transmute(layout_data_ref.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.data
|
||||||
|
.after_style
|
||||||
|
.as_ref()
|
||||||
|
.unwrap())
|
||||||
|
}
|
||||||
|
Normal => {
|
||||||
|
mem::transmute(layout_data_ref.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.shared_data
|
||||||
|
.style
|
||||||
|
.as_ref()
|
||||||
|
.unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_style(&self) -> bool {
|
||||||
|
let layout_data_ref = self.borrow_layout_data();
|
||||||
|
layout_data_ref.as_ref().unwrap().shared_data.style.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unstyle(self) {
|
fn unstyle(self) {
|
||||||
self.remove_css_select_results()
|
let mut layout_data_ref = self.mutate_layout_data();
|
||||||
|
let layout_data = layout_data_ref.as_mut().expect("no layout data");
|
||||||
|
|
||||||
|
let style =
|
||||||
|
match self.get_pseudo_element_type() {
|
||||||
|
Before(_) => &mut layout_data.data.before_style,
|
||||||
|
After (_) => &mut layout_data.data.after_style,
|
||||||
|
Normal => &mut layout_data.shared_data.style,
|
||||||
|
};
|
||||||
|
|
||||||
|
*style = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
use util::LayoutDataAccess;
|
|
||||||
use wrapper::ThreadSafeLayoutNode;
|
|
||||||
use wrapper::{After, Before, Normal};
|
|
||||||
|
|
||||||
use std::mem;
|
|
||||||
use style::ComputedValues;
|
|
||||||
use sync::Arc;
|
|
||||||
|
|
||||||
pub trait NodeUtil {
|
|
||||||
fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues>;
|
|
||||||
fn have_css_select_results(&self) -> bool;
|
|
||||||
fn remove_css_select_results(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ln> NodeUtil for ThreadSafeLayoutNode<'ln> {
|
|
||||||
/// Returns the style results for the given node. If CSS selector
|
|
||||||
/// matching has not yet been performed, fails.
|
|
||||||
#[inline]
|
|
||||||
fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues> {
|
|
||||||
unsafe {
|
|
||||||
let layout_data_ref = self.borrow_layout_data();
|
|
||||||
match self.get_pseudo_element_type() {
|
|
||||||
Before(_) => {
|
|
||||||
mem::transmute(layout_data_ref.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.data
|
|
||||||
.before_style
|
|
||||||
.as_ref()
|
|
||||||
.unwrap())
|
|
||||||
}
|
|
||||||
After(_) => {
|
|
||||||
mem::transmute(layout_data_ref.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.data
|
|
||||||
.after_style
|
|
||||||
.as_ref()
|
|
||||||
.unwrap())
|
|
||||||
}
|
|
||||||
Normal => {
|
|
||||||
mem::transmute(layout_data_ref.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.shared_data
|
|
||||||
.style
|
|
||||||
.as_ref()
|
|
||||||
.unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Does this node have a computed style yet?
|
|
||||||
fn have_css_select_results(&self) -> bool {
|
|
||||||
let layout_data_ref = self.borrow_layout_data();
|
|
||||||
layout_data_ref.as_ref().unwrap().shared_data.style.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_css_select_results(self) {
|
|
||||||
let mut layout_data_ref = self.mutate_layout_data();
|
|
||||||
let layout_data = layout_data_ref.as_mut().expect("no layout data");
|
|
||||||
|
|
||||||
let style =
|
|
||||||
match self.get_pseudo_element_type() {
|
|
||||||
Before(_) => &mut layout_data.data.before_style,
|
|
||||||
After (_) => &mut layout_data.data.after_style,
|
|
||||||
Normal => &mut layout_data.shared_data.style,
|
|
||||||
};
|
|
||||||
|
|
||||||
*style = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ use script::layout_interface::{ContentBoxesQuery, ContentBoxQuery, ExitNowMsg, G
|
||||||
use script::layout_interface::{HitTestResponse, LayoutChan, LayoutRPC, LoadStylesheetMsg};
|
use script::layout_interface::{HitTestResponse, LayoutChan, LayoutRPC, LoadStylesheetMsg};
|
||||||
use script::layout_interface::{MouseOverResponse, Msg, NoQuery, PrepareToExitMsg};
|
use script::layout_interface::{MouseOverResponse, Msg, NoQuery, PrepareToExitMsg};
|
||||||
use script::layout_interface::{ReapLayoutDataMsg, Reflow, ReflowForDisplay, ReflowMsg};
|
use script::layout_interface::{ReapLayoutDataMsg, Reflow, ReflowForDisplay, ReflowMsg};
|
||||||
use script::layout_interface::{ScriptLayoutChan, TrustedNodeAddress};
|
use script::layout_interface::{ScriptLayoutChan, SetQuirksModeMsg, TrustedNodeAddress};
|
||||||
use script_traits::{SendEventMsg, ReflowEvent, ReflowCompleteMsg, OpaqueScriptLayoutChannel};
|
use script_traits::{SendEventMsg, ReflowEvent, ReflowCompleteMsg, OpaqueScriptLayoutChannel};
|
||||||
use script_traits::{ScriptControlChan, UntrustedNodeAddress};
|
use script_traits::{ScriptControlChan, UntrustedNodeAddress};
|
||||||
use servo_msg::compositor_msg::Scrollable;
|
use servo_msg::compositor_msg::Scrollable;
|
||||||
|
@ -390,6 +390,7 @@ impl LayoutTask {
|
||||||
match request {
|
match request {
|
||||||
AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet, possibly_locked_rw_data),
|
AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet, possibly_locked_rw_data),
|
||||||
LoadStylesheetMsg(url) => self.handle_load_stylesheet(url, possibly_locked_rw_data),
|
LoadStylesheetMsg(url) => self.handle_load_stylesheet(url, possibly_locked_rw_data),
|
||||||
|
SetQuirksModeMsg => self.handle_set_quirks_mode(possibly_locked_rw_data),
|
||||||
GetRPCMsg(response_chan) => {
|
GetRPCMsg(response_chan) => {
|
||||||
response_chan.send(box LayoutRPCImpl(self.rw_data.clone()) as
|
response_chan.send(box LayoutRPCImpl(self.rw_data.clone()) as
|
||||||
Box<LayoutRPC + Send>);
|
Box<LayoutRPC + Send>);
|
||||||
|
@ -500,6 +501,15 @@ impl LayoutTask {
|
||||||
LayoutTask::return_rw_data(possibly_locked_rw_data, rw_data);
|
LayoutTask::return_rw_data(possibly_locked_rw_data, rw_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets quirks mode for the document, causing the quirks mode stylesheet to be loaded.
|
||||||
|
fn handle_set_quirks_mode<'a>(&'a self,
|
||||||
|
possibly_locked_rw_data:
|
||||||
|
&mut Option<MutexGuard<'a, LayoutTaskData>>) {
|
||||||
|
let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
|
||||||
|
rw_data.stylist.add_quirks_mode_stylesheet();
|
||||||
|
LayoutTask::return_rw_data(possibly_locked_rw_data, rw_data);
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieves the flow tree root from the root node.
|
/// Retrieves the flow tree root from the root node.
|
||||||
fn try_get_layout_root(&self, node: LayoutNode) -> Option<FlowRef> {
|
fn try_get_layout_root(&self, node: LayoutNode) -> Option<FlowRef> {
|
||||||
let mut layout_data_ref = node.mutate_layout_data();
|
let mut layout_data_ref = node.mutate_layout_data();
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#[phase(plugin, link)]
|
#[phase(plugin, link)]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
|
extern crate cssparser;
|
||||||
extern crate geom;
|
extern crate geom;
|
||||||
extern crate gfx;
|
extern crate gfx;
|
||||||
extern crate layout_traits;
|
extern crate layout_traits;
|
||||||
|
@ -70,8 +71,6 @@ pub mod incremental;
|
||||||
pub mod wrapper;
|
pub mod wrapper;
|
||||||
|
|
||||||
pub mod css {
|
pub mod css {
|
||||||
mod node_util;
|
|
||||||
|
|
||||||
pub mod matching;
|
pub mod matching;
|
||||||
pub mod node_style;
|
pub mod node_style;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,12 @@ use block::{ISizeConstraintInput, ISizeConstraintSolution};
|
||||||
use construct::FlowConstructor;
|
use construct::FlowConstructor;
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use floats::FloatKind;
|
use floats::FloatKind;
|
||||||
use flow::{Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS, ImmutableFlowUtils};
|
use flow::{mod, Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS};
|
||||||
use flow::{TableFlowClass};
|
use flow::{ImmutableFlowUtils, TableFlowClass};
|
||||||
use fragment::{Fragment, FragmentBoundsIterator};
|
use fragment::{Fragment, FragmentBoundsIterator};
|
||||||
use layout_debug;
|
use layout_debug;
|
||||||
use model::{IntrinsicISizes, IntrinsicISizesContribution};
|
use model::{IntrinsicISizes, IntrinsicISizesContribution};
|
||||||
|
use table_row::CellIntrinsicInlineSize;
|
||||||
use table_wrapper::{TableLayout, FixedLayout, AutoLayout};
|
use table_wrapper::{TableLayout, FixedLayout, AutoLayout};
|
||||||
use wrapper::ThreadSafeLayoutNode;
|
use wrapper::ThreadSafeLayoutNode;
|
||||||
|
|
||||||
|
@ -105,24 +106,53 @@ impl TableFlow {
|
||||||
/// Update the corresponding value of `self_inline_sizes` if a value of `kid_inline_sizes` has
|
/// Update the corresponding value of `self_inline_sizes` if a value of `kid_inline_sizes` has
|
||||||
/// a larger value than one of `self_inline_sizes`. Returns the minimum and preferred inline
|
/// a larger value than one of `self_inline_sizes`. Returns the minimum and preferred inline
|
||||||
/// sizes.
|
/// sizes.
|
||||||
pub fn update_column_inline_sizes(parent_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>,
|
fn update_automatic_column_inline_sizes(
|
||||||
child_inline_sizes: &Vec<ColumnIntrinsicInlineSize>)
|
parent_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>,
|
||||||
|
child_cell_inline_sizes: &[CellIntrinsicInlineSize])
|
||||||
-> IntrinsicISizes {
|
-> IntrinsicISizes {
|
||||||
let mut total_inline_sizes = IntrinsicISizes::new();
|
let mut total_inline_sizes = IntrinsicISizes::new();
|
||||||
for (parent_sizes, child_sizes) in parent_inline_sizes.iter_mut()
|
let mut column_index = 0;
|
||||||
.zip(child_inline_sizes.iter()) {
|
for child_cell_inline_size in child_cell_inline_sizes.iter() {
|
||||||
|
for _ in range(0, child_cell_inline_size.column_span) {
|
||||||
|
if column_index < parent_inline_sizes.len() {
|
||||||
|
// We already have some intrinsic size information for this column. Merge it in
|
||||||
|
// according to the rules specified in INTRINSIC § 4.
|
||||||
|
let parent_sizes = &mut parent_inline_sizes[column_index];
|
||||||
|
if child_cell_inline_size.column_span > 1 {
|
||||||
|
// TODO(pcwalton): Perform the recursive algorithm specified in INTRINSIC §
|
||||||
|
// 4. For now we make this column contribute no width.
|
||||||
|
} else {
|
||||||
|
let column_size = &child_cell_inline_size.column_size;
|
||||||
*parent_sizes = ColumnIntrinsicInlineSize {
|
*parent_sizes = ColumnIntrinsicInlineSize {
|
||||||
minimum_length: max(parent_sizes.minimum_length, child_sizes.minimum_length),
|
minimum_length: max(parent_sizes.minimum_length,
|
||||||
percentage: parent_sizes.greatest_percentage(child_sizes),
|
column_size.minimum_length),
|
||||||
preferred: max(parent_sizes.preferred, child_sizes.preferred),
|
percentage: parent_sizes.greatest_percentage(column_size),
|
||||||
constrained: parent_sizes.constrained || child_sizes.constrained
|
preferred: max(parent_sizes.preferred, column_size.preferred),
|
||||||
};
|
constrained: parent_sizes.constrained || column_size.constrained,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We discovered a new column. Initialize its data.
|
||||||
|
debug_assert!(column_index == parent_inline_sizes.len());
|
||||||
|
if child_cell_inline_size.column_span > 1 {
|
||||||
|
// TODO(pcwalton): Perform the recursive algorithm specified in INTRINSIC §
|
||||||
|
// 4. For now we make this column contribute no width.
|
||||||
|
parent_inline_sizes.push(ColumnIntrinsicInlineSize::new())
|
||||||
|
} else {
|
||||||
|
parent_inline_sizes.push(child_cell_inline_size.column_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
total_inline_sizes.minimum_inline_size = total_inline_sizes.minimum_inline_size +
|
total_inline_sizes.minimum_inline_size = total_inline_sizes.minimum_inline_size +
|
||||||
parent_sizes.minimum_length;
|
parent_inline_sizes[column_index].minimum_length;
|
||||||
total_inline_sizes.preferred_inline_size = total_inline_sizes.preferred_inline_size +
|
total_inline_sizes.preferred_inline_size =
|
||||||
parent_sizes.preferred;
|
total_inline_sizes.preferred_inline_size +
|
||||||
|
parent_inline_sizes[column_index].preferred;
|
||||||
|
|
||||||
|
column_index += 1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
total_inline_sizes
|
total_inline_sizes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,6 +166,39 @@ impl TableFlow {
|
||||||
fn assign_block_size_table_base<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
|
fn assign_block_size_table_base<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
|
||||||
self.block_flow.assign_block_size_block_base(layout_context, MarginsMayNotCollapse);
|
self.block_flow.assign_block_size_block_base(layout_context, MarginsMayNotCollapse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates the minimum and preferred inline-size calculation for a single row. This is
|
||||||
|
/// factored out into a separate function because we process children of rowgroups too.
|
||||||
|
fn update_column_inline_sizes_for_row(child: &mut Flow,
|
||||||
|
column_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>,
|
||||||
|
computation: &mut IntrinsicISizesContribution,
|
||||||
|
did_first_row: &mut bool,
|
||||||
|
table_layout: TableLayout) {
|
||||||
|
// Read column inline-sizes from the table-row, and assign inline-size=0 for the columns
|
||||||
|
// not defined in the column group.
|
||||||
|
//
|
||||||
|
// FIXME: Need to read inline-sizes from either table-header-group OR the first table-row.
|
||||||
|
debug_assert!(child.is_table_row());
|
||||||
|
let row = child.as_table_row();
|
||||||
|
match table_layout {
|
||||||
|
FixedLayout => {
|
||||||
|
// Fixed table layout only looks at the first row.
|
||||||
|
//
|
||||||
|
// FIXME(pcwalton): This is really inefficient. We should stop after the first row!
|
||||||
|
if !*did_first_row {
|
||||||
|
*did_first_row = true;
|
||||||
|
for cell_inline_size in row.cell_intrinsic_inline_sizes.iter() {
|
||||||
|
column_inline_sizes.push(cell_inline_size.column_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AutoLayout => {
|
||||||
|
computation.union_block(&TableFlow::update_automatic_column_inline_sizes(
|
||||||
|
column_inline_sizes,
|
||||||
|
row.cell_intrinsic_inline_sizes.as_slice()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Flow for TableFlow {
|
impl Flow for TableFlow {
|
||||||
|
@ -190,50 +253,22 @@ impl Flow for TableFlow {
|
||||||
constrained: false,
|
constrained: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else if kid.is_table_rowgroup() || kid.is_table_row() {
|
} else if kid.is_table_rowgroup() {
|
||||||
// Read column inline-sizes from the table-row-group/table-row, and assign
|
for grandkid in flow::mut_base(kid).child_iter() {
|
||||||
// inline-size=0 for the columns not defined in the column group.
|
TableFlow::update_column_inline_sizes_for_row(
|
||||||
// FIXME: Need to read inline-sizes from either table-header-group OR the first
|
grandkid,
|
||||||
// table-row.
|
|
||||||
match self.table_layout {
|
|
||||||
FixedLayout => {
|
|
||||||
// Fixed table layout only looks at the first row.
|
|
||||||
if !did_first_row {
|
|
||||||
did_first_row = true;
|
|
||||||
for child_column_inline_size in kid.column_intrinsic_inline_sizes()
|
|
||||||
.iter() {
|
|
||||||
self.column_intrinsic_inline_sizes.push(*child_column_inline_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AutoLayout => {
|
|
||||||
let child_column_inline_sizes = kid.column_intrinsic_inline_sizes();
|
|
||||||
let mut child_intrinsic_sizes = TableFlow::update_column_inline_sizes(
|
|
||||||
&mut self.column_intrinsic_inline_sizes,
|
&mut self.column_intrinsic_inline_sizes,
|
||||||
child_column_inline_sizes);
|
&mut computation,
|
||||||
|
&mut did_first_row,
|
||||||
// Add new columns if processing this row caused us to discover them.
|
self.table_layout)
|
||||||
let child_column_count = child_column_inline_sizes.len();
|
|
||||||
let parent_column_count = self.column_intrinsic_inline_sizes.len();
|
|
||||||
debug!("table until the previous row has {} column(s) and this row has {} \
|
|
||||||
column(s)",
|
|
||||||
parent_column_count,
|
|
||||||
child_column_count);
|
|
||||||
self.column_intrinsic_inline_sizes.reserve(child_column_count);
|
|
||||||
for i in range(parent_column_count, child_column_count) {
|
|
||||||
let inline_size_for_new_column = (*child_column_inline_sizes)[i];
|
|
||||||
child_intrinsic_sizes.minimum_inline_size =
|
|
||||||
child_intrinsic_sizes.minimum_inline_size +
|
|
||||||
inline_size_for_new_column.minimum_length;
|
|
||||||
child_intrinsic_sizes.preferred_inline_size =
|
|
||||||
child_intrinsic_sizes.preferred_inline_size +
|
|
||||||
inline_size_for_new_column.preferred;
|
|
||||||
self.column_intrinsic_inline_sizes.push(inline_size_for_new_column);
|
|
||||||
}
|
|
||||||
|
|
||||||
computation.union_block(&child_intrinsic_sizes)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else if kid.is_table_row() {
|
||||||
|
TableFlow::update_column_inline_sizes_for_row(
|
||||||
|
kid,
|
||||||
|
&mut self.column_intrinsic_inline_sizes,
|
||||||
|
&mut computation,
|
||||||
|
&mut did_first_row,
|
||||||
|
self.table_layout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,8 +312,7 @@ impl Flow for TableFlow {
|
||||||
// In fixed table layout, we distribute extra space among the unspecified columns
|
// In fixed table layout, we distribute extra space among the unspecified columns
|
||||||
// if there are any, or among all the columns if all are specified.
|
// if there are any, or among all the columns if all are specified.
|
||||||
self.column_computed_inline_sizes.clear();
|
self.column_computed_inline_sizes.clear();
|
||||||
if total_column_inline_size < content_inline_size &&
|
if num_unspecified_inline_sizes == 0 {
|
||||||
num_unspecified_inline_sizes == 0 {
|
|
||||||
let ratio = content_inline_size.to_subpx() /
|
let ratio = content_inline_size.to_subpx() /
|
||||||
total_column_inline_size.to_subpx();
|
total_column_inline_size.to_subpx();
|
||||||
for column_inline_size in self.column_intrinsic_inline_sizes.iter() {
|
for column_inline_size in self.column_intrinsic_inline_sizes.iter() {
|
||||||
|
@ -413,6 +447,16 @@ pub struct ColumnIntrinsicInlineSize {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ColumnIntrinsicInlineSize {
|
impl ColumnIntrinsicInlineSize {
|
||||||
|
/// Returns a newly-initialized `ColumnIntrinsicInlineSize` with all fields blank.
|
||||||
|
pub fn new() -> ColumnIntrinsicInlineSize {
|
||||||
|
ColumnIntrinsicInlineSize {
|
||||||
|
preferred: Au(0),
|
||||||
|
minimum_length: Au(0),
|
||||||
|
percentage: 0.0,
|
||||||
|
constrained: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the true minimum size of this column, given the containing block's inline size.
|
/// Returns the true minimum size of this column, given the containing block's inline size.
|
||||||
/// Beware that this is generally only correct for fixed table layout. (Compare CSS 2.1 §
|
/// Beware that this is generally only correct for fixed table layout. (Compare CSS 2.1 §
|
||||||
/// 17.5.2.1 with the algorithm in INTRINSIC § 4.)
|
/// 17.5.2.1 with the algorithm in INTRINSIC § 4.)
|
||||||
|
|
|
@ -17,7 +17,7 @@ use wrapper::ThreadSafeLayoutNode;
|
||||||
|
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style::ComputedValues;
|
use style::{ColSpanUnsignedIntegerAttribute, ComputedValues};
|
||||||
use sync::Arc;
|
use sync::Arc;
|
||||||
|
|
||||||
/// A table formatting context.
|
/// A table formatting context.
|
||||||
|
@ -25,13 +25,17 @@ use sync::Arc;
|
||||||
pub struct TableCellFlow {
|
pub struct TableCellFlow {
|
||||||
/// Data common to all block flows.
|
/// Data common to all block flows.
|
||||||
pub block_flow: BlockFlow,
|
pub block_flow: BlockFlow,
|
||||||
|
/// The column span of this cell.
|
||||||
|
pub column_span: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TableCellFlow {
|
impl TableCellFlow {
|
||||||
pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, fragment: Fragment)
|
pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, fragment: Fragment)
|
||||||
-> TableCellFlow {
|
-> TableCellFlow {
|
||||||
TableCellFlow {
|
TableCellFlow {
|
||||||
block_flow: BlockFlow::from_node_and_fragment(node, fragment)
|
block_flow: BlockFlow::from_node_and_fragment(node, fragment),
|
||||||
|
column_span: node.get_unsigned_integer_attribute(ColSpanUnsignedIntegerAttribute)
|
||||||
|
.unwrap_or(1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,20 +30,29 @@ use sync::Arc;
|
||||||
pub struct TableRowFlow {
|
pub struct TableRowFlow {
|
||||||
pub block_flow: BlockFlow,
|
pub block_flow: BlockFlow,
|
||||||
|
|
||||||
/// Information about the intrinsic inline-sizes of each column.
|
/// Information about the intrinsic inline-sizes of each cell.
|
||||||
pub column_intrinsic_inline_sizes: Vec<ColumnIntrinsicInlineSize>,
|
pub cell_intrinsic_inline_sizes: Vec<CellIntrinsicInlineSize>,
|
||||||
|
|
||||||
/// Information about the computed inline-sizes of each column.
|
/// Information about the computed inline-sizes of each column.
|
||||||
pub column_computed_inline_sizes: Vec<ColumnComputedInlineSize>,
|
pub column_computed_inline_sizes: Vec<ColumnComputedInlineSize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Information about the column inline size and span for each cell.
|
||||||
|
#[deriving(Encodable)]
|
||||||
|
pub struct CellIntrinsicInlineSize {
|
||||||
|
/// Inline sizes that this cell contributes to the column.
|
||||||
|
pub column_size: ColumnIntrinsicInlineSize,
|
||||||
|
/// The column span of this cell.
|
||||||
|
pub column_span: u32,
|
||||||
|
}
|
||||||
|
|
||||||
impl TableRowFlow {
|
impl TableRowFlow {
|
||||||
pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode,
|
pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode,
|
||||||
fragment: Fragment)
|
fragment: Fragment)
|
||||||
-> TableRowFlow {
|
-> TableRowFlow {
|
||||||
TableRowFlow {
|
TableRowFlow {
|
||||||
block_flow: BlockFlow::from_node_and_fragment(node, fragment),
|
block_flow: BlockFlow::from_node_and_fragment(node, fragment),
|
||||||
column_intrinsic_inline_sizes: Vec::new(),
|
cell_intrinsic_inline_sizes: Vec::new(),
|
||||||
column_computed_inline_sizes: Vec::new(),
|
column_computed_inline_sizes: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,8 +62,8 @@ impl TableRowFlow {
|
||||||
-> TableRowFlow {
|
-> TableRowFlow {
|
||||||
TableRowFlow {
|
TableRowFlow {
|
||||||
block_flow: BlockFlow::from_node(constructor, node),
|
block_flow: BlockFlow::from_node(constructor, node),
|
||||||
column_intrinsic_inline_sizes: Vec::new(),
|
cell_intrinsic_inline_sizes: Vec::new(),
|
||||||
column_computed_inline_sizes: Vec::new(),
|
column_computed_inline_sizes: Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +165,7 @@ impl Flow for TableRowFlow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn column_intrinsic_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnIntrinsicInlineSize> {
|
fn column_intrinsic_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnIntrinsicInlineSize> {
|
||||||
&mut self.column_intrinsic_inline_sizes
|
panic!("can't call column_intrinsic_inline_sizes() on table row")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn column_computed_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnComputedInlineSize> {
|
fn column_computed_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnComputedInlineSize> {
|
||||||
|
@ -181,10 +190,15 @@ impl Flow for TableRowFlow {
|
||||||
|
|
||||||
// Collect the specified column inline-size of the cell. This is used in both fixed and
|
// Collect the specified column inline-size of the cell. This is used in both fixed and
|
||||||
// automatic table layout calculation.
|
// automatic table layout calculation.
|
||||||
let child_specified_inline_size = kid.as_table_cell()
|
let child_specified_inline_size;
|
||||||
.fragment()
|
let child_column_span;
|
||||||
|
{
|
||||||
|
let child_table_cell = kid.as_table_cell();
|
||||||
|
child_specified_inline_size = child_table_cell.fragment()
|
||||||
.style()
|
.style()
|
||||||
.content_inline_size();
|
.content_inline_size();
|
||||||
|
child_column_span = child_table_cell.column_span
|
||||||
|
}
|
||||||
|
|
||||||
// Collect minimum and preferred inline-sizes of the cell for automatic table layout
|
// Collect minimum and preferred inline-sizes of the cell for automatic table layout
|
||||||
// calculation.
|
// calculation.
|
||||||
|
@ -208,15 +222,16 @@ impl Flow for TableRowFlow {
|
||||||
};
|
};
|
||||||
min_inline_size = min_inline_size + child_column_inline_size.minimum_length;
|
min_inline_size = min_inline_size + child_column_inline_size.minimum_length;
|
||||||
pref_inline_size = pref_inline_size + child_column_inline_size.preferred;
|
pref_inline_size = pref_inline_size + child_column_inline_size.preferred;
|
||||||
self.column_intrinsic_inline_sizes.push(child_column_inline_size);
|
self.cell_intrinsic_inline_sizes.push(CellIntrinsicInlineSize {
|
||||||
|
column_size: child_column_inline_size,
|
||||||
|
column_span: child_column_span,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size = min_inline_size;
|
self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size = min_inline_size;
|
||||||
self.block_flow.base.intrinsic_inline_sizes.preferred_inline_size = max(min_inline_size,
|
self.block_flow.base.intrinsic_inline_sizes.preferred_inline_size = max(min_inline_size,
|
||||||
pref_inline_size);
|
pref_inline_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recursively (top-down) determines the actual inline-size of child contexts and fragments.
|
|
||||||
/// When called on this context, the context has had its inline-size set by the parent context.
|
|
||||||
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
|
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
|
||||||
let _scope = layout_debug_scope!("table_row::assign_inline_sizes {:x}",
|
let _scope = layout_debug_scope!("table_row::assign_inline_sizes {:x}",
|
||||||
self.block_flow.base.debug_id());
|
self.block_flow.base.debug_id());
|
||||||
|
@ -233,11 +248,46 @@ impl Flow for TableRowFlow {
|
||||||
layout_context,
|
layout_context,
|
||||||
containing_block_inline_size);
|
containing_block_inline_size);
|
||||||
|
|
||||||
|
// Spread out the completed inline sizes among columns with spans > 1.
|
||||||
|
let mut computed_inline_size_for_cells = Vec::new();
|
||||||
|
let mut column_computed_inline_size_iterator = self.column_computed_inline_sizes.iter();
|
||||||
|
for cell_intrinsic_inline_size in self.cell_intrinsic_inline_sizes.iter() {
|
||||||
|
// Start with the computed inline size for the first column in the span.
|
||||||
|
let mut column_computed_inline_size =
|
||||||
|
match column_computed_inline_size_iterator.next() {
|
||||||
|
Some(column_computed_inline_size) => *column_computed_inline_size,
|
||||||
|
None => {
|
||||||
|
// We're in fixed layout mode and there are more cells in this row than
|
||||||
|
// columns we know about. According to CSS 2.1 § 17.5.2.1, the behavior is
|
||||||
|
// now undefined. So just use zero.
|
||||||
|
//
|
||||||
|
// FIXME(pcwalton): $10 says this isn't Web compatible.
|
||||||
|
ColumnComputedInlineSize {
|
||||||
|
size: Au(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add in computed inline sizes for any extra columns in the span.
|
||||||
|
for _ in range(1, cell_intrinsic_inline_size.column_span) {
|
||||||
|
let extra_column_computed_inline_size =
|
||||||
|
match column_computed_inline_size_iterator.next() {
|
||||||
|
Some(column_computed_inline_size) => column_computed_inline_size,
|
||||||
|
None => break,
|
||||||
|
};
|
||||||
|
column_computed_inline_size.size = column_computed_inline_size.size +
|
||||||
|
extra_column_computed_inline_size.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
computed_inline_size_for_cells.push(column_computed_inline_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push those inline sizes down to the cells.
|
||||||
self.block_flow.propagate_assigned_inline_size_to_children(
|
self.block_flow.propagate_assigned_inline_size_to_children(
|
||||||
layout_context,
|
layout_context,
|
||||||
inline_start_content_edge,
|
inline_start_content_edge,
|
||||||
containing_block_inline_size,
|
containing_block_inline_size,
|
||||||
Some(self.column_computed_inline_sizes.as_slice()));
|
Some(computed_inline_size_for_cells.as_slice()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
|
fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
|
||||||
|
|
|
@ -9,11 +9,10 @@
|
||||||
use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayNotCollapse};
|
use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayNotCollapse};
|
||||||
use construct::FlowConstructor;
|
use construct::FlowConstructor;
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use flow::{TableRowGroupFlowClass, FlowClass, Flow, ImmutableFlowUtils};
|
use flow::{Flow, FlowClass, TableRowGroupFlowClass};
|
||||||
use fragment::{Fragment, FragmentBoundsIterator};
|
use fragment::{Fragment, FragmentBoundsIterator};
|
||||||
use layout_debug;
|
use layout_debug;
|
||||||
use model::IntrinsicISizesContribution;
|
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable};
|
||||||
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable, TableFlow};
|
|
||||||
use wrapper::ThreadSafeLayoutNode;
|
use wrapper::ThreadSafeLayoutNode;
|
||||||
|
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
|
@ -24,6 +23,7 @@ use sync::Arc;
|
||||||
/// A table formatting context.
|
/// A table formatting context.
|
||||||
#[deriving(Encodable)]
|
#[deriving(Encodable)]
|
||||||
pub struct TableRowGroupFlow {
|
pub struct TableRowGroupFlow {
|
||||||
|
/// Fields common to all block flows.
|
||||||
pub block_flow: BlockFlow,
|
pub block_flow: BlockFlow,
|
||||||
|
|
||||||
/// Information about the intrinsic inline-sizes of each column.
|
/// Information about the intrinsic inline-sizes of each column.
|
||||||
|
@ -91,54 +91,11 @@ impl Flow for TableRowGroupFlow {
|
||||||
&mut self.column_computed_inline_sizes
|
&mut self.column_computed_inline_sizes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Recursively (bottom-up) determines the context's preferred and minimum inline-sizes. When
|
|
||||||
/// called on this context, all child contexts have had their min/pref inline-sizes set. This
|
|
||||||
/// function must decide min/pref inline-sizes based on child context inline-sizes and
|
|
||||||
/// dimensions of any fragments it is responsible for flowing.
|
|
||||||
///
|
|
||||||
/// Min/pref inline-sizes set by this function are used in automatic table layout calculation.
|
|
||||||
///
|
|
||||||
/// Also, this function finds the specified column inline-sizes from the first row. These are
|
|
||||||
/// used in fixed table layout calculation.
|
|
||||||
fn bubble_inline_sizes(&mut self) {
|
fn bubble_inline_sizes(&mut self) {
|
||||||
let _scope = layout_debug_scope!("table_rowgroup::bubble_inline_sizes {:x}",
|
let _scope = layout_debug_scope!("table_rowgroup::bubble_inline_sizes {:x}",
|
||||||
self.block_flow.base.debug_id());
|
self.block_flow.base.debug_id());
|
||||||
|
// Proper calculation of intrinsic sizes in table layout requires access to the entire
|
||||||
let mut computation = IntrinsicISizesContribution::new();
|
// table, which we don't have yet. Defer to our parent.
|
||||||
for kid in self.block_flow.base.child_iter() {
|
|
||||||
assert!(kid.is_table_row());
|
|
||||||
|
|
||||||
// Calculate minimum and preferred inline sizes for automatic table layout.
|
|
||||||
if self.column_intrinsic_inline_sizes.is_empty() {
|
|
||||||
// We're the first row.
|
|
||||||
self.column_intrinsic_inline_sizes = kid.column_intrinsic_inline_sizes().clone();
|
|
||||||
} else {
|
|
||||||
let mut child_intrinsic_sizes =
|
|
||||||
TableFlow::update_column_inline_sizes(&mut self.column_intrinsic_inline_sizes,
|
|
||||||
kid.column_intrinsic_inline_sizes());
|
|
||||||
|
|
||||||
// update the number of column inline-sizes from table-rows.
|
|
||||||
let column_count = self.column_intrinsic_inline_sizes.len();
|
|
||||||
let child_column_count = kid.column_intrinsic_inline_sizes().len();
|
|
||||||
for i in range(column_count, child_column_count) {
|
|
||||||
let this_column_inline_size = (*kid.column_intrinsic_inline_sizes())[i];
|
|
||||||
|
|
||||||
// FIXME(pcwalton): Ignoring the percentage here seems dubious.
|
|
||||||
child_intrinsic_sizes.minimum_inline_size =
|
|
||||||
child_intrinsic_sizes.minimum_inline_size +
|
|
||||||
this_column_inline_size.minimum_length;
|
|
||||||
child_intrinsic_sizes.preferred_inline_size =
|
|
||||||
child_intrinsic_sizes.preferred_inline_size +
|
|
||||||
this_column_inline_size.preferred;
|
|
||||||
self.column_intrinsic_inline_sizes.push(this_column_inline_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
computation.union_block(&child_intrinsic_sizes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.block_flow.base.intrinsic_inline_sizes = computation.finish()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recursively (top-down) determines the actual inline-size of child contexts and fragments.
|
/// Recursively (top-down) determines the actual inline-size of child contexts and fragments.
|
||||||
|
|
|
@ -31,7 +31,7 @@ use style::{ComputedValues, CSSFloat};
|
||||||
use style::computed_values::table_layout;
|
use style::computed_values::table_layout;
|
||||||
use sync::Arc;
|
use sync::Arc;
|
||||||
|
|
||||||
#[deriving(Encodable)]
|
#[deriving(Encodable, Show)]
|
||||||
pub enum TableLayout {
|
pub enum TableLayout {
|
||||||
FixedLayout,
|
FixedLayout,
|
||||||
AutoLayout
|
AutoLayout
|
||||||
|
|
|
@ -36,6 +36,7 @@ use incremental::RestyleDamage;
|
||||||
use util::{LayoutDataAccess, LayoutDataFlags, LayoutDataWrapper, OpaqueNodeMethods};
|
use util::{LayoutDataAccess, LayoutDataFlags, LayoutDataWrapper, OpaqueNodeMethods};
|
||||||
use util::{PrivateLayoutData};
|
use util::{PrivateLayoutData};
|
||||||
|
|
||||||
|
use cssparser::RGBA;
|
||||||
use gfx::display_list::OpaqueNode;
|
use gfx::display_list::OpaqueNode;
|
||||||
use script::dom::bindings::codegen::InheritTypes::{ElementCast, HTMLIFrameElementCast};
|
use script::dom::bindings::codegen::InheritTypes::{ElementCast, HTMLIFrameElementCast};
|
||||||
use script::dom::bindings::codegen::InheritTypes::{HTMLImageElementCast, HTMLInputElementCast};
|
use script::dom::bindings::codegen::InheritTypes::{HTMLImageElementCast, HTMLInputElementCast};
|
||||||
|
@ -56,11 +57,12 @@ use servo_msg::constellation_msg::{PipelineId, SubpageId};
|
||||||
use servo_util::str::{LengthOrPercentageOrAuto, is_whitespace};
|
use servo_util::str::{LengthOrPercentageOrAuto, is_whitespace};
|
||||||
use std::kinds::marker::ContravariantLifetime;
|
use std::kinds::marker::ContravariantLifetime;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use style::computed_values::{content, display, white_space};
|
|
||||||
use style::{AnyNamespace, AttrSelector, IntegerAttribute, LengthAttribute};
|
|
||||||
use style::{PropertyDeclarationBlock, SpecificNamespace, TElement, TElementAttributes, TNode};
|
|
||||||
use url::Url;
|
|
||||||
use string_cache::{Atom, Namespace};
|
use string_cache::{Atom, Namespace};
|
||||||
|
use style::computed_values::{content, display, white_space};
|
||||||
|
use style::{AnyNamespace, AttrSelector, BorderUnsignedIntegerAttribute, IntegerAttribute};
|
||||||
|
use style::{LengthAttribute, PropertyDeclarationBlock, SimpleColorAttribute, SpecificNamespace};
|
||||||
|
use style::{TElement, TElementAttributes, TNode, UnsignedIntegerAttribute};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use std::cell::{Ref, RefMut};
|
use std::cell::{Ref, RefMut};
|
||||||
|
|
||||||
|
@ -580,6 +582,17 @@ impl<'le> TElement<'le> for LayoutElement<'le> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn has_nonzero_border(self) -> bool {
|
||||||
|
unsafe {
|
||||||
|
match self.element
|
||||||
|
.get_unsigned_integer_attribute_for_layout(BorderUnsignedIntegerAttribute) {
|
||||||
|
None | Some(0) => false,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'le> TElementAttributes for LayoutElement<'le> {
|
impl<'le> TElementAttributes for LayoutElement<'le> {
|
||||||
|
@ -594,6 +607,18 @@ impl<'le> TElementAttributes for LayoutElement<'le> {
|
||||||
self.element.get_integer_attribute_for_layout(integer_attribute)
|
self.element.get_integer_attribute_for_layout(integer_attribute)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_unsigned_integer_attribute(self, attribute: UnsignedIntegerAttribute) -> Option<u32> {
|
||||||
|
unsafe {
|
||||||
|
self.element.get_unsigned_integer_attribute_for_layout(attribute)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_simple_color_attribute(self, attribute: SimpleColorAttribute) -> Option<RGBA> {
|
||||||
|
unsafe {
|
||||||
|
self.element.get_simple_color_attribute_for_layout(attribute)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_content(content_list: &content::T) -> String {
|
fn get_content(content_list: &content::T) -> String {
|
||||||
|
@ -913,6 +938,18 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_unsigned_integer_attribute(self, attribute: UnsignedIntegerAttribute)
|
||||||
|
-> Option<u32> {
|
||||||
|
unsafe {
|
||||||
|
match ElementCast::to_js(self.get_jsmanaged()) {
|
||||||
|
Some(element) => {
|
||||||
|
(*element.unsafe_get()).get_unsigned_integer_attribute_for_layout(attribute)
|
||||||
|
}
|
||||||
|
None => panic!("not an element!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the description of how to account for recent style changes.
|
/// Get the description of how to account for recent style changes.
|
||||||
/// This is a simple bitfield and fine to copy by value.
|
/// This is a simple bitfield and fine to copy by value.
|
||||||
pub fn restyle_damage(self) -> RestyleDamage {
|
pub fn restyle_damage(self) -> RestyleDamage {
|
||||||
|
|
|
@ -32,6 +32,7 @@ use dom::bindings::utils::{Reflectable, Reflector, WindowProxyHandler};
|
||||||
use dom::node::{Node, TrustedNodeAddress};
|
use dom::node::{Node, TrustedNodeAddress};
|
||||||
|
|
||||||
use collections::hash::{Hash, Hasher};
|
use collections::hash::{Hash, Hasher};
|
||||||
|
use cssparser::RGBA;
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
use html5ever::tree_builder::QuirksMode;
|
use html5ever::tree_builder::QuirksMode;
|
||||||
use hyper::header::Headers;
|
use hyper::header::Headers;
|
||||||
|
@ -48,7 +49,7 @@ use script_traits::UntrustedNodeAddress;
|
||||||
use servo_msg::compositor_msg::ScriptListener;
|
use servo_msg::compositor_msg::ScriptListener;
|
||||||
use servo_msg::constellation_msg::ConstellationChan;
|
use servo_msg::constellation_msg::ConstellationChan;
|
||||||
use servo_util::smallvec::{SmallVec1, SmallVec};
|
use servo_util::smallvec::{SmallVec1, SmallVec};
|
||||||
use servo_util::str::LengthOrPercentageOrAuto;
|
use servo_util::str::{LengthOrPercentageOrAuto};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::comm::{Receiver, Sender};
|
use std::comm::{Receiver, Sender};
|
||||||
|
@ -214,6 +215,7 @@ no_jsmanaged_fields!(LayoutChan)
|
||||||
no_jsmanaged_fields!(WindowProxyHandler)
|
no_jsmanaged_fields!(WindowProxyHandler)
|
||||||
no_jsmanaged_fields!(UntrustedNodeAddress)
|
no_jsmanaged_fields!(UntrustedNodeAddress)
|
||||||
no_jsmanaged_fields!(LengthOrPercentageOrAuto)
|
no_jsmanaged_fields!(LengthOrPercentageOrAuto)
|
||||||
|
no_jsmanaged_fields!(RGBA)
|
||||||
|
|
||||||
impl<'a> JSTraceable for &'a str {
|
impl<'a> JSTraceable for &'a str {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -61,6 +61,7 @@ use servo_util::namespace;
|
||||||
use servo_util::str::{DOMString, split_html_space_chars};
|
use servo_util::str::{DOMString, split_html_space_chars};
|
||||||
|
|
||||||
use html5ever::tree_builder::{QuirksMode, NoQuirks, LimitedQuirks, Quirks};
|
use html5ever::tree_builder::{QuirksMode, NoQuirks, LimitedQuirks, Quirks};
|
||||||
|
use layout_interface::{LayoutChan, SetQuirksModeMsg};
|
||||||
use string_cache::{Atom, QualName};
|
use string_cache::{Atom, QualName};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -217,6 +218,15 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
|
||||||
|
|
||||||
fn set_quirks_mode(self, mode: QuirksMode) {
|
fn set_quirks_mode(self, mode: QuirksMode) {
|
||||||
self.quirks_mode.set(mode);
|
self.quirks_mode.set(mode);
|
||||||
|
|
||||||
|
match mode {
|
||||||
|
Quirks => {
|
||||||
|
let window = self.window.root();
|
||||||
|
let LayoutChan(ref layout_chan) = window.page().layout_chan;
|
||||||
|
layout_chan.send(SetQuirksModeMsg);
|
||||||
|
}
|
||||||
|
NoQuirks | LimitedQuirks => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_last_modified(self, value: DOMString) {
|
fn set_last_modified(self, value: DOMString) {
|
||||||
|
|
|
@ -15,8 +15,12 @@ use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
|
||||||
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
||||||
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
|
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
|
||||||
use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods;
|
use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods;
|
||||||
use dom::bindings::codegen::InheritTypes::{ElementDerived, HTMLInputElementDerived, HTMLTableCellElementDerived};
|
use dom::bindings::codegen::InheritTypes::{ElementCast, ElementDerived, EventTargetCast};
|
||||||
use dom::bindings::codegen::InheritTypes::{HTMLInputElementCast, NodeCast, EventTargetCast, ElementCast};
|
use dom::bindings::codegen::InheritTypes::{HTMLBodyElementDerived, HTMLInputElementCast};
|
||||||
|
use dom::bindings::codegen::InheritTypes::{HTMLInputElementDerived, HTMLTableElementCast};
|
||||||
|
use dom::bindings::codegen::InheritTypes::{HTMLTableElementDerived, HTMLTableCellElementDerived};
|
||||||
|
use dom::bindings::codegen::InheritTypes::{HTMLTableRowElementDerived};
|
||||||
|
use dom::bindings::codegen::InheritTypes::{HTMLTableSectionElementDerived, NodeCast};
|
||||||
use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary, TemporaryPushable};
|
use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary, TemporaryPushable};
|
||||||
use dom::bindings::js::{OptionalRootable, Root};
|
use dom::bindings::js::{OptionalRootable, Root};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
|
@ -29,22 +33,28 @@ use dom::document::{Document, DocumentHelpers, LayoutDocumentHelpers};
|
||||||
use dom::domtokenlist::DOMTokenList;
|
use dom::domtokenlist::DOMTokenList;
|
||||||
use dom::event::Event;
|
use dom::event::Event;
|
||||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId, EventTargetHelpers};
|
use dom::eventtarget::{EventTarget, NodeTargetTypeId, EventTargetHelpers};
|
||||||
|
use dom::htmlbodyelement::{HTMLBodyElement, HTMLBodyElementHelpers};
|
||||||
use dom::htmlcollection::HTMLCollection;
|
use dom::htmlcollection::HTMLCollection;
|
||||||
use dom::htmlinputelement::{HTMLInputElement, RawLayoutHTMLInputElementHelpers};
|
use dom::htmlinputelement::{HTMLInputElement, RawLayoutHTMLInputElementHelpers};
|
||||||
use dom::htmlserializer::serialize;
|
use dom::htmlserializer::serialize;
|
||||||
|
use dom::htmltableelement::{HTMLTableElement, HTMLTableElementHelpers};
|
||||||
use dom::htmltablecellelement::{HTMLTableCellElement, HTMLTableCellElementHelpers};
|
use dom::htmltablecellelement::{HTMLTableCellElement, HTMLTableCellElementHelpers};
|
||||||
use dom::node::{CLICK_IN_PROGRESS, ElementNodeTypeId, Node, NodeHelpers, NodeIterator};
|
use dom::htmltablerowelement::{HTMLTableRowElement, HTMLTableRowElementHelpers};
|
||||||
use dom::node::{document_from_node, window_from_node, LayoutNodeHelpers, NodeStyleDamaged};
|
use dom::htmltablesectionelement::{HTMLTableSectionElement, HTMLTableSectionElementHelpers};
|
||||||
use dom::node::{OtherNodeDamage};
|
use dom::node::{CLICK_IN_PROGRESS, ElementNodeTypeId, LayoutNodeHelpers, Node, NodeHelpers};
|
||||||
|
use dom::node::{NodeIterator, NodeStyleDamaged, OtherNodeDamage, document_from_node};
|
||||||
|
use dom::node::{window_from_node};
|
||||||
use dom::nodelist::NodeList;
|
use dom::nodelist::NodeList;
|
||||||
use dom::virtualmethods::{VirtualMethods, vtable_for};
|
use dom::virtualmethods::{VirtualMethods, vtable_for};
|
||||||
use devtools_traits::AttrInfo;
|
use devtools_traits::AttrInfo;
|
||||||
use style::{IntegerAttribute, LengthAttribute, SizeIntegerAttribute, WidthLengthAttribute};
|
use style::{mod, AuthorOrigin, BgColorSimpleColorAttribute, BorderUnsignedIntegerAttribute};
|
||||||
use style::{matches, parse_selector_list_from_str};
|
use style::{ColSpanUnsignedIntegerAttribute, IntegerAttribute, LengthAttribute, ParserContext};
|
||||||
use style;
|
use style::{SimpleColorAttribute, SizeIntegerAttribute, UnsignedIntegerAttribute};
|
||||||
|
use style::{WidthLengthAttribute, matches};
|
||||||
use servo_util::namespace;
|
use servo_util::namespace;
|
||||||
use servo_util::str::{DOMString, LengthOrPercentageOrAuto};
|
use servo_util::str::{DOMString, LengthOrPercentageOrAuto};
|
||||||
|
|
||||||
|
use cssparser::RGBA;
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::cell::{Ref, RefMut};
|
use std::cell::{Ref, RefMut};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
@ -201,6 +211,10 @@ pub trait RawLayoutElementHelpers {
|
||||||
unsafe fn get_integer_attribute_for_layout(&self, integer_attribute: IntegerAttribute)
|
unsafe fn get_integer_attribute_for_layout(&self, integer_attribute: IntegerAttribute)
|
||||||
-> Option<i32>;
|
-> Option<i32>;
|
||||||
unsafe fn get_checked_state_for_layout(&self) -> bool;
|
unsafe fn get_checked_state_for_layout(&self) -> bool;
|
||||||
|
unsafe fn get_unsigned_integer_attribute_for_layout(&self, attribute: UnsignedIntegerAttribute)
|
||||||
|
-> Option<u32>;
|
||||||
|
unsafe fn get_simple_color_attribute_for_layout(&self, attribute: SimpleColorAttribute)
|
||||||
|
-> Option<RGBA>;
|
||||||
fn local_name<'a>(&'a self) -> &'a Atom;
|
fn local_name<'a>(&'a self) -> &'a Atom;
|
||||||
fn namespace<'a>(&'a self) -> &'a Namespace;
|
fn namespace<'a>(&'a self) -> &'a Namespace;
|
||||||
fn style_attribute<'a>(&'a self) -> &'a DOMRefCell<Option<style::PropertyDeclarationBlock>>;
|
fn style_attribute<'a>(&'a self) -> &'a DOMRefCell<Option<style::PropertyDeclarationBlock>>;
|
||||||
|
@ -285,11 +299,15 @@ impl RawLayoutElementHelpers for Element {
|
||||||
-> LengthOrPercentageOrAuto {
|
-> LengthOrPercentageOrAuto {
|
||||||
match length_attribute {
|
match length_attribute {
|
||||||
WidthLengthAttribute => {
|
WidthLengthAttribute => {
|
||||||
if !self.is_htmltablecellelement() {
|
if self.is_htmltableelement() {
|
||||||
panic!("I'm not a table cell!")
|
let this: &HTMLTableElement = mem::transmute(self);
|
||||||
}
|
this.get_width()
|
||||||
|
} else if self.is_htmltablecellelement() {
|
||||||
let this: &HTMLTableCellElement = mem::transmute(self);
|
let this: &HTMLTableCellElement = mem::transmute(self);
|
||||||
this.get_width()
|
this.get_width()
|
||||||
|
} else {
|
||||||
|
panic!("I'm not a table or table cell!")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -319,6 +337,61 @@ impl RawLayoutElementHelpers for Element {
|
||||||
this.get_checked_state_for_layout()
|
this.get_checked_state_for_layout()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn get_unsigned_integer_attribute_for_layout(&self,
|
||||||
|
attribute: UnsignedIntegerAttribute)
|
||||||
|
-> Option<u32> {
|
||||||
|
match attribute {
|
||||||
|
BorderUnsignedIntegerAttribute => {
|
||||||
|
if self.is_htmltableelement() {
|
||||||
|
let this: &HTMLTableElement = mem::transmute(self);
|
||||||
|
this.get_border()
|
||||||
|
} else {
|
||||||
|
// Don't panic since `:-servo-nonzero-border` can cause this to be called on
|
||||||
|
// arbitrary elements.
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ColSpanUnsignedIntegerAttribute => {
|
||||||
|
if self.is_htmltablecellelement() {
|
||||||
|
let this: &HTMLTableCellElement = mem::transmute(self);
|
||||||
|
this.get_colspan()
|
||||||
|
} else {
|
||||||
|
// Don't panic since `display` can cause this to be called on arbitrary
|
||||||
|
// elements.
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[allow(unrooted_must_root)]
|
||||||
|
unsafe fn get_simple_color_attribute_for_layout(&self, attribute: SimpleColorAttribute)
|
||||||
|
-> Option<RGBA> {
|
||||||
|
match attribute {
|
||||||
|
BgColorSimpleColorAttribute => {
|
||||||
|
if self.is_htmlbodyelement() {
|
||||||
|
let this: &HTMLBodyElement = mem::transmute(self);
|
||||||
|
this.get_background_color()
|
||||||
|
} else if self.is_htmltableelement() {
|
||||||
|
let this: &HTMLTableElement = mem::transmute(self);
|
||||||
|
this.get_background_color()
|
||||||
|
} else if self.is_htmltablecellelement() {
|
||||||
|
let this: &HTMLTableCellElement = mem::transmute(self);
|
||||||
|
this.get_background_color()
|
||||||
|
} else if self.is_htmltablerowelement() {
|
||||||
|
let this: &HTMLTableRowElement = mem::transmute(self);
|
||||||
|
this.get_background_color()
|
||||||
|
} else if self.is_htmltablesectionelement() {
|
||||||
|
let this: &HTMLTableSectionElement = mem::transmute(self);
|
||||||
|
this.get_background_color()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Getters used in components/layout/wrapper.rs
|
// Getters used in components/layout/wrapper.rs
|
||||||
|
|
||||||
fn local_name<'a>(&'a self) -> &'a Atom {
|
fn local_name<'a>(&'a self) -> &'a Atom {
|
||||||
|
@ -947,7 +1020,10 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
|
||||||
|
|
||||||
// http://dom.spec.whatwg.org/#dom-element-matches
|
// http://dom.spec.whatwg.org/#dom-element-matches
|
||||||
fn Matches(self, selectors: DOMString) -> Fallible<bool> {
|
fn Matches(self, selectors: DOMString) -> Fallible<bool> {
|
||||||
match parse_selector_list_from_str(selectors.as_slice()) {
|
let parser_context = ParserContext {
|
||||||
|
origin: AuthorOrigin,
|
||||||
|
};
|
||||||
|
match style::parse_selector_list_from_str(&parser_context, selectors.as_slice()) {
|
||||||
Err(()) => Err(Syntax),
|
Err(()) => Err(Syntax),
|
||||||
Ok(ref selectors) => {
|
Ok(ref selectors) => {
|
||||||
let root: JSRef<Node> = NodeCast::from_ref(self);
|
let root: JSRef<Node> = NodeCast::from_ref(self);
|
||||||
|
@ -1222,6 +1298,17 @@ impl<'a> style::TElement<'a> for JSRef<'a, Element> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn has_nonzero_border(self) -> bool {
|
||||||
|
match HTMLTableElementCast::to_ref(self) {
|
||||||
|
None => false,
|
||||||
|
Some(this) => {
|
||||||
|
match this.get_border() {
|
||||||
|
None | Some(0) => false,
|
||||||
|
Some(_) => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ActivationElementHelpers<'a> {
|
pub trait ActivationElementHelpers<'a> {
|
||||||
|
|
|
@ -2,11 +2,9 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::attr::Attr;
|
use dom::attr::{Attr, AttrHelpers};
|
||||||
use dom::attr::AttrHelpers;
|
|
||||||
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
||||||
use dom::bindings::codegen::Bindings::HTMLBodyElementBinding;
|
use dom::bindings::codegen::Bindings::HTMLBodyElementBinding::{mod, HTMLBodyElementMethods};
|
||||||
use dom::bindings::codegen::Bindings::HTMLBodyElementBinding::HTMLBodyElementMethods;
|
|
||||||
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
||||||
use dom::bindings::codegen::InheritTypes::EventTargetCast;
|
use dom::bindings::codegen::InheritTypes::EventTargetCast;
|
||||||
use dom::bindings::codegen::InheritTypes::{HTMLBodyElementDerived, HTMLElementCast};
|
use dom::bindings::codegen::InheritTypes::{HTMLBodyElementDerived, HTMLElementCast};
|
||||||
|
@ -19,11 +17,14 @@ use dom::htmlelement::HTMLElement;
|
||||||
use dom::node::{Node, ElementNodeTypeId, window_from_node};
|
use dom::node::{Node, ElementNodeTypeId, window_from_node};
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
|
|
||||||
use servo_util::str::DOMString;
|
use cssparser::RGBA;
|
||||||
|
use servo_util::str::{mod, DOMString};
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct HTMLBodyElement {
|
pub struct HTMLBodyElement {
|
||||||
htmlelement: HTMLElement
|
htmlelement: HTMLElement,
|
||||||
|
background_color: Cell<Option<RGBA>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLBodyElementDerived for EventTarget {
|
impl HTMLBodyElementDerived for EventTarget {
|
||||||
|
@ -33,14 +34,20 @@ impl HTMLBodyElementDerived for EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLBodyElement {
|
impl HTMLBodyElement {
|
||||||
fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLBodyElement {
|
fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>)
|
||||||
|
-> HTMLBodyElement {
|
||||||
HTMLBodyElement {
|
HTMLBodyElement {
|
||||||
htmlelement: HTMLElement::new_inherited(HTMLBodyElementTypeId, localName, prefix, document)
|
htmlelement: HTMLElement::new_inherited(HTMLBodyElementTypeId,
|
||||||
|
localName,
|
||||||
|
prefix,
|
||||||
|
document),
|
||||||
|
background_color: Cell::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> Temporary<HTMLBodyElement> {
|
pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>)
|
||||||
|
-> Temporary<HTMLBodyElement> {
|
||||||
let element = HTMLBodyElement::new_inherited(localName, prefix, document);
|
let element = HTMLBodyElement::new_inherited(localName, prefix, document);
|
||||||
Node::reflect_node(box element, document, HTMLBodyElementBinding::Wrap)
|
Node::reflect_node(box element, document, HTMLBodyElementBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
@ -58,6 +65,16 @@ impl<'a> HTMLBodyElementMethods for JSRef<'a, HTMLBodyElement> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait HTMLBodyElementHelpers {
|
||||||
|
fn get_background_color(&self) -> Option<RGBA>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HTMLBodyElementHelpers for HTMLBodyElement {
|
||||||
|
fn get_background_color(&self) -> Option<RGBA> {
|
||||||
|
self.background_color.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> VirtualMethods for JSRef<'a, HTMLBodyElement> {
|
impl<'a> VirtualMethods for JSRef<'a, HTMLBodyElement> {
|
||||||
fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
|
fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
|
||||||
let element: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
|
let element: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
|
||||||
|
@ -91,6 +108,25 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLBodyElement> {
|
||||||
name.slice_from(2),
|
name.slice_from(2),
|
||||||
attr.value().as_slice().to_string());
|
attr.value().as_slice().to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match attr.local_name() {
|
||||||
|
&atom!("bgcolor") => {
|
||||||
|
self.background_color.set(str::parse_legacy_color(attr.value().as_slice()).ok())
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_remove_attr(&self, attr: JSRef<Attr>) {
|
||||||
|
match self.super_type() {
|
||||||
|
Some(ref s) => s.before_remove_attr(attr),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
match attr.local_name() {
|
||||||
|
&atom!("bgcolor") => self.background_color.set(None),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::attr::Attr;
|
use dom::attr::{Attr, AttrHelpers};
|
||||||
use dom::attr::AttrHelpers;
|
|
||||||
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTableCellElementDerived};
|
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTableCellElementDerived};
|
||||||
use dom::bindings::js::JSRef;
|
use dom::bindings::js::JSRef;
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
|
@ -15,13 +14,15 @@ use dom::htmlelement::HTMLElement;
|
||||||
use dom::node::ElementNodeTypeId;
|
use dom::node::ElementNodeTypeId;
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
|
|
||||||
use servo_util::str::{AutoLpa, DOMString, LengthOrPercentageOrAuto};
|
use cssparser::RGBA;
|
||||||
use servo_util::str;
|
use servo_util::str::{mod, AutoLpa, DOMString, LengthOrPercentageOrAuto};
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct HTMLTableCellElement {
|
pub struct HTMLTableCellElement {
|
||||||
htmlelement: HTMLElement,
|
htmlelement: HTMLElement,
|
||||||
|
background_color: Cell<Option<RGBA>>,
|
||||||
|
colspan: Cell<Option<u32>>,
|
||||||
width: Cell<LengthOrPercentageOrAuto>,
|
width: Cell<LengthOrPercentageOrAuto>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,10 +37,16 @@ impl HTMLTableCellElementDerived for EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLTableCellElement {
|
impl HTMLTableCellElement {
|
||||||
pub fn new_inherited(type_id: ElementTypeId, tag_name: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLTableCellElement {
|
pub fn new_inherited(type_id: ElementTypeId,
|
||||||
|
tag_name: DOMString,
|
||||||
|
prefix: Option<DOMString>,
|
||||||
|
document: JSRef<Document>)
|
||||||
|
-> HTMLTableCellElement {
|
||||||
HTMLTableCellElement {
|
HTMLTableCellElement {
|
||||||
htmlelement: HTMLElement::new_inherited(type_id, tag_name, prefix, document),
|
htmlelement: HTMLElement::new_inherited(type_id, tag_name, prefix, document),
|
||||||
width: Cell::new(AutoLpa)
|
background_color: Cell::new(None),
|
||||||
|
colspan: Cell::new(None),
|
||||||
|
width: Cell::new(AutoLpa),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,10 +57,20 @@ impl HTMLTableCellElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait HTMLTableCellElementHelpers {
|
pub trait HTMLTableCellElementHelpers {
|
||||||
|
fn get_background_color(&self) -> Option<RGBA>;
|
||||||
|
fn get_colspan(&self) -> Option<u32>;
|
||||||
fn get_width(&self) -> LengthOrPercentageOrAuto;
|
fn get_width(&self) -> LengthOrPercentageOrAuto;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLTableCellElementHelpers for HTMLTableCellElement {
|
impl HTMLTableCellElementHelpers for HTMLTableCellElement {
|
||||||
|
fn get_background_color(&self) -> Option<RGBA> {
|
||||||
|
self.background_color.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_colspan(&self) -> Option<u32> {
|
||||||
|
self.colspan.get()
|
||||||
|
}
|
||||||
|
|
||||||
fn get_width(&self) -> LengthOrPercentageOrAuto {
|
fn get_width(&self) -> LengthOrPercentageOrAuto {
|
||||||
self.width.get()
|
self.width.get()
|
||||||
}
|
}
|
||||||
|
@ -72,6 +89,12 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTableCellElement> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match attr.local_name() {
|
match attr.local_name() {
|
||||||
|
&atom!("bgcolor") => {
|
||||||
|
self.background_color.set(str::parse_legacy_color(attr.value().as_slice()).ok())
|
||||||
|
}
|
||||||
|
&atom!("colspan") => {
|
||||||
|
self.colspan.set(str::parse_unsigned_integer(attr.value().as_slice().chars()));
|
||||||
|
}
|
||||||
&atom!("width") => self.width.set(str::parse_length(attr.value().as_slice())),
|
&atom!("width") => self.width.set(str::parse_length(attr.value().as_slice())),
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
@ -84,6 +107,8 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTableCellElement> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match attr.local_name() {
|
match attr.local_name() {
|
||||||
|
&atom!("bgcolor") => self.background_color.set(None),
|
||||||
|
&atom!("colspan") => self.colspan.set(None),
|
||||||
&atom!("width") => self.width.set(AutoLpa),
|
&atom!("width") => self.width.set(AutoLpa),
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::bindings::codegen::Bindings::HTMLTableElementBinding;
|
use dom::attr::{Attr, AttrHelpers};
|
||||||
use dom::bindings::codegen::Bindings::HTMLTableElementBinding::HTMLTableElementMethods;
|
use dom::bindings::codegen::Bindings::HTMLTableElementBinding::HTMLTableElementMethods;
|
||||||
use dom::bindings::codegen::InheritTypes::{HTMLTableElementDerived, NodeCast, HTMLTableCaptionElementCast};
|
use dom::bindings::codegen::Bindings::HTMLTableElementBinding;
|
||||||
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
||||||
|
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTableCaptionElementCast};
|
||||||
|
use dom::bindings::codegen::InheritTypes::{HTMLTableElementDerived, NodeCast};
|
||||||
use dom::bindings::js::{JSRef, Temporary};
|
use dom::bindings::js::{JSRef, Temporary};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
|
@ -14,11 +16,18 @@ use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::htmltablecaptionelement::HTMLTableCaptionElement;
|
use dom::htmltablecaptionelement::HTMLTableCaptionElement;
|
||||||
use dom::node::{Node, NodeHelpers, ElementNodeTypeId};
|
use dom::node::{Node, NodeHelpers, ElementNodeTypeId};
|
||||||
use servo_util::str::DOMString;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
|
|
||||||
|
use cssparser::RGBA;
|
||||||
|
use servo_util::str::{mod, AutoLpa, DOMString, LengthOrPercentageOrAuto};
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct HTMLTableElement {
|
pub struct HTMLTableElement {
|
||||||
htmlelement: HTMLElement,
|
htmlelement: HTMLElement,
|
||||||
|
background_color: Cell<Option<RGBA>>,
|
||||||
|
border: Cell<Option<u32>>,
|
||||||
|
width: Cell<LengthOrPercentageOrAuto>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLTableElementDerived for EventTarget {
|
impl HTMLTableElementDerived for EventTarget {
|
||||||
|
@ -28,14 +37,22 @@ impl HTMLTableElementDerived for EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLTableElement {
|
impl HTMLTableElement {
|
||||||
fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLTableElement {
|
fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>)
|
||||||
|
-> HTMLTableElement {
|
||||||
HTMLTableElement {
|
HTMLTableElement {
|
||||||
htmlelement: HTMLElement::new_inherited(HTMLTableElementTypeId, localName, prefix, document)
|
htmlelement: HTMLElement::new_inherited(HTMLTableElementTypeId,
|
||||||
|
localName,
|
||||||
|
prefix,
|
||||||
|
document),
|
||||||
|
background_color: Cell::new(None),
|
||||||
|
border: Cell::new(None),
|
||||||
|
width: Cell::new(AutoLpa),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> Temporary<HTMLTableElement> {
|
pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>)
|
||||||
|
-> Temporary<HTMLTableElement> {
|
||||||
let element = HTMLTableElement::new_inherited(localName, prefix, document);
|
let element = HTMLTableElement::new_inherited(localName, prefix, document);
|
||||||
Node::reflect_node(box element, document, HTMLTableElementBinding::Wrap)
|
Node::reflect_node(box element, document, HTMLTableElementBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
@ -77,3 +94,66 @@ impl<'a> HTMLTableElementMethods for JSRef<'a, HTMLTableElement> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait HTMLTableElementHelpers {
|
||||||
|
fn get_background_color(&self) -> Option<RGBA>;
|
||||||
|
fn get_border(&self) -> Option<u32>;
|
||||||
|
fn get_width(&self) -> LengthOrPercentageOrAuto;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HTMLTableElementHelpers for HTMLTableElement {
|
||||||
|
fn get_background_color(&self) -> Option<RGBA> {
|
||||||
|
self.background_color.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_border(&self) -> Option<u32> {
|
||||||
|
self.border.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_width(&self) -> LengthOrPercentageOrAuto {
|
||||||
|
self.width.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> VirtualMethods for JSRef<'a, HTMLTableElement> {
|
||||||
|
fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
|
||||||
|
let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
|
||||||
|
Some(htmlelement as &VirtualMethods)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_set_attr(&self, attr: JSRef<Attr>) {
|
||||||
|
match self.super_type() {
|
||||||
|
Some(ref s) => s.after_set_attr(attr),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
match attr.local_name() {
|
||||||
|
&atom!("bgcolor") => {
|
||||||
|
self.background_color.set(str::parse_legacy_color(attr.value().as_slice()).ok())
|
||||||
|
}
|
||||||
|
&atom!("border") => {
|
||||||
|
// According to HTML5 § 14.3.9, invalid values map to 1px.
|
||||||
|
self.border.set(Some(str::parse_unsigned_integer(attr.value()
|
||||||
|
.as_slice()
|
||||||
|
.chars()).unwrap_or(1)))
|
||||||
|
}
|
||||||
|
&atom!("width") => self.width.set(str::parse_length(attr.value().as_slice())),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_remove_attr(&self, attr: JSRef<Attr>) {
|
||||||
|
match self.super_type() {
|
||||||
|
Some(ref s) => s.before_remove_attr(attr),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
match attr.local_name() {
|
||||||
|
&atom!("bgcolor") => self.background_color.set(None),
|
||||||
|
&atom!("border") => self.border.set(None),
|
||||||
|
&atom!("width") => self.width.set(AutoLpa),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use dom::attr::{Attr, AttrHelpers};
|
||||||
use dom::bindings::codegen::Bindings::HTMLTableRowElementBinding;
|
use dom::bindings::codegen::Bindings::HTMLTableRowElementBinding;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLTableRowElementDerived;
|
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTableRowElementDerived};
|
||||||
use dom::bindings::js::{JSRef, Temporary};
|
use dom::bindings::js::{JSRef, Temporary};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
|
@ -11,11 +12,16 @@ use dom::element::HTMLTableRowElementTypeId;
|
||||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::node::{Node, ElementNodeTypeId};
|
use dom::node::{Node, ElementNodeTypeId};
|
||||||
use servo_util::str::DOMString;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
|
|
||||||
|
use cssparser::RGBA;
|
||||||
|
use servo_util::str::{mod, DOMString};
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct HTMLTableRowElement {
|
pub struct HTMLTableRowElement {
|
||||||
htmlelement: HTMLElement,
|
htmlelement: HTMLElement,
|
||||||
|
background_color: Cell<Option<RGBA>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLTableRowElementDerived for EventTarget {
|
impl HTMLTableRowElementDerived for EventTarget {
|
||||||
|
@ -25,9 +31,14 @@ impl HTMLTableRowElementDerived for EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLTableRowElement {
|
impl HTMLTableRowElement {
|
||||||
fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLTableRowElement {
|
fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>)
|
||||||
|
-> HTMLTableRowElement {
|
||||||
HTMLTableRowElement {
|
HTMLTableRowElement {
|
||||||
htmlelement: HTMLElement::new_inherited(HTMLTableRowElementTypeId, localName, prefix, document)
|
htmlelement: HTMLElement::new_inherited(HTMLTableRowElementTypeId,
|
||||||
|
localName,
|
||||||
|
prefix,
|
||||||
|
document),
|
||||||
|
background_color: Cell::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,3 +56,47 @@ impl Reflectable for HTMLTableRowElement {
|
||||||
self.htmlelement.reflector()
|
self.htmlelement.reflector()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait HTMLTableRowElementHelpers {
|
||||||
|
fn get_background_color(&self) -> Option<RGBA>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HTMLTableRowElementHelpers for HTMLTableRowElement {
|
||||||
|
fn get_background_color(&self) -> Option<RGBA> {
|
||||||
|
self.background_color.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> VirtualMethods for JSRef<'a, HTMLTableRowElement> {
|
||||||
|
fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
|
||||||
|
let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
|
||||||
|
Some(htmlelement as &VirtualMethods)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_set_attr(&self, attr: JSRef<Attr>) {
|
||||||
|
match self.super_type() {
|
||||||
|
Some(ref s) => s.after_set_attr(attr),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
match attr.local_name() {
|
||||||
|
&atom!("bgcolor") => {
|
||||||
|
self.background_color.set(str::parse_legacy_color(attr.value().as_slice()).ok())
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_remove_attr(&self, attr: JSRef<Attr>) {
|
||||||
|
match self.super_type() {
|
||||||
|
Some(ref s) => s.before_remove_attr(attr),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
match attr.local_name() {
|
||||||
|
&atom!("bgcolor") => self.background_color.set(None),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use dom::attr::{Attr, AttrHelpers};
|
||||||
use dom::bindings::codegen::Bindings::HTMLTableSectionElementBinding;
|
use dom::bindings::codegen::Bindings::HTMLTableSectionElementBinding;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLTableSectionElementDerived;
|
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTableSectionElementDerived};
|
||||||
use dom::bindings::js::{JSRef, Temporary};
|
use dom::bindings::js::{JSRef, Temporary};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
|
@ -11,11 +12,16 @@ use dom::element::HTMLTableSectionElementTypeId;
|
||||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::node::{Node, ElementNodeTypeId};
|
use dom::node::{Node, ElementNodeTypeId};
|
||||||
use servo_util::str::DOMString;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
|
|
||||||
|
use cssparser::RGBA;
|
||||||
|
use servo_util::str::{mod, DOMString};
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct HTMLTableSectionElement {
|
pub struct HTMLTableSectionElement {
|
||||||
htmlelement: HTMLElement,
|
htmlelement: HTMLElement,
|
||||||
|
background_color: Cell<Option<RGBA>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLTableSectionElementDerived for EventTarget {
|
impl HTMLTableSectionElementDerived for EventTarget {
|
||||||
|
@ -25,14 +31,20 @@ impl HTMLTableSectionElementDerived for EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLTableSectionElement {
|
impl HTMLTableSectionElement {
|
||||||
fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLTableSectionElement {
|
fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>)
|
||||||
|
-> HTMLTableSectionElement {
|
||||||
HTMLTableSectionElement {
|
HTMLTableSectionElement {
|
||||||
htmlelement: HTMLElement::new_inherited(HTMLTableSectionElementTypeId, localName, prefix, document)
|
htmlelement: HTMLElement::new_inherited(HTMLTableSectionElementTypeId,
|
||||||
|
localName,
|
||||||
|
prefix,
|
||||||
|
document),
|
||||||
|
background_color: Cell::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> Temporary<HTMLTableSectionElement> {
|
pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>)
|
||||||
|
-> Temporary<HTMLTableSectionElement> {
|
||||||
let element = HTMLTableSectionElement::new_inherited(localName, prefix, document);
|
let element = HTMLTableSectionElement::new_inherited(localName, prefix, document);
|
||||||
Node::reflect_node(box element, document, HTMLTableSectionElementBinding::Wrap)
|
Node::reflect_node(box element, document, HTMLTableSectionElementBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
@ -43,3 +55,47 @@ impl Reflectable for HTMLTableSectionElement {
|
||||||
self.htmlelement.reflector()
|
self.htmlelement.reflector()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait HTMLTableSectionElementHelpers {
|
||||||
|
fn get_background_color(&self) -> Option<RGBA>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HTMLTableSectionElementHelpers for HTMLTableSectionElement {
|
||||||
|
fn get_background_color(&self) -> Option<RGBA> {
|
||||||
|
self.background_color.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> VirtualMethods for JSRef<'a, HTMLTableSectionElement> {
|
||||||
|
fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
|
||||||
|
let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
|
||||||
|
Some(htmlelement as &VirtualMethods)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_set_attr(&self, attr: JSRef<Attr>) {
|
||||||
|
match self.super_type() {
|
||||||
|
Some(ref s) => s.after_set_attr(attr),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
match attr.local_name() {
|
||||||
|
&atom!("bgcolor") => {
|
||||||
|
self.background_color.set(str::parse_legacy_color(attr.value().as_slice()).ok())
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_remove_attr(&self, attr: JSRef<Attr>) {
|
||||||
|
match self.super_type() {
|
||||||
|
Some(ref s) => s.before_remove_attr(attr),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
match attr.local_name() {
|
||||||
|
&atom!("bgcolor") => self.background_color.set(None),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ use devtools_traits::NodeInfo;
|
||||||
use script_traits::UntrustedNodeAddress;
|
use script_traits::UntrustedNodeAddress;
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use servo_util::str::{DOMString, null_str_as_empty};
|
use servo_util::str::{DOMString, null_str_as_empty};
|
||||||
use style::{parse_selector_list_from_str, matches, SelectorList};
|
use style::{matches, AuthorOrigin, ParserContext, SelectorList};
|
||||||
|
|
||||||
use js::jsapi::{JSContext, JSObject, JSTracer, JSRuntime};
|
use js::jsapi::{JSContext, JSObject, JSTracer, JSRuntime};
|
||||||
use js::jsfriendapi;
|
use js::jsfriendapi;
|
||||||
|
@ -60,8 +60,7 @@ use std::cell::{Cell, RefCell, Ref, RefMut};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::iter::{FilterMap, Peekable};
|
use std::iter::{FilterMap, Peekable};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use style;
|
use style::{mod, ComputedValues};
|
||||||
use style::ComputedValues;
|
|
||||||
use sync::Arc;
|
use sync::Arc;
|
||||||
use uuid;
|
use uuid;
|
||||||
use string_cache::QualName;
|
use string_cache::QualName;
|
||||||
|
@ -741,7 +740,10 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> {
|
||||||
// http://dom.spec.whatwg.org/#dom-parentnode-queryselector
|
// http://dom.spec.whatwg.org/#dom-parentnode-queryselector
|
||||||
fn query_selector(self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>> {
|
fn query_selector(self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>> {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
match parse_selector_list_from_str(selectors.as_slice()) {
|
let parser_context = ParserContext {
|
||||||
|
origin: AuthorOrigin,
|
||||||
|
};
|
||||||
|
match style::parse_selector_list_from_str(&parser_context, selectors.as_slice()) {
|
||||||
// Step 2.
|
// Step 2.
|
||||||
Err(()) => return Err(Syntax),
|
Err(()) => return Err(Syntax),
|
||||||
// Step 3.
|
// Step 3.
|
||||||
|
@ -758,11 +760,15 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> {
|
||||||
/// Get an iterator over all nodes which match a set of selectors
|
/// Get an iterator over all nodes which match a set of selectors
|
||||||
/// Be careful not to do anything which may manipulate the DOM tree whilst iterating, otherwise
|
/// Be careful not to do anything which may manipulate the DOM tree whilst iterating, otherwise
|
||||||
/// the iterator may be invalidated
|
/// the iterator may be invalidated
|
||||||
unsafe fn query_selector_iter(self, selectors: DOMString) -> Fallible<QuerySelectorIterator<'a>> {
|
unsafe fn query_selector_iter(self, selectors: DOMString)
|
||||||
|
-> Fallible<QuerySelectorIterator<'a>> {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
let nodes;
|
let nodes;
|
||||||
let root = self.ancestors().last().unwrap_or(self.clone());
|
let root = self.ancestors().last().unwrap_or(self.clone());
|
||||||
match parse_selector_list_from_str(selectors.as_slice()) {
|
let parser_context = ParserContext {
|
||||||
|
origin: AuthorOrigin,
|
||||||
|
};
|
||||||
|
match style::parse_selector_list_from_str(&parser_context, selectors.as_slice()) {
|
||||||
// Step 2.
|
// Step 2.
|
||||||
Err(()) => return Err(Syntax),
|
Err(()) => return Err(Syntax),
|
||||||
// Step 3.
|
// Step 3.
|
||||||
|
|
|
@ -22,7 +22,10 @@ use dom::bindings::codegen::InheritTypes::HTMLOptionElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLScriptElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLScriptElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLSelectElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLSelectElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLStyleElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLStyleElementCast;
|
||||||
|
use dom::bindings::codegen::InheritTypes::HTMLTableElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLTableCellElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLTableCellElementCast;
|
||||||
|
use dom::bindings::codegen::InheritTypes::HTMLTableRowElementCast;
|
||||||
|
use dom::bindings::codegen::InheritTypes::HTMLTableSectionElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLTextAreaElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLTextAreaElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLTitleElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLTitleElementCast;
|
||||||
use dom::bindings::js::JSRef;
|
use dom::bindings::js::JSRef;
|
||||||
|
@ -46,7 +49,10 @@ use dom::element::HTMLScriptElementTypeId;
|
||||||
use dom::element::HTMLSelectElementTypeId;
|
use dom::element::HTMLSelectElementTypeId;
|
||||||
use dom::element::HTMLStyleElementTypeId;
|
use dom::element::HTMLStyleElementTypeId;
|
||||||
use dom::element::HTMLTableDataCellElementTypeId;
|
use dom::element::HTMLTableDataCellElementTypeId;
|
||||||
|
use dom::element::HTMLTableElementTypeId;
|
||||||
use dom::element::HTMLTableHeaderCellElementTypeId;
|
use dom::element::HTMLTableHeaderCellElementTypeId;
|
||||||
|
use dom::element::HTMLTableRowElementTypeId;
|
||||||
|
use dom::element::HTMLTableSectionElementTypeId;
|
||||||
use dom::element::HTMLTextAreaElementTypeId;
|
use dom::element::HTMLTextAreaElementTypeId;
|
||||||
use dom::element::HTMLTitleElementTypeId;
|
use dom::element::HTMLTitleElementTypeId;
|
||||||
use dom::event::Event;
|
use dom::event::Event;
|
||||||
|
@ -67,7 +73,10 @@ use dom::htmloptionelement::HTMLOptionElement;
|
||||||
use dom::htmlscriptelement::HTMLScriptElement;
|
use dom::htmlscriptelement::HTMLScriptElement;
|
||||||
use dom::htmlselectelement::HTMLSelectElement;
|
use dom::htmlselectelement::HTMLSelectElement;
|
||||||
use dom::htmlstyleelement::HTMLStyleElement;
|
use dom::htmlstyleelement::HTMLStyleElement;
|
||||||
|
use dom::htmltableelement::HTMLTableElement;
|
||||||
use dom::htmltablecellelement::HTMLTableCellElement;
|
use dom::htmltablecellelement::HTMLTableCellElement;
|
||||||
|
use dom::htmltablerowelement::HTMLTableRowElement;
|
||||||
|
use dom::htmltablesectionelement::HTMLTableSectionElement;
|
||||||
use dom::htmltextareaelement::HTMLTextAreaElement;
|
use dom::htmltextareaelement::HTMLTextAreaElement;
|
||||||
use dom::htmltitleelement::HTMLTitleElement;
|
use dom::htmltitleelement::HTMLTitleElement;
|
||||||
use dom::node::{Node, NodeHelpers, ElementNodeTypeId, CloneChildrenFlag};
|
use dom::node::{Node, NodeHelpers, ElementNodeTypeId, CloneChildrenFlag};
|
||||||
|
@ -226,9 +235,25 @@ pub fn vtable_for<'a>(node: &'a JSRef<'a, Node>) -> &'a VirtualMethods + 'a {
|
||||||
let element: &'a JSRef<'a, HTMLStyleElement> = HTMLStyleElementCast::to_borrowed_ref(node).unwrap();
|
let element: &'a JSRef<'a, HTMLStyleElement> = HTMLStyleElementCast::to_borrowed_ref(node).unwrap();
|
||||||
element as &'a VirtualMethods + 'a
|
element as &'a VirtualMethods + 'a
|
||||||
}
|
}
|
||||||
|
ElementNodeTypeId(HTMLTableElementTypeId) => {
|
||||||
|
let element: &'a JSRef<'a, HTMLTableElement> =
|
||||||
|
HTMLTableElementCast::to_borrowed_ref(node).unwrap();
|
||||||
|
element as &'a VirtualMethods + 'a
|
||||||
|
}
|
||||||
ElementNodeTypeId(HTMLTableDataCellElementTypeId) |
|
ElementNodeTypeId(HTMLTableDataCellElementTypeId) |
|
||||||
ElementNodeTypeId(HTMLTableHeaderCellElementTypeId) => {
|
ElementNodeTypeId(HTMLTableHeaderCellElementTypeId) => {
|
||||||
let element: &'a JSRef<'a, HTMLTableCellElement> = HTMLTableCellElementCast::to_borrowed_ref(node).unwrap();
|
let element: &'a JSRef<'a, HTMLTableCellElement> =
|
||||||
|
HTMLTableCellElementCast::to_borrowed_ref(node).unwrap();
|
||||||
|
element as &'a VirtualMethods + 'a
|
||||||
|
}
|
||||||
|
ElementNodeTypeId(HTMLTableRowElementTypeId) => {
|
||||||
|
let element: &'a JSRef<'a, HTMLTableRowElement> =
|
||||||
|
HTMLTableRowElementCast::to_borrowed_ref(node).unwrap();
|
||||||
|
element as &'a VirtualMethods + 'a
|
||||||
|
}
|
||||||
|
ElementNodeTypeId(HTMLTableSectionElementTypeId) => {
|
||||||
|
let element: &'a JSRef<'a, HTMLTableSectionElement> =
|
||||||
|
HTMLTableSectionElementCast::to_borrowed_ref(node).unwrap();
|
||||||
element as &'a VirtualMethods + 'a
|
element as &'a VirtualMethods + 'a
|
||||||
}
|
}
|
||||||
ElementNodeTypeId(HTMLTextAreaElementTypeId) => {
|
ElementNodeTypeId(HTMLTextAreaElementTypeId) => {
|
||||||
|
|
|
@ -29,6 +29,9 @@ pub enum Msg {
|
||||||
/// Adds the given stylesheet to the document.
|
/// Adds the given stylesheet to the document.
|
||||||
LoadStylesheetMsg(Url),
|
LoadStylesheetMsg(Url),
|
||||||
|
|
||||||
|
/// Puts a document into quirks mode, causing the quirks mode stylesheet to be loaded.
|
||||||
|
SetQuirksModeMsg,
|
||||||
|
|
||||||
/// Requests a reflow.
|
/// Requests a reflow.
|
||||||
ReflowMsg(Box<Reflow>),
|
ReflowMsg(Box<Reflow>),
|
||||||
|
|
||||||
|
|
4
components/servo/Cargo.lock
generated
4
components/servo/Cargo.lock
generated
|
@ -121,7 +121,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cssparser"
|
name = "cssparser"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/rust-cssparser#cbbfd66f794bd019bbdeaefc88b29eff455b62e5"
|
source = "git+https://github.com/servo/rust-cssparser#3f98f1308b769b5d61efc6c133ac520df2b074ac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"encoding 0.2.0 (git+https://github.com/lifthrasiir/rust-encoding)",
|
"encoding 0.2.0 (git+https://github.com/lifthrasiir/rust-encoding)",
|
||||||
]
|
]
|
||||||
|
@ -410,6 +410,7 @@ dependencies = [
|
||||||
name = "layout"
|
name = "layout"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cssparser 0.1.0 (git+https://github.com/servo/rust-cssparser)",
|
||||||
"encoding 0.2.0 (git+https://github.com/lifthrasiir/rust-encoding)",
|
"encoding 0.2.0 (git+https://github.com/lifthrasiir/rust-encoding)",
|
||||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
||||||
"gfx 0.0.1",
|
"gfx 0.0.1",
|
||||||
|
@ -672,6 +673,7 @@ dependencies = [
|
||||||
name = "util"
|
name = "util"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cssparser 0.1.0 (git+https://github.com/servo/rust-cssparser)",
|
||||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
||||||
"layers 0.1.0 (git+https://github.com/servo/rust-layers)",
|
"layers 0.1.0 (git+https://github.com/servo/rust-layers)",
|
||||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)",
|
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)",
|
||||||
|
|
|
@ -5,6 +5,17 @@
|
||||||
//! Legacy presentational attributes defined in the HTML5 specification: `<td width>`,
|
//! Legacy presentational attributes defined in the HTML5 specification: `<td width>`,
|
||||||
//! `<input size>`, and so forth.
|
//! `<input size>`, and so forth.
|
||||||
|
|
||||||
|
use node::{TElement, TElementAttributes, TNode};
|
||||||
|
use properties::{BackgroundColorDeclaration, BorderBottomWidthDeclaration};
|
||||||
|
use properties::{BorderLeftWidthDeclaration, BorderRightWidthDeclaration};
|
||||||
|
use properties::{BorderTopWidthDeclaration, SpecifiedValue, WidthDeclaration, specified};
|
||||||
|
use selector_matching::{DeclarationBlock, Stylist};
|
||||||
|
|
||||||
|
use cssparser::RGBAColor;
|
||||||
|
use servo_util::geometry::Au;
|
||||||
|
use servo_util::smallvec::VecLike;
|
||||||
|
use servo_util::str::{AutoLpa, LengthLpa, PercentageLpa};
|
||||||
|
|
||||||
/// Legacy presentational attributes that take a length as defined in HTML5 § 2.4.4.4.
|
/// Legacy presentational attributes that take a length as defined in HTML5 § 2.4.4.4.
|
||||||
pub enum LengthAttribute {
|
pub enum LengthAttribute {
|
||||||
/// `<td width>`
|
/// `<td width>`
|
||||||
|
@ -17,3 +28,187 @@ pub enum IntegerAttribute {
|
||||||
SizeIntegerAttribute,
|
SizeIntegerAttribute,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Legacy presentational attributes that take a nonnegative integer as defined in HTML5 § 2.4.4.2.
|
||||||
|
pub enum UnsignedIntegerAttribute {
|
||||||
|
/// `<td border>`
|
||||||
|
BorderUnsignedIntegerAttribute,
|
||||||
|
/// `<td colspan>`
|
||||||
|
ColSpanUnsignedIntegerAttribute,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Legacy presentational attributes that take a simple color as defined in HTML5 § 2.4.6.
|
||||||
|
pub enum SimpleColorAttribute {
|
||||||
|
/// `<body bgcolor>`
|
||||||
|
BgColorSimpleColorAttribute,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extension methods for `Stylist` that cause rules to be synthesized for legacy attributes.
|
||||||
|
pub trait PresentationalHintSynthesis {
|
||||||
|
/// Synthesizes rules from various HTML attributes (mostly legacy junk from HTML4) that confer
|
||||||
|
/// *presentational hints* as defined in the HTML5 specification. This handles stuff like
|
||||||
|
/// `<body bgcolor>`, `<input size>`, `<td width>`, and so forth.
|
||||||
|
///
|
||||||
|
/// NB: Beware! If you add an attribute to this list, be sure to add it to
|
||||||
|
/// `common_style_affecting_attributes` or `rare_style_affecting_attributes` as appropriate. If
|
||||||
|
/// you don't, you risk strange random nondeterministic failures due to false positives in
|
||||||
|
/// style sharing.
|
||||||
|
fn synthesize_presentational_hints_for_legacy_attributes<'a,E,N,V>(
|
||||||
|
&self,
|
||||||
|
node: &N,
|
||||||
|
matching_rules_list: &mut V,
|
||||||
|
shareable: &mut bool)
|
||||||
|
where E: TElement<'a> +
|
||||||
|
TElementAttributes,
|
||||||
|
N: TNode<'a,E>,
|
||||||
|
V: VecLike<DeclarationBlock>;
|
||||||
|
/// Synthesizes rules for the legacy `bgcolor` attribute.
|
||||||
|
fn synthesize_presentational_hint_for_legacy_background_color_attribute<'a,E,V>(
|
||||||
|
&self,
|
||||||
|
element: E,
|
||||||
|
matching_rules_list:
|
||||||
|
&mut V,
|
||||||
|
shareable: &mut bool)
|
||||||
|
where
|
||||||
|
E: TElement<'a> +
|
||||||
|
TElementAttributes,
|
||||||
|
V: VecLike<
|
||||||
|
DeclarationBlock>;
|
||||||
|
/// Synthesizes rules for the legacy `border` attribute.
|
||||||
|
fn synthesize_presentational_hint_for_legacy_border_attribute<'a,E,V>(
|
||||||
|
&self,
|
||||||
|
element: E,
|
||||||
|
matching_rules_list: &mut V,
|
||||||
|
shareable: &mut bool)
|
||||||
|
where
|
||||||
|
E: TElement<'a> +
|
||||||
|
TElementAttributes,
|
||||||
|
V: VecLike<DeclarationBlock>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PresentationalHintSynthesis for Stylist {
|
||||||
|
fn synthesize_presentational_hints_for_legacy_attributes<'a,E,N,V>(
|
||||||
|
&self,
|
||||||
|
node: &N,
|
||||||
|
matching_rules_list: &mut V,
|
||||||
|
shareable: &mut bool)
|
||||||
|
where E: TElement<'a> +
|
||||||
|
TElementAttributes,
|
||||||
|
N: TNode<'a,E>,
|
||||||
|
V: VecLike<DeclarationBlock> {
|
||||||
|
let element = node.as_element();
|
||||||
|
match element.get_local_name() {
|
||||||
|
name if *name == atom!("td") => {
|
||||||
|
match element.get_length_attribute(WidthLengthAttribute) {
|
||||||
|
AutoLpa => {}
|
||||||
|
PercentageLpa(percentage) => {
|
||||||
|
let width_value = specified::LPA_Percentage(percentage);
|
||||||
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
|
WidthDeclaration(SpecifiedValue(width_value))));
|
||||||
|
*shareable = false
|
||||||
|
}
|
||||||
|
LengthLpa(length) => {
|
||||||
|
let width_value = specified::LPA_Length(specified::Au_(length));
|
||||||
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
|
WidthDeclaration(SpecifiedValue(width_value))));
|
||||||
|
*shareable = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.synthesize_presentational_hint_for_legacy_background_color_attribute(
|
||||||
|
element,
|
||||||
|
matching_rules_list,
|
||||||
|
shareable);
|
||||||
|
self.synthesize_presentational_hint_for_legacy_border_attribute(
|
||||||
|
element,
|
||||||
|
matching_rules_list,
|
||||||
|
shareable);
|
||||||
|
}
|
||||||
|
name if *name == atom!("table") => {
|
||||||
|
self.synthesize_presentational_hint_for_legacy_background_color_attribute(
|
||||||
|
element,
|
||||||
|
matching_rules_list,
|
||||||
|
shareable);
|
||||||
|
self.synthesize_presentational_hint_for_legacy_border_attribute(
|
||||||
|
element,
|
||||||
|
matching_rules_list,
|
||||||
|
shareable);
|
||||||
|
}
|
||||||
|
name if *name == atom!("body") || *name == atom!("tr") || *name == atom!("thead") ||
|
||||||
|
*name == atom!("tbody") || *name == atom!("tfoot") => {
|
||||||
|
self.synthesize_presentational_hint_for_legacy_background_color_attribute(
|
||||||
|
element,
|
||||||
|
matching_rules_list,
|
||||||
|
shareable);
|
||||||
|
}
|
||||||
|
name if *name == atom!("input") => {
|
||||||
|
match element.get_integer_attribute(SizeIntegerAttribute) {
|
||||||
|
Some(value) if value != 0 => {
|
||||||
|
// Per HTML 4.01 § 17.4, this value is in characters if `type` is `text` or
|
||||||
|
// `password` and in pixels otherwise.
|
||||||
|
//
|
||||||
|
// FIXME(pcwalton): More use of atoms, please!
|
||||||
|
let value = match element.get_attr(&ns!(""), &atom!("type")) {
|
||||||
|
Some("text") | Some("password") => {
|
||||||
|
specified::ServoCharacterWidth(value)
|
||||||
|
}
|
||||||
|
_ => specified::Au_(Au::from_px(value as int)),
|
||||||
|
};
|
||||||
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
|
WidthDeclaration(SpecifiedValue(specified::LPA_Length(
|
||||||
|
value)))));
|
||||||
|
*shareable = false
|
||||||
|
}
|
||||||
|
Some(_) | None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn synthesize_presentational_hint_for_legacy_background_color_attribute<'a,E,V>(
|
||||||
|
&self,
|
||||||
|
element: E,
|
||||||
|
matching_rules_list:
|
||||||
|
&mut V,
|
||||||
|
shareable: &mut bool)
|
||||||
|
where
|
||||||
|
E: TElement<'a> +
|
||||||
|
TElementAttributes,
|
||||||
|
V: VecLike<
|
||||||
|
DeclarationBlock> {
|
||||||
|
match element.get_simple_color_attribute(BgColorSimpleColorAttribute) {
|
||||||
|
None => {}
|
||||||
|
Some(color) => {
|
||||||
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
|
BackgroundColorDeclaration(SpecifiedValue(RGBAColor(color)))));
|
||||||
|
*shareable = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn synthesize_presentational_hint_for_legacy_border_attribute<'a,E,V>(
|
||||||
|
&self,
|
||||||
|
element: E,
|
||||||
|
matching_rules_list: &mut V,
|
||||||
|
shareable: &mut bool)
|
||||||
|
where
|
||||||
|
E: TElement<'a> +
|
||||||
|
TElementAttributes,
|
||||||
|
V: VecLike<DeclarationBlock> {
|
||||||
|
match element.get_unsigned_integer_attribute(BorderUnsignedIntegerAttribute) {
|
||||||
|
None => {}
|
||||||
|
Some(length) => {
|
||||||
|
let width_value = specified::Au_(Au::from_px(length as int));
|
||||||
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
|
BorderTopWidthDeclaration(SpecifiedValue(width_value))));
|
||||||
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
|
BorderLeftWidthDeclaration(SpecifiedValue(width_value))));
|
||||||
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
|
BorderBottomWidthDeclaration(SpecifiedValue(width_value))));
|
||||||
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
|
BorderRightWidthDeclaration(SpecifiedValue(width_value))));
|
||||||
|
*shareable = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,8 @@ pub use selector_matching::{DeclarationBlock, CommonStyleAffectingAttributes};
|
||||||
pub use selector_matching::{CommonStyleAffectingAttributeInfo, CommonStyleAffectingAttributeMode};
|
pub use selector_matching::{CommonStyleAffectingAttributeInfo, CommonStyleAffectingAttributeMode};
|
||||||
pub use selector_matching::{AttrIsPresentMode, AttrIsEqualMode};
|
pub use selector_matching::{AttrIsPresentMode, AttrIsEqualMode};
|
||||||
pub use selector_matching::{matches, matches_simple_selector, common_style_affecting_attributes};
|
pub use selector_matching::{matches, matches_simple_selector, common_style_affecting_attributes};
|
||||||
pub use selector_matching::{RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE,SELECTOR_WHITESPACE};
|
pub use selector_matching::{rare_style_affecting_attributes};
|
||||||
|
pub use selector_matching::{RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE, SELECTOR_WHITESPACE};
|
||||||
pub use properties::{cascade, cascade_anonymous, computed};
|
pub use properties::{cascade, cascade_anonymous, computed};
|
||||||
pub use properties::{PropertyDeclaration, ComputedValues, computed_values, style_structs};
|
pub use properties::{PropertyDeclaration, ComputedValues, computed_values, style_structs};
|
||||||
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
|
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
|
||||||
|
@ -49,11 +50,14 @@ pub use properties::{CSSFloat, DeclaredValue, PropertyDeclarationParseResult};
|
||||||
pub use properties::{Angle, AngleOrCorner, AngleAoc, CornerAoc};
|
pub use properties::{Angle, AngleOrCorner, AngleAoc, CornerAoc};
|
||||||
pub use properties::{Left, Right, Bottom, Top};
|
pub use properties::{Left, Right, Bottom, Top};
|
||||||
pub use node::{TElement, TElementAttributes, TNode};
|
pub use node::{TElement, TElementAttributes, TNode};
|
||||||
pub use selectors::{PseudoElement, Before, After, SelectorList, parse_selector_list_from_str};
|
pub use selectors::{PseudoElement, Before, After, ParserContext, SelectorList};
|
||||||
pub use selectors::{AttrSelector, NamespaceConstraint, SpecificNamespace, AnyNamespace};
|
pub use selectors::{AttrSelector, NamespaceConstraint, SpecificNamespace, AnyNamespace};
|
||||||
pub use selectors::{SimpleSelector,LocalNameSelector};
|
pub use selectors::{SimpleSelector, LocalNameSelector, parse_selector_list_from_str};
|
||||||
pub use cssparser::{Color, RGBA};
|
pub use cssparser::{Color, RGBA};
|
||||||
pub use legacy::{IntegerAttribute, LengthAttribute, SizeIntegerAttribute, WidthLengthAttribute};
|
pub use legacy::{BgColorSimpleColorAttribute, BorderUnsignedIntegerAttribute};
|
||||||
|
pub use legacy::{ColSpanUnsignedIntegerAttribute, IntegerAttribute, LengthAttribute};
|
||||||
|
pub use legacy::{SimpleColorAttribute, SizeIntegerAttribute, UnsignedIntegerAttribute};
|
||||||
|
pub use legacy::{WidthLengthAttribute};
|
||||||
pub use font_face::{Source, LocalSource, UrlSource_};
|
pub use font_face::{Source, LocalSource, UrlSource_};
|
||||||
|
|
||||||
mod stylesheets;
|
mod stylesheets;
|
||||||
|
|
|
@ -8,12 +8,14 @@ use cssparser::ast::*;
|
||||||
|
|
||||||
use errors::{ErrorLoggerIterator, log_css_error};
|
use errors::{ErrorLoggerIterator, log_css_error};
|
||||||
use geom::size::TypedSize2D;
|
use geom::size::TypedSize2D;
|
||||||
use stylesheets::{CSSRule, CSSMediaRule, parse_style_rule, parse_nested_at_rule};
|
use selectors::ParserContext;
|
||||||
|
use stylesheets::{CSSRule, CSSMediaRule};
|
||||||
use namespaces::NamespaceMap;
|
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::ViewportPx;
|
use servo_util::geometry::ViewportPx;
|
||||||
|
use stylesheets;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub struct MediaRule {
|
pub struct MediaRule {
|
||||||
|
@ -95,8 +97,11 @@ impl Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_media_rule(rule: AtRule, parent_rules: &mut Vec<CSSRule>,
|
pub fn parse_media_rule(context: &ParserContext,
|
||||||
namespaces: &NamespaceMap, base_url: &Url) {
|
rule: AtRule,
|
||||||
|
parent_rules: &mut Vec<CSSRule>,
|
||||||
|
namespaces: &NamespaceMap,
|
||||||
|
base_url: &Url) {
|
||||||
let media_queries = parse_media_query_list(rule.prelude.as_slice());
|
let media_queries = parse_media_query_list(rule.prelude.as_slice());
|
||||||
let block = match rule.block {
|
let block = match rule.block {
|
||||||
Some(block) => block,
|
Some(block) => block,
|
||||||
|
@ -108,9 +113,17 @@ pub fn parse_media_rule(rule: AtRule, parent_rules: &mut Vec<CSSRule>,
|
||||||
let mut rules = vec!();
|
let mut rules = vec!();
|
||||||
for rule in ErrorLoggerIterator(parse_rule_list(block.into_iter())) {
|
for rule in ErrorLoggerIterator(parse_rule_list(block.into_iter())) {
|
||||||
match rule {
|
match rule {
|
||||||
QualifiedRule_(rule) => parse_style_rule(rule, &mut rules, namespaces, base_url),
|
QualifiedRule_(rule) => {
|
||||||
AtRule_(rule) => parse_nested_at_rule(
|
stylesheets::parse_style_rule(context, rule, &mut rules, namespaces, base_url)
|
||||||
rule.name.as_slice().to_ascii_lower().as_slice(), rule, &mut rules, namespaces, base_url),
|
}
|
||||||
|
AtRule_(rule) => {
|
||||||
|
stylesheets::parse_nested_at_rule(context,
|
||||||
|
rule.name.as_slice().to_ascii_lower().as_slice(),
|
||||||
|
rule,
|
||||||
|
&mut rules,
|
||||||
|
namespaces,
|
||||||
|
base_url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parent_rules.push(CSSMediaRule(MediaRule {
|
parent_rules.push(CSSMediaRule(MediaRule {
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
//! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and
|
//! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and
|
||||||
//! style.
|
//! style.
|
||||||
|
|
||||||
use legacy::{IntegerAttribute, LengthAttribute};
|
use cssparser::RGBA;
|
||||||
|
use legacy::{IntegerAttribute, LengthAttribute, SimpleColorAttribute, UnsignedIntegerAttribute};
|
||||||
use selectors::AttrSelector;
|
use selectors::AttrSelector;
|
||||||
use servo_util::str::LengthOrPercentageOrAuto;
|
use servo_util::str::LengthOrPercentageOrAuto;
|
||||||
use string_cache::{Atom, Namespace};
|
use string_cache::{Atom, Namespace};
|
||||||
|
@ -47,6 +48,7 @@ pub trait TElement<'a> : Copy {
|
||||||
fn get_enabled_state(self) -> bool;
|
fn get_enabled_state(self) -> bool;
|
||||||
fn get_checked_state(self) -> bool;
|
fn get_checked_state(self) -> bool;
|
||||||
fn has_class(self, name: &Atom) -> bool;
|
fn has_class(self, name: &Atom) -> bool;
|
||||||
|
fn has_nonzero_border(self) -> bool;
|
||||||
|
|
||||||
// Ordinarily I wouldn't use callbacks like this, but the alternative is
|
// Ordinarily I wouldn't use callbacks like this, but the alternative is
|
||||||
// really messy, since there is a `JSRef` and a `RefCell` involved. Maybe
|
// really messy, since there is a `JSRef` and a `RefCell` involved. Maybe
|
||||||
|
@ -58,4 +60,6 @@ pub trait TElement<'a> : Copy {
|
||||||
pub trait TElementAttributes : Copy {
|
pub trait TElementAttributes : Copy {
|
||||||
fn get_length_attribute(self, attribute: LengthAttribute) -> LengthOrPercentageOrAuto;
|
fn get_length_attribute(self, attribute: LengthAttribute) -> LengthOrPercentageOrAuto;
|
||||||
fn get_integer_attribute(self, attribute: IntegerAttribute) -> Option<i32>;
|
fn get_integer_attribute(self, attribute: IntegerAttribute) -> Option<i32>;
|
||||||
|
fn get_unsigned_integer_attribute(self, attribute: UnsignedIntegerAttribute) -> Option<u32>;
|
||||||
|
fn get_simple_color_attribute(self, attribute: SimpleColorAttribute) -> Option<RGBA>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,21 +11,31 @@ use sync::Arc;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use servo_util::bloom::BloomFilter;
|
use servo_util::bloom::BloomFilter;
|
||||||
use servo_util::geometry::Au;
|
|
||||||
use servo_util::resource_files::read_resource_file;
|
use servo_util::resource_files::read_resource_file;
|
||||||
use servo_util::smallvec::VecLike;
|
use servo_util::smallvec::VecLike;
|
||||||
use servo_util::sort;
|
use servo_util::sort;
|
||||||
use servo_util::str::{AutoLpa, LengthLpa, PercentageLpa};
|
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
|
|
||||||
use legacy::{SizeIntegerAttribute, WidthLengthAttribute};
|
use legacy::PresentationalHintSynthesis;
|
||||||
use media_queries::Device;
|
use media_queries::Device;
|
||||||
use node::{TElement, TElementAttributes, TNode};
|
use node::{TElement, TElementAttributes, TNode};
|
||||||
use properties::{PropertyDeclaration, PropertyDeclarationBlock, SpecifiedValue, WidthDeclaration};
|
use properties::{PropertyDeclaration, PropertyDeclarationBlock};
|
||||||
use properties::{specified};
|
use selectors::{After, AnyLink, AttrDashMatch, AttrEqual};
|
||||||
use selectors::*;
|
use selectors::{AttrExists, AttrIncludes, AttrPrefixMatch};
|
||||||
|
use selectors::{AttrSubstringMatch, AttrSuffixMatch, Before, CaseInsensitive, CaseSensitive};
|
||||||
|
use selectors::{Checked, Child, ClassSelector};
|
||||||
|
use selectors::{CompoundSelector, Descendant, Disabled, Enabled, FirstChild, FirstOfType};
|
||||||
|
use selectors::{Hover, IDSelector, LastChild, LastOfType};
|
||||||
|
use selectors::{LaterSibling, LocalName, LocalNameSelector};
|
||||||
|
use selectors::{NamespaceSelector, Link, Negation};
|
||||||
|
use selectors::{NextSibling, NthChild};
|
||||||
|
use selectors::{NthLastChild, NthLastOfType};
|
||||||
|
use selectors::{NthOfType, OnlyChild, OnlyOfType, PseudoElement, Root};
|
||||||
|
use selectors::{SelectorList, ServoNonzeroBorder, SimpleSelector, Visited};
|
||||||
|
use selectors::{get_selector_list_selectors};
|
||||||
use stylesheets::{Stylesheet, iter_stylesheet_media_rules, iter_stylesheet_style_rules};
|
use stylesheets::{Stylesheet, iter_stylesheet_media_rules, iter_stylesheet_style_rules};
|
||||||
|
|
||||||
|
#[deriving(Clone, PartialEq)]
|
||||||
pub enum StylesheetOrigin {
|
pub enum StylesheetOrigin {
|
||||||
UserAgentOrigin,
|
UserAgentOrigin,
|
||||||
AuthorOrigin,
|
AuthorOrigin,
|
||||||
|
@ -295,7 +305,6 @@ impl Stylist {
|
||||||
after_map: PerPseudoElementSelectorMap::new(),
|
after_map: PerPseudoElementSelectorMap::new(),
|
||||||
rules_source_order: 0u,
|
rules_source_order: 0u,
|
||||||
};
|
};
|
||||||
// FIXME: Add quirks-mode.css in quirks mode.
|
|
||||||
// FIXME: Add iso-8859-9.css when the document’s encoding is ISO-8859-8.
|
// FIXME: Add iso-8859-9.css when the document’s encoding is ISO-8859-8.
|
||||||
// FIXME: presentational-hints.css should be at author origin with zero specificity.
|
// FIXME: presentational-hints.css should be at author origin with zero specificity.
|
||||||
// (Does it make a difference?)
|
// (Does it make a difference?)
|
||||||
|
@ -391,6 +400,15 @@ impl Stylist {
|
||||||
self.is_dirty |= is_dirty;
|
self.is_dirty |= is_dirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_quirks_mode_stylesheet(&mut self) {
|
||||||
|
self.add_stylesheet(Stylesheet::from_bytes(
|
||||||
|
read_resource_file(["quirks-mode.css"]).unwrap().as_slice(),
|
||||||
|
Url::parse("chrome:///quirks-mode.css").unwrap(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
UserAgentOrigin))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_stylesheet(&mut self, stylesheet: Stylesheet) {
|
pub fn add_stylesheet(&mut self, stylesheet: Stylesheet) {
|
||||||
self.stylesheets.push(stylesheet);
|
self.stylesheets.push(stylesheet);
|
||||||
self.is_dirty = true;
|
self.is_dirty = true;
|
||||||
|
@ -477,62 +495,6 @@ impl Stylist {
|
||||||
|
|
||||||
shareable
|
shareable
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Synthesizes rules from various HTML attributes (mostly legacy junk from HTML4) that confer
|
|
||||||
/// *presentational hints* as defined in the HTML5 specification. This handles stuff like
|
|
||||||
/// `<body bgcolor>`, `<input size>`, `<td width>`, and so forth.
|
|
||||||
fn synthesize_presentational_hints_for_legacy_attributes<'a,E,N,V>(
|
|
||||||
&self,
|
|
||||||
node: &N,
|
|
||||||
matching_rules_list: &mut V,
|
|
||||||
shareable: &mut bool)
|
|
||||||
where E: TElement<'a> +
|
|
||||||
TElementAttributes,
|
|
||||||
N: TNode<'a,E>,
|
|
||||||
V: VecLike<DeclarationBlock> {
|
|
||||||
let element = node.as_element();
|
|
||||||
match element.get_local_name() {
|
|
||||||
name if *name == atom!("td") => {
|
|
||||||
match element.get_length_attribute(WidthLengthAttribute) {
|
|
||||||
AutoLpa => {}
|
|
||||||
PercentageLpa(percentage) => {
|
|
||||||
let width_value = specified::LPA_Percentage(percentage);
|
|
||||||
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
|
||||||
WidthDeclaration(SpecifiedValue(width_value))));
|
|
||||||
*shareable = false
|
|
||||||
}
|
|
||||||
LengthLpa(length) => {
|
|
||||||
let width_value = specified::LPA_Length(specified::Au_(length));
|
|
||||||
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
|
||||||
WidthDeclaration(SpecifiedValue(width_value))));
|
|
||||||
*shareable = false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
name if *name == atom!("input") => {
|
|
||||||
match element.get_integer_attribute(SizeIntegerAttribute) {
|
|
||||||
Some(value) if value != 0 => {
|
|
||||||
// Per HTML 4.01 § 17.4, this value is in characters if `type` is `text` or
|
|
||||||
// `password` and in pixels otherwise.
|
|
||||||
//
|
|
||||||
// FIXME(pcwalton): More use of atoms, please!
|
|
||||||
let value = match element.get_attr(&ns!(""), &atom!("type")) {
|
|
||||||
Some("text") | Some("password") => {
|
|
||||||
specified::ServoCharacterWidth(value)
|
|
||||||
}
|
|
||||||
_ => specified::Au_(Au::from_px(value as int)),
|
|
||||||
};
|
|
||||||
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
|
||||||
WidthDeclaration(SpecifiedValue(specified::LPA_Length(
|
|
||||||
value)))));
|
|
||||||
*shareable = false
|
|
||||||
}
|
|
||||||
Some(_) | None => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PerOriginSelectorMap {
|
struct PerOriginSelectorMap {
|
||||||
|
@ -858,6 +820,13 @@ pub fn common_style_affecting_attributes() -> [CommonStyleAffectingAttributeInfo
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attributes that, if present, disable style sharing. All legacy HTML attributes must be in
|
||||||
|
/// either this list or `common_style_affecting_attributes`. See the comment in
|
||||||
|
/// `synthesize_presentational_hints_for_legacy_attributes`.
|
||||||
|
pub fn rare_style_affecting_attributes() -> [Atom, ..3] {
|
||||||
|
[ atom!("bgcolor"), atom!("border"), atom!("colspan") ]
|
||||||
|
}
|
||||||
|
|
||||||
/// Determines whether the given element matches the given single selector.
|
/// Determines whether the given element matches the given single selector.
|
||||||
///
|
///
|
||||||
/// NB: If you add support for any new kinds of selectors to this routine, be sure to set
|
/// NB: If you add support for any new kinds of selectors to this routine, be sure to set
|
||||||
|
@ -1052,6 +1021,12 @@ pub fn matches_simple_selector<'a,E,N>(selector: &SimpleSelector,
|
||||||
matches_generic_nth_child(element, 0, 1, true, true)
|
matches_generic_nth_child(element, 0, 1, true, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ServoNonzeroBorder => {
|
||||||
|
*shareable = false;
|
||||||
|
let elem = element.as_element();
|
||||||
|
elem.has_nonzero_border()
|
||||||
|
}
|
||||||
|
|
||||||
Negation(ref negated) => {
|
Negation(ref negated) => {
|
||||||
*shareable = false;
|
*shareable = false;
|
||||||
!negated.iter().all(|s| matches_simple_selector(s, element, shareable))
|
!negated.iter().all(|s| matches_simple_selector(s, element, shareable))
|
||||||
|
@ -1204,12 +1179,16 @@ mod tests {
|
||||||
/// Each sublist of the result contains the Rules for one StyleRule.
|
/// Each sublist of the result contains the Rules for one StyleRule.
|
||||||
fn get_mock_rules(css_selectors: &[&str]) -> Vec<Vec<Rule>> {
|
fn get_mock_rules(css_selectors: &[&str]) -> Vec<Vec<Rule>> {
|
||||||
use namespaces::NamespaceMap;
|
use namespaces::NamespaceMap;
|
||||||
use selectors::parse_selector_list;
|
use selectors::{ParserContext, parse_selector_list};
|
||||||
|
use selector_matching::AuthorOrigin;
|
||||||
use cssparser::tokenize;
|
use cssparser::tokenize;
|
||||||
|
|
||||||
let namespaces = NamespaceMap::new();
|
let namespaces = NamespaceMap::new();
|
||||||
css_selectors.iter().enumerate().map(|(i, selectors)| {
|
css_selectors.iter().enumerate().map(|(i, selectors)| {
|
||||||
parse_selector_list(tokenize(*selectors).map(|(c, _)| c), &namespaces)
|
let context = ParserContext {
|
||||||
|
origin: AuthorOrigin,
|
||||||
|
};
|
||||||
|
parse_selector_list(&context, tokenize(*selectors).map(|(c, _)| c), &namespaces)
|
||||||
.unwrap().into_iter().map(|s| {
|
.unwrap().into_iter().map(|s| {
|
||||||
Rule {
|
Rule {
|
||||||
selector: s.compound_selectors.clone(),
|
selector: s.compound_selectors.clone(),
|
||||||
|
|
|
@ -9,10 +9,16 @@ use sync::Arc;
|
||||||
use cssparser::ast::*;
|
use cssparser::ast::*;
|
||||||
use cssparser::{tokenize, parse_nth};
|
use cssparser::{tokenize, parse_nth};
|
||||||
|
|
||||||
|
use selector_matching::{StylesheetOrigin, UserAgentOrigin};
|
||||||
use string_cache::{Atom, Namespace};
|
use string_cache::{Atom, Namespace};
|
||||||
|
|
||||||
use namespaces::NamespaceMap;
|
use namespaces::NamespaceMap;
|
||||||
|
|
||||||
|
/// Ambient data used by the parser.
|
||||||
|
pub struct ParserContext {
|
||||||
|
/// The origin of this stylesheet.
|
||||||
|
pub origin: StylesheetOrigin,
|
||||||
|
}
|
||||||
|
|
||||||
#[deriving(PartialEq, Clone)]
|
#[deriving(PartialEq, Clone)]
|
||||||
pub struct Selector {
|
pub struct Selector {
|
||||||
|
@ -79,7 +85,8 @@ pub enum SimpleSelector {
|
||||||
NthLastOfType(i32, i32),
|
NthLastOfType(i32, i32),
|
||||||
FirstOfType,
|
FirstOfType,
|
||||||
LastOfType,
|
LastOfType,
|
||||||
OnlyOfType
|
OnlyOfType,
|
||||||
|
ServoNonzeroBorder,
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,12 +118,6 @@ pub enum NamespaceConstraint {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_selector_list_from_str(input: &str) -> Result<SelectorList, ()> {
|
|
||||||
let namespaces = NamespaceMap::new();
|
|
||||||
let iter = tokenize(input).map(|(token, _)| token);
|
|
||||||
parse_selector_list(iter, &namespaces).map(|s| SelectorList { selectors: s })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Re-exported to script, but opaque.
|
/// Re-exported to script, but opaque.
|
||||||
pub struct SelectorList {
|
pub struct SelectorList {
|
||||||
selectors: Vec<Selector>
|
selectors: Vec<Selector>
|
||||||
|
@ -127,70 +128,9 @@ pub fn get_selector_list_selectors<'a>(selector_list: &'a SelectorList) -> &'a [
|
||||||
selector_list.selectors.as_slice()
|
selector_list.selectors.as_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a comma-separated list of Selectors.
|
|
||||||
/// aka Selector Group in http://www.w3.org/TR/css3-selectors/#grouping
|
|
||||||
///
|
|
||||||
/// Return the Selectors or None if there is an invalid selector.
|
|
||||||
pub fn parse_selector_list<I: Iterator<ComponentValue>>(
|
|
||||||
iter: I, namespaces: &NamespaceMap)
|
|
||||||
-> Result<Vec<Selector>, ()> {
|
|
||||||
let iter = &mut iter.peekable();
|
|
||||||
let mut results = vec![try!(parse_selector(iter, namespaces))];
|
|
||||||
|
|
||||||
loop {
|
|
||||||
skip_whitespace(iter);
|
|
||||||
match iter.peek() {
|
|
||||||
None => break, // EOF
|
|
||||||
Some(&Comma) => {
|
|
||||||
iter.next();
|
|
||||||
}
|
|
||||||
_ => return Err(()),
|
|
||||||
}
|
|
||||||
results.push(try!(parse_selector(iter, namespaces)));
|
|
||||||
}
|
|
||||||
Ok(results)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type Iter<I> = iter::Peekable<ComponentValue, I>;
|
type Iter<I> = iter::Peekable<ComponentValue, I>;
|
||||||
|
|
||||||
/// Build up a Selector.
|
|
||||||
/// selector : simple_selector_sequence [ combinator simple_selector_sequence ]* ;
|
|
||||||
///
|
|
||||||
/// `Err` means invalid selector.
|
|
||||||
fn parse_selector<I: Iterator<ComponentValue>>(
|
|
||||||
iter: &mut Iter<I>, namespaces: &NamespaceMap)
|
|
||||||
-> Result<Selector, ()> {
|
|
||||||
let (first, mut pseudo_element) = try!(parse_simple_selectors(iter, namespaces));
|
|
||||||
let mut compound = CompoundSelector{ simple_selectors: first, next: None };
|
|
||||||
|
|
||||||
while pseudo_element.is_none() {
|
|
||||||
let any_whitespace = skip_whitespace(iter);
|
|
||||||
let combinator = match iter.peek() {
|
|
||||||
None => break, // EOF
|
|
||||||
Some(&Comma) => break,
|
|
||||||
Some(&Delim('>')) => { iter.next(); Child },
|
|
||||||
Some(&Delim('+')) => { iter.next(); NextSibling },
|
|
||||||
Some(&Delim('~')) => { iter.next(); LaterSibling },
|
|
||||||
Some(_) => {
|
|
||||||
if any_whitespace { Descendant }
|
|
||||||
else { return Err(()) }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let (simple_selectors, pseudo) = try!(parse_simple_selectors(iter, namespaces));
|
|
||||||
compound = CompoundSelector {
|
|
||||||
simple_selectors: simple_selectors,
|
|
||||||
next: Some((box compound, combinator))
|
|
||||||
};
|
|
||||||
pseudo_element = pseudo;
|
|
||||||
}
|
|
||||||
Ok(Selector {
|
|
||||||
specificity: compute_specificity(&compound, &pseudo_element),
|
|
||||||
compound_selectors: Arc::new(compound),
|
|
||||||
pseudo_element: pseudo_element,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn compute_specificity(mut selector: &CompoundSelector,
|
fn compute_specificity(mut selector: &CompoundSelector,
|
||||||
pseudo_element: &Option<PseudoElement>) -> u32 {
|
pseudo_element: &Option<PseudoElement>) -> u32 {
|
||||||
|
@ -231,7 +171,7 @@ fn compute_specificity(mut selector: &CompoundSelector,
|
||||||
// | &Empty | &Lang(*)
|
// | &Empty | &Lang(*)
|
||||||
| &NthChild(..) | &NthLastChild(..)
|
| &NthChild(..) | &NthLastChild(..)
|
||||||
| &NthOfType(..) | &NthLastOfType(..)
|
| &NthOfType(..) | &NthLastOfType(..)
|
||||||
| &FirstOfType | &LastOfType | &OnlyOfType
|
| &FirstOfType | &LastOfType | &OnlyOfType | &ServoNonzeroBorder
|
||||||
=> specificity.class_like_selectors += 1,
|
=> specificity.class_like_selectors += 1,
|
||||||
&NamespaceSelector(..) => (),
|
&NamespaceSelector(..) => (),
|
||||||
&Negation(ref negated)
|
&Negation(ref negated)
|
||||||
|
@ -247,32 +187,6 @@ fn compute_specificity(mut selector: &CompoundSelector,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// simple_selector_sequence
|
|
||||||
/// : [ type_selector | universal ] [ HASH | class | attrib | pseudo | negation ]*
|
|
||||||
/// | [ HASH | class | attrib | pseudo | negation ]+
|
|
||||||
///
|
|
||||||
/// `Err(())` means invalid selector
|
|
||||||
fn parse_simple_selectors<I: Iterator<ComponentValue>>(
|
|
||||||
iter: &mut Iter<I>, namespaces: &NamespaceMap)
|
|
||||||
-> Result<(Vec<SimpleSelector>, Option<PseudoElement>), ()> {
|
|
||||||
let mut empty = true;
|
|
||||||
let mut simple_selectors = match try!(parse_type_selector(iter, namespaces)) {
|
|
||||||
None => vec![],
|
|
||||||
Some(s) => { empty = false; s }
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut pseudo_element = None;
|
|
||||||
loop {
|
|
||||||
match try!(parse_one_simple_selector(iter, namespaces, /* inside_negation = */ false)) {
|
|
||||||
None => break,
|
|
||||||
Some(SimpleSelectorResult(s)) => { simple_selectors.push(s); empty = false },
|
|
||||||
Some(PseudoElementResult(p)) => { pseudo_element = Some(p); empty = false; break },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if empty { Err(()) } // An empty selector is invalid
|
|
||||||
else { Ok((simple_selectors, pseudo_element)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// * `Err(())`: Invalid selector, abort
|
/// * `Err(())`: Invalid selector, abort
|
||||||
/// * `Ok(None)`: Not a type selector, could be something else. `iter` was not consumed.
|
/// * `Ok(None)`: Not a type selector, could be something else. `iter` was not consumed.
|
||||||
|
@ -309,67 +223,6 @@ enum SimpleSelectorParseResult {
|
||||||
PseudoElementResult(PseudoElement),
|
PseudoElementResult(PseudoElement),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a simple selector other than a type selector.
|
|
||||||
///
|
|
||||||
/// * `Err(())`: Invalid selector, abort
|
|
||||||
/// * `Ok(None)`: Not a simple selector, could be something else. `iter` was not consumed.
|
|
||||||
/// * `Ok(Some(_))`: Parsed a simple selector or pseudo-element
|
|
||||||
fn parse_one_simple_selector<I: Iterator<ComponentValue>>(
|
|
||||||
iter: &mut Iter<I>, namespaces: &NamespaceMap, inside_negation: bool)
|
|
||||||
-> Result<Option<SimpleSelectorParseResult>, ()> {
|
|
||||||
match iter.peek() {
|
|
||||||
Some(&IDHash(_)) => match iter.next() {
|
|
||||||
Some(IDHash(id)) => Ok(Some(SimpleSelectorResult(
|
|
||||||
IDSelector(Atom::from_slice(id.as_slice()))))),
|
|
||||||
_ => panic!("Implementation error, this should not happen."),
|
|
||||||
},
|
|
||||||
Some(&Delim('.')) => {
|
|
||||||
iter.next();
|
|
||||||
match iter.next() {
|
|
||||||
Some(Ident(class)) => Ok(Some(SimpleSelectorResult(
|
|
||||||
ClassSelector(Atom::from_slice(class.as_slice()))))),
|
|
||||||
_ => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(&SquareBracketBlock(_)) => match iter.next() {
|
|
||||||
Some(SquareBracketBlock(content))
|
|
||||||
=> Ok(Some(SimpleSelectorResult(try!(parse_attribute_selector(content, namespaces))))),
|
|
||||||
_ => panic!("Implementation error, this should not happen."),
|
|
||||||
},
|
|
||||||
Some(&Colon) => {
|
|
||||||
iter.next();
|
|
||||||
match iter.next() {
|
|
||||||
Some(Ident(name)) => match parse_simple_pseudo_class(name.as_slice()) {
|
|
||||||
Err(()) => {
|
|
||||||
match name.as_slice().to_ascii_lower().as_slice() {
|
|
||||||
// Supported CSS 2.1 pseudo-elements only.
|
|
||||||
// ** Do not add to this list! **
|
|
||||||
"before" => Ok(Some(PseudoElementResult(Before))),
|
|
||||||
"after" => Ok(Some(PseudoElementResult(After))),
|
|
||||||
// "first-line" => PseudoElementResult(FirstLine),
|
|
||||||
// "first-letter" => PseudoElementResult(FirstLetter),
|
|
||||||
_ => Err(())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Ok(result) => Ok(Some(SimpleSelectorResult(result))),
|
|
||||||
},
|
|
||||||
Some(Function(name, arguments))
|
|
||||||
=> Ok(Some(SimpleSelectorResult(try!(parse_functional_pseudo_class(
|
|
||||||
name, arguments, namespaces, inside_negation))))),
|
|
||||||
Some(Colon) => {
|
|
||||||
match iter.next() {
|
|
||||||
Some(Ident(name))
|
|
||||||
=> Ok(Some(PseudoElementResult(try!(parse_pseudo_element(name))))),
|
|
||||||
_ => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Ok(None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// * `Err(())`: Invalid selector, abort
|
/// * `Err(())`: Invalid selector, abort
|
||||||
/// * `Ok(None)`: Not a simple selector, could be something else. `iter` was not consumed.
|
/// * `Ok(None)`: Not a simple selector, could be something else. `iter` was not consumed.
|
||||||
|
@ -489,8 +342,224 @@ fn parse_attribute_flags<I: Iterator<ComponentValue>>(iter: &mut Iter<I>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_selector_list_from_str(context: &ParserContext, input: &str)
|
||||||
|
-> Result<SelectorList,()> {
|
||||||
|
let namespaces = NamespaceMap::new();
|
||||||
|
let iter = tokenize(input).map(|(token, _)| token);
|
||||||
|
parse_selector_list(context, iter, &namespaces).map(|s| SelectorList { selectors: s })
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_simple_pseudo_class(name: &str) -> Result<SimpleSelector, ()> {
|
/// Parse a comma-separated list of Selectors.
|
||||||
|
/// aka Selector Group in http://www.w3.org/TR/css3-selectors/#grouping
|
||||||
|
///
|
||||||
|
/// Return the Selectors or None if there is an invalid selector.
|
||||||
|
pub fn parse_selector_list<I>(context: &ParserContext, iter: I, namespaces: &NamespaceMap)
|
||||||
|
-> Result<Vec<Selector>,()>
|
||||||
|
where I: Iterator<ComponentValue> {
|
||||||
|
let iter = &mut iter.peekable();
|
||||||
|
let mut results = vec![try!(parse_selector(context, iter, namespaces))];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
skip_whitespace(iter);
|
||||||
|
match iter.peek() {
|
||||||
|
None => break, // EOF
|
||||||
|
Some(&Comma) => {
|
||||||
|
iter.next();
|
||||||
|
}
|
||||||
|
_ => return Err(()),
|
||||||
|
}
|
||||||
|
results.push(try!(parse_selector(context, iter, namespaces)));
|
||||||
|
}
|
||||||
|
Ok(results)
|
||||||
|
}
|
||||||
|
/// Build up a Selector.
|
||||||
|
/// selector : simple_selector_sequence [ combinator simple_selector_sequence ]* ;
|
||||||
|
///
|
||||||
|
/// `Err` means invalid selector.
|
||||||
|
fn parse_selector<I>(context: &ParserContext, iter: &mut Iter<I>, namespaces: &NamespaceMap)
|
||||||
|
-> Result<Selector,()>
|
||||||
|
where I: Iterator<ComponentValue> {
|
||||||
|
let (first, mut pseudo_element) = try!(parse_simple_selectors(context, iter, namespaces));
|
||||||
|
let mut compound = CompoundSelector{ simple_selectors: first, next: None };
|
||||||
|
|
||||||
|
while pseudo_element.is_none() {
|
||||||
|
let any_whitespace = skip_whitespace(iter);
|
||||||
|
let combinator = match iter.peek() {
|
||||||
|
None => break, // EOF
|
||||||
|
Some(&Comma) => break,
|
||||||
|
Some(&Delim('>')) => { iter.next(); Child },
|
||||||
|
Some(&Delim('+')) => { iter.next(); NextSibling },
|
||||||
|
Some(&Delim('~')) => { iter.next(); LaterSibling },
|
||||||
|
Some(_) => {
|
||||||
|
if any_whitespace { Descendant }
|
||||||
|
else { return Err(()) }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let (simple_selectors, pseudo) = try!(parse_simple_selectors(context, iter, namespaces));
|
||||||
|
compound = CompoundSelector {
|
||||||
|
simple_selectors: simple_selectors,
|
||||||
|
next: Some((box compound, combinator))
|
||||||
|
};
|
||||||
|
pseudo_element = pseudo;
|
||||||
|
}
|
||||||
|
Ok(Selector {
|
||||||
|
specificity: compute_specificity(&compound, &pseudo_element),
|
||||||
|
compound_selectors: Arc::new(compound),
|
||||||
|
pseudo_element: pseudo_element,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Level 3: Parse **one** simple_selector
|
||||||
|
fn parse_negation(context: &ParserContext,
|
||||||
|
arguments: Vec<ComponentValue>,
|
||||||
|
namespaces: &NamespaceMap)
|
||||||
|
-> Result<SimpleSelector,()> {
|
||||||
|
let iter = &mut arguments.into_iter().peekable();
|
||||||
|
match try!(parse_type_selector(iter, namespaces)) {
|
||||||
|
Some(type_selector) => Ok(Negation(type_selector)),
|
||||||
|
None => {
|
||||||
|
match try!(parse_one_simple_selector(context,
|
||||||
|
iter,
|
||||||
|
namespaces,
|
||||||
|
/* inside_negation = */ true)) {
|
||||||
|
Some(SimpleSelectorResult(simple_selector)) => {
|
||||||
|
Ok(Negation(vec![simple_selector]))
|
||||||
|
}
|
||||||
|
_ => Err(())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// simple_selector_sequence
|
||||||
|
/// : [ type_selector | universal ] [ HASH | class | attrib | pseudo | negation ]*
|
||||||
|
/// | [ HASH | class | attrib | pseudo | negation ]+
|
||||||
|
///
|
||||||
|
/// `Err(())` means invalid selector
|
||||||
|
fn parse_simple_selectors<I>(context: &ParserContext,
|
||||||
|
iter: &mut Iter<I>,
|
||||||
|
namespaces: &NamespaceMap)
|
||||||
|
-> Result<(Vec<SimpleSelector>, Option<PseudoElement>),()>
|
||||||
|
where I: Iterator<ComponentValue> {
|
||||||
|
let mut empty = true;
|
||||||
|
let mut simple_selectors = match try!(parse_type_selector(iter, namespaces)) {
|
||||||
|
None => vec![],
|
||||||
|
Some(s) => { empty = false; s }
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut pseudo_element = None;
|
||||||
|
loop {
|
||||||
|
match try!(parse_one_simple_selector(context,
|
||||||
|
iter,
|
||||||
|
namespaces,
|
||||||
|
/* inside_negation = */ false)) {
|
||||||
|
None => break,
|
||||||
|
Some(SimpleSelectorResult(s)) => { simple_selectors.push(s); empty = false },
|
||||||
|
Some(PseudoElementResult(p)) => { pseudo_element = Some(p); empty = false; break },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if empty {
|
||||||
|
// An empty selector is invalid.
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
Ok((simple_selectors, pseudo_element))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_functional_pseudo_class(context: &ParserContext,
|
||||||
|
name: String,
|
||||||
|
arguments: Vec<ComponentValue>,
|
||||||
|
namespaces: &NamespaceMap,
|
||||||
|
inside_negation: bool)
|
||||||
|
-> Result<SimpleSelector,()> {
|
||||||
|
match name.as_slice().to_ascii_lower().as_slice() {
|
||||||
|
// "lang" => parse_lang(arguments),
|
||||||
|
"nth-child" => parse_nth(arguments.as_slice()).map(|(a, b)| NthChild(a, b)),
|
||||||
|
"nth-last-child" => parse_nth(arguments.as_slice()).map(|(a, b)| NthLastChild(a, b)),
|
||||||
|
"nth-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| NthOfType(a, b)),
|
||||||
|
"nth-last-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| NthLastOfType(a, b)),
|
||||||
|
"not" => {
|
||||||
|
if inside_negation {
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
parse_negation(context, arguments, namespaces)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse a simple selector other than a type selector.
|
||||||
|
///
|
||||||
|
/// * `Err(())`: Invalid selector, abort
|
||||||
|
/// * `Ok(None)`: Not a simple selector, could be something else. `iter` was not consumed.
|
||||||
|
/// * `Ok(Some(_))`: Parsed a simple selector or pseudo-element
|
||||||
|
fn parse_one_simple_selector<I>(context: &ParserContext,
|
||||||
|
iter: &mut Iter<I>,
|
||||||
|
namespaces: &NamespaceMap,
|
||||||
|
inside_negation: bool)
|
||||||
|
-> Result<Option<SimpleSelectorParseResult>,()>
|
||||||
|
where I: Iterator<ComponentValue> {
|
||||||
|
match iter.peek() {
|
||||||
|
Some(&IDHash(_)) => match iter.next() {
|
||||||
|
Some(IDHash(id)) => Ok(Some(SimpleSelectorResult(
|
||||||
|
IDSelector(Atom::from_slice(id.as_slice()))))),
|
||||||
|
_ => panic!("Implementation error, this should not happen."),
|
||||||
|
},
|
||||||
|
Some(&Delim('.')) => {
|
||||||
|
iter.next();
|
||||||
|
match iter.next() {
|
||||||
|
Some(Ident(class)) => Ok(Some(SimpleSelectorResult(
|
||||||
|
ClassSelector(Atom::from_slice(class.as_slice()))))),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(&SquareBracketBlock(_)) => match iter.next() {
|
||||||
|
Some(SquareBracketBlock(content))
|
||||||
|
=> Ok(Some(SimpleSelectorResult(try!(parse_attribute_selector(content, namespaces))))),
|
||||||
|
_ => panic!("Implementation error, this should not happen."),
|
||||||
|
},
|
||||||
|
Some(&Colon) => {
|
||||||
|
iter.next();
|
||||||
|
match iter.next() {
|
||||||
|
Some(Ident(name)) => match parse_simple_pseudo_class(context, name.as_slice()) {
|
||||||
|
Err(()) => {
|
||||||
|
match name.as_slice().to_ascii_lower().as_slice() {
|
||||||
|
// Supported CSS 2.1 pseudo-elements only.
|
||||||
|
// ** Do not add to this list! **
|
||||||
|
"before" => Ok(Some(PseudoElementResult(Before))),
|
||||||
|
"after" => Ok(Some(PseudoElementResult(After))),
|
||||||
|
// "first-line" => PseudoElementResult(FirstLine),
|
||||||
|
// "first-letter" => PseudoElementResult(FirstLetter),
|
||||||
|
_ => Err(())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Ok(result) => Ok(Some(SimpleSelectorResult(result))),
|
||||||
|
},
|
||||||
|
Some(Function(name, arguments))
|
||||||
|
=> {
|
||||||
|
Ok(Some(SimpleSelectorResult(try!(parse_functional_pseudo_class(
|
||||||
|
context,
|
||||||
|
name,
|
||||||
|
arguments,
|
||||||
|
namespaces,
|
||||||
|
inside_negation)))))
|
||||||
|
}
|
||||||
|
Some(Colon) => {
|
||||||
|
match iter.next() {
|
||||||
|
Some(Ident(name))
|
||||||
|
=> Ok(Some(PseudoElementResult(try!(parse_pseudo_element(name))))),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_simple_pseudo_class(context: &ParserContext, name: &str) -> Result<SimpleSelector,()> {
|
||||||
match name.to_ascii_lower().as_slice() {
|
match name.to_ascii_lower().as_slice() {
|
||||||
"any-link" => Ok(AnyLink),
|
"any-link" => Ok(AnyLink),
|
||||||
"link" => Ok(Link),
|
"link" => Ok(Link),
|
||||||
|
@ -506,27 +575,12 @@ fn parse_simple_pseudo_class(name: &str) -> Result<SimpleSelector, ()> {
|
||||||
"first-of-type" => Ok(FirstOfType),
|
"first-of-type" => Ok(FirstOfType),
|
||||||
"last-of-type" => Ok(LastOfType),
|
"last-of-type" => Ok(LastOfType),
|
||||||
"only-of-type" => Ok(OnlyOfType),
|
"only-of-type" => Ok(OnlyOfType),
|
||||||
|
"-servo-nonzero-border" if context.origin == UserAgentOrigin => Ok(ServoNonzeroBorder),
|
||||||
// "empty" => Ok(Empty),
|
// "empty" => Ok(Empty),
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn parse_functional_pseudo_class(name: String, arguments: Vec<ComponentValue>,
|
|
||||||
namespaces: &NamespaceMap, inside_negation: bool)
|
|
||||||
-> Result<SimpleSelector, ()> {
|
|
||||||
match name.as_slice().to_ascii_lower().as_slice() {
|
|
||||||
// "lang" => parse_lang(arguments),
|
|
||||||
"nth-child" => parse_nth(arguments.as_slice()).map(|(a, b)| NthChild(a, b)),
|
|
||||||
"nth-last-child" => parse_nth(arguments.as_slice()).map(|(a, b)| NthLastChild(a, b)),
|
|
||||||
"nth-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| NthOfType(a, b)),
|
|
||||||
"nth-last-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| NthLastOfType(a, b)),
|
|
||||||
"not" => if inside_negation { Err(()) } else { parse_negation(arguments, namespaces) },
|
|
||||||
_ => Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn parse_pseudo_element(name: String) -> Result<PseudoElement, ()> {
|
fn parse_pseudo_element(name: String) -> Result<PseudoElement, ()> {
|
||||||
match name.as_slice().to_ascii_lower().as_slice() {
|
match name.as_slice().to_ascii_lower().as_slice() {
|
||||||
// All supported pseudo-elements
|
// All supported pseudo-elements
|
||||||
|
@ -551,21 +605,6 @@ fn parse_pseudo_element(name: String) -> Result<PseudoElement, ()> {
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
|
||||||
/// Level 3: Parse **one** simple_selector
|
|
||||||
fn parse_negation(arguments: Vec<ComponentValue>, namespaces: &NamespaceMap)
|
|
||||||
-> Result<SimpleSelector, ()> {
|
|
||||||
let iter = &mut arguments.into_iter().peekable();
|
|
||||||
match try!(parse_type_selector(iter, namespaces)) {
|
|
||||||
Some(type_selector) => Ok(Negation(type_selector)),
|
|
||||||
None => {
|
|
||||||
match try!(parse_one_simple_selector(iter, namespaces, /* inside_negation = */ true)) {
|
|
||||||
Some(SimpleSelectorResult(simple_selector)) => Ok(Negation(vec![simple_selector])),
|
|
||||||
_ => Err(())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Assuming the next token is an ident, consume it and return its value
|
/// Assuming the next token is an ident, consume it and return its value
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -593,6 +632,7 @@ mod tests {
|
||||||
use sync::Arc;
|
use sync::Arc;
|
||||||
use cssparser;
|
use cssparser;
|
||||||
use namespaces::NamespaceMap;
|
use namespaces::NamespaceMap;
|
||||||
|
use selector_matching::AuthorOrigin;
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -601,7 +641,10 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ns(input: &str, namespaces: &NamespaceMap) -> Result<Vec<Selector>, ()> {
|
fn parse_ns(input: &str, namespaces: &NamespaceMap) -> Result<Vec<Selector>, ()> {
|
||||||
parse_selector_list(cssparser::tokenize(input).map(|(v, _)| v), namespaces)
|
let context = ParserContext {
|
||||||
|
origin: AuthorOrigin,
|
||||||
|
};
|
||||||
|
parse_selector_list(&context, cssparser::tokenize(input).map(|(v, _)| v), namespaces)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn specificity(a: u32, b: u32, c: u32) -> u32 {
|
fn specificity(a: u32, b: u32, c: u32) -> u32 {
|
||||||
|
|
|
@ -10,12 +10,11 @@ use encoding::EncodingRef;
|
||||||
|
|
||||||
use cssparser::{decode_stylesheet_bytes, tokenize, parse_stylesheet_rules, ToCss};
|
use cssparser::{decode_stylesheet_bytes, tokenize, parse_stylesheet_rules, ToCss};
|
||||||
use cssparser::ast::*;
|
use cssparser::ast::*;
|
||||||
use selectors;
|
use selectors::{mod, ParserContext};
|
||||||
use properties;
|
use properties;
|
||||||
use errors::{ErrorLoggerIterator, log_css_error};
|
use errors::{ErrorLoggerIterator, log_css_error};
|
||||||
use namespaces::{NamespaceMap, parse_namespace_rule};
|
use namespaces::{NamespaceMap, parse_namespace_rule};
|
||||||
use media_queries::{Device, MediaRule, parse_media_rule};
|
use media_queries::{mod, Device, MediaRule};
|
||||||
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;
|
use selector_matching::StylesheetOrigin;
|
||||||
|
|
||||||
|
@ -53,9 +52,12 @@ impl Stylesheet {
|
||||||
Stylesheet::from_bytes(bytes.as_slice(), base_url, protocol_encoding_label, environment_encoding, origin)
|
Stylesheet::from_bytes(bytes.as_slice(), base_url, protocol_encoding_label, environment_encoding, origin)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_bytes(
|
pub fn from_bytes(bytes: &[u8],
|
||||||
bytes: &[u8], base_url: Url, protocol_encoding_label: Option<&str>,
|
base_url: Url,
|
||||||
environment_encoding: Option<EncodingRef>, origin: StylesheetOrigin) -> Stylesheet {
|
protocol_encoding_label: Option<&str>,
|
||||||
|
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);
|
||||||
|
@ -67,6 +69,11 @@ impl Stylesheet {
|
||||||
static STATE_IMPORTS: uint = 2;
|
static STATE_IMPORTS: uint = 2;
|
||||||
static STATE_NAMESPACES: uint = 3;
|
static STATE_NAMESPACES: uint = 3;
|
||||||
static STATE_BODY: uint = 4;
|
static STATE_BODY: uint = 4;
|
||||||
|
|
||||||
|
let parser_context = ParserContext {
|
||||||
|
origin: origin,
|
||||||
|
};
|
||||||
|
|
||||||
let mut state: uint = STATE_CHARSET;
|
let mut state: uint = STATE_CHARSET;
|
||||||
|
|
||||||
let mut rules = vec!();
|
let mut rules = vec!();
|
||||||
|
@ -77,7 +84,7 @@ impl Stylesheet {
|
||||||
match rule {
|
match rule {
|
||||||
QualifiedRule_(rule) => {
|
QualifiedRule_(rule) => {
|
||||||
next_state = STATE_BODY;
|
next_state = STATE_BODY;
|
||||||
parse_style_rule(rule, &mut rules, &namespaces, &base_url)
|
parse_style_rule(&parser_context, rule, &mut rules, &namespaces, &base_url)
|
||||||
},
|
},
|
||||||
AtRule_(rule) => {
|
AtRule_(rule) => {
|
||||||
let lower_name = rule.name.as_slice().to_ascii_lower();
|
let lower_name = rule.name.as_slice().to_ascii_lower();
|
||||||
|
@ -114,7 +121,12 @@ impl Stylesheet {
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
next_state = STATE_BODY;
|
next_state = STATE_BODY;
|
||||||
parse_nested_at_rule(lower_name.as_slice(), rule, &mut rules, &namespaces, &base_url)
|
parse_nested_at_rule(&parser_context,
|
||||||
|
lower_name.as_slice(),
|
||||||
|
rule,
|
||||||
|
&mut rules,
|
||||||
|
&namespaces,
|
||||||
|
&base_url)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -128,13 +140,36 @@ impl Stylesheet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lower_name is passed explicitly to avoid computing it twice.
|
||||||
|
pub fn parse_nested_at_rule(context: &ParserContext,
|
||||||
|
lower_name: &str,
|
||||||
|
rule: AtRule,
|
||||||
|
parent_rules: &mut Vec<CSSRule>,
|
||||||
|
namespaces: &NamespaceMap,
|
||||||
|
base_url: &Url) {
|
||||||
|
match lower_name {
|
||||||
|
"media" => {
|
||||||
|
media_queries::parse_media_rule(context, rule, parent_rules, namespaces, base_url)
|
||||||
|
}
|
||||||
|
"font-face" => parse_font_face_rule(rule, parent_rules, base_url),
|
||||||
|
_ => log_css_error(rule.location,
|
||||||
|
format!("Unsupported at-rule: @{:s}", lower_name).as_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_style_rule(rule: QualifiedRule, parent_rules: &mut Vec<CSSRule>,
|
pub fn parse_style_rule(context: &ParserContext,
|
||||||
namespaces: &NamespaceMap, base_url: &Url) {
|
rule: QualifiedRule,
|
||||||
let QualifiedRule { location, prelude, block} = rule;
|
parent_rules: &mut Vec<CSSRule>,
|
||||||
|
namespaces: &NamespaceMap,
|
||||||
|
base_url: &Url) {
|
||||||
|
let QualifiedRule {
|
||||||
|
location,
|
||||||
|
prelude,
|
||||||
|
block
|
||||||
|
} = rule;
|
||||||
// FIXME: avoid doing this for valid selectors
|
// FIXME: avoid doing this for valid selectors
|
||||||
let serialized = prelude.iter().to_css();
|
let serialized = prelude.iter().to_css();
|
||||||
match selectors::parse_selector_list(prelude.into_iter(), namespaces) {
|
match selectors::parse_selector_list(context, prelude.into_iter(), namespaces) {
|
||||||
Ok(selectors) => parent_rules.push(CSSStyleRule(StyleRule{
|
Ok(selectors) => parent_rules.push(CSSStyleRule(StyleRule{
|
||||||
selectors: selectors,
|
selectors: selectors,
|
||||||
declarations: properties::parse_property_declaration_list(block.into_iter(), base_url)
|
declarations: properties::parse_property_declaration_list(block.into_iter(), base_url)
|
||||||
|
@ -144,19 +179,6 @@ pub fn parse_style_rule(rule: QualifiedRule, parent_rules: &mut Vec<CSSRule>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// lower_name is passed explicitly to avoid computing it twice.
|
|
||||||
pub fn parse_nested_at_rule(lower_name: &str, rule: AtRule,
|
|
||||||
parent_rules: &mut Vec<CSSRule>, namespaces: &NamespaceMap, base_url: &Url) {
|
|
||||||
match lower_name {
|
|
||||||
"media" => parse_media_rule(rule, parent_rules, namespaces, base_url),
|
|
||||||
"font-face" => parse_font_face_rule(rule, parent_rules, base_url),
|
|
||||||
_ => log_css_error(rule.location,
|
|
||||||
format!("Unsupported at-rule: @{:s}", lower_name).as_slice())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn iter_style_rules<'a>(rules: &[CSSRule], device: &media_queries::Device,
|
pub fn iter_style_rules<'a>(rules: &[CSSRule], device: &media_queries::Device,
|
||||||
callback: |&StyleRule|) {
|
callback: |&StyleRule|) {
|
||||||
for rule in rules.iter() {
|
for rule in rules.iter() {
|
||||||
|
|
|
@ -7,6 +7,9 @@ authors = ["The Servo Project Developers"]
|
||||||
name = "util"
|
name = "util"
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
||||||
|
[dependencies.cssparser]
|
||||||
|
git = "https://github.com/servo/rust-cssparser"
|
||||||
|
|
||||||
[dependencies.geom]
|
[dependencies.geom]
|
||||||
git = "https://github.com/servo/rust-geom"
|
git = "https://github.com/servo/rust-geom"
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ extern crate log;
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
extern crate collections;
|
extern crate collections;
|
||||||
|
extern crate cssparser;
|
||||||
extern crate geom;
|
extern crate geom;
|
||||||
extern crate getopts;
|
extern crate getopts;
|
||||||
extern crate layers;
|
extern crate layers;
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
use geometry::Au;
|
use geometry::Au;
|
||||||
|
|
||||||
|
use cssparser::{mod, RGBA, RGBAColor};
|
||||||
|
use std::ascii::AsciiExt;
|
||||||
use std::from_str::FromStr;
|
use std::from_str::FromStr;
|
||||||
use std::iter::Filter;
|
use std::iter::Filter;
|
||||||
use std::str::{CharEq, CharSplits};
|
use std::str::{CharEq, CharSplits};
|
||||||
|
@ -61,7 +63,8 @@ pub static HTML_SPACE_CHARACTERS: StaticCharVec = &[
|
||||||
'\u000d',
|
'\u000d',
|
||||||
];
|
];
|
||||||
|
|
||||||
pub fn split_html_space_chars<'a>(s: &'a str) -> Filter<'a, &'a str, CharSplits<'a, StaticCharVec>> {
|
pub fn split_html_space_chars<'a>(s: &'a str)
|
||||||
|
-> Filter<'a, &'a str, CharSplits<'a, StaticCharVec>> {
|
||||||
s.split(HTML_SPACE_CHARACTERS).filter(|&split| !split.is_empty())
|
s.split(HTML_SPACE_CHARACTERS).filter(|&split| !split.is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +79,6 @@ fn do_parse_integer<T: Iterator<char>>(input: T) -> Option<i64> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let mut input = input.skip_while(|c| {
|
let mut input = input.skip_while(|c| {
|
||||||
HTML_SPACE_CHARACTERS.iter().any(|s| s == c)
|
HTML_SPACE_CHARACTERS.iter().any(|s| s == c)
|
||||||
}).peekable();
|
}).peekable();
|
||||||
|
@ -184,6 +186,137 @@ pub fn parse_length(mut value: &str) -> LengthOrPercentageOrAuto {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses a legacy color per HTML5 § 2.4.6. If unparseable, `Err` is returned.
|
||||||
|
pub fn parse_legacy_color(mut input: &str) -> Result<RGBA,()> {
|
||||||
|
// Steps 1 and 2.
|
||||||
|
if input.len() == 0 {
|
||||||
|
return Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3.
|
||||||
|
input = input.trim_left_chars(Whitespace).trim_right_chars(Whitespace);
|
||||||
|
|
||||||
|
// Step 4.
|
||||||
|
if input.eq_ignore_ascii_case("transparent") {
|
||||||
|
return Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5.
|
||||||
|
match cssparser::parse_color_keyword(input) {
|
||||||
|
Ok(RGBAColor(rgba)) => return Ok(rgba),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6.
|
||||||
|
if input.len() == 4 {
|
||||||
|
match (input.as_bytes()[0],
|
||||||
|
hex(input.as_bytes()[1] as char),
|
||||||
|
hex(input.as_bytes()[2] as char),
|
||||||
|
hex(input.as_bytes()[3] as char)) {
|
||||||
|
(b'#', Ok(r), Ok(g), Ok(b)) => {
|
||||||
|
return Ok(RGBA {
|
||||||
|
red: (r as f32) * 17.0 / 255.0,
|
||||||
|
green: (g as f32) * 17.0 / 255.0,
|
||||||
|
blue: (b as f32) * 17.0 / 255.0,
|
||||||
|
alpha: 1.0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7.
|
||||||
|
let mut new_input = String::new();
|
||||||
|
for ch in input.chars() {
|
||||||
|
if ch as u32 > 0xffff {
|
||||||
|
new_input.push_str("00")
|
||||||
|
} else {
|
||||||
|
new_input.push(ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut input = new_input.as_slice();
|
||||||
|
|
||||||
|
// Step 8.
|
||||||
|
for (char_count, (index, _)) in input.char_indices().enumerate() {
|
||||||
|
if char_count == 128 {
|
||||||
|
input = input.slice_to(index);
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 9.
|
||||||
|
if input.char_at(0) == '#' {
|
||||||
|
input = input.slice_from(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 10.
|
||||||
|
let mut new_input = Vec::new();
|
||||||
|
for ch in input.chars() {
|
||||||
|
if hex(ch).is_ok() {
|
||||||
|
new_input.push(ch as u8)
|
||||||
|
} else {
|
||||||
|
new_input.push(b'0')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut input = new_input;
|
||||||
|
|
||||||
|
// Step 11.
|
||||||
|
while input.len() == 0 || (input.len() % 3) != 0 {
|
||||||
|
input.push(b'0')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 12.
|
||||||
|
let mut length = input.len() / 3;
|
||||||
|
let (mut red, mut green, mut blue) = (input.slice_to(length),
|
||||||
|
input.slice(length, length * 2),
|
||||||
|
input.slice_from(length * 2));
|
||||||
|
|
||||||
|
// Step 13.
|
||||||
|
if length > 8 {
|
||||||
|
red = red.slice_from(length - 8);
|
||||||
|
green = green.slice_from(length - 8);
|
||||||
|
blue = blue.slice_from(length - 8);
|
||||||
|
length = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 14.
|
||||||
|
while length > 2 && red[0] == b'0' && green[0] == b'0' && blue[0] == b'0' {
|
||||||
|
red = red.slice_from(1);
|
||||||
|
green = green.slice_from(1);
|
||||||
|
blue = blue.slice_from(1);
|
||||||
|
length -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Steps 15-20.
|
||||||
|
return Ok(RGBA {
|
||||||
|
red: hex_string(red).unwrap() as f32 / 255.0,
|
||||||
|
green: hex_string(green).unwrap() as f32 / 255.0,
|
||||||
|
blue: hex_string(blue).unwrap() as f32 / 255.0,
|
||||||
|
alpha: 1.0,
|
||||||
|
});
|
||||||
|
|
||||||
|
fn hex(ch: char) -> Result<u8,()> {
|
||||||
|
match ch {
|
||||||
|
'0'...'9' => Ok((ch as u8) - b'0'),
|
||||||
|
'a'...'f' => Ok((ch as u8) - b'a' + 10),
|
||||||
|
'A'...'F' => Ok((ch as u8) - b'A' + 10),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hex_string(string: &[u8]) -> Result<u8,()> {
|
||||||
|
match string.len() {
|
||||||
|
0 => Err(()),
|
||||||
|
1 => hex(string[0] as char),
|
||||||
|
_ => {
|
||||||
|
let upper = try!(hex(string[0] as char));
|
||||||
|
let lower = try!(hex(string[1] as char));
|
||||||
|
Ok((upper << 4) | lower)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[deriving(Clone, Eq, PartialEq, Hash, Show)]
|
#[deriving(Clone, Eq, PartialEq, Hash, Show)]
|
||||||
pub struct LowercaseString {
|
pub struct LowercaseString {
|
||||||
|
|
4
ports/cef/Cargo.lock
generated
4
ports/cef/Cargo.lock
generated
|
@ -118,7 +118,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cssparser"
|
name = "cssparser"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/rust-cssparser#cbbfd66f794bd019bbdeaefc88b29eff455b62e5"
|
source = "git+https://github.com/servo/rust-cssparser#3f98f1308b769b5d61efc6c133ac520df2b074ac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"encoding 0.2.0 (git+https://github.com/lifthrasiir/rust-encoding)",
|
"encoding 0.2.0 (git+https://github.com/lifthrasiir/rust-encoding)",
|
||||||
]
|
]
|
||||||
|
@ -380,6 +380,7 @@ dependencies = [
|
||||||
name = "layout"
|
name = "layout"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cssparser 0.1.0 (git+https://github.com/servo/rust-cssparser)",
|
||||||
"encoding 0.2.0 (git+https://github.com/lifthrasiir/rust-encoding)",
|
"encoding 0.2.0 (git+https://github.com/lifthrasiir/rust-encoding)",
|
||||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
||||||
"gfx 0.0.1",
|
"gfx 0.0.1",
|
||||||
|
@ -657,6 +658,7 @@ dependencies = [
|
||||||
name = "util"
|
name = "util"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cssparser 0.1.0 (git+https://github.com/servo/rust-cssparser)",
|
||||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
||||||
"layers 0.1.0 (git+https://github.com/servo/rust-layers)",
|
"layers 0.1.0 (git+https://github.com/servo/rust-layers)",
|
||||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)",
|
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)",
|
||||||
|
|
2
ports/gonk/Cargo.lock
generated
2
ports/gonk/Cargo.lock
generated
|
@ -101,7 +101,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cssparser"
|
name = "cssparser"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/rust-cssparser#cbbfd66f794bd019bbdeaefc88b29eff455b62e5"
|
source = "git+https://github.com/servo/rust-cssparser#3f98f1308b769b5d61efc6c133ac520df2b074ac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"encoding 0.2.0 (git+https://github.com/lifthrasiir/rust-encoding)",
|
"encoding 0.2.0 (git+https://github.com/lifthrasiir/rust-encoding)",
|
||||||
]
|
]
|
||||||
|
|
|
@ -57,12 +57,8 @@ table:matches([rules=none i], [rules=groups i], [rules=rows i], [rules=cols i],
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
table[border] {
|
table:-servo-nonzero-border {
|
||||||
border-style: outset;
|
border-style: outset;
|
||||||
/*
|
|
||||||
FIXME: only if border is not equivalent to zero
|
|
||||||
https://html.spec.whatwg.org/multipage/rendering.html#magic-border-selector
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
table[frame=void i] { border-style: hidden; }
|
table[frame=void i] { border-style: hidden; }
|
||||||
table[frame=above i] { border-style: outset hidden hidden hidden; }
|
table[frame=above i] { border-style: outset hidden hidden hidden; }
|
||||||
|
@ -74,12 +70,14 @@ table[frame=vsides i] { border-style: hidden outset; }
|
||||||
table[frame=box i], table[frame=border i] { border-style: outset; }
|
table[frame=box i], table[frame=border i] { border-style: outset; }
|
||||||
|
|
||||||
|
|
||||||
table[border] > tr > :matches(td, th),
|
table:-servo-nonzero-border > tr > td,
|
||||||
table[border] > :matches(thead, tbody, tfoot) > tr > :matches(td, th) {
|
table:-servo-nonzero-border > tr > th,
|
||||||
/*
|
table:-servo-nonzero-border > thead > tr > td,
|
||||||
FIXME: only if border is not equivalent to zero
|
table:-servo-nonzero-border > thead > tr > th,
|
||||||
https://html.spec.whatwg.org/multipage/rendering.html#magic-border-selector
|
table:-servo-nonzero-border > tbody > tr > td,
|
||||||
*/
|
table:-servo-nonzero-border > tbody > tr > th,
|
||||||
|
table:-servo-nonzero-border > tfoot > tr > td,
|
||||||
|
table:-servo-nonzero-border > tfoot > tr > th {
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-style: inset;
|
border-style: inset;
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,3 +209,7 @@ fragment=top != ../html/acid2.html acid2_ref.html
|
||||||
== box_shadow_inset_parsing_a.html box_shadow_inset_parsing_ref.html
|
== box_shadow_inset_parsing_a.html box_shadow_inset_parsing_ref.html
|
||||||
!= list_style_type_a.html list_style_type_ref.html
|
!= list_style_type_a.html list_style_type_ref.html
|
||||||
== list_style_position_a.html list_style_position_ref.html
|
== list_style_position_a.html list_style_position_ref.html
|
||||||
|
== table_colspan_simple_a.html table_colspan_simple_ref.html
|
||||||
|
== table_colspan_fixed_a.html table_colspan_fixed_ref.html
|
||||||
|
== legacy_td_bgcolor_attribute_a.html legacy_td_bgcolor_attribute_ref.html
|
||||||
|
== legacy_table_border_attribute_a.html legacy_table_border_attribute_ref.html
|
||||||
|
|
16
tests/ref/legacy_table_border_attribute_a.html
Normal file
16
tests/ref/legacy_table_border_attribute_a.html
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
table {
|
||||||
|
border-color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table border=10><tr><td style="border: none">:-)</td></tr></table>
|
||||||
|
<table border=mimi><tr><td style="border: none">:-)</td></tr></table>
|
||||||
|
<table border=0><tr><td style="border: none">:-)</td></tr></table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
11
tests/ref/legacy_table_border_attribute_ref.html
Normal file
11
tests/ref/legacy_table_border_attribute_ref.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<body>
|
||||||
|
<table style="border: outset red 10px"><tr><td>:-)</td></tr></table>
|
||||||
|
<table style="border: outset red 1px"><tr><td>:-)</td></tr></table>
|
||||||
|
<table style="border: none"><tr><td>:-)</td></tr></table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
20
tests/ref/legacy_td_bgcolor_attribute_a.html
Normal file
20
tests/ref/legacy_td_bgcolor_attribute_a.html
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<table border=0 cellspacing=0 cellpadding=0>
|
||||||
|
<tr><td bgcolor=chucknorris width=100> </td></tr>
|
||||||
|
<tr><td bgcolor=ChuckNorris width=100> </td></tr>
|
||||||
|
<tr><td bgcolor=sick width=100> </td></tr>
|
||||||
|
<tr><td bgcolor=crap width=100> </td></tr>
|
||||||
|
<tr><td bgcolor=LuckBeALadyTonight width=100> </td></tr>
|
||||||
|
<tr><td bgcolor=#abc width=100> </td></tr>
|
||||||
|
<tr><td bgcolor=#123456 width=100> </td></tr>
|
||||||
|
<tr><td bgcolor=#abacab width=100> </td></tr>
|
||||||
|
<tr><td bgcolor=#AbaCab width=100> </td></tr>
|
||||||
|
<tr><td bgcolor=#ABACAB width=100> </td></tr>
|
||||||
|
<tr><td bgcolor=transparent width=100> </td></tr>
|
||||||
|
<tr><td bgcolor=gold width=100> </td></tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
21
tests/ref/legacy_td_bgcolor_attribute_ref.html
Normal file
21
tests/ref/legacy_td_bgcolor_attribute_ref.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<table border=0 cellspacing=0 cellpadding=0>
|
||||||
|
<tr><td style="background: #c00000" width=100> </td></tr>
|
||||||
|
<tr><td style="background: #c00000" width=100> </td></tr>
|
||||||
|
<tr><td style="background: #00c000" width=100> </td></tr>
|
||||||
|
<tr><td style="background: #c0a000" width=100> </td></tr>
|
||||||
|
<tr><td style="background: #00a000" width=100> </td></tr>
|
||||||
|
<tr><td style="background: #aabbcc" width=100> </td></tr>
|
||||||
|
<tr><td style="background: #123456" width=100> </td></tr>
|
||||||
|
<tr><td style="background: #abacab" width=100> </td></tr>
|
||||||
|
<tr><td style="background: #abacab" width=100> </td></tr>
|
||||||
|
<tr><td style="background: #abacab" width=100> </td></tr>
|
||||||
|
<tr><td width=100> </td></tr>
|
||||||
|
<tr><td style="background: gold" width=100> </td></tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
26
tests/ref/table_colspan_fixed_a.html
Normal file
26
tests/ref/table_colspan_fixed_a.html
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<style>
|
||||||
|
table {
|
||||||
|
width: 300px;
|
||||||
|
table-layout: fixed;
|
||||||
|
}
|
||||||
|
td[colspan="2"] {
|
||||||
|
background-color: blue;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
td[colspan="3"] {
|
||||||
|
background-color: green;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<table border=0 cellspacing=0 cellpadding=0>
|
||||||
|
<tr><td width=100> </td><td width=100> </td><td width=100> </td></tr>
|
||||||
|
<tr><td colspan=2> </td><td> </td></tr>
|
||||||
|
<tr><td> </td><td colspan=2> </td></tr>
|
||||||
|
<tr><td colspan=3> </td></tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
26
tests/ref/table_colspan_fixed_ref.html
Normal file
26
tests/ref/table_colspan_fixed_ref.html
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<style>
|
||||||
|
table {
|
||||||
|
table-layout: fixed;
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
td.two {
|
||||||
|
background-color: blue;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
td.three {
|
||||||
|
background-color: green;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<table border=0 cellspacing=0 cellpadding=0>
|
||||||
|
<tr><td width=100> </td><td width=100> </td><td width=100> </td></tr>
|
||||||
|
<tr><td class=two> </td><td class=two></td><td> </td></tr>
|
||||||
|
<tr><td> <td class=two> </td><td class=two></td></tr>
|
||||||
|
<tr><td class=three> </td><td class=three></td><td class=three></td></tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
22
tests/ref/table_colspan_simple_a.html
Normal file
22
tests/ref/table_colspan_simple_a.html
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<style>
|
||||||
|
td[colspan="2"] {
|
||||||
|
background-color: blue;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
td[colspan="3"] {
|
||||||
|
background-color: green;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<table border=0 cellspacing=0 cellpadding=0>
|
||||||
|
<tr><td width=100> </td><td width=100> </td><td width=100> </td></tr>
|
||||||
|
<tr><td colspan=2> </td><td> </td></tr>
|
||||||
|
<tr><td> <td colspan=2> </td></tr>
|
||||||
|
<tr><td colspan=3> </td></tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
22
tests/ref/table_colspan_simple_ref.html
Normal file
22
tests/ref/table_colspan_simple_ref.html
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<style>
|
||||||
|
td.two {
|
||||||
|
background-color: blue;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
td.three {
|
||||||
|
background-color: green;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<table border=0 cellspacing=0 cellpadding=0>
|
||||||
|
<tr><td width=100> </td><td width=100> </td><td width=100> </td></tr>
|
||||||
|
<tr><td class=two> </td><td class=two></td><td> </td></tr>
|
||||||
|
<tr><td> <td class=two> </td><td class=two></td></tr>
|
||||||
|
<tr><td class=three> </td><td class=three></td><td class=three></td></tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue