Commit c9c5964a authored by dglazkov@chromium.org's avatar dglazkov@chromium.org

2011-06-22 Dimitri Glazkov <dglazkov@chromium.org>

        Reviewed by Kent Tamura.

        Move file-choosing and icon-loading management to FileInputType
        https://bugs.webkit.org/show_bug.cgi?id=62069

        1) Moved the duties of FileChooserClient and FileIconLoaderClient from
        RenderFileUploadControl to FileInputType, along with all of the
        supporting functions.

        2) Moved Icon ownership to FileInputType and exposed accessor on
        HTMInputElement to allow RenderFileUploadControl to query current icon.

        As a result, RenderFileUploadControl is now completely stateless, which is
        neat and clean.

        Refactoring, covered by existing tests.

        * html/FileInputType.cpp:
        (WebCore::FileInputType::handleDOMActivateEvent): Moved logic here from RenderFileUploadControl.
        (WebCore::FileInputType::requestIcon): Ditto.
        (WebCore::FileInputType::filesChosen): Ditto.
        (WebCore::FileInputType::receiveDropForDirectoryUpload): Ditto.
        (WebCore::FileInputType::updateRendering): Ditto.
        (WebCore::FileInputType::chrome): Ditto.
        (WebCore::FileInputType::receiveDroppedFiles): Ditto.
        (WebCore::FileInputType::icon): Added.
        * html/FileInputType.h:
        * html/HTMLInputElement.cpp:
        (WebCore::HTMLInputElement::setValueFromRenderer): Updated comment.
        (WebCore::HTMLInputElement::receiveDroppedFiles): Added to replace setFileListFromRenderer.
        (WebCore::HTMLInputElement::icon): Added.
        * html/HTMLInputElement.h:
        * html/InputType.cpp:
        (WebCore::InputType::receiveDroppedFiles): Added.
        (WebCore::InputType::icon): Added.
        * html/InputType.h:
        * page/DragController.cpp:
        (WebCore::DragController::concludeEditDrag): Changed to use HTMLInputElement. Ahh, nice and clean!
        * rendering/RenderFileUploadControl.cpp:
        (WebCore::RenderFileUploadControl::RenderFileUploadControl): Removed code that is no longer necessary.
        (WebCore::RenderFileUploadControl::updateFromElement): Ditto.
        (WebCore::RenderFileUploadControl::maxFilenameWidth): Changed to use HTMLInputElement icon accessor.
        (WebCore::RenderFileUploadControl::paintObject): Ditto.
        * rendering/RenderFileUploadControl.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@89535 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 9efe4829
2011-06-22 Dimitri Glazkov <dglazkov@chromium.org>
Reviewed by Kent Tamura.
Move file-choosing and icon-loading management to FileInputType
https://bugs.webkit.org/show_bug.cgi?id=62069
1) Moved the duties of FileChooserClient and FileIconLoaderClient from
RenderFileUploadControl to FileInputType, along with all of the
supporting functions.
2) Moved Icon ownership to FileInputType and exposed accessor on
HTMInputElement to allow RenderFileUploadControl to query current icon.
As a result, RenderFileUploadControl is now completely stateless, which is
neat and clean.
Refactoring, covered by existing tests.
* html/FileInputType.cpp:
(WebCore::FileInputType::handleDOMActivateEvent): Moved logic here from RenderFileUploadControl.
(WebCore::FileInputType::requestIcon): Ditto.
(WebCore::FileInputType::filesChosen): Ditto.
(WebCore::FileInputType::receiveDropForDirectoryUpload): Ditto.
(WebCore::FileInputType::updateRendering): Ditto.
(WebCore::FileInputType::chrome): Ditto.
(WebCore::FileInputType::receiveDroppedFiles): Ditto.
(WebCore::FileInputType::icon): Added.
* html/FileInputType.h:
* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::setValueFromRenderer): Updated comment.
(WebCore::HTMLInputElement::receiveDroppedFiles): Added to replace setFileListFromRenderer.
(WebCore::HTMLInputElement::icon): Added.
* html/HTMLInputElement.h:
* html/InputType.cpp:
(WebCore::InputType::receiveDroppedFiles): Added.
(WebCore::InputType::icon): Added.
* html/InputType.h:
* page/DragController.cpp:
(WebCore::DragController::concludeEditDrag): Changed to use HTMLInputElement. Ahh, nice and clean!
* rendering/RenderFileUploadControl.cpp:
(WebCore::RenderFileUploadControl::RenderFileUploadControl): Removed code that is no longer necessary.
(WebCore::RenderFileUploadControl::updateFromElement): Ditto.
(WebCore::RenderFileUploadControl::maxFilenameWidth): Changed to use HTMLInputElement icon accessor.
(WebCore::RenderFileUploadControl::paintObject): Ditto.
* rendering/RenderFileUploadControl.h:
2011-06-22 Pratik Solanki <psolanki@apple.com>
Reviewed by Darin Adler.
......
......@@ -22,15 +22,20 @@
#include "config.h"
#include "FileInputType.h"
#include "Chrome.h"
#include "Event.h"
#include "File.h"
#include "FileList.h"
#include "FileSystem.h"
#include "FormDataList.h"
#include "Frame.h"
#include "HTMLInputElement.h"
#include "HTMLNames.h"
#include "Icon.h"
#include "LocalizedStrings.h"
#include "Page.h"
#include "RenderFileUploadControl.h"
#include "ScriptController.h"
#include "ShadowRoot.h"
#include <wtf/PassOwnPtr.h>
#include <wtf/text/WTFString.h>
......@@ -128,7 +133,24 @@ void FileInputType::handleDOMActivateEvent(Event* event)
{
if (element()->disabled() || !element()->renderer())
return;
toRenderFileUploadControl(element()->renderer())->click();
if (!ScriptController::processingUserGesture())
return;
if (Chrome* chrome = this->chrome()) {
FileChooserSettings settings;
HTMLInputElement* input = element();
#if ENABLE(DIRECTORY_UPLOAD)
settings.allowsDirectoryUpload = input->fastHasAttribute(webkitdirectoryAttr);
settings.allowsMultipleFiles = settings.allowsDirectoryUpload || input->fastHasAttribute(multipleAttr);
#else
settings.allowsMultipleFiles = input->fastHasAttribute(multipleAttr);
#endif
settings.acceptTypes = input->accept();
ASSERT(input->files());
settings.selectedFiles = input->files()->filenames();
chrome->runOpenPanel(input->document()->frame(), newFileChooser(settings));
}
event->setDefaultHandled();
}
......@@ -230,4 +252,84 @@ void FileInputType::createShadowSubtree()
element()->ensureShadowRoot()->appendChild(UploadButtonElement::create(element()->document()), ec);
}
void FileInputType::requestIcon(const Vector<String>& filenames)
{
if (!filenames.size())
return;
if (Chrome* chrome = this->chrome())
chrome->loadIconForFiles(filenames, newFileIconLoader());
}
void FileInputType::filesChosen(const Vector<String>& filenames)
{
HTMLInputElement* input = element();
setFileList(filenames);
input->setFormControlValueMatchesRenderer(true);
input->notifyFormStateChanged();
input->setNeedsValidityCheck();
requestIcon(filenames);
if (input->renderer())
input->renderer()->repaint();
// This call may cause destruction of this instance and thus must always be last in the function.
input->dispatchFormControlChangeEvent();
}
#if ENABLE(DIRECTORY_UPLOAD)
void FileInputType::receiveDropForDirectoryUpload(const Vector<String>& paths)
{
if (Chrome* chrome = this->chrome()) {
FileChooserSettings settings;
settings.allowsDirectoryUpload = true;
settings.allowsMultipleFiles = true;
settings.selectedFiles.append(paths[0]);
chrome->enumerateChosenDirectory(newFileChooser(settings));
}
}
#endif
void FileInputType::updateRendering(PassRefPtr<Icon> icon)
{
if (m_icon == icon)
return;
m_icon = icon;
if (element()->renderer())
element()->renderer()->repaint();
}
Chrome* FileInputType::chrome() const
{
if (Page* page = element()->document()->page())
return page->chrome();
return 0;
}
void FileInputType::receiveDroppedFiles(const Vector<String>& paths)
{
HTMLInputElement* input = element();
#if ENABLE(DIRECTORY_UPLOAD)
if (input->fastHasAttribute(webkitdirectoryAttr)) {
receiveDropForDirectoryUpload(paths);
return;
}
#endif
if (input->fastHasAttribute(multipleAttr))
filesChosen(paths);
else {
Vector<String> firstPathOnly;
firstPathOnly.append(paths[0]);
filesChosen(firstPathOnly);
}
}
Icon* FileInputType::icon() const
{
return m_icon.get();
}
} // namespace WebCore
......@@ -33,13 +33,16 @@
#define FileInputType_h
#include "BaseButtonInputType.h"
#include "FileChooser.h"
#include "FileIconLoader.h"
#include <wtf/RefPtr.h>
namespace WebCore {
class Chrome;
class FileList;
class FileInputType : public BaseButtonInputType {
class FileInputType : public BaseButtonInputType, private FileChooserClient, private FileIconLoaderClient {
public:
static PassOwnPtr<InputType> create(HTMLInputElement*);
......@@ -57,11 +60,26 @@ private:
virtual bool canSetValue(const String&);
virtual bool getTypeSpecificValue(String&); // Checked first, before internal storage or the value attribute.
virtual bool storesValueSeparateFromAttribute();
virtual void setFileList(const Vector<String>& paths);
virtual void receiveDroppedFiles(const Vector<String>&);
virtual Icon* icon() const;
virtual bool isFileUpload() const;
virtual void createShadowSubtree();
// FileChooserClient implementation.
virtual void filesChosen(const Vector<String>&);
// FileIconLoaderClient implementation.
virtual void updateRendering(PassRefPtr<Icon>);
void setFileList(const Vector<String>& paths);
#if ENABLE(DIRECTORY_UPLOAD)
void receiveDropForDirectoryUpload(const Vector<String>&);
#endif
void requestIcon(const Vector<String>&);
Chrome* chrome() const;
RefPtr<FileList> m_fileList;
RefPtr<Icon> m_icon;
};
} // namespace WebCore
......
......@@ -45,6 +45,7 @@
#include "HTMLNames.h"
#include "HTMLOptionElement.h"
#include "HTMLParserIdioms.h"
#include "Icon.h"
#include "InputType.h"
#include "KeyboardEvent.h"
#include "LocalizedStrings.h"
......@@ -1057,7 +1058,7 @@ bool HTMLInputElement::searchEventsShouldBeDispatched() const
void HTMLInputElement::setValueFromRenderer(const String& value)
{
// File upload controls will always use setFileListFromRenderer.
// File upload controls will never use this.
ASSERT(!isFileUpload());
m_suggestedValue = String();
......@@ -1085,15 +1086,6 @@ void HTMLInputElement::setValueFromRenderer(const String& value)
setAutofilled(false);
}
void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths)
{
m_inputType->setFileList(paths);
setFormControlValueMatchesRenderer(true);
notifyFormStateChanged();
setNeedsValidityCheck();
}
void* HTMLInputElement::preDispatchEventHandler(Event* event)
{
if (event->type() == eventNames().textInputEvent && m_inputType->shouldSubmitImplicitly(event)) {
......@@ -1275,6 +1267,16 @@ FileList* HTMLInputElement::files()
return m_inputType->files();
}
void HTMLInputElement::receiveDroppedFiles(const Vector<String>& filenames)
{
m_inputType->receiveDroppedFiles(filenames);
}
Icon* HTMLInputElement::icon() const
{
return m_inputType->icon();
}
String HTMLInputElement::visibleValue() const
{
return m_inputType->visibleValue();
......
......@@ -31,6 +31,7 @@ namespace WebCore {
class FileList;
class HTMLDataListElement;
class HTMLOptionElement;
class Icon;
class InputType;
class KURL;
......@@ -163,7 +164,6 @@ public:
String valueWithDefault() const;
void setValueFromRenderer(const String&);
void setFileListFromRenderer(const Vector<String>&);
bool canHaveSelection() const;
......@@ -202,6 +202,8 @@ public:
void setAutofilled(bool = true);
FileList* files();
void receiveDroppedFiles(const Vector<String>&);
Icon* icon() const;
void addSearchResult();
void onSearch();
......@@ -226,6 +228,7 @@ public:
bool lastChangeWasUserEdit() const;
void cacheSelection(int start, int end);
void notifyFormStateChanged();
static const int maximumLength;
......@@ -318,7 +321,6 @@ private:
#if ENABLE(DATALIST)
HTMLDataListElement* dataList() const;
#endif
void notifyFormStateChanged();
void parseMaxLengthAttribute(Attribute*);
void updateValueIfNeeded();
#if ENABLE(WCSS)
......
......@@ -537,11 +537,17 @@ bool InputType::hasUnacceptableValue()
return false;
}
void InputType::setFileList(const Vector<String>&)
void InputType::receiveDroppedFiles(const Vector<String>&)
{
ASSERT_NOT_REACHED();
}
Icon* InputType::icon() const
{
ASSERT_NOT_REACHED();
return 0;
}
bool InputType::shouldResetOnDocumentActivation()
{
return false;
......
......@@ -48,6 +48,7 @@ class FormDataList;
class HTMLElement;
class HTMLFormElement;
class HTMLInputElement;
class Icon;
class KeyboardEvent;
class MouseEvent;
class Node;
......@@ -209,12 +210,13 @@ public:
virtual void willMoveToNewOwnerDocument();
virtual bool shouldRespectAlignAttribute();
virtual FileList* files();
virtual void receiveDroppedFiles(const Vector<String>&);
virtual Icon* icon() const;
// Should return true if the corresponding renderer for a type can display a suggested value.
virtual bool canSetSuggestedValue();
virtual bool shouldSendChangeEventAfterCheckedChanged();
virtual bool canSetValue(const String&);
virtual bool storesValueSeparateFromAttribute();
virtual void setFileList(const Vector<String>& paths);
virtual bool shouldResetOnDocumentActivation();
virtual bool shouldRespectListAttribute();
virtual bool shouldRespectSpeechAttribute();
......
......@@ -420,14 +420,7 @@ bool DragController::concludeEditDrag(DragData* dragData)
if (filenames.isEmpty())
return false;
// Ugly. For security none of the APIs available to us can set the input value
// on file inputs. Even forcing a change in HTMLInputElement doesn't work as
// RenderFileUploadControl clears the file when doing updateFromElement().
RenderFileUploadControl* renderer = toRenderFileUploadControl(fileInput->renderer());
if (!renderer)
return false;
renderer->receiveDroppedFiles(filenames);
fileInput->receiveDroppedFiles(filenames);
return true;
}
......
......@@ -21,24 +21,19 @@
#include "config.h"
#include "RenderFileUploadControl.h"
#include "Chrome.h"
#include "FileList.h"
#include "Frame.h"
#include "FrameView.h"
#include "GraphicsContext.h"
#include "HTMLInputElement.h"
#include "HTMLNames.h"
#include "Icon.h"
#include "LocalizedStrings.h"
#include "Page.h"
#include "PaintInfo.h"
#include "RenderButton.h"
#include "RenderText.h"
#include "RenderTheme.h"
#include "RenderView.h"
#include "ScriptController.h"
#include "ShadowRoot.h"
#include "TextRun.h"
#include "VisiblePosition.h"
#include <math.h>
using namespace std;
......@@ -57,106 +52,16 @@ const int buttonShadowHeight = 2;
RenderFileUploadControl::RenderFileUploadControl(HTMLInputElement* input)
: RenderBlock(input)
{
ASSERT(input->files());
requestIcon(input->files()->filenames());
}
RenderFileUploadControl::~RenderFileUploadControl()
{
}
void RenderFileUploadControl::requestIcon(const Vector<String>& filenames)
{
if (!filenames.size())
return;
if (Chrome* chrome = this->chrome())
chrome->loadIconForFiles(filenames, newFileIconLoader());
}
void RenderFileUploadControl::filesChosen(const Vector<String>& filenames)
{
HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node());
inputElement->setFileListFromRenderer(filenames);
requestIcon(filenames);
repaint();
// This call may cause destruction of this instance and thus must always be last in the function.
inputElement->dispatchFormControlChangeEvent();
}
#if ENABLE(DIRECTORY_UPLOAD)
void RenderFileUploadControl::receiveDropForDirectoryUpload(const Vector<String>& paths)
{
if (Chrome* chrome = this->chrome()) {
FileChooserSettings settings;
settings.allowsDirectoryUpload = true;
settings.allowsMultipleFiles = true;
settings.selectedFiles.append(paths[0]);
chrome->enumerateChosenDirectory(newFileChooser(settings));
}
}
#endif
void RenderFileUploadControl::updateRendering(PassRefPtr<Icon> icon)
{
if (m_icon == icon)
return;
m_icon = icon;
repaint();
}
void RenderFileUploadControl::click()
{
if (!ScriptController::processingUserGesture())
return;
if (Chrome* chrome = this->chrome()) {
FileChooserSettings settings;
HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
#if ENABLE(DIRECTORY_UPLOAD)
settings.allowsDirectoryUpload = input->fastHasAttribute(webkitdirectoryAttr);
settings.allowsMultipleFiles = settings.allowsDirectoryUpload || input->fastHasAttribute(multipleAttr);
#else
settings.allowsMultipleFiles = input->fastHasAttribute(multipleAttr);
#endif
settings.acceptTypes = input->accept();
ASSERT(input->files());
settings.selectedFiles = input->files()->filenames();
chrome->runOpenPanel(frame(), newFileChooser(settings));
}
}
Chrome* RenderFileUploadControl::chrome() const
{
Frame* frame = node()->document()->frame();
if (!frame)
return 0;
Page* page = frame->page();
if (!page)
return 0;
return page->chrome();
}
void RenderFileUploadControl::updateFromElement()
{
HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node());
ASSERT(inputElement->isFileUpload());
if (HTMLInputElement* button = uploadButton())
button->setDisabled(!theme()->isEnabled(this));
// This only supports clearing out the files, but that's OK because for
// security reasons that's the only change the DOM is allowed to make.
FileList* files = inputElement->files();
ASSERT(files);
if (files && files->isEmpty() && m_icon) {
m_icon = 0;
repaint();
}
}
static int nodeWidth(Node* node)
......@@ -166,8 +71,9 @@ static int nodeWidth(Node* node)
int RenderFileUploadControl::maxFilenameWidth() const
{
HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
return max(0, contentWidth() - nodeWidth(uploadButton()) - afterButtonSpacing
- (m_icon ? iconWidth + iconFilenameSpacing : 0));
- (input->icon() ? iconWidth + iconFilenameSpacing : 0));
}
void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, const IntPoint& paintOffset)
......@@ -197,9 +103,10 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, const IntPoint&
if (!button)
return;
HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
int buttonWidth = nodeWidth(button);
int buttonAndIconWidth = buttonWidth + afterButtonSpacing
+ (m_icon ? iconWidth + iconFilenameSpacing : 0);
+ (input->icon() ? iconWidth + iconFilenameSpacing : 0);
int textX;
if (style()->isLeftToRightDirection())
textX = contentLeft + buttonAndIconWidth;
......@@ -216,7 +123,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, const IntPoint&
// Draw the filename
paintInfo.context->drawBidiText(font, textRun, IntPoint(textX, textY));
if (m_icon) {
if (input->icon()) {
// Determine where the icon should be placed
int iconY = paintOffset.y() + borderTop() + paddingTop() + (contentHeight() - iconHeight) / 2;
int iconX;
......@@ -226,7 +133,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, const IntPoint&
iconX = contentLeft + contentWidth() - buttonWidth - afterButtonSpacing - iconWidth;
// Draw the file icon
m_icon->paint(paintInfo.context, IntRect(iconX, iconY, iconWidth, iconHeight));
input->icon()->paint(paintInfo.context, IntRect(iconX, iconY, iconWidth, iconHeight));
}
}
......@@ -290,25 +197,6 @@ HTMLInputElement* RenderFileUploadControl::uploadButton() const
return buttonNode && buttonNode->isHTMLElement() && buttonNode->hasTagName(inputTag) ? static_cast<HTMLInputElement*>(buttonNode) : 0;
}
void RenderFileUploadControl::receiveDroppedFiles(const Vector<String>& paths)
{
HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
#if ENABLE(DIRECTORY_UPLOAD)
if (input->fastHasAttribute(webkitdirectoryAttr)) {
receiveDropForDirectoryUpload(paths);
return;
}
#endif
if (input->fastHasAttribute(multipleAttr))
filesChosen(paths);
else {
Vector<String> firstPathOnly;
firstPathOnly.append(paths[0]);
filesChosen(firstPathOnly);
}
}
String RenderFileUploadControl::buttonValue()
{
if (HTMLInputElement* button = uploadButton())
......
......@@ -21,30 +21,23 @@
#ifndef RenderFileUploadControl_h
#define RenderFileUploadControl_h
#include "FileChooser.h"
#include "FileIconLoader.h"
#include "RenderBlock.h"
namespace WebCore {
class Chrome;
class HTMLInputElement;
// Each RenderFileUploadControl contains a RenderButton (for opening the file chooser), and
// sufficient space to draw a file icon and filename. The RenderButton has a shadow node
// associated with it to receive click/hover events.
class RenderFileUploadControl : public RenderBlock, private FileChooserClient, private FileIconLoaderClient {
class RenderFileUploadControl : public RenderBlock {
public:
RenderFileUploadControl(HTMLInputElement*);
virtual ~RenderFileUploadControl();
virtual bool isFileUploadControl() const { return true; }
void click();
void receiveDroppedFiles(const Vector<String>&);
String buttonValue();
String fileTextValue() const;
......@@ -57,25 +50,11 @@ private:
virtual bool requiresForcedStyleRecalcPropagation() const { return true; }
// FileChooserClient implementation.
virtual void filesChosen(const Vector<String>&);
// FileIconLoaderClient implementation.
virtual void updateRendering(PassRefPtr<Icon>);
#if ENABLE(DIRECTORY_UPLOAD)
void receiveDropForDirectoryUpload(const Vector<String>&);
#endif
Chrome* chrome() const;
int maxFilenameWidth() const;
virtual VisiblePosition positionForPoint(const IntPoint&);
HTMLInputElement* uploadButton() const;
void requestIcon(const Vector<String>&);
RefPtr<Icon> m_icon;
};
inline RenderFileUploadControl* toRenderFileUploadControl(RenderObject* object)
......
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