DOMQuad.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. * Copyright (c) 2023, Bastiaan van der Plaat <bastiaan.v.d.plaat@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibWeb/Bindings/DOMQuadPrototype.h>
  7. #include <LibWeb/Bindings/Intrinsics.h>
  8. #include <LibWeb/Geometry/DOMQuad.h>
  9. namespace Web::Geometry {
  10. JS_DEFINE_ALLOCATOR(DOMQuad);
  11. JS::NonnullGCPtr<DOMQuad> DOMQuad::construct_impl(JS::Realm& realm, DOMPointInit const& p1, DOMPointInit const& p2, DOMPointInit const& p3, DOMPointInit const& p4)
  12. {
  13. return realm.heap().allocate<DOMQuad>(realm, realm, p1, p2, p3, p4);
  14. }
  15. JS::NonnullGCPtr<DOMQuad> DOMQuad::create(JS::Realm& realm)
  16. {
  17. return realm.heap().allocate<DOMQuad>(realm, realm);
  18. }
  19. DOMQuad::DOMQuad(JS::Realm& realm, DOMPointInit const& p1, DOMPointInit const& p2, DOMPointInit const& p3, DOMPointInit const& p4)
  20. : PlatformObject(realm)
  21. , m_p1(DOMPoint::from_point(realm.vm(), p1))
  22. , m_p2(DOMPoint::from_point(realm.vm(), p2))
  23. , m_p3(DOMPoint::from_point(realm.vm(), p3))
  24. , m_p4(DOMPoint::from_point(realm.vm(), p4))
  25. {
  26. }
  27. DOMQuad::DOMQuad(JS::Realm& realm)
  28. : PlatformObject(realm)
  29. , m_p1(DOMPoint::create(realm))
  30. , m_p2(DOMPoint::create(realm))
  31. , m_p3(DOMPoint::create(realm))
  32. , m_p4(DOMPoint::create(realm))
  33. {
  34. }
  35. DOMQuad::~DOMQuad() = default;
  36. // https://drafts.fxtf.org/geometry/#dom-domquad-fromrect
  37. JS::NonnullGCPtr<DOMQuad> DOMQuad::from_rect(JS::VM& vm, DOMRectInit const& other)
  38. {
  39. // The fromRect(other) static method on DOMQuad must create a DOMQuad from the DOMRectInit dictionary other.
  40. return construct_impl(*vm.current_realm(), { other.x, other.y },
  41. { other.x + other.width, other.y },
  42. { other.x + other.width, other.y + other.height },
  43. { other.x, other.y + other.height });
  44. }
  45. // https://drafts.fxtf.org/geometry/#dom-domquad-fromquad
  46. JS::NonnullGCPtr<DOMQuad> DOMQuad::from_quad(JS::VM& vm, DOMQuadInit const& other)
  47. {
  48. // The fromQuad(other) static method on DOMQuad must create a DOMQuad from the DOMQuadInit dictionary other.
  49. return construct_impl(*vm.current_realm(), other.p1, other.p2, other.p3, other.p4);
  50. }
  51. // https://drafts.fxtf.org/geometry/#dom-domquad-getbounds
  52. JS::NonnullGCPtr<DOMRect> DOMQuad::get_bounds() const
  53. {
  54. auto nan_safe_minimum = [](double a, double b, double c, double d) -> double {
  55. if (isnan(a) || isnan(b) || isnan(c) || isnan(d))
  56. return NAN;
  57. return min(a, min(b, min(c, d)));
  58. };
  59. auto nan_safe_maximum = [](double a, double b, double c, double d) -> double {
  60. if (isnan(a) || isnan(b) || isnan(c) || isnan(d))
  61. return NAN;
  62. return max(a, max(b, max(c, d)));
  63. };
  64. // 1. Let bounds be a DOMRect object.
  65. auto bounds = DOMRect::create(realm(), {});
  66. // 2. Let left be the NaN-safe minimum of point 1’s x coordinate, point 2’s x coordinate, point 3’s x coordinate and point 4’s x coordinate.
  67. auto left = nan_safe_minimum(m_p1->x(), m_p2->x(), m_p3->x(), m_p4->x());
  68. // 3. Let top be the NaN-safe minimum of point 1’s y coordinate, point 2’s y coordinate, point 3’s y coordinate and point 4’s y coordinate.
  69. auto top = nan_safe_minimum(m_p1->y(), m_p2->y(), m_p3->y(), m_p4->y());
  70. // 4. Let right be the NaN-safe maximum of point 1’s x coordinate, point 2’s x coordinate, point 3’s x coordinate and point 4’s x coordinate.
  71. auto right = nan_safe_maximum(m_p1->x(), m_p2->x(), m_p3->x(), m_p4->x());
  72. // 5. Let bottom be the NaN-safe maximum of point 1’s y coordinate, point 2’s y coordinate, point 3’s y coordinate and point 4’s y coordinate.
  73. auto bottom = nan_safe_maximum(m_p1->y(), m_p2->y(), m_p3->y(), m_p4->y());
  74. // 6. Set x coordinate of bounds to left, y coordinate of bounds to top, width dimension of bounds to right - left and height dimension of bounds to bottom - top.
  75. bounds->set_x(left);
  76. bounds->set_y(top);
  77. bounds->set_width(right - left);
  78. bounds->set_height(bottom - top);
  79. // 7. Return bounds.
  80. return bounds;
  81. }
  82. // https://drafts.fxtf.org/geometry/#structured-serialization
  83. WebIDL::ExceptionOr<void> DOMQuad::serialization_steps(HTML::SerializationRecord& serialzied, bool for_storage, HTML::SerializationMemory& memory)
  84. {
  85. auto& vm = this->vm();
  86. // 1. Set serialized.[[P1]] to the sub-serialization of value’s point 1.
  87. serialzied.extend(TRY(HTML::structured_serialize_internal(vm, m_p1, for_storage, memory)));
  88. // 2. Set serialized.[[P2]] to the sub-serialization of value’s point 2.
  89. serialzied.extend(TRY(HTML::structured_serialize_internal(vm, m_p2, for_storage, memory)));
  90. // 3. Set serialized.[[P3]] to the sub-serialization of value’s point 3.
  91. serialzied.extend(TRY(HTML::structured_serialize_internal(vm, m_p3, for_storage, memory)));
  92. // 4. Set serialized.[[P4]] to the sub-serialization of value’s point 4.
  93. serialzied.extend(TRY(HTML::structured_serialize_internal(vm, m_p4, for_storage, memory)));
  94. return {};
  95. }
  96. // https://drafts.fxtf.org/geometry/#structured-serialization
  97. WebIDL::ExceptionOr<void> DOMQuad::deserialization_steps(ReadonlySpan<u32> const& serialized, size_t& position, HTML::DeserializationMemory& memory)
  98. {
  99. auto& realm = this->realm();
  100. // 1. Set value’s point 1 to the sub-deserialization of serialized.[[P1]].
  101. auto deserialized_record = TRY(HTML::structured_deserialize_internal(vm(), serialized, realm, memory, position));
  102. if (deserialized_record.value.has_value() && is<DOMPoint>(deserialized_record.value.value().as_object()))
  103. m_p1 = dynamic_cast<DOMPoint&>(deserialized_record.value.release_value().as_object());
  104. position = deserialized_record.position;
  105. // 2. Set value’s point 2 to the sub-deserialization of serialized.[[P2]].
  106. deserialized_record = TRY(HTML::structured_deserialize_internal(vm(), serialized, realm, memory, position));
  107. if (deserialized_record.value.has_value() && is<DOMPoint>(deserialized_record.value.value().as_object()))
  108. m_p2 = dynamic_cast<DOMPoint&>(deserialized_record.value.release_value().as_object());
  109. position = deserialized_record.position;
  110. // 3. Set value’s point 3 to the sub-deserialization of serialized.[[P3]].
  111. deserialized_record = TRY(HTML::structured_deserialize_internal(vm(), serialized, realm, memory, position));
  112. if (deserialized_record.value.has_value() && is<DOMPoint>(deserialized_record.value.value().as_object()))
  113. m_p3 = dynamic_cast<DOMPoint&>(deserialized_record.value.release_value().as_object());
  114. position = deserialized_record.position;
  115. // 4. Set value’s point 4 to the sub-deserialization of serialized.[[P4]].
  116. deserialized_record = TRY(HTML::structured_deserialize_internal(vm(), serialized, realm, memory, position));
  117. if (deserialized_record.value.has_value() && is<DOMPoint>(deserialized_record.value.value().as_object()))
  118. m_p4 = dynamic_cast<DOMPoint&>(deserialized_record.value.release_value().as_object());
  119. position = deserialized_record.position;
  120. return {};
  121. }
  122. void DOMQuad::initialize(JS::Realm& realm)
  123. {
  124. Base::initialize(realm);
  125. WEB_SET_PROTOTYPE_FOR_INTERFACE(DOMQuad);
  126. }
  127. void DOMQuad::visit_edges(Cell::Visitor& visitor)
  128. {
  129. Base::visit_edges(visitor);
  130. visitor.visit(m_p1);
  131. visitor.visit(m_p2);
  132. visitor.visit(m_p3);
  133. visitor.visit(m_p4);
  134. }
  135. }