2 * Copyright (C) 2006, 2007, 2012 Apple Inc. All rights reserved.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
22 #include "core/layout/LayoutFileUploadControl.h"
24 #include "core/HTMLNames.h"
25 #include "core/InputTypeNames.h"
26 #include "core/dom/shadow/ElementShadow.h"
27 #include "core/dom/shadow/ShadowRoot.h"
28 #include "core/editing/PositionWithAffinity.h"
29 #include "core/fileapi/FileList.h"
30 #include "core/html/HTMLInputElement.h"
31 #include "core/layout/LayoutButton.h"
32 #include "core/layout/LayoutTheme.h"
33 #include "core/layout/TextRunConstructor.h"
34 #include "core/paint/FileUploadControlPainter.h"
35 #include "platform/fonts/Font.h"
36 #include "platform/text/PlatformLocale.h"
37 #include "platform/text/TextRun.h"
42 using namespace HTMLNames
;
44 const int defaultWidthNumChars
= 34;
46 LayoutFileUploadControl::LayoutFileUploadControl(HTMLInputElement
* input
)
47 : LayoutBlockFlow(input
)
48 , m_canReceiveDroppedFiles(input
->canReceiveDroppedFiles())
52 LayoutFileUploadControl::~LayoutFileUploadControl()
56 void LayoutFileUploadControl::updateFromElement()
58 HTMLInputElement
* input
= toHTMLInputElement(node());
59 ASSERT(input
->type() == InputTypeNames::file
);
61 if (HTMLInputElement
* button
= uploadButton()) {
62 bool newCanReceiveDroppedFilesState
= input
->canReceiveDroppedFiles();
63 if (m_canReceiveDroppedFiles
!= newCanReceiveDroppedFilesState
) {
64 m_canReceiveDroppedFiles
= newCanReceiveDroppedFilesState
;
65 button
->setActive(newCanReceiveDroppedFilesState
);
69 // This only supports clearing out the files, but that's OK because for
70 // security reasons that's the only change the DOM is allowed to make.
71 FileList
* files
= input
->files();
73 if (files
&& files
->isEmpty())
74 setShouldDoFullPaintInvalidation();
77 int LayoutFileUploadControl::maxFilenameWidth() const
79 int uploadButtonWidth
= (uploadButton() && uploadButton()->layoutBox()) ? uploadButton()->layoutBox()->pixelSnappedWidth() : 0;
80 return std::max(0, contentBoxRect().pixelSnappedWidth() - uploadButtonWidth
- afterButtonSpacing
);
83 void LayoutFileUploadControl::paintObject(const PaintInfo
& paintInfo
, const LayoutPoint
& paintOffset
)
85 FileUploadControlPainter(*this).paintObject(paintInfo
, paintOffset
);
88 void LayoutFileUploadControl::computeIntrinsicLogicalWidths(LayoutUnit
& minLogicalWidth
, LayoutUnit
& maxLogicalWidth
) const
90 // Figure out how big the filename space needs to be for a given number of characters
91 // (using "0" as the nominal character).
92 const UChar character
= '0';
93 const String characterAsString
= String(&character
, 1);
94 const Font
& font
= style()->font();
95 float minDefaultLabelWidth
= defaultWidthNumChars
* font
.width(constructTextRun(font
, characterAsString
, styleRef(), TextRun::AllowTrailingExpansion
));
97 const String label
= toHTMLInputElement(node())->locale().queryString(WebLocalizedString::FileButtonNoFileSelectedLabel
);
98 float defaultLabelWidth
= font
.width(constructTextRun(font
, label
, styleRef(), TextRun::AllowTrailingExpansion
));
99 if (HTMLInputElement
* button
= uploadButton()) {
100 if (LayoutObject
* buttonLayoutObject
= button
->layoutObject())
101 defaultLabelWidth
+= buttonLayoutObject
->maxPreferredLogicalWidth() + afterButtonSpacing
;
103 maxLogicalWidth
= static_cast<int>(ceilf(std::max(minDefaultLabelWidth
, defaultLabelWidth
)));
105 if (!style()->width().hasPercent())
106 minLogicalWidth
= maxLogicalWidth
;
109 void LayoutFileUploadControl::computePreferredLogicalWidths()
111 ASSERT(preferredLogicalWidthsDirty());
113 m_minPreferredLogicalWidth
= 0;
114 m_maxPreferredLogicalWidth
= 0;
115 const ComputedStyle
& styleToUse
= styleRef();
117 if (styleToUse
.width().isFixed() && styleToUse
.width().value() > 0)
118 m_minPreferredLogicalWidth
= m_maxPreferredLogicalWidth
= adjustContentBoxLogicalWidthForBoxSizing(styleToUse
.width().value());
120 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth
, m_maxPreferredLogicalWidth
);
122 if (styleToUse
.minWidth().isFixed() && styleToUse
.minWidth().value() > 0) {
123 m_maxPreferredLogicalWidth
= std::max(m_maxPreferredLogicalWidth
, adjustContentBoxLogicalWidthForBoxSizing(styleToUse
.minWidth().value()));
124 m_minPreferredLogicalWidth
= std::max(m_minPreferredLogicalWidth
, adjustContentBoxLogicalWidthForBoxSizing(styleToUse
.minWidth().value()));
127 if (styleToUse
.maxWidth().isFixed()) {
128 m_maxPreferredLogicalWidth
= std::min(m_maxPreferredLogicalWidth
, adjustContentBoxLogicalWidthForBoxSizing(styleToUse
.maxWidth().value()));
129 m_minPreferredLogicalWidth
= std::min(m_minPreferredLogicalWidth
, adjustContentBoxLogicalWidthForBoxSizing(styleToUse
.maxWidth().value()));
132 int toAdd
= borderAndPaddingWidth();
133 m_minPreferredLogicalWidth
+= toAdd
;
134 m_maxPreferredLogicalWidth
+= toAdd
;
136 clearPreferredLogicalWidthsDirty();
139 PositionWithAffinity
LayoutFileUploadControl::positionForPoint(const LayoutPoint
&)
141 return PositionWithAffinity();
144 HTMLInputElement
* LayoutFileUploadControl::uploadButton() const
146 // FIXME: This should be on HTMLInputElement as an API like innerButtonElement().
147 HTMLInputElement
* input
= toHTMLInputElement(node());
148 Node
* buttonNode
= input
->userAgentShadowRoot()->firstChild();
149 return isHTMLInputElement(buttonNode
) ? toHTMLInputElement(buttonNode
) : 0;
152 String
LayoutFileUploadControl::buttonValue()
154 if (HTMLInputElement
* button
= uploadButton())
155 return button
->value();
160 String
LayoutFileUploadControl::fileTextValue() const
162 HTMLInputElement
* input
= toHTMLInputElement(node());
163 ASSERT(input
->files());
164 return LayoutTheme::theme().fileListNameForWidth(input
->locale(), input
->files(), style()->font(), maxFilenameWidth());