text: /*
   * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org>
   * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
   * Copyright (C) 2005 Alexander Kellett <lypanov@kde.org>
   * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
   * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
   * Copyright (C) 2014 Adobe Systems Incorporated. All rights reserved.
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Library General Public
   * License as published by the Free Software Foundation; either
   * version 2 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Library General Public License for more details.
   *
   * You should have received a copy of the GNU Library General Public License
   * along with this library; see the file COPYING.LIB.  If not, write to
   * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   * Boston, MA 02110-1301, USA.
   */
  
  #include "config.h"
  #include "SVGMaskElement.h"
  
  #include "RenderSVGResourceMasker.h"
  #include "SVGNames.h"
  #include "SVGRenderSupport.h"
  #include "SVGStringList.h"
  #include "SVGUnitTypes.h"
  #include "StyleResolver.h"
  #include <wtf/NeverDestroyed.h>
  
  namespace WebCore {
  
  // Animated property definitions
  DEFINE_ANIMATED_ENUMERATION(SVGMaskElement, SVGNames::maskUnitsAttr, MaskUnits, maskUnits, SVGUnitTypes::SVGUnitType)
  DEFINE_ANIMATED_ENUMERATION(SVGMaskElement, SVGNames::maskContentUnitsAttr, MaskContentUnits, maskContentUnits, SVGUnitTypes::SVGUnitType)
  DEFINE_ANIMATED_LENGTH(SVGMaskElement, SVGNames::xAttr, X, x)
  DEFINE_ANIMATED_LENGTH(SVGMaskElement, SVGNames::yAttr, Y, y)
  DEFINE_ANIMATED_LENGTH(SVGMaskElement, SVGNames::widthAttr, Width, width)
  DEFINE_ANIMATED_LENGTH(SVGMaskElement, SVGNames::heightAttr, Height, height)
  DEFINE_ANIMATED_BOOLEAN(SVGMaskElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
  
  BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGMaskElement)
      REGISTER_LOCAL_ANIMATED_PROPERTY(maskUnits)
      REGISTER_LOCAL_ANIMATED_PROPERTY(maskContentUnits)
      REGISTER_LOCAL_ANIMATED_PROPERTY(x)
      REGISTER_LOCAL_ANIMATED_PROPERTY(y)
      REGISTER_LOCAL_ANIMATED_PROPERTY(width)
      REGISTER_LOCAL_ANIMATED_PROPERTY(height)
      REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
      REGISTER_PARENT_ANIMATED_PROPERTIES(SVGElement)
      REGISTER_PARENT_ANIMATED_PROPERTIES(SVGTests)
  END_REGISTER_ANIMATED_PROPERTIES
  
  inline SVGMaskElement::SVGMaskElement(const QualifiedName& tagName, Document& document)
      : SVGElement(tagName, document)
      , m_maskUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
      , m_maskContentUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
      , m_x(LengthModeWidth, "-10%")
      , m_y(LengthModeHeight, "-10%")
      , m_width(LengthModeWidth, "120%")
      , m_height(LengthModeHeight, "120%")
  {
      // Spec: If the x/y attribute is not specified, the effect is as if a value of "-10%" were specified.
      // Spec: If the width/height attribute is not specified, the effect is as if a value of "120%" were specified.
      ASSERT(hasTagName(SVGNames::maskTag));
      registerAnimatedPropertiesForSVGMaskElement();
  }
  
  Ref<SVGMaskElement> SVGMaskElement::create(const QualifiedName& tagName, Document& document)
  {
      return adoptRef(*new SVGMaskElement(tagName, document));
  }
  
  bool SVGMaskElement::isSupportedAttribute(const QualifiedName& attrName)
  {
      static const auto supportedAttributes = makeNeverDestroyed([] {
          HashSet<QualifiedName> set;
          SVGTests::addSupportedAttributes(set);
          SVGLangSpace::addSupportedAttributes(set);
          SVGExternalResourcesRequired::addSupportedAttributes(set);
          set.add({
              SVGNames::maskUnitsAttr,
              SVGNames::maskContentUnitsAttr,
              SVGNames::refYAttr,
              SVGNames::xAttr,
              SVGNames::yAttr,
              SVGNames::widthAttr,
              SVGNames::heightAttr,
          });
          return set;
      }());
      return supportedAttributes.get().contains<SVGAttributeHashTranslator>(attrName);
  }
  
  void SVGMaskElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
  {
      if (name == SVGNames::maskUnitsAttr) {
          auto propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
          if (propertyValue > 0)
              setMaskUnitsBaseValue(propertyValue);
          return;
      }
      if (name == SVGNames::maskContentUnitsAttr) {
          auto propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
          if (propertyValue > 0)
              setMaskContentUnitsBaseValue(propertyValue);
          return;
      }
  
      SVGParsingError parseError = NoError;
  
      if (name == SVGNames::xAttr)
          setXBaseValue(SVGLengthValue::construct(LengthModeWidth, value, parseError));
      else if (name == SVGNames::yAttr)
          setYBaseValue(SVGLengthValue::construct(LengthModeHeight, value, parseError));
      else if (name == SVGNames::widthAttr)
          setWidthBaseValue(SVGLengthValue::construct(LengthModeWidth, value, parseError));
      else if (name == SVGNames::heightAttr)
          setHeightBaseValue(SVGLengthValue::construct(LengthModeHeight, value, parseError));
  
      reportAttributeParsingError(parseError, name, value);
  
      SVGElement::parseAttribute(name, value);
      SVGTests::parseAttribute(name, value);
      SVGExternalResourcesRequired::parseAttribute(name, value);
  }
  
  void SVGMaskElement::svgAttributeChanged(const QualifiedName& attrName)
  {
      if (!isSupportedAttribute(attrName)) {
          SVGElement::svgAttributeChanged(attrName);
          return;
      }
  
      InstanceInvalidationGuard guard(*this);
  
      if (attrName == SVGNames::xAttr
          || attrName == SVGNames::yAttr
          || attrName == SVGNames::widthAttr
          || attrName == SVGNames::heightAttr) {
          invalidateSVGPresentationAttributeStyle();
          return;
      }
  
      if (RenderObject* object = renderer())
          object->setNeedsLayout();
  }
  
  void SVGMaskElement::childrenChanged(const ChildChange& change)
  {
      SVGElement::childrenChanged(change);
  
      if (change.source == ChildChangeSourceParser)
          return;
  
      if (RenderObject* object = renderer())
          object->setNeedsLayout();
  }
  
  RenderPtr<RenderElement> SVGMaskElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
  {
      return createRenderer<RenderSVGResourceMasker>(*this, WTFMove(style));
  }
  
  Ref<SVGStringList> SVGMaskElement::requiredFeatures()
  {
      return SVGTests::requiredFeatures(*this);
  }
  
  Ref<SVGStringList> SVGMaskElement::requiredExtensions()
  { 
      return SVGTests::requiredExtensions(*this);
  }
  
  Ref<SVGStringList> SVGMaskElement::systemLanguage()
  {
      return SVGTests::systemLanguage(*this);
  }
  
  }
  