18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * This library is free software; you can redistribute it and/or
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modify it under the terms of the GNU Library General Public
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * License as published by the Free Software Foundation; either
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * version 2 of the License, or (at your option) any later version.
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * This library is distributed in the hope that it will be useful,
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * but WITHOUT ANY WARRANTY; without even the implied warranty of
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Library General Public License for more details.
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * You should have received a copy of the GNU Library General Public License
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * along with this library; see the file COPYING.LIB.  If not, write to
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Boston, MA 02110-1301, USA.
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RenderFileUploadControl.h"
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
24d0825bca7fe65beaee391d30da42e937db621564Steve Block#include "Chrome.h"
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "FileList.h"
268f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian#include "Frame.h"
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "FrameView.h"
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "GraphicsContext.h"
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "HTMLInputElement.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "HTMLNames.h"
31545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch#include "ShadowElement.h"
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Icon.h"
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "LocalizedStrings.h"
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Page.h"
3565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch#include "PaintInfo.h"
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RenderButton.h"
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RenderText.h"
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RenderTheme.h"
398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RenderView.h"
40ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch#include "TextRun.h"
418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <math.h>
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace std;
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace HTMLNames;
488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectconst int afterButtonSpacing = 4;
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectconst int iconHeight = 16;
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectconst int iconWidth = 16;
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectconst int iconFilenameSpacing = 2;
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectconst int defaultWidthNumChars = 34;
548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectconst int buttonShadowHeight = 2;
558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectRenderFileUploadControl::RenderFileUploadControl(HTMLInputElement* input)
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    : RenderBlock(input)
588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
59643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    FileList* list = input->files();
60643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    Vector<String> filenames;
61643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    unsigned length = list ? list->length() : 0;
62643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    for (unsigned i = 0; i < length; ++i)
63643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        filenames.append(list->item(i)->path());
64643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    m_fileChooser = FileChooser::create(this, filenames);
658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectRenderFileUploadControl::~RenderFileUploadControl()
688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_button)
708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_button->detach();
718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_fileChooser->disconnectClient();
728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
748f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qianvoid RenderFileUploadControl::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RenderBlock::styleDidChange(diff, oldStyle);
778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_button)
788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_button->renderer()->setStyle(createButtonStyle(style()));
798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid RenderFileUploadControl::valueChanged()
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // dispatchFormControlChangeEvent may destroy this renderer
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RefPtr<FileChooser> fileChooser = m_fileChooser;
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node());
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    inputElement->setFileListFromRenderer(fileChooser->filenames());
885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    inputElement->dispatchFormControlChangeEvent();
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // only repaint if it doesn't seem we have been destroyed
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!fileChooser->disconnected())
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        repaint();
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool RenderFileUploadControl::allowsMultipleFiles()
968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
97967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch#if ENABLE(DIRECTORY_UPLOAD)
98967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (allowsDirectoryUpload())
99967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch      return true;
100967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch#endif
101967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
103f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    return input->fastHasAttribute(multipleAttr);
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
106967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch#if ENABLE(DIRECTORY_UPLOAD)
107967717af5423377c967781471ee106e2bb4e11c8Ben Murdochbool RenderFileUploadControl::allowsDirectoryUpload()
108967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{
109967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
110f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    return input->fastHasAttribute(webkitdirectoryAttr);
111967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch}
1122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochvoid RenderFileUploadControl::receiveDropForDirectoryUpload(const Vector<String>& paths)
1142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
1152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (Chrome* chromePointer = chrome())
1162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        chromePointer->enumerateChosenDirectory(paths[0], m_fileChooser.get());
1172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
118967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch#endif
119967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
120d0825bca7fe65beaee391d30da42e937db621564Steve BlockString RenderFileUploadControl::acceptTypes()
121d0825bca7fe65beaee391d30da42e937db621564Steve Block{
122d0825bca7fe65beaee391d30da42e937db621564Steve Block    return static_cast<HTMLInputElement*>(node())->accept();
123d0825bca7fe65beaee391d30da42e937db621564Steve Block}
124d0825bca7fe65beaee391d30da42e937db621564Steve Block
12516e49e63e74d9236b0d8b72846201697a8ebaedcBen Murdoch#if ENABLE(MEDIA_CAPTURE)
12616e49e63e74d9236b0d8b72846201697a8ebaedcBen MurdochString RenderFileUploadControl::capture()
12716e49e63e74d9236b0d8b72846201697a8ebaedcBen Murdoch{
12816e49e63e74d9236b0d8b72846201697a8ebaedcBen Murdoch    return static_cast<HTMLInputElement*>(node())->capture();
12916e49e63e74d9236b0d8b72846201697a8ebaedcBen Murdoch}
13016e49e63e74d9236b0d8b72846201697a8ebaedcBen Murdoch#endif
13116e49e63e74d9236b0d8b72846201697a8ebaedcBen Murdoch
132dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid RenderFileUploadControl::chooseIconForFiles(FileChooser* chooser, const Vector<String>& filenames)
133692e5dbf12901edacf14812a6fae25462920af42Steve Block{
134692e5dbf12901edacf14812a6fae25462920af42Steve Block    if (Chrome* chromePointer = chrome())
135dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        chromePointer->chooseIconForFiles(filenames, chooser);
136692e5dbf12901edacf14812a6fae25462920af42Steve Block}
137692e5dbf12901edacf14812a6fae25462920af42Steve Block
1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid RenderFileUploadControl::click()
1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
140a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // Requires a user gesture to open the file dialog.
141a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!frame() || !frame()->loader()->isProcessingUserGesture())
142a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return;
143692e5dbf12901edacf14812a6fae25462920af42Steve Block    if (Chrome* chromePointer = chrome())
144a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        chromePointer->runOpenPanel(frame(), m_fileChooser);
145692e5dbf12901edacf14812a6fae25462920af42Steve Block}
146692e5dbf12901edacf14812a6fae25462920af42Steve Block
147692e5dbf12901edacf14812a6fae25462920af42Steve BlockChrome* RenderFileUploadControl::chrome() const
148692e5dbf12901edacf14812a6fae25462920af42Steve Block{
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Frame* frame = node()->document()->frame();
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!frame)
151692e5dbf12901edacf14812a6fae25462920af42Steve Block        return 0;
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Page* page = frame->page();
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!page)
154692e5dbf12901edacf14812a6fae25462920af42Steve Block        return 0;
155692e5dbf12901edacf14812a6fae25462920af42Steve Block    return page->chrome();
1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid RenderFileUploadControl::updateFromElement()
1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node());
16168513a70bcd92384395513322f1b801e7bf9c729Steve Block    ASSERT(inputElement->isFileUpload());
1628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_button) {
1645af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke        m_button = ShadowInputElement::create(inputElement);
16568513a70bcd92384395513322f1b801e7bf9c729Steve Block        m_button->setType("button");
1668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_button->setValue(fileButtonChooseFileLabel());
1678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        RefPtr<RenderStyle> buttonStyle = createButtonStyle(style());
1688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        RenderObject* renderer = m_button->createRenderer(renderArena(), buttonStyle.get());
1698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_button->setRenderer(renderer);
1708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        renderer->setStyle(buttonStyle.release());
1718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        renderer->updateFromElement();
1728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_button->setAttached();
17321939df44de1705786c545cd1bf519d47250322dBen Murdoch        m_button->setInDocument();
1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        addChild(renderer);
1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_button->setDisabled(!theme()->isEnabled(this));
1798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // This only supports clearing out the files, but that's OK because for
1818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // security reasons that's the only change the DOM is allowed to make.
1828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FileList* files = inputElement->files();
1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(files);
1848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (files && files->isEmpty() && !m_fileChooser->filenames().isEmpty()) {
1858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_fileChooser->clear();
1868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        repaint();
1878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectint RenderFileUploadControl::maxFilenameWidth() const
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
192635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return max(0, contentWidth() - m_button->renderBox()->width() - afterButtonSpacing
1938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        - (m_fileChooser->icon() ? iconWidth + iconFilenameSpacing : 0));
1948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectPassRefPtr<RenderStyle> RenderFileUploadControl::createButtonStyle(const RenderStyle* parentStyle) const
1978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1988f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    RefPtr<RenderStyle> style = getCachedPseudoStyle(FILE_UPLOAD_BUTTON);
1998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!style) {
2008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        style = RenderStyle::create();
2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (parentStyle)
2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            style->inheritFrom(parentStyle);
2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Button text will wrap on file upload controls with widths smaller than the intrinsic button width
2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // without this setWhiteSpace.
2078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    style->setWhiteSpace(NOWRAP);
2088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return style.release();
2108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid RenderFileUploadControl::paintObject(PaintInfo& paintInfo, int tx, int ty)
2138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (style()->visibility() != VISIBLE)
2158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
216dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT(m_fileChooser);
2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Push a clip.
2198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseChildBlockBackgrounds) {
2208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        IntRect clipRect(tx + borderLeft(), ty + borderTop(),
2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                         width() - borderLeft() - borderRight(), height() - borderBottom() - borderTop() + buttonShadowHeight);
2228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (clipRect.isEmpty())
2238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
2248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        paintInfo.context->save();
2258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        paintInfo.context->clip(clipRect);
2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintInfo.phase == PaintPhaseForeground) {
229643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        const String& displayedFilename = fileTextValue();
2308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        unsigned length = displayedFilename.length();
2318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const UChar* string = displayedFilename.characters();
2322fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        TextRun textRun(string, length, false, 0, 0, TextRun::AllowTrailingExpansion, !style()->isLeftToRightDirection(), style()->unicodeBidi() == Override);
2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Determine where the filename should be placed
2358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int contentLeft = tx + borderLeft() + paddingLeft();
236635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int buttonAndIconWidth = m_button->renderBox()->width() + afterButtonSpacing
2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            + (m_fileChooser->icon() ? iconWidth + iconFilenameSpacing : 0);
2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int textX;
239a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (style()->isLeftToRightDirection())
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            textX = contentLeft + buttonAndIconWidth;
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        else
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            textX = contentLeft + contentWidth() - buttonAndIconWidth - style()->font().width(textRun);
2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // We want to match the button's baseline
2448f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        RenderButton* buttonRenderer = toRenderButton(m_button->renderer());
2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int textY = buttonRenderer->absoluteBoundingBoxRect().y()
2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            + buttonRenderer->marginTop() + buttonRenderer->borderTop() + buttonRenderer->paddingTop()
2476b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            + buttonRenderer->baselinePosition(AlphabeticBaseline, true, HorizontalLine, PositionOnContainingLine);
2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
249e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block        paintInfo.context->setFillColor(style()->visitedDependentColor(CSSPropertyColor), style()->colorSpace());
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Draw the filename
252635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        paintInfo.context->drawBidiText(style()->font(), textRun, IntPoint(textX, textY));
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (m_fileChooser->icon()) {
2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Determine where the icon should be placed
2568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            int iconY = ty + borderTop() + paddingTop() + (contentHeight() - iconHeight) / 2;
2578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            int iconX;
258a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (style()->isLeftToRightDirection())
259635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                iconX = contentLeft + m_button->renderBox()->width() + afterButtonSpacing;
2608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            else
261635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                iconX = contentLeft + contentWidth() - m_button->renderBox()->width() - afterButtonSpacing - iconWidth;
2628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Draw the file icon
2648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_fileChooser->icon()->paint(paintInfo.context, IntRect(iconX, iconY, iconWidth, iconHeight));
2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Paint the children.
2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RenderBlock::paintObject(paintInfo, tx, ty);
2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Pop the clip.
2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseChildBlockBackgrounds)
2738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        paintInfo.context->restore();
2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
276bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsenvoid RenderFileUploadControl::computePreferredLogicalWidths()
2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
278bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    ASSERT(preferredLogicalWidthsDirty());
2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
280bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    m_minPreferredLogicalWidth = 0;
281bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    m_maxPreferredLogicalWidth = 0;
2828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (style()->width().isFixed() && style()->width().value() > 0)
284bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(style()->width().value());
2858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else {
2868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Figure out how big the filename space needs to be for a given number of characters
2878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // (using "0" as the nominal character).
2888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const UChar ch = '0';
28981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        float charWidth = style()->font().width(TextRun(&ch, 1, false, 0, 0, TextRun::AllowTrailingExpansion, false));
290bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        m_maxPreferredLogicalWidth = (int)ceilf(charWidth * defaultWidthNumChars);
2918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
294bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->minWidth().value()));
295bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->minWidth().value()));
2968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
297bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        m_minPreferredLogicalWidth = 0;
2988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
299bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth;
3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
302bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->maxWidth().value()));
303bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->maxWidth().value()));
3048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
30621939df44de1705786c545cd1bf519d47250322dBen Murdoch    int toAdd = borderAndPaddingWidth();
307bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    m_minPreferredLogicalWidth += toAdd;
308bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    m_maxPreferredLogicalWidth += toAdd;
3098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
310bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    setPreferredLogicalWidthsDirty(false);
3118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3132fc2651226baac27029e38c9d6ef883fa32084dbSteve BlockVisiblePosition RenderFileUploadControl::positionForPoint(const IntPoint&)
3142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
3152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    return VisiblePosition();
3162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
3172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
3188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid RenderFileUploadControl::receiveDroppedFiles(const Vector<String>& paths)
3198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#if ENABLE(DIRECTORY_UPLOAD)
3212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (allowsDirectoryUpload()) {
3222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        receiveDropForDirectoryUpload(paths);
3232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return;
3242daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    }
3252daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#endif
3262daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
3278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (allowsMultipleFiles())
3288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_fileChooser->chooseFiles(paths);
3298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
3308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_fileChooser->chooseFile(paths[0]);
3318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString RenderFileUploadControl::buttonValue()
3348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_button)
3368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return String();
3378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_button->value();
3398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
341643ca7872b450ea4efacab6188849e5aac2ba161Steve BlockString RenderFileUploadControl::fileTextValue() const
3428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_fileChooser->basenameForWidth(style()->font(), maxFilenameWidth());
3448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} // namespace WebCore
347