source: webkit/trunk/Source/WebCore/rendering/RenderFileUploadControl.cpp

Last change on this file was 294607, checked in by [email protected], 3 years ago

Convert ExpansionBehavior to a struct of left/right expansion behaviors
https://bugs.webkit.org/show_bug.cgi?id=240554

Patch by Kiet Ho <Kiet Ho> on 2022-05-20
Reviewed by Myles C. Maxfield.

  • Tools/TestWebKitAPI/Tests/WebCore/ComplexTextController.cpp:

(TestWebKitAPI::TEST_F):

  • Source/WebKit/WebProcess/WebCoreSupport/win/WebPopupMenuWin.cpp:

(WebKit::WebPopupMenu::setUpPlatformData):

No new tests, no functional changes made.

  • Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp:

(WebCore::CanvasRenderingContext2D::measureText):
(WebCore::CanvasRenderingContext2D::drawTextInternal):

  • Source/WebCore/html/canvas/CanvasRenderingContext2DBase.cpp:

(WebCore::CanvasRenderingContext2DBase::drawText):
(WebCore::CanvasRenderingContext2DBase::measureTextInternal):

  • Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp:

(WebCore::Layout::Line::applyRunExpansion):

  • Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayBox.h:
  • Source/WebCore/layout/formattingContexts/inline/text/TextUtil.cpp:

(WebCore::Layout::TextUtil::fallbackFontsForText):

  • Source/WebCore/platform/graphics/ComplexTextController.cpp:

(WebCore::ComplexTextController::adjustGlyphsAndAdvances):

  • Source/WebCore/platform/graphics/FontCascade.cpp:

(WebCore::FontCascade::expansionOpportunityCountInternal):

  • Source/WebCore/platform/graphics/TextRun.h:

(WebCore::TextRun::TextRun):

  • Source/WebCore/platform/graphics/WidthIterator.cpp:

(WebCore::WidthIterator::WidthIterator):
(WebCore::WidthIterator::calculateAdditionalWidth const):

  • Source/WebCore/platform/text/TextFlags.h:

(WebCore::ExpansionBehavior::ExpansionBehavior):
(WebCore::ExpansionBehavior::allowLeftOnly):
(WebCore::ExpansionBehavior::forceLeftOnly):
(WebCore::ExpansionBehavior::allowRightOnly):

  • Source/WebCore/platform/win/PopupMenuWin.cpp:

(WebCore::PopupMenuWin::paint):

  • Source/WebCore/rendering/LegacyEllipsisBox.cpp:

(WebCore::LegacyEllipsisBox::paint):
(WebCore::LegacyEllipsisBox::selectionRect const):
(WebCore::LegacyEllipsisBox::paintSelection):

  • Source/WebCore/rendering/LegacyInlineTextBox.cpp:

(WebCore::LegacyInlineTextBox::expansionBehavior const):

  • Source/WebCore/rendering/LegacyLineLayout.cpp:

(WebCore::expansionBehaviorForInlineTextBox):
(WebCore::applyExpansionBehavior):

  • Source/WebCore/rendering/RenderBlock.h:
  • Source/WebCore/rendering/RenderFileUploadControl.cpp:

(WebCore::RenderFileUploadControl::paintObject):
(WebCore::RenderFileUploadControl::computeIntrinsicLogicalWidths const):

  • Source/WebCore/rendering/RenderImage.cpp:

(WebCore::RenderImage::paintReplaced):

  • Source/WebCore/rendering/RenderListBox.cpp:

(WebCore::RenderListBox::updateFromElement):
(WebCore::RenderListBox::paintItemForeground):

  • Source/WebCore/rendering/RenderTextControl.cpp:

(WebCore::RenderTextControl::getAverageCharWidth):

  • Source/WebCore/rendering/svg/SVGInlineTextBox.cpp:

(WebCore::SVGInlineTextBox::constructTextRun const):

  • Source/WebCore/rendering/svg/SVGTextMetrics.cpp:

(WebCore::SVGTextMetrics::constructTextRun):

Canonical link: https://commits.webkit.org/250833@main

  • Property svn:eol-style set to native
File size: 10.3 KB
Line 
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 "ElementRareData.h"
25#include "FileList.h"
26#include "FontCascade.h"
27#include "GraphicsContext.h"
28#include "HTMLInputElement.h"
29#include "HTMLNames.h"
30#include "Icon.h"
31#include "LocalizedStrings.h"
32#include "PaintInfo.h"
33#include "RenderButton.h"
34#include "RenderText.h"
35#include "RenderTheme.h"
36#include "ShadowRoot.h"
37#include "StringTruncator.h"
38#include "TextRun.h"
39#include "VisiblePosition.h"
40#include <math.h>
41#include <wtf/IsoMallocInlines.h>
42
43namespace WebCore {
44
45using namespace HTMLNames;
46
47WTF_MAKE_ISO_ALLOCATED_IMPL(RenderFileUploadControl);
48
49const int afterButtonSpacing = 4;
50#if !PLATFORM(IOS_FAMILY)
51const int iconHeight = 16;
52const int iconWidth = 16;
53const int iconFilenameSpacing = 2;
54const int defaultWidthNumChars = 34;
55#else
56// On iOS the icon height matches the button height, to maximize the icon size.
57const int iconFilenameSpacing = afterButtonSpacing;
58const int defaultWidthNumChars = 38;
59#endif
60const int buttonShadowHeight = 2;
61
62RenderFileUploadControl::RenderFileUploadControl(HTMLInputElement& input, RenderStyle&& style)
63 : RenderBlockFlow(input, WTFMove(style))
64 , m_canReceiveDroppedFiles(input.canReceiveDroppedFiles())
65{
66}
67
68RenderFileUploadControl::~RenderFileUploadControl() = default;
69
70HTMLInputElement& RenderFileUploadControl::inputElement() const
71{
72 return downcast<HTMLInputElement>(nodeForNonAnonymous());
73}
74
75void RenderFileUploadControl::updateFromElement()
76{
77 ASSERT(inputElement().isFileUpload());
78
79 if (HTMLInputElement* button = uploadButton()) {
80 bool newCanReceiveDroppedFilesState = inputElement().canReceiveDroppedFiles();
81 if (m_canReceiveDroppedFiles != newCanReceiveDroppedFilesState) {
82 m_canReceiveDroppedFiles = newCanReceiveDroppedFilesState;
83 button->setActive(newCanReceiveDroppedFilesState);
84 }
85 }
86
87 // This only supports clearing out the files, but that's OK because for
88 // security reasons that's the only change the DOM is allowed to make.
89 FileList* files = inputElement().files();
90 ASSERT(files);
91 if (files && files->isEmpty())
92 repaint();
93}
94
95static int nodeWidth(Node* node)
96{
97 return (node && node->renderBox()) ? roundToInt(node->renderBox()->size().width()) : 0;
98}
99
100#if PLATFORM(IOS_FAMILY)
101static int nodeHeight(Node* node)
102{
103 return (node && node->renderBox()) ? roundToInt(node->renderBox()->size().height()) : 0;
104}
105#endif
106
107int RenderFileUploadControl::maxFilenameWidth() const
108{
109#if PLATFORM(IOS_FAMILY)
110 int iconWidth = nodeHeight(uploadButton());
111#endif
112 return std::max(0, snappedIntRect(contentBoxRect()).width() - nodeWidth(uploadButton()) - afterButtonSpacing
113 - (inputElement().icon() ? iconWidth + iconFilenameSpacing : 0));
114}
115
116void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
117{
118 if (style().visibility() != Visibility::Visible)
119 return;
120
121 if (paintInfo.context().paintingDisabled())
122 return;
123
124 // Push a clip.
125 GraphicsContextStateSaver stateSaver(paintInfo.context(), false);
126 if (paintInfo.phase == PaintPhase::Foreground || paintInfo.phase == PaintPhase::ChildBlockBackgrounds) {
127 IntRect clipRect = enclosingIntRect(LayoutRect(paintOffset.x() + borderLeft(), paintOffset.y() + borderTop(),
128 width() - borderLeft() - borderRight(), height() - borderBottom() - borderTop() + buttonShadowHeight));
129 if (clipRect.isEmpty())
130 return;
131 stateSaver.save();
132 paintInfo.context().clip(clipRect);
133 }
134
135 if (paintInfo.phase == PaintPhase::Foreground) {
136 const String& displayedFilename = fileTextValue();
137 const FontCascade& font = style().fontCascade();
138 TextRun textRun = constructTextRun(displayedFilename, style(), ExpansionBehavior::allowRightOnly(), RespectDirection | RespectDirectionOverride);
139
140#if PLATFORM(IOS_FAMILY)
141 int iconHeight = nodeHeight(uploadButton());
142 int iconWidth = iconHeight;
143#endif
144 // Determine where the filename should be placed
145 LayoutUnit contentLeft = paintOffset.x() + borderLeft() + paddingLeft();
146 HTMLInputElement* button = uploadButton();
147 if (!button)
148 return;
149
150 LayoutUnit buttonWidth = nodeWidth(button);
151 LayoutUnit buttonAndIconWidth = buttonWidth + afterButtonSpacing
152 + (inputElement().icon() ? iconWidth + iconFilenameSpacing : 0);
153 LayoutUnit textX;
154 if (style().isLeftToRightDirection())
155 textX = contentLeft + buttonAndIconWidth;
156 else
157 textX = contentLeft + contentWidth() - buttonAndIconWidth - font.width(textRun);
158
159 LayoutUnit textY;
160 // We want to match the button's baseline
161 // FIXME: Make this work with transforms.
162 if (RenderButton* buttonRenderer = downcast<RenderButton>(button->renderer()))
163 textY = paintOffset.y() + borderTop() + paddingTop() + buttonRenderer->baselinePosition(AlphabeticBaseline, true, HorizontalLine, PositionOnContainingLine);
164 else
165 textY = baselinePosition(AlphabeticBaseline, true, HorizontalLine, PositionOnContainingLine);
166
167 paintInfo.context().setFillColor(style().visitedDependentColorWithColorFilter(CSSPropertyColor));
168
169 // Draw the filename
170 paintInfo.context().drawBidiText(font, textRun, IntPoint(roundToInt(textX), roundToInt(textY)));
171
172 if (inputElement().icon()) {
173 // Determine where the icon should be placed
174 LayoutUnit iconY = paintOffset.y() + borderTop() + paddingTop() + (contentHeight() - iconHeight) / 2;
175 LayoutUnit iconX;
176 if (style().isLeftToRightDirection())
177 iconX = contentLeft + buttonWidth + afterButtonSpacing;
178 else
179 iconX = contentLeft + contentWidth() - buttonWidth - afterButtonSpacing - iconWidth;
180
181#if PLATFORM(IOS_FAMILY)
182 if (RenderButton* buttonRenderer = downcast<RenderButton>(button->renderer())) {
183 // Draw the file icon and decorations.
184 IntRect iconRect(iconX, iconY, iconWidth, iconHeight);
185 RenderTheme::FileUploadDecorations decorationsType = inputElement().files()->length() == 1 ? RenderTheme::SingleFile : RenderTheme::MultipleFiles;
186 theme().paintFileUploadIconDecorations(*this, *buttonRenderer, paintInfo, iconRect, inputElement().icon(), decorationsType);
187 }
188#else
189 // Draw the file icon
190 inputElement().icon()->paint(paintInfo.context(), IntRect(roundToInt(iconX), roundToInt(iconY), iconWidth, iconHeight));
191#endif
192 }
193 }
194
195 // Paint the children.
196 RenderBlockFlow::paintObject(paintInfo, paintOffset);
197}
198
199void RenderFileUploadControl::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
200{
201 if (shouldApplySizeContainment())
202 return;
203 // Figure out how big the filename space needs to be for a given number of characters
204 // (using "0" as the nominal character).
205 const UChar character = '0';
206 const String characterAsString = String(&character, 1);
207 const FontCascade& font = style().fontCascade();
208 // FIXME: Remove the need for this const_cast by making constructTextRun take a const RenderObject*.
209 float minDefaultLabelWidth = defaultWidthNumChars * font.width(constructTextRun(characterAsString, style(), ExpansionBehavior::allowRightOnly()));
210
211 const String label = theme().fileListDefaultLabel(inputElement().multiple());
212 float defaultLabelWidth = font.width(constructTextRun(label, style(), ExpansionBehavior::allowRightOnly()));
213 if (HTMLInputElement* button = uploadButton())
214 if (RenderObject* buttonRenderer = button->renderer())
215 defaultLabelWidth += buttonRenderer->maxPreferredLogicalWidth() + afterButtonSpacing;
216 maxLogicalWidth = static_cast<int>(ceilf(std::max(minDefaultLabelWidth, defaultLabelWidth)));
217
218 if (!style().width().isPercentOrCalculated())
219 minLogicalWidth = maxLogicalWidth;
220}
221
222void RenderFileUploadControl::computePreferredLogicalWidths()
223{
224 ASSERT(preferredLogicalWidthsDirty());
225
226 m_minPreferredLogicalWidth = 0;
227 m_maxPreferredLogicalWidth = 0;
228
229 if (style().width().isFixed() && style().width().value() > 0)
230 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style().width());
231 else
232 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
233
234 RenderBox::computePreferredLogicalWidths(style().minWidth(), style().maxWidth(), horizontalBorderAndPaddingExtent());
235
236 setPreferredLogicalWidthsDirty(false);
237}
238
239VisiblePosition RenderFileUploadControl::positionForPoint(const LayoutPoint&, const RenderFragmentContainer*)
240{
241 return VisiblePosition();
242}
243
244HTMLInputElement* RenderFileUploadControl::uploadButton() const
245{
246 ASSERT(inputElement().shadowRoot());
247 return dynamicDowncast<HTMLInputElement>(inputElement().shadowRoot()->firstChild());
248}
249
250String RenderFileUploadControl::buttonValue()
251{
252 if (HTMLInputElement* button = uploadButton())
253 return button->value();
254
255 return String();
256}
257
258String RenderFileUploadControl::fileTextValue() const
259{
260 auto& input = inputElement();
261 if (!input.files())
262 return { };
263 if (input.files()->length() && !input.displayString().isEmpty())
264 return StringTruncator::rightTruncate(input.displayString(), maxFilenameWidth(), style().fontCascade());
265 return theme().fileListNameForWidth(input.files(), style().fontCascade(), maxFilenameWidth(), input.multiple());
266}
267
268} // namespace WebCore
Note: See TracBrowser for help on using the repository browser.