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