tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TimelineManager.cpp (6372B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "TimelineManager.h"
      8 
      9 #include "mozilla/ElementAnimationData.h"
     10 #include "mozilla/dom/Element.h"
     11 #include "mozilla/dom/ScrollTimeline.h"
     12 #include "mozilla/dom/ViewTimeline.h"
     13 #include "nsPresContext.h"
     14 
     15 namespace mozilla {
     16 using dom::Element;
     17 using dom::ScrollTimeline;
     18 using dom::ViewTimeline;
     19 
     20 template <typename TimelineType>
     21 static void TryDestroyTimeline(Element* aElement,
     22                               const PseudoStyleRequest& aPseudoRequest) {
     23  auto* collection =
     24      TimelineCollection<TimelineType>::Get(aElement, aPseudoRequest);
     25  if (!collection) {
     26    return;
     27  }
     28  collection->Destroy();
     29 }
     30 
     31 void TimelineManager::UpdateTimelines(Element* aElement,
     32                                      const PseudoStyleRequest& aPseudoRequest,
     33                                      const ComputedStyle* aComputedStyle,
     34                                      ProgressTimelineType aType) {
     35  MOZ_ASSERT(
     36      aElement->IsInComposedDoc(),
     37      "No need to update timelines that are not attached to the document tree");
     38 
     39  // If we are in a display:none subtree we will have no computed values.
     40  // However, if we are on the root of display:none subtree, the computed values
     41  // might not have been cleared yet. In either case, since CSS animations
     42  // should not run in display:none subtrees, so we don't need timeline, either.
     43  const bool shouldDestroyTimelines =
     44      !aComputedStyle ||
     45      aComputedStyle->StyleDisplay()->mDisplay == StyleDisplay::None;
     46 
     47  switch (aType) {
     48    case ProgressTimelineType::Scroll:
     49      if (shouldDestroyTimelines) {
     50        TryDestroyTimeline<ScrollTimeline>(aElement, aPseudoRequest);
     51        return;
     52      }
     53      DoUpdateTimelines<StyleScrollTimeline, ScrollTimeline>(
     54          mPresContext, aElement, aPseudoRequest,
     55          aComputedStyle->StyleUIReset()->mScrollTimelines,
     56          aComputedStyle->StyleUIReset()->mScrollTimelineNameCount);
     57      break;
     58 
     59    case ProgressTimelineType::View:
     60      if (shouldDestroyTimelines) {
     61        TryDestroyTimeline<ViewTimeline>(aElement, aPseudoRequest);
     62        return;
     63      }
     64      DoUpdateTimelines<StyleViewTimeline, ViewTimeline>(
     65          mPresContext, aElement, aPseudoRequest,
     66          aComputedStyle->StyleUIReset()->mViewTimelines,
     67          aComputedStyle->StyleUIReset()->mViewTimelineNameCount);
     68      break;
     69  }
     70 }
     71 
     72 template <typename TimelineType>
     73 static already_AddRefed<TimelineType> PopExistingTimeline(
     74    nsAtom* aName, TimelineCollection<TimelineType>* aCollection) {
     75  if (!aCollection) {
     76    return nullptr;
     77  }
     78  return aCollection->Extract(aName);
     79 }
     80 
     81 template <typename StyleType, typename TimelineType>
     82 static auto BuildTimelines(nsPresContext* aPresContext, Element* aElement,
     83                           const PseudoStyleRequest& aPseudoRequest,
     84                           const nsStyleAutoArray<StyleType>& aTimelines,
     85                           size_t aTimelineCount,
     86                           TimelineCollection<TimelineType>* aCollection) {
     87  typename TimelineCollection<TimelineType>::TimelineMap result;
     88  // If multiple timelines are attempting to modify the same property, then the
     89  // timeline closest to the end of the list of names wins.
     90  // The spec doesn't mention this specifically for scroll-timeline-name and
     91  // view-timeline-name, so we follow the same rule with animation-name.
     92  for (size_t idx = 0; idx < aTimelineCount; ++idx) {
     93    const StyleType& timeline = aTimelines[idx];
     94    if (timeline.GetName() == nsGkAtoms::_empty) {
     95      continue;
     96    }
     97 
     98    RefPtr<TimelineType> dest =
     99        PopExistingTimeline(timeline.GetName(), aCollection);
    100    if (dest) {
    101      dest->ReplacePropertiesWith(aElement, aPseudoRequest, timeline);
    102    } else {
    103      dest = TimelineType::MakeNamed(aPresContext->Document(), aElement,
    104                                     aPseudoRequest, timeline);
    105    }
    106    MOZ_ASSERT(dest);
    107 
    108    // Override the previous one if it is duplicated.
    109    (void)result.InsertOrUpdate(timeline.GetName(), dest);
    110  }
    111  return result;
    112 }
    113 
    114 template <typename TimelineType>
    115 static TimelineCollection<TimelineType>& EnsureTimelineCollection(
    116    Element& aElement, const PseudoStyleRequest& aPseudoRequest);
    117 
    118 template <>
    119 ScrollTimelineCollection& EnsureTimelineCollection<ScrollTimeline>(
    120    Element& aElement, const PseudoStyleRequest& aPseudoRequest) {
    121  return aElement.EnsureAnimationData().EnsureScrollTimelineCollection(
    122      aElement, aPseudoRequest);
    123 }
    124 
    125 template <>
    126 ViewTimelineCollection& EnsureTimelineCollection<ViewTimeline>(
    127    Element& aElement, const PseudoStyleRequest& aPseudoRequest) {
    128  return aElement.EnsureAnimationData().EnsureViewTimelineCollection(
    129      aElement, aPseudoRequest);
    130 }
    131 
    132 template <typename StyleType, typename TimelineType>
    133 void TimelineManager::DoUpdateTimelines(
    134    nsPresContext* aPresContext, Element* aElement,
    135    const PseudoStyleRequest& aPseudoRequest,
    136    const nsStyleAutoArray<StyleType>& aStyleTimelines, size_t aTimelineCount) {
    137  auto* collection =
    138      TimelineCollection<TimelineType>::Get(aElement, aPseudoRequest);
    139  if (!collection && aTimelineCount == 1 &&
    140      aStyleTimelines[0].GetName() == nsGkAtoms::_empty) {
    141    return;
    142  }
    143 
    144  // We create a new timeline list based on its computed style and the existing
    145  // timelines.
    146  auto newTimelines = BuildTimelines<StyleType, TimelineType>(
    147      aPresContext, aElement, aPseudoRequest, aStyleTimelines, aTimelineCount,
    148      collection);
    149 
    150  if (newTimelines.IsEmpty()) {
    151    if (collection) {
    152      collection->Destroy();
    153    }
    154    return;
    155  }
    156 
    157  if (!collection) {
    158    collection =
    159        &EnsureTimelineCollection<TimelineType>(*aElement, aPseudoRequest);
    160    if (!collection->isInList()) {
    161      AddTimelineCollection(collection);
    162    }
    163  }
    164 
    165  // Replace unused timeline with new ones.
    166  collection->Swap(newTimelines);
    167 
    168  // FIXME: Bug 1774060. We may have to restyle the animations which use the
    169  // dropped timelines. Or rely on restyling the subtree and the following
    170  // siblings when mutating {scroll|view}-timeline-name.
    171 }
    172 
    173 }  // namespace mozilla