1 // Copyright 2016 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fpdfapi/page/cpdf_color.h"
8
9 #include <optional>
10 #include <utility>
11
12 #include "core/fpdfapi/page/cpdf_patterncs.h"
13 #include "core/fxcrt/check.h"
14 #include "core/fxcrt/check_op.h"
15
16 CPDF_Color::CPDF_Color() = default;
17
CPDF_Color(const CPDF_Color & that)18 CPDF_Color::CPDF_Color(const CPDF_Color& that) {
19 *this = that;
20 }
21
22 CPDF_Color::~CPDF_Color() = default;
23
IsNull() const24 bool CPDF_Color::IsNull() const {
25 return absl::holds_alternative<absl::monostate>(color_data_);
26 }
27
IsPattern() const28 bool CPDF_Color::IsPattern() const {
29 return cs_ && IsPatternInternal();
30 }
31
IsPatternInternal() const32 bool CPDF_Color::IsPatternInternal() const {
33 return cs_->GetFamily() == CPDF_ColorSpace::Family::kPattern;
34 }
35
SetColorSpace(RetainPtr<CPDF_ColorSpace> colorspace)36 void CPDF_Color::SetColorSpace(RetainPtr<CPDF_ColorSpace> colorspace) {
37 cs_ = std::move(colorspace);
38 if (IsPatternInternal()) {
39 color_data_ = std::make_unique<PatternValue>();
40 } else {
41 color_data_ = cs_->CreateBufAndSetDefaultColor();
42 }
43 }
44
SetValueForNonPattern(std::vector<float> values)45 void CPDF_Color::SetValueForNonPattern(std::vector<float> values) {
46 CHECK(!IsPatternInternal());
47 CHECK_LE(cs_->ComponentCount(), values.size());
48 color_data_ = std::move(values);
49 }
50
SetValueForPattern(RetainPtr<CPDF_Pattern> pattern,pdfium::span<float> values)51 void CPDF_Color::SetValueForPattern(RetainPtr<CPDF_Pattern> pattern,
52 pdfium::span<float> values) {
53 if (values.size() > kMaxPatternColorComps) {
54 return;
55 }
56
57 if (!IsPattern()) {
58 SetColorSpace(
59 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kPattern));
60 }
61
62 auto& pattern_value = absl::get<std::unique_ptr<PatternValue>>(color_data_);
63 pattern_value->SetPattern(std::move(pattern));
64 pattern_value->SetComps(values);
65 }
66
operator =(const CPDF_Color & that)67 CPDF_Color& CPDF_Color::operator=(const CPDF_Color& that) {
68 if (this == &that) {
69 return *this;
70 }
71
72 cs_ = that.cs_;
73
74 if (absl::holds_alternative<std::vector<float>>(that.color_data_)) {
75 color_data_ = absl::get<std::vector<float>>(that.color_data_);
76 } else if (absl::holds_alternative<std::unique_ptr<PatternValue>>(
77 that.color_data_)) {
78 auto& pattern_value =
79 absl::get<std::unique_ptr<PatternValue>>(that.color_data_);
80 color_data_ = std::make_unique<PatternValue>(*pattern_value);
81 } else {
82 color_data_ = absl::monostate();
83 }
84
85 return *this;
86 }
87
ComponentCount() const88 uint32_t CPDF_Color::ComponentCount() const {
89 return cs_->ComponentCount();
90 }
91
IsColorSpaceRGB() const92 bool CPDF_Color::IsColorSpaceRGB() const {
93 return cs_ ==
94 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceRGB);
95 }
96
IsColorSpaceGray() const97 bool CPDF_Color::IsColorSpaceGray() const {
98 return cs_ ==
99 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray);
100 }
101
GetColorRef() const102 std::optional<FX_COLORREF> CPDF_Color::GetColorRef() const {
103 std::optional<FX_RGB_STRUCT<float>> maybe_rgb = GetRGB();
104 if (!maybe_rgb.has_value()) {
105 return std::nullopt;
106 }
107
108 const float r = std::clamp(maybe_rgb.value().red, 0.0f, 1.0f);
109 const float g = std::clamp(maybe_rgb.value().green, 0.0f, 1.0f);
110 const float b = std::clamp(maybe_rgb.value().blue, 0.0f, 1.0f);
111 return FXSYS_BGR(FXSYS_roundf(b * 255.0f), FXSYS_roundf(g * 255.0f),
112 FXSYS_roundf(r * 255.0f));
113 }
114
GetRGB() const115 std::optional<FX_RGB_STRUCT<float>> CPDF_Color::GetRGB() const {
116 if (IsPatternInternal()) {
117 if (absl::holds_alternative<std::unique_ptr<PatternValue>>(color_data_)) {
118 const auto& pattern_value =
119 absl::get<std::unique_ptr<PatternValue>>(color_data_);
120 return cs_->AsPatternCS()->GetPatternRGB(*pattern_value);
121 }
122 } else {
123 if (absl::holds_alternative<std::vector<float>>(color_data_)) {
124 const auto& buffer = absl::get<std::vector<float>>(color_data_);
125 return cs_->GetRGB(buffer);
126 }
127 }
128 return std::nullopt;
129 }
130
GetPattern() const131 RetainPtr<CPDF_Pattern> CPDF_Color::GetPattern() const {
132 DCHECK(IsPattern());
133
134 const auto& pattern_value =
135 absl::get<std::unique_ptr<PatternValue>>(color_data_);
136 return pattern_value->GetPattern();
137 }
138