LCOV - code coverage report
Current view: top level - dom/svg - SVGViewportElement.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 78 113 69.0 %
Date: 2017-07-14 16:53:18 Functions: 14 18 77.8 %
Legend: Lines: hit not hit

          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 <stdint.h>
       8             : #include "mozilla/ArrayUtils.h"
       9             : #include "mozilla/ContentEvents.h"
      10             : #include "mozilla/EventDispatcher.h"
      11             : #include "mozilla/Likely.h"
      12             : #include "mozilla/dom/SVGMatrix.h"
      13             : #include "mozilla/dom/SVGViewportElement.h"
      14             : #include "mozilla/dom/SVGViewElement.h"
      15             : 
      16             : #include "DOMSVGLength.h"
      17             : #include "DOMSVGPoint.h"
      18             : #include "nsCOMPtr.h"
      19             : #include "nsContentUtils.h"
      20             : #include "nsFrameSelection.h"
      21             : #include "nsError.h"
      22             : #include "nsGkAtoms.h"
      23             : #include "nsIDocument.h"
      24             : #include "nsIFrame.h"
      25             : #include "nsIPresShell.h"
      26             : #include "nsISVGSVGFrame.h" //XXX
      27             : #include "nsLayoutUtils.h"
      28             : #include "nsStyleUtil.h"
      29             : #include "nsSMILTypes.h"
      30             : #include "SVGContentUtils.h"
      31             : 
      32             : #include <algorithm>
      33             : #include "prtime.h"
      34             : 
      35             : using namespace mozilla::gfx;
      36             : 
      37             : namespace mozilla {
      38             : namespace dom {
      39             : 
      40             : nsSVGElement::LengthInfo SVGViewportElement::sLengthInfo[4] =
      41             : {
      42             :   { &nsGkAtoms::x, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::X },
      43             :   { &nsGkAtoms::y, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::Y },
      44             :   { &nsGkAtoms::width, 100, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::X },
      45             :   { &nsGkAtoms::height, 100, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::Y },
      46             : };
      47             : 
      48             : //----------------------------------------------------------------------
      49             : // Implementation
      50             : 
      51          22 : SVGViewportElement::SVGViewportElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
      52             :   : SVGGraphicsElement(aNodeInfo),
      53             :     mViewportWidth(0),
      54             :     mViewportHeight(0),
      55          22 :     mHasChildrenOnlyTransform(false)
      56             : {
      57          22 : }
      58             : 
      59           0 : SVGViewportElement::~SVGViewportElement()
      60             : {
      61           0 : }
      62             : 
      63             : //----------------------------------------------------------------------
      64             : 
      65             : already_AddRefed<SVGAnimatedRect>
      66           0 : SVGViewportElement::ViewBox()
      67             : {
      68           0 :   return mViewBox.ToSVGAnimatedRect(this);
      69             : }
      70             : 
      71             : already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
      72           0 : SVGViewportElement::PreserveAspectRatio()
      73             : {
      74           0 :   return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(this);
      75             : }
      76             : 
      77             : //----------------------------------------------------------------------
      78             : // nsIContent methods
      79             : 
      80             : NS_IMETHODIMP_(bool)
      81         189 : SVGViewportElement::IsAttributeMapped(const nsIAtom* name) const
      82             : {
      83             :   // We want to map the 'width' and 'height' attributes into style for
      84             :   // outer-<svg>, except when the attributes aren't set (since their default
      85             :   // values of '100%' can cause unexpected and undesirable behaviour for SVG
      86             :   // inline in HTML). We rely on nsSVGElement::UpdateContentStyleRule() to
      87             :   // prevent mapping of the default values into style (it only maps attributes
      88             :   // that are set). We also rely on a check in nsSVGElement::
      89             :   // UpdateContentStyleRule() to prevent us mapping the attributes when they're
      90             :   // given a <length> value that is not currently recognized by the SVG
      91             :   // specification.
      92             : 
      93         189 :   if (!IsInner() && (name == nsGkAtoms::width || name == nsGkAtoms::height)) {
      94         123 :     return true;
      95             :   }
      96             : 
      97             :   static const MappedAttributeEntry* const map[] = {
      98             :     sColorMap,
      99             :     sFEFloodMap,
     100             :     sFillStrokeMap,
     101             :     sFiltersMap,
     102             :     sFontSpecificationMap,
     103             :     sGradientStopMap,
     104             :     sGraphicsMap,
     105             :     sLightingEffectsMap,
     106             :     sMarkersMap,
     107             :     sTextContentElementsMap,
     108             :     sViewportsMap
     109             :   };
     110             : 
     111         129 :   return FindAttributeDependence(name, map) ||
     112         129 :     SVGGraphicsElement::IsAttributeMapped(name);
     113             : }
     114             : 
     115             : //----------------------------------------------------------------------
     116             : // nsSVGElement overrides
     117             : 
     118             : // Helper for GetViewBoxTransform on root <svg> node
     119             : // * aLength: internal value for our <svg> width or height attribute.
     120             : // * aViewportLength: length of the corresponding dimension of the viewport.
     121             : // * aSelf: the outermost <svg> node itself.
     122             : // NOTE: aSelf is not an ancestor viewport element, so it can't be used to
     123             : // resolve percentage lengths. (It can only be used to resolve
     124             : // 'em'/'ex'-valued units).
     125             : inline float
     126         236 : ComputeSynthesizedViewBoxDimension(const nsSVGLength2& aLength,
     127             :                                    float aViewportLength,
     128             :                                    const SVGViewportElement* aSelf)
     129             : {
     130         236 :   if (aLength.IsPercentage()) {
     131           0 :     return aViewportLength * aLength.GetAnimValInSpecifiedUnits() / 100.0f;
     132             :   }
     133             : 
     134         236 :   return aLength.GetAnimValue(const_cast<SVGViewportElement*>(aSelf));
     135             : }
     136             : 
     137             : //----------------------------------------------------------------------
     138             : // public helpers:
     139             : 
     140             : void
     141          40 : SVGViewportElement::UpdateHasChildrenOnlyTransform()
     142             : {
     143             :   bool hasChildrenOnlyTransform =
     144          80 :     HasViewBoxOrSyntheticViewBox() ||
     145          41 :     (IsRoot() && (GetCurrentTranslate() != SVGPoint(0.0f, 0.0f) ||
     146          80 :                   GetCurrentScale() != 1.0f));
     147          40 :   mHasChildrenOnlyTransform = hasChildrenOnlyTransform;
     148          40 : }
     149             : 
     150             : void
     151          18 : SVGViewportElement::ChildrenOnlyTransformChanged(uint32_t aFlags)
     152             : {
     153             :   // Avoid wasteful calls:
     154          18 :   MOZ_ASSERT(!(GetPrimaryFrame()->GetStateBits() & NS_FRAME_IS_NONDISPLAY),
     155             :              "Non-display SVG frames don't maintain overflow rects");
     156             : 
     157             :   nsChangeHint changeHint;
     158             : 
     159          18 :   bool hadChildrenOnlyTransform = mHasChildrenOnlyTransform;
     160             : 
     161          18 :   UpdateHasChildrenOnlyTransform();
     162             : 
     163          18 :   if (hadChildrenOnlyTransform != mHasChildrenOnlyTransform) {
     164             :     // Reconstruct the frame tree to handle stacking context changes:
     165             :     // XXXjwatt don't do this for root-<svg> or even outer-<svg>?
     166           0 :     changeHint = nsChangeHint_ReconstructFrame;
     167             :   } else {
     168             :     // We just assume the old and new transforms are different.
     169             :     changeHint = nsChangeHint(nsChangeHint_UpdateOverflow |
     170          18 :                               nsChangeHint_ChildrenOnlyTransform);
     171             :   }
     172             : 
     173             :   // If we're not reconstructing the frame tree, then we only call
     174             :   // PostRestyleEvent if we're not being called under reflow to avoid recursing
     175             :   // to death. See bug 767056 comments 10 and 12. Since our nsSVGOuterSVGFrame
     176             :   // is being reflowed we're going to invalidate and repaint its entire area
     177             :   // anyway (which will include our children).
     178          36 :   if ((changeHint & nsChangeHint_ReconstructFrame) ||
     179          18 :       !(aFlags & eDuringReflow)) {
     180           0 :     nsLayoutUtils::PostRestyleEvent(this, nsRestyleHint(0), changeHint);
     181             :   }
     182          18 : }
     183             : 
     184             : gfx::Matrix
     185         770 : SVGViewportElement::GetViewBoxTransform() const
     186             : {
     187             :   float viewportWidth, viewportHeight;
     188         770 :   if (IsInner()) {
     189           0 :     SVGViewportElement *ctx = GetCtx();
     190           0 :     viewportWidth = mLengthAttributes[ATTR_WIDTH].GetAnimValue(ctx);
     191           0 :     viewportHeight = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(ctx);
     192             :   } else {
     193         770 :     viewportWidth = mViewportWidth;
     194         770 :     viewportHeight = mViewportHeight;
     195             :   }
     196             : 
     197         770 :   if (viewportWidth <= 0.0f || viewportHeight <= 0.0f) {
     198         231 :     return gfx::Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
     199             :   }
     200             : 
     201             :   nsSVGViewBoxRect viewBox =
     202         539 :     GetViewBoxWithSynthesis(viewportWidth, viewportHeight);
     203             : 
     204         539 :   if (viewBox.width <= 0.0f || viewBox.height <= 0.0f) {
     205           0 :     return gfx::Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
     206             :   }
     207             : 
     208             :   return SVGContentUtils::GetViewBoxTransform(viewportWidth, viewportHeight,
     209             :                                               viewBox.x, viewBox.y,
     210             :                                               viewBox.width, viewBox.height,
     211         539 :                                               GetPreserveAspectRatioWithOverride());
     212             : }
     213             : //----------------------------------------------------------------------
     214             : // SVGViewportElement
     215             : 
     216             : float
     217          84 : SVGViewportElement::GetLength(uint8_t aCtxType)
     218             : {
     219             :   const nsSVGViewBoxRect* viewbox =
     220          84 :     GetViewBoxInternal().HasRect() ? &GetViewBoxInternal().GetAnimValue()
     221          84 :                                    : nullptr;
     222             : 
     223             :   float h, w;
     224          84 :   if (viewbox) {
     225          84 :     w = viewbox->width;
     226          84 :     h = viewbox->height;
     227           0 :   } else if (IsInner()) {
     228           0 :     SVGViewportElement *ctx = GetCtx();
     229           0 :     w = mLengthAttributes[ATTR_WIDTH].GetAnimValue(ctx);
     230           0 :     h = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(ctx);
     231           0 :   } else if (ShouldSynthesizeViewBox()) {
     232           0 :     w = ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_WIDTH],
     233             :                                            mViewportWidth, this);
     234           0 :     h = ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_HEIGHT],
     235             :                                            mViewportHeight, this);
     236             :   } else {
     237           0 :     w = mViewportWidth;
     238           0 :     h = mViewportHeight;
     239             :   }
     240             : 
     241          84 :   w = std::max(w, 0.0f);
     242          84 :   h = std::max(h, 0.0f);
     243             : 
     244          84 :   switch (aCtxType) {
     245             :   case SVGContentUtils::X:
     246          42 :     return w;
     247             :   case SVGContentUtils::Y:
     248          42 :     return h;
     249             :   case SVGContentUtils::XY:
     250           0 :     return float(SVGContentUtils::ComputeNormalizedHypotenuse(w, h));
     251             :   }
     252           0 :   return 0;
     253             : }
     254             : 
     255             : //----------------------------------------------------------------------
     256             : // nsSVGElement methods
     257             : 
     258             : /* virtual */ gfxMatrix
     259         770 : SVGViewportElement::PrependLocalTransformsTo(const gfxMatrix& aMatrix,
     260             :                                         SVGTransformTypes aWhich) const
     261             : {
     262             :   // 'transform' attribute (or an override from a fragment identifier):
     263         770 :   gfxMatrix userToParent;
     264             : 
     265         770 :   if (aWhich == eUserSpaceToParent || aWhich == eAllTransforms) {
     266             :     userToParent = GetUserToParentTransform(mAnimateMotionTransform,
     267           0 :                                             GetTransformInternal());
     268           0 :     if (aWhich == eUserSpaceToParent) {
     269           0 :       return userToParent * aMatrix;
     270             :     }
     271             :   }
     272             : 
     273         770 :   gfxMatrix childToUser;
     274             : 
     275         770 :   if (IsInner()) {
     276             :     float x, y;
     277           0 :     const_cast<SVGViewportElement*>(this)->GetAnimatedLengthValues(&x, &y, nullptr);
     278           0 :     childToUser = ThebesMatrix(GetViewBoxTransform().PostTranslate(x, y));
     279         770 :   } else if (IsRoot()) {
     280         770 :     SVGPoint translate = GetCurrentTranslate();
     281         770 :     float scale = GetCurrentScale();
     282        1540 :     childToUser = ThebesMatrix(GetViewBoxTransform()
     283         770 :                                  .PostScale(scale, scale)
     284             :                                  .PostTranslate(translate.GetX(),
     285        1540 :                                                 translate.GetY()));
     286             :   } else {
     287             :     // outer-<svg>, but inline in some other content:
     288           0 :     childToUser = ThebesMatrix(GetViewBoxTransform());
     289             :   }
     290             : 
     291         770 :   if (aWhich == eAllTransforms) {
     292           0 :     return childToUser * userToParent * aMatrix;
     293             :   }
     294             : 
     295         770 :   MOZ_ASSERT(aWhich == eChildToUserSpace, "Unknown TransformTypes");
     296             : 
     297             :   // The following may look broken because pre-multiplying our eChildToUserSpace
     298             :   // transform with another matrix without including our eUserSpaceToParent
     299             :   // transform between the two wouldn't make sense.  We don't expect that to
     300             :   // ever happen though.  We get here either when the identity matrix has been
     301             :   // passed because our caller just wants our eChildToUserSpace transform, or
     302             :   // when our eUserSpaceToParent transform has already been multiplied into the
     303             :   // matrix that our caller passes (such as when we're called from PaintSVG).
     304         770 :   return childToUser * aMatrix;
     305             : }
     306             : 
     307             : /* virtual */ bool
     308          18 : SVGViewportElement::HasValidDimensions() const
     309             : {
     310          36 :   return !IsInner() ||
     311           0 :     ((!mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() ||
     312           0 :        mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0) &&
     313           0 :      (!mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet() ||
     314          18 :        mLengthAttributes[ATTR_HEIGHT].GetAnimValInSpecifiedUnits() > 0));
     315             : }
     316             : 
     317             : 
     318             : 
     319             : nsSVGViewBox*
     320          38 : SVGViewportElement::GetViewBox()
     321             : {
     322          38 :   return &mViewBox;
     323             : }
     324             : 
     325             : SVGAnimatedPreserveAspectRatio *
     326          25 : SVGViewportElement::GetPreserveAspectRatio()
     327             : {
     328          25 :   return &mPreserveAspectRatio;
     329             : }
     330             : 
     331             : bool
     332         264 : SVGViewportElement::ShouldSynthesizeViewBox() const
     333             : {
     334         264 :   MOZ_ASSERT(!HasViewBoxRect(), "Should only be called if we lack a viewBox");
     335             : 
     336         264 :   return IsRoot() && OwnerDoc()->IsBeingUsedAsImage();
     337             : }
     338             : 
     339             : //----------------------------------------------------------------------
     340             : // implementation helpers
     341             : 
     342             : nsSVGViewBoxRect
     343         539 : SVGViewportElement::GetViewBoxWithSynthesis(
     344             :   float aViewportWidth, float aViewportHeight) const
     345             : {
     346         539 :   if (GetViewBoxInternal().HasRect()) {
     347         421 :     return GetViewBoxInternal().GetAnimValue();
     348             :   }
     349             : 
     350         118 :   if (ShouldSynthesizeViewBox()) {
     351             :     // Special case -- fake a viewBox, using height & width attrs.
     352             :     // (Use |this| as context, since if we get here, we're outermost <svg>.)
     353             :     return nsSVGViewBoxRect(0, 0,
     354             :               ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_WIDTH],
     355         118 :                                                  mViewportWidth, this),
     356             :               ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_HEIGHT],
     357         236 :                                                  mViewportHeight, this));
     358             : 
     359             :   }
     360             : 
     361             :   // No viewBox attribute, so we shouldn't auto-scale. This is equivalent
     362             :   // to having a viewBox that exactly matches our viewport size.
     363           0 :   return nsSVGViewBoxRect(0, 0, aViewportWidth, aViewportHeight);
     364             : }
     365             : 
     366             : nsSVGElement::LengthAttributesInfo
     367         124 : SVGViewportElement::GetLengthInfo()
     368             : {
     369             :   return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
     370         124 :                               ArrayLength(sLengthInfo));
     371             : }
     372             : 
     373             : } // namespace dom
     374             : } // namespace mozilla

Generated by: LCOV version 1.13