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 <X11/extensions/Xrandr.h>
      8 #include <X11/Xatom.h>
      9 #include <X11/Xlib.h>
     10 
     11 #include "base/strings/string_util.h"
     12 #include "base/x11/edid_parser_x11.h"
     13 
     14 namespace chromeos {
     15 namespace {
     16 
     17 // Prefixes for the built-in displays.
     18 const char kInternal_LVDS[] = "LVDS";
     19 const char kInternal_eDP[] = "eDP";
     20 const char kInternal_DSI[] = "DSI";
     21 
     22 // Gets some useful data from the specified output device, such like
     23 // manufacturer's ID, product code, and human readable name. Returns false if it
     24 // fails to get those data and doesn't touch manufacturer ID/product code/name.
     25 // NULL can be passed for unwanted output parameters.
     26 bool GetOutputDeviceData(XID output,
     27                          uint16* manufacturer_id,
     28                          std::string* human_readable_name) {
     29   unsigned long nitems = 0;
     30   unsigned char *prop = NULL;
     31   if (!base::GetEDIDProperty(output, &nitems, &prop))
     32     return false;
     33 
     34   bool result = base::ParseOutputDeviceData(
     35       prop, nitems, manufacturer_id, human_readable_name);
     36   XFree(prop);
     37   return result;
     38 }
     39 
     40 }  // namespace
     41 
     42 std::string GetDisplayName(XID output_id) {
     43   std::string display_name;
     44   GetOutputDeviceData(output_id, NULL, &display_name);
     45   return display_name;
     46 }
     47 
     48 bool GetOutputOverscanFlag(XID output, bool* flag) {
     49   unsigned long nitems = 0;
     50   unsigned char *prop = NULL;
     51   if (!base::GetEDIDProperty(output, &nitems, &prop))
     52     return false;
     53 
     54   bool found = ParseOutputOverscanFlag(prop, nitems, flag);
     55   XFree(prop);
     56   return found;
     57 }
     58 
     59 bool ParseOutputOverscanFlag(const unsigned char* prop,
     60                              unsigned long nitems,
     61                              bool *flag) {
     62   // See http://en.wikipedia.org/wiki/Extended_display_identification_data
     63   // for the extension format of EDID.  Also see EIA/CEA-861 spec for
     64   // the format of the extensions and how video capability is encoded.
     65   //  - byte 0: tag.  should be 02h.
     66   //  - byte 1: revision.  only cares revision 3 (03h).
     67   //  - byte 4-: data block.
     68   const unsigned int kExtensionBase = 128;
     69   const unsigned int kExtensionSize = 128;
     70   const unsigned int kNumExtensionsOffset = 126;
     71   const unsigned int kDataBlockOffset = 4;
     72   const unsigned char kCEAExtensionTag = '\x02';
     73   const unsigned char kExpectedExtensionRevision = '\x03';
     74   const unsigned char kExtendedTag = 7;
     75   const unsigned char kExtendedVideoCapabilityTag = 0;
     76   const unsigned int kPTOverscan = 4;
     77   const unsigned int kITOverscan = 2;
     78   const unsigned int kCEOverscan = 0;
     79 
     80   if (nitems <= kNumExtensionsOffset)
     81     return false;
     82 
     83   unsigned char num_extensions = prop[kNumExtensionsOffset];
     84 
     85   for (size_t i = 0; i < num_extensions; ++i) {
     86     // Skip parsing the whole extension if size is not enough.
     87     if (nitems < kExtensionBase + (i + 1) * kExtensionSize)
     88       break;
     89 
     90     const unsigned char* extension = prop + kExtensionBase + i * kExtensionSize;
     91     unsigned char tag = extension[0];
     92     unsigned char revision = extension[1];
     93     if (tag != kCEAExtensionTag || revision != kExpectedExtensionRevision)
     94       continue;
     95 
     96     unsigned char timing_descriptors_start =
     97         std::min(extension[2], static_cast<unsigned char>(kExtensionSize));
     98     const unsigned char* data_block = extension + kDataBlockOffset;
     99     while (data_block < extension + timing_descriptors_start) {
    100       // A data block is encoded as:
    101       // - byte 1 high 3 bits: tag. '07' for extended tags.
    102       // - byte 1 remaining bits: the length of data block.
    103       // - byte 2: the extended tag.  '0' for video capability.
    104       // - byte 3: the capability.
    105       unsigned char tag = data_block[0] >> 5;
    106       unsigned char payload_length = data_block[0] & 0x1f;
    107       if (static_cast<unsigned long>(data_block + payload_length - prop) >
    108           nitems)
    109         break;
    110 
    111       if (tag != kExtendedTag || payload_length < 2) {
    112         data_block += payload_length + 1;
    113         continue;
    114       }
    115 
    116       unsigned char extended_tag_code = data_block[1];
    117       if (extended_tag_code != kExtendedVideoCapabilityTag) {
    118         data_block += payload_length + 1;
    119         continue;
    120       }
    121 
    122       // The difference between preferred, IT, and CE video formats
    123       // doesn't matter. Sets |flag| to true if any of these flags are true.
    124       if ((data_block[2] & (1 << kPTOverscan)) ||
    125           (data_block[2] & (1 << kITOverscan)) ||
    126           (data_block[2] & (1 << kCEOverscan))) {
    127         *flag = true;
    128       } else {
    129         *flag = false;
    130       }
    131       return true;
    132     }
    133   }
    134 
    135   return false;
    136 }
    137 
    138 bool IsInternalOutputName(const std::string& name) {
    139   return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0 ||
    140       name.find(kInternal_DSI) == 0;
    141 }
    142 
    143 const XRRModeInfo* FindXRRModeInfo(const XRRScreenResources* screen_resources,
    144                                    XID current_mode) {
    145   for (int m = 0; m < screen_resources->nmode; m++) {
    146     XRRModeInfo *mode = &screen_resources->modes[m];
    147     if (mode->id == current_mode)
    148       return mode;
    149   }
    150   return NULL;
    151 }
    152 
    153 namespace test {
    154 
    155 XRRModeInfo CreateModeInfo(int id,
    156                            int width,
    157                            int height,
    158                            bool interlaced,
    159                            float refresh_rate) {
    160   XRRModeInfo mode_info = {0};
    161   mode_info.id = id;
    162   mode_info.width = width;
    163   mode_info.height = height;
    164   if (interlaced)
    165     mode_info.modeFlags = RR_Interlace;
    166   if (refresh_rate != 0.0f) {
    167     mode_info.hTotal = 1;
    168     mode_info.vTotal = 1;
    169     mode_info.dotClock = refresh_rate;
    170   }
    171   return mode_info;
    172 }
    173 
    174 }  // namespace test
    175 
    176 }  // namespace chromeos
    177