Skip to content

Commit

Permalink
dynamicDowncast<> adoption in platform code, primarily animation
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=270052

Reviewed by Chris Dumez.

For security & performance. Also use uncheckedDowncast<> in a switch
construct where the relationship between type and class is
straightforward.

* Source/WebCore/platform/DragImage.cpp:
(WebCore::createDragImageFromSnapshot):
* Source/WebCore/platform/ScrollingEffectsController.cpp:
(WebCore::ScrollingEffectsController::finishKeyboardScroll):
(WebCore::ScrollingEffectsController::retargetAnimatedScroll):
(WebCore::ScrollingEffectsController::processWheelEventForKineticScrolling):
* Source/WebCore/platform/VideoFrame.mm:
(WebCore::VideoFrame::asVideoFrameCV):
* Source/WebCore/platform/animation/AcceleratedEffect.cpp:
(WebCore::AcceleratedEffect::AcceleratedEffect):
(WebCore::AcceleratedEffect::apply):
(WebCore::AcceleratedEffect::timingFunctionForKeyframe const):
* Source/WebCore/platform/animation/TimingFunction.cpp:
(WebCore::operator<<):
(WebCore::TimingFunction::transformProgress const):
(WebCore::TimingFunction::createFromCSSValue):
(WebCore::TimingFunction::cssText const):
* Source/WebCore/platform/animation/TimingFunction.h:

Canonical link: https://commits.webkit.org/275329@main
  • Loading branch information
annevk committed Feb 26, 2024
1 parent f697006 commit a057d5d
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 86 deletions.
6 changes: 3 additions & 3 deletions Source/WebCore/platform/DragImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,11 @@ static DragImageRef createDragImageFromSnapshot(RefPtr<ImageBuffer> snapshot, No

ImageOrientation orientation;
if (node) {
RenderObject* renderer = node->renderer();
if (!renderer || !is<RenderElement>(renderer))
auto* elementRenderer = dynamicDowncast<RenderElement>(node->renderer());
if (!elementRenderer)
return nullptr;

orientation = downcast<RenderElement>(*renderer).imageOrientation();
orientation = elementRenderer->imageOrientation();
}

auto image = BitmapImage::create(ImageBuffer::sinkIntoNativeImage(WTFMove(snapshot)));
Expand Down
23 changes: 11 additions & 12 deletions Source/WebCore/platform/ScrollingEffectsController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ bool ScrollingEffectsController::startKeyboardScroll(const KeyboardScroll& scrol

void ScrollingEffectsController::finishKeyboardScroll(bool immediate)
{
if (is<ScrollAnimationKeyboard>(m_currentAnimation))
downcast<ScrollAnimationKeyboard>(*m_currentAnimation).finishKeyboardScroll(immediate);
if (auto* animationKeyboard = dynamicDowncast<ScrollAnimationKeyboard>(m_currentAnimation.get()))
animationKeyboard->finishKeyboardScroll(immediate);
}

bool ScrollingEffectsController::startAnimatedScrollToDestination(FloatPoint startOffset, FloatPoint destinationOffset)
Expand All @@ -125,13 +125,14 @@ bool ScrollingEffectsController::startAnimatedScrollToDestination(FloatPoint sta

bool ScrollingEffectsController::retargetAnimatedScroll(FloatPoint newDestinationOffset)
{
if (!is<ScrollAnimationSmooth>(m_currentAnimation.get()))
auto* animationSmooth = dynamicDowncast<ScrollAnimationSmooth>(m_currentAnimation.get());
if (!animationSmooth)
return false;

LOG_WITH_STREAM(ScrollAnimations, stream << "ScrollingEffectsController " << this << " retargetAnimatedScroll to " << newDestinationOffset);

ASSERT(m_currentAnimation->isActive());
return downcast<ScrollAnimationSmooth>(*m_currentAnimation).retargetActiveAnimation(newDestinationOffset);
ASSERT(animationSmooth->isActive());
return animationSmooth->retargetActiveAnimation(newDestinationOffset);
}

bool ScrollingEffectsController::retargetAnimatedScrollBy(FloatSize offset)
Expand Down Expand Up @@ -290,14 +291,12 @@ float ScrollingEffectsController::adjustedScrollDestination(ScrollEventAxis axis
#if ENABLE(KINETIC_SCROLLING)
bool ScrollingEffectsController::processWheelEventForKineticScrolling(const PlatformWheelEvent& event)
{
if (is<ScrollAnimationKinetic>(m_currentAnimation.get())) {
auto& kineticAnimation = downcast<ScrollAnimationKinetic>(*m_currentAnimation);
if (auto* kineticAnimation = dynamicDowncast<ScrollAnimationKinetic>(m_currentAnimation.get())) {
m_previousKineticAnimationInfo.startTime = kineticAnimation->startTime();
m_previousKineticAnimationInfo.initialOffset = kineticAnimation->initialOffset();
m_previousKineticAnimationInfo.initialVelocity = kineticAnimation->initialVelocity();

m_previousKineticAnimationInfo.startTime = kineticAnimation.startTime();
m_previousKineticAnimationInfo.initialOffset = kineticAnimation.initialOffset();
m_previousKineticAnimationInfo.initialVelocity = kineticAnimation.initialVelocity();

m_currentAnimation->stop();
kineticAnimation->stop();
}

if (!event.hasPreciseScrollingDeltas()) {
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/platform/VideoFrame.mm
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
#if USE(AVFOUNDATION)
RefPtr<VideoFrameCV> VideoFrame::asVideoFrameCV()
{
if (isCV())
return downcast<VideoFrameCV>(this);
if (auto* videoFrameCV = dynamicDowncast<VideoFrameCV>(*this))
return videoFrameCV;

auto buffer = pixelBuffer();
if (!buffer)
Expand Down
17 changes: 7 additions & 10 deletions Source/WebCore/platform/animation/AcceleratedEffect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,8 @@ AcceleratedEffect::AcceleratedEffect(const KeyframeEffect& effect, const IntRect
ASSERT(animation->holdTime() || animation->startTime());
m_holdTime = animation->holdTime();
m_startTime = animation->startTime();
if (is<StyleOriginatedAnimation>(animation)) {
if (auto* defaultKeyframeTimingFunction = downcast<StyleOriginatedAnimation>(*animation).backingAnimation().timingFunction())
if (auto* styleAnimation = dynamicDowncast<StyleOriginatedAnimation>(*animation)) {
if (auto* defaultKeyframeTimingFunction = styleAnimation->backingAnimation().timingFunction())
m_defaultKeyframeTimingFunction = defaultKeyframeTimingFunction;
}
}
Expand Down Expand Up @@ -385,12 +385,10 @@ void AcceleratedEffect::apply(Seconds currentTime, AcceleratedEffectValues& valu
auto* startKeyframe = interval.endpoints.first();
auto* endKeyframe = interval.endpoints.last();

ASSERT(is<AcceleratedEffect::Keyframe>(startKeyframe) && is<AcceleratedEffect::Keyframe>(endKeyframe));
auto startKeyframeValues = downcast<AcceleratedEffect::Keyframe>(startKeyframe)->values();
auto endKeyframeValues = downcast<AcceleratedEffect::Keyframe>(endKeyframe)->values();

KeyframeInterpolation::CompositionCallback composeProperty = [&](const KeyframeInterpolation::Keyframe& keyframe, CompositeOperation compositeOperation) {
ASSERT(is<AcceleratedEffect::Keyframe>(keyframe));
auto& acceleratedKeyframe = downcast<AcceleratedEffect::Keyframe>(keyframe);
BlendingContext context { 1, false, compositeOperation };
if (acceleratedKeyframe.offset() == startKeyframe->offset())
Expand Down Expand Up @@ -507,24 +505,23 @@ const KeyframeInterpolation::Keyframe& AcceleratedEffect::keyframeAtIndex(size_t

const TimingFunction* AcceleratedEffect::timingFunctionForKeyframe(const KeyframeInterpolation::Keyframe& keyframe) const
{
if (!is<Keyframe>(keyframe)) {
ASSERT_NOT_REACHED();
auto* acceleratedEffectKeyframe = dynamicDowncast<Keyframe>(keyframe);
ASSERT(acceleratedEffectKeyframe);
if (!acceleratedEffectKeyframe)
return nullptr;
}

auto& acceleratedEffectKeyframe = downcast<Keyframe>(keyframe);
if (m_animationType == WebAnimationType::CSSAnimation || m_animationType == WebAnimationType::CSSTransition) {
// If we're dealing with a CSS Animation, the timing function may be specified on the keyframe.
if (m_animationType == WebAnimationType::CSSAnimation) {
if (auto& timingFunction = acceleratedEffectKeyframe.timingFunction())
if (auto& timingFunction = acceleratedEffectKeyframe->timingFunction())
return timingFunction.get();
}

// Failing that, or for a CSS Transition, the timing function is the default timing function.
return m_defaultKeyframeTimingFunction.get();
}

return acceleratedEffectKeyframe.timingFunction().get();
return acceleratedEffectKeyframe->timingFunction().get();
}

bool AcceleratedEffect::isPropertyAdditiveOrCumulative(KeyframeInterpolation::Property property) const
Expand Down
65 changes: 27 additions & 38 deletions Source/WebCore/platform/animation/TimingFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ TextStream& operator<<(TextStream& ts, const TimingFunction& timingFunction)
{
switch (timingFunction.type()) {
case TimingFunction::Type::LinearFunction: {
auto& function = downcast<LinearTimingFunction>(timingFunction);
auto& function = uncheckedDowncast<LinearTimingFunction>(timingFunction);
ts << "linear(";
for (size_t i = 0; i < function.points().size(); ++i) {
if (i)
Expand All @@ -55,12 +55,12 @@ TextStream& operator<<(TextStream& ts, const TimingFunction& timingFunction)
break;
}
case TimingFunction::Type::CubicBezierFunction: {
auto& function = downcast<CubicBezierTimingFunction>(timingFunction);
auto& function = uncheckedDowncast<CubicBezierTimingFunction>(timingFunction);
ts << "cubic-bezier(" << function.x1() << ", " << function.y1() << ", " << function.x2() << ", " << function.y2() << ")";
break;
}
case TimingFunction::Type::StepsFunction: {
auto& function = downcast<StepsTimingFunction>(timingFunction);
auto& function = uncheckedDowncast<StepsTimingFunction>(timingFunction);
ts << "steps(" << function.numberOfSteps();
if (auto stepPosition = function.stepPosition()) {
ts << ", ";
Expand Down Expand Up @@ -94,7 +94,7 @@ TextStream& operator<<(TextStream& ts, const TimingFunction& timingFunction)
break;
}
case TimingFunction::Type::SpringFunction: {
auto& function = downcast<SpringTimingFunction>(timingFunction);
auto& function = uncheckedDowncast<SpringTimingFunction>(timingFunction);
ts << "spring(" << function.mass() << " " << function.stiffness() << " " << function.damping() << " " << function.initialVelocity() << ")";
break;
}
Expand All @@ -106,7 +106,7 @@ double TimingFunction::transformProgress(double progress, double duration, bool
{
switch (type()) {
case Type::CubicBezierFunction: {
auto& function = downcast<CubicBezierTimingFunction>(*this);
auto& function = uncheckedDowncast<CubicBezierTimingFunction>(*this);
if (function.isLinear())
return progress;
// The epsilon value we pass to UnitBezier::solve given that the animation is going to run over |dur| seconds. The longer the
Expand All @@ -116,7 +116,7 @@ double TimingFunction::transformProgress(double progress, double duration, bool
}
case Type::StepsFunction: {
// https://drafts.csswg.org/css-easing-1/#step-timing-functions
auto& function = downcast<StepsTimingFunction>(*this);
auto& function = uncheckedDowncast<StepsTimingFunction>(*this);
auto steps = function.numberOfSteps();
auto stepPosition = function.stepPosition();
// 1. Calculate the current step as floor(input progress value × steps).
Expand Down Expand Up @@ -145,11 +145,11 @@ double TimingFunction::transformProgress(double progress, double duration, bool
return currentStep / steps;
}
case Type::SpringFunction: {
auto& function = downcast<SpringTimingFunction>(*this);
auto& function = uncheckedDowncast<SpringTimingFunction>(*this);
return SpringSolver(function.mass(), function.stiffness(), function.damping(), function.initialVelocity()).solve(progress * duration);
}
case Type::LinearFunction: {
auto& function = downcast<LinearTimingFunction>(*this);
auto& function = uncheckedDowncast<LinearTimingFunction>(*this);

auto& points = function.points();
if (points.size() < 2)
Expand Down Expand Up @@ -208,51 +208,40 @@ RefPtr<TimingFunction> TimingFunction::createFromCSSValue(const CSSValue& value)
}
}

if (is<CSSLinearTimingFunctionValue>(value)) {
auto& linearTimingFunction = downcast<CSSLinearTimingFunctionValue>(value);
return LinearTimingFunction::create(linearTimingFunction.points());
}
if (is<CSSCubicBezierTimingFunctionValue>(value)) {
auto& cubicTimingFunction = downcast<CSSCubicBezierTimingFunctionValue>(value);
return CubicBezierTimingFunction::create(CubicBezierTimingFunction::TimingFunctionPreset::Custom, cubicTimingFunction.x1(), cubicTimingFunction.y1(), cubicTimingFunction.x2(), cubicTimingFunction.y2());
}
if (is<CSSStepsTimingFunctionValue>(value)) {
auto& stepsTimingFunction = downcast<CSSStepsTimingFunctionValue>(value);
return StepsTimingFunction::create(stepsTimingFunction.numberOfSteps(), stepsTimingFunction.stepPosition());
}
if (is<CSSSpringTimingFunctionValue>(value)) {
auto& springTimingFunction = downcast<CSSSpringTimingFunctionValue>(value);
return SpringTimingFunction::create(springTimingFunction.mass(), springTimingFunction.stiffness(), springTimingFunction.damping(), springTimingFunction.initialVelocity());
}
if (auto* linearTimingFunction = dynamicDowncast<CSSLinearTimingFunctionValue>(value))
return LinearTimingFunction::create(linearTimingFunction->points());
if (auto* cubicTimingFunction = dynamicDowncast<CSSCubicBezierTimingFunctionValue>(value))
return CubicBezierTimingFunction::create(CubicBezierTimingFunction::TimingFunctionPreset::Custom, cubicTimingFunction->x1(), cubicTimingFunction->y1(), cubicTimingFunction->x2(), cubicTimingFunction->y2());
if (auto* stepsTimingFunction = dynamicDowncast<CSSStepsTimingFunctionValue>(value))
return StepsTimingFunction::create(stepsTimingFunction->numberOfSteps(), stepsTimingFunction->stepPosition());
if (auto* springTimingFunction = dynamicDowncast<CSSSpringTimingFunctionValue>(value))
return SpringTimingFunction::create(springTimingFunction->mass(), springTimingFunction->stiffness(), springTimingFunction->damping(), springTimingFunction->initialVelocity());

return nullptr;
}

String TimingFunction::cssText() const
{
if (type() == Type::LinearFunction) {
auto& function = downcast<LinearTimingFunction>(*this);
if (function.points().isEmpty())
if (auto* function = dynamicDowncast<LinearTimingFunction>(*this)) {
if (function->points().isEmpty())
return "linear"_s;
}

if (type() == Type::CubicBezierFunction) {
auto& function = downcast<CubicBezierTimingFunction>(*this);
if (function.x1() == 0.25 && function.y1() == 0.1 && function.x2() == 0.25 && function.y2() == 1.0)
if (auto* function = dynamicDowncast<CubicBezierTimingFunction>(*this)) {
if (function->x1() == 0.25 && function->y1() == 0.1 && function->x2() == 0.25 && function->y2() == 1.0)
return "ease"_s;
if (function.x1() == 0.42 && !function.y1() && function.x2() == 1.0 && function.y2() == 1.0)
if (function->x1() == 0.42 && !function->y1() && function->x2() == 1.0 && function->y2() == 1.0)
return "ease-in"_s;
if (!function.x1() && !function.y1() && function.x2() == 0.58 && function.y2() == 1.0)
if (!function->x1() && !function->y1() && function->x2() == 0.58 && function->y2() == 1.0)
return "ease-out"_s;
if (function.x1() == 0.42 && !function.y1() && function.x2() == 0.58 && function.y2() == 1.0)
if (function->x1() == 0.42 && !function->y1() && function->x2() == 0.58 && function->y2() == 1.0)
return "ease-in-out"_s;
return makeString("cubic-bezier(", function.x1(), ", ", function.y1(), ", ", function.x2(), ", ", function.y2(), ')');
return makeString("cubic-bezier(", function->x1(), ", ", function->y1(), ", ", function->x2(), ", ", function->y2(), ')');
}

if (type() == Type::StepsFunction) {
auto& function = downcast<StepsTimingFunction>(*this);
if (function.stepPosition() == StepsTimingFunction::StepPosition::JumpEnd || function.stepPosition() == StepsTimingFunction::StepPosition::End)
return makeString("steps(", function.numberOfSteps(), ')');
if (auto* function = dynamicDowncast<StepsTimingFunction>(*this)) {
if (function->stepPosition() == StepsTimingFunction::StepPosition::JumpEnd || function->stepPosition() == StepsTimingFunction::StepPosition::End)
return makeString("steps(", function->numberOfSteps(), ')');
}

TextStream stream;
Expand Down
33 changes: 12 additions & 21 deletions Source/WebCore/platform/animation/TimingFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,8 @@ class LinearTimingFunction final : public TimingFunction {

bool operator==(const TimingFunction& other) const final
{
if (!is<LinearTimingFunction>(other))
return false;
auto& otherLinear = downcast<LinearTimingFunction>(other);
return m_points == otherLinear.m_points;
auto* otherLinear = dynamicDowncast<LinearTimingFunction>(other);
return otherLinear && m_points == otherLinear->m_points;
}

const Vector<Point>& points() const { return m_points; }
Expand Down Expand Up @@ -146,14 +144,12 @@ class CubicBezierTimingFunction final : public TimingFunction {

bool operator==(const TimingFunction& other) const final
{
if (!is<CubicBezierTimingFunction>(other))
return false;
auto& otherCubic = downcast<CubicBezierTimingFunction>(other);
if (m_timingFunctionPreset != otherCubic.m_timingFunctionPreset)
auto* otherCubic = dynamicDowncast<CubicBezierTimingFunction>(other);
if (!otherCubic || m_timingFunctionPreset != otherCubic->m_timingFunctionPreset)
return false;
if (m_timingFunctionPreset != TimingFunctionPreset::Custom)
return true;
return m_x1 == otherCubic.m_x1 && m_y1 == otherCubic.m_y1 && m_x2 == otherCubic.m_x2 && m_y2 == otherCubic.m_y2;
return m_x1 == otherCubic->m_x1 && m_y1 == otherCubic->m_y1 && m_x2 == otherCubic->m_x2 && m_y2 == otherCubic->m_y2;
}

double x1() const { return m_x1; }
Expand Down Expand Up @@ -225,20 +221,17 @@ class StepsTimingFunction final : public TimingFunction {

bool operator==(const TimingFunction& other) const final
{
if (!is<StepsTimingFunction>(other))
auto* otherSteps = dynamicDowncast<StepsTimingFunction>(other);
if (!otherSteps || m_steps != otherSteps->m_steps)
return false;
auto& otherSteps = downcast<StepsTimingFunction>(other);

if (m_steps != otherSteps.m_steps)
return false;

if (m_stepPosition == otherSteps.m_stepPosition)
if (m_stepPosition == otherSteps->m_stepPosition)
return true;

if (!m_stepPosition && *otherSteps.m_stepPosition == StepPosition::End)
if (!m_stepPosition && *otherSteps->m_stepPosition == StepPosition::End)
return true;

if (!otherSteps.m_stepPosition && *m_stepPosition == StepPosition::End)
if (!otherSteps->m_stepPosition && *m_stepPosition == StepPosition::End)
return true;

return false;
Expand Down Expand Up @@ -281,10 +274,8 @@ class SpringTimingFunction final : public TimingFunction {

bool operator==(const TimingFunction& other) const final
{
if (!is<SpringTimingFunction>(other))
return false;
auto& otherSpring = downcast<SpringTimingFunction>(other);
return m_mass == otherSpring.m_mass && m_stiffness == otherSpring.m_stiffness && m_damping == otherSpring.m_damping && m_initialVelocity == otherSpring.m_initialVelocity;
auto* otherSpring = dynamicDowncast<SpringTimingFunction>(other);
return otherSpring && m_mass == otherSpring->m_mass && m_stiffness == otherSpring->m_stiffness && m_damping == otherSpring->m_damping && m_initialVelocity == otherSpring->m_initialVelocity;
}

double mass() const { return m_mass; }
Expand Down

0 comments on commit a057d5d

Please sign in to comment.