diff options
author | erg@chromium.org <erg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-25 21:32:21 +0000 |
---|---|---|
committer | erg@chromium.org <erg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-25 21:32:21 +0000 |
commit | c68f03565460122348c5a437b814f85f58ee04d5 (patch) | |
tree | e241a28fe68483d864277663c6dfd901a4ec9bab /chromeos | |
parent | 769e94ab4f20554bd0ae0c2be5ad2654a62ce16b (diff) | |
download | chromium_src-c68f03565460122348c5a437b814f85f58ee04d5.zip chromium_src-c68f03565460122348c5a437b814f85f58ee04d5.tar.gz chromium_src-c68f03565460122348c5a437b814f85f58ee04d5.tar.bz2 |
Reland linux_aura: Implement most of DesktopScreenX11.
[[Making changes to '_toolset=="target"' section in system.gyp to fix
cros compiling.]]
The linux_aura port didn't deal with multiple monitors very well because
it was treating the X root window as one big display. When xrandr is
present, get the screen areas from it, and exposes this data back to
chrome.
This patch also factors out the EDID parser than chromeos was using into
a common directory. Like chromeos, we use it to assign stable display
IDs.
BUG=287972
TBR=brettw@chromium.org, derat@chromium.org, sky@chromium.org
First Review URL: https://codereview.chromium.org/23536057
Review URL: https://codereview.chromium.org/24459002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@225254 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos')
-rw-r--r-- | chromeos/display/output_util.cc | 191 | ||||
-rw-r--r-- | chromeos/display/output_util.h | 22 | ||||
-rw-r--r-- | chromeos/display/output_util_unittest.cc | 108 | ||||
-rw-r--r-- | chromeos/display/real_output_configurator_delegate.cc | 3 |
4 files changed, 8 insertions, 316 deletions
diff --git a/chromeos/display/output_util.cc b/chromeos/display/output_util.cc index 5e223c5..a1485b4 100644 --- a/chromeos/display/output_util.cc +++ b/chromeos/display/output_util.cc @@ -4,14 +4,12 @@ #include "chromeos/display/output_util.h" -#include <X11/Xlib.h> #include <X11/extensions/Xrandr.h> #include <X11/Xatom.h> +#include <X11/Xlib.h> -#include "base/hash.h" -#include "base/message_loop/message_loop.h" #include "base/strings/string_util.h" -#include "base/sys_byteorder.h" +#include "base/x11/edid_parser_x11.h" namespace chromeos { namespace { @@ -21,78 +19,6 @@ const char kInternal_LVDS[] = "LVDS"; const char kInternal_eDP[] = "eDP"; const char kInternal_DSI[] = "DSI"; -// Returns 64-bit persistent ID for the specified manufacturer's ID and -// product_code_hash, and the index of the output it is connected to. -// |output_index| is used to distinguish the displays of the same type. For -// example, swapping two identical display between two outputs will not be -// treated as swap. The 'serial number' field in EDID isn't used here because -// it is not guaranteed to have unique number and it may have the same fixed -// value (like 0). -int64 GetID(uint16 manufacturer_id, - uint32 product_code_hash, - uint8 output_index) { - return ((static_cast<int64>(manufacturer_id) << 40) | - (static_cast<int64>(product_code_hash) << 8) | output_index); -} - -bool IsRandRAvailable() { - int randr_version_major = 0; - int randr_version_minor = 0; - static bool is_randr_available = XRRQueryVersion( - base::MessagePumpX11::GetDefaultXDisplay(), - &randr_version_major, &randr_version_minor); - return is_randr_available; -} - -// Get the EDID data from the |output| and stores to |prop|. |nitem| will store -// the number of characters |prop| will have. It doesn't take the ownership of -// |prop|, so caller must release it by XFree(). -// Returns true if EDID property is successfully obtained. Otherwise returns -// false and does not touch |prop| and |nitems|. -bool GetEDIDProperty(XID output, unsigned long* nitems, unsigned char** prop) { - if (!IsRandRAvailable()) - return false; - - Display* display = base::MessagePumpX11::GetDefaultXDisplay(); - - static Atom edid_property = XInternAtom( - base::MessagePumpX11::GetDefaultXDisplay(), - RR_PROPERTY_RANDR_EDID, false); - - bool has_edid_property = false; - int num_properties = 0; - Atom* properties = XRRListOutputProperties(display, output, &num_properties); - for (int i = 0; i < num_properties; ++i) { - if (properties[i] == edid_property) { - has_edid_property = true; - break; - } - } - XFree(properties); - if (!has_edid_property) - return false; - - Atom actual_type; - int actual_format; - unsigned long bytes_after; - XRRGetOutputProperty(display, - output, - edid_property, - 0, // offset - 128, // length - false, // _delete - false, // pending - AnyPropertyType, // req_type - &actual_type, - &actual_format, - nitems, - &bytes_after, - prop); - DCHECK_EQ(XA_INTEGER, actual_type); - DCHECK_EQ(8, actual_format); - return true; -} - // Gets some useful data from the specified output device, such like // manufacturer's ID, product code, and human readable name. Returns false if it // fails to get those data and doesn't touch manufacturer ID/product code/name. @@ -102,10 +28,10 @@ bool GetOutputDeviceData(XID output, std::string* human_readable_name) { unsigned long nitems = 0; unsigned char *prop = NULL; - if (!GetEDIDProperty(output, &nitems, &prop)) + if (!base::GetEDIDProperty(output, &nitems, &prop)) return false; - bool result = ParseOutputDeviceData( + bool result = base::ParseOutputDeviceData( prop, nitems, manufacturer_id, human_readable_name); XFree(prop); return result; @@ -119,117 +45,10 @@ std::string GetDisplayName(XID output_id) { return display_name; } -bool GetDisplayId(XID output_id, size_t output_index, int64* display_id_out) { - unsigned long nitems = 0; - unsigned char* prop = NULL; - if (!GetEDIDProperty(output_id, &nitems, &prop)) - return false; - - bool result = - GetDisplayIdFromEDID(prop, nitems, output_index, display_id_out); - XFree(prop); - return result; -} - -bool GetDisplayIdFromEDID(const unsigned char* prop, - unsigned long nitems, - size_t output_index, - int64* display_id_out) { - uint16 manufacturer_id = 0; - std::string product_name; - - // ParseOutputDeviceData fails if it doesn't have product_name. - ParseOutputDeviceData(prop, nitems, &manufacturer_id, &product_name); - - // Generates product specific value from product_name instead of product code. - // See crbug.com/240341 - uint32 product_code_hash = product_name.empty() ? - 0 : base::Hash(product_name); - if (manufacturer_id != 0) { - // An ID based on display's index will be assigned later if this call - // fails. - *display_id_out = GetID( - manufacturer_id, product_code_hash, output_index); - return true; - } - return false; -} - -bool ParseOutputDeviceData(const unsigned char* prop, - unsigned long nitems, - uint16* manufacturer_id, - std::string* human_readable_name) { - // See http://en.wikipedia.org/wiki/Extended_display_identification_data - // for the details of EDID data format. We use the following data: - // bytes 8-9: manufacturer EISA ID, in big-endian - // bytes 54-125: four descriptors (18-bytes each) which may contain - // the display name. - const unsigned int kManufacturerOffset = 8; - const unsigned int kManufacturerLength = 2; - const unsigned int kDescriptorOffset = 54; - const unsigned int kNumDescriptors = 4; - const unsigned int kDescriptorLength = 18; - // The specifier types. - const unsigned char kMonitorNameDescriptor = 0xfc; - - if (manufacturer_id) { - if (nitems < kManufacturerOffset + kManufacturerLength) { - LOG(ERROR) << "too short EDID data: manifacturer id"; - return false; - } - - *manufacturer_id = - *reinterpret_cast<const uint16*>(prop + kManufacturerOffset); -#if defined(ARCH_CPU_LITTLE_ENDIAN) - *manufacturer_id = base::ByteSwap(*manufacturer_id); -#endif - } - - if (!human_readable_name) - return true; - - human_readable_name->clear(); - for (unsigned int i = 0; i < kNumDescriptors; ++i) { - if (nitems < kDescriptorOffset + (i + 1) * kDescriptorLength) - break; - - const unsigned char* desc_buf = - prop + kDescriptorOffset + i * kDescriptorLength; - // If the descriptor contains the display name, it has the following - // structure: - // bytes 0-2, 4: \0 - // byte 3: descriptor type, defined above. - // bytes 5-17: text data, ending with \r, padding with spaces - // we should check bytes 0-2 and 4, since it may have other values in - // case that the descriptor contains other type of data. - if (desc_buf[0] == 0 && desc_buf[1] == 0 && desc_buf[2] == 0 && - desc_buf[4] == 0) { - if (desc_buf[3] == kMonitorNameDescriptor) { - std::string found_name( - reinterpret_cast<const char*>(desc_buf + 5), kDescriptorLength - 5); - TrimWhitespaceASCII(found_name, TRIM_TRAILING, human_readable_name); - break; - } - } - } - - // Verify if the |human_readable_name| consists of printable characters only. - for (size_t i = 0; i < human_readable_name->size(); ++i) { - char c = (*human_readable_name)[i]; - if (!isascii(c) || !isprint(c)) { - human_readable_name->clear(); - LOG(ERROR) << "invalid EDID: human unreadable char in name"; - return false; - } - } - - return true; -} - bool GetOutputOverscanFlag(XID output, bool* flag) { unsigned long nitems = 0; unsigned char *prop = NULL; - if (!GetEDIDProperty(output, &nitems, &prop)) + if (!base::GetEDIDProperty(output, &nitems, &prop)) return false; bool found = ParseOutputOverscanFlag(prop, nitems, flag); diff --git a/chromeos/display/output_util.h b/chromeos/display/output_util.h index d2f1f01..3c7a49f 100644 --- a/chromeos/display/output_util.h +++ b/chromeos/display/output_util.h @@ -23,19 +23,6 @@ typedef _XRROutputInfo XRROutputInfo; namespace chromeos { -// Gets the EDID data from |output| and generates the display id through -// |GetDisplayIdFromEDID|. -CHROMEOS_EXPORT bool GetDisplayId(XID output, size_t index, - int64* display_id_out); - -// Generates the display id for the pair of |prop| with |nitems| length and -// |index|, and store in |display_id_out|. Returns true if the display id is -// successfully generated, or false otherwise. -CHROMEOS_EXPORT bool GetDisplayIdFromEDID(const unsigned char* prop, - unsigned long nitems, - size_t index, - int64* display_id_out); - // Generates the human readable string from EDID obtained for |output|. CHROMEOS_EXPORT std::string GetDisplayName(XID output); @@ -46,15 +33,6 @@ CHROMEOS_EXPORT std::string GetDisplayName(XID output); // false. CHROMEOS_EXPORT bool GetOutputOverscanFlag(XID output, bool* flag); -// Parses |prop| as EDID data and stores extracted data into |manufacturer_id| -// and |human_readable_name| and returns true. NULL can be passed for unwanted -// output parameters. Some devices (especially internal displays) may not have -// the field for |human_readable_name|, and it will return true in that case. -CHROMEOS_EXPORT bool ParseOutputDeviceData(const unsigned char* prop, - unsigned long nitems, - uint16* manufacturer_id, - std::string* human_readable_name); - // Parses |prop| as EDID data and stores the overscan flag to |flag|. Returns // true if the flag is found. This is exported for x11_util_unittest.cc. CHROMEOS_EXPORT bool ParseOutputOverscanFlag(const unsigned char* prop, diff --git a/chromeos/display/output_util_unittest.cc b/chromeos/display/output_util_unittest.cc index 9c72d7b..1229b4f 100644 --- a/chromeos/display/output_util_unittest.cc +++ b/chromeos/display/output_util_unittest.cc @@ -75,90 +75,7 @@ const unsigned char kMisdetecedDisplay[] = "\x0a\xd0\x8a\x20\xe0\x2d\x10\x10\x3e\x96\x00\x81\x91\x21\x00\x00" "\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x94"; -} - -const unsigned char kLP2565A[] = - "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x22\xF0\x76\x26\x01\x01\x01\x01" - "\x02\x12\x01\x03\x80\x34\x21\x78\xEE\xEF\x95\xA3\x54\x4C\x9B\x26" - "\x0F\x50\x54\xA5\x6B\x80\x81\x40\x81\x80\x81\x99\x71\x00\xA9\x00" - "\xA9\x40\xB3\x00\xD1\x00\x28\x3C\x80\xA0\x70\xB0\x23\x40\x30\x20" - "\x36\x00\x07\x44\x21\x00\x00\x1A\x00\x00\x00\xFD\x00\x30\x55\x1E" - "\x5E\x11\x00\x0A\x20\x20\x20\x20\x20\x20\x00\x00\x00\xFC\x00\x48" - "\x50\x20\x4C\x50\x32\x34\x36\x35\x0A\x20\x20\x20\x00\x00\x00\xFF" - "\x00\x43\x4E\x4B\x38\x30\x32\x30\x34\x48\x4D\x0A\x20\x20\x00\xA4"; - -const unsigned char kLP2565B[] = - "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x22\xF0\x75\x26\x01\x01\x01\x01" - "\x02\x12\x01\x03\x6E\x34\x21\x78\xEE\xEF\x95\xA3\x54\x4C\x9B\x26" - "\x0F\x50\x54\xA5\x6B\x80\x81\x40\x71\x00\xA9\x00\xA9\x40\xA9\x4F" - "\xB3\x00\xD1\xC0\xD1\x00\x28\x3C\x80\xA0\x70\xB0\x23\x40\x30\x20" - "\x36\x00\x07\x44\x21\x00\x00\x1A\x00\x00\x00\xFD\x00\x30\x55\x1E" - "\x5E\x15\x00\x0A\x20\x20\x20\x20\x20\x20\x00\x00\x00\xFC\x00\x48" - "\x50\x20\x4C\x50\x32\x34\x36\x35\x0A\x20\x20\x20\x00\x00\x00\xFF" - "\x00\x43\x4E\x4B\x38\x30\x32\x30\x34\x48\x4D\x0A\x20\x20\x00\x45"; - -TEST(OutputUtilTest, ParseEDID) { - uint16 manufacturer_id = 0; - std::string human_readable_name; - EXPECT_TRUE(ParseOutputDeviceData( - kNormalDisplay, charsize(kNormalDisplay), - &manufacturer_id, &human_readable_name)); - EXPECT_EQ(0x22f0u, manufacturer_id); - EXPECT_EQ("HP ZR30w", human_readable_name); - - manufacturer_id = 0; - human_readable_name.clear(); - EXPECT_TRUE(ParseOutputDeviceData( - kInternalDisplay, charsize(kInternalDisplay), - &manufacturer_id, NULL)); - EXPECT_EQ(0x4ca3u, manufacturer_id); - EXPECT_EQ("", human_readable_name); - - // Internal display doesn't have name. - EXPECT_TRUE(ParseOutputDeviceData( - kInternalDisplay, charsize(kInternalDisplay), - NULL, &human_readable_name)); - EXPECT_TRUE(human_readable_name.empty()); - - manufacturer_id = 0; - human_readable_name.clear(); - EXPECT_TRUE(ParseOutputDeviceData( - kOverscanDisplay, charsize(kOverscanDisplay), - &manufacturer_id, &human_readable_name)); - EXPECT_EQ(0x4c2du, manufacturer_id); - EXPECT_EQ("SAMSUNG", human_readable_name); -} - -TEST(OutputUtilTest, ParseBrokenEDID) { - uint16 manufacturer_id = 0; - std::string human_readable_name; - - // length == 0 - EXPECT_FALSE(ParseOutputDeviceData( - kNormalDisplay, 0, - &manufacturer_id, &human_readable_name)); - - // name is broken. Copying kNormalDisplay and substitute its name data by - // some control code. - std::string display_data( - reinterpret_cast<const char*>(kNormalDisplay), charsize(kNormalDisplay)); - - // display's name data is embedded in byte 95-107 in this specific example. - // Fix here too when the contents of kNormalDisplay is altered. - display_data[97] = '\x1b'; - EXPECT_FALSE(ParseOutputDeviceData( - reinterpret_cast<const unsigned char*>(display_data.data()), - display_data.size(), - &manufacturer_id, &human_readable_name)); - - // If |human_readable_name| isn't specified, it skips parsing the name. - manufacturer_id = 0; - EXPECT_TRUE(ParseOutputDeviceData( - reinterpret_cast<const unsigned char*>(display_data.data()), - display_data.size(), - &manufacturer_id, NULL)); - EXPECT_EQ(0x22f0u, manufacturer_id); -} +} // namespace TEST(OutputUtilTest, ParseOverscanFlag) { bool flag = false; @@ -223,27 +140,4 @@ TEST(OutputUtilTest, IsInternalOutputName) { EXPECT_FALSE(IsInternalOutputName("DS")); } -TEST(OutputUtilTest, GetDisplayId) { - // EDID of kLP2565A and B are slightly different but actually the same device. - int64 id1 = -1; - int64 id2 = -1; - EXPECT_TRUE(GetDisplayIdFromEDID(kLP2565A, charsize(kLP2565A), 0, &id1)); - EXPECT_TRUE(GetDisplayIdFromEDID(kLP2565B, charsize(kLP2565B), 0, &id2)); - EXPECT_EQ(id1, id2); - EXPECT_NE(-1, id1); -} - -TEST(OutputUtilTest, GetDisplayIdFromInternal) { - int64 id = -1; - EXPECT_TRUE(GetDisplayIdFromEDID( - kInternalDisplay, charsize(kInternalDisplay), 0, &id)); - EXPECT_NE(-1, id); -} - -TEST(OutputUtilTest, GetDisplayIdFailure) { - int64 id = -1; - EXPECT_FALSE(GetDisplayIdFromEDID(NULL, 0, 0, &id)); - EXPECT_EQ(-1, id); -} - } // namespace chromeos diff --git a/chromeos/display/real_output_configurator_delegate.cc b/chromeos/display/real_output_configurator_delegate.cc index 43b4cdb..fd7d7b0 100644 --- a/chromeos/display/real_output_configurator_delegate.cc +++ b/chromeos/display/real_output_configurator_delegate.cc @@ -17,6 +17,7 @@ #include "base/logging.h" #include "base/message_loop/message_pump_x11.h" +#include "base/x11/edid_parser_x11.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/power_manager_client.h" #include "chromeos/display/output_util.h" @@ -263,7 +264,7 @@ RealOutputConfiguratorDelegate::InitOutputSnapshot( output.output = id; output.width_mm = info->mm_width; output.height_mm = info->mm_height; - output.has_display_id = GetDisplayId(id, index, &output.display_id); + output.has_display_id = base::GetDisplayId(id, index, &output.display_id); output.is_internal = IsInternalOutput(info); output.index = index; |