Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/ContentEvents.h"
8 : #include "mozilla/dom/SVGSVGElement.h"
9 : #include "mozilla/dom/SVGSVGElementBinding.h"
10 : #include "mozilla/dom/SVGMatrix.h"
11 : #include "mozilla/dom/SVGViewElement.h"
12 : #include "mozilla/EventDispatcher.h"
13 :
14 : #include "DOMSVGLength.h"
15 : #include "DOMSVGNumber.h"
16 : #include "DOMSVGPoint.h"
17 : #include "nsLayoutStylesheetCache.h"
18 : #include "nsSVGAngle.h"
19 : #include "nsFrameSelection.h"
20 : #include "nsIFrame.h"
21 : #include "nsISVGSVGFrame.h"
22 : #include "nsSMILAnimationController.h"
23 : #include "nsSMILTimeContainer.h"
24 : #include "nsSVGDisplayableFrame.h"
25 : #include "nsSVGUtils.h"
26 : #include "SVGAngle.h"
27 :
28 44 : NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT_CHECK_PARSER(SVG)
29 :
30 : using namespace mozilla::gfx;
31 :
32 : namespace mozilla {
33 : namespace dom {
34 :
35 : nsSVGEnumMapping SVGSVGElement::sZoomAndPanMap[] = {
36 : {&nsGkAtoms::disable, SVG_ZOOMANDPAN_DISABLE},
37 : {&nsGkAtoms::magnify, SVG_ZOOMANDPAN_MAGNIFY},
38 : {nullptr, 0}
39 : };
40 :
41 : nsSVGElement::EnumInfo SVGSVGElement::sEnumInfo[1] =
42 : {
43 : { &nsGkAtoms::zoomAndPan,
44 : sZoomAndPanMap,
45 : SVG_ZOOMANDPAN_MAGNIFY
46 : }
47 : };
48 :
49 0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMSVGTranslatePoint, nsISVGPoint,
50 : mElement)
51 :
52 0 : NS_IMPL_ADDREF_INHERITED(DOMSVGTranslatePoint, nsISVGPoint)
53 0 : NS_IMPL_RELEASE_INHERITED(DOMSVGTranslatePoint, nsISVGPoint)
54 :
55 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGTranslatePoint)
56 0 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
57 : // We have to qualify nsISVGPoint because NS_GET_IID looks for a class in the
58 : // global namespace
59 0 : NS_INTERFACE_MAP_ENTRY(mozilla::nsISVGPoint)
60 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
61 0 : NS_INTERFACE_MAP_END
62 :
63 : DOMSVGPoint*
64 0 : DOMSVGTranslatePoint::Copy()
65 : {
66 0 : return new DOMSVGPoint(mPt.GetX(), mPt.GetY());
67 : }
68 :
69 : nsISupports*
70 0 : DOMSVGTranslatePoint::GetParentObject()
71 : {
72 0 : return static_cast<nsIDOMSVGElement*>(mElement);
73 : }
74 :
75 : void
76 0 : DOMSVGTranslatePoint::SetX(float aValue, ErrorResult& rv)
77 : {
78 0 : mElement->SetCurrentTranslate(aValue, mPt.GetY());
79 0 : }
80 :
81 : void
82 0 : DOMSVGTranslatePoint::SetY(float aValue, ErrorResult& rv)
83 : {
84 0 : mElement->SetCurrentTranslate(mPt.GetX(), aValue);
85 0 : }
86 :
87 : already_AddRefed<nsISVGPoint>
88 0 : DOMSVGTranslatePoint::MatrixTransform(SVGMatrix& matrix)
89 : {
90 0 : float a = matrix.A(), b = matrix.B(), c = matrix.C();
91 0 : float d = matrix.D(), e = matrix.E(), f = matrix.F();
92 0 : float x = mPt.GetX();
93 0 : float y = mPt.GetY();
94 :
95 0 : nsCOMPtr<nsISVGPoint> point = new DOMSVGPoint(a*x + c*y + e, b*x + d*y + f);
96 0 : return point.forget();
97 : }
98 :
99 : JSObject*
100 0 : SVGSVGElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
101 : {
102 0 : return SVGSVGElementBinding::Wrap(aCx, this, aGivenProto);
103 : }
104 :
105 : //----------------------------------------------------------------------
106 : // nsISupports methods
107 :
108 : NS_IMPL_CYCLE_COLLECTION_CLASS(SVGSVGElement)
109 :
110 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SVGSVGElement,
111 : SVGSVGElementBase)
112 0 : if (tmp->mTimedDocumentRoot) {
113 0 : tmp->mTimedDocumentRoot->Unlink();
114 : }
115 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
116 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SVGSVGElement,
117 : SVGSVGElementBase)
118 0 : if (tmp->mTimedDocumentRoot) {
119 0 : tmp->mTimedDocumentRoot->Traverse(&cb);
120 : }
121 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
122 :
123 1088 : NS_IMPL_ADDREF_INHERITED(SVGSVGElement,SVGSVGElementBase)
124 813 : NS_IMPL_RELEASE_INHERITED(SVGSVGElement,SVGSVGElementBase)
125 :
126 425 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(SVGSVGElement)
127 403 : NS_INTERFACE_TABLE_INHERITED(SVGSVGElement, nsIDOMNode, nsIDOMElement,
128 : nsIDOMSVGElement)
129 403 : NS_INTERFACE_TABLE_TAIL_INHERITING(SVGSVGElementBase)
130 :
131 0 : SVGView::SVGView()
132 : {
133 0 : mZoomAndPan.Init(SVGSVGElement::ZOOMANDPAN,
134 0 : SVG_ZOOMANDPAN_MAGNIFY);
135 0 : mViewBox.Init();
136 0 : mPreserveAspectRatio.Init();
137 0 : }
138 :
139 : //----------------------------------------------------------------------
140 : // Implementation
141 :
142 22 : SVGSVGElement::SVGSVGElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
143 22 : FromParser aFromParser)
144 : : SVGSVGElementBase(aNodeInfo),
145 : mCurrentTranslate(0.0f, 0.0f),
146 : mCurrentScale(1.0f),
147 : mPreviousTranslate(0.0f, 0.0f),
148 : mPreviousScale(1.0f),
149 21 : mStartAnimationOnBindToTree(aFromParser == NOT_FROM_PARSER ||
150 43 : aFromParser == FROM_PARSER_FRAGMENT ||
151 : aFromParser == FROM_PARSER_XSLT),
152 44 : mImageNeedsTransformInvalidation(false)
153 : {
154 22 : }
155 :
156 0 : SVGSVGElement::~SVGSVGElement()
157 : {
158 0 : }
159 :
160 : //----------------------------------------------------------------------
161 : // nsIDOMNode methods
162 :
163 0 : NS_IMPL_ELEMENT_CLONE_WITH_INIT_AND_PARSER(SVGSVGElement)
164 :
165 : //----------------------------------------------------------------------
166 : // nsIDOMSVGSVGElement methods:
167 :
168 : already_AddRefed<SVGAnimatedLength>
169 0 : SVGSVGElement::X()
170 : {
171 0 : return mLengthAttributes[ATTR_X].ToDOMAnimatedLength(this);
172 : }
173 :
174 : already_AddRefed<SVGAnimatedLength>
175 0 : SVGSVGElement::Y()
176 : {
177 0 : return mLengthAttributes[ATTR_Y].ToDOMAnimatedLength(this);
178 : }
179 :
180 : already_AddRefed<SVGAnimatedLength>
181 0 : SVGSVGElement::Width()
182 : {
183 0 : return mLengthAttributes[ATTR_WIDTH].ToDOMAnimatedLength(this);
184 : }
185 :
186 : already_AddRefed<SVGAnimatedLength>
187 0 : SVGSVGElement::Height()
188 : {
189 0 : return mLengthAttributes[ATTR_HEIGHT].ToDOMAnimatedLength(this);
190 : }
191 : float
192 0 : SVGSVGElement::PixelUnitToMillimeterX()
193 : {
194 0 : return MM_PER_INCH_FLOAT / 96;
195 : }
196 :
197 : float
198 0 : SVGSVGElement::PixelUnitToMillimeterY()
199 : {
200 0 : return PixelUnitToMillimeterX();
201 : }
202 :
203 : float
204 0 : SVGSVGElement::ScreenPixelToMillimeterX()
205 : {
206 0 : return MM_PER_INCH_FLOAT / 96;
207 : }
208 :
209 : float
210 0 : SVGSVGElement::ScreenPixelToMillimeterY()
211 : {
212 0 : return ScreenPixelToMillimeterX();
213 : }
214 : bool
215 2 : SVGSVGElement::UseCurrentView()
216 : {
217 2 : return mSVGView || mCurrentViewID;
218 : }
219 :
220 : float
221 0 : SVGSVGElement::CurrentScale()
222 : {
223 0 : return mCurrentScale;
224 : }
225 :
226 : #define CURRENT_SCALE_MAX 16.0f
227 : #define CURRENT_SCALE_MIN 0.0625f
228 :
229 : void
230 0 : SVGSVGElement::SetCurrentScale(float aCurrentScale)
231 : {
232 0 : SetCurrentScaleTranslate(aCurrentScale,
233 0 : mCurrentTranslate.GetX(), mCurrentTranslate.GetY());
234 0 : }
235 :
236 : already_AddRefed<nsISVGPoint>
237 0 : SVGSVGElement::CurrentTranslate()
238 : {
239 0 : nsCOMPtr<nsISVGPoint> point = new DOMSVGTranslatePoint(&mCurrentTranslate, this);
240 0 : return point.forget();
241 : }
242 :
243 : uint32_t
244 0 : SVGSVGElement::SuspendRedraw(uint32_t max_wait_milliseconds)
245 : {
246 : // suspendRedraw is a no-op in Mozilla, so it doesn't matter what
247 : // we return
248 0 : return 1;
249 : }
250 :
251 : void
252 0 : SVGSVGElement::UnsuspendRedraw(uint32_t suspend_handle_id)
253 : {
254 : // no-op
255 0 : }
256 :
257 : void
258 0 : SVGSVGElement::UnsuspendRedrawAll()
259 : {
260 : // no-op
261 0 : }
262 :
263 : void
264 0 : SVGSVGElement::ForceRedraw()
265 : {
266 : // no-op
267 0 : }
268 :
269 : void
270 0 : SVGSVGElement::PauseAnimations()
271 : {
272 0 : if (mTimedDocumentRoot) {
273 0 : mTimedDocumentRoot->Pause(nsSMILTimeContainer::PAUSE_SCRIPT);
274 : }
275 : // else we're not the outermost <svg> or not bound to a tree, so silently fail
276 0 : }
277 :
278 : void
279 0 : SVGSVGElement::UnpauseAnimations()
280 : {
281 0 : if (mTimedDocumentRoot) {
282 0 : mTimedDocumentRoot->Resume(nsSMILTimeContainer::PAUSE_SCRIPT);
283 : }
284 : // else we're not the outermost <svg> or not bound to a tree, so silently fail
285 0 : }
286 :
287 : bool
288 0 : SVGSVGElement::AnimationsPaused()
289 : {
290 0 : nsSMILTimeContainer* root = GetTimedDocumentRoot();
291 0 : return root && root->IsPausedByType(nsSMILTimeContainer::PAUSE_SCRIPT);
292 : }
293 :
294 : float
295 91 : SVGSVGElement::GetCurrentTime()
296 : {
297 91 : nsSMILTimeContainer* root = GetTimedDocumentRoot();
298 91 : if (root) {
299 91 : double fCurrentTimeMs = double(root->GetCurrentTime());
300 91 : return (float)(fCurrentTimeMs / PR_MSEC_PER_SEC);
301 : } else {
302 0 : return 0.f;
303 : }
304 : }
305 :
306 : void
307 36 : SVGSVGElement::SetCurrentTime(float seconds)
308 : {
309 36 : if (mTimedDocumentRoot) {
310 : // Make sure the timegraph is up-to-date
311 36 : FlushAnimations();
312 36 : double fMilliseconds = double(seconds) * PR_MSEC_PER_SEC;
313 : // Round to nearest whole number before converting, to avoid precision
314 : // errors
315 36 : nsSMILTime lMilliseconds = int64_t(NS_round(fMilliseconds));
316 36 : mTimedDocumentRoot->SetCurrentTime(lMilliseconds);
317 36 : AnimationNeedsResample();
318 : // Trigger synchronous sample now, to:
319 : // - Make sure we get an up-to-date paint after this method
320 : // - re-enable event firing (it got disabled during seeking, and it
321 : // doesn't get re-enabled until the first sample after the seek -- so
322 : // let's make that happen now.)
323 36 : FlushAnimations();
324 : }
325 : // else we're not the outermost <svg> or not bound to a tree, so silently fail
326 36 : }
327 :
328 : void
329 0 : SVGSVGElement::DeselectAll()
330 : {
331 0 : nsIFrame* frame = GetPrimaryFrame();
332 0 : if (frame) {
333 0 : RefPtr<nsFrameSelection> frameSelection = frame->GetFrameSelection();
334 0 : frameSelection->ClearNormalSelection();
335 : }
336 0 : }
337 :
338 : already_AddRefed<DOMSVGNumber>
339 0 : SVGSVGElement::CreateSVGNumber()
340 : {
341 0 : RefPtr<DOMSVGNumber> number = new DOMSVGNumber(ToSupports(this));
342 0 : return number.forget();
343 : }
344 :
345 : already_AddRefed<DOMSVGLength>
346 0 : SVGSVGElement::CreateSVGLength()
347 : {
348 0 : nsCOMPtr<DOMSVGLength> length = new DOMSVGLength();
349 0 : return length.forget();
350 : }
351 :
352 : already_AddRefed<SVGAngle>
353 0 : SVGSVGElement::CreateSVGAngle()
354 : {
355 0 : nsSVGAngle* angle = new nsSVGAngle();
356 0 : angle->Init();
357 0 : RefPtr<SVGAngle> svgangle = new SVGAngle(angle, this, SVGAngle::CreatedValue);
358 0 : return svgangle.forget();
359 : }
360 :
361 : already_AddRefed<nsISVGPoint>
362 0 : SVGSVGElement::CreateSVGPoint()
363 : {
364 0 : nsCOMPtr<nsISVGPoint> point = new DOMSVGPoint(0, 0);
365 0 : return point.forget();
366 : }
367 :
368 : already_AddRefed<SVGMatrix>
369 0 : SVGSVGElement::CreateSVGMatrix()
370 : {
371 0 : RefPtr<SVGMatrix> matrix = new SVGMatrix();
372 0 : return matrix.forget();
373 : }
374 :
375 : already_AddRefed<SVGIRect>
376 0 : SVGSVGElement::CreateSVGRect()
377 : {
378 0 : return NS_NewSVGRect(this);
379 : }
380 :
381 : already_AddRefed<SVGTransform>
382 0 : SVGSVGElement::CreateSVGTransform()
383 : {
384 0 : RefPtr<SVGTransform> transform = new SVGTransform();
385 0 : return transform.forget();
386 : }
387 :
388 : already_AddRefed<SVGTransform>
389 0 : SVGSVGElement::CreateSVGTransformFromMatrix(SVGMatrix& matrix)
390 : {
391 0 : RefPtr<SVGTransform> transform = new SVGTransform(matrix.GetMatrix());
392 0 : return transform.forget();
393 : }
394 :
395 : //----------------------------------------------------------------------
396 : // helper method for implementing SetCurrentScale/Translate
397 :
398 : void
399 0 : SVGSVGElement::SetCurrentScaleTranslate(float s, float x, float y)
400 : {
401 0 : if (s == mCurrentScale &&
402 0 : x == mCurrentTranslate.GetX() && y == mCurrentTranslate.GetY()) {
403 0 : return;
404 : }
405 :
406 : // Prevent bizarre behaviour and maxing out of CPU and memory by clamping
407 0 : if (s < CURRENT_SCALE_MIN)
408 0 : s = CURRENT_SCALE_MIN;
409 0 : else if (s > CURRENT_SCALE_MAX)
410 0 : s = CURRENT_SCALE_MAX;
411 :
412 : // IMPORTANT: If either mCurrentTranslate *or* mCurrentScale is changed then
413 : // mPreviousTranslate_x, mPreviousTranslate_y *and* mPreviousScale must all
414 : // be updated otherwise SVGZoomEvents will end up with invalid data. I.e. an
415 : // SVGZoomEvent's properties previousScale and previousTranslate must contain
416 : // the state of currentScale and currentTranslate immediately before the
417 : // change that caused the event's dispatch, which is *not* necessarily the
418 : // same thing as the values of currentScale and currentTranslate prior to
419 : // their own last change.
420 : //
421 : // XXX This comment is out-of-date due to removal of SVGZoomEvent. Can we
422 : // remove some of this code?
423 0 : mPreviousScale = mCurrentScale;
424 0 : mPreviousTranslate = mCurrentTranslate;
425 :
426 0 : mCurrentScale = s;
427 0 : mCurrentTranslate = SVGPoint(x, y);
428 :
429 : // now dispatch the appropriate event if we are the root element
430 0 : nsIDocument* doc = GetUncomposedDoc();
431 0 : if (doc) {
432 0 : nsCOMPtr<nsIPresShell> presShell = doc->GetShell();
433 0 : if (presShell && IsRoot()) {
434 0 : nsEventStatus status = nsEventStatus_eIgnore;
435 0 : if (mPreviousScale == mCurrentScale) {
436 0 : WidgetEvent svgScrollEvent(true, eSVGScroll);
437 0 : presShell->HandleDOMEventWithTarget(this, &svgScrollEvent, &status);
438 : }
439 0 : InvalidateTransformNotifyFrame();
440 : }
441 : }
442 : }
443 :
444 : void
445 0 : SVGSVGElement::SetCurrentTranslate(float x, float y)
446 : {
447 0 : SetCurrentScaleTranslate(mCurrentScale, x, y);
448 0 : }
449 :
450 : //----------------------------------------------------------------------
451 : // SVGZoomAndPanValues
452 : uint16_t
453 0 : SVGSVGElement::ZoomAndPan()
454 : {
455 0 : return mEnumAttributes[ZOOMANDPAN].GetAnimValue();
456 : }
457 :
458 : void
459 0 : SVGSVGElement::SetZoomAndPan(uint16_t aZoomAndPan, ErrorResult& rv)
460 : {
461 0 : if (aZoomAndPan == SVG_ZOOMANDPAN_DISABLE ||
462 : aZoomAndPan == SVG_ZOOMANDPAN_MAGNIFY) {
463 0 : mEnumAttributes[ZOOMANDPAN].SetBaseValue(aZoomAndPan, this);
464 0 : return;
465 : }
466 :
467 0 : rv.ThrowRangeError<MSG_INVALID_ZOOMANDPAN_VALUE_ERROR>();
468 : }
469 :
470 : //----------------------------------------------------------------------
471 : nsSMILTimeContainer*
472 91 : SVGSVGElement::GetTimedDocumentRoot()
473 : {
474 91 : if (mTimedDocumentRoot) {
475 91 : return mTimedDocumentRoot;
476 : }
477 :
478 : // We must not be the outermost <svg> element, try to find it
479 : SVGSVGElement *outerSVGElement =
480 0 : SVGContentUtils::GetOuterSVGElement(this);
481 :
482 0 : if (outerSVGElement) {
483 0 : return outerSVGElement->GetTimedDocumentRoot();
484 : }
485 : // invalid structure
486 0 : return nullptr;
487 : }
488 : //----------------------------------------------------------------------
489 : // nsSVGElement
490 : nsresult
491 22 : SVGSVGElement::BindToTree(nsIDocument* aDocument,
492 : nsIContent* aParent,
493 : nsIContent* aBindingParent,
494 : bool aCompileEventHandlers)
495 : {
496 22 : nsSMILAnimationController* smilController = nullptr;
497 :
498 22 : if (aDocument) {
499 22 : smilController = aDocument->GetAnimationController();
500 22 : if (smilController) {
501 : // SMIL is enabled in this document
502 22 : if (WillBeOutermostSVG(aParent, aBindingParent)) {
503 : // We'll be the outermost <svg> element. We'll need a time container.
504 22 : if (!mTimedDocumentRoot) {
505 22 : mTimedDocumentRoot = new nsSMILTimeContainer();
506 : }
507 : } else {
508 : // We're a child of some other <svg> element, so we don't need our own
509 : // time container. However, we need to make sure that we'll get a
510 : // kick-start if we get promoted to be outermost later on.
511 0 : mTimedDocumentRoot = nullptr;
512 0 : mStartAnimationOnBindToTree = true;
513 : }
514 : }
515 : }
516 :
517 22 : nsresult rv = SVGGraphicsElement::BindToTree(aDocument, aParent,
518 : aBindingParent,
519 22 : aCompileEventHandlers);
520 22 : NS_ENSURE_SUCCESS(rv,rv);
521 :
522 22 : nsIDocument* doc = GetComposedDoc();
523 22 : if (doc) {
524 : // Setup the style sheet during binding, not element construction,
525 : // because we could move the root SVG element from the document
526 : // that created it to another document.
527 22 : auto cache = nsLayoutStylesheetCache::For(doc->GetStyleBackendType());
528 22 : doc->EnsureOnDemandBuiltInUASheet(cache->SVGSheet());
529 : }
530 :
531 22 : if (mTimedDocumentRoot && smilController) {
532 22 : rv = mTimedDocumentRoot->SetParent(smilController);
533 22 : if (mStartAnimationOnBindToTree) {
534 1 : mTimedDocumentRoot->Begin();
535 1 : mStartAnimationOnBindToTree = false;
536 : }
537 : }
538 :
539 22 : return rv;
540 : }
541 :
542 : void
543 0 : SVGSVGElement::UnbindFromTree(bool aDeep, bool aNullParent)
544 : {
545 0 : if (mTimedDocumentRoot) {
546 0 : mTimedDocumentRoot->SetParent(nullptr);
547 : }
548 :
549 0 : SVGGraphicsElement::UnbindFromTree(aDeep, aNullParent);
550 0 : }
551 :
552 : nsSVGAnimatedTransformList*
553 132 : SVGSVGElement::GetAnimatedTransformList(uint32_t aFlags)
554 : {
555 132 : if (!(aFlags & DO_ALLOCATE) && mSVGView && mSVGView->mTransforms) {
556 0 : return mSVGView->mTransforms;
557 : }
558 132 : return SVGGraphicsElement::GetAnimatedTransformList(aFlags);
559 : }
560 :
561 : nsresult
562 26 : SVGSVGElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
563 : {
564 26 : if (aVisitor.mEvent->mMessage == eSVGLoad) {
565 21 : if (mTimedDocumentRoot) {
566 21 : mTimedDocumentRoot->Begin();
567 : // Set 'resample needed' flag, so that if any script calls a DOM method
568 : // that requires up-to-date animations before our first sample callback,
569 : // we'll force a synchronous sample.
570 21 : AnimationNeedsResample();
571 : }
572 : }
573 26 : return SVGSVGElementBase::GetEventTargetParent(aVisitor);
574 : }
575 :
576 : bool
577 0 : SVGSVGElement::IsEventAttributeNameInternal(nsIAtom* aName)
578 : {
579 : /* The events in EventNameType_SVGSVG are for events that are only
580 : applicable to outermost 'svg' elements. We don't check if we're an outer
581 : 'svg' element in case we're not inserted into the document yet, but since
582 : the target of the events in question will always be the outermost 'svg'
583 : element, this shouldn't cause any real problems.
584 : */
585 : return nsContentUtils::IsEventAttributeName(aName,
586 0 : (EventNameType_SVGGraphic | EventNameType_SVGSVG));
587 : }
588 :
589 : //----------------------------------------------------------------------
590 : // public helpers:
591 :
592 : int32_t
593 325 : SVGSVGElement::GetIntrinsicWidth()
594 : {
595 325 : if (mLengthAttributes[ATTR_WIDTH].IsPercentage()) {
596 0 : return -1;
597 : }
598 : // Passing |this| as a SVGViewportElement* invokes the variant of GetAnimValue
599 : // that uses the passed argument as the context, but that's fine since we
600 : // know the length isn't a percentage so the context won't be used (and we
601 : // need to pass the element to be able to resolve em/ex units).
602 325 : float width = mLengthAttributes[ATTR_WIDTH].GetAnimValue(this);
603 325 : return nsSVGUtils::ClampToInt(width);
604 : }
605 :
606 : int32_t
607 325 : SVGSVGElement::GetIntrinsicHeight()
608 : {
609 325 : if (mLengthAttributes[ATTR_HEIGHT].IsPercentage()) {
610 0 : return -1;
611 : }
612 : // Passing |this| as a SVGViewportElement* invokes the variant of GetAnimValue
613 : // that uses the passed argument as the context, but that's fine since we
614 : // know the length isn't a percentage so the context won't be used (and we
615 : // need to pass the element to be able to resolve em/ex units).
616 325 : float height = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(this);
617 325 : return nsSVGUtils::ClampToInt(height);
618 : }
619 :
620 : void
621 18 : SVGSVGElement::FlushImageTransformInvalidation()
622 : {
623 18 : MOZ_ASSERT(!GetParent(), "Should only be called on root node");
624 18 : MOZ_ASSERT(OwnerDoc()->IsBeingUsedAsImage(),
625 : "Should only be called on image documents");
626 :
627 18 : if (mImageNeedsTransformInvalidation) {
628 0 : InvalidateTransformNotifyFrame();
629 0 : mImageNeedsTransformInvalidation = false;
630 : }
631 18 : }
632 :
633 : //----------------------------------------------------------------------
634 : // implementation helpers
635 :
636 : bool
637 22 : SVGSVGElement::WillBeOutermostSVG(nsIContent* aParent,
638 : nsIContent* aBindingParent) const
639 : {
640 22 : nsIContent* parent = aBindingParent ? aBindingParent : aParent;
641 :
642 22 : while (parent && parent->IsSVGElement()) {
643 0 : if (parent->IsSVGElement(nsGkAtoms::foreignObject)) {
644 : // SVG in a foreignObject must have its own <svg> (nsSVGOuterSVGFrame).
645 0 : return false;
646 : }
647 0 : if (parent->IsSVGElement(nsGkAtoms::svg)) {
648 0 : return false;
649 : }
650 0 : parent = parent->GetParent();
651 : }
652 :
653 22 : return true;
654 : }
655 :
656 : void
657 0 : SVGSVGElement::InvalidateTransformNotifyFrame()
658 : {
659 0 : nsISVGSVGFrame* svgframe = do_QueryFrame(GetPrimaryFrame());
660 : // might fail this check if we've failed conditional processing
661 0 : if (svgframe) {
662 : svgframe->NotifyViewportOrTransformChanged(
663 0 : nsSVGDisplayableFrame::TRANSFORM_CHANGED);
664 : }
665 0 : }
666 :
667 : nsSVGElement::EnumAttributesInfo
668 42 : SVGSVGElement::GetEnumInfo()
669 : {
670 : return EnumAttributesInfo(mEnumAttributes, sEnumInfo,
671 42 : ArrayLength(sEnumInfo));
672 : }
673 :
674 : void
675 0 : SVGSVGElement::
676 : SetImageOverridePreserveAspectRatio(const SVGPreserveAspectRatio& aPAR)
677 : {
678 : #ifdef DEBUG
679 0 : MOZ_ASSERT(OwnerDoc()->IsBeingUsedAsImage(),
680 : "should only override preserveAspectRatio in images");
681 : #endif
682 :
683 0 : bool hasViewBoxRect = HasViewBoxRect();
684 0 : if (!hasViewBoxRect && ShouldSynthesizeViewBox()) {
685 : // My non-<svg:image> clients will have been painting me with a synthesized
686 : // viewBox, but my <svg:image> client that's about to paint me now does NOT
687 : // want that. Need to tell ourselves to flush our transform.
688 0 : mImageNeedsTransformInvalidation = true;
689 : }
690 :
691 0 : if (!hasViewBoxRect) {
692 0 : return; // preserveAspectRatio irrelevant (only matters if we have viewBox)
693 : }
694 :
695 0 : if (SetPreserveAspectRatioProperty(aPAR)) {
696 0 : mImageNeedsTransformInvalidation = true;
697 : }
698 : }
699 :
700 : void
701 0 : SVGSVGElement::ClearImageOverridePreserveAspectRatio()
702 : {
703 : #ifdef DEBUG
704 0 : MOZ_ASSERT(OwnerDoc()->IsBeingUsedAsImage(),
705 : "should only override image preserveAspectRatio in images");
706 : #endif
707 :
708 0 : if (!HasViewBoxRect() && ShouldSynthesizeViewBox()) {
709 : // My non-<svg:image> clients will want to paint me with a synthesized
710 : // viewBox, but my <svg:image> client that just painted me did NOT
711 : // use that. Need to tell ourselves to flush our transform.
712 0 : mImageNeedsTransformInvalidation = true;
713 : }
714 :
715 0 : if (ClearPreserveAspectRatioProperty()) {
716 0 : mImageNeedsTransformInvalidation = true;
717 : }
718 0 : }
719 :
720 : bool
721 0 : SVGSVGElement::SetPreserveAspectRatioProperty(const SVGPreserveAspectRatio& aPAR)
722 : {
723 0 : SVGPreserveAspectRatio* pAROverridePtr = new SVGPreserveAspectRatio(aPAR);
724 0 : nsresult rv = SetProperty(nsGkAtoms::overridePreserveAspectRatio,
725 : pAROverridePtr,
726 : nsINode::DeleteProperty<SVGPreserveAspectRatio>,
727 0 : true);
728 0 : MOZ_ASSERT(rv != NS_PROPTABLE_PROP_OVERWRITTEN,
729 : "Setting override value when it's already set...?");
730 :
731 0 : if (MOZ_UNLIKELY(NS_FAILED(rv))) {
732 : // property-insertion failed (e.g. OOM in property-table code)
733 : delete pAROverridePtr;
734 0 : return false;
735 : }
736 0 : return true;
737 : }
738 :
739 : const SVGPreserveAspectRatio*
740 539 : SVGSVGElement::GetPreserveAspectRatioProperty() const
741 : {
742 539 : void* valPtr = GetProperty(nsGkAtoms::overridePreserveAspectRatio);
743 539 : if (valPtr) {
744 0 : return static_cast<SVGPreserveAspectRatio*>(valPtr);
745 : }
746 539 : return nullptr;
747 : }
748 :
749 : bool
750 0 : SVGSVGElement::ClearPreserveAspectRatioProperty()
751 : {
752 0 : void* valPtr = UnsetProperty(nsGkAtoms::overridePreserveAspectRatio);
753 : delete static_cast<SVGPreserveAspectRatio*>(valPtr);
754 0 : return valPtr;
755 : }
756 :
757 :
758 : SVGPreserveAspectRatio
759 539 : SVGSVGElement::GetPreserveAspectRatioWithOverride() const
760 : {
761 539 : nsIDocument* doc = GetUncomposedDoc();
762 539 : if (doc && doc->IsBeingUsedAsImage()) {
763 539 : const SVGPreserveAspectRatio *pAROverridePtr = GetPreserveAspectRatioProperty();
764 539 : if (pAROverridePtr) {
765 0 : return *pAROverridePtr;
766 : }
767 : }
768 :
769 539 : SVGViewElement* viewElement = GetCurrentViewElement();
770 :
771 : // This check is equivalent to "!HasViewBoxRect() && ShouldSynthesizeViewBox()".
772 : // We're just holding onto the viewElement that HasViewBoxRect() would look up,
773 : // so that we don't have to look it up again later.
774 1617 : if (!((viewElement && viewElement->mViewBox.HasRect()) ||
775 539 : (mSVGView && mSVGView->mViewBox.HasRect()) ||
776 1196 : mViewBox.HasRect()) &&
777 118 : ShouldSynthesizeViewBox()) {
778 : // If we're synthesizing a viewBox, use preserveAspectRatio="none";
779 118 : return SVGPreserveAspectRatio(SVG_PRESERVEASPECTRATIO_NONE, SVG_MEETORSLICE_SLICE);
780 : }
781 :
782 421 : if (viewElement && viewElement->mPreserveAspectRatio.IsExplicitlySet()) {
783 0 : return viewElement->mPreserveAspectRatio.GetAnimValue();
784 : }
785 421 : if (mSVGView && mSVGView->mPreserveAspectRatio.IsExplicitlySet()) {
786 0 : return mSVGView->mPreserveAspectRatio.GetAnimValue();
787 : }
788 421 : return mPreserveAspectRatio.GetAnimValue();
789 : }
790 :
791 : SVGViewElement*
792 2015 : SVGSVGElement::GetCurrentViewElement() const
793 : {
794 2015 : if (mCurrentViewID) {
795 : //XXXsmaug It is unclear how this should work in case we're in Shadow DOM.
796 0 : nsIDocument* doc = GetUncomposedDoc();
797 0 : if (doc) {
798 0 : Element *element = doc->GetElementById(*mCurrentViewID);
799 0 : if (element && element->IsSVGElement(nsGkAtoms::view)) {
800 0 : return static_cast<SVGViewElement*>(element);
801 : }
802 : }
803 : }
804 2015 : return nullptr;
805 : }
806 :
807 : const nsSVGViewBox&
808 1475 : SVGSVGElement::GetViewBoxInternal() const
809 : {
810 1475 : SVGViewElement* viewElement = GetCurrentViewElement();
811 :
812 1475 : if (viewElement && viewElement->mViewBox.HasRect()) {
813 0 : return viewElement->mViewBox;
814 1475 : } else if (mSVGView && mSVGView->mViewBox.HasRect()) {
815 0 : return mSVGView->mViewBox;
816 : }
817 :
818 1475 : return mViewBox;
819 : }
820 :
821 : nsSVGAnimatedTransformList*
822 0 : SVGSVGElement::GetTransformInternal() const
823 : {
824 0 : return (mSVGView && mSVGView->mTransforms)
825 0 : ? mSVGView->mTransforms: mTransforms;
826 : }
827 :
828 : } // namespace dom
829 : } // namespace mozilla
|