Home | History | Annotate | Download | only in x11
      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
      3 // found in the LICENSE file.
      4 
      5 #include "ui/display/chromeos/x11/native_display_delegate_x11.h"
      6 
      7 #include <X11/Xatom.h>
      8 #include <X11/Xlib.h>
      9 #include <X11/extensions/dpms.h>
     10 #include <X11/extensions/Xrandr.h>
     11 #include <X11/extensions/XInput2.h>
     12 
     13 #include <utility>
     14 
     15 #include "base/logging.h"
     16 #include "base/stl_util.h"
     17 #include "ui/display/chromeos/x11/display_mode_x11.h"
     18 #include "ui/display/chromeos/x11/display_snapshot_x11.h"
     19 #include "ui/display/chromeos/x11/display_util_x11.h"
     20 #include "ui/display/chromeos/x11/native_display_event_dispatcher_x11.h"
     21 #include "ui/display/types/chromeos/native_display_observer.h"
     22 #include "ui/display/util/x11/edid_parser_x11.h"
     23 #include "ui/events/platform/platform_event_observer.h"
     24 #include "ui/events/platform/platform_event_source.h"
     25 #include "ui/gfx/geometry/rect.h"
     26 #include "ui/gfx/x/x11_error_tracker.h"
     27 #include "ui/gfx/x/x11_types.h"
     28 
     29 namespace ui {
     30 
     31 namespace {
     32 
     33 // DPI measurements.
     34 const float kMmInInch = 25.4;
     35 const float kDpi96 = 96.0;
     36 const float kPixelsToMmScale = kMmInInch / kDpi96;
     37 
     38 const char kContentProtectionAtomName[] = "Content Protection";
     39 const char kProtectionUndesiredAtomName[] = "Undesired";
     40 const char kProtectionDesiredAtomName[] = "Desired";
     41 const char kProtectionEnabledAtomName[] = "Enabled";
     42 
     43 RRMode GetOutputNativeMode(const XRROutputInfo* output_info) {
     44   return output_info->nmode > 0 ? output_info->modes[0] : None;
     45 }
     46 
     47 XRRCrtcGamma* ResampleGammaRamp(XRRCrtcGamma* gamma_ramp, int gamma_ramp_size) {
     48   if (gamma_ramp->size == gamma_ramp_size)
     49     return gamma_ramp;
     50 
     51 #define RESAMPLE(array, i, r) \
     52   array[i] + (array[i + 1] - array[i]) * r / gamma_ramp_size
     53 
     54   XRRCrtcGamma* resampled = XRRAllocGamma(gamma_ramp_size);
     55   for (int i = 0; i < gamma_ramp_size; ++i) {
     56     int base_index = gamma_ramp->size * i / gamma_ramp_size;
     57     int remaining = gamma_ramp->size * i % gamma_ramp_size;
     58     if (base_index < gamma_ramp->size - 1) {
     59       resampled->red[i] = RESAMPLE(gamma_ramp->red, base_index, remaining);
     60       resampled->green[i] = RESAMPLE(gamma_ramp->green, base_index, remaining);
     61       resampled->blue[i] = RESAMPLE(gamma_ramp->blue, base_index, remaining);
     62     } else {
     63       resampled->red[i] = gamma_ramp->red[gamma_ramp->size - 1];
     64       resampled->green[i] = gamma_ramp->green[gamma_ramp->size - 1];
     65       resampled->blue[i] = gamma_ramp->blue[gamma_ramp->size - 1];
     66     }
     67   }
     68 
     69 #undef RESAMPLE
     70   XRRFreeGamma(gamma_ramp);
     71   return resampled;
     72 }
     73 
     74 }  // namespace
     75 
     76 ////////////////////////////////////////////////////////////////////////////////
     77 // NativeDisplayDelegateX11::HelperDelegateX11
     78 
     79 class NativeDisplayDelegateX11::HelperDelegateX11
     80     : public NativeDisplayDelegateX11::HelperDelegate {
     81  public:
     82   HelperDelegateX11(NativeDisplayDelegateX11* delegate) : delegate_(delegate) {}
     83   virtual ~HelperDelegateX11() {}
     84 
     85   // NativeDisplayDelegateX11::HelperDelegate overrides:
     86   virtual void UpdateXRandRConfiguration(const base::NativeEvent& event)
     87       OVERRIDE {
     88     XRRUpdateConfiguration(event);
     89   }
     90   virtual const std::vector<DisplaySnapshot*>& GetCachedDisplays() const
     91       OVERRIDE {
     92     return delegate_->cached_outputs_.get();
     93   }
     94   virtual void NotifyDisplayObservers() OVERRIDE {
     95     FOR_EACH_OBSERVER(
     96         NativeDisplayObserver, delegate_->observers_, OnConfigurationChanged());
     97   }
     98 
     99  private:
    100   NativeDisplayDelegateX11* delegate_;
    101 
    102   DISALLOW_COPY_AND_ASSIGN(HelperDelegateX11);
    103 };
    104 
    105 ////////////////////////////////////////////////////////////////////////////////
    106 // NativeDisplayDelegateX11::PlatformEventObserverX11
    107 
    108 class NativeDisplayDelegateX11::PlatformEventObserverX11
    109     : public PlatformEventObserver {
    110  public:
    111   PlatformEventObserverX11(HelperDelegate* delegate);
    112   virtual ~PlatformEventObserverX11();
    113 
    114   // PlatformEventObserverX11:
    115   virtual void WillProcessEvent(const ui::PlatformEvent& event) OVERRIDE;
    116   virtual void DidProcessEvent(const ui::PlatformEvent& event) OVERRIDE;
    117 
    118  private:
    119   HelperDelegate* delegate_;  // Not owned.
    120 
    121   DISALLOW_COPY_AND_ASSIGN(PlatformEventObserverX11);
    122 };
    123 
    124 NativeDisplayDelegateX11::PlatformEventObserverX11::PlatformEventObserverX11(
    125     HelperDelegate* delegate)
    126     : delegate_(delegate) {}
    127 
    128 NativeDisplayDelegateX11::PlatformEventObserverX11::
    129     ~PlatformEventObserverX11() {}
    130 
    131 void NativeDisplayDelegateX11::PlatformEventObserverX11::WillProcessEvent(
    132     const ui::PlatformEvent& event) {
    133   // XI_HierarchyChanged events are special. There is no window associated with
    134   // these events. So process them directly from here.
    135   if (event->type == GenericEvent &&
    136       event->xgeneric.evtype == XI_HierarchyChanged) {
    137     VLOG(1) << "Received XI_HierarchyChanged event";
    138     // Defer configuring outputs to not stall event processing.
    139     // This also takes care of same event being received twice.
    140     delegate_->NotifyDisplayObservers();
    141   }
    142 }
    143 
    144 void NativeDisplayDelegateX11::PlatformEventObserverX11::DidProcessEvent(
    145     const ui::PlatformEvent& event) {}
    146 
    147 ////////////////////////////////////////////////////////////////////////////////
    148 // NativeDisplayDelegateX11 implementation:
    149 
    150 NativeDisplayDelegateX11::NativeDisplayDelegateX11()
    151     : display_(gfx::GetXDisplay()),
    152       window_(DefaultRootWindow(display_)),
    153       screen_(NULL),
    154       background_color_argb_(0) {}
    155 
    156 NativeDisplayDelegateX11::~NativeDisplayDelegateX11() {
    157   if (ui::PlatformEventSource::GetInstance()) {
    158     ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(
    159         platform_event_dispatcher_.get());
    160     ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(
    161         platform_event_observer_.get());
    162   }
    163 
    164   STLDeleteContainerPairSecondPointers(modes_.begin(), modes_.end());
    165 }
    166 
    167 void NativeDisplayDelegateX11::Initialize() {
    168   int error_base_ignored = 0;
    169   int xrandr_event_base = 0;
    170   XRRQueryExtension(display_, &xrandr_event_base, &error_base_ignored);
    171 
    172   helper_delegate_.reset(new HelperDelegateX11(this));
    173   platform_event_dispatcher_.reset(new NativeDisplayEventDispatcherX11(
    174       helper_delegate_.get(), xrandr_event_base));
    175   platform_event_observer_.reset(
    176       new PlatformEventObserverX11(helper_delegate_.get()));
    177 
    178   if (ui::PlatformEventSource::GetInstance()) {
    179     ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(
    180         platform_event_dispatcher_.get());
    181 
    182     // We can't do this with a root window listener because XI_HierarchyChanged
    183     // messages don't have a target window.
    184     ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(
    185         platform_event_observer_.get());
    186   }
    187 }
    188 
    189 void NativeDisplayDelegateX11::GrabServer() {
    190   CHECK(!screen_) << "Server already grabbed";
    191   XGrabServer(display_);
    192   screen_ = XRRGetScreenResources(display_, window_);
    193   CHECK(screen_);
    194 }
    195 
    196 void NativeDisplayDelegateX11::UngrabServer() {
    197   CHECK(screen_) << "Server not grabbed";
    198   XRRFreeScreenResources(screen_);
    199   screen_ = NULL;
    200   XUngrabServer(display_);
    201   // crbug.com/366125
    202   XFlush(display_);
    203 }
    204 
    205 void NativeDisplayDelegateX11::SyncWithServer() { XSync(display_, 0); }
    206 
    207 void NativeDisplayDelegateX11::SetBackgroundColor(uint32_t color_argb) {
    208   background_color_argb_ = color_argb;
    209 }
    210 
    211 void NativeDisplayDelegateX11::ForceDPMSOn() {
    212   CHECK(DPMSEnable(display_));
    213   CHECK(DPMSForceLevel(display_, DPMSModeOn));
    214 }
    215 
    216 std::vector<DisplaySnapshot*> NativeDisplayDelegateX11::GetDisplays() {
    217   CHECK(screen_) << "Server not grabbed";
    218 
    219   cached_outputs_.clear();
    220   RRCrtc last_used_crtc = None;
    221 
    222   InitModes();
    223   for (int i = 0; i < screen_->noutput && cached_outputs_.size() < 2; ++i) {
    224     RROutput output_id = screen_->outputs[i];
    225     XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_, output_id);
    226     if (output_info->connection == RR_Connected) {
    227       DisplaySnapshotX11* output =
    228           InitDisplaySnapshot(output_id, output_info, &last_used_crtc, i);
    229       cached_outputs_.push_back(output);
    230     }
    231     XRRFreeOutputInfo(output_info);
    232   }
    233 
    234   return cached_outputs_.get();
    235 }
    236 
    237 void NativeDisplayDelegateX11::AddMode(const DisplaySnapshot& output,
    238                                        const DisplayMode* mode) {
    239   CHECK(screen_) << "Server not grabbed";
    240   CHECK(mode) << "Must add valid mode";
    241 
    242   const DisplaySnapshotX11& x11_output =
    243       static_cast<const DisplaySnapshotX11&>(output);
    244   RRMode mode_id = static_cast<const DisplayModeX11*>(mode)->mode_id();
    245 
    246   VLOG(1) << "AddDisplayMode: output=" << x11_output.output()
    247           << " mode=" << mode_id;
    248   XRRAddOutputMode(display_, x11_output.output(), mode_id);
    249 }
    250 
    251 bool NativeDisplayDelegateX11::Configure(const DisplaySnapshot& output,
    252                                          const DisplayMode* mode,
    253                                          const gfx::Point& origin) {
    254   const DisplaySnapshotX11& x11_output =
    255       static_cast<const DisplaySnapshotX11&>(output);
    256   RRMode mode_id = None;
    257   if (mode)
    258     mode_id = static_cast<const DisplayModeX11*>(mode)->mode_id();
    259 
    260   return ConfigureCrtc(
    261       x11_output.crtc(), mode_id, x11_output.output(), origin.x(), origin.y());
    262 }
    263 
    264 bool NativeDisplayDelegateX11::ConfigureCrtc(RRCrtc crtc,
    265                                              RRMode mode,
    266                                              RROutput output,
    267                                              int x,
    268                                              int y) {
    269   CHECK(screen_) << "Server not grabbed";
    270   VLOG(1) << "ConfigureCrtc: crtc=" << crtc << " mode=" << mode
    271           << " output=" << output << " x=" << x << " y=" << y;
    272   // Xrandr.h is full of lies. XRRSetCrtcConfig() is defined as returning a
    273   // Status, which is typically 0 for failure and 1 for success. In
    274   // actuality it returns a RRCONFIGSTATUS, which uses 0 for success.
    275   if (XRRSetCrtcConfig(display_,
    276                        screen_,
    277                        crtc,
    278                        CurrentTime,
    279                        x,
    280                        y,
    281                        mode,
    282                        RR_Rotate_0,
    283                        (output && mode) ? &output : NULL,
    284                        (output && mode) ? 1 : 0) != RRSetConfigSuccess) {
    285     LOG(WARNING) << "Unable to configure CRTC " << crtc << ":"
    286                  << " mode=" << mode << " output=" << output << " x=" << x
    287                  << " y=" << y;
    288     return false;
    289   }
    290 
    291   return true;
    292 }
    293 
    294 void NativeDisplayDelegateX11::CreateFrameBuffer(const gfx::Size& size) {
    295   CHECK(screen_) << "Server not grabbed";
    296   gfx::Size current_screen_size(
    297       DisplayWidth(display_, DefaultScreen(display_)),
    298       DisplayHeight(display_, DefaultScreen(display_)));
    299 
    300   VLOG(1) << "CreateFrameBuffer: new=" << size.ToString()
    301           << " current=" << current_screen_size.ToString();
    302 
    303   DestroyUnusedCrtcs();
    304 
    305   if (size == current_screen_size)
    306     return;
    307 
    308   gfx::Size min_screen_size(current_screen_size);
    309   min_screen_size.SetToMin(size);
    310   UpdateCrtcsForNewFramebuffer(min_screen_size);
    311 
    312   int mm_width = size.width() * kPixelsToMmScale;
    313   int mm_height = size.height() * kPixelsToMmScale;
    314   XRRSetScreenSize(
    315       display_, window_, size.width(), size.height(), mm_width, mm_height);
    316   // We don't wait for root window resize, therefore this end up with drawing
    317   // in the old window size, which we care during the boot.
    318   DrawBackground();
    319 
    320   // Don't redraw the background upon framebuffer change again. This should
    321   // happen only once after boot.
    322   background_color_argb_ = 0;
    323 }
    324 
    325 void NativeDisplayDelegateX11::AddObserver(NativeDisplayObserver* observer) {
    326   observers_.AddObserver(observer);
    327 }
    328 
    329 void NativeDisplayDelegateX11::RemoveObserver(NativeDisplayObserver* observer) {
    330   observers_.RemoveObserver(observer);
    331 }
    332 
    333 void NativeDisplayDelegateX11::InitModes() {
    334   CHECK(screen_) << "Server not grabbed";
    335 
    336   STLDeleteContainerPairSecondPointers(modes_.begin(), modes_.end());
    337   modes_.clear();
    338 
    339   for (int i = 0; i < screen_->nmode; ++i) {
    340     const XRRModeInfo& info = screen_->modes[i];
    341     float refresh_rate = 0.0f;
    342     if (info.hTotal && info.vTotal) {
    343       refresh_rate =
    344           static_cast<float>(info.dotClock) /
    345           (static_cast<float>(info.hTotal) * static_cast<float>(info.vTotal));
    346     }
    347 
    348     modes_.insert(
    349         std::make_pair(info.id,
    350                        new DisplayModeX11(gfx::Size(info.width, info.height),
    351                                           info.modeFlags & RR_Interlace,
    352                                           refresh_rate,
    353                                           info.id)));
    354   }
    355 }
    356 
    357 DisplaySnapshotX11* NativeDisplayDelegateX11::InitDisplaySnapshot(
    358     RROutput id,
    359     XRROutputInfo* info,
    360     RRCrtc* last_used_crtc,
    361     int index) {
    362   int64_t display_id = 0;
    363   bool has_display_id = GetDisplayId(
    364       id, static_cast<uint8_t>(index), &display_id);
    365 
    366   bool has_overscan = false;
    367   GetOutputOverscanFlag(id, &has_overscan);
    368 
    369   DisplayConnectionType type = GetDisplayConnectionTypeFromName(info->name);
    370   if (type == DISPLAY_CONNECTION_TYPE_UNKNOWN)
    371     LOG(ERROR) << "Unknown link type: " << info->name;
    372 
    373   // Use the index as a valid display ID even if the internal
    374   // display doesn't have valid EDID because the index
    375   // will never change.
    376   if (!has_display_id) {
    377     if (type == DISPLAY_CONNECTION_TYPE_INTERNAL)
    378       has_display_id = true;
    379 
    380     // Fallback to output index.
    381     display_id = index;
    382   }
    383 
    384   RRMode native_mode_id = GetOutputNativeMode(info);
    385   RRMode current_mode_id = None;
    386   gfx::Point origin;
    387   if (info->crtc) {
    388     XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(display_, screen_, info->crtc);
    389     current_mode_id = crtc_info->mode;
    390     origin.SetPoint(crtc_info->x, crtc_info->y);
    391     XRRFreeCrtcInfo(crtc_info);
    392   }
    393 
    394   RRCrtc crtc = None;
    395   // Assign a CRTC that isn't already in use.
    396   for (int i = 0; i < info->ncrtc; ++i) {
    397     if (info->crtcs[i] != *last_used_crtc) {
    398       crtc = info->crtcs[i];
    399       *last_used_crtc = crtc;
    400       break;
    401     }
    402   }
    403 
    404   const DisplayMode* current_mode = NULL;
    405   const DisplayMode* native_mode = NULL;
    406   std::vector<const DisplayMode*> display_modes;
    407 
    408   for (int i = 0; i < info->nmode; ++i) {
    409     const RRMode mode = info->modes[i];
    410     if (modes_.find(mode) != modes_.end()) {
    411       display_modes.push_back(modes_.at(mode));
    412 
    413       if (mode == current_mode_id)
    414         current_mode = display_modes.back();
    415       if (mode == native_mode_id)
    416         native_mode = display_modes.back();
    417     } else {
    418       LOG(WARNING) << "Unable to find XRRModeInfo for mode " << mode;
    419     }
    420   }
    421 
    422   DisplaySnapshotX11* output =
    423       new DisplaySnapshotX11(display_id,
    424                              has_display_id,
    425                              origin,
    426                              gfx::Size(info->mm_width, info->mm_height),
    427                              type,
    428                              IsOutputAspectPreservingScaling(id),
    429                              has_overscan,
    430                              GetDisplayName(id),
    431                              display_modes,
    432                              current_mode,
    433                              native_mode,
    434                              id,
    435                              crtc,
    436                              index);
    437 
    438   VLOG(2) << "Found display " << cached_outputs_.size() << ":"
    439           << " output=" << output << " crtc=" << crtc
    440           << " current_mode=" << current_mode_id;
    441 
    442   return output;
    443 }
    444 
    445 bool NativeDisplayDelegateX11::GetHDCPState(const DisplaySnapshot& output,
    446                                             HDCPState* state) {
    447   unsigned char* values = NULL;
    448   int actual_format = 0;
    449   unsigned long nitems = 0;
    450   unsigned long bytes_after = 0;
    451   Atom actual_type = None;
    452   int success = 0;
    453   RROutput output_id = static_cast<const DisplaySnapshotX11&>(output).output();
    454   // TODO(kcwu): Use X11AtomCache to save round trip time of XInternAtom.
    455   Atom prop = XInternAtom(display_, kContentProtectionAtomName, False);
    456 
    457   bool ok = true;
    458   // TODO(kcwu): Move this to x11_util (similar method calls in this file and
    459   // output_util.cc)
    460   success = XRRGetOutputProperty(display_,
    461                                  output_id,
    462                                  prop,
    463                                  0,
    464                                  100,
    465                                  False,
    466                                  False,
    467                                  AnyPropertyType,
    468                                  &actual_type,
    469                                  &actual_format,
    470                                  &nitems,
    471                                  &bytes_after,
    472                                  &values);
    473   if (actual_type == None) {
    474     LOG(ERROR) << "Property '" << kContentProtectionAtomName
    475                << "' does not exist";
    476     ok = false;
    477   } else if (success == Success && actual_type == XA_ATOM &&
    478              actual_format == 32 && nitems == 1) {
    479     Atom value = reinterpret_cast<Atom*>(values)[0];
    480     if (value == XInternAtom(display_, kProtectionUndesiredAtomName, False)) {
    481       *state = HDCP_STATE_UNDESIRED;
    482     } else if (value ==
    483                XInternAtom(display_, kProtectionDesiredAtomName, False)) {
    484       *state = HDCP_STATE_DESIRED;
    485     } else if (value ==
    486                XInternAtom(display_, kProtectionEnabledAtomName, False)) {
    487       *state = HDCP_STATE_ENABLED;
    488     } else {
    489       LOG(ERROR) << "Unknown " << kContentProtectionAtomName
    490                  << " value: " << value;
    491       ok = false;
    492     }
    493   } else {
    494     LOG(ERROR) << "XRRGetOutputProperty failed";
    495     ok = false;
    496   }
    497   if (values)
    498     XFree(values);
    499 
    500   VLOG(3) << "HDCP state: " << ok << "," << *state;
    501   return ok;
    502 }
    503 
    504 bool NativeDisplayDelegateX11::SetHDCPState(const DisplaySnapshot& output,
    505                                             HDCPState state) {
    506   Atom name = XInternAtom(display_, kContentProtectionAtomName, False);
    507   Atom value = None;
    508   switch (state) {
    509     case HDCP_STATE_UNDESIRED:
    510       value = XInternAtom(display_, kProtectionUndesiredAtomName, False);
    511       break;
    512     case HDCP_STATE_DESIRED:
    513       value = XInternAtom(display_, kProtectionDesiredAtomName, False);
    514       break;
    515     default:
    516       NOTREACHED() << "Invalid HDCP state: " << state;
    517       return false;
    518   }
    519   gfx::X11ErrorTracker err_tracker;
    520   unsigned char* data = reinterpret_cast<unsigned char*>(&value);
    521   RROutput output_id = static_cast<const DisplaySnapshotX11&>(output).output();
    522   XRRChangeOutputProperty(
    523       display_, output_id, name, XA_ATOM, 32, PropModeReplace, data, 1);
    524   if (err_tracker.FoundNewError()) {
    525     LOG(ERROR) << "XRRChangeOutputProperty failed";
    526     return false;
    527   } else {
    528     return true;
    529   }
    530 }
    531 
    532 void NativeDisplayDelegateX11::DestroyUnusedCrtcs() {
    533   CHECK(screen_) << "Server not grabbed";
    534 
    535   for (int i = 0; i < screen_->ncrtc; ++i) {
    536     bool in_use = false;
    537     for (ScopedVector<DisplaySnapshot>::const_iterator it =
    538              cached_outputs_.begin();
    539          it != cached_outputs_.end();
    540          ++it) {
    541       DisplaySnapshotX11* x11_output = static_cast<DisplaySnapshotX11*>(*it);
    542       if (screen_->crtcs[i] == x11_output->crtc()) {
    543         in_use = true;
    544         break;
    545       }
    546     }
    547 
    548     if (!in_use)
    549       ConfigureCrtc(screen_->crtcs[i], None, None, 0, 0);
    550   }
    551 }
    552 
    553 void NativeDisplayDelegateX11::UpdateCrtcsForNewFramebuffer(
    554     const gfx::Size& min_screen_size) {
    555   CHECK(screen_) << "Server not grabbed";
    556   // Setting the screen size will fail if any CRTC doesn't fit afterwards.
    557   // At the same time, turning CRTCs off and back on uses up a lot of time.
    558   // This function tries to be smart to avoid too many off/on cycles:
    559   // - We set the new modes on CRTCs, if they fit in both the old and new
    560   //   FBs, and park them at (0,0)
    561   // - We disable the CRTCs we will need but don't fit in the old FB. Those
    562   //   will be reenabled after the resize.
    563   // We don't worry about the cached state of the outputs here since we are
    564   // not interested in the state we are setting - we just try to get the CRTCs
    565   // out of the way so we can rebuild the frame buffer.
    566   gfx::Rect fb_rect(min_screen_size);
    567   for (ScopedVector<DisplaySnapshot>::const_iterator it =
    568            cached_outputs_.begin();
    569        it != cached_outputs_.end();
    570        ++it) {
    571     DisplaySnapshotX11* x11_output = static_cast<DisplaySnapshotX11*>(*it);
    572     const DisplayMode* mode_info = x11_output->current_mode();
    573     RROutput output = x11_output->output();
    574     RRMode mode = None;
    575 
    576     if (mode_info) {
    577       mode = static_cast<const DisplayModeX11*>(mode_info)->mode_id();
    578 
    579       if (!fb_rect.Contains(gfx::Rect(mode_info->size()))) {
    580         // In case our CRTC doesn't fit in common area of our current and about
    581         // to be resized framebuffer, disable it.
    582         // It'll get reenabled after we resize the framebuffer.
    583         mode = None;
    584         output = None;
    585         mode_info = NULL;
    586       }
    587     }
    588 
    589     ConfigureCrtc(x11_output->crtc(), mode, output, 0, 0);
    590   }
    591 }
    592 
    593 bool NativeDisplayDelegateX11::IsOutputAspectPreservingScaling(RROutput id) {
    594   bool ret = false;
    595 
    596   Atom scaling_prop = XInternAtom(display_, "scaling mode", False);
    597   Atom full_aspect_atom = XInternAtom(display_, "Full aspect", False);
    598   if (scaling_prop == None || full_aspect_atom == None)
    599     return false;
    600 
    601   int nprop = 0;
    602   Atom* props = XRRListOutputProperties(display_, id, &nprop);
    603   for (int j = 0; j < nprop && !ret; j++) {
    604     Atom prop = props[j];
    605     if (scaling_prop == prop) {
    606       unsigned char* values = NULL;
    607       int actual_format;
    608       unsigned long nitems;
    609       unsigned long bytes_after;
    610       Atom actual_type;
    611       int success;
    612 
    613       success = XRRGetOutputProperty(display_,
    614                                      id,
    615                                      prop,
    616                                      0,
    617                                      100,
    618                                      False,
    619                                      False,
    620                                      AnyPropertyType,
    621                                      &actual_type,
    622                                      &actual_format,
    623                                      &nitems,
    624                                      &bytes_after,
    625                                      &values);
    626       if (success == Success && actual_type == XA_ATOM && actual_format == 32 &&
    627           nitems == 1) {
    628         Atom value = reinterpret_cast<Atom*>(values)[0];
    629         if (full_aspect_atom == value)
    630           ret = true;
    631       }
    632       if (values)
    633         XFree(values);
    634     }
    635   }
    636   if (props)
    637     XFree(props);
    638 
    639   return ret;
    640 }
    641 
    642 
    643 std::vector<ColorCalibrationProfile>
    644 NativeDisplayDelegateX11::GetAvailableColorCalibrationProfiles(
    645     const DisplaySnapshot& output) {
    646   // TODO(mukai|marcheu): Checks the system data and fills the result.
    647   // Note that the order would be Dynamic -> Standard -> Movie -> Reading.
    648   return std::vector<ColorCalibrationProfile>();
    649 }
    650 
    651 bool NativeDisplayDelegateX11::SetColorCalibrationProfile(
    652     const DisplaySnapshot& output,
    653     ColorCalibrationProfile new_profile) {
    654   const DisplaySnapshotX11& x11_output =
    655       static_cast<const DisplaySnapshotX11&>(output);
    656 
    657   XRRCrtcGamma* gamma_ramp = CreateGammaRampForProfile(x11_output, new_profile);
    658 
    659   if (!gamma_ramp)
    660     return false;
    661 
    662   int gamma_ramp_size = XRRGetCrtcGammaSize(display_, x11_output.crtc());
    663   XRRSetCrtcGamma(display_,
    664                   x11_output.crtc(),
    665                   ResampleGammaRamp(gamma_ramp, gamma_ramp_size));
    666   XRRFreeGamma(gamma_ramp);
    667   return true;
    668 }
    669 
    670 XRRCrtcGamma* NativeDisplayDelegateX11::CreateGammaRampForProfile(
    671     const DisplaySnapshotX11& x11_output,
    672     ColorCalibrationProfile new_profile) {
    673   // TODO(mukai|marcheu): Creates the appropriate gamma ramp data from the
    674   // profile enum. It would be served by the vendor.
    675   return NULL;
    676 }
    677 
    678 void NativeDisplayDelegateX11::DrawBackground() {
    679   if (!background_color_argb_)
    680     return;
    681   // Configuring CRTCs/Framebuffer clears the boot screen image.  Paint the
    682   // same background color after updating framebuffer to minimize the
    683   // duration of black screen at boot time.
    684   XColor color;
    685   Colormap colormap = DefaultColormap(display_, 0);
    686   // XColor uses 16 bits per color.
    687   color.red = (background_color_argb_ & 0x00FF0000) >> 8;
    688   color.green = (background_color_argb_ & 0x0000FF00);
    689   color.blue = (background_color_argb_ & 0x000000FF) << 8;
    690   color.flags = DoRed | DoGreen | DoBlue;
    691   XAllocColor(display_, colormap, &color);
    692 
    693   GC gc = XCreateGC(display_, window_, 0, 0);
    694   XSetForeground(display_, gc, color.pixel);
    695   XSetFillStyle(display_, gc, FillSolid);
    696   int width = DisplayWidth(display_, DefaultScreen(display_));
    697   int height = DisplayHeight(display_, DefaultScreen(display_));
    698   XFillRectangle(display_, window_, gc, 0, 0, width, height);
    699   XFreeGC(display_, gc);
    700   XFreeColors(display_, colormap, &color.pixel, 1, 0);
    701 }
    702 
    703 }  // namespace ui
    704