layout/svg/nsSVGFilterFrame.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/svg/nsSVGFilterFrame.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,205 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +// Main header first:
    1.10 +#include "nsSVGFilterFrame.h"
    1.11 +
    1.12 +// Keep others in (case-insensitive) order:
    1.13 +#include "gfxUtils.h"
    1.14 +#include "nsGkAtoms.h"
    1.15 +#include "nsRenderingContext.h"
    1.16 +#include "nsSVGEffects.h"
    1.17 +#include "nsSVGElement.h"
    1.18 +#include "mozilla/dom/SVGFilterElement.h"
    1.19 +#include "nsSVGFilterInstance.h"
    1.20 +#include "nsSVGFilterPaintCallback.h"
    1.21 +#include "nsSVGIntegrationUtils.h"
    1.22 +#include "nsSVGUtils.h"
    1.23 +#include "nsContentUtils.h"
    1.24 +
    1.25 +using namespace mozilla::dom;
    1.26 +
    1.27 +nsIFrame*
    1.28 +NS_NewSVGFilterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    1.29 +{
    1.30 +  return new (aPresShell) nsSVGFilterFrame(aContext);
    1.31 +}
    1.32 +
    1.33 +NS_IMPL_FRAMEARENA_HELPERS(nsSVGFilterFrame)
    1.34 +
    1.35 +class MOZ_STACK_CLASS nsSVGFilterFrame::AutoFilterReferencer
    1.36 +{
    1.37 +public:
    1.38 +  AutoFilterReferencer(nsSVGFilterFrame *aFrame MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
    1.39 +    : mFrame(aFrame)
    1.40 +  {
    1.41 +    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
    1.42 +    // Reference loops should normally be detected in advance and handled, so
    1.43 +    // we're not expecting to encounter them here
    1.44 +    NS_ABORT_IF_FALSE(!mFrame->mLoopFlag, "Undetected reference loop!");
    1.45 +    mFrame->mLoopFlag = true;
    1.46 +  }
    1.47 +  ~AutoFilterReferencer() {
    1.48 +    mFrame->mLoopFlag = false;
    1.49 +  }
    1.50 +private:
    1.51 +  nsSVGFilterFrame *mFrame;
    1.52 +  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
    1.53 +};
    1.54 +
    1.55 +uint16_t
    1.56 +nsSVGFilterFrame::GetEnumValue(uint32_t aIndex, nsIContent *aDefault)
    1.57 +{
    1.58 +  nsSVGEnum& thisEnum =
    1.59 +    static_cast<SVGFilterElement *>(mContent)->mEnumAttributes[aIndex];
    1.60 +
    1.61 +  if (thisEnum.IsExplicitlySet())
    1.62 +    return thisEnum.GetAnimValue();
    1.63 +
    1.64 +  AutoFilterReferencer filterRef(this);
    1.65 +
    1.66 +  nsSVGFilterFrame *next = GetReferencedFilterIfNotInUse();
    1.67 +  return next ? next->GetEnumValue(aIndex, aDefault) :
    1.68 +    static_cast<SVGFilterElement *>(aDefault)->
    1.69 +      mEnumAttributes[aIndex].GetAnimValue();
    1.70 +}
    1.71 +
    1.72 +const nsSVGLength2 *
    1.73 +nsSVGFilterFrame::GetLengthValue(uint32_t aIndex, nsIContent *aDefault)
    1.74 +{
    1.75 +  const nsSVGLength2 *thisLength =
    1.76 +    &static_cast<SVGFilterElement *>(mContent)->mLengthAttributes[aIndex];
    1.77 +
    1.78 +  if (thisLength->IsExplicitlySet())
    1.79 +    return thisLength;
    1.80 +
    1.81 +  AutoFilterReferencer filterRef(this);
    1.82 +
    1.83 +  nsSVGFilterFrame *next = GetReferencedFilterIfNotInUse();
    1.84 +  return next ? next->GetLengthValue(aIndex, aDefault) :
    1.85 +    &static_cast<SVGFilterElement *>(aDefault)->mLengthAttributes[aIndex];
    1.86 +}
    1.87 +
    1.88 +const SVGFilterElement *
    1.89 +nsSVGFilterFrame::GetFilterContent(nsIContent *aDefault)
    1.90 +{
    1.91 +  for (nsIContent* child = mContent->GetFirstChild();
    1.92 +       child;
    1.93 +       child = child->GetNextSibling()) {
    1.94 +    nsRefPtr<nsSVGFE> primitive;
    1.95 +    CallQueryInterface(child, (nsSVGFE**)getter_AddRefs(primitive));
    1.96 +    if (primitive) {
    1.97 +      return static_cast<SVGFilterElement *>(mContent);
    1.98 +    }
    1.99 +  }
   1.100 +
   1.101 +  AutoFilterReferencer filterRef(this);
   1.102 +
   1.103 +  nsSVGFilterFrame *next = GetReferencedFilterIfNotInUse();
   1.104 +  return next ? next->GetFilterContent(aDefault) :
   1.105 +    static_cast<SVGFilterElement *>(aDefault);
   1.106 +}
   1.107 +
   1.108 +nsSVGFilterFrame *
   1.109 +nsSVGFilterFrame::GetReferencedFilter()
   1.110 +{
   1.111 +  if (mNoHRefURI)
   1.112 +    return nullptr;
   1.113 +
   1.114 +  nsSVGPaintingProperty *property = static_cast<nsSVGPaintingProperty*>
   1.115 +    (Properties().Get(nsSVGEffects::HrefProperty()));
   1.116 +
   1.117 +  if (!property) {
   1.118 +    // Fetch our Filter element's xlink:href attribute
   1.119 +    SVGFilterElement *filter = static_cast<SVGFilterElement *>(mContent);
   1.120 +    nsAutoString href;
   1.121 +    filter->mStringAttributes[SVGFilterElement::HREF].GetAnimValue(href, filter);
   1.122 +    if (href.IsEmpty()) {
   1.123 +      mNoHRefURI = true;
   1.124 +      return nullptr; // no URL
   1.125 +    }
   1.126 +
   1.127 +    // Convert href to an nsIURI
   1.128 +    nsCOMPtr<nsIURI> targetURI;
   1.129 +    nsCOMPtr<nsIURI> base = mContent->GetBaseURI();
   1.130 +    nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
   1.131 +                                              mContent->GetCurrentDoc(), base);
   1.132 +
   1.133 +    property =
   1.134 +      nsSVGEffects::GetPaintingProperty(targetURI, this, nsSVGEffects::HrefProperty());
   1.135 +    if (!property)
   1.136 +      return nullptr;
   1.137 +  }
   1.138 +
   1.139 +  nsIFrame *result = property->GetReferencedFrame();
   1.140 +  if (!result)
   1.141 +    return nullptr;
   1.142 +
   1.143 +  nsIAtom* frameType = result->GetType();
   1.144 +  if (frameType != nsGkAtoms::svgFilterFrame)
   1.145 +    return nullptr;
   1.146 +
   1.147 +  return static_cast<nsSVGFilterFrame*>(result);
   1.148 +}
   1.149 +
   1.150 +nsSVGFilterFrame *
   1.151 +nsSVGFilterFrame::GetReferencedFilterIfNotInUse()
   1.152 +{
   1.153 +  nsSVGFilterFrame *referenced = GetReferencedFilter();
   1.154 +  if (!referenced)
   1.155 +    return nullptr;
   1.156 +
   1.157 +  if (referenced->mLoopFlag) {
   1.158 +    // XXXjwatt: we should really send an error to the JavaScript Console here:
   1.159 +    NS_WARNING("Filter reference loop detected while inheriting attribute!");
   1.160 +    return nullptr;
   1.161 +  }
   1.162 +
   1.163 +  return referenced;
   1.164 +}
   1.165 +
   1.166 +nsresult
   1.167 +nsSVGFilterFrame::AttributeChanged(int32_t  aNameSpaceID,
   1.168 +                                   nsIAtom* aAttribute,
   1.169 +                                   int32_t  aModType)
   1.170 +{
   1.171 +  if (aNameSpaceID == kNameSpaceID_None &&
   1.172 +      (aAttribute == nsGkAtoms::x ||
   1.173 +       aAttribute == nsGkAtoms::y ||
   1.174 +       aAttribute == nsGkAtoms::width ||
   1.175 +       aAttribute == nsGkAtoms::height ||
   1.176 +       aAttribute == nsGkAtoms::filterUnits ||
   1.177 +       aAttribute == nsGkAtoms::primitiveUnits)) {
   1.178 +    nsSVGEffects::InvalidateDirectRenderingObservers(this);
   1.179 +  } else if (aNameSpaceID == kNameSpaceID_XLink &&
   1.180 +             aAttribute == nsGkAtoms::href) {
   1.181 +    // Blow away our reference, if any
   1.182 +    Properties().Delete(nsSVGEffects::HrefProperty());
   1.183 +    mNoHRefURI = false;
   1.184 +    // And update whoever references us
   1.185 +    nsSVGEffects::InvalidateDirectRenderingObservers(this);
   1.186 +  }
   1.187 +  return nsSVGFilterFrameBase::AttributeChanged(aNameSpaceID,
   1.188 +                                                aAttribute, aModType);
   1.189 +}
   1.190 +
   1.191 +#ifdef DEBUG
   1.192 +void
   1.193 +nsSVGFilterFrame::Init(nsIContent* aContent,
   1.194 +                       nsIFrame* aParent,
   1.195 +                       nsIFrame* aPrevInFlow)
   1.196 +{
   1.197 +  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::filter),
   1.198 +               "Content is not an SVG filter");
   1.199 +
   1.200 +  nsSVGFilterFrameBase::Init(aContent, aParent, aPrevInFlow);
   1.201 +}
   1.202 +#endif /* DEBUG */
   1.203 +
   1.204 +nsIAtom *
   1.205 +nsSVGFilterFrame::GetType() const
   1.206 +{
   1.207 +  return nsGkAtoms::svgFilterFrame;
   1.208 +}

mercurial