Remove all 'std' using directives from WebCore
[WebKit-https.git] / Source / WebCore / rendering / RenderFileUploadControl.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2012 Apple Inc. All rights reserved.
3  *
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.
8  *
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.
13  *
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.
18  *
19  */
20
21 #include "config.h"
22 #include "RenderFileUploadControl.h"
23
24 #include "FileList.h"
25 #include "Font.h"
26 #include "GraphicsContext.h"
27 #include "HTMLInputElement.h"
28 #include "HTMLNames.h"
29 #include "Icon.h"
30 #include "LocalizedStrings.h"
31 #include "PaintInfo.h"
32 #include "RenderButton.h"
33 #include "RenderText.h"
34 #include "RenderTheme.h"
35 #include "ShadowRoot.h"
36 #include "TextRun.h"
37 #include "VisiblePosition.h"
38 #include <math.h>
39
40 namespace WebCore {
41
42 using namespace HTMLNames;
43
44 const int afterButtonSpacing = 4;
45 const int iconHeight = 16;
46 const int iconWidth = 16;
47 const int iconFilenameSpacing = 2;
48 const int defaultWidthNumChars = 34;
49 const int buttonShadowHeight = 2;
50
51 RenderFileUploadControl::RenderFileUploadControl(HTMLInputElement& input, PassRef<RenderStyle> style)
52     : RenderBlockFlow(input, std::move(style))
53     , m_canReceiveDroppedFiles(input.canReceiveDroppedFiles())
54 {
55 }
56
57 RenderFileUploadControl::~RenderFileUploadControl()
58 {
59 }
60
61 HTMLInputElement& RenderFileUploadControl::inputElement() const
62 {
63     return toHTMLInputElement(nodeForNonAnonymous());
64 }
65
66 bool RenderFileUploadControl::canBeReplacedWithInlineRunIn() const
67 {
68     return false;
69 }
70
71 void RenderFileUploadControl::updateFromElement()
72 {
73     ASSERT(inputElement().isFileUpload());
74
75     if (HTMLInputElement* button = uploadButton()) {
76         bool newCanReceiveDroppedFilesState = inputElement().canReceiveDroppedFiles();
77         if (m_canReceiveDroppedFiles != newCanReceiveDroppedFilesState) {
78             m_canReceiveDroppedFiles = newCanReceiveDroppedFilesState;
79             button->setActive(newCanReceiveDroppedFilesState);
80         }
81     }
82
83     // This only supports clearing out the files, but that's OK because for
84     // security reasons that's the only change the DOM is allowed to make.
85     FileList* files = inputElement().files();
86     ASSERT(files);
87     if (files && files->isEmpty())
88         repaint();
89 }
90
91 static int nodeWidth(Node* node)
92 {
93     return (node && node->renderBox()) ? node->renderBox()->pixelSnappedWidth() : 0;
94 }
95
96 int RenderFileUploadControl::maxFilenameWidth() const
97 {
98     return std::max(0, contentBoxRect().pixelSnappedWidth() - nodeWidth(uploadButton()) - afterButtonSpacing
99         - (inputElement().icon() ? iconWidth + iconFilenameSpacing : 0));
100 }
101
102 void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
103 {
104     if (style().visibility() != VISIBLE)
105         return;
106     
107     // Push a clip.
108     GraphicsContextStateSaver stateSaver(*paintInfo.context, false);
109     if (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseChildBlockBackgrounds) {
110         IntRect clipRect = enclosingIntRect(LayoutRect(paintOffset.x() + borderLeft(), paintOffset.y() + borderTop(),
111                          width() - borderLeft() - borderRight(), height() - borderBottom() - borderTop() + buttonShadowHeight));
112         if (clipRect.isEmpty())
113             return;
114         stateSaver.save();
115         paintInfo.context->clip(clipRect);
116     }
117
118     if (paintInfo.phase == PaintPhaseForeground) {
119         const String& displayedFilename = fileTextValue();
120         const Font& font = style().font();
121         TextRun textRun = constructTextRun(this, font, displayedFilename, style(), TextRun::AllowTrailingExpansion, RespectDirection | RespectDirectionOverride);
122         textRun.disableRoundingHacks();
123
124         // Determine where the filename should be placed
125         LayoutUnit contentLeft = paintOffset.x() + borderLeft() + paddingLeft();
126         HTMLInputElement* button = uploadButton();
127         if (!button)
128             return;
129
130         LayoutUnit buttonWidth = nodeWidth(button);
131         LayoutUnit buttonAndIconWidth = buttonWidth + afterButtonSpacing
132             + (inputElement().icon() ? iconWidth + iconFilenameSpacing : 0);
133         LayoutUnit textX;
134         if (style().isLeftToRightDirection())
135             textX = contentLeft + buttonAndIconWidth;
136         else
137             textX = contentLeft + contentWidth() - buttonAndIconWidth - font.width(textRun);
138
139         LayoutUnit textY = 0;
140         // We want to match the button's baseline
141         // FIXME: Make this work with transforms.
142         if (RenderButton* buttonRenderer = toRenderButton(button->renderer()))
143             textY = paintOffset.y() + borderTop() + paddingTop() + buttonRenderer->baselinePosition(AlphabeticBaseline, true, HorizontalLine, PositionOnContainingLine);
144         else
145             textY = baselinePosition(AlphabeticBaseline, true, HorizontalLine, PositionOnContainingLine);
146
147         paintInfo.context->setFillColor(style().visitedDependentColor(CSSPropertyColor), style().colorSpace());
148         
149         // Draw the filename
150         paintInfo.context->drawBidiText(font, textRun, IntPoint(roundToInt(textX), roundToInt(textY)));
151         
152         if (inputElement().icon()) {
153             // Determine where the icon should be placed
154             LayoutUnit iconY = paintOffset.y() + borderTop() + paddingTop() + (contentHeight() - iconHeight) / 2;
155             LayoutUnit iconX;
156             if (style().isLeftToRightDirection())
157                 iconX = contentLeft + buttonWidth + afterButtonSpacing;
158             else
159                 iconX = contentLeft + contentWidth() - buttonWidth - afterButtonSpacing - iconWidth;
160
161             // Draw the file icon
162             inputElement().icon()->paint(paintInfo.context, IntRect(roundToInt(iconX), roundToInt(iconY), iconWidth, iconHeight));
163         }
164     }
165
166     // Paint the children.
167     RenderBlockFlow::paintObject(paintInfo, paintOffset);
168 }
169
170 void RenderFileUploadControl::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
171 {
172     // Figure out how big the filename space needs to be for a given number of characters
173     // (using "0" as the nominal character).
174     const UChar character = '0';
175     const String characterAsString = String(&character, 1);
176     const Font& font = style().font();
177     // FIXME: Remove the need for this const_cast by making constructTextRun take a const RenderObject*.
178     RenderFileUploadControl* renderer = const_cast<RenderFileUploadControl*>(this);
179     float minDefaultLabelWidth = defaultWidthNumChars * font.width(constructTextRun(renderer, font, characterAsString, style(), TextRun::AllowTrailingExpansion));
180
181     const String label = theme()->fileListDefaultLabel(inputElement().multiple());
182     float defaultLabelWidth = font.width(constructTextRun(renderer, font, label, style(), TextRun::AllowTrailingExpansion));
183     if (HTMLInputElement* button = uploadButton())
184         if (RenderObject* buttonRenderer = button->renderer())
185             defaultLabelWidth += buttonRenderer->maxPreferredLogicalWidth() + afterButtonSpacing;
186     maxLogicalWidth = static_cast<int>(ceilf(std::max(minDefaultLabelWidth, defaultLabelWidth)));
187
188     if (!style().width().isPercent())
189         minLogicalWidth = maxLogicalWidth;
190 }
191
192 void RenderFileUploadControl::computePreferredLogicalWidths()
193 {
194     ASSERT(preferredLogicalWidthsDirty());
195
196     m_minPreferredLogicalWidth = 0;
197     m_maxPreferredLogicalWidth = 0;
198
199     if (style().width().isFixed() && style().width().value() > 0)
200         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style().width().value());
201     else
202         computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
203
204     if (style().minWidth().isFixed() && style().minWidth().value() > 0) {
205         m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style().minWidth().value()));
206         m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style().minWidth().value()));
207     }
208
209     if (style().maxWidth().isFixed()) {
210         m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style().maxWidth().value()));
211         m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style().maxWidth().value()));
212     }
213
214     int toAdd = borderAndPaddingWidth();
215     m_minPreferredLogicalWidth += toAdd;
216     m_maxPreferredLogicalWidth += toAdd;
217
218     setPreferredLogicalWidthsDirty(false);
219 }
220
221 VisiblePosition RenderFileUploadControl::positionForPoint(const LayoutPoint&)
222 {
223     return VisiblePosition();
224 }
225
226 HTMLInputElement* RenderFileUploadControl::uploadButton() const
227 {
228     ASSERT(inputElement().shadowRoot());
229     Node* buttonNode = inputElement().shadowRoot()->firstChild();
230     return buttonNode && buttonNode->isHTMLElement() && isHTMLInputElement(buttonNode) ? toHTMLInputElement(buttonNode) : 0;
231 }
232
233 String RenderFileUploadControl::buttonValue()
234 {
235     if (HTMLInputElement* button = uploadButton())
236         return button->value();
237     
238     return String();
239 }
240
241 String RenderFileUploadControl::fileTextValue() const
242 {
243     ASSERT(inputElement().files());
244     return theme()->fileListNameForWidth(inputElement().files(), style().font(), maxFilenameWidth(), inputElement().multiple());
245 }
246     
247 } // namespace WebCore