1# Copyright 2019 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5from .runtime_enabled_features import RuntimeEnabledFeatures 6 7 8class _Feature(str): 9 """Represents a runtime-enabled feature.""" 10 11 def __init__(self, value): 12 str.__init__(self, value) 13 self._is_context_dependent = ( 14 RuntimeEnabledFeatures.is_context_dependent(self)) 15 16 @property 17 def is_context_dependent(self): 18 return self._is_context_dependent 19 20 21class _GlobalNameAndFeature(object): 22 def __init__(self, global_name, feature=None): 23 assert isinstance(global_name, str) 24 assert feature is None or isinstance(feature, str) 25 26 self._global_name = global_name 27 if feature is None: 28 self._feature = None 29 else: 30 self._feature = _Feature(feature) 31 32 @property 33 def global_name(self): 34 return self._global_name 35 36 @property 37 def feature(self): 38 return self._feature 39 40 41class Exposure(object): 42 """Represents a set of conditions under which the construct is exposed.""" 43 44 def __init__(self, other=None): 45 assert other is None or isinstance(other, Exposure) 46 47 if other: 48 self._global_names_and_features = tuple( 49 other.global_names_and_features) 50 self._runtime_enabled_features = tuple( 51 other.runtime_enabled_features) 52 self._context_independent_runtime_enabled_features = tuple( 53 other.context_independent_runtime_enabled_features) 54 self._context_dependent_runtime_enabled_features = tuple( 55 other.context_dependent_runtime_enabled_features) 56 self._context_enabled_features = tuple( 57 other.context_enabled_features) 58 self._only_in_secure_contexts = other.only_in_secure_contexts 59 else: 60 self._global_names_and_features = tuple() 61 self._runtime_enabled_features = tuple() 62 self._context_independent_runtime_enabled_features = tuple() 63 self._context_dependent_runtime_enabled_features = tuple() 64 self._context_enabled_features = tuple() 65 self._only_in_secure_contexts = None 66 67 @property 68 def global_names_and_features(self): 69 """ 70 Returns a list of pairs of global name and runtime enabled feature, 71 which is None if not applicable. 72 """ 73 return self._global_names_and_features 74 75 @property 76 def runtime_enabled_features(self): 77 """ 78 Returns a list of runtime enabled features. This construct is exposed 79 only when all these features are enabled. 80 """ 81 return self._runtime_enabled_features 82 83 @property 84 def context_independent_runtime_enabled_features(self): 85 """Returns runtime enabled features that are context-independent.""" 86 return self._context_independent_runtime_enabled_features 87 88 @property 89 def context_dependent_runtime_enabled_features(self): 90 """Returns runtime enabled features that are context-dependent.""" 91 return self._context_dependent_runtime_enabled_features 92 93 @property 94 def context_enabled_features(self): 95 """ 96 Returns a list of context enabled features. This construct is exposed 97 only when one of these features is enabled in the context. 98 """ 99 return self._context_enabled_features 100 101 @property 102 def only_in_secure_contexts(self): 103 """ 104 Returns whether this construct is available only in secure contexts or 105 not. The returned value is either of a boolean (True: unconditionally 106 restricted in secure contexts, or False: never restricted) or a list of 107 flag names (restricted only when all flags are enabled). 108 109 https://heycam.github.io/webidl/#dfn-available-only-in-secure-contexts 110 """ 111 if self._only_in_secure_contexts is None: 112 return False 113 return self._only_in_secure_contexts 114 115 def is_context_dependent(self, global_names=None): 116 """ 117 Returns True if the exposure of this construct depends on a context. 118 119 Args: 120 global_names: When specified, it's taken into account that the 121 global object implements |global_names|. 122 """ 123 assert (global_names is None 124 or (isinstance(global_names, (list, tuple)) 125 and all(isinstance(name, str) for name in global_names))) 126 127 if (self.context_dependent_runtime_enabled_features 128 or self.context_enabled_features 129 or self.only_in_secure_contexts): 130 return True 131 132 if not global_names: 133 return bool(self.global_names_and_features) 134 135 is_context_dependent = False 136 for entry in self.global_names_and_features: 137 if entry.global_name not in global_names: 138 continue 139 if entry.feature and entry.feature.is_context_dependent: 140 is_context_dependent = True 141 return is_context_dependent 142 143 144class ExposureMutable(Exposure): 145 def __init__(self): 146 Exposure.__init__(self) 147 148 self._global_names_and_features = [] 149 self._runtime_enabled_features = [] 150 self._context_independent_runtime_enabled_features = [] 151 self._context_dependent_runtime_enabled_features = [] 152 self._context_enabled_features = [] 153 self._only_in_secure_contexts = None 154 155 def __getstate__(self): 156 assert False, "ExposureMutable must not be pickled." 157 158 def __setstate__(self, state): 159 assert False, "ExposureMutable must not be pickled." 160 161 def add_global_name_and_feature(self, global_name, feature_name=None): 162 self._global_names_and_features.append( 163 _GlobalNameAndFeature(global_name, feature_name)) 164 165 def add_runtime_enabled_feature(self, name): 166 assert isinstance(name, str) 167 feature = _Feature(name) 168 if feature.is_context_dependent: 169 self._context_dependent_runtime_enabled_features.append(feature) 170 else: 171 self._context_independent_runtime_enabled_features.append(feature) 172 self._runtime_enabled_features.append(feature) 173 174 def add_context_enabled_feature(self, name): 175 assert isinstance(name, str) 176 self._context_enabled_features.append(name) 177 178 def set_only_in_secure_contexts(self, value): 179 assert (isinstance(value, (bool, str)) 180 or (isinstance(value, (list, tuple)) 181 and all(isinstance(name, str) for name in value))) 182 assert self._only_in_secure_contexts is None 183 if isinstance(value, bool): 184 self._only_in_secure_contexts = value 185 elif isinstance(value, str): 186 self._only_in_secure_contexts = (_Feature(value), ) 187 else: 188 self._only_in_secure_contexts = tuple(map(_Feature, value)) 189