1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Mozilla SVG project.
16 : *
17 : * The Initial Developer of the Original Code is IBM Corporation.
18 : * Portions created by the Initial Developer are Copyright (C) 2004
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : *
23 : * Alternatively, the contents of this file may be used under the terms of
24 : * either the GNU General Public License Version 2 or later (the "GPL"), or
25 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 : * in which case the provisions of the GPL or the LGPL are applicable instead
27 : * of those above. If you wish to allow use of your version of this file only
28 : * under the terms of either the GPL or the LGPL, and not to allow others to
29 : * use your version of this file under the terms of the MPL, indicate your
30 : * decision by deleting the provisions above and replace them with the notice
31 : * and other provisions required by the GPL or the LGPL. If you do not delete
32 : * the provisions above, a recipient may use your version of this file under
33 : * the terms of any one of the MPL, the GPL or the LGPL.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #include "nsSVGGFrame.h"
38 : #include "nsIAnonymousContentCreator.h"
39 : #include "nsIDOMSVGUseElement.h"
40 : #include "nsIDOMSVGTransformable.h"
41 : #include "nsSVGElement.h"
42 : #include "nsSVGUseElement.h"
43 : #include "gfxMatrix.h"
44 :
45 : typedef nsSVGGFrame nsSVGUseFrameBase;
46 :
47 : class nsSVGUseFrame : public nsSVGUseFrameBase,
48 : public nsIAnonymousContentCreator
49 0 : {
50 : friend nsIFrame*
51 : NS_NewSVGUseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
52 :
53 : protected:
54 0 : nsSVGUseFrame(nsStyleContext* aContext) :
55 : nsSVGUseFrameBase(aContext),
56 0 : mHasValidDimensions(true)
57 0 : {}
58 :
59 : public:
60 : NS_DECL_QUERYFRAME
61 : NS_DECL_FRAMEARENA_HELPERS
62 :
63 :
64 : // nsIFrame interface:
65 : NS_IMETHOD Init(nsIContent* aContent,
66 : nsIFrame* aParent,
67 : nsIFrame* aPrevInFlow);
68 :
69 : NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
70 : nsIAtom* aAttribute,
71 : PRInt32 aModType);
72 :
73 : virtual void DestroyFrom(nsIFrame* aDestructRoot);
74 :
75 : /**
76 : * Get the "type" of the frame
77 : *
78 : * @see nsGkAtoms::svgUseFrame
79 : */
80 : virtual nsIAtom* GetType() const;
81 :
82 : virtual bool IsLeaf() const;
83 :
84 : #ifdef DEBUG
85 0 : NS_IMETHOD GetFrameName(nsAString& aResult) const
86 : {
87 0 : return MakeFrameName(NS_LITERAL_STRING("SVGUse"), aResult);
88 : }
89 : #endif
90 :
91 : // nsISVGChildFrame interface:
92 : virtual void NotifySVGChanged(PRUint32 aFlags);
93 :
94 : // nsIAnonymousContentCreator
95 : virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements);
96 : virtual void AppendAnonymousContentTo(nsBaseContentList& aElements,
97 : PRUint32 aFilter);
98 :
99 : private:
100 : bool mHasValidDimensions;
101 : };
102 :
103 : //----------------------------------------------------------------------
104 : // Implementation
105 :
106 : nsIFrame*
107 0 : NS_NewSVGUseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
108 : {
109 0 : return new (aPresShell) nsSVGUseFrame(aContext);
110 : }
111 :
112 0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGUseFrame)
113 :
114 : nsIAtom *
115 0 : nsSVGUseFrame::GetType() const
116 : {
117 0 : return nsGkAtoms::svgUseFrame;
118 : }
119 :
120 : //----------------------------------------------------------------------
121 : // nsQueryFrame methods
122 :
123 0 : NS_QUERYFRAME_HEAD(nsSVGUseFrame)
124 0 : NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
125 0 : NS_QUERYFRAME_TAIL_INHERITING(nsSVGUseFrameBase)
126 :
127 : //----------------------------------------------------------------------
128 : // nsIFrame methods:
129 :
130 : NS_IMETHODIMP
131 0 : nsSVGUseFrame::Init(nsIContent* aContent,
132 : nsIFrame* aParent,
133 : nsIFrame* aPrevInFlow)
134 : {
135 : #ifdef DEBUG
136 0 : nsCOMPtr<nsIDOMSVGUseElement> use = do_QueryInterface(aContent);
137 0 : NS_ASSERTION(use, "Content is not an SVG use!");
138 : #endif /* DEBUG */
139 :
140 : mHasValidDimensions =
141 0 : static_cast<nsSVGUseElement*>(aContent)->HasValidDimensions();
142 :
143 0 : return nsSVGUseFrameBase::Init(aContent, aParent, aPrevInFlow);
144 : }
145 :
146 : NS_IMETHODIMP
147 0 : nsSVGUseFrame::AttributeChanged(PRInt32 aNameSpaceID,
148 : nsIAtom* aAttribute,
149 : PRInt32 aModType)
150 : {
151 0 : if (aNameSpaceID == kNameSpaceID_None) {
152 0 : if (aAttribute == nsGkAtoms::x ||
153 : aAttribute == nsGkAtoms::y) {
154 : // make sure our cached transform matrix gets (lazily) updated
155 0 : mCanvasTM = nsnull;
156 :
157 0 : nsSVGUtils::NotifyChildrenOfSVGChange(this, TRANSFORM_CHANGED);
158 0 : } else if (aAttribute == nsGkAtoms::width ||
159 : aAttribute == nsGkAtoms::height) {
160 0 : static_cast<nsSVGUseElement*>(mContent)->SyncWidthOrHeight(aAttribute);
161 :
162 0 : if (mHasValidDimensions !=
163 0 : static_cast<nsSVGUseElement*>(mContent)->HasValidDimensions()) {
164 :
165 0 : mHasValidDimensions = !mHasValidDimensions;
166 0 : nsSVGUtils::UpdateGraphic(this);
167 : }
168 : }
169 0 : } else if (aNameSpaceID == kNameSpaceID_XLink &&
170 : aAttribute == nsGkAtoms::href) {
171 : // we're changing our nature, clear out the clone information
172 0 : nsSVGUseElement *use = static_cast<nsSVGUseElement*>(mContent);
173 0 : use->mOriginal = nsnull;
174 0 : use->UnlinkSource();
175 0 : use->TriggerReclone();
176 : }
177 :
178 : return nsSVGUseFrameBase::AttributeChanged(aNameSpaceID,
179 0 : aAttribute, aModType);
180 : }
181 :
182 : void
183 0 : nsSVGUseFrame::DestroyFrom(nsIFrame* aDestructRoot)
184 : {
185 0 : nsRefPtr<nsSVGUseElement> use = static_cast<nsSVGUseElement*>(mContent);
186 0 : nsSVGUseFrameBase::DestroyFrom(aDestructRoot);
187 0 : use->DestroyAnonymousContent();
188 0 : }
189 :
190 : bool
191 0 : nsSVGUseFrame::IsLeaf() const
192 : {
193 0 : return true;
194 : }
195 :
196 :
197 : //----------------------------------------------------------------------
198 : // nsISVGChildFrame methods
199 :
200 : void
201 0 : nsSVGUseFrame::NotifySVGChanged(PRUint32 aFlags)
202 : {
203 0 : if (aFlags & COORD_CONTEXT_CHANGED &&
204 0 : !(aFlags & TRANSFORM_CHANGED)) {
205 : // Coordinate context changes affect mCanvasTM if we have a
206 : // percentage 'x' or 'y'
207 0 : nsSVGUseElement *use = static_cast<nsSVGUseElement*>(mContent);
208 0 : if (use->mLengthAttributes[nsSVGUseElement::X].IsPercentage() ||
209 0 : use->mLengthAttributes[nsSVGUseElement::Y].IsPercentage()) {
210 0 : aFlags |= TRANSFORM_CHANGED;
211 : }
212 : }
213 :
214 0 : nsSVGUseFrameBase::NotifySVGChanged(aFlags);
215 0 : }
216 :
217 : //----------------------------------------------------------------------
218 : // nsIAnonymousContentCreator methods:
219 :
220 : nsresult
221 0 : nsSVGUseFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
222 : {
223 0 : nsSVGUseElement *use = static_cast<nsSVGUseElement*>(mContent);
224 :
225 0 : nsIContent* clone = use->CreateAnonymousContent();
226 0 : if (!clone)
227 0 : return NS_ERROR_FAILURE;
228 0 : if (!aElements.AppendElement(clone))
229 0 : return NS_ERROR_OUT_OF_MEMORY;
230 0 : return NS_OK;
231 : }
232 :
233 : void
234 0 : nsSVGUseFrame::AppendAnonymousContentTo(nsBaseContentList& aElements,
235 : PRUint32 aFilter)
236 : {
237 0 : nsSVGUseElement *use = static_cast<nsSVGUseElement*>(mContent);
238 0 : nsIContent* clone = use->GetAnonymousContent();
239 0 : aElements.MaybeAppendElement(clone);
240 0 : }
|