Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] svg: support <circle> element #17681

Closed
wants to merge 10 commits into from

script: Ensure a geometry key for an <svg> element in html tree

Add a geometry key field to the SVGSVGElement, When the <svg> element
is bind to a parent html element, ensure it contains one, and delete
it when the element is unbind.

Also, pass the svg data to layout when the key is present.
  • Loading branch information
stshine committed Sep 11, 2017
commit 3cce8252b85b8dd0194e36c568555244bd14f557
@@ -31,7 +31,7 @@ use net_traits::image::base::{Image, ImageMetadata};
use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
use range::*;
use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource};
use script_layout_interface::SVGSVGData;
use script_layout_interface::SVGImageData;
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
use serde::ser::{Serialize, SerializeStruct, Serializer};
use servo_url::ServoUrl;
@@ -360,13 +360,15 @@ impl CanvasFragmentInfo {
pub struct SvgFragmentInfo {
pub dom_width: Au,
pub dom_height: Au,
pub geometry_key: webrender_api::GeometryKey,
}

impl SvgFragmentInfo {
pub fn new(data: SVGSVGData) -> SvgFragmentInfo {
pub fn new(data: SVGImageData) -> SvgFragmentInfo {
SvgFragmentInfo {
dom_width: Au::from_px(data.width as i32),
dom_height: Au::from_px(data.height as i32),
geometry_key: data.geometry_key,
}
}
}
@@ -46,7 +46,7 @@ use script::layout_exports::{LayoutCharacterDataHelpers, LayoutDocumentHelpers};
use script::layout_exports::{LayoutElementHelpers, LayoutNodeHelpers, RawLayoutElementHelpers};
use script::layout_exports::LayoutJS;
use script::layout_exports::PendingRestyle;
use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress};
use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGImageData, TrustedNodeAddress};
use script_layout_interface::{OpaqueStyleAndLayoutData, StyleData};
use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode};
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
@@ -966,7 +966,7 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
this.canvas_data()
}

fn svg_data(&self) -> Option<SVGSVGData> {
fn svg_data(&self) -> Option<SVGImageData> {
let this = unsafe { self.get_jsmanaged() };
this.svg_data()
}
@@ -99,7 +99,7 @@ use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto};
use style::context::QuirksMode;
use style::element_state::*;
use style::media_queries::MediaList;
use style::properties::PropertyDeclarationBlock;
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
use style::selector_parser::{PseudoElement, Snapshot};
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
use style::stylesheet_set::StylesheetSet;
@@ -109,7 +109,10 @@ use style::stylesheets::keyframes_rule::Keyframe;
use style::values::specified::Length;
use time::Duration;
use uuid::Uuid;
use webrender_api::GeometryKey;
use webrender_api::ImageKey;
use webrender_api::{WebGLBufferId, WebGLError, WebGLFramebufferId, WebGLProgramId};
use webrender_api::{WebGLRenderbufferId, WebGLShaderId, WebGLTextureId, WebGLVertexArrayId};
use webvr_traits::WebVRGamepadHand;

/// A trait to allow tracing (only) DOM objects.
@@ -343,6 +346,7 @@ unsafe_no_jsmanaged_fields!(Metadata);
unsafe_no_jsmanaged_fields!(NetworkError);
unsafe_no_jsmanaged_fields!(Atom, Prefix, LocalName, Namespace, QualName);
unsafe_no_jsmanaged_fields!(TrustedPromise);
unsafe_no_jsmanaged_fields!(PropertyDeclaration);
unsafe_no_jsmanaged_fields!(PropertyDeclarationBlock);
// These three are interdependent, if you plan to put jsmanaged data
// in one of these make sure it is propagated properly to containing structs
@@ -395,6 +399,7 @@ unsafe_no_jsmanaged_fields!(OpaqueStyleAndLayoutData);
unsafe_no_jsmanaged_fields!(PathBuf);
unsafe_no_jsmanaged_fields!(CSSErrorReporter);
unsafe_no_jsmanaged_fields!(DrawAPaintImageResult);
unsafe_no_jsmanaged_fields!(GeometryKey);
unsafe_no_jsmanaged_fields!(ImageKey);
unsafe_no_jsmanaged_fields!(WebGLBufferId);
unsafe_no_jsmanaged_fields!(WebGLChan);
@@ -64,7 +64,7 @@ use js::jsapi::{JSContext, JSObject, JSRuntime};
use libc::{self, c_void, uintptr_t};
use msg::constellation_msg::{BrowsingContextId, PipelineId};
use ref_slice::ref_slice;
use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData, SVGSVGData};
use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData, SVGImageData};
use script_layout_interface::{LayoutElementType, LayoutNodeType, TrustedNodeAddress};
use script_layout_interface::message::Msg;
use script_thread::ScriptThread;
@@ -1020,7 +1020,7 @@ pub trait LayoutNodeHelpers {
fn selection(&self) -> Option<Range<usize>>;
fn image_url(&self) -> Option<ServoUrl>;
fn canvas_data(&self) -> Option<HTMLCanvasData>;
fn svg_data(&self) -> Option<SVGSVGData>;
fn svg_data(&self) -> Option<SVGImageData>;
fn iframe_browsing_context_id(&self) -> BrowsingContextId;
fn iframe_pipeline_id(&self) -> PipelineId;
fn opaque(&self) -> OpaqueNode;
@@ -1167,9 +1167,9 @@ impl LayoutNodeHelpers for LayoutJS<Node> {
.map(|canvas| canvas.data())
}

fn svg_data(&self) -> Option<SVGSVGData> {
fn svg_data(&self) -> Option<SVGImageData> {
self.downcast::<SVGSVGElement>()
.map(|svg| svg.data())
.and_then(|svg| svg.data())
}

fn iframe_browsing_context_id(&self) -> BrowsingContextId {
@@ -3,64 +3,79 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::attr::Attr;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
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::htmlelement::HTMLElement;
use dom::node::{Node, UnbindContext, window_from_node};
use dom::svggraphicselement::SVGGraphicsElement;
use dom::virtualmethods::VirtualMethods;
use dom_struct::dom_struct;
use html5ever::{LocalName, Prefix};
use script_layout_interface::SVGSVGData;
use script_layout_interface::SVGImageData;
use std::cell::Cell;
use style::attr::AttrValue;
use webrender_api::GeometryKey;

const DEFAULT_WIDTH: u32 = 300;
const DEFAULT_HEIGHT: u32 = 150;

#[dom_struct]
pub struct SVGSVGElement {
svggraphicselement: SVGGraphicsElement
svggraphicselement: SVGGraphicsElement,
geometry_key: Cell<Option<GeometryKey>>,
}

impl SVGSVGElement {
fn new_inherited(local_name: LocalName,
prefix: Option<Prefix>,
document: &Document) -> SVGSVGElement {
document: &Document)
-> SVGSVGElement {
SVGSVGElement {
svggraphicselement:
SVGGraphicsElement::new_inherited(local_name, prefix, document)
svggraphicselement: SVGGraphicsElement::new_inherited(local_name, prefix, document),
geometry_key: Cell::new(None),
}
}

#[allow(unrooted_must_root)]
pub fn new(local_name: LocalName,
prefix: Option<Prefix>,
document: &Document) -> Root<SVGSVGElement> {
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;
fn data(&self) -> Option<SVGImageData>;
}

impl LayoutSVGSVGElementHelpers for LayoutJS<SVGSVGElement> {
#[allow(unsafe_code)]
fn data(&self) -> SVGSVGData {
fn data(&self) -> Option<SVGImageData> {
unsafe {
let SVG = &*self.unsafe_get();
let element = &*self.unsafe_get();

let width_attr = SVG.upcast::<Element>().get_attr_for_layout(&ns!(), &local_name!("width"));
let height_attr = SVG.upcast::<Element>().get_attr_for_layout(&ns!(), &local_name!("height"));
SVGSVGData {
width: width_attr.map_or(DEFAULT_WIDTH, |val| val.as_uint()),
height: height_attr.map_or(DEFAULT_HEIGHT, |val| val.as_uint()),
}
let width_attr = element
.upcast::<Element>()
.get_attr_for_layout(&ns!(), &local_name!("width"));
let height_attr = element
.upcast::<Element>()
.get_attr_for_layout(&ns!(), &local_name!("height"));

element.geometry_key.get().map(|key| {
SVGImageData {
width: width_attr.map_or(DEFAULT_WIDTH, |val| val.as_uint()),
height: height_attr.map_or(DEFAULT_HEIGHT, |val| val.as_uint()),
geometry_key: key
}
})
}
}
}
@@ -70,6 +85,30 @@ impl VirtualMethods for SVGSVGElement {
Some(self.upcast::<SVGGraphicsElement>() as &VirtualMethods)
}

// When the <svg> element is appended to a tree and its parent is an html element,
// ensure a geometry key for it.
fn bind_to_tree(&self, tree_in_doc: bool) {
if self.upcast::<Node>().GetParentNode().unwrap().is::<HTMLElement>() {
if self.geometry_key.get().is_none() {
let window = window_from_node(self);
let key = window.image_cache().create_geometry_key();
self.geometry_key.set(Some(key));
}
}

This comment has been minimized.

Copy link
@emilio

emilio Jul 12, 2017

Member

nit: Indentation is off.

self.super_type().unwrap().bind_to_tree(tree_in_doc);
}

// When the <svg> element is removed from the tree, delete the corresponding
// geometry key if it exists.
fn unbind_from_tree(&self, context: &UnbindContext) {
if let Some(key) = self.geometry_key.get() {
let window = window_from_node(self);
window.image_cache().delete_geometry(key);
self.geometry_key.set(None);
}
self.super_type().unwrap().unbind_from_tree(context);
}

fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
self.super_type().unwrap().attribute_mutated(attr, mutation);
}
@@ -52,6 +52,7 @@ use script_traits::UntrustedNodeAddress;
use servo_url::ServoUrl;
use std::sync::atomic::AtomicIsize;
use style::data::ElementData;
use webrender_api::GeometryKey;

#[repr(C)]
pub struct StyleData {
@@ -122,6 +123,7 @@ pub enum LayoutElementType {
HTMLTableSectionElement,
HTMLTextAreaElement,
SVGSVGElement,
SVGCircleElement
}

pub enum HTMLCanvasDataSource {
@@ -135,9 +137,10 @@ pub struct HTMLCanvasData {
pub height: u32,
}

pub struct SVGSVGData {
pub struct SVGImageData {
pub width: u32,
pub height: u32,
pub geometry_key: GeometryKey
}

/// The address of a node known to be valid. These are sent from script to layout.
@@ -7,7 +7,7 @@
use HTMLCanvasData;
use LayoutNodeType;
use OpaqueStyleAndLayoutData;
use SVGSVGData;
use SVGImageData;
use atomic_refcell::AtomicRef;
use gfx_traits::{ByteIndex, FragmentType, combine_id_with_fragment_type};
use html5ever::{Namespace, LocalName};
@@ -272,7 +272,7 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Debug + GetLayoutData + NodeInfo

fn canvas_data(&self) -> Option<HTMLCanvasData>;

fn svg_data(&self) -> Option<SVGSVGData>;
fn svg_data(&self) -> Option<SVGImageData>;

/// If this node is an iframe element, returns its browsing context ID. If this node is
/// not an iframe element, fails.
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.