Commit message: None
CVE: CVE-2019-5757
CWE: CWE-704
Vulnerability description: An incorrect object type assumption in SVG in Google Chrome prior to 72.0.3626.81 allowed a remote attacker to potentially exploit object corruption via a crafted HTML page.

Project: Chrome

void SVGElement::AddReferenceTo(SVGElement* target_element) {
  DCHECK(target_element);

  EnsureSVGRareData()->OutgoingReferences().insert(target_element);
  target_element->EnsureSVGRareData()->IncomingReferences().insert(this);
}

Project: Chrome

void SVGElement::AddToPropertyMap(SVGAnimatedPropertyBase* property) {
  attribute_to_property_map_.Set(property->AttributeName(), property);
}

Project: Chrome

AnimatedPropertyType SVGElement::AnimatedPropertyTypeForCSSAttribute(
    const QualifiedName& attribute_name) {
  DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, css_property_map, ());

  if (css_property_map.IsEmpty()) {
    struct AttrToTypeEntry {
      const QualifiedName& attr;
      const AnimatedPropertyType prop_type;
    };
    const AttrToTypeEntry attr_to_types[] = {
        {kAlignmentBaselineAttr, kAnimatedString},
        {kBaselineShiftAttr, kAnimatedString},
        {kBufferedRenderingAttr, kAnimatedString},
        {kClipPathAttr, kAnimatedString},
        {kClipRuleAttr, kAnimatedString},
        {svg_names::kColorAttr, kAnimatedColor},
        {kColorInterpolationAttr, kAnimatedString},
        {kColorInterpolationFiltersAttr, kAnimatedString},
        {kColorRenderingAttr, kAnimatedString},
        {kCursorAttr, kAnimatedString},
        {kDisplayAttr, kAnimatedString},
        {kDominantBaselineAttr, kAnimatedString},
        {kFillAttr, kAnimatedColor},
        {kFillOpacityAttr, kAnimatedNumber},
        {kFillRuleAttr, kAnimatedString},
        {kFilterAttr, kAnimatedString},
        {kFloodColorAttr, kAnimatedColor},
        {kFloodOpacityAttr, kAnimatedNumber},
        {kFontFamilyAttr, kAnimatedString},
        {kFontSizeAttr, kAnimatedLength},
        {kFontStretchAttr, kAnimatedString},
        {kFontStyleAttr, kAnimatedString},
        {kFontVariantAttr, kAnimatedString},
        {kFontWeightAttr, kAnimatedString},
        {kImageRenderingAttr, kAnimatedString},
        {kLetterSpacingAttr, kAnimatedLength},
        {kLightingColorAttr, kAnimatedColor},
        {kMarkerEndAttr, kAnimatedString},
        {kMarkerMidAttr, kAnimatedString},
        {kMarkerStartAttr, kAnimatedString},
        {kMaskAttr, kAnimatedString},
        {kMaskTypeAttr, kAnimatedString},
        {kOpacityAttr, kAnimatedNumber},
        {kOverflowAttr, kAnimatedString},
        {kPaintOrderAttr, kAnimatedString},
        {kPointerEventsAttr, kAnimatedString},
        {kShapeRenderingAttr, kAnimatedString},
        {kStopColorAttr, kAnimatedColor},
        {kStopOpacityAttr, kAnimatedNumber},
        {kStrokeAttr, kAnimatedColor},
        {kStrokeDasharrayAttr, kAnimatedLengthList},
        {kStrokeDashoffsetAttr, kAnimatedLength},
        {kStrokeLinecapAttr, kAnimatedString},
        {kStrokeLinejoinAttr, kAnimatedString},
        {kStrokeMiterlimitAttr, kAnimatedNumber},
        {kStrokeOpacityAttr, kAnimatedNumber},
        {kStrokeWidthAttr, kAnimatedLength},
        {kTextAnchorAttr, kAnimatedString},
        {kTextDecorationAttr, kAnimatedString},
        {kTextRenderingAttr, kAnimatedString},
        {kVectorEffectAttr, kAnimatedString},
        {kVisibilityAttr, kAnimatedString},
        {kWordSpacingAttr, kAnimatedLength},
    };
    for (size_t i = 0; i < arraysize(attr_to_types); i++)
      css_property_map.Set(attr_to_types[i].attr, attr_to_types[i].prop_type);
  }
  return css_property_map.at(attribute_name);
}

Project: Chrome

 MutableCSSPropertyValueSet* SVGElement::AnimatedSMILStyleProperties() const {
  if (HasSVGRareData())
    return SvgRareData()->AnimatedSMILStyleProperties();
  return nullptr;
}

Project: Chrome

void SVGElement::ApplyActiveWebAnimations() {
  ActiveInterpolationsMap active_interpolations_map =
      EffectStack::ActiveInterpolations(
          &GetElementAnimations()->GetEffectStack(), nullptr, nullptr,
          KeyframeEffect::kDefaultPriority, IsSVGAttributeHandle);
  for (auto& entry : active_interpolations_map) {
    const QualifiedName& attribute = entry.key.SvgAttribute();
    SVGInterpolationTypesMap map;
    SVGInterpolationEnvironment environment(
        map, *this, PropertyFromAttribute(attribute)->BaseValueBase());
    InvalidatableInterpolation::ApplyStack(entry.value, environment);
  }
  if (!HasSVGRareData())
    return;
  SvgRareData()->SetWebAnimatedAttributesDirty(false);
}

Project: Chrome

void SVGElement::AttributeChanged(const AttributeModificationParams& params) {
  Element::AttributeChanged(params);

  if (params.name == html_names::kIdAttr) {
    RebuildAllIncomingReferences();
    InvalidateInstances();
    return;
  }

  if (params.name == html_names::kStyleAttr)
    return;

  SvgAttributeBaseValChanged(params.name);
}

Project: Chrome

void SVGElement::ChildrenChanged(const ChildrenChange& change) {
  Element::ChildrenChanged(change);

  InvalidateInstances();
}

Project: Chrome

void SVGElement::ClearWebAnimatedAttributes() {
  if (!HasSVGRareData())
    return;
  for (const QualifiedName* attribute :
       SvgRareData()->WebAnimatedAttributes()) {
    ForSelfAndInstances(this, [&attribute](SVGElement* element) {
      if (SVGAnimatedPropertyBase* animated_property =
              element->PropertyFromAttribute(*attribute)) {
        animated_property->AnimationEnded();
        NotifyAnimValChanged(element, *attribute);
      }
    });
  }
  SvgRareData()->WebAnimatedAttributes().clear();
}

Project: Chrome

static inline void CollectInstancesForSVGElement(
    SVGElement* element,
    HeapHashSet<WeakMember<SVGElement>>& instances) {
  DCHECK(element);
  if (element->ContainingShadowRoot())
    return;

  DCHECK(!element->InstanceUpdatesBlocked());

  instances = element->InstancesForElement();
}

Project: Chrome

void SVGElement::CollectStyleForPresentationAttribute(
    const QualifiedName& name,
    const AtomicString& value,
    MutableCSSPropertyValueSet* style) {
  CSSPropertyID property_id = CssPropertyIdForSVGAttributeName(name);
  if (property_id > 0)
    AddPropertyToPresentationAttributeStyle(style, property_id, value);
}

Project: Chrome

static FloatRect ComputeTransformReferenceBox(const SVGElement& element) {
  const LayoutObject& layout_object = *element.GetLayoutObject();
  const ComputedStyle& style = layout_object.StyleRef();
  if (style.TransformBox() == ETransformBox::kFillBox)
    return layout_object.ObjectBoundingBox();
  DCHECK_EQ(style.TransformBox(), ETransformBox::kViewBox);
  SVGLengthContext length_context(&element);
  FloatSize viewport_size;
  length_context.DetermineViewport(viewport_size);
  return FloatRect(FloatPoint(), viewport_size);
}

Project: Chrome

SVGElement* SVGElement::CorrespondingElement() const {
  DCHECK(!HasSVGRareData() || !SvgRareData()->CorrespondingElement() ||
         ContainingShadowRoot());
  return HasSVGRareData() ? SvgRareData()->CorrespondingElement() : nullptr;
}

Project: Chrome

SVGUseElement* SVGElement::CorrespondingUseElement() const {
  if (ShadowRoot* root = ContainingShadowRoot()) {
    if (IsSVGUseElement(root->host()))
      return &ToSVGUseElement(root->host());
  }
  return nullptr;
}

Project: Chrome

CSSPropertyID SVGElement::CssPropertyIdForSVGAttributeName(
    const QualifiedName& attr_name) {
  if (!attr_name.NamespaceURI().IsNull())
    return CSSPropertyInvalid;

  static HashMap<StringImpl*, CSSPropertyID>* property_name_to_id_map = nullptr;
  if (!property_name_to_id_map) {
    property_name_to_id_map = new HashMap<StringImpl*, CSSPropertyID>;
    const QualifiedName* const attr_names[] = {
        &kAlignmentBaselineAttr,
        &kBaselineShiftAttr,
        &kBufferedRenderingAttr,
        &kClipAttr,
        &kClipPathAttr,
        &kClipRuleAttr,
        &svg_names::kColorAttr,
        &kColorInterpolationAttr,
        &kColorInterpolationFiltersAttr,
        &kColorRenderingAttr,
        &kCursorAttr,
        &svg_names::kDirectionAttr,
        &kDisplayAttr,
        &kDominantBaselineAttr,
        &kFillAttr,
        &kFillOpacityAttr,
        &kFillRuleAttr,
        &kFilterAttr,
        &kFloodColorAttr,
        &kFloodOpacityAttr,
        &kFontFamilyAttr,
        &kFontSizeAttr,
        &kFontStretchAttr,
        &kFontStyleAttr,
        &kFontVariantAttr,
        &kFontWeightAttr,
        &kImageRenderingAttr,
        &kLetterSpacingAttr,
        &kLightingColorAttr,
        &kMarkerEndAttr,
        &kMarkerMidAttr,
        &kMarkerStartAttr,
        &kMaskAttr,
        &kMaskTypeAttr,
        &kOpacityAttr,
        &kOverflowAttr,
        &kPaintOrderAttr,
        &kPointerEventsAttr,
        &kShapeRenderingAttr,
        &kStopColorAttr,
        &kStopOpacityAttr,
        &kStrokeAttr,
        &kStrokeDasharrayAttr,
        &kStrokeDashoffsetAttr,
        &kStrokeLinecapAttr,
        &kStrokeLinejoinAttr,
        &kStrokeMiterlimitAttr,
        &kStrokeOpacityAttr,
        &kStrokeWidthAttr,
        &kTextAnchorAttr,
        &kTextDecorationAttr,
        &kTextRenderingAttr,
        &kTransformOriginAttr,
        &kUnicodeBidiAttr,
        &kVectorEffectAttr,
        &kVisibilityAttr,
        &kWordSpacingAttr,
        &kWritingModeAttr,
    };
    for (size_t i = 0; i < arraysize(attr_names); i++) {
      CSSPropertyID property_id = cssPropertyID(attr_names[i]->LocalName());
      DCHECK_GT(property_id, 0);
      property_name_to_id_map->Set(attr_names[i]->LocalName().Impl(),
                                   property_id);
    }
  }

  return property_name_to_id_map->at(attr_name.LocalName().Impl());
}

Project: Chrome

scoped_refptr<ComputedStyle> SVGElement::CustomStyleForLayoutObject() {
  if (!CorrespondingElement())
    return GetDocument().EnsureStyleResolver().StyleForElement(this);

  const ComputedStyle* style = nullptr;
  if (Element* parent = ParentOrShadowHostElement())
    style = parent->GetComputedStyle();

  return GetDocument().EnsureStyleResolver().StyleForElement(
      CorrespondingElement(), style, style);
}

Project: Chrome

void SVGElement::DetachLayoutTree(const AttachContext& context) {
  Element::DetachLayoutTree(context);
  if (SVGElement* element = CorrespondingElement())
    element->RemoveInstanceMapping(this);
  if (HasSVGRareData())
    SvgRareData()->ClearOverriddenComputedStyle();
}

Project: Chrome

static HeapHashSet<WeakMember<SVGElement>>& EmptyInstances() {
  DEFINE_STATIC_LOCAL(
      Persistent<HeapHashSet<WeakMember<SVGElement>>>, empty_instances,
      (MakeGarbageCollected<HeapHashSet<WeakMember<SVGElement>>>()));
  return *empty_instances;
}

Project: Chrome

  static AnimatedPropertyType EmptyValue() { return kAnimatedUnknown; }

Project: Chrome

MutableCSSPropertyValueSet* SVGElement::EnsureAnimatedSMILStyleProperties() {
  return EnsureSVGRareData()->EnsureAnimatedSMILStyleProperties();
}

Project: Chrome

void SVGElement::EnsureAttributeAnimValUpdated() {
  if (!RuntimeEnabledFeatures::WebAnimationsSVGEnabled())
    return;

  if ((HasSVGRareData() && SvgRareData()->WebAnimatedAttributesDirty()) ||
      (GetElementAnimations() &&
       DocumentAnimations::NeedsAnimationTimingUpdate(GetDocument()))) {
    DocumentAnimations::UpdateAnimationTimingIfNeeded(GetDocument());
    ApplyActiveWebAnimations();
  }
}

Project: Chrome

const ComputedStyle* SVGElement::EnsureComputedStyle(
    PseudoId pseudo_element_specifier) {
  if (!HasSVGRareData() || !SvgRareData()->UseOverrideComputedStyle())
    return Element::EnsureComputedStyle(pseudo_element_specifier);

  const ComputedStyle* parent_style = nullptr;
  if (Element* parent = ParentOrShadowHostElement()) {
    if (LayoutObject* layout_object = parent->GetLayoutObject())
      parent_style = layout_object->Style();
  }

  return SvgRareData()->OverrideComputedStyle(this, parent_style);
}

Project: Chrome

static void ForSelfAndInstances(SVGElement* element, T callback) {
  SVGElement::InstanceUpdateBlocker blocker(element);
  callback(element);
  for (SVGElement* instance : element->InstancesForElement())
    callback(instance);
}

Project: Chrome

SVGElementSet& SVGElement::GetDependencyTraversalVisitedSet() {
  DEFINE_STATIC_LOCAL(Persistent<SVGElementSet>, invalidating_dependencies,
                      (MakeGarbageCollected<SVGElementSet>()));
  return *invalidating_dependencies;
}

Project: Chrome

SVGResourceClient* SVGElement::GetSVGResourceClient() {
  if (!HasSVGRareData())
    return nullptr;
  return SvgRareData()->GetSVGResourceClient();
}

Project: Chrome

bool SVGElement::HasFocusEventListeners() const {
  return HasEventListeners(event_type_names::kFocusin) ||
         HasEventListeners(event_type_names::kFocusout) ||
         HasEventListeners(event_type_names::kFocus) ||
         HasEventListeners(event_type_names::kBlur);
}

Project: Chrome

bool SVGElement::HasTransform(
    ApplyMotionTransform apply_motion_transform) const {
  return (GetLayoutObject() && GetLayoutObject()->StyleRef().HasTransform()) ||
         (apply_motion_transform == kIncludeMotionTransform &&
          HasSVGRareData());
}

Project: Chrome

bool SVGElement::InUseShadowTree() const {
  return CorrespondingUseElement();
}

Project: Chrome

SVGElement::InstanceUpdateBlocker::InstanceUpdateBlocker(
    SVGElement* target_element)
    : target_element_(target_element) {
  if (target_element_)
    target_element_->SetInstanceUpdatesBlocked(true);
}

Project: Chrome

bool SVGElement::InstanceUpdatesBlocked() const {
  return HasSVGRareData() && SvgRareData()->InstanceUpdatesBlocked();
}

Project: Chrome

const HeapHashSet<WeakMember<SVGElement>>& SVGElement::InstancesForElement()
    const {
  if (!HasSVGRareData())
    return EmptyInstances();
  return SvgRareData()->ElementInstances();
}

Project: Chrome

void SVGElement::InvalidateAnimatedAttribute(const QualifiedName& attribute) {
  ForSelfAndInstances(this, [&attribute](SVGElement* element) {
    NotifyAnimValChanged(element, attribute);
  });
}

Project: Chrome

void SVGElement::InvalidateRelativeLengthClients(
    SubtreeLayoutScope* layout_scope) {
  if (!isConnected())
    return;

#if DCHECK_IS_ON()
  DCHECK(!in_relative_length_clients_invalidation_);
  base::AutoReset<bool> in_relative_length_clients_invalidation_change(
      &in_relative_length_clients_invalidation_, true);
#endif

  if (LayoutObject* layout_object = this->GetLayoutObject()) {
    if (HasRelativeLengths() && layout_object->IsSVGResourceContainer()) {
      ToLayoutSVGResourceContainer(layout_object)
          ->InvalidateCacheAndMarkForLayout(
              layout_invalidation_reason::kSizeChanged, layout_scope);
    } else if (SelfHasRelativeLengths()) {
      layout_object->SetNeedsLayoutAndFullPaintInvalidation(
          layout_invalidation_reason::kUnknown, kMarkContainerChain,
          layout_scope);
    }
  }

  for (SVGElement* element : elements_with_relative_lengths_) {
    if (element != this)
      element->InvalidateRelativeLengthClients(layout_scope);
  }
}

Project: Chrome

bool SVGElement::IsAnimatableAttribute(const QualifiedName& name) const {
  DEFINE_THREAD_SAFE_STATIC_LOCAL(HashSet<QualifiedName>, animatable_attributes,
                                  ({
                                      svg_names::kAmplitudeAttr,
                                      svg_names::kAzimuthAttr,
                                      svg_names::kBaseFrequencyAttr,
                                      svg_names::kBiasAttr,
                                      svg_names::kClipPathUnitsAttr,
                                      svg_names::kCxAttr,
                                      svg_names::kCyAttr,
                                      svg_names::kDiffuseConstantAttr,
                                      svg_names::kDivisorAttr,
                                      svg_names::kDxAttr,
                                      svg_names::kDyAttr,
                                      svg_names::kEdgeModeAttr,
                                      svg_names::kElevationAttr,
                                      svg_names::kExponentAttr,
                                      svg_names::kFilterUnitsAttr,
                                      svg_names::kFxAttr,
                                      svg_names::kFyAttr,
                                      svg_names::kGradientTransformAttr,
                                      svg_names::kGradientUnitsAttr,
                                      svg_names::kHeightAttr,
                                      svg_names::kHrefAttr,
                                      svg_names::kIn2Attr,
                                      svg_names::kInAttr,
                                      svg_names::kInterceptAttr,
                                      svg_names::kK1Attr,
                                      svg_names::kK2Attr,
                                      svg_names::kK3Attr,
                                      svg_names::kK4Attr,
                                      svg_names::kKernelMatrixAttr,
                                      svg_names::kKernelUnitLengthAttr,
                                      svg_names::kLengthAdjustAttr,
                                      svg_names::kLimitingConeAngleAttr,
                                      svg_names::kMarkerHeightAttr,
                                      svg_names::kMarkerUnitsAttr,
                                      svg_names::kMarkerWidthAttr,
                                      svg_names::kMaskContentUnitsAttr,
                                      svg_names::kMaskUnitsAttr,
                                      svg_names::kMethodAttr,
                                      svg_names::kModeAttr,
                                      svg_names::kNumOctavesAttr,
                                      svg_names::kOffsetAttr,
                                      svg_names::kOperatorAttr,
                                      svg_names::kOrderAttr,
                                      svg_names::kOrientAttr,
                                      svg_names::kPathLengthAttr,
                                      svg_names::kPatternContentUnitsAttr,
                                      svg_names::kPatternTransformAttr,
                                      svg_names::kPatternUnitsAttr,
                                      svg_names::kPointsAtXAttr,
                                      svg_names::kPointsAtYAttr,
                                      svg_names::kPointsAtZAttr,
                                      svg_names::kPreserveAlphaAttr,
                                      svg_names::kPreserveAspectRatioAttr,
                                      svg_names::kPrimitiveUnitsAttr,
                                      svg_names::kRadiusAttr,
                                      svg_names::kRAttr,
                                      svg_names::kRefXAttr,
                                      svg_names::kRefYAttr,
                                      svg_names::kResultAttr,
                                      svg_names::kRotateAttr,
                                      svg_names::kRxAttr,
                                      svg_names::kRyAttr,
                                      svg_names::kScaleAttr,
                                      svg_names::kSeedAttr,
                                      svg_names::kSlopeAttr,
                                      svg_names::kSpacingAttr,
                                      svg_names::kSpecularConstantAttr,
                                      svg_names::kSpecularExponentAttr,
                                      svg_names::kSpreadMethodAttr,
                                      svg_names::kStartOffsetAttr,
                                      svg_names::kStdDeviationAttr,
                                      svg_names::kStitchTilesAttr,
                                      svg_names::kSurfaceScaleAttr,
                                      svg_names::kTableValuesAttr,
                                      svg_names::kTargetAttr,
                                      svg_names::kTargetXAttr,
                                      svg_names::kTargetYAttr,
                                      svg_names::kTransformAttr,
                                      svg_names::kTypeAttr,
                                      svg_names::kValuesAttr,
                                      svg_names::kViewBoxAttr,
                                      svg_names::kWidthAttr,
                                      svg_names::kX1Attr,
                                      svg_names::kX2Attr,
                                      svg_names::kXAttr,
                                      svg_names::kXChannelSelectorAttr,
                                      svg_names::kY1Attr,
                                      svg_names::kY2Attr,
                                      svg_names::kYAttr,
                                      svg_names::kYChannelSelectorAttr,
                                      svg_names::kZAttr,
                                  }));

  if (name == kClassAttr)
    return true;

  return animatable_attributes.Contains(name);
}

Project: Chrome

bool SVGElement::IsAnimatableCSSProperty(const QualifiedName& attr_name) {
  return AnimatedPropertyTypeForCSSAttribute(attr_name) != kAnimatedUnknown;
}

Project: Chrome

bool SVGElement::IsOutermostSVGSVGElement() const {
  if (!IsSVGSVGElement(*this))
    return false;

  if (!parentNode())
    return true;

  if (IsSVGForeignObjectElement(*parentNode()))
    return true;

  if (InUseShadowTree() && ParentOrShadowHostElement() &&
      ParentOrShadowHostElement()->IsSVGElement())
    return false;

  return !parentNode()->IsSVGElement();
}

Project: Chrome

bool SVGElement::IsPresentationAttribute(const QualifiedName& name) const {
  if (const SVGAnimatedPropertyBase* property = PropertyFromAttribute(name))
    return property->HasPresentationAttributeMapping();
  return CssPropertyIdForSVGAttributeName(name) > 0;
}

Project: Chrome

static bool IsSVGAttributeHandle(const PropertyHandle& property_handle) {
  return property_handle.IsSVGAttribute();
}

Project: Chrome

bool SVGElement::LayoutObjectIsNeeded(const ComputedStyle& style) const {
  return IsValid() && HasSVGParent() && Element::LayoutObjectIsNeeded(style);
 }

Project: Chrome

AffineTransform SVGElement::LocalCoordinateSpaceTransform(CTMScope) const {
  return AffineTransform();
}

Project: Chrome

void SVGElement::MapInstanceToElement(SVGElement* instance) {
  DCHECK(instance);
  DCHECK(instance->InUseShadowTree());

  HeapHashSet<WeakMember<SVGElement>>& instances =
      EnsureSVGRareData()->ElementInstances();
  DCHECK(!instances.Contains(instance));

  instances.insert(instance);
}

Project: Chrome

void SVGElement::MarkForLayoutAndParentResourceInvalidation(
    LayoutObject& layout_object) {
  LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(
      layout_object, true);
}

Project: Chrome

static inline void NotifyAnimValChanged(SVGElement* target_element,
                                        const QualifiedName& attribute_name) {
  target_element->InvalidateSVGAttributes();
  target_element->SvgAttributeChanged(attribute_name);
}

Project: Chrome

void SVGElement::RebuildAllIncomingReferences() {
  if (!HasSVGRareData())
    return;

  const SVGElementSet& incoming_references =
      SvgRareData()->IncomingReferences();

  HeapVector<Member<SVGElement>> incoming_references_snapshot;
  CopyToVector(incoming_references, incoming_references_snapshot);

  for (SVGElement* source_element : incoming_references_snapshot) {
    if (incoming_references.Contains(source_element))
      source_element->SvgAttributeChanged(svg_names::kHrefAttr);
  }
}

Project: Chrome

void SVGElement::RemoveAllIncomingReferences() {
  if (!HasSVGRareData())
    return;

  SVGElementSet& incoming_references = SvgRareData()->IncomingReferences();
  for (SVGElement* source_element : incoming_references) {
    DCHECK(source_element->HasSVGRareData());
    source_element->EnsureSVGRareData()->OutgoingReferences().erase(this);
  }
  incoming_references.clear();
}

Project: Chrome

void SVGElement::RemoveAllOutgoingReferences() {
  if (!HasSVGRareData())
    return;

  SVGElementSet& outgoing_references = SvgRareData()->OutgoingReferences();
  for (SVGElement* target_element : outgoing_references) {
    DCHECK(target_element->HasSVGRareData());
    target_element->EnsureSVGRareData()->IncomingReferences().erase(this);
  }
  outgoing_references.clear();
}

Project: Chrome

void SVGElement::RemoveInstanceMapping(SVGElement* instance) {
  DCHECK(instance);
  DCHECK(instance->InUseShadowTree());

  if (!HasSVGRareData())
    return;

  HeapHashSet<WeakMember<SVGElement>>& instances =
      SvgRareData()->ElementInstances();

  instances.erase(instance);
}

Project: Chrome

void SVGElement::RemovedEventListener(
    const AtomicString& event_type,
    const RegisteredEventListener& registered_listener) {
  Node::RemovedEventListener(event_type, registered_listener);

  HeapHashSet<WeakMember<SVGElement>> instances;
  CollectInstancesForSVGElement(this, instances);
  EventListenerOptions* options = registered_listener.Options();
  const EventListener* listener = registered_listener.Callback();
  for (SVGElement* shadow_tree_element : instances) {
    DCHECK(shadow_tree_element);

    shadow_tree_element->Node::RemoveEventListenerInternal(event_type, listener,
                                                           options);
  }
}

Project: Chrome

void SVGElement::RemovedFrom(ContainerNode& root_parent) {
  bool was_in_document = root_parent.isConnected();

  if (was_in_document && HasRelativeLengths()) {
    if (root_parent.IsSVGElement() && !parentNode()) {
      DCHECK(ToSVGElement(root_parent)
                 .elements_with_relative_lengths_.Contains(this));
      ToSVGElement(root_parent).UpdateRelativeLengthsInformation(false, this);
    }

    elements_with_relative_lengths_.clear();
  }

  SECURITY_DCHECK(!root_parent.IsSVGElement() ||
                  !ToSVGElement(root_parent)
                       .elements_with_relative_lengths_.Contains(this));

  Element::RemovedFrom(root_parent);

  if (was_in_document) {
    RebuildAllIncomingReferences();
    RemoveAllIncomingReferences();
  }

  InvalidateInstances();
}

Project: Chrome

void SVGElement::ReportAttributeParsingError(SVGParsingError error,
                                             const QualifiedName& name,
                                             const AtomicString& value) {
  if (error == SVGParseStatus::kNoError)
    return;
  if (value.IsNull())
    return;
  GetDocument().AddConsoleMessage(
      ConsoleMessage::Create(kRenderingMessageSource, kErrorMessageLevel,
                             "Error: " + error.Format(tagName(), name, value)));
}

Project: Chrome

SVGElement::SVGElement(const QualifiedName& tag_name,
                       Document& document,
                       ConstructionType construction_type)
    : Element(tag_name, &document, construction_type),
      svg_rare_data_(nullptr),
      class_name_(SVGAnimatedString::Create(this, html_names::kClassAttr)) {
  AddToPropertyMap(class_name_);
  SetHasCustomStyleCallbacks();
}

Project: Chrome

bool SVGElement::SendSVGLoadEventIfPossible() {
  if (!HaveLoadedRequiredResources())
    return false;
  if ((IsStructurallyExternal() || IsSVGSVGElement(*this)) &&
      HasLoadListener(this))
    DispatchEvent(*Event::Create(event_type_names::kLoad));
  return true;
}

Project: Chrome

void SVGElement::SendSVGLoadEventToSelfAndAncestorChainIfPossible() {
  if (IsOutermostSVGSVGElement())
    return;

  Element* parent = ParentOrShadowHostElement();
  if (!SendSVGLoadEventIfPossible())
    return;

  if (GetDocument().LoadEventFinished())
    return;

  if (!parent || !parent->IsSVGElement())
    return;

  ToSVGElement(parent)->SendSVGLoadEventToSelfAndAncestorChainIfPossible();
}

Project: Chrome

void SVGElement::SetAnimatedAttribute(const QualifiedName& attribute,
                                      SVGPropertyBase* value) {
  ForSelfAndInstances(this, [&attribute, &value](SVGElement* element) {
    if (SVGAnimatedPropertyBase* animated_property =
            element->PropertyFromAttribute(attribute))
      animated_property->SetAnimatedValue(value);
  });
}

Project: Chrome

void SVGElement::SetCorrespondingElement(SVGElement* corresponding_element) {
  EnsureSVGRareData()->SetCorrespondingElement(corresponding_element);
}

Project: Chrome

void SVGElement::SetInstanceUpdatesBlocked(bool value) {
  if (HasSVGRareData())
    SvgRareData()->SetInstanceUpdatesBlocked(value);
}

Project: Chrome

void SVGElement::SetNeedsStyleRecalcForInstances(
    StyleChangeType change_type,
    const StyleChangeReasonForTracing& reason) {
  const HeapHashSet<WeakMember<SVGElement>>& set = InstancesForElement();
  if (set.IsEmpty())
    return;

  for (SVGElement* instance : set)
    instance->SetNeedsStyleRecalc(change_type, reason);
}

Project: Chrome

SVGElementSet* SVGElement::SetOfIncomingReferences() const {
  if (!HasSVGRareData())
    return nullptr;
  return &SvgRareData()->IncomingReferences();
}

Project: Chrome

void SVGElement::SetUseOverrideComputedStyle(bool value) {
  if (HasSVGRareData())
    SvgRareData()->SetUseOverrideComputedStyle(value);
}

Project: Chrome

void SVGElement::SetWebAnimatedAttribute(const QualifiedName& attribute,
                                         SVGPropertyBase* value) {
  ForSelfAndInstances(this, [&attribute, &value](SVGElement* element) {
    if (SVGAnimatedPropertyBase* animated_property =
            element->PropertyFromAttribute(attribute)) {
      animated_property->SetAnimatedValue(value);
      NotifyAnimValChanged(element, attribute);
    }
  });
  EnsureSVGRareData()->WebAnimatedAttributes().insert(&attribute);
}

Project: Chrome

void SVGElement::SetWebAnimationsPending() {
  GetDocument().AccessSVGExtensions().AddWebAnimationsPendingSVGElement(*this);
  EnsureSVGRareData()->SetWebAnimatedAttributesDirty(true);
  EnsureUniqueElementData().animated_svg_attributes_are_dirty_ = true;
}

Project: Chrome

void SVGElement::SvgAttributeBaseValChanged(const QualifiedName& attribute) {
  SvgAttributeChanged(attribute);

  if (!HasSVGRareData() || SvgRareData()->WebAnimatedAttributes().IsEmpty())
    return;

  SvgRareData()->SetWebAnimatedAttributesDirty(true);
  GetElementData()->animated_svg_attributes_are_dirty_ = true;
}

Project: Chrome

void SVGElement::SvgAttributeChanged(const QualifiedName& attr_name) {
  CSSPropertyID prop_id =
      SVGElement::CssPropertyIdForSVGAttributeName(attr_name);
  if (prop_id > 0) {
    InvalidateInstances();
    return;
  }

  if (attr_name == html_names::kClassAttr) {
    ClassAttributeChanged(AtomicString(class_name_->CurrentValue()->Value()));
    InvalidateInstances();
    return;
  }
}

Project: Chrome

void SVGElement::SynchronizeAnimatedSVGAttribute(
    const QualifiedName& name) const {
  if (!GetElementData() ||
      !GetElementData()->animated_svg_attributes_are_dirty_)
    return;

  const_cast<SVGElement*>(this)->EnsureAttributeAnimValUpdated();

  if (name == AnyQName()) {
    AttributeToPropertyMap::const_iterator::ValuesIterator it =
        attribute_to_property_map_.Values().begin();
    AttributeToPropertyMap::const_iterator::ValuesIterator end =
        attribute_to_property_map_.Values().end();
    for (; it != end; ++it) {
      if ((*it)->NeedsSynchronizeAttribute())
        (*it)->SynchronizeAttribute();
    }

    GetElementData()->animated_svg_attributes_are_dirty_ = false;
  } else {
    SVGAnimatedPropertyBase* property = attribute_to_property_map_.at(name);
    if (property && property->NeedsSynchronizeAttribute())
      property->SynchronizeAttribute();
  }
}

Project: Chrome

void SVGElement::Trace(blink::Visitor* visitor) {
  visitor->Trace(elements_with_relative_lengths_);
  visitor->Trace(attribute_to_property_map_);
  visitor->Trace(svg_rare_data_);
  visitor->Trace(class_name_);
  Element::Trace(visitor);
}

Project: Chrome

TreeScope& SVGElement::TreeScopeForIdResolution() const {
  const SVGElement* tree_scope_element = this;
  if (const SVGElement* element = CorrespondingUseElement())
    tree_scope_element = element;
  return tree_scope_element->GetTreeScope();
}

Project: Chrome

void SVGElement::WillRecalcStyle(StyleRecalcChange change) {
  if (!HasSVGRareData())
    return;
  if (change > kNoChange || NeedsStyleRecalc())
    SvgRareData()->SetNeedsOverrideComputedStyleUpdate();
}

Project: Chrome

SVGSVGElement* SVGElement::ownerSVGElement() const {
  ContainerNode* n = ParentOrShadowHostNode();
  while (n) {
    if (IsSVGSVGElement(*n))
      return ToSVGSVGElement(n);

    n = n->ParentOrShadowHostNode();
  }

  return nullptr;
}

Project: Chrome

int SVGElement::tabIndex() const {
  if (SupportsFocus())
    return Element::tabIndex();
  return -1;
}

Project: Chrome

String SVGElement::title() const {
  if (IsSVGSVGElement(*this) && this == GetDocument().documentElement())
    return String();

  if (InUseShadowTree()) {
    String use_title(OwnerShadowHost()->title());
    if (!use_title.IsEmpty())
      return use_title;
  }

  if (Element* title_element = Traversal<SVGTitleElement>::FirstChild(*this))
    return title_element->innerText();

  return String();
}

Project: Chrome

SVGElement* SVGElement::viewportElement() const {
  ContainerNode* n = ParentOrShadowHostNode();
  while (n) {
    if (IsSVGSVGElement(*n) || IsSVGImageElement(*n) || IsSVGSymbolElement(*n))
      return ToSVGElement(n);

    n = n->ParentOrShadowHostNode();
  }

  return nullptr;
}

Project: Chrome

SVGElement::InstanceUpdateBlocker::~InstanceUpdateBlocker() {
  if (target_element_)
    target_element_->SetInstanceUpdatesBlocked(false);
}

Project: Chrome

SVGElement::~SVGElement() {
  DCHECK(isConnected() || !HasRelativeLengths());
}