Chromium Code Reviews| 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 |
| 31 } // namespace | 32 } // namespace |
| 32 | 33 |
| 33 bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid, | 34 bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid, |
| 34 uint8_t output_index, | 35 uint8_t output_index, |
| 35 int64_t* display_id_out) { | 36 int64_t* display_id_out) { |
| 36 uint16_t manufacturer_id = 0; | 37 uint16_t manufacturer_id = 0; |
| 37 std::string product_name; | 38 std::string product_name; |
| 38 | 39 |
| 39 // ParseOutputDeviceData fails if it doesn't have product_name. | 40 // ParseOutputDeviceData fails if it doesn't have product_name. |
| 40 ParseOutputDeviceData(edid, &manufacturer_id, &product_name); | 41 ParseOutputDeviceData(edid, &manufacturer_id, &product_name, nullptr, |
| 42 nullptr); | |
| 41 | 43 |
| 42 // Generates product specific value from product_name instead of product code. | 44 // Generates product specific value from product_name instead of product code. |
| 43 // See crbug.com/240341 | 45 // See crbug.com/240341 |
| 44 uint32_t product_code_hash = product_name.empty() ? | 46 uint32_t product_code_hash = product_name.empty() ? |
| 45 0 : base::Hash(product_name); | 47 0 : base::Hash(product_name); |
| 46 if (manufacturer_id != 0) { | 48 if (manufacturer_id != 0) { |
| 47 // An ID based on display's index will be assigned later if this call | 49 // An ID based on display's index will be assigned later if this call |
| 48 // fails. | 50 // fails. |
| 49 *display_id_out = GetID( | 51 *display_id_out = GetID( |
| 50 manufacturer_id, product_code_hash, output_index); | 52 manufacturer_id, product_code_hash, output_index); |
| 51 return true; | 53 return true; |
| 52 } | 54 } |
| 53 return false; | 55 return false; |
| 54 } | 56 } |
| 55 | 57 |
| 56 bool ParseOutputDeviceData(const std::vector<uint8_t>& edid, | 58 bool ParseOutputDeviceData(const std::vector<uint8_t>& edid, |
| 57 uint16_t* manufacturer_id, | 59 uint16_t* manufacturer_id, |
| 58 std::string* human_readable_name) { | 60 std::string* human_readable_name, |
| 61 gfx::Size* active_active_pixel_out, | |
|
Jun Mukai
2015/01/22 02:07:39
nit: active_active_pixel_out -> active_pixel_out
| |
| 62 gfx::Size* physical_display_size_out) { | |
| 59 // See http://en.wikipedia.org/wiki/Extended_display_identification_data | 63 // See http://en.wikipedia.org/wiki/Extended_display_identification_data |
| 60 // for the details of EDID data format. We use the following data: | 64 // for the details of EDID data format. We use the following data: |
| 61 // bytes 8-9: manufacturer EISA ID, in big-endian | 65 // bytes 8-9: manufacturer EISA ID, in big-endian |
| 62 // bytes 54-125: four descriptors (18-bytes each) which may contain | 66 // bytes 54-125: four descriptors (18-bytes each) which may contain |
| 63 // the display name. | 67 // the display name. |
| 64 const unsigned int kManufacturerOffset = 8; | 68 const unsigned int kManufacturerOffset = 8; |
| 65 const unsigned int kManufacturerLength = 2; | 69 const unsigned int kManufacturerLength = 2; |
| 66 const unsigned int kDescriptorOffset = 54; | 70 const unsigned int kDescriptorOffset = 54; |
| 67 const unsigned int kNumDescriptors = 4; | 71 const unsigned int kNumDescriptors = 4; |
| 68 const unsigned int kDescriptorLength = 18; | 72 const unsigned int kDescriptorLength = 18; |
| 69 // The specifier types. | 73 // The specifier types. |
| 70 const unsigned char kMonitorNameDescriptor = 0xfc; | 74 const unsigned char kMonitorNameDescriptor = 0xfc; |
| 71 | 75 |
| 72 if (manufacturer_id) { | 76 if (manufacturer_id) { |
| 73 if (edid.size() < kManufacturerOffset + kManufacturerLength) { | 77 if (edid.size() < kManufacturerOffset + kManufacturerLength) { |
| 74 LOG(ERROR) << "too short EDID data: manifacturer id"; | 78 LOG(ERROR) << "too short EDID data: manifacturer id"; |
| 75 return false; | 79 return false; |
| 76 } | 80 } |
| 77 | 81 |
| 78 *manufacturer_id = | 82 *manufacturer_id = |
| 79 *reinterpret_cast<const uint16_t*>(&edid[kManufacturerOffset]); | 83 *reinterpret_cast<const uint16_t*>(&edid[kManufacturerOffset]); |
| 80 #if defined(ARCH_CPU_LITTLE_ENDIAN) | 84 #if defined(ARCH_CPU_LITTLE_ENDIAN) |
| 81 *manufacturer_id = base::ByteSwap(*manufacturer_id); | 85 *manufacturer_id = base::ByteSwap(*manufacturer_id); |
| 82 #endif | 86 #endif |
| 83 } | 87 } |
| 84 | 88 |
| 85 if (!human_readable_name) | 89 if (human_readable_name) |
| 86 return true; | 90 human_readable_name->clear(); |
| 87 | 91 |
| 88 human_readable_name->clear(); | |
| 89 for (unsigned int i = 0; i < kNumDescriptors; ++i) { | 92 for (unsigned int i = 0; i < kNumDescriptors; ++i) { |
| 90 if (edid.size() < kDescriptorOffset + (i + 1) * kDescriptorLength) | 93 if (edid.size() < kDescriptorOffset + (i + 1) * kDescriptorLength) |
| 91 break; | 94 break; |
| 92 | 95 |
| 93 size_t offset = kDescriptorOffset + i * kDescriptorLength; | 96 size_t offset = kDescriptorOffset + i * kDescriptorLength; |
| 97 | |
| 98 // Detailed Timing Descriptor: | |
| 99 if (edid[offset] != 0 && edid[offset + 1] != 0) { | |
| 100 const int kMaxResolution = 10080; // 8k display. | |
| 101 | |
| 102 if (active_pixel_out) { | |
| 103 const int kHorizontalPixelLsbOffset = 2; | |
| 104 const int kHorizontalPixelMsbOffset = 4; | |
| 105 const int kVerticalPixelLsbOffset = 5; | |
| 106 const int kVerticalPixelMsbOffset = 7; | |
| 107 | |
| 108 int h_lsb = edid[offset + kHorizontalPixelLsbOffset]; | |
| 109 int h_msb = edid[offset + kHorizontalPixelMsbOffset]; | |
| 110 int h_pixel = std::min(h_lsb + ((h_msb & 0xF0) << 4), kMaxResolution); | |
| 111 | |
| 112 int v_lsb = edid[offset + kVerticalPixelLsbOffset]; | |
| 113 int v_msb = edid[offset + kVerticalPixelMsbOffset]; | |
| 114 int v_pixel = std::min(v_lsb + ((v_msb & 0xF0) << 4), kMaxResolution); | |
| 115 | |
| 116 active_pixel_out->SetSize(h_pixel, v_pixel); | |
| 117 // EDID may contain multiple DTD. Use first one that | |
| 118 // contains the highest resolution. | |
| 119 active_pixel_out = nullptr; | |
| 120 } | |
| 121 | |
| 122 if (physical_display_size_out) { | |
| 123 const int kHorizontalSizeLsbOffset = 12; | |
| 124 const int kVerticalSizeLsbOffset = 13; | |
| 125 const int kSizeMsbOffset = 14; | |
| 126 | |
| 127 int h_lsb = edid[offset + kHorizontalSizeLsbOffset]; | |
| 128 int v_lsb = edid[offset + kVerticalSizeLsbOffset]; | |
| 129 | |
| 130 int msb = edid[offset + kSizeMsbOffset]; | |
| 131 int h_size = h_lsb + ((msb & 0xF0) << 4); | |
| 132 int v_size = v_lsb + ((msb & 0x0F) << 8); | |
| 133 physical_display_size_out->SetSize(h_size, v_size); | |
| 134 physical_display_size_out = nullptr; | |
| 135 } | |
| 136 continue; | |
| 137 } | |
| 138 | |
| 139 // EDID Other Monitor Descriptors: | |
| 94 // If the descriptor contains the display name, it has the following | 140 // If the descriptor contains the display name, it has the following |
| 95 // structure: | 141 // structure: |
| 96 // bytes 0-2, 4: \0 | 142 // bytes 0-2, 4: \0 |
| 97 // byte 3: descriptor type, defined above. | 143 // byte 3: descriptor type, defined above. |
| 98 // bytes 5-17: text data, ending with \r, padding with spaces | 144 // 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 | 145 // 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. | 146 // case that the descriptor contains other type of data. |
| 101 if (edid[offset] == 0 && edid[offset + 1] == 0 && edid[offset + 2] == 0 && | 147 if (edid[offset] == 0 && edid[offset + 1] == 0 && edid[offset + 2] == 0 && |
| 102 edid[offset + 3] == kMonitorNameDescriptor && edid[offset + 4] == 0) { | 148 edid[offset + 3] == kMonitorNameDescriptor && edid[offset + 4] == 0 && |
| 149 human_readable_name) { | |
| 103 std::string found_name(reinterpret_cast<const char*>(&edid[offset + 5]), | 150 std::string found_name(reinterpret_cast<const char*>(&edid[offset + 5]), |
| 104 kDescriptorLength - 5); | 151 kDescriptorLength - 5); |
| 105 base::TrimWhitespaceASCII( | 152 base::TrimWhitespaceASCII( |
| 106 found_name, base::TRIM_TRAILING, human_readable_name); | 153 found_name, base::TRIM_TRAILING, human_readable_name); |
| 107 break; | 154 continue; |
| 108 } | 155 } |
| 109 } | 156 } |
| 110 | 157 |
| 111 // Verify if the |human_readable_name| consists of printable characters only. | 158 // Verify if the |human_readable_name| consists of printable characters only. |
| 112 for (size_t i = 0; i < human_readable_name->size(); ++i) { | 159 // TODO(oshima|muka): Consider replacing unprintable chars with white space. |
| 113 char c = (*human_readable_name)[i]; | 160 if (human_readable_name) { |
| 114 if (!isascii(c) || !isprint(c)) { | 161 for (size_t i = 0; i < human_readable_name->size(); ++i) { |
| 115 human_readable_name->clear(); | 162 char c = (*human_readable_name)[i]; |
| 116 LOG(ERROR) << "invalid EDID: human unreadable char in name"; | 163 if (!isascii(c) || !isprint(c)) { |
| 117 return false; | 164 human_readable_name->clear(); |
| 165 LOG(ERROR) << "invalid EDID: human unreadable char in name"; | |
| 166 return false; | |
| 167 } | |
| 118 } | 168 } |
| 119 } | 169 } |
| 120 | 170 |
| 121 return true; | 171 return true; |
| 122 } | 172 } |
| 123 | 173 |
| 124 bool ParseOutputOverscanFlag(const std::vector<uint8_t>& edid, | 174 bool ParseOutputOverscanFlag(const std::vector<uint8_t>& edid, |
| 125 bool* flag) { | 175 bool* flag) { |
| 126 // See http://en.wikipedia.org/wiki/Extended_display_identification_data | 176 // See http://en.wikipedia.org/wiki/Extended_display_identification_data |
| 127 // for the extension format of EDID. Also see EIA/CEA-861 spec for | 177 // 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; | 238 *flag = false; |
| 189 } | 239 } |
| 190 return true; | 240 return true; |
| 191 } | 241 } |
| 192 } | 242 } |
| 193 | 243 |
| 194 return false; | 244 return false; |
| 195 } | 245 } |
| 196 | 246 |
| 197 } // namespace ui | 247 } // namespace ui |
| OLD | NEW |