@@ -833,6 +833,119 @@ bool Element::IsSelected() {
833
833
return selected;
834
834
}
835
835
836
+ bool Element::IsImageMap (LocationInfo* location) {
837
+ CComPtr<IHTMLElement> map_element;
838
+ CComPtr<IHTMLAreaElement> area_element;
839
+ CComPtr<IHTMLMapElement> map_element_candidate;
840
+ this ->element_ ->QueryInterface <IHTMLMapElement>(&map_element_candidate);
841
+ if (map_element_candidate == NULL ) {
842
+ this ->element_ ->QueryInterface <IHTMLAreaElement>(&area_element);
843
+ if (area_element) {
844
+ this ->element_ ->get_parentElement (&map_element);
845
+ if (map_element) {
846
+ map_element->QueryInterface <IHTMLMapElement>(&map_element_candidate);
847
+ }
848
+ }
849
+ }
850
+
851
+ if (map_element_candidate && map_element) {
852
+ CComBSTR name_bstr;
853
+ map_element_candidate->get_name (&name_bstr);
854
+ CComBSTR img_selector = L" *[usemap='#" ;
855
+ img_selector.Append (name_bstr);
856
+ img_selector.Append (L" ']" );
857
+
858
+ CComPtr<IDispatch> doc_dispatch;
859
+ map_element->get_document (&doc_dispatch);
860
+
861
+ CComPtr<IDocumentSelector> doc;
862
+ doc_dispatch->QueryInterface <IDocumentSelector>(&doc);
863
+ if (doc) {
864
+ CComPtr<IHTMLElement> img_element;
865
+ doc->querySelector (img_selector, &img_element);
866
+ if (img_element) {
867
+ CComPtr<IHTMLElement2> rect_element;
868
+ img_element->QueryInterface <IHTMLElement2>(&rect_element);
869
+ if (rect_element) {
870
+ CComPtr<IHTMLRect> rect;
871
+ rect_element->getBoundingClientRect (&rect);
872
+ RECT img_rect;
873
+ rect->get_left (&img_rect.left );
874
+ rect->get_top (&img_rect.top );
875
+ rect->get_right (&img_rect.right );
876
+ rect->get_bottom (&img_rect.bottom );
877
+
878
+ CComBSTR shape;
879
+ area_element->get_shape (&shape);
880
+ shape.ToLower ();
881
+ if (shape == L" default" ) {
882
+ location->x = img_rect.left ;
883
+ location->y = img_rect.top ;
884
+ location->width = img_rect.right - img_rect.left ;
885
+ location->height = img_rect.bottom - img_rect.top ;
886
+ return true ;
887
+ }
888
+
889
+ CComBSTR coords_bstr;
890
+ area_element->get_coords (&coords_bstr);
891
+ std::wstring coords (coords_bstr);
892
+ std::vector<std::wstring> individual;
893
+ StringUtilities::Split (coords, L" ," , &individual);
894
+ RECT area_rect = { 0 , 0 , 0 , 0 };
895
+ if (shape == L" rect" && individual.size () == 4 ) {
896
+ area_rect.left = std::stol (individual.at (0 ).c_str (), 0 , 10 );
897
+ area_rect.top = std::stol (individual.at (1 ).c_str (), 0 , 10 );
898
+ area_rect.right = std::stol (individual.at (2 ).c_str (), 0 , 10 );
899
+ area_rect.bottom = std::stol (individual.at (3 ).c_str (), 0 , 10 );
900
+ }
901
+ else if ((shape == L" circle" || shape == " circ" ) && individual.size () == 3 ) {
902
+ long center_x = std::stol (individual.at (0 ), 0 , 10 );
903
+ long center_y = std::stol (individual.at (1 ), 0 , 10 );
904
+ long radius = std::stol (individual.at (2 ), 0 , 10 );
905
+ area_rect.left = center_x - radius;
906
+ area_rect.top = center_y - radius;
907
+ area_rect.right = center_x + radius;
908
+ area_rect.bottom = center_y + radius;
909
+ }
910
+ else if ((shape == L" poly" || shape == L" polygon" ) && individual.size () > 2 ) {
911
+ long min_x = std::stol (individual.at (0 ), 0 , 10 );
912
+ long min_y = std::stol (individual.at (1 ), 0 , 10 );
913
+ long max_x = min_x;
914
+ long max_y = min_y;
915
+ for (size_t i = 2 ; i + 1 < individual.size (); i += 2 ) {
916
+ long next_x = std::stol (individual.at (i), 0 , 10 );
917
+ long next_y = std::stol (individual.at (i + 1 ), 0 , 10 );
918
+ min_x = min (min_x, next_x);
919
+ max_x = max (max_x, next_x);
920
+ min_y = min (min_y, next_y);
921
+ max_y = max (max_y, next_y);
922
+ }
923
+ area_rect.left = min_x;
924
+ area_rect.bottom = min_y;
925
+ area_rect.right = max_x;
926
+ area_rect.bottom = max_y;
927
+ }
928
+ else {
929
+ // Invalid shape value or coordinate values. Not modifying location.
930
+ return false ;
931
+ }
932
+
933
+ long img_width = img_rect.right - img_rect.left ;
934
+ long img_height = img_rect.bottom - img_rect.top ;
935
+ long area_width = area_rect.right - area_rect.left ;
936
+ long area_height = area_rect.bottom - area_rect.top ;
937
+ location->x = img_rect.left + min (max (area_rect.left , 0 ), img_width);
938
+ location->y = img_rect.top + min (max (area_rect.top , 0 ), img_height);
939
+ location->width = min (area_width, img_width - location->x );
940
+ location->height = min (area_height, img_height - location->y );
941
+ return true ;
942
+ }
943
+ }
944
+ }
945
+ }
946
+ return false ;
947
+ }
948
+
836
949
int Element::GetLocation (LocationInfo* location,
837
950
std::vector<LocationInfo>* frame_locations) {
838
951
LOG (TRACE) << " Entering Element::GetLocation" ;
@@ -846,102 +959,112 @@ int Element::GetLocation(LocationInfo* location,
846
959
return EOBSOLETEELEMENT;
847
960
}
848
961
849
- // If this element is inline, we need to check whether we should
850
- // use getBoundingClientRect() or the first non-zero-sized rect returned
851
- // by getClientRects(). If the element is not inline, we can use
852
- // getBoundingClientRect() directly.
853
- CComPtr<IHTMLRect> rect;
854
- if (this ->IsInline ()) {
855
- CComPtr<IHTMLRectCollection> rects;
856
- hr = element2->getClientRects (&rects);
857
- long rect_count;
858
- rects->get_length (&rect_count);
859
- if (rect_count > 1 ) {
860
- LOG (DEBUG) << " Element is inline with multiple client rects, finding first non-zero sized client rect" ;
861
- for (long i = 0 ; i < rect_count; ++i) {
862
- CComVariant index (i);
863
- CComVariant rect_variant;
864
- hr = rects->item (&index, &rect_variant);
865
- if (SUCCEEDED (hr) && rect_variant.pdispVal ) {
866
- CComPtr<IHTMLRect> qi_rect;
867
- rect_variant.pdispVal ->QueryInterface <IHTMLRect>(&qi_rect);
868
- if (qi_rect) {
869
- rect = qi_rect;
870
- if (RectHasNonZeroDimensions (rect)) {
871
- // IE returns absolute positions in the page, rather than frame- and scroll-bound
872
- // positions, for clientRects (as opposed to boundingClientRects).
873
- has_absolute_position_ready_to_return = true ;
874
- break ;
962
+ long top = 0 , bottom = 0 , left = 0 , right = 0 ;
963
+ LocationInfo map_location = { 0 , 0 , 0 , 0 };
964
+ if (this ->IsImageMap (&map_location)) {
965
+ left = map_location.x ;
966
+ top = map_location.y ;
967
+ right = map_location.x + map_location.width ;
968
+ bottom = map_location.y + map_location.height ;
969
+ } else {
970
+ // If this element is inline, we need to check whether we should
971
+ // use getBoundingClientRect() or the first non-zero-sized rect returned
972
+ // by getClientRects(). If the element is not inline, we can use
973
+ // getBoundingClientRect() directly.
974
+ CComPtr<IHTMLRect> rect;
975
+ if (this ->IsInline ()) {
976
+ CComPtr<IHTMLRectCollection> rects;
977
+ hr = element2->getClientRects (&rects);
978
+ long rect_count;
979
+ rects->get_length (&rect_count);
980
+ if (rect_count > 1 ) {
981
+ LOG (DEBUG) << " Element is inline with multiple client rects, finding first non-zero sized client rect" ;
982
+ for (long i = 0 ; i < rect_count; ++i) {
983
+ CComVariant index (i);
984
+ CComVariant rect_variant;
985
+ hr = rects->item (&index, &rect_variant);
986
+ if (SUCCEEDED (hr) && rect_variant.pdispVal ) {
987
+ CComPtr<IHTMLRect> qi_rect;
988
+ rect_variant.pdispVal ->QueryInterface <IHTMLRect>(&qi_rect);
989
+ if (qi_rect) {
990
+ rect = qi_rect;
991
+ if (RectHasNonZeroDimensions (rect)) {
992
+ // IE returns absolute positions in the page, rather than frame- and scroll-bound
993
+ // positions, for clientRects (as opposed to boundingClientRects).
994
+ has_absolute_position_ready_to_return = true ;
995
+ break ;
996
+ }
875
997
}
876
998
}
877
999
}
878
1000
}
879
- } else {
880
- LOG (DEBUG) << " Element is inline with one client rect, using IHTMLElement2::getBoundingClientRect" ;
1001
+ else {
1002
+ LOG (DEBUG) << " Element is inline with one client rect, using IHTMLElement2::getBoundingClientRect" ;
1003
+ hr = element2->getBoundingClientRect (&rect);
1004
+ }
1005
+ }
1006
+ else {
1007
+ LOG (DEBUG) << " Element is a block element, using IHTMLElement2::getBoundingClientRect" ;
881
1008
hr = element2->getBoundingClientRect (&rect);
1009
+ if (this ->HasFirstChildTextNodeOfMultipleChildren ()) {
1010
+ LOG (DEBUG) << " Element has multiple children, but the first child is a text node, using text node boundaries" ;
1011
+ // Note that since subsequent statements in this method use the HTMLRect
1012
+ // object, we will update that object with the values of the text node.
1013
+ LocationInfo text_node_location;
1014
+ this ->GetTextBoundaries (&text_node_location);
1015
+ rect->put_left (text_node_location.x );
1016
+ rect->put_top (text_node_location.y );
1017
+ rect->put_right (text_node_location.x + text_node_location.width );
1018
+ rect->put_bottom (text_node_location.y + text_node_location.height );
1019
+ }
882
1020
}
883
- } else {
884
- LOG (DEBUG) << " Element is a block element, using IHTMLElement2::getBoundingClientRect" ;
885
- hr = element2->getBoundingClientRect (&rect);
886
- if (this ->HasFirstChildTextNodeOfMultipleChildren ()) {
887
- LOG (DEBUG) << " Element has multiple children, but the first child is a text node, using text node boundaries" ;
888
- // Note that since subsequent statements in this method use the HTMLRect
889
- // object, we will update that object with the values of the text node.
890
- LocationInfo text_node_location;
891
- this ->GetTextBoundaries (&text_node_location);
892
- rect->put_left (text_node_location.x );
893
- rect->put_top (text_node_location.y );
894
- rect->put_right (text_node_location.x + text_node_location.width );
895
- rect->put_bottom (text_node_location.y + text_node_location.height );
1021
+ if (FAILED (hr)) {
1022
+ LOGHR (WARN, hr) << " Cannot figure out where the element is on screen, client rect retrieval failed" ;
1023
+ return EUNHANDLEDERROR;
896
1024
}
897
- }
898
- if (FAILED (hr)) {
899
- LOGHR (WARN, hr) << " Cannot figure out where the element is on screen, client rect retrieval failed" ;
900
- return EUNHANDLEDERROR;
901
- }
902
-
903
- // If the rect of the element has zero width and height, check its
904
- // children to see if any of them have width and height, in which
905
- // case, this element will be visible.
906
- if (!RectHasNonZeroDimensions (rect)) {
907
- LOG (DEBUG) << " Element has client rect with zero dimension, checking children for non-zero dimension client rects" ;
908
- CComPtr<IHTMLDOMNode> node;
909
- element2->QueryInterface (&node);
910
- CComPtr<IDispatch> children_dispatch;
911
- node->get_childNodes (&children_dispatch);
912
- CComPtr<IHTMLDOMChildrenCollection> children;
913
- children_dispatch->QueryInterface <IHTMLDOMChildrenCollection>(&children);
914
- if (!!children) {
915
- long children_count = 0 ;
916
- children->get_length (&children_count);
917
- for (long i = 0 ; i < children_count; ++i) {
918
- CComPtr<IDispatch> child_dispatch;
919
- children->item (i, &child_dispatch);
920
- CComPtr<IHTMLElement> child;
921
- child_dispatch->QueryInterface (&child);
922
- if (child != NULL ) {
923
- int result = WD_SUCCESS;
924
- Element child_element (child, this ->containing_window_handle_ );
925
- if (frame_locations == nullptr ) {
926
- result = child_element.GetLocation (location, nullptr );
927
- } else {
928
- std::vector<LocationInfo> child_frame_locations;
929
- result = child_element.GetLocation (location, &child_frame_locations);
930
- }
931
- if (result == WD_SUCCESS) {
932
- return result;
1025
+
1026
+ // If the rect of the element has zero width and height, check its
1027
+ // children to see if any of them have width and height, in which
1028
+ // case, this element will be visible.
1029
+ if (!RectHasNonZeroDimensions (rect)) {
1030
+ LOG (DEBUG) << " Element has client rect with zero dimension, checking children for non-zero dimension client rects" ;
1031
+ CComPtr<IHTMLDOMNode> node;
1032
+ element2->QueryInterface (&node);
1033
+ CComPtr<IDispatch> children_dispatch;
1034
+ node->get_childNodes (&children_dispatch);
1035
+ CComPtr<IHTMLDOMChildrenCollection> children;
1036
+ children_dispatch->QueryInterface <IHTMLDOMChildrenCollection>(&children);
1037
+ if (!!children) {
1038
+ long children_count = 0 ;
1039
+ children->get_length (&children_count);
1040
+ for (long i = 0 ; i < children_count; ++i) {
1041
+ CComPtr<IDispatch> child_dispatch;
1042
+ children->item (i, &child_dispatch);
1043
+ CComPtr<IHTMLElement> child;
1044
+ child_dispatch->QueryInterface (&child);
1045
+ if (child != NULL ) {
1046
+ int result = WD_SUCCESS;
1047
+ Element child_element (child, this ->containing_window_handle_ );
1048
+ if (frame_locations == nullptr ) {
1049
+ result = child_element.GetLocation (location, nullptr );
1050
+ }
1051
+ else {
1052
+ std::vector<LocationInfo> child_frame_locations;
1053
+ result = child_element.GetLocation (location, &child_frame_locations);
1054
+ }
1055
+ if (result == WD_SUCCESS) {
1056
+ return result;
1057
+ }
933
1058
}
934
1059
}
935
1060
}
936
1061
}
937
- }
938
-
939
- long top = 0 , bottom = 0 , left = 0 , right = 0 ;
940
1062
941
- rect->get_top (&top);
942
- rect->get_left (&left);
943
- rect->get_bottom (&bottom);
944
- rect->get_right (&right);
1063
+ rect->get_top (&top);
1064
+ rect->get_left (&left);
1065
+ rect->get_bottom (&bottom);
1066
+ rect->get_right (&right);
1067
+ }
945
1068
946
1069
long w = right - left;
947
1070
long h = bottom - top;
0 commit comments