Skip to content

Commit

Permalink
Cherry-pick 267815.359@safari-7617-branch (1f4ca4f). https://bugs.web…
Browse files Browse the repository at this point in the history
…kit.org/show_bug.cgi?id=264327

    [Hardening] Introduce checkedDowncast<>() and use it in a few places where the type is not obvious
    https://bugs.webkit.org/show_bug.cgi?id=263463
    rdar://117247122

    Reviewed by Darin Adler and Ryosuke Niwa.

    Introduce checkedDowncast<>() and use it in a few places where the type is not
    obvious (no earlier is<>() check).

    checkedDowncast<>() is just like downcast<>() but its internal type check is a
    RELEASE_ASSERT() instead of a debug ASSERT().

    In the future, we may want to promote using either dynamicDowncast<>() or
    checkedDowncast<>() and maybe phasing out downcast<>() (in which case we could
    rename checkedDowncast<>() to downcast()).

    * Source/WTF/wtf/Ref.h:
    (WTF::checkedDowncast):
    * Source/WTF/wtf/RefPtr.h:
    (WTF::checkedDowncast):
    * Source/WTF/wtf/TypeCasts.h:
    (WTF::checkedDowncast):
    * Source/WebCore/html/shadow/DateTimeEditElement.cpp:
    (WebCore::DateTimeEditElement::fieldsWrapperElement const):
    * Source/WebCore/html/shadow/DateTimeFieldElement.cpp:
    (WebCore::DateTimeFieldElement::updateVisibleValue):
    * Source/WebCore/html/shadow/DetailsMarkerControl.cpp:
    (WebCore::DetailsMarkerControl::rendererIsNeeded):
    * Source/WebCore/html/shadow/ProgressShadowElement.cpp:
    (WebCore::ProgressShadowElement::progressElement const):
    * Source/WebCore/html/shadow/SliderThumbElement.cpp:
    (WebCore::RenderSliderContainer::computeLogicalHeight const):
    (WebCore::RenderSliderContainer::layout):
    (WebCore::SliderThumbElement::hostInput const):
    * Source/WebCore/html/shadow/TextControlInnerElements.cpp:
    (WebCore::isStrongPasswordTextField):
    (WebCore::TextControlInnerTextElement::renderer const):
    (WebCore::TextControlInnerTextElement::resolveCustomStyle):
    (WebCore::TextControlPlaceholderElement::resolveCustomStyle):
    (WebCore::SearchFieldResultsButtonElement::defaultEventHandler):
    (WebCore::SearchFieldCancelButtonElement::resolveCustomStyle):
    (WebCore::SearchFieldCancelButtonElement::defaultEventHandler):
    (WebCore::SearchFieldCancelButtonElement::willRespondToMouseClickEventsWithEditability const):

    Canonical link: https://commits.webkit.org/267815.359@safari-7617-branch

Canonical link: https://commits.webkit.org/266719.162@webkitglib/2.42
  • Loading branch information
cdumez authored and mcatanzaro committed Dec 13, 2023
1 parent c3ca39c commit 53cf2a6
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 20 deletions.
9 changes: 9 additions & 0 deletions Source/WTF/wtf/Ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,15 @@ inline Target& downcast(Ref<Source, PtrTraits>& source)
return downcast<Target>(source.get());
}

template<typename Target, typename Source, typename PtrTraits>
inline Ref<Target> checkedDowncast(Ref<Source, PtrTraits> source)
{
static_assert(!std::is_same_v<Source, Target>, "Unnecessary cast to same type");
static_assert(std::is_base_of_v<Source, Target>, "Should be a downcast");
RELEASE_ASSERT(is<Target>(source));
return static_reference_cast<Target>(WTFMove(source));
}

template<typename Target, typename Source, typename PtrTraits>
inline Target& downcast(const Ref<Source, PtrTraits>& source)
{
Expand Down
9 changes: 9 additions & 0 deletions Source/WTF/wtf/RefPtr.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,15 @@ inline bool is(const RefPtr<ArgType, PtrTraits, RefDerefTraits>& source)
return is<ExpectedType>(source.get());
}

template<typename Target, typename Source, typename PtrTraits, typename RefDerefTraits>
inline RefPtr<Target> checkedDowncast(RefPtr<Source, PtrTraits, RefDerefTraits> source)
{
static_assert(!std::is_same_v<Source, Target>, "Unnecessary cast to same type");
static_assert(std::is_base_of_v<Source, Target>, "Should be a downcast");
RELEASE_ASSERT(!source || is<Target>(*source));
return static_pointer_cast<Target>(WTFMove(source));
}

template<typename Target, typename Source, typename PtrTraits, typename RefDerefTraits>
inline Target* downcast(RefPtr<Source, PtrTraits, RefDerefTraits>& source)
{
Expand Down
18 changes: 18 additions & 0 deletions Source/WTF/wtf/TypeCasts.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,23 @@ using match_constness_t =
typename std::conditional_t<std::is_const_v<Reference>, typename std::add_const_t<T>, typename std::remove_const_t<T>>;

// Safe downcasting functions.
template<typename Target, typename Source>
inline match_constness_t<Source, Target>& checkedDowncast(Source& source)
{
static_assert(!std::is_same_v<Source, Target>, "Unnecessary cast to same type");
static_assert(std::is_base_of_v<Source, Target>, "Should be a downcast");
RELEASE_ASSERT(is<Target>(source));
return static_cast<match_constness_t<Source, Target>&>(source);
}
template<typename Target, typename Source>
inline match_constness_t<Source, Target>* checkedDowncast(Source* source)
{
static_assert(!std::is_same_v<Source, Target>, "Unnecessary cast to same type");
static_assert(std::is_base_of_v<Source, Target>, "Should be a downcast");
RELEASE_ASSERT(!source || is<Target>(*source));
return static_cast<match_constness_t<Source, Target>*>(source);
}

template<typename Target, typename Source>
inline match_constness_t<Source, Target>& downcast(Source& source)
{
Expand Down Expand Up @@ -134,5 +151,6 @@ inline bool is(const std::unique_ptr<ArgType, Deleter>& source)

using WTF::TypeCastTraits;
using WTF::is;
using WTF::checkedDowncast;
using WTF::downcast;
using WTF::dynamicDowncast;
2 changes: 1 addition & 1 deletion Source/WebCore/html/shadow/DateTimeEditElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ DateTimeEditElement::~DateTimeEditElement() = default;
inline Element& DateTimeEditElement::fieldsWrapperElement() const
{
ASSERT(firstChild());
return downcast<Element>(*firstChild());
return checkedDowncast<Element>(*firstChild());
}

void DateTimeEditElement::addField(Ref<DateTimeFieldElement> field)
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/html/shadow/DateTimeFieldElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ void DateTimeFieldElement::updateVisibleValue(EventBehavior eventBehavior)
if (!firstChild())
appendChild(Text::create(document(), String { emptyString() }));

Ref textNode = downcast<Text>(*firstChild());
Ref textNode = checkedDowncast<Text>(*firstChild());
String newVisibleValue = visibleValue();
if (textNode->wholeText() != newVisibleValue)
textNode->replaceWholeText(newVisibleValue);
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/html/shadow/DetailsMarkerControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ RenderPtr<RenderElement> DetailsMarkerControl::createElementRenderer(RenderStyle

bool DetailsMarkerControl::rendererIsNeeded(const RenderStyle& style)
{
return downcast<HTMLSummaryElement>(shadowHost())->isActiveSummary() && HTMLDivElement::rendererIsNeeded(style);
return checkedDowncast<HTMLSummaryElement>(shadowHost())->isActiveSummary() && HTMLDivElement::rendererIsNeeded(style);
}

}
2 changes: 1 addition & 1 deletion Source/WebCore/html/shadow/ProgressShadowElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ ProgressShadowElement::ProgressShadowElement(Document& document)

HTMLProgressElement* ProgressShadowElement::progressElement() const
{
return downcast<HTMLProgressElement>(shadowHost());
return checkedDowncast<HTMLProgressElement>(shadowHost());
}

bool ProgressShadowElement::rendererIsNeeded(const RenderStyle& style)
Expand Down
6 changes: 3 additions & 3 deletions Source/WebCore/html/shadow/SliderThumbElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class RenderSliderContainer final : public RenderFlexibleBox {
RenderBox::LogicalExtentComputedValues RenderSliderContainer::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop) const
{
ASSERT(element()->shadowHost());
auto& input = downcast<HTMLInputElement>(*element()->shadowHost());
auto& input = checkedDowncast<HTMLInputElement>(*element()->shadowHost());
bool isVertical = hasVerticalAppearance(input);

#if ENABLE(DATALIST_ELEMENT)
Expand Down Expand Up @@ -133,7 +133,7 @@ RenderBox::LogicalExtentComputedValues RenderSliderContainer::computeLogicalHeig
void RenderSliderContainer::layout()
{
ASSERT(element()->shadowHost());
auto& input = downcast<HTMLInputElement>(*element()->shadowHost());
auto& input = checkedDowncast<HTMLInputElement>(*element()->shadowHost());
bool isVertical = hasVerticalAppearance(input);
mutableStyle().setFlexDirection(isVertical && style().isHorizontalWritingMode() ? FlexDirection::Column : FlexDirection::Row);
TextDirection oldTextDirection = style().direction();
Expand Down Expand Up @@ -554,7 +554,7 @@ RefPtr<HTMLInputElement> SliderThumbElement::hostInput() const
{
// Only HTMLInputElement creates SliderThumbElement instances as its shadow nodes.
// So, shadowHost() must be an HTMLInputElement.
return downcast<HTMLInputElement>(shadowHost());
return checkedDowncast<HTMLInputElement>(shadowHost());
}

std::optional<Style::ResolvedStyle> SliderThumbElement::resolveCustomStyle(const Style::ResolutionContext& resolutionContext, const RenderStyle* hostStyle)
Expand Down
27 changes: 14 additions & 13 deletions Source/WebCore/html/shadow/TextControlInnerElements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
#include "TextEventInputType.h"
#include <wtf/IsoMallocInlines.h>
#include <wtf/Ref.h>
#include <wtf/RefPtr.h>
#include <wtf/SetForScope.h>

namespace WebCore {
Expand Down Expand Up @@ -82,7 +83,8 @@ RenderPtr<RenderElement> TextControlInnerContainer::createElementRenderer(Render

static inline bool isStrongPasswordTextField(const Element* element)
{
return is<HTMLInputElement>(element) && downcast<HTMLInputElement>(element)->hasAutoFillStrongPasswordButton();
RefPtr input = dynamicDowncast<HTMLInputElement>(element);
return input && input->hasAutoFillStrongPasswordButton();
}

std::optional<Style::ResolvedStyle> TextControlInnerContainer::resolveCustomStyle(const Style::ResolutionContext& resolutionContext, const RenderStyle*)
Expand Down Expand Up @@ -191,12 +193,12 @@ RenderPtr<RenderElement> TextControlInnerTextElement::createElementRenderer(Rend

RenderTextControlInnerBlock* TextControlInnerTextElement::renderer() const
{
return downcast<RenderTextControlInnerBlock>(HTMLDivElement::renderer());
return checkedDowncast<RenderTextControlInnerBlock>(HTMLDivElement::renderer());
}

std::optional<Style::ResolvedStyle> TextControlInnerTextElement::resolveCustomStyle(const Style::ResolutionContext&, const RenderStyle* shadowHostStyle)
{
auto style = downcast<HTMLTextFormControlElement>(*shadowHost()).createInnerTextStyle(*shadowHostStyle);
auto style = checkedDowncast<HTMLTextFormControlElement>(*shadowHost()).createInnerTextStyle(*shadowHostStyle);
return Style::ResolvedStyle { makeUnique<RenderStyle>(WTFMove(style)) };
}

Expand All @@ -219,12 +221,11 @@ std::optional<Style::ResolvedStyle> TextControlPlaceholderElement::resolveCustom
{
auto style = resolveStyle(resolutionContext);

auto& controlElement = downcast<HTMLTextFormControlElement>(*containingShadowRoot()->host());
style.style->setDisplay(controlElement.isPlaceholderVisible() ? DisplayType::Block : DisplayType::None);
Ref controlElement = checkedDowncast<HTMLTextFormControlElement>(*containingShadowRoot()->host());
style.style->setDisplay(controlElement->isPlaceholderVisible() ? DisplayType::Block : DisplayType::None);

if (is<HTMLInputElement>(controlElement)) {
auto& inputElement = downcast<HTMLInputElement>(controlElement);
style.style->setTextOverflow(inputElement.shouldTruncateText(*shadowHostStyle) ? TextOverflow::Ellipsis : TextOverflow::Clip);
if (RefPtr inputElement = dynamicDowncast<HTMLInputElement>(controlElement.get())) {
style.style->setTextOverflow(inputElement->shouldTruncateText(*shadowHostStyle) ? TextOverflow::Ellipsis : TextOverflow::Clip);
style.style->setPaddingTop(Length { 0, LengthType::Fixed });
style.style->setPaddingBottom(Length { 0, LengthType::Fixed });
}
Expand Down Expand Up @@ -271,7 +272,7 @@ std::optional<Style::ResolvedStyle> SearchFieldResultsButtonElement::resolveCust
void SearchFieldResultsButtonElement::defaultEventHandler(Event& event)
{
// On mousedown, bring up a menu, if needed
RefPtr input = downcast<HTMLInputElement>(shadowHost());
RefPtr input = checkedDowncast<HTMLInputElement>(shadowHost());
if (input && event.type() == eventNames().mousedownEvent && is<MouseEvent>(event) && downcast<MouseEvent>(event).button() == LeftButton) {
input->focus();
input->select();
Expand Down Expand Up @@ -323,8 +324,8 @@ Ref<SearchFieldCancelButtonElement> SearchFieldCancelButtonElement::create(Docum
std::optional<Style::ResolvedStyle> SearchFieldCancelButtonElement::resolveCustomStyle(const Style::ResolutionContext& resolutionContext, const RenderStyle* shadowHostStyle)
{
auto elementStyle = resolveStyle(resolutionContext);
auto& inputElement = downcast<HTMLInputElement>(*shadowHost());
elementStyle.style->setVisibility(elementStyle.style->visibility() == Visibility::Hidden || inputElement.value().isEmpty() ? Visibility::Hidden : Visibility::Visible);
Ref inputElement = checkedDowncast<HTMLInputElement>(*shadowHost());
elementStyle.style->setVisibility(elementStyle.style->visibility() == Visibility::Hidden || inputElement->value().isEmpty() ? Visibility::Hidden : Visibility::Visible);

if (shadowHostStyle && shadowHostStyle->effectiveAppearance() == StyleAppearance::TextField)
elementStyle.style->setDisplay(DisplayType::None);
Expand All @@ -334,7 +335,7 @@ std::optional<Style::ResolvedStyle> SearchFieldCancelButtonElement::resolveCusto

void SearchFieldCancelButtonElement::defaultEventHandler(Event& event)
{
RefPtr<HTMLInputElement> input(downcast<HTMLInputElement>(shadowHost()));
RefPtr input = checkedDowncast<HTMLInputElement>(shadowHost());
if (!input || !input->isMutable()) {
if (!event.defaultHandled())
HTMLDivElement::defaultEventHandler(event);
Expand All @@ -361,7 +362,7 @@ void SearchFieldCancelButtonElement::defaultEventHandler(Event& event)
#if !PLATFORM(IOS_FAMILY)
bool SearchFieldCancelButtonElement::willRespondToMouseClickEventsWithEditability(Editability editability) const
{
const RefPtr<HTMLInputElement> input = downcast<HTMLInputElement>(shadowHost());
RefPtr input = checkedDowncast<HTMLInputElement>(shadowHost());
if (input && input->isMutable())
return true;

Expand Down

0 comments on commit 53cf2a6

Please sign in to comment.