@@ -12,7 +12,6 @@ namespace client_layout
1212
1313 LayoutBox::LayoutBox (shared_ptr<dom::Node> node)
1414 : LayoutBoxModelObject(node)
15- , hit_testable_bounding_box_{glm::vec3 (0 .0f ), glm::vec3 (0 .0f ), glm::mat4 (1 .0f )}
1615 {
1716 }
1817
@@ -287,21 +286,30 @@ namespace client_layout
287286
288287 bool LayoutBox::mayIntersect (const HitTestResult &r, const HitTestRay &ray, const glm::vec3 &accumulatedOffset) const
289288 {
290- optional <geometry::BoundingBox> overflowBox = nullopt ;
289+ vector <geometry::BoundingBox> overflowBoxes ;
291290 if (hasHitTestableOverflow ())
292291 {
293292 // TODO(yorkie): handle the hit test for the box with overflow.
294293 }
295294 else
296- overflowBox = getHitTestableBoundingBox ();
295+ overflowBoxes = getHitTestableBoundingBoxes ();
297296
298- if (overflowBox. has_value () )
297+ if (overflowBoxes. size () > 0 )
299298 {
300- overflowBox->move (accumulatedOffset);
301-
302- auto min = overflowBox->minimumWorld ;
303- auto max = overflowBox->maximumWorld ;
304- return ray.intersectsBoxMinMax (min, max);
299+ bool intersects = false ;
300+ for (auto box : overflowBoxes)
301+ {
302+ box.move (accumulatedOffset);
303+
304+ auto min = box.minimumWorld ;
305+ auto max = box.maximumWorld ;
306+ if (ray.intersectsBoxMinMax (min, max))
307+ {
308+ intersects = true ;
309+ break ;
310+ }
311+ }
312+ return intersects;
305313 }
306314 else
307315 {
@@ -329,6 +337,14 @@ namespace client_layout
329337 return false ;
330338 }
331339
340+ void LayoutBox::didComputeLayout (const ConstraintSpace &availableSpace)
341+ {
342+ LayoutBoxModelObject::didComputeLayout (availableSpace);
343+
344+ // Update the hit-testable bounding box.
345+ updateHitTestableBoundingBoxes ();
346+ }
347+
332348 void LayoutBox::didComputeLayoutOnce (const ConstraintSpace &availableSpace)
333349 {
334350 LayoutBoxModelObject::didComputeLayoutOnce (availableSpace);
@@ -340,9 +356,6 @@ namespace client_layout
340356 getScrollableArea ()
341357 ->updateAfterLayout (formattingContext ().liveFragment ());
342358 }
343-
344- // Update the hit-testable bounding box.
345- updateHitTestableBoundingBox ();
346359 }
347360
348361 void LayoutBox::updateFromStyle ()
@@ -398,31 +411,43 @@ namespace client_layout
398411 return childBoxes;
399412 }
400413
401- void LayoutBox::updateHitTestableBoundingBox ()
414+ void LayoutBox::updateHitTestableBoundingBoxes ()
402415 {
403- auto selfBoundingBox = physicalBorderBoxRect ();
404- glm::vec3 unionMin = selfBoundingBox.minimumWorld ;
405- glm::vec3 unionMax = selfBoundingBox.maximumWorld ;
416+ hit_testable_bounding_boxes_.clear ();
417+
418+ geometry::BoundingBox mainBoundingBox = physicalBorderBoxRect ();
419+ hit_testable_bounding_boxes_.push_back (mainBoundingBox);
420+
421+ glm::vec3 mainMin = mainBoundingBox.minimumWorld ;
422+ glm::vec3 mainMax = mainBoundingBox.maximumWorld ;
406423
407424 for (const auto &childBox : getChildBoxes ())
408425 {
409426 if (!childBox->visible ())
410427 continue ;
411428
412- const geometry::BoundingBox &childBoundingBox = childBox->getHitTestableBoundingBox ();
413- unionMin.x = min (unionMin.x , childBoundingBox.minimumWorld .x );
414- unionMin.y = min (unionMin.y , childBoundingBox.minimumWorld .y );
415- unionMin.z = min (unionMin.z , childBoundingBox.minimumWorld .z );
416- unionMax.x = max (unionMax.x , childBoundingBox.maximumWorld .x );
417- unionMax.y = max (unionMax.y , childBoundingBox.maximumWorld .y );
418- unionMax.z = max (unionMax.z , childBoundingBox.maximumWorld .z );
429+ for (const auto &childBoundingBox : childBox->getHitTestableBoundingBoxes ())
430+ {
431+ // Skip extending if the child box has no size.
432+ if (glm::all (glm::epsilonEqual (childBoundingBox.extendSizeWorld ,
433+ glm::vec3 (0 .0f ),
434+ glm::epsilon<float >())))
435+ {
436+ continue ;
437+ }
438+
439+ // Check if the child box is fully contained in the main bounding box.
440+ glm::vec3 childMin = childBoundingBox.minimumWorld ;
441+ glm::vec3 childMax = childBoundingBox.maximumWorld ;
442+ if (childMin.x >= mainMin.x && childMin.y >= mainMin.y && childMin.z >= mainMin.z &&
443+ childMax.x <= mainMax.x && childMax.y <= mainMax.y && childMax.z <= mainMax.z )
444+ {
445+ continue ; // Child box is fully contained, skip adding it.
446+ }
447+ hit_testable_bounding_boxes_.push_back (childBoundingBox);
448+ }
419449 }
420- hit_testable_bounding_box_ = geometry::BoundingBox (unionMin, unionMax, glm::mat4 (1 .0f ));
421450
422- // Notify the parent box to update its hit-testable bounding box.
423- if (parent () && parent ()->isBox ())
424- {
425- parentBox ()->updateHitTestableBoundingBox ();
426- }
451+ assert (hit_testable_bounding_boxes_.size () > 0 );
427452 }
428453}
0 commit comments