Пример #1
0
nsIStyleRule*
CommonAnimationManager::GetAnimationRule(mozilla::dom::Element* aElement,
                                         nsCSSPseudoElements::Type aPseudoType)
{
  MOZ_ASSERT(
    aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement ||
    aPseudoType == nsCSSPseudoElements::ePseudo_before ||
    aPseudoType == nsCSSPseudoElements::ePseudo_after,
    "forbidden pseudo type");

  if (!mPresContext->IsDynamic()) {
    // For print or print preview, ignore animations.
    return nullptr;
  }

  AnimationPlayerCollection* collection =
    GetAnimations(aElement, aPseudoType, false);
  if (!collection) {
    return nullptr;
  }

  RestyleManager* restyleManager = mPresContext->RestyleManager();
  if (restyleManager->SkipAnimationRules()) {
    return nullptr;
  }

  collection->EnsureStyleRuleFor(
    mPresContext->RefreshDriver()->MostRecentRefresh(),
    EnsureStyleRule_IsNotThrottled);

  return collection->mStyleRule;
}
Пример #2
0
void
CommonAnimationManager::AddStyleUpdatesTo(RestyleTracker& aTracker)
{
    TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh();

    PRCList* next = PR_LIST_HEAD(&mElementCollections);
    while (next != &mElementCollections) {
        AnimationPlayerCollection* collection =
            static_cast<AnimationPlayerCollection*>(next);
        next = PR_NEXT_LINK(next);

        if (!collection->mNeedsRefreshes) {
            continue;
        }

        collection->EnsureStyleRuleFor(now, EnsureStyleRule_IsNotThrottled);

        dom::Element* elementToRestyle = collection->GetElementToRestyle();
        if (elementToRestyle) {
            nsRestyleHint rshint = collection->IsForTransitions()
                                   ? eRestyle_CSSTransitions : eRestyle_CSSAnimations;
            aTracker.AddPendingRestyle(elementToRestyle, rshint, nsChangeHint(0));
        }
    }
}
Пример #3
0
void
AnimationPlayer::PostUpdate()
{
  AnimationPlayerCollection* collection = GetCollection();
  if (collection) {
    collection->NotifyPlayerUpdated();
  }
}
Пример #4
0
void
CommonAnimationManager::NotifyCollectionUpdated(AnimationPlayerCollection&
                                                  aCollection)
{
  MaybeStartObservingRefreshDriver();
  mPresContext->ClearLastStyleUpdateForAllAnimations();
  mPresContext->RestyleManager()->IncrementAnimationGeneration();
  aCollection.UpdateAnimationGeneration(mPresContext);
  aCollection.PostRestyleForAnimation(mPresContext);
}
Пример #5
0
void
CommonAnimationManager::NotifyCollectionUpdated(AnimationPlayerCollection&
        aCollection)
{
    CheckNeedsRefresh();
    mPresContext->ClearLastStyleUpdateForAllAnimations();
    mPresContext->RestyleManager()->IncrementAnimationGeneration();
    aCollection.UpdateAnimationGeneration(mPresContext);
    aCollection.PostRestyleForAnimation(mPresContext);
}
Пример #6
0
nsIStyleRule*
CommonAnimationManager::GetAnimationRule(mozilla::dom::Element* aElement,
                                         nsCSSPseudoElements::Type aPseudoType)
{
  MOZ_ASSERT(
    aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement ||
    aPseudoType == nsCSSPseudoElements::ePseudo_before ||
    aPseudoType == nsCSSPseudoElements::ePseudo_after,
    "forbidden pseudo type");

  if (!mPresContext->IsDynamic()) {
    // For print or print preview, ignore animations.
    return nullptr;
  }

  AnimationPlayerCollection* collection =
    GetAnimationPlayers(aElement, aPseudoType, false);
  if (!collection) {
    return nullptr;
  }

  RestyleManager* restyleManager = mPresContext->RestyleManager();
  if (restyleManager->SkipAnimationRules()) {
    // During the non-animation part of processing restyles, we don't
    // add the animation rule.

    if (collection->mStyleRule && restyleManager->PostAnimationRestyles()) {
      collection->PostRestyleForAnimation(mPresContext);
    }

    return nullptr;
  }

  // Animations should already be refreshed, but transitions may not be.
  // Note that this is temporary, we would like both animations and transitions
  // to both be refreshed by this point.
  if (IsAnimationManager()) {
    NS_WARN_IF_FALSE(!collection->mNeedsRefreshes ||
                     collection->mStyleRuleRefreshTime ==
                       mPresContext->RefreshDriver()->MostRecentRefresh(),
                     "should already have refreshed style rule");
  } else {
    // FIXME: Remove this assignment.  See bug 1061364.
    collection->mNeedsRefreshes = true;
    collection->EnsureStyleRuleFor(
      mPresContext->RefreshDriver()->MostRecentRefresh(),
      EnsureStyleRule_IsNotThrottled);
  }

  return collection->mStyleRule;
}
Пример #7
0
AnimationPlayerCollection*
CommonAnimationManager::GetAnimationsForCompositor(nsIContent* aContent,
                                                   nsIAtom* aElementProperty,
                                                   nsCSSProperty aProperty)
{
  if (!aContent->MayHaveAnimations())
    return nullptr;

  AnimationPlayerCollection* collection =
    static_cast<AnimationPlayerCollection*>(
      aContent->GetProperty(aElementProperty));
  if (!collection ||
      !collection->HasAnimationOfProperty(aProperty) ||
      !collection->CanPerformOnCompositorThread(
        AnimationPlayerCollection::CanAnimate_AllowPartial)) {
    return nullptr;
  }

  // This animation can be done on the compositor.
  return collection;
}
Пример #8
0
nsIStyleRule*
nsAnimationManager::GetAnimationRule(mozilla::dom::Element* aElement,
                                     nsCSSPseudoElements::Type aPseudoType)
{
  NS_ABORT_IF_FALSE(
    aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement ||
    aPseudoType == nsCSSPseudoElements::ePseudo_before ||
    aPseudoType == nsCSSPseudoElements::ePseudo_after,
    "forbidden pseudo type");

  if (!mPresContext->IsDynamic()) {
    // For print or print preview, ignore animations.
    return nullptr;
  }

  AnimationPlayerCollection* collection =
    GetAnimationPlayers(aElement, aPseudoType, false);
  if (!collection) {
    return nullptr;
  }

  RestyleManager* restyleManager = mPresContext->RestyleManager();
  if (restyleManager->SkipAnimationRules()) {
    // During the non-animation part of processing restyles, we don't
    // add the animation rule.

    if (collection->mStyleRule && restyleManager->PostAnimationRestyles()) {
      collection->PostRestyleForAnimation(mPresContext);
    }

    return nullptr;
  }

  NS_WARN_IF_FALSE(!collection->mNeedsRefreshes ||
                   collection->mStyleRuleRefreshTime ==
                     mPresContext->RefreshDriver()->MostRecentRefresh(),
                   "should already have refreshed style rule");

  return collection->mStyleRule;
}
void
nsAnimationManager::FlushAnimations(FlushFlags aFlags)
{
  // FIXME: check that there's at least one style rule that's not
  // in its "done" state, and if there isn't, remove ourselves from
  // the refresh driver (but leave the animations!).
  TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh();
  bool didThrottle = false;
  for (PRCList *l = PR_LIST_HEAD(&mElementCollections);
       l != &mElementCollections;
       l = PR_NEXT_LINK(l)) {
    AnimationPlayerCollection* collection =
      static_cast<AnimationPlayerCollection*>(l);

    nsAutoAnimationMutationBatch mb(collection->mElement);

    collection->Tick();
    bool canThrottleTick = aFlags == Can_Throttle &&
      collection->CanPerformOnCompositorThread(
        AnimationPlayerCollection::CanAnimateFlags(0)) &&
      collection->CanThrottleAnimation(now);

    nsRefPtr<css::AnimValuesStyleRule> oldStyleRule = collection->mStyleRule;
    UpdateStyleAndEvents(collection, now, canThrottleTick
                                          ? EnsureStyleRule_IsThrottled
                                          : EnsureStyleRule_IsNotThrottled);
    if (oldStyleRule != collection->mStyleRule) {
      collection->PostRestyleForAnimation(mPresContext);
    } else {
      didThrottle = true;
    }
  }

  if (didThrottle) {
    mPresContext->Document()->SetNeedStyleFlush();
  }

  DispatchEvents(); // may destroy us
}
Пример #10
0
nsIStyleRule*
nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext,
                                       mozilla::dom::Element* aElement)
{
  // FIXME (bug 960465): This test should go away.
  if (!mPresContext->RestyleManager()->IsProcessingAnimationStyleChange()) {
    if (!mPresContext->IsDynamic()) {
      // For print or print preview, ignore animations.
      return nullptr;
    }

    // Everything that causes our animation data to change triggers a
    // style change, which in turn triggers a non-animation restyle.
    // Likewise, when we initially construct frames, we're not in a
    // style change, but also not in an animation restyle.

    const nsStyleDisplay* disp = aStyleContext->StyleDisplay();
    AnimationPlayerCollection* collection =
      GetAnimationPlayers(aElement, aStyleContext->GetPseudoType(), false);
    if (!collection &&
        disp->mAnimationNameCount == 1 &&
        disp->mAnimations[0].GetName().IsEmpty()) {
      return nullptr;
    }

    // build the animations list
    dom::AnimationTimeline* timeline = aElement->OwnerDoc()->Timeline();
    AnimationPlayerPtrArray newPlayers;
    BuildAnimations(aStyleContext, aElement, timeline, newPlayers);

    if (newPlayers.IsEmpty()) {
      if (collection) {
        collection->Destroy();
      }
      return nullptr;
    }

    if (collection) {
      collection->mStyleRule = nullptr;
      collection->mStyleRuleRefreshTime = TimeStamp();
      collection->UpdateAnimationGeneration(mPresContext);

      // Copy over the start times and (if still paused) pause starts
      // for each animation (matching on name only) that was also in the
      // old list of animations.
      // This means that we honor dynamic changes, which isn't what the
      // spec says to do, but WebKit seems to honor at least some of
      // them.  See
      // http://lists.w3.org/Archives/Public/www-style/2011Apr/0079.html
      // In order to honor what the spec said, we'd copy more data over
      // (or potentially optimize BuildAnimations to avoid rebuilding it
      // in the first place).
      if (!collection->mPlayers.IsEmpty()) {

        for (size_t newIdx = newPlayers.Length(); newIdx-- != 0;) {
          AnimationPlayer* newPlayer = newPlayers[newIdx];

          // Find the matching animation with this name in the old list
          // of animations.  We iterate through both lists in a backwards
          // direction which means that if there are more animations in
          // the new list of animations with a given name than in the old
          // list, it will be the animations towards the of the beginning of
          // the list that do not match and are treated as new animations.
          nsRefPtr<CSSAnimationPlayer> oldPlayer;
          size_t oldIdx = collection->mPlayers.Length();
          while (oldIdx-- != 0) {
            CSSAnimationPlayer* a =
              collection->mPlayers[oldIdx]->AsCSSAnimationPlayer();
            MOZ_ASSERT(a, "All players in the CSS Animation collection should"
                          " be CSSAnimationPlayer objects");
            if (a->Name() == newPlayer->Name()) {
              oldPlayer = a;
              break;
            }
          }
          if (!oldPlayer) {
            continue;
          }

          // Update the old from the new so we can keep the original object
          // identity (and any expando properties attached to it).
          if (oldPlayer->GetSource() && newPlayer->GetSource()) {
            Animation* oldAnim = oldPlayer->GetSource();
            Animation* newAnim = newPlayer->GetSource();
            oldAnim->Timing() = newAnim->Timing();
            oldAnim->Properties() = newAnim->Properties();
          }

          // Reset compositor state so animation will be re-synchronized.
          oldPlayer->ClearIsRunningOnCompositor();

          // Handle changes in play state.
          // CSSAnimationPlayer takes care of override behavior so that,
          // for example, if the author has called pause(), that will
          // override the animation-play-state.
          // (We should check newPlayer->IsStylePaused() but that requires
          //  downcasting to CSSAnimationPlayer and we happen to know that
          //  newPlayer will only ever be paused by calling PauseFromStyle
          //  making IsPaused synonymous in this case.)
          if (!oldPlayer->IsStylePaused() && newPlayer->IsPaused()) {
            oldPlayer->PauseFromStyle();
          } else if (oldPlayer->IsStylePaused() && !newPlayer->IsPaused()) {
            oldPlayer->PlayFromStyle();
          }

          // Replace new animation with the (updated) old one and remove the
          // old one from the array so we don't try to match it any more.
          //
          // Although we're doing this while iterating this is safe because
          // we're not changing the length of newPlayers and we've finished
          // iterating over the list of old iterations.
          newPlayer = nullptr;
          newPlayers.ReplaceElementAt(newIdx, oldPlayer);
          collection->mPlayers.RemoveElementAt(oldIdx);
        }
      }
    } else {
      collection =
        GetAnimationPlayers(aElement, aStyleContext->GetPseudoType(), true);
    }
    collection->mPlayers.SwapElements(newPlayers);
    collection->mNeedsRefreshes = true;
    collection->Tick();

    TimeStamp refreshTime = mPresContext->RefreshDriver()->MostRecentRefresh();
    UpdateStyleAndEvents(collection, refreshTime,
                         EnsureStyleRule_IsNotThrottled);
    // We don't actually dispatch the mPendingEvents now.  We'll either
    // dispatch them the next time we get a refresh driver notification
    // or the next time somebody calls
    // nsPresShell::FlushPendingNotifications.
    if (!mPendingEvents.IsEmpty()) {
      mPresContext->Document()->SetNeedStyleFlush();
    }
  }

  return GetAnimationRule(aElement, aStyleContext->GetPseudoType());
}