dom/animation/EffectSet.cpp
author George Wright <george@mozilla.com>
Fri, 08 Apr 2016 13:33:27 -0400
changeset 317655 8d87452bfc44bf502e2a1a172db91f88e5284782
parent 309018 06bc3102b90004470fba71fcaff4ba7b437ebfd7
child 326188 d3c0af860e07e8bb805f591a4d85a25416d9cd85
permissions -rw-r--r--
Revert "Bug 1261416 - Rename firefox-plugin-container back to plugin-container to satisfy Flash's protected mode checks, and ensure that we launch the correct binary r=ted" because of widespread breakage due to whitelisted executable names in third parties This reverts commit 2d44e8ffaf63a32292f8e5b8fdd1485d0a462afc.

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "EffectSet.h"
#include "mozilla/dom/Element.h" // For Element
#include "mozilla/RestyleManagerHandle.h"
#include "mozilla/RestyleManagerHandleInlines.h"
#include "nsCSSPseudoElements.h" // For CSSPseudoElementType
#include "nsCycleCollectionNoteChild.h" // For CycleCollectionNoteChild
#include "nsPresContext.h"
#include "nsLayoutUtils.h"

namespace mozilla {

/* static */ void
EffectSet::PropertyDtor(void* aObject, nsIAtom* aPropertyName,
                        void* aPropertyValue, void* aData)
{
  EffectSet* effectSet = static_cast<EffectSet*>(aPropertyValue);

#ifdef DEBUG
  MOZ_ASSERT(!effectSet->mCalledPropertyDtor, "Should not call dtor twice");
  effectSet->mCalledPropertyDtor = true;
#endif

  delete effectSet;
}

void
EffectSet::Traverse(nsCycleCollectionTraversalCallback& aCallback)
{
  for (auto iter = mEffects.Iter(); !iter.Done(); iter.Next()) {
    CycleCollectionNoteChild(aCallback, iter.Get()->GetKey(),
                             "EffectSet::mEffects[]", aCallback.Flags());
  }
}

/* static */ EffectSet*
EffectSet::GetEffectSet(dom::Element* aElement,
                        CSSPseudoElementType aPseudoType)
{
  nsIAtom* propName = GetEffectSetPropertyAtom(aPseudoType);
  return static_cast<EffectSet*>(aElement->GetProperty(propName));
}

/* static */ EffectSet*
EffectSet::GetEffectSet(const nsIFrame* aFrame)
{
  nsIContent* content = aFrame->GetContent();
  if (!content) {
    return nullptr;
  }

  nsIAtom* propName;
  if (aFrame->IsGeneratedContentFrame()) {
    nsIFrame* parent = aFrame->GetParent();
    if (parent->IsGeneratedContentFrame()) {
      return nullptr;
    }
    nsIAtom* name = content->NodeInfo()->NameAtom();
    if (name == nsGkAtoms::mozgeneratedcontentbefore) {
      propName = nsGkAtoms::animationEffectsForBeforeProperty;
    } else if (name == nsGkAtoms::mozgeneratedcontentafter) {
      propName = nsGkAtoms::animationEffectsForAfterProperty;
    } else {
      return nullptr;
    }
    content = content->GetParent();
    if (!content) {
      return nullptr;
    }
  } else {
    if (nsLayoutUtils::GetStyleFrame(content) != aFrame) {
      // The effects associated with an element are for its primary frame.
      return nullptr;
    }
    propName = nsGkAtoms::animationEffectsProperty;
  }

  if (!content->MayHaveAnimations()) {
    return nullptr;
  }

  return static_cast<EffectSet*>(content->GetProperty(propName));
}

/* static */ EffectSet*
EffectSet::GetOrCreateEffectSet(dom::Element* aElement,
                                CSSPseudoElementType aPseudoType)
{
  EffectSet* effectSet = GetEffectSet(aElement, aPseudoType);
  if (effectSet) {
    return effectSet;
  }

  nsIAtom* propName = GetEffectSetPropertyAtom(aPseudoType);
  effectSet = new EffectSet();

  nsresult rv = aElement->SetProperty(propName, effectSet,
                                      &EffectSet::PropertyDtor, true);
  if (NS_FAILED(rv)) {
    NS_WARNING("SetProperty failed");
    // The set must be destroyed via PropertyDtor, otherwise
    // mCalledPropertyDtor assertion is triggered in destructor.
    EffectSet::PropertyDtor(aElement, propName, effectSet, nullptr);
    return nullptr;
  }

  aElement->SetMayHaveAnimations();

  return effectSet;
}

/* static */ void
EffectSet::DestroyEffectSet(dom::Element* aElement,
                            CSSPseudoElementType aPseudoType)
{
  nsIAtom* propName = GetEffectSetPropertyAtom(aPseudoType);
  EffectSet* effectSet =
    static_cast<EffectSet*>(aElement->GetProperty(propName));
  if (!effectSet) {
    return;
  }

  MOZ_ASSERT(!effectSet->IsBeingEnumerated(),
             "Should not destroy an effect set while it is being enumerated");
  effectSet = nullptr;

  aElement->DeleteProperty(propName);
}

void
EffectSet::UpdateAnimationGeneration(nsPresContext* aPresContext)
{
  MOZ_ASSERT(aPresContext->RestyleManager()->IsGecko(),
             "stylo: Servo-backed style system should not be using "
             "EffectSet");
  mAnimationGeneration =
    aPresContext->RestyleManager()->AsGecko()->GetAnimationGeneration();
}

/* static */ nsIAtom**
EffectSet::GetEffectSetPropertyAtoms()
{
  static nsIAtom* effectSetPropertyAtoms[] =
    {
      nsGkAtoms::animationEffectsProperty,
      nsGkAtoms::animationEffectsForBeforeProperty,
      nsGkAtoms::animationEffectsForAfterProperty,
      nullptr
    };

  return effectSetPropertyAtoms;
}

/* static */ nsIAtom*
EffectSet::GetEffectSetPropertyAtom(CSSPseudoElementType aPseudoType)
{
  switch (aPseudoType) {
    case CSSPseudoElementType::NotPseudo:
      return nsGkAtoms::animationEffectsProperty;

    case CSSPseudoElementType::before:
      return nsGkAtoms::animationEffectsForBeforeProperty;

    case CSSPseudoElementType::after:
      return nsGkAtoms::animationEffectsForAfterProperty;

    default:
      NS_NOTREACHED("Should not try to get animation effects for a pseudo "
                    "other that :before or :after");
      return nullptr;
  }
}

void
EffectSet::AddEffect(dom::KeyframeEffectReadOnly& aEffect)
{
  if (mEffects.Contains(&aEffect)) {
    return;
  }

  mEffects.PutEntry(&aEffect);
  MarkCascadeNeedsUpdate();
}

void
EffectSet::RemoveEffect(dom::KeyframeEffectReadOnly& aEffect)
{
  if (!mEffects.Contains(&aEffect)) {
    return;
  }

  mEffects.RemoveEntry(&aEffect);
  MarkCascadeNeedsUpdate();
}

} // namespace mozilla