OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org> | 2 * Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org> |
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Rob Buis <buis@kde.org> | 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Rob Buis <buis@kde.org> |
4 * Copyright (C) 2007 Apple Inc. All rights reserved. | 4 * Copyright (C) 2007 Apple Inc. All rights reserved. |
5 * Copyright (C) 2014 Google, Inc. | 5 * Copyright (C) 2014 Google, Inc. |
6 * | 6 * |
7 * This library is free software; you can redistribute it and/or | 7 * This library is free software; you can redistribute it and/or |
8 * modify it under the terms of the GNU Library General Public | 8 * modify it under the terms of the GNU Library General Public |
9 * License as published by the Free Software Foundation; either | 9 * License as published by the Free Software Foundation; either |
10 * version 2 of the License, or (at your option) any later version. | 10 * version 2 of the License, or (at your option) any later version. |
(...skipping 21 matching lines...) Expand all Loading... |
32 #include "core/dom/StyleChangeReason.h" | 32 #include "core/dom/StyleChangeReason.h" |
33 #include "core/editing/FrameSelection.h" | 33 #include "core/editing/FrameSelection.h" |
34 #include "core/events/EventListener.h" | 34 #include "core/events/EventListener.h" |
35 #include "core/frame/Deprecation.h" | 35 #include "core/frame/Deprecation.h" |
36 #include "core/frame/FrameView.h" | 36 #include "core/frame/FrameView.h" |
37 #include "core/frame/LocalFrame.h" | 37 #include "core/frame/LocalFrame.h" |
38 #include "core/layout/LayoutObject.h" | 38 #include "core/layout/LayoutObject.h" |
39 #include "core/layout/svg/LayoutSVGModelObject.h" | 39 #include "core/layout/svg/LayoutSVGModelObject.h" |
40 #include "core/layout/svg/LayoutSVGRoot.h" | 40 #include "core/layout/svg/LayoutSVGRoot.h" |
41 #include "core/layout/svg/LayoutSVGViewportContainer.h" | 41 #include "core/layout/svg/LayoutSVGViewportContainer.h" |
42 #include "core/page/FrameTree.h" | |
43 #include "core/svg/SVGAngleTearOff.h" | 42 #include "core/svg/SVGAngleTearOff.h" |
44 #include "core/svg/SVGDocumentExtensions.h" | 43 #include "core/svg/SVGDocumentExtensions.h" |
45 #include "core/svg/SVGLengthTearOff.h" | 44 #include "core/svg/SVGLengthTearOff.h" |
46 #include "core/svg/SVGMatrixTearOff.h" | 45 #include "core/svg/SVGMatrixTearOff.h" |
47 #include "core/svg/SVGNumberTearOff.h" | 46 #include "core/svg/SVGNumberTearOff.h" |
48 #include "core/svg/SVGPointTearOff.h" | 47 #include "core/svg/SVGPointTearOff.h" |
49 #include "core/svg/SVGPreserveAspectRatio.h" | 48 #include "core/svg/SVGPreserveAspectRatio.h" |
50 #include "core/svg/SVGRectTearOff.h" | 49 #include "core/svg/SVGRectTearOff.h" |
51 #include "core/svg/SVGTransform.h" | 50 #include "core/svg/SVGTransform.h" |
52 #include "core/svg/SVGTransformList.h" | 51 #include "core/svg/SVGTransformList.h" |
(...skipping 22 matching lines...) Expand all Loading... |
75 CSSPropertyY)), | 74 CSSPropertyY)), |
76 m_width(SVGAnimatedLength::create(this, | 75 m_width(SVGAnimatedLength::create(this, |
77 SVGNames::widthAttr, | 76 SVGNames::widthAttr, |
78 SVGLength::create(SVGLengthMode::Width), | 77 SVGLength::create(SVGLengthMode::Width), |
79 CSSPropertyWidth)), | 78 CSSPropertyWidth)), |
80 m_height( | 79 m_height( |
81 SVGAnimatedLength::create(this, | 80 SVGAnimatedLength::create(this, |
82 SVGNames::heightAttr, | 81 SVGNames::heightAttr, |
83 SVGLength::create(SVGLengthMode::Height), | 82 SVGLength::create(SVGLengthMode::Height), |
84 CSSPropertyHeight)), | 83 CSSPropertyHeight)), |
85 m_useCurrentView(false), | |
86 m_timeContainer(SMILTimeContainer::create(*this)), | 84 m_timeContainer(SMILTimeContainer::create(*this)), |
87 m_translation(SVGPoint::create()), | 85 m_translation(SVGPoint::create()), |
88 m_currentScale(1) { | 86 m_currentScale(1) { |
89 m_width->setDefaultValueAsString("100%"); | 87 m_width->setDefaultValueAsString("100%"); |
90 m_height->setDefaultValueAsString("100%"); | 88 m_height->setDefaultValueAsString("100%"); |
91 | 89 |
92 addToPropertyMap(m_x); | 90 addToPropertyMap(m_x); |
93 addToPropertyMap(m_y); | 91 addToPropertyMap(m_y); |
94 addToPropertyMap(m_width); | 92 addToPropertyMap(m_width); |
95 addToPropertyMap(m_height); | 93 addToPropertyMap(m_height); |
96 | 94 |
97 UseCounter::count(doc, UseCounter::SVGSVGElement); | 95 UseCounter::count(doc, UseCounter::SVGSVGElement); |
98 } | 96 } |
99 | 97 |
100 DEFINE_NODE_FACTORY(SVGSVGElement) | 98 DEFINE_NODE_FACTORY(SVGSVGElement) |
101 | 99 |
102 SVGSVGElement::~SVGSVGElement() {} | 100 SVGSVGElement::~SVGSVGElement() {} |
103 | 101 |
104 SVGViewSpec& SVGSVGElement::ensureViewSpec() { | |
105 if (!m_viewSpec) | |
106 m_viewSpec = SVGViewSpec::create(); | |
107 return *m_viewSpec; | |
108 } | |
109 | |
110 float SVGSVGElement::currentScale() const { | 102 float SVGSVGElement::currentScale() const { |
111 if (!isConnected() || !isOutermostSVGSVGElement()) | 103 if (!isConnected() || !isOutermostSVGSVGElement()) |
112 return 1; | 104 return 1; |
113 | 105 |
114 return m_currentScale; | 106 return m_currentScale; |
115 } | 107 } |
116 | 108 |
117 void SVGSVGElement::setCurrentScale(float scale) { | 109 void SVGSVGElement::setCurrentScale(float scale) { |
118 ASSERT(std::isfinite(scale)); | 110 ASSERT(std::isfinite(scale)); |
119 if (!isConnected() || !isOutermostSVGSVGElement()) | 111 if (!isConnected() || !isOutermostSVGSVGElement()) |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 } | 143 } |
152 | 144 |
153 void SVGSVGElement::updateUserTransform() { | 145 void SVGSVGElement::updateUserTransform() { |
154 if (LayoutObject* object = layoutObject()) | 146 if (LayoutObject* object = layoutObject()) |
155 object->setNeedsLayoutAndFullPaintInvalidation( | 147 object->setNeedsLayoutAndFullPaintInvalidation( |
156 LayoutInvalidationReason::Unknown); | 148 LayoutInvalidationReason::Unknown); |
157 } | 149 } |
158 | 150 |
159 bool SVGSVGElement::zoomAndPanEnabled() const { | 151 bool SVGSVGElement::zoomAndPanEnabled() const { |
160 SVGZoomAndPanType zoomAndPan = this->zoomAndPan(); | 152 SVGZoomAndPanType zoomAndPan = this->zoomAndPan(); |
161 if (m_useCurrentView) | 153 if (m_viewSpec) |
162 zoomAndPan = m_viewSpec->zoomAndPan(); | 154 zoomAndPan = m_viewSpec->zoomAndPan(); |
163 return zoomAndPan == SVGZoomAndPanMagnify; | 155 return zoomAndPan == SVGZoomAndPanMagnify; |
164 } | 156 } |
165 | 157 |
166 void SVGSVGElement::parseAttribute(const QualifiedName& name, | 158 void SVGSVGElement::parseAttribute(const QualifiedName& name, |
167 const AtomicString& oldValue, | 159 const AtomicString& oldValue, |
168 const AtomicString& value) { | 160 const AtomicString& value) { |
169 if (!nearestViewportElement()) { | 161 if (!nearestViewportElement()) { |
170 bool setListener = true; | 162 bool setListener = true; |
171 | 163 |
(...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
590 m_width->currentValue()->isRelative() || | 582 m_width->currentValue()->isRelative() || |
591 m_height->currentValue()->isRelative(); | 583 m_height->currentValue()->isRelative(); |
592 } | 584 } |
593 | 585 |
594 bool SVGSVGElement::shouldSynthesizeViewBox() const { | 586 bool SVGSVGElement::shouldSynthesizeViewBox() const { |
595 return layoutObject() && layoutObject()->isSVGRoot() && | 587 return layoutObject() && layoutObject()->isSVGRoot() && |
596 toLayoutSVGRoot(layoutObject())->isEmbeddedThroughSVGImage(); | 588 toLayoutSVGRoot(layoutObject())->isEmbeddedThroughSVGImage(); |
597 } | 589 } |
598 | 590 |
599 FloatRect SVGSVGElement::currentViewBoxRect() const { | 591 FloatRect SVGSVGElement::currentViewBoxRect() const { |
600 if (m_useCurrentView) { | 592 if (m_viewSpec) |
601 DCHECK(m_viewSpec); | |
602 return m_viewSpec->viewBox()->value(); | 593 return m_viewSpec->viewBox()->value(); |
603 } | |
604 | 594 |
605 FloatRect useViewBox = viewBox()->currentValue()->value(); | 595 FloatRect useViewBox = viewBox()->currentValue()->value(); |
606 if (!useViewBox.isEmpty()) | 596 if (!useViewBox.isEmpty()) |
607 return useViewBox; | 597 return useViewBox; |
608 if (!shouldSynthesizeViewBox()) | 598 if (!shouldSynthesizeViewBox()) |
609 return FloatRect(); | 599 return FloatRect(); |
610 | 600 |
611 // If no viewBox is specified but non-relative width/height values, then we | 601 // If no viewBox is specified but non-relative width/height values, then we |
612 // should always synthesize a viewBox if we're embedded through a SVGImage. | 602 // should always synthesize a viewBox if we're embedded through a SVGImage. |
613 FloatSize synthesizedViewBoxSize(intrinsicWidth(), intrinsicHeight()); | 603 FloatSize synthesizedViewBoxSize(intrinsicWidth(), intrinsicHeight()); |
614 if (!hasIntrinsicWidth()) | 604 if (!hasIntrinsicWidth()) |
615 synthesizedViewBoxSize.setWidth(width()->currentValue()->scaleByPercentage( | 605 synthesizedViewBoxSize.setWidth(width()->currentValue()->scaleByPercentage( |
616 currentViewportSize().width())); | 606 currentViewportSize().width())); |
617 if (!hasIntrinsicHeight()) | 607 if (!hasIntrinsicHeight()) |
618 synthesizedViewBoxSize.setHeight( | 608 synthesizedViewBoxSize.setHeight( |
619 height()->currentValue()->scaleByPercentage( | 609 height()->currentValue()->scaleByPercentage( |
620 currentViewportSize().height())); | 610 currentViewportSize().height())); |
621 return FloatRect(FloatPoint(), synthesizedViewBoxSize); | 611 return FloatRect(FloatPoint(), synthesizedViewBoxSize); |
622 } | 612 } |
623 | 613 |
624 SVGPreserveAspectRatio* SVGSVGElement::currentPreserveAspectRatio() const { | 614 SVGPreserveAspectRatio* SVGSVGElement::currentPreserveAspectRatio() const { |
625 if (m_useCurrentView) { | 615 if (m_viewSpec) |
626 DCHECK(m_viewSpec); | |
627 return m_viewSpec->preserveAspectRatio(); | 616 return m_viewSpec->preserveAspectRatio(); |
628 } | 617 |
629 if (!viewBox()->currentValue()->isValid() && shouldSynthesizeViewBox()) { | 618 if (!viewBox()->currentValue()->isValid() && shouldSynthesizeViewBox()) { |
630 // If no viewBox is specified and we're embedded through SVGImage, then | 619 // If no viewBox is specified and we're embedded through SVGImage, then |
631 // synthesize a pAR with the value 'none'. | 620 // synthesize a pAR with the value 'none'. |
632 SVGPreserveAspectRatio* synthesizedPAR = SVGPreserveAspectRatio::create(); | 621 SVGPreserveAspectRatio* synthesizedPAR = SVGPreserveAspectRatio::create(); |
633 synthesizedPAR->setAlign( | 622 synthesizedPAR->setAlign( |
634 SVGPreserveAspectRatio::kSvgPreserveaspectratioNone); | 623 SVGPreserveAspectRatio::kSvgPreserveaspectratioNone); |
635 return synthesizedPAR; | 624 return synthesizedPAR; |
636 } | 625 } |
637 return preserveAspectRatio()->currentValue(); | 626 return preserveAspectRatio()->currentValue(); |
638 } | 627 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
680 | 669 |
681 SVGLengthContext lengthContext(this); | 670 SVGLengthContext lengthContext(this); |
682 return height()->currentValue()->value(lengthContext); | 671 return height()->currentValue()->value(lengthContext); |
683 } | 672 } |
684 | 673 |
685 AffineTransform SVGSVGElement::viewBoxToViewTransform(float viewWidth, | 674 AffineTransform SVGSVGElement::viewBoxToViewTransform(float viewWidth, |
686 float viewHeight) const { | 675 float viewHeight) const { |
687 AffineTransform ctm = SVGFitToViewBox::viewBoxToViewTransform( | 676 AffineTransform ctm = SVGFitToViewBox::viewBoxToViewTransform( |
688 currentViewBoxRect(), currentPreserveAspectRatio(), viewWidth, | 677 currentViewBoxRect(), currentPreserveAspectRatio(), viewWidth, |
689 viewHeight); | 678 viewHeight); |
690 if (!m_useCurrentView) | 679 if (!m_viewSpec) |
691 return ctm; | 680 return ctm; |
692 DCHECK(m_viewSpec); | |
693 | 681 |
694 SVGTransformList* transformList = m_viewSpec->transform(); | 682 SVGTransformList* transformList = m_viewSpec->transform(); |
695 if (transformList->isEmpty()) | 683 if (transformList->isEmpty()) |
696 return ctm; | 684 return ctm; |
697 | 685 |
698 AffineTransform transform; | 686 AffineTransform transform; |
699 if (transformList->concatenate(transform)) | 687 if (transformList->concatenate(transform)) |
700 ctm *= transform; | 688 ctm *= transform; |
701 | 689 |
702 return ctm; | 690 return ctm; |
703 } | 691 } |
704 | 692 |
| 693 void SVGSVGElement::setViewSpec(SVGViewSpec* viewSpec) { |
| 694 // Even if the viewspec object itself doesn't change, it could still |
| 695 // have been mutated, so only treat a "no viewspec" -> "no viewspec" |
| 696 // transition as a no-op. |
| 697 if (!m_viewSpec && !viewSpec) |
| 698 return; |
| 699 m_viewSpec = viewSpec; |
| 700 if (LayoutObject* layoutObject = this->layoutObject()) |
| 701 markForLayoutAndParentResourceInvalidation(layoutObject); |
| 702 } |
| 703 |
705 void SVGSVGElement::setupInitialView(const String& fragmentIdentifier, | 704 void SVGSVGElement::setupInitialView(const String& fragmentIdentifier, |
706 Element* anchorNode) { | 705 Element* anchorNode) { |
707 if (m_viewSpec) | |
708 m_viewSpec->reset(); | |
709 | |
710 // If we previously had a view, we need to layout again, regardless of the | |
711 // state after setting. | |
712 bool needsViewUpdate = m_useCurrentView; | |
713 m_useCurrentView = false; | |
714 | |
715 if (fragmentIdentifier.startsWith("svgView(")) { | 706 if (fragmentIdentifier.startsWith("svgView(")) { |
716 // Ensure the SVGViewSpec has been created. | 707 SVGViewSpec* viewSpec = SVGViewSpec::createForElement(*this); |
717 SVGViewSpec& view = ensureViewSpec(); | 708 if (viewSpec->parseViewSpec(fragmentIdentifier)) { |
718 view.inheritViewAttributesFromElement(this); | |
719 | |
720 if (view.parseViewSpec(fragmentIdentifier)) { | |
721 UseCounter::count(document(), UseCounter::SVGSVGElementFragmentSVGView); | 709 UseCounter::count(document(), UseCounter::SVGSVGElementFragmentSVGView); |
722 m_useCurrentView = true; | 710 setViewSpec(viewSpec); |
723 needsViewUpdate = true; | |
724 } else { | |
725 view.reset(); | |
726 } | |
727 } else if (isSVGViewElement(anchorNode)) { | |
728 // Spec: If the SVG fragment identifier addresses a 'view' element | |
729 // within an SVG document (e.g., MyDrawing.svg#MyView or | |
730 // MyDrawing.svg#xpointer(id('MyView'))) then the closest ancestor | |
731 // 'svg' element is displayed in the viewport. Any view specification | |
732 // attributes included on the given 'view' element override the | |
733 // corresponding view specification attributes on the closest ancestor | |
734 // 'svg' element. | |
735 // TODO(ed): The spec text above is a bit unclear. | |
736 // Should the transform from outermost svg to nested svg be applied to | |
737 // "display" the inner svg in the viewport, then let the view element | |
738 // override the inner svg's view specification attributes. Should it | |
739 // fill/override the outer viewport? | |
740 SVGViewElement& viewElement = toSVGViewElement(*anchorNode); | |
741 | |
742 if (SVGSVGElement* svg = viewElement.ownerSVGElement()) { | |
743 svg->inheritViewAttributes(&viewElement); | |
744 | |
745 if (LayoutObject* layoutObject = svg->layoutObject()) | |
746 markForLayoutAndParentResourceInvalidation(layoutObject); | |
747 | |
748 return; | 711 return; |
749 } | 712 } |
750 } | 713 } |
751 | 714 |
752 LayoutObject* layoutObject = this->layoutObject(); | 715 setViewSpec(nullptr); |
753 if (layoutObject && needsViewUpdate) | |
754 markForLayoutAndParentResourceInvalidation(layoutObject); | |
755 | 716 |
756 // If m_useCurrentView is true we should have a view-spec. | 717 if (!isSVGViewElement(anchorNode)) |
757 DCHECK(!m_useCurrentView || m_viewSpec); | 718 return; |
758 | 719 |
759 // FIXME: We need to decide which <svg> to focus on, and zoom to it. | 720 SVGViewElement& viewElement = toSVGViewElement(*anchorNode); |
760 // FIXME: We need to actually "highlight" the viewTarget(s). | |
761 } | |
762 | 721 |
763 void SVGSVGElement::inheritViewAttributes(SVGViewElement* viewElement) { | 722 // Spec: If the SVG fragment identifier addresses a 'view' element |
764 SVGViewSpec& view = ensureViewSpec(); | 723 // within an SVG document (e.g., MyDrawing.svg#MyView) then the |
765 m_useCurrentView = true; | 724 // closest ancestor 'svg' element is displayed in the |
766 UseCounter::count(document(), | 725 // viewport. Any view specification attributes included on the |
| 726 // given 'view' element override the corresponding view |
| 727 // specification attributes on the closest ancestor 'svg' element. |
| 728 // TODO(ed): The spec text above is a bit unclear. |
| 729 // Should the transform from outermost svg to nested svg be applied to |
| 730 // "display" the inner svg in the viewport, then let the view element |
| 731 // override the inner svg's view specification attributes. Should it |
| 732 // fill/override the outer viewport? |
| 733 SVGSVGElement* svg = viewElement.ownerSVGElement(); |
| 734 if (!svg) |
| 735 return; |
| 736 SVGViewSpec* viewSpec = SVGViewSpec::createForElement(*svg); |
| 737 viewSpec->inheritViewAttributesFromElement(viewElement); |
| 738 UseCounter::count(svg->document(), |
767 UseCounter::SVGSVGElementFragmentSVGViewElement); | 739 UseCounter::SVGSVGElementFragmentSVGViewElement); |
768 view.inheritViewAttributesFromElement(this); | 740 svg->setViewSpec(viewSpec); |
769 view.inheritViewAttributesFromElement(viewElement); | |
770 DCHECK(!m_useCurrentView || m_viewSpec); | |
771 } | 741 } |
772 | 742 |
773 void SVGSVGElement::finishParsingChildren() { | 743 void SVGSVGElement::finishParsingChildren() { |
774 SVGGraphicsElement::finishParsingChildren(); | 744 SVGGraphicsElement::finishParsingChildren(); |
775 | 745 |
776 // The outermost SVGSVGElement SVGLoad event is fired through | 746 // The outermost SVGSVGElement SVGLoad event is fired through |
777 // LocalDOMWindow::dispatchWindowLoadEvent. | 747 // LocalDOMWindow::dispatchWindowLoadEvent. |
778 if (isOutermostSVGSVGElement()) | 748 if (isOutermostSVGSVGElement()) |
779 return; | 749 return; |
780 | 750 |
781 // finishParsingChildren() is called when the close tag is reached for an | 751 // finishParsingChildren() is called when the close tag is reached for an |
782 // element (e.g. </svg>) we send SVGLoad events here if we can, otherwise | 752 // element (e.g. </svg>) we send SVGLoad events here if we can, otherwise |
783 // they'll be sent when any required loads finish | 753 // they'll be sent when any required loads finish |
784 sendSVGLoadEventIfPossible(); | 754 sendSVGLoadEventIfPossible(); |
785 } | 755 } |
786 | 756 |
787 DEFINE_TRACE(SVGSVGElement) { | 757 DEFINE_TRACE(SVGSVGElement) { |
788 visitor->trace(m_x); | 758 visitor->trace(m_x); |
789 visitor->trace(m_y); | 759 visitor->trace(m_y); |
790 visitor->trace(m_width); | 760 visitor->trace(m_width); |
791 visitor->trace(m_height); | 761 visitor->trace(m_height); |
792 visitor->trace(m_translation); | 762 visitor->trace(m_translation); |
793 visitor->trace(m_timeContainer); | 763 visitor->trace(m_timeContainer); |
794 visitor->trace(m_viewSpec); | 764 visitor->trace(m_viewSpec); |
795 SVGGraphicsElement::trace(visitor); | 765 SVGGraphicsElement::trace(visitor); |
796 SVGFitToViewBox::trace(visitor); | 766 SVGFitToViewBox::trace(visitor); |
797 } | 767 } |
798 | 768 |
799 } // namespace blink | 769 } // namespace blink |
OLD | NEW |