OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/display/fake_display_snapshot.h" | 5 #include "ui/display/fake_display_snapshot.h" |
6 | 6 |
7 #include <inttypes.h> | 7 #include <inttypes.h> |
8 | 8 |
9 #include <sstream> | 9 #include <sstream> |
10 #include <utility> | 10 #include <utility> |
11 #include <vector> | 11 #include <vector> |
12 | 12 |
13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
14 #include "base/strings/string_number_conversions.h" | |
15 #include "base/strings/string_split.h" | |
14 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
17 #include "third_party/re2/src/re2/re2.h" | |
18 | |
19 using base::StringPiece; | |
15 | 20 |
16 namespace display { | 21 namespace display { |
17 | 22 |
18 namespace { | 23 namespace { |
19 | 24 |
20 static const float kInchInMm = 25.4f; | 25 static const float kInchInMm = 25.4f; |
21 | 26 |
22 // Get pixel pitch in millimeters from DPI. | 27 // Get pixel pitch in millimeters from DPI. |
23 float PixelPitchMmFromDPI(float dpi) { | 28 float PixelPitchMmFromDPI(float dpi) { |
24 return (1.0f / dpi) * kInchInMm; | 29 return (1.0f / dpi) * kInchInMm; |
(...skipping 30 matching lines...) Expand all Loading... | |
55 return "dp"; | 60 return "dp"; |
56 case ui::DISPLAY_CONNECTION_TYPE_NETWORK: | 61 case ui::DISPLAY_CONNECTION_TYPE_NETWORK: |
57 return "network"; | 62 return "network"; |
58 case ui::DISPLAY_CONNECTION_TYPE_VIRTUAL: | 63 case ui::DISPLAY_CONNECTION_TYPE_VIRTUAL: |
59 return "virtual"; | 64 return "virtual"; |
60 } | 65 } |
61 NOTREACHED(); | 66 NOTREACHED(); |
62 return ""; | 67 return ""; |
63 } | 68 } |
64 | 69 |
70 // Extracts text after specified delimiter. If the delimiter doesn't exist then | |
Daniel Erat
2016/10/07 17:17:22
nit: "If the delimiter doesn't appear exactly once
kylechar
2016/10/11 13:56:49
Done.
| |
71 // the result will be empty and the input string will be unmodified. Otherwise, | |
72 // the input string will contain the text before the delimiter and the result | |
73 // will be the text after the delimiter. | |
74 StringPiece ExtractSuffix(StringPiece* str, StringPiece delimiter) { | |
75 std::vector<StringPiece> parts = base::SplitStringPiece( | |
76 *str, delimiter, base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
77 | |
78 if (parts.size() == 2) { | |
79 *str = parts[0]; | |
80 return parts[1]; | |
81 } | |
82 | |
83 return StringPiece(); | |
84 } | |
85 | |
86 // Parses a display mode from |str| in the format HxW[%R], returning null if | |
87 // |str| is invalid. | |
88 std::unique_ptr<ui::DisplayMode> ParseDisplayMode(const std::string& str) { | |
89 int width = 0; | |
90 int height = 0; | |
91 float refresh_rate = 60.0f; | |
92 | |
93 // With sscanf() it will happily ignore characters at the end of the string, | |
94 // so check |str| is valid using a regex. | |
95 if (!RE2::FullMatch(str, "\\d+x\\d+(?:%\\d+(?:\\.\\d*)?)?")) { | |
Daniel Erat
2016/10/07 17:17:22
since you're already using a regexp, why not extra
kylechar
2016/10/11 13:56:49
For the caveat I don't think it applies to the reg
| |
96 LOG(ERROR) << "Invalid display mode string \"" << str << "\""; | |
97 return nullptr; | |
98 } | |
99 | |
100 // Refresh rate is optional and will be be 60 if not specified. | |
101 if (sscanf(str.c_str(), "%dx%d%%%f", &width, &height, &refresh_rate) < 2) { | |
102 LOG(ERROR) << "Unable to parse display mode \"" << str << "\""; | |
103 return nullptr; | |
104 } | |
105 | |
106 return base::MakeUnique<ui::DisplayMode>(gfx::Size(width, height), false, | |
107 refresh_rate); | |
108 } | |
109 | |
110 // Parses a list of alternate display modes, adding each new display mode to | |
111 // |builder|. Returns false if any of the modes are invalid. | |
112 bool HandleModes(FakeDisplaySnapshot::Builder* builder, | |
113 StringPiece resolutions) { | |
114 for (const std::string& mode_str : | |
115 base::SplitString(resolutions, ":", base::TRIM_WHITESPACE, | |
116 base::SPLIT_WANT_NONEMPTY)) { | |
117 std::unique_ptr<ui::DisplayMode> mode = ParseDisplayMode(mode_str); | |
118 if (!mode) | |
119 return false; | |
120 | |
121 builder->AddMode(std::move(mode)); | |
122 } | |
123 | |
124 return true; | |
125 } | |
126 | |
127 // Parses device DPI and updates |builder|. Returns false if an invalid DPI | |
128 // string is provided. | |
129 bool HandleDPI(FakeDisplaySnapshot::Builder* builder, StringPiece dpi) { | |
130 if (dpi.empty()) | |
131 return true; | |
132 | |
133 int dpi_value = 0; | |
134 if (base::StringToInt(dpi, &dpi_value)) { | |
135 builder->SetDPI(dpi_value); | |
136 return true; | |
137 } | |
138 | |
139 LOG(ERROR) << "Invalid DPI string \"" << dpi << "\""; | |
140 return false; | |
141 } | |
142 | |
143 // Parses a list of display options and set each option true on |builder|. | |
144 // Returns false if any invalid options are provided. If an option appears more | |
145 // than once it will have no effect the second time. | |
146 bool HandleOptions(FakeDisplaySnapshot::Builder* builder, StringPiece options) { | |
147 for (size_t i = 0; i < options.size(); ++i) { | |
148 switch (options[i]) { | |
149 case 'o': | |
150 builder->SetHasOverscan(true); | |
151 break; | |
152 case 'c': | |
153 builder->SetHasColorCorrectionMatrix(true); | |
154 break; | |
155 case 'a': | |
156 builder->SetIsAspectPerservingScaling(true); | |
157 break; | |
158 case 'i': | |
159 builder->SetType(ui::DISPLAY_CONNECTION_TYPE_INTERNAL); | |
160 break; | |
161 default: | |
162 LOG(ERROR) << "Invalid option specifier \"" << options[i] << "\""; | |
163 return false; | |
164 } | |
165 } | |
166 | |
167 return true; | |
168 } | |
169 | |
65 } // namespace | 170 } // namespace |
66 | 171 |
67 using Builder = FakeDisplaySnapshot::Builder; | 172 using Builder = FakeDisplaySnapshot::Builder; |
68 | 173 |
69 Builder::Builder() {} | 174 Builder::Builder() {} |
70 | 175 |
71 Builder::~Builder() {} | 176 Builder::~Builder() {} |
72 | 177 |
73 std::unique_ptr<FakeDisplaySnapshot> Builder::Build() { | 178 std::unique_ptr<FakeDisplaySnapshot> Builder::Build() { |
74 if (modes_.empty() || id_ == Display::kInvalidDisplayID) { | 179 if (modes_.empty() || id_ == Display::kInvalidDisplayID) { |
75 NOTREACHED() << "Display modes or display ID missing"; | 180 NOTREACHED() << "Display modes or display ID missing"; |
76 return nullptr; | 181 return nullptr; |
77 } | 182 } |
78 | 183 |
79 // If there is no native mode set, use the first display mode. | 184 // If there is no native mode set, use the first display mode. |
80 if (!native_mode_) | 185 if (!native_mode_) |
81 native_mode_ = modes_.back().get(); | 186 native_mode_ = modes_.back().get(); |
82 | 187 |
83 // Calculate physical size to match set DPI. | 188 // Calculate physical size to match set DPI. |
84 gfx::Size physical_size = | 189 gfx::Size physical_size = |
85 gfx::ScaleToRoundedSize(native_mode_->size(), PixelPitchMmFromDPI(dpi_)); | 190 gfx::ScaleToRoundedSize(native_mode_->size(), PixelPitchMmFromDPI(dpi_)); |
86 | 191 |
87 return base::WrapUnique(new FakeDisplaySnapshot( | 192 return base::MakeUnique<FakeDisplaySnapshot>( |
88 id_, origin_, physical_size, type_, is_aspect_preserving_scaling_, | 193 id_, origin_, physical_size, type_, is_aspect_preserving_scaling_, |
89 has_overscan_, has_color_correction_matrix_, name_, product_id_, | 194 has_overscan_, has_color_correction_matrix_, name_, product_id_, |
90 std::move(modes_), current_mode_, native_mode_)); | 195 std::move(modes_), current_mode_, native_mode_); |
91 } | 196 } |
92 | 197 |
93 Builder& Builder::SetId(int64_t id) { | 198 Builder& Builder::SetId(int64_t id) { |
94 id_ = id; | 199 id_ = id; |
95 return *this; | 200 return *this; |
96 } | 201 } |
97 | 202 |
98 Builder& Builder::SetNativeMode(const gfx::Size& size) { | 203 Builder& Builder::SetNativeMode(const gfx::Size& size) { |
99 native_mode_ = AddOrFindDisplayMode(size); | 204 native_mode_ = AddOrFindDisplayMode(size); |
100 return *this; | 205 return *this; |
101 } | 206 } |
102 | 207 |
208 Builder& Builder::SetNativeMode(std::unique_ptr<ui::DisplayMode> mode) { | |
209 native_mode_ = AddOrFindDisplayMode(std::move(mode)); | |
210 return *this; | |
211 } | |
212 | |
103 Builder& Builder::SetCurrentMode(const gfx::Size& size) { | 213 Builder& Builder::SetCurrentMode(const gfx::Size& size) { |
104 current_mode_ = AddOrFindDisplayMode(size); | 214 current_mode_ = AddOrFindDisplayMode(size); |
105 return *this; | 215 return *this; |
106 } | 216 } |
107 | 217 |
218 Builder& Builder::SetCurrentMode(std::unique_ptr<ui::DisplayMode> mode) { | |
219 current_mode_ = AddOrFindDisplayMode(std::move(mode)); | |
220 return *this; | |
221 } | |
222 | |
108 Builder& Builder::AddMode(const gfx::Size& size) { | 223 Builder& Builder::AddMode(const gfx::Size& size) { |
109 AddOrFindDisplayMode(size); | 224 AddOrFindDisplayMode(size); |
110 return *this; | 225 return *this; |
111 } | 226 } |
112 | 227 |
228 Builder& Builder::AddMode(std::unique_ptr<ui::DisplayMode> mode) { | |
229 AddOrFindDisplayMode(std::move(mode)); | |
230 return *this; | |
231 } | |
232 | |
113 Builder& Builder::SetOrigin(const gfx::Point& origin) { | 233 Builder& Builder::SetOrigin(const gfx::Point& origin) { |
114 origin_ = origin; | 234 origin_ = origin; |
115 return *this; | 235 return *this; |
116 } | 236 } |
117 | 237 |
118 Builder& Builder::SetType(ui::DisplayConnectionType type) { | 238 Builder& Builder::SetType(ui::DisplayConnectionType type) { |
119 type_ = type; | 239 type_ = type; |
120 return *this; | 240 return *this; |
121 } | 241 } |
122 | 242 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
162 for (auto& mode : modes_) { | 282 for (auto& mode : modes_) { |
163 if (mode->size() == size) | 283 if (mode->size() == size) |
164 return mode.get(); | 284 return mode.get(); |
165 } | 285 } |
166 | 286 |
167 // Not found, insert a mode with the size and return. | 287 // Not found, insert a mode with the size and return. |
168 modes_.push_back(base::MakeUnique<ui::DisplayMode>(size, false, 60.0f)); | 288 modes_.push_back(base::MakeUnique<ui::DisplayMode>(size, false, 60.0f)); |
169 return modes_.back().get(); | 289 return modes_.back().get(); |
170 } | 290 } |
171 | 291 |
172 FakeDisplaySnapshot::FakeDisplaySnapshot( | 292 const ui::DisplayMode* Builder::AddOrFindDisplayMode( |
173 int64_t display_id, | 293 std::unique_ptr<ui::DisplayMode> mode) { |
174 const gfx::Point& origin, | 294 for (auto& existing : modes_) { |
175 const gfx::Size& physical_size, | 295 if (mode->size() == existing->size() && |
176 ui::DisplayConnectionType type, | 296 mode->is_interlaced() == existing->is_interlaced() && |
177 bool is_aspect_preserving_scaling, | 297 mode->refresh_rate() == existing->refresh_rate()) |
178 bool has_overscan, | 298 return existing.get(); |
179 bool has_color_correction_matrix, | 299 } |
180 std::string display_name, | 300 |
181 int64_t product_id, | 301 // Not found, insert mode and return. |
182 std::vector<std::unique_ptr<const ui::DisplayMode>> modes, | 302 modes_.push_back(std::move(mode)); |
183 const ui::DisplayMode* current_mode, | 303 return modes_.back().get(); |
184 const ui::DisplayMode* native_mode) | 304 } |
305 | |
306 FakeDisplaySnapshot::FakeDisplaySnapshot(int64_t display_id, | |
307 const gfx::Point& origin, | |
308 const gfx::Size& physical_size, | |
309 ui::DisplayConnectionType type, | |
310 bool is_aspect_preserving_scaling, | |
311 bool has_overscan, | |
312 bool has_color_correction_matrix, | |
313 std::string display_name, | |
314 int64_t product_id, | |
315 DisplayModeList modes, | |
316 const ui::DisplayMode* current_mode, | |
317 const ui::DisplayMode* native_mode) | |
185 : DisplaySnapshot(display_id, | 318 : DisplaySnapshot(display_id, |
186 origin, | 319 origin, |
187 physical_size, | 320 physical_size, |
188 type, | 321 type, |
189 is_aspect_preserving_scaling, | 322 is_aspect_preserving_scaling, |
190 has_overscan, | 323 has_overscan, |
191 has_color_correction_matrix, | 324 has_color_correction_matrix, |
192 display_name, | 325 display_name, |
193 base::FilePath(), | 326 base::FilePath(), |
194 std::move(modes), | 327 std::move(modes), |
195 std::vector<uint8_t>(), | 328 std::vector<uint8_t>(), |
196 current_mode, | 329 current_mode, |
197 native_mode) { | 330 native_mode) { |
198 product_id_ = product_id; | 331 product_id_ = product_id; |
199 } | 332 } |
200 | 333 |
201 FakeDisplaySnapshot::~FakeDisplaySnapshot() {} | 334 FakeDisplaySnapshot::~FakeDisplaySnapshot() {} |
202 | 335 |
336 // static | |
337 std::unique_ptr<ui::DisplaySnapshot> FakeDisplaySnapshot::CreateFromSpec( | |
338 int64_t id, | |
339 const std::string& spec) { | |
340 StringPiece leftover(spec); | |
341 | |
342 // Cut off end of string at each delimiter to split. | |
343 StringPiece options = ExtractSuffix(&leftover, "/"); | |
344 StringPiece dpi = ExtractSuffix(&leftover, "^"); | |
345 StringPiece resolutions = ExtractSuffix(&leftover, "#"); | |
346 | |
347 // Leftovers should be just the native mode at this point. | |
348 std::unique_ptr<ui::DisplayMode> native_mode = | |
349 ParseDisplayMode(leftover.as_string()); | |
350 | |
351 // Fail without valid native mode. | |
352 if (!native_mode) | |
353 return nullptr; | |
354 | |
355 FakeDisplaySnapshot::Builder builder; | |
356 builder.SetId(id).SetNativeMode(std::move(native_mode)); | |
357 builder.SetName(base::StringPrintf("Fake Display %" PRId64, id)); | |
358 | |
359 if (!HandleModes(&builder, resolutions) || !HandleDPI(&builder, dpi) || | |
360 !HandleOptions(&builder, options)) | |
361 return nullptr; | |
362 | |
363 return builder.Build(); | |
364 } | |
365 | |
203 std::string FakeDisplaySnapshot::ToString() const { | 366 std::string FakeDisplaySnapshot::ToString() const { |
204 return base::StringPrintf( | 367 return base::StringPrintf( |
205 "id=%" PRId64 | 368 "id=%" PRId64 |
206 " current_mode=%s native_mode=%s origin=%s" | 369 " current_mode=%s native_mode=%s origin=%s" |
207 " physical_size=%s, type=%s name=\"%s\" modes=(%s)", | 370 " physical_size=%s, type=%s name=\"%s\" modes=(%s)", |
208 display_id_, | 371 display_id_, |
209 current_mode_ ? current_mode_->ToString().c_str() : "nullptr", | 372 current_mode_ ? current_mode_->ToString().c_str() : "nullptr", |
210 native_mode_ ? native_mode_->ToString().c_str() : "nullptr", | 373 native_mode_ ? native_mode_->ToString().c_str() : "nullptr", |
211 origin_.ToString().c_str(), physical_size_.ToString().c_str(), | 374 origin_.ToString().c_str(), physical_size_.ToString().c_str(), |
212 DisplayConnectionTypeString(type_).c_str(), display_name_.c_str(), | 375 DisplayConnectionTypeString(type_).c_str(), display_name_.c_str(), |
213 ModeListString(modes_).c_str()); | 376 ModeListString(modes_).c_str()); |
214 } | 377 } |
215 | 378 |
216 } // namespace display | 379 } // namespace display |
OLD | NEW |