Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / render_widget_host_view_mac.mm
index 71dfb16..2e89069 100644 (file)
@@ -27,8 +27,9 @@
 #include "base/sys_info.h"
 #import "content/browser/accessibility/browser_accessibility_cocoa.h"
 #include "content/browser/accessibility/browser_accessibility_manager_mac.h"
-#include "content/browser/renderer_host/backing_store_mac.h"
-#include "content/browser/renderer_host/backing_store_manager.h"
+#include "content/browser/frame_host/frame_tree.h"
+#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
 #include "content/browser/renderer_host/compositing_iosurface_layer_mac.h"
 #include "content/browser/renderer_host/compositing_iosurface_mac.h"
 #include "content/common/input_messages.h"
 #include "content/common/view_messages.h"
 #include "content/common/webplugin_geometry.h"
-#include "content/port/browser/render_widget_host_view_frame_subscriber.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/native_web_keyboard_event.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
 #import "content/public/browser/render_widget_host_view_mac_delegate.h"
 #include "content/public/browser/user_metrics.h"
-#include "content/public/common/content_switches.h"
+#include "content/public/browser/web_contents.h"
 #include "skia/ext/platform_canvas.h"
+#include "third_party/WebKit/public/platform/WebScreenInfo.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "third_party/WebKit/public/web/WebScreenInfo.h"
 #include "third_party/WebKit/public/web/mac/WebInputEventFactory.h"
 #import "third_party/mozilla/ComplexTextInputPanel.h"
 #include "ui/base/cocoa/animation_utils.h"
 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
 #include "ui/gfx/screen.h"
 #include "ui/gfx/size_conversions.h"
+#include "ui/gl/gl_switches.h"
 #include "ui/gl/io_surface_support_mac.h"
 
-using content::BackingStoreMac;
 using content::BrowserAccessibility;
 using content::BrowserAccessibilityManager;
 using content::EditCommand;
+using content::FrameTreeNode;
 using content::NativeWebKeyboardEvent;
+using content::RenderFrameHost;
+using content::RenderViewHost;
 using content::RenderViewHostImpl;
 using content::RenderWidgetHostImpl;
 using content::RenderWidgetHostViewMac;
 using content::RenderWidgetHostViewMacEditCommandHelper;
 using content::TextInputClientMac;
-using WebKit::WebInputEvent;
-using WebKit::WebInputEventFactory;
-using WebKit::WebMouseEvent;
-using WebKit::WebMouseWheelEvent;
-
-enum CoreAnimationStatus {
-  CORE_ANIMATION_DISABLED,
-  CORE_ANIMATION_ENABLED_LAZY,
-  CORE_ANIMATION_ENABLED_ALWAYS,
-};
-
-static CoreAnimationStatus GetCoreAnimationStatus() {
-  // TODO(sail) Remove this.
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kUseCoreAnimation)) {
-    return CORE_ANIMATION_DISABLED;
-  }
-  if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-          switches::kUseCoreAnimation) == "lazy") {
-    return CORE_ANIMATION_ENABLED_LAZY;
-  }
-  if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-          switches::kUseCoreAnimation) == "disabled") {
-    return CORE_ANIMATION_DISABLED;
-  }
-  return CORE_ANIMATION_ENABLED_ALWAYS;
-}
+using content::WebContents;
+using blink::WebInputEvent;
+using blink::WebInputEventFactory;
+using blink::WebMouseEvent;
+using blink::WebMouseWheelEvent;
+using blink::WebGestureEvent;
 
 // These are not documented, so use only after checking -respondsToSelector:.
 @interface NSApplication (UndocumentedSpeechMethods)
@@ -120,26 +105,9 @@ static CoreAnimationStatus GetCoreAnimationStatus() {
 
 static NSString* const NSWindowDidChangeBackingPropertiesNotification =
     @"NSWindowDidChangeBackingPropertiesNotification";
-static NSString* const NSBackingPropertyOldScaleFactorKey =
-    @"NSBackingPropertyOldScaleFactorKey";
-// Note: Apple's example code (linked from the comment above
-// -windowDidChangeBackingProperties:) uses
-// @"NSWindowBackingPropertiesChangeOldBackingScaleFactorKey", but that always
-// returns an old scale of 0. @"NSBackingPropertyOldScaleFactorKey" seems to
-// work in practice, and it's what's used in Apple's WebKit port
-// (WebKit/mac/WebView/WebView.mm).
 
 #endif  // 10.7
 
-static inline int ToWebKitModifiers(NSUInteger flags) {
-  int modifiers = 0;
-  if (flags & NSControlKeyMask) modifiers |= WebInputEvent::ControlKey;
-  if (flags & NSShiftKeyMask) modifiers |= WebInputEvent::ShiftKey;
-  if (flags & NSAlternateKeyMask) modifiers |= WebInputEvent::AltKey;
-  if (flags & NSCommandKeyMask) modifiers |= WebInputEvent::MetaKey;
-  return modifiers;
-}
-
 // This method will return YES for OS X versions 10.7.3 and later, and NO
 // otherwise.
 // Used to prevent a crash when building with the 10.7 SDK and accessing the
@@ -163,7 +131,7 @@ static BOOL SupportsBackingPropertiesChangedNotification() {
   return methodDescription.name != NULL || methodDescription.types != NULL;
 }
 
-static float ScaleFactor(NSView* view) {
+static float ScaleFactorForView(NSView* view) {
   return ui::GetImageScale(ui::GetScaleFactorForNativeView(view));
 }
 
@@ -171,8 +139,6 @@ static float ScaleFactor(NSView* view) {
 @interface RenderWidgetHostViewCocoa ()
 @property(nonatomic, assign) NSRange selectedRange;
 @property(nonatomic, assign) NSRange markedRange;
-@property(nonatomic, assign)
-    NSObject<RenderWidgetHostViewMacDelegate>* delegate;
 
 + (BOOL)shouldAutohideCursorForEvent:(NSEvent*)event;
 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r;
@@ -182,12 +148,12 @@ static float ScaleFactor(NSView* view) {
 - (void)keyEvent:(NSEvent*)theEvent wasKeyEquivalent:(BOOL)equiv;
 - (void)windowDidChangeBackingProperties:(NSNotification*)notification;
 - (void)windowChangedGlobalFrame:(NSNotification*)notification;
-- (void)drawBackingStore:(BackingStoreMac*)backingStore
-               dirtyRect:(CGRect)dirtyRect
-               inContext:(CGContextRef)context;
-- (void)updateSoftwareLayerScaleFactor;
+- (void)drawWithDirtyRect:(CGRect)dirtyRect
+                inContext:(CGContextRef)context;
 - (void)checkForPluginImeCancellation;
-- (void)updateTabBackingStoreScaleFactor;
+- (void)updateScreenProperties;
+- (void)setResponderDelegate:
+        (NSObject<RenderWidgetHostViewMacDelegate>*)delegate;
 @end
 
 // A window subclass that allows the fullscreen window to become main and gain
@@ -225,7 +191,8 @@ static float ScaleFactor(NSView* view) {
                               styleMask:windowStyle
                                 backing:bufferingType
                                   defer:deferCreation]) {
-    CHECK_EQ(CORE_ANIMATION_DISABLED, GetCoreAnimationStatus());
+    DCHECK_EQ(content::CORE_ANIMATION_DISABLED,
+              content::GetCoreAnimationStatus());
     [self setOpaque:NO];
     [self setBackgroundColor:[NSColor clearColor]];
     [self startObservingClicks];
@@ -287,7 +254,7 @@ namespace {
 const size_t kMaxTooltipLength = 1024;
 
 // TODO(suzhe): Upstream this function.
-WebKit::WebColor WebColorFromNSColor(NSColor *color) {
+blink::WebColor WebColorFromNSColor(NSColor *color) {
   CGFloat r, g, b, a;
   [color getRed:&r green:&g blue:&b alpha:&a];
 
@@ -302,7 +269,7 @@ WebKit::WebColor WebColorFromNSColor(NSColor *color) {
 // third_party/WebKit/Source/WebKit/mac/WebView/WebHTMLView.mm
 void ExtractUnderlines(
     NSAttributedString* string,
-    std::vector<WebKit::WebCompositionUnderline>* underlines) {
+    std::vector<blink::WebCompositionUnderline>* underlines) {
   int length = [[string string] length];
   int i = 0;
   while (i < length) {
@@ -311,13 +278,13 @@ void ExtractUnderlines(
                               longestEffectiveRange:&range
                                             inRange:NSMakeRange(i, length - i)];
     if (NSNumber *style = [attrs objectForKey:NSUnderlineStyleAttributeName]) {
-      WebKit::WebColor color = SK_ColorBLACK;
+      blink::WebColor color = SK_ColorBLACK;
       if (NSColor *colorAttr =
           [attrs objectForKey:NSUnderlineColorAttributeName]) {
         color = WebColorFromNSColor(
             [colorAttr colorUsingColorSpaceName:NSDeviceRGBColorSpace]);
       }
-      underlines->push_back(WebKit::WebCompositionUnderline(
+      underlines->push_back(blink::WebCompositionUnderline(
           range.location, NSMaxRange(range), color, [style intValue] > 1));
     }
     i = range.location + range.length;
@@ -341,15 +308,35 @@ void DisablePasswordInput() {
   TSMRemoveDocumentProperty(0, kTSMDocumentEnabledInputSourcesPropertyTag);
 }
 
+// Calls to [NSScreen screens], required by FlipYFromRectToScreen and
+// FlipNSRectToRectScreen, can take several milliseconds. Only re-compute this
+// value when screen info changes.
+// TODO(ccameron): An observer on every RWHVCocoa will set this to false
+// on NSApplicationDidChangeScreenParametersNotification. Only one observer
+// is necessary.
+bool g_screen_info_up_to_date = false;
+
+float FlipYFromRectToScreen(float y, float rect_height) {
+  TRACE_EVENT0("browser", "FlipYFromRectToScreen");
+  static CGFloat screen_zero_height = 0;
+  if (!g_screen_info_up_to_date) {
+    if ([[NSScreen screens] count] > 0) {
+      screen_zero_height =
+          [[[NSScreen screens] objectAtIndex:0] frame].size.height;
+      g_screen_info_up_to_date = true;
+    } else {
+      return y;
+    }
+  }
+  return screen_zero_height - y - rect_height;
+}
+
 // Adjusts an NSRect in Cocoa screen coordinates to have an origin in the upper
 // left of the primary screen (Carbon coordinates), and stuffs it into a
 // gfx::Rect.
 gfx::Rect FlipNSRectToRectScreen(const NSRect& rect) {
   gfx::Rect new_rect(NSRectToCGRect(rect));
-  if ([[NSScreen screens] count] > 0) {
-    new_rect.set_y([[[NSScreen screens] objectAtIndex:0] frame].size.height -
-                   new_rect.y() - new_rect.height());
-  }
+  new_rect.set_y(FlipYFromRectToScreen(new_rect.y(), new_rect.height()));
   return new_rect;
 }
 
@@ -374,13 +361,13 @@ NSWindow* ApparentWindowForView(NSView* view) {
   return enclosing_window;
 }
 
-WebKit::WebScreenInfo GetWebScreenInfo(NSView* view) {
+blink::WebScreenInfo GetWebScreenInfo(NSView* view) {
   gfx::Display display =
       gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(view);
 
   NSScreen* screen = [NSScreen deepestScreen];
 
-  WebKit::WebScreenInfo results;
+  blink::WebScreenInfo results;
 
   results.deviceScaleFactor = static_cast<int>(display.device_scale_factor());
   results.depth = NSBitsPerPixelFromDepth([screen depth]);
@@ -389,25 +376,28 @@ WebKit::WebScreenInfo GetWebScreenInfo(NSView* view) {
       [[screen colorSpace] colorSpaceModel] == NSGrayColorSpaceModel;
   results.rect = display.bounds();
   results.availableRect = display.work_area();
+  results.orientationAngle = display.RotationAsDegree();
+
   return results;
 }
 
+void RemoveLayerFromSuperlayer(
+    base::scoped_nsobject<CompositingIOSurfaceLayer> layer) {
+  // Disable the fade-out animation as the layer is removed.
+  ScopedCAActionDisabler disabler;
+  [layer removeFromSuperlayer];
+}
+
 }  // namespace
 
 namespace content {
 
 ///////////////////////////////////////////////////////////////////////////////
-// RenderWidgetHostView, public:
-
-// static
-RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget(
-    RenderWidgetHost* widget) {
-  return new RenderWidgetHostViewMac(widget);
-}
+// RenderWidgetHostViewBase, public:
 
 // static
-void RenderWidgetHostViewPort::GetDefaultScreenInfo(
-    WebKit::WebScreenInfo* results) {
+void RenderWidgetHostViewBase::GetDefaultScreenInfo(
+    blink::WebScreenInfo* results) {
   *results = GetWebScreenInfo(NULL);
 }
 
@@ -416,18 +406,22 @@ void RenderWidgetHostViewPort::GetDefaultScreenInfo(
 
 RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget)
     : render_widget_host_(RenderWidgetHostImpl::From(widget)),
-      about_to_validate_and_paint_(false),
-      call_set_needs_display_in_rect_pending_(false),
       last_frame_was_accelerated_(false),
       text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
       can_compose_inline_(true),
+      compositing_iosurface_layer_async_timer_(
+            FROM_HERE, base::TimeDelta::FromMilliseconds(250),
+            this, &RenderWidgetHostViewMac::TimerSinceGotAcceleratedFrameFired),
       allow_overlapping_views_(false),
       use_core_animation_(false),
+      pending_latency_info_delay_(0),
+      pending_latency_info_delay_weak_ptr_factory_(this),
+      backing_store_scale_factor_(1),
       is_loading_(false),
       weak_factory_(this),
       fullscreen_parent_host_view_(NULL),
-      pending_swap_buffers_acks_weak_factory_(this),
-      next_swap_ack_time_(base::Time::Now()),
+      underlay_view_has_drawn_(false),
+      overlay_view_weak_factory_(this),
       software_frame_weak_ptr_factory_(this) {
   software_frame_manager_.reset(new SoftwareFrameManager(
       software_frame_weak_ptr_factory_.GetWeakPtr()));
@@ -437,8 +431,13 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget)
   cocoa_view_ = [[[RenderWidgetHostViewCocoa alloc]
                   initWithRenderWidgetHostViewMac:this] autorelease];
 
-  if (GetCoreAnimationStatus() == CORE_ANIMATION_ENABLED_ALWAYS) {
-    EnableCoreAnimation();
+  if (GetCoreAnimationStatus() == CORE_ANIMATION_ENABLED) {
+    use_core_animation_ = true;
+    background_layer_.reset([[CALayer alloc] init]);
+    [background_layer_
+        setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
+    [cocoa_view_ setLayer:background_layer_];
+    [cocoa_view_ setWantsLayer:YES];
   }
 
   render_widget_host_->SetView(this);
@@ -449,12 +448,11 @@ RenderWidgetHostViewMac::~RenderWidgetHostViewMac() {
   // pointer.
   cocoa_view_ = nil;
 
-  AckPendingSwapBuffers();
   UnlockMouse();
 
   // Make sure that the layer doesn't reach into the now-invalid object.
   DestroyCompositedIOSurfaceAndLayer(kDestroyContext);
-  software_layer_.reset();
+  DestroySoftwareLayer();
 
   // We are owned by RenderWidgetHostViewCocoa, so if we go away before the
   // RenderWidgetHost does we need to tell it not to hold a stale pointer to
@@ -465,18 +463,10 @@ RenderWidgetHostViewMac::~RenderWidgetHostViewMac() {
 
 void RenderWidgetHostViewMac::SetDelegate(
     NSObject<RenderWidgetHostViewMacDelegate>* delegate) {
-  [cocoa_view_ setDelegate:delegate];
+  [cocoa_view_ setResponderDelegate:delegate];
 }
 
 void RenderWidgetHostViewMac::SetAllowOverlappingViews(bool overlapping) {
-  if (GetCoreAnimationStatus() == CORE_ANIMATION_ENABLED_LAZY) {
-    if (overlapping) {
-      ScopedCAActionDisabler disabler;
-      EnableCoreAnimation();
-      return;
-    }
-  }
-
   if (allow_overlapping_views_ == overlapping)
     return;
   allow_overlapping_views_ = overlapping;
@@ -487,106 +477,126 @@ void RenderWidgetHostViewMac::SetAllowOverlappingViews(bool overlapping) {
 ///////////////////////////////////////////////////////////////////////////////
 // RenderWidgetHostViewMac, RenderWidgetHostView implementation:
 
-void RenderWidgetHostViewMac::EnableCoreAnimation() {
-  if (use_core_animation_)
-    return;
-
-  use_core_animation_ = true;
-
-  // Un-bind the GL context from this view because the CoreAnimation path will
-  // not use explicit setView and clearDrawable calls.
-  ClearBoundContextDrawable();
-
-  software_layer_.reset([[CALayer alloc] init]);
-  if (!software_layer_)
-    LOG(ERROR) << "Failed to create CALayer for software rendering";
-  [software_layer_ setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
-  [software_layer_ setDelegate:cocoa_view_];
-  [software_layer_ setContentsGravity:kCAGravityTopLeft];
-  [software_layer_ setFrame:NSRectToCGRect([cocoa_view_ bounds])];
-  [software_layer_ setNeedsDisplay];
-  [cocoa_view_ updateSoftwareLayerScaleFactor];
-
-  [cocoa_view_ setLayer:software_layer_];
-  [cocoa_view_ setWantsLayer:YES];
-
-  if (compositing_iosurface_) {
-    if (!CreateCompositedIOSurfaceLayer()) {
-      LOG(ERROR) << "Failed to create CALayer for existing IOSurface";
-      GotAcceleratedCompositingError();
-      return;
-    }
+bool RenderWidgetHostViewMac::EnsureCompositedIOSurface() {
+  // If the context or the IOSurface's context has had an error, re-build
+  // everything from scratch.
+  if (compositing_iosurface_context_ &&
+      compositing_iosurface_context_->HasBeenPoisoned()) {
+    LOG(ERROR) << "Failing EnsureCompositedIOSurface because "
+               << "context was poisoned";
+    return false;
+  }
+  if (compositing_iosurface_ &&
+      compositing_iosurface_->HasBeenPoisoned()) {
+    LOG(ERROR) << "Failing EnsureCompositedIOSurface because "
+               << "surface was poisoned";
+    return false;
   }
-}
 
-bool RenderWidgetHostViewMac::CreateCompositedIOSurface() {
-  if (compositing_iosurface_context_ && compositing_iosurface_)
-    return true;
+  int current_window_number = use_core_animation_ ?
+      CompositingIOSurfaceContext::kOffscreenContextWindowNumber :
+      window_number();
+  bool new_surface_needed = !compositing_iosurface_;
+  bool new_context_needed =
+    !compositing_iosurface_context_ ||
+        (compositing_iosurface_context_ &&
+            compositing_iosurface_context_->window_number() !=
+                current_window_number);
 
-  ScopedCAActionDisabler disabler;
+  if (!new_surface_needed && !new_context_needed)
+    return true;
 
   // Create the GL context and shaders.
-  if (!compositing_iosurface_context_) {
-    compositing_iosurface_context_ =
-        CompositingIOSurfaceContext::Get(window_number());
-    if (!compositing_iosurface_context_) {
+  if (new_context_needed) {
+    scoped_refptr<CompositingIOSurfaceContext> new_context =
+        CompositingIOSurfaceContext::Get(current_window_number);
+    // Un-bind the GL context from this view before binding the new GL
+    // context. Having two GL contexts bound to a view will result in
+    // crashes and corruption.
+    // http://crbug.com/230883
+    ClearBoundContextDrawable();
+    if (!new_context) {
       LOG(ERROR) << "Failed to create CompositingIOSurfaceContext";
       return false;
     }
+    compositing_iosurface_context_ = new_context;
   }
+
   // Create the IOSurface texture.
-  if (!compositing_iosurface_) {
-    compositing_iosurface_.reset(CompositingIOSurfaceMac::Create(
-        compositing_iosurface_context_));
+  if (new_surface_needed) {
+    compositing_iosurface_.reset(CompositingIOSurfaceMac::Create());
     if (!compositing_iosurface_) {
       LOG(ERROR) << "Failed to create CompositingIOSurface";
       return false;
     }
   }
-  // Make sure that the IOSurface is updated to use the context that is owned
-  // by the view.
-  compositing_iosurface_->SetContext(compositing_iosurface_context_);
 
   return true;
 }
 
-bool RenderWidgetHostViewMac::CreateCompositedIOSurfaceLayer() {
-  CHECK(compositing_iosurface_context_ && compositing_iosurface_);
+void RenderWidgetHostViewMac::EnsureSoftwareLayer() {
+  TRACE_EVENT0("browser", "RenderWidgetHostViewMac::EnsureSoftwareLayer");
+  if (software_layer_ || !use_core_animation_)
+    return;
+
+  software_layer_.reset([[SoftwareLayer alloc]
+      initWithRenderWidgetHostViewMac:this]);
+  DCHECK(software_layer_);
+
+  // Disable the fade-in animation as the layer is added.
+  ScopedCAActionDisabler disabler;
+  [background_layer_ addSublayer:software_layer_];
+}
+
+void RenderWidgetHostViewMac::DestroySoftwareLayer() {
+  if (!software_layer_)
+    return;
+
+  // Disable the fade-out animation as the layer is removed.
+  ScopedCAActionDisabler disabler;
+  [software_layer_ removeFromSuperlayer];
+  [software_layer_ disableRendering];
+  software_layer_.reset();
+}
+
+void RenderWidgetHostViewMac::EnsureCompositedIOSurfaceLayer() {
+  TRACE_EVENT0("browser",
+               "RenderWidgetHostViewMac::EnsureCompositedIOSurfaceLayer");
+  DCHECK(compositing_iosurface_context_);
   if (compositing_iosurface_layer_ || !use_core_animation_)
-    return true;
+    return;
 
+  compositing_iosurface_layer_.reset([[CompositingIOSurfaceLayer alloc]
+      initWithRenderWidgetHostViewMac:this]);
+  DCHECK(compositing_iosurface_layer_);
+
+  // Disable the fade-in animation as the layer is added.
   ScopedCAActionDisabler disabler;
+  [background_layer_ addSublayer:compositing_iosurface_layer_];
+}
 
-  // Create the GL CoreAnimation layer.
-  if (!compositing_iosurface_layer_) {
-    compositing_iosurface_layer_.reset([[CompositingIOSurfaceLayer alloc]
-        initWithRenderWidgetHostViewMac:this]);
-    if (!compositing_iosurface_layer_) {
-      LOG(ERROR) << "Failed to create CALayer for IOSurface";
-      return false;
-    }
-    [software_layer_ addSublayer:compositing_iosurface_layer_];
-  }
+void RenderWidgetHostViewMac::DestroyCompositedIOSurfaceLayer(
+    DestroyCompositedIOSurfaceLayerBehavior destroy_layer_behavior) {
+  if (!compositing_iosurface_layer_)
+    return;
 
-  // Creating the CompositingIOSurfaceLayer may attempt to draw in setLayer,
-  // which, if it fails, will promptly tear down everything that was just
-  // created. If that happened, return failure.
-  return compositing_iosurface_context_ &&
-         compositing_iosurface_ &&
-         (compositing_iosurface_layer_ || !use_core_animation_);
+  if (destroy_layer_behavior == kRemoveLayerFromHierarchy) {
+    // Disable the fade-out animation as the layer is removed.
+    ScopedCAActionDisabler disabler;
+    [compositing_iosurface_layer_ removeFromSuperlayer];
+  }
+  [compositing_iosurface_layer_ disableCompositing];
+  compositing_iosurface_layer_.reset();
 }
 
 void RenderWidgetHostViewMac::DestroyCompositedIOSurfaceAndLayer(
     DestroyContextBehavior destroy_context_behavior) {
-  ScopedCAActionDisabler disabler;
+  // Any pending frames will not be displayed, so ack them now.
+  SendPendingSwapAck();
 
+  DestroyCompositedIOSurfaceLayer(kRemoveLayerFromHierarchy);
   compositing_iosurface_.reset();
-  if (compositing_iosurface_layer_) {
-    [software_layer_ setNeedsDisplay];
-    [compositing_iosurface_layer_ removeFromSuperlayer];
-    [compositing_iosurface_layer_ disableCompositing];
-    compositing_iosurface_layer_.reset();
-  }
+
   switch (destroy_context_behavior) {
     case kLeaveContextBoundToView:
       break;
@@ -601,10 +611,16 @@ void RenderWidgetHostViewMac::DestroyCompositedIOSurfaceAndLayer(
 }
 
 void RenderWidgetHostViewMac::ClearBoundContextDrawable() {
+  if (use_core_animation_)
+    return;
+
   if (compositing_iosurface_context_ &&
       cocoa_view_ &&
       [[compositing_iosurface_context_->nsgl_context() view]
           isEqual:cocoa_view_]) {
+    // Disable screen updates because removing the GL context from below can
+    // cause flashes.
+    [[cocoa_view_ window] disableScreenUpdatesUntilFlush];
     [compositing_iosurface_context_->nsgl_context() clearDrawable];
   }
 }
@@ -614,6 +630,8 @@ bool RenderWidgetHostViewMac::OnMessageReceived(const IPC::Message& message) {
   IPC_BEGIN_MESSAGE_MAP(RenderWidgetHostViewMac, message)
     IPC_MESSAGE_HANDLER(ViewHostMsg_PluginFocusChanged, OnPluginFocusChanged)
     IPC_MESSAGE_HANDLER(ViewHostMsg_StartPluginIme, OnStartPluginIme)
+    IPC_MESSAGE_HANDLER(ViewHostMsg_DidChangeScrollbarsForMainFrame,
+                        OnDidChangeScrollbarsForMainFrame)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -626,15 +644,12 @@ void RenderWidgetHostViewMac::InitAsChild(
 void RenderWidgetHostViewMac::InitAsPopup(
     RenderWidgetHostView* parent_host_view,
     const gfx::Rect& pos) {
-  bool activatable = popup_type_ == WebKit::WebPopupTypeNone;
+  bool activatable = popup_type_ == blink::WebPopupTypeNone;
   [cocoa_view_ setCloseOnDeactivate:YES];
   [cocoa_view_ setCanBeKeyView:activatable ? YES : NO];
 
   NSPoint origin_global = NSPointFromCGPoint(pos.origin().ToCGPoint());
-  if ([[NSScreen screens] count] > 0) {
-    origin_global.y = [[[NSScreen screens] objectAtIndex:0] frame].size.height -
-        pos.height() - origin_global.y;
-  }
+  origin_global.y = FlipYFromRectToScreen(origin_global.y, pos.height());
 
   popup_window_.reset([[RenderWidgetPopupWindow alloc]
       initWithContentRect:NSMakeRect(origin_global.x, origin_global.y,
@@ -721,8 +736,51 @@ int RenderWidgetHostViewMac::window_number() const {
   return [window windowNumber];
 }
 
-float RenderWidgetHostViewMac::scale_factor() const {
-  return ScaleFactor(cocoa_view_);
+float RenderWidgetHostViewMac::ViewScaleFactor() const {
+  return ScaleFactorForView(cocoa_view_);
+}
+
+void RenderWidgetHostViewMac::UpdateDisplayLink() {
+  static bool is_vsync_disabled =
+      CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync);
+  if (is_vsync_disabled)
+    return;
+
+  NSScreen* screen = [[cocoa_view_ window] screen];
+  NSDictionary* screen_description = [screen deviceDescription];
+  NSNumber* screen_number = [screen_description objectForKey:@"NSScreenNumber"];
+  CGDirectDisplayID display_id = [screen_number unsignedIntValue];
+
+  display_link_ = DisplayLinkMac::GetForDisplay(display_id);
+  if (!display_link_) {
+    // Note that on some headless systems, the display link will fail to be
+    // created, so this should not be a fatal error.
+    LOG(ERROR) << "Failed to create display link.";
+  }
+}
+
+void RenderWidgetHostViewMac::SendVSyncParametersToRenderer() {
+  if (!render_widget_host_ || !display_link_)
+    return;
+
+  base::TimeTicks timebase;
+  base::TimeDelta interval;
+  if (!display_link_->GetVSyncParameters(&timebase, &interval))
+    return;
+
+  render_widget_host_->UpdateVSyncParameters(timebase, interval);
+}
+
+void RenderWidgetHostViewMac::UpdateBackingStoreScaleFactor() {
+  if (!render_widget_host_)
+    return;
+
+  float new_scale_factor = ScaleFactorForView(cocoa_view_);
+  if (new_scale_factor == backing_store_scale_factor_)
+    return;
+  backing_store_scale_factor_ = new_scale_factor;
+
+  render_widget_host_->NotifyScreenInfoChanged();
 }
 
 RenderWidgetHost* RenderWidgetHostViewMac::GetRenderWidgetHost() const {
@@ -738,20 +796,24 @@ void RenderWidgetHostViewMac::WasShown() {
   render_widget_host_->WasShown();
   software_frame_manager_->SetVisibility(true);
 
+  // Call setNeedsDisplay before pausing for new frames to come in -- if any
+  // do, and are drawn, then the needsDisplay bit will be cleared.
+  [software_layer_ setNeedsDisplay];
+  [compositing_iosurface_layer_ setNeedsDisplay];
+  PauseForPendingResizeOrRepaintsAndDraw();
+
   // We're messing with the window, so do this to ensure no flashes.
   if (!use_core_animation_)
     [[cocoa_view_ window] disableScreenUpdatesUntilFlush];
-
-  [compositing_iosurface_layer_ setNeedsDisplay];
 }
 
 void RenderWidgetHostViewMac::WasHidden() {
   if (render_widget_host_->is_hidden())
     return;
 
-  // Send ACKs for any pending SwapBuffers (if any) since we won't be displaying
-  // them and the GPU process is waiting.
-  AckPendingSwapBuffers();
+  // Any pending frames will not be displayed until this is shown again. Ack
+  // them now.
+  SendPendingSwapAck();
 
   // If we have a renderer, then inform it that we are being hidden so it can
   // reduce its resource utilization.
@@ -794,23 +856,27 @@ void RenderWidgetHostViewMac::SetBounds(const gfx::Rect& rect) {
   // Ignore the position of |rect| for non-popup rwhvs. This is because
   // background tabs do not have a window, but the window is required for the
   // coordinate conversions. Popups are always for a visible tab.
-  if (IsPopup()) {
+  //
+  // Note: If |cocoa_view_| has been removed from the view hierarchy, it's still
+  // valid for resizing to be requested (e.g., during tab capture, to size the
+  // view to screen-capture resolution). In this case, simply treat the view as
+  // relative to the screen.
+  BOOL isRelativeToScreen = IsPopup() ||
+      ![[cocoa_view_ superview] isKindOfClass:[BaseView class]];
+  if (isRelativeToScreen) {
     // The position of |rect| is screen coordinate system and we have to
     // consider Cocoa coordinate system is upside-down and also multi-screen.
     NSPoint origin_global = NSPointFromCGPoint(rect.origin().ToCGPoint());
     NSSize size = NSMakeSize(rect.width(), rect.height());
     size = [cocoa_view_ convertSize:size toView:nil];
-    if ([[NSScreen screens] count] > 0) {
-      NSScreen* screen =
-          static_cast<NSScreen*>([[NSScreen screens] objectAtIndex:0]);
-      origin_global.y =
-          NSHeight([screen frame]) - size.height - origin_global.y;
-    }
-    [popup_window_ setFrame:NSMakeRect(origin_global.x, origin_global.y,
-                                       size.width, size.height)
-                    display:YES];
+    origin_global.y = FlipYFromRectToScreen(origin_global.y, size.height);
+    NSRect frame = NSMakeRect(origin_global.x, origin_global.y,
+                              size.width, size.height);
+    if (IsPopup())
+      [popup_window_ setFrame:frame display:YES];
+    else
+      [cocoa_view_ setFrame:frame];
   } else {
-    DCHECK([[cocoa_view_ superview] isKindOfClass:[BaseView class]]);
     BaseView* superview = static_cast<BaseView*>([cocoa_view_ superview]);
     gfx::Rect rect2 = [superview flipNSRectToRect:[cocoa_view_ frame]];
     rect2.set_width(rect.width());
@@ -833,12 +899,11 @@ gfx::NativeViewAccessible RenderWidgetHostViewMac::GetNativeViewAccessible() {
 }
 
 void RenderWidgetHostViewMac::MovePluginWindows(
-    const gfx::Vector2d& scroll_offset,
     const std::vector<WebPluginGeometry>& moves) {
   // Must be overridden, but unused on this platform. Core Animation
   // plugins are drawn by the GPU process (through the compositor),
   // and Core Graphics plugins are drawn by the renderer process.
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 void RenderWidgetHostViewMac::Focus() {
@@ -855,8 +920,8 @@ bool RenderWidgetHostViewMac::HasFocus() const {
 }
 
 bool RenderWidgetHostViewMac::IsSurfaceAvailableForCopy() const {
-  return !!render_widget_host_->GetBackingStore(false) ||
-      (compositing_iosurface_ && compositing_iosurface_->HasIOSurface());
+  return software_frame_manager_->HasCurrentFrame() ||
+         (compositing_iosurface_ && compositing_iosurface_->HasIOSurface());
 }
 
 void RenderWidgetHostViewMac::Show() {
@@ -940,65 +1005,12 @@ void RenderWidgetHostViewMac::ImeCompositionRangeChanged(
   composition_bounds_ = character_bounds;
 }
 
-void RenderWidgetHostViewMac::DidUpdateBackingStore(
-    const gfx::Rect& scroll_rect,
-    const gfx::Vector2d& scroll_delta,
-    const std::vector<gfx::Rect>& copy_rects,
-    const ui::LatencyInfo& latency_info) {
-  GotSoftwareFrame();
-
-  software_latency_info_.MergeWith(latency_info);
-
-  if (render_widget_host_->is_hidden())
-    return;
-
-  std::vector<gfx::Rect> rects(copy_rects);
-
-  // Because the findbar might be open, we cannot use scrollRect:by: here. For
-  // now, simply mark all of scroll rect as dirty.
-  if (!scroll_rect.IsEmpty())
-    rects.push_back(scroll_rect);
-
-  for (size_t i = 0; i < rects.size(); ++i) {
-    NSRect ns_rect = [cocoa_view_ flipRectToNSRect:rects[i]];
-
-    if (about_to_validate_and_paint_) {
-      // As much as we'd like to use -setNeedsDisplayInRect: here, we can't.
-      // We're in the middle of executing a -drawRect:, and as soon as it
-      // returns Cocoa will clear its record of what needs display. We instead
-      // use |performSelector:| to call |setNeedsDisplayInRect:| after returning
-      //  to the main loop, at which point |drawRect:| is no longer on the
-      // stack.
-      DCHECK([NSThread isMainThread]);
-      if (!call_set_needs_display_in_rect_pending_) {
-        [cocoa_view_ performSelector:@selector(callSetNeedsDisplayInRect)
-                      withObject:nil
-                      afterDelay:0];
-        call_set_needs_display_in_rect_pending_ = true;
-        invalid_rect_ = ns_rect;
-      } else {
-        // The old invalid rect is probably invalid now, since the view has most
-        // likely been resized, but there's no harm in dirtying the union.  In
-        // the limit, this becomes equivalent to dirtying the whole view.
-        invalid_rect_ = NSUnionRect(invalid_rect_, ns_rect);
-      }
-    } else {
-      [cocoa_view_ setNeedsDisplayInRect:ns_rect];
-    }
-  }
-
-  if (!about_to_validate_and_paint_)
-    [cocoa_view_ displayIfNeeded];
-}
-
 void RenderWidgetHostViewMac::RenderProcessGone(base::TerminationStatus status,
                                                 int error_code) {
   Destroy();
 }
 
 void RenderWidgetHostViewMac::Destroy() {
-  AckPendingSwapBuffers();
-
   [[NSNotificationCenter defaultCenter]
       removeObserver:cocoa_view_
                 name:NSWindowWillCloseNotification
@@ -1032,7 +1044,8 @@ void RenderWidgetHostViewMac::Destroy() {
 // Called from the renderer to tell us what the tooltip text should be. It
 // calls us frequently so we need to cache the value to prevent doing a lot
 // of repeat work.
-void RenderWidgetHostViewMac::SetTooltipText(const string16& tooltip_text) {
+void RenderWidgetHostViewMac::SetTooltipText(
+    const base::string16& tooltip_text) {
   if (tooltip_text != tooltip_text_ && [[cocoa_view_ window] isKeyWindow]) {
     tooltip_text_ = tooltip_text;
 
@@ -1040,7 +1053,7 @@ void RenderWidgetHostViewMac::SetTooltipText(const string16& tooltip_text) {
     // Windows; we're just trying to be polite. Don't persist the trimmed
     // string, as then the comparison above will always fail and we'll try to
     // set it again every single time the mouse moves.
-    string16 display_text = tooltip_text_;
+    base::string16 display_text = tooltip_text_;
     if (tooltip_text_.length() > kMaxTooltipLength)
       display_text = tooltip_text_.substr(0, kMaxTooltipLength);
 
@@ -1073,7 +1086,7 @@ void RenderWidgetHostViewMac::StopSpeaking() {
 // RenderWidgetHostViewCocoa uses the stored selection text,
 // which implements NSServicesRequests protocol.
 //
-void RenderWidgetHostViewMac::SelectionChanged(const string16& text,
+void RenderWidgetHostViewMac::SelectionChanged(const base::string16& text,
                                                size_t offset,
                                                const gfx::Range& range) {
   if (range.is_empty() || text.empty()) {
@@ -1087,7 +1100,7 @@ void RenderWidgetHostViewMac::SelectionChanged(const string16& text,
       DCHECK(false) << "The text can not cover range.";
       return;
     }
-    selected_text_ = UTF16ToUTF8(text.substr(pos, n));
+    selected_text_ = base::UTF16ToUTF8(text.substr(pos, n));
   }
 
   [cocoa_view_ setSelectedRange:range.ToNSRange()];
@@ -1139,34 +1152,65 @@ void RenderWidgetHostViewMac::SetShowingContextMenu(bool showing) {
 }
 
 bool RenderWidgetHostViewMac::IsPopup() const {
-  return popup_type_ != WebKit::WebPopupTypeNone;
-}
-
-BackingStore* RenderWidgetHostViewMac::AllocBackingStore(
-    const gfx::Size& size) {
-  float scale = ScaleFactor(cocoa_view_);
-  return new BackingStoreMac(render_widget_host_, size, scale);
+  return popup_type_ != blink::WebPopupTypeNone;
 }
 
 void RenderWidgetHostViewMac::CopyFromCompositingSurface(
     const gfx::Rect& src_subrect,
     const gfx::Size& dst_size,
-    const base::Callback<void(bool, const SkBitmap&)>& callback) {
+    const base::Callback<void(bool, const SkBitmap&)>& callback,
+    const SkBitmap::Config config) {
+  if (config != SkBitmap::kARGB_8888_Config) {
+    NOTIMPLEMENTED();
+    callback.Run(false, SkBitmap());
+  }
   base::ScopedClosureRunner scoped_callback_runner(
       base::Bind(callback, false, SkBitmap()));
-  if (!compositing_iosurface_ ||
-      !compositing_iosurface_->HasIOSurface())
-    return;
-
-  float scale = ScaleFactor(cocoa_view_);
+  float scale = ScaleFactorForView(cocoa_view_);
   gfx::Size dst_pixel_size = gfx::ToFlooredSize(
       gfx::ScaleSize(dst_size, scale));
+  if (compositing_iosurface_ && compositing_iosurface_->HasIOSurface()) {
+    ignore_result(scoped_callback_runner.Release());
+    compositing_iosurface_->CopyTo(GetScaledOpenGLPixelRect(src_subrect),
+                                   dst_pixel_size,
+                                   callback);
+  } else if (software_frame_manager_->HasCurrentFrame()) {
+    gfx::Rect src_pixel_rect = gfx::ToEnclosingRect(gfx::ScaleRect(
+        src_subrect,
+        software_frame_manager_->GetCurrentFrameDeviceScaleFactor()));
+    SkBitmap source_bitmap;
+    source_bitmap.setConfig(
+        SkBitmap::kARGB_8888_Config,
+        software_frame_manager_->GetCurrentFrameSizeInPixels().width(),
+        software_frame_manager_->GetCurrentFrameSizeInPixels().height(),
+        0,
+        kOpaque_SkAlphaType);
+    source_bitmap.setPixels(software_frame_manager_->GetCurrentFramePixels());
+
+    SkBitmap target_bitmap;
+    target_bitmap.setConfig(
+        SkBitmap::kARGB_8888_Config,
+        dst_pixel_size.width(),
+        dst_pixel_size.height(),
+        0,
+        kOpaque_SkAlphaType);
+    if (!target_bitmap.allocPixels())
+      return;
 
-  ignore_result(scoped_callback_runner.Release());
+    SkCanvas target_canvas(target_bitmap);
+    SkRect src_pixel_skrect = SkRect::MakeXYWH(
+        src_pixel_rect.x(), src_pixel_rect.y(),
+        src_pixel_rect.width(), src_pixel_rect.height());
+    target_canvas.drawBitmapRectToRect(
+        source_bitmap,
+        &src_pixel_skrect,
+        SkRect::MakeXYWH(0, 0, dst_pixel_size.width(), dst_pixel_size.height()),
+        NULL,
+        SkCanvas::kNone_DrawBitmapRectFlag);
 
-  compositing_iosurface_->CopyTo(GetScaledOpenGLPixelRect(src_subrect),
-                                 dst_pixel_size,
-                                 callback);
+    ignore_result(scoped_callback_runner.Release());
+    callback.Run(true, target_bitmap);
+  }
 }
 
 void RenderWidgetHostViewMac::CopyFromCompositingSurfaceToVideoFrame(
@@ -1201,14 +1245,14 @@ void RenderWidgetHostViewMac::CopyFromCompositingSurfaceToVideoFrame(
 }
 
 bool RenderWidgetHostViewMac::CanCopyToVideoFrame() const {
-  return (!render_widget_host_->GetBackingStore(false) &&
+  return (!software_frame_manager_->HasCurrentFrame() &&
           render_widget_host_->is_accelerated_compositing_active() &&
           compositing_iosurface_ &&
           compositing_iosurface_->HasIOSurface());
 }
 
 bool RenderWidgetHostViewMac::CanSubscribeFrame() const {
-  return true;
+  return !software_frame_manager_->HasCurrentFrame();
 }
 
 void RenderWidgetHostViewMac::BeginFrameSubscription(
@@ -1258,7 +1302,7 @@ bool RenderWidgetHostViewMac::PostProcessEventForPluginIme(
 }
 
 void RenderWidgetHostViewMac::PluginImeCompositionCompleted(
-    const string16& text, int plugin_id) {
+    const base::string16& text, int plugin_id) {
   if (render_widget_host_) {
     render_widget_host_->Send(new ViewMsg_PluginImeCompositionCompleted(
         render_widget_host_->GetRoutingID(), text, plugin_id));
@@ -1269,71 +1313,85 @@ void RenderWidgetHostViewMac::CompositorSwapBuffers(
     uint64 surface_handle,
     const gfx::Size& size,
     float surface_scale_factor,
-    const ui::LatencyInfo& latency_info) {
+    const std::vector<ui::LatencyInfo>& latency_info) {
+  // Ensure that the frame be acked unless it is explicitly passed to a
+  // display function.
+  base::ScopedClosureRunner scoped_ack(
+      base::Bind(&RenderWidgetHostViewMac::SendPendingSwapAck,
+                 weak_factory_.GetWeakPtr()));
+
   if (render_widget_host_->is_hidden())
     return;
 
-  NSWindow* window = [cocoa_view_ window];
-  if (window_number() <= 0) {
-    // There is no window to present so capturing during present won't work.
-    // We check if frame subscriber wants this frame and capture manually.
-    if (compositing_iosurface_ && frame_subscriber_) {
-      const base::Time present_time = base::Time::Now();
-      scoped_refptr<media::VideoFrame> frame;
-      RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback;
-      if (frame_subscriber_->ShouldCaptureFrame(present_time,
-                                                &frame, &callback)) {
-        compositing_iosurface_->SetIOSurface(
-            surface_handle, size, surface_scale_factor, latency_info);
-        compositing_iosurface_->CopyToVideoFrame(
-            gfx::Rect(size), frame,
-            base::Bind(callback, present_time));
-        return;
-      }
-    }
+  // Ensure that if this function exits before the frame is set up (but not
+  // necessarily drawn) then it is treated as an error.
+  base::ScopedClosureRunner scoped_error(
+      base::Bind(&RenderWidgetHostViewMac::GotAcceleratedCompositingError,
+                 weak_factory_.GetWeakPtr()));
 
-    // TODO(shess) If the view does not have a window, or the window
-    // does not have backing, the IOSurface will log "invalid drawable"
-    // in -setView:.  It is not clear how this code is reached with such
-    // a case, so record some info into breakpad (some subset of
-    // browsers are likely to crash later for unrelated reasons).
-    // http://crbug.com/148882
-    const char* const kCrashKey = "rwhvm_window";
-    if (!window) {
-      base::debug::SetCrashKeyValue(kCrashKey, "Missing window");
-    } else {
-      std::string value =
-          base::StringPrintf("window %s delegate %s controller %s",
-              object_getClassName(window),
-              object_getClassName([window delegate]),
-              object_getClassName([window windowController]));
-      base::debug::SetCrashKeyValue(kCrashKey, value);
-    }
+  AddPendingLatencyInfo(latency_info);
 
-    return;
+  // If compositing_iosurface_ exists and has been poisoned, destroy it
+  // and allow EnsureCompositedIOSurface to recreate it below. Keep a
+  // reference to the destroyed layer around until after the below call
+  // to LayoutLayers, to avoid flickers.
+  base::ScopedClosureRunner scoped_layer_remover;
+  if (compositing_iosurface_context_ &&
+      compositing_iosurface_context_->HasBeenPoisoned()) {
+    scoped_layer_remover.Reset(
+        base::Bind(RemoveLayerFromSuperlayer, compositing_iosurface_layer_));
+    DestroyCompositedIOSurfaceLayer(kLeaveLayerInHierarchy);
+    DestroyCompositedIOSurfaceAndLayer(kDestroyContext);
   }
 
-  if (!CreateCompositedIOSurface()) {
-    LOG(ERROR) << "Failed to create CompositingIOSurface";
-    GotAcceleratedCompositingError();
+  // Ensure compositing_iosurface_ and compositing_iosurface_context_ be
+  // allocated.
+  if (!EnsureCompositedIOSurface()) {
+    LOG(ERROR) << "Failed EnsureCompositingIOSurface";
     return;
   }
 
-  if (!compositing_iosurface_->SetIOSurface(
-          surface_handle, size, surface_scale_factor, latency_info)) {
-    LOG(ERROR) << "Failed SetIOSurface on CompositingIOSurfaceMac";
-    GotAcceleratedCompositingError();
-    return;
+  // Make the context current and update the IOSurface with the handle
+  // passed in by the swap command.
+  {
+    gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+        compositing_iosurface_context_->cgl_context());
+    if (!compositing_iosurface_->SetIOSurfaceWithContextCurrent(
+            compositing_iosurface_context_, surface_handle, size,
+            surface_scale_factor)) {
+      LOG(ERROR) << "Failed SetIOSurface on CompositingIOSurfaceMac";
+      return;
+    }
   }
 
-  // Create the layer for the composited content only after the IOSurface has
-  // been initialized.
-  if (!CreateCompositedIOSurfaceLayer()) {
-    LOG(ERROR) << "Failed to create CompositingIOSurface layer";
-    GotAcceleratedCompositingError();
-    return;
+  // Grab video frames now that the IOSurface has been set up. Note that this
+  // will be done in an offscreen context, so it is necessary to re-set the
+  // current context afterward.
+  bool frame_was_captured = false;
+  if (frame_subscriber_) {
+    const base::TimeTicks present_time = base::TimeTicks::Now();
+    scoped_refptr<media::VideoFrame> frame;
+    RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback;
+    if (frame_subscriber_->ShouldCaptureFrame(present_time,
+                                              &frame, &callback)) {
+      // Flush the context that updated the IOSurface, to ensure that the
+      // context that does the copy picks up the correct version.
+      {
+        gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+            compositing_iosurface_context_->cgl_context());
+        glFlush();
+      }
+      compositing_iosurface_->CopyToVideoFrame(
+          gfx::Rect(size), frame,
+          base::Bind(callback, present_time));
+      frame_was_captured = true;
+    }
   }
 
+  // At this point the surface, its context, and its layer have been set up, so
+  // don't generate an error (one may be generated when drawing).
+  ignore_result(scoped_error.Release());
+
   GotAcceleratedFrame();
 
   gfx::Size window_size(NSSizeToCGSize([cocoa_view_ frame].size));
@@ -1342,84 +1400,71 @@ void RenderWidgetHostViewMac::CompositorSwapBuffers(
     // empty, so ack now and don't bother calling setNeedsDisplay below.
     return;
   }
+  if (window_number() <= 0) {
+    // It's normal for a backgrounded tab that is being captured to have no
+    // window but not be hidden. Immediately ack the frame, and don't try to
+    // draw it.
+    if (frame_was_captured)
+      return;
 
-  // No need to draw the surface if we are inside a drawRect. It will be done
-  // later.
-  if (!about_to_validate_and_paint_) {
-    if (use_core_animation_) {
-      DCHECK(compositing_iosurface_layer_);
-      [compositing_iosurface_layer_ setNeedsDisplay];
+    // If this frame was not captured, there is likely some sort of bug. Ack
+    // the frame and hope for the best. Because the IOSurface and layer are
+    // populated, it will likely be displayed when the view is added to a
+    // window's hierarchy.
+
+    // TODO(shess) If the view does not have a window, or the window
+    // does not have backing, the IOSurface will log "invalid drawable"
+    // in -setView:.  It is not clear how this code is reached with such
+    // a case, so record some info into breakpad (some subset of
+    // browsers are likely to crash later for unrelated reasons).
+    // http://crbug.com/148882
+    const char* const kCrashKey = "rwhvm_window";
+    NSWindow* window = [cocoa_view_ window];
+    if (!window) {
+      base::debug::SetCrashKeyValue(kCrashKey, "Missing window");
     } else {
-      if (!DrawIOSurfaceWithoutCoreAnimation()) {
-        [cocoa_view_ setNeedsDisplay:YES];
-        GotAcceleratedCompositingError();
-        return;
-      }
+      std::string value =
+          base::StringPrintf("window %s delegate %s controller %s",
+              object_getClassName(window),
+              object_getClassName([window delegate]),
+              object_getClassName([window windowController]));
+      base::debug::SetCrashKeyValue(kCrashKey, value);
     }
+    return;
   }
-}
 
-void RenderWidgetHostViewMac::AckPendingSwapBuffers() {
-  TRACE_EVENT0("browser", "RenderWidgetHostViewMac::AckPendingSwapBuffers");
-
-  // Cancel any outstanding delayed calls to this function.
-  pending_swap_buffers_acks_weak_factory_.InvalidateWeakPtrs();
-
-  while (!pending_swap_buffers_acks_.empty()) {
-    if (pending_swap_buffers_acks_.front().first != 0) {
-      AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
-      ack_params.sync_point = 0;
-      if (compositing_iosurface_)
-        ack_params.renderer_id = compositing_iosurface_->GetRendererID();
-      RenderWidgetHostImpl::AcknowledgeBufferPresent(
-          pending_swap_buffers_acks_.front().first,
-          pending_swap_buffers_acks_.front().second,
-          ack_params);
-      if (render_widget_host_) {
-        render_widget_host_->AcknowledgeSwapBuffersToRenderer();
-      }
-    }
-    pending_swap_buffers_acks_.erase(pending_swap_buffers_acks_.begin());
-  }
-}
-
-void RenderWidgetHostViewMac::ThrottledAckPendingSwapBuffers() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  // Send VSync parameters to the renderer's compositor thread.
-  base::TimeTicks vsync_timebase;
-  base::TimeDelta vsync_interval;
-  GetVSyncParameters(&vsync_timebase, &vsync_interval);
-  if (render_widget_host_ && compositing_iosurface_)
-    render_widget_host_->UpdateVSyncParameters(vsync_timebase, vsync_interval);
-
-  // If the render widget host is responsible for throttling swaps to vsync rate
-  // then don't ack the swapbuffers until a full vsync has passed since the last
-  // ack was sent.
-  bool throttle_swap_ack =
-      render_widget_host_ &&
-      !render_widget_host_->is_threaded_compositing_enabled() &&
-      compositing_iosurface_ &&
-      !compositing_iosurface_->is_vsync_disabled();
-  base::Time now = base::Time::Now();
-  if (throttle_swap_ack && next_swap_ack_time_ > now) {
-    base::TimeDelta next_swap_ack_delay = next_swap_ack_time_ - now;
-    next_swap_ack_time_ += vsync_interval;
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&RenderWidgetHostViewMac::AckPendingSwapBuffers,
-                   pending_swap_buffers_acks_weak_factory_.GetWeakPtr()),
-        next_swap_ack_delay);
+  // If we reach here, then the frame will be displayed by a future draw
+  // call, so don't make the callback.
+  ignore_result(scoped_ack.Release());
+  if (use_core_animation_) {
+    DCHECK(compositing_iosurface_layer_);
+    compositing_iosurface_layer_async_timer_.Reset();
+    [compositing_iosurface_layer_ gotNewFrame];
   } else {
-    next_swap_ack_time_ = now + vsync_interval;
-    AckPendingSwapBuffers();
+    gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+        compositing_iosurface_context_->cgl_context());
+    DrawIOSurfaceWithoutCoreAnimation();
   }
+
+  // Try to finish previous copy requests after draw to get better pipelining.
+  if (compositing_iosurface_)
+    compositing_iosurface_->CheckIfAllCopiesAreFinished(false);
+
+  // The IOSurface's size may have changed, so re-layout the layers to take
+  // this into account. This may force an immediate draw.
+  LayoutLayers();
 }
 
-bool RenderWidgetHostViewMac::DrawIOSurfaceWithoutCoreAnimation() {
+void RenderWidgetHostViewMac::DrawIOSurfaceWithoutCoreAnimation() {
   CHECK(!use_core_animation_);
   CHECK(compositing_iosurface_);
-  CHECK(compositing_iosurface_context_ == compositing_iosurface_->context());
+
+  // If there is a pending frame, it should be acked by the end of this
+  // function. Note that the ack should happen only after all drawing is
+  // complete, so that the ack happens after any blocking due to vsync.
+  base::ScopedClosureRunner scoped_ack(
+      base::Bind(&RenderWidgetHostViewMac::SendPendingSwapAck,
+                 weak_factory_.GetWeakPtr()));
 
   GLint old_gl_surface_order = 0;
   GLint new_gl_surface_order = allow_overlapping_views_ ? -1 : 1;
@@ -1432,56 +1477,111 @@ bool RenderWidgetHostViewMac::DrawIOSurfaceWithoutCoreAnimation() {
         forParameter:NSOpenGLCPSurfaceOrder];
   }
 
-  CGLError cgl_error = CGLSetCurrentContext(
-      compositing_iosurface_context_->cgl_context());
-  if (cgl_error != kCGLNoError) {
-    LOG(ERROR) << "CGLSetCurrentContext error in DrawIOSurface: " << cgl_error;
-    return false;
+  // Instead of drawing, request that underlay view redraws.
+  if (underlay_view_ &&
+      underlay_view_->compositing_iosurface_ &&
+      underlay_view_has_drawn_) {
+    [underlay_view_->cocoa_view() setNeedsDisplayInRect:NSMakeRect(0, 0, 1, 1)];
+    return;
   }
 
+  bool has_overlay = overlay_view_ && overlay_view_->compositing_iosurface_;
+  if (has_overlay) {
+    // Un-bind the overlay view's OpenGL context, since its content will be
+    // drawn by this context. Not doing this can result in corruption.
+    // http://crbug.com/330701
+    overlay_view_->ClearBoundContextDrawable();
+  }
   [compositing_iosurface_context_->nsgl_context() setView:cocoa_view_];
-  return compositing_iosurface_->DrawIOSurface(
-      gfx::Size(NSSizeToCGSize([cocoa_view_ frame].size)),
-      scale_factor(),
-      frame_subscriber(),
-      false);
+
+  gfx::Rect view_rect(NSRectToCGRect([cocoa_view_ frame]));
+  if (!compositing_iosurface_->DrawIOSurface(
+          compositing_iosurface_context_, view_rect,
+          ViewScaleFactor(), !has_overlay)) {
+    GotAcceleratedCompositingError();
+    return;
+  }
+
+  if (has_overlay) {
+    overlay_view_->underlay_view_has_drawn_ = true;
+    gfx::Rect overlay_view_rect(
+        NSRectToCGRect([overlay_view_->cocoa_view() frame]));
+    overlay_view_rect.set_x(overlay_view_offset_.x());
+    overlay_view_rect.set_y(view_rect.height() -
+                            overlay_view_rect.height() -
+                            overlay_view_offset_.y());
+    if (!overlay_view_->compositing_iosurface_->DrawIOSurface(
+            compositing_iosurface_context_, overlay_view_rect,
+            overlay_view_->ViewScaleFactor(), true)) {
+      GotAcceleratedCompositingError();
+      return;
+    }
+  }
+
+  SendPendingLatencyInfoToHost();
 }
 
 void RenderWidgetHostViewMac::GotAcceleratedCompositingError() {
-  AckPendingSwapBuffers();
-  DestroyCompositedIOSurfaceAndLayer(kDestroyContext);
+  LOG(ERROR) << "Encountered accelerated compositing error";
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&RenderWidgetHostViewMac::DestroyCompositingStateOnError,
+                 weak_factory_.GetWeakPtr()));
+}
+
+void RenderWidgetHostViewMac::DestroyCompositingStateOnError() {
+  // This should be called with a clean stack. Make sure that no context is
+  // current.
+  DCHECK(!CGLGetCurrentContext());
+
   // The existing GL contexts may be in a bad state, so don't re-use any of the
   // existing ones anymore, rather, allocate new ones.
-  CompositingIOSurfaceContext::MarkExistingContextsAsNotShareable();
-  // Request that a new frame be generated.
+  if (compositing_iosurface_context_)
+    compositing_iosurface_context_->PoisonContextAndSharegroup();
+
+  DestroyCompositedIOSurfaceAndLayer(kDestroyContext);
+
+  // Request that a new frame be generated and dirty the view.
   if (render_widget_host_)
     render_widget_host_->ScheduleComposite();
+  [cocoa_view_ setNeedsDisplay:YES];
+
+  // Mark the last frame as not accelerated (so that the window is prepared for
+  // an underlay next time an accelerated frame comes in).
+  last_frame_was_accelerated_ = false;
+
   // TODO(ccameron): It may be a good idea to request that the renderer recreate
   // its GL context as well, and fall back to software if this happens
   // repeatedly.
 }
 
-void RenderWidgetHostViewMac::GetVSyncParameters(
-  base::TimeTicks* timebase, base::TimeDelta* interval) {
-  if (compositing_iosurface_) {
-    uint32 numerator = 0;
-    uint32 denominator = 0;
-    compositing_iosurface_->GetVSyncParameters(
-        timebase, &numerator, &denominator);
-    if (numerator > 0 && denominator > 0) {
-      int64 interval_micros =
-          1000000 * static_cast<int64>(numerator) / denominator;
-      *interval = base::TimeDelta::FromMicroseconds(interval_micros);
-      return;
-    }
+void RenderWidgetHostViewMac::SetOverlayView(
+    RenderWidgetHostViewMac* overlay, const gfx::Point& offset) {
+  if (overlay_view_)
+    overlay_view_->underlay_view_.reset();
+
+  overlay_view_ = overlay->overlay_view_weak_factory_.GetWeakPtr();
+  overlay_view_->underlay_view_ = overlay_view_weak_factory_.GetWeakPtr();
+  if (use_core_animation_)
+    return;
+
+  overlay_view_offset_ = offset;
+  overlay_view_->underlay_view_has_drawn_ = false;
+
+  [cocoa_view_ setNeedsDisplay:YES];
+  [[cocoa_view_ window] disableScreenUpdatesUntilFlush];
+}
+
+void RenderWidgetHostViewMac::RemoveOverlayView() {
+  if (overlay_view_) {
+    overlay_view_->underlay_view_.reset();
+    overlay_view_.reset();
   }
+  if (use_core_animation_)
+    return;
 
-  // Pass reasonable default values if unable to get the actual ones
-  // (e.g. CVDisplayLink failed to return them because the display is
-  // in sleep mode).
-  static const int64 kOneOverSixtyMicroseconds = 16669;
-  *timebase = base::TimeTicks::Now(),
-  *interval = base::TimeDelta::FromMicroseconds(kOneOverSixtyMicroseconds);
+  [cocoa_view_ setNeedsDisplay:YES];
+  [[cocoa_view_ window] disableScreenUpdatesUntilFlush];
 }
 
 bool RenderWidgetHostViewMac::GetLineBreakIndex(
@@ -1569,6 +1669,14 @@ gfx::Range RenderWidgetHostViewMac::ConvertCharacterRangeToCompositionRange(
       request_range.end() - composition_range_.start());
 }
 
+WebContents* RenderWidgetHostViewMac::GetWebContents() {
+  if (!render_widget_host_->IsRenderView())
+    return NULL;
+
+  return WebContents::FromRenderViewHost(
+      RenderViewHost::From(render_widget_host_));
+}
+
 bool RenderWidgetHostViewMac::GetCachedFirstRectForCharacterRange(
     NSRange range,
     NSRect* rect,
@@ -1614,17 +1722,16 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped(
     int gpu_host_id) {
   TRACE_EVENT0("browser",
       "RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped");
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  pending_swap_buffers_acks_.push_back(std::make_pair(params.route_id,
-                                                      gpu_host_id));
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
+  AddPendingSwapAck(params.route_id,
+                    gpu_host_id,
+                    compositing_iosurface_ ?
+                        compositing_iosurface_->GetRendererID() : 0);
   CompositorSwapBuffers(params.surface_handle,
                         params.size,
                         params.scale_factor,
                         params.latency_info);
-
-  ThrottledAckPendingSwapBuffers();
 }
 
 void RenderWidgetHostViewMac::AcceleratedSurfacePostSubBuffer(
@@ -1632,17 +1739,16 @@ void RenderWidgetHostViewMac::AcceleratedSurfacePostSubBuffer(
     int gpu_host_id) {
   TRACE_EVENT0("browser",
       "RenderWidgetHostViewMac::AcceleratedSurfacePostSubBuffer");
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  pending_swap_buffers_acks_.push_back(std::make_pair(params.route_id,
-                                                      gpu_host_id));
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
+  AddPendingSwapAck(params.route_id,
+                    gpu_host_id,
+                    compositing_iosurface_ ?
+                        compositing_iosurface_->GetRendererID() : 0);
   CompositorSwapBuffers(params.surface_handle,
                         params.surface_size,
                         params.surface_scale_factor,
                         params.latency_info);
-
-  ThrottledAckPendingSwapBuffers();
 }
 
 void RenderWidgetHostViewMac::AcceleratedSurfaceSuspend() {
@@ -1670,22 +1776,17 @@ bool RenderWidgetHostViewMac::HasAcceleratedSurface(
   return false;
 }
 
-void RenderWidgetHostViewMac::AboutToWaitForBackingStoreMsg() {
-  AckPendingSwapBuffers();
-}
-
 void RenderWidgetHostViewMac::OnSwapCompositorFrame(
     uint32 output_surface_id, scoped_ptr<cc::CompositorFrame> frame) {
   // Only software compositor frames are accepted.
   if (!frame->software_frame_data) {
     DLOG(ERROR) << "Received unexpected frame type.";
     RecordAction(
-        UserMetricsAction("BadMessageTerminate_UnexpectedFrameType"));
+        base::UserMetricsAction("BadMessageTerminate_UnexpectedFrameType"));
     render_widget_host_->GetProcess()->ReceivedBadMessage();
     return;
   }
 
-  GotSoftwareFrame();
   if (!software_frame_manager_->SwapToNewFrame(
           output_surface_id,
           frame->software_frame_data.get(),
@@ -1694,16 +1795,36 @@ void RenderWidgetHostViewMac::OnSwapCompositorFrame(
     render_widget_host_->GetProcess()->ReceivedBadMessage();
     return;
   }
+
+  // Add latency info to report when the frame finishes drawing.
+  AddPendingLatencyInfo(frame->metadata.latency_info);
+  GotSoftwareFrame();
+
+  cc::CompositorFrameAck ack;
+  RenderWidgetHostImpl::SendSwapCompositorFrameAck(
+      render_widget_host_->GetRoutingID(),
+      software_frame_manager_->GetCurrentFrameOutputSurfaceId(),
+      render_widget_host_->GetProcess()->GetID(),
+      ack);
   software_frame_manager_->SwapToNewFrameComplete(
       !render_widget_host_->is_hidden());
 
-  [cocoa_view_ setNeedsDisplay:YES];
+  // Notify observers, tab capture observers in particular, that a new software
+  // frame has come in.
+  NotificationService::current()->Notify(
+      NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
+      Source<RenderWidgetHost>(render_widget_host_),
+      NotificationService::NoDetails());
 }
 
 void RenderWidgetHostViewMac::OnAcceleratedCompositingStateChange() {
 }
 
-void RenderWidgetHostViewMac::GetScreenInfo(WebKit::WebScreenInfo* results) {
+void RenderWidgetHostViewMac::AcceleratedSurfaceInitialized(int host_id,
+                                                            int route_id) {
+}
+
+void RenderWidgetHostViewMac::GetScreenInfo(blink::WebScreenInfo* results) {
   *results = GetWebScreenInfo(GetNativeView());
 }
 
@@ -1725,11 +1846,6 @@ gfx::GLSurfaceHandle RenderWidgetHostViewMac::GetCompositingSurface() {
   return gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::NATIVE_TRANSPORT);
 }
 
-void RenderWidgetHostViewMac::SetHasHorizontalScrollbar(
-    bool has_horizontal_scrollbar) {
-  [cocoa_view_ setHasHorizontalScrollbar:has_horizontal_scrollbar];
-}
-
 void RenderWidgetHostViewMac::SetScrollOffsetPinning(
     bool is_pinned_to_left, bool is_pinned_to_right) {
   [cocoa_view_ scrollOffsetPinnedToLeft:is_pinned_to_left
@@ -1747,7 +1863,7 @@ bool RenderWidgetHostViewMac::LockMouse() {
   [NSCursor hide];
 
   // Clear the tooltip window.
-  SetTooltipText(string16());
+  SetTooltipText(base::string16());
 
   return true;
 }
@@ -1766,7 +1882,7 @@ void RenderWidgetHostViewMac::UnlockMouse() {
 }
 
 void RenderWidgetHostViewMac::UnhandledWheelEvent(
-    const WebKit::WebMouseWheelEvent& event) {
+    const blink::WebMouseWheelEvent& event) {
   // Only record a wheel event as unhandled if JavaScript handlers got a chance
   // to see it (no-op wheel events are ignored by the event dispatcher)
   if (event.deltaX || event.deltaY)
@@ -1782,6 +1898,8 @@ bool RenderWidgetHostViewMac::Send(IPC::Message* message) {
 
 void RenderWidgetHostViewMac::SoftwareFrameWasFreed(
     uint32 output_surface_id, unsigned frame_id) {
+  if (!render_widget_host_)
+    return;
   cc::CompositorFrameAck ack;
   ack.last_software_frame_id = frame_id;
   RenderWidgetHostImpl::SendReclaimCompositorResources(
@@ -1792,6 +1910,7 @@ void RenderWidgetHostViewMac::SoftwareFrameWasFreed(
 }
 
 void RenderWidgetHostViewMac::ReleaseReferencesToSoftwareFrame() {
+  DestroySoftwareLayer();
 }
 
 void RenderWidgetHostViewMac::ShutdownHost() {
@@ -1801,10 +1920,8 @@ void RenderWidgetHostViewMac::ShutdownHost() {
 }
 
 void RenderWidgetHostViewMac::GotAcceleratedFrame() {
-  // Update the scale factor of the layer to match the scale factor of the
-  // IOSurface.
-  [compositing_iosurface_layer_ updateScaleFactor];
-
+  EnsureCompositedIOSurfaceLayer();
+  SendVSyncParametersToRenderer();
   if (!last_frame_was_accelerated_) {
     last_frame_was_accelerated_ = true;
 
@@ -1814,18 +1931,34 @@ void RenderWidgetHostViewMac::GotAcceleratedFrame() {
       [cocoa_view_ setNeedsDisplay:YES];
     }
 
-    // Delete software backingstore.
-    BackingStoreManager::RemoveBackingStore(render_widget_host_);
+    // Delete software backingstore and layer.
     software_frame_manager_->DiscardCurrentFrame();
+    DestroySoftwareLayer();
   }
 }
 
 void RenderWidgetHostViewMac::GotSoftwareFrame() {
+  if (!render_widget_host_)
+    return;
+
+  EnsureSoftwareLayer();
+  LayoutLayers();
+  SendVSyncParametersToRenderer();
+
+  // Draw the contents of the frame immediately. It is critical that this
+  // happen before the frame be acked, otherwise the new frame will likely be
+  // ready before the drawing is complete, thrashing the browser main thread.
+  if (use_core_animation_) {
+    [software_layer_ setNeedsDisplay];
+    [software_layer_ displayIfNeeded];
+  } else {
+    [cocoa_view_ setNeedsDisplay:YES];
+    [cocoa_view_ displayIfNeeded];
+  }
+
   if (last_frame_was_accelerated_) {
     last_frame_was_accelerated_ = false;
 
-    AckPendingSwapBuffers();
-
     // If overlapping views are allowed, then don't unbind the context
     // from the view (that is, don't call clearDrawble -- just delete the
     // texture and IOSurface). Rather, let it sit behind the software frame
@@ -1846,6 +1979,10 @@ void RenderWidgetHostViewMac::GotSoftwareFrame() {
   }
 }
 
+void RenderWidgetHostViewMac::TimerSinceGotAcceleratedFrameFired() {
+  [compositing_iosurface_layer_ timerSinceGotNewFrameFired];
+}
+
 void RenderWidgetHostViewMac::SetActive(bool active) {
   if (render_widget_host_) {
     render_widget_host_->SetActive(active);
@@ -1878,18 +2015,10 @@ void RenderWidgetHostViewMac::WindowFrameChanged() {
         GetViewBounds()));
   }
 
-  if (compositing_iosurface_ && use_core_animation_) {
-    scoped_refptr<CompositingIOSurfaceContext> new_context =
-        CompositingIOSurfaceContext::Get(window_number());
-    if (new_context) {
-      // Un-bind the GL context from this view before binding the new GL
-      // context. Having two GL contexts bound to a view will result in
-      // crashes and corruption.
-      // http://crbug.com/230883
-      ClearBoundContextDrawable();
-      compositing_iosurface_context_ = new_context;
-      compositing_iosurface_->SetContext(compositing_iosurface_context_);
-    }
+  if (compositing_iosurface_ && !use_core_animation_) {
+    // This will migrate the context to the appropriate window.
+    if (!EnsureCompositedIOSurface())
+      GotAcceleratedCompositingError();
   }
 }
 
@@ -1905,18 +2034,71 @@ void RenderWidgetHostViewMac::SetBackground(const SkBitmap& background) {
         render_widget_host_->GetRoutingID(), background));
 }
 
-void RenderWidgetHostViewMac::OnAccessibilityEvents(
-    const std::vector<AccessibilityHostMsg_EventParams>& params) {
+void RenderWidgetHostViewMac::CreateBrowserAccessibilityManagerIfNeeded() {
   if (!GetBrowserAccessibilityManager()) {
     SetBrowserAccessibilityManager(
         new BrowserAccessibilityManagerMac(
             cocoa_view_,
             BrowserAccessibilityManagerMac::GetEmptyDocument(),
-            NULL));
+            render_widget_host_));
   }
-  GetBrowserAccessibilityManager()->OnAccessibilityEvents(params);
 }
 
+gfx::Point RenderWidgetHostViewMac::AccessibilityOriginInScreen(
+    const gfx::Rect& bounds) {
+  NSPoint origin = NSMakePoint(bounds.x(), bounds.y());
+  NSSize size = NSMakeSize(bounds.width(), bounds.height());
+  origin.y = NSHeight([cocoa_view_ bounds]) - origin.y;
+  NSPoint originInWindow = [cocoa_view_ convertPoint:origin toView:nil];
+  NSPoint originInScreen =
+      [[cocoa_view_ window] convertBaseToScreen:originInWindow];
+  originInScreen.y = originInScreen.y - size.height;
+  return gfx::Point(originInScreen.x, originInScreen.y);
+}
+
+void RenderWidgetHostViewMac::OnAccessibilitySetFocus(int accObjId) {
+  // Immediately set the focused item even though we have not officially set
+  // focus on it as VoiceOver expects to get the focused item after this
+  // method returns.
+  BrowserAccessibilityManager* manager = GetBrowserAccessibilityManager();
+  if (manager)
+    manager->SetFocus(manager->GetFromID(accObjId), false);
+}
+
+void RenderWidgetHostViewMac::AccessibilityShowMenu(int accObjId) {
+  BrowserAccessibilityManager* manager = GetBrowserAccessibilityManager();
+  if (!manager)
+    return;
+  BrowserAccessibilityCocoa* obj =
+      manager->GetFromID(accObjId)->ToBrowserAccessibilityCocoa();
+
+  // Performs a right click copying WebKit's
+  // accessibilityPerformShowMenuAction.
+  NSPoint objOrigin = [obj origin];
+  NSSize size = [[obj size] sizeValue];
+  gfx::Point origin = AccessibilityOriginInScreen(
+      gfx::Rect(objOrigin.x, objOrigin.y, size.width, size.height));
+  NSPoint location = NSMakePoint(origin.x(), origin.y());
+  location = [[cocoa_view_ window] convertScreenToBase:location];
+  location.x += size.width/2;
+  location.y += size.height/2;
+
+  NSEvent* fakeRightClick = [NSEvent
+                          mouseEventWithType:NSRightMouseDown
+                                    location:location
+                               modifierFlags:0
+                                   timestamp:0
+                                windowNumber:[[cocoa_view_ window] windowNumber]
+                                     context:[NSGraphicsContext currentContext]
+                                 eventNumber:0
+                                  clickCount:1
+                                    pressure:0];
+
+  [cocoa_view_ mouseEvent:fakeRightClick];
+}
+
+
+
 void RenderWidgetHostViewMac::SetTextInputActive(bool active) {
   if (active) {
     if (text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD)
@@ -1938,20 +2120,225 @@ void RenderWidgetHostViewMac::OnStartPluginIme() {
   [cocoa_view_ setPluginImeActive:YES];
 }
 
+void RenderWidgetHostViewMac::OnDidChangeScrollbarsForMainFrame(
+    bool has_horizontal_scrollbar, bool has_vertical_scrollbar) {
+  [cocoa_view_ setHasHorizontalScrollbar:has_horizontal_scrollbar];
+}
+
 gfx::Rect RenderWidgetHostViewMac::GetScaledOpenGLPixelRect(
     const gfx::Rect& rect) {
   gfx::Rect src_gl_subrect = rect;
   src_gl_subrect.set_y(GetViewBounds().height() - rect.bottom());
 
   return gfx::ToEnclosingRect(gfx::ScaleRect(src_gl_subrect,
-                                             scale_factor()));
+                                             ViewScaleFactor()));
+}
+
+void RenderWidgetHostViewMac::AddPendingLatencyInfo(
+    const std::vector<ui::LatencyInfo>& latency_info) {
+  // If a screenshot is being taken when using CoreAnimation, send a few extra
+  // calls to setNeedsDisplay and wait for their resulting display calls,
+  // before reporting that the frame has reached the screen.
+  if (use_core_animation_) {
+    bool should_defer = false;
+    for (size_t i = 0; i < latency_info.size(); i++) {
+      if (latency_info[i].FindLatency(
+              ui::WINDOW_SNAPSHOT_FRAME_NUMBER_COMPONENT,
+              render_widget_host_->GetLatencyComponentId(),
+              NULL)) {
+        should_defer = true;
+      }
+    }
+    if (should_defer) {
+      // Multiple pending screenshot requests will work, but if every frame
+      // requests a screenshot, then the delay will never expire. Assert this
+      // here to avoid this.
+      CHECK_EQ(pending_latency_info_delay_, 0u);
+      // Wait a fixed number of frames (calls to CALayer::display) before
+      // claiming that the screenshot has reached the screen. This number
+      // comes from taking the first number where tests didn't fail (six),
+      // and doubling it.
+      const uint32 kScreenshotLatencyDelayInFrames = 12;
+      pending_latency_info_delay_ = kScreenshotLatencyDelayInFrames;
+      TickPendingLatencyInfoDelay();
+    }
+  }
+
+  for (size_t i = 0; i < latency_info.size(); i++) {
+    pending_latency_info_.push_back(latency_info[i]);
+  }
+}
+
+void RenderWidgetHostViewMac::SendPendingLatencyInfoToHost() {
+  if (pending_latency_info_delay_) {
+    pending_latency_info_delay_ -= 1;
+    return;
+  }
+  pending_latency_info_delay_weak_ptr_factory_.InvalidateWeakPtrs();
+
+  for (size_t i = 0; i < pending_latency_info_.size(); i++) {
+    pending_latency_info_[i].AddLatencyNumber(
+        ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
+    render_widget_host_->FrameSwapped(pending_latency_info_[i]);
+  }
+  pending_latency_info_.clear();
+}
+
+void RenderWidgetHostViewMac::TickPendingLatencyInfoDelay() {
+  if (compositing_iosurface_layer_) {
+    // Keep calling gotNewFrame in a loop until enough display calls come in.
+    // Each call will be separated by about a vsync.
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&RenderWidgetHostViewMac::TickPendingLatencyInfoDelay,
+                   pending_latency_info_delay_weak_ptr_factory_.GetWeakPtr()));
+    [compositing_iosurface_layer_ gotNewFrame];
+  }
+  if (software_layer_) {
+    // In software mode, setNeedsDisplay will almost immediately result in the
+    // layer's draw function being called, so manually insert a pretend-vsync
+    // at 60 Hz.
+    base::MessageLoop::current()->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&RenderWidgetHostViewMac::TickPendingLatencyInfoDelay,
+                   pending_latency_info_delay_weak_ptr_factory_.GetWeakPtr()),
+        base::TimeDelta::FromMilliseconds(1000/60));
+    [software_layer_ setNeedsDisplay];
+  }
 }
 
-void RenderWidgetHostViewMac::FrameSwapped() {
-  software_latency_info_.AddLatencyNumber(
-      ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
-  render_widget_host_->FrameSwapped(software_latency_info_);
-  software_latency_info_.Clear();
+void RenderWidgetHostViewMac::AddPendingSwapAck(
+    int32 route_id, int gpu_host_id, int32 renderer_id) {
+  // Note that multiple un-acked swaps can come in the event of a GPU process
+  // loss. Drop the old acks.
+  pending_swap_ack_.reset(new PendingSwapAck(
+      route_id, gpu_host_id, renderer_id));
+
+  // A trace value of 2 indicates that there is a pending swap ack. See
+  // CompositingIOSurfaceLayer's canDrawInCGLContext for other value meanings.
+  TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, 2);
+}
+
+void RenderWidgetHostViewMac::SendPendingSwapAck() {
+  if (!pending_swap_ack_)
+    return;
+
+  AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
+  ack_params.sync_point = 0;
+  ack_params.renderer_id = pending_swap_ack_->renderer_id;
+  RenderWidgetHostImpl::AcknowledgeBufferPresent(pending_swap_ack_->route_id,
+                                                 pending_swap_ack_->gpu_host_id,
+                                                 ack_params);
+  pending_swap_ack_.reset();
+  TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, 0);
+}
+
+void RenderWidgetHostViewMac::PauseForPendingResizeOrRepaintsAndDraw() {
+  if (!render_widget_host_ || render_widget_host_->is_hidden())
+    return;
+
+  // Pausing for the overlay view prevents the underlay from receiving
+  // frames. This may lead to large delays, causing overlaps. If both
+  // overlay and underlay resize at the same time, let them both to have
+  // some time waiting. See crbug.com/352020.
+  if (underlay_view_ &&
+      underlay_view_->render_widget_host_ &&
+      !underlay_view_->render_widget_host_->
+          CanPauseForPendingResizeOrRepaints())
+    return;
+
+  // Ensure that all frames are acked before waiting for a frame to come in.
+  // Note that we will draw a frame at the end of this function, so it is safe
+  // to ack a never-drawn frame here.
+  SendPendingSwapAck();
+
+  // Wait for a frame of the right size to come in.
+  render_widget_host_->PauseForPendingResizeOrRepaints();
+
+  // Immediately draw any frames that haven't been drawn yet. This is necessary
+  // to keep the window and the window's contents in sync.
+  [cocoa_view_ displayIfNeeded];
+  [software_layer_ displayIfNeeded];
+  [compositing_iosurface_layer_ displayIfNeeded];
+}
+
+void RenderWidgetHostViewMac::LayoutLayers() {
+  if (!use_core_animation_)
+    return;
+
+  // Disable animation of the layer's resizing or change in contents scale.
+  ScopedCAActionDisabler disabler;
+
+  CGRect new_background_frame = NSRectToCGRect([cocoa_view() bounds]);
+
+  // Dynamically calling setContentsScale on a CAOpenGLLayer for which
+  // setAsynchronous is dynamically toggled can result in flashes of corrupt
+  // content. Work around this by replacing the entire layer when the scale
+  // factor changes.
+  if (compositing_iosurface_ &&
+      [compositing_iosurface_layer_
+          respondsToSelector:(@selector(contentsScale))]) {
+    if (compositing_iosurface_->scale_factor() !=
+        [compositing_iosurface_layer_ contentsScale]) {
+      DestroyCompositedIOSurfaceLayer(kRemoveLayerFromHierarchy);
+      EnsureCompositedIOSurfaceLayer();
+    }
+  }
+  if (compositing_iosurface_ &&
+      compositing_iosurface_->HasIOSurface() &&
+      compositing_iosurface_layer_) {
+    CGRect layer_bounds = CGRectMake(
+      0,
+      0,
+      compositing_iosurface_->dip_io_surface_size().width(),
+      compositing_iosurface_->dip_io_surface_size().height());
+    CGPoint layer_position = CGPointMake(
+      0,
+      CGRectGetHeight(new_background_frame) - CGRectGetHeight(layer_bounds));
+    bool bounds_changed = !CGRectEqualToRect(
+        layer_bounds, [compositing_iosurface_layer_ bounds]);
+    [compositing_iosurface_layer_ setPosition:layer_position];
+    [compositing_iosurface_layer_ setBounds:layer_bounds];
+
+    // If the bounds changed, then draw the frame immediately, to ensure that
+    // content displayed is in sync with the window size.
+    if (bounds_changed) {
+      // Also, sometimes, especially when infobars are being removed, the
+      // setNeedsDisplay calls are dropped on the floor, and stale content is
+      // displayed. Calling displayIfNeeded will ensure that the right size
+      // frame is drawn to the screen.
+      // http://crbug.com/350817
+      [compositing_iosurface_layer_ setNeedsDisplay];
+      [compositing_iosurface_layer_ displayIfNeeded];
+    }
+  }
+
+  // Dynamically update the software layer's contents scale to match the
+  // software frame.
+  if (software_frame_manager_->HasCurrentFrame() &&
+      [software_layer_ respondsToSelector:(@selector(contentsScale))] &&
+      [software_layer_ respondsToSelector:(@selector(setContentsScale:))]) {
+    if (software_frame_manager_->GetCurrentFrameDeviceScaleFactor() !=
+        [software_layer_ contentsScale]) {
+      [software_layer_ setContentsScale:
+          software_frame_manager_->GetCurrentFrameDeviceScaleFactor()];
+    }
+  }
+  // Changing the software layer's bounds and position doesn't always result
+  // in the layer being anchored to the top-left. Set the layer's frame
+  // explicitly, since this is more reliable in practice.
+  if (software_layer_) {
+    bool frame_changed = !CGRectEqualToRect(
+        new_background_frame, [software_layer_ frame]);
+    if (frame_changed) {
+      [software_layer_ setFrame:new_background_frame];
+      [software_layer_ setNeedsDisplay];
+    }
+  }
+}
+
+SkBitmap::Config RenderWidgetHostViewMac::PreferredReadbackFormat() {
+  return SkBitmap::kARGB_8888_Config;
 }
 
 }  // namespace content
@@ -1959,22 +2346,22 @@ void RenderWidgetHostViewMac::FrameSwapped() {
 // RenderWidgetHostViewCocoa ---------------------------------------------------
 
 @implementation RenderWidgetHostViewCocoa
-
 @synthesize selectedRange = selectedRange_;
 @synthesize suppressNextEscapeKeyUp = suppressNextEscapeKeyUp_;
 @synthesize markedRange = markedRange_;
-@synthesize delegate = delegate_;
 
 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r {
   self = [super initWithFrame:NSZeroRect];
   if (self) {
+    self.acceptsTouchEvents = YES;
     editCommand_helper_.reset(new RenderWidgetHostViewMacEditCommandHelper);
     editCommand_helper_->AddEditingSelectorsToClass([self class]);
 
     renderWidgetHostView_.reset(r);
     canBeKeyView_ = YES;
     focusedPluginIdentifier_ = -1;
-    deviceScaleFactor_ = ScaleFactor(self);
+    renderWidgetHostView_->backing_store_scale_factor_ =
+        ScaleFactorForView(self);
 
     // OpenGL support:
     if ([self respondsToSelector:
@@ -1987,6 +2374,11 @@ void RenderWidgetHostViewMac::FrameSwapped() {
            selector:@selector(globalFrameDidChange:)
                name:NSViewGlobalFrameDidChangeNotification
              object:self];
+    [[NSNotificationCenter defaultCenter]
+        addObserver:self
+           selector:@selector(didChangeScreenParameters:)
+               name:NSApplicationDidChangeScreenParametersNotification
+             object:nil];
   }
   return self;
 }
@@ -1999,13 +2391,26 @@ void RenderWidgetHostViewMac::FrameSwapped() {
   if (renderWidgetHostView_)
     renderWidgetHostView_->AcceleratedSurfaceRelease();
 
-  if (delegate_ && [delegate_ respondsToSelector:@selector(viewGone:)])
-    [delegate_ viewGone:self];
+  if (responderDelegate_ &&
+      [responderDelegate_ respondsToSelector:@selector(viewGone:)])
+    [responderDelegate_ viewGone:self];
+  responderDelegate_.reset();
+
   [[NSNotificationCenter defaultCenter] removeObserver:self];
 
   [super dealloc];
 }
 
+- (void)didChangeScreenParameters:(NSNotification*)notify {
+  g_screen_info_up_to_date = false;
+}
+
+- (void)setResponderDelegate:
+            (NSObject<RenderWidgetHostViewMacDelegate>*)delegate {
+  DCHECK(!responderDelegate_);
+  responderDelegate_.reset([delegate retain]);
+}
+
 - (void)resetCursorRects {
   if (currentCursor_) {
     [self addCursorRect:[self visibleRect] cursor:currentCursor_];
@@ -2014,23 +2419,26 @@ void RenderWidgetHostViewMac::FrameSwapped() {
 }
 
 - (void)gotUnhandledWheelEvent {
-  if (delegate_ &&
-      [delegate_ respondsToSelector:@selector(gotUnhandledWheelEvent)]) {
-    [delegate_ gotUnhandledWheelEvent];
+  if (responderDelegate_ &&
+      [responderDelegate_
+          respondsToSelector:@selector(gotUnhandledWheelEvent)]) {
+    [responderDelegate_ gotUnhandledWheelEvent];
   }
 }
 
 - (void)scrollOffsetPinnedToLeft:(BOOL)left toRight:(BOOL)right {
-  if (delegate_ && [delegate_ respondsToSelector:
-      @selector(scrollOffsetPinnedToLeft:toRight:)]) {
-    [delegate_ scrollOffsetPinnedToLeft:left toRight:right];
+  if (responderDelegate_ &&
+      [responderDelegate_
+          respondsToSelector:@selector(scrollOffsetPinnedToLeft:toRight:)]) {
+    [responderDelegate_ scrollOffsetPinnedToLeft:left toRight:right];
   }
 }
 
 - (void)setHasHorizontalScrollbar:(BOOL)has_horizontal_scrollbar {
-  if (delegate_ &&
-      [delegate_ respondsToSelector:@selector(setHasHorizontalScrollbar:)]) {
-    [delegate_ setHasHorizontalScrollbar:has_horizontal_scrollbar];
+  if (responderDelegate_ &&
+      [responderDelegate_
+          respondsToSelector:@selector(setHasHorizontalScrollbar:)]) {
+    [responderDelegate_ setHasHorizontalScrollbar:has_horizontal_scrollbar];
   }
 }
 
@@ -2041,15 +2449,15 @@ void RenderWidgetHostViewMac::FrameSwapped() {
   if ([super respondsToSelector:selector])
     return YES;
 
-  if (delegate_)
-    return [delegate_ respondsToSelector:selector];
+  if (responderDelegate_)
+    return [responderDelegate_ respondsToSelector:selector];
 
   return NO;
 }
 
 - (id)forwardingTargetForSelector:(SEL)selector {
-  if ([delegate_ respondsToSelector:selector])
-    return delegate_;
+  if ([responderDelegate_ respondsToSelector:selector])
+    return responderDelegate_.get();
 
   return [super forwardingTargetForSelector:selector];
 }
@@ -2101,10 +2509,16 @@ void RenderWidgetHostViewMac::FrameSwapped() {
       // The cursor is over a nonWebContentView - ignore this mouse event.
       return YES;
     }
-    if ([view isKindOfClass:[self class]] && ![view isEqual:self]) {
+    if ([view isKindOfClass:[self class]] && ![view isEqual:self] &&
+        !hasOpenMouseDown_) {
       // The cursor is over an overlapping render widget. This check is done by
       // both views so the one that's returned by -hitTest: will end up
       // processing the event.
+      // Note that while dragging, we only get events for the render view where
+      // drag started, even if mouse is  actually over another view or outside
+      // the window. Cocoa does this for us. We should handle these events and
+      // not ignore (since there is no other render view to handle them). Thus
+      // the |!hasOpenMouseDown_| check above.
       return YES;
     }
     view = [view superview];
@@ -2114,8 +2528,9 @@ void RenderWidgetHostViewMac::FrameSwapped() {
 
 - (void)mouseEvent:(NSEvent*)theEvent {
   TRACE_EVENT0("browser", "RenderWidgetHostViewCocoa::mouseEvent");
-  if (delegate_ && [delegate_ respondsToSelector:@selector(handleEvent:)]) {
-    BOOL handled = [delegate_ handleEvent:theEvent];
+  if (responderDelegate_ &&
+      [responderDelegate_ respondsToSelector:@selector(handleEvent:)]) {
+    BOOL handled = [responderDelegate_ handleEvent:theEvent];
     if (handled)
       return;
   }
@@ -2226,8 +2641,9 @@ void RenderWidgetHostViewMac::FrameSwapped() {
 }
 
 - (EventHandled)keyEvent:(NSEvent*)theEvent {
-  if (delegate_ && [delegate_ respondsToSelector:@selector(handleEvent:)]) {
-    BOOL handled = [delegate_ handleEvent:theEvent];
+  if (responderDelegate_ &&
+      [responderDelegate_ respondsToSelector:@selector(handleEvent:)]) {
+    BOOL handled = [responderDelegate_ handleEvent:theEvent];
     if (handled)
       return kEventHandled;
   }
@@ -2396,7 +2812,7 @@ void RenderWidgetHostViewMac::FrameSwapped() {
   } else if (oldHasMarkedText && !hasMarkedText_ && !textInserted) {
     if (unmarkTextCalled_) {
       widgetHost->ImeConfirmComposition(
-          string16(), gfx::Range::InvalidRange(), false);
+          base::string16(), gfx::Range::InvalidRange(), false);
     } else {
       widgetHost->ImeCancelComposition();
     }
@@ -2413,7 +2829,7 @@ void RenderWidgetHostViewMac::FrameSwapped() {
     // So before sending the real key down event, we need to send a fake key up
     // event to balance it.
     NativeWebKeyboardEvent fakeEvent = event;
-    fakeEvent.type = WebKit::WebInputEvent::KeyUp;
+    fakeEvent.type = blink::WebInputEvent::KeyUp;
     fakeEvent.skip_in_browser = true;
     widgetHost->ForwardKeyboardEvent(fakeEvent);
     // Not checking |renderWidgetHostView_->render_widget_host_| here because
@@ -2439,7 +2855,7 @@ void RenderWidgetHostViewMac::FrameSwapped() {
     if (!textInserted && textToBeInserted_.length() == 1) {
       // If a single character was inserted, then we just send it as a keypress
       // event.
-      event.type = WebKit::WebInputEvent::Char;
+      event.type = blink::WebInputEvent::Char;
       event.text[0] = textToBeInserted_[0];
       event.text[1] = 0;
       event.skip_in_browser = true;
@@ -2451,7 +2867,7 @@ void RenderWidgetHostViewMac::FrameSwapped() {
       // We don't get insertText: calls if ctrl or cmd is down, or the key event
       // generates an insert command. So synthesize a keypress event for these
       // cases, unless the key event generated any other command.
-      event.type = WebKit::WebInputEvent::Char;
+      event.type = blink::WebInputEvent::Char;
       event.skip_in_browser = true;
       widgetHost->ForwardKeyboardEvent(event);
     }
@@ -2471,8 +2887,12 @@ void RenderWidgetHostViewMac::FrameSwapped() {
   }
 
   if (renderWidgetHostView_->render_widget_host_) {
-    const WebMouseWheelEvent& webEvent =
-        WebInputEventFactory::mouseWheelEvent(event, self);
+    // History-swiping is not possible if the logic reaches this point.
+    // Allow rubber-banding in both directions.
+    bool canRubberbandLeft = true;
+    bool canRubberbandRight = true;
+    const WebMouseWheelEvent webEvent = WebInputEventFactory::mouseWheelEvent(
+        event, self, canRubberbandLeft, canRubberbandRight);
     renderWidgetHostView_->render_widget_host_->ForwardWheelEvent(webEvent);
   }
 
@@ -2482,9 +2902,69 @@ void RenderWidgetHostViewMac::FrameSwapped() {
   }
 }
 
+- (void)beginGestureWithEvent:(NSEvent*)event {
+  [responderDelegate_ beginGestureWithEvent:event];
+}
+- (void)endGestureWithEvent:(NSEvent*)event {
+  [responderDelegate_ endGestureWithEvent:event];
+}
+- (void)touchesMovedWithEvent:(NSEvent*)event {
+  [responderDelegate_ touchesMovedWithEvent:event];
+}
+- (void)touchesBeganWithEvent:(NSEvent*)event {
+  [responderDelegate_ touchesBeganWithEvent:event];
+}
+- (void)touchesCancelledWithEvent:(NSEvent*)event {
+  [responderDelegate_ touchesCancelledWithEvent:event];
+}
+- (void)touchesEndedWithEvent:(NSEvent*)event {
+  [responderDelegate_ touchesEndedWithEvent:event];
+}
+
+// This is invoked only on 10.8 or newer when the user taps a word using
+// three fingers.
+- (void)quickLookWithEvent:(NSEvent*)event {
+  NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
+  TextInputClientMac::GetInstance()->GetStringAtPoint(
+      renderWidgetHostView_->render_widget_host_,
+      gfx::Point(point.x, NSHeight([self frame]) - point.y),
+      ^(NSAttributedString* string, NSPoint baselinePoint) {
+          if (string && [string length] > 0) {
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [self showDefinitionForAttributedString:string
+                                                atPoint:baselinePoint];
+            });
+          }
+      }
+  );
+}
+
+// This method handles 2 different types of hardware events.
+// (Apple does not distinguish between them).
+//  a. Scrolling the middle wheel of a mouse.
+//  b. Swiping on the track pad.
+//
+// This method is responsible for 2 types of behavior:
+//  a. Scrolling the content of window.
+//  b. Navigating forwards/backwards in history.
+//
+// This is a brief description of the logic:
+//  1. If the content can be scrolled, scroll the content.
+//     (This requires a roundtrip to blink to determine whether the content
+//      can be scrolled.)
+//     Once this logic is triggered, the navigate logic cannot be triggered
+//     until the gesture finishes.
+//  2. If the user is making a horizontal swipe, start the navigate
+//     forward/backwards UI.
+//     Once this logic is triggered, the user can either cancel or complete
+//     the gesture. If the user completes the gesture, all remaining touches
+//     are swallowed, and not allowed to scroll the content. If the user
+//     cancels the gesture, all remaining touches are forwarded to the content
+//     scroll logic. The user cannot trigger the navigation logic again.
 - (void)scrollWheel:(NSEvent*)event {
-  if (delegate_ && [delegate_ respondsToSelector:@selector(handleEvent:)]) {
-    BOOL handled = [delegate_ handleEvent:event];
+  if (responderDelegate_ &&
+      [responderDelegate_ respondsToSelector:@selector(handleEvent:)]) {
+    BOOL handled = [responderDelegate_ handleEvent:event];
     if (handled)
       return;
   }
@@ -2496,20 +2976,37 @@ void RenderWidgetHostViewMac::FrameSwapped() {
   if (base::mac::IsOSLionOrLater() && [event phase] == NSEventPhaseBegan &&
       !endWheelMonitor_) {
     endWheelMonitor_ =
-        [NSEvent addLocalMonitorForEventsMatchingMask:NSScrollWheelMask
-            handler:^(NSEvent* blockEvent) {
-              [self shortCircuitScrollWheelEvent:blockEvent];
-              return blockEvent;
-            }];
+      [NSEvent addLocalMonitorForEventsMatchingMask:NSScrollWheelMask
+      handler:^(NSEvent* blockEvent) {
+          [self shortCircuitScrollWheelEvent:blockEvent];
+          return blockEvent;
+      }];
   }
 
+  // This is responsible for content scrolling!
   if (renderWidgetHostView_->render_widget_host_) {
-    const WebMouseWheelEvent& webEvent =
-        WebInputEventFactory::mouseWheelEvent(event, self);
+    BOOL canRubberbandLeft = [responderDelegate_ canRubberbandLeft:self];
+    BOOL canRubberbandRight = [responderDelegate_ canRubberbandRight:self];
+    const WebMouseWheelEvent webEvent = WebInputEventFactory::mouseWheelEvent(
+        event, self, canRubberbandLeft, canRubberbandRight);
     renderWidgetHostView_->render_widget_host_->ForwardWheelEvent(webEvent);
   }
 }
 
+// Called repeatedly during a pinch gesture, with incremental change values.
+- (void)magnifyWithEvent:(NSEvent*)event {
+  if (renderWidgetHostView_->render_widget_host_) {
+    // Send a GesturePinchUpdate event.
+    // Note that we don't attempt to bracket these by GesturePinchBegin/End (or
+    // GestureSrollBegin/End) as is done for touchscreen.  Keeping track of when
+    // a pinch is active would take a little more work here, and we don't need
+    // it for anything yet.
+    const WebGestureEvent& webEvent =
+        WebInputEventFactory::gestureEvent(event, self);
+    renderWidgetHostView_->render_widget_host_->ForwardGestureEvent(webEvent);
+  }
+}
+
 - (void)viewWillMoveToWindow:(NSWindow*)newWindow {
   NSWindow* oldWindow = [self window];
 
@@ -2518,13 +3015,6 @@ void RenderWidgetHostViewMac::FrameSwapped() {
   if (!renderWidgetHostView_->use_core_animation_)
     [oldWindow disableScreenUpdatesUntilFlush];
 
-  // If the new window for this view is using CoreAnimation then enable
-  // CoreAnimation on this view.
-  if (GetCoreAnimationStatus() == CORE_ANIMATION_ENABLED_LAZY &&
-      [[newWindow contentView] wantsLayer]) {
-    renderWidgetHostView_->EnableCoreAnimation();
-  }
-
   NSNotificationCenter* notificationCenter =
       [NSNotificationCenter defaultCenter];
 
@@ -2570,44 +3060,23 @@ void RenderWidgetHostViewMac::FrameSwapped() {
   }
 }
 
-- (void)updateTabBackingStoreScaleFactor {
-  if (!renderWidgetHostView_->render_widget_host_)
-    return;
-
-  float scaleFactor = ScaleFactor(self);
-  if (scaleFactor == deviceScaleFactor_)
-    return;
-  deviceScaleFactor_ = scaleFactor;
-
-  BackingStoreMac* backingStore = static_cast<BackingStoreMac*>(
-      renderWidgetHostView_->render_widget_host_->GetBackingStore(false));
-  if (backingStore)  // NULL in hardware path.
-    backingStore->ScaleFactorChanged(scaleFactor);
-
-  [self updateSoftwareLayerScaleFactor];
-  renderWidgetHostView_->render_widget_host_->NotifyScreenInfoChanged();
+- (void)updateScreenProperties{
+  renderWidgetHostView_->UpdateBackingStoreScaleFactor();
+  renderWidgetHostView_->UpdateDisplayLink();
 }
 
 // http://developer.apple.com/library/mac/#documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/CapturingScreenContents/CapturingScreenContents.html#//apple_ref/doc/uid/TP40012302-CH10-SW4
 - (void)windowDidChangeBackingProperties:(NSNotification*)notification {
-  NSWindow* window = (NSWindow*)[notification object];
+  // Background tabs check if their scale factor or vsync properties changed
+  // when they are added to a window.
 
-  CGFloat newBackingScaleFactor = [window backingScaleFactor];
-  CGFloat oldBackingScaleFactor = [base::mac::ObjCCast<NSNumber>(
-      [[notification userInfo] objectForKey:NSBackingPropertyOldScaleFactorKey])
-      doubleValue];
-  if (newBackingScaleFactor != oldBackingScaleFactor) {
-    // Background tabs check if their scale factor changed when they are added
-    // to a window.
-
-    // Allocating a CGLayerRef with the current scale factor immediately from
-    // this handler doesn't work. Schedule the backing store update on the
-    // next runloop cycle, then things are read for CGLayerRef allocations to
-    // work.
-    [self performSelector:@selector(updateTabBackingStoreScaleFactor)
-               withObject:nil
-               afterDelay:0];
-  }
+  // Allocating a CGLayerRef with the current scale factor immediately from
+  // this handler doesn't work. Schedule the backing store update on the
+  // next runloop cycle, then things are read for CGLayerRef allocations to
+  // work.
+  [self performSelector:@selector(updateScreenProperties)
+             withObject:nil
+             afterDelay:0];
 }
 
 - (void)globalFrameDidChange:(NSNotification*)notification {
@@ -2615,7 +3084,8 @@ void RenderWidgetHostViewMac::FrameSwapped() {
     return;
 
   handlingGlobalFrameDidChange_ = YES;
-  if (renderWidgetHostView_->compositing_iosurface_context_) {
+  if (!renderWidgetHostView_->use_core_animation_ &&
+      renderWidgetHostView_->compositing_iosurface_context_) {
     [renderWidgetHostView_->compositing_iosurface_context_->nsgl_context()
         update];
   }
@@ -2633,32 +3103,23 @@ void RenderWidgetHostViewMac::FrameSwapped() {
   // NB: -[NSView setFrame:] calls through -setFrameSize:, so overriding
   // -setFrame: isn't neccessary.
   [super setFrameSize:newSize];
-  if (renderWidgetHostView_->render_widget_host_) {
-    renderWidgetHostView_->render_widget_host_->SendScreenRects();
-    renderWidgetHostView_->render_widget_host_->WasResized();
-  }
 
-  // This call is necessary to make the window wait for a new frame at the new
-  // size to be available before the resize completes. Calling only
-  // setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawOnSetNeedsDisplay on
-  // this is not sufficient.
-  ScopedCAActionDisabler disabler;
-  CGRect frame = NSRectToCGRect([renderWidgetHostView_->cocoa_view() bounds]);
-  [renderWidgetHostView_->software_layer_ setFrame:frame];
-  [renderWidgetHostView_->software_layer_ setNeedsDisplay];
-  [renderWidgetHostView_->compositing_iosurface_layer_ setFrame:frame];
-  [renderWidgetHostView_->compositing_iosurface_layer_ setNeedsDisplay];
-}
+  if (!renderWidgetHostView_->render_widget_host_)
+    return;
+
+  // Move the CALayers to their positions in the new view size. Note that
+  // this will not draw anything because the non-background layers' sizes
+  // didn't actually change.
+  renderWidgetHostView_->LayoutLayers();
 
-- (void)callSetNeedsDisplayInRect {
-  DCHECK([NSThread isMainThread]);
-  DCHECK(renderWidgetHostView_->call_set_needs_display_in_rect_pending_);
-  [self setNeedsDisplayInRect:renderWidgetHostView_->invalid_rect_];
-  renderWidgetHostView_->call_set_needs_display_in_rect_pending_ = false;
-  renderWidgetHostView_->invalid_rect_ = NSZeroRect;
+  renderWidgetHostView_->render_widget_host_->SendScreenRects();
+  renderWidgetHostView_->render_widget_host_->WasResized();
 
-  if (renderWidgetHostView_->compositing_iosurface_layer_)
-    [renderWidgetHostView_->compositing_iosurface_layer_ setNeedsDisplay];
+  // Wait for the frame that WasResize might have requested. If the view is
+  // being made visible at a new size, then this call will have no effect
+  // because the view widget is still hidden, and the pause call in WasShown
+  // will have this effect for us.
+  renderWidgetHostView_->PauseForPendingResizeOrRepaintsAndDraw();
 }
 
 // Fills with white the parts of the area to the right and bottom for |rect|
@@ -2714,32 +3175,22 @@ void RenderWidgetHostViewMac::FrameSwapped() {
 
 - (void)drawRect:(NSRect)dirtyRect {
   TRACE_EVENT0("browser", "RenderWidgetHostViewCocoa::drawRect");
-  CHECK(!renderWidgetHostView_->use_core_animation_);
+  DCHECK(!renderWidgetHostView_->use_core_animation_);
 
   if (!renderWidgetHostView_->render_widget_host_) {
-    // TODO(shess): Consider using something more noticable?
+    // When using CoreAnimation, this path is used to paint the contents area
+    // white before any frames come in. When layers to draw frames exist, this
+    // is not hit.
     [[NSColor whiteColor] set];
     NSRectFill(dirtyRect);
     return;
   }
 
-  DCHECK(!renderWidgetHostView_->about_to_validate_and_paint_);
-
-  // GetBackingStore works for both software and accelerated frames. If a
-  // SwapBuffers occurs while GetBackingStore is blocking, we will continue to
-  // blit the IOSurface below.
-  renderWidgetHostView_->about_to_validate_and_paint_ = true;
-  BackingStoreMac* backingStore = static_cast<BackingStoreMac*>(
-      renderWidgetHostView_->render_widget_host_->GetBackingStore(true));
-  renderWidgetHostView_->about_to_validate_and_paint_ = false;
-
   const gfx::Rect damagedRect([self flipNSRectToRect:dirtyRect]);
 
   if (renderWidgetHostView_->last_frame_was_accelerated_ &&
       renderWidgetHostView_->compositing_iosurface_) {
     if (renderWidgetHostView_->allow_overlapping_views_) {
-      CHECK_EQ(CORE_ANIMATION_DISABLED, GetCoreAnimationStatus());
-
       // If overlapping views need to be allowed, punch a hole in the window
       // to expose the GL underlay.
       TRACE_EVENT2("gpu", "NSRectFill clear", "w", damagedRect.width(),
@@ -2753,36 +3204,26 @@ void RenderWidgetHostViewMac::FrameSwapped() {
       NSRectFill(dirtyRect);
     }
 
-    if (renderWidgetHostView_->DrawIOSurfaceWithoutCoreAnimation())
-      return;
-
-    // On error, fall back to software and fall through to the non-accelerated
-    // drawing path.
-    renderWidgetHostView_->GotAcceleratedCompositingError();
+    gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+        renderWidgetHostView_->compositing_iosurface_context_->cgl_context());
+    renderWidgetHostView_->DrawIOSurfaceWithoutCoreAnimation();
+    return;
   }
 
   CGContextRef context = static_cast<CGContextRef>(
       [[NSGraphicsContext currentContext] graphicsPort]);
-  [self drawBackingStore:backingStore
-               dirtyRect:NSRectToCGRect(dirtyRect)
-               inContext:context];
+  [self drawWithDirtyRect:NSRectToCGRect(dirtyRect)
+                inContext:context];
 }
 
-- (void)drawBackingStore:(BackingStoreMac*)backingStore
-               dirtyRect:(CGRect)dirtyRect
-               inContext:(CGContextRef)context {
+- (void)drawWithDirtyRect:(CGRect)dirtyRect
+                inContext:(CGContextRef)context {
   content::SoftwareFrameManager* software_frame_manager =
       renderWidgetHostView_->software_frame_manager_.get();
-  // There should never be both a legacy software and software composited
-  // frame.
-  DCHECK(!backingStore || !software_frame_manager->HasCurrentFrame());
-
-  if (backingStore || software_frame_manager->HasCurrentFrame()) {
+  if (software_frame_manager->HasCurrentFrame()) {
     // Note: All coordinates are in view units, not pixels.
     gfx::Rect bitmapRect(
-        software_frame_manager->HasCurrentFrame() ?
-            software_frame_manager->GetCurrentFrameSizeInDIP() :
-            backingStore->size());
+            software_frame_manager->GetCurrentFrameSizeInDIP());
 
     // Specify the proper y offset to ensure that the view is rooted to the
     // upper left corner.  This can be negative, if the window was resized
@@ -2794,50 +3235,33 @@ void RenderWidgetHostViewMac::FrameSwapped() {
 
     gfx::Rect paintRect = gfx::IntersectRects(bitmapRect, damagedRect);
     if (!paintRect.IsEmpty()) {
-      if (software_frame_manager->HasCurrentFrame()) {
-        // If a software compositor framebuffer is present, draw using that.
-        gfx::Size sizeInPixels =
-            software_frame_manager->GetCurrentFrameSizeInPixels();
-        base::ScopedCFTypeRef<CGDataProviderRef> dataProvider(
-            CGDataProviderCreateWithData(
-                NULL,
-                software_frame_manager->GetCurrentFramePixels(),
-                4 * sizeInPixels.width() * sizeInPixels.height(),
-                NULL));
-        base::ScopedCFTypeRef<CGImageRef> image(
-            CGImageCreate(
-                sizeInPixels.width(),
-                sizeInPixels.height(),
-                8,
-                32,
-                4 * sizeInPixels.width(),
-                base::mac::GetSystemColorSpace(),
-                kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
-                dataProvider,
-                NULL,
-                false,
-                kCGRenderingIntentDefault));
-        CGRect imageRect = bitmapRect.ToCGRect();
-        imageRect.origin.y = yOffset;
-        CGContextDrawImage(context, imageRect, image);
-      } else if (backingStore->cg_layer()) {
-        // If we have a CGLayer, draw that into the window
-        // TODO: add clipping to dirtyRect if it improves drawing performance.
-        CGContextDrawLayerAtPoint(context, CGPointMake(0.0, yOffset),
-                                  backingStore->cg_layer());
-      } else {
-        // If we haven't created a layer yet, draw the cached bitmap into
-        // the window.  The CGLayer will be created the next time the renderer
-        // paints.
-        base::ScopedCFTypeRef<CGImageRef> image(
-            CGBitmapContextCreateImage(backingStore->cg_bitmap()));
-        CGRect imageRect = bitmapRect.ToCGRect();
-        imageRect.origin.y = yOffset;
-        CGContextDrawImage(context, imageRect, image);
-      }
+      gfx::Size sizeInPixels =
+          software_frame_manager->GetCurrentFrameSizeInPixels();
+      base::ScopedCFTypeRef<CGDataProviderRef> dataProvider(
+          CGDataProviderCreateWithData(
+              NULL,
+              software_frame_manager->GetCurrentFramePixels(),
+              4 * sizeInPixels.width() * sizeInPixels.height(),
+              NULL));
+      base::ScopedCFTypeRef<CGImageRef> image(
+          CGImageCreate(
+              sizeInPixels.width(),
+              sizeInPixels.height(),
+              8,
+              32,
+              4 * sizeInPixels.width(),
+              base::mac::GetSystemColorSpace(),
+              kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
+              dataProvider,
+              NULL,
+              false,
+              kCGRenderingIntentDefault));
+      CGRect imageRect = bitmapRect.ToCGRect();
+      imageRect.origin.y = yOffset;
+      CGContextDrawImage(context, imageRect, image);
     }
 
-    renderWidgetHostView_->FrameSwapped();
+    renderWidgetHostView_->SendPendingLatencyInfoToHost();
 
     // Fill the remaining portion of the damagedRect with white
     [self fillBottomRightRemainderOfRect:bitmapRect
@@ -2934,11 +3358,13 @@ void RenderWidgetHostViewMac::FrameSwapped() {
 }
 
 - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
-  if (delegate_ && [delegate_ respondsToSelector:
-      @selector(validateUserInterfaceItem:isValidItem:)]) {
+  if (responderDelegate_ &&
+      [responderDelegate_
+          respondsToSelector:@selector(validateUserInterfaceItem:
+                                                     isValidItem:)]) {
     BOOL valid;
-    BOOL known = [delegate_ validateUserInterfaceItem:item
-                                          isValidItem:&valid];
+    BOOL known =
+        [responderDelegate_ validateUserInterfaceItem:item isValidItem:&valid];
     if (known)
       return valid;
   }
@@ -3070,73 +3496,6 @@ void RenderWidgetHostViewMac::FrameSwapped() {
   return [super accessibilityFocusedUIElement];
 }
 
-- (void)doDefaultAction:(int32)accessibilityObjectId {
-  RenderWidgetHostImpl* rwh = renderWidgetHostView_->render_widget_host_;
-  rwh->Send(new AccessibilityMsg_DoDefaultAction(
-      rwh->GetRoutingID(), accessibilityObjectId));
-}
-
-// VoiceOver uses this method to move the caret to the beginning of the next
-// word in a text field.
-- (void)accessibilitySetTextSelection:(int32)accId
-                          startOffset:(int32)startOffset
-                            endOffset:(int32)endOffset {
-  RenderWidgetHostImpl* rwh = renderWidgetHostView_->render_widget_host_;
-  rwh->AccessibilitySetTextSelection(accId, startOffset, endOffset);
-}
-
-// Convert a web accessibility's location in web coordinates into a cocoa
-// screen coordinate.
-- (NSPoint)accessibilityPointInScreen:
-    (BrowserAccessibilityCocoa*)accessibility {
-  NSPoint origin = [accessibility origin];
-  NSSize size = [[accessibility size] sizeValue];
-  origin.y = NSHeight([self bounds]) - origin.y;
-  NSPoint originInWindow = [self convertPoint:origin toView:nil];
-  NSPoint originInScreen = [[self window] convertBaseToScreen:originInWindow];
-  originInScreen.y = originInScreen.y - size.height;
-  return originInScreen;
-}
-
-- (void)setAccessibilityFocus:(BOOL)focus
-              accessibilityId:(int32)accessibilityObjectId {
-  if (focus) {
-    RenderWidgetHostImpl* rwh = renderWidgetHostView_->render_widget_host_;
-    rwh->Send(new AccessibilityMsg_SetFocus(
-        rwh->GetRoutingID(), accessibilityObjectId));
-
-    // Immediately set the focused item even though we have not officially set
-    // focus on it as VoiceOver expects to get the focused item after this
-    // method returns.
-    BrowserAccessibilityManager* manager =
-        renderWidgetHostView_->GetBrowserAccessibilityManager();
-    manager->SetFocus(manager->GetFromRendererID(accessibilityObjectId), false);
-  }
-}
-
-- (void)performShowMenuAction:(BrowserAccessibilityCocoa*)accessibility {
-  // Performs a right click copying WebKit's
-  // accessibilityPerformShowMenuAction.
-  NSPoint location = [self accessibilityPointInScreen:accessibility];
-  NSSize size = [[accessibility size] sizeValue];
-  location = [[self window] convertScreenToBase:location];
-  location.x += size.width/2;
-  location.y += size.height/2;
-
-  NSEvent* fakeRightClick = [NSEvent
-                           mouseEventWithType:NSRightMouseDown
-                                     location:location
-                                modifierFlags:0
-                                    timestamp:0
-                                 windowNumber:[[self window] windowNumber]
-                                      context:[NSGraphicsContext currentContext]
-                                  eventNumber:0
-                                   clickCount:1
-                                     pressure:0];
-
-  [self mouseEvent:fakeRightClick];
-}
-
 // Below is the nasty tooltip stuff -- copied from WebKit's WebHTMLView.mm
 // with minor modifications for code style and commenting.
 //
@@ -3510,7 +3869,7 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
   // called in keyEvent: method.
   if (!handlingKeyDown_) {
     renderWidgetHostView_->render_widget_host_->ImeConfirmComposition(
-        string16(), gfx::Range::InvalidRange(), false);
+        base::string16(), gfx::Range::InvalidRange(), false);
   } else {
     unmarkTextCalled_ = YES;
   }
@@ -3538,7 +3897,7 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
   } else {
     // Use a thin black underline by default.
     underlines_.push_back(
-        WebKit::WebCompositionUnderline(0, length, SK_ColorBLACK, false));
+        blink::WebCompositionUnderline(0, length, SK_ColorBLACK, false));
   }
 
   // If we are handling a key down event, then SetComposition() will be
@@ -3618,7 +3977,7 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
 
 - (void)viewDidMoveToWindow {
   if ([self window])
-    [self updateTabBackingStoreScaleFactor];
+    [self updateScreenProperties];
 
   if (canBeKeyView_) {
     NSWindow* newWindow = [self window];
@@ -3646,62 +4005,48 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
 
     hasOpenMouseDown_ = NO;
   }
-
-  // Resize the view's layers to match the new window size.
-  ScopedCAActionDisabler disabler;
-  [renderWidgetHostView_->software_layer_
-      setFrame:NSRectToCGRect([self bounds])];
-  [renderWidgetHostView_->compositing_iosurface_layer_
-      setFrame:NSRectToCGRect([self bounds])];
 }
 
 - (void)undo:(id)sender {
-  if (renderWidgetHostView_->render_widget_host_->IsRenderView()) {
-    static_cast<RenderViewHostImpl*>(
-        renderWidgetHostView_->render_widget_host_)->Undo();
-  }
+  WebContents* web_contents = renderWidgetHostView_->GetWebContents();
+  if (web_contents)
+    web_contents->Undo();
 }
 
 - (void)redo:(id)sender {
-  if (renderWidgetHostView_->render_widget_host_->IsRenderView()) {
-    static_cast<RenderViewHostImpl*>(
-        renderWidgetHostView_->render_widget_host_)->Redo();
-  }
+  WebContents* web_contents = renderWidgetHostView_->GetWebContents();
+  if (web_contents)
+    web_contents->Redo();
 }
 
 - (void)cut:(id)sender {
-  if (renderWidgetHostView_->render_widget_host_->IsRenderView()) {
-    static_cast<RenderViewHostImpl*>(
-        renderWidgetHostView_->render_widget_host_)->Cut();
-  }
+  WebContents* web_contents = renderWidgetHostView_->GetWebContents();
+  if (web_contents)
+    web_contents->Cut();
 }
 
 - (void)copy:(id)sender {
-  if (renderWidgetHostView_->render_widget_host_->IsRenderView()) {
-    static_cast<RenderViewHostImpl*>(
-        renderWidgetHostView_->render_widget_host_)->Copy();
-  }
+  WebContents* web_contents = renderWidgetHostView_->GetWebContents();
+  if (web_contents)
+    web_contents->Copy();
 }
 
 - (void)copyToFindPboard:(id)sender {
-  if (renderWidgetHostView_->render_widget_host_->IsRenderView()) {
-    static_cast<RenderViewHostImpl*>(
-        renderWidgetHostView_->render_widget_host_)->CopyToFindPboard();
-  }
+  WebContents* web_contents = renderWidgetHostView_->GetWebContents();
+  if (web_contents)
+    web_contents->CopyToFindPboard();
 }
 
 - (void)paste:(id)sender {
-  if (renderWidgetHostView_->render_widget_host_->IsRenderView()) {
-    static_cast<RenderViewHostImpl*>(
-        renderWidgetHostView_->render_widget_host_)->Paste();
-  }
+  WebContents* web_contents = renderWidgetHostView_->GetWebContents();
+  if (web_contents)
+    web_contents->Paste();
 }
 
 - (void)pasteAndMatchStyle:(id)sender {
-  if (renderWidgetHostView_->render_widget_host_->IsRenderView()) {
-    static_cast<RenderViewHostImpl*>(
-        renderWidgetHostView_->render_widget_host_)->PasteAndMatchStyle();
-  }
+  WebContents* web_contents = renderWidgetHostView_->GetWebContents();
+  if (web_contents)
+    web_contents->PasteAndMatchStyle();
 }
 
 - (void)selectAll:(id)sender {
@@ -3712,10 +4057,9 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
   // menu handler, neither is true.
   // Explicitly call SelectAll() here to make sure the renderer returns
   // selection results.
-  if (renderWidgetHostView_->render_widget_host_->IsRenderView()) {
-    static_cast<RenderViewHostImpl*>(
-        renderWidgetHostView_->render_widget_host_)->SelectAll();
-  }
+  WebContents* web_contents = renderWidgetHostView_->GetWebContents();
+  if (web_contents)
+    web_contents->SelectAll();
 }
 
 - (void)startSpeaking:(id)sender {
@@ -3748,7 +4092,7 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
 
   if (renderWidgetHostView_->render_widget_host_)
     renderWidgetHostView_->render_widget_host_->ImeConfirmComposition(
-        string16(), gfx::Range::InvalidRange(), false);
+        base::string16(), gfx::Range::InvalidRange(), false);
 
   [self cancelComposition];
 }
@@ -3761,7 +4105,7 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
   if (!active) {
     [[ComplexTextInputPanel sharedComplexTextInputPanel] cancelComposition];
     renderWidgetHostView_->PluginImeCompositionCompleted(
-        string16(), focusedPluginIdentifier_);
+        base::string16(), focusedPluginIdentifier_);
   }
 }
 
@@ -3796,7 +4140,7 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
   if (pluginImeActive_ &&
       ![[ComplexTextInputPanel sharedComplexTextInputPanel] inComposition]) {
     renderWidgetHostView_->PluginImeCompositionCompleted(
-        string16(), focusedPluginIdentifier_);
+        base::string16(), focusedPluginIdentifier_);
     pluginImeActive_ = NO;
   }
 }
@@ -3851,54 +4195,6 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
   renderWidgetHostView_->KillSelf();
 }
 
-- (void)updateSoftwareLayerScaleFactor {
-  if (![renderWidgetHostView_->software_layer_
-          respondsToSelector:@selector(setContentsScale:)])
-    return;
-
-  ScopedCAActionDisabler disabler;
-  [renderWidgetHostView_->software_layer_ setContentsScale:deviceScaleFactor_];
-}
-
-// Delegate methods for the software CALayer
-- (void)drawLayer:(CALayer*)layer
-        inContext:(CGContextRef)context {
-  TRACE_EVENT0("browser", "CompositingIOSurfaceLayer::drawLayer");
-
-  DCHECK(renderWidgetHostView_->use_core_animation_);
-  DCHECK([layer isEqual:renderWidgetHostView_->software_layer_]);
-
-  CGRect clipRect = CGContextGetClipBoundingBox(context);
-
-  if (!renderWidgetHostView_->render_widget_host_ ||
-      renderWidgetHostView_->render_widget_host_->is_hidden()) {
-    CGContextSetFillColorWithColor(context,
-                                   CGColorGetConstantColor(kCGColorWhite));
-    CGContextFillRect(context, clipRect);
-    return;
-  }
-
-  renderWidgetHostView_->about_to_validate_and_paint_ = true;
-  BackingStoreMac* backingStore = static_cast<BackingStoreMac*>(
-      renderWidgetHostView_->render_widget_host_->GetBackingStore(true));
-  renderWidgetHostView_->about_to_validate_and_paint_ = false;
-
-  [self drawBackingStore:backingStore
-               dirtyRect:clipRect
-               inContext:context];
-}
-
-- (void)setNeedsDisplay:(BOOL)flag {
-  [renderWidgetHostView_->software_layer_ setNeedsDisplay];
-  [super setNeedsDisplay:flag];
-}
-
-- (void)setNeedsDisplayInRect:(NSRect)rect {
-  [renderWidgetHostView_->software_layer_
-      setNeedsDisplayInRect:NSRectToCGRect(rect)];
-  [super setNeedsDisplayInRect:rect];
-}
-
 @end
 
 //
@@ -3935,4 +4231,58 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
   return [super isOpaque];
 }
 
+// "-webkit-app-region: drag | no-drag" is implemented on Mac by excluding
+// regions that are not draggable. (See ControlRegionView in
+// native_app_window_cocoa.mm). This requires the render host view to be
+// draggable by default.
+- (BOOL)mouseDownCanMoveWindow {
+  return YES;
+}
+
 @end
+
+@implementation SoftwareLayer
+
+- (id)initWithRenderWidgetHostViewMac:(content::RenderWidgetHostViewMac*)r {
+  if (self = [super init]) {
+    renderWidgetHostView_ = r;
+
+    [self setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
+    [self setAnchorPoint:CGPointMake(0, 0)];
+    // Setting contents gravity is necessary to prevent the layer from being
+    // scaled during dyanmic resizes (especially with devtools open).
+    [self setContentsGravity:kCAGravityTopLeft];
+    if (renderWidgetHostView_->software_frame_manager_->HasCurrentFrame() &&
+        [self respondsToSelector:(@selector(setContentsScale:))]) {
+      [self setContentsScale:renderWidgetHostView_->software_frame_manager_->
+          GetCurrentFrameDeviceScaleFactor()];
+    }
+
+    // Ensure that the transition between frames not be animated.
+    [self setActions:@{ @"contents" : [NSNull null] }];
+  }
+  return self;
+}
+
+- (void)drawInContext:(CGContextRef)context {
+  TRACE_EVENT0("browser", "SoftwareLayer::drawInContext");
+
+  CGRect clipRect = CGContextGetClipBoundingBox(context);
+  if (renderWidgetHostView_) {
+    [renderWidgetHostView_->cocoa_view() drawWithDirtyRect:clipRect
+                                                 inContext:context];
+  } else {
+    CGContextSetFillColorWithColor(context,
+                                   CGColorGetConstantColor(kCGColorWhite));
+    CGContextFillRect(context, clipRect);
+  }
+}
+
+- (void)disableRendering {
+  // Disable the fade-out animation as the layer is removed.
+  ScopedCAActionDisabler disabler;
+  [self removeFromSuperlayer];
+  renderWidgetHostView_ = nil;
+}
+
+@end  // implementation SoftwareLayer