123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- // Copyright 2021 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef UI_BASE_METADATA_BASE_TYPE_CONVERSION_H_
- #define UI_BASE_METADATA_BASE_TYPE_CONVERSION_H_
- #include <stdint.h>
- #include <algorithm> // Silence broken lint check
- #include <memory>
- #include <string>
- #include <utility>
- #include <vector>
- #include "base/component_export.h"
- #include "base/containers/fixed_flat_map.h"
- #include "base/files/file_path.h"
- #include "base/ranges/algorithm.h"
- #include "base/ranges/ranges.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/string_piece.h"
- #include "base/strings/string_split.h"
- #include "base/strings/string_util.h"
- #include "base/strings/stringprintf.h"
- #include "base/strings/sys_string_conversions.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/time/time.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "third_party/skia/include/core/SkColor.h"
- #include "ui/base/models/menu_separator_types.h"
- #include "ui/gfx/geometry/insets.h"
- #include "ui/gfx/geometry/point.h"
- #include "ui/gfx/geometry/point_f.h"
- #include "ui/gfx/geometry/rect.h"
- #include "ui/gfx/geometry/rect_f.h"
- #include "ui/gfx/geometry/size.h"
- #include "ui/gfx/geometry/size_f.h"
- #include "ui/gfx/range/range.h"
- #include "ui/gfx/shadow_value.h"
- #include "ui/gfx/text_constants.h"
- #include "url/gurl.h"
- #include "url/third_party/mozilla/url_parse.h"
- namespace ui {
- namespace metadata {
- using ValidStrings = std::vector<std::u16string>;
- // Various metadata methods pass types either by value or const ref depending on
- // whether the types are "small" (defined as "fundamental, enum, or pointer").
- // ArgType<T> gives the appropriate type to use as an argument in such cases.
- template <typename T>
- using ArgType =
- typename std::conditional<std::is_fundamental<T>::value ||
- std::is_enum<T>::value ||
- std::is_pointer<T>::value ||
- (std::is_move_assignable<T>::value &&
- std::is_move_constructible<T>::value &&
- !std::is_copy_assignable<T>::value &&
- !std::is_copy_constructible<T>::value),
- T,
- const T&>::type;
- COMPONENT_EXPORT(UI_BASE_METADATA) extern const char kNoPrefix[];
- COMPONENT_EXPORT(UI_BASE_METADATA) extern const char kSkColorPrefix[];
- // General Type Conversion Template Functions ---------------------------------
- template <bool serializable,
- bool read_only = false,
- const char* name_prefix = kNoPrefix>
- struct BaseTypeConverter {
- static constexpr bool is_serializable = serializable;
- static constexpr bool is_read_only = read_only;
- static bool IsSerializable() { return is_serializable; }
- static bool IsReadOnly() { return is_read_only; }
- static const char* PropertyNamePrefix() { return name_prefix; }
- };
- template <typename T>
- struct TypeConverter : BaseTypeConverter<std::is_enum<T>::value> {
- static std::u16string ToString(ArgType<T> source_value);
- static absl::optional<T> FromString(const std::u16string& source_value);
- static ValidStrings GetValidStrings();
- };
- // The following definitions and macros are needed only in cases where a type
- // is a mere alias to a POD type AND a specialized type converter is also needed
- // to handle different the string conversions different from the existing POD
- // type converter. See SkColor below as an example of their use.
- // NOTE: This should be a rare occurrence and if possible use a unique type and
- // a TypeConverter specialization based on that unique type.
- template <typename T, typename K>
- struct Uniquifier {
- using type = T;
- using tag = K;
- };
- #define MAKE_TYPE_UNIQUE(type_name) \
- struct type_name##Tag {}; \
- using type_name##Unique = \
- ::ui::metadata::Uniquifier<type_name, type_name##Tag>
- #define _UNIQUE_TYPE_NAME1(type_name) type_name##Unique
- #define _UNIQUE_TYPE_NAME2(qualifier, type_name) qualifier::type_name##Unique
- #define _GET_TYPE_MACRO(_1, _2, NAME, ...) NAME
- #define UNIQUE_TYPE_NAME(name, ...) \
- _GET_TYPE_MACRO(name, ##__VA_ARGS__, _UNIQUE_TYPE_NAME2, _UNIQUE_TYPE_NAME1) \
- (name, ##__VA_ARGS__)
- // Types and macros for generating enum converters ----------------------------
- template <typename T>
- struct EnumStringsMap;
- // *****************************************************************
- // * NOTE: The ENUM macros *must* be placed outside any namespace. *
- // *****************************************************************
- //
- // Use this macro only if your enum converters need to be accessible across
- // modules. Place this in the header file for the module and use the other macro
- // below as described.
- //
- #define EXPORT_ENUM_CONVERTERS(T, EXPORT) \
- template <> \
- EXPORT std::u16string ui::metadata::TypeConverter<T>::ToString( \
- ui::metadata::ArgType<T> source_value); \
- \
- template <> \
- EXPORT absl::optional<T> ui::metadata::TypeConverter<T>::FromString( \
- const std::u16string& str); \
- \
- template <> \
- EXPORT ui::metadata::ValidStrings \
- ui::metadata::TypeConverter<T>::GetValidStrings();
- // Generate the code to define a enum type to and from std::u16string
- // conversions. The first argument is the type T, and the rest of the argument
- // should have the enum value and string pairs defined in a format like
- // "{enum_value0, string16_value0}, {enum_value1, string16_value1} ...".
- // Both enum_values and string16_values need to be compile time constants.
- //
- #define DEFINE_ENUM_CONVERTERS(T, ...) \
- template <> \
- struct ui::metadata::EnumStringsMap<T> { \
- static_assert(std::is_enum<T>::value, "Error: " #T " is not an enum."); \
- \
- static const auto& Get() { \
- static constexpr auto kMap = \
- base::MakeFixedFlatMap<T, base::StringPiece16>({__VA_ARGS__}); \
- return kMap; \
- } \
- }; \
- \
- template <> \
- std::u16string ui::metadata::TypeConverter<T>::ToString( \
- ui::metadata::ArgType<T> source_value) { \
- const auto& map = EnumStringsMap<T>::Get(); \
- auto* it = map.find(source_value); \
- return it != map.end() ? std::u16string(it->second) : std::u16string(); \
- } \
- \
- template <> \
- absl::optional<T> ui::metadata::TypeConverter<T>::FromString( \
- const std::u16string& str) { \
- const auto& map = EnumStringsMap<T>::Get(); \
- using Pair = base::ranges::range_value_t<decltype(map)>; \
- auto* it = base::ranges::find(map, str, &Pair::second); \
- return it != map.end() ? absl::make_optional(it->first) : absl::nullopt; \
- } \
- \
- template <> \
- ui::metadata::ValidStrings \
- ui::metadata::TypeConverter<T>::GetValidStrings() { \
- ValidStrings string_values; \
- base::ranges::transform( \
- EnumStringsMap<T>::Get(), std::back_inserter(string_values), \
- [](const auto& pair) { return std::u16string(pair.second); }); \
- return string_values; \
- }
- // String Conversions ---------------------------------------------------------
- COMPONENT_EXPORT(UI_BASE_METADATA)
- std::u16string PointerToString(const void* pointer_val);
- #define DECLARE_CONVERSIONS(T) \
- template <> \
- struct COMPONENT_EXPORT(UI_BASE_METADATA) \
- TypeConverter<T> : BaseTypeConverter<true> { \
- static std::u16string ToString(ArgType<T> source_value); \
- static absl::optional<T> FromString(const std::u16string& source_value); \
- static ValidStrings GetValidStrings() { return {}; } \
- };
- DECLARE_CONVERSIONS(int8_t)
- DECLARE_CONVERSIONS(int16_t)
- DECLARE_CONVERSIONS(int32_t)
- DECLARE_CONVERSIONS(int64_t)
- DECLARE_CONVERSIONS(uint8_t)
- DECLARE_CONVERSIONS(uint16_t)
- DECLARE_CONVERSIONS(uint32_t)
- DECLARE_CONVERSIONS(uint64_t)
- DECLARE_CONVERSIONS(float)
- DECLARE_CONVERSIONS(double)
- DECLARE_CONVERSIONS(const char*)
- DECLARE_CONVERSIONS(base::FilePath)
- DECLARE_CONVERSIONS(std::u16string)
- DECLARE_CONVERSIONS(base::TimeDelta)
- DECLARE_CONVERSIONS(gfx::Insets)
- DECLARE_CONVERSIONS(gfx::Point)
- DECLARE_CONVERSIONS(gfx::PointF)
- DECLARE_CONVERSIONS(gfx::Range)
- DECLARE_CONVERSIONS(gfx::Rect)
- DECLARE_CONVERSIONS(gfx::RectF)
- DECLARE_CONVERSIONS(gfx::ShadowValues)
- DECLARE_CONVERSIONS(gfx::Size)
- DECLARE_CONVERSIONS(gfx::SizeF)
- DECLARE_CONVERSIONS(std::string)
- DECLARE_CONVERSIONS(url::Component)
- #undef DECLARE_CONVERSIONS
- template <>
- struct COMPONENT_EXPORT(UI_BASE_METADATA) TypeConverter<bool>
- : BaseTypeConverter<true> {
- static std::u16string ToString(bool source_value);
- static absl::optional<bool> FromString(const std::u16string& source_value);
- static ValidStrings GetValidStrings();
- };
- // Special conversions for wrapper types --------------------------------------
- COMPONENT_EXPORT(UI_BASE_METADATA) const std::u16string& GetNullOptStr();
- template <typename T>
- struct TypeConverter<absl::optional<T>>
- : BaseTypeConverter<TypeConverter<T>::is_serializable> {
- static std::u16string ToString(ArgType<absl::optional<T>> source_value) {
- if (!source_value)
- return GetNullOptStr();
- return TypeConverter<T>::ToString(source_value.value());
- }
- static absl::optional<absl::optional<T>> FromString(
- const std::u16string& source_value) {
- if (source_value == GetNullOptStr())
- return absl::make_optional<absl::optional<T>>(absl::nullopt);
- auto ret = TypeConverter<T>::FromString(source_value);
- return ret ? absl::make_optional(ret) : absl::nullopt;
- }
- static ValidStrings GetValidStrings() { return {}; }
- };
- // Special Conversions for std:unique_ptr<T> and T* types ----------------------
- template <typename T>
- struct TypeConverter<std::unique_ptr<T>> : BaseTypeConverter<false, true> {
- static std::u16string ToString(const std::unique_ptr<T>& source_value) {
- return PointerToString(source_value.get());
- }
- static std::u16string ToString(const T* source_value) {
- return PointerToString(source_value);
- }
- static absl::optional<std::unique_ptr<T>> FromString(
- const std::u16string& source_value) {
- DCHECK(false) << "Type converter cannot convert from string.";
- return absl::nullopt;
- }
- static ValidStrings GetValidStrings() { return {}; }
- };
- template <typename T>
- struct TypeConverter<T*> : BaseTypeConverter<false, true> {
- static std::u16string ToString(ArgType<T*> source_value) {
- return PointerToString(source_value);
- }
- static absl::optional<T*> FromString(const std::u16string& source_value) {
- DCHECK(false) << "Type converter cannot convert from string.";
- return absl::nullopt;
- }
- static ValidStrings GetValidStrings() { return {}; }
- };
- template <typename T>
- struct TypeConverter<std::vector<T>>
- : BaseTypeConverter<TypeConverter<T>::is_serializable> {
- static std::u16string ToString(ArgType<std::vector<T>> source_value) {
- std::vector<std::u16string> serialized;
- base::ranges::transform(source_value, std::back_inserter(serialized),
- &TypeConverter<T>::ToString);
- return u"{" + base::JoinString(serialized, u",") + u"}";
- }
- static absl::optional<std::vector<T>> FromString(
- const std::u16string& source_value) {
- if (source_value.empty() || source_value.front() != u'{' ||
- source_value.back() != u'}')
- return absl::nullopt;
- const auto values =
- base::SplitString(source_value.substr(1, source_value.length() - 2),
- u",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- std::vector<T> output;
- for (const auto& value : values) {
- auto ret = TypeConverter<T>::FromString(value);
- if (!ret)
- return absl::nullopt;
- output.push_back(*ret);
- }
- return absl::make_optional(output);
- }
- static ValidStrings GetValidStrings() { return {}; }
- };
- MAKE_TYPE_UNIQUE(SkColor);
- template <>
- struct COMPONENT_EXPORT(UI_BASE_METADATA)
- TypeConverter<UNIQUE_TYPE_NAME(SkColor)>
- : BaseTypeConverter<true, false, kSkColorPrefix> {
- static std::u16string ToString(SkColor source_value);
- static absl::optional<SkColor> FromString(const std::u16string& source_value);
- static ValidStrings GetValidStrings();
- // Parses a string within |start| and |end| for a color string in the forms
- // rgb(r, g, b), rgba(r, g, b, a), hsl(h, s%, l%), hsla(h, s%, l%, a),
- // 0xXXXXXX, 0xXXXXXXXX, <decimal number>
- // Returns the full string in |color| and the position immediately following
- // the last token in |next_token|.
- // Returns false if the input string cannot be properly parsed. |color| and
- // |next_token| will be undefined.
- static bool GetNextColor(std::u16string::const_iterator start,
- std::u16string::const_iterator end,
- std::u16string& color,
- std::u16string::const_iterator& next_token);
- static bool GetNextColor(std::u16string::const_iterator start,
- std::u16string::const_iterator end,
- std::u16string& color);
- // Same as above, except returns the color string converted into an |SkColor|.
- // Returns absl::nullopt if the color string cannot be properly parsed or the
- // string cannot be converted into a valid SkColor and |next_token| may be
- // undefined.
- static absl::optional<SkColor> GetNextColor(
- std::u16string::const_iterator start,
- std::u16string::const_iterator end,
- std::u16string::const_iterator& next_token);
- static absl::optional<SkColor> GetNextColor(
- std::u16string::const_iterator start,
- std::u16string::const_iterator end);
- // Converts the four elements of |pieces| beginning at |start_piece| to an
- // SkColor by assuming the pieces are split from a string like
- // "rgba(r,g,b,a)". Returns nullopt if conversion was unsuccessful.
- static absl::optional<SkColor> RgbaPiecesToSkColor(
- const std::vector<base::StringPiece16>& pieces,
- size_t start_piece);
- private:
- static absl::optional<SkColor> ParseHexString(
- const std::u16string& hex_string);
- static absl::optional<SkColor> ParseHslString(
- const std::u16string& hsl_string);
- static absl::optional<SkColor> ParseRgbString(
- const std::u16string& rgb_string);
- };
- using SkColorConverter = TypeConverter<UNIQUE_TYPE_NAME(SkColor)>;
- } // namespace metadata
- } // namespace ui
- EXPORT_ENUM_CONVERTERS(gfx::HorizontalAlignment,
- COMPONENT_EXPORT(UI_BASE_METADATA))
- EXPORT_ENUM_CONVERTERS(gfx::VerticalAlignment,
- COMPONENT_EXPORT(UI_BASE_METADATA))
- EXPORT_ENUM_CONVERTERS(gfx::ElideBehavior, COMPONENT_EXPORT(UI_BASE_METADATA))
- EXPORT_ENUM_CONVERTERS(ui::MenuSeparatorType,
- COMPONENT_EXPORT(UI_BASE_METADATA))
- #endif // UI_BASE_METADATA_BASE_TYPE_CONVERSION_H_
|