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