@@ -740,6 +740,16 @@ int Element::GetLocationOnceScrolledIntoView(const ElementScrollBehavior scroll,
740
740
LOG (WARN) << " Scrolled element is not in view" ;
741
741
status_code = EELEMENTCLICKPOINTNOTSCROLLED;
742
742
}
743
+
744
+ // TODO: Handle the case where the element's click point is in
745
+ // the view port but hidden by the overflow of a parent element.
746
+ // That could would look something like the following:
747
+ // if (this->IsHiddenByOverflow(element_location, click_location)) {
748
+ // if (!this->IsEntirelyHiddenByOverflow()) {
749
+ // this->ScrollWithinOverflow(element_location);
750
+ // }
751
+ // status_code = EELEMENTCLICKPOINTNOTSCROLLED;
752
+ // }
743
753
}
744
754
745
755
LOG (DEBUG) << " (x, y, w, h): "
@@ -793,6 +803,83 @@ bool Element::IsHiddenByOverflow(const LocationInfo element_location,
793
803
return is_overflow;
794
804
}
795
805
806
+ bool Element::IsEntirelyHiddenByOverflow () {
807
+ LOG (TRACE) << " Entering Element::IsEntirelyHiddenByOverflow" ;
808
+
809
+ bool is_overflow = false ;
810
+
811
+ std::wstring script_source (L" (function() { return (" );
812
+ script_source += atoms::asString (atoms::IS_ELEMENT_IN_PARENT_OVERFLOW);
813
+ script_source += L" )})();" ;
814
+
815
+ CComPtr<IHTMLDocument2> doc;
816
+ this ->GetContainingDocument (false , &doc);
817
+ Script script_wrapper (doc, script_source, 1 );
818
+ script_wrapper.AddArgument (this ->element_ );
819
+ int status_code = script_wrapper.Execute ();
820
+ if (status_code == WD_SUCCESS) {
821
+ std::wstring raw_overflow_state (script_wrapper.result ().bstrVal );
822
+ std::string overflow_state = StringUtilities::ToString (raw_overflow_state);
823
+ is_overflow = (overflow_state == " scroll" );
824
+ } else {
825
+ LOG (WARN) << " Unable to determine is element hidden by overflow" ;
826
+ }
827
+
828
+ return is_overflow;
829
+ }
830
+
831
+ bool Element::ScrollWithinOverflow (const LocationInfo element_location) {
832
+ RECT element_rect;
833
+ element_rect.left = element_location.x ;
834
+ element_rect.top = element_location.y ;
835
+ element_rect.right = element_location.x + element_location.width ;
836
+ element_rect.bottom = element_location.y + element_location.height ;
837
+
838
+ CComPtr<IHTMLElement> parent_element;
839
+ this ->element_ ->get_parentElement (&parent_element);
840
+ while (parent_element != NULL ) {
841
+ CComPtr<IHTMLElement2> el2;
842
+ parent_element->QueryInterface <IHTMLElement2>(&el2);
843
+ CComPtr<IHTMLRect> parent_bounding_rect;
844
+ el2->getBoundingClientRect (&parent_bounding_rect);
845
+ RECT parent_rect;
846
+ parent_bounding_rect->get_left (&parent_rect.left );
847
+ parent_bounding_rect->get_top (&parent_rect.top );
848
+ parent_bounding_rect->get_right (&parent_rect.right );
849
+ parent_bounding_rect->get_bottom (&parent_rect.bottom );
850
+ RECT intersection;
851
+ if (::IntersectRect (&intersection, &element_rect, &parent_rect)) {
852
+ if (::EqualRect (&intersection, &element_rect)) {
853
+ CComPtr<IHTMLElement> next_ancestor;
854
+ // The entire element is visible within this ancestor.
855
+ // Need to proceed to the next ancestor in the tree.
856
+ parent_element->get_parentElement (&next_ancestor);
857
+ parent_element.Release ();
858
+ parent_element = next_ancestor;
859
+ } else {
860
+ // We have the intersecting rect, so adjust the location
861
+ long intersection_vert_center = intersection.top + ((intersection.bottom - intersection.top ) / 2 );
862
+ long intersection_horiz_center = intersection.left + ((intersection.right - intersection.left ) / 2 );
863
+
864
+ long offset_top = 0 ;
865
+ element_->get_offsetTop (&offset_top);
866
+ offset_top += element_location.height / 2 ;
867
+
868
+ long offset_left = 0 ;
869
+ element_->get_offsetLeft (&offset_left);
870
+ offset_left += element_location.width / 2 ;
871
+
872
+ el2->put_scrollTop (offset_top - intersection_vert_center);
873
+ el2->put_scrollLeft (offset_left - intersection_horiz_center);
874
+ return true ;
875
+ }
876
+ } else {
877
+ // the rects don't intersect, so something went wrong.
878
+ break ;
879
+ }
880
+ }
881
+ return false ;
882
+ }
796
883
bool Element::IsLocationVisibleInFrames (const LocationInfo location,
797
884
const std::vector<LocationInfo> frame_locations) {
798
885
std::vector<LocationInfo>::const_iterator iterator = frame_locations.begin ();
@@ -1417,7 +1504,20 @@ LocationInfo Element::CalculateClickPoint(const LocationInfo location, const boo
1417
1504
LocationInfo clickable_viewport = {};
1418
1505
bool result = this ->GetClickableViewPortLocation (document_contains_frames,
1419
1506
&clickable_viewport);
1507
+
1420
1508
if (result) {
1509
+ // TODO: Handle the case where the center of the target element
1510
+ // is already in the view port. The code would look something like
1511
+ // the following:
1512
+ // If the center of the target element is already in the view port,
1513
+ // we don't need to adjust to find the "in view center point."
1514
+ // Technically, this is a deliberate violation of the spec.
1515
+ // long element_center_x = location.x + static_cast<long>(floor(location.width / 2.0));
1516
+ // long element_center_y = location.y + static_cast<long>(floor(location.height / 2.0));
1517
+ // if (element_center_x < 0 ||
1518
+ // element_center_x >= clickable_viewport.width ||
1519
+ // element_center_y < 0 ||
1520
+ // element_center_y >= clickable_viewport.height) {
1421
1521
RECT element_rect;
1422
1522
element_rect.left = location.x ;
1423
1523
element_rect.top = location.y ;
@@ -1432,8 +1532,8 @@ LocationInfo Element::CalculateClickPoint(const LocationInfo location, const boo
1432
1532
1433
1533
RECT intersect_rect;
1434
1534
BOOL is_intersecting = ::IntersectRect (&intersect_rect,
1435
- &element_rect,
1436
- &viewport_rect);
1535
+ &element_rect,
1536
+ &viewport_rect);
1437
1537
if (is_intersecting) {
1438
1538
corrected_width = intersect_rect.right - intersect_rect.left ;
1439
1539
corrected_height = intersect_rect.bottom - intersect_rect.top ;
0 commit comments