Beispiel #1
0
void
Animation::Tick()
{
    // Finish pending if we have a pending ready time, but only if we also
    // have an active timeline.
    if (mPendingState != PendingState::NotPending &&
            !mPendingReadyTime.IsNull() &&
            mTimeline &&
            !mTimeline->GetCurrentTime().IsNull()) {
        // Even though mPendingReadyTime is initialized using TimeStamp::Now()
        // during the *previous* tick of the refresh driver, it can still be
        // ahead of the *current* timeline time when we are using the
        // vsync timer so we need to clamp it to the timeline time.
        mPendingReadyTime.SetValue(std::min(mTimeline->GetCurrentTime().Value(),
                                            mPendingReadyTime.Value()));
        FinishPendingAt(mPendingReadyTime.Value());
        mPendingReadyTime.SetNull();
    }

    if (IsPossiblyOrphanedPendingAnimation()) {
        MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTime().IsNull(),
                   "Orphaned pending animtaions should have an active timeline");
        FinishPendingAt(mTimeline->GetCurrentTime().Value());
    }

    UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);

    // FIXME: Detect the no-change case and don't request a restyle at all
    // FIXME: Detect changes to IsPlaying() state and request RestyleType::Layer
    //        so that layers get updated immediately
    AnimationCollection* collection = GetCollection();
    if (collection) {
        collection->RequestRestyle(CanThrottle() ?
                                   AnimationCollection::RestyleType::Throttled :
                                   AnimationCollection::RestyleType::Standard);
    }
}
/* static */ void
EffectCompositor::UpdateCascadeResults(EffectSet& aEffectSet,
                                       Element* aElement,
                                       nsCSSPseudoElements::Type aPseudoType,
                                       nsStyleContext* aStyleContext)
{
  MOZ_ASSERT(EffectSet::GetEffectSet(aElement, aPseudoType) == &aEffectSet,
             "Effect set should correspond to the specified (pseudo-)element");
  if (aEffectSet.IsEmpty()) {
    aEffectSet.MarkCascadeUpdated();
    return;
  }

  // Get a list of effects sorted by composite order.
  nsTArray<KeyframeEffectReadOnly*> sortedEffectList;
  for (KeyframeEffectReadOnly* effect : aEffectSet) {
    sortedEffectList.AppendElement(effect);
  }
  sortedEffectList.Sort(EffectCompositeOrderComparator());

  // Get properties that override the *animations* level of the cascade.
  //
  // We only do this for properties that we can animate on the compositor
  // since we will apply other properties on the main thread where the usual
  // cascade applies.
  nsCSSPropertySet overriddenProperties;
  if (aStyleContext) {
    GetOverriddenProperties(aStyleContext, aEffectSet, overriddenProperties);
  }

  bool changed = false;
  nsCSSPropertySet animatedProperties;

  // Iterate from highest to lowest composite order.
  for (KeyframeEffectReadOnly* effect : Reversed(sortedEffectList)) {
    MOZ_ASSERT(effect->GetAnimation(),
               "Effects on a target element should have an Animation");
    bool inEffect = effect->IsInEffect();
    for (AnimationProperty& prop : effect->Properties()) {

      bool winsInCascade = !animatedProperties.HasProperty(prop.mProperty) &&
                           inEffect;

      // If this property wins in the cascade, add it to the set of animated
      // properties. We need to do this even if the property is overridden
      // (in which case we set winsInCascade to false below) since we don't
      // want to fire transitions on these properties.
      if (winsInCascade) {
        animatedProperties.AddProperty(prop.mProperty);
      }

      // For effects that will be applied to the animations level of the
      // cascade, we need to check that the property isn't being set by
      // something with higher priority in the cascade.
      //
      // We only do this, however, for properties that can be animated on
      // the compositor. For properties animated on the main thread the usual
      // cascade ensures these animations will be correctly overridden.
      if (winsInCascade &&
          effect->GetAnimation()->CascadeLevel() == CascadeLevel::Animations &&
          overriddenProperties.HasProperty(prop.mProperty)) {
        winsInCascade = false;
      }

      if (winsInCascade != prop.mWinsInCascade) {
        changed = true;
      }
      prop.mWinsInCascade = winsInCascade;
    }
  }

  aEffectSet.MarkCascadeUpdated();

  // If there is any change in the cascade result, update animations on
  // layers with the winning animations.
  nsPresContext* presContext = GetPresContext(aElement);
  if (changed && presContext) {
    // We currently unconditionally update both animations and transitions
    // even if we could, for example, get away with only updating animations.
    // This is a temporary measure until we unify all animation style updating
    // under EffectCompositor.
    AnimationCollection* animations =
      presContext->AnimationManager()->GetAnimationCollection(aElement,
                                                              aPseudoType,
                                                              false);
                                                             /* don't create */
    if (animations) {
      animations->RequestRestyle(AnimationCollection::RestyleType::Layer);
    }

    AnimationCollection* transitions =
      presContext->TransitionManager()->GetAnimationCollection(aElement,
                                                               aPseudoType,
                                                               false);
                                                             /* don't create */
    if (transitions) {
      transitions->RequestRestyle(AnimationCollection::RestyleType::Layer);
    }
  }
}