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

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

Issue 10382213: Defer CGLFlushDrawable until OSX-requested drawRect to avoid spinning when window is obscured. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed animation halt during resize Created 8 years, 7 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 | Annotate | Revision Log
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 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 weak_factory_(this) { 268 weak_factory_(this) {
269 // |cocoa_view_| owns us and we will be deleted when |cocoa_view_| 269 // |cocoa_view_| owns us and we will be deleted when |cocoa_view_|
270 // goes away. Since we autorelease it, our caller must put 270 // goes away. Since we autorelease it, our caller must put
271 // |GetNativeView()| into the view hierarchy right after calling us. 271 // |GetNativeView()| into the view hierarchy right after calling us.
272 cocoa_view_ = [[[RenderWidgetHostViewCocoa alloc] 272 cocoa_view_ = [[[RenderWidgetHostViewCocoa alloc]
273 initWithRenderWidgetHostViewMac:this] autorelease]; 273 initWithRenderWidgetHostViewMac:this] autorelease];
274 render_widget_host_->SetView(this); 274 render_widget_host_->SetView(this);
275 } 275 }
276 276
277 RenderWidgetHostViewMac::~RenderWidgetHostViewMac() { 277 RenderWidgetHostViewMac::~RenderWidgetHostViewMac() {
278 AckPendingSwapBuffers();
278 UnlockMouse(); 279 UnlockMouse();
279 } 280 }
280 281
281 void RenderWidgetHostViewMac::SetDelegate( 282 void RenderWidgetHostViewMac::SetDelegate(
282 NSObject<RenderWidgetHostViewMacDelegate>* delegate) { 283 NSObject<RenderWidgetHostViewMacDelegate>* delegate) {
283 [cocoa_view_ setRWHVDelegate:delegate]; 284 [cocoa_view_ setRWHVDelegate:delegate];
284 } 285 }
285 286
286 /////////////////////////////////////////////////////////////////////////////// 287 ///////////////////////////////////////////////////////////////////////////////
287 // RenderWidgetHostViewMac, RenderWidgetHostView implementation: 288 // RenderWidgetHostViewMac, RenderWidgetHostView implementation:
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 render_widget_host_->WasRestored(); 362 render_widget_host_->WasRestored();
362 363
363 // We're messing with the window, so do this to ensure no flashes. 364 // We're messing with the window, so do this to ensure no flashes.
364 [[cocoa_view_ window] disableScreenUpdatesUntilFlush]; 365 [[cocoa_view_ window] disableScreenUpdatesUntilFlush];
365 } 366 }
366 367
367 void RenderWidgetHostViewMac::WasHidden() { 368 void RenderWidgetHostViewMac::WasHidden() {
368 if (is_hidden_) 369 if (is_hidden_)
369 return; 370 return;
370 371
372 // Send ACKs for any pending SwapBuffers (if any) since we won't be displaying
373 // them and the GPU process is waiting.
Ken Russell (switch to Gerrit) 2012/05/17 20:28:34 Is there any issue with this being inside the shor
jbates 2012/05/18 00:31:47 The code at line 953 ensures that we only need to
374 AckPendingSwapBuffers();
375
371 // If we receive any more paint messages while we are hidden, we want to 376 // If we receive any more paint messages while we are hidden, we want to
372 // ignore them so we don't re-allocate the backing store. We will paint 377 // ignore them so we don't re-allocate the backing store. We will paint
373 // everything again when we become selected again. 378 // everything again when we become selected again.
374 is_hidden_ = true; 379 is_hidden_ = true;
375 380
376 // If we have a renderer, then inform it that we are being hidden so it can 381 // If we have a renderer, then inform it that we are being hidden so it can
377 // reduce its resource utilization. 382 // reduce its resource utilization.
378 render_widget_host_->WasHidden(); 383 render_widget_host_->WasHidden();
379 384
380 // There can be a transparent flash as this view is removed and the next is 385 // There can be a transparent flash as this view is removed and the next is
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
653 [cocoa_view_ displayIfNeeded]; 658 [cocoa_view_ displayIfNeeded];
654 } 659 }
655 } 660 }
656 661
657 void RenderWidgetHostViewMac::RenderViewGone(base::TerminationStatus status, 662 void RenderWidgetHostViewMac::RenderViewGone(base::TerminationStatus status,
658 int error_code) { 663 int error_code) {
659 Destroy(); 664 Destroy();
660 } 665 }
661 666
662 void RenderWidgetHostViewMac::Destroy() { 667 void RenderWidgetHostViewMac::Destroy() {
668 AckPendingSwapBuffers();
669
663 // On Windows, popups are implemented with a popup window style, so that when 670 // On Windows, popups are implemented with a popup window style, so that when
664 // an event comes in that would "cancel" it, it receives the OnCancelMode 671 // an event comes in that would "cancel" it, it receives the OnCancelMode
665 // message and can kill itself. Alas, on the Mac, views cannot capture events 672 // message and can kill itself. Alas, on the Mac, views cannot capture events
666 // outside of themselves. On Windows, if Destroy is being called on a view, 673 // outside of themselves. On Windows, if Destroy is being called on a view,
667 // then the event causing the destroy had also cancelled any popups by the 674 // then the event causing the destroy had also cancelled any popups by the
668 // time Destroy() was called. On the Mac we have to destroy all the popups 675 // time Destroy() was called. On the Mac we have to destroy all the popups
669 // ourselves. 676 // ourselves.
670 677
671 // Depth-first destroy all popups. Use ShutdownHost() to enforce 678 // Depth-first destroy all popups. Use ShutdownHost() to enforce
672 // deepest-first ordering. 679 // deepest-first ordering.
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
935 int32 width, 942 int32 width,
936 int32 height, 943 int32 height,
937 TransportDIB::Handle transport_dib) { 944 TransportDIB::Handle transport_dib) {
938 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 945 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
939 plugin_container_manager_.SetSizeAndTransportDIB(window, 946 plugin_container_manager_.SetSizeAndTransportDIB(window,
940 width, 947 width,
941 height, 948 height,
942 transport_dib); 949 transport_dib);
943 } 950 }
944 951
945 void RenderWidgetHostViewMac::CompositorSwapBuffers(uint64 surface_handle) { 952 bool RenderWidgetHostViewMac::CompositorSwapBuffers(uint64 surface_handle) {
946 if (is_hidden_) 953 if (is_hidden_)
947 return; 954 return true;
948 955
949 if (!compositing_iosurface_.get()) 956 if (!compositing_iosurface_.get())
950 compositing_iosurface_.reset(CompositingIOSurfaceMac::Create()); 957 compositing_iosurface_.reset(CompositingIOSurfaceMac::Create());
951 958
952 if (!compositing_iosurface_.get()) 959 if (!compositing_iosurface_.get())
953 return; 960 return true;
954 961
955 compositing_iosurface_->SetIOSurface(surface_handle); 962 compositing_iosurface_->SetIOSurface(surface_handle);
963
964 GotAcceleratedFrame();
965
956 // No need to draw the surface if we are inside a drawRect. It will be done 966 // No need to draw the surface if we are inside a drawRect. It will be done
957 // later. 967 // later.
958 if (!about_to_validate_and_paint_) 968 if (!about_to_validate_and_paint_) {
959 compositing_iosurface_->DrawIOSurface(cocoa_view_); 969 // Trigger a drawRect, but don't invalidate the whole window because it
960 GotAcceleratedFrame(); 970 // is expensive to clear it with transparency to expose the GL underneath.
971 [cocoa_view_ setNeedsDisplayInRect:NSMakeRect(0, 0, 1, 1)];
972
973 // While resizing, OSX fails to call drawRect on the NSView unless the
974 // window size has changed. That means we won't see animations update if the
975 // user has the mouse button held down, but is not currently changing the
976 // size of the window. To work around that, display here while resizing.
977 if ([cocoa_view_ inLiveResize])
978 [cocoa_view_ displayIfNeeded];
979 }
980 return false;
981 }
982
983 void RenderWidgetHostViewMac::AckPendingSwapBuffers() {
984 TRACE_EVENT0("browser", "RenderWidgetHostViewMac::AckPendingSwapBuffers");
985 while (!pending_swap_buffers_acks_.empty()) {
986 if (pending_swap_buffers_acks_.front().first != 0) {
987 RenderWidgetHostImpl::AcknowledgeSwapBuffers(
988 pending_swap_buffers_acks_.front().first,
989 pending_swap_buffers_acks_.front().second);
990 }
991 pending_swap_buffers_acks_.erase(pending_swap_buffers_acks_.begin());
992 }
961 } 993 }
962 994
963 void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped( 995 void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped(
964 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, 996 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
965 int gpu_host_id) { 997 int gpu_host_id) {
966 TRACE_EVENT0("browser", 998 TRACE_EVENT0("browser",
967 "RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped"); 999 "RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped");
968 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1000 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1001
1002 pending_swap_buffers_acks_.push_back(std::make_pair(params.route_id,
1003 gpu_host_id));
969 1004
970 // Compositor window is always gfx::kNullPluginWindow. 1005 // Compositor window is always gfx::kNullPluginWindow.
971 // TODO(jbates) http://crbug.com/105344 This will be removed when there are no 1006 // TODO(jbates) http://crbug.com/105344 This will be removed when there are no
972 // plugin windows. 1007 // plugin windows.
973 if (params.window == gfx::kNullPluginWindow) { 1008 if (params.window == gfx::kNullPluginWindow) {
974 CompositorSwapBuffers(params.surface_handle); 1009 if (CompositorSwapBuffers(params.surface_handle))
1010 AckPendingSwapBuffers();
975 } else { 1011 } else {
976 // Deprecated accelerated plugin code path. 1012 // Deprecated accelerated plugin code path.
977 AcceleratedPluginView* view = ViewForPluginWindowHandle(params.window); 1013 AcceleratedPluginView* view = ViewForPluginWindowHandle(params.window);
978 DCHECK(view); 1014 DCHECK(view);
979 if (view) { 1015 if (view) {
980 plugin_container_manager_.SetSurfaceWasPaintedTo(params.window, 1016 plugin_container_manager_.SetSurfaceWasPaintedTo(params.window,
981 params.surface_handle); 1017 params.surface_handle);
982 1018
983 // The surface is hidden until its first paint, to not show garbage. 1019 // The surface is hidden until its first paint, to not show garbage.
984 if (plugin_container_manager_.SurfaceShouldBeVisible(params.window)) 1020 if (plugin_container_manager_.SurfaceShouldBeVisible(params.window))
985 [view setHidden:NO]; 1021 [view setHidden:NO];
986 [view drawView]; 1022 [view drawView];
987 } 1023 }
988 } 1024 AckPendingSwapBuffers();
989
990 if (params.route_id != 0) {
991 RenderWidgetHostImpl::AcknowledgeSwapBuffers(params.route_id,
992 gpu_host_id);
993 } 1025 }
994 } 1026 }
995 1027
996 void RenderWidgetHostViewMac::AcceleratedSurfacePostSubBuffer( 1028 void RenderWidgetHostViewMac::AcceleratedSurfacePostSubBuffer(
997 const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params, 1029 const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
998 int gpu_host_id) { 1030 int gpu_host_id) {
999 TRACE_EVENT0("browser", 1031 TRACE_EVENT0("browser",
1000 "RenderWidgetHostViewMac::AcceleratedSurfacePostSubBuffer"); 1032 "RenderWidgetHostViewMac::AcceleratedSurfacePostSubBuffer");
1001 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1033 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1034
1035 pending_swap_buffers_acks_.push_back(std::make_pair(params.route_id,
1036 gpu_host_id));
1002 1037
1003 // Compositor window is always gfx::kNullPluginWindow. 1038 // Compositor window is always gfx::kNullPluginWindow.
1004 // TODO(jbates) http://crbug.com/105344 This will be removed when there are no 1039 // TODO(jbates) http://crbug.com/105344 This will be removed when there are no
1005 // plugin windows. 1040 // plugin windows.
1006 if (params.window == gfx::kNullPluginWindow) { 1041 if (params.window == gfx::kNullPluginWindow) {
1007 CompositorSwapBuffers(params.surface_handle); 1042 if (CompositorSwapBuffers(params.surface_handle))
1043 AckPendingSwapBuffers();
1008 } else { 1044 } else {
1009 // Deprecated accelerated plugin code path. 1045 // Deprecated accelerated plugin code path.
1010 AcceleratedPluginView* view = ViewForPluginWindowHandle(params.window); 1046 AcceleratedPluginView* view = ViewForPluginWindowHandle(params.window);
1011 DCHECK(view); 1047 DCHECK(view);
1012 if (view) { 1048 if (view) {
1013 plugin_container_manager_.SetSurfaceWasPaintedTo( 1049 plugin_container_manager_.SetSurfaceWasPaintedTo(
1014 params.window, 1050 params.window,
1015 params.surface_handle, 1051 params.surface_handle,
1016 gfx::Rect(params.x, params.y, params.width, params.height)); 1052 gfx::Rect(params.x, params.y, params.width, params.height));
1017 1053
1018 // The surface is hidden until its first paint, to not show garbage. 1054 // The surface is hidden until its first paint, to not show garbage.
1019 if (plugin_container_manager_.SurfaceShouldBeVisible(params.window)) 1055 if (plugin_container_manager_.SurfaceShouldBeVisible(params.window))
1020 [view setHidden:NO]; 1056 [view setHidden:NO];
1021 [view drawView]; 1057 [view drawView];
1022 } 1058 }
1023 } 1059 AckPendingSwapBuffers();
1024
1025 if (params.route_id != 0) {
1026 RenderWidgetHostImpl::AcknowledgePostSubBuffer(
1027 params.route_id, gpu_host_id);
1028 } 1060 }
1029 } 1061 }
1030 1062
1031 void RenderWidgetHostViewMac::AcceleratedSurfaceSuspend() { 1063 void RenderWidgetHostViewMac::AcceleratedSurfaceSuspend() {
1032 if (compositing_iosurface_.get()) 1064 if (compositing_iosurface_.get())
1033 compositing_iosurface_->UnrefIOSurface(); 1065 compositing_iosurface_->UnrefIOSurface();
1034 } 1066 }
1035 1067
1036 bool RenderWidgetHostViewMac::HasAcceleratedSurface( 1068 bool RenderWidgetHostViewMac::HasAcceleratedSurface(
1037 const gfx::Size& desired_size) { 1069 const gfx::Size& desired_size) {
1038 return last_frame_was_accelerated_ && 1070 return last_frame_was_accelerated_ &&
1039 compositing_iosurface_.get() && 1071 compositing_iosurface_.get() &&
1040 compositing_iosurface_->HasIOSurface() && 1072 compositing_iosurface_->HasIOSurface() &&
1041 (desired_size.IsEmpty() || 1073 (desired_size.IsEmpty() ||
1042 compositing_iosurface_->io_surface_size() == desired_size); 1074 compositing_iosurface_->io_surface_size() == desired_size);
1043 } 1075 }
1044 1076
1077 void RenderWidgetHostViewMac::AboutToWaitForBackingStoreMsg() {
1078 AckPendingSwapBuffers();
1079 }
1080
1045 void RenderWidgetHostViewMac::OnAcceleratedCompositingStateChange() { 1081 void RenderWidgetHostViewMac::OnAcceleratedCompositingStateChange() {
1046 } 1082 }
1047 1083
1048 void RenderWidgetHostViewMac::GetScreenInfo(WebKit::WebScreenInfo* results) { 1084 void RenderWidgetHostViewMac::GetScreenInfo(WebKit::WebScreenInfo* results) {
1049 *results = WebKit::WebScreenInfoFactory::screenInfo(GetNativeView()); 1085 *results = WebKit::WebScreenInfoFactory::screenInfo(GetNativeView());
1050 } 1086 }
1051 1087
1052 gfx::Rect RenderWidgetHostViewMac::GetRootWindowBounds() { 1088 gfx::Rect RenderWidgetHostViewMac::GetRootWindowBounds() {
1053 // TODO(shess): In case of !window, the view has been removed from 1089 // TODO(shess): In case of !window, the view has been removed from
1054 // the view hierarchy because the tab isn't main. Could retrieve 1090 // the view hierarchy because the tab isn't main. Could retrieve
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
1146 render_widget_host_->Shutdown(); 1182 render_widget_host_->Shutdown();
1147 // Do not touch any members at this point, |this| has been deleted. 1183 // Do not touch any members at this point, |this| has been deleted.
1148 } 1184 }
1149 1185
1150 void RenderWidgetHostViewMac::GotAcceleratedFrame() { 1186 void RenderWidgetHostViewMac::GotAcceleratedFrame() {
1151 if (!last_frame_was_accelerated_) { 1187 if (!last_frame_was_accelerated_) {
1152 last_frame_was_accelerated_ = true; 1188 last_frame_was_accelerated_ = true;
1153 1189
1154 // Need to wipe the software view with transparency to expose the GL 1190 // Need to wipe the software view with transparency to expose the GL
1155 // underlay. Invalidate the whole window to do that. 1191 // underlay. Invalidate the whole window to do that.
1156 if (!about_to_validate_and_paint_) { 1192 if (!about_to_validate_and_paint_)
1157 [cocoa_view_ setNeedsDisplay:YES]; 1193 [cocoa_view_ setNeedsDisplay:YES];
1158 [cocoa_view_ displayIfNeeded];
1159 }
1160 1194
1161 // Delete software backingstore. 1195 // Delete software backingstore.
1162 BackingStoreManager::RemoveBackingStore(render_widget_host_); 1196 BackingStoreManager::RemoveBackingStore(render_widget_host_);
1163 } 1197 }
1164 } 1198 }
1165 1199
1166 void RenderWidgetHostViewMac::GotSoftwareFrame() { 1200 void RenderWidgetHostViewMac::GotSoftwareFrame() {
1167 if (last_frame_was_accelerated_) { 1201 if (last_frame_was_accelerated_) {
1168 last_frame_was_accelerated_ = false; 1202 last_frame_was_accelerated_ = false;
1169 1203
1204 AckPendingSwapBuffers();
1205
1170 // Forget IOSurface since we are drawing a software frame now. 1206 // Forget IOSurface since we are drawing a software frame now.
1171 if (compositing_iosurface_.get() && 1207 if (compositing_iosurface_.get() &&
1172 compositing_iosurface_->HasIOSurface()) { 1208 compositing_iosurface_->HasIOSurface()) {
1173 compositing_iosurface_->UnrefIOSurface(); 1209 compositing_iosurface_->UnrefIOSurface();
1174 } 1210 }
1175 } 1211 }
1176 } 1212 }
1177 1213
1178 gfx::Rect RenderWidgetHostViewMac::GetViewCocoaBounds() const { 1214 gfx::Rect RenderWidgetHostViewMac::GetViewCocoaBounds() const {
1179 return gfx::Rect(NSRectToCGRect([cocoa_view_ bounds])); 1215 return gfx::Rect(NSRectToCGRect([cocoa_view_ bounds]));
(...skipping 707 matching lines...) Expand 10 before | Expand all | Expand 10 after
1887 // blit the IOSurface below. 1923 // blit the IOSurface below.
1888 renderWidgetHostView_->about_to_validate_and_paint_ = true; 1924 renderWidgetHostView_->about_to_validate_and_paint_ = true;
1889 BackingStoreMac* backingStore = static_cast<BackingStoreMac*>( 1925 BackingStoreMac* backingStore = static_cast<BackingStoreMac*>(
1890 renderWidgetHostView_->render_widget_host_->GetBackingStore(true)); 1926 renderWidgetHostView_->render_widget_host_->GetBackingStore(true));
1891 renderWidgetHostView_->about_to_validate_and_paint_ = false; 1927 renderWidgetHostView_->about_to_validate_and_paint_ = false;
1892 1928
1893 const gfx::Rect damagedRect([self flipNSRectToRect:dirtyRect]); 1929 const gfx::Rect damagedRect([self flipNSRectToRect:dirtyRect]);
1894 1930
1895 if (renderWidgetHostView_->last_frame_was_accelerated_ && 1931 if (renderWidgetHostView_->last_frame_was_accelerated_ &&
1896 renderWidgetHostView_->compositing_iosurface_.get()) { 1932 renderWidgetHostView_->compositing_iosurface_.get()) {
1897 // Note that this code path is only executed when there's window damage
1898 // (when the window is foregrounded, for example). Normally, GPU frames
1899 // arrive and are drawn during AcceleratedSurfaceBuffersSwapped.
1900 { 1933 {
1901 TRACE_EVENT0("browser", "NSRectFill"); 1934 TRACE_EVENT0("browser", "NSRectFill");
1902 // Draw transparency to expose the GL underlay. NSRectFill is extremely 1935 // Draw transparency to expose the GL underlay. NSRectFill is extremely
1903 // slow (15ms for a window on a fast MacPro), so this is only done for the 1936 // slow (15ms for a window on a fast MacPro), so this is only done for the
1904 // dirty rect. The composited swap-buffers typically happens outside of 1937 // dirty rect. The composited swap-buffers typically happens outside of
1905 // drawRect to avoid invalidating the entire NSView. 1938 // drawRect to avoid invalidating the entire NSView.
1906 [[NSColor clearColor] set]; 1939 [[NSColor clearColor] set];
1907 NSRectFill(dirtyRect); 1940 NSRectFill(dirtyRect);
1908 } 1941 }
1909 1942
1910 renderWidgetHostView_->compositing_iosurface_->DrawIOSurface(self); 1943 renderWidgetHostView_->compositing_iosurface_->DrawIOSurface(self);
1944 renderWidgetHostView_->AckPendingSwapBuffers();
1911 return; 1945 return;
1912 } 1946 }
1913 1947
1914 if (backingStore) { 1948 if (backingStore) {
1915 gfx::Rect bitmapRect(0, 0, 1949 gfx::Rect bitmapRect(0, 0,
1916 backingStore->size().width(), 1950 backingStore->size().width(),
1917 backingStore->size().height()); 1951 backingStore->size().height());
1918 1952
1919 // Specify the proper y offset to ensure that the view is rooted to the 1953 // Specify the proper y offset to ensure that the view is rooted to the
1920 // upper left corner. This can be negative, if the window was resized 1954 // upper left corner. This can be negative, if the window was resized
(...skipping 972 matching lines...) Expand 10 before | Expand all | Expand 10 after
2893 if (!string) return NO; 2927 if (!string) return NO;
2894 2928
2895 // If the user is currently using an IME, confirm the IME input, 2929 // If the user is currently using an IME, confirm the IME input,
2896 // and then insert the text from the service, the same as TextEdit and Safari. 2930 // and then insert the text from the service, the same as TextEdit and Safari.
2897 [self confirmComposition]; 2931 [self confirmComposition];
2898 [self insertText:string]; 2932 [self insertText:string];
2899 return YES; 2933 return YES;
2900 } 2934 }
2901 2935
2902 @end 2936 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698