Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/renderer_host/render_widget_host_view_mac.h" | 5 #include "content/browser/renderer_host/render_widget_host_view_mac.h" |
| 6 | 6 |
| 7 #include <QuartzCore/QuartzCore.h> | 7 #include <QuartzCore/QuartzCore.h> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| (...skipping 617 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 628 // See http://crbug.com/73039. | 628 // See http://crbug.com/73039. |
| 629 [NSApp updateWindows]; | 629 [NSApp updateWindows]; |
| 630 UseInputWindow(TSMGetActiveDocument(), !can_compose_inline_); | 630 UseInputWindow(TSMGetActiveDocument(), !can_compose_inline_); |
| 631 } | 631 } |
| 632 } | 632 } |
| 633 } | 633 } |
| 634 | 634 |
| 635 void RenderWidgetHostViewMac::SelectionBoundsChanged( | 635 void RenderWidgetHostViewMac::SelectionBoundsChanged( |
| 636 const gfx::Rect& start_rect, | 636 const gfx::Rect& start_rect, |
| 637 const gfx::Rect& end_rect) { | 637 const gfx::Rect& end_rect) { |
| 638 if (start_rect == end_rect) | |
| 639 caret_rect_ = start_rect; | |
| 638 } | 640 } |
| 639 | 641 |
| 640 void RenderWidgetHostViewMac::ImeCancelComposition() { | 642 void RenderWidgetHostViewMac::ImeCancelComposition() { |
| 641 [cocoa_view_ cancelComposition]; | 643 [cocoa_view_ cancelComposition]; |
| 642 } | 644 } |
| 643 | 645 |
| 644 void RenderWidgetHostViewMac::ImeCompositionRangeChanged( | 646 void RenderWidgetHostViewMac::ImeCompositionRangeChanged( |
| 645 const ui::Range& range, | 647 const ui::Range& range, |
| 646 const std::vector<gfx::Rect>& character_bounds) { | 648 const std::vector<gfx::Rect>& character_bounds) { |
| 647 // The RangeChanged message is only sent with valid values. The current | 649 // The RangeChanged message is only sent with valid values. The current |
| 648 // caret position (start == end) will be sent if there is no IME range. | 650 // caret position (start == end) will be sent if there is no IME range. |
| 649 [cocoa_view_ setMarkedRange:range.ToNSRange()]; | 651 [cocoa_view_ setMarkedRange:range.ToNSRange()]; |
| 652 composition_range_ = range; | |
| 653 composition_bounds_ = character_bounds; | |
| 650 } | 654 } |
| 651 | 655 |
| 652 void RenderWidgetHostViewMac::DidUpdateBackingStore( | 656 void RenderWidgetHostViewMac::DidUpdateBackingStore( |
| 653 const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, | 657 const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, |
| 654 const std::vector<gfx::Rect>& copy_rects) { | 658 const std::vector<gfx::Rect>& copy_rects) { |
| 655 GotSoftwareFrame(); | 659 GotSoftwareFrame(); |
| 656 | 660 |
| 657 if (!is_hidden_) { | 661 if (!is_hidden_) { |
| 658 std::vector<gfx::Rect> rects(copy_rects); | 662 std::vector<gfx::Rect> rects(copy_rects); |
| 659 | 663 |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 783 selected_text_ = UTF16ToUTF8(text.substr(pos, n)); | 787 selected_text_ = UTF16ToUTF8(text.substr(pos, n)); |
| 784 } | 788 } |
| 785 | 789 |
| 786 [cocoa_view_ setSelectedRange:range.ToNSRange()]; | 790 [cocoa_view_ setSelectedRange:range.ToNSRange()]; |
| 787 // Updaes markedRange when there is no marked text so that retrieving | 791 // Updaes markedRange when there is no marked text so that retrieving |
| 788 // markedRange immediately after calling setMarkdText: returns the current | 792 // markedRange immediately after calling setMarkdText: returns the current |
| 789 // caret position. | 793 // caret position. |
| 790 if (![cocoa_view_ hasMarkedText]) { | 794 if (![cocoa_view_ hasMarkedText]) { |
| 791 [cocoa_view_ setMarkedRange:range.ToNSRange()]; | 795 [cocoa_view_ setMarkedRange:range.ToNSRange()]; |
| 792 } | 796 } |
| 797 | |
| 798 RenderWidgetHostViewBase::SelectionChanged(text, offset, range); | |
| 793 } | 799 } |
| 794 | 800 |
| 795 void RenderWidgetHostViewMac::SetShowingContextMenu(bool showing) { | 801 void RenderWidgetHostViewMac::SetShowingContextMenu(bool showing) { |
| 796 content::RenderWidgetHostViewBase::SetShowingContextMenu(showing); | 802 content::RenderWidgetHostViewBase::SetShowingContextMenu(showing); |
| 797 | 803 |
| 798 // Create a fake mouse event to inform the render widget that the mouse | 804 // Create a fake mouse event to inform the render widget that the mouse |
| 799 // left or entered. | 805 // left or entered. |
| 800 NSWindow* window = [cocoa_view_ window]; | 806 NSWindow* window = [cocoa_view_ window]; |
| 801 // TODO(asvitkine): If the location outside of the event stream doesn't | 807 // TODO(asvitkine): If the location outside of the event stream doesn't |
| 802 // correspond to the current event (due to delayed event processing), then | 808 // correspond to the current event (due to delayed event processing), then |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1032 pending_swap_buffers_acks_.front().first, | 1038 pending_swap_buffers_acks_.front().first, |
| 1033 pending_swap_buffers_acks_.front().second, | 1039 pending_swap_buffers_acks_.front().second, |
| 1034 0); | 1040 0); |
| 1035 if (render_widget_host_) | 1041 if (render_widget_host_) |
| 1036 render_widget_host_->AcknowledgeSwapBuffersToRenderer(); | 1042 render_widget_host_->AcknowledgeSwapBuffersToRenderer(); |
| 1037 } | 1043 } |
| 1038 pending_swap_buffers_acks_.erase(pending_swap_buffers_acks_.begin()); | 1044 pending_swap_buffers_acks_.erase(pending_swap_buffers_acks_.begin()); |
| 1039 } | 1045 } |
| 1040 } | 1046 } |
| 1041 | 1047 |
| 1048 bool RenderWidgetHostViewMac::GetLineBreakIdx( | |
| 1049 const std::vector<gfx::Rect>& bounds, | |
| 1050 const ui::Range& range, | |
| 1051 size_t* line_break_point) { | |
| 1052 DCHECK(line_break_point); | |
| 1053 if (range.start() >= bounds.size() || range.is_reversed() || range.is_empty()) | |
| 1054 return false; | |
| 1055 | |
| 1056 // We can't check line breaking completely from only rectangle array. Thus we | |
| 1057 // assume the line breaking as the next character's y offset is larger than | |
| 1058 // a threshold. Currently the threshold is determined as minimum y offset plus | |
| 1059 // 75% of maximum height. | |
| 1060 // TODO(nona): Check the threshold is reliable or not. | |
| 1061 // TODO(nona): Bidi support. | |
| 1062 const size_t loop_end_idx = std::min(bounds.size(), range.end()); | |
| 1063 int max_height = 0; | |
| 1064 int min_y_offset = kint32max; | |
| 1065 for (size_t idx = range.start(); idx < loop_end_idx; ++idx) { | |
| 1066 max_height = std::max(max_height, bounds[idx].height()); | |
| 1067 min_y_offset = std::min(min_y_offset, bounds[idx].y()); | |
| 1068 } | |
| 1069 int line_break_threshold = min_y_offset + (max_height * 3 / 4); | |
| 1070 for (size_t idx = range.start(); idx < loop_end_idx; ++idx) { | |
| 1071 if (bounds[idx].y() > line_break_threshold) { | |
| 1072 *line_break_point = idx; | |
| 1073 return true; | |
| 1074 } | |
| 1075 } | |
| 1076 return false; | |
| 1077 } | |
| 1078 | |
| 1079 gfx::Rect RenderWidgetHostViewMac::GetFirstRectForCompositionRange( | |
| 1080 const ui::Range& range, | |
| 1081 ui::Range* actual_range) { | |
| 1082 DCHECK(actual_range); | |
| 1083 DCHECK(!composition_bounds_.empty()); | |
| 1084 DCHECK(range.start() <= composition_bounds_.size()); | |
| 1085 DCHECK(range.end() <= composition_bounds_.size()); | |
| 1086 | |
| 1087 if (range.is_empty()) { | |
| 1088 *actual_range = range; | |
| 1089 if (range.start() == composition_bounds_.size()) { | |
| 1090 return gfx::Rect(composition_bounds_[range.start() - 1].right(), | |
| 1091 composition_bounds_[range.start() - 1].y(), | |
| 1092 0, | |
| 1093 composition_bounds_[range.start() - 1].height()); | |
| 1094 } else { | |
| 1095 return gfx::Rect(composition_bounds_[range.start()].x(), | |
| 1096 composition_bounds_[range.start()].y(), | |
| 1097 0, | |
| 1098 composition_bounds_[range.start()].height()); | |
| 1099 } | |
| 1100 } | |
| 1101 | |
| 1102 size_t end_idx; | |
| 1103 if (!GetLineBreakIdx(composition_bounds_, range, &end_idx)) { | |
| 1104 end_idx = range.end(); | |
| 1105 } | |
| 1106 *actual_range = ui::Range(range.start(), end_idx); | |
| 1107 gfx::Rect rect = composition_bounds_[range.start()]; | |
| 1108 for (size_t i = range.start() + 1; i < end_idx; ++i) { | |
| 1109 rect = rect.Union(composition_bounds_[i]); | |
| 1110 } | |
| 1111 return rect; | |
| 1112 } | |
| 1113 | |
| 1114 ui::Range RenderWidgetHostViewMac::ConvertCharacterRangeToCompositionRange( | |
| 1115 const ui::Range& request_range) { | |
| 1116 if (composition_range_.is_empty()) | |
| 1117 return ui::Range::InvalidRange(); | |
| 1118 | |
| 1119 if (request_range.is_reversed()) | |
| 1120 return ui::Range::InvalidRange(); | |
| 1121 | |
| 1122 if (request_range.start() < composition_range_.start() || | |
| 1123 request_range.start() > composition_range_.end() || | |
| 1124 request_range.end() > composition_range_.end()) { | |
| 1125 return ui::Range::InvalidRange(); | |
| 1126 } | |
| 1127 | |
| 1128 return ui::Range( | |
| 1129 request_range.start() - composition_range_.start(), | |
| 1130 request_range.end() - composition_range_.start()); | |
| 1131 } | |
| 1132 | |
| 1133 bool RenderWidgetHostViewMac::GetCachedFirstRectForCharacterRange( | |
| 1134 NSRange range, | |
|
Nico
2012/07/21 16:43:27
nit: indent arguments 4
Seigo Nonaka
2012/07/23 08:36:55
Done.
| |
| 1135 NSRect* rect, | |
| 1136 NSRange* actual_range) { | |
|
Nico
2012/07/21 16:43:27
Add a comment "// This exists to make IMEs more re
Seigo Nonaka
2012/07/23 08:36:55
Done.
| |
| 1137 TRACE_EVENT0("browser", | |
| 1138 "RenderWidgetHostViewMac::GetFirstRectForCharacterRange"); | |
| 1139 | |
| 1140 // If requested range is same as caret location, we can just return it. | |
| 1141 if (selection_range_.is_empty() && ui::Range(range) == selection_range_) { | |
| 1142 *actual_range = range; | |
| 1143 *rect = NSRectFromCGRect(caret_rect_.ToCGRect()); | |
| 1144 return true; | |
| 1145 } | |
| 1146 | |
| 1147 const ui::Range request_range_in_composition = | |
| 1148 ConvertCharacterRangeToCompositionRange(ui::Range(range)); | |
|
Nico
2012/07/21 16:43:27
nit: indent continuations 2 more
Seigo Nonaka
2012/07/23 08:36:55
Done.
| |
| 1149 if (request_range_in_composition == ui::Range::InvalidRange()) | |
| 1150 return false; | |
| 1151 | |
| 1152 ui::Range ui_actual_range; | |
| 1153 *rect = NSRectFromCGRect(GetFirstRectForCompositionRange( | |
| 1154 request_range_in_composition, | |
| 1155 &ui_actual_range).ToCGRect()); | |
| 1156 if (actual_range) { | |
| 1157 *actual_range = ui::Range( | |
| 1158 composition_range_.start() + ui_actual_range.start(), | |
| 1159 composition_range_.start() + ui_actual_range.end()).ToNSRange(); | |
| 1160 } | |
| 1161 return true; | |
| 1162 } | |
| 1163 | |
| 1042 void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped( | 1164 void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped( |
| 1043 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, | 1165 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, |
| 1044 int gpu_host_id) { | 1166 int gpu_host_id) { |
| 1045 TRACE_EVENT0("browser", | 1167 TRACE_EVENT0("browser", |
| 1046 "RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped"); | 1168 "RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped"); |
| 1047 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1048 | 1170 |
| 1049 pending_swap_buffers_acks_.push_back(std::make_pair(params.route_id, | 1171 pending_swap_buffers_acks_.push_back(std::make_pair(params.route_id, |
| 1050 gpu_host_id)); | 1172 gpu_host_id)); |
| 1051 | 1173 |
| (...skipping 1622 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2674 | 2796 |
| 2675 NSUInteger index = | 2797 NSUInteger index = |
| 2676 TextInputClientMac::GetInstance()->GetCharacterIndexAtPoint( | 2798 TextInputClientMac::GetInstance()->GetCharacterIndexAtPoint( |
| 2677 renderWidgetHostView_->render_widget_host_, | 2799 renderWidgetHostView_->render_widget_host_, |
| 2678 gfx::Point(thePoint.x, thePoint.y)); | 2800 gfx::Point(thePoint.x, thePoint.y)); |
| 2679 return index; | 2801 return index; |
| 2680 } | 2802 } |
| 2681 | 2803 |
| 2682 - (NSRect)firstRectForCharacterRange:(NSRange)theRange | 2804 - (NSRect)firstRectForCharacterRange:(NSRange)theRange |
| 2683 actualRange:(NSRangePointer)actualRange { | 2805 actualRange:(NSRangePointer)actualRange { |
| 2684 // TODO(thakis): Pipe |actualRange| through TextInputClientMac machinery. | 2806 NSRect rect; |
| 2685 if (actualRange) | 2807 if (!renderWidgetHostView_->GetCachedFirstRectForCharacterRange( |
| 2686 *actualRange = theRange; | 2808 theRange, |
| 2687 NSRect rect = TextInputClientMac::GetInstance()->GetFirstRectForRange( | 2809 &rect, |
| 2688 renderWidgetHostView_->render_widget_host_, theRange); | 2810 actualRange)) { |
| 2811 rect = TextInputClientMac::GetInstance()->GetFirstRectForRange( | |
| 2812 renderWidgetHostView_->render_widget_host_, theRange); | |
| 2813 | |
| 2814 // TODO(thakis): Pipe |actualRange| through TextInputClientMac machinery. | |
| 2815 if (actualRange) | |
| 2816 *actualRange = theRange; | |
| 2817 } | |
| 2689 | 2818 |
| 2690 // The returned rectangle is in WebKit coordinates (upper left origin), so | 2819 // The returned rectangle is in WebKit coordinates (upper left origin), so |
| 2691 // flip the coordinate system and then convert it into screen coordinates for | 2820 // flip the coordinate system and then convert it into screen coordinates for |
| 2692 // return. | 2821 // return. |
| 2693 NSRect viewFrame = [self frame]; | 2822 NSRect viewFrame = [self frame]; |
| 2694 rect.origin.y = NSHeight(viewFrame) - rect.origin.y; | 2823 rect.origin.y = NSHeight(viewFrame) - rect.origin.y; |
| 2695 rect.origin.y -= rect.size.height; | 2824 rect.origin.y -= rect.size.height; |
| 2696 rect = [self convertRectToBase:rect]; | 2825 rect = [self convertRectToBase:rect]; |
| 2697 rect.origin = [[self window] convertBaseToScreen:rect.origin]; | 2826 rect.origin = [[self window] convertBaseToScreen:rect.origin]; |
| 2698 return rect; | 2827 return rect; |
| (...skipping 392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3091 if (!string) return NO; | 3220 if (!string) return NO; |
| 3092 | 3221 |
| 3093 // If the user is currently using an IME, confirm the IME input, | 3222 // If the user is currently using an IME, confirm the IME input, |
| 3094 // and then insert the text from the service, the same as TextEdit and Safari. | 3223 // and then insert the text from the service, the same as TextEdit and Safari. |
| 3095 [self confirmComposition]; | 3224 [self confirmComposition]; |
| 3096 [self insertText:string]; | 3225 [self insertText:string]; |
| 3097 return YES; | 3226 return YES; |
| 3098 } | 3227 } |
| 3099 | 3228 |
| 3100 @end | 3229 @end |
| OLD | NEW |