1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_BASE_INTERACTION_FRAMEWORK_SPECIFIC_IMPLEMENTATION_H_
#define UI_BASE_INTERACTION_FRAMEWORK_SPECIFIC_IMPLEMENTATION_H_
#include <ostream>
#include <string>
#include "base/component_export.h"
#include "ui/base/interaction/element_identifier.h"
namespace ui {
// Represents a type that has different implementations in different frameworks.
// This provides a very simple RTTI implementation so that we can retrieve
// platform-specific implementations from platform-agnostic systems (such as
// ElementTracker).
//
// To use this class, implement a base class for your implementations:
//
// class ThingBase : public FrameworkSpecificImplementation {
// ~ThingBase() override; // optional, include if class has local data
// // <-- interface methods and common implementation here
// };
//
// Then, in your framework-specific .h file:
//
// class ThingInMyFramework : public ThingBase {
// public:
// ~ThingInMyFramework() override;
// DECLARE_FRAMEWORK_SPECIFIC_METADATA()
// };
//
// In the corresponding .cc file:
//
// DEFINE_FRAMEWORK_SPECIFIC_METADATA(ThingInMyFramework)
//
// If you want to have a derived class that also reports as one of its ancestor
// classes, instead use this:
//
// DEFINE_FRAMEWORK_SPECIFIC_METADATA_SUBCLASS(
// SubclassInMyFramework, SuperclassInMyFramework)
//
// In this case, SubclassInMyFramework::IsA<SuperclassInMyFramework>() will
// return true. The superclass must also DECLARE_FRAMEWORK_SPECIFIC_METADATA().
//
// This is transitive, so if C is declared as a framework specific subclass of
// B, and B of A, then C::IsA<A>() will return true.
//
// While the subclass must be a descendant of the superclass by inheritance,
// not every intermediate class need be registered. Furthermore, inheritance is
// not automatic; DEFINE_FRAMEWORK_SPECIFIC_METADATA_SUBCLASS() is required to
// establish the association.
class COMPONENT_EXPORT(UI_BASE_INTERACTION) FrameworkSpecificImplementation {
public:
// Used by IsA() and AsA() methods to do runtime type-checking.
using FrameworkIdentifier = ElementIdentifier;
FrameworkSpecificImplementation() = default;
FrameworkSpecificImplementation(const FrameworkSpecificImplementation&) =
delete;
virtual ~FrameworkSpecificImplementation() = default;
void operator=(const FrameworkSpecificImplementation&) = delete;
// Returns whether this object is a specific subtype - for example, whether a
// `TrackedElement` is a `views::TrackedElementViews`.
template <typename T>
bool IsA() const {
return AsA<T>();
}
// Dynamically casts this object to a specific subtype, returning null if the
// element is the wrong type. This version converts non-const objects.
template <typename T>
T* AsA() {
return CheckInstanceFrameworkHierarchy(T::GetFrameworkIdentifier())
? static_cast<T*>(this)
: nullptr;
}
// Dynamically casts this object to a specific subtype, returning null if the
// object is the wrong type. This version converts const objects.
template <typename T>
const T* AsA() const {
return CheckInstanceFrameworkHierarchy(T::GetFrameworkIdentifier())
? static_cast<const T*>(this)
: nullptr;
}
// Gets the class name of the implementation.
virtual const char* GetImplementationName() const = 0;
// Gets a string representation of this element.
virtual std::string ToString() const;
protected:
// Checks that `id` corresponds to something in this class' hierarchy.
// Use DECLARE/DEFINE_FRAMEWORK_SPECIFIC_METADATA() - see below - to
// implement this method in your framework-specific derived classes.
virtual bool CheckInstanceFrameworkHierarchy(
FrameworkIdentifier id) const = 0;
};
// These macros can be used to help define platform-specific subclasses of
// base classes derived from FrameworkSpecificImplementation.
// Put this at the top of the class declaration, in the public section.
#define DECLARE_FRAMEWORK_SPECIFIC_METADATA() \
const char* GetImplementationName() const override; \
static FrameworkIdentifier GetFrameworkIdentifier(); \
bool CheckInstanceFrameworkHierarchy(FrameworkIdentifier) const override;
// This is used internally; don't use it directly.
#define DEFINE_FRAMEWORK_SPECIFIC_METADATA_COMMON(ClassName) \
const char* ClassName::GetImplementationName() const { \
return #ClassName; \
} \
ui::FrameworkSpecificImplementation::FrameworkIdentifier \
ClassName::GetFrameworkIdentifier() { \
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(k##ClassName##Identifier); \
return k##ClassName##Identifier; \
}
// Use to define an implementation that will only report as itself. Put this in
// `ClassName`'s .cc file.
#define DEFINE_FRAMEWORK_SPECIFIC_METADATA(ClassName) \
DEFINE_FRAMEWORK_SPECIFIC_METADATA_COMMON(ClassName) \
bool ClassName::CheckInstanceFrameworkHierarchy(FrameworkIdentifier id) \
const { \
return id == GetFrameworkIdentifier(); \
}
// Use to define an implementation that will report as both itself and as
// `BaseClassName`. Put this in `ClassName`'s .cc file.
#define DEFINE_FRAMEWORK_SPECIFIC_METADATA_SUBCLASS(ClassName, BaseClassName) \
static_assert(std::derived_from<ClassName, BaseClassName>); \
DEFINE_FRAMEWORK_SPECIFIC_METADATA_COMMON(ClassName) \
bool ClassName::CheckInstanceFrameworkHierarchy(FrameworkIdentifier id) \
const { \
return id == GetFrameworkIdentifier() || \
BaseClassName::CheckInstanceFrameworkHierarchy(id); \
}
COMPONENT_EXPORT(UI_BASE_INTERACTION)
extern void PrintTo(const FrameworkSpecificImplementation& impl,
std::ostream* os);
COMPONENT_EXPORT(UI_BASE_INTERACTION)
extern std::ostream& operator<<(std::ostream& os,
const FrameworkSpecificImplementation& impl);
} // namespace ui
#endif // UI_BASE_INTERACTION_FRAMEWORK_SPECIFIC_IMPLEMENTATION_H_
|