blob: 6bdb6aa31346bb9e22e44dd718a233fe575d274f [file] [log] [blame]
/*
* Copyright (C) 2006, 2007, 2012 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "third_party/blink/renderer/core/layout/layout_file_upload_control.h"
#include <math.h>
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
#include "third_party/blink/renderer/core/fileapi/file_list.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/core/layout/layout_theme.h"
#include "third_party/blink/renderer/core/paint/file_upload_control_painter.h"
#include "third_party/blink/renderer/platform/fonts/font.h"
#include "third_party/blink/renderer/platform/text/platform_locale.h"
#include "third_party/blink/renderer/platform/text/text_run.h"
namespace blink {
using namespace HTMLNames;
const int kDefaultWidthNumChars = 34;
const int kButtonShadowHeight = 2;
LayoutFileUploadControl::LayoutFileUploadControl(HTMLInputElement* input)
: LayoutBlockFlow(input),
can_receive_dropped_files_(input->CanReceiveDroppedFiles()) {}
LayoutFileUploadControl::~LayoutFileUploadControl() = default;
void LayoutFileUploadControl::UpdateFromElement() {
HTMLInputElement* input = ToHTMLInputElement(GetNode());
DCHECK_EQ(input->type(), InputTypeNames::file);
if (HTMLInputElement* button = UploadButton()) {
bool new_can_receive_dropped_files_state = input->CanReceiveDroppedFiles();
if (can_receive_dropped_files_ != new_can_receive_dropped_files_state) {
can_receive_dropped_files_ = new_can_receive_dropped_files_state;
button->SetActive(new_can_receive_dropped_files_state);
}
}
// 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 = input->files();
DCHECK(files);
if (files && files->IsEmpty())
SetShouldDoFullPaintInvalidation();
}
int LayoutFileUploadControl::MaxFilenameWidth() const {
int upload_button_width =
(UploadButton() && UploadButton()->GetLayoutBox())
? UploadButton()->GetLayoutBox()->PixelSnappedWidth()
: 0;
return std::max(0, ContentBoxRect().PixelSnappedWidth() -
upload_button_width - kAfterButtonSpacing);
}
void LayoutFileUploadControl::PaintObject(
const PaintInfo& paint_info,
const LayoutPoint& paint_offset) const {
FileUploadControlPainter(*this).PaintObject(paint_info, paint_offset);
}
void LayoutFileUploadControl::ComputeIntrinsicLogicalWidths(
LayoutUnit& min_logical_width,
LayoutUnit& max_logical_width) const {
// Figure out how big the filename space needs to be for a given number of
// characters (using "0" as the nominal character).
const UChar kCharacter = '0';
const String character_as_string = String(&kCharacter, 1);
const Font& font = StyleRef().GetFont();
float min_default_label_width =
kDefaultWidthNumChars *
font.Width(ConstructTextRun(font, character_as_string, StyleRef(),
TextRun::kAllowTrailingExpansion));
const String label = ToHTMLInputElement(GetNode())->GetLocale().QueryString(
WebLocalizedString::kFileButtonNoFileSelectedLabel);
float default_label_width = font.Width(ConstructTextRun(
font, label, StyleRef(), TextRun::kAllowTrailingExpansion));
if (HTMLInputElement* button = UploadButton()) {
if (LayoutObject* button_layout_object = button->GetLayoutObject())
default_label_width += button_layout_object->MaxPreferredLogicalWidth() +
kAfterButtonSpacing;
}
max_logical_width =
LayoutUnit(ceilf(std::max(min_default_label_width, default_label_width)));
if (!StyleRef().Width().IsPercentOrCalc())
min_logical_width = max_logical_width;
}
void LayoutFileUploadControl::ComputePreferredLogicalWidths() {
DCHECK(PreferredLogicalWidthsDirty());
min_preferred_logical_width_ = LayoutUnit();
max_preferred_logical_width_ = LayoutUnit();
const ComputedStyle& style_to_use = StyleRef();
if (style_to_use.Width().IsFixed() && style_to_use.Width().Value() > 0)
min_preferred_logical_width_ = max_preferred_logical_width_ =
AdjustContentBoxLogicalWidthForBoxSizing(
LayoutUnit(style_to_use.Width().Value()));
else
ComputeIntrinsicLogicalWidths(min_preferred_logical_width_,
max_preferred_logical_width_);
if (style_to_use.MinWidth().IsFixed() &&
style_to_use.MinWidth().Value() > 0) {
max_preferred_logical_width_ =
std::max(max_preferred_logical_width_,
AdjustContentBoxLogicalWidthForBoxSizing(
LayoutUnit(style_to_use.MinWidth().Value())));
min_preferred_logical_width_ =
std::max(min_preferred_logical_width_,
AdjustContentBoxLogicalWidthForBoxSizing(
LayoutUnit(style_to_use.MinWidth().Value())));
}
if (style_to_use.MaxWidth().IsFixed()) {
max_preferred_logical_width_ =
std::min(max_preferred_logical_width_,
AdjustContentBoxLogicalWidthForBoxSizing(
LayoutUnit(style_to_use.MaxWidth().Value())));
min_preferred_logical_width_ =
std::min(min_preferred_logical_width_,
AdjustContentBoxLogicalWidthForBoxSizing(
LayoutUnit(style_to_use.MaxWidth().Value())));
}
int to_add = BorderAndPaddingWidth().ToInt();
min_preferred_logical_width_ += to_add;
max_preferred_logical_width_ += to_add;
ClearPreferredLogicalWidthsDirty();
}
PositionWithAffinity LayoutFileUploadControl::PositionForPoint(
const LayoutPoint&) const {
return PositionWithAffinity();
}
HTMLInputElement* LayoutFileUploadControl::UploadButton() const {
// FIXME: This should be on HTMLInputElement as an API like
// innerButtonElement().
HTMLInputElement* input = ToHTMLInputElement(GetNode());
return ToHTMLInputElementOrNull(input->UserAgentShadowRoot()->firstChild());
}
String LayoutFileUploadControl::ButtonValue() {
if (HTMLInputElement* button = UploadButton())
return button->value();
return String();
}
String LayoutFileUploadControl::FileTextValue() const {
HTMLInputElement* input = ToHTMLInputElement(GetNode());
DCHECK(input->files());
return LayoutTheme::GetTheme().FileListNameForWidth(
input->GetLocale(), input->files(), StyleRef().GetFont(),
MaxFilenameWidth());
}
LayoutRect LayoutFileUploadControl::ControlClipRect(
const LayoutPoint& additional_offset) const {
LayoutRect rect(additional_offset, Size());
rect.Expand(BorderInsets());
rect.Expand(LayoutUnit(), LayoutUnit(kButtonShadowHeight));
return rect;
}
// Override to allow effective ControlClipRect to be bigger than the padding
// box because of kButtonShadowHeight.
LayoutRect LayoutFileUploadControl::OverflowClipRect(
const LayoutPoint& additional_offset,
OverlayScrollbarClipBehavior) const {
return ControlClipRect(additional_offset);
}
} // namespace blink