Index: remoting/host/video_frame_capturer_mac_unittest.cc |
diff --git a/remoting/host/video_frame_capturer_mac_unittest.cc b/remoting/host/video_frame_capturer_mac_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0bd3e117306ce720211364ecd0a86bbc1ab9844a |
--- /dev/null |
+++ b/remoting/host/video_frame_capturer_mac_unittest.cc |
@@ -0,0 +1,155 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "remoting/host/video_frame_capturer.h" |
+ |
+#include <ApplicationServices/ApplicationServices.h> |
+ |
+#include <ostream> |
+ |
+#include "base/bind.h" |
+#include "base/callback.h" |
+#include "base/memory/scoped_ptr.h" |
+#include "remoting/base/capture_data.h" |
+#include "remoting/proto/control.pb.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace remoting { |
+ |
+// Verify that the OS is at least Snow Leopard (10.6). |
+// Chromoting doesn't support 10.5 or earlier. |
+bool CheckSnowLeopard() { |
+ long minorVersion, majorVersion; |
+ Gestalt(gestaltSystemVersionMajor, &majorVersion); |
+ Gestalt(gestaltSystemVersionMinor, &minorVersion); |
+ return majorVersion == 10 && minorVersion > 5; |
+} |
+ |
+class VideoFrameCapturerMacTest : public testing::Test { |
+ protected: |
+ virtual void SetUp() OVERRIDE { |
+ capturer_.reset(VideoFrameCapturer::Create()); |
+ } |
+ |
+ void AddDirtyRect() { |
+ SkIRect rect = SkIRect::MakeXYWH(0, 0, 10, 10); |
+ region_.op(rect, SkRegion::kUnion_Op); |
+ } |
+ |
+ scoped_ptr<VideoFrameCapturer> capturer_; |
+ SkRegion region_; |
+}; |
+ |
+// CapturerCallback1 verifies that the whole screen is initially dirty. |
+class VideoFrameCapturerCallback1 { |
+ public: |
+ VideoFrameCapturerCallback1() {} |
+ |
+ void CaptureDoneCallback(scoped_refptr<CaptureData> capture_data); |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(VideoFrameCapturerCallback1); |
+}; |
+ |
+void VideoFrameCapturerCallback1::CaptureDoneCallback( |
+ scoped_refptr<CaptureData> capture_data) { |
+ CGDirectDisplayID mainDevice = CGMainDisplayID(); |
+ int width = CGDisplayPixelsWide(mainDevice); |
+ int height = CGDisplayPixelsHigh(mainDevice); |
+ SkRegion initial_region(SkIRect::MakeXYWH(0, 0, width, height)); |
+ EXPECT_EQ(initial_region, capture_data->dirty_region()); |
+} |
+ |
+// VideoFrameCapturerCallback2 verifies that a rectangle explicitly marked as |
+// dirty is propagated correctly. |
+class VideoFrameCapturerCallback2 { |
+ public: |
+ explicit VideoFrameCapturerCallback2(const SkRegion& expected_dirty_region) |
+ : expected_dirty_region_(expected_dirty_region) {} |
+ |
+ void CaptureDoneCallback(scoped_refptr<CaptureData> capture_data); |
+ |
+ protected: |
+ SkRegion expected_dirty_region_; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(VideoFrameCapturerCallback2); |
+}; |
+ |
+void VideoFrameCapturerCallback2::CaptureDoneCallback( |
+ scoped_refptr<CaptureData> capture_data) { |
+ CGDirectDisplayID mainDevice = CGMainDisplayID(); |
+ int width = CGDisplayPixelsWide(mainDevice); |
+ int height = CGDisplayPixelsHigh(mainDevice); |
+ |
+ EXPECT_EQ(expected_dirty_region_, capture_data->dirty_region()); |
+ EXPECT_EQ(width, capture_data->size().width()); |
+ EXPECT_EQ(height, capture_data->size().height()); |
+ const DataPlanes &planes = capture_data->data_planes(); |
+ EXPECT_TRUE(planes.data[0] != NULL); |
+ EXPECT_TRUE(planes.data[1] == NULL); |
+ EXPECT_TRUE(planes.data[2] == NULL); |
+ // Depending on the capture method, the screen may be flipped or not, so |
+ // the stride may be positive or negative. |
+ EXPECT_EQ(static_cast<int>(sizeof(uint32_t) * width), |
+ abs(planes.strides[0])); |
+ EXPECT_EQ(0, planes.strides[1]); |
+ EXPECT_EQ(0, planes.strides[2]); |
+} |
+ |
+class CursorCallback { |
+ public: |
+ CursorCallback() {} |
+ |
+ void CursorShapeChangedCallback( |
+ scoped_ptr<protocol::CursorShapeInfo> cursor_data); |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(CursorCallback); |
+}; |
+ |
+void CursorCallback::CursorShapeChangedCallback( |
+ scoped_ptr<protocol::CursorShapeInfo> cursor_data) { |
+} |
+ |
+TEST_F(VideoFrameCapturerMacTest, Capture) { |
+ if (!CheckSnowLeopard()) { |
+ return; |
+ } |
+ |
+ SCOPED_TRACE(""); |
+ CursorCallback cursor_callback; |
+ capturer_->Start(base::Bind(&CursorCallback::CursorShapeChangedCallback, |
+ base::Unretained(&cursor_callback))); |
+ // Check that we get an initial full-screen updated. |
+ VideoFrameCapturerCallback1 callback1; |
+ capturer_->CaptureInvalidRegion(base::Bind( |
+ &VideoFrameCapturerCallback1::CaptureDoneCallback, |
+ base::Unretained(&callback1))); |
+ // Check that subsequent dirty rects are propagated correctly. |
+ AddDirtyRect(); |
+ VideoFrameCapturerCallback2 callback2(region_); |
+ capturer_->InvalidateRegion(region_); |
+ capturer_->CaptureInvalidRegion(base::Bind( |
+ &VideoFrameCapturerCallback2::CaptureDoneCallback, |
+ base::Unretained(&callback2))); |
+ capturer_->Stop(); |
+} |
+ |
+} // namespace remoting |
+ |
+namespace gfx { |
+ |
+std::ostream& operator<<(std::ostream& out, const SkRegion& region) { |
+ out << "SkRegion("; |
+ for (SkRegion::Iterator i(region); !i.done(); i.next()) { |
+ const SkIRect& r = i.rect(); |
+ out << "(" << r.fLeft << "," << r.fTop << "," |
+ << r.fRight << "," << r.fBottom << ")"; |
+ } |
+ out << ")"; |
+ return out; |
+} |
+ |
+} // namespace gfx |