Commit 2d422e7f authored by abarth@webkit.org's avatar abarth@webkit.org
Browse files

Add support for download='filename' attribute in anchors.

https://bugs.webkit.org/show_bug.cgi?id=64580

Patch by Sadrul Habib Chowdhury <sadrul@chromium.org> on 2011-07-26
Reviewed by Adam Barth.

Source/WebCore: 

The download attribute allows the author of the hyperlink to cause the
browser to download the linked URL.  The author can also supply a
suggested file name in the attribute value.  This feature is a recent
addition to HTML to better support offline applications that use blob
URLs.  Traditionally, web sites use the HTTP Content-Disposition header
to trigger downloads, but that option isn't available when working
offline.

There is some question about whether we should initiate a download when
we receive a DOM-created click event.  This patch does initiate the
download, but we might revise that decision in the future as part of a
larger change in how WebKit treats the interaction between default
event handlers and DOM-created events.

Tests: fast/dom/HTMLAnchorElement/anchor-download.html
       fast/dom/HTMLAnchorElement/anchor-nodownload.html
       fast/dom/HTMLAnchorElement/anchor-download-unset.html
       fast/dom/HTMLAnchorElement/anchor-nodownload-set.html

* html/HTMLAnchorElement.cpp:
(WebCore::HTMLAnchorElement::defaultEventHandler):
(WebCore::HTMLAnchorElement::handleClick):
* html/HTMLAnchorElement.h:
* html/HTMLAnchorElement.idl:
* html/HTMLAttributeNames.in:
* loader/EmptyClients.h:
(WebCore::EmptyFrameLoaderClient::startDownload):
* loader/FrameLoaderClient.h:

Source/WebKit/chromium: 

* features.gypi:
* public/WebFrameClient.h:
(WebKit::WebFrameClient::loadURLExternally):
* src/FrameLoaderClientImpl.cpp:
(WebKit::FrameLoaderClientImpl::dispatchDecidePolicyForNavigationAction):
(WebKit::FrameLoaderClientImpl::startDownload):
* src/FrameLoaderClientImpl.h:

Source/WebKit/efl: 

* WebCoreSupport/FrameLoaderClientEfl.cpp:
(WebCore::FrameLoaderClientEfl::startDownload):
* WebCoreSupport/FrameLoaderClientEfl.h:

Source/WebKit/gtk: 

* WebCoreSupport/FrameLoaderClientGtk.cpp:
(WebKit::FrameLoaderClient::startDownload):
* WebCoreSupport/FrameLoaderClientGtk.h:

Source/WebKit/haiku: 

* WebCoreSupport/FrameLoaderClientHaiku.cpp:
(WebCore::FrameLoaderClientHaiku::startDownload):
* WebCoreSupport/FrameLoaderClientHaiku.h:

Source/WebKit/qt: 

* WebCoreSupport/FrameLoaderClientQt.cpp:
(WebCore::FrameLoaderClientQt::startDownload):
* WebCoreSupport/FrameLoaderClientQt.h:

Source/WebKit/win: 

* WebFrame.cpp:
(WebFrame::startDownload):
* WebFrame.h:

Source/WebKit/wince: 

* WebCoreSupport/FrameLoaderClientWinCE.cpp:
(WebKit::FrameLoaderClientWinCE::startDownload):
* WebCoreSupport/FrameLoaderClientWinCE.h:

Source/WebKit/wx: 

* WebKitSupport/FrameLoaderClientWx.cpp:
(WebCore::FrameLoaderClientWx::startDownload):
* WebKitSupport/FrameLoaderClientWx.h:

Source/WebKit2: 

* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::startDownload):
* WebProcess/WebCoreSupport/WebFrameLoaderClient.h:

Tools: 

* DumpRenderTree/chromium/WebViewHost.cpp:
(WebViewHost::loadURLExternally):
* DumpRenderTree/chromium/WebViewHost.h:

LayoutTests: 

* fast/dom/HTMLAnchorElement/anchor-download-expected.txt: Added.
* fast/dom/HTMLAnchorElement/anchor-download.html: Added.
* fast/dom/HTMLAnchorElement/anchor-nodownload-expected.txt: Added.
* fast/dom/HTMLAnchorElement/anchor-nodownload.html: Added.
* fast/dom/HTMLAnchorElement/anchor-download-unset-expected.txt: Added.
* fast/dom/HTMLAnchorElement/anchor-download-unset.html: Added.
* fast/dom/HTMLAnchorElement/anchor-nodownload-set-expected.txt: Added.
* fast/dom/HTMLAnchorElement/anchor-nodownload-set.html: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@91797 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent c674f223
2011-07-26 Sadrul Habib Chowdhury <sadrul@chromium.org>
Add support for download='filename' attribute in anchors.
https://bugs.webkit.org/show_bug.cgi?id=64580
Reviewed by Adam Barth.
* fast/dom/HTMLAnchorElement/anchor-download-expected.txt: Added.
* fast/dom/HTMLAnchorElement/anchor-download.html: Added.
* fast/dom/HTMLAnchorElement/anchor-nodownload-expected.txt: Added.
* fast/dom/HTMLAnchorElement/anchor-nodownload.html: Added.
* fast/dom/HTMLAnchorElement/anchor-download-unset-expected.txt: Added.
* fast/dom/HTMLAnchorElement/anchor-download-unset.html: Added.
* fast/dom/HTMLAnchorElement/anchor-nodownload-set-expected.txt: Added.
* fast/dom/HTMLAnchorElement/anchor-nodownload-set.html: Added.
2011-07-26 Adrienne Walker <enne@google.com>
 
[chromium] Mark webaudio/test-basic as crashing on Windows.
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>
if (window.layoutTestController) {
layoutTestController.dumpAsText();
layoutTestController.waitUntilDone();
}
</script>
</head>
<body>
<a id="blob-url" download>Blob URL</a>
<script>
function click(elmt)
{
if (!window.eventSender) {
alert('Click the link to run the test.');
return;
}
eventSender.mouseMoveTo(elmt.offsetLeft + 5, elmt.offsetTop + 5);
eventSender.mouseDown();
eventSender.mouseUp();
}
function runTest()
{
var bb = new WebKitBlobBuilder();
bb.append("<!doctype html><html><head><title>Title</title><script>if (window.layoutTestController) layoutTestController.dumpAsText(); </" + "script></head><body>PASS</body><script>if (window.layoutTestController) layoutTestController.notifyDone();</scr" + "ipt></html>");
var blob = bb.getBlob("text/html", "inline");
var link = document.getElementById("blob-url");
link.href = window.webkitURL.createObjectURL(blob);
link.removeAttribute('download');
click(link);
}
runTest();
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>
if (window.layoutTestController) {
layoutTestController.dumpAsText();
layoutTestController.waitUntilDone();
}
</script>
</head>
<body>
<a id="blob-url" download>Blob URL</a>
<script>
function click(elmt)
{
if (!window.eventSender) {
alert('Click the link to run the test.');
return;
}
eventSender.mouseMoveTo(elmt.offsetLeft + 5, elmt.offsetTop + 5);
eventSender.mouseDown();
eventSender.mouseUp();
}
function runTest()
{
var bb = new WebKitBlobBuilder();
bb.append("<!doctype html><html><head><title>Title</title><script>if (window.layoutTestController) layoutTestController.dumpAsText(); </" + "script></head><body>PASS</body><script>if (window.layoutTestController) layoutTestController.notifyDone();</scr" + "ipt></html>");
var blob = bb.getBlob("text/html", "inline");
var link = document.getElementById("blob-url");
link.href = window.webkitURL.createObjectURL(blob);
click(link);
}
runTest();
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>
if (window.layoutTestController) {
layoutTestController.dumpAsText();
layoutTestController.waitUntilDone();
}
</script>
</head>
<body>
<a id="blob-url">Blob URL</a>
<script>
function click(elmt)
{
if (!window.eventSender) {
alert('Click the link to run the test.');
return;
}
eventSender.mouseMoveTo(elmt.offsetLeft + 5, elmt.offsetTop + 5);
eventSender.mouseDown();
eventSender.mouseUp();
}
function runTest()
{
var bb = new WebKitBlobBuilder();
bb.append("<!doctype html><html><head><title>Title</title><script>if (window.layoutTestController) layoutTestController.dumpAsText(); </" + "script></head><body>PASS</body><script>if (window.layoutTestController) layoutTestController.notifyDone();</scr" + "ipt></html>");
var blob = bb.getBlob("text/html", "inline");
var link = document.getElementById("blob-url");
link.href = window.webkitURL.createObjectURL(blob);
link.setAttribute('download');
click(link);
}
runTest();
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>
if (window.layoutTestController) {
layoutTestController.dumpAsText();
layoutTestController.waitUntilDone();
}
</script>
</head>
<body>
<a id="blob-url">Blob URL</a>
<script>
function click(elmt)
{
if (!window.eventSender) {
alert('Click the link to run the test.');
return;
}
eventSender.mouseMoveTo(elmt.offsetLeft + 5, elmt.offsetTop + 5);
eventSender.mouseDown();
eventSender.mouseUp();
}
function runTest()
{
var bb = new WebKitBlobBuilder();
bb.append("<!doctype html><html><head><title>Title</title><script>if (window.layoutTestController) layoutTestController.dumpAsText(); </" + "script></head><body>PASS</body><script>if (window.layoutTestController) layoutTestController.notifyDone();</scr" + "ipt></html>");
var blob = bb.getBlob("text/html", "inline");
var link = document.getElementById("blob-url");
link.href = window.webkitURL.createObjectURL(blob);
click(link);
}
runTest();
</script>
</body>
</html>
......@@ -1525,6 +1525,12 @@ http/tests/eventsource/workers/eventsource-simple.html
# failing dropzone test(http://bugs.webkit.org/show_bug.cgi?id=61630)
fast/events/dropzone-002.html
# Tests that require ENABLE(DOWNLOAD_ATTRIBUTE).
fast/dom/HTMLAnchorElement/anchor-nodownload.html
fast/dom/HTMLAnchorElement/anchor-download.html
fast/dom/HTMLAnchorElement/anchor-nodownload-set.html
fast/dom/HTMLAnchorElement/anchor-download-unset.html
# Failing because WebGL is not enabled
http/tests/security/webgl-remote-read-remote-image-allowed.html
http/tests/security/webgl-remote-read-remote-image-allowed-with-credentials.html
......
......@@ -341,6 +341,12 @@ storage/storageinfo-query-usage.html
storage/storageinfo-request-quota.html
storage/storageinfo-no-callbacks.html
# Tests that require ENABLE(DOWNLOAD_ATTRIBUTE).
fast/dom/HTMLAnchorElement/anchor-nodownload.html
fast/dom/HTMLAnchorElement/anchor-download.html
fast/dom/HTMLAnchorElement/anchor-nodownload-set.html
fast/dom/HTMLAnchorElement/anchor-download-unset.html
# Expose title direction in WebKit API
# https://bugs.webkit.org/show_bug.cgi?id=58845
fast/dom/title-directionality.html
......
......@@ -2398,6 +2398,12 @@ http/tests/loading/preload-slow-loading.php
http/tests/security/contentSecurityPolicy/media-src-allowed.html
http/tests/security/contentSecurityPolicy/media-src-blocked.html
# Tests that require ENABLE(DOWNLOAD_ATTRIBUTE).
fast/dom/HTMLAnchorElement/anchor-nodownload.html
fast/dom/HTMLAnchorElement/anchor-download.html
fast/dom/HTMLAnchorElement/anchor-nodownload-set.html
fast/dom/HTMLAnchorElement/anchor-download-unset.html
# This platform does not support the Page Visibility API.
fast/events/page-visibility-iframe-delete-test.html
fast/events/page-visibility-iframe-move-test.html
......
......@@ -1342,6 +1342,12 @@ http/tests/security/webgl-remote-read-remote-image-allowed.html
http/tests/security/webgl-remote-read-remote-image-allowed-with-credentials.html
http/tests/security/webgl-remote-read-remote-image-blocked-no-crossorigin.html
# Tests that require ENABLE(DOWNLOAD_ATTRIBUTE).
fast/dom/HTMLAnchorElement/anchor-nodownload.html
fast/dom/HTMLAnchorElement/anchor-download.html
fast/dom/HTMLAnchorElement/anchor-nodownload-set.html
fast/dom/HTMLAnchorElement/anchor-download-unset.html
# New flexbox is not yet enabled. http://webkit.org/b/62048
css3/flexbox
......
2011-07-26 Sadrul Habib Chowdhury <sadrul@chromium.org>
Add support for download='filename' attribute in anchors.
https://bugs.webkit.org/show_bug.cgi?id=64580
Reviewed by Adam Barth.
The download attribute allows the author of the hyperlink to cause the
browser to download the linked URL. The author can also supply a
suggested file name in the attribute value. This feature is a recent
addition to HTML to better support offline applications that use blob
URLs. Traditionally, web sites use the HTTP Content-Disposition header
to trigger downloads, but that option isn't available when working
offline.
There is some question about whether we should initiate a download when
we receive a DOM-created click event. This patch does initiate the
download, but we might revise that decision in the future as part of a
larger change in how WebKit treats the interaction between default
event handlers and DOM-created events.
Tests: fast/dom/HTMLAnchorElement/anchor-download.html
fast/dom/HTMLAnchorElement/anchor-nodownload.html
fast/dom/HTMLAnchorElement/anchor-download-unset.html
fast/dom/HTMLAnchorElement/anchor-nodownload-set.html
* html/HTMLAnchorElement.cpp:
(WebCore::HTMLAnchorElement::defaultEventHandler):
(WebCore::HTMLAnchorElement::handleClick):
* html/HTMLAnchorElement.h:
* html/HTMLAnchorElement.idl:
* html/HTMLAttributeNames.in:
* loader/EmptyClients.h:
(WebCore::EmptyFrameLoaderClient::startDownload):
* loader/FrameLoaderClient.h:
2011-07-26 Mark Hahnenberg <mhahnenberg@apple.com>
 
Refactor automatically generated JS DOM bindings to replace operator new with static create methods
......@@ -27,6 +27,7 @@
#include "Attribute.h"
#include "EventNames.h"
#include "Frame.h"
#include "FrameLoaderClient.h"
#include "FrameLoaderTypes.h"
#include "HTMLImageElement.h"
#include "HTMLNames.h"
......@@ -147,10 +148,7 @@ void HTMLAnchorElement::defaultEventHandler(Event* event)
}
if (isLinkClick(event) && treatLinkAsLiveForEventType(eventType(event))) {
String url = stripLeadingAndTrailingHTMLSpaces(getAttribute(hrefAttr));
appendServerMapMousePosition(url, event);
handleLinkClick(event, document(), url, getAttribute(targetAttr), hasRel(RelationNoReferrer));
sendPings(document()->completeURL(url));
handleClick(event);
return;
}
......@@ -492,6 +490,37 @@ void HTMLAnchorElement::sendPings(const KURL& destinationURL)
PingLoader::sendPing(document()->frame(), document()->completeURL(pingURLs[i]), destinationURL);
}
void HTMLAnchorElement::handleClick(Event* event)
{
event->setDefaultHandled();
Frame* frame = document()->frame();
if (!frame)
return;
String url = stripLeadingAndTrailingHTMLSpaces(fastGetAttribute(hrefAttr));
appendServerMapMousePosition(url, event);
KURL kurl = document()->completeURL(url);
#if ENABLE(DOWNLOAD_ATTRIBUTE)
if (hasAttribute(downloadAttr)) {
ResourceRequest request(kurl);
if (!hasRel(RelationNoReferrer)) {
String referrer = frame->loader()->outgoingReferrer();
if (!referrer.isEmpty() && !SecurityOrigin::shouldHideReferrer(kurl, referrer))
request.setHTTPReferrer(referrer);
frame->loader()->addExtraFieldsToMainResourceRequest(request);
}
frame->loader()->client()->startDownload(request, fastGetAttribute(downloadAttr));
} else
#endif
frame->loader()->urlSelected(kurl, target(), event, false, false, hasRel(RelationNoReferrer) ? NoReferrer : SendReferrer);
sendPings(kurl);
}
HTMLAnchorElement::EventType HTMLAnchorElement::eventType(Event* event)
{
if (!event->isMouseEvent())
......
......@@ -115,6 +115,8 @@ private:
void sendPings(const KURL& destinationURL);
void handleClick(Event*);
enum EventType {
MouseEventWithoutShiftKey,
MouseEventWithShiftKey,
......
......@@ -26,6 +26,7 @@ module html {
attribute [Reflect] DOMString accessKey;
attribute [Reflect] DOMString charset;
attribute [Reflect] DOMString coords;
attribute [Conditional=DOWNLOAD_ATTRIBUTE, Reflect] DOMString download;
attribute [Reflect, URL] DOMString href;
attribute [Reflect] DOMString hreflang;
attribute [Reflect] DOMString name;
......
......@@ -91,6 +91,7 @@ defer
dir
direction
disabled
download
draggable
webkitdropzone
enctype
......
......@@ -310,7 +310,7 @@ public:
virtual void setMainFrameDocumentReady(bool) { }
virtual void startDownload(const ResourceRequest&) { }
virtual void startDownload(const ResourceRequest&, const String& suggestedName = String()) { UNUSED_PARAM(suggestedName); }
virtual void willChangeTitle(DocumentLoader*) { }
virtual void didChangeTitle(DocumentLoader*) { }
......
......@@ -179,7 +179,7 @@ namespace WebCore {
virtual void setMainFrameDocumentReady(bool) = 0;
virtual void startDownload(const ResourceRequest&) = 0;
virtual void startDownload(const ResourceRequest&, const String& suggestedName = String()) = 0;
virtual void willChangeTitle(DocumentLoader*) = 0;
virtual void didChangeTitle(DocumentLoader*) = 0;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment