aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/layout/block.rs1
-rw-r--r--components/layout/construct.rs9
-rw-r--r--components/layout/display_list_builder.rs3
-rw-r--r--components/layout/fragment.rs109
-rw-r--r--components/script/dom/create.rs53
-rw-r--r--components/script/dom/mod.rs3
-rw-r--r--components/script/dom/node.rs16
-rw-r--r--components/script/dom/svgelement.rs48
-rw-r--r--components/script/dom/svggraphicselement.rs48
-rw-r--r--components/script/dom/svgsvgelement.rs83
-rw-r--r--components/script/dom/virtualmethods.rs8
-rw-r--r--components/script/dom/webidls/SVGElement.webidl22
-rw-r--r--components/script/dom/webidls/SVGGraphicsElement.webidl22
-rw-r--r--components/script/dom/webidls/SVGSVGElement.webidl45
-rw-r--r--components/script/layout_wrapper.rs7
-rw-r--r--components/script_layout_interface/lib.rs6
-rw-r--r--components/script_layout_interface/wrapper_traits.rs3
17 files changed, 469 insertions, 17 deletions
diff --git a/components/layout/block.rs b/components/layout/block.rs
index 7de8f379560..e28e85d139a 100644
--- a/components/layout/block.rs
+++ b/components/layout/block.rs
@@ -678,6 +678,7 @@ impl BlockFlow {
fn is_replaced_content(&self) -> bool {
match self.fragment.specific {
SpecificFragmentInfo::ScannedText(_) |
+ SpecificFragmentInfo::Svg(_) |
SpecificFragmentInfo::Image(_) |
SpecificFragmentInfo::Canvas(_) |
SpecificFragmentInfo::InlineBlock(_) => true,
diff --git a/components/layout/construct.rs b/components/layout/construct.rs
index 8a463ded66a..ae77f4d7751 100644
--- a/components/layout/construct.rs
+++ b/components/layout/construct.rs
@@ -22,7 +22,7 @@ use floats::FloatKind;
use flow::{self, AbsoluteDescendants, IS_ABSOLUTELY_POSITIONED, ImmutableFlowUtils};
use flow::{CAN_BE_FRAGMENTED, MutableFlowUtils, MutableOwnedFlowUtils};
use flow_ref::{self, FlowRef};
-use fragment::{CanvasFragmentInfo, ImageFragmentInfo, InlineAbsoluteFragmentInfo};
+use fragment::{CanvasFragmentInfo, ImageFragmentInfo, InlineAbsoluteFragmentInfo, SvgFragmentInfo};
use fragment::{Fragment, GeneratedContentInfo, IframeFragmentInfo};
use fragment::{InlineAbsoluteHypotheticalFragmentInfo, TableColumnFragmentInfo};
use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo};
@@ -335,6 +335,10 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let data = node.canvas_data().unwrap();
SpecificFragmentInfo::Canvas(box CanvasFragmentInfo::new(node, data, self.style_context()))
}
+ Some(LayoutNodeType::Element(LayoutElementType::SVGSVGElement)) => {
+ let data = node.svg_data().unwrap();
+ SpecificFragmentInfo::Svg(box SvgFragmentInfo::new(node, data, self.style_context()))
+ }
_ => {
// This includes pseudo-elements.
SpecificFragmentInfo::Generic
@@ -1701,7 +1705,8 @@ impl<ConcreteThreadSafeLayoutNode> NodeUtils for ConcreteThreadSafeLayoutNode
Some(LayoutNodeType::Document) |
Some(LayoutNodeType::Element(LayoutElementType::HTMLImageElement)) |
Some(LayoutNodeType::Element(LayoutElementType::HTMLIFrameElement)) |
- Some(LayoutNodeType::Element(LayoutElementType::HTMLCanvasElement)) => true,
+ Some(LayoutNodeType::Element(LayoutElementType::HTMLCanvasElement)) |
+ Some(LayoutNodeType::Element(LayoutElementType::SVGSVGElement)) => true,
Some(LayoutNodeType::Element(LayoutElementType::HTMLObjectElement)) => self.has_object_data(),
Some(LayoutNodeType::Element(_)) => false,
None => self.get_pseudo_element_type().is_replaced_content(),
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index 91b70ebed34..d163389f1bd 100644
--- a/components/layout/display_list_builder.rs
+++ b/components/layout/display_list_builder.rs
@@ -1239,7 +1239,8 @@ impl FragmentDisplayListBuilding for Fragment {
SpecificFragmentInfo::MulticolColumn |
SpecificFragmentInfo::InlineBlock(_) |
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
- SpecificFragmentInfo::InlineAbsolute(_) => {
+ SpecificFragmentInfo::InlineAbsolute(_) |
+ SpecificFragmentInfo::Svg(_) => {
if opts::get().show_debug_fragment_borders {
self.build_debug_borders_around_fragment(state,
stacking_relative_border_box,
diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs
index a6f3e92f1be..910497daca2 100644
--- a/components/layout/fragment.rs
+++ b/components/layout/fragment.rs
@@ -30,6 +30,7 @@ use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
use range::*;
use rustc_serialize::{Encodable, Encoder};
use script_layout_interface::HTMLCanvasData;
+use script_layout_interface::SVGSVGData;
use script_layout_interface::restyle_damage::{RECONSTRUCT_FLOW, RestyleDamage};
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
use std::borrow::ToOwned;
@@ -155,6 +156,7 @@ pub enum SpecificFragmentInfo {
Iframe(IframeFragmentInfo),
Image(Box<ImageFragmentInfo>),
Canvas(Box<CanvasFragmentInfo>),
+ Svg(Box<SvgFragmentInfo>),
/// A hypothetical box (see CSS 2.1 § 10.3.7) for an absolutely-positioned block that was
/// declared with `display: inline;`.
@@ -186,6 +188,7 @@ impl SpecificFragmentInfo {
SpecificFragmentInfo::Iframe(_) |
SpecificFragmentInfo::Image(_) |
SpecificFragmentInfo::ScannedText(_) |
+ SpecificFragmentInfo::Svg(_) |
SpecificFragmentInfo::Table |
SpecificFragmentInfo::TableCell |
SpecificFragmentInfo::TableColumn(_) |
@@ -216,6 +219,7 @@ impl SpecificFragmentInfo {
}
SpecificFragmentInfo::InlineBlock(_) => "SpecificFragmentInfo::InlineBlock",
SpecificFragmentInfo::ScannedText(_) => "SpecificFragmentInfo::ScannedText",
+ SpecificFragmentInfo::Svg(_) => "SpecificFragmentInfo::Svg",
SpecificFragmentInfo::Table => "SpecificFragmentInfo::Table",
SpecificFragmentInfo::TableCell => "SpecificFragmentInfo::TableCell",
SpecificFragmentInfo::TableColumn(_) => "SpecificFragmentInfo::TableColumn",
@@ -356,6 +360,44 @@ impl CanvasFragmentInfo {
}
}
+#[derive(Clone)]
+pub struct SvgFragmentInfo {
+ pub replaced_image_fragment_info: ReplacedImageFragmentInfo,
+ pub dom_width: Au,
+ pub dom_height: Au,
+}
+
+impl SvgFragmentInfo {
+ pub fn new<N: ThreadSafeLayoutNode>(node: &N,
+ data: SVGSVGData,
+ ctx: &SharedStyleContext)
+ -> SvgFragmentInfo {
+ SvgFragmentInfo {
+ replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node, ctx),
+ dom_width: Au::from_px(data.width as i32),
+ dom_height: Au::from_px(data.height as i32),
+ }
+ }
+
+ /// Returns the original inline-size of the SVG element.
+ pub fn svg_inline_size(&self) -> Au {
+ if self.replaced_image_fragment_info.writing_mode_is_vertical {
+ self.dom_height
+ } else {
+ self.dom_width
+ }
+ }
+
+ /// Returns the original block-size of the SVG element.
+ pub fn svg_block_size(&self) -> Au {
+ if self.replaced_image_fragment_info.writing_mode_is_vertical {
+ self.dom_width
+ } else {
+ self.dom_height
+ }
+ }
+}
+
/// A fragment that represents a replaced content image and its accompanying borders, shadows, etc.
#[derive(Clone)]
@@ -1007,7 +1049,8 @@ impl Fragment {
SpecificFragmentInfo::Iframe(_) |
SpecificFragmentInfo::Image(_) |
SpecificFragmentInfo::InlineAbsolute(_) |
- SpecificFragmentInfo::Multicol => {
+ SpecificFragmentInfo::Multicol |
+ SpecificFragmentInfo::Svg(_) => {
QuantitiesIncludedInIntrinsicInlineSizes::all()
}
SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell => {
@@ -1509,6 +1552,26 @@ impl Fragment {
preferred_inline_size: canvas_inline_size,
});
}
+ SpecificFragmentInfo::Svg(ref mut svg_fragment_info) => {
+ let mut svg_inline_size = match self.style.content_inline_size() {
+ LengthOrPercentageOrAuto::Auto |
+ LengthOrPercentageOrAuto::Percentage(_) => {
+ svg_fragment_info.svg_inline_size()
+ }
+ LengthOrPercentageOrAuto::Length(length) => length,
+ LengthOrPercentageOrAuto::Calc(calc) => calc.length(),
+ };
+
+ svg_inline_size = max(model::specified(self.style.min_inline_size(), Au(0)), svg_inline_size);
+ if let Some(max) = model::specified_or_none(self.style.max_inline_size(), Au(0)) {
+ svg_inline_size = min(svg_inline_size, max)
+ }
+
+ result.union_block(&IntrinsicISizes {
+ minimum_inline_size: svg_inline_size,
+ preferred_inline_size: svg_inline_size,
+ });
+ }
SpecificFragmentInfo::ScannedText(ref text_fragment_info) => {
let range = &text_fragment_info.range;
@@ -1596,6 +1659,9 @@ impl Fragment {
SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => {
canvas_fragment_info.replaced_image_fragment_info.computed_inline_size()
}
+ SpecificFragmentInfo::Svg(ref svg_fragment_info) => {
+ svg_fragment_info.replaced_image_fragment_info.computed_inline_size()
+ }
SpecificFragmentInfo::Image(ref image_fragment_info) => {
image_fragment_info.replaced_image_fragment_info.computed_inline_size()
}
@@ -1885,7 +1951,8 @@ impl Fragment {
SpecificFragmentInfo::InlineBlock(_) |
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
SpecificFragmentInfo::InlineAbsolute(_) |
- SpecificFragmentInfo::ScannedText(_) => {}
+ SpecificFragmentInfo::ScannedText(_) |
+ SpecificFragmentInfo::Svg(_) => {}
};
let style = &*self.style;
@@ -1945,6 +2012,18 @@ impl Fragment {
fragment_inline_size,
fragment_block_size);
}
+ SpecificFragmentInfo::Svg(ref mut svg_fragment_info) => {
+ let fragment_inline_size = svg_fragment_info.svg_inline_size();
+ let fragment_block_size = svg_fragment_info.svg_block_size();
+ self.border_box.size.inline =
+ svg_fragment_info.replaced_image_fragment_info
+ .calculate_replaced_inline_size(style,
+ noncontent_inline_size,
+ container_inline_size,
+ container_block_size,
+ fragment_inline_size,
+ fragment_block_size);
+ }
SpecificFragmentInfo::Iframe(ref iframe_fragment_info) => {
self.border_box.size.inline =
iframe_fragment_info.calculate_replaced_inline_size(style,
@@ -1981,7 +2060,8 @@ impl Fragment {
SpecificFragmentInfo::InlineBlock(_) |
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
SpecificFragmentInfo::InlineAbsolute(_) |
- SpecificFragmentInfo::ScannedText(_) => {}
+ SpecificFragmentInfo::ScannedText(_) |
+ SpecificFragmentInfo::Svg(_) => {}
}
let style = &*self.style;
@@ -2010,6 +2090,17 @@ impl Fragment {
fragment_inline_size,
fragment_block_size);
}
+ SpecificFragmentInfo::Svg(ref mut svg_fragment_info) => {
+ let fragment_inline_size = svg_fragment_info.svg_inline_size();
+ let fragment_block_size = svg_fragment_info.svg_block_size();
+ self.border_box.size.block =
+ svg_fragment_info.replaced_image_fragment_info
+ .calculate_replaced_block_size(style,
+ noncontent_block_size,
+ containing_block_block_size,
+ fragment_inline_size,
+ fragment_block_size);
+ }
SpecificFragmentInfo::ScannedText(ref info) => {
// Scanned text fragments' content block-sizes are calculated by the text run
// scanner during flow construction.
@@ -2065,6 +2156,16 @@ impl Fragment {
ascent: computed_block_size + self.border_padding.block_start,
}
}
+ SpecificFragmentInfo::Svg(ref svg_fragment_info) => {
+ let computed_block_size = svg_fragment_info.replaced_image_fragment_info
+ .computed_block_size();
+ InlineMetrics {
+ block_size_above_baseline: computed_block_size +
+ self.border_padding.block_start,
+ depth_below_baseline: self.border_padding.block_end,
+ ascent: computed_block_size + self.border_padding.block_start,
+ }
+ }
SpecificFragmentInfo::ScannedText(ref info) => {
// Fragments with no glyphs don't contribute any inline metrics.
// TODO: Filter out these fragments during flow construction?
@@ -2213,6 +2314,7 @@ impl Fragment {
SpecificFragmentInfo::Iframe(_) |
SpecificFragmentInfo::Image(_) |
SpecificFragmentInfo::ScannedText(_) |
+ SpecificFragmentInfo::Svg(_) |
SpecificFragmentInfo::Table |
SpecificFragmentInfo::TableCell |
SpecificFragmentInfo::TableColumn(_) |
@@ -2699,6 +2801,7 @@ impl Fragment {
SpecificFragmentInfo::Iframe(_) |
SpecificFragmentInfo::Image(_) |
SpecificFragmentInfo::ScannedText(_) |
+ SpecificFragmentInfo::Svg(_) |
SpecificFragmentInfo::UnscannedText(_) => true
}
}
diff --git a/components/script/dom/create.rs b/components/script/dom/create.rs
index 6cdaf2b0e78..98a2e5ad4ed 100644
--- a/components/script/dom/create.rs
+++ b/components/script/dom/create.rs
@@ -76,21 +76,44 @@ use dom::htmltrackelement::HTMLTrackElement;
use dom::htmlulistelement::HTMLUListElement;
use dom::htmlunknownelement::HTMLUnknownElement;
use dom::htmlvideoelement::HTMLVideoElement;
+use dom::svgsvgelement::SVGSVGElement;
use string_cache::{Atom, QualName};
+use util::prefs::PREFS;
-pub fn create_element(name: QualName,
- prefix: Option<Atom>,
- document: &Document,
- creator: ElementCreator)
+fn create_svg_element(name: QualName,
+ prefix: Option<DOMString>,
+ document: &Document)
-> Root<Element> {
- // FIXME(ajeffrey): Convert directly from Atom to DOMString.
+ assert!(name.ns == ns!(svg));
- let prefix = prefix.map(|p| DOMString::from(&*p));
+ macro_rules! make(
+ ($ctor:ident) => ({
+ let obj = $ctor::new(name.local, prefix, document);
+ Root::upcast(obj)
+ });
+ ($ctor:ident, $($arg:expr),+) => ({
+ let obj = $ctor::new(name.local, prefix, document, $($arg),+);
+ Root::upcast(obj)
+ })
+ );
- if name.ns != ns!(html) {
+ if !PREFS.get("dom.svg.enabled").as_boolean().unwrap_or(false) {
return Element::new(name.local, name.ns, prefix, document);
}
+ match name.local {
+ atom!("svg") => make!(SVGSVGElement),
+ _ => Element::new(name.local, name.ns, prefix, document),
+ }
+}
+
+fn create_html_element(name: QualName,
+ prefix: Option<DOMString>,
+ document: &Document,
+ creator: ElementCreator)
+ -> Root<Element> {
+ assert!(name.ns == ns!(html));
+
macro_rules! make(
($ctor:ident) => ({
let obj = $ctor::new(name.local, prefix, document);
@@ -249,3 +272,19 @@ pub fn create_element(name: QualName,
_ => make!(HTMLUnknownElement),
}
}
+
+pub fn create_element(name: QualName,
+ prefix: Option<Atom>,
+ document: &Document,
+ creator: ElementCreator)
+ -> Root<Element> {
+ // FIXME(ajeffrey): Convert directly from Atom to DOMString.
+
+ let prefix = prefix.map(|p| DOMString::from(&*p));
+
+ match name.ns {
+ ns!(html) => create_html_element(name, prefix, document, creator),
+ ns!(svg) => create_svg_element(name, prefix, document),
+ _ => Element::new(name.local, name.ns, prefix, document)
+ }
+}
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index 2335f8a0a25..ace4f979be6 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -392,6 +392,9 @@ pub mod storage;
pub mod storageevent;
pub mod stylesheet;
pub mod stylesheetlist;
+pub mod svgelement;
+pub mod svggraphicselement;
+pub mod svgsvgelement;
pub mod testbinding;
pub mod testbindingiterable;
pub mod testbindingpairiterable;
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index c18613ac6a2..b52a8aec965 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -22,6 +22,7 @@ use dom::bindings::conversions::{self, DerivedFrom};
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::inheritance::{Castable, CharacterDataTypeId, ElementTypeId};
use dom::bindings::inheritance::{EventTargetTypeId, HTMLElementTypeId, NodeTypeId};
+use dom::bindings::inheritance::{SVGElementTypeId, SVGGraphicsElementTypeId};
use dom::bindings::js::{JS, LayoutJS, MutNullableHeap};
use dom::bindings::js::Root;
use dom::bindings::js::RootedReference;
@@ -36,7 +37,7 @@ use dom::element::{Element, ElementCreator};
use dom::eventtarget::EventTarget;
use dom::globalscope::GlobalScope;
use dom::htmlbodyelement::HTMLBodyElement;
-use dom::htmlcanvaselement::LayoutHTMLCanvasElementHelpers;
+use dom::htmlcanvaselement::{HTMLCanvasElement, LayoutHTMLCanvasElementHelpers};
use dom::htmlcollection::HTMLCollection;
use dom::htmlelement::HTMLElement;
use dom::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods};
@@ -46,6 +47,7 @@ use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHel
use dom::nodelist::NodeList;
use dom::processinginstruction::ProcessingInstruction;
use dom::range::WeakRangeVec;
+use dom::svgsvgelement::{SVGSVGElement, LayoutSVGSVGElementHelpers};
use dom::text::Text;
use dom::virtualmethods::{VirtualMethods, vtable_for};
use dom::window::Window;
@@ -59,7 +61,7 @@ use libc::{self, c_void, uintptr_t};
use msg::constellation_msg::PipelineId;
use parse::html::parse_html_fragment;
use ref_slice::ref_slice;
-use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData};
+use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData, SVGSVGData};
use script_layout_interface::{LayoutElementType, LayoutNodeType, TrustedNodeAddress};
use script_layout_interface::message::Msg;
use script_traits::UntrustedNodeAddress;
@@ -955,6 +957,7 @@ pub trait LayoutNodeHelpers {
fn selection(&self) -> Option<Range<usize>>;
fn image_url(&self) -> Option<Url>;
fn canvas_data(&self) -> Option<HTMLCanvasData>;
+ fn svg_data(&self) -> Option<SVGSVGData>;
fn iframe_pipeline_id(&self) -> PipelineId;
fn opaque(&self) -> OpaqueNode;
}
@@ -1088,10 +1091,15 @@ impl LayoutNodeHelpers for LayoutJS<Node> {
}
fn canvas_data(&self) -> Option<HTMLCanvasData> {
- self.downcast()
+ self.downcast::<HTMLCanvasElement>()
.map(|canvas| canvas.data())
}
+ fn svg_data(&self) -> Option<SVGSVGData> {
+ self.downcast::<SVGSVGElement>()
+ .map(|svg| svg.data())
+ }
+
fn iframe_pipeline_id(&self) -> PipelineId {
let iframe_element = self.downcast::<HTMLIFrameElement>()
.expect("not an iframe element!");
@@ -2689,6 +2697,8 @@ impl Into<LayoutElementType> for ElementTypeId {
LayoutElementType::HTMLTableSectionElement,
ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement) =>
LayoutElementType::HTMLTextAreaElement,
+ ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(SVGGraphicsElementTypeId::SVGSVGElement)) =>
+ LayoutElementType::SVGSVGElement,
_ => LayoutElementType::Element,
}
}
diff --git a/components/script/dom/svgelement.rs b/components/script/dom/svgelement.rs
new file mode 100644
index 00000000000..95fd42c40b6
--- /dev/null
+++ b/components/script/dom/svgelement.rs
@@ -0,0 +1,48 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use dom::bindings::codegen::Bindings::SVGElementBinding;
+use dom::bindings::inheritance::Castable;
+use dom::bindings::js::Root;
+use dom::bindings::str::DOMString;
+use dom::document::Document;
+use dom::element::Element;
+use dom::node::Node;
+use dom::virtualmethods::VirtualMethods;
+use string_cache::Atom;
+use style::element_state::ElementState;
+
+#[dom_struct]
+pub struct SVGElement {
+ element: Element,
+}
+
+impl SVGElement {
+ pub fn new_inherited(tag_name: Atom, prefix: Option<DOMString>,
+ document: &Document) -> SVGElement {
+ SVGElement::new_inherited_with_state(ElementState::empty(), tag_name, prefix, document)
+ }
+
+ pub fn new_inherited_with_state(state: ElementState, tag_name: Atom,
+ prefix: Option<DOMString>, document: &Document)
+ -> SVGElement {
+ SVGElement {
+ element:
+ Element::new_inherited_with_state(state, tag_name, ns!(svg), prefix, document),
+ }
+ }
+
+ #[allow(unrooted_must_root)]
+ pub fn new(local_name: Atom, prefix: Option<DOMString>, document: &Document) -> Root<SVGElement> {
+ Node::reflect_node(box SVGElement::new_inherited(local_name, prefix, document),
+ document,
+ SVGElementBinding::Wrap)
+ }
+}
+
+impl VirtualMethods for SVGElement {
+ fn super_type(&self) -> Option<&VirtualMethods> {
+ Some(self.upcast::<Element>() as &VirtualMethods)
+ }
+}
diff --git a/components/script/dom/svggraphicselement.rs b/components/script/dom/svggraphicselement.rs
new file mode 100644
index 00000000000..bd7c8d581f7
--- /dev/null
+++ b/components/script/dom/svggraphicselement.rs
@@ -0,0 +1,48 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use dom::bindings::codegen::Bindings::SVGGraphicsElementBinding;
+use dom::bindings::inheritance::Castable;
+use dom::bindings::js::Root;
+use dom::bindings::str::DOMString;
+use dom::document::Document;
+use dom::node::Node;
+use dom::svgelement::SVGElement;
+use dom::virtualmethods::VirtualMethods;
+use string_cache::Atom;
+use style::element_state::ElementState;
+
+#[dom_struct]
+pub struct SVGGraphicsElement {
+ svgelement: SVGElement,
+}
+
+impl SVGGraphicsElement {
+ pub fn new_inherited(tag_name: Atom, prefix: Option<DOMString>,
+ document: &Document) -> SVGGraphicsElement {
+ SVGGraphicsElement::new_inherited_with_state(ElementState::empty(), tag_name, prefix, document)
+ }
+
+ pub fn new_inherited_with_state(state: ElementState, tag_name: Atom,
+ prefix: Option<DOMString>, document: &Document)
+ -> SVGGraphicsElement {
+ SVGGraphicsElement {
+ svgelement:
+ SVGElement::new_inherited_with_state(state, tag_name, prefix, document),
+ }
+ }
+
+ #[allow(unrooted_must_root)]
+ pub fn new(local_name: Atom, prefix: Option<DOMString>, document: &Document) -> Root<SVGGraphicsElement> {
+ Node::reflect_node(box SVGGraphicsElement::new_inherited(local_name, prefix, document),
+ document,
+ SVGGraphicsElementBinding::Wrap)
+ }
+}
+
+impl VirtualMethods for SVGGraphicsElement {
+ fn super_type(&self) -> Option<&VirtualMethods> {
+ Some(self.upcast::<SVGElement>() as &VirtualMethods)
+ }
+}
diff --git a/components/script/dom/svgsvgelement.rs b/components/script/dom/svgsvgelement.rs
new file mode 100644
index 00000000000..11c1e35b9e9
--- /dev/null
+++ b/components/script/dom/svgsvgelement.rs
@@ -0,0 +1,83 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use dom::attr::Attr;
+use dom::bindings::codegen::Bindings::SVGSVGElementBinding;
+use dom::bindings::inheritance::Castable;
+use dom::bindings::js::{LayoutJS, Root};
+use dom::bindings::str::DOMString;
+use dom::document::Document;
+use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
+use dom::node::Node;
+use dom::svggraphicselement::SVGGraphicsElement;
+use dom::virtualmethods::VirtualMethods;
+use script_layout_interface::SVGSVGData;
+use string_cache::Atom;
+use style::attr::AttrValue;
+
+const DEFAULT_WIDTH: u32 = 300;
+const DEFAULT_HEIGHT: u32 = 150;
+
+#[dom_struct]
+pub struct SVGSVGElement {
+ svggraphicselement: SVGGraphicsElement
+}
+
+impl SVGSVGElement {
+ fn new_inherited(local_name: Atom,
+ prefix: Option<DOMString>,
+ document: &Document) -> SVGSVGElement {
+ SVGSVGElement {
+ svggraphicselement:
+ SVGGraphicsElement::new_inherited(local_name, prefix, document)
+ }
+ }
+
+ #[allow(unrooted_must_root)]
+ pub fn new(local_name: Atom,
+ prefix: Option<DOMString>,
+ document: &Document) -> Root<SVGSVGElement> {
+ Node::reflect_node(box SVGSVGElement::new_inherited(local_name, prefix, document),
+ document,
+ SVGSVGElementBinding::Wrap)
+ }
+}
+
+pub trait LayoutSVGSVGElementHelpers {
+ fn data(&self) -> SVGSVGData;
+}
+
+impl LayoutSVGSVGElementHelpers for LayoutJS<SVGSVGElement> {
+ #[allow(unsafe_code)]
+ fn data(&self) -> SVGSVGData {
+ unsafe {
+ let SVG = &*self.unsafe_get();
+
+ let width_attr = SVG.upcast::<Element>().get_attr_for_layout(&ns!(), &atom!("width"));
+ let height_attr = SVG.upcast::<Element>().get_attr_for_layout(&ns!(), &atom!("height"));
+ SVGSVGData {
+ width: width_attr.map_or(DEFAULT_WIDTH, |val| val.as_uint()),
+ height: height_attr.map_or(DEFAULT_HEIGHT, |val| val.as_uint()),
+ }
+ }
+ }
+}
+
+impl VirtualMethods for SVGSVGElement {
+ fn super_type(&self) -> Option<&VirtualMethods> {
+ Some(self.upcast::<SVGGraphicsElement>() as &VirtualMethods)
+ }
+
+ fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
+ self.super_type().unwrap().attribute_mutated(attr, mutation);
+ }
+
+ fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue {
+ match name {
+ &atom!("width") => AttrValue::from_u32(value.into(), DEFAULT_WIDTH),
+ &atom!("height") => AttrValue::from_u32(value.into(), DEFAULT_HEIGHT),
+ _ => self.super_type().unwrap().parse_plain_attribute(name, value),
+ }
+ }
+}
diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs
index d4cf1609568..c8a8a7436a4 100644
--- a/components/script/dom/virtualmethods.rs
+++ b/components/script/dom/virtualmethods.rs
@@ -7,6 +7,8 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::inheritance::ElementTypeId;
use dom::bindings::inheritance::HTMLElementTypeId;
use dom::bindings::inheritance::NodeTypeId;
+use dom::bindings::inheritance::SVGElementTypeId;
+use dom::bindings::inheritance::SVGGraphicsElementTypeId;
use dom::bindings::str::DOMString;
use dom::document::Document;
use dom::element::{AttributeMutation, Element};
@@ -47,6 +49,7 @@ use dom::htmltemplateelement::HTMLTemplateElement;
use dom::htmltextareaelement::HTMLTextAreaElement;
use dom::htmltitleelement::HTMLTitleElement;
use dom::node::{ChildrenMutation, CloneChildrenFlag, Node, UnbindContext};
+use dom::svgsvgelement::SVGSVGElement;
use string_cache::Atom;
use style::attr::AttrValue;
@@ -231,6 +234,11 @@ pub fn vtable_for(node: &Node) -> &VirtualMethods {
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTitleElement)) => {
node.downcast::<HTMLTitleElement>().unwrap() as &VirtualMethods
}
+ NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
+ SVGGraphicsElementTypeId::SVGSVGElement
+ ))) => {
+ node.downcast::<SVGSVGElement>().unwrap() as &VirtualMethods
+ }
NodeTypeId::Element(ElementTypeId::Element) => {
node.downcast::<Element>().unwrap() as &VirtualMethods
}
diff --git a/components/script/dom/webidls/SVGElement.webidl b/components/script/dom/webidls/SVGElement.webidl
new file mode 100644
index 00000000000..02f673a420e
--- /dev/null
+++ b/components/script/dom/webidls/SVGElement.webidl
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// https://svgwg.org/svg2-draft/types.html#InterfaceSVGElement
+[Pref="dom.svg.enabled"]
+interface SVGElement : Element {
+
+ //[SameObject] readonly attribute SVGAnimatedString className;
+
+ //[SameObject] readonly attribute DOMStringMap dataset;
+
+ //readonly attribute SVGSVGElement? ownerSVGElement;
+ //readonly attribute SVGElement? viewportElement;
+
+ //attribute long tabIndex;
+ //void focus();
+ //void blur();
+};
+
+//SVGElement implements GlobalEventHandlers;
+//SVGElement implements SVGElementInstance;
diff --git a/components/script/dom/webidls/SVGGraphicsElement.webidl b/components/script/dom/webidls/SVGGraphicsElement.webidl
new file mode 100644
index 00000000000..d8f90e639ea
--- /dev/null
+++ b/components/script/dom/webidls/SVGGraphicsElement.webidl
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// https://svgwg.org/svg2-draft/types.html#InterfaceSVGGraphicsElement
+[Pref="dom.svg.enabled"]
+//dictionary SVGBoundingBoxOptions {
+// boolean fill = true;
+// boolean stroke = false;
+// boolean markers = false;
+// boolean clipped = false;
+//};
+
+interface SVGGraphicsElement : SVGElement {
+ //[SameObject] readonly attribute SVGAnimatedTransformList transform;
+
+ //DOMRect getBBox(optional SVGBoundingBoxOptions options);
+ //DOMMatrix? getCTM();
+ //DOMMatrix? getScreenCTM();
+};
+
+//SVGGraphicsElement implements SVGTests;
diff --git a/components/script/dom/webidls/SVGSVGElement.webidl b/components/script/dom/webidls/SVGSVGElement.webidl
new file mode 100644
index 00000000000..bed2c03a74b
--- /dev/null
+++ b/components/script/dom/webidls/SVGSVGElement.webidl
@@ -0,0 +1,45 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// https://svgwg.org/svg2-draft/struct.html#InterfaceSVGSVGElement
+[Pref="dom.svg.enabled"]
+interface SVGSVGElement : SVGGraphicsElement {
+
+ //[SameObject] readonly attribute SVGAnimatedLength x;
+ //[SameObject] readonly attribute SVGAnimatedLength y;
+ //[SameObject] readonly attribute SVGAnimatedLength width;
+ //[SameObject] readonly attribute SVGAnimatedLength height;
+
+ //attribute float currentScale;
+ //[SameObject] readonly attribute DOMPointReadOnly currentTranslate;
+
+ //NodeList getIntersectionList(DOMRectReadOnly rect, SVGElement? referenceElement);
+ //NodeList getEnclosureList(DOMRectReadOnly rect, SVGElement? referenceElement);
+ //boolean checkIntersection(SVGElement element, DOMRectReadOnly rect);
+ //boolean checkEnclosure(SVGElement element, DOMRectReadOnly rect);
+
+ //void deselectAll();
+
+ //SVGNumber createSVGNumber();
+ //SVGLength createSVGLength();
+ //SVGAngle createSVGAngle();
+ //DOMPoint createSVGPoint();
+ //DOMMatrix createSVGMatrix();
+ //DOMRect createSVGRect();
+ //SVGTransform createSVGTransform();
+ //SVGTransform createSVGTransformFromMatrix(DOMMatrixReadOnly matrix);
+
+ //Element getElementById(DOMString elementId);
+
+ // Deprecated methods that have no effect when called,
+ // but which are kept for compatibility reasons.
+ //unsigned long suspendRedraw(unsigned long maxWaitMilliseconds);
+ //void unsuspendRedraw(unsigned long suspendHandleID);
+ //void unsuspendRedrawAll();
+ //void forceRedraw();
+};
+
+//SVGSVGElement implements SVGFitToViewBox;
+//SVGSVGElement implements SVGZoomAndPan;
+//SVGSVGElement implements WindowEventHandlers;
diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs
index 19b00c422e5..91c2a29285d 100644
--- a/components/script/layout_wrapper.rs
+++ b/components/script/layout_wrapper.rs
@@ -43,7 +43,7 @@ use gfx_traits::ByteIndex;
use msg::constellation_msg::PipelineId;
use parking_lot::RwLock;
use range::Range;
-use script_layout_interface::{HTMLCanvasData, LayoutNodeType, TrustedNodeAddress};
+use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress};
use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData};
use script_layout_interface::restyle_damage::RestyleDamage;
use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, LayoutNode, PseudoElementType};
@@ -861,6 +861,11 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
this.canvas_data()
}
+ fn svg_data(&self) -> Option<SVGSVGData> {
+ let this = unsafe { self.get_jsmanaged() };
+ this.svg_data()
+ }
+
fn iframe_pipeline_id(&self) -> PipelineId {
let this = unsafe { self.get_jsmanaged() };
this.iframe_pipeline_id()
diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs
index cad2e012c7c..18c4805a485 100644
--- a/components/script_layout_interface/lib.rs
+++ b/components/script_layout_interface/lib.rs
@@ -95,6 +95,7 @@ pub enum LayoutElementType {
HTMLTableRowElement,
HTMLTableSectionElement,
HTMLTextAreaElement,
+ SVGSVGElement,
}
pub struct HTMLCanvasData {
@@ -103,6 +104,11 @@ pub struct HTMLCanvasData {
pub height: u32,
}
+pub struct SVGSVGData {
+ pub width: u32,
+ pub height: u32,
+}
+
/// The address of a node known to be valid. These are sent from script to layout.
#[derive(Clone, PartialEq, Eq, Copy)]
pub struct TrustedNodeAddress(pub *const c_void);
diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs
index c02d76a2f4e..c98afa3a72e 100644
--- a/components/script_layout_interface/wrapper_traits.rs
+++ b/components/script_layout_interface/wrapper_traits.rs
@@ -5,6 +5,7 @@
use HTMLCanvasData;
use LayoutNodeType;
use OpaqueStyleAndLayoutData;
+use SVGSVGData;
use gfx_traits::{ByteIndex, LayerId, LayerType};
use msg::constellation_msg::PipelineId;
use range::Range;
@@ -362,6 +363,8 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized {
fn canvas_data(&self) -> Option<HTMLCanvasData>;
+ fn svg_data(&self) -> Option<SVGSVGData>;
+
/// If this node is an iframe element, returns its pipeline ID. If this node is
/// not an iframe element, fails.
fn iframe_pipeline_id(&self) -> PipelineId;