tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SVGGeometryElement.h (9534B)


      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 #ifndef DOM_SVG_SVGGEOMETRYELEMENT_H_
      8 #define DOM_SVG_SVGGEOMETRYELEMENT_H_
      9 
     10 #include "mozilla/dom/SVGAnimatedNumber.h"
     11 #include "mozilla/dom/SVGGraphicsElement.h"
     12 #include "mozilla/gfx/2D.h"
     13 
     14 namespace mozilla {
     15 
     16 struct SVGMark {
     17  enum Type {
     18    eStart,
     19    eMid,
     20    eEnd,
     21 
     22    eTypeCount
     23  };
     24 
     25  float x, y, angle;
     26  Type type;
     27  SVGMark(float aX, float aY, float aAngle, Type aType)
     28      : x(aX), y(aY), angle(aAngle), type(aType) {}
     29 };
     30 
     31 namespace dom {
     32 
     33 class DOMSVGAnimatedNumber;
     34 class DOMSVGPoint;
     35 
     36 using SVGGeometryElementBase = mozilla::dom::SVGGraphicsElement;
     37 
     38 class SVGGeometryElement : public SVGGeometryElementBase {
     39 protected:
     40  using CapStyle = mozilla::gfx::CapStyle;
     41  using DrawTarget = mozilla::gfx::DrawTarget;
     42  using FillRule = mozilla::gfx::FillRule;
     43  using Float = mozilla::gfx::Float;
     44  using Matrix = mozilla::gfx::Matrix;
     45  using Path = mozilla::gfx::Path;
     46  using Point = mozilla::gfx::Point;
     47  using PathBuilder = mozilla::gfx::PathBuilder;
     48  using Rect = mozilla::gfx::Rect;
     49  using StrokeOptions = mozilla::gfx::StrokeOptions;
     50 
     51 public:
     52  explicit SVGGeometryElement(
     53      already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
     54 
     55  NS_IMPL_FROMNODE_HELPER(SVGGeometryElement, IsSVGGeometryElement())
     56 
     57  void AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
     58                    const nsAttrValue* aValue, const nsAttrValue* aOldValue,
     59                    nsIPrincipal* aSubjectPrincipal, bool aNotify) override;
     60  bool IsSVGGeometryElement() const override { return true; }
     61 
     62  /**
     63   * Causes this element to discard any Path object that GetOrBuildPath may
     64   * have cached.
     65   */
     66  void ClearAnyCachedPath() final { mCachedPath = nullptr; }
     67 
     68  virtual bool AttributeDefinesGeometry(const nsAtom* aName);
     69 
     70  /**
     71   * Returns true if this element's geometry depends on the width or height of
     72   * its coordinate context (typically the viewport established by its nearest
     73   * <svg> ancestor). In other words, returns true if one of the attributes for
     74   * which AttributeDefinesGeometry returns true has a percentage value.
     75   *
     76   * This could be moved up to a more general class so it can be used for
     77   * non-leaf elements, but that would require care and for now there's no need.
     78   */
     79  bool GeometryDependsOnCoordCtx();
     80 
     81  virtual bool IsMarkable();
     82  virtual void GetMarkPoints(nsTArray<SVGMark>* aMarks);
     83 
     84  /**
     85   * A method that can be faster than using a Moz2D Path and calling GetBounds/
     86   * GetStrokedBounds on it.  It also helps us avoid rounding error for simple
     87   * shapes and simple transforms where the Moz2D Path backends can fail to
     88   * produce the clean integer bounds that content authors expect in some cases.
     89   *
     90   * If |aToNonScalingStrokeSpace| is non-null then |aBounds|, which is computed
     91   * in bounds space, has the property that it's the smallest (axis-aligned)
     92   * rectangular bound containing the image of this shape as stroked in
     93   * non-scaling-stroke space.  (When all transforms involved are rectilinear
     94   * the bounds of the image of |aBounds| in non-scaling-stroke space will be
     95   * tight, but if there are non-rectilinear transforms involved then that may
     96   * be impossible and this method will return false).
     97   *
     98   * If |aToNonScalingStrokeSpace| is non-null then |*aToNonScalingStrokeSpace|
     99   * must be non-singular.
    100   */
    101  virtual bool GetGeometryBounds(
    102      Rect* aBounds, const StrokeOptions& aStrokeOptions,
    103      const Matrix& aToBoundsSpace,
    104      const Matrix* aToNonScalingStrokeSpace = nullptr) {
    105    return false;
    106  }
    107 
    108  /**
    109   * For use with GetAsSimplePath.
    110   */
    111  class SimplePath {
    112   public:
    113    SimplePath()
    114        : mX(0.0), mY(0.0), mWidthOrX2(0.0), mHeightOrY2(0.0), mType(NONE) {}
    115    bool IsPath() const { return mType != NONE; }
    116    void SetRect(Float x, Float y, Float width, Float height) {
    117      mX = x;
    118      mY = y;
    119      mWidthOrX2 = width;
    120      mHeightOrY2 = height;
    121      mType = RECT;
    122    }
    123    Rect AsRect() const {
    124      MOZ_ASSERT(mType == RECT);
    125      return Rect(mX, mY, mWidthOrX2, mHeightOrY2);
    126    }
    127    bool IsRect() const { return mType == RECT; }
    128    void SetLine(Float x1, Float y1, Float x2, Float y2) {
    129      mX = x1;
    130      mY = y1;
    131      mWidthOrX2 = x2;
    132      mHeightOrY2 = y2;
    133      mType = LINE;
    134    }
    135    Point Point1() const {
    136      MOZ_ASSERT(mType == LINE);
    137      return Point(mX, mY);
    138    }
    139    Point Point2() const {
    140      MOZ_ASSERT(mType == LINE);
    141      return Point(mWidthOrX2, mHeightOrY2);
    142    }
    143    bool IsLine() const { return mType == LINE; }
    144    void Reset() { mType = NONE; }
    145 
    146   private:
    147    enum Type { NONE, RECT, LINE };
    148    Float mX, mY, mWidthOrX2, mHeightOrY2;
    149    Type mType;
    150  };
    151 
    152  /**
    153   * For some platforms there is significant overhead to creating and painting
    154   * a Moz2D Path object. For Rects and lines it is better to get the path data
    155   * using this method and then use the optimized DrawTarget methods for
    156   * filling/stroking rects and lines.
    157   */
    158  virtual void GetAsSimplePath(SimplePath* aSimplePath) {
    159    aSimplePath->Reset();
    160  }
    161 
    162  /**
    163   * Returns a Path that can be used to paint, hit-test or calculate bounds for
    164   * this element. May return nullptr if there is no [valid] path. The path
    165   * that is created may be cached and returned on subsequent calls.
    166   */
    167  virtual already_AddRefed<Path> GetOrBuildPath(const DrawTarget* aDrawTarget,
    168                                                FillRule fillRule);
    169 
    170  /**
    171   * The same as GetOrBuildPath, but bypasses the cache (neither returns any
    172   * previously cached Path, nor caches the Path that in does return).
    173   * this element. May return nullptr if there is no [valid] path.
    174   */
    175  virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) = 0;
    176 
    177  /**
    178   * Get the distances from the origin of the path segments.
    179   * For non-path elements that's just 0 and the total length of the shape.
    180   */
    181  virtual bool GetDistancesFromOriginToEndsOfVisibleSegments(
    182      FallibleTArray<double>* aOutput) {
    183    aOutput->Clear();
    184    double distances[] = {0.0, GetTotalLength()};
    185    return aOutput->AppendElements(Span<double>(distances), fallible);
    186  }
    187 
    188  /**
    189   * Returns a Path that can be used to measure the length of this elements
    190   * path, or to find the position at a given distance along it.
    191   *
    192   * This is currently equivalent to calling GetOrBuildPath, but it may not be
    193   * in the future. The reason for this function to be separate from
    194   * GetOrBuildPath is because SVGPathData::BuildPath inserts small lines into
    195   * the path if zero length subpaths are encountered, in order to implement
    196   * the SVG specifications requirements that zero length subpaths should
    197   * render circles/squares if stroke-linecap is round/square, respectively.
    198   * In principle these inserted lines could interfere with path measurement,
    199   * so we keep callers that are looking to do measurement separate in case we
    200   * run into problems with the inserted lines negatively affecting measuring
    201   * for content.
    202   */
    203  virtual already_AddRefed<Path> GetOrBuildPathForMeasuring();
    204 
    205  /**
    206   * If this shape element is a closed loop, this returns true. If it is an
    207   * unclosed interval, this returns false. This function is used for motion
    208   * path especially.
    209   *
    210   * 1. SVG Paths are closed loops only if the final command in the path list is
    211   *    a closepath command ("z" or "Z"), otherwise they are unclosed intervals.
    212   * 2. SVG circles, ellipses, polygons and rects are closed loops.
    213   * 3. SVG lines and polylines are unclosed intervals.
    214   *
    215   * https://drafts.fxtf.org/motion/#path-distance
    216   */
    217  virtual bool IsClosedLoop() const { return false; }
    218 
    219  /**
    220   * Return |true| if some geometry properties (|x|, |y|, etc) are changed
    221   * because of CSS change.
    222   */
    223  bool IsGeometryChangedViaCSS(ComputedStyle const& aNewStyle,
    224                               ComputedStyle const& aOldStyle) const;
    225 
    226  /**
    227   * Returns the current computed value of the CSS property 'fill-rule' for
    228   * this element.
    229   */
    230  FillRule GetFillRule();
    231 
    232  enum PathLengthScaleForType { eForTextPath, eForStroking };
    233 
    234  /**
    235   * Gets the ratio of the actual element's length to the content author's
    236   * estimated length (as provided by the element's 'pathLength' attribute).
    237   * This is used to scale stroke dashing, and to scale offsets along a
    238   * textPath.
    239   */
    240  float GetPathLengthScale(PathLengthScaleForType aFor);
    241 
    242  // WebIDL
    243  already_AddRefed<DOMSVGAnimatedNumber> PathLength();
    244  MOZ_CAN_RUN_SCRIPT bool IsPointInFill(const DOMPointInit& aPoint);
    245  MOZ_CAN_RUN_SCRIPT bool IsPointInStroke(const DOMPointInit& aPoint);
    246  MOZ_CAN_RUN_SCRIPT float GetTotalLengthForBinding();
    247  MOZ_CAN_RUN_SCRIPT already_AddRefed<DOMSVGPoint> GetPointAtLength(
    248      float distance, ErrorResult& rv);
    249 
    250  gfx::Matrix LocalTransform() const;
    251 
    252 protected:
    253  // SVGElement method
    254  NumberAttributesInfo GetNumberInfo() override;
    255 
    256  MOZ_CAN_RUN_SCRIPT void FlushIfNeeded();
    257 
    258  SVGAnimatedNumber mPathLength;
    259  static NumberInfo sNumberInfo;
    260  mutable RefPtr<Path> mCachedPath;
    261 
    262 private:
    263  already_AddRefed<Path> GetOrBuildPathForHitTest();
    264 
    265  float GetTotalLength();
    266 };
    267 
    268 }  // namespace dom
    269 }  // namespace mozilla
    270 
    271 #endif  // DOM_SVG_SVGGEOMETRYELEMENT_H_