Chromium Code Reviews| Index: ui/display/fake_display_snapshot.cc |
| diff --git a/ui/display/fake_display_snapshot.cc b/ui/display/fake_display_snapshot.cc |
| index a431a2a2f652418470ae1c24b3b7fbfb081d232a..562b6890165bc2442e3d5ad62a267cae35846ec7 100644 |
| --- a/ui/display/fake_display_snapshot.cc |
| +++ b/ui/display/fake_display_snapshot.cc |
| @@ -11,7 +11,12 @@ |
| #include <vector> |
| #include "base/memory/ptr_util.h" |
| +#include "base/strings/string_number_conversions.h" |
| +#include "base/strings/string_split.h" |
| #include "base/strings/stringprintf.h" |
| +#include "third_party/re2/src/re2/re2.h" |
| + |
| +using base::StringPiece; |
| namespace display { |
| @@ -62,6 +67,106 @@ std::string DisplayConnectionTypeString(ui::DisplayConnectionType type) { |
| return ""; |
| } |
| +// 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.
|
| +// the result will be empty and the input string will be unmodified. Otherwise, |
| +// the input string will contain the text before the delimiter and the result |
| +// will be the text after the delimiter. |
| +StringPiece ExtractSuffix(StringPiece* str, StringPiece delimiter) { |
| + std::vector<StringPiece> parts = base::SplitStringPiece( |
| + *str, delimiter, base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| + |
| + if (parts.size() == 2) { |
| + *str = parts[0]; |
| + return parts[1]; |
| + } |
| + |
| + return StringPiece(); |
| +} |
| + |
| +// Parses a display mode from |str| in the format HxW[%R], returning null if |
| +// |str| is invalid. |
| +std::unique_ptr<ui::DisplayMode> ParseDisplayMode(const std::string& str) { |
| + int width = 0; |
| + int height = 0; |
| + float refresh_rate = 60.0f; |
| + |
| + // With sscanf() it will happily ignore characters at the end of the string, |
| + // so check |str| is valid using a regex. |
| + 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
|
| + LOG(ERROR) << "Invalid display mode string \"" << str << "\""; |
| + return nullptr; |
| + } |
| + |
| + // Refresh rate is optional and will be be 60 if not specified. |
| + if (sscanf(str.c_str(), "%dx%d%%%f", &width, &height, &refresh_rate) < 2) { |
| + LOG(ERROR) << "Unable to parse display mode \"" << str << "\""; |
| + return nullptr; |
| + } |
| + |
| + return base::MakeUnique<ui::DisplayMode>(gfx::Size(width, height), false, |
| + refresh_rate); |
| +} |
| + |
| +// Parses a list of alternate display modes, adding each new display mode to |
| +// |builder|. Returns false if any of the modes are invalid. |
| +bool HandleModes(FakeDisplaySnapshot::Builder* builder, |
| + StringPiece resolutions) { |
| + for (const std::string& mode_str : |
| + base::SplitString(resolutions, ":", base::TRIM_WHITESPACE, |
| + base::SPLIT_WANT_NONEMPTY)) { |
| + std::unique_ptr<ui::DisplayMode> mode = ParseDisplayMode(mode_str); |
| + if (!mode) |
| + return false; |
| + |
| + builder->AddMode(std::move(mode)); |
| + } |
| + |
| + return true; |
| +} |
| + |
| +// Parses device DPI and updates |builder|. Returns false if an invalid DPI |
| +// string is provided. |
| +bool HandleDPI(FakeDisplaySnapshot::Builder* builder, StringPiece dpi) { |
| + if (dpi.empty()) |
| + return true; |
| + |
| + int dpi_value = 0; |
| + if (base::StringToInt(dpi, &dpi_value)) { |
| + builder->SetDPI(dpi_value); |
| + return true; |
| + } |
| + |
| + LOG(ERROR) << "Invalid DPI string \"" << dpi << "\""; |
| + return false; |
| +} |
| + |
| +// Parses a list of display options and set each option true on |builder|. |
| +// Returns false if any invalid options are provided. If an option appears more |
| +// than once it will have no effect the second time. |
| +bool HandleOptions(FakeDisplaySnapshot::Builder* builder, StringPiece options) { |
| + for (size_t i = 0; i < options.size(); ++i) { |
| + switch (options[i]) { |
| + case 'o': |
| + builder->SetHasOverscan(true); |
| + break; |
| + case 'c': |
| + builder->SetHasColorCorrectionMatrix(true); |
| + break; |
| + case 'a': |
| + builder->SetIsAspectPerservingScaling(true); |
| + break; |
| + case 'i': |
| + builder->SetType(ui::DISPLAY_CONNECTION_TYPE_INTERNAL); |
| + break; |
| + default: |
| + LOG(ERROR) << "Invalid option specifier \"" << options[i] << "\""; |
| + return false; |
| + } |
| + } |
| + |
| + return true; |
| +} |
| + |
| } // namespace |
| using Builder = FakeDisplaySnapshot::Builder; |
| @@ -84,10 +189,10 @@ std::unique_ptr<FakeDisplaySnapshot> Builder::Build() { |
| gfx::Size physical_size = |
| gfx::ScaleToRoundedSize(native_mode_->size(), PixelPitchMmFromDPI(dpi_)); |
| - return base::WrapUnique(new FakeDisplaySnapshot( |
| + return base::MakeUnique<FakeDisplaySnapshot>( |
| id_, origin_, physical_size, type_, is_aspect_preserving_scaling_, |
| has_overscan_, has_color_correction_matrix_, name_, product_id_, |
| - std::move(modes_), current_mode_, native_mode_)); |
| + std::move(modes_), current_mode_, native_mode_); |
| } |
| Builder& Builder::SetId(int64_t id) { |
| @@ -100,16 +205,31 @@ Builder& Builder::SetNativeMode(const gfx::Size& size) { |
| return *this; |
| } |
| +Builder& Builder::SetNativeMode(std::unique_ptr<ui::DisplayMode> mode) { |
| + native_mode_ = AddOrFindDisplayMode(std::move(mode)); |
| + return *this; |
| +} |
| + |
| Builder& Builder::SetCurrentMode(const gfx::Size& size) { |
| current_mode_ = AddOrFindDisplayMode(size); |
| return *this; |
| } |
| +Builder& Builder::SetCurrentMode(std::unique_ptr<ui::DisplayMode> mode) { |
| + current_mode_ = AddOrFindDisplayMode(std::move(mode)); |
| + return *this; |
| +} |
| + |
| Builder& Builder::AddMode(const gfx::Size& size) { |
| AddOrFindDisplayMode(size); |
| return *this; |
| } |
| +Builder& Builder::AddMode(std::unique_ptr<ui::DisplayMode> mode) { |
| + AddOrFindDisplayMode(std::move(mode)); |
| + return *this; |
| +} |
| + |
| Builder& Builder::SetOrigin(const gfx::Point& origin) { |
| origin_ = origin; |
| return *this; |
| @@ -169,19 +289,32 @@ const ui::DisplayMode* Builder::AddOrFindDisplayMode(const gfx::Size& size) { |
| return modes_.back().get(); |
| } |
| -FakeDisplaySnapshot::FakeDisplaySnapshot( |
| - int64_t display_id, |
| - const gfx::Point& origin, |
| - const gfx::Size& physical_size, |
| - ui::DisplayConnectionType type, |
| - bool is_aspect_preserving_scaling, |
| - bool has_overscan, |
| - bool has_color_correction_matrix, |
| - std::string display_name, |
| - int64_t product_id, |
| - std::vector<std::unique_ptr<const ui::DisplayMode>> modes, |
| - const ui::DisplayMode* current_mode, |
| - const ui::DisplayMode* native_mode) |
| +const ui::DisplayMode* Builder::AddOrFindDisplayMode( |
| + std::unique_ptr<ui::DisplayMode> mode) { |
| + for (auto& existing : modes_) { |
| + if (mode->size() == existing->size() && |
| + mode->is_interlaced() == existing->is_interlaced() && |
| + mode->refresh_rate() == existing->refresh_rate()) |
| + return existing.get(); |
| + } |
| + |
| + // Not found, insert mode and return. |
| + modes_.push_back(std::move(mode)); |
| + return modes_.back().get(); |
| +} |
| + |
| +FakeDisplaySnapshot::FakeDisplaySnapshot(int64_t display_id, |
| + const gfx::Point& origin, |
| + const gfx::Size& physical_size, |
| + ui::DisplayConnectionType type, |
| + bool is_aspect_preserving_scaling, |
| + bool has_overscan, |
| + bool has_color_correction_matrix, |
| + std::string display_name, |
| + int64_t product_id, |
| + DisplayModeList modes, |
| + const ui::DisplayMode* current_mode, |
| + const ui::DisplayMode* native_mode) |
| : DisplaySnapshot(display_id, |
| origin, |
| physical_size, |
| @@ -200,6 +333,36 @@ FakeDisplaySnapshot::FakeDisplaySnapshot( |
| FakeDisplaySnapshot::~FakeDisplaySnapshot() {} |
| +// static |
| +std::unique_ptr<ui::DisplaySnapshot> FakeDisplaySnapshot::CreateFromSpec( |
| + int64_t id, |
| + const std::string& spec) { |
| + StringPiece leftover(spec); |
| + |
| + // Cut off end of string at each delimiter to split. |
| + StringPiece options = ExtractSuffix(&leftover, "/"); |
| + StringPiece dpi = ExtractSuffix(&leftover, "^"); |
| + StringPiece resolutions = ExtractSuffix(&leftover, "#"); |
| + |
| + // Leftovers should be just the native mode at this point. |
| + std::unique_ptr<ui::DisplayMode> native_mode = |
| + ParseDisplayMode(leftover.as_string()); |
| + |
| + // Fail without valid native mode. |
| + if (!native_mode) |
| + return nullptr; |
| + |
| + FakeDisplaySnapshot::Builder builder; |
| + builder.SetId(id).SetNativeMode(std::move(native_mode)); |
| + builder.SetName(base::StringPrintf("Fake Display %" PRId64, id)); |
| + |
| + if (!HandleModes(&builder, resolutions) || !HandleDPI(&builder, dpi) || |
| + !HandleOptions(&builder, options)) |
| + return nullptr; |
| + |
| + return builder.Build(); |
| +} |
| + |
| std::string FakeDisplaySnapshot::ToString() const { |
| return base::StringPrintf( |
| "id=%" PRId64 |