tor-browser

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

SVGContentUtils.h (11915B)


      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_SVGCONTENTUTILS_H_
      8 #define DOM_SVG_SVGCONTENTUTILS_H_
      9 
     10 // include math.h to pick up definition of M_ maths defines e.g. M_PI
     11 #include <math.h>
     12 
     13 #include "gfx2DGlue.h"
     14 #include "mozilla/EnumSet.h"
     15 #include "mozilla/gfx/2D.h"  // for StrokeOptions
     16 #include "mozilla/gfx/Matrix.h"
     17 #include "nsDependentSubstring.h"
     18 #include "nsError.h"
     19 #include "nsStringFwd.h"
     20 #include "nsTArray.h"
     21 
     22 class nsIContent;
     23 
     24 class nsIFrame;
     25 class nsPresContext;
     26 
     27 namespace mozilla {
     28 class ComputedStyle;
     29 class SVGAnimatedTransformList;
     30 class SVGAnimatedPreserveAspectRatio;
     31 class SVGContextPaint;
     32 class SVGPreserveAspectRatio;
     33 union StyleLengthPercentageUnion;
     34 namespace dom {
     35 class Document;
     36 class Element;
     37 class SVGElement;
     38 class SVGSVGElement;
     39 class SVGViewportElement;
     40 }  // namespace dom
     41 
     42 #define SVG_ZERO_LENGTH_PATH_FIX_FACTOR 512
     43 
     44 /**
     45 * Functions generally used by SVG Content classes. Functions here
     46 * should not generally depend on layout methods/classes e.g. SVGUtils
     47 */
     48 class SVGContentUtils {
     49 public:
     50  using Float = gfx::Float;
     51  using Matrix = gfx::Matrix;
     52  using Rect = gfx::Rect;
     53  using StrokeOptions = gfx::StrokeOptions;
     54 
     55  /*
     56   * Get the outer SVG element of an nsIContent
     57   */
     58  static dom::SVGSVGElement* GetOuterSVGElement(dom::SVGElement* aSVGElement);
     59 
     60  /**
     61   * Moz2D's StrokeOptions requires someone else to own its mDashPattern
     62   * buffer, which is a pain when you want to initialize a StrokeOptions object
     63   * in a helper function and pass it out. This sub-class owns the mDashPattern
     64   * buffer so that consumers of such a helper function don't need to worry
     65   * about creating it, passing it in, or deleting it. (An added benefit is
     66   * that in the typical case when stroke-dasharray is short it will avoid
     67   * allocating.)
     68   */
     69  struct AutoStrokeOptions : public StrokeOptions {
     70    AutoStrokeOptions() {
     71      MOZ_ASSERT(mDashLength == 0, "InitDashPattern() depends on this");
     72    }
     73    ~AutoStrokeOptions() {
     74      if (mDashPattern && mDashPattern != mSmallArray) {
     75        delete[] mDashPattern;
     76      }
     77    }
     78    /**
     79     * Creates the buffer to store the stroke-dasharray, assuming out-of-memory
     80     * does not occur. The buffer's address is assigned to mDashPattern and
     81     * returned to the caller as a non-const pointer (so that the caller can
     82     * initialize the values in the buffer, since mDashPattern is const).
     83     */
     84    Float* InitDashPattern(size_t aDashCount) {
     85      if (aDashCount <= std::size(mSmallArray)) {
     86        mDashPattern = mSmallArray;
     87        return mSmallArray;
     88      }
     89      Float* nonConstArray = new (fallible) Float[aDashCount];
     90      mDashPattern = nonConstArray;
     91      return nonConstArray;
     92    }
     93    void DiscardDashPattern() {
     94      if (mDashPattern && mDashPattern != mSmallArray) {
     95        delete[] mDashPattern;
     96      }
     97      mDashLength = 0;
     98      mDashPattern = nullptr;
     99    }
    100 
    101   private:
    102    // Most dasharrays will fit in this and save us allocating
    103    Float mSmallArray[16];
    104  };
    105 
    106  enum class StrokeOptionFlag { IgnoreStrokeDashing };
    107  using StrokeOptionFlags = EnumSet<StrokeOptionFlag>;
    108 
    109  /**
    110   * Note: the linecap style returned in aStrokeOptions is not valid when
    111   * ShapeTypeHasNoCorners(aElement) == true && aFlags == eIgnoreStrokeDashing,
    112   * since when aElement has no corners the rendered linecap style depends on
    113   * whether or not the stroke is dashed.
    114   */
    115  static void GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
    116                               dom::SVGElement* aElement,
    117                               const ComputedStyle* aComputedStyle,
    118                               const SVGContextPaint* aContextPaint,
    119                               StrokeOptionFlags aFlags = {});
    120 
    121  /**
    122   * Returns the current computed value of the CSS property 'stroke-width' for
    123   * the given element. aComputedStyle may be provided as an optimization.
    124   * aContextPaint is also optional.
    125   *
    126   * Note that this function does NOT take account of the value of the 'stroke'
    127   * and 'stroke-opacity' properties to, say, return zero if they are "none" or
    128   * "0", respectively.
    129   */
    130  static Float GetStrokeWidth(const dom::SVGElement* aElement,
    131                              const ComputedStyle* aComputedStyle,
    132                              const SVGContextPaint* aContextPaint);
    133 
    134  /*
    135   * Get the number of CSS px (user units) per em (i.e. the em-height in user
    136   * units) for an nsIContent
    137   *
    138   * XXX document the conditions under which these may fail, and what they
    139   * return in those cases.
    140   */
    141  static float GetFontSize(const dom::Element* aElement);
    142  static float GetFontSize(const nsIFrame* aFrame);
    143  static float GetFontSize(const ComputedStyle*, nsPresContext*);
    144  /*
    145   * Get the number of CSS px (user units) per ex (i.e. the x-height in user
    146   * units) for an nsIContent
    147   *
    148   * XXX document the conditions under which these may fail, and what they
    149   * return in those cases.
    150   */
    151  static float GetFontXHeight(const dom::Element* aElement);
    152  static float GetFontXHeight(const nsIFrame* aFrame);
    153  static float GetFontXHeight(const ComputedStyle*, nsPresContext*);
    154 
    155  /*
    156   * Get the number of CSS px (user units) per lh (i.e. the line-height in
    157   * user units) for an nsIContent.
    158   *
    159   * Requires the element be styled - if not, a default value assuming
    160   * the font-size of 16px and line-height of 1.2 is returned.
    161   */
    162  static float GetLineHeight(const dom::Element* aElement);
    163 
    164  /*
    165   * Report a localized error message to the error console.
    166   */
    167  static nsresult ReportToConsole(const dom::Document* doc,
    168                                  const char* aWarning,
    169                                  const nsTArray<nsString>& aParams);
    170 
    171  static Matrix GetCTM(dom::SVGElement* aElement);
    172 
    173  static Matrix GetNonScalingStrokeCTM(dom::SVGElement* aElement);
    174 
    175  static Matrix GetScreenCTM(dom::SVGElement* aElement);
    176 
    177  /**
    178   * Gets the tight bounds-space stroke bounds of the non-scaling-stroked rect
    179   * aRect.
    180   * @param aToBoundsSpace transforms from source space to the space aBounds
    181   *        should be computed in.  Must be rectilinear.
    182   * @param aToNonScalingStrokeSpace transforms from source
    183   *        space to the space in which non-scaling stroke should be applied.
    184   *        Must be rectilinear.
    185   */
    186  static void RectilinearGetStrokeBounds(const Rect& aRect,
    187                                         const Matrix& aToBoundsSpace,
    188                                         const Matrix& aToNonScalingStrokeSpace,
    189                                         float aStrokeWidth, Rect* aBounds);
    190 
    191  static dom::SVGViewportElement* GetNearestViewportElement(
    192      const nsIContent* aContent);
    193 
    194  /* enum for specifying coordinate direction for ObjectSpace/UserSpace */
    195  enum ctxDirection { X, Y, XY };
    196 
    197  /**
    198   * Computes sqrt((aWidth^2 + aHeight^2)/2);
    199   */
    200  static double ComputeNormalizedHypotenuse(double aWidth, double aHeight);
    201 
    202  /* Returns the angle halfway between the two specified angles */
    203  static float AngleBisect(float a1, float a2);
    204 
    205  /* Generate a viewbox to viewport transformation matrix */
    206 
    207  static Matrix GetViewBoxTransform(
    208      float aViewportWidth, float aViewportHeight, float aViewboxX,
    209      float aViewboxY, float aViewboxWidth, float aViewboxHeight,
    210      const SVGAnimatedPreserveAspectRatio& aPreserveAspectRatio);
    211 
    212  static Matrix GetViewBoxTransform(
    213      float aViewportWidth, float aViewportHeight, float aViewboxX,
    214      float aViewboxY, float aViewboxWidth, float aViewboxHeight,
    215      const SVGPreserveAspectRatio& aPreserveAspectRatio);
    216 
    217  /**
    218   * Parses the sign (+ or -) of a number and moves aIter to the next
    219   * character if a sign is found.
    220   * @param aSignMultiplier [outparam] -1 if the sign is negative otherwise 1
    221   * @return false if we hit the end of the string (i.e. if aIter is initially
    222   *         at aEnd, or if we reach aEnd right after the sign character).
    223   */
    224  static inline bool ParseOptionalSign(nsAString::const_iterator& aIter,
    225                                       const nsAString::const_iterator& aEnd,
    226                                       int32_t& aSignMultiplier) {
    227    if (aIter == aEnd) {
    228      return false;
    229    }
    230    aSignMultiplier = *aIter == '-' ? -1 : 1;
    231 
    232    nsAString::const_iterator iter(aIter);
    233 
    234    if (*iter == '-' || *iter == '+') {
    235      ++iter;
    236      if (iter == aEnd) {
    237        return false;
    238      }
    239    }
    240    aIter = iter;
    241    return true;
    242  }
    243 
    244  /**
    245   * Parse a number of the form:
    246   * number ::= integer ([Ee] integer)? | [+-]? [0-9]* "." [0-9]+ ([Ee]
    247   * integer)? Parsing fails if the number cannot be represented by a floatType.
    248   * If parsing succeeds, aIter is updated so that it points to the character
    249   * after the end of the number, otherwise it is left unchanged
    250   */
    251  template <class floatType>
    252  static bool ParseNumber(nsAString::const_iterator& aIter,
    253                          const nsAString::const_iterator& aEnd,
    254                          floatType& aValue);
    255 
    256  /**
    257   * Parse a number of the form:
    258   * number ::= integer ([Ee] integer)? | [+-]? [0-9]* "." [0-9]+ ([Ee]
    259   * integer)? Parsing fails if there is anything left over after the number, or
    260   * the number cannot be represented by a floatType.
    261   */
    262  template <class floatType>
    263  static bool ParseNumber(const nsAString& aString, floatType& aValue);
    264 
    265  /**
    266   * Parse an integer of the form:
    267   * integer ::= [+-]? [0-9]+
    268   * The returned number is clamped to an int32_t if outside that range.
    269   * If parsing succeeds, aIter is updated so that it points to the character
    270   * after the end of the number, otherwise it is left unchanged
    271   */
    272  static bool ParseInteger(nsAString::const_iterator& aIter,
    273                           const nsAString::const_iterator& aEnd,
    274                           int32_t& aValue);
    275 
    276  /**
    277   * Parse an integer of the form:
    278   * integer ::= [+-]? [0-9]+
    279   * The returned number is clamped to an int32_t if outside that range.
    280   * Parsing fails if there is anything left over after the number.
    281   */
    282  static bool ParseInteger(const nsAString& aString, int32_t& aValue);
    283 
    284  // XXX This should rather use LengthPercentage instead of
    285  // StyleLengthPercentageUnion, but that's a type alias defined in
    286  // ServoStyleConsts.h, and we don't want to avoid including that large header
    287  // with all its dependencies. If a forwarding header were generated by
    288  // cbindgen, we could include that.
    289  // https://github.com/eqrion/cbindgen/issues/617 addresses this.
    290  /**
    291   * Converts a LengthPercentage into a userspace value, resolving percentage
    292   * values relative to aContent's SVG viewport.
    293   */
    294  static float CoordToFloat(const dom::SVGElement* aContent,
    295                            const StyleLengthPercentageUnion&,
    296                            uint8_t aCtxType = SVGContentUtils::XY);
    297  /**
    298   * Parse the SVG path string
    299   * Returns a path
    300   * string formatted as an SVG path
    301   */
    302  static already_AddRefed<gfx::Path> GetPath(const nsACString& aPathString);
    303 
    304  /**
    305   *  Returns true if aContent is one of the elements whose stroke is guaranteed
    306   *  to have no corners: circle or ellipse
    307   */
    308  static bool ShapeTypeHasNoCorners(const nsIContent* aContent);
    309 
    310  /**
    311   *  Return one token in aString, aString may have leading and trailing
    312   * whitespace; aSuccess will be set to false if there is no token or more than
    313   * one token, otherwise it's set to true.
    314   */
    315  static nsDependentSubstring GetAndEnsureOneToken(const nsAString& aString,
    316                                                   bool& aSuccess);
    317 };
    318 
    319 }  // namespace mozilla
    320 
    321 #endif  // DOM_SVG_SVGCONTENTUTILS_H_