tor-browser

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

SVGEllipseElement.cpp (6487B)


      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 "mozilla/dom/SVGEllipseElement.h"
      8 
      9 #include "ComputedStyle.h"
     10 #include "SVGGeometryProperty.h"
     11 #include "mozilla/dom/SVGEllipseElementBinding.h"
     12 #include "mozilla/dom/SVGLengthBinding.h"
     13 #include "mozilla/gfx/2D.h"
     14 #include "mozilla/gfx/PathHelpers.h"
     15 
     16 NS_IMPL_NS_NEW_SVG_ELEMENT(Ellipse)
     17 
     18 using namespace mozilla::gfx;
     19 
     20 namespace mozilla::dom {
     21 
     22 JSObject* SVGEllipseElement::WrapNode(JSContext* aCx,
     23                                      JS::Handle<JSObject*> aGivenProto) {
     24  return SVGEllipseElement_Binding::Wrap(aCx, this, aGivenProto);
     25 }
     26 
     27 SVGElement::LengthInfo SVGEllipseElement::sLengthInfo[4] = {
     28    {nsGkAtoms::cx, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
     29     SVGContentUtils::X},
     30    {nsGkAtoms::cy, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
     31     SVGContentUtils::Y},
     32    {nsGkAtoms::rx, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
     33     SVGContentUtils::X},
     34    {nsGkAtoms::ry, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
     35     SVGContentUtils::Y},
     36 };
     37 
     38 //----------------------------------------------------------------------
     39 // Implementation
     40 
     41 SVGEllipseElement::SVGEllipseElement(
     42    already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
     43    : SVGEllipseElementBase(std::move(aNodeInfo)) {}
     44 
     45 bool SVGEllipseElement::IsAttributeMapped(const nsAtom* aAttribute) const {
     46  return IsInLengthInfo(aAttribute, sLengthInfo) ||
     47         SVGEllipseElementBase::IsAttributeMapped(aAttribute);
     48 }
     49 
     50 namespace SVGT = SVGGeometryProperty::Tags;
     51 
     52 //----------------------------------------------------------------------
     53 // nsINode methods
     54 
     55 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGEllipseElement)
     56 
     57 //----------------------------------------------------------------------
     58 // nsIDOMSVGEllipseElement methods
     59 
     60 already_AddRefed<DOMSVGAnimatedLength> SVGEllipseElement::Cx() {
     61  return mLengthAttributes[CX].ToDOMAnimatedLength(this);
     62 }
     63 
     64 already_AddRefed<DOMSVGAnimatedLength> SVGEllipseElement::Cy() {
     65  return mLengthAttributes[CY].ToDOMAnimatedLength(this);
     66 }
     67 
     68 already_AddRefed<DOMSVGAnimatedLength> SVGEllipseElement::Rx() {
     69  return mLengthAttributes[RX].ToDOMAnimatedLength(this);
     70 }
     71 
     72 already_AddRefed<DOMSVGAnimatedLength> SVGEllipseElement::Ry() {
     73  return mLengthAttributes[RY].ToDOMAnimatedLength(this);
     74 }
     75 
     76 //----------------------------------------------------------------------
     77 // SVGElement methods
     78 
     79 /* virtual */
     80 bool SVGEllipseElement::HasValidDimensions() const {
     81  float rx, ry;
     82 
     83  if (SVGGeometryProperty::ResolveAll<SVGT::Rx, SVGT::Ry>(this, &rx, &ry)) {
     84    return rx > 0 && ry > 0;
     85  }
     86  // This function might be called for an element in display:none subtree
     87  // (e.g. SMIL animateMotion), we fall back to use SVG attributes.
     88  bool hasRx = mLengthAttributes[RX].IsExplicitlySet();
     89  bool hasRy = mLengthAttributes[RY].IsExplicitlySet();
     90  if ((hasRx && mLengthAttributes[RX].GetAnimValInSpecifiedUnits() <= 0) ||
     91      (hasRy && mLengthAttributes[RY].GetAnimValInSpecifiedUnits() <= 0)) {
     92    return false;
     93  }
     94  return hasRx || hasRy;
     95 }
     96 
     97 SVGElement::LengthAttributesInfo SVGEllipseElement::GetLengthInfo() {
     98  return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
     99                              std::size(sLengthInfo));
    100 }
    101 
    102 //----------------------------------------------------------------------
    103 // SVGGeometryElement methods
    104 
    105 bool SVGEllipseElement::GetGeometryBounds(
    106    Rect* aBounds, const StrokeOptions& aStrokeOptions,
    107    const Matrix& aToBoundsSpace, const Matrix* aToNonScalingStrokeSpace) {
    108  float x, y, rx, ry;
    109 
    110  DebugOnly<bool> ok =
    111      SVGGeometryProperty::ResolveAll<SVGT::Cx, SVGT::Cy, SVGT::Rx, SVGT::Ry>(
    112          this, &x, &y, &rx, &ry);
    113  MOZ_ASSERT(ok, "SVGGeometryProperty::ResolveAll failed");
    114 
    115  if (rx <= 0.f || ry <= 0.f) {
    116    // Rendering of the element is disabled
    117    *aBounds = Rect(aToBoundsSpace.TransformPoint(Point(x, y)), Size());
    118    return true;
    119  }
    120 
    121  if (aToBoundsSpace.IsRectilinear()) {
    122    // Optimize the case where we can treat the ellipse as a rectangle and
    123    // still get tight bounds.
    124    if (aStrokeOptions.mLineWidth > 0.f) {
    125      if (aToNonScalingStrokeSpace) {
    126        if (aToNonScalingStrokeSpace->IsRectilinear()) {
    127          MOZ_ASSERT(!aToNonScalingStrokeSpace->IsSingular());
    128          Rect userBounds(x - rx, y - ry, 2 * rx, 2 * ry);
    129          SVGContentUtils::RectilinearGetStrokeBounds(
    130              userBounds, aToBoundsSpace, *aToNonScalingStrokeSpace,
    131              aStrokeOptions.mLineWidth, aBounds);
    132          return true;
    133        }
    134        return false;
    135      }
    136      rx += aStrokeOptions.mLineWidth / 2.f;
    137      ry += aStrokeOptions.mLineWidth / 2.f;
    138    }
    139    Rect rect(x - rx, y - ry, 2 * rx, 2 * ry);
    140    *aBounds = aToBoundsSpace.TransformBounds(rect);
    141    return true;
    142  }
    143 
    144  return false;
    145 }
    146 
    147 already_AddRefed<Path> SVGEllipseElement::BuildPath(PathBuilder* aBuilder) {
    148  float x, y, rx, ry;
    149 
    150  if (!SVGGeometryProperty::ResolveAll<SVGT::Cx, SVGT::Cy, SVGT::Rx, SVGT::Ry>(
    151          this, &x, &y, &rx, &ry)) {
    152    // This function might be called for element in display:none subtree
    153    // (e.g. getTotalLength), we fall back to use SVG attributes.
    154    GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
    155  }
    156 
    157  if (rx <= 0.0f || ry <= 0.0f) {
    158    return nullptr;
    159  }
    160 
    161  EllipseToBezier(aBuilder, Point(x, y), Size(rx, ry));
    162 
    163  return aBuilder->Finish();
    164 }
    165 
    166 bool SVGEllipseElement::IsLengthChangedViaCSS(const ComputedStyle& aNewStyle,
    167                                              const ComputedStyle& aOldStyle) {
    168  const auto& newSVGReset = *aNewStyle.StyleSVGReset();
    169  const auto& oldSVGReset = *aOldStyle.StyleSVGReset();
    170  return newSVGReset.mCx != oldSVGReset.mCx ||
    171         newSVGReset.mCy != oldSVGReset.mCy ||
    172         newSVGReset.mRx != oldSVGReset.mRx ||
    173         newSVGReset.mRy != oldSVGReset.mRy;
    174 }
    175 
    176 NonCustomCSSPropertyId SVGEllipseElement::GetCSSPropertyIdForAttrEnum(
    177    uint8_t aAttrEnum) {
    178  switch (aAttrEnum) {
    179    case CX:
    180      return eCSSProperty_cx;
    181    case CY:
    182      return eCSSProperty_cy;
    183    case RX:
    184      return eCSSProperty_rx;
    185    case RY:
    186      return eCSSProperty_ry;
    187    default:
    188      MOZ_ASSERT_UNREACHABLE("Unknown attr enum");
    189      return eCSSProperty_UNKNOWN;
    190  }
    191 }
    192 
    193 }  // namespace mozilla::dom