继续修复css3动画一处小bug

2019-02-20 14:38:39 浏览数 (1)

起因还是上次那个wke3d-cube-loading动画。在启动后如果鼠标不hover上去,动画居然不会动。

借此机会学习了下css3在blink里的部分逻辑。

首先需要确定下css3是怎么设置层的transform的。下个GraphicsLayer::setTransform的断点,可以看到:

content::WebPageImpl::setNeedsCommitAndNotLayout cc_blink::WebLayerImpl::setNeedsCommit cc_blink::WebLayerImpl::setTransform blink::GraphicsLayer::setTransform blink::CompositedDeprecatedPaintLayerMapping::updateTransform blink::CompositedDeprecatedPaintLayerMapping::updateGraphicsLayerGeometry blink::GraphicsLayerUpdater::updateRecursive(blink::DeprecatedPaintLayer  blink::GraphicsLayerUpdater::updateRecursive(blink::DeprecatedPaintLayer  blink::GraphicsLayerUpdater::updateRecursive(blink::DeprecatedPaintLayer  blink::GraphicsLayerUpdater::updateRecursive(blink::DeprecatedPaintLayer  blink::GraphicsLayerUpdater::update blink::DeprecatedPaintLayerCompositor::updateIfNeeded blink::DeprecatedPaintLayerCompositor::updateIfNeededRecursive blink::FrameView::updateAllLifecyclePhasesInternal blink::PageAnimator::updateLayoutAndStyleForPainting blink::PageWidgetDelegate::layout

看这组堆栈,原来是每镇layout的时候,更新所有层的transform。

具体就是在CompositedDeprecatedPaintLayerMapping::updateTransform里调用style.applyTransform来设置的。

这个style又是在哪被设置的呢,原来是在这里:

ComputedStyle::setTransform AnimatedStyleBuilder::applyProperty LegacyStyleInterpolation::apply DeferredLegacyStyleInterpolation::apply StyleResolver::applyAnimatedProperties<1> StyleResolver::applyAnimatedProperties StyleResolver::styleForElement Element::originalStyleForLayoutObject Element::styleForLayoutObject Element::recalcOwnStyle(blink::StyleRecalc Element::recalcStyle ContainerNode::recalcChildStyle(blink::Sty Element::recalcStyle(blink::StyleRecalcCha ContainerNode::recalcChildStyle(blink::Sty Element::recalcStyle(blink::StyleRecalcCha ContainerNode::recalcChildStyle(blink::Sty Element::recalcStyle(blink::StyleRecalcCha Document::updateStyle(blink::StyleRecalcCh Document::updateLayoutTree(blink::StyleRec Document::updateLayoutTreeIfNeeded() 行 43 FrameView::updateStyleAndLayoutIfNeededRec FrameView::updateAllLifecyclePhasesInterna FrameView::updateAllLifecyclePhases() 行 2 PageAnimator::updateLayoutAndStyleForPaint PageWidgetDelegate::layout(blink::Page & p WebViewImpl::layout() 行 1913 C

原来是通过StyleResolver::styleForElement这个地方来搞的。StyleResolver::styleForElement这个函数很重要,是所有样式对元素进行更新时候都会调用的。

仔细看这个DeferredLegacyStyleInterpolation::apply,这玩意不但会导致设置transform,还会:

libcef.dll!blink::AnimatableTransform::AnimatableTransform libcef.dll!blink::AnimatableTransform::create libcef.dll!blink::AnimatableTransform::interpolateTo libcef.dll!blink::AnimatableValue::interpolate libcef.dll!blink::InterpolableAnimatableValue::interpolate libcef.dll!blink::Interpolation::interpolate libcef.dll!blink::DeferredLegacyStyleInterpolation::apply

创建插值的动画transform。

代码语言:javascript复制
>	libcef.dll!blink::AnimationEffect::updateInheritedTime(double inheritedTime, blink::TimingUpdateReason reason) 行 149	C  
 	libcef.dll!blink::InertEffect::sample(WTF::RawPtr<blink::HeapVector<blink::Member<blink::Interpolation>,0> > & result) 行 54	C  
 	libcef.dll!blink::AnimationStack::activeInterpolations
 	libcef.dll!blink::CSSAnimations::calculateAnimationActiveInterpolations
 	libcef.dll!blink::CSSAnimations::calculateUpdate
 	libcef.dll!blink::StyleResolver::applyAnimatedProperties
 	libcef.dll!blink::StyleResolver::styleForElement
 	libcef.dll!blink::Element::originalStyleForLayoutObject() 行 1625	C  
 	libcef.dll!blink::Element::styleForLayoutObject() 行 1601	C  

中间N字的过程就省略了,最后我发现

minichrome.exe!blink::WebViewImpl::scheduleAnimation() 行 4158 C minichrome.exe!blink::ChromeClientImpl::scheduleAnimation() 行 488 C minichrome.exe!blink::ScrollableArea::scheduleAnimation() 行 499 C minichrome.exe!blink::AnimationTimeline::AnimationTimelineTiming::serviceOnNextFrame() 行 198 C minichrome.exe!blink::AnimationTimeline::scheduleNextService() 行 172 C minichrome.exe!blink::DocumentAnimations::updateCompositorAnimations(blink::Document & document) 行 99 C minichrome.exe!blink::DeprecatedPaintLayerCompositor::updateIfNeededRecursive() 行 235 C minichrome.exe!blink::FrameView::updateAllLifecyclePhasesInternal() 行 2481 C minichrome.exe!blink::FrameView::updateAllLifecyclePhases() 行 2452 C minichrome.exe!blink::PageAnimator::updateLayoutAndStyleForPainting(blink::LocalFrame * rootFrame) 行 98 C minichrome.exe!blink::PageWidgetDelegate::layout(blink::Page & page, blink::LocalFrame & root) 行 67 C minichrome.exe!blink::WebViewImpl::layout() 行 1913 C

重点是这个函数:

代码语言:javascript复制
void AnimationTimeline::scheduleNextService()
{
    ASSERT(m_outdatedAnimationCount == 0);

    double timeToNextEffect = std::numeric_limits<double>::infinity();
    for (const auto& animation : m_animationsNeedingUpdate) {
        timeToNextEffect = std::min(timeToNextEffect, animation->timeToEffectChange());
    }

    if (timeToNextEffect < s_minimumDelay) {
        m_timing->serviceOnNextFrame();
    } else if (timeToNextEffect != std::numeric_limits<double>::infinity()) {
        m_timing->wakeAfter(timeToNextEffect - s_minimumDelay);
    }
}

在layout的过程中,会检查AnimationTimeline,这里面包含了所有正在做动画的列表。如果有的话,就

去通知外部要么马上调度(

代码语言:javascript复制
 m_timing->serviceOnNextFrame();

),要么定时唤醒(

代码语言:javascript复制
m_timing->wakeAfter

然而通过log,我发现调用

代码语言:javascript复制
 m_timing->serviceOnNextFrame();

后并没有马上调度。仔细一看,我外层代码写的有问题:

代码语言:javascript复制
if (m_needsLayout) {
     WebBeginFrameArgs frameArgs(lastFrameTimeMonotonic, 0, lastFrameTimeMonotonic - m_lastFrameTimeMonotonic);
     m_webViewImpl->beginFrame(frameArgs);
     m_webViewImpl->layout();
代码语言:javascript复制
	  m_needsLayout = false;
代码语言:javascript复制
}

这个

代码语言:javascript复制
m_needsLayout 

位置不对,不应该在layout后面。因为layout过程中由于上述讨论,会再次设置m_needsLayout = true;而执行完layout后,m_needsLayout = false;会冲掉。导致失去一次调度的机会。

问题的解决其实很简单,但要调这坨css3动画在blink里的流程比较费劲。有时间我再补充这篇文章里动画流程相关。

未完待续····

0 人点赞