1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166

ash / display / display_color_manager.h [blame]

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef ASH_DISPLAY_DISPLAY_COLOR_MANAGER_H_
#define ASH_DISPLAY_DISPLAY_COLOR_MANAGER_H_

#include <stdint.h>

#include <memory>
#include <vector>

#include "ash/ash_export.h"
#include "base/containers/flat_map.h"
#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "third_party/skia/include/core/SkM44.h"
#include "ui/display/display_observer.h"
#include "ui/display/manager/display_configurator.h"
#include "ui/display/types/display_color_management.h"
#include "ui/display/types/display_constants.h"

namespace base {
class SequencedTaskRunner;
}

namespace display {
class DisplaySnapshot;
}  // namespace display

namespace ash {

// An object that observes changes in display configuration applies any color
// calibration where needed.
class ASH_EXPORT DisplayColorManager
    : public display::DisplayConfigurator::Observer,
      public display::DisplayObserver {
 public:
  // The type of CRTC color transform matrix (CTM) support for the currently
  // connected displays.
  // WARNING: These values are persisted to logs. Entries should not be
  // renumbered and numeric values should never be reused.
  enum class DisplayCtmSupport {
    // All connected displays don't support CRTC CTMs.
    kNone = 0,
    // Mixed support; some displays support CRTC CTMs while others don't.
    kMixed = 1,
    // All connected displays support CRTC CTMs.
    kAll = 2,
    kMaxValue = kAll,
  };

  explicit DisplayColorManager(display::DisplayConfigurator* configurator);

  DisplayColorManager(const DisplayColorManager&) = delete;
  DisplayColorManager& operator=(const DisplayColorManager&) = delete;

  ~DisplayColorManager() override;

  DisplayCtmSupport displays_ctm_support() const {
    return displays_ctm_support_;
  }

  // Sets the color temperature adjustment for |display_id|. Returns true if the
  // hardware supports this operation.
  bool SetDisplayColorTemperatureAdjustment(
      int64_t display_id,
      const display::ColorTemperatureAdjustment& cta);

  // display::DisplayConfigurator::Observer
  void OnDisplayConfigurationChanged(
      const display::DisplayConfigurator::DisplayStateList& outputs) override;
  void OnDisplayConfigurationChangeFailed(
      const display::DisplayConfigurator::DisplayStateList& displays,
      display::MultipleDisplayState failed_new_state) override {}

  // display::DisplayObserver:
  void OnDisplaysRemoved(const display::Displays& removed_displays) override;

 protected:
  virtual void FinishLoadCalibrationForDisplay(
      int64_t display_id,
      int64_t product_code,
      bool has_color_correction_matrix,
      display::DisplayConnectionType type,
      const base::FilePath& path,
      bool file_downloaded);
  virtual void UpdateCalibrationData(
      int64_t display_id,
      int64_t product_code,
      std::unique_ptr<display::ColorCalibration> data);

 private:
  friend class DisplayColorManagerTest;

  void ApplyDisplayColorCalibration(
      int64_t display_id,
      const display::ColorCalibration& calibration_data);

  // Attempts to start requesting the ICC profile for |display|. Returns true if
  // it was successful at initiating the request, false otherwise.
  // TODO(jchinlee): Investigate if we need this return value, or if we can
  // switch to a callback model.
  bool LoadCalibrationForDisplay(const display::DisplaySnapshot* display);

  // Display-specific calibration methods.
  // Look for VPD display profiles entry.
  bool HasVpdDisplayProfilesEntry(int64_t product_code) const;
  // Look for VPD-written calibration.
  void QueryVpdForCalibration(int64_t display_id,
                              int64_t product_code,
                              bool has_color_correction_matrix,
                              display::DisplayConnectionType type);
  void FinishQueryVpdForCalibration(int64_t display_id,
                                    int64_t product_code,
                                    bool has_color_correction_matrix,
                                    display::DisplayConnectionType type,
                                    const base::FilePath& expected_icc_path,
                                    bool found_icc);
  // Look for calibration for this display in Quirks.
  void QueryQuirksForCalibration(int64_t display_id,
                                 const std::string& display_name,
                                 int64_t product_code,
                                 bool has_color_correction_matrix,
                                 display::DisplayConnectionType type);

  // Applies an empty color calibration data, potentially with a color
  // matrix from |displays_color_matrix_map_| (if any for this display is
  // available). This is needed in cases we fail to load ICC profiles for
  // displays and we won't be getting any calibration data for them. We must
  // reset their configuration because some drivers hold on to it across screen
  // changes, https://crrev.com/1914343003.
  void ResetDisplayColorCalibration(int64_t display_id);

  raw_ptr<display::DisplayConfigurator> configurator_;

  // This is a pre-allocated storage in order to avoid re-allocating the
  // matrix array every time when converting a skia matrix to a matrix array.
  std::vector<float> matrix_buffer_;

  // Contains a per display color transform matrix that can be post-multiplied
  // by any available color calibration matrix for the corresponding display.
  // The key is the display ID.
  base::flat_map<int64_t, SkM44> displays_color_matrix_map_;

  // Maps a display's color calibration data by the display's product code as
  // the key.
  base::flat_map<int64_t, std::unique_ptr<display::ColorCalibration>>
      calibration_map_;

  SEQUENCE_CHECKER(sequence_checker_);
  scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;

  DisplayCtmSupport displays_ctm_support_;

  display::ScopedOptionalDisplayObserver display_observer_{this};

  // Factory for callbacks.
  base::WeakPtrFactory<DisplayColorManager> weak_ptr_factory_{this};
};

}  // namespace ash

#endif  // ASH_DISPLAY_DISPLAY_COLOR_MANAGER_H_