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 +}