blob: e36cf7439ae58410daf74db22a757c5d8ba79a67 [file] [log] [blame]
# Copyright 2019 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.
from .runtime_enabled_features import RuntimeEnabledFeatures
class _Feature(str):
"""Represents a runtime-enabled feature."""
def __new__(cls, value):
return str.__new__(cls, value)
def __init__(self, value):
str.__init__(self)
self._is_context_dependent = (
RuntimeEnabledFeatures.is_context_dependent(self))
@property
def is_context_dependent(self):
return self._is_context_dependent
class _GlobalNameAndFeature(object):
def __init__(self, global_name, feature=None):
assert isinstance(global_name, str)
assert feature is None or isinstance(feature, str)
self._global_name = global_name
if feature is None:
self._feature = None
else:
self._feature = _Feature(feature)
@property
def global_name(self):
return self._global_name
@property
def feature(self):
return self._feature
class Exposure(object):
"""Represents a set of conditions under which the construct is exposed."""
def __init__(self, other=None):
assert other is None or isinstance(other, Exposure)
if other:
self._global_names_and_features = tuple(
other.global_names_and_features)
self._runtime_enabled_features = tuple(
other.runtime_enabled_features)
self._context_independent_runtime_enabled_features = tuple(
other.context_independent_runtime_enabled_features)
self._context_dependent_runtime_enabled_features = tuple(
other.context_dependent_runtime_enabled_features)
self._context_enabled_features = tuple(
other.context_enabled_features)
self._only_in_secure_contexts = other.only_in_secure_contexts
else:
self._global_names_and_features = tuple()
self._runtime_enabled_features = tuple()
self._context_independent_runtime_enabled_features = tuple()
self._context_dependent_runtime_enabled_features = tuple()
self._context_enabled_features = tuple()
self._only_in_secure_contexts = None
@property
def global_names_and_features(self):
"""
Returns a list of pairs of global name and runtime enabled feature,
which is None if not applicable.
"""
return self._global_names_and_features
@property
def runtime_enabled_features(self):
"""
Returns a list of runtime enabled features. This construct is exposed
only when all these features are enabled.
"""
return self._runtime_enabled_features
@property
def context_independent_runtime_enabled_features(self):
"""Returns runtime enabled features that are context-independent."""
return self._context_independent_runtime_enabled_features
@property
def context_dependent_runtime_enabled_features(self):
"""Returns runtime enabled features that are context-dependent."""
return self._context_dependent_runtime_enabled_features
@property
def context_enabled_features(self):
"""
Returns a list of context enabled features. This construct is exposed
only when one of these features is enabled in the context.
"""
return self._context_enabled_features
@property
def only_in_secure_contexts(self):
"""
Returns whether this construct is available only in secure contexts or
not. The returned value is either of a boolean (True: unconditionally
restricted in secure contexts, or False: never restricted) or a list of
flag names (restricted only when all flags are enabled).
https://heycam.github.io/webidl/#dfn-available-only-in-secure-contexts
"""
if self._only_in_secure_contexts is None:
return False
return self._only_in_secure_contexts
def is_context_dependent(self, global_names=None):
"""
Returns True if the exposure of this construct depends on a context.
Args:
global_names: When specified, it's taken into account that the
global object implements |global_names|.
"""
assert (global_names is None
or (isinstance(global_names, (list, tuple))
and all(isinstance(name, str) for name in global_names)))
if (self.context_dependent_runtime_enabled_features
or self.context_enabled_features
or self.only_in_secure_contexts):
return True
if not global_names:
return bool(self.global_names_and_features)
is_context_dependent = False
for entry in self.global_names_and_features:
if entry.global_name not in global_names:
continue
if entry.feature and entry.feature.is_context_dependent:
is_context_dependent = True
return is_context_dependent
class ExposureMutable(Exposure):
def __init__(self):
Exposure.__init__(self)
self._global_names_and_features = []
self._runtime_enabled_features = []
self._context_independent_runtime_enabled_features = []
self._context_dependent_runtime_enabled_features = []
self._context_enabled_features = []
self._only_in_secure_contexts = None
def __getstate__(self):
assert False, "ExposureMutable must not be pickled."
def __setstate__(self, state):
assert False, "ExposureMutable must not be pickled."
def add_global_name_and_feature(self, global_name, feature_name=None):
self._global_names_and_features.append(
_GlobalNameAndFeature(global_name, feature_name))
def add_runtime_enabled_feature(self, name):
assert isinstance(name, str)
feature = _Feature(name)
if feature.is_context_dependent:
self._context_dependent_runtime_enabled_features.append(feature)
else:
self._context_independent_runtime_enabled_features.append(feature)
self._runtime_enabled_features.append(feature)
def add_context_enabled_feature(self, name):
assert isinstance(name, str)
self._context_enabled_features.append(name)
def set_only_in_secure_contexts(self, value):
assert (isinstance(value, (bool, str))
or (isinstance(value, (list, tuple))
and all(isinstance(name, str) for name in value)))
assert self._only_in_secure_contexts is None
if isinstance(value, bool):
self._only_in_secure_contexts = value
elif isinstance(value, str):
self._only_in_secure_contexts = (_Feature(value), )
else:
self._only_in_secure_contexts = tuple(map(_Feature, value))