Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(164)

Side by Side Diff: ui/display/util/edid_parser.cc

Issue 1285183008: Ozone integration. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: add missing license header Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/display/util/edid_parser.h ('k') | ui/display/util/edid_parser_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
OLDNEW
« no previous file with comments | « ui/display/util/edid_parser.h ('k') | ui/display/util/edid_parser_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698