Home | History | Annotate | Download | only in display
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chromeos/display/output_util.h"
      6 
      7 #include "base/memory/scoped_ptr.h"
      8 #include "testing/gtest/include/gtest/gtest.h"
      9 
     10 #include <X11/extensions/Xrandr.h>
     11 
     12 namespace chromeos {
     13 
     14 namespace {
     15 
     16 // Returns the number of characters in the string literal but doesn't count its
     17 // terminator NULL byte.
     18 #define charsize(str) (arraysize(str) - 1)
     19 
     20 // Sample EDID data extracted from real devices.
     21 const unsigned char kNormalDisplay[] =
     22     "\x00\xff\xff\xff\xff\xff\xff\x00\x22\xf0\x6c\x28\x01\x01\x01\x01"
     23     "\x02\x16\x01\x04\xb5\x40\x28\x78\xe2\x8d\x85\xad\x4f\x35\xb1\x25"
     24     "\x0e\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
     25     "\x01\x01\x01\x01\x01\x01\xe2\x68\x00\xa0\xa0\x40\x2e\x60\x30\x20"
     26     "\x36\x00\x81\x90\x21\x00\x00\x1a\xbc\x1b\x00\xa0\x50\x20\x17\x30"
     27     "\x30\x20\x36\x00\x81\x90\x21\x00\x00\x1a\x00\x00\x00\xfc\x00\x48"
     28     "\x50\x20\x5a\x52\x33\x30\x77\x0a\x20\x20\x20\x20\x00\x00\x00\xff"
     29     "\x00\x43\x4e\x34\x32\x30\x32\x31\x33\x37\x51\x0a\x20\x20\x00\x71";
     30 
     31 const unsigned char kInternalDisplay[] =
     32     "\x00\xff\xff\xff\xff\xff\xff\x00\x4c\xa3\x42\x31\x00\x00\x00\x00"
     33     "\x00\x15\x01\x03\x80\x1a\x10\x78\x0a\xd3\xe5\x95\x5c\x60\x90\x27"
     34     "\x19\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
     35     "\x01\x01\x01\x01\x01\x01\x9e\x1b\x00\xa0\x50\x20\x12\x30\x10\x30"
     36     "\x13\x00\x05\xa3\x10\x00\x00\x19\x00\x00\x00\x0f\x00\x00\x00\x00"
     37     "\x00\x00\x00\x00\x00\x23\x87\x02\x64\x00\x00\x00\x00\xfe\x00\x53"
     38     "\x41\x4d\x53\x55\x4e\x47\x0a\x20\x20\x20\x20\x20\x00\x00\x00\xfe"
     39     "\x00\x31\x32\x31\x41\x54\x31\x31\x2d\x38\x30\x31\x0a\x20\x00\x45";
     40 
     41 const unsigned char kOverscanDisplay[] =
     42     "\x00\xff\xff\xff\xff\xff\xff\x00\x4c\x2d\xfe\x08\x00\x00\x00\x00"
     43     "\x29\x15\x01\x03\x80\x10\x09\x78\x0a\xee\x91\xa3\x54\x4c\x99\x26"
     44     "\x0f\x50\x54\xbd\xef\x80\x71\x4f\x81\xc0\x81\x00\x81\x80\x95\x00"
     45     "\xa9\xc0\xb3\x00\x01\x01\x02\x3a\x80\x18\x71\x38\x2d\x40\x58\x2c"
     46     "\x45\x00\xa0\x5a\x00\x00\x00\x1e\x66\x21\x56\xaa\x51\x00\x1e\x30"
     47     "\x46\x8f\x33\x00\xa0\x5a\x00\x00\x00\x1e\x00\x00\x00\xfd\x00\x18"
     48     "\x4b\x0f\x51\x17\x00\x0a\x20\x20\x20\x20\x20\x20\x00\x00\x00\xfc"
     49     "\x00\x53\x41\x4d\x53\x55\x4e\x47\x0a\x20\x20\x20\x20\x20\x01\x1d"
     50     "\x02\x03\x1f\xf1\x47\x90\x04\x05\x03\x20\x22\x07\x23\x09\x07\x07"
     51     "\x83\x01\x00\x00\xe2\x00\x0f\x67\x03\x0c\x00\x20\x00\xb8\x2d\x01"
     52     "\x1d\x80\x18\x71\x1c\x16\x20\x58\x2c\x25\x00\xa0\x5a\x00\x00\x00"
     53     "\x9e\x01\x1d\x00\x72\x51\xd0\x1e\x20\x6e\x28\x55\x00\xa0\x5a\x00"
     54     "\x00\x00\x1e\x8c\x0a\xd0\x8a\x20\xe0\x2d\x10\x10\x3e\x96\x00\xa0"
     55     "\x5a\x00\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
     56     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
     57     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6";
     58 
     59 // The EDID info misdetecting overscan once. see crbug.com/226318
     60 const unsigned char kMisdetecedDisplay[] =
     61     "\x00\xff\xff\xff\xff\xff\xff\x00\x10\xac\x64\x40\x4c\x30\x30\x32"
     62     "\x0c\x15\x01\x03\x80\x40\x28\x78\xea\x8d\x85\xad\x4f\x35\xb1\x25"
     63     "\x0e\x50\x54\xa5\x4b\x00\x71\x4f\x81\x00\x81\x80\xd1\x00\xa9\x40"
     64     "\x01\x01\x01\x01\x01\x01\x28\x3c\x80\xa0\x70\xb0\x23\x40\x30\x20"
     65     "\x36\x00\x81\x91\x21\x00\x00\x1a\x00\x00\x00\xff\x00\x50\x48\x35"
     66     "\x4e\x59\x31\x33\x4e\x32\x30\x30\x4c\x0a\x00\x00\x00\xfc\x00\x44"
     67     "\x45\x4c\x4c\x20\x55\x33\x30\x31\x31\x0a\x20\x20\x00\x00\x00\xfd"
     68     "\x00\x31\x56\x1d\x5e\x12\x00\x0a\x20\x20\x20\x20\x20\x20\x01\x38"
     69     "\x02\x03\x29\xf1\x50\x90\x05\x04\x03\x02\x07\x16\x01\x06\x11\x12"
     70     "\x15\x13\x14\x1f\x20\x23\x0d\x7f\x07\x83\x0f\x00\x00\x67\x03\x0c"
     71     "\x00\x10\x00\x38\x2d\xe3\x05\x03\x01\x02\x3a\x80\x18\x71\x38\x2d"
     72     "\x40\x58\x2c\x45\x00\x81\x91\x21\x00\x00\x1e\x01\x1d\x80\x18\x71"
     73     "\x1c\x16\x20\x58\x2c\x25\x00\x81\x91\x21\x00\x00\x9e\x01\x1d\x00"
     74     "\x72\x51\xd0\x1e\x20\x6e\x28\x55\x00\x81\x91\x21\x00\x00\x1e\x8c"
     75     "\x0a\xd0\x8a\x20\xe0\x2d\x10\x10\x3e\x96\x00\x81\x91\x21\x00\x00"
     76     "\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x94";
     77 
     78 }
     79 
     80 const unsigned char kLP2565A[] =
     81     "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x22\xF0\x76\x26\x01\x01\x01\x01"
     82     "\x02\x12\x01\x03\x80\x34\x21\x78\xEE\xEF\x95\xA3\x54\x4C\x9B\x26"
     83     "\x0F\x50\x54\xA5\x6B\x80\x81\x40\x81\x80\x81\x99\x71\x00\xA9\x00"
     84     "\xA9\x40\xB3\x00\xD1\x00\x28\x3C\x80\xA0\x70\xB0\x23\x40\x30\x20"
     85     "\x36\x00\x07\x44\x21\x00\x00\x1A\x00\x00\x00\xFD\x00\x30\x55\x1E"
     86     "\x5E\x11\x00\x0A\x20\x20\x20\x20\x20\x20\x00\x00\x00\xFC\x00\x48"
     87     "\x50\x20\x4C\x50\x32\x34\x36\x35\x0A\x20\x20\x20\x00\x00\x00\xFF"
     88     "\x00\x43\x4E\x4B\x38\x30\x32\x30\x34\x48\x4D\x0A\x20\x20\x00\xA4";
     89 
     90 const unsigned char kLP2565B[] =
     91     "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x22\xF0\x75\x26\x01\x01\x01\x01"
     92     "\x02\x12\x01\x03\x6E\x34\x21\x78\xEE\xEF\x95\xA3\x54\x4C\x9B\x26"
     93     "\x0F\x50\x54\xA5\x6B\x80\x81\x40\x71\x00\xA9\x00\xA9\x40\xA9\x4F"
     94     "\xB3\x00\xD1\xC0\xD1\x00\x28\x3C\x80\xA0\x70\xB0\x23\x40\x30\x20"
     95     "\x36\x00\x07\x44\x21\x00\x00\x1A\x00\x00\x00\xFD\x00\x30\x55\x1E"
     96     "\x5E\x15\x00\x0A\x20\x20\x20\x20\x20\x20\x00\x00\x00\xFC\x00\x48"
     97     "\x50\x20\x4C\x50\x32\x34\x36\x35\x0A\x20\x20\x20\x00\x00\x00\xFF"
     98     "\x00\x43\x4E\x4B\x38\x30\x32\x30\x34\x48\x4D\x0A\x20\x20\x00\x45";
     99 
    100 TEST(OutputUtilTest, ParseEDID) {
    101   uint16 manufacturer_id = 0;
    102   std::string human_readable_name;
    103   EXPECT_TRUE(ParseOutputDeviceData(
    104       kNormalDisplay, charsize(kNormalDisplay),
    105       &manufacturer_id, &human_readable_name));
    106   EXPECT_EQ(0x22f0u, manufacturer_id);
    107   EXPECT_EQ("HP ZR30w", human_readable_name);
    108 
    109   manufacturer_id = 0;
    110   human_readable_name.clear();
    111   EXPECT_TRUE(ParseOutputDeviceData(
    112       kInternalDisplay, charsize(kInternalDisplay),
    113       &manufacturer_id, NULL));
    114   EXPECT_EQ(0x4ca3u, manufacturer_id);
    115   EXPECT_EQ("", human_readable_name);
    116 
    117   // Internal display doesn't have name.
    118   EXPECT_TRUE(ParseOutputDeviceData(
    119       kInternalDisplay, charsize(kInternalDisplay),
    120       NULL, &human_readable_name));
    121   EXPECT_TRUE(human_readable_name.empty());
    122 
    123   manufacturer_id = 0;
    124   human_readable_name.clear();
    125   EXPECT_TRUE(ParseOutputDeviceData(
    126       kOverscanDisplay, charsize(kOverscanDisplay),
    127       &manufacturer_id, &human_readable_name));
    128   EXPECT_EQ(0x4c2du, manufacturer_id);
    129   EXPECT_EQ("SAMSUNG", human_readable_name);
    130 }
    131 
    132 TEST(OutputUtilTest, ParseBrokenEDID) {
    133   uint16 manufacturer_id = 0;
    134   std::string human_readable_name;
    135 
    136   // length == 0
    137   EXPECT_FALSE(ParseOutputDeviceData(
    138       kNormalDisplay, 0,
    139       &manufacturer_id, &human_readable_name));
    140 
    141   // name is broken. Copying kNormalDisplay and substitute its name data by
    142   // some control code.
    143   std::string display_data(
    144       reinterpret_cast<const char*>(kNormalDisplay), charsize(kNormalDisplay));
    145 
    146   // display's name data is embedded in byte 95-107 in this specific example.
    147   // Fix here too when the contents of kNormalDisplay is altered.
    148   display_data[97] = '\x1b';
    149   EXPECT_FALSE(ParseOutputDeviceData(
    150       reinterpret_cast<const unsigned char*>(display_data.data()),
    151       display_data.size(),
    152       &manufacturer_id, &human_readable_name));
    153 
    154   // If |human_readable_name| isn't specified, it skips parsing the name.
    155   manufacturer_id = 0;
    156   EXPECT_TRUE(ParseOutputDeviceData(
    157       reinterpret_cast<const unsigned char*>(display_data.data()),
    158       display_data.size(),
    159       &manufacturer_id, NULL));
    160   EXPECT_EQ(0x22f0u, manufacturer_id);
    161 }
    162 
    163 TEST(OutputUtilTest, ParseOverscanFlag) {
    164   bool flag = false;
    165   EXPECT_FALSE(ParseOutputOverscanFlag(
    166       kNormalDisplay, charsize(kNormalDisplay), &flag));
    167 
    168   flag = false;
    169   EXPECT_FALSE(ParseOutputOverscanFlag(
    170       kInternalDisplay, charsize(kInternalDisplay), &flag));
    171 
    172   flag = false;
    173   EXPECT_TRUE(ParseOutputOverscanFlag(
    174       kOverscanDisplay, charsize(kOverscanDisplay), &flag));
    175   EXPECT_TRUE(flag);
    176 
    177   flag = false;
    178   EXPECT_FALSE(ParseOutputOverscanFlag(
    179       kMisdetecedDisplay, charsize(kMisdetecedDisplay), &flag));
    180 
    181   flag = false;
    182   // Copy |kOverscanDisplay| and set flags to false in it. The overscan flags
    183   // are embedded at byte 150 in this specific example. Fix here too when the
    184   // contents of kOverscanDisplay is altered.
    185   std::string display_data(reinterpret_cast<const char*>(kOverscanDisplay),
    186                            charsize(kOverscanDisplay));
    187   display_data[150] = '\0';
    188   EXPECT_TRUE(ParseOutputOverscanFlag(
    189       reinterpret_cast<const unsigned char*>(display_data.data()),
    190       display_data.size(), &flag));
    191   EXPECT_FALSE(flag);
    192 }
    193 
    194 TEST(OutputUtilTest, ParseBrokenOverscanData) {
    195   // Do not fill valid data here because it anyway fails to parse the data.
    196   scoped_ptr<unsigned char[]> data(new unsigned char[126]);
    197   bool flag = false;
    198   EXPECT_FALSE(ParseOutputOverscanFlag(data.get(), 0, &flag));
    199   EXPECT_FALSE(ParseOutputOverscanFlag(data.get(), 126, &flag));
    200 
    201   // extending data because ParseOutputOverscanFlag() will access the data.
    202   data.reset(new unsigned char[150]);
    203   // The number of CEA extensions is stored at byte 126.
    204   data[126] = '\x01';
    205   EXPECT_FALSE(ParseOutputOverscanFlag(data.get(), 128, &flag));
    206   EXPECT_FALSE(ParseOutputOverscanFlag(data.get(), 150, &flag));
    207 }
    208 
    209 TEST(OutputUtilTest, IsInternalOutputName) {
    210   EXPECT_TRUE(IsInternalOutputName("LVDS"));
    211   EXPECT_TRUE(IsInternalOutputName("eDP"));
    212   EXPECT_TRUE(IsInternalOutputName("DSI"));
    213   EXPECT_TRUE(IsInternalOutputName("LVDSxx"));
    214   EXPECT_TRUE(IsInternalOutputName("eDPzz"));
    215   EXPECT_TRUE(IsInternalOutputName("DSIyy"));
    216 
    217   EXPECT_FALSE(IsInternalOutputName("xyz"));
    218   EXPECT_FALSE(IsInternalOutputName("abcLVDS"));
    219   EXPECT_FALSE(IsInternalOutputName("cdeeDP"));
    220   EXPECT_FALSE(IsInternalOutputName("abcDSI"));
    221   EXPECT_FALSE(IsInternalOutputName("LVD"));
    222   EXPECT_FALSE(IsInternalOutputName("eD"));
    223   EXPECT_FALSE(IsInternalOutputName("DS"));
    224 }
    225 
    226 TEST(OutputUtilTest, GetDisplayId) {
    227   // EDID of kLP2565A and B are slightly different but actually the same device.
    228   int64 id1 = -1;
    229   int64 id2 = -1;
    230   EXPECT_TRUE(GetDisplayIdFromEDID(kLP2565A, charsize(kLP2565A), 0, &id1));
    231   EXPECT_TRUE(GetDisplayIdFromEDID(kLP2565B, charsize(kLP2565B), 0, &id2));
    232   EXPECT_EQ(id1, id2);
    233   EXPECT_NE(-1, id1);
    234 }
    235 
    236 TEST(OutputUtilTest, GetDisplayIdFromInternal) {
    237   int64 id = -1;
    238   EXPECT_TRUE(GetDisplayIdFromEDID(
    239       kInternalDisplay, charsize(kInternalDisplay), 0, &id));
    240   EXPECT_NE(-1, id);
    241 }
    242 
    243 TEST(OutputUtilTest, GetDisplayIdFailure) {
    244   int64 id = -1;
    245   EXPECT_FALSE(GetDisplayIdFromEDID(NULL, 0, 0, &id));
    246   EXPECT_EQ(-1, id);
    247 }
    248 
    249 TEST(OutputUtilTest, FindOutputModeMatchingSize) {
    250   XRRScreenResources resources = {0};
    251   RROutput outputs[] = {1};
    252   resources.noutput = arraysize(outputs);
    253   resources.outputs = outputs;
    254   XRRModeInfo modes[] = {
    255     // id, width, height, interlaced, refresh rate
    256     test::CreateModeInfo(11, 1920, 1200, false, 60.0f),
    257 
    258     // different rates
    259     test::CreateModeInfo(12, 1920, 1080, false, 30.0f),
    260     test::CreateModeInfo(13, 1920, 1080, false, 50.0f),
    261     test::CreateModeInfo(14, 1920, 1080, false, 40.0f),
    262     test::CreateModeInfo(15, 1920, 1080, false, 0.0f),
    263 
    264     // interlace vs non interlace
    265     test::CreateModeInfo(16, 1280, 720, true, 60.0f),
    266     test::CreateModeInfo(17, 1280, 720, false, 40.0f),
    267 
    268     // interlace only
    269     test::CreateModeInfo(18, 1024, 768, true, 0.0f),
    270     test::CreateModeInfo(19, 1024, 768, true, 40.0f),
    271     test::CreateModeInfo(20, 1024, 768, true, 60.0f),
    272 
    273     // mixed
    274     test::CreateModeInfo(21, 1024, 600, true, 60.0f),
    275     test::CreateModeInfo(22, 1024, 600, false, 40.0f),
    276     test::CreateModeInfo(23, 1024, 600, false, 50.0f),
    277 
    278     // just one interlaced mode
    279     test::CreateModeInfo(24, 640, 480, true, 60.0f),
    280 
    281     // refresh rate not available.
    282     test::CreateModeInfo(25, 320, 200, false, 0.0f),
    283   };
    284   resources.nmode = arraysize(modes);
    285   resources.modes = modes;
    286 
    287   XRROutputInfo output_info = {0};
    288   RRMode output_modes[] = {
    289     11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
    290   };
    291   output_info.nmode = arraysize(output_modes);
    292   output_info.modes = output_modes;
    293 
    294   EXPECT_EQ(11u, FindOutputModeMatchingSize(&resources,
    295                                            &output_info,
    296                                            1920, 1200));
    297 
    298   // Should pick highest refresh rate.
    299   EXPECT_EQ(13u, FindOutputModeMatchingSize(&resources,
    300                                             &output_info,
    301                                             1920, 1080));
    302 
    303   // Should pick non interlaced mode.
    304   EXPECT_EQ(17u, FindOutputModeMatchingSize(&resources,
    305                                             &output_info,
    306                                             1280, 720));
    307 
    308   // Interlaced only. Should pick one with the highest refresh rate in
    309   // interlaced mode.
    310   EXPECT_EQ(20u, FindOutputModeMatchingSize(&resources,
    311                                             &output_info,
    312                                             1024, 768));
    313 
    314   // Mixed: Should pick one with the highest refresh rate in
    315   // interlaced mode.
    316   EXPECT_EQ(23u, FindOutputModeMatchingSize(&resources,
    317                                             &output_info,
    318                                             1024, 600));
    319 
    320   // Just one interlaced mode.
    321   EXPECT_EQ(24u, FindOutputModeMatchingSize(&resources,
    322                                             &output_info,
    323                                             640, 480));
    324 
    325   // Refresh rate not available.
    326   EXPECT_EQ(25u, FindOutputModeMatchingSize(&resources,
    327                                             &output_info,
    328                                             320, 200));
    329 
    330   // No mode found.
    331   EXPECT_EQ(static_cast<XID>(None),
    332             FindOutputModeMatchingSize(&resources,
    333                                        &output_info,
    334                                        1440, 900));
    335 }
    336 
    337 }   // namespace chromeos
    338