tor-browser

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

nsDOMCSSAttrDeclaration.cpp (10344B)


      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 /* DOM object for element.style */
      8 
      9 #include "nsDOMCSSAttrDeclaration.h"
     10 
     11 #include "ActiveLayerTracker.h"
     12 #include "mozAutoDocUpdate.h"
     13 #include "mozilla/DeclarationBlock.h"
     14 #include "mozilla/SMILCSSValueType.h"
     15 #include "mozilla/SMILValue.h"
     16 #include "mozilla/dom/Document.h"
     17 #include "mozilla/dom/Element.h"
     18 #include "mozilla/dom/SVGElement.h"
     19 #include "mozilla/layers/ScrollLinkedEffectDetector.h"
     20 #include "nsIFrame.h"
     21 #include "nsWrapperCacheInlines.h"
     22 
     23 using namespace mozilla;
     24 using namespace mozilla::dom;
     25 
     26 nsDOMCSSAttributeDeclaration::nsDOMCSSAttributeDeclaration(Element* aElement,
     27                                                           bool aIsSMILOverride)
     28    : mElement(aElement), mIsSMILOverride(aIsSMILOverride) {
     29  NS_ASSERTION(aElement, "Inline style for a NULL element?");
     30 }
     31 
     32 nsDOMCSSAttributeDeclaration::~nsDOMCSSAttributeDeclaration() = default;
     33 
     34 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCSSAttributeDeclaration, mElement)
     35 
     36 // mElement holds a strong ref to us, so if it's going to be
     37 // skipped, the attribute declaration can't be part of a garbage
     38 // cycle.
     39 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDOMCSSAttributeDeclaration)
     40  if (tmp->mElement && Element::CanSkip(tmp->mElement, true)) {
     41    if (tmp->PreservingWrapper()) {
     42      tmp->MarkWrapperLive();
     43    }
     44    return true;
     45  }
     46  return tmp->HasKnownLiveWrapper();
     47 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
     48 
     49 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDOMCSSAttributeDeclaration)
     50  return tmp->HasKnownLiveWrapper() ||
     51         (tmp->mElement && Element::CanSkipInCC(tmp->mElement));
     52 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
     53 
     54 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsDOMCSSAttributeDeclaration)
     55  return tmp->HasKnownLiveWrapper() ||
     56         (tmp->mElement && Element::CanSkipThis(tmp->mElement));
     57 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
     58 
     59 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCSSAttributeDeclaration)
     60  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     61 NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration)
     62 
     63 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCSSAttributeDeclaration)
     64 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCSSAttributeDeclaration)
     65 
     66 nsresult nsDOMCSSAttributeDeclaration::SetCSSDeclaration(
     67    DeclarationBlock* aDecl, MutationClosureData* aClosureData) {
     68  NS_ASSERTION(mElement, "Must have Element to set the declaration!");
     69 
     70  // Whenever changing element.style values, aClosureData must be non-null.
     71  // SMIL doesn't update Element's attribute values, so closure data isn't
     72  // needed.
     73  MOZ_ASSERT_IF(!mIsSMILOverride, aClosureData);
     74 
     75  // The closure needs to have been called by now, otherwise we shouldn't be
     76  // getting here when the attribute hasn't changed.
     77  MOZ_ASSERT_IF(aClosureData && aClosureData->mShouldBeCalled,
     78                aClosureData->mWasCalled);
     79 
     80  aDecl->SetDirty();
     81  if (mIsSMILOverride) {
     82    mElement->SetSMILOverrideStyleDeclaration(*aDecl);
     83    return NS_OK;
     84  }
     85  return mElement->SetInlineStyleDeclaration(*aDecl, *aClosureData);
     86 }
     87 
     88 Document* nsDOMCSSAttributeDeclaration::DocToUpdate() {
     89  // We need OwnerDoc() rather than GetUncomposedDoc() because it might
     90  // be the BeginUpdate call that inserts mElement into the document.
     91  return mElement->OwnerDoc();
     92 }
     93 
     94 DeclarationBlock* nsDOMCSSAttributeDeclaration::GetOrCreateCSSDeclaration(
     95    Operation aOperation, DeclarationBlock** aCreated) {
     96  MOZ_ASSERT(aOperation != Operation::Modify || aCreated);
     97 
     98  if (!mElement) {
     99    return nullptr;
    100  }
    101 
    102  DeclarationBlock* declaration;
    103  if (mIsSMILOverride) {
    104    declaration = mElement->GetSMILOverrideStyleDeclaration();
    105  } else {
    106    declaration = mElement->GetInlineStyleDeclaration();
    107  }
    108 
    109  if (declaration) {
    110    return declaration;
    111  }
    112 
    113  if (aOperation != Operation::Modify) {
    114    return nullptr;
    115  }
    116 
    117  // cannot fail
    118  auto decl = MakeRefPtr<DeclarationBlock>();
    119  // Mark the declaration dirty so that it can be reused by the caller.
    120  // Normally SetDirty is called later in SetCSSDeclaration.
    121  decl->SetDirty();
    122 #ifdef DEBUG
    123  RefPtr<DeclarationBlock> mutableDecl = decl->EnsureMutable();
    124  MOZ_ASSERT(mutableDecl == decl);
    125 #endif
    126  decl.swap(*aCreated);
    127  return *aCreated;
    128 }
    129 
    130 nsDOMCSSDeclaration::ParsingEnvironment
    131 nsDOMCSSAttributeDeclaration::GetParsingEnvironment(
    132    nsIPrincipal* aSubjectPrincipal) const {
    133  return {
    134      mElement->GetURLDataForStyleAttr(aSubjectPrincipal),
    135      mElement->OwnerDoc()->GetCompatibilityMode(),
    136      mElement->OwnerDoc()->GetExistingCSSLoader(),  // For error reporting only
    137  };
    138 }
    139 
    140 template <typename SetterFunc>
    141 nsresult nsDOMCSSAttributeDeclaration::SetSMILValueHelper(SetterFunc aFunc) {
    142  MOZ_ASSERT(mIsSMILOverride);
    143 
    144  // No need to do the ActiveLayerTracker / ScrollLinkedEffectDetector bits,
    145  // since we're in a SMIL animation anyway, no need to try to detect we're a
    146  // scripted animation.
    147  RefPtr<DeclarationBlock> created;
    148  DeclarationBlock* olddecl =
    149      GetOrCreateCSSDeclaration(Operation::Modify, getter_AddRefs(created));
    150  if (!olddecl) {
    151    return NS_ERROR_NOT_AVAILABLE;
    152  }
    153  mozAutoDocUpdate autoUpdate(DocToUpdate(), true);
    154  RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
    155 
    156  bool changed = aFunc(*decl);
    157 
    158  if (changed) {
    159    // We can pass nullptr as the latter param, since this is
    160    // mIsSMILOverride == true case.
    161    SetCSSDeclaration(decl, nullptr);
    162  }
    163  return NS_OK;
    164 }
    165 
    166 nsresult nsDOMCSSAttributeDeclaration::SetSMILValue(
    167    const NonCustomCSSPropertyId aPropId, const SMILValue& aValue) {
    168  MOZ_ASSERT(aValue.mType == &SMILCSSValueType::sSingleton,
    169             "We should only try setting a CSS value type");
    170  return SetSMILValueHelper([&](DeclarationBlock& aDecl) {
    171    return SMILCSSValueType::SetPropertyValues(aPropId, aValue, aDecl);
    172  });
    173 }
    174 
    175 nsresult nsDOMCSSAttributeDeclaration::SetSMILValue(
    176    const NonCustomCSSPropertyId aPropId, const SVGAnimatedLength& aLength) {
    177  return SetSMILValueHelper([aPropId, &aLength](DeclarationBlock& aDecl) {
    178    MOZ_ASSERT(aDecl.IsMutable());
    179    return SVGElement::UpdateDeclarationBlockFromLength(
    180        *aDecl.Raw(), aPropId, aLength, SVGElement::ValToUse::Anim);
    181  });
    182 }
    183 
    184 nsresult nsDOMCSSAttributeDeclaration::SetSMILValue(
    185    const NonCustomCSSPropertyId aPropId, const SVGAnimatedPathSegList& aPath) {
    186  MOZ_ASSERT(aPropId == eCSSProperty_d);
    187  return SetSMILValueHelper([&aPath](DeclarationBlock& aDecl) {
    188    MOZ_ASSERT(aDecl.IsMutable());
    189    return SVGElement::UpdateDeclarationBlockFromPath(
    190        *aDecl.Raw(), aPath, SVGElement::ValToUse::Anim);
    191  });
    192 }
    193 
    194 nsresult nsDOMCSSAttributeDeclaration::SetSMILValue(
    195    const NonCustomCSSPropertyId aPropId,
    196    const SVGAnimatedTransformList* aTransform,
    197    const gfx::Matrix* aAnimateMotionTransform) {
    198  MOZ_ASSERT(aPropId == eCSSProperty_transform);
    199  return SetSMILValueHelper(
    200      [aTransform, aAnimateMotionTransform](DeclarationBlock& aDecl) {
    201        MOZ_ASSERT(aDecl.IsMutable());
    202        return SVGElement::UpdateDeclarationBlockFromTransform(
    203            *aDecl.Raw(), aTransform, aAnimateMotionTransform,
    204            SVGElement::ValToUse::Anim);
    205      });
    206 }
    207 
    208 // Scripted modifications to style.opacity or style.transform (or other
    209 // transform-like properties, e.g. style.translate, style.rotate, style.scale)
    210 // could immediately force us into the animated state if heuristics suggest
    211 // this is a scripted animation.
    212 //
    213 // FIXME: This is missing the margin shorthand and the logical versions of
    214 // the margin properties, see bug 1266287.
    215 static bool IsActiveLayerProperty(NonCustomCSSPropertyId aPropId) {
    216  switch (aPropId) {
    217    case eCSSProperty_opacity:
    218    case eCSSProperty_transform:
    219    case eCSSProperty_translate:
    220    case eCSSProperty_rotate:
    221    case eCSSProperty_scale:
    222    case eCSSProperty_offset_path:
    223    case eCSSProperty_offset_distance:
    224    case eCSSProperty_offset_rotate:
    225    case eCSSProperty_offset_anchor:
    226    case eCSSProperty_offset_position:
    227      return true;
    228    default:
    229      return false;
    230  }
    231 }
    232 
    233 void nsDOMCSSAttributeDeclaration::SetPropertyValue(
    234    const NonCustomCSSPropertyId aPropId, const nsACString& aValue,
    235    nsIPrincipal* aSubjectPrincipal, ErrorResult& aRv) {
    236  nsDOMCSSDeclaration::SetPropertyValue(aPropId, aValue, aSubjectPrincipal,
    237                                        aRv);
    238 }
    239 
    240 static bool IsScrollLinkedEffectiveProperty(
    241    const NonCustomCSSPropertyId aPropId) {
    242  switch (aPropId) {
    243    case eCSSProperty_background_position:
    244    case eCSSProperty_background_position_x:
    245    case eCSSProperty_background_position_y:
    246    case eCSSProperty_transform:
    247    case eCSSProperty_translate:
    248    case eCSSProperty_rotate:
    249    case eCSSProperty_scale:
    250    case eCSSProperty_offset_path:
    251    case eCSSProperty_offset_distance:
    252    case eCSSProperty_offset_rotate:
    253    case eCSSProperty_offset_anchor:
    254    case eCSSProperty_offset_position:
    255    case eCSSProperty_top:
    256    case eCSSProperty_left:
    257    case eCSSProperty_bottom:
    258    case eCSSProperty_right:
    259    case eCSSProperty_margin:
    260    case eCSSProperty_margin_top:
    261    case eCSSProperty_margin_left:
    262    case eCSSProperty_margin_bottom:
    263    case eCSSProperty_margin_right:
    264    case eCSSProperty_margin_inline_start:
    265    case eCSSProperty_margin_inline_end:
    266    case eCSSProperty_margin_block_start:
    267    case eCSSProperty_margin_block_end:
    268      return true;
    269    default:
    270      return false;
    271  }
    272 }
    273 
    274 void nsDOMCSSAttributeDeclaration::MutationClosureFunction(
    275    void* aData, NonCustomCSSPropertyId aPropId) {
    276  auto* data = static_cast<MutationClosureData*>(aData);
    277  MOZ_ASSERT(
    278      data->mShouldBeCalled,
    279      "Did we pass a non-null closure to the style system unnecessarily?");
    280  if (data->mWasCalled) {
    281    return;
    282  }
    283  if (IsScrollLinkedEffectiveProperty(aPropId)) {
    284    mozilla::layers::ScrollLinkedEffectDetector::PositioningPropertyMutated();
    285  }
    286  if (IsActiveLayerProperty(aPropId)) {
    287    if (nsIFrame* frame = data->mElement->GetPrimaryFrame()) {
    288      ActiveLayerTracker::NotifyInlineStyleRuleModified(frame, aPropId);
    289    }
    290  }
    291 
    292  data->mWasCalled = true;
    293  data->mElement->InlineStyleDeclarationWillChange(*data);
    294 }