Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  data.py

  Sprache: Python
 

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

import re
import toml
import os
from itertools import groupby
from counted_unknown_properties import COUNTED_UNKNOWN_PROPERTIES

# It is important that the order of these physical / logical variants matches
# the order of the enum variants in logical_geometry.rs
PHYSICAL_SIDES = ["top""right""bottom""left"]
PHYSICAL_CORNERS = ["top-left""top-right""bottom-right""bottom-left"]
PHYSICAL_AXES = ["y""x"]
PHYSICAL_SIZES = ["height""width"]
LOGICAL_SIDES = ["block-start""block-end""inline-start""inline-end"]
LOGICAL_CORNERS = ["start-start""start-end""end-start""end-end"]
LOGICAL_SIZES = ["block-size""inline-size"]
LOGICAL_AXES = ["block""inline"]

SYSTEM_FONT_LONGHANDS = """font_family font_size font_style
                           font_stretch font_weight""".split()

PRIORITARY_PROPERTIES = set(
    [
        # The writing-mode group has the most priority of all property groups, as
        # sizes like font-size can depend on it.
        "writing-mode",
        "direction",
        "text-orientation",
        # The fonts and colors group has the second priority, as all other lengths
        # and colors depend on them.
        #
        # There are some interdependencies between these, but we fix them up in
        # Cascade::fixup_font_stuff.
        # Needed to properly compute the zoomed font-size.
        "-x-text-scale",
        # Needed to do font-size computation in a language-dependent way.
        "-x-lang",
        # Needed for ruby to respect language-dependent min-font-size
        # preferences properly, see bug 1165538.
        "-moz-min-font-size-ratio",
        # font-size depends on math-depth's computed value.
        "math-depth",
        # Needed to compute the first available font and its used size,
        # in order to compute font-relative units correctly.
        "font-size",
        "font-size-adjust",
        "font-weight",
        "font-stretch",
        "font-style",
        "font-family",
        # color-scheme affects how system colors and light-dark() resolve.
        "color-scheme",
        # forced-color-adjust affects whether colors are adjusted.
        "forced-color-adjust",
        # Zoom affects all absolute lengths.
        "zoom",
        # Line height lengths depend on this.
        "line-height",
        # appearance and -moz-default-appearance control whether
        # @appearance-base rules apply.
        "-moz-default-appearance",
        "appearance",
    ]
)

VISITED_DEPENDENT_PROPERTIES = set(
    [
        "column-rule-color",
        "text-emphasis-color",
        "-webkit-text-fill-color",
        "-webkit-text-stroke-color",
        "text-decoration-color",
        "fill",
        "stroke",
        "caret-color",
        "background-color",
        "border-top-color",
        "border-right-color",
        "border-bottom-color",
        "border-left-color",
        "border-block-start-color",
        "border-inline-end-color",
        "border-block-end-color",
        "border-inline-start-color",
        "outline-color",
        "color",
    ]
)

# Bitfield values for all rule types which can have property declarations.
STYLE_RULE = 1 << 0
PAGE_RULE = 1 << 1
KEYFRAME_RULE = 1 << 2
POSITION_TRY_RULE = 1 << 3
SCOPE_RULE = 1 << 4

ALL_RULES = STYLE_RULE | PAGE_RULE | KEYFRAME_RULE | SCOPE_RULE
DEFAULT_RULES = STYLE_RULE | KEYFRAME_RULE | SCOPE_RULE
DEFAULT_RULES_AND_PAGE = DEFAULT_RULES | PAGE_RULE
DEFAULT_RULES_EXCEPT_KEYFRAME = STYLE_RULE | SCOPE_RULE
DEFAULT_RULES_AND_POSITION_TRY = DEFAULT_RULES | POSITION_TRY_RULE

# Rule name to value dict
RULE_VALUES = {
    "style": STYLE_RULE,
    "page": PAGE_RULE,
    "keyframe": KEYFRAME_RULE,
    "position-try": POSITION_TRY_RULE,
    "scope": SCOPE_RULE,
}


def rule_values_from_arg(rule_types):
    if not rule_types:
        return DEFAULT_RULES
    mask = 0
    for rule in rule_types:
        mask |= RULE_VALUES[rule]
    return mask


def to_rust_ident(name):
    name = name.replace("-""_")
    if name in ["static""super""box""move"]:  # Rust keywords
        name += "_"
    return name


def idl_method(name, camel_case):
    if name == "float":
        return "CssFloat"
    if name.startswith("-x-"):
        return camel_case[1:]
    return camel_case


def to_snake_case(ident):
    return re.sub("([A-Z]+)"lambda m: "_" + m.group(1).lower(), ident).strip("_")


def to_camel_case(ident):
    return re.sub(
        "(^|_|-)([a-z0-9])"lambda m: m.group(2).upper(), ident.strip("_").strip("-")
    )


def to_camel_case_lower(ident):
    camel = to_camel_case(ident)
    return camel[0].lower() + camel[1:]


https://drafts.csswg.org/cssom/#css-property-to-idl-attribute
def to_idl_name(name):
    return re.sub("-([a-z])"lambda m: m.group(1).upper(), name)


def parse_aliases(value):
    aliases = {}
    for pair in value:
        [a, v] = pair.split("=")
        aliases[a] = v
    return aliases


class Vector(object):
    def __init__(
        self,
        need_index=False,
        none_value=None,
        separator='Comma',
        animation_type=None,
        simple_bindings=False,
    ):
        self.need_index = need_index
        self.none_value = none_value
        self.separator = separator
        self.animation_type = animation_type
        self.simple_bindings = simple_bindings


class Keyword(object):
    def __init__(
        self,
        name,
        values,
        gecko_constant_prefix=None,
        gecko_enum_prefix=None,
        extra_gecko_values=None,
        extra_servo_values=None,
        gecko_aliases=None,
        servo_aliases=None,
        gecko_inexhaustive=None,
    ):
        self.name = name
        self.values = values;
        assert isinstance(values, list), name
        if gecko_constant_prefix and gecko_enum_prefix:
            raise TypeError(
                "Only one of gecko_constant_prefix and gecko_enum_prefix "
                "can be specified"
            )
        self.gecko_constant_prefix = gecko_constant_prefix
        self.gecko_enum_prefix = gecko_enum_prefix
        if not gecko_constant_prefix and not gecko_enum_prefix:
            self.gecko_enum_prefix = "Style" + to_camel_case(name.replace("-moz-""").replace("-webkit-"""))
        self.extra_gecko_values = extra_gecko_values or []
        self.extra_servo_values = extra_servo_values or []
        self.gecko_aliases = parse_aliases(gecko_aliases or [])
        self.servo_aliases = parse_aliases(servo_aliases or [])
        self.gecko_inexhaustive = gecko_inexhaustive or self.gecko_constant_prefix is not None

    def values_for(self, engine):
        if engine == "gecko":
            return self.values + self.extra_gecko_values
        elif engine == "servo":
            return self.values + self.extra_servo_values
        else:
            raise Exception("Bad engine: " + engine)

    def aliases_for(self, engine):
        if engine == "gecko":
            return self.gecko_aliases
        elif engine == "servo":
            return self.servo_aliases
        else:
            raise Exception("Bad engine: " + engine)

    def gecko_constant(self, value):
        moz_stripped = value.replace("-moz-""")
        if self.gecko_enum_prefix:
            parts = moz_stripped.replace("-""_").split("_")
            parts = [p.title() for p in parts]
            return self.gecko_enum_prefix + "::" + "".join(parts)
        else:
            suffix = moz_stripped.replace("-""_")
            return self.gecko_constant_prefix + "_" + suffix.upper()

    def needs_cast(self):
        return self.gecko_enum_prefix is None

    def maybe_cast(self, type_str):
        return "as " + type_str if self.needs_cast() else ""

    def casted_constant_name(self, value, cast_type):
        if cast_type is None:
            raise TypeError("We should specify the cast_type.")

        if self.gecko_enum_prefix is None:
            return cast_type.upper() + "_" + self.gecko_constant(value)
        else:
            return (
                cast_type.upper()
                + "_"
                + self.gecko_constant(value).upper().replace("::""_")
            )


def parse_property_aliases(alias_list):
    result = []
    if alias_list:
        for alias in alias_list:
            (name, _, pref) = alias.partition(":")
            result.append((name, pref))
    return result


def to_phys(name, logical, physical):
    return name.replace(logical, physical).replace("inset-""")


class Property(object):
    def __init__(
        self,
        name,
        spec,
        servo_pref,
        gecko_pref,
        enabled_in,
        rule_types_allowed,
        aliases,
        extra_prefixes,
        flags,
    ):
        self.name = name
        if not spec:
            raise TypeError("Spec should be specified for " + name)
        self.spec = spec
        self.ident = to_rust_ident(name)
        self.camel_case = to_camel_case(self.ident)
        self.servo_pref = servo_pref
        self.gecko_pref = gecko_pref
        self.idl_method = idl_method(name, self.camel_case)
        self.rule_types_allowed = rule_values_from_arg(rule_types_allowed)
        # For enabled_in, the setup is as follows:
        # It needs to be one of the four values: ["", "ua", "chrome", "content"]
        #  * "chrome" implies "ua", and implies that they're explicitly
        #    enabled.
        #  * "" implies the property will never be parsed.
        #  * "content" implies the property is accessible unconditionally,
        #    modulo a pref, set via servo_pref / gecko_pref.
        assert enabled_in in ("""ua""chrome""content")
        self.enabled_in = enabled_in
        self.aliases = parse_property_aliases(aliases)
        self.extra_prefixes = parse_property_aliases(extra_prefixes)
        self.flags = flags.split() if flags else []

    def rule_types_allowed_names(self):
        for name in RULE_VALUES:
            if self.rule_types_allowed & RULE_VALUES[name] != 0:
                yield name

    def experimental(self, engine):
        if engine == "gecko":
            return bool(self.gecko_pref)
        elif engine == "servo":
            return bool(self.servo_pref)
        else:
            raise Exception("Bad engine: " + engine)

    def explicitly_enabled_in_ua_sheets(self):
        return self.enabled_in in ("ua""chrome")

    def explicitly_enabled_in_chrome(self):
        return self.enabled_in == "chrome"

    def enabled_in_content(self):
        return self.enabled_in == "content"

    def is_visited_dependent(self):
        return self.name in VISITED_DEPENDENT_PROPERTIES

    def is_prioritary(self):
        return self.name in PRIORITARY_PROPERTIES

    def noncustomcsspropertyid(self):
        return "NonCustomCSSPropertyId::eCSSProperty_" + self.ident


class Longhand(Property):
    def __init__(
        self,
        style_struct,
        name,
        initial_value=None,
        initial_specified_value=None,
        parse_method='parse',
        spec=None,
        animation_type="normal",
        keyword=None,
        predefined_type=None,
        servo_pref=None,
        gecko_pref=None,
        enabled_in="content",
        gecko_ffi_name=None,
        has_effect_on_gecko_scrollbars=None,
        rule_types_allowed=None,
        cast_type="u8",
        logical=False,
        logical_group=None,
        aliases=None,
        extra_prefixes=None,
        boxed=False,
        flags=None,
        allow_quirks=False,
        ignored_when_colors_disabled=False,
        vector=None,
        servo_restyle_damage="rebuild_box",
        affects=None,
    ):
        Property.__init__(
            self,
            name=name,
            spec=spec,
            servo_pref=servo_pref,
            gecko_pref=gecko_pref,
            enabled_in=enabled_in,
            rule_types_allowed=rule_types_allowed,
            aliases=aliases,
            extra_prefixes=extra_prefixes,
            flags=flags,
        )

        self.affects = affects
        self.flags += self.affects_flags()

        self.parse_method = parse_method
        self.initial_value = initial_value
        self.initial_specified_value = initial_specified_value
        self.keyword = keyword
        self.predefined_type = predefined_type
        self.style_struct = style_struct
        self.has_effect_on_gecko_scrollbars = has_effect_on_gecko_scrollbars
        assert (
            has_effect_on_gecko_scrollbars in [NoneFalseTrue]
            and not style_struct.inherited
            or (gecko_pref is None and enabled_in != "")
            == (has_effect_on_gecko_scrollbars is None)
        ), (
            "Property "
            + name
            + ": has_effect_on_gecko_scrollbars must be "
            + "specified, and must have a value of True or False, iff a "
            + "property is inherited and is behind a Gecko pref or internal"
        )
        self.gecko_ffi_name = gecko_ffi_name or "m" + self.camel_case
        self.cast_type = cast_type
        self.logical = logical
        self.logical_group = logical_group
        if self.logical:
            assert logical_group, f"Property {name} must have a logical group"

        self.boxed = boxed
        self.allow_quirks = allow_quirks
        self.ignored_when_colors_disabled = ignored_when_colors_disabled
        self.vector = Vector(**vector) if vector is not None else None

        assert animation_type in ["none""normal""discrete"]
        self.animation_type = animation_type
        self.animatable = animation_type != "none"

        # See compute_damage for the various values this can take
        self.servo_restyle_damage = servo_restyle_damage

    def affects_flags(self):
        # Layout is the stronger hint. This property animation affects layout
        # or frame construction. `display` or `width` are examples that should
        # use this.
        if self.affects == "layout":
            return ["AFFECTS_LAYOUT"]
        # This property doesn't affect layout, but affects overflow.
        # `transform` and co. are examples of this.
        if self.affects == "overflow":
            return ["AFFECTS_OVERFLOW"]
        # This property affects the rendered output but doesn't affect layout.
        # `opacity`, `color`, or `z-index` are examples of this.
        if self.affects == "paint":
            return ["AFFECTS_PAINT"]
        # This property doesn't affect rendering in any way.
        # `user-select` is an example of this.
        assert self.affects == "", (
            "Property "
            + self.name
            + ': affects must be specified and be one of ["layout", "overflow", "paint", ""], see Longhand.affects_flags for documentation'
        )
        return []

    @staticmethod
    def type():
        return "longhand"

    # For a given logical property, return the kind of mapping we need to
    # perform, and which logical value we represent, in a tuple.
    def logical_mapping_data(self, data):
        if not self.logical:
            return []
        # Sizes and axes are basically the same for mapping, we just need
        # slightly different replacements (block-size -> height, etc rather
        # than -x/-y) below.
        for [ty, logical_items, physical_items] in [
            ["Side", LOGICAL_SIDES, PHYSICAL_SIDES],
            ["Corner", LOGICAL_CORNERS, PHYSICAL_CORNERS],
            ["Axis", LOGICAL_SIZES, PHYSICAL_SIZES],
            ["Axis", LOGICAL_AXES, PHYSICAL_AXES],
        ]:
            candidate = [s for s in logical_items if s in self.name]
            if candidate:
                assert len(candidate) == 1
                return [ty, candidate[0], logical_items, physical_items]
        assert False"Don't know how to deal with " + self.name

    def logical_mapping_kind(self, data):
        assert self.logical
        [kind, item, _, _] = self.logical_mapping_data(data)
        return "LogicalMappingKind::{}(Logical{}::{})".format(
            kind, kind, to_camel_case(item.replace("-size"""))
        )

    # For a given logical property return all the physical property names
    # corresponding to it.
    def all_physical_mapped_properties(self, data):
        if not self.logical:
            return []
        [_, logical_side, _, physical_items] = self.logical_mapping_data(data)
        return [
            data.longhands_by_name[to_phys(self.name, logical_side, physical_side)]
            for physical_side in physical_items
        ]

    def may_be_disabled_in(self, shorthand, engine):
        if engine == "gecko":
            return self.gecko_pref and self.gecko_pref != shorthand.gecko_pref
        elif engine == "servo":
            return self.servo_pref and self.servo_pref != shorthand.servo_pref
        else:
            raise Exception("Bad engine: " + engine)

    def base_type(self):
        if self.predefined_type and not self.vector:
            return "crate::values::specified::{}".format(self.predefined_type)
        return "longhands::{}::SpecifiedValue".format(self.ident)

    def specified_type(self):
        if self.predefined_type and not self.vector:
            ty = "crate::values::specified::{}".format(self.predefined_type)
        else:
            ty = "longhands::{}::SpecifiedValue".format(self.ident)
        if self.boxed:
            ty = "Box<{}>".format(ty)
        return ty

    def is_zoom_dependent(self):
        if not self.predefined_type:
            return False
        # TODO: Get this from SpecifiedValueInfo or so instead; see bug 1887627.
        return self.predefined_type in {
            "BorderSideWidth",
            "BorderSpacing",
            "BoxShadow",
            "Filter",
            "FontSize",
            "Inset",
            "Length",
            "LengthPercentage",
            "LengthPercentageOrAuto",
            "LetterSpacing",
            "LineHeight",
            "LineWidth",
            "MaxSize",
            "Margin",
            "NonNegativeLength",
            "NonNegativeLengthOrAuto",
            "NonNegativeLengthOrNumber",
            "NonNegativeLengthOrNumberRect",
            "NonNegativeLengthPercentage",
            "NonNegativeLengthPercentageOrAuto",
            "NonNegativeLengthPercentageOrNormal",
            "Position",
            "PositionOrAuto",
            "SimpleShadow",
            "Size",
            "SVGLength",
            "SVGStrokeDashArray",
            "SVGWidth",
            "TextDecorationLength",
            "TextDecorationInset",
            "TextIndent",
            "WordSpacing",
        }

    def is_inherited_zoom_dependent_property(self):
        if self.logical:
            return False
        if not self.style_struct.inherited:
            return False
        return self.is_zoom_dependent()

    def specified_is_copy(self):
        if self.vector or self.boxed:
            return False
        if self.predefined_type:
            return self.predefined_type in {
                "AlignmentBaseline",
                "Appearance",
                "AnimationComposition",
                "AnimationDirection",
                "AnimationFillMode",
                "AnimationPlayState",
                "BaselineSource",
                "BreakBetween",
                "BreakWithin",
                "BackgroundRepeat",
                "BorderImageRepeat",
                "BorderStyle",
                "table::CaptionSide",
                "Clear",
                "Contain",
                "ContentVisibility",
                "ContainerType",
                "Display",
                "DominantBaseline",
                "FillRule",
                "Float",
                "FontLanguageOverride",
                "FontSynthesis",
                "FontSynthesisStyle",
                "FontVariantEastAsian",
                "FontVariantLigatures",
                "FontVariantNumeric",
                "GridAutoFlow",
                "ImageRendering",
                "Inert",
                "PositionArea",
                "PositionAreaKeyword",
                "PositionProperty",
                "ContentDistribution",
                "ItemPlacement",
                "SelfAlignment",
                "JustifyItems",
                "LineBreak",
                "MasonryAutoFlow",
                "MozTheme",
                "BoolInteger",
                "text::MozControlCharacterVisibility",
                "MozScriptMinSize",
                "MozScriptSizeMultiplier",
                "TransformBox",
                "TextDecorationSkipInk",
                "OutlineStyle",
                "Overflow",
                "OverflowAnchor",
                "OverflowWrap",
                "OverscrollBehavior",
                "PageOrientation",
                "PointerEvents",
                "PositionTryOrder",
                "PositionVisibility",
                "PrintColorAdjust",
                "ForcedColorAdjust",
                "Resize",
                "RubyPosition",
                "SVGPaintOrder",
                "ScrollbarGutter",
                "ScrollSnapAlign",
                "ScrollSnapAxis",
                "ScrollSnapStop",
                "ScrollSnapStrictness",
                "ScrollSnapType",
                "TextAlign",
                "TextAlignLast",
                "TextAutospace",
                "TextBoxEdge",
                "TextBoxTrim",
                "TextDecorationLine",
                "TextEmphasisPosition",
                "TextJustify",
                "TextTransform",
                "TextUnderlinePosition",
                "TouchAction",
                "TransformStyle",
                "UserFocus",
                "UserSelect",
                "VectorEffect",
                "WordBreak",
                "WritingModeProperty",
                "XSpan",
                "XTextScale",
            }
        if self.name == "overflow-y":
            return True
        return bool(self.keyword)

    def animated_type(self):
        assert self.animatable
        computed = "<{} as ToComputedValue>::ComputedValue".format(self.base_type())
        if self.animation_type == "discrete":
            return computed
        return "<{} as ToAnimatedValue>::AnimatedValue".format(computed)


class Shorthand(Property):
    def __init__(
        self,
        name,
        sub_properties,
        spec=None,
        servo_pref=None,
        gecko_pref=None,
        kind=None,
        allow_quirks=False,
        derive_serialize=False,
        derive_value_info=True,
        enabled_in="content",
        rule_types_allowed=None,
        aliases=None,
        extra_prefixes=None,
        flags=None,
    ):
        Property.__init__(
            self,
            name=name,
            spec=spec,
            servo_pref=servo_pref,
            gecko_pref=gecko_pref,
            enabled_in=enabled_in,
            rule_types_allowed=rule_types_allowed,
            aliases=aliases,
            extra_prefixes=extra_prefixes,
            flags=flags,
        )
        self.sub_properties = sub_properties
        self.derive_serialize = derive_serialize
        self.derive_value_info = derive_value_info
        self.allow_quirks = allow_quirks
        self.kind = kind

    def get_animatable(self):
        for sub in self.sub_properties:
            if sub.animatable:
                return True
        return False

    animatable = property(get_animatable)

    @staticmethod
    def type():
        return "shorthand"


class Alias(object):
    def __init__(self, name, original, gecko_pref):
        self.name = name
        self.ident = to_rust_ident(name)
        self.camel_case = to_camel_case(self.ident)
        self.idl_method = idl_method(name, self.camel_case)
        self.original = original
        self.enabled_in = original.enabled_in
        self.animatable = original.animatable
        self.servo_pref = original.servo_pref
        self.gecko_pref = gecko_pref
        self.rule_types_allowed = original.rule_types_allowed
        self.flags = original.flags

    @staticmethod
    def type():
        return "alias"

    def rule_types_allowed_names(self):
        for name in RULE_VALUES:
            if self.rule_types_allowed & RULE_VALUES[name] != 0:
                yield name

    def experimental(self, engine):
        if engine == "gecko":
            return bool(self.gecko_pref)
        elif engine == "servo":
            return bool(self.servo_pref)
        else:
            raise Exception("Bad engine: " + engine)

    def explicitly_enabled_in_ua_sheets(self):
        return self.enabled_in in ["ua""chrome"]

    def explicitly_enabled_in_chrome(self):
        return self.enabled_in == "chrome"

    def enabled_in_content(self):
        return self.enabled_in == "content"

    def noncustomcsspropertyid(self):
        return "NonCustomCSSPropertyId::eCSSPropertyAlias_%s" % self.ident


class Method(object):
    def __init__(self, name, return_type=None, arg_types=None, is_mut=False):
        self.name = name
        self.return_type = return_type
        self.arg_types = arg_types or []
        self.is_mut = is_mut

    def arg_list(self):
        args = ["_: " + x for x in self.arg_types]
        args = ["&mut self" if self.is_mut else "&self"] + args
        return ", ".join(args)

    def signature(self):
        sig = "fn %s(%s)" % (self.name, self.arg_list())
        if self.return_type:
            sig = sig + " -> " + self.return_type
        return sig

    def declare(self):
        return self.signature() + ";"

    def stub(self):
        return self.signature() + "{ unimplemented!() }"


class StyleStruct(object):
    def __init__(self, name, inherited, gecko_name=None):
        self.gecko_struct_name = "Gecko" + name
        self.name = name
        self.name_lower = to_snake_case(name)
        self.ident = to_rust_ident(self.name_lower)
        self.longhands = []
        self.inherited = inherited
        self.gecko_name = gecko_name or name
        self.gecko_ffi_name = "nsStyle" + self.gecko_name
        self.document_dependent = self.gecko_name in ["Font""Visibility""Text"]


class Descriptor(object):
    def __init__(self, name, type, parser=None, gecko_pref=None, ignore_malloc_size_of=None):
        self.name = name
        self.type = type
        self.parser = parser
        self.gecko_pref = gecko_pref
        self.ignore_malloc_size_of = ignore_malloc_size_of
        self.ident = to_rust_ident(name)
        self.camel_case = to_camel_case(name)


class PropertiesData(object):
    def __init__(self, engine):
        self.engine = engine
        self.longhands = []
        self.longhands_by_name = {}
        self.logical_groups = {}
        self.longhand_aliases = []
        self.shorthands = []
        self.shorthands_by_name = {}
        self.shorthand_aliases = []
        self.counted_unknown_properties = [
            CountedUnknownProperty(p) for p in COUNTED_UNKNOWN_PROPERTIES
        ]

        self.style_structs = [
            StyleStruct("Background", inherited=False),
            StyleStruct("Border", inherited=False),
            StyleStruct("Box", inherited=False, gecko_name="Display"),
            StyleStruct("Column", inherited=False),
            StyleStruct("Counters", inherited=False, gecko_name="Content"),
            StyleStruct("Effects", inherited=False),
            StyleStruct("Font", inherited=True),
            StyleStruct("InheritedBox", inherited=True, gecko_name="Visibility"),
            StyleStruct("InheritedSVG", inherited=True, gecko_name="SVG"),
            StyleStruct("InheritedTable", inherited=True, gecko_name="TableBorder"),
            StyleStruct("InheritedText", inherited=True, gecko_name="Text"),
            StyleStruct("InheritedUI", inherited=True, gecko_name="UI"),
            StyleStruct("List", inherited=True),
            StyleStruct("Margin", inherited=False),
            StyleStruct("Outline", inherited=False),
            StyleStruct("Padding", inherited=False),
            StyleStruct("Page", inherited=False),
            StyleStruct("Position", inherited=False),
            StyleStruct("SVG", inherited=False, gecko_name="SVGReset"),
            StyleStruct("Table", inherited=False),
            StyleStruct("Text", inherited=False, gecko_name="TextReset"),
            StyleStruct("UI", inherited=False, gecko_name="UIReset"),
            StyleStruct("XUL", inherited=False),
        ]

        longhands_toml = toml.loads(open(os.path.join(os.path.dirname(__file__), "longhands.toml")).read())
        for name, args in longhands_toml.items():
            style_struct = self.style_struct_by_name_lower(args["struct"])
            del args['struct']

            # Handle keyword properties
            if 'keyword' in args:
                keyword_dict = args.pop('keyword')
                if 'values' not in keyword_dict:
                    raise TypeError(f"{name}: keyword should have 'values'")
                values = keyword_dict.pop('values')
                keyword = Keyword(name, values, **keyword_dict)
                self.declare_longhand(style_struct, name, keyword=keyword, **args)
            else:
                # Handle predefined_type properties
                if 'type' not in args:
                    raise TypeError(f"{name} should have a type")
                args['predefined_type'] = args.pop('type')
                if 'initial' not in args and not args.get('vector'):
                    raise TypeError(f"{name} should have an initial value (only vector properties should lack one)")
                args['initial_value'] = args.pop('initial'None)
                self.declare_longhand(style_struct, name, **args)

        for group, props in self.logical_groups.items():
            logical_count = sum(1 for p in props if p.logical)
            if logical_count * 2 != len(props):
                raise RuntimeError(f"Logical group {group} has unbalanced logical / physical properties")

        # After this code, `data.longhands` is sorted in the following order:
        # - first all keyword variants and all variants known to be Copy,
        # - second all the other variants, such as all variants with the same field
        #   have consecutive discriminants.
        # The variable `variants` contain the same entries as `data.longhands` in
        # the same order, but must exist separately to the data source, because
        # we then need to add three additional variants `WideKeywordDeclaration`,
        # `VariableDeclaration` and `CustomDeclaration`.
        self.declaration_variants = []
        for property in self.longhands:
            self.declaration_variants.append({
                "name": property.camel_case,
                "type": property.specified_type(),
                "doc""`" + property.name + "`",
                "copy": property.specified_is_copy(),
            })
        groups = {}
        keyfunc = lambda x: x["type"]
        sortkeys = {}
        # WARNING: It is *really* important for the variants of `LonghandId`
        # and `PropertyDeclaration` to be defined in the exact same order,
        # with the exception of `CSSWideKeyword`, `WithVariables` and `Custom`,
        # which don't exist in `LonghandId`.
        for ty, group in groupby(sorted(self.declaration_variants, key=keyfunc), keyfunc):
            group = list(group)
            groups[ty] = group
            for v in group:
                if len(group) == 1:
                    sortkeys[v["name"]] = (not v["copy"], 1, v["name"], "")
                else:
                    sortkeys[v["name"]] = (not v["copy"], len(group), ty, v["name"])
        # It is extremely important to sort the `data.longhands` array here so
        # that it is in the same order as `variants`, for `LonghandId` and
        # `PropertyDeclarationId` to coincide.
        self.longhands.sort(key=lambda x: sortkeys[x.camel_case])
        self.declaration_variants.sort(key=lambda x: sortkeys[x["name"]])
        self.declaration_extra_variants = [
            {
                "name""CSSWideKeyword",
                "type""WideKeywordDeclaration",
                "doc""A CSS-wide keyword.",
                "copy"False,
            },
            {
                "name""WithVariables",
                "type""VariableDeclaration",
                "doc""An unparsed declaration.",
                "copy"False,
            },
            {
                "name""Custom",
                "type""CustomDeclaration",
                "doc""A custom property declaration.",
                "copy"False,
            },
        ]
        for v in self.declaration_extra_variants:
            self.declaration_variants.append(v)
            groups[v["type"]] = [v]

        shorthands_toml = toml.loads(open(os.path.join(os.path.dirname(__file__), "shorthands.toml")).read())
        for name, args in shorthands_toml.items():
            self.declare_shorthand(name, **args)
        self.declare_all_shorthand()

        self.font_face_descriptors = self._load_descriptors("font_face_descriptors.toml")
        self.counter_style_descriptors = self._load_descriptors("counter_style_descriptors.toml")
        self.property_descriptors = self._load_descriptors("property_descriptors.toml")
        self.view_transition_descriptors = self._load_descriptors("view_transition_descriptors.toml")


    def declare_all_shorthand(self):
        # We don't define the 'all' shorthand using the regular helpers:shorthand
        # mechanism, since it causes some very large types to be generated.
        #
        # Make sure logical properties appear before its physical
        # counter-parts, in order to prevent bugs like:
        #
        #   https://bugzilla.mozilla.org/show_bug.cgi?id=1410028
        #
        # FIXME(emilio): Adopt the resolution from:
        #
        #   https://github.com/w3c/csswg-drafts/issues/1898
        #
        # when there is one, whatever that is.
        logical_longhands = []
        other_longhands = []
        for p in self.longhands:
            if p.name in ['direction''unicode-bidi']:
                continue;
            if not p.enabled_in_content() and not p.experimental(self.engine):
                continue;
            if "style" not in p.rule_types_allowed_names():
                continue;
            if p.logical:
                logical_longhands.append(p)
            else:
                other_longhands.append(p)

        # Cache locality when iterating over the `all` shorthand is important
        # for transition handling, so we sort by style struct.
        # We technically don't care about the logical prop order (because those
        # are not animated themselves), but we sort them the same way for
        # consistency.
        logical_longhands.sort(key=lambda p: p.style_struct.name)
        other_longhands.sort(key=lambda p: p.style_struct.name)

        all_names = list(map(lambda p: p.name, logical_longhands + other_longhands))

        self.all_shorthand_length = len(all_names)
        self.declare_shorthand(
            "all",
            all_names,
            spec="https://drafts.csswg.org/css-cascade-3/#all-shorthand"
        )


    def _load_descriptors(self, filename):
        path = os.path.join(os.path.dirname(__file__), filename)
        data = toml.loads(open(path).read())
        return [Descriptor(name, **args) for name, args in data.items()]

    def style_struct_by_name_lower(self, name):
        for s in self.style_structs:
            if s.name_lower == name:
                return s
        raise TypeError(f"Unexpected struct name {name}")

    def active_style_structs(self):
        return [s for s in self.style_structs if s.longhands]

    def add_prefixed_aliases(self, property):
        for prefix, pref in property.extra_prefixes:
            property.aliases.append(("-%s-%s" % (prefix, property.name), pref))

    def declare_longhand(self, style_struct, name, extra_gecko_aliases=None, engine=None**kwargs):
        if engine and self.engine != engine:
            return
        if extra_gecko_aliases and self.engine == "gecko":
            kwargs.setdefault('aliases', []).extend(extra_gecko_aliases)
        longhand = Longhand(style_struct, name, **kwargs)
        self.add_prefixed_aliases(longhand)
        longhand.aliases = [Alias(xp[0], longhand, xp[1]) for xp in longhand.aliases]
        self.longhand_aliases += longhand.aliases
        style_struct.longhands.append(longhand)
        self.longhands.append(longhand)
        self.longhands_by_name[name] = longhand
        if longhand.logical_group:
            self.logical_groups.setdefault(
                longhand.logical_group, []
            ).append(longhand)

        return longhand

    def declare_shorthand(self, name, sub_properties, extra_gecko_sub_properties=None, extra_gecko_aliases=None, engine=None, *args, **kwargs):
        if engine and self.engine != engine:
            return
        if self.engine == "gecko":
            if extra_gecko_sub_properties:
                sub_properties.extend(extra_gecko_sub_properties)
            if extra_gecko_aliases:
                kwargs.setdefault('aliases', []).extend(extra_gecko_aliases)
        sub_properties = [self.longhands_by_name[s] for s in sub_properties]
        shorthand = Shorthand(name, sub_properties, *args, **kwargs)
        self.add_prefixed_aliases(shorthand)
        shorthand.aliases = [Alias(xp[0], shorthand, xp[1]) for xp in shorthand.aliases]
        self.shorthand_aliases += shorthand.aliases
        self.shorthands.append(shorthand)
        self.shorthands_by_name[name] = shorthand
        return shorthand

    def shorthands_except_all(self):
        return [s for s in self.shorthands if s.name != "all"]

    def all_aliases(self):
        return self.longhand_aliases + self.shorthand_aliases

    def all_properties_and_aliases(self):
        return self.longhands + self.shorthands + self.longhand_aliases + self.shorthand_aliases


def _add_logical_props(data, props):
    groups = set()
    for prop in props:
        if prop not in data.longhands_by_name:
            assert data.engine == "servo"
            continue
        prop = data.longhands_by_name[prop]
        if prop.logical_group:
            groups.add(prop.logical_group)
    for group in groups:
        for prop in data.logical_groups[group]:
            props.add(prop.name)


# These are probably Gecko bugs and should be supported per spec.
def _remove_common_first_line_and_first_letter_properties(props, engine):
    if engine == "gecko":
        props.remove("tab-size")
        props.remove("hyphens")
        props.remove("line-break")
        props.remove("text-align-last")
        props.remove("text-emphasis-position")
        props.remove("text-emphasis-style")
        props.remove("text-emphasis-color")
        props.remove("text-wrap-style")

    props.remove("overflow-wrap")
    props.remove("text-align")
    props.remove("text-justify")
    props.remove("white-space-collapse")
    props.remove("text-wrap-mode")
    props.remove("word-break")
    props.remove("text-indent")


class PropertyRestrictions:
    @staticmethod
    def logical_group(data, group):
        return [p.name for p in data.logical_groups[group]]

    @staticmethod
    def shorthand(data, shorthand):
        if shorthand not in data.shorthands_by_name:
            return []
        return [p.name for p in data.shorthands_by_name[shorthand].sub_properties]

    @staticmethod
    def spec(data, spec_path):
        return [p.name for p in data.longhands if spec_path in p.spec]

    https://svgwg.org/svg2-draft/propidx.html
    @staticmethod
    def svg_text_properties():
        props = set(
            [
                "fill",
                "fill-opacity",
                "fill-rule",
                "paint-order",
                "stroke",
                "stroke-dasharray",
                "stroke-dashoffset",
                "stroke-linecap",
                "stroke-linejoin",
                "stroke-miterlimit",
                "stroke-opacity",
                "stroke-width",
                "text-rendering",
                "vector-effect",
            ]
        )
        return props

    @staticmethod
    def webkit_text_properties():
        props = set(
            [
                # Kinda like css-text?
                "-webkit-text-stroke-width",
                "-webkit-text-fill-color",
                "-webkit-text-stroke-color",
            ]
        )
        return props

    https://drafts.csswg.org/css-pseudo/#first-letter-styling
    @staticmethod
    def first_letter(data):
        props = set(
            [
                "color",
                "opacity",
                "float",
                "initial-letter",
                # Kinda like css-fonts?
                "-moz-osx-font-smoothing",
                "alignment-baseline",
                "baseline-shift",
                "baseline-source",
                "line-height",
                # Kinda like css-backgrounds?
                "background-blend-mode",
            ]
            + PropertyRestrictions.shorthand(data, "padding")
            + PropertyRestrictions.shorthand(data, "margin")
            + PropertyRestrictions.spec(data, "css-fonts")
            + PropertyRestrictions.spec(data, "css-backgrounds")
            + PropertyRestrictions.spec(data, "css-text")
            + PropertyRestrictions.spec(data, "css-shapes")
            + PropertyRestrictions.spec(data, "css-text-decor")
        )
        props = props.union(PropertyRestrictions.svg_text_properties())
        props = props.union(PropertyRestrictions.webkit_text_properties())

        _add_logical_props(data, props)

        _remove_common_first_line_and_first_letter_properties(props, data.engine)
        return props

    https://drafts.csswg.org/css-pseudo/#first-line-styling
    @staticmethod
    def first_line(data):
        props = set(
            [
                # Per spec.
                "color",
                "opacity",
                # Kinda like css-fonts?
                "-moz-osx-font-smoothing",
                "alignment-baseline",
                "baseline-shift",
                "baseline-source",
                "line-height",
                # Kinda like css-backgrounds?
                "background-blend-mode",
            ]
            + PropertyRestrictions.spec(data, "css-fonts")
            + PropertyRestrictions.spec(data, "css-backgrounds")
            + PropertyRestrictions.spec(data, "css-text")
            + PropertyRestrictions.spec(data, "css-text-decor")
        )
        props = props.union(PropertyRestrictions.svg_text_properties())
        props = props.union(PropertyRestrictions.webkit_text_properties())

        # These are probably Gecko bugs and should be supported per spec.
        for prop in PropertyRestrictions.shorthand(data, "border"):
            props.remove(prop)
        for prop in PropertyRestrictions.shorthand(data, "border-radius"):
            props.remove(prop)
        props.remove("box-shadow")

        _remove_common_first_line_and_first_letter_properties(props, data.engine)
        return props

    https://drafts.csswg.org/css-pseudo/#placeholder
    #
    # The spec says that placeholder and first-line have the same restrictions,
    # but that's not true in Gecko and we also allow a handful other properties
    # for ::placeholder.
    @staticmethod
    def placeholder(data):
        props = PropertyRestrictions.first_line(data)
        props.add("opacity")
        props.add("text-overflow")
        props.add("text-align")
        props.add("text-justify")
        for p in PropertyRestrictions.shorthand(data, "text-wrap"):
            props.add(p)
        for p in PropertyRestrictions.shorthand(data, "white-space"):
            props.add(p)
        # ::placeholder can't be SVG text
        props -= PropertyRestrictions.svg_text_properties()
        # Historically ::placeholder's line-height was !important in the UA sheet.
        props.remove("line-height")

        return props

    https://drafts.csswg.org/css-lists-3/#marker-properties
    @staticmethod
    def marker(data):
        return set(
            [
                "color",
                "content",
                "counter-increment",
                "counter-reset",
                "counter-set",
                "cursor",
                "direction",
                "hyphens",
                "line-height",
                "quotes",
                "text-combine-upright",
                "text-emphasis-color",
                "text-emphasis-position",
                "text-emphasis-style",
                "text-orientation",
                "text-shadow",
                "text-transform",
                "unicode-bidi",
                "-moz-osx-font-smoothing",
            ]
            + PropertyRestrictions.shorthand(data, "animation-range")
            + PropertyRestrictions.shorthand(data, "text-wrap")
            + PropertyRestrictions.shorthand(data, "white-space")
            + PropertyRestrictions.spec(data, "css-fonts")
            + PropertyRestrictions.spec(data, "css-animations")
            + PropertyRestrictions.spec(data, "css-transitions")
        )

    https://www.w3.org/TR/webvtt1/#the-cue-pseudo-element
    @staticmethod
    def cue(data):
        return set(
            [
                "color",
                "opacity",
                "visibility",
                "text-shadow",
                "text-combine-upright",
                "ruby-position",
                # XXX Should these really apply to cue?
                "-moz-osx-font-smoothing",
                # FIXME(emilio): background-blend-mode should be part of the
                # background shorthand, and get reset, per
                https://drafts.fxtf.org/compositing/#background-blend-mode
                "background-blend-mode",
            ]
            + PropertyRestrictions.shorthand(data, "text-decoration")
            + PropertyRestrictions.shorthand(data, "text-wrap")
            + PropertyRestrictions.shorthand(data, "white-space")
            + PropertyRestrictions.shorthand(data, "background")
            + PropertyRestrictions.shorthand(data, "outline")
            + PropertyRestrictions.shorthand(data, "font")
            + PropertyRestrictions.shorthand(data, "font-synthesis")
        )


class CountedUnknownProperty:
    def __init__(self, name):
        self.name = name
        self.ident = to_rust_ident(name)
        self.camel_case = to_camel_case(self.ident)

Messung V0.5 in Prozent
C=82 H=97 G=89

¤ Dauer der Verarbeitung: 0.19 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002