Impl Basic support for object element

This commit is contained in:
Youngmin Yoo 2014-02-10 11:26:39 +09:00
parent ec4c31c214
commit 13f9a66632
6 changed files with 83 additions and 18 deletions

View file

@ -34,14 +34,19 @@ use layout::util::{LayoutDataAccess, OpaqueNode};
use layout::wrapper::{PostorderNodeMutTraversal, TLayoutNode, ThreadSafeLayoutNode};
use gfx::font_context::FontContext;
use script::dom::element::{HTMLIframeElementTypeId, HTMLImageElementTypeId};
use script::dom::element::{HTMLIframeElementTypeId, HTMLImageElementTypeId, HTMLObjectElementTypeId};
use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId};
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, ProcessingInstructionNodeTypeId};
use script::dom::node::{TextNodeTypeId};
use style::computed_values::{display, position, float, white_space};
use style::ComputedValues;
use servo_util::namespace;
use servo_util::url::parse_url;
use servo_util::url::is_image_data;
use extra::url::Url;
use extra::arc::Arc;
use std::cell::RefCell;
use std::util;
use std::num::Zero;
@ -220,16 +225,20 @@ pub struct FlowConstructor<'a> {
/// The font context.
font_context: ~FontContext,
/// The URL of the page.
url: &'a Url,
}
impl<'fc> FlowConstructor<'fc> {
/// Creates a new flow constructor.
pub fn init<'a>(layout_context: &'a mut LayoutContext) -> FlowConstructor<'a> {
pub fn init<'a>(layout_context: &'a mut LayoutContext, url: &'a Url) -> FlowConstructor<'a> {
let font_context = ~FontContext::new(layout_context.font_context_info.clone());
FlowConstructor {
layout_context: layout_context,
next_flow_id: RefCell::new(0),
font_context: font_context,
url: url,
}
}
@ -241,14 +250,13 @@ impl<'fc> FlowConstructor<'fc> {
}
/// Builds the `ImageBoxInfo` for the given image. This is out of line to guide inlining.
fn build_box_info_for_image(&mut self, node: ThreadSafeLayoutNode) -> Option<ImageBoxInfo> {
// FIXME(pcwalton): Don't copy URLs.
match node.image_url() {
None => None,
fn build_box_info_for_image(&mut self, node: ThreadSafeLayoutNode, url: Option<Url>) -> SpecificBoxInfo {
match url {
None => GenericBox,
Some(url) => {
// FIXME(pcwalton): The fact that image boxes store the cache within them makes
// little sense to me.
Some(ImageBoxInfo::new(&node, url, self.layout_context.image_cache.clone()))
ImageBox(ImageBoxInfo::new(&node, url, self.layout_context.image_cache.clone()))
}
}
}
@ -257,13 +265,11 @@ impl<'fc> FlowConstructor<'fc> {
pub fn build_specific_box_info_for_node(&mut self, node: ThreadSafeLayoutNode)
-> SpecificBoxInfo {
match node.type_id() {
ElementNodeTypeId(HTMLImageElementTypeId) => {
match self.build_box_info_for_image(node) {
None => GenericBox,
Some(image_box_info) => ImageBox(image_box_info),
}
}
ElementNodeTypeId(HTMLImageElementTypeId) => self.build_box_info_for_image(node, node.image_url()),
ElementNodeTypeId(HTMLIframeElementTypeId) => IframeBox(IframeBoxInfo::new(&node)),
ElementNodeTypeId(HTMLObjectElementTypeId) => {
self.build_box_info_for_image(node, node.get_object_data(self.url))
}
TextNodeTypeId => UnscannedTextBox(UnscannedTextBoxInfo::new(&node)),
_ => GenericBox,
}
@ -709,6 +715,7 @@ impl<'ln> NodeUtils for ThreadSafeLayoutNode<'ln> {
DocumentFragmentNodeTypeId |
DocumentNodeTypeId(_) |
ElementNodeTypeId(HTMLImageElementTypeId) => true,
ElementNodeTypeId(HTMLObjectElementTypeId) => self.has_object_data(),
ElementNodeTypeId(_) => false,
}
}
@ -761,6 +768,39 @@ impl<'ln> NodeUtils for ThreadSafeLayoutNode<'ln> {
}
}
/// Methods for interacting with HTMLObjectElement nodes
trait ObjectElement {
/// Returns None if this node is not matching attributes.
fn get_type_and_data(self) -> (Option<&'static str>, Option<&'static str>);
/// Returns true if this node has object data that is correct uri.
fn has_object_data(self) -> bool;
/// Returns the "data" attribute value parsed as a URL
fn get_object_data(self, base_url: &Url) -> Option<Url>;
}
impl<'ln> ObjectElement for ThreadSafeLayoutNode<'ln> {
fn get_type_and_data(self) -> (Option<&'static str>, Option<&'static str>) {
(self.with_element(|e| { e.get_attr(&namespace::Null, "type") } ),
self.with_element(|e| { e.get_attr(&namespace::Null, "data") } ))
}
fn has_object_data(self) -> bool {
match self.get_type_and_data() {
(None, Some(uri)) => is_image_data(uri),
_ => false
}
}
fn get_object_data(self, base_url: &Url) -> Option<Url> {
match self.get_type_and_data() {
(None, Some(uri)) if is_image_data(uri) => Some(parse_url(uri, Some(base_url.clone()))),
_ => None
}
}
}
/// Strips ignorable whitespace from the start of a list of boxes.
fn strip_ignorable_whitespace_from_start(opt_boxes: &mut Option<~[Box]>) {
match util::replace(opt_boxes, None) {

View file

@ -22,6 +22,7 @@ use layout::parallel;
use layout::util::{LayoutDataAccess, OpaqueNode, LayoutDataWrapper};
use layout::wrapper::{DomLeafSet, LayoutNode, TLayoutNode, ThreadSafeLayoutNode};
use extra::url::Url;
use extra::arc::{Arc, MutexArc};
use geom::rect::Rect;
use geom::size::Size2D;
@ -427,9 +428,9 @@ impl LayoutTask {
/// is intertwined with selector matching, making it difficult to compare directly. It is
/// marked `#[inline(never)]` to aid benchmarking in sampling profilers.
#[inline(never)]
fn construct_flow_tree(&self, layout_context: &mut LayoutContext, node: LayoutNode) -> ~Flow {
fn construct_flow_tree(&self, layout_context: &mut LayoutContext, node: LayoutNode, url: &Url) -> ~Flow {
let node = ThreadSafeLayoutNode::new(node);
node.traverse_postorder_mut(&mut FlowConstructor::init(layout_context));
node.traverse_postorder_mut(&mut FlowConstructor::init(layout_context, url));
let mut layout_data_ref = node.mutate_layout_data();
let result = match *layout_data_ref.get() {
@ -594,7 +595,7 @@ impl LayoutTask {
// Construct the flow tree.
profile(time::LayoutTreeBuilderCategory,
self.profiler_chan.clone(),
|| self.construct_flow_tree(&mut layout_ctx, *node))
|| self.construct_flow_tree(&mut layout_ctx, *node, &data.url))
});
// Verification of the flow tree, which ensures that all nodes were either marked as leaves

View file

@ -248,6 +248,11 @@ impl Element {
iframe.AfterSetAttr(local_name.clone(), value.clone());
});
}
ElementNodeTypeId(HTMLObjectElementTypeId) => {
abstract_self.with_mut_object_element(|object| {
object.AfterSetAttr(local_name.clone(), value.clone());
});
}
_ => ()
}

View file

@ -10,11 +10,12 @@ use dom::bindings::utils;
use dom::characterdata::CharacterData;
use dom::document::{AbstractDocument, DocumentTypeId};
use dom::documenttype::DocumentType;
use dom::element::{Element, ElementTypeId, HTMLImageElementTypeId, HTMLIframeElementTypeId};
use dom::element::{Element, ElementTypeId, HTMLImageElementTypeId, HTMLIframeElementTypeId, HTMLObjectElementTypeId};
use dom::element::{HTMLAnchorElementTypeId, HTMLStyleElementTypeId};
use dom::eventtarget::{AbstractEventTarget, EventTarget, NodeTypeId};
use dom::htmliframeelement::HTMLIFrameElement;
use dom::htmlimageelement::HTMLImageElement;
use dom::htmlobjectelement::HTMLObjectElement;
use dom::nodelist::{NodeList};
use dom::text::Text;
use dom::processinginstruction::ProcessingInstruction;
@ -488,6 +489,18 @@ impl<'a> AbstractNode {
self.type_id() == ElementNodeTypeId(HTMLIframeElementTypeId)
}
#[inline]
pub fn is_object_element(self) -> bool {
self.type_id() == ElementNodeTypeId(HTMLObjectElementTypeId)
}
pub fn with_mut_object_element<R>(self, f: |&mut HTMLObjectElement| -> R) -> R {
if !self.is_object_element() {
fail!(~"node is not an image element");
}
self.transmute_mut(f)
}
pub fn with_mut_iframe_element<R>(self, f: |&mut HTMLIFrameElement| -> R) -> R {
if !self.is_iframe_element() {
fail!(~"node is not an iframe element");

View file

@ -392,7 +392,6 @@ pub fn parse_html(cx: *JSContext,
image_element.update_image(image_cache_task.clone(), Some(url2.clone()));
});
}
_ => {}
}

View file

@ -196,3 +196,10 @@ pub fn url_map<T: Clone + 'static>() -> UrlMap<T> {
HashMap::new()
}
pub fn is_image_data(uri: &str) -> bool {
static types: &'static [&'static str] = &[&"data:image/png", &"data:image/gif", &"data:image/jpeg"];
types.iter().any(|&type_| uri.starts_with(type_))
}