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 08f5acfe6d1d2b2f8c2d200f51f36cea8954bb2c..7f38bf23f737e625f2bd99125fa49c5b105c26af 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 f726d61e8debc665deab3f2e5fa8dd5383c23ef8..b9206a377f0a2b9620af50b70a8653b532f13f62 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 e26b5daba65db5a712d4dde99ed5fa05148c701f..8990f13e018bbf77113b60ef426217569b7e812d 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 e1e5fe0c81d1d43e6a8523e854894ad0725bf26b..652038224ce1fb2c97a20c3eafa3b2b88da1a18c 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 8f0e33eb797b8b04a695576f6e3c7d8b1cab5760..b8129fef41da4e0ad01fc42144eb59398577fabe 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 519d414446e3ba7a207abe11d540df241c22df8f..91210e73365ca7b2543a29140d7b6ba2660b2195 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 29ccad3f7ceb8957663f35990a068e064c359a1d..19be056d1d5409359972992819f331a4f588a6aa 100755 (executable)
                                RelativePath="..\loader\ImageLoader.h"
                                >
                        </File>
+                       <File
+                               RelativePath="..\loader\ImageLoaderClient.h"
+                               >
+                       </File>
                        <File
                                RelativePath="..\loader\LinkLoader.cpp"
                                >
                                        RelativePath="..\html\shadow\InsertionPoint.h"
                                        >
                                </File>
+                               <File
+                                       RelativePath="..\html\shadow\ImageInnerElement.cpp"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath="..\html\shadow\ImageInnerElement.h"
+                                       >
+                               </File>
                                <File
                                        RelativePath="..\html\shadow\MediaControlElements.cpp"
                                        >
index b7bc2c3cae332ca9e1cc79dbae7d3435fd255270..93be27504910b8b094f8b91381c07e786f24a0f7 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 1769d49f194c55fbf24638d7b8ea0bfc366781ea..5aab06fc7bbb0ce14d114522d0d5e150258d5bdb 100644 (file)
@@ -851,6 +851,10 @@ progress::-webkit-progress-value {
 
 /* inline elements */
 
+img {
+    display: inline-block;
+}
+
 u, ins {
     text-decoration: underline
 }
index 012d9ec69d099e3f01d252d023b47b6257c37d96..2992b6a175a851193b53bce08b3bfff015c6bb2b 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 9c6ff5af4c28feca301db4ca8edcf1de9cfcbf1b..07a297372dc1a3a3a6783635a1ebdef55e7228d6 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 9bf013d5b7b9888ffd3e8e38b5809b68cac72b59..e69c3e0919aec694e34d27422856b0c43b5168b4 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 d3b606871f46dd58ba9c12684566e6d77f8101a2..89399a62a8d708905fb8f44dc8c4485d8e3bf143 100644 (file)
@@ -29,7 +29,7 @@ namespace WebCore {
 
 class HTMLImageLoader : public ImageLoader {
 public:
-    HTMLImageLoader(Element*);
+    HTMLImageLoader(ImageLoaderClient*);
     virtual ~HTMLImageLoader();
 
     virtual void dispatchLoadEvent();
index 20f0b42d194f18d57b7f22fbc50ed669008c84e8..2fd43d863b96678f333f8e0c7752849a246d28d5 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 932e5bccd9a13214b00e0ccff00ce1bd8047dbee..e12785d10970f038d4fce60e941f87945f8f13db 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "FormAssociatedElement.h"
 #include "HTMLPlugInImageElement.h"
+#include "ImageLoaderClient.h"
 
 namespace WebCore {
 
index 813f8063d9e1813f4f3b608cb2d3bb3d79128411..067e9aef9e90ca2cea40cf4624d4d852691a2367 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 bfdcd35718da5d1cd3d16a07d2f16a77c5349a23..4119ba9b66cde78d8db7d47a4765df5a5d2a6911 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 f1467052726006a05c4dccc11f31e63b8bee2833..b4c0391a7ac08673652ef51bedc832b48feb39f2 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 0e3781cdb312e51c5ca5a042fffb6b7fa03de434..f4d1209f06e48e675624bd8c0394f5d90d6e2bb1 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 943549069000664c5710591599d0a05546d74516..269fa67be64621130f8c7e7b415021716ddf5780 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 776e2787bf28949d4f321b173543bc842c8e507e..3feb57c5445f4db8dd9c6be78a4c0abeb93d4023 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 b6725f0055a8da26f0f8b1d1854f4517e1920efe..6bddb0a58daffb479fd3be8a77557bf7a8b2c1e3 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 04f27e652bf3a7ca305dbcaf151f4b7c6121aeb8..7adeda992bcd76bb9d3922708b2d3bd1f0d69e8b 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 f2f8d9b038c8315b8c20ed4dd51f475b5f4a03c4..4ee7d783c338671a27a153d9f0096f10e900c134 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 4f33d569e1452257145096adec80516150db750d..290acdb88482b5bd38486c8cfb7f9f769f176192 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 b7a16175cc59ab8ea88d2b18ea3f68385a73c29e..d617cd85051f1254714ed21dcb58ae40a82effdc 100644 (file)
@@ -29,7 +29,7 @@ class SVGImageElement;
 
 class SVGImageLoader : public ImageLoader {
 public:
-    SVGImageLoader(SVGImageElement*);
+    SVGImageLoader(ImageLoaderClient*);
 
 private:
     virtual void dispatchLoadEvent();