Shadow DOM for img element
authorshinyak@chromium.org <shinyak@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 17 Jul 2012 08:27:27 +0000 (08:27 +0000)
committershinyak@chromium.org <shinyak@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 17 Jul 2012 08:27:27 +0000 (08:27 +0000)
https://bugs.webkit.org/show_bug.cgi?id=90532

Reviewed by Hajime Morita.

Source/WebCore:

This patch adds Shadow DOM support for img element.

According to the Shadow DOM spec, img element should behave like having a user agent Shadow DOM.
However, if we add Shadow DOM to img by default, it will cause performance regression and memory bloat.

So, we would like to postpone adding a Shadow DOM to img until when we really need it. In other words,
we add our User Agent Shadow DOM to img just before a user adds Author Shadow DOM.

The User Agent Shadow DOM for img has only one element, which displays an image. If img has
a Shadow DOM, img will behave like <span style="display: inline-block"> by default. The display style can
be chagned using CSS though.

This patch also adds ImageLoaderClient. The element we render an image and the element we take an argument
from were the same, however not they might be different. We would like to encapsulate the fact into
ImageLoaderClient.

Tests: fast/dom/shadow/shadowdom-for-image-alt-update.html
       fast/dom/shadow/shadowdom-for-image-alt.html
       fast/dom/shadow/shadowdom-for-image-content.html
       fast/dom/shadow/shadowdom-for-image-dynamic.html
       fast/dom/shadow/shadowdom-for-image-event-click.html
       fast/dom/shadow/shadowdom-for-image-in-shadowdom.html
       fast/dom/shadow/shadowdom-for-image-map.html
       fast/dom/shadow/shadowdom-for-image-style.html
       fast/dom/shadow/shadowdom-for-image-with-multiple-shadow.html
       fast/dom/shadow/shadowdom-for-image-with-width-and-height.html
       fast/dom/shadow/shadowdom-for-image.html

* CMakeLists.txt:
* GNUmakefile.list.am:
* Target.pri:
* WebCore.gypi:
* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:
* css/html.css:
(img):
* html/HTMLImageElement.cpp:
(WebCore::ImageElement::setImageIfNecessary):
(WebCore):
(WebCore::ImageElement::createRendererForImage):
(WebCore::HTMLImageElement::willAddAuthorShadowRoot): When we don't have a user agent Shadow DOM yet
we add it.
(WebCore::HTMLImageElement::createShadowSubtree):
(WebCore::HTMLImageElement::imageElement):
(WebCore::HTMLImageElement::parseAttribute):
(WebCore::HTMLImageElement::createRenderer): If a user agent Shadow DOM is attached, we create
Renderer from style, instead of creating RenderImage.
(WebCore::HTMLImageElement::attach):
(WebCore::HTMLImageElement::innerElement):
* html/HTMLImageElement.h:
(WebCore):
(ImageElement):
(HTMLImageElement):
(WebCore::HTMLImageElement::sourceElement):
(WebCore::HTMLImageElement::refSourceElement):
(WebCore::HTMLImageElement::derefSourceElement):
(WebCore::HTMLImageElement::imageRenderer):
(WebCore::HTMLImageElement::imageLoader):
(WebCore::isHTMLImageElement):
(WebCore::toHTMLImageElement):
* html/HTMLImageLoader.cpp:
(WebCore::HTMLImageLoader::HTMLImageLoader):
(WebCore::HTMLImageLoader::dispatchLoadEvent):
(WebCore::HTMLImageLoader::sourceURI):
(WebCore::HTMLImageLoader::notifyFinished):
* html/HTMLImageLoader.h:
(HTMLImageLoader):
* html/HTMLInputElement.h:
* html/HTMLObjectElement.h:
* html/HTMLPlugInElement.h:
* html/HTMLTagNames.in:
* html/HTMLVideoElement.h:
* html/shadow/ImageInnerElement.cpp: Added.
(WebCore):
(WebCore::ImageInnerElement::ImageInnerElement):
(WebCore::ImageInnerElement::hostImage):
(WebCore::ImageInnerElement::imageLoader):
(WebCore::ImageInnerElement::attach):
(WebCore::ImageInnerElement::createRenderer):
* html/shadow/ImageInnerElement.h: Added.
(WebCore):
(ImageInnerElement):
(WebCore::ImageInnerElement::imageRenderer):
(WebCore::ImageInnerElement::create):
(WebCore::isImageInnerElement):
(WebCore::toImageInnerElement):
* loader/ImageLoader.cpp:
(WebCore::ImageLoader::ImageLoader):
(WebCore::ImageLoader::~ImageLoader):
(WebCore):
(WebCore::ImageLoader::document):
(WebCore::ImageLoader::updateFromElement):
(WebCore::ImageLoader::notifyFinished):
(WebCore::ImageLoader::renderImageResource):
(WebCore::ImageLoader::updatedHasPendingLoadEvent):
(WebCore::ImageLoader::dispatchPendingBeforeLoadEvent):
(WebCore::ImageLoader::dispatchPendingLoadEvent):
(WebCore::ImageLoader::dispatchPendingErrorEvent):
* loader/ImageLoader.h:
(WebCore):
(ImageLoader):
(WebCore::ImageLoader::client):
* loader/ImageLoaderClient.h: Added.
(WebCore):
(ImageLoaderClient): Provides the necessary interfaces to ImageLoader.
(WebCore::ImageLoaderClient::~ImageLoaderClient):
(ImageLoaderClientBase):
(WebCore::ImageLoaderClientBase::sourceElement):
(WebCore::ImageLoaderClientBase::imageElement):
(WebCore::ImageLoaderClientBase::refSourceElement):
(WebCore::ImageLoaderClientBase::derefSourceElement):
* rendering/RenderImage.cpp:
(WebCore::RenderImage::paintIntoRect):
(WebCore::RenderImage::imageMap):
(WebCore::RenderImage::updateAltText):
(WebCore::RenderImage::hostImageElement):
(WebCore):
* rendering/RenderImage.h:
(WebCore):
(RenderImage):
* rendering/RenderObject.cpp:
(WebCore::RenderObject::shouldRespectImageOrientation):
* svg/SVGImageElement.h:
(SVGImageElement):
* svg/SVGImageLoader.cpp:
(WebCore::SVGImageLoader::SVGImageLoader):
(WebCore::SVGImageLoader::dispatchLoadEvent):
(WebCore::SVGImageLoader::sourceURI):
* svg/SVGImageLoader.h:
(SVGImageLoader):

LayoutTests:

Contains the following test cases.
(1) ShadowDOM is attached to an img element and use a shadow element
(2) ShadowDOM is attached to an img element and use a content element
(3) width and height are specified
(4) src attribute is dynamically changed
(5) multiple ShadowDOMs are attached to an img element
(6) ShadowDOM is attached to an img element in Shadow DOM
(7) event retargetting
(8) img with display: none, display: inline, display: block
(9) image map
(10) alt text
(11) alt text with dynamic update

* fast/dom/shadow/shadowdom-for-image-alt-expected.html: Added.
* fast/dom/shadow/shadowdom-for-image-alt-update-expected.html: Added.
* fast/dom/shadow/shadowdom-for-image-alt-update.html: Added.
* fast/dom/shadow/shadowdom-for-image-alt.html: Added.
* fast/dom/shadow/shadowdom-for-image-content-expected.html: Added.
* fast/dom/shadow/shadowdom-for-image-content.html: Added.
* fast/dom/shadow/shadowdom-for-image-dynamic-expected.html: Added.
* fast/dom/shadow/shadowdom-for-image-dynamic.html: Added.
* fast/dom/shadow/shadowdom-for-image-event-click-expected.txt: Added.
* fast/dom/shadow/shadowdom-for-image-event-click.html: Added.
* fast/dom/shadow/shadowdom-for-image-expected.html: Added.
* fast/dom/shadow/shadowdom-for-image-in-shadowdom-expected.html: Added.
* fast/dom/shadow/shadowdom-for-image-in-shadowdom.html: Added.
* fast/dom/shadow/shadowdom-for-image-map-expected.txt: Added.
* fast/dom/shadow/shadowdom-for-image-map.html: Added.
* fast/dom/shadow/shadowdom-for-image-style-expected.html: Added.
* fast/dom/shadow/shadowdom-for-image-style.html: Added.
* fast/dom/shadow/shadowdom-for-image-with-multiple-shadow-expected.html: Added.
* fast/dom/shadow/shadowdom-for-image-with-multiple-shadow.html: Added.
* fast/dom/shadow/shadowdom-for-image-with-width-and-height-expected.html: Added.
* fast/dom/shadow/shadowdom-for-image-with-width-and-height.html: Added.
* fast/dom/shadow/shadowdom-for-image.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@122824 268f45cc-cd09-0410-ab3c-d52691b4dbfc

51 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/dom/shadow/shadowdom-for-image-alt-expected.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-alt-update-expected.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-alt-update.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-alt.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-content-expected.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-content.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-dynamic-expected.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-dynamic.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-event-click-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-event-click.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-expected.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-in-shadowdom-expected.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-in-shadowdom.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-map-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-map.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-style-expected.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-style.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-with-multiple-shadow-expected.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-with-multiple-shadow.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-with-width-and-height-expected.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image-with-width-and-height.html [new file with mode: 0644]
LayoutTests/fast/dom/shadow/shadowdom-for-image.html [new file with mode: 0644]
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/Target.pri
Source/WebCore/WebCore.gypi
Source/WebCore/WebCore.vcproj/WebCore.vcproj
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/css/html.css
Source/WebCore/html/HTMLImageElement.cpp
Source/WebCore/html/HTMLImageElement.h
Source/WebCore/html/HTMLImageLoader.cpp
Source/WebCore/html/HTMLImageLoader.h
Source/WebCore/html/HTMLInputElement.h
Source/WebCore/html/HTMLObjectElement.h
Source/WebCore/html/HTMLPlugInElement.h
Source/WebCore/html/HTMLTagNames.in
Source/WebCore/html/HTMLVideoElement.h
Source/WebCore/html/shadow/ImageInnerElement.cpp [new file with mode: 0644]
Source/WebCore/html/shadow/ImageInnerElement.h [new file with mode: 0644]
Source/WebCore/loader/ImageLoader.cpp
Source/WebCore/loader/ImageLoader.h
Source/WebCore/loader/ImageLoaderClient.h [new file with mode: 0644]
Source/WebCore/rendering/RenderImage.cpp
Source/WebCore/rendering/RenderImage.h
Source/WebCore/rendering/RenderObject.cpp
Source/WebCore/svg/SVGImageElement.h
Source/WebCore/svg/SVGImageLoader.cpp
Source/WebCore/svg/SVGImageLoader.h

index 08f5acf..7f38bf2 100644 (file)
@@ -1,3 +1,46 @@
+2012-07-17  Shinya Kawanaka  <shinyak@chromium.org>
+
+        Shadow DOM for img element
+        https://bugs.webkit.org/show_bug.cgi?id=90532
+
+        Reviewed by Hajime Morita.
+
+        Contains the following test cases.
+        (1) ShadowDOM is attached to an img element and use a shadow element
+        (2) ShadowDOM is attached to an img element and use a content element
+        (3) width and height are specified
+        (4) src attribute is dynamically changed
+        (5) multiple ShadowDOMs are attached to an img element
+        (6) ShadowDOM is attached to an img element in Shadow DOM
+        (7) event retargetting
+        (8) img with display: none, display: inline, display: block
+        (9) image map
+        (10) alt text
+        (11) alt text with dynamic update
+
+        * fast/dom/shadow/shadowdom-for-image-alt-expected.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-alt-update-expected.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-alt-update.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-alt.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-content-expected.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-content.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-dynamic-expected.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-dynamic.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-event-click-expected.txt: Added.
+        * fast/dom/shadow/shadowdom-for-image-event-click.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-expected.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-in-shadowdom-expected.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-in-shadowdom.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-map-expected.txt: Added.
+        * fast/dom/shadow/shadowdom-for-image-map.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-style-expected.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-style.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-with-multiple-shadow-expected.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-with-multiple-shadow.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-with-width-and-height-expected.html: Added.
+        * fast/dom/shadow/shadowdom-for-image-with-width-and-height.html: Added.
+        * fast/dom/shadow/shadowdom-for-image.html: Added.
+
 2012-07-17  Vsevolod Vlasov  <vsevik@chromium.org>
 
         Unreviewed chromium tests rebaselines after r122791.
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-alt-expected.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-alt-expected.html
new file mode 100644 (file)
index 0000000..5bc300c
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div id="container">
+    <div>
+        <div style="display: inline-block">(before)<img src="there-is-no-such-image.png" alt="Kotori Otonashi" width="300" height="200">(after)</div>
+    </div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-alt-update-expected.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-alt-update-expected.html
new file mode 100644 (file)
index 0000000..2305fac
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div id="container">
+    <div>
+        <div style="display: inline-block">(before)<img src="there-is-no-such-image.png" alt="72" width="300" height="200">(after)</div>
+    </div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-alt-update.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-alt-update.html
new file mode 100644 (file)
index 0000000..9535976
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="resources/polyfill.js"></script>
+
+<div id="container">
+    <div>
+        <img id="host" src="there-is-no-such-image.png" alt="Chihaya Kisaragi">
+    </div>
+</div>
+
+<script>
+function addShadowDOM(host) {
+    var shadowRoot = new WebKitShadowRoot(host);
+    shadowRoot.innerHTML = "(before)<shadow></shadow>(after)";
+
+    var userAgentShadowRoot = internals.oldestShadowRoot(host);
+    var innerElement = userAgentShadowRoot.firstChild;
+    innerElement.style.width = '300px';
+    innerElement.style.height = '200px';
+
+    host.setAttribute('alt', '72');
+}
+
+addShadowDOM(host);
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-alt.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-alt.html
new file mode 100644 (file)
index 0000000..dd6468b
--- /dev/null
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="resources/polyfill.js"></script>
+
+<div id="container">
+    <div>
+        <img id="host" src="there-is-no-such-image.png" alt="Kotori Otonashi">
+    </div>
+</div>
+
+<script>
+function addShadowDOM(host) {
+    var shadowRoot = new WebKitShadowRoot(host);
+    shadowRoot.innerHTML = "(before)<shadow></shadow>(after)";
+
+    var userAgentShadowRoot = internals.oldestShadowRoot(host);
+    var innerElement = userAgentShadowRoot.firstChild;
+    innerElement.style.width = '300px';
+    innerElement.style.height = '200px';
+}
+
+addShadowDOM(host);
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-content-expected.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-content-expected.html
new file mode 100644 (file)
index 0000000..f7d8a75
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div id="container">
+    <div>
+        <div style="display: inline-block">(before)<img src="../resources/apple.gif">(after)<span>light child of span</span></div>
+    </div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-content.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-content.html
new file mode 100644 (file)
index 0000000..f44dd1e
--- /dev/null
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="resources/polyfill.js"></script>
+
+<div id="container">
+    <div>
+        <img id="host" src="../resources/apple.gif">
+    </div>
+</div>
+
+<script>
+function addShadowDOM(host) {
+    var shadowRoot = new WebKitShadowRoot(host);
+    shadowRoot.innerHTML = "(before)<shadow></shadow>(after)<content></content>";
+}
+
+var span = document.createElement('span');
+span.innerHTML = 'light child of span';
+
+host.appendChild(span);
+addShadowDOM(host);
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-dynamic-expected.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-dynamic-expected.html
new file mode 100644 (file)
index 0000000..00d1d9c
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div id="container">
+    <div>
+        <div style="display: inline-block; width: 20px; height:20px">(before)<img src="../resources/mozilla.gif">(after)</div>
+    </div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-dynamic.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-dynamic.html
new file mode 100644 (file)
index 0000000..46718f8
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="resources/polyfill.js"></script>
+
+<div id="container">
+    <div>
+        <img id="host" src="../resources/apple.gif">
+    </div>
+</div>
+
+<script>
+function addShadowDOM(host) {
+    var shadowRoot = new WebKitShadowRoot(host);
+    shadowRoot.innerHTML = "(before)<shadow></shadow>(after)"
+}
+
+addShadowDOM(host);
+
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+setTimeout(function() {
+    host.setAttribute("src", "../resources/mozilla.gif");
+    host.setAttribute("width", "20");
+    host.setAttribute("height", "20");
+
+    host.onload = function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }
+}, 0);
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-event-click-expected.txt b/LayoutTests/fast/dom/shadow/shadowdom-for-image-event-click-expected.txt
new file mode 100644 (file)
index 0000000..cc1f63e
--- /dev/null
@@ -0,0 +1,3 @@
+This test confirms img element can listen an event from its Shadow DOM.
+
+PASS
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-event-click.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-event-click.html
new file mode 100644 (file)
index 0000000..4721106
--- /dev/null
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="resources/polyfill.js"></script>
+
+<p>This test confirms img element can listen an event from its Shadow DOM.</p>
+<div id="container">
+    <div>
+        <img id="host" src="../resources/apple.gif">
+    </div>
+</div>
+
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+function addShadowDOM(host) {
+    var shadowRoot = new WebKitShadowRoot(host);
+    shadowRoot.innerHTML = "(before)<shadow></shadow>(after) <span id='target'>target</span>";
+    return shadowRoot;
+}
+
+host.addEventListener('click', function() {
+    container.innerHTML = "PASS";
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+
+var shadowRoot = addShadowDOM(host);
+
+var target = shadowRoot.getElementById('target');
+if (window.eventSender) {
+    eventSender.mouseMoveTo(target.offsetLeft + target.offsetWidth / 2, target.offsetTop + target.offsetHeight / 2);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+}
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-expected.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-expected.html
new file mode 100644 (file)
index 0000000..324774f
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div id="container">
+    <div>
+        <div style="display: inline-block">(before)<img src="../resources/apple.gif">(after)</div>
+    </div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-in-shadowdom-expected.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-in-shadowdom-expected.html
new file mode 100644 (file)
index 0000000..f4bed00
--- /dev/null
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div id="container">
+    <div id="host">before(before)<img src="../resources/apple.gif">(after)after</div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-in-shadowdom.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-in-shadowdom.html
new file mode 100644 (file)
index 0000000..c11e17e
--- /dev/null
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="resources/polyfill.js"></script>
+
+<div id="container">
+    <div id="host"></div>
+</div>
+
+<script>
+var shadowRoot = new WebKitShadowRoot(host);
+shadowRoot.innerHTML = "before<img id='img' src='../resources/apple.gif'>after";
+
+var img = shadowRoot.getElementById('img');
+var nestedShadowRoot = new WebKitShadowRoot(img);
+
+nestedShadowRoot.innerHTML = "(before)<shadow></shadow>(after)";
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-map-expected.txt b/LayoutTests/fast/dom/shadow/shadowdom-for-image-map-expected.txt
new file mode 100644 (file)
index 0000000..bf9cb4d
--- /dev/null
@@ -0,0 +1,5 @@
+This test ensures that image map works in img with Shadow DOM.
+
+PASS
+PASS
+PASS
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-map.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-map.html
new file mode 100644 (file)
index 0000000..f57e257
--- /dev/null
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="resources/polyfill.js"></script>
+
+<p>This test ensures that image map works in img with Shadow DOM.</p>
+<div id="container">
+    <div>
+        <map name="map">
+            <area href="#rect" shape="rect" alt="Rect" coords="0,0,10,10" onclick="result1.innerHTML='PASS'; return false;">
+            <area href="#circle" shape="circle" alt="Circle" coords="20,10,5" onclick="result2.innerHTML='PASS'; return false;">
+            <area href="#poly" shape="poly" alt="Poly" coords="30,0,40,0,40,10,30,10" onclick="result3.innerHTML='PASS'; return false;">
+        </map>
+        <img id="host" src="../resources/apple.gif" usemap="#map" width="100" height="100" ismap>
+    </div>
+</div>
+<div id="result1"></div>
+<div id="result2"></div>
+<div id="result3"></div>
+
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+
+function addShadowDOM(host) {
+    var shadowRoot = new WebKitShadowRoot(host);
+    shadowRoot.innerHTML = "<shadow></shadow>";
+
+    var userAgentShadowRoot = internals.oldestShadowRoot(host);
+    userAgentShadowRoot.firstChild.style.width='100px';
+    userAgentShadowRoot.firstChild.style.height='100px';
+}
+addShadowDOM(host);
+
+function click(x, y) {
+    eventSender.mouseMoveTo(x, y);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+}
+
+click(host.offsetLeft + 5, host.offsetTop + 5);
+click(host.offsetLeft + 20, host.offsetTop + 10);
+click(host.offsetLeft + 35, host.offsetTop + 5);
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-style-expected.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-style-expected.html
new file mode 100644 (file)
index 0000000..15007d1
--- /dev/null
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div>
+    <div>
+        <div style="display: none; width: 20px; height: 20px;">(before)<img src="../resources/apple.gif">(after)</div>
+    </div>
+</div>
+<div>
+    <div>
+        <div style="display: block; width: 20px; height: 20px;">(before)<img src="../resources/apple.gif">(after)</div>
+    </div>
+</div>
+<div>
+    <div>
+        <div style="display: inline; width: 20px; height: 20px;">(before)<img src="../resources/apple.gif">(after)</div>
+    </div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-style.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-style.html
new file mode 100644 (file)
index 0000000..5574a66
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="resources/polyfill.js"></script>
+
+<div>
+    <div>
+        <img id="host1" style="display: none" src="../resources/apple.gif" width="20" height="20">
+    </div>
+</div>
+
+<div>
+    <div>
+        <img id="host2" style="display: block" src="../resources/apple.gif" width="20" height="20">
+    </div>
+</div>
+
+<div>
+    <div>
+        <img id="host3" style="display: inline" src="../resources/apple.gif" width="20" height="20">
+    </div>
+</div>
+
+<script>
+function addShadowDOM(host) {
+    var shadowRoot = new WebKitShadowRoot(host);
+    shadowRoot.innerHTML = "(before)<shadow></shadow>(after)";
+}
+
+addShadowDOM(host1);
+addShadowDOM(host2);
+addShadowDOM(host3);
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-with-multiple-shadow-expected.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-with-multiple-shadow-expected.html
new file mode 100644 (file)
index 0000000..2d3a262
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div id="container">
+    <div>
+        <div style="display: inline-block">(before)<div style="display: inline-block">(before)<img src="../resources/apple.gif">(after)</div>(after)</div>
+    </div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-with-multiple-shadow.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-with-multiple-shadow.html
new file mode 100644 (file)
index 0000000..12ca5f8
--- /dev/null
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="resources/polyfill.js"></script>
+
+<div id="container">
+    <div>
+        <img id="host" src="../resources/apple.gif">
+    </div>
+</div>
+
+<script>
+function addShadowDOM(host) {
+    var shadowRoot = new WebKitShadowRoot(host);
+    shadowRoot.innerHTML = "(before)<shadow></shadow>(after)"
+}
+
+addShadowDOM(host);
+addShadowDOM(host);
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-with-width-and-height-expected.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-with-width-and-height-expected.html
new file mode 100644 (file)
index 0000000..9ecdf94
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div id="container">
+    <div>
+        <div style="display: inline-block; width: 30px; height: 30px;">(before)<img src="../resources/apple.gif">(after)</div>
+    </div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image-with-width-and-height.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image-with-width-and-height.html
new file mode 100644 (file)
index 0000000..5fcd429
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="resources/polyfill.js"></script>
+
+<div id="container">
+    <div>
+        <img id="host" src="../resources/apple.gif" width="30" height="30">
+    </div>
+</div>
+
+<script>
+function addShadowDOM(host) {
+    var shadowRoot = new WebKitShadowRoot(host);
+    shadowRoot.innerHTML = "(before)<shadow></shadow>(after)";
+}
+
+addShadowDOM(host);
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/shadow/shadowdom-for-image.html b/LayoutTests/fast/dom/shadow/shadowdom-for-image.html
new file mode 100644 (file)
index 0000000..dc28983
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="resources/polyfill.js"></script>
+
+<div id="container">
+    <div>
+        <img id="host" src="../resources/apple.gif">
+    </div>
+</div>
+
+<script>
+function addShadowDOM(host) {
+    var shadowRoot = new WebKitShadowRoot(host);
+    shadowRoot.innerHTML = "(before)<shadow></shadow>(after)";
+}
+
+addShadowDOM(host);
+</script>
+
+</body>
+</html>
index f726d61..b9206a3 100644 (file)
@@ -930,6 +930,7 @@ SET(WebCore_SOURCES
     html/shadow/DetailsMarkerControl.cpp
     html/shadow/HTMLContentElement.cpp
     html/shadow/HTMLShadowElement.cpp
+    html/shadow/ImageInnerElement.cpp
     html/shadow/InsertionPoint.cpp
     html/shadow/MediaControls.cpp
     html/shadow/MediaControlRootElement.cpp
index e26b5da..8990f13 100644 (file)
@@ -1,3 +1,141 @@
+2012-07-17  Shinya Kawanaka  <shinyak@chromium.org>
+
+        Shadow DOM for img element
+        https://bugs.webkit.org/show_bug.cgi?id=90532
+
+        Reviewed by Hajime Morita.
+
+        This patch adds Shadow DOM support for img element.
+
+        According to the Shadow DOM spec, img element should behave like having a user agent Shadow DOM.
+        However, if we add Shadow DOM to img by default, it will cause performance regression and memory bloat.
+
+        So, we would like to postpone adding a Shadow DOM to img until when we really need it. In other words,
+        we add our User Agent Shadow DOM to img just before a user adds Author Shadow DOM.
+
+        The User Agent Shadow DOM for img has only one element, which displays an image. If img has
+        a Shadow DOM, img will behave like <span style="display: inline-block"> by default. The display style can
+        be chagned using CSS though.
+
+        This patch also adds ImageLoaderClient. The element we render an image and the element we take an argument
+        from were the same, however not they might be different. We would like to encapsulate the fact into
+        ImageLoaderClient.
+
+        Tests: fast/dom/shadow/shadowdom-for-image-alt-update.html
+               fast/dom/shadow/shadowdom-for-image-alt.html
+               fast/dom/shadow/shadowdom-for-image-content.html
+               fast/dom/shadow/shadowdom-for-image-dynamic.html
+               fast/dom/shadow/shadowdom-for-image-event-click.html
+               fast/dom/shadow/shadowdom-for-image-in-shadowdom.html
+               fast/dom/shadow/shadowdom-for-image-map.html
+               fast/dom/shadow/shadowdom-for-image-style.html
+               fast/dom/shadow/shadowdom-for-image-with-multiple-shadow.html
+               fast/dom/shadow/shadowdom-for-image-with-width-and-height.html
+               fast/dom/shadow/shadowdom-for-image.html
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * Target.pri:
+        * WebCore.gypi:
+        * WebCore.vcproj/WebCore.vcproj:
+        * WebCore.xcodeproj/project.pbxproj:
+        * css/html.css:
+        (img):
+        * html/HTMLImageElement.cpp:
+        (WebCore::ImageElement::setImageIfNecessary):
+        (WebCore):
+        (WebCore::ImageElement::createRendererForImage):
+        (WebCore::HTMLImageElement::willAddAuthorShadowRoot): When we don't have a user agent Shadow DOM yet
+        we add it.
+        (WebCore::HTMLImageElement::createShadowSubtree):
+        (WebCore::HTMLImageElement::imageElement):
+        (WebCore::HTMLImageElement::parseAttribute):
+        (WebCore::HTMLImageElement::createRenderer): If a user agent Shadow DOM is attached, we create
+        Renderer from style, instead of creating RenderImage.
+        (WebCore::HTMLImageElement::attach):
+        (WebCore::HTMLImageElement::innerElement):
+        * html/HTMLImageElement.h:
+        (WebCore):
+        (ImageElement):
+        (HTMLImageElement):
+        (WebCore::HTMLImageElement::sourceElement):
+        (WebCore::HTMLImageElement::refSourceElement):
+        (WebCore::HTMLImageElement::derefSourceElement):
+        (WebCore::HTMLImageElement::imageRenderer):
+        (WebCore::HTMLImageElement::imageLoader):
+        (WebCore::isHTMLImageElement):
+        (WebCore::toHTMLImageElement):
+        * html/HTMLImageLoader.cpp:
+        (WebCore::HTMLImageLoader::HTMLImageLoader):
+        (WebCore::HTMLImageLoader::dispatchLoadEvent):
+        (WebCore::HTMLImageLoader::sourceURI):
+        (WebCore::HTMLImageLoader::notifyFinished):
+        * html/HTMLImageLoader.h:
+        (HTMLImageLoader):
+        * html/HTMLInputElement.h:
+        * html/HTMLObjectElement.h:
+        * html/HTMLPlugInElement.h:
+        * html/HTMLTagNames.in:
+        * html/HTMLVideoElement.h:
+        * html/shadow/ImageInnerElement.cpp: Added.
+        (WebCore):
+        (WebCore::ImageInnerElement::ImageInnerElement):
+        (WebCore::ImageInnerElement::hostImage):
+        (WebCore::ImageInnerElement::imageLoader):
+        (WebCore::ImageInnerElement::attach):
+        (WebCore::ImageInnerElement::createRenderer):
+        * html/shadow/ImageInnerElement.h: Added.
+        (WebCore):
+        (ImageInnerElement):
+        (WebCore::ImageInnerElement::imageRenderer):
+        (WebCore::ImageInnerElement::create):
+        (WebCore::isImageInnerElement):
+        (WebCore::toImageInnerElement):
+        * loader/ImageLoader.cpp:
+        (WebCore::ImageLoader::ImageLoader):
+        (WebCore::ImageLoader::~ImageLoader):
+        (WebCore):
+        (WebCore::ImageLoader::document):
+        (WebCore::ImageLoader::updateFromElement):
+        (WebCore::ImageLoader::notifyFinished):
+        (WebCore::ImageLoader::renderImageResource):
+        (WebCore::ImageLoader::updatedHasPendingLoadEvent):
+        (WebCore::ImageLoader::dispatchPendingBeforeLoadEvent):
+        (WebCore::ImageLoader::dispatchPendingLoadEvent):
+        (WebCore::ImageLoader::dispatchPendingErrorEvent):
+        * loader/ImageLoader.h:
+        (WebCore):
+        (ImageLoader):
+        (WebCore::ImageLoader::client):
+        * loader/ImageLoaderClient.h: Added.
+        (WebCore):
+        (ImageLoaderClient): Provides the necessary interfaces to ImageLoader.
+        (WebCore::ImageLoaderClient::~ImageLoaderClient):
+        (ImageLoaderClientBase):
+        (WebCore::ImageLoaderClientBase::sourceElement):
+        (WebCore::ImageLoaderClientBase::imageElement):
+        (WebCore::ImageLoaderClientBase::refSourceElement):
+        (WebCore::ImageLoaderClientBase::derefSourceElement):
+        * rendering/RenderImage.cpp:
+        (WebCore::RenderImage::paintIntoRect):
+        (WebCore::RenderImage::imageMap):
+        (WebCore::RenderImage::updateAltText):
+        (WebCore::RenderImage::hostImageElement):
+        (WebCore):
+        * rendering/RenderImage.h:
+        (WebCore):
+        (RenderImage):
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::shouldRespectImageOrientation):
+        * svg/SVGImageElement.h:
+        (SVGImageElement):
+        * svg/SVGImageLoader.cpp:
+        (WebCore::SVGImageLoader::SVGImageLoader):
+        (WebCore::SVGImageLoader::dispatchLoadEvent):
+        (WebCore::SVGImageLoader::sourceURI):
+        * svg/SVGImageLoader.h:
+        (SVGImageLoader):
+
 2012-07-17  Kent Tamura  <tkent@chromium.org>
 
         Internals: Remove injectPagePopupController()
index e1e5fe0..6520382 100644 (file)
@@ -2588,6 +2588,8 @@ webcore_sources += \
        Source/WebCore/html/shadow/HTMLContentElement.h \
        Source/WebCore/html/shadow/InsertionPoint.cpp \
        Source/WebCore/html/shadow/InsertionPoint.h \
+       Source/WebCore/html/shadow/ImageInnerElement.cpp \
+       Source/WebCore/html/shadow/ImageInnerElement.h \
        Source/WebCore/html/shadow/MediaControls.cpp \
        Source/WebCore/html/shadow/MediaControls.h \
        Source/WebCore/html/shadow/MediaControlElements.cpp \
@@ -2917,6 +2919,7 @@ webcore_sources += \
        Source/WebCore/loader/icon/PageURLRecord.h \
        Source/WebCore/loader/ImageLoader.cpp \
        Source/WebCore/loader/ImageLoader.h \
+       Source/WebCore/loader/ImageLoaderClient.h \
        Source/WebCore/loader/LinkLoader.h \
        Source/WebCore/loader/LinkLoader.cpp \
        Source/WebCore/loader/LinkLoaderClient.h \
index 8f0e33e..b8129fe 100644 (file)
@@ -889,6 +889,7 @@ SOURCES += \
     html/shadow/HTMLContentElement.cpp \
     html/shadow/HTMLShadowElement.cpp \
     html/shadow/InsertionPoint.cpp \
+    html/shadow/ImageInnerElement.cpp \
     html/shadow/MediaControls.cpp \
     html/shadow/MediaControlRootElement.cpp \
     html/shadow/MeterShadowElement.cpp \
index 519d414..91210e7 100644 (file)
             'loader/HistoryController.cpp',
             'loader/ImageLoader.cpp',
             'loader/ImageLoader.h',
+            'loader/ImageLoaderClient.h',
             'loader/LinkLoader.cpp',
             'loader/LinkLoader.h',
             'loader/LinkLoaderClient.h',
             'html/shadow/HTMLContentElement.h',
             'html/shadow/HTMLShadowElement.cpp',
             'html/shadow/HTMLShadowElement.h',
+            'html/shadow/ImageInnerElement.cpp',
+            'html/shadow/ImageInnerElement.h',
             'html/shadow/InsertionPoint.cpp',
             'html/shadow/InsertionPoint.h',
             'html/shadow/MediaControls.cpp',
index 29ccad3..19be056 100755 (executable)
                                >
                        </File>
                        <File
+                               RelativePath="..\loader\ImageLoaderClient.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\loader\LinkLoader.cpp"
                                >
                        </File>
                                        >
                                </File>
                                <File
+                                       RelativePath="..\html\shadow\ImageInnerElement.cpp"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath="..\html\shadow\ImageInnerElement.h"
+                                       >
+                               </File>
+                               <File
                                        RelativePath="..\html\shadow\MediaControlElements.cpp"
                                        >
                                </File>
index b7bc2c3..93be275 100644 (file)
                550A0BC9085F6039007353D6 /* QualifiedName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 550A0BC7085F6039007353D6 /* QualifiedName.cpp */; };
                550A0BCA085F6039007353D6 /* QualifiedName.h in Headers */ = {isa = PBXBuildFile; fileRef = 550A0BC8085F6039007353D6 /* QualifiedName.h */; settings = {ATTRIBUTES = (Private, ); }; };
                573D134714CE39FF0057ABCA /* InspectorTypeBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 573D134514CE39FF0057ABCA /* InspectorTypeBuilder.cpp */; };
+               5759898715AAC0B100353C31 /* ImageInnerElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 572145CC15A51DA700AD119C /* ImageInnerElement.h */; };
+               5759898915AAC0E900353C31 /* ImageInnerElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 572145CB15A51DA700AD119C /* ImageInnerElement.cpp */; };
+               5759898F15AEAB9400353C31 /* ImageLoaderClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 5759898E15AEAB9400353C31 /* ImageLoaderClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
                578DA20E1520EB8C006141C1 /* InspectorFrontend.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F4F5FFC11CBD30100A186BF /* InspectorFrontend.h */; settings = {ATTRIBUTES = (Private, ); }; };
                578DA20F1520EBA3006141C1 /* InspectorTypeBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 573D134614CE39FF0057ABCA /* InspectorTypeBuilder.h */; settings = {ATTRIBUTES = (Private, ); }; };
                57B791A314C6A62900F202D1 /* ContentDistributor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57B7919F14C6A62900F202D1 /* ContentDistributor.cpp */; };
                53C8298C13D8D92700DE2DEB /* RenderFlexibleBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderFlexibleBox.h; sourceTree = "<group>"; };
                550A0BC7085F6039007353D6 /* QualifiedName.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = QualifiedName.cpp; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                550A0BC8085F6039007353D6 /* QualifiedName.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = QualifiedName.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
+               572145CB15A51DA700AD119C /* ImageInnerElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageInnerElement.cpp; sourceTree = "<group>"; };
+               572145CC15A51DA700AD119C /* ImageInnerElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageInnerElement.h; sourceTree = "<group>"; };
                573D134514CE39FF0057ABCA /* InspectorTypeBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorTypeBuilder.cpp; sourceTree = "<group>"; };
                573D134614CE39FF0057ABCA /* InspectorTypeBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorTypeBuilder.h; sourceTree = "<group>"; };
+               5759898E15AEAB9400353C31 /* ImageLoaderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageLoaderClient.h; sourceTree = "<group>"; };
                57B7919F14C6A62900F202D1 /* ContentDistributor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ContentDistributor.cpp; sourceTree = "<group>"; };
                57B791A014C6A62900F202D1 /* ContentDistributor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentDistributor.h; sourceTree = "<group>"; };
                57B791A114C6A62900F202D1 /* ContentSelectorQuery.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ContentSelectorQuery.cpp; sourceTree = "<group>"; };
                                4ABDFF0714DBE312004D117D /* HTMLShadowElement.cpp */,
                                4ABDFF0814DBE312004D117D /* HTMLShadowElement.h */,
                                4ABDFF0914DBE312004D117D /* HTMLShadowElement.idl */,
+                               572145CB15A51DA700AD119C /* ImageInnerElement.cpp */,
+                               572145CC15A51DA700AD119C /* ImageInnerElement.h */,
                                57CF497214EE36D700ECFF14 /* InsertionPoint.cpp */,
                                57CF497314EE36D700ECFF14 /* InsertionPoint.h */,
                                417253A81354BBBC00360F2A /* MediaControlElements.cpp */,
                                97DCE20010807C750057D394 /* HistoryController.h */,
                                089582530E857A7E00F82C83 /* ImageLoader.cpp */,
                                089582540E857A7E00F82C83 /* ImageLoader.h */,
+                               5759898E15AEAB9400353C31 /* ImageLoaderClient.h */,
                                98CE4325129E00BD005821DC /* LinkLoader.cpp */,
                                98CE4329129E00E5005821DC /* LinkLoader.h */,
                                984264EF12D5280A000D88A4 /* LinkLoaderClient.h */,
                                22BD9F81135364FE009BD102 /* ImageBufferDataCG.h in Headers */,
                                A779791A0D6B9D0C003851B9 /* ImageData.h in Headers */,
                                97205AB61239291000B17380 /* ImageDocument.h in Headers */,
+                               5759898715AAC0B100353C31 /* ImageInnerElement.h in Headers */,
                                F55B3DC21251F12D003EF269 /* ImageInputType.h in Headers */,
                                089582560E857A7E00F82C83 /* ImageLoader.h in Headers */,
+                               5759898F15AEAB9400353C31 /* ImageLoaderClient.h in Headers */,
                                BC7F44A80B9E324E00A9D081 /* ImageObserver.h in Headers */,
                                2D5A5931152525D00036EE51 /* ImageOrientation.h in Headers */,
                                49291E4B134172C800E753DE /* ImageRenderingMode.h in Headers */,
                                B275355E0B053814002CE64F /* ImageCG.cpp in Sources */,
                                A77979190D6B9D0C003851B9 /* ImageData.cpp in Sources */,
                                97205AB51239291000B17380 /* ImageDocument.cpp in Sources */,
+                               5759898915AAC0E900353C31 /* ImageInnerElement.cpp in Sources */,
                                F55B3DC11251F12D003EF269 /* ImageInputType.cpp in Sources */,
                                089582550E857A7E00F82C83 /* ImageLoader.cpp in Sources */,
                                B275357B0B053814002CE64F /* ImageMac.mm in Sources */,
index 1769d49..5aab06f 100644 (file)
@@ -851,6 +851,10 @@ progress::-webkit-progress-value {
 
 /* inline elements */
 
+img {
+    display: inline-block;
+}
+
 u, ins {
     text-decoration: underline
 }
index 012d9ec..2992b6a 100644 (file)
 #include "Attribute.h"
 #include "CSSPropertyNames.h"
 #include "CSSValueKeywords.h"
+#include "ElementShadow.h"
 #include "EventNames.h"
 #include "FrameView.h"
 #include "HTMLDocument.h"
 #include "HTMLFormElement.h"
 #include "HTMLNames.h"
 #include "HTMLParserIdioms.h"
+#include "ImageInnerElement.h"
 #include "RenderImage.h"
 #include "ScriptEventListener.h"
+#include "ShadowRoot.h"
 
 using namespace std;
 
@@ -41,6 +44,29 @@ namespace WebCore {
 
 using namespace HTMLNames;
 
+void ImageElement::setImageIfNecessary(RenderObject* renderObject, ImageLoader* imageLoader)
+{
+    if (renderObject && renderObject->isImage() && !imageLoader->hasPendingBeforeLoadEvent()) {
+        RenderImage* renderImage = toRenderImage(renderObject);
+        RenderImageResource* renderImageResource = renderImage->imageResource();
+        if (renderImageResource->hasImage())
+            return;
+        renderImageResource->setCachedImage(imageLoader->image());
+
+        // If we have no image at all because we have no src attribute, set
+        // image height and width for the alt text instead.
+        if (!imageLoader->image() && !renderImageResource->cachedImage())
+            renderImage->setImageSizeForAltText();
+    }
+}
+
+RenderObject* ImageElement::createRendererForImage(HTMLElement* element, RenderArena* arena)
+{
+    RenderImage* image = new (arena) RenderImage(element);
+    image->setImageResource(RenderImageResource::create());
+    return image;
+}
+
 HTMLImageElement::HTMLImageElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
     : HTMLElement(tagName, document)
     , m_imageLoader(this)
@@ -68,6 +94,32 @@ HTMLImageElement::~HTMLImageElement()
         m_form->removeImgElement(this);
 }
 
+void HTMLImageElement::willAddAuthorShadowRoot()
+{
+    if (shadow()->oldestShadowRoot())
+        return;
+
+    createShadowSubtree();
+}
+
+void HTMLImageElement::createShadowSubtree()
+{
+    RefPtr<ImageInnerElement> innerElement = ImageInnerElement::create(document());
+    
+    RefPtr<ShadowRoot> root = ShadowRoot::create(this, ShadowRoot::UserAgentShadowRoot);
+    root->appendChild(innerElement);
+}
+
+Element* HTMLImageElement::imageElement()
+{
+    if (ElementShadow* elementShadow = shadow()) {
+        ASSERT(elementShadow->oldestShadowRoot()->firstChild()->hasTagName(webkitInnerImageTag));
+        return toElement(elementShadow->oldestShadowRoot()->firstChild());
+    }
+
+    return this;
+}
+
 PassRefPtr<HTMLImageElement> HTMLImageElement::createForJSConstructor(Document* document, const int* optionalWidth, const int* optionalHeight)
 {
     RefPtr<HTMLImageElement> image = adoptRef(new HTMLImageElement(imgTag, document));
@@ -110,11 +162,14 @@ void HTMLImageElement::collectStyleForAttribute(const Attribute& attribute, Styl
 void HTMLImageElement::parseAttribute(const Attribute& attribute)
 {
     if (attribute.name() == altAttr) {
-        if (renderer() && renderer()->isImage())
-            toRenderImage(renderer())->updateAltText();
-    } else if (attribute.name() == srcAttr)
+        RenderObject* renderObject = shadow() ? innerElement()->renderer() : renderer();
+        if (renderObject && renderObject->isImage())
+            toRenderImage(renderObject)->updateAltText();
+    } else if (attribute.name() == srcAttr) {
         m_imageLoader.updateFromElementIgnoringPreviousError();
-    else if (attribute.name() == usemapAttr)
+        if (ElementShadow* elementShadow = shadow())
+            elementShadow->invalidateDistribution();
+    } else if (attribute.name() == usemapAttr)
         setIsLink(!attribute.isNull());
     else if (attribute.name() == onloadAttr)
         setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attribute));
@@ -141,30 +196,16 @@ String HTMLImageElement::altText() const
 
 RenderObject* HTMLImageElement::createRenderer(RenderArena* arena, RenderStyle* style)
 {
-    if (style->hasContent())
+    if (style->hasContent() || shadow())
         return RenderObject::createObject(this, style);
 
-    RenderImage* image = new (arena) RenderImage(this);
-    image->setImageResource(RenderImageResource::create());
-    return image;
+    return createRendererForImage(this, arena);
 }
 
 void HTMLImageElement::attach()
 {
     HTMLElement::attach();
-
-    if (renderer() && renderer()->isImage() && !m_imageLoader.hasPendingBeforeLoadEvent()) {
-        RenderImage* renderImage = toRenderImage(renderer());
-        RenderImageResource* renderImageResource = renderImage->imageResource();
-        if (renderImageResource->hasImage())
-            return;
-        renderImageResource->setCachedImage(m_imageLoader.image());
-
-        // If we have no image at all because we have no src attribute, set
-        // image height and width for the alt text instead.
-        if (!m_imageLoader.image() && !renderImageResource->cachedImage())
-            renderImage->setImageSizeForAltText();
-    }
+    setImageIfNecessary(renderer(), imageLoader());
 }
 
 Node::InsertionNotificationRequest HTMLImageElement::insertedInto(ContainerNode* insertionPoint)
@@ -366,4 +407,10 @@ void HTMLImageElement::setItemValueText(const String& value, ExceptionCode&)
 }
 #endif
 
+inline ImageInnerElement* HTMLImageElement::innerElement() const
+{
+    ASSERT(shadow());
+    return toImageInnerElement(shadow()->oldestShadowRoot()->firstChild());
+}
+
 }
index 9c6ff5a..07a2973 100644 (file)
 #include "GraphicsTypes.h"
 #include "HTMLElement.h"
 #include "HTMLImageLoader.h"
+#include "ImageLoaderClient.h"
 
 namespace WebCore {
 
 class HTMLFormElement;
+class ImageInnerElement;
 
-class HTMLImageElement : public HTMLElement {
+class ImageElement {
+protected:
+    void setImageIfNecessary(RenderObject*, ImageLoader*);
+    RenderObject* createRendererForImage(HTMLElement*, RenderArena*);
+};
+
+class HTMLImageElement : public HTMLElement, public ImageElement, public ImageLoaderClient {
     friend class HTMLFormElement;
+    friend class ImageInnerElement;
 public:
     static PassRefPtr<HTMLImageElement> create(Document*);
     static PassRefPtr<HTMLImageElement> create(const QualifiedName&, Document*, HTMLFormElement*);
@@ -41,6 +50,8 @@ public:
 
     virtual ~HTMLImageElement();
 
+    virtual void willAddAuthorShadowRoot() OVERRIDE;
+
     int width(bool ignorePendingStylesheets = false);
     int height(bool ignorePendingStylesheets = false);
 
@@ -84,6 +95,14 @@ protected:
     virtual void didMoveToNewDocument(Document* oldDocument) OVERRIDE;
 
 private:
+    virtual void createShadowSubtree();
+
+    // Implementation of ImageLoaderClient
+    Element* sourceElement() { return this; }
+    Element* imageElement();
+    void refSourceElement() { ref(); }
+    void derefSourceElement() { deref(); }
+
     virtual void parseAttribute(const Attribute&) OVERRIDE;
     virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
     virtual void collectStyleForAttribute(const Attribute&, StylePropertySet*) OVERRIDE;
@@ -109,11 +128,26 @@ private:
     virtual void setItemValueText(const String&, ExceptionCode&) OVERRIDE;
 #endif
 
+    RenderObject* imageRenderer() const { return HTMLElement::renderer(); }
+    HTMLImageLoader* imageLoader() { return &m_imageLoader; }
+    ImageInnerElement* innerElement() const;
+
     HTMLImageLoader m_imageLoader;
     HTMLFormElement* m_form;
     CompositeOperator m_compositeOperator;
 };
 
+inline bool isHTMLImageElement(Node* node)
+{
+    return node->hasTagName(HTMLNames::imgTag);
+}
+
+inline HTMLImageElement* toHTMLImageElement(Node* node)
+{
+    ASSERT(!node || isHTMLImageElement(node));
+    return static_cast<HTMLImageElement*>(node);
+}
+
 } //namespace
 
 #endif
index 9bf013d..e69c3e0 100644 (file)
@@ -38,8 +38,8 @@
 
 namespace WebCore {
 
-HTMLImageLoader::HTMLImageLoader(Element* node)
-    : ImageLoader(node)
+HTMLImageLoader::HTMLImageLoader(ImageLoaderClient* client)
+    : ImageLoader(client)
 {
 }
 
@@ -50,19 +50,19 @@ HTMLImageLoader::~HTMLImageLoader()
 void HTMLImageLoader::dispatchLoadEvent()
 {
     // HTMLVideoElement uses this class to load the poster image, but it should not fire events for loading or failure.
-    if (element()->hasTagName(HTMLNames::videoTag))
+    if (client()->sourceElement()->hasTagName(HTMLNames::videoTag))
         return;
 
     bool errorOccurred = image()->errorOccurred();
     if (!errorOccurred && image()->response().httpStatusCode() >= 400)
-        errorOccurred = element()->hasTagName(HTMLNames::objectTag); // An <object> considers a 404 to be an error and should fire onerror.
-    element()->dispatchEvent(Event::create(errorOccurred ? eventNames().errorEvent : eventNames().loadEvent, false, false));
+        errorOccurred = client()->sourceElement()->hasTagName(HTMLNames::objectTag); // An <object> considers a 404 to be an error and should fire onerror.
+    client()->imageElement()->dispatchEvent(Event::create(errorOccurred ? eventNames().errorEvent : eventNames().loadEvent, false, false));
 }
 
 String HTMLImageLoader::sourceURI(const AtomicString& attr) const
 {
 #if ENABLE(DASHBOARD_SUPPORT)
-    Settings* settings = element()->document()->settings();
+    Settings* settings = client()->sourceElement()->document()->settings();
     if (settings && settings->usesDashboardBackwardCompatibilityMode() && attr.length() > 7 && attr.startsWith("url(\"") && attr.endsWith("\")"))
         return attr.string().substring(5, attr.length() - 7);
 #endif
@@ -74,7 +74,7 @@ void HTMLImageLoader::notifyFinished(CachedResource*)
 {
     CachedImage* cachedImage = image();
 
-    Element* elem = element();
+    Element* elem = client()->sourceElement();
     ImageLoader::notifyFinished(cachedImage);
 
     bool loadError = cachedImage->errorOccurred() || cachedImage->response().httpStatusCode() >= 400;
index d3b6068..89399a6 100644 (file)
@@ -29,7 +29,7 @@ namespace WebCore {
 
 class HTMLImageLoader : public ImageLoader {
 public:
-    HTMLImageLoader(Element*);
+    HTMLImageLoader(ImageLoaderClient*);
     virtual ~HTMLImageLoader();
 
     virtual void dispatchLoadEvent();
index 20f0b42..2fd43d8 100644 (file)
@@ -26,6 +26,7 @@
 #define HTMLInputElement_h
 
 #include "HTMLTextFormControlElement.h"
+#include "ImageLoaderClient.h"
 #include "StepRange.h"
 
 namespace WebCore {
@@ -39,7 +40,7 @@ class Icon;
 class InputType;
 class KURL;
 
-class HTMLInputElement : public HTMLTextFormControlElement {
+class HTMLInputElement : public HTMLTextFormControlElement, public ImageLoaderClientBase<HTMLInputElement> {
 public:
     static PassRefPtr<HTMLInputElement> create(const QualifiedName&, Document*, HTMLFormElement*, bool createdByParser);
     virtual ~HTMLInputElement();
index 932e5bc..e12785d 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "FormAssociatedElement.h"
 #include "HTMLPlugInImageElement.h"
+#include "ImageLoaderClient.h"
 
 namespace WebCore {
 
index 813f806..067e9ae 100644 (file)
@@ -24,6 +24,7 @@
 #define HTMLPlugInElement_h
 
 #include "HTMLFrameOwnerElement.h"
+#include "ImageLoaderClient.h"
 #include "ScriptInstance.h"
 
 #if ENABLE(NETSCAPE_PLUGIN_API)
@@ -36,7 +37,7 @@ class RenderEmbeddedObject;
 class RenderWidget;
 class Widget;
 
-class HTMLPlugInElement : public HTMLFrameOwnerElement {
+class HTMLPlugInElement : public HTMLFrameOwnerElement, public ImageLoaderClientBase<HTMLPlugInElement> {
 public:
     virtual ~HTMLPlugInElement();
 
index bfdcd35..4119ba9 100644 (file)
@@ -68,6 +68,7 @@ i interfaceName=HTMLElement
 iframe interfaceName=HTMLIFrameElement
 image mapToTagName=img
 img interfaceName=HTMLImageElement, constructorNeedsFormElement
+webkitInnerImage interfaceName=HTMLElement, noConstructor
 input constructorNeedsFormElement, constructorNeedsCreatedByParser
 intent conditional=WEB_INTENTS_TAG
 ins interfaceName=HTMLModElement
index f146705..b4c0391 100644 (file)
 #if ENABLE(VIDEO)
 
 #include "HTMLMediaElement.h"
+#include "ImageLoaderClient.h"
 
 namespace WebCore {
 
 class HTMLImageLoader;
 
-class HTMLVideoElement : public HTMLMediaElement {
+class HTMLVideoElement : public HTMLMediaElement, public ImageLoaderClientBase<HTMLVideoElement> {
 public:
     static PassRefPtr<HTMLVideoElement> create(const QualifiedName&, Document*, bool);
 
diff --git a/Source/WebCore/html/shadow/ImageInnerElement.cpp b/Source/WebCore/html/shadow/ImageInnerElement.cpp
new file mode 100644 (file)
index 0000000..4ca44e9
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ImageInnerElement.h"
+
+#include "HTMLImageElement.h"
+#include "ImageLoader.h"
+#include "RenderImage.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+ImageInnerElement::ImageInnerElement(Document* document)
+    : HTMLElement(HTMLNames::webkitInnerImageTag, document)
+{
+}
+
+inline HTMLImageElement* ImageInnerElement::hostImage()
+{
+    return toHTMLImageElement(shadowAncestorNode());
+}
+
+inline ImageLoader* ImageInnerElement::imageLoader()
+{
+    return hostImage()->imageLoader();
+}
+
+void ImageInnerElement::attach()
+{
+    HTMLElement::attach();
+    setImageIfNecessary(renderer(), imageLoader());
+}
+
+RenderObject* ImageInnerElement::createRenderer(RenderArena* arena, RenderStyle* style)
+{
+    if (style->hasContent())
+        return RenderObject::createObject(this, style);
+
+    return createRendererForImage(this, arena);
+}
+
+}
diff --git a/Source/WebCore/html/shadow/ImageInnerElement.h b/Source/WebCore/html/shadow/ImageInnerElement.h
new file mode 100644 (file)
index 0000000..2586306
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ImageInnerElement_h
+#define ImageInnerElement_h
+
+#include "HTMLImageElement.h"
+
+namespace WebCore {
+
+class HTMLImageElement;
+class ImageLoader;
+class RenderObject;
+
+class ImageInnerElement : public HTMLElement, public ImageElement {
+public:
+    static PassRefPtr<ImageInnerElement> create(Document*);
+
+private:
+    ImageInnerElement(Document*);
+
+    HTMLImageElement* hostImage();
+
+    ImageLoader* imageLoader();
+    RenderObject* imageRenderer() const { return HTMLElement::renderer(); }
+
+    virtual void attach() OVERRIDE;
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) OVERRIDE;
+};
+
+inline PassRefPtr<ImageInnerElement> ImageInnerElement::create(Document* document)
+{
+    return adoptRef(new ImageInnerElement(document));
+}
+
+inline bool isImageInnerElement(Node* node)
+{
+    return !node || node->hasTagName(HTMLNames::webkitInnerImageTag);
+}
+
+inline ImageInnerElement* toImageInnerElement(Node* node)
+{
+    ASSERT(isImageInnerElement(node));
+    return static_cast<ImageInnerElement*>(node);
+}
+
+}
+
+#endif
index 0e3781c..f4d1209 100644 (file)
 #include "CrossOriginAccessControl.h"
 #include "Document.h"
 #include "Element.h"
+#include "ElementShadow.h"
 #include "Event.h"
 #include "EventSender.h"
 #include "HTMLNames.h"
 #include "HTMLObjectElement.h"
 #include "HTMLParserIdioms.h"
+#include "ImageLoaderClient.h"
 #include "RenderImage.h"
 #include "ScriptCallStack.h"
 #include "SecurityOrigin.h"
@@ -53,8 +55,8 @@ template<> struct ValueCheck<WebCore::ImageLoader*> {
     {
         if (!p)
             return;
-        ASSERT(p->element());
-        ValueCheck<WebCore::Element*>::checkConsistency(p->element());
+        ASSERT(p->client()->imageElement());
+        ValueCheck<WebCore::Element*>::checkConsistency(p->client()->imageElement());
     }
 };
 
@@ -81,8 +83,8 @@ static ImageEventSender& errorEventSender()
     return sender;
 }
 
-ImageLoader::ImageLoader(Element* element)
-    : m_element(element)
+ImageLoader::ImageLoader(ImageLoaderClient* client)
+    : m_client(client)
     , m_image(0)
     , m_hasPendingBeforeLoadEvent(false)
     , m_hasPendingLoadEvent(false)
@@ -113,7 +115,12 @@ ImageLoader::~ImageLoader()
     // If the ImageLoader is being destroyed but it is still protecting its image-loading Element,
     // remove that protection here.
     if (m_elementIsProtected)
-        m_element->deref();
+        client()->derefSourceElement();
+}
+
+inline Document* ImageLoader::document()
+{
+    return client()->sourceElement()->document();
 }
 
 void ImageLoader::setImage(CachedImage* newImage)
@@ -153,11 +160,10 @@ void ImageLoader::updateFromElement()
 {
     // If we're not making renderers for the page, then don't load images.  We don't want to slow
     // down the raw HTML parsing case by loading images we don't intend to display.
-    Document* document = m_element->document();
-    if (!document->renderer())
+    if (!document()->renderer())
         return;
 
-    AtomicString attr = m_element->getAttribute(m_element->imageSourceAttributeName());
+    AtomicString attr = client()->sourceElement()->getAttribute(client()->sourceElement()->imageSourceAttributeName());
 
     if (attr == m_failedLoadURL)
         return;
@@ -166,24 +172,24 @@ void ImageLoader::updateFromElement()
     // an empty string.
     CachedResourceHandle<CachedImage> newImage = 0;
     if (!attr.isNull() && !stripLeadingAndTrailingHTMLSpaces(attr).isEmpty()) {
-        ResourceRequest request = ResourceRequest(document->completeURL(sourceURI(attr)));
+        ResourceRequest request = ResourceRequest(document()->completeURL(sourceURI(attr)));
 
-        String crossOriginMode = m_element->fastGetAttribute(HTMLNames::crossoriginAttr);
+        String crossOriginMode = client()->sourceElement()->fastGetAttribute(HTMLNames::crossoriginAttr);
         if (!crossOriginMode.isNull()) {
             StoredCredentials allowCredentials = equalIgnoringCase(crossOriginMode, "use-credentials") ? AllowStoredCredentials : DoNotAllowStoredCredentials;
-            updateRequestForAccessControl(request, document->securityOrigin(), allowCredentials);
+            updateRequestForAccessControl(request, document()->securityOrigin(), allowCredentials);
         }
 
         if (m_loadManually) {
-            bool autoLoadOtherImages = document->cachedResourceLoader()->autoLoadImages();
-            document->cachedResourceLoader()->setAutoLoadImages(false);
+            bool autoLoadOtherImages = document()->cachedResourceLoader()->autoLoadImages();
+            document()->cachedResourceLoader()->setAutoLoadImages(false);
             newImage = new CachedImage(request);
             newImage->setLoading(true);
-            newImage->setOwningCachedResourceLoader(document->cachedResourceLoader());
-            document->cachedResourceLoader()->m_documentResources.set(newImage->url(), newImage.get());
-            document->cachedResourceLoader()->setAutoLoadImages(autoLoadOtherImages);
+            newImage->setOwningCachedResourceLoader(document()->cachedResourceLoader());
+            document()->cachedResourceLoader()->m_documentResources.set(newImage->url(), newImage.get());
+            document()->cachedResourceLoader()->setAutoLoadImages(autoLoadOtherImages);
         } else
-            newImage = document->cachedResourceLoader()->requestImage(request);
+            newImage = document()->cachedResourceLoader()->requestImage(request);
 
         // If we do not have an image here, it means that a cross-site
         // violation occurred.
@@ -191,7 +197,7 @@ void ImageLoader::updateFromElement()
     } else if (!attr.isNull()) {
         // Fire an error event if the url is empty.
         // FIXME: Should we fire this event asynchronoulsy via errorEventSender()?
-        m_element->dispatchEvent(Event::create(eventNames().errorEvent, false, false));
+        client()->imageElement()->dispatchEvent(Event::create(eventNames().errorEvent, false, false));
     }
     
     CachedImage* oldImage = m_image.get();
@@ -204,13 +210,13 @@ void ImageLoader::updateFromElement()
             errorEventSender().cancelEvent(this);
 
         m_image = newImage;
-        m_hasPendingBeforeLoadEvent = !m_element->document()->isImageDocument() && newImage;
+        m_hasPendingBeforeLoadEvent = !document()->isImageDocument() && newImage;
         m_hasPendingLoadEvent = newImage;
         m_imageComplete = !newImage;
 
         if (newImage) {
-            if (!m_element->document()->isImageDocument()) {
-                if (!m_element->document()->hasListenerType(Document::BEFORELOAD_LISTENER))
+            if (!document()->isImageDocument()) {
+                if (!document()->hasListenerType(Document::BEFORELOAD_LISTENER))
                     dispatchPendingBeforeLoadEvent();
                 else
                     beforeLoadEventSender().dispatchEventSoon(this);
@@ -253,9 +259,9 @@ void ImageLoader::notifyFinished(CachedResource* resource)
     if (!m_hasPendingLoadEvent)
         return;
 
-    if (m_element->fastHasAttribute(HTMLNames::crossoriginAttr)
-        && !m_element->document()->securityOrigin()->canRequest(image()->response().url())
-        && !resource->passesAccessControlCheck(m_element->document()->securityOrigin())) {
+    if (client()->sourceElement()->fastHasAttribute(HTMLNames::crossoriginAttr)
+        && !document()->securityOrigin()->canRequest(image()->response().url())
+        && !resource->passesAccessControlCheck(document()->securityOrigin())) {
 
         setImage(0);
 
@@ -263,7 +269,7 @@ void ImageLoader::notifyFinished(CachedResource* resource)
         errorEventSender().dispatchEventSoon(this);
 
         DEFINE_STATIC_LOCAL(String, consoleMessage, ("Cross-origin image load denied by Cross-Origin Resource Sharing policy."));
-        m_element->document()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage);
+        document()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage);
 
         ASSERT(!m_hasPendingLoadEvent);
         return;
@@ -282,7 +288,7 @@ void ImageLoader::notifyFinished(CachedResource* resource)
 
 RenderImageResource* ImageLoader::renderImageResource()
 {
-    RenderObject* renderer = m_element->renderer();
+    RenderObject* renderer = client()->imageElement()->renderer();
 
     if (!renderer)
         return 0;
@@ -333,9 +339,9 @@ void ImageLoader::updatedHasPendingLoadEvent()
     m_elementIsProtected = m_hasPendingLoadEvent;
 
     if (m_elementIsProtected)
-        m_element->ref();
+        client()->refSourceElement();
     else
-        m_element->deref();
+        client()->derefSourceElement();
 }
 
 void ImageLoader::dispatchPendingEvent(ImageEventSender* eventSender)
@@ -356,10 +362,10 @@ void ImageLoader::dispatchPendingBeforeLoadEvent()
         return;
     if (!m_image)
         return;
-    if (!m_element->document()->attached())
+    if (!document()->attached())
         return;
     m_hasPendingBeforeLoadEvent = false;
-    if (m_element->dispatchBeforeLoadEvent(m_image->url())) {
+    if (client()->sourceElement()->dispatchBeforeLoadEvent(m_image->url())) {
         updateRenderer();
         return;
     }
@@ -370,9 +376,9 @@ void ImageLoader::dispatchPendingBeforeLoadEvent()
 
     loadEventSender().cancelEvent(this);
     m_hasPendingLoadEvent = false;
-    
-    if (m_element->hasTagName(HTMLNames::objectTag))
-        static_cast<HTMLObjectElement*>(m_element)->renderFallbackContent();
+
+    if (client()->sourceElement()->hasTagName(HTMLNames::objectTag))
+        static_cast<HTMLObjectElement*>(client()->sourceElement())->renderFallbackContent();
 
     // Only consider updating the protection ref-count of the Element immediately before returning
     // from this function as doing so might result in the destruction of this ImageLoader.
@@ -385,7 +391,7 @@ void ImageLoader::dispatchPendingLoadEvent()
         return;
     if (!m_image)
         return;
-    if (!m_element->document()->attached())
+    if (!document()->attached())
         return;
     m_hasPendingLoadEvent = false;
     dispatchLoadEvent();
@@ -399,10 +405,10 @@ void ImageLoader::dispatchPendingErrorEvent()
 {
     if (!m_hasPendingErrorEvent)
         return;
-    if (!m_element->document()->attached())
+    if (!document()->attached())
         return;
     m_hasPendingErrorEvent = false;
-    m_element->dispatchEvent(Event::create(eventNames().errorEvent, false, false));
+    client()->imageElement()->dispatchEvent(Event::create(eventNames().errorEvent, false, false));
 }
 
 void ImageLoader::dispatchPendingBeforeLoadEvents()
index 9435490..269fa67 100644 (file)
 
 #include "CachedImage.h"
 #include "CachedResourceHandle.h"
+#include "Element.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
 #include <wtf/text/AtomicString.h>
 
 namespace WebCore {
 
 class Element;
 class ImageLoader;
+class ImageLoaderClient;
+class QualifiedName;
 class RenderImageResource;
 
 template<typename T> class EventSender;
@@ -38,9 +43,11 @@ typedef EventSender<ImageLoader> ImageEventSender;
 
 class ImageLoader : public CachedImageClient {
 public:
-    ImageLoader(Element*);
+    ImageLoader(ImageLoaderClient*);
     virtual ~ImageLoader();
 
+    ImageLoaderClient* client() const { return m_client; }
+
     // This function should be called when the element is attached to a document; starts
     // loading if a load hasn't already been started.
     void updateFromElement();
@@ -51,7 +58,6 @@ public:
 
     void elementDidMoveToNewDocument();
 
-    Element* element() const { return m_element; }
     bool imageComplete() const { return m_imageComplete; }
 
     CachedImage* image() const { return m_image.get(); }
@@ -72,6 +78,7 @@ protected:
     virtual void notifyFinished(CachedResource*);
 
 private:
+    Document* document();
     virtual void dispatchLoadEvent() = 0;
     virtual String sourceURI(const AtomicString&) const = 0;
 
@@ -84,7 +91,7 @@ private:
     RenderImageResource* renderImageResource();
     void updateRenderer();
 
-    Element* m_element;
+    ImageLoaderClient* m_client;
     CachedResourceHandle<CachedImage> m_image;
     AtomicString m_failedLoadURL;
     bool m_hasPendingBeforeLoadEvent : 1;
diff --git a/Source/WebCore/loader/ImageLoaderClient.h b/Source/WebCore/loader/ImageLoaderClient.h
new file mode 100644 (file)
index 0000000..f08344b
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef ImageLoaderClient_h
+#define ImageLoaderClient_h
+
+namespace WebCore {
+
+class Element;
+
+class ImageLoaderClient {
+public:
+    virtual ~ImageLoaderClient() { }
+
+    virtual Element* sourceElement() = 0;
+    virtual Element* imageElement() = 0;
+
+    virtual void refSourceElement() = 0;
+    virtual void derefSourceElement() = 0;
+};
+
+template<typename T>
+class ImageLoaderClientBase : public ImageLoaderClient {
+public:
+    Element* sourceElement() { return static_cast<T*>(this); }
+    Element* imageElement() { return static_cast<T*>(this); }
+
+    void refSourceElement() { static_cast<T*>(this)->ref(); }
+    void derefSourceElement() { static_cast<T*>(this)->deref(); }
+};
+
+}
+
+#endif
index 776e278..3feb57c 100644 (file)
@@ -446,7 +446,7 @@ void RenderImage::paintIntoRect(GraphicsContext* context, const LayoutRect& rect
     if (!img || img->isNull())
         return;
 
-    HTMLImageElement* imageElt = (node() && node()->hasTagName(imgTag)) ? static_cast<HTMLImageElement*>(node()) : 0;
+    HTMLImageElement* imageElt = hostImageElement();
     CompositeOperator compositeOperator = imageElt ? imageElt->compositeOperator() : CompositeSourceOver;
     Image* image = m_imageResource->image().get();
     bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, image, alignedRect.size());
@@ -494,7 +494,7 @@ int RenderImage::minimumReplacedHeight() const
 
 HTMLMapElement* RenderImage::imageMap() const
 {
-    HTMLImageElement* i = node() && node()->hasTagName(imgTag) ? static_cast<HTMLImageElement*>(node()) : 0;
+    HTMLImageElement* i = hostImageElement();
     return i ? i->treeScope()->getImageMap(i->fastGetAttribute(usemapAttr)) : 0;
 }
 
@@ -529,8 +529,8 @@ void RenderImage::updateAltText()
 
     if (node()->hasTagName(inputTag))
         m_altText = static_cast<HTMLInputElement*>(node())->altText();
-    else if (node()->hasTagName(imgTag))
-        m_altText = static_cast<HTMLImageElement*>(node())->altText();
+    else if (HTMLImageElement* image = hostImageElement())
+        m_altText = image->altText();
 }
 
 void RenderImage::layout()
@@ -563,6 +563,24 @@ void RenderImage::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, dou
     }
 }
 
+HTMLImageElement* RenderImage::hostImageElement() const
+{
+    if (!node())
+        return 0;
+
+    if (isHTMLImageElement(node()))
+        return toHTMLImageElement(node());
+
+    if (node()->hasTagName(webkitInnerImageTag)) {
+        if (Node* ancestor = node()->shadowAncestorNode()) {
+            if (ancestor->hasTagName(imgTag))
+                return toHTMLImageElement(ancestor);
+        }
+    }
+
+    return 0;
+}
+
 bool RenderImage::needsPreferredWidthsRecalculation() const
 {
     if (RenderReplaced::needsPreferredWidthsRecalculation())
index b6725f0..6bddb0a 100644 (file)
@@ -31,6 +31,7 @@
 namespace WebCore {
 
 class HTMLAreaElement;
+class HTMLImageElement;
 class HTMLMapElement;
 
 class RenderImage : public RenderReplaced {
@@ -58,6 +59,8 @@ public:
     bool isGeneratedContent() const { return m_isGeneratedContent; }
 
 protected:
+    HTMLImageElement* hostImageElement() const;
+
     virtual bool needsPreferredWidthsRecalculation() const;
     virtual RenderBox* embeddedContentBox() const;
     virtual void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const;
index 04f27e6..7adeda9 100755 (executable)
@@ -2180,7 +2180,7 @@ RespectImageOrientationEnum RenderObject::shouldRespectImageOrientation() const
 {
     // Respect the image's orientation if it's being used as a full-page image or it's
     // an <img> and the setting to respect it everywhere is set.
-    return document()->isImageDocument() || (document()->settings() && document()->settings()->shouldRespectImageOrientation() && node() && node()->hasTagName(HTMLNames::imgTag)) ? RespectImageOrientation : DoNotRespectImageOrientation;
+    return document()->isImageDocument() || (document()->settings() && document()->settings()->shouldRespectImageOrientation() && node() && (node()->hasTagName(HTMLNames::imgTag) || node()->hasTagName(HTMLNames::webkitInnerImageTag))) ? RespectImageOrientation : DoNotRespectImageOrientation;
 }
 
 bool RenderObject::hasOutlineAnnotation() const
index f2f8d9b..4ee7d78 100644 (file)
@@ -22,6 +22,7 @@
 #define SVGImageElement_h
 
 #if ENABLE(SVG)
+#include "ImageLoaderClient.h"
 #include "SVGAnimatedBoolean.h"
 #include "SVGAnimatedLength.h"
 #include "SVGAnimatedPreserveAspectRatio.h"
@@ -38,13 +39,14 @@ class SVGImageElement : public SVGStyledTransformableElement,
                         public SVGTests,
                         public SVGLangSpace,
                         public SVGExternalResourcesRequired,
-                        public SVGURIReference {
+                        public SVGURIReference,
+                        public ImageLoaderClientBase<SVGImageElement> {
 public:
     static PassRefPtr<SVGImageElement> create(const QualifiedName&, Document*);
 
 private:
     SVGImageElement(const QualifiedName&, Document*);
-    
+
     virtual bool isValid() const { return SVGTests::isValid(); }
     virtual bool supportsFocus() const { return true; }
 
index 4f33d56..290acdb 100644 (file)
 #include "Event.h"
 #include "EventNames.h"
 #include "HTMLParserIdioms.h"
+#include "ImageLoaderClient.h"
 #include "RenderImage.h"
 #include "SVGImageElement.h"
 
 namespace WebCore {
 
-SVGImageLoader::SVGImageLoader(SVGImageElement* node)
-    : ImageLoader(node)
+SVGImageLoader::SVGImageLoader(ImageLoaderClient* client)
+    : ImageLoader(client)
 {
 }
 
 void SVGImageLoader::dispatchLoadEvent()
 {
     if (image()->errorOccurred())
-        element()->dispatchEvent(Event::create(eventNames().errorEvent, false, false));
+        client()->imageElement()->dispatchEvent(Event::create(eventNames().errorEvent, false, false));
     else {
-        SVGImageElement* imageElement = static_cast<SVGImageElement*>(element());
+        SVGImageElement* imageElement = static_cast<SVGImageElement*>(client()->imageElement());
         if (imageElement->externalResourcesRequiredBaseValue())
             imageElement->sendSVGLoadEventIfPossible(true);
     }
@@ -49,10 +50,10 @@ void SVGImageLoader::dispatchLoadEvent()
 
 String SVGImageLoader::sourceURI(const AtomicString& attribute) const
 {
-    KURL base = element()->baseURI();
+    KURL base = client()->sourceElement()->baseURI();
     if (base.isValid())
         return KURL(base, stripLeadingAndTrailingHTMLSpaces(attribute)).string();
-    return element()->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(attribute));
+    return client()->sourceElement()->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(attribute));
 }
 
 }
index b7a1617..d617cd8 100644 (file)
@@ -29,7 +29,7 @@ class SVGImageElement;
 
 class SVGImageLoader : public ImageLoader {
 public:
-    SVGImageLoader(SVGImageElement*);
+    SVGImageLoader(ImageLoaderClient*);
 
 private:
     virtual void dispatchLoadEvent();