aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorbors-servo <release+servo@mozilla.com>2014-02-20 04:28:55 -0500
committerbors-servo <release+servo@mozilla.com>2014-02-20 04:28:55 -0500
commit1f90716bc10d9134a13ac41a97d217104247010f (patch)
tree9ab55b7f70fc44c0fccdfd882b12575dee313516 /src
parentec4c31c214724b60a41a700c4eb0cb8333e26d60 (diff)
parented0c15a93aa9598b3f2f0bc49b8560f640960c44 (diff)
downloadservo-1f90716bc10d9134a13ac41a97d217104247010f.tar.gz
servo-1f90716bc10d9134a13ac41a97d217104247010f.zip
auto merge of #1664 : recrack/servo/object-element, r=jdm
Support for #1636 Now, we can see eyes in acid2.html :)
Diffstat (limited to 'src')
-rw-r--r--src/components/main/layout/construct.rs66
-rw-r--r--src/components/main/layout/layout_task.rs7
-rw-r--r--src/components/script/dom/element.rs5
-rw-r--r--src/components/script/dom/htmlobjectelement.rs40
-rw-r--r--src/components/script/dom/node.rs15
-rw-r--r--src/components/script/html/hubbub_html_parser.rs1
-rw-r--r--src/components/util/url.rs7
-rw-r--r--src/test/html/object_element.html15
-rw-r--r--src/test/ref/basic.list1
-rw-r--r--src/test/ref/object_element_a.html15
-rw-r--r--src/test/ref/object_element_b.html9
11 files changed, 161 insertions, 20 deletions
diff --git a/src/components/main/layout/construct.rs b/src/components/main/layout/construct.rs
index 293ba995da3..98d33db8d26 100644
--- a/src/components/main/layout/construct.rs
+++ b/src/components/main/layout/construct.rs
@@ -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) {
diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs
index 2d79208b6ed..64482cd9803 100644
--- a/src/components/main/layout/layout_task.rs
+++ b/src/components/main/layout/layout_task.rs
@@ -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
diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs
index 2eb0553f2f6..12361d7ec85 100644
--- a/src/components/script/dom/element.rs
+++ b/src/components/script/dom/element.rs
@@ -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());
+ });
+ }
_ => ()
}
diff --git a/src/components/script/dom/htmlobjectelement.rs b/src/components/script/dom/htmlobjectelement.rs
index aeb6ad754e9..74f40db40dd 100644
--- a/src/components/script/dom/htmlobjectelement.rs
+++ b/src/components/script/dom/htmlobjectelement.rs
@@ -12,14 +12,21 @@ use dom::validitystate::ValidityState;
use dom::windowproxy::WindowProxy;
use servo_util::str::DOMString;
+use extra::url::Url;
+use servo_net::image_cache_task;
+use servo_net::image_cache_task::ImageCacheTask;
+use servo_util::url::parse_url;
+use servo_util::namespace::Null;
+use servo_util::url::is_image_data;
+
pub struct HTMLObjectElement {
- htmlelement: HTMLElement
+ htmlelement: HTMLElement,
}
impl HTMLObjectElement {
pub fn new_inherited(localName: DOMString, document: AbstractDocument) -> HTMLObjectElement {
HTMLObjectElement {
- htmlelement: HTMLElement::new_inherited(HTMLObjectElementTypeId, localName, document)
+ htmlelement: HTMLElement::new_inherited(HTMLObjectElementTypeId, localName, document),
}
}
@@ -30,6 +37,35 @@ impl HTMLObjectElement {
}
impl HTMLObjectElement {
+
+ // Makes the local `data` member match the status of the `data` attribute and starts
+ /// prefetching the image. This method must be called after `data` is changed.
+ pub fn process_data_url(&mut self, image_cache: ImageCacheTask, url: Option<Url>) {
+ let elem = &mut self.htmlelement.element;
+
+ // TODO: support other values
+ match (elem.get_attribute(Null, "type").map(|x| x.Value()),
+ elem.get_attribute(Null, "data").map(|x| x.Value())) {
+ (None, Some(uri)) => {
+ if is_image_data(uri) {
+ let data_url = parse_url(uri, url);
+ // Issue #84
+ image_cache.send(image_cache_task::Prefetch(data_url));
+ }
+ }
+ _ => { }
+ }
+ }
+
+ pub fn AfterSetAttr(&mut self, name: DOMString, _value: DOMString) {
+ if "data" == name {
+ let document = self.htmlelement.element.node.owner_doc();
+ let window = document.document().window;
+ let url = window.page.url.as_ref().map(|&(ref url, _)| url.clone());
+ self.process_data_url(window.image_cache_task.clone(), url);
+ }
+ }
+
pub fn Data(&self) -> DOMString {
~""
}
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs
index 87e2bddaa37..3f0649fbdac 100644
--- a/src/components/script/dom/node.rs
+++ b/src/components/script/dom/node.rs
@@ -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");
diff --git a/src/components/script/html/hubbub_html_parser.rs b/src/components/script/html/hubbub_html_parser.rs
index 9b66e4ecb1a..d388a77b0e3 100644
--- a/src/components/script/html/hubbub_html_parser.rs
+++ b/src/components/script/html/hubbub_html_parser.rs
@@ -392,7 +392,6 @@ pub fn parse_html(cx: *JSContext,
image_element.update_image(image_cache_task.clone(), Some(url2.clone()));
});
}
-
_ => {}
}
diff --git a/src/components/util/url.rs b/src/components/util/url.rs
index 6ef650a64cd..004d72e48b8 100644
--- a/src/components/util/url.rs
+++ b/src/components/util/url.rs
@@ -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_))
+}
+
+
diff --git a/src/test/html/object_element.html b/src/test/html/object_element.html
new file mode 100644
index 00000000000..501e0c049f9
--- /dev/null
+++ b/src/test/html/object_element.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+ <head>
+ <title></title>
+ </head>
+<body>
+<object data="data:application/x-unknown,ERROR">
+ <object data="./nonexistent" type="text/html">
+ <object data="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAAYCAYAAAFy7sgCAAAGsUlEQVRo3u2ZbWwcZxHHf3s%2B7LNbO3ZjXBtowprGODRX0qpNQCjmJKuVKhMl1P2AkCwhFOIKkCBSm9IXavGFKAixIAECwkmWo5MrhRI3Ub40IEwQgp6aIDg3Cd6eEqyIHEteah%2B1E69vhw%2BZtTaX8704ZzkKjHS6271nZ56ZZ%2BY%2F%2F%2BdZKF%2FCwYshx3EkkggLsD1v4FQkEZZYLCbAKyG9%2Ba9EIsG6hnUAf8x74K3aUC3j4%2BM54HcsR2oAIomwZOezkv%2FnSHpYNh%2BNCmAE7xv94zvFdd1bHsjMZmQkPSxAJP%2B%2FfuBLwK54PC7JZFKAVJmzXLBt2w%2FMvcDLwIb8QS8CeJ4nkURYIomw7J%2FYJ8BvSiiXptGGxWds2%2Fa9%2Bnaxh%2BYAD%2Bgt04NDgABTpQY2cvvSFLzw86gWeBVwC8SzlOSv2YeBPfmDBoBHgKmR9LBEEmHZfDTqGykqfkUE0nA78BzQGfSgUeP3wNeTXwXg7MwZDhw4UHL6ra2ti79%2FOvljgG8AZ4H64Lhm4MvAocxsRppGG%2FxcXihlwLIs6R%2FfKV2HO%2F26uA94pdDYUKUZUU7W1RQYXA98Gnhaf5%2FXWX0HeAHYoQonqa4sZSOsSWMCWeC9Yko%2BCQwBe4E6oNc0Tc91XTl1%2BaTsn9gnI%2Blhyc5nZWxsrBIkKSbl2tiic3tW53YDEwOKaoFBrcOfqKee53lG9xsPMjV784r%2F4lO%2FpPvyJ9iyZcuvFSaXK5XYeAZ4CDgGvB3MS4B54LQuWYPeuy4iRFsevsXqpuYoqVQKIH2bK1CuDQNo11o4XUzh%2FcDWYIe1LEtyuZx4niee54njOGKapgfsqlL%2Bl2OjEXg8nxrc1dJ0h3hbtL%2BGCtz7KPBF4CuBe9uB15VafE8hr9qylI3HgG8C2%2FK7VyHZoJj7MrBRm30qFotJMpkU27YlHo%2F7Ha5a%2BV%2FKRkSJ4KuKRLVLKapTjB1SzAVIjY2NSXY%2BKyPpYdk%2FsU9OXT4pruv6BdZbBQfKsVGnvWlIe1VB6VQO8JxC1vZYLCbZ%2BaxsPhpdZDyRRFhG0sPiOE6ldKBg2lRg4xF1YCDIIIKN7DGgD3gH%2BBXwejKZfPrs2tPs%2FvPN2bKuYR1nd7xLKBSSJeqoXKnERjPwNWAG%2BLn2rZuM%2B4Tpml6vaWlp4eLcxVusZq5lCgVgOVKJjRqdX86ffL4D5wIoZACnTpw4wRMdT96i%2FImOJxERAs4uVyqxUacF%2FPdiCj%2BjdRBRGFtwXVdG0sPSdbhTmkYbpH98p2RmM2JZlig1vl0GWo4NQ%2Fn%2Bs5pKRXfwjweaxy7TND3HcRZbfC6X8xVPVQlGy7WxVWlO5XRXFXm6EZmrQuSXYyPE3SiVoEhE6Wyr0u2rumO6zv%2B21AFdQAswC1wCMuUCXCmyWQus103Qg8qlDO0lxwOb%2Fl4FiK3AB3VS%2FuKKLtK%2FgbeAnwG%2FvUODuRw%2FFrR0H1UC75fwu8oJ%2FhFsW5VIG%2FBUgEIN6Y65O4AHu4Ap0zQ9y7LEcZyb9lRBUHQcRyzL8unZVBW5bFWAvAp%2BhDQ2g4F47dUYtlU6obXA54DnVdFLekjUGGifh4AFy7LEdV3xj3X9I66m0QZpGm2QrsOd0j%2B%2BU0bSw5KZzYjrun6HWlAd961i4FfCj0aN1Usau%2Bc1lmuXPFwvAEumUut7tQQvAb%2FXb%2FT0bCAej9cODg7yt%2Bm%2F8q2%2F7OUHZ76PnZ1k2p0mJzlykmPancbOTnL0whHs7CQfb%2B5mx2d3sH79%2BtCRI0c6FeaOr9ICrIQfLvA%2B8BGNXxi4R6HrisJVUWrxAVW2oMFf0Aczim8o3kV6enowDIPjF9%2Fk%2BMU3S3rrjzMMg56eHr%2BxP7qKFbASfojG6kpeDGs1tiW53RxwWT%2Bin5q8w4xpQK5evQpAR30H7ZH2khNvj7TTUd8BgD4rqmu1ZKX8qNeY%2BfHz4zlXDgT5E8tpCTUq7XSBC4Euv8227TV9fX1E73%2BYtvo27BmbS9cvFVTY3bSRFza9yOcf6Gfmygy7d%2B%2Fm%2FPnzF4DvrsBLhnJlJfwIKXxv1PheAE4qK6p4H9AGbNKTuhngBPBPXYRe4IemaT5kWZbR19fHNbmGnZ1k4r3U4glDR30Hm5qjbGjsImJEOHbsGHv27JFz5869o0eFq01Jq%2BmHAXwI6FFKagMTgHM7GzFDS%2BoeLSMv7zjzC9x4Y7gxFovVDAwMEI1GaWlpWSzRVCrFwYMH%2FXfxZ4AfAa8B%2F7lDaGg1%2FQgp43lfK0yqtRMuJa3ceKe5DfgYsCYAZ2ngD8CfAkzqTpW7xY%2F%2FSznyX%2FVeUb2kVmX4AAAAAElFTkSuQmCC">
+ ERROR
+ </object>
+ </object>
+</object>
+</body>
+</html>
diff --git a/src/test/ref/basic.list b/src/test/ref/basic.list
index 97e2770f93f..e3e7997a5ae 100644
--- a/src/test/ref/basic.list
+++ b/src/test/ref/basic.list
@@ -33,3 +33,4 @@
== background_external_stylesheet.html background_ref.html
== block_image.html 500x300_green.html
# == simple_iframe.html simple_iframe_ref.html -- disabled due to iframe crashiness
+== object_element_a.html object_element_b.html
diff --git a/src/test/ref/object_element_a.html b/src/test/ref/object_element_a.html
new file mode 100644
index 00000000000..501e0c049f9
--- /dev/null
+++ b/src/test/ref/object_element_a.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+ <head>
+ <title></title>
+ </head>
+<body>
+<object data="data:application/x-unknown,ERROR">
+ <object data="./nonexistent" type="text/html">
+ <object data="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAAYCAYAAAFy7sgCAAAGsUlEQVRo3u2ZbWwcZxHHf3s%2B7LNbO3ZjXBtowprGODRX0qpNQCjmJKuVKhMl1P2AkCwhFOIKkCBSm9IXavGFKAixIAECwkmWo5MrhRI3Ub40IEwQgp6aIDg3Cd6eEqyIHEteah%2B1E69vhw%2BZtTaX8704ZzkKjHS6271nZ56ZZ%2BY%2F%2F%2BdZKF%2FCwYshx3EkkggLsD1v4FQkEZZYLCbAKyG9%2Ba9EIsG6hnUAf8x74K3aUC3j4%2BM54HcsR2oAIomwZOezkv%2FnSHpYNh%2BNCmAE7xv94zvFdd1bHsjMZmQkPSxAJP%2B%2FfuBLwK54PC7JZFKAVJmzXLBt2w%2FMvcDLwIb8QS8CeJ4nkURYIomw7J%2FYJ8BvSiiXptGGxWds2%2Fa9%2Bnaxh%2BYAD%2Bgt04NDgABTpQY2cvvSFLzw86gWeBVwC8SzlOSv2YeBPfmDBoBHgKmR9LBEEmHZfDTqGykqfkUE0nA78BzQGfSgUeP3wNeTXwXg7MwZDhw4UHL6ra2ti79%2FOvljgG8AZ4H64Lhm4MvAocxsRppGG%2FxcXihlwLIs6R%2FfKV2HO%2F26uA94pdDYUKUZUU7W1RQYXA98Gnhaf5%2FXWX0HeAHYoQonqa4sZSOsSWMCWeC9Yko%2BCQwBe4E6oNc0Tc91XTl1%2BaTsn9gnI%2Blhyc5nZWxsrBIkKSbl2tiic3tW53YDEwOKaoFBrcOfqKee53lG9xsPMjV784r%2F4lO%2FpPvyJ9iyZcuvFSaXK5XYeAZ4CDgGvB3MS4B54LQuWYPeuy4iRFsevsXqpuYoqVQKIH2bK1CuDQNo11o4XUzh%2FcDWYIe1LEtyuZx4niee54njOGKapgfsqlL%2Bl2OjEXg8nxrc1dJ0h3hbtL%2BGCtz7KPBF4CuBe9uB15VafE8hr9qylI3HgG8C2%2FK7VyHZoJj7MrBRm30qFotJMpkU27YlHo%2F7Ha5a%2BV%2FKRkSJ4KuKRLVLKapTjB1SzAVIjY2NSXY%2BKyPpYdk%2FsU9OXT4pruv6BdZbBQfKsVGnvWlIe1VB6VQO8JxC1vZYLCbZ%2BaxsPhpdZDyRRFhG0sPiOE6ldKBg2lRg4xF1YCDIIIKN7DGgD3gH%2BBXwejKZfPrs2tPs%2FvPN2bKuYR1nd7xLKBSSJeqoXKnERjPwNWAG%2BLn2rZuM%2B4Tpml6vaWlp4eLcxVusZq5lCgVgOVKJjRqdX86ffL4D5wIoZACnTpw4wRMdT96i%2FImOJxERAs4uVyqxUacF%2FPdiCj%2BjdRBRGFtwXVdG0sPSdbhTmkYbpH98p2RmM2JZlig1vl0GWo4NQ%2Fn%2Bs5pKRXfwjweaxy7TND3HcRZbfC6X8xVPVQlGy7WxVWlO5XRXFXm6EZmrQuSXYyPE3SiVoEhE6Wyr0u2rumO6zv%2B21AFdQAswC1wCMuUCXCmyWQus103Qg8qlDO0lxwOb%2Fl4FiK3AB3VS%2FuKKLtK%2FgbeAnwG%2FvUODuRw%2FFrR0H1UC75fwu8oJ%2FhFsW5VIG%2FBUgEIN6Y65O4AHu4Ap0zQ9y7LEcZyb9lRBUHQcRyzL8unZVBW5bFWAvAp%2BhDQ2g4F47dUYtlU6obXA54DnVdFLekjUGGifh4AFy7LEdV3xj3X9I66m0QZpGm2QrsOd0j%2B%2BU0bSw5KZzYjrun6HWlAd961i4FfCj0aN1Usau%2Bc1lmuXPFwvAEumUut7tQQvAb%2FXb%2FT0bCAej9cODg7yt%2Bm%2F8q2%2F7OUHZ76PnZ1k2p0mJzlykmPancbOTnL0whHs7CQfb%2B5mx2d3sH79%2BtCRI0c6FeaOr9ICrIQfLvA%2B8BGNXxi4R6HrisJVUWrxAVW2oMFf0Aczim8o3kV6enowDIPjF9%2Fk%2BMU3S3rrjzMMg56eHr%2BxP7qKFbASfojG6kpeDGs1tiW53RxwWT%2Bin5q8w4xpQK5evQpAR30H7ZH2khNvj7TTUd8BgD4rqmu1ZKX8qNeY%2BfHz4zlXDgT5E8tpCTUq7XSBC4Euv8227TV9fX1E73%2BYtvo27BmbS9cvFVTY3bSRFza9yOcf6Gfmygy7d%2B%2Fm%2FPnzF4DvrsBLhnJlJfwIKXxv1PheAE4qK6p4H9AGbNKTuhngBPBPXYRe4IemaT5kWZbR19fHNbmGnZ1k4r3U4glDR30Hm5qjbGjsImJEOHbsGHv27JFz5869o0eFq01Jq%2BmHAXwI6FFKagMTgHM7GzFDS%2BoeLSMv7zjzC9x4Y7gxFovVDAwMEI1GaWlpWSzRVCrFwYMH%2FXfxZ4AfAa8B%2F7lDaGg1%2FQgp43lfK0yqtRMuJa3ceKe5DfgYsCYAZ2ngD8CfAkzqTpW7xY%2F%2FSznyX%2FVeUb2kVmX4AAAAAElFTkSuQmCC">
+ ERROR
+ </object>
+ </object>
+</object>
+</body>
+</html>
diff --git a/src/test/ref/object_element_b.html b/src/test/ref/object_element_b.html
new file mode 100644
index 00000000000..ae6d8ab3648
--- /dev/null
+++ b/src/test/ref/object_element_b.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+ <head>
+ <title></title>
+ </head>
+<body>
+<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAAYCAYAAAFy7sgCAAAGsUlEQVRo3u2ZbWwcZxHHf3s%2B7LNbO3ZjXBtowprGODRX0qpNQCjmJKuVKhMl1P2AkCwhFOIKkCBSm9IXavGFKAixIAECwkmWo5MrhRI3Ub40IEwQgp6aIDg3Cd6eEqyIHEteah%2B1E69vhw%2BZtTaX8704ZzkKjHS6271nZ56ZZ%2BY%2F%2F%2BdZKF%2FCwYshx3EkkggLsD1v4FQkEZZYLCbAKyG9%2Ba9EIsG6hnUAf8x74K3aUC3j4%2BM54HcsR2oAIomwZOezkv%2FnSHpYNh%2BNCmAE7xv94zvFdd1bHsjMZmQkPSxAJP%2B%2FfuBLwK54PC7JZFKAVJmzXLBt2w%2FMvcDLwIb8QS8CeJ4nkURYIomw7J%2FYJ8BvSiiXptGGxWds2%2Fa9%2Bnaxh%2BYAD%2Bgt04NDgABTpQY2cvvSFLzw86gWeBVwC8SzlOSv2YeBPfmDBoBHgKmR9LBEEmHZfDTqGykqfkUE0nA78BzQGfSgUeP3wNeTXwXg7MwZDhw4UHL6ra2ti79%2FOvljgG8AZ4H64Lhm4MvAocxsRppGG%2FxcXihlwLIs6R%2FfKV2HO%2F26uA94pdDYUKUZUU7W1RQYXA98Gnhaf5%2FXWX0HeAHYoQonqa4sZSOsSWMCWeC9Yko%2BCQwBe4E6oNc0Tc91XTl1%2BaTsn9gnI%2Blhyc5nZWxsrBIkKSbl2tiic3tW53YDEwOKaoFBrcOfqKee53lG9xsPMjV784r%2F4lO%2FpPvyJ9iyZcuvFSaXK5XYeAZ4CDgGvB3MS4B54LQuWYPeuy4iRFsevsXqpuYoqVQKIH2bK1CuDQNo11o4XUzh%2FcDWYIe1LEtyuZx4niee54njOGKapgfsqlL%2Bl2OjEXg8nxrc1dJ0h3hbtL%2BGCtz7KPBF4CuBe9uB15VafE8hr9qylI3HgG8C2%2FK7VyHZoJj7MrBRm30qFotJMpkU27YlHo%2F7Ha5a%2BV%2FKRkSJ4KuKRLVLKapTjB1SzAVIjY2NSXY%2BKyPpYdk%2FsU9OXT4pruv6BdZbBQfKsVGnvWlIe1VB6VQO8JxC1vZYLCbZ%2BaxsPhpdZDyRRFhG0sPiOE6ldKBg2lRg4xF1YCDIIIKN7DGgD3gH%2BBXwejKZfPrs2tPs%2FvPN2bKuYR1nd7xLKBSSJeqoXKnERjPwNWAG%2BLn2rZuM%2B4Tpml6vaWlp4eLcxVusZq5lCgVgOVKJjRqdX86ffL4D5wIoZACnTpw4wRMdT96i%2FImOJxERAs4uVyqxUacF%2FPdiCj%2BjdRBRGFtwXVdG0sPSdbhTmkYbpH98p2RmM2JZlig1vl0GWo4NQ%2Fn%2Bs5pKRXfwjweaxy7TND3HcRZbfC6X8xVPVQlGy7WxVWlO5XRXFXm6EZmrQuSXYyPE3SiVoEhE6Wyr0u2rumO6zv%2B21AFdQAswC1wCMuUCXCmyWQus103Qg8qlDO0lxwOb%2Fl4FiK3AB3VS%2FuKKLtK%2FgbeAnwG%2FvUODuRw%2FFrR0H1UC75fwu8oJ%2FhFsW5VIG%2FBUgEIN6Y65O4AHu4Ap0zQ9y7LEcZyb9lRBUHQcRyzL8unZVBW5bFWAvAp%2BhDQ2g4F47dUYtlU6obXA54DnVdFLekjUGGifh4AFy7LEdV3xj3X9I66m0QZpGm2QrsOd0j%2B%2BU0bSw5KZzYjrun6HWlAd961i4FfCj0aN1Usau%2Bc1lmuXPFwvAEumUut7tQQvAb%2FXb%2FT0bCAej9cODg7yt%2Bm%2F8q2%2F7OUHZ76PnZ1k2p0mJzlykmPancbOTnL0whHs7CQfb%2B5mx2d3sH79%2BtCRI0c6FeaOr9ICrIQfLvA%2B8BGNXxi4R6HrisJVUWrxAVW2oMFf0Aczim8o3kV6enowDIPjF9%2Fk%2BMU3S3rrjzMMg56eHr%2BxP7qKFbASfojG6kpeDGs1tiW53RxwWT%2Bin5q8w4xpQK5evQpAR30H7ZH2khNvj7TTUd8BgD4rqmu1ZKX8qNeY%2BfHz4zlXDgT5E8tpCTUq7XSBC4Euv8227TV9fX1E73%2BYtvo27BmbS9cvFVTY3bSRFza9yOcf6Gfmygy7d%2B%2Fm%2FPnzF4DvrsBLhnJlJfwIKXxv1PheAE4qK6p4H9AGbNKTuhngBPBPXYRe4IemaT5kWZbR19fHNbmGnZ1k4r3U4glDR30Hm5qjbGjsImJEOHbsGHv27JFz5869o0eFq01Jq%2BmHAXwI6FFKagMTgHM7GzFDS%2BoeLSMv7zjzC9x4Y7gxFovVDAwMEI1GaWlpWSzRVCrFwYMH%2FXfxZ4AfAa8B%2F7lDaGg1%2FQgp43lfK0yqtRMuJa3ceKe5DfgYsCYAZ2ngD8CfAkzqTpW7xY%2F%2FSznyX%2FVeUb2kVmX4AAAAAElFTkSuQmCC"/>
+</body>
+</html> \ No newline at end of file