DOMQuad.cpp 7.4 KB

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