起因还是上次那个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里的流程比较费劲。有时间我再补充这篇文章里动画流程相关。
未完待续····