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