OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/display/util/edid_parser.h" | 5 #include "ui/display/util/edid_parser.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/hash.h" | 9 #include "base/hash.h" |
10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
11 #include "base/sys_byteorder.h" | 11 #include "base/sys_byteorder.h" |
| 12 #include "ui/gfx/geometry/size.h" |
12 | 13 |
13 namespace ui { | 14 namespace ui { |
14 | 15 |
15 namespace { | 16 namespace { |
16 | 17 |
17 // Returns 64-bit persistent ID for the specified manufacturer's ID and | 18 // Returns 64-bit persistent ID for the specified manufacturer's ID and |
18 // product_code_hash, and the index of the output it is connected to. | 19 // product_code_hash, and the index of the output it is connected to. |
19 // |output_index| is used to distinguish the displays of the same type. For | 20 // |output_index| is used to distinguish the displays of the same type. For |
20 // example, swapping two identical display between two outputs will not be | 21 // example, swapping two identical display between two outputs will not be |
21 // treated as swap. The 'serial number' field in EDID isn't used here because | 22 // treated as swap. The 'serial number' field in EDID isn't used here because |
22 // it is not guaranteed to have unique number and it may have the same fixed | 23 // it is not guaranteed to have unique number and it may have the same fixed |
23 // value (like 0). | 24 // value (like 0). |
24 int64_t GetID(uint16_t manufacturer_id, | 25 int64_t GetID(uint16_t manufacturer_id, |
25 uint32_t product_code_hash, | 26 uint32_t product_code_hash, |
26 uint8_t output_index) { | 27 uint8_t output_index) { |
27 return ((static_cast<int64_t>(manufacturer_id) << 40) | | 28 return ((static_cast<int64_t>(manufacturer_id) << 40) | |
28 (static_cast<int64_t>(product_code_hash) << 8) | output_index); | 29 (static_cast<int64_t>(product_code_hash) << 8) | output_index); |
29 } | 30 } |
30 | 31 |
| 32 // Returns a 32-bit identifier for this model of display, using |
| 33 // |manufacturer_id| and |product_code|. |
| 34 uint32_t GetProductID(uint16_t manufacturer_id, uint16_t product_code) { |
| 35 return ((static_cast<uint32_t>(manufacturer_id) << 16) | |
| 36 (static_cast<uint32_t>(product_code))); |
| 37 } |
| 38 |
31 } // namespace | 39 } // namespace |
32 | 40 |
33 bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid, | 41 bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid, |
34 uint8_t output_index, | 42 uint8_t output_index, |
35 int64_t* display_id_out) { | 43 int64_t* display_id_out, |
| 44 int64_t* product_id_out) { |
36 uint16_t manufacturer_id = 0; | 45 uint16_t manufacturer_id = 0; |
| 46 uint16_t product_code = 0; |
37 std::string product_name; | 47 std::string product_name; |
38 | 48 |
39 // ParseOutputDeviceData fails if it doesn't have product_name. | 49 // ParseOutputDeviceData fails if it doesn't have product_name. |
40 ParseOutputDeviceData(edid, &manufacturer_id, &product_name); | 50 ParseOutputDeviceData(edid, &manufacturer_id, &product_code, &product_name, |
| 51 nullptr, nullptr); |
41 | 52 |
42 // Generates product specific value from product_name instead of product code. | |
43 // See crbug.com/240341 | |
44 uint32_t product_code_hash = product_name.empty() ? | |
45 0 : base::Hash(product_name); | |
46 if (manufacturer_id != 0) { | 53 if (manufacturer_id != 0) { |
| 54 // Generates product specific value from product_name instead of product |
| 55 // code. |
| 56 // See crbug.com/240341 |
| 57 uint32_t product_code_hash = |
| 58 product_name.empty() ? 0 : base::Hash(product_name); |
47 // An ID based on display's index will be assigned later if this call | 59 // An ID based on display's index will be assigned later if this call |
48 // fails. | 60 // fails. |
49 *display_id_out = GetID( | 61 *display_id_out = GetID( |
50 manufacturer_id, product_code_hash, output_index); | 62 manufacturer_id, product_code_hash, output_index); |
| 63 // product_id is 64-bit signed so it can store -1 as kInvalidProductID and |
| 64 // not match a valid product id which will all be in the lowest 32-bits. |
| 65 if (product_id_out) |
| 66 *product_id_out = GetProductID(manufacturer_id, product_code); |
51 return true; | 67 return true; |
52 } | 68 } |
53 return false; | 69 return false; |
54 } | 70 } |
55 | 71 |
56 bool ParseOutputDeviceData(const std::vector<uint8_t>& edid, | 72 bool ParseOutputDeviceData(const std::vector<uint8_t>& edid, |
57 uint16_t* manufacturer_id, | 73 uint16_t* manufacturer_id, |
58 std::string* human_readable_name) { | 74 uint16_t* product_code, |
| 75 std::string* human_readable_name, |
| 76 gfx::Size* active_pixel_out, |
| 77 gfx::Size* physical_display_size_out) { |
59 // See http://en.wikipedia.org/wiki/Extended_display_identification_data | 78 // See http://en.wikipedia.org/wiki/Extended_display_identification_data |
60 // for the details of EDID data format. We use the following data: | 79 // for the details of EDID data format. We use the following data: |
61 // bytes 8-9: manufacturer EISA ID, in big-endian | 80 // bytes 8-9: manufacturer EISA ID, in big-endian |
| 81 // bytes 10-11: manufacturer product code, in little-endian |
62 // bytes 54-125: four descriptors (18-bytes each) which may contain | 82 // bytes 54-125: four descriptors (18-bytes each) which may contain |
63 // the display name. | 83 // the display name. |
64 const unsigned int kManufacturerOffset = 8; | 84 const unsigned int kManufacturerOffset = 8; |
65 const unsigned int kManufacturerLength = 2; | 85 const unsigned int kManufacturerLength = 2; |
| 86 const unsigned int kProductCodeOffset = 10; |
| 87 const unsigned int kProductCodeLength = 2; |
66 const unsigned int kDescriptorOffset = 54; | 88 const unsigned int kDescriptorOffset = 54; |
67 const unsigned int kNumDescriptors = 4; | 89 const unsigned int kNumDescriptors = 4; |
68 const unsigned int kDescriptorLength = 18; | 90 const unsigned int kDescriptorLength = 18; |
69 // The specifier types. | 91 // The specifier types. |
70 const unsigned char kMonitorNameDescriptor = 0xfc; | 92 const unsigned char kMonitorNameDescriptor = 0xfc; |
71 | 93 |
72 if (manufacturer_id) { | 94 if (manufacturer_id) { |
73 if (edid.size() < kManufacturerOffset + kManufacturerLength) { | 95 if (edid.size() < kManufacturerOffset + kManufacturerLength) { |
74 LOG(ERROR) << "too short EDID data: manifacturer id"; | 96 LOG(ERROR) << "too short EDID data: manufacturer id"; |
75 return false; | 97 return false; |
76 } | 98 } |
77 | 99 |
78 *manufacturer_id = | 100 *manufacturer_id = |
79 *reinterpret_cast<const uint16_t*>(&edid[kManufacturerOffset]); | 101 *reinterpret_cast<const uint16_t*>(&edid[kManufacturerOffset]); |
80 #if defined(ARCH_CPU_LITTLE_ENDIAN) | 102 #if defined(ARCH_CPU_LITTLE_ENDIAN) |
81 *manufacturer_id = base::ByteSwap(*manufacturer_id); | 103 *manufacturer_id = base::ByteSwap(*manufacturer_id); |
82 #endif | 104 #endif |
83 } | 105 } |
84 | 106 |
85 if (!human_readable_name) | 107 if (product_code) { |
86 return true; | 108 if (edid.size() < kProductCodeOffset + kProductCodeLength) { |
| 109 LOG(ERROR) << "too short EDID data: manufacturer product code"; |
| 110 return false; |
| 111 } |
87 | 112 |
88 human_readable_name->clear(); | 113 *product_code = |
| 114 *reinterpret_cast<const uint16_t*>(&edid[kProductCodeOffset]); |
| 115 } |
| 116 |
| 117 if (human_readable_name) |
| 118 human_readable_name->clear(); |
| 119 |
89 for (unsigned int i = 0; i < kNumDescriptors; ++i) { | 120 for (unsigned int i = 0; i < kNumDescriptors; ++i) { |
90 if (edid.size() < kDescriptorOffset + (i + 1) * kDescriptorLength) | 121 if (edid.size() < kDescriptorOffset + (i + 1) * kDescriptorLength) |
91 break; | 122 break; |
92 | 123 |
93 size_t offset = kDescriptorOffset + i * kDescriptorLength; | 124 size_t offset = kDescriptorOffset + i * kDescriptorLength; |
| 125 |
| 126 // Detailed Timing Descriptor: |
| 127 if (edid[offset] != 0 && edid[offset + 1] != 0) { |
| 128 const int kMaxResolution = 10080; // 8k display. |
| 129 |
| 130 if (active_pixel_out) { |
| 131 const int kHorizontalPixelLsbOffset = 2; |
| 132 const int kHorizontalPixelMsbOffset = 4; |
| 133 const int kVerticalPixelLsbOffset = 5; |
| 134 const int kVerticalPixelMsbOffset = 7; |
| 135 |
| 136 int h_lsb = edid[offset + kHorizontalPixelLsbOffset]; |
| 137 int h_msb = edid[offset + kHorizontalPixelMsbOffset]; |
| 138 int h_pixel = std::min(h_lsb + ((h_msb & 0xF0) << 4), kMaxResolution); |
| 139 |
| 140 int v_lsb = edid[offset + kVerticalPixelLsbOffset]; |
| 141 int v_msb = edid[offset + kVerticalPixelMsbOffset]; |
| 142 int v_pixel = std::min(v_lsb + ((v_msb & 0xF0) << 4), kMaxResolution); |
| 143 |
| 144 active_pixel_out->SetSize(h_pixel, v_pixel); |
| 145 // EDID may contain multiple DTD. Use first one that |
| 146 // contains the highest resolution. |
| 147 active_pixel_out = nullptr; |
| 148 } |
| 149 |
| 150 if (physical_display_size_out) { |
| 151 const int kHorizontalSizeLsbOffset = 12; |
| 152 const int kVerticalSizeLsbOffset = 13; |
| 153 const int kSizeMsbOffset = 14; |
| 154 |
| 155 int h_lsb = edid[offset + kHorizontalSizeLsbOffset]; |
| 156 int v_lsb = edid[offset + kVerticalSizeLsbOffset]; |
| 157 |
| 158 int msb = edid[offset + kSizeMsbOffset]; |
| 159 int h_size = h_lsb + ((msb & 0xF0) << 4); |
| 160 int v_size = v_lsb + ((msb & 0x0F) << 8); |
| 161 physical_display_size_out->SetSize(h_size, v_size); |
| 162 physical_display_size_out = nullptr; |
| 163 } |
| 164 continue; |
| 165 } |
| 166 |
| 167 // EDID Other Monitor Descriptors: |
94 // If the descriptor contains the display name, it has the following | 168 // If the descriptor contains the display name, it has the following |
95 // structure: | 169 // structure: |
96 // bytes 0-2, 4: \0 | 170 // bytes 0-2, 4: \0 |
97 // byte 3: descriptor type, defined above. | 171 // byte 3: descriptor type, defined above. |
98 // bytes 5-17: text data, ending with \r, padding with spaces | 172 // bytes 5-17: text data, ending with \r, padding with spaces |
99 // we should check bytes 0-2 and 4, since it may have other values in | 173 // we should check bytes 0-2 and 4, since it may have other values in |
100 // case that the descriptor contains other type of data. | 174 // case that the descriptor contains other type of data. |
101 if (edid[offset] == 0 && edid[offset + 1] == 0 && edid[offset + 2] == 0 && | 175 if (edid[offset] == 0 && edid[offset + 1] == 0 && edid[offset + 2] == 0 && |
102 edid[offset + 3] == kMonitorNameDescriptor && edid[offset + 4] == 0) { | 176 edid[offset + 3] == kMonitorNameDescriptor && edid[offset + 4] == 0 && |
| 177 human_readable_name) { |
103 std::string found_name(reinterpret_cast<const char*>(&edid[offset + 5]), | 178 std::string found_name(reinterpret_cast<const char*>(&edid[offset + 5]), |
104 kDescriptorLength - 5); | 179 kDescriptorLength - 5); |
105 base::TrimWhitespaceASCII( | 180 base::TrimWhitespaceASCII( |
106 found_name, base::TRIM_TRAILING, human_readable_name); | 181 found_name, base::TRIM_TRAILING, human_readable_name); |
107 break; | 182 continue; |
108 } | 183 } |
109 } | 184 } |
110 | 185 |
111 // Verify if the |human_readable_name| consists of printable characters only. | 186 // Verify if the |human_readable_name| consists of printable characters only. |
112 for (size_t i = 0; i < human_readable_name->size(); ++i) { | 187 // TODO(oshima|muka): Consider replacing unprintable chars with white space. |
113 char c = (*human_readable_name)[i]; | 188 if (human_readable_name) { |
114 if (!isascii(c) || !isprint(c)) { | 189 for (size_t i = 0; i < human_readable_name->size(); ++i) { |
115 human_readable_name->clear(); | 190 char c = (*human_readable_name)[i]; |
116 LOG(ERROR) << "invalid EDID: human unreadable char in name"; | 191 if (!isascii(c) || !isprint(c)) { |
117 return false; | 192 human_readable_name->clear(); |
| 193 LOG(ERROR) << "invalid EDID: human unreadable char in name"; |
| 194 return false; |
| 195 } |
118 } | 196 } |
119 } | 197 } |
120 | 198 |
121 return true; | 199 return true; |
122 } | 200 } |
123 | 201 |
124 bool ParseOutputOverscanFlag(const std::vector<uint8_t>& edid, | 202 bool ParseOutputOverscanFlag(const std::vector<uint8_t>& edid, |
125 bool* flag) { | 203 bool* flag) { |
126 // See http://en.wikipedia.org/wiki/Extended_display_identification_data | 204 // See http://en.wikipedia.org/wiki/Extended_display_identification_data |
127 // for the extension format of EDID. Also see EIA/CEA-861 spec for | 205 // for the extension format of EDID. Also see EIA/CEA-861 spec for |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
188 *flag = false; | 266 *flag = false; |
189 } | 267 } |
190 return true; | 268 return true; |
191 } | 269 } |
192 } | 270 } |
193 | 271 |
194 return false; | 272 return false; |
195 } | 273 } |
196 | 274 |
197 } // namespace ui | 275 } // namespace ui |
OLD | NEW |