chromium/ash/display/display_color_manager.h

// 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_