tor-browser

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

SVGGeometryProperty.h (10067B)


      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_SVGGEOMETRYPROPERTY_H_
      8 #define DOM_SVG_SVGGEOMETRYPROPERTY_H_
      9 
     10 #include <type_traits>
     11 
     12 #include "ComputedStyle.h"
     13 #include "SVGAnimatedLength.h"
     14 #include "mozilla/SVGImageFrame.h"
     15 #include "mozilla/dom/SVGElement.h"
     16 #include "nsComputedDOMStyle.h"
     17 #include "nsGkAtoms.h"
     18 #include "nsIFrame.h"
     19 
     20 namespace mozilla::dom::SVGGeometryProperty {
     21 namespace ResolverTypes {
     22 struct LengthPercentNoAuto {};
     23 struct LengthPercentRXY {};
     24 struct LengthPercentWidthHeight {};
     25 }  // namespace ResolverTypes
     26 
     27 namespace Tags {
     28 
     29 #define SVGGEOMETRYPROPERTY_GENERATETAG(tagName, resolver, direction, \
     30                                        styleStruct)                  \
     31  struct tagName {                                                    \
     32    using ResolverType = ResolverTypes::resolver;                     \
     33    constexpr static auto CtxDirection = SVGContentUtils::direction;  \
     34    constexpr static auto Getter = &styleStruct::m##tagName;          \
     35  }
     36 
     37 SVGGEOMETRYPROPERTY_GENERATETAG(X, LengthPercentNoAuto, X, nsStyleSVGReset);
     38 SVGGEOMETRYPROPERTY_GENERATETAG(Y, LengthPercentNoAuto, Y, nsStyleSVGReset);
     39 SVGGEOMETRYPROPERTY_GENERATETAG(Cx, LengthPercentNoAuto, X, nsStyleSVGReset);
     40 SVGGEOMETRYPROPERTY_GENERATETAG(Cy, LengthPercentNoAuto, Y, nsStyleSVGReset);
     41 SVGGEOMETRYPROPERTY_GENERATETAG(R, LengthPercentNoAuto, XY, nsStyleSVGReset);
     42 
     43 #undef SVGGEOMETRYPROPERTY_GENERATETAG
     44 
     45 using StyleSizeGetter = AnchorResolvedSize (nsStylePosition::*)(
     46    const AnchorPosResolutionParams& aParams) const;
     47 
     48 struct Height;
     49 struct Width {
     50  using ResolverType = ResolverTypes::LengthPercentWidthHeight;
     51  constexpr static auto CtxDirection = SVGContentUtils::X;
     52  constexpr static StyleSizeGetter Getter = &nsStylePosition::GetWidth;
     53  constexpr static auto SizeGetter = &gfx::Size::width;
     54  static AspectRatio AspectRatioRelative(AspectRatio aAspectRatio) {
     55    return aAspectRatio.Inverted();
     56  }
     57  constexpr static uint32_t DefaultObjectSize = kFallbackIntrinsicWidthInPixels;
     58  using CounterPart = Height;
     59 };
     60 struct Height {
     61  using ResolverType = ResolverTypes::LengthPercentWidthHeight;
     62  constexpr static auto CtxDirection = SVGContentUtils::Y;
     63  constexpr static StyleSizeGetter Getter = &nsStylePosition::GetHeight;
     64  constexpr static auto SizeGetter = &gfx::Size::height;
     65  static AspectRatio AspectRatioRelative(AspectRatio aAspectRatio) {
     66    return aAspectRatio;
     67  }
     68  constexpr static uint32_t DefaultObjectSize =
     69      kFallbackIntrinsicHeightInPixels;
     70  using CounterPart = Width;
     71 };
     72 
     73 struct Ry;
     74 struct Rx {
     75  using ResolverType = ResolverTypes::LengthPercentRXY;
     76  constexpr static auto CtxDirection = SVGContentUtils::X;
     77  constexpr static auto Getter = &nsStyleSVGReset::mRx;
     78  using CounterPart = Ry;
     79 };
     80 struct Ry {
     81  using ResolverType = ResolverTypes::LengthPercentRXY;
     82  constexpr static auto CtxDirection = SVGContentUtils::Y;
     83  constexpr static auto Getter = &nsStyleSVGReset::mRy;
     84  using CounterPart = Rx;
     85 };
     86 
     87 }  // namespace Tags
     88 
     89 namespace details {
     90 template <class T>
     91 using AlwaysFloat = float;
     92 using dummy = int[];
     93 
     94 using CtxDirectionType = decltype(SVGContentUtils::X);
     95 
     96 template <CtxDirectionType CTD>
     97 float ResolvePureLengthPercentage(const SVGElement* aElement,
     98                                  const LengthPercentage& aLP) {
     99  return aLP.ResolveToCSSPixelsWith(
    100      [&] { return CSSCoord{SVGElementMetrics(aElement).GetAxisLength(CTD)}; });
    101 }
    102 
    103 template <class Tag>
    104 float ResolveImpl(ComputedStyle const& aStyle, const SVGElement* aElement,
    105                  ResolverTypes::LengthPercentNoAuto) {
    106  auto const& value = aStyle.StyleSVGReset()->*Tag::Getter;
    107  return ResolvePureLengthPercentage<Tag::CtxDirection>(aElement, value);
    108 }
    109 
    110 template <class Tag>
    111 float ResolveImpl(ComputedStyle const& aStyle, const SVGElement* aElement,
    112                  ResolverTypes::LengthPercentWidthHeight) {
    113  static_assert(
    114      std::is_same<Tag, Tags::Width>{} || std::is_same<Tag, Tags::Height>{},
    115      "Wrong tag");
    116 
    117  auto const value = std::invoke(
    118      Tag::Getter, aStyle.StylePosition(),
    119      AnchorPosResolutionParams{nullptr, aStyle.StyleDisplay()->mPosition});
    120  if (value->IsLengthPercentage()) {
    121    return ResolvePureLengthPercentage<Tag::CtxDirection>(
    122        aElement, value->AsLengthPercentage());
    123  }
    124 
    125  if (aElement->IsSVGElement(nsGkAtoms::image)) {
    126    // It's not clear per SVG2 spec what should be done for values other
    127    // than |auto| (e.g. |max-content|). We treat them as nonsense, thus
    128    // using the initial value behavior, i.e. |auto|.
    129    // The following procedure follows the Default Sizing Algorithm as
    130    // specified in:
    131    // https://svgwg.org/svg2-draft/embedded.html#ImageElement
    132 
    133    SVGImageFrame* imgf = do_QueryFrame(aElement->GetPrimaryFrame());
    134    if (!imgf) {
    135      return 0.f;
    136    }
    137 
    138    using Other = typename Tag::CounterPart;
    139    auto const valueOther = std::invoke(
    140        Other::Getter, aStyle.StylePosition(),
    141        AnchorPosResolutionParams{nullptr, aStyle.StyleDisplay()->mPosition});
    142 
    143    gfx::Size intrinsicImageSize;
    144    AspectRatio aspectRatio;
    145    if (!imgf->GetIntrinsicImageDimensions(intrinsicImageSize, aspectRatio)) {
    146      // No image container, just return 0.
    147      return 0.f;
    148    }
    149 
    150    if (valueOther->IsLengthPercentage()) {
    151      // We are |auto|, but the other side has specifed length.
    152      float lengthOther = ResolvePureLengthPercentage<Other::CtxDirection>(
    153          aElement, valueOther->AsLengthPercentage());
    154 
    155      if (aspectRatio) {
    156        // Preserve aspect ratio if it's present.
    157        return Other::AspectRatioRelative(aspectRatio)
    158            .ApplyToFloat(lengthOther);
    159      }
    160 
    161      float intrinsicLength = intrinsicImageSize.*Tag::SizeGetter;
    162      if (intrinsicLength >= 0) {
    163        // Use the intrinsic length if it's present.
    164        return intrinsicLength;
    165      }
    166 
    167      // No specified size, no aspect ratio, no intrinsic length,
    168      // then use default size.
    169      return Tag::DefaultObjectSize;
    170    }
    171 
    172    // |width| and |height| are both |auto|
    173    if (intrinsicImageSize.*Tag::SizeGetter >= 0) {
    174      return intrinsicImageSize.*Tag::SizeGetter;
    175    }
    176 
    177    if (intrinsicImageSize.*Other::SizeGetter >= 0 && aspectRatio) {
    178      return Other::AspectRatioRelative(aspectRatio)
    179          .ApplyTo(intrinsicImageSize.*Other::SizeGetter);
    180    }
    181 
    182    if (aspectRatio) {
    183      // Resolve as a contain constraint against the default object size.
    184      auto defaultAspectRatioRelative =
    185          AspectRatio{float(Other::DefaultObjectSize) / Tag::DefaultObjectSize};
    186      auto aspectRatioRelative = Tag::AspectRatioRelative(aspectRatio);
    187 
    188      if (defaultAspectRatioRelative < aspectRatioRelative) {
    189        // Using default length in our side and the intrinsic aspect ratio,
    190        // the other side cannot be contained.
    191        return aspectRatioRelative.Inverted().ApplyTo(Other::DefaultObjectSize);
    192      }
    193 
    194      return Tag::DefaultObjectSize;
    195    }
    196 
    197    return Tag::DefaultObjectSize;
    198  }
    199 
    200  // For other elements, |auto| and |max-content| etc. are treated as 0.
    201  return 0.f;
    202 }
    203 
    204 template <class Tag>
    205 float ResolveImpl(ComputedStyle const& aStyle, const SVGElement* aElement,
    206                  ResolverTypes::LengthPercentRXY) {
    207  static_assert(std::is_same<Tag, Tags::Rx>{} || std::is_same<Tag, Tags::Ry>{},
    208                "Wrong tag");
    209 
    210  auto const& value = aStyle.StyleSVGReset()->*Tag::Getter;
    211  if (value.IsLengthPercentage()) {
    212    return ResolvePureLengthPercentage<Tag::CtxDirection>(
    213        aElement, value.AsLengthPercentage());
    214  }
    215 
    216  MOZ_ASSERT(value.IsAuto());
    217  using Rother = typename Tag::CounterPart;
    218  auto const& valueOther = aStyle.StyleSVGReset()->*Rother::Getter;
    219 
    220  if (valueOther.IsAuto()) {
    221    // Per SVG2, |Rx|, |Ry| resolve to 0 if both are |auto|
    222    return 0.f;
    223  }
    224 
    225  // If |Rx| is auto while |Ry| not, |Rx| gets the value of |Ry|.
    226  return ResolvePureLengthPercentage<Rother::CtxDirection>(
    227      aElement, valueOther.AsLengthPercentage());
    228 }
    229 
    230 }  // namespace details
    231 
    232 template <class Tag>
    233 float ResolveWith(const ComputedStyle& aStyle, const SVGElement* aElement) {
    234  return details::ResolveImpl<Tag>(aStyle, aElement,
    235                                   typename Tag::ResolverType{});
    236 }
    237 
    238 template <class Func>
    239 bool DoForComputedStyle(const Element* aElement, Func aFunc) {
    240  if (!aElement) {
    241    return false;
    242  }
    243  if (const nsIFrame* f = aElement->GetPrimaryFrame()) {
    244    aFunc(f->Style());
    245    return true;
    246  }
    247 
    248  if (RefPtr<const ComputedStyle> computedStyle =
    249          nsComputedDOMStyle::GetComputedStyleNoFlush(aElement)) {
    250    aFunc(computedStyle.get());
    251    return true;
    252  }
    253 
    254  return false;
    255 }
    256 
    257 #define SVGGEOMETRYPROPERTY_EVAL_ALL(expr) \
    258  (void)details::dummy { 0, (static_cast<void>(expr), 0)... }
    259 
    260 // To add support for new properties, or to handle special cases for
    261 // existing properties, you can add a new tag in |Tags| and |ResolverTypes|
    262 // namespace, then implement the behavior in |details::ResolveImpl|.
    263 template <class... Tags>
    264 bool ResolveAll(const SVGElement* aElement,
    265                details::AlwaysFloat<Tags>*... aRes) {
    266  bool res = DoForComputedStyle(aElement, [&](auto const* style) {
    267    SVGGEOMETRYPROPERTY_EVAL_ALL(*aRes = ResolveWith<Tags>(*style, aElement));
    268  });
    269 
    270  if (res) {
    271    return true;
    272  }
    273 
    274  SVGGEOMETRYPROPERTY_EVAL_ALL(*aRes = 0);
    275  return false;
    276 }
    277 
    278 #undef SVGGEOMETRYPROPERTY_EVAL_ALL
    279 
    280 nsCSSUnit SpecifiedUnitTypeToCSSUnit(uint8_t aSpecifiedUnit);
    281 NonCustomCSSPropertyId AttrEnumToCSSPropId(const SVGElement* aElement,
    282                                           uint8_t aAttrEnum);
    283 
    284 bool IsNonNegativeGeometryProperty(NonCustomCSSPropertyId aProp);
    285 bool ElementMapsLengthsToStyle(SVGElement const* aElement);
    286 
    287 }  // namespace mozilla::dom::SVGGeometryProperty
    288 
    289 #endif  // DOM_SVG_SVGGEOMETRYPROPERTY_H_