Changeset 251543 in webkit
- Timestamp:
- Oct 24, 2019 9:35:08 AM (4 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r251542 r251543 1 2019-10-24 Antoine Quint <graouts@apple.com> 2 3 [Web Animations] Only process CSS properties affected by a given CSS transition 4 https://bugs.webkit.org/show_bug.cgi?id=203238 5 6 Reviewed by Simon Fraser. 7 8 When the "transition" property, or one of its longhands, would change we would iterate over every known CSS property to identify whether the before and after 9 styles showed reasons to create, modify or cancel a backing CSSTransition object. However, we only need to do this in the case where "transition-property" is 10 "all", ie. where the Animation object has its animationMode() set to Animation::AnimateAll. In all other cases, we only need to iterate over the CSS properties 11 specified by "transition-property". 12 13 We now compile a list of CSS properties to iterate over by looking at all properties listed in the "transition-property" for the before and after styles. 14 15 * animation/AnimationTimeline.cpp: 16 (WebCore::compileTransitionPropertiesInStyle): 17 (WebCore::AnimationTimeline::updateCSSTransitionsForElementAndProperty): 18 (WebCore::AnimationTimeline::updateCSSTransitionsForElement): 19 * animation/AnimationTimeline.h: 20 1 21 2019-10-24 youenn fablet <youenn@apple.com> 2 22 -
trunk/Source/WebCore/animation/AnimationTimeline.cpp
r250626 r251543 350 350 } 351 351 352 static void compileTransitionPropertiesInStyle(const RenderStyle& style, HashSet<CSSPropertyID>& transitionProperties, bool& transitionPropertiesContainAll) 353 { 354 if (transitionPropertiesContainAll) 355 return; 356 357 auto* transitions = style.transitions(); 358 if (!transitions) 359 return; 360 361 for (size_t i = 0; i < transitions->size(); ++i) { 362 const auto& animation = transitions->animation(i); 363 auto mode = animation.animationMode(); 364 if (mode == Animation::AnimateSingleProperty) { 365 auto property = animation.property(); 366 if (isShorthandCSSProperty(property)) { 367 auto shorthand = shorthandForProperty(property); 368 for (size_t j = 0; j < shorthand.length(); ++j) 369 transitionProperties.add(shorthand.properties()[j]); 370 } else 371 transitionProperties.add(property); 372 } else if (mode == Animation::AnimateAll) { 373 transitionPropertiesContainAll = true; 374 return; 375 } 376 } 377 } 378 379 void AnimationTimeline::updateCSSTransitionsForElementAndProperty(Element& element, CSSPropertyID property, const RenderStyle& currentStyle, const RenderStyle& afterChangeStyle, AnimationTimeline::PropertyToTransitionMap& runningTransitionsByProperty, PropertyToTransitionMap& completedTransitionsByProperty, const MonotonicTime generationTime) 380 { 381 const Animation* matchingBackingAnimation = nullptr; 382 if (auto* transitions = afterChangeStyle.transitions()) { 383 for (size_t i = 0; i < transitions->size(); ++i) { 384 auto& backingAnimation = transitions->animation(i); 385 if (transitionMatchesProperty(backingAnimation, property)) 386 matchingBackingAnimation = &backingAnimation; 387 } 388 } 389 390 // https://drafts.csswg.org/css-transitions-1/#before-change-style 391 // Define the before-change style as the computed values of all properties on the element as of the previous style change event, except with 392 // any styles derived from declarative animations such as CSS Transitions, CSS Animations, and SMIL Animations updated to the current time. 393 auto existingAnimation = cssAnimationForElementAndProperty(element, property); 394 const auto& beforeChangeStyle = existingAnimation ? downcast<CSSAnimation>(existingAnimation.get())->unanimatedStyle() : currentStyle; 395 396 if (!runningTransitionsByProperty.contains(property) 397 && !CSSPropertyAnimation::propertiesEqual(property, &beforeChangeStyle, &afterChangeStyle) 398 && CSSPropertyAnimation::canPropertyBeInterpolated(property, &beforeChangeStyle, &afterChangeStyle) 399 && !propertyInStyleMatchesValueForTransitionInMap(property, afterChangeStyle, completedTransitionsByProperty) 400 && matchingBackingAnimation && transitionCombinedDuration(matchingBackingAnimation) > 0) { 401 // 1. If all of the following are true: 402 // - the element does not have a running transition for the property, 403 // - the before-change style is different from and can be interpolated with the after-change style for that property, 404 // - the element does not have a completed transition for the property or the end value of the completed transition is different from the after-change style for the property, 405 // - there is a matching transition-property value, and 406 // - the combined duration is greater than 0s, 407 408 // then implementations must remove the completed transition (if present) from the set of completed transitions 409 completedTransitionsByProperty.remove(property); 410 411 // and start a transition whose: 412 // - start time is the time of the style change event plus the matching transition delay, 413 // - end time is the start time plus the matching transition duration, 414 // - start value is the value of the transitioning property in the before-change style, 415 // - end value is the value of the transitioning property in the after-change style, 416 // - reversing-adjusted start value is the same as the start value, and 417 // - reversing shortening factor is 1. 418 auto delay = Seconds(matchingBackingAnimation->delay()); 419 auto duration = Seconds(matchingBackingAnimation->duration()); 420 auto& reversingAdjustedStartStyle = beforeChangeStyle; 421 auto reversingShorteningFactor = 1; 422 runningTransitionsByProperty.set(property, CSSTransition::create(element, property, generationTime, *matchingBackingAnimation, &beforeChangeStyle, afterChangeStyle, delay, duration, reversingAdjustedStartStyle, reversingShorteningFactor)); 423 } else if (completedTransitionsByProperty.contains(property) && !propertyInStyleMatchesValueForTransitionInMap(property, afterChangeStyle, completedTransitionsByProperty)) { 424 // 2. Otherwise, if the element has a completed transition for the property and the end value of the completed transition is different from 425 // the after-change style for the property, then implementations must remove the completed transition from the set of completed transitions. 426 completedTransitionsByProperty.remove(property); 427 } 428 429 bool hasRunningTransition = runningTransitionsByProperty.contains(property); 430 if ((hasRunningTransition || completedTransitionsByProperty.contains(property)) && !matchingBackingAnimation) { 431 // 3. If the element has a running transition or completed transition for the property, and there is not a matching transition-property 432 // value, then implementations must cancel the running transition or remove the completed transition from the set of completed transitions. 433 if (hasRunningTransition) 434 runningTransitionsByProperty.take(property)->cancel(); 435 else 436 completedTransitionsByProperty.remove(property); 437 } 438 439 if (matchingBackingAnimation && runningTransitionsByProperty.contains(property) && !propertyInStyleMatchesValueForTransitionInMap(property, afterChangeStyle, runningTransitionsByProperty)) { 440 auto previouslyRunningTransition = runningTransitionsByProperty.take(property); 441 auto& previouslyRunningTransitionCurrentStyle = previouslyRunningTransition->currentStyle(); 442 // 4. If the element has a running transition for the property, there is a matching transition-property value, and the end value of the running 443 // transition is not equal to the value of the property in the after-change style, then: 444 if (CSSPropertyAnimation::propertiesEqual(property, &previouslyRunningTransitionCurrentStyle, &afterChangeStyle) || !CSSPropertyAnimation::canPropertyBeInterpolated(property, ¤tStyle, &afterChangeStyle)) { 445 // 1. If the current value of the property in the running transition is equal to the value of the property in the after-change style, 446 // or if these two values cannot be interpolated, then implementations must cancel the running transition. 447 cancelDeclarativeAnimation(*previouslyRunningTransition); 448 } else if (transitionCombinedDuration(matchingBackingAnimation) <= 0.0 || !CSSPropertyAnimation::canPropertyBeInterpolated(property, &previouslyRunningTransitionCurrentStyle, &afterChangeStyle)) { 449 // 2. Otherwise, if the combined duration is less than or equal to 0s, or if the current value of the property in the running transition 450 // cannot be interpolated with the value of the property in the after-change style, then implementations must cancel the running transition. 451 cancelDeclarativeAnimation(*previouslyRunningTransition); 452 } else if (CSSPropertyAnimation::propertiesEqual(property, &previouslyRunningTransition->reversingAdjustedStartStyle(), &afterChangeStyle)) { 453 // 3. Otherwise, if the reversing-adjusted start value of the running transition is the same as the value of the property in the after-change 454 // style (see the section on reversing of transitions for why these case exists), implementations must cancel the running transition 455 cancelDeclarativeAnimation(*previouslyRunningTransition); 456 457 // and start a new transition whose: 458 // - reversing-adjusted start value is the end value of the running transition, 459 // - reversing shortening factor is the absolute value, clamped to the range [0, 1], of the sum of: 460 // 1. the output of the timing function of the old transition at the time of the style change event, times the reversing shortening factor of the old transition 461 // 2. 1 minus the reversing shortening factor of the old transition. 462 // - start time is the time of the style change event plus: 463 // 1. if the matching transition delay is nonnegative, the matching transition delay, or 464 // 2. if the matching transition delay is negative, the product of the new transition’s reversing shortening factor and the matching transition delay, 465 // - end time is the start time plus the product of the matching transition duration and the new transition’s reversing shortening factor, 466 // - start value is the current value of the property in the running transition, 467 // - end value is the value of the property in the after-change style 468 auto& reversingAdjustedStartStyle = previouslyRunningTransition->targetStyle(); 469 double transformedProgress = 1; 470 if (auto* effect = previouslyRunningTransition->effect()) { 471 if (auto computedTimingProgress = effect->getComputedTiming().progress) 472 transformedProgress = *computedTimingProgress; 473 } 474 auto reversingShorteningFactor = std::max(std::min(((transformedProgress * previouslyRunningTransition->reversingShorteningFactor()) + (1 - previouslyRunningTransition->reversingShorteningFactor())), 1.0), 0.0); 475 auto delay = matchingBackingAnimation->delay() < 0 ? Seconds(matchingBackingAnimation->delay()) * reversingShorteningFactor : Seconds(matchingBackingAnimation->delay()); 476 auto duration = Seconds(matchingBackingAnimation->duration()) * reversingShorteningFactor; 477 478 ensureRunningTransitionsByProperty(element).set(property, CSSTransition::create(element, property, generationTime, *matchingBackingAnimation, &previouslyRunningTransitionCurrentStyle, afterChangeStyle, delay, duration, reversingAdjustedStartStyle, reversingShorteningFactor)); 479 } else { 480 // 4. Otherwise, implementations must cancel the running transition 481 cancelDeclarativeAnimation(*previouslyRunningTransition); 482 483 // and start a new transition whose: 484 // - start time is the time of the style change event plus the matching transition delay, 485 // - end time is the start time plus the matching transition duration, 486 // - start value is the current value of the property in the running transition, 487 // - end value is the value of the property in the after-change style, 488 // - reversing-adjusted start value is the same as the start value, and 489 // - reversing shortening factor is 1. 490 auto delay = Seconds(matchingBackingAnimation->delay()); 491 auto duration = Seconds(matchingBackingAnimation->duration()); 492 auto& reversingAdjustedStartStyle = currentStyle; 493 auto reversingShorteningFactor = 1; 494 ensureRunningTransitionsByProperty(element).set(property, CSSTransition::create(element, property, generationTime, *matchingBackingAnimation, &previouslyRunningTransitionCurrentStyle, afterChangeStyle, delay, duration, reversingAdjustedStartStyle, reversingShorteningFactor)); 495 } 496 } 497 } 498 352 499 void AnimationTimeline::updateCSSTransitionsForElement(Element& element, const RenderStyle& currentStyle, const RenderStyle& afterChangeStyle) 353 500 { … … 372 519 auto generationTime = MonotonicTime::now(); 373 520 374 auto numberOfProperties = CSSPropertyAnimation::getNumProperties(); 375 for (int propertyIndex = 0; propertyIndex < numberOfProperties; ++propertyIndex) { 376 Optional<bool> isShorthand; 377 auto property = CSSPropertyAnimation::getPropertyAtIndex(propertyIndex, isShorthand); 378 if (isShorthand && *isShorthand) 379 continue; 380 381 const Animation* matchingBackingAnimation = nullptr; 382 if (auto* transitions = afterChangeStyle.transitions()) { 383 for (size_t i = 0; i < transitions->size(); ++i) { 384 auto& backingAnimation = transitions->animation(i); 385 if (transitionMatchesProperty(backingAnimation, property)) 386 matchingBackingAnimation = &backingAnimation; 387 } 388 } 389 390 // https://drafts.csswg.org/css-transitions-1/#before-change-style 391 // Define the before-change style as the computed values of all properties on the element as of the previous style change event, except with 392 // any styles derived from declarative animations such as CSS Transitions, CSS Animations, and SMIL Animations updated to the current time. 393 auto existingAnimation = cssAnimationForElementAndProperty(element, property); 394 const auto& beforeChangeStyle = existingAnimation ? downcast<CSSAnimation>(existingAnimation.get())->unanimatedStyle() : currentStyle; 395 396 if (!runningTransitionsByProperty.contains(property) 397 && !CSSPropertyAnimation::propertiesEqual(property, &beforeChangeStyle, &afterChangeStyle) 398 && CSSPropertyAnimation::canPropertyBeInterpolated(property, &beforeChangeStyle, &afterChangeStyle) 399 && !propertyInStyleMatchesValueForTransitionInMap(property, afterChangeStyle, completedTransitionsByProperty) 400 && matchingBackingAnimation && transitionCombinedDuration(matchingBackingAnimation) > 0) { 401 // 1. If all of the following are true: 402 // - the element does not have a running transition for the property, 403 // - the before-change style is different from and can be interpolated with the after-change style for that property, 404 // - the element does not have a completed transition for the property or the end value of the completed transition is different from the after-change style for the property, 405 // - there is a matching transition-property value, and 406 // - the combined duration is greater than 0s, 407 408 // then implementations must remove the completed transition (if present) from the set of completed transitions 409 completedTransitionsByProperty.remove(property); 410 411 // and start a transition whose: 412 // - start time is the time of the style change event plus the matching transition delay, 413 // - end time is the start time plus the matching transition duration, 414 // - start value is the value of the transitioning property in the before-change style, 415 // - end value is the value of the transitioning property in the after-change style, 416 // - reversing-adjusted start value is the same as the start value, and 417 // - reversing shortening factor is 1. 418 auto delay = Seconds(matchingBackingAnimation->delay()); 419 auto duration = Seconds(matchingBackingAnimation->duration()); 420 auto& reversingAdjustedStartStyle = beforeChangeStyle; 421 auto reversingShorteningFactor = 1; 422 runningTransitionsByProperty.set(property, CSSTransition::create(element, property, generationTime, *matchingBackingAnimation, &beforeChangeStyle, afterChangeStyle, delay, duration, reversingAdjustedStartStyle, reversingShorteningFactor)); 423 } else if (completedTransitionsByProperty.contains(property) && !propertyInStyleMatchesValueForTransitionInMap(property, afterChangeStyle, completedTransitionsByProperty)) { 424 // 2. Otherwise, if the element has a completed transition for the property and the end value of the completed transition is different from 425 // the after-change style for the property, then implementations must remove the completed transition from the set of completed transitions. 426 completedTransitionsByProperty.remove(property); 427 } 428 429 bool hasRunningTransition = runningTransitionsByProperty.contains(property); 430 if ((hasRunningTransition || completedTransitionsByProperty.contains(property)) && !matchingBackingAnimation) { 431 // 3. If the element has a running transition or completed transition for the property, and there is not a matching transition-property 432 // value, then implementations must cancel the running transition or remove the completed transition from the set of completed transitions. 433 if (hasRunningTransition) 434 runningTransitionsByProperty.take(property)->cancel(); 435 else 436 completedTransitionsByProperty.remove(property); 437 } 438 439 if (matchingBackingAnimation && runningTransitionsByProperty.contains(property) && !propertyInStyleMatchesValueForTransitionInMap(property, afterChangeStyle, runningTransitionsByProperty)) { 440 auto previouslyRunningTransition = runningTransitionsByProperty.take(property); 441 auto& previouslyRunningTransitionCurrentStyle = previouslyRunningTransition->currentStyle(); 442 // 4. If the element has a running transition for the property, there is a matching transition-property value, and the end value of the running 443 // transition is not equal to the value of the property in the after-change style, then: 444 if (CSSPropertyAnimation::propertiesEqual(property, &previouslyRunningTransitionCurrentStyle, &afterChangeStyle) || !CSSPropertyAnimation::canPropertyBeInterpolated(property, ¤tStyle, &afterChangeStyle)) { 445 // 1. If the current value of the property in the running transition is equal to the value of the property in the after-change style, 446 // or if these two values cannot be interpolated, then implementations must cancel the running transition. 447 cancelDeclarativeAnimation(*previouslyRunningTransition); 448 } else if (transitionCombinedDuration(matchingBackingAnimation) <= 0.0 || !CSSPropertyAnimation::canPropertyBeInterpolated(property, &previouslyRunningTransitionCurrentStyle, &afterChangeStyle)) { 449 // 2. Otherwise, if the combined duration is less than or equal to 0s, or if the current value of the property in the running transition 450 // cannot be interpolated with the value of the property in the after-change style, then implementations must cancel the running transition. 451 cancelDeclarativeAnimation(*previouslyRunningTransition); 452 } else if (CSSPropertyAnimation::propertiesEqual(property, &previouslyRunningTransition->reversingAdjustedStartStyle(), &afterChangeStyle)) { 453 // 3. Otherwise, if the reversing-adjusted start value of the running transition is the same as the value of the property in the after-change 454 // style (see the section on reversing of transitions for why these case exists), implementations must cancel the running transition 455 cancelDeclarativeAnimation(*previouslyRunningTransition); 456 457 // and start a new transition whose: 458 // - reversing-adjusted start value is the end value of the running transition, 459 // - reversing shortening factor is the absolute value, clamped to the range [0, 1], of the sum of: 460 // 1. the output of the timing function of the old transition at the time of the style change event, times the reversing shortening factor of the old transition 461 // 2. 1 minus the reversing shortening factor of the old transition. 462 // - start time is the time of the style change event plus: 463 // 1. if the matching transition delay is nonnegative, the matching transition delay, or 464 // 2. if the matching transition delay is negative, the product of the new transition’s reversing shortening factor and the matching transition delay, 465 // - end time is the start time plus the product of the matching transition duration and the new transition’s reversing shortening factor, 466 // - start value is the current value of the property in the running transition, 467 // - end value is the value of the property in the after-change style 468 auto& reversingAdjustedStartStyle = previouslyRunningTransition->targetStyle(); 469 double transformedProgress = 1; 470 if (auto* effect = previouslyRunningTransition->effect()) { 471 if (auto computedTimingProgress = effect->getComputedTiming().progress) 472 transformedProgress = *computedTimingProgress; 473 } 474 auto reversingShorteningFactor = std::max(std::min(((transformedProgress * previouslyRunningTransition->reversingShorteningFactor()) + (1 - previouslyRunningTransition->reversingShorteningFactor())), 1.0), 0.0); 475 auto delay = matchingBackingAnimation->delay() < 0 ? Seconds(matchingBackingAnimation->delay()) * reversingShorteningFactor : Seconds(matchingBackingAnimation->delay()); 476 auto duration = Seconds(matchingBackingAnimation->duration()) * reversingShorteningFactor; 477 478 ensureRunningTransitionsByProperty(element).set(property, CSSTransition::create(element, property, generationTime, *matchingBackingAnimation, &previouslyRunningTransitionCurrentStyle, afterChangeStyle, delay, duration, reversingAdjustedStartStyle, reversingShorteningFactor)); 479 } else { 480 // 4. Otherwise, implementations must cancel the running transition 481 cancelDeclarativeAnimation(*previouslyRunningTransition); 482 483 // and start a new transition whose: 484 // - start time is the time of the style change event plus the matching transition delay, 485 // - end time is the start time plus the matching transition duration, 486 // - start value is the current value of the property in the running transition, 487 // - end value is the value of the property in the after-change style, 488 // - reversing-adjusted start value is the same as the start value, and 489 // - reversing shortening factor is 1. 490 auto delay = Seconds(matchingBackingAnimation->delay()); 491 auto duration = Seconds(matchingBackingAnimation->duration()); 492 auto& reversingAdjustedStartStyle = currentStyle; 493 auto reversingShorteningFactor = 1; 494 ensureRunningTransitionsByProperty(element).set(property, CSSTransition::create(element, property, generationTime, *matchingBackingAnimation, &previouslyRunningTransitionCurrentStyle, afterChangeStyle, delay, duration, reversingAdjustedStartStyle, reversingShorteningFactor)); 495 } 496 } 497 } 521 // First, let's compile the list of all CSS properties found in the current style and the after-change style. 522 bool transitionPropertiesContainAll = false; 523 HashSet<CSSPropertyID> transitionProperties; 524 compileTransitionPropertiesInStyle(currentStyle, transitionProperties, transitionPropertiesContainAll); 525 compileTransitionPropertiesInStyle(afterChangeStyle, transitionProperties, transitionPropertiesContainAll); 526 527 if (transitionPropertiesContainAll) { 528 auto numberOfProperties = CSSPropertyAnimation::getNumProperties(); 529 for (int propertyIndex = 0; propertyIndex < numberOfProperties; ++propertyIndex) { 530 Optional<bool> isShorthand; 531 auto property = CSSPropertyAnimation::getPropertyAtIndex(propertyIndex, isShorthand); 532 if (isShorthand && *isShorthand) 533 continue; 534 updateCSSTransitionsForElementAndProperty(element, property, currentStyle, afterChangeStyle, runningTransitionsByProperty, completedTransitionsByProperty, generationTime); 535 } 536 return; 537 } 538 539 for (auto property : transitionProperties) 540 updateCSSTransitionsForElementAndProperty(element, property, currentStyle, afterChangeStyle, runningTransitionsByProperty, completedTransitionsByProperty, generationTime); 498 541 } 499 542 -
trunk/Source/WebCore/animation/AnimationTimeline.h
r243263 r251543 85 85 RefPtr<WebAnimation> cssAnimationForElementAndProperty(Element&, CSSPropertyID); 86 86 PropertyToTransitionMap& ensureRunningTransitionsByProperty(Element&); 87 void updateCSSTransitionsForElementAndProperty(Element&, CSSPropertyID, const RenderStyle& currentStyle, const RenderStyle& afterChangeStyle, PropertyToTransitionMap&, PropertyToTransitionMap&, const MonotonicTime); 87 88 void cancelDeclarativeAnimation(DeclarativeAnimation&); 88 89
Note: See TracChangeset
for help on using the changeset viewer.