Home | History | Annotate | Download | only in renderer_host
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
      6 
      7 #include "base/mac/scoped_nsautorelease_pool.h"
      8 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
      9 #include "chrome/browser/ui/cocoa/test_event_utils.h"
     10 #include "content/browser/browser_thread.h"
     11 #include "content/browser/renderer_host/test_render_view_host.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 #include "webkit/plugins/npapi/webplugin.h"
     14 
     15 class RenderWidgetHostViewMacTest : public RenderViewHostTestHarness {
     16  public:
     17   RenderWidgetHostViewMacTest() : old_rwhv_(NULL), rwhv_mac_(NULL) {}
     18 
     19   virtual void SetUp() {
     20     // Set up Cocoa.
     21     [CrApplication sharedApplication];
     22 
     23     RenderViewHostTestHarness::SetUp();
     24 
     25     // TestRenderViewHost's destruction assumes that its view is a
     26     // TestRenderWidgetHostView, so store its view and reset it back to the
     27     // stored view in |TearDown()|.
     28     old_rwhv_ = rvh()->view();
     29 
     30     // Owned by its |native_view()|, i.e. |rwhv_cocoa_|.
     31     rwhv_mac_ = new RenderWidgetHostViewMac(rvh());
     32     rwhv_cocoa_.reset([rwhv_mac_->native_view() retain]);
     33   }
     34   virtual void TearDown() {
     35     // See comment in SetUp().
     36     rvh()->set_view(old_rwhv_);
     37 
     38     // Make sure the rwhv_mac_ is gone once the superclass's |TearDown()| runs.
     39     rwhv_cocoa_.reset();
     40     pool_.Recycle();
     41     MessageLoop::current()->RunAllPending();
     42     pool_.Recycle();
     43 
     44     RenderViewHostTestHarness::TearDown();
     45   }
     46  protected:
     47   // Adds an accelerated plugin view to |rwhv_cocoa_|.  Returns a handle to the
     48   // newly-added view.  Callers must ensure that a UI thread is present and
     49   // running before calling this function.
     50   gfx::PluginWindowHandle AddAcceleratedPluginView(int w, int h) {
     51     // Create an accelerated view the size of the rhwvmac.
     52     [rwhv_cocoa_.get() setFrame:NSMakeRect(0, 0, w, h)];
     53     gfx::PluginWindowHandle accelerated_handle =
     54         rwhv_mac_->AllocateFakePluginWindowHandle(/*opaque=*/false,
     55                                                   /*root=*/false);
     56     rwhv_mac_->AcceleratedSurfaceSetIOSurface(accelerated_handle, w, h, 0);
     57 
     58     // The accelerated view isn't shown until it has a valid rect and has been
     59     // painted to.
     60     rwhv_mac_->AcceleratedSurfaceBuffersSwapped(accelerated_handle,
     61                                                 0, 0, 0, 0, 0);
     62     webkit::npapi::WebPluginGeometry geom;
     63     gfx::Rect rect(0, 0, w, h);
     64     geom.window = accelerated_handle;
     65     geom.window_rect = rect;
     66     geom.clip_rect = rect;
     67     geom.visible = true;
     68     geom.rects_valid = true;
     69     rwhv_mac_->MovePluginWindows(
     70         std::vector<webkit::npapi::WebPluginGeometry>(1, geom));
     71 
     72     return accelerated_handle;
     73   }
     74  private:
     75   // This class isn't derived from PlatformTest.
     76   base::mac::ScopedNSAutoreleasePool pool_;
     77 
     78   RenderWidgetHostView* old_rwhv_;
     79 
     80  protected:
     81   RenderWidgetHostViewMac* rwhv_mac_;
     82   scoped_nsobject<RenderWidgetHostViewCocoa> rwhv_cocoa_;
     83 
     84  private:
     85   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewMacTest);
     86 };
     87 
     88 TEST_F(RenderWidgetHostViewMacTest, Basic) {
     89 }
     90 
     91 // Regression test for http://crbug.com/60318
     92 TEST_F(RenderWidgetHostViewMacTest, FocusAcceleratedView) {
     93   // The accelerated view methods want to be called on the UI thread.
     94   scoped_ptr<BrowserThread> ui_thread_(
     95       new BrowserThread(BrowserThread::UI, MessageLoop::current()));
     96 
     97   int w = 400, h = 300;
     98   gfx::PluginWindowHandle accelerated_handle = AddAcceleratedPluginView(w, h);
     99   EXPECT_FALSE([rwhv_cocoa_.get() isHidden]);
    100   NSView* accelerated_view = static_cast<NSView*>(
    101       rwhv_mac_->ViewForPluginWindowHandle(accelerated_handle));
    102   EXPECT_FALSE([accelerated_view isHidden]);
    103 
    104   // Take away first responder from the rwhvmac, then simulate the effect of a
    105   // click on the accelerated view. The rwhvmac should be first responder
    106   // again.
    107   scoped_nsobject<NSWindow> window([[CocoaTestHelperWindow alloc] init]);
    108   scoped_nsobject<NSView> other_view(
    109       [[NSTextField alloc] initWithFrame:NSMakeRect(0, h, w, 40)]);
    110   [[window contentView] addSubview:rwhv_cocoa_.get()];
    111   [[window contentView] addSubview:other_view.get()];
    112 
    113   EXPECT_TRUE([rwhv_cocoa_.get() acceptsFirstResponder]);
    114   [window makeFirstResponder:rwhv_cocoa_.get()];
    115   EXPECT_EQ(rwhv_cocoa_.get(), [window firstResponder]);
    116   EXPECT_FALSE([accelerated_view acceptsFirstResponder]);
    117 
    118   EXPECT_TRUE([other_view acceptsFirstResponder]);
    119   [window makeFirstResponder:other_view];
    120   EXPECT_NE(rwhv_cocoa_.get(), [window firstResponder]);
    121 
    122   EXPECT_TRUE([accelerated_view acceptsFirstResponder]);
    123   [window makeFirstResponder:accelerated_view];
    124   EXPECT_EQ(rwhv_cocoa_.get(), [window firstResponder]);
    125 
    126   // Clean up.
    127   rwhv_mac_->DestroyFakePluginWindowHandle(accelerated_handle);
    128 }
    129 
    130 TEST_F(RenderWidgetHostViewMacTest, AcceptsFirstResponder) {
    131   // The RWHVCocoa should normally accept first responder status.
    132   EXPECT_TRUE([rwhv_cocoa_.get() acceptsFirstResponder]);
    133 
    134   // Unless we tell it not to.
    135   rwhv_mac_->SetTakesFocusOnlyOnMouseDown(true);
    136   EXPECT_FALSE([rwhv_cocoa_.get() acceptsFirstResponder]);
    137 
    138   // But we can set things back to the way they were originally.
    139   rwhv_mac_->SetTakesFocusOnlyOnMouseDown(false);
    140   EXPECT_TRUE([rwhv_cocoa_.get() acceptsFirstResponder]);
    141 }
    142 
    143 TEST_F(RenderWidgetHostViewMacTest, TakesFocusOnMouseDown) {
    144   scoped_nsobject<CocoaTestHelperWindow>
    145       window([[CocoaTestHelperWindow alloc] init]);
    146   [[window contentView] addSubview:rwhv_cocoa_.get()];
    147 
    148   // Even if the RWHVCocoa disallows first responder, clicking on it gives it
    149   // focus.
    150   [window setPretendIsKeyWindow:YES];
    151   [window makeFirstResponder:nil];
    152   ASSERT_NE(rwhv_cocoa_.get(), [window firstResponder]);
    153 
    154   rwhv_mac_->SetTakesFocusOnlyOnMouseDown(true);
    155   EXPECT_FALSE([rwhv_cocoa_.get() acceptsFirstResponder]);
    156 
    157   std::pair<NSEvent*, NSEvent*> clicks =
    158       test_event_utils::MouseClickInView(rwhv_cocoa_.get(), 1);
    159   [rwhv_cocoa_.get() mouseDown:clicks.first];
    160   EXPECT_EQ(rwhv_cocoa_.get(), [window firstResponder]);
    161 }
    162 
    163 // Regression test for http://crbug.com/64256
    164 TEST_F(RenderWidgetHostViewMacTest, TakesFocusOnMouseDownWithAcceleratedView) {
    165   // The accelerated view methods want to be called on the UI thread.
    166   scoped_ptr<BrowserThread> ui_thread_(
    167       new BrowserThread(BrowserThread::UI, MessageLoop::current()));
    168 
    169   int w = 400, h = 300;
    170   gfx::PluginWindowHandle accelerated_handle = AddAcceleratedPluginView(w, h);
    171   EXPECT_FALSE([rwhv_cocoa_.get() isHidden]);
    172   NSView* accelerated_view = static_cast<NSView*>(
    173       rwhv_mac_->ViewForPluginWindowHandle(accelerated_handle));
    174   EXPECT_FALSE([accelerated_view isHidden]);
    175 
    176   // Add the RWHVCocoa to the window and remove first responder status.
    177   scoped_nsobject<CocoaTestHelperWindow>
    178       window([[CocoaTestHelperWindow alloc] init]);
    179   [[window contentView] addSubview:rwhv_cocoa_.get()];
    180   [window setPretendIsKeyWindow:YES];
    181   [window makeFirstResponder:nil];
    182   EXPECT_NE(rwhv_cocoa_.get(), [window firstResponder]);
    183 
    184   // Tell the RWHVMac to not accept first responder status.  The accelerated
    185   // view should also stop accepting first responder.
    186   rwhv_mac_->SetTakesFocusOnlyOnMouseDown(true);
    187   EXPECT_FALSE([accelerated_view acceptsFirstResponder]);
    188 
    189   // A click on the accelerated view should focus the RWHVCocoa.
    190   std::pair<NSEvent*, NSEvent*> clicks =
    191       test_event_utils::MouseClickInView(accelerated_view, 1);
    192   [rwhv_cocoa_.get() mouseDown:clicks.first];
    193   EXPECT_EQ(rwhv_cocoa_.get(), [window firstResponder]);
    194 
    195   // Clean up.
    196   rwhv_mac_->DestroyFakePluginWindowHandle(accelerated_handle);
    197 }
    198