author Masayuki Nakano <>
Sun, 16 Jan 2022 06:21:17 +0000
changeset 604634 9ef0614a59629916c1e182eb8eda055b0b0e8b32
parent 587290 771f07bccfc35468516dfa391d5913f554889bd8
permissions -rw-r--r--
Bug 1749299 - Make `HTMLEditor::HandleInsertLinefeed()` stop handling it if insertion point cannot have text nodes r=m_kato Ideally, it should not be called when the editor cannot insert new text node. However, the callers are complicated. Therefore, let's check in it for avoiding making the callers more complicated. Fortunately, this is not realistic path for normal web apps. Therefore, the compatibility of the behavior is not matter. That's the reason why this patch does not have a test comparing the result. Differential Revision:

# 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

# This script generates jit/MIROpsGenerated.h (list of MIR instructions)
# from MIROps.yaml, as well as MIR op definitions.

import yaml
from collections import OrderedDict

/* 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 */

#ifndef {includeguard}
#define {includeguard}

/* This file is generated by DO NOT EDIT! */

// Profiler sub-categories are applied to each sampled stack to describe the
// type of workload that the CPU is busy with. Only one sub-category can be
// assigned so be mindful that these are non-overlapping. The active category is
// set by pushing a label to the profiling stack, or by the unwinder in cases
// such as JITs. A profile sample in arbitrary C++/Rust will typically be
// categorized based on the top of the label stack.
// The list of available color names for categories is:
//    transparent
//    blue
//    green
//    grey
//    lightblue
//    magenta
//    orange
//    purple
//    yellow

// clang-format off


// clang-format on

#endif // {includeguard}


/* 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 */

/* This file is generated by DO NOT EDIT! */


#[derive(Debug, Copy, Clone)]
pub enum {name} {{

impl {name} {{
  pub fn to_cpp_enum_value(&self) -> u32 {{

impl Default for {name} {{
  fn default() -> Self {{

    match *self {{

def generate_header(c_out, includeguard, contents):
        CPP_HEADER_TEMPLATE.format(includeguard=includeguard, contents=contents)

def generate_rust_file(c_out, contents):

def load_yaml(yaml_path):
    # Load into an OrderedDict to ensure order is preserved. Note: Python 3.7+
    # also preserves ordering for normal dictionaries.
    # Code based on
    class OrderedLoader(yaml.Loader):

    def construct_mapping(loader, node):
        return OrderedDict(loader.construct_pairs(node))

    tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG
    OrderedLoader.add_constructor(tag, construct_mapping)

    file_handler = open(yaml_path)
    return yaml.load(file_handler, OrderedLoader)

def generate_category_macro(name, label, color, subcategories):
    contents = '  BEGIN_CATEGORY({name}, "{label}", "{color}") \\\n'.format(
        name=name, label=label, color=color

    subcategory_items = []

    for subcategory in subcategories:
        subcat_name = subcategory["name"]
        assert isinstance(subcat_name, str)
        subcat_label = subcategory["label"]
        assert isinstance(subcat_label, str)

            '    SUBCATEGORY({parent_cat}, {name}, "{label}") \\\n'.format(
                parent_cat=name, name=subcat_name, label=subcat_label

    contents += "".join(subcategory_items)
    contents += "  END_CATEGORY"

    return contents

def generate_macro_header(c_out, yaml_path):
    """Generate ProfilingCategoryList.h from profiling_categories.yaml.
    The generated file has a macro to generate the profiling category enums.

    data = load_yaml(yaml_path)

    # Stores the macro definition of each categories.
    category_items = []

    for category in data:
        name = category["name"]
        assert isinstance(name, str)
        label = category["label"]
        assert isinstance(label, str)
        color = category["color"]
        assert isinstance(color, str)
        subcategories = category.get("subcategories", None)
        assert (
            isinstance(subcategories, list) and len(subcategories) > 0
        ), "At least one subcategory expected as default in {}.".format(name)

            generate_category_macro(name, label, color, subcategories)

    contents += " \\\n".join(category_items)

    generate_header(c_out, "baseprofiler_ProfilingCategoryList_h", contents)

class RustEnum:
    """Class that keeps the rust enum fields and impls.
    This is used for generating the Rust ProfilingCategoryPair and ProfilingCategory
    enums as well as ProfilingCategoryPair's sub category enums.
    For example, this can either generate an enum with discrimant fields for sub
    category enums and ProfilingCategory:
    #[derive(Debug, Copy, Clone)]
    pub enum Graphics {
        LayerBuilding = 0,
    or can generate an enum with optional tuple values for ProfilingCategoryPair
     to explicitly mention their sub categories:
    #[derive(Debug, Copy, Clone)]
    pub enum ProfilingCategoryPair {

    And in addition to enums, it will generate impls for each enum. See one
    example below:
    impl Default for Network {
        fn default() -> Self {

    def __init__(self, name):
        # Name of the Rust enum. = name
        # Fields of the Rust enum. This list contains elements of
        # (field_name, field_string) tuple for convenience.
        self.fields = []
        # Impls of the Rust enum. Each element is a string.
        self.impls = []
        # Default category of the Rust enum. Main enums won't have it, but all
        # sub category enums must have one. This is being checked later.
        self.default_category = None

    def append_optional_tuple_field(self, field_name):
        """Append the enum fields list with an optional tuple field."""
        field = (field_name, "  {name}(Option<{name}>),".format(name=field_name))

    def append_discriminant_field(self, field_name, field_value):
        """Append the enum fields list with a discriminant field."""
        field = (
            "  {name} = {value},".format(name=field_name, value=field_value),

    def append_default_impl(self, default_category):
        """Append the enum impls list with a default implementation."""
        self.default_category = default_category

                content="      {category}::{subcategory}".format(
          , subcategory=self.default_category

    def append_conversion_impl(self, content):
        """Append the enum impls list with a conversion implementation for cpp values."""
            RUST_CONVERSION_IMPL_TEMPLATE.format(, content=content)

    def to_rust_string(self):
        """Serialize the enum with its impls as a string"""
        joined_fields = "\n".join(map(lambda field: field[1], self.fields))
        result = RUST_ENUM_TEMPLATE.format(, fields=joined_fields)
        result += "\n"
        result += "\n".join(self.impls)
        return result

def generate_rust_enums(c_out, yaml_path):
    """Generate from profiling_categories.yaml.
    The generated file has a profiling category enums and their impls.

    data = load_yaml(yaml_path)

    # Each category has its own enum for keeping its subcategories. We are
    # keeping all of them here.
    enums = []
    # Parent enums for prifiling category and profiling category pair. They will
    # be appended to the end of the `enums`.
    profiling_category_pair_enum = RustEnum("ProfilingCategoryPair")
    profiling_category_enum = RustEnum("ProfilingCategory")
    profiling_category_pair_value = 0

    for cat_index, category in enumerate(data):
        cat_name = category["name"]
        assert isinstance(cat_name, str)
        cat_label = category["label"]
        assert isinstance(cat_label, str)
        # This will be used as our main enum field and sub category enum.
        cat_label = "".join(filter(str.isalnum, cat_label))
        cat_subcategories = category.get("subcategories", None)
        assert (
            isinstance(cat_subcategories, list) and len(cat_subcategories) > 0
        ), "At least one subcategory expected as default in {}.".format(cat_name)

        # Create a new enum for this sub category and append it to the enums list.
        category_enum = RustEnum(cat_label)

        for subcategory in cat_subcategories:
            subcat_name = subcategory["name"]
            assert isinstance(subcat_name, str)
            subcat_label = subcategory["label"]
            assert isinstance(subcat_label, str)
            friendly_subcat_name = None

            if cat_name == subcat_name:
                # This is the default sub-category. It should use the label as name.
                friendly_subcat_name = subcat_label
                # This is a non-default sub-category.
                underscore_pos = subcat_name.find("_")
                friendly_subcat_name = subcat_name[underscore_pos + 1 :]

            friendly_subcat_name = "".join(filter(str.isalnum, friendly_subcat_name))
                friendly_subcat_name, profiling_category_pair_value
            profiling_category_pair_value += 1

        assert (
            category_enum.default_category is not None
        ), "There must be a default subcategory with the same name."

        # Append the main enums.
        profiling_category_enum.append_discriminant_field(cat_label, cat_index)

    # Add the main enums impls for conversion into cpp values.
    profiling_category_pair_impl_fields = "\n".join(
        "      {enum_name}::{field_name}(val) => val.unwrap_or_default() as u32,".format(
            enum_name="ProfilingCategoryPair", field_name=field
        for field, _ in profiling_category_pair_enum.fields
    profiling_category_enum.append_conversion_impl("      *self as u32")

    # After adding all the sub category enums, we can add the main enums to the list.

    # Print all the enums and their impls.
    contents = "\n".join(map(lambda enum: enum.to_rust_string(), enums))
    generate_rust_file(c_out, contents)