Commit ac030e20 authored by noel's avatar noel Committed by Commit bot

ui/gfx/color_profile: implement GetDisplayColorProfile on mac

Like https://codereview.chromium.org/312723003 for win32, extract
the display color profile associated with a screen display device
on mac given rectangular bounds in screen coordinates.

Use gfx::ScreenRectFromNSRect to compute the screen that overlaps
the bounds most to match the gfx::Screen concept of overlap.

Add unit tests for on-screen, partially-on-screen, off-screen and
empty bounds.

Note an sRGB color profile is a common case, especially on win32,
so GetDisplayColorProfile returns true and an empty color profile
in that case. Add a header file comment about that.

TEST=gfx_unittests --gtest_filter="ColorProfileTest*Bounds"
BUG=368694

Review URL: https://codereview.chromium.org/612613002

Cr-Commit-Position: refs/heads/master@{#299253}
parent 04e2c855
...@@ -434,6 +434,7 @@ test("gfx_unittests") { ...@@ -434,6 +434,7 @@ test("gfx_unittests") {
"codec/jpeg_codec_unittest.cc", "codec/jpeg_codec_unittest.cc",
"codec/png_codec_unittest.cc", "codec/png_codec_unittest.cc",
"color_analysis_unittest.cc", "color_analysis_unittest.cc",
"color_profile_mac_unittest.mm",
"color_utils_unittest.cc", "color_utils_unittest.cc",
"display_change_notifier_unittest.cc", "display_change_notifier_unittest.cc",
"display_unittest.cc", "display_unittest.cc",
......
...@@ -17,7 +17,7 @@ static const size_t kMaxProfileLength = 4 * 1024 * 1024; ...@@ -17,7 +17,7 @@ static const size_t kMaxProfileLength = 4 * 1024 * 1024;
class GFX_EXPORT ColorProfile { class GFX_EXPORT ColorProfile {
public: public:
// On Windows, this reads a file from disk so it shouldn't be run on the UI // On Windows, this reads a file from disk so it should not be run on the UI
// or IO thread. // or IO thread.
ColorProfile(); ColorProfile();
~ColorProfile(); ~ColorProfile();
...@@ -35,9 +35,11 @@ inline bool InvalidColorProfileLength(size_t length) { ...@@ -35,9 +35,11 @@ inline bool InvalidColorProfileLength(size_t length) {
} }
// Return the color profile of the display nearest the screen bounds. On Win32, // Return the color profile of the display nearest the screen bounds. On Win32,
// this may read a file from disk, so it shouldn't be run on the UI/IO threads. // this may read a file from disk so it should not be run on the UI/IO threads.
// If the given bounds are empty, or are off-screen, return false meaning there // If the given bounds are empty, or are off-screen, return false meaning there
// is no color profile associated with the bounds. // is no color profile associated with the bounds. Otherwise return true after
// storing the display's color profile in |profile|, which will be empty if the
// standard sRGB color profile should be assumed.
GFX_EXPORT bool GetDisplayColorProfile(const gfx::Rect& bounds, GFX_EXPORT bool GetDisplayColorProfile(const gfx::Rect& bounds,
std::vector<char>* profile); std::vector<char>* profile);
} // namespace gfx } // namespace gfx
......
...@@ -4,16 +4,53 @@ ...@@ -4,16 +4,53 @@
#include "ui/gfx/color_profile.h" #include "ui/gfx/color_profile.h"
#import <Cocoa/Cocoa.h>
#include "base/mac/mac_util.h" #include "base/mac/mac_util.h"
#include "ui/gfx/mac/coordinate_conversion.h"
namespace {
NSScreen* GetNSScreenFromBounds(const gfx::Rect& bounds) {
NSScreen* screen = nil;
int overlap = 0;
for (NSScreen* monitor in [NSScreen screens]) {
gfx::Rect monitor_rect = gfx::ScreenRectFromNSRect([monitor frame]);
gfx::Rect overlap_rect = gfx::IntersectRects(monitor_rect, bounds);
int overlap_size = overlap_rect.width() * overlap_rect.height();
if (overlap_size > overlap) {
overlap = overlap_size;
screen = monitor;
}
}
return screen;
}
} // namespace
namespace gfx { namespace gfx {
bool GetDisplayColorProfile(const gfx::Rect& bounds, bool GetDisplayColorProfile(const gfx::Rect& bounds,
std::vector<char>* profile) { std::vector<char>* profile) {
if (bounds.IsEmpty()) DCHECK(profile->empty());
NSScreen* screen = GetNSScreenFromBounds(bounds);
if (!screen || bounds.IsEmpty())
return false; return false;
// TODO(noel): implement. NSColorSpace* color_space = [screen colorSpace];
return false; if (!color_space)
return false;
if ([color_space isEqual:[NSColorSpace sRGBColorSpace]])
return true;
NSData* profile_data = [color_space ICCProfileData];
const char* data = static_cast<const char*>([profile_data bytes]);
size_t length = [profile_data length];
if (data && !gfx::InvalidColorProfileLength(length))
profile->assign(data, data + length);
return true;
} }
void ReadColorProfile(std::vector<char>* profile) { void ReadColorProfile(std::vector<char>* profile) {
......
// Copyright 2014 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.
#import <Cocoa/Cocoa.h>
#include "base/mac/scoped_nsobject.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/color_profile.h"
#include "ui/gfx/mac/coordinate_conversion.h"
#import "ui/gfx/test/ui_cocoa_test_helper.h"
namespace {
class ColorProfileTest : public ui::CocoaTest {
public:
virtual void SetUp() override {
ui::CocoaTest::SetUp();
// Verify the primary screen origin.
NSRect primary_screen_frame = PrimaryScreenFrame();
EXPECT_EQ(0, primary_screen_frame.origin.x);
EXPECT_EQ(0, primary_screen_frame.origin.y);
// Move the test window onto the screen.
MoveTestWindowTo(gfx::Rect(0, 0, 200, 200));
// Verify it is contained by the screen.
BOOL screen_contains_test_window = NSContainsRect(
primary_screen_frame, [test_window() frame]);
EXPECT_TRUE(screen_contains_test_window);
}
void MoveTestWindowTo(gfx::Rect bounds) {
[test_window() setFrame:gfx::ScreenRectToNSRect(bounds) display:NO];
EXPECT_EQ(bounds.ToString(), TestWindowBounds().ToString());
}
gfx::Rect TestWindowBounds() {
return gfx::ScreenRectFromNSRect([test_window() frame]);
}
BOOL TestWindowOnScreen() {
return NSIntersectsRect(PrimaryScreenFrame(), [test_window() frame]);
}
BOOL TestWindowContainedOnScreen() {
return NSContainsRect(PrimaryScreenFrame(), [test_window() frame]);
}
NSRect PrimaryScreenFrame() {
return [[[NSScreen screens] objectAtIndex:0] frame];
}
};
bool TestColorProfileForBounds(const gfx::Rect& bounds) {
std::vector<char> color_profile;
return gfx::GetDisplayColorProfile(bounds, &color_profile);
}
TEST_F(ColorProfileTest, GetDisplayColorProfileForOnScreenBounds) {
MoveTestWindowTo(gfx::Rect(10, 10, 100, 100));
EXPECT_FALSE(TestWindowBounds().IsEmpty());
EXPECT_TRUE(TestWindowContainedOnScreen());
EXPECT_TRUE(TestColorProfileForBounds(TestWindowBounds()));
}
TEST_F(ColorProfileTest, GetDisplayColorProfileForPartiallyOnScreenBounds) {
MoveTestWindowTo(gfx::Rect(-50, -50, 80, 80));
EXPECT_FALSE(TestWindowBounds().IsEmpty());
EXPECT_TRUE(TestWindowOnScreen());
EXPECT_TRUE(TestColorProfileForBounds(TestWindowBounds()));
}
TEST_F(ColorProfileTest, GetDisplayColorProfileForOffScreenBounds) {
MoveTestWindowTo(gfx::Rect(-100, -100, 10, 10));
EXPECT_FALSE(TestWindowBounds().IsEmpty());
EXPECT_FALSE(TestWindowOnScreen());
EXPECT_FALSE(TestColorProfileForBounds(TestWindowBounds()));
}
TEST_F(ColorProfileTest, GetDisplayColorProfileForEmptyOnScreenBounds) {
MoveTestWindowTo(gfx::Rect(10, 10, 0, 0));
EXPECT_TRUE(TestWindowBounds().IsEmpty());
EXPECT_FALSE(TestWindowOnScreen());
EXPECT_FALSE(TestColorProfileForBounds(TestWindowBounds()));
}
TEST_F(ColorProfileTest, GetDisplayColorProfileForEmptyOffScreenBounds) {
MoveTestWindowTo(gfx::Rect(-100, -100, 0, 0));
EXPECT_TRUE(TestWindowBounds().IsEmpty());
EXPECT_FALSE(TestWindowOnScreen());
EXPECT_FALSE(TestColorProfileForBounds(TestWindowBounds()));
}
} // namespace
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
'codec/jpeg_codec_unittest.cc', 'codec/jpeg_codec_unittest.cc',
'codec/png_codec_unittest.cc', 'codec/png_codec_unittest.cc',
'color_analysis_unittest.cc', 'color_analysis_unittest.cc',
'color_profile_mac_unittest.mm',
'color_utils_unittest.cc', 'color_utils_unittest.cc',
'display_change_notifier_unittest.cc', 'display_change_notifier_unittest.cc',
'display_unittest.cc', 'display_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment