Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(307)

Side by Side Diff: content/browser/renderer_host/render_widget_host_view_mac.mm

Issue 10656019: Use cached composition bounds for firstRectForCharacterRange (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: address comments Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 597 matching lines...) Expand 10 before | Expand all | Expand 10 after
608 // See http://crbug.com/73039. 608 // See http://crbug.com/73039.
609 [NSApp updateWindows]; 609 [NSApp updateWindows];
610 UseInputWindow(TSMGetActiveDocument(), !can_compose_inline_); 610 UseInputWindow(TSMGetActiveDocument(), !can_compose_inline_);
611 } 611 }
612 } 612 }
613 } 613 }
614 614
615 void RenderWidgetHostViewMac::SelectionBoundsChanged( 615 void RenderWidgetHostViewMac::SelectionBoundsChanged(
616 const gfx::Rect& start_rect, 616 const gfx::Rect& start_rect,
617 const gfx::Rect& end_rect) { 617 const gfx::Rect& end_rect) {
618 if (start_rect == end_rect)
619 caret_rect_ = start_rect;
618 } 620 }
619 621
620 void RenderWidgetHostViewMac::ImeCancelComposition() { 622 void RenderWidgetHostViewMac::ImeCancelComposition() {
621 [cocoa_view_ cancelComposition]; 623 [cocoa_view_ cancelComposition];
622 } 624 }
623 625
624 void RenderWidgetHostViewMac::ImeCompositionRangeChanged( 626 void RenderWidgetHostViewMac::ImeCompositionRangeChanged(
625 const ui::Range& range, 627 const ui::Range& range,
626 const std::vector<gfx::Rect>& character_bounds) { 628 const std::vector<gfx::Rect>& character_bounds) {
627 // The RangeChanged message is only sent with valid values. The current 629 // The RangeChanged message is only sent with valid values. The current
628 // caret position (start == end) will be sent if there is no IME range. 630 // caret position (start == end) will be sent if there is no IME range.
629 [cocoa_view_ setMarkedRange:range.ToNSRange()]; 631 [cocoa_view_ setMarkedRange:range.ToNSRange()];
632 composition_range_ = range;
633 composition_bounds_ = character_bounds;
630 } 634 }
631 635
632 void RenderWidgetHostViewMac::DidUpdateBackingStore( 636 void RenderWidgetHostViewMac::DidUpdateBackingStore(
633 const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, 637 const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy,
634 const std::vector<gfx::Rect>& copy_rects) { 638 const std::vector<gfx::Rect>& copy_rects) {
635 GotSoftwareFrame(); 639 GotSoftwareFrame();
636 640
637 if (!is_hidden_) { 641 if (!is_hidden_) {
638 std::vector<gfx::Rect> rects(copy_rects); 642 std::vector<gfx::Rect> rects(copy_rects);
639 643
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
763 selected_text_ = UTF16ToUTF8(text.substr(pos, n)); 767 selected_text_ = UTF16ToUTF8(text.substr(pos, n));
764 } 768 }
765 769
766 [cocoa_view_ setSelectedRange:range.ToNSRange()]; 770 [cocoa_view_ setSelectedRange:range.ToNSRange()];
767 // Updaes markedRange when there is no marked text so that retrieving 771 // Updaes markedRange when there is no marked text so that retrieving
768 // markedRange immediately after calling setMarkdText: returns the current 772 // markedRange immediately after calling setMarkdText: returns the current
769 // caret position. 773 // caret position.
770 if (![cocoa_view_ hasMarkedText]) { 774 if (![cocoa_view_ hasMarkedText]) {
771 [cocoa_view_ setMarkedRange:range.ToNSRange()]; 775 [cocoa_view_ setMarkedRange:range.ToNSRange()];
772 } 776 }
777
778 RenderWidgetHostViewBase::SelectionChanged(text, offset, range);
773 } 779 }
774 780
775 void RenderWidgetHostViewMac::SetShowingContextMenu(bool showing) { 781 void RenderWidgetHostViewMac::SetShowingContextMenu(bool showing) {
776 RenderWidgetHostViewBase::SetShowingContextMenu(showing); 782 RenderWidgetHostViewBase::SetShowingContextMenu(showing);
777 783
778 // Create a fake mouse event to inform the render widget that the mouse 784 // Create a fake mouse event to inform the render widget that the mouse
779 // left or entered. 785 // left or entered.
780 NSWindow* window = [cocoa_view_ window]; 786 NSWindow* window = [cocoa_view_ window];
781 // TODO(asvitkine): If the location outside of the event stream doesn't 787 // TODO(asvitkine): If the location outside of the event stream doesn't
782 // correspond to the current event (due to delayed event processing), then 788 // correspond to the current event (due to delayed event processing), then
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after
1012 pending_swap_buffers_acks_.front().first, 1018 pending_swap_buffers_acks_.front().first,
1013 pending_swap_buffers_acks_.front().second, 1019 pending_swap_buffers_acks_.front().second,
1014 0); 1020 0);
1015 if (render_widget_host_) 1021 if (render_widget_host_)
1016 render_widget_host_->AcknowledgeSwapBuffersToRenderer(); 1022 render_widget_host_->AcknowledgeSwapBuffersToRenderer();
1017 } 1023 }
1018 pending_swap_buffers_acks_.erase(pending_swap_buffers_acks_.begin()); 1024 pending_swap_buffers_acks_.erase(pending_swap_buffers_acks_.begin());
1019 } 1025 }
1020 } 1026 }
1021 1027
1028 bool RenderWidgetHostViewMac::GetLineBreakIndex(
1029 const std::vector<gfx::Rect>& bounds,
1030 const ui::Range& range,
1031 size_t* line_break_point) {
1032 DCHECK(line_break_point);
1033 if (range.start() >= bounds.size() || range.is_reversed() || range.is_empty())
1034 return false;
1035
1036 // We can't check line breaking completely from only rectangle array. Thus we
1037 // assume the line breaking as the next character's y offset is larger than
1038 // a threshold. Currently the threshold is determined as minimum y offset plus
1039 // 75% of maximum height.
1040 // TODO(nona): Check the threshold is reliable or not.
1041 // TODO(nona): Bidi support.
1042 const size_t loop_end_idx = std::min(bounds.size(), range.end());
1043 int max_height = 0;
1044 int min_y_offset = kint32max;
1045 for (size_t idx = range.start(); idx < loop_end_idx; ++idx) {
1046 max_height = std::max(max_height, bounds[idx].height());
1047 min_y_offset = std::min(min_y_offset, bounds[idx].y());
1048 }
1049 int line_break_threshold = min_y_offset + (max_height * 3 / 4);
1050 for (size_t idx = range.start(); idx < loop_end_idx; ++idx) {
1051 if (bounds[idx].y() > line_break_threshold) {
1052 *line_break_point = idx;
1053 return true;
1054 }
1055 }
1056 return false;
1057 }
1058
1059 gfx::Rect RenderWidgetHostViewMac::GetFirstRectForCompositionRange(
1060 const ui::Range& range,
1061 ui::Range* actual_range) {
1062 DCHECK(actual_range);
1063 DCHECK(!composition_bounds_.empty());
1064 DCHECK(range.start() <= composition_bounds_.size());
1065 DCHECK(range.end() <= composition_bounds_.size());
1066
1067 if (range.is_empty()) {
1068 *actual_range = range;
1069 if (range.start() == composition_bounds_.size()) {
1070 return gfx::Rect(composition_bounds_[range.start() - 1].right(),
1071 composition_bounds_[range.start() - 1].y(),
1072 0,
1073 composition_bounds_[range.start() - 1].height());
1074 } else {
1075 return gfx::Rect(composition_bounds_[range.start()].x(),
1076 composition_bounds_[range.start()].y(),
1077 0,
1078 composition_bounds_[range.start()].height());
1079 }
1080 }
1081
1082 size_t end_idx;
1083 if (!GetLineBreakIndex(composition_bounds_, range, &end_idx)) {
1084 end_idx = range.end();
1085 }
1086 *actual_range = ui::Range(range.start(), end_idx);
1087 gfx::Rect rect = composition_bounds_[range.start()];
1088 for (size_t i = range.start() + 1; i < end_idx; ++i) {
1089 rect = rect.Union(composition_bounds_[i]);
1090 }
1091 return rect;
1092 }
1093
1094 ui::Range RenderWidgetHostViewMac::ConvertCharacterRangeToCompositionRange(
1095 const ui::Range& request_range) {
1096 if (composition_range_.is_empty())
1097 return ui::Range::InvalidRange();
1098
1099 if (request_range.is_reversed())
1100 return ui::Range::InvalidRange();
1101
1102 if (request_range.start() < composition_range_.start() ||
1103 request_range.start() > composition_range_.end() ||
1104 request_range.end() > composition_range_.end()) {
1105 return ui::Range::InvalidRange();
1106 }
1107
1108 return ui::Range(
1109 request_range.start() - composition_range_.start(),
1110 request_range.end() - composition_range_.start());
1111 }
1112
1113 bool RenderWidgetHostViewMac::GetCachedFirstRectForCharacterRange(
1114 NSRange range,
1115 NSRect* rect,
1116 NSRange* actual_range) {
1117 // This exists to make IMEs more responsive, see http://crbug.com/115920
1118 TRACE_EVENT0("browser",
1119 "RenderWidgetHostViewMac::GetFirstRectForCharacterRange");
1120
1121 // If requested range is same as caret location, we can just return it.
1122 if (selection_range_.is_empty() && ui::Range(range) == selection_range_) {
1123 *actual_range = range;
1124 *rect = NSRectFromCGRect(caret_rect_.ToCGRect());
1125 return true;
1126 }
1127
1128 const ui::Range request_range_in_composition =
1129 ConvertCharacterRangeToCompositionRange(ui::Range(range));
1130 if (request_range_in_composition == ui::Range::InvalidRange())
1131 return false;
1132
1133 ui::Range ui_actual_range;
1134 *rect = NSRectFromCGRect(GetFirstRectForCompositionRange(
1135 request_range_in_composition,
1136 &ui_actual_range).ToCGRect());
1137 if (actual_range) {
1138 *actual_range = ui::Range(
1139 composition_range_.start() + ui_actual_range.start(),
1140 composition_range_.start() + ui_actual_range.end()).ToNSRange();
1141 }
1142 return true;
1143 }
1144
1022 void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped( 1145 void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped(
1023 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, 1146 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
1024 int gpu_host_id) { 1147 int gpu_host_id) {
1025 TRACE_EVENT0("browser", 1148 TRACE_EVENT0("browser",
1026 "RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped"); 1149 "RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped");
1027 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1028 1151
1029 pending_swap_buffers_acks_.push_back(std::make_pair(params.route_id, 1152 pending_swap_buffers_acks_.push_back(std::make_pair(params.route_id,
1030 gpu_host_id)); 1153 gpu_host_id));
1031 1154
(...skipping 1623 matching lines...) Expand 10 before | Expand all | Expand 10 after
2655 2778
2656 NSUInteger index = 2779 NSUInteger index =
2657 TextInputClientMac::GetInstance()->GetCharacterIndexAtPoint( 2780 TextInputClientMac::GetInstance()->GetCharacterIndexAtPoint(
2658 renderWidgetHostView_->render_widget_host_, 2781 renderWidgetHostView_->render_widget_host_,
2659 gfx::Point(thePoint.x, thePoint.y)); 2782 gfx::Point(thePoint.x, thePoint.y));
2660 return index; 2783 return index;
2661 } 2784 }
2662 2785
2663 - (NSRect)firstRectForCharacterRange:(NSRange)theRange 2786 - (NSRect)firstRectForCharacterRange:(NSRange)theRange
2664 actualRange:(NSRangePointer)actualRange { 2787 actualRange:(NSRangePointer)actualRange {
2665 // TODO(thakis): Pipe |actualRange| through TextInputClientMac machinery. 2788 NSRect rect;
2666 if (actualRange) 2789 if (!renderWidgetHostView_->GetCachedFirstRectForCharacterRange(
2667 *actualRange = theRange; 2790 theRange,
2668 NSRect rect = TextInputClientMac::GetInstance()->GetFirstRectForRange( 2791 &rect,
2669 renderWidgetHostView_->render_widget_host_, theRange); 2792 actualRange)) {
2793 rect = TextInputClientMac::GetInstance()->GetFirstRectForRange(
2794 renderWidgetHostView_->render_widget_host_, theRange);
2795
2796 // TODO(thakis): Pipe |actualRange| through TextInputClientMac machinery.
2797 if (actualRange)
2798 *actualRange = theRange;
2799 }
2670 2800
2671 // The returned rectangle is in WebKit coordinates (upper left origin), so 2801 // The returned rectangle is in WebKit coordinates (upper left origin), so
2672 // flip the coordinate system and then convert it into screen coordinates for 2802 // flip the coordinate system and then convert it into screen coordinates for
2673 // return. 2803 // return.
2674 NSRect viewFrame = [self frame]; 2804 NSRect viewFrame = [self frame];
2675 rect.origin.y = NSHeight(viewFrame) - rect.origin.y; 2805 rect.origin.y = NSHeight(viewFrame) - rect.origin.y;
2676 rect.origin.y -= rect.size.height; 2806 rect.origin.y -= rect.size.height;
2677 rect = [self convertRectToBase:rect]; 2807 rect = [self convertRectToBase:rect];
2678 rect.origin = [[self window] convertBaseToScreen:rect.origin]; 2808 rect.origin = [[self window] convertBaseToScreen:rect.origin];
2679 return rect; 2809 return rect;
(...skipping 392 matching lines...) Expand 10 before | Expand all | Expand 10 after
3072 if (!string) return NO; 3202 if (!string) return NO;
3073 3203
3074 // If the user is currently using an IME, confirm the IME input, 3204 // If the user is currently using an IME, confirm the IME input,
3075 // and then insert the text from the service, the same as TextEdit and Safari. 3205 // and then insert the text from the service, the same as TextEdit and Safari.
3076 [self confirmComposition]; 3206 [self confirmComposition];
3077 [self insertText:string]; 3207 [self insertText:string];
3078 return YES; 3208 return YES;
3079 } 3209 }
3080 3210
3081 @end 3211 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698