waterfox Documentation

The official Waterfox 💧 source code repository

6,380 stars JavaScript JavaScript 100 files · ~166,805 tokens #browser#gecko#waterfox#web#web-browser
RAW Doc

Technical Documentation: BrowserWorks/waterfox

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (README.md)

Waterfox

Waterfox is a customisable browser based on Mozilla Firefox. This repository contains Mozilla platform code, Waterfox product code, branding, features, packaging, and release files.

Building

Waterfox uses the Mozilla build system. The usual ./mach entry points apply:

sh
./mach bootstrap
./mach build
./mach package
./mach test --auto

Contributing

Most Firefox development documentation still applies to this tree. Use the Firefox Source Docs for the shared Mozilla build system, testing tools, and platform code.

Resources


Metrics Index (`docs/metrics/index.md`)

Metrics

The metrics collected by Firefox using the
Glean SDK
are documented in
The Glean Dictionary.


Performance Index (`docs/performance/index.md`)

Performance

This page explains how to optimize the performance of the Firefox code base.

The test documentation
explains how to test for performance in Firefox.
The profiler documentation
explains how to use the Gecko profiler.

{toctree}
:hidden:
:glob:

*
memory/*

General Performance references

Memory profiling and leak detection tools

  • The Developer Tools Memory panel supports taking heap snapshots, diffing them, computing dominator trees to surface "heavy retainers", and recording allocation stacks.
  • About:memory about:memory is the easiest-to-use tool for measuring memory usage in Mozilla code, and is the best place to start. It also lets you do other memory-related operations like trigger GC and CC, dump GC & CC logs, and dump DMD reports. about:memory is built on top of Firefox's memory reporting infrastructure.
  • DMD is a tool that identifies shortcomings in about:memory's measurements, and can also do multiple kinds of general heap profiling.
  • AWSY (are we slim yet?) is a memory usage and regression tracker.
  • Bloatview prints per-class statistics on allocations and refcounts, and provides gross numbers on the amount of memory being leaked broken down by class. It is used as part of Mozilla's continuous integration testing.
  • Refcount Tracing and Balancing are ways to track down leaks caused by incorrect uses of reference counting. They are slow and not particular easy to use, and thus most suitable for use by expert developers.
  • GC and CC Logs
  • LogAlloc is a tool that dumps a log of memory allocations in Gecko. That log can then be replayed against Firefox's default memory allocator independently or through another replace-malloc library, allowing the testing of other allocators under the exact same workload.
  • See also the documentation on Leak-hunting strategies and tips.

Profiling and performance tools

Power Profiling

  • An overview of power profiling. It includes details about hardware, what can be measured, and recommended approaches. It should be the starting point for anybody new to power profiling.
  • (Mac, Linux) tools/power/rapl is a command-line utility in the Mozilla codebase that uses the Intel RAPL interface to gather direct power estimates for the package, cores, GPU and memory.
  • (Mac-only) powermetrics is a command-line utility that gathers and displays a wide range of global and per-process measurements, including CPU usage, GPU usage, and various wakeups frequencies.
  • (All-platforms) TimerFirings logging is a built-in logging mechanism that prints data on every time fired.
  • (Mac-only) Activity Monitor and top The battery status menu, Activity Monitor and top are three related Mac tools that have major flaws but often consulted by users, and so are worth understanding.
  • (Windows, Mac and Linux) Intel Power Gadget Intel Power Gadget provides real-time graphs for package and processor RAPL estimates. It also provides an API through which those estimates can be obtained.
  • (Linux only) perf perf is a powerful command-line utility that can measure many different things, including energy estimates and high-context measurements of things such as wakeups.
  • (Linux-only) turbostat is a command-line utility that gathers and displays various power-related measurements, with a focus on per-CPU measurements such as frequencies and C-states.
  • (Linux-only) powertop is an interactive command-line utility that gathers and displays various power-related measurements.

Performance Metrics

  • PerfStats - A framework for low-overhead collection of internal performance metrics.

Performance Power Profiling Overview (`docs/performance/power_profiling_overview.md`)

Power profiling

This article covers important background information about power
profiling, with an emphasis on Intel processors used in desktop and
laptop machines. It serves as a starting point for anybody doing power
profiling for the first time.

Basic physics concepts

In physics, power
is the rate of doing
work.
It is equivalent to an amount of
energy{.mw-redirect}
consumed per unit time. In SI units, energy is measured in Joules, and
power is measured in Watts, which is equivalent to Joules per second.

Although power is an instantaneous concept, in practice measurements of
it are determined in a non-instantaneous fashion, i.e. by dividing an
energy amount by a non-infinitesimal time period. Strictly speaking,
such a computation gives the average power but this is often referred
to as just the power when context makes it clear.

In the context of computing, a fully-charged mobile device battery (as
found in a laptop or smartphone) holds a certain amount of energy, and
the speed at which that stored energy is depleted depends on the power
consumption of the mobile device. That in turn depends on the software
running on the device. Web browsers are popular applications and can be
power-intensive, and therefore can significantly affect battery life. As
a result, it is worth optimizing (i.e. reducing) the power consumption
caused by Firefox and Firefox OS.

Intel processor basics

Processor layout

The following diagram (from the Intel Power Governor
documentation)

shows how machines using recent Intel processors are constructed.

The important points are as follows.

  • The processor has one or more packages. These are part of the
    actual processor that you buy from Intel. Client processors (e.g.
    Core i3/i5/i7) have one package. Server processors (e.g. Xeon)
    typically have two or more packages.
  • Each package contains multiple cores.
  • Each core typically has
    hyper-threading,
    which means it contains two logical CPUs.
  • The part of the package outside the cores is called the uncore or
    system agent
    . It includes
    various components including the L3 cache, memory controller, and,
    for processors that have one, the integrated GPU.
  • RAM is separate from the processor.

C-states

Intel processors have aggressive power-saving features. The first is the
ability to switch frequently (thousands of times per second) between
active and idle states, and there are actually several different kinds
of idle states. These different states are called
C-states.
C0 is the active/busy state, where instructions are being executed. The
other states have higher numbers and reflect increasing deeper idle
states. The deeper an idle state is, the less power it uses, but the
longer it takes to wake up from.

Note: the ACPI
standard

specifies four states, C0, C1, C2 and C3. Intel maps these to
processor-specific states such as C0, C1, C2, C6 and C7. and many tools
report C-states using the latter names. The exact relationship is
confusing, and chapter 13 of the Intel optimization
manual

has more details. The important thing is that C0 is always the active
state, and for the idle states a higher number always means less power
consumption.

The other thing to note about C-states is that they apply both to cores
and the entire package --- i.e. if all cores are idle then the entire
package can also become idle, which reduces power consumption even
further.

The fraction of time that a package or core spends in an idle C-state is
called the C-state residency. This is a misleading term --- the active
state, C0, is also a C-state --- but one that is nonetheless common.

Intel processors have model-specific registers (MSRs) containing
measurements of how much time is spent in different C-states, and tools
such as powermetrics
(Mac), powertop and
turbostat (Linux) can
expose this information.

A wakeup occurs when a core or package transitions from an idle state
to the active state. This happens when the OS schedules a process to run
due to some kind of event. Common causes of wakeups include scheduled
timers going off and blocked I/O system calls receiving data.
Maintaining C-state residency is crucial to keep power consumption low,
and so reducing wakeup frequency is one of the best ways to reduce power
consumption.

One consequence of the existence of C-states is that observations made
during power profiling --- even more than with other kinds of profiling
--- can disturb what is being observed. For example, the Gecko Profiler
takes samples at 1000Hz using a timer. Each of these samples can trigger
a wakeup, which consumes power and obscures Firefox's natural wakeup
patterns. For this reason, integrating power measurements into the Gecko
Profiler is unlikely to be useful, and other power profiling tools
typically use much lower sampling rates (e.g. 1Hz.)

P-states

Intel processors also support multiple P-states. P0 is the state where
the processor is operating at maximum frequency and voltage, and
higher-numbered P-states operate at a lower frequency and voltage to
reduce power consumption. Processors can have dozens of P-states, but
the transitions are controlled by the hardware and OS and so P-states
are of less interest to application developers than C-states.

There are several kinds of power and power-related measurements. Some
are global (whole-system) and some are per-process. The following
sections list them from best to worst.

Power measurements

The best measurements are measured in joules and/or watts, and are taken
by measuring the actual hardware in some fashion. These are global
(whole-system) measurements that are affected by running programs but
also by other things such as (for laptops) how bright the monitor
backlight is.

  • Devices such as ammeters give the best results, but these can be
    expensive and difficult to set up.
  • A cruder technique that works with mobile machines and devices is to
    run a program for a long time and simply time how long it takes for
    the battery to drain. The long measurement times required are a
    disadvantage, though.

Power estimates

The next best measurements come from recent (Sandy Bridge and later)
Intel processors that implement the RAPL (Running Average Power Limit)
interface that provides MSRs containing energy consumption estimates for
up to four power planes or domains of a machine, as seen in the
diagram above.

  • PKG: The entire package.
    • PP0: The cores.
    • PP1: An uncore device, usually the GPU (not available on all
      processor models.)
  • DRAM: main memory (not available on all processor models.)

The following relationship holds: PP0 + PP1 <= PKG. DRAM is independent
of the other three domains.

These values are computed using a power model that uses
processor-internal counts as inputs, and they have been
verified
as being fairly accurate. They are also updated frequently, at
approximately 1,000 Hz, though the variability in their update latency
means that they are probably only accurate at lower frequencies, e.g. up
to 20 Hz or so. See section 14.9 of Volume 3 of the Intel Software
Developer's
Manual

for more details about RAPL.

Tools that can take RAPL readings include the following.

Of these,
tools/power/rapl is
generally the easiest and best to use because it reads all power planes,
it's a command line utility, and it doesn't measure anything else.

Proxy measurements

The next best measurements are proxy measurements, i.e. measurements of
things that affect power consumption such as CPU activity, GPU activity,
wakeup frequency, C-state residency, disk activity, and network
activity. Some of these are measured on a global basis, and some can be
measured on a per-process basis. Some can also be measured via
instrumentation within Firefox itself.

The correlation between each proxy measure and power consumption is hard
to know and can vary greatly. When used carefully, however, they can
still be useful. This is because they can often be measured in a more
fine-grained fashion than power measurements and estimates, which is
vital for gaining insight into how a program can reduce power
consumption.

Most profiling tools provide at least some proxy measurements.

Hybrid proxy measurements

These are combinations of proxy measurements. The combinations are
semi-arbitrary, they amplify the unreliability of proxy measurements,
and unlike non-hybrid proxy measurements, they don't have a clear
physical meaning. Avoid them.

The most notable example of a hybrid proxy measurement is the ["Energy
Impact" used by OS X's Activity
Monitor.

Low-context measurements

Most power-related measurements are global or per-process. Such
low-context measurements are typically good for understand if power
consumption is good or bad, but in the latter case they often don't
provide much insight into why the problem is occurring, which part of
the code is at fault, or how it can be fixed. Nonetheless, they can
still help improve understanding of a problem by using differential
profiling
.

  • Compare browsers to see if Firefox is doing better or worse than
    another browser on a particular workload.
  • Compare different versions of Firefox to see if Firefox has improved
    or worsened over time on a particular workload. This can identify
    specific changes that caused regressions, for example.
  • Compare different configurations of Firefox to see if a particular
    feature is affecting things.
  • Compare different workloads. This can be particularly useful if the
    workloads only vary slightly. For example, it can be useful to
    gradually remove elements from a web page and see how the
    power-related measurements change. Even just switching a tab from
    the foreground to the background can make a difference.

High-context measurements

A few power-related measurements can be obtained in a high-context
fashion, e.g. with stack traces that clearly pinpoint specific parts of
the code as being responsible.

  • Standard performance profiling tools that measure CPU usage or
    proxies of CPU usage (such as instruction counts) typically provide
    high-context measurements. This is useful because high CPU usage
    typically causes high power consumption.
  • Some tools can provide high-context wakeup measurements:
    dtrace (on Mac) and
    perf (on Linux.)
  • Source-level instrumentation, such as TimerFirings
    logging
    , can
    identify which timers are firing frequently.

Power profiling how-to

This section aims to put together all the above information and provide
a set of strategies for finding, diagnosing and fixing cases of high
power consumption.

  • First of all, all measurements are best done on a quiet machine that
    is running little other than the program of interest. Global
    measurements in particular can be completely skewed and unreliable
    if this is not the case.
  • Find or confirm a test case where Firefox's power consumption is
    high. "High" can most easily be gauged by comparing against other
    browsers. Use power measurements or estimates (e.g. via
    tools/power/rapl,
    or mach power on Mac, or Intel Power
    Gadget
    on
    Windows) for the comparisons. Avoid lower-quality measurements,
    especially Activity Monitor's "Energy Impact".
  • Try using differential profiling to narrow down the cause.
    • Try turning hardware acceleration on or off; e10s on or off;
      Flash on or off.
    • Try putting the relevant tab in the foreground vs. in the
      background.
    • If the problem manifests on a particular website, try saving a
      local copy of the site and then manually removing HTML elements
      to see if a particular page feature is causing the problem
  • Many power problems are caused by either high CPU usage or high
    wakeup frequency. Use one of the low-context tools to determine if
    this is the case (e.g. on Mac use
    powermetrics.) If
    so, follow that up by using a tool that gives high-context
    measurements, which hopefully will identify the cause of the
    problem.
    • For high CPU usage, many profilers can be used: Firefox's dev
      tools profiler, the Gecko Profiler, or generic performance
      profilers.
    • For high wakeup counts, use
      dtrace or
      perf or TimerFirings logging.
  • On Mac workloads that use graphics, Activity Monitor's "Energy"
    tab can tell you if the high-performance GPU is being used, which
    uses more power than the integrated GPU.
  • If neither CPU usage nor wakeup frequency identifies the problem,
    more ingenuity may be needed. Looking at other measurements (C-state
    residency, GPU usage, etc.) may be helpful.
  • Animations are sometimes the cause of high power consumption. The
    animation
    inspector

    in the Firefox Devtools can identify them. Alternatively, here is
    an
    explanation

    of how one developer diagnosed two animation-related problems the
    hard way (which required genuine platform expertise).
  • The approximate cause of power problems often isn't that hard to
    find. Fixing them is often the hard part. Good luck.
  • If you do fix a problem by improving a proxy measurement, you should
    verify that it also improves a power measurement or estimate. That
    way you know the fix had a genuine effect.

Further reading

Chapter 13 of the Intel optimization
manual

has many details about optimizing for power consumption. Section 13.5
("Tuning Software for Intelligent Power Consumption") in particular is
worth reading.


Rust Components Index (`docs/rust-components/index.md`)

Rust Components

This section is meant to make it easier to use and implement cross-platform components written in Rust.

{toctree}
:titlesonly:
:maxdepth: 2

Topic Guides <topic-guides/index>
API References <api/index>
Developing Rust Components <developing-rust-components/index>
uniffi-bindgen-gecko-js developers guide <uniffi-bindgen-gecko-js-dev-guide/index>

Testing Rust Code Index (`docs/testing-rust-code/index.md`)

Testing & Debugging Rust Code

This page explains how to test and debug Rust code in Firefox.

The build documentation explains how to add
new Rust code to Firefox. The code documentation
explains how to write and work with Rust code in Firefox.

Testing Mozilla crates

Rust code will naturally be tested as part of system tests such as Mochitests.
This section describes the two methods for unit testing of individual Rust
crates. Which method should be used depends on the circumstances.

Rust tests

If a Mozilla crate has "normal" Rust tests (i.e. #[test] functions that run
with cargo test), you can add the crate's name to RUST_TESTS in
toolkit/library/rust/moz.build.
(Cargo features can be activated for Rust tests by adding them to
RUST_TEST_FEATURES in the same file.)

Rust tests are run with ./mach rusttests. They run on automation in a couple
of rusttests jobs, but not on all platforms.

Rust tests have one major restriction: they cannot link against Gecko symbols.
Therefore, Rust tests cannot be used for crates that use Gecko crates like
nsstring and xpcom.

It's also possible to use RUST_TESTS in a different moz.build file. See
testing/geckodriver/moz.build and the geckodriver testing docs for an
example.

GTests

Another way to unit test a Mozilla crate is by writing a GTest that uses FFI to
call into Rust code. This requires the following steps.

  • Create a new test crate whose name is the same as the name of crate being
    tested, with a -gtest suffix.
  • Add to the test crate a Rust file, a C++ file containing GTest TEST()
    functions that use FFI to call into the Rust file, a Cargo.toml file that
    references the Rust file, and a moz.build file that references the C++
    file.
  • Add an entry to the [dependencies] section in
    toolkit/library/gtest/rust/Cargo.toml.
  • Add an extern crate entry to
    toolkit/library/gtest/rust/lib.rs.

See
xpcom/rust/gtest/nsstring/
for a simple example. (Note that the moz.build file is in the parent
directory for that crate.)

A Rust GTest can be run like any other GTest via ./mach gtest, using the C++
TEST() functions as the starting point.

Unlike Rust tests, GTests can be used when linking against Gecko symbols is required.

Testing third-party crates

In general we don't run tests for third-party crates. The assumption is that
these crates are sufficiently well-tested elsewhere.

Debugging Rust code

In theory, Rust code is debuggable much like C++ code, using standard tools
like gdb, rr, and the Microsoft Visual Studio Debugger. In practice, the
experience can be worse, because shortcomings such as the following can occur.

  • Inability to print local variables, even in non-optimized builds.
  • Inability to call generic functions.
  • Missing line numbers and stack frames.
  • Printing of basic types such as Option and Vec is sometimes sub-optimal.
    If you see a warning "Missing auto-load script at offset 0 in section
    .debug_gdb_scripts" when starting gdb, the rust-gdb wrapper may give
    better results.

Logging from Rust code

Rust logging

The RUST_LOG environment variable (from the env_logger crate) can be used
to enable logging to stderr from Rust code in Firefox. The logging macros from
the log crate can be used. In order of importance, they are: error!,
warn!, info!, debug!, trace!.

For example, to show all log messages of info level or higher, run:

text
RUST_LOG=info firefox

Module-level logging can also be specified, see the documentation for the
env_logger crate for details.

To restrict logging to child processes, use RUST_LOG_CHILD instead of
RUST_LOG.

Gecko logging

Rust logging can also be forwarded to the Gecko logger for capture via
MOZ_LOG and MOZ_LOG_FILE.

  • When parsing modules from MOZ_LOG, modules containing :: are considered
    to be Rust modules. To log everything in a top-level module like
    neqo_transport, specify it as neqo_transport::*. For example:
text
MOZ_LOG=timestamp,sync,nsHostResolver:5,neqo_transport::*:5,proxy:5 firefox
  • When logging from a submodule the ::* is allowed but isn't necessary.
    So these two lines are equivalent:
text
MOZ_LOG=timestamp,sync,neqo_transport::recovery:5 firefox
MOZ_LOG=timestamp,sync,neqo_transport::recovery::*:5 firefox
  • debug! and trace! logs will not appear in non-debug builds. This is due
    to our use of the release_max_level_info feature in the log crate.

  • When using both MOZ_LOG and RUST_LOG, modules that are specified in
    MOZ_LOG will not appear in RUST_LOG.


Update Infrastructure Index (`docs/update-infrastructure/index.md`)

Mozilla Update Infrastructure

Firefox, Thunderbird, and Mozilla VPN updates rely on backend service known as Balrog. Periodically, these applications check for updates by pinging an URL[^1] which contains information about both the application running, and details of the system it is running on. If Balrog finds an update based on the provided information, it returns a simple XML response with a link to the update file, and some metadata about it.

Watershed Updates

Most of the time, an update will take an application directly from whatever version it is currently running to the latest version of that application. This is greatly preferred, both to save time, bandwidth, reduce restarts, and increase security by ensuring we get to the latest version of something as quickly as possible. Unfortunately, sometimes we must route through an intermediate version first, typically the version that is currently running does not provide Balrog with enough information to accurately serve a correct update to the latest version. These are colloquially known as "watershed" updates. (This name comes from the fact that these updates change something about the update process itself, making them a kind of "watershed moment" for updates.)

At the time of writing (July, 2024), we currently have the following watershed updates in place for Firefox's release channel:

[^1]: Here is a sample URL: https://aus5.mozilla.org/update/3/Firefox/85.0/20200518093924/WINNT_x86_64-msvc-x64/en-US/release/Windows_NT%2010.0.0.0.18363.1016%20(x64)/default/default/update.xml
[^2]: While not directly related to the watershed, it is notable that due to LZMA MAR support shipping in the previous version (56.0), which was not a watershed for Linux and Mac, we shipped two different sets of MARs for 57.0, 57.0.1, 57.0.2, 57.0.3, and 57.0.4: we had bz2 MARs, which builds older than 56.0 were served, and a separate set of LZMA MARs that were shipped to 56.0 and higher. More details on this can be found on this awfully complicated spreadsheet that was produced around that time.

Desupport Updates

From time to time we stop supporting a platform, hardware or library that we depend on. When we do this, we must ensure we don't update affected users to a version that they can no longer run. This can take two forms:

  • In the distant past, we would simply stop serving updates altogether, leaving users on their current version.
  • More recently, we will first move users to our esr channel - generally giving them another year of support before ending updates altogether.

Below is a list of desupports and moves to esr that we've done on the Firefox release channel:


Writing Rust Code Index (`docs/writing-rust-code/index.md`)

Writing Rust Code

This page explains how to write and work with Rust code in Firefox, with an
emphasis on interoperation with C++ code.

The build documentation explains how to add
new Rust code to Firefox. The test documentation
explains how to test and debug Rust code in Firefox.

{toctree}
:titlesonly:
:maxdepth: 1
:glob:

*

Devtools Docs Contributor README (`devtools/docs/contributor/README.md`)

Firefox Developer Tools: Contributor Docs

This is a guide to working on the code for Firefox Developer Tools. If you're looking for help with using the tools, see the user docs. For other ways to get involved, check out our community site.


Devtools Docs Contributor Architecture Overview (`devtools/docs/contributor/architecture-overview.md`)

Architecture overview

Broadly speaking, the tools are divided in two parts: the server and the client. A server is anything that can be debugged: for example, your browser, but it could also be Firefox for Android, running on another device. The client is the front-end side of the tools, and it is what developers interact with when using the tools.

Since these two parts are decoupled, we can connect to any server using the same client. This enables us to debug multiple types of servers, using the same protocol to communicate.

You will often hear about actors. Each feature that can be debugged (for example, network) is exposed via an actor, which provides data about that specific feature. It's up to each server to implement some or all actors; the client needs to find out and decide what it can render on the front-side when it connects to the server. So when we want to debug a new feature, we might need to do work in two parts of the code: the server (perhaps implementing a new actor, or extending existing ones) and the client (to display the debugging data returned by the actor).

Often, an actor will correspond to a panel. But a panel might want to get data from multiple actors.

You might also hear about the toolbox. The toolbox is what everyone else calls developer tools i.e. the front-end that you see when you open the tools in your browser.


Code Quality Typescript Index (`docs/code-quality/typescript/index.md`)

TypeScript

In firefox-main, we are introducing the use of TypeScript
to help provide type autocompletion, static analysis and type checking of our
JavaScript code.

:::{note}
At the moment we are in the bootstrap/experimentation phase, there are various
parts of infrastructure that have not yet been created, and incomplete type
definitions which may cause issues for projects. Hence TypeScript is not
recommended for all projects for the time being.

We are currently prioritising enabling type autocompletion across the code base,
before we proceed to more work on type checking.

You can work towards enabling TypeScript by ensuring your code passes the
ESLint jsdoc rules.

If you are interested, please ask in the Lint and Formatting channel (#lint:mozilla.org)
on Matrix.
:::

Where TypeScript is Currently Enabled

TypeScript is currently only enabled on a limited set of directories.

Editor Support

VS Code has TypeScript support built-in and should work "out of the box".

For other editors, see this TypeScript Wiki Page.

Running TypeScript Locally

The TypeScript linter may be run on the directories where it is enabled using:

text
./mach lint -l typescript path/to/file # (or to the directory)

Updating Gecko Type Definitions

Updating types currently happens manually, although we are in the process of
automating it
.

In the meantime, developers using TypeScript must update the type definitions
manually using some scripts.

Best Practices

For working with TypeScript we have some best practices
which will help to get the type definitions set up correctly.

Frequently Asked Questions

  • Why does running TypeScript check and report errors in other files?
    • Changes in one file may impact on another, and TypeScript can detect this.
    • Additionally, the way that TypeScript works means that it will run across
      the whole project regardless, so we report all the issues that it reports.
  • Will my patches get backed out due to TypeScript failures?
    • Currently no. Whilst we have a TypeScript Linter on CI
      it is currently tier-3 which is hidden from the sheriffs view.
    • Failures will however, be reported on reviews on Phabricator.
    • We will promote the linter to tier-2 and tier-1 once we have more automation
      in place for type generation.
  • Why isn't this being encouraged for everyone?
    • As discussed in the note at the top of the page, we are still in the set-up
      and experimentation phase. There is a lot of infrastructure that is required
      to make TypeScript usable on a day to day basis.
  • Are we planning to allow using TypeScript files and compiling directly from
    TypeScript?
    • No. In the past we've worked to avoid processing or compilation steps,
      wherever possible when developing JavaScript. This helps to reduce code-test
      cycle times and make debugging simpler.
    • Whilst it is possible we could change the approach in future, it is not an
      objective of enabling TypeScript over the firefox-main code base.
  • Something isn't working as I would expect, where should I look/ask?
    • We have a meta bug
      for TypeScript issues in firefox-main. We work through them over time, though
      we appreciate help as well.
    • See the Getting Help section.

Getting Help

The Lint & Formatting channel (#lint:mozilla.org) on Matrix is the best place
to ask questions.

Further Reading


Rust Components Api Index (`docs/rust-components/api/index.md`)

Rust components API References

Choose a language to get started


Rust Components Developing Rust Components Index (`docs/rust-components/developing-rust-components/index.md`)

Developing Shared Rust Components

Shared Rust Components is a strategy to create a single component that provides the same functionality for Firefox Desktop, Firefox Android and Firefox iOS.

This strategy was first adopted for sync in response to issues stemming from separate sync implementations for each application. Separate sync implementations lead to duplicate logic across platforms, which was difficult to maintain. Furthermore, the likelihood of errors was very high -- especially since each implementation had to sync with the other implementations. Since then more components have adopted the Rust components strategy and some non-Firefox projects have started using the components (for example nimbus-experimenter).

The basic idea is to write the component in Rust then generate a set of Kotlin/Swift/JS bindings that can be consumed by the Firefox applications.
Rust was chosen because it supports a large number of target platforms, including Android and iOS.
The UniFFI library was created to handle bindings
generation.

Pros and cons of adding a shared Rust component

Pros

  • Less work than creating a multiple implementations.
  • More consistent behavior across different applications.
  • Better sync integrations (this follows from the last point, since behavior differences often become larger bugs when sync is involved).
  • Build JavaScript, Kotlin, and Swift docs from the Rust docstrings.

Cons

  • More work than creating a single implementation.
  • Requires engineers to write and understand Rust.
  • Still requires some application glue code to integrate the component.
    Often it's trivial like TabsStore, but sometimes it's larger.

Neutral

  • Performance is usually similar to JavaScript/Kotlin code.
    FFI overhead typically negates any speedups from using Rust.

Shared Rust component ownership

Teams that write shared Rust components are responsible for maintaining their health.
This includes monitoring error reports and working with application teams to maintain integrations as the application code changes.
Error reports are currently only available for Android, but we will soon be extending this to all platforms.

{toctree}
:titlesonly:
:maxdepth: 1

example-component
uniffi
logging
observability
threading
other-desktop-specific-concerns

Rust Components Topic Guides Index (`docs/rust-components/topic-guides/index.md`)

Topic Guides

Here are the guides on various topics related to Rust components.

{toctree}
:titlesonly:
:maxdepth: 1
:glob:

*

Rust Components Uniffi Bindgen Gecko Js Dev Guide Index (`docs/rust-components/uniffi-bindgen-gecko-js-dev-guide/index.md`)

uniffi-bindgen-gecko-js Developers Guide

This section describes the internal workings of uniffi-bindgen-gecko-js for developers working with this code.
It builds on the UniFFI user guide internals documentation, which is recommended reading before diving into these specifics.

UniFFI bindings pipeline

uniffi-bindgen-gecko-js uses the bindings pipeline (docs more docs).
uniffi-bindgen-gecko-js is the first bindings generator to adopt this code, although we hope to eventually move all bindings to this system.
This means the uniffi-bindgen-gecko-js code may look different than other bindings, but we hope it's only temporary.

{toctree}
:titlesonly:
:maxdepth: 1

js-and-cpp-layers
lifting-and-lowering
rust-calls
js-callback-interfaces

Dom Docs Push Index (`dom/docs/push/index.md`)

Push

Note
This document describes how Firefox implements the Web Push standard internally, and is intended for developers working directly on Push. If you are looking for how to consume push, please refer to the following MDN document

High level push architecture

The following sequence diagram describes the high level push architecture as observed by web application. The diagram describes the interactions between a Web application's client code running in the browser, Firefox, Autopush (Firefox's push server that delivers push notifications) and a third party server that sends the push notifications to Autopush

The dotted lines are done by the consumer of push.

{mermaid}
sequenceDiagram
	participant TP as Web Application JS
	participant F as Firefox
	participant A as Autopush
	participant TPS as Third party Server
		TP->>F: subscribe(scope)
		activate TP
		activate F
		F->>A: subscribe(scope) using web socket
		activate A
		A->>F: URL
		deactivate A
		F->>F: Create pub/privKey Encryption pair
		F->>F: Persist URL, pubKey, privKey indexed using an id derived from scope
		F->>TP: URL + pubKey
		deactivate F
		TP-->>TPS: URL + pubKey
		deactivate TP
		TPS-->>TPS: Encrypt payload using pubKey
		TPS-->>A: Send encrypted payload using URL
		activate A
		A->>F: Send encrypted payload using web socket
		deactivate A
		activate F
		F->>F: Decrypt payload using privKey
		F->>F: Display Notification
		deactivate F

Firefox Desktop

Flow diagram for source code

The source code for push is available under dom/push in mozilla-central.

The following flow diagram describes how different modules interact with each other to provide the push API to consumers.

{mermaid}
flowchart TD
    subgraph Public API

    W[Third party Web app]-->|imports| P[PushManager.webidl]
    end
    subgraph Browser Code
        P-->|Implemented by| MM
        MM{Main Thread?}-->|Yes| B[Push.sys.mjs]
        MM -->|NO| A[PushManager.cpp]
        B-->|subscribe,getSubscription| D[PushComponents.sys.mjs]
        A-->|subscribe,getSubscription| D
        D-->|subscribe,getSubscription| M[PushService.sys.mjs]
        M-->|Storage| S[PushDB.sys.mjs]
        M-->|Network| N[PushWebSocket.sys.mjs]
        F[FxAccountsPush.sys.mjs] -->|uses| D
    end
    subgraph Server
    N-. Send, Receive.-> O[Autopush]
    end
    subgraph Local Storage
    S-->|Read,Write| PP[(IndexedDB)]
    end

The Push Web Socket

Push in Firefox Desktop communicates with Autopush using a web socket connection.

The web socket connection is created as the browser initializes and is managed by the following state diagram.

{mermaid}
stateDiagram-v2
		state "Shut Down" as SD
		state "Waiting for WebSocket to start" as W1
		state "Waiting for server hello" as W2
		state "Ready" as R
    [*] --> SD
		 SD --> W1: beginWSSetup
		 W1 --> W2: wsOnStart Success
		 W2 --> R: handleHelloReply
		 R --> R: send (subscribe)
         R --> R: Receive + notify observers
		 R --> SD: wsOnStop
		 R --> SD: sendPing Fails
		 W1 --> SD: wsOnStart fails
		 W2 --> SD: invalid server hello
		 R --> [*]

Once the Push web socket is on the Ready state, it is ready to send new subscriptions to Autopush, and receive push notifications from those subscriptions.

Push uses an observer pattern to notify observers of any incoming push notifications. See the high level architecture section.

Push Storage

Push uses IndexedDB to store subscriptions for the following reasons:

  1. In case the consumer attempts to re-subscribe, storage is used as a cache to serve the URL and the public key
  2. In order to persist the private key, so that it can be used to decrypt any incoming push notifications

The following is what gets persisted:

{mermaid}
erDiagram
    Subscription {
        string channelID "Key, Derived from scope"
        string pushEndpoint "Unique endpoint for this subscription"
        string scope "Usually the origin, unique value for internal consumers"
        Object p256dhPublicKey "Object representing the public key"
        Object p256dhPrivateKey "Object representing the private key"
    }

Firefox for Android

See also:

Flow diagram for source code

The source code for push is available under the following paths in mozilla-central:

The following flow diagram describes how different modules interact with each other to provide the push API to consumers.

{mermaid}
flowchart TD
    subgraph Public API

    W[Third party Web app]-->|imports| P[PushManager.webidl]
    end
    subgraph Browser Code
        P-->|Implemented by| MM
        MM{Main Thread?}-->|Yes| B[Push.sys.mjs]
        MM -->|NO| A[PushManager.cpp]
        B-->|subscribe,getSubscription| D[GeckoViewPush.sys.mjs]
        A-->|subscribe,getSubscription| D
        D-->|PushSubscribe,PushGetSubscription| WPC[WebPushController.java]
        WPC-->|onSubscribe,onGetSubscription| WPEI[WebPushEngineIntegration.kt]
        WPEI-->|subscribe,getSubscription| APF[AutoPushFeature.kt]
        APF-->|start| PS[AbstractFirebasePushService.kt]
        FCM[Firebase Cloud Messaging]-->|onNewToken| PS
        PS-->|onNewToken| APF
        APF-->|subscribe,getSubscription| PRS[push/src/lib.rs]
        PRS-->|subscribe,get_subscription| PM[internal/push_manager.rs]
        PM-->|Storage| S[internal/storage/db.rs]
        PM-->|Network| N[internal/communications.rs]
    end
    subgraph Server
    N-. bridge interface.-> O[Autopush]
    end
    subgraph Local Storage
    S-->|Read,Write| SQL[(SQLite)]
    end

Dom Docs WebIdlBindings Index (`dom/docs/webIdlBindings/index.md`)

Web IDL bindings

Note

Need to document the setup for indexed and named
setters/creators/deleters.

The Web IDL bindings are generated
at build time based on two things: the actual Web IDL file and a
configuration file that lists some metadata about how the Web IDL should
be reflected into Gecko-internal code.

All Web IDL files should be placed in
dom/webidl
and added to the list in the
moz.build
file in that directory.

Note that if you're adding new interfaces, then the test at
dom/tests/mochitest/general/test_interfaces.html will most likely
fail. This is a signal that you need to get a review from a DOM
peer
.
Resist the urge to just add your interfaces to the
moz.build list
without the review; it will just annoy the DOM peers and they'll make
you get the review anyway.

The configuration file, dom/bindings/Bindings.conf, is basically a
Python dict that maps interface names to information about the
interface, called a descriptor. There are all sorts of possible
options here that handle various edge cases, but most descriptors can be
very simple.

All the generated code is placed in the mozilla::dom namespace. For
each interface, a namespace whose name is the name of the interface with
Binding appended is created, and all the things pertaining to that
interface's binding go in that namespace.

There are various helper objects and utility methods in
dom/bindings
that are also all in the mozilla::dom namespace and whose headers
are all exported into mozilla/dom (placed in
$OBJDIR/dist/include by the build process).

Adding Web IDL bindings to a class

To add a Web IDL binding for interface MyInterface to a class
mozilla::dom::MyInterface that's supposed to implement that
interface, you need to do the following:

  1. If your interface doesn't inherit from any other interfaces, inherit
    from nsWrapperCache and hook up the class to the cycle collector
    so it will trace the wrapper cache properly. Note that you may not
    need to do this if your objects can only be created, never gotten
    from other objects. If you also inherit from nsISupports, make
    sure the nsISupports comes before the nsWrapperCache in your
    list of parent classes. If your interface does inherit from another
    interface, just inherit from the C++ type that the other interface
    corresponds to.

    If you do need to hook up cycle collection, it will look like this in
    the common case of also inheriting from nsISupports:

    cpp
    // Add strong pointers your class holds here. If you do, change to using
    // NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE.
    NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(MyClass)
    NS_IMPL_CYCLE_COLLECTING_ADDREF(MyClass)
    NS_IMPL_CYCLE_COLLECTING_RELEASE(MyClass)
    NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MyClass)
      NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
      NS_INTERFACE_MAP_ENTRY(nsISupports)
    NS_INTERFACE_MAP_END
  2. If your class doesn't inherit from a class that implements
    GetParentObject, then add a function of that name that, for a
    given instance of your class, returns the same object every time
    (unless you write explicit code that handles your parent object
    changing by reparenting JS wrappers, as nodes do). The idea is that
    walking the GetParentObject chain will eventually get you to a
    Window, so that every Web IDL object is associated with a particular
    Window.
    For example, nsINode::GetParentObject returns the node's owner
    document. The return type of GetParentObject doesn't matter other
    than it must either singly-inherit from nsISupports or have a
    corresponding
    ToSupports
    method that can produce an nsISupports from it. (This allows the
    return value to be implicitly converted to a
    ParentObject
    instance by the compiler via one of that class's non-explicit
    constructors.)
    If many instances of MyInterface are expected to be created
    quickly, the return value of GetParentObject should itself inherit
    from nsWrapperCache for optimal performance. Returning null from
    GetParentObject is allowed in situations in which it's OK to
    associate the resulting object with a random global object for
    security purposes; this is not usually ok for things that are exposed
    to web content. Again, if you do not need wrapper caching you don't
    need to do this. The actual type returned from GetParentObject
    must be defined in a header included from your implementation header,
    so that this type's definition is visible to the binding code.

  3. Add the Web IDL for MyInterface in dom/webidl and to the list
    in dom/webidl/moz.build.

  4. Add an entry to dom/bindings/Bindings.conf that sets some basic
    information about the implementation of the interface. If the C++
    type is not mozilla::dom::MyInterface, you need to set the
    'nativeType' to the right type. If the type is not in the header
    file one gets by replacing '::' with '/' and appending '.h', then
    add a corresponding 'headerFile' annotation (or
    HeaderFile annotation to the .webidl file). If
    you don't have to set any annotations, then you don't need to add an
    entry either and the code generator will simply assume the defaults
    here. Note that using a 'headerFile' annotation is generally not
    recommended. If you do use it, you will need to make sure your
    header includes all the headers needed for your Func
    annotations.

  5. Add external interface entries to Bindings.conf for whatever
    non-Web IDL interfaces your new interface has as arguments or return
    values.

  6. Implement a WrapObject override on mozilla::dom::MyInterface
    that just calls through to
    mozilla::dom::MyInterface_Binding::Wrap. Note that if your C++
    type is implementing multiple distinct Web IDL interfaces, you need
    to choose which mozilla::dom::MyInterface_Binding::Wrap to call
    here. See AudioContext::WrapObject, for example.

  7. Expose whatever methods the interface needs on
    mozilla::dom::MyInterface. These can be inline, virtual, have any
    calling convention, and so forth, as long as they have the right
    argument types and return types. You can see an example of what the
    function declarations should look like by running
    mach webidl-example MyInterface. This will produce two files in
    dom/bindings in your objdir: MyInterface-example.h and
    MyInterface-example.cpp, which show a basic implementation of the
    interface using a class that inherits from nsISupports and has a
    wrapper cache.

See this sample patch that migrates window.performance.* to Web IDL
bindings
.

Note

If your object can only be reflected into JS by creating it, not by
retrieving it from somewhere, you can skip steps 1 and 2 above and
instead add 'wrapperCache': False to your descriptor. You will
need to flag the functions that return your object as
[NewObject] in
the Web IDL. If your object is not refcounted then the return value of
functions that return it should return a UniquePtr.

C++ reflections of Web IDL constructs

C++ reflections of Web IDL operations (methods)

A Web IDL operation is turned into a method call on the underlying C++
object. The return type and argument types are determined as described
below
. In addition to those, all methods that are
allowed to throw
will get an ErrorResult& argument
appended to their argument list. Non-static methods that use certain
Web IDL types like any or object will get a JSContext*
argument prepended to the argument list. Static methods will be passed a
const GlobalObject& for the relevant global and
can get a JSContext* by calling Context() on it.

The name of the C++ method is simply the name of the Web IDL operation
with the first letter converted to uppercase.

Web IDL overloads are turned into C++ overloads: they simply call C++
methods with the same name and different signatures.

For example, this Web IDL:

webidl
interface MyInterface
{
  undefined doSomething(long number);
  double doSomething(MyInterface? otherInstance);

  [Throws]
  MyInterface doSomethingElse(optional long maybeNumber);
  [Throws]
  undefined doSomethingElse(MyInterface otherInstance);

  undefined doTheOther(any something);

  undefined doYetAnotherThing(optional boolean actuallyDoIt = false);

  static undefined staticOperation(any arg);
};

will require these method declarations:

cpp
class MyClass
{
  void DoSomething(int32_t a number);
  double DoSomething(MyClass* aOtherInstance);

  already_AddRefed<MyInterface> DoSomethingElse(Optional<int32_t> aMaybeNumber,
                                                ErrorResult& rv);
  void DoSomethingElse(MyClass& aOtherInstance, ErrorResult& rv);

  void DoTheOther(JSContext* cx, JS::Handle<JS::Value> aSomething);

  void DoYetAnotherThing(bool aActuallyDoIt);

  static void StaticOperation(const GlobalObject& aGlobal, JS::Handle<JS::Value> aSomething);
}

C++ reflections of Web IDL attributes

A Web IDL attribute is turned into a pair of method calls for the getter
and setter on the underlying C++ object. A readonly attribute only has a
getter and no setter.

The getter's name is the name of the attribute with the first letter
converted to uppercase. This has Get prepended to it if any of these
conditions hold:

  1. The type of the attribute is nullable.
  2. The getter can throw.
  3. The return value of the attribute is returned via an out parameter in
    the C++.

The method signature for the getter looks just like an operation with no
arguments and the attribute's type as the return type.

The setter's name is Set followed by the name of the attribute with
the first letter converted to uppercase. The method signature looks just
like an operation with an undefined return value and a single argument
whose type is the attribute's type.

C++ reflections of Web IDL constructors

A Web IDL constructor is turned into a static class method named
Constructor. The arguments of this method will be the arguments of
the Web IDL constructor, with a
const GlobalObject& for the relevant global
prepended. For the non-worker case, the global is typically the inner
window for the DOM Window the constructor function is attached to. If a
JSContext* is also needed due to some of the argument types, it will
come after the global. The return value of the constructor for
MyInterface is exactly the same as that of a method returning an
instance of MyInterface. Constructors are always allowed to throw.

For example, this IDL:

webidl
interface MyInterface {
  constructor();
  constructor(unsigned long someNumber);
};

will require the following declarations in MyClass:

cpp
class MyClass {
  // Various nsISupports stuff or whatnot
  static
  already_AddRefed<MyClass> Constructor(const GlobalObject& aGlobal,
                                        ErrorResult& rv);
  static
  already_AddRefed<MyClass> Constructor(const GlobalObject& aGlobal,
                                        uint32_t aSomeNumber,
                                        ErrorResult& rv);
};

C++ reflections of Web IDL types

The exact C++ representation for Web IDL types can depend on the precise
way that they're being used (e.g., return values, arguments, and
sequence or dictionary members might all have different
representations).

Unless stated otherwise, a type only has one representation. Also,
unless stated otherwise, nullable types are represented by wrapping
Nullable<> around the base type.

In all cases, optional arguments which do not have a default value are
represented by wrapping const Optional<>& around the
representation of the argument type. If the argument type is a C++
reference, it will also become a NonNull<> around the
actual type of the object in the process. Optional arguments which do
have a default value are just represented by the argument type itself,
set to the default value if the argument was not in fact passed in.

Variadic Web IDL arguments are treated as a
const Sequence<>& around the actual argument type.

Here's a table, see the specific sections below for more details and
explanations.

Web IDL Type Argument Type Return Type Dictionary/Member Type
any JS::Handle<JS::Value> JS::MutableHandle<JS::Value> JS::Value
boolean bool bool bool
byte int8_t int8_t int8_t
ByteString const nsACString& nsCString& (outparam)nsACString& (outparam) nsCString
Date mozilla::dom::Date
DOMString const nsAString& mozilla::dom::DOMString& (outparam)nsAString& (outparam)nsString& (outparam) nsString
UTF8String const nsACString& (outparam) nsACString& nsCString
double double double double
float float float float
interface:non-nullable Foo& already_addRefed<Foo> OwningNonNull<Foo>
interface:nullable Foo* already_addRefed<Foo>``Foo* RefPtr<Foo>
long int32_t int32_t int32_t
long long int64_t int64_t int64_t
object JS::Handle<JSObject*> JS::MutableHandle<JSObject*> JSObject*
octet uint8_t uint8_t uint8_t
sequence const Sequence<T>& nsTArray<T>& (outparam)
short int16_t int16_t int16_t
unrestricted double double double double
unrestricted float float float float
unsigned long uint32_t uint32_t uint32_t
unsigned long long uint64_t uint64_t uint64_t
unsigned short uint16_t uint16_t uint16_t
USVString const nsAString& mozilla::dom::DOMString& (outparam)nsAString& (outparam)nsString& (outparam) nsString

`any`

any is represented in three different ways, depending on use:

  • any arguments become JS::Handle<JS::Value>. They will be in
    the compartment of the passed-in JSContext.
  • any return values become a JS::MutableHandle<JS::Value> out
    param appended to the argument list. This comes after all IDL
    arguments, but before the ErrorResult&, if any, for the method.
    The return value is allowed to be in any compartment; bindings will
    wrap it into the context compartment as needed.
  • any dictionary members and sequence elements become
    JS::Value. The dictionary members and sequence elements are
    guaranteed to be marked by whomever puts the sequence or dictionary
    on the stack, using SequenceRooter and DictionaryRooter.

Methods using any always get a JSContext* argument.

For example, this Web IDL:

webidl
interface Test {
  attribute any myAttr;
  any myMethod(any arg1, sequence<any> arg2, optional any arg3);
};

will correspond to these C++ function declarations:

cpp
void MyAttr(JSContext* cx, JS::MutableHandle<JS::Value> retval);
void SetMyAttr(JSContext* cx, JS::Handle<JS::Value> value);
void MyMethod(JSContext* cx, JS::Handle<JS::Value> arg1,
              const Sequence<JS::Value>& arg2,
              const Optional<JS::Handle<JS::Value>>& arg3,
              JS::MutableHandle<JS::Value> retval);

`boolean`

The boolean Web IDL type is represented as a C++ bool.

For example, this Web IDL:

webidl
interface Test {
  attribute boolean myAttr;
  boolean myMethod(optional boolean arg);
};

will correspond to these C++ function declarations:

cpp
bool MyAttr();
void SetMyAttr(bool value);
bool MyMethod(const Optional<bool>& arg);

Integer types

Integer Web IDL types are mapped to the corresponding C99 stdint types.

For example, this Web IDL:

webidl
interface Test {
  attribute short myAttr;
  long long myMethod(unsigned long? arg);
};

will correspond to these C++ function declarations:

cpp
int16_t MyAttr();
void SetMyAttr(int16_t value);
int64_t MyMethod(const Nullable<uint32_t>& arg);

Floating point types

Floating point Web IDL types are mapped to the C++ type of the same
name. So float and unrestricted float become a C++ float,
while double and unrestricted double become a C++ double.

For example, this Web IDL:

webidl
interface Test {
  float myAttr;
  double myMethod(unrestricted double? arg);
};

will correspond to these C++ function declarations:

cpp
float MyAttr();
void SetMyAttr(float value);
double MyMethod(const Nullable<double>& arg);

`DOMString`

Strings are reflected in three different ways, depending on use:

  • String arguments become const nsAString&.
  • String return values become a
    mozilla::dom::DOMString& out param
    appended to the argument list. This comes after all IDL arguments,
    but before the ErrorResult&, if any, for the method. Note that
    this allows callees to declare their methods as taking an
    nsAString& or nsString& if desired.
  • Strings in sequences, dictionaries, owning unions, and variadic
    arguments become nsString.

Nullable strings are represented by the same types as non-nullable ones,
but the string will return true for DOMStringIsNull(). Returning
null as a string value can be done using SetDOMStringToNull on the
out param if it's an nsAString or calling SetNull() on a
DOMString.

For example, this Web IDL:

webidl
interface Test {
  DOMString myAttr;
  [Throws]
  DOMString myMethod(sequence<DOMString> arg1, DOMString? arg2, optional DOMString arg3);
};

will correspond to these C++ function declarations:

cpp
void GetMyAttr(nsString& retval);
void SetMyAttr(const nsAString& value);
void MyMethod(const Sequence<nsString>& arg1, const nsAString& arg2,
              const Optional<nsAString>& arg3, nsString& retval, ErrorResult& rv);

`USVString`

USVString is reflected just like DOMString.

`UTF8String`

UTF8String is a string with guaranteed-valid UTF-8 contents. It is
not a standard in the Web IDL spec, but its observables are the same as
those of USVString.

It is a good fit for when the specification allows a USVString, but
you want to process the string as UTF-8 rather than UTF-16.

It is reflected in three different ways, depending on use:

  • Arguments become const nsACString&.
  • Return values become an nsACString& out param appended to the
    argument list. This comes after all IDL arguments, but before the
    ErrorResult&, if any, for the method.
  • In sequences, dictionaries owning unions, and variadic arguments it
    becomes nsCString.

Nullable UTF8Strings are represented by the same types as
non-nullable ones, but the string will return true for IsVoid().
Returning null as a string value can be done using SetIsVoid() on
the out param.

`ByteString`

ByteString is reflected in three different ways, depending on use:

  • ByteString arguments become const nsACString&.
  • ByteString return values become an nsCString& out param
    appended to the argument list. This comes after all IDL arguments,
    but before the ErrorResult&, if any, for the method.
  • ByteString in sequences, dictionaries, owning unions, and
    variadic arguments becomes nsCString.

Nullable ByteString are represented by the same types as
non-nullable ones, but the string will return true for IsVoid().
Returning null as a string value can be done using SetIsVoid() on
the out param.

`object`

object is represented in three different ways, depending on use:

  • object arguments become JS::Handle<JSObject*>. They will be
    in the compartment of the passed-in JSContext.
  • object return values become a JS::MutableHandle<JSObject*>
    out param appended to the argument list. This comes after all IDL
    arguments, but before the ErrorResult&, if any, for the method.
    The return value is allowed to be in any compartment; bindings will
    wrap it into the context compartment as needed.
  • object dictionary members and sequence elements become
    JSObject*. The dictionary members and sequence elements are
    guaranteed to be marked by whoever puts the sequence or dictionary on
    the stack, using SequenceRooter and DictionaryRooter.

Methods using object always get a JSContext* argument.

For example, this Web IDL:

webidl
interface Test {
  object myAttr;
  object myMethod(object arg1, object? arg2, sequence<object> arg3, optional object arg4,
                  optional object? arg5);
};

will correspond to these C++ function declarations:

cpp
void GetMyAttr(JSContext* cx, JS::MutableHandle<JSObject*> retval);
void SetMyAttr(JSContext* cx, JS::Handle<JSObject*> value);
void MyMethod(JSContext* cx, JS::Handle<JSObject*> arg1, JS::Handle<JSObject*> arg2,
              const Sequence<JSObject*>& arg3,
              const Optional<JS::Handle<JSObject*>>& arg4,
              const Optional<JS::Handle<JSObject*>>& arg5,
              JS::MutableHandle<JSObject*> retval);

Interface types

There are four kinds of interface types in the Web IDL bindings. Callback
interfaces are used to represent script objects that browser code can
call into. External interfaces are used to represent objects that have
not been converted to the Web IDL bindings yet. Web IDL interfaces are
used to represent Web IDL binding objects. "SpiderMonkey" interfaces are
used to represent objects that are implemented natively by the
JavaScript engine (e.g., typed arrays).

Callback interfaces

Callback interfaces are represented in C++ as objects inheriting from
mozilla::dom::CallbackInterface, whose
name, in the mozilla::dom namespace, matches the name of the
callback interface in the Web IDL. The exact representation depends on
how the type is being used.

  • Nullable arguments become Foo*.
  • Non-nullable arguments become Foo&.
  • Return values become already_AddRefed<Foo> or Foo* as
    desired. The pointer form is preferred because it results in faster
    code, but it should only be used if the return value was not addrefed
    (and so it can only be used if the return value is kept alive by the
    callee until at least the binding method has returned).
  • Web IDL callback interfaces in sequences, dictionaries, owning unions,
    and variadic arguments are represented by RefPtr<Foo> if nullable
    and OwningNonNull<Foo> otherwise.

If the interface is a single-operation interface, the object exposes two
methods that both invoke the same underlying JS callable. The first of
these methods allows the caller to pass in a this object, while the
second defaults to undefined as the this value. In either case,
the this value is only used if the callback interface is implemented
by a JS callable. If it's implemented by an object with a property whose
name matches the operation, the object itself is always used as
this.

If the interface is not a single-operation interface, it just exposes a
single method for every IDL method/getter/setter.

The signatures of the methods correspond to the signatures for throwing
IDL methods/getters/setters with an additional trailing
mozilla::dom::CallbackObject::ExceptionHandling aExceptionHandling
argument, defaulting to eReportExceptions.
If aReportExceptions is set to eReportExceptions, the methods
will report JS exceptions before returning. If aReportExceptions is
set to eRethrowExceptions, JS exceptions will be stashed in the
ErrorResult and will be reported when the stack unwinds to wherever
the ErrorResult was set up.

For example, this Web IDL:

webidl
callback interface MyCallback {
  attribute long someNumber;
  short someMethod(DOMString someString);
};
callback interface MyOtherCallback {
  // single-operation interface
  short doSomething(Node someNode);
};
interface MyInterface {
  attribute MyCallback foo;
  attribute MyCallback? bar;
};

will lead to these C++ class declarations in the mozilla::dom
namespace:

cpp
class MyCallback : public CallbackInterface
{
  int32_t GetSomeNumber(ErrorResult& rv, ExceptionHandling aExceptionHandling = eReportExceptions);
  void SetSomeNumber(int32_t arg, ErrorResult& rv,
                     ExceptionHandling aExceptionHandling = eReportExceptions);
  int16_t SomeMethod(const nsAString& someString, ErrorResult& rv,
                     ExceptionHandling aExceptionHandling = eReportExceptions);
};

class MyOtherCallback : public CallbackInterface
{
public:
  int16_t
  DoSomething(nsINode& someNode, ErrorResult& rv,
              ExceptionHandling aExceptionHandling = eReportExceptions);

  template<typename T>
  int16_t
  DoSomething(const T& thisObj, nsINode& someNode, ErrorResult& rv,
              ExceptionHandling aExceptionHandling = eReportExceptions);
};

and these C++ function declarations on the implementation of
MyInterface:

cpp
already_AddRefed<MyCallback> GetFoo();
void SetFoo(MyCallback&);
already_AddRefed<MyCallback> GetBar();
void SetBar(MyCallback*);

A consumer of MyCallback would be able to use it like this:

cpp
void
SomeClass::DoSomethingWithCallback(MyCallback& aCallback)
{
  ErrorResult rv;
  int32_t number = aCallback.GetSomeNumber(rv);
  if (rv.Failed()) {
    // The error has already been reported to the JS console; you can handle
    // things however you want here.
    return;
  }

  // For some reason we want to catch and rethrow exceptions from SetSomeNumber, say.
  aCallback.SetSomeNumber(2*number, rv, eRethrowExceptions);
  if (rv.Failed()) {
    // The exception is now stored on rv. This code MUST report
    // it usefully; otherwise it will assert.
  }
}

External interfaces

External interfaces are represented in C++ as objects that XPConnect
knows how to unwrap to. This can mean XPCOM interfaces (whether declared
in XPIDL or not) or it can mean some type that there's a castable native
unwrapping function for. The C++ type to be used should be the
nativeType listed for the external interface in the
Bindings.conf file. The exact representation
depends on how the type is being used.

  • Arguments become nsIFoo*.
  • Return values can be already_AddRefed<nsIFoo> or nsIFoo* as
    desired. The pointer form is preferred because it results in faster
    code, but it should only be used if the return value was not addrefed
    (and so it can only be used if the return value is kept alive by the
    callee until at least the binding method has returned).
  • External interfaces in sequences, dictionaries, owning unions, and
    variadic arguments are represented by RefPtr<nsIFoo>.

Web IDL interfaces

Web IDL interfaces are represented in C++ as C++ classes. The class
involved must either be refcounted or must be explicitly annotated in
Bindings.conf as being directly owned by the JS object. If the class
inherits from nsISupports, then the canonical nsISupports must
be on the primary inheritance chain of the object. If the interface has
a parent interface, the C++ class corresponding to the parent must be on
the primary inheritance chain of the object. This guarantees that a
void* can be stored in the JSObject which can then be
reinterpret_cast to any of the classes that correspond to interfaces
the object implements. The C++ type to be used should be the
nativeType listed for the interface in the
Bindings.conf file, or
mozilla::dom::InterfaceName if none is listed. The exact
representation depends on how the type is being used.

  • Nullable arguments become Foo*.
  • Non-nullable arguments become Foo&.
  • Return values become already_AddRefed<Foo> or Foo* as
    desired. The pointer form is preferred because it results in faster
    code, but it should only be used if the return value was not addrefed
    (and so it can only be used if the return value is kept alive by the
    callee until at least the binding method has returned).
  • Web IDL interfaces in sequences, dictionaries, owning unions, and
    variadic arguments are represented by RefPtr<Foo> if nullable and
    OwningNonNull<Foo> otherwise.

For example, this Web IDL:

webidl
interface MyInterface {
  attribute MyInterface myAttr;
  undefined passNullable(MyInterface? arg);
  MyInterface? doSomething(sequence<MyInterface> arg);
  MyInterface doTheOther(sequence<MyInterface?> arg);
  readonly attribute MyInterface? nullableAttr;
  readonly attribute MyInterface someOtherAttr;
  readonly attribute MyInterface someYetOtherAttr;
};

Would correspond to these C++ function declarations:

cpp
already_AddRefed<MyClass> MyAttr();
void SetMyAttr(MyClass& value);
void PassNullable(MyClass* arg);
already_AddRefed<MyClass> doSomething(const Sequence<OwningNonNull<MyClass>>& arg);
already_AddRefed<MyClass> doTheOther(const Sequence<RefPtr<MyClass>>& arg);
already_Addrefed<MyClass> GetNullableAttr();
MyClass* SomeOtherAttr();
MyClass* SomeYetOtherAttr(); // Don't have to return already_AddRefed!

"SpiderMonkey" interfaces

Typed array, array buffer, and array buffer view arguments are
represented by the objects in TypedArray.h. For
example, this Web IDL:

webidl
interface Test {
  undefined passTypedArrayBuffer(ArrayBuffer arg);
  undefined passTypedArray(ArrayBufferView arg);
  undefined passInt16Array(Int16Array? arg);
}

will correspond to these C++ function declarations:

cpp
void PassTypedArrayBuffer(const ArrayBuffer& arg);
void PassTypedArray(const ArrayBufferView& arg);
void PassInt16Array(const Nullable<Int16Array>& arg);

Typed array return values become a JS::MutableHandle<JSObject*> out
param appended to the argument list. This comes after all IDL arguments,
but before the ErrorResult&, if any, for the method. The return
value is allowed to be in any compartment; bindings will wrap it into
the context compartment as needed.

Typed arrays store a JSObject* and hence need to be rooted
properly. On-stack typed arrays can be declared as
RootedTypedArray<TypedArrayType> (e.g.
RootedTypedArray). Typed arrays on the heap need to be
traced.

Dictionary types

A dictionary argument is represented by a const reference to a struct
whose name is the dictionary name in the mozilla::dom namespace.
The struct has one member for each of the dictionary's members with the
same name except the first letter uppercased and prefixed with "m". The
members that are required or have default values have types as described
under the corresponding Web IDL type in this document. The members that
are not required and don't have default values have those types wrapped
in Optional<>.

Dictionary return values are represented by an out parameter whose type
is a non-const reference to the struct described above, with all the
members that have default values preinitialized to those default values.

Note that optional dictionary arguments are always forced to have a
default value of an empty dictionary by the IDL parser and code
generator, so dictionary arguments are never wrapped in Optional<>.

If necessary, dictionaries can be directly initialized from a
JS::Value in C++ code by invoking their Init() method. Consumers
doing this should declare their dictionary as
RootedDictionary<DictionaryName>. When this is done, passing in a
null JSContext* is allowed if the passed-in JS::Value is
JS::NullValue(). Likewise, a dictionary struct can be converted to a
JS::Value in C++ by calling ToJSValue with the dictionary as the
second argument. If Init() or ToJSValue() returns false, they
will generally set a pending exception on the JSContext; reporting those
is the responsibility of the caller.

For example, this Web IDL:

text
dictionary Dict {
  long foo = 5;
  DOMString bar;
};

interface Test {
  undefined initSomething(optional Dict arg = {});
};

will correspond to this C++ function declaration:

cpp
void InitSomething(const Dict& arg);

and the Dict struct will look like this:

cpp
struct Dict {
  bool Init(JSContext* aCx, JS::Handle<JS::Value> aVal, const char* aSourceDescription = "value");

  Optional<nsString> mBar;
  int32_t mFoo;
}

Note that the dictionary members are sorted in the struct in
alphabetical order.

API for working with dictionaries

There are a few useful methods found on dictionaries and dictionary
members that you can use to quickly determine useful things.

  • member.WasPassed() - as the name suggests, was a particular
    member passed?
    (e.g., if (arg.foo.WasPassed() { /* do nice things!*/ })
  • dictionary.IsAnyMemberPresent() - great for checking if you need
    to do anything.
    (e.g., if (!arg.IsAnyMemberPresent()) return; // nothing to do)
  • member.Value() - getting the actual data/value of a member that
    was passed.
    (e.g., mBar.Assign(args.mBar.value()))

Example implementation using all of the above:

cpp
void
MyInterface::InitSomething(const Dict& aArg){
  if (!aArg.IsAnyMemberPresent()) {
    return; // nothing to do!
  }
  if (aArg.mBar.WasPassed() && !mBar.Equals(aArg.mBar.value())) {
    mBar.Assign(aArg.mBar.Value());
  }
}

Enumeration types

Web IDL enumeration types are represented as C++ enum classes. The values
of the C++ enum are named by taking the strings in the Web IDL
enumeration, replacing all non-alphanumerics with underscores, and
uppercasing the first letter, with a special case for the empty string,
which becomes the value _empty.

For a Web IDL enum named MyEnum, the C++ enum is named MyEnum and
placed in the mozilla::dom namespace, while the values are placed in
the mozilla::dom::MyEnum namespace.

The type of the enum class is automatically selected to be the smallest
unsigned integer type that can hold all the values. In practice, this
is always uint8_t, because Web IDL enums tend to not have more than 255
values.

For example, this Web IDL:

webidl
enum MyEnum {
  "something",
  "something-else",
  "",
  "another"
};

would lead to this C++ enum declaration:

cpp
enum class MyEnum : uint8_t {
  Something,
  Something_else,
  _empty,
  Another
};

mozilla::dom::GetEnumString is a templated helper function declared in
BindingUtils.h
and exported to mozilla/dom/BindingUtils.h that can be used to convert an enum
value to its corresponding string value. It returns a const nsCString&
containing the string value.

mozilla::dom::StringToEnum is a templated helper function in
BindingUtils.h
and exported to mozilla/dom/BindingUtils.h that can be used to convert a
string to the corresponding enum value. It needs to be supplied with the enum
class as a template argument, and returns a mozilla::Maybe<Enum>. If the string
value passed to it as an argument is not one of the string values for the enum
then it returns mozilla::Nothing(), else it returns the right enum value in
the mozilla::Maybe.

mozilla::dom::WebIDLEnumSerializer is a templated alias in
BindingIPCUtils.h
exported to mozilla/dom/BindingIPCUtils.h to implement an IPC serializer with
the right validation for WebIDL enums. It uses a
mozilla::MaxContinuousEnumValue that is generated for every WebIDL enum to
implement the validation.

mozilla::dom::MakeWebIDLEnumeratedRange is a templated helper function in
BindingUtils.h
and exported to mozilla/dom/BindingUtils.h that can be used to create a
mozilla::EnumeratedRange for a WebIDL enum.

Callback function types

Callback functions are represented as an object, inheriting from
mozilla::dom::CallbackFunction, whose name,
in the mozilla::dom namespace, matches the name of the callback
function in the Web IDL. If the type is nullable, a pointer is passed in;
otherwise a reference is passed in.

The object exposes two Call methods, which both invoke the
underlying JS callable. The first Call method has the same signature
as a throwing method declared just like the callback function, with an
additional trailing mozilla::dom::CallbackObject::ExceptionHandling aExceptionHandling
argument, defaulting to eReportExceptions,
and calling it will invoke the callable with undefined as the
this value. The second Call method allows passing in an explicit
this value as the first argument. This second call method is a
template on the type of the first argument, so the this value can be
passed in in whatever form is most convenient, as long as it's either a
type that can be wrapped by XPConnect or a Web IDL interface type.

If aReportExceptions is set to eReportExceptions, the Call
methods will report JS exceptions before returning. If
aReportExceptions is set to eRethrowExceptions, JS exceptions
will be stashed in the ErrorResult and will be reported when the
stack unwinds to wherever the ErrorResult was set up.

For example, this Web IDL:

webidl
callback MyCallback = long (MyInterface arg1, boolean arg2);
interface MyInterface {
  attribute MyCallback foo;
  attribute MyCallback? bar;
};

will lead to this C++ class declaration, in the mozilla::dom
namespace:

cpp
class MyCallback : public CallbackFunction
{
public:
  int32_t
  Call(MyInterface& arg1, bool arg2, ErrorResult& rv,
       ExceptionHandling aExceptionHandling = eReportExceptions);

  template<typename T>
  int32_t
  Call(const T& thisObj, MyInterface& arg1, bool arg2, ErrorResult& rv,
       ExceptionHandling aExceptionHandling = eReportExceptions);
};

and these C++ function declarations in the MyInterface class:

cpp
already_AddRefed<MyCallback> GetFoo();
void SetFoo(MyCallback&);
already_AddRefed<MyCallback> GetBar();
void SetBar(MyCallback*);

A consumer of MyCallback would be able to use it like this:

cpp
void
SomeClass::DoSomethingWithCallback(MyCallback& aCallback, MyInterface& aInterfaceInstance)
{
  ErrorResult rv;
  int32_t number = aCallback.Call(aInterfaceInstance, false, rv);
  if (rv.Failed()) {
    // The error has already been reported to the JS console; you can handle
    // things however you want here.
    return;
  }

  // Now for some reason we want to catch and rethrow exceptions from the callback,
  // and use "this" as the this value for the call to JS.
  number = aCallback.Call(*this, true, rv, eRethrowExceptions);
  if (rv.Failed()) {
    // The exception is now stored on rv.  This code MUST report
    // it usefully; otherwise it will assert.
  }
}

Sequences

Sequence arguments are represented by
const Sequence<T>&, where T depends on the type
of elements in the Web IDL sequence.

Sequence return values are represented by an nsTArray<T> out param
appended to the argument list, where T is the return type for the
elements of the Web IDL sequence. This comes after all IDL arguments, but
before the ErrorResult&, if any, for the method.

Arrays

IDL array objects are not supported yet. The spec on these is likely to
change drastically anyway.

Union types

Union types are reflected as a struct in the mozilla::dom namespace.
There are two kinds of union structs: one kind does not keep its members
alive (is "non-owning"), and the other does (is "owning"). Const
references to non-owning unions are used for plain arguments. Owning
unions are used in dictionaries, sequences, and for variadic arguments.
Union return values become a non-const owning union out param. The name
of the struct is the concatenation of the names of the types in the
union, with "Or" inserted between them, and for an owning struct
"Owning" prepended. So for example, this IDL:

text
undefined passUnion((object or long) arg);
(object or long) receiveUnion();
undefined passSequenceOfUnions(sequence<(object or long)> arg);
undefined passOtherUnion((HTMLDivElement or ArrayBuffer or EventInit) arg);

would correspond to these C++ function declarations:

cpp
void PassUnion(const ObjectOrLong& aArg);
void ReceiveUnion(OwningObjectObjectOrLong& aArg);
void PassSequenceOfUnions(const Sequence<OwningObjectOrLong>& aArg);
void PassOtherUnion(const HTMLDivElementOrArrayBufferOrEventInit& aArg);

Union structs expose accessors to test whether they're of a given type
and to get hold of the data of that type. They also expose setters that
set the union as being of a particular type and return a reference to
the union's internal storage where that type could be stored. The one
exception is the object type, which uses a somewhat different form
of setter where the JSObject* is passed in directly. For example,
ObjectOrLong would have the following methods:

cpp
bool IsObject() const;
JSObject* GetAsObject() const;
void SetToObject(JSContext*, JSObject*);
bool IsLong() const;
int32_t GetAsLong() const;
int32_t& SetAsLong()

Owning unions used on the stack should be declared as a
RootedUnion, for example,
RootedUnion<OwningObjectOrLong>.

`Date`

Web IDL Date types are represented by a mozilla::dom::Date
struct.

C++ reflections of Web IDL declarations

Web IDL declarations (maplike/setlike/iterable) are turned into a set of
properties and functions on the interface they are declared on. Each has
a different set of helper functions it comes with. In addition, for
iterable, there are requirements for C++ function implementation by the
interface developer.

Maplike

Example Interface:

webidl
interface StringToLongMap {
  maplike<DOMString, long>;
};

The bindings for this interface will generate the storage structure for
the map, as well as helper functions for accessing that structure from
C++. The generated C++ API will look as follows:

cpp
namespace StringToLongMapBinding {
namespace MaplikeHelpers {
void Clear(mozilla::dom::StringToLongMap* self, ErrorResult& aRv);
bool Delete(mozilla::dom::StringToLongMap* self, const nsAString& aKey, ErrorResult& aRv);
bool Has(mozilla::dom::StringToLongMap* self, const nsAString& aKey, ErrorResult& aRv);
void Set(mozilla::dom::StringToLongMap* self, const nsAString& aKey, int32_t aValue, ErrorResult& aRv);
} // namespace MaplikeHelpers
} // namespace StringToLongMapBindings

Setlike

Example Interface:

webidl
interface StringSet {
  setlike<DOMString>;
};

The bindings for this interface will generate the storage structure for
the set, as well as helper functions for accessing that structure from
c++. The generated C++ API will look as follows:

cpp
namespace StringSetBinding {
namespace SetlikeHelpers {
void Clear(mozilla::dom::StringSet* self, ErrorResult& aRv);
bool Delete(mozilla::dom::StringSet* self, const nsAString& aKey, ErrorResult& aRv);
bool Has(mozilla::dom::StringSet* self, const nsAString& aKey, ErrorResult& aRv);
void Add(mozilla::dom::StringSet* self, const nsAString& aKey, ErrorResult& aRv);
} // namespace SetlikeHelpers
}

Iterable

Unlike maplike and setlike, iterable does not have any C++ helpers, as
the structure backing the iterable data for the interface is left up to
the developer. With that in mind, the generated iterable bindings expect
the wrapper object to provide certain methods for the interface to
access.

Iterable interfaces have different requirements, based on if they are
single or pair value iterators.

Example Interface for a single value iterator:

webidl
interface LongIterable {
  iterable<long>;
  getter long(unsigned long index);
  readonly attribute unsigned long length;
};

For single value iterator interfaces, we treat the interface as an
indexed getter, as required by the spec. See the
indexed getter implementation section for more
information on building this kind of structure.

Example Interface for a pair value iterator:

webidl
interface StringAndLongIterable {
  iterable<DOMString, long>;
};

The bindings for this pair value iterator interface require the
following methods be implemented in the C++ object:

cpp
class StringAndLongIterable {
public:
  // Returns the number of items in the iterable storage
  size_t GetIterableLength();
  // Returns key of pair at aIndex in iterable storage
  nsAString& GetKeyAtIndex(uint32_t aIndex);
  // Returns value of pair at aIndex in iterable storage
  uint32_t& GetValueAtIndex(uint32_t aIndex);
}

Stringifiers

Named stringifiers operations in Web IDL will just invoke the
corresponding C++ method.

Anonymous stringifiers in Web IDL will invoke the C++ method called
Stringify. So, for example, given this IDL:

webidl
interface FirstInterface {
  stringifier;
};

interface SecondInterface {
  stringifier DOMString getStringRepresentation();
};

the corresponding C++ would be:

cpp
class FirstInterface {
public:
  void Stringify(nsAString& aResult);
};

class SecondInterface {
public:
  void GetStringRepresentation(nsAString& aResult);
};

Legacy Callers

Only anonymous legacy callers are supported, and will invoke the C++
method called LegacyCall. This will be passed the JS "this" value as
the first argument, then the arguments to the actual operation. A
JSContext will be passed if any of the operation arguments need it.
So for example, given this IDL:

webidl
interface InterfaceWithCall {
  legacycaller long (float arg);
};

the corresponding C++ would be:

cpp
class InterfaceWithCall {
public:
  int32_t LegacyCall(JS::Handle<JS::Value> aThisVal, float aArgument);
};

Named getters

If the interface has a named getter, the binding will expect several
methods on the C++ implementation:

  • A NamedGetter method. This takes a property name and returns
    whatever type the named getter is declared to return. It also has a
    boolean out param for whether a property with that name should exist
    at all.
  • A NameIsEnumerable method. This takes a property name and
    returns a boolean that indicates whether the property is enumerable.
  • A GetSupportedNames method. This takes an unsigned integer which
    corresponds to the flags passed to the iterate proxy trap and
    returns a list of property names. For implementations of this method,
    the important flags is JSITER_HIDDEN. If that flag is set, the
    call needs to return all supported property names. If it's not set,
    the call needs to return only the enumerable ones.

The NameIsEnumerable and GetSupportedNames methods need to agree
on which names are and are not enumerable. The NamedGetter and
GetSupportedNames methods need to agree on which names are
supported.

So for example, given this IDL:

webidl
interface InterfaceWithNamedGetter {
  getter long(DOMString arg);
};

the corresponding C++ would be:

cpp
class InterfaceWithNamedGetter
{
public:
  int32_t NamedGetter(const nsAString& aName, bool& aFound);
  bool NameIsEnumerable(const nsAString& aName);
  undefined GetSupportedNames(unsigned aFlags, nsTArray<nsString>& aNames);
};

Indexed getters

If the interface has a indexed getter, the binding will expect the
following methods on the C++ implementation:

  • A IndexedGetter method. This takes an integer index value and
    returns whatever type the indexed getter is declared to return. It
    also has a boolean out param for whether a property with that index
    should exist at all. The implementation must set this out param
    correctly. The return value is guaranteed to be ignored if the out
    param is set to false.

So for example, given this IDL:

webidl
interface InterfaceWithIndexedGetter {
  getter long(unsigned long index);
  readonly attribute unsigned long length;
};

the corresponding C++ would be:

cpp
class InterfaceWithIndexedGetter
{
public:
  uint32_t Length() const;
  int32_t IndexedGetter(uint32_t aIndex, bool& aFound) const;
};

Throwing exceptions from Web IDL methods, getters, and setters

Web IDL methods, getters, and setters that are explicitly marked as
allowed to throw
have an ErrorResult& argument as their
last argument. To throw an exception, simply call Throw() on the
ErrorResult& and return from your C++ back into the binding code.

In cases when the specification calls for throwing a TypeError, you
should use ErrorResult::ThrowTypeError() instead of calling
Throw().

Custom extended attributes

Our Web IDL parser and code generator recognize several extended
attributes that are not present in the Web IDL spec.

`[AllowLarge]`

Can be specified on buffer source types (ArrayBuffer, ArrayBufferView,
typed arrays) to skip the default 2 GB size check. This allows
incremental migration of consumers to support buffers larger than 2 GB.
Can be combined with [AllowShared]. On the C++ side, use
ProcessData(...) or ProcessFixedData(...) to access the
data.

`[Alias=propName]`

This extended attribute can be specified on a method and indicates that
another property with the specified name will also appear on the
interface prototype object and will have the same Function object value
as the property for the method. For example:

webidl
interface MyInterface {
  [Alias=performSomething] undefined doSomething();
};

MyInterface.prototype.performSomething will have the same Function
object value as MyInterface.prototype.doSomething.

Multiple [Alias] extended attribute can be used on the one method.
[Alias] cannot be used on a static method, nor on methods on a
global interface (such as Window).

Aside from regular property names, the name of an alias can be
Symbol.iterator.
This is specified by writing [Alias="@@iterator"].

`[BindingAlias=propName]`

This extended attribute can be specified on an attribute and indicates
that another property with the specified name will also appear on the
interface prototype object and will call the same underlying C++
implementation for the getter and setter. This is more efficient than
using the same BinaryName for both attributes, because it shares the
binding glue code between them. The properties still have separate
getter/setter functions in JavaScript, so from the point of view of web
consumers it's as if you actually had two separate attribute
declarations on your interface. For example:

webidl
interface MyInterface {
  [BindingAlias=otherAttr] readonly attribute boolean attr;
};

MyInterface.prototype.otherAttr and MyInterface.prototype.attr
will both exist, have separate getter/setter functions, but call the
same binding glue code and implementation function on the objects
implementing MyInterface.

Multiple [BindingAlias] extended attributes can be used on a single
attribute.

`[BindingTemplate=(name, type, value)]`

This extended attribute can be specified on an attribute, and causes the getter
and setter for this attribute to forward to a common generated implementation,
shared with all other attributes that have a [BindingTemplate] with the same
value for the name argument. The TemplatedAttributes dictionary in
Bindings.conf needs to contain a definition for the template with the name
name. The argument type::value will be passed when calling the common
generated implementation.

This is aimed at very specialized use cases where an interface has a
large number of attributes that all have the same type, and for which we have a
native implementation that's common to all these attributes, and typically uses
some id based on the attribute's name in the implementation. All the attributes
that use the same template need to mostly have the same extended attributes,
except form a small number that are allowed to differ ([BindingTemplate],
[BindingAlias], [Pure], [Pref] and [Func], and the annotations for
whether the getter and setter throws exceptions).

`[ChromeOnly]`

This extended attribute can be specified on any method, attribute, or
constant on an interface or on an interface as a whole. It can also be
specified on dictionary members.

Interface members flagged as [ChromeOnly] are only exposed in chrome
Windows (and in particular, are not exposed to webpages). From the point
of view of web content, it's as if the interface member were not there
at all. These members are exposed to chrome script working with a
content object via Xrays.

If specified on an interface as a whole, this functions like
[Func] except that the binding code will automatically
check whether the caller script has the system principal (is chrome or a
worker started from a chrome page) instead of calling into the C++
implementation to determine whether to expose the interface object on
the global. This means that accessing a content global via Xrays will
show [ChromeOnly] interface objects on it.

If specified on a dictionary member, then the dictionary member will
only appear to exist in system-privileged code.

This extended attribute can be specified together with [Func], and
[Pref]. If more than one of these is specified, all conditions will
need to test true for the interface or interface member to be exposed.

`[Pref=prefname]`

This extended attribute can be specified on any method, attribute, or
constant on an interface or on an interface as a whole. It can also be
specified on dictionary members. It takes a value, which must be the
name of a boolean preference exposed from StaticPrefs. The
StaticPrefs function that will be called is calculated from the
value of the extended attribute, with dots replaced by underscores
(StaticPrefs::my_pref_name() in the example below).

If specified on an interface member, the interface member involved is
only exposed if the preference is set to true. An example of how
this can be used:

webidl
interface MyInterface {
  attribute long alwaysHere;
  [Pref="my.pref.name"] attribute long onlyHereIfEnabled;
};

If specified on an interface as a whole, this functions like
[Func] except that the binding will check the value of
the preference directly without calling into the C++ implementation of
the interface at all. This is useful when the enable check is simple and
it's desirable to keep the prefname with the Web IDL declaration.

If specified on a dictionary member, the web-observable behavior when
the pref is set to false will be as if the dictionary did not have a
member of that name defined. That means that on the JS side no
observable get of the property will happen. On the C++ side, the
behavior would be as if the passed-in object did not have a property
with the relevant name: the dictionary member would either be
!Passed() or have the default value if there is a default value.

An example of how this can be used:

webidl
[Pref="my.pref.name"]
interface MyConditionalInterface {
};

This extended attribute can be specified together with [ChromeOnly],
and [Func]. If more than one of these is specified, all conditions
will need to test true for the interface or interface member to be
exposed.

`[Func="funcname"]`

This extended attribute can be specified on any method, attribute, or
constant on an interface or on an interface as a whole. It can also be
specified on dictionary members. It takes a value, which must be the
name of a static function.

If specified on an interface member, the interface member involved is
only exposed if the specified function returns true. An example of
how this can be used:

webidl
interface MyInterface {
  attribute long alwaysHere;
  [Func="MyClass::StuffEnabled"] attribute long onlyHereIfEnabled;
};

The function is invoked with two arguments: the JSContext that the
operation is happening on and the JSObject for the global of the
object that the property will be defined on if the function returns
true. In particular, in the Xray case the JSContext is in the caller
compartment (typically chrome) but the JSObject is in the target
compartment (typically content). This allows the method implementation
to select which compartment it cares about in its checks.

The above IDL would also require the following C++:

cpp
class MyClass {
  static bool StuffEnabled(JSContext* cx, JSObject* obj);
};

If specified on an interface as a whole, then lookups for the interface
object for this interface on a DOM Window will only find it if the
specified function returns true. For objects that can only be created
via a constructor, this allows disabling the functionality altogether
and making it look like the feature is not implemented at all.

If specified on a dictionary member, the web-observable behavior when
the function returns false will be as if the dictionary did not have a
member of that name defined. That means that on the JS side no
observable get of the property will happen. On the C++ side, the
behavior would be as if the passed-in object did not have a property
with the relevant name: the dictionary member would either be
!Passed() or have the default value if there is a default value.

An example of how [Func] can be used:

webidl
[Func="MyClass::MyConditionalInterfaceEnabled"]
interface MyConditionalInterface {
};

In this case, the C++ function is passed a JS::Handle<JSObject*>. So
the C++ in this case would look like this:

cpp
class MyClass {
  static bool MyConditionalInterfaceEnabled(JSContext* cx, JS::Handle<JSObject*> obj);
};

Just like in the interface member case, the JSContext is in the
caller compartment but the JSObject is the actual object the
property would be defined on. In the Xray case that means obj is in the
target compartment (typically content) and cx is typically chrome.

This extended attribute can be specified together with [ChromeOnly],
and [Pref]. If more than one of these is specified, all conditions
will need to test true for the interface or interface member to be
exposed.

Binding code will include the headers necessary for a [Func], unless
the interface is using a non-default header file. If a non-default
header file is used, that header file needs to do any header inclusions
necessary for [Func] annotations.

`[Throws]`, `[GetterThrows]`, `[SetterThrows]`

Used to flag methods or attributes as allowing the C++ callee to throw.
This causes the binding generator, and in many cases the JIT, to
generate extra code to handle possible exceptions. Possibly-throwing
methods and attributes get an ErrorResult& argument.

[Throws] applies to both methods and attributes; for attributes it
means both the getter and the setter can throw. [GetterThrows]
applies only to attributes. [SetterThrows] applies only to
non-readonly attributes.

For interfaces flagged with [JSImplementation], all methods and
properties are assumed to be able to throw and do not need to be flagged
as throwing.

`[DependsOn]`

Used for a method or attribute to indicate what the return value depends
on. Possible values are:

  • Everything

    This value can't actually be specified explicitly; this is the
    default value you get when [DependsOn] is not specified. This
    means we don't know anything about the return value's dependencies
    and hence can't rearrange other code that might change values around
    the method or attribute.

  • DOMState

    The return value depends on the state of the "DOM", by which we mean
    all objects specified via Web IDL. The return value is guaranteed to
    not depend on the state of the JS heap or other JS engine data
    structures, and is guaranteed to not change unless some function with
    [Affects=Everything] is executed.

  • DeviceState

    The return value depends on the state of the device we're running on
    (e.g., the system clock). The return value is guaranteed to not be
    affected by any code running inside Gecko itself, but we might get a
    new value every time the method or getter is called even if no Gecko
    code ran between the calls.

  • Nothing

    The return value is a constant that never changes. This value cannot
    be used on non-readonly attributes, since having a non-readonly
    attribute whose value never changes doesn't make sense.

Values other than Everything, when used in combination with
[Affects=Nothing], can used by the JIT to
perform loop-hoisting and common subexpression elimination on the return
values of IDL attributes and methods.

`[Affects]`

Used for a method or attribute getter to indicate what sorts of state
can be affected when the function is called. Attribute setters are, for
now, assumed to affect everything. Possible values are:

  • Everything

    This value can't actually be specified explicitly; this is the
    default value you get when [Affects] is not specified. This means
    that calling the method or getter might change any mutable state in
    the DOM or JS heap.

  • Nothing

    Calling the method or getter will have no side-effects on either the
    DOM or the JS heap.

Methods and attribute getters with [Affects=Nothing] are allowed to
throw exceptions, as long as they do so deterministically. In the case
of methods, whether an exception is thrown is allowed to depend on the
arguments, as long as calling the method with the same arguments will
always either throw or not throw.

The Nothing value, when used with [DependsOn] values other than
Everything, can used by the JIT to perform loop-hoisting and common
subexpression elimination on the return values of IDL attributes and
methods, as well as code motion past DOM methods that might depend on
system state but have no side effects.

`[Pure]`

This is an alias for [Affects=Nothing, DependsOn=DOMState].
Attributes/methods flagged in this way promise that they will keep
returning the same value as long as nothing that has
[Affects=Everything] executes.

`[Constant]`

This is an alias for [Affects=Nothing, DependsOn=Nothing]. Used to
flag readonly attributes or methods that could have been annotated with
[Pure] and also always return the same value. This should only be
used when it's absolutely guaranteed that the return value of the
attribute getter will always be the same from the JS engine's point of
view.

The spec's [SameObject] extended attribute is an alias for
[Constant], but can only be applied to things returning objects,
whereas [Constant] can be used for any type of return value.

`[NeedResolve]`

Used to flag interfaces which have a custom resolve hook. This
annotation will cause the DoResolve method to be called on the
underlying C++ class when a property lookup happens on the object. The
signature of this method is:
bool DoResolve(JSContext*, JS::Handle<JSObject*>, JS::Handle<jsid>, JS::MutableHandle<JS::Value>).
Here the passed-in object is the object the property lookup is happening
on (which may be an Xray for the actual DOM object) and the jsid is the
property name. The value that the property should have is returned in
the MutableHandle<Value>, with UndefinedValue() indicating that
the property does not exist.

If this extended attribute is used, then the underlying C++ class must
also implement a method called GetOwnPropertyNames with the
signature
void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames, ErrorResult& aRv).
This method will be called by the JS engine's enumerate hook and must
provide a superset of all the property names that DoResolve might
resolve. Providing names that DoResolve won't actually resolve is
OK.

`[HeaderFile="path/to/headerfile.h"]`

Indicates where the implementation can be found. Similar to the
headerFile annotation in Bindings.conf. Just like headerFile in
Bindings.conf, should be avoided.

`[JSImplementation="@mozilla.org/some-contractid;1"]`

Used on an interface to provide the contractid of the JavaScript
component implementing the
interface
.

`[StoreInSlot]`

Used to flag attributes that can be gotten very quickly from the JS
object by the JIT. Such attributes will have their getter called
immediately when the JS wrapper for the DOM object is created, and the
returned value will be stored directly on the JS object. Later gets of
the attribute will not call the C++ getter and instead use the cached
value. If the value returned by the attribute needs to change, the C++
code should call the ClearCachedFooValue method in the namespace of
the relevant binding, where foo is the name of the attribute. This
will immediately call the C++ getter and cache the value it returns, so
it needs a JSContext to work on. This extended attribute can only be
used on attributes whose getters are [Pure] or
[Constant] and which are not
[Throws] or [GetterThrows].

So for example, given this IDL:

webidl
interface MyInterface {
  [Pure, StoreInSlot] attribute long myAttribute;
};

the C++ implementation of MyInterface would clear the cached value by
calling
mozilla::dom::MyInterface_Binding::ClearCachedMyAttributeValue(cx, this).
This function will return false on error and the caller is responsible
for handling any JSAPI exception that is set by the failure.

If the attribute is not readonly, setting it will automatically clear
the cached value and reget it again before the setter returns.

`[Cached]`

Used to flag attributes that, when their getter is called, will cache
the returned value on the JS object. This can be used to implement
attributes whose value is a sequence or dictionary (which would
otherwise end up returning a new object each time and hence not be
allowed in Web IDL).

Unlike [StoreInSlot] this does not cause the
getter to be eagerly called at JS wrapper creation time; the caching is
lazy. [Cached] attributes must be [Pure] or
[Constant], because otherwise not calling the C++
getter would be observable, but are allowed to have throwing getters.
Their cached value can be cleared by calling the ClearCachedFooValue
method in the namespace of the relevant binding, where foo is the
name of the attribute. Unlike [StoreInSlot] attributes, doing so
will not immediately invoke the getter, so it does not need a
JSContext.

So for example, given this IDL:

webidl
interface MyInterface {
  [Pure, Cached] attribute long myAttribute;
};

the C++ implementation of MyInterface would clear the cached value by
calling
mozilla::dom::MyInterface_Binding::ClearCachedMyAttributeValue(this).
JS-implemented Web IDL can clear the cached value by calling
this.__DOM_IMPL__._clearCachedMyAttributeValue().

If the attribute is not readonly, setting it will automatically clear
the cached value.

`[Frozen]`

Used to flag attributes that, when their getter is called, will call
Object.freeze
on the return value before returning it. This extended attribute is only
allowed on attributes that return sequences, dictionaries and
MozMap, and corresponds to returning a frozen Array (for the
sequence case) or Object (for the other two cases).

`[BinaryName]`

[BinaryName] can be specified on method or attribute to change the
C++ function name that will be used for the method or attribute. It
takes a single string argument, which is the name you wish the method or
attribute had instead of the one it actually has.

For example, given this IDL:

webidl
interface InterfaceWithRenamedThings {
  [BinaryName="renamedMethod"]
  undefined someMethod();
  [BinaryName="renamedAttribute"]
  attribute long someAttribute;
};

the corresponding C++ would be:

cpp
class InterfaceWithRenamedThings
{
public:
  void RenamedMethod();
  int32_t RenamedAttribute();
  void SetRenamedAttribute(int32_t);
};

`[Deprecated="tag"]`

When deprecating an interface or method, the [Deprecated] annotation
causes the Web IDL compiler to insert code that generates deprecation
warnings. This annotation can be added to interface methods or
interfaces. Adding this to an interface causes a warning to be issued
the first time the object is constructed, or any static method on the
object is invoked.

The complete list of valid deprecation tags is maintained in
nsDeprecatedOperationList.inc.
Each new tag requires that a localized string be defined, containing the
deprecation message to display.

`[CrossOriginReadable]`

Used to flag an attribute that, when read, will not have the same-origin
constraint tested: it can be read from a context with a different
origin.

`[CrossOriginWrite]`

Used to flag an attribute that, when written, will not have the
same-origin constraint tested: it can be written from a context with a
different origin.

`[CrossOriginCallable]`

Used to flag a method that, when called, will not have the same-origin
constraint tested: it can be called from a context with a different
origin.

`[SecureContext]`

We implement the standard extended
attribute
with a few
details specific to Gecko:

  • System principals are considered secure.
  • An extension poking at non-secured DOM objects will see APIs marked
    with [SecureContext].
  • XPConnect sandboxes don't see [SecureContext] APIs, except if
    they're created with isSecureContext: true.

`[NeedsSubjectPrincipal]`, `[GetterNeedsSubjectPrincipal]`, `[SetterNeedsSubjectPrincipal]`

Used to flag a method or an attribute that needs to know the subject
principal. This principal will be passed as argument. The argument
will be a nsIPrincipal& because a subject principal is always
available.

[NeedsSubjectPrincipal] applies to both methods and attributes; for
attributes it means both the getter and the setter need a subject
principal. [GetterNeedsSubjectPrincipal] applies only to attributes.
[SetterNeedsSubjectPrincipal] applies only to non-readonly
attributes.

These attributes may also be constrained to non-system principals using
[{Getter,Setter,}NeedsSubjectPrincipal=NonSystem]. This changes the argument
type to nsIPrincipal*, and passes nullptr when called with a system
principal.

`[NeedsCallerType]`

Used to flag a method or an attribute that needs to know the caller
type, in the mozilla::dom::CallerType sense. This can be safely
used for APIs exposed in workers; there it will indicate whether the
worker involved is a ChromeWorker or not. At the moment the only
possible caller types are System (representing system-principal
callers) and NonSystem.

`[GenerateInit]`

When set on a dictionary it will add two Init methods to the generated C++
class with the following signatures:

cpp
bool Init(BindingCallContext& cx, JS::Handle<JS::Value> val, const char* sourceDescription="Value", bool passedToJSImpl=false);
bool Init(JSContext* cx_, JS::Handle<JS::Value> val, const char* sourceDescription="Value", bool passedToJSImpl=false);

These methods will initialize the dictionary from val by following WebIDL's
JavaScript type mapping.

`[GenerateInitFromJSON]`

When set on a dictionary it will add Init methods to the generated C++
class with the following signatures:

cpp
bool Init(const nsAString& aJSON);
bool Init(const nsACString& aJSON);

This extended attribute will only have an effect if all of the types of the
dictionary's members are representable in JSON (they are a string type, a
primitive type that's not an unrestricted float/double, a void type, or a
sequence, union, dictionary or record containing these types).

The method is expected to be called with a JSON string as input. The JSON string
will be parsed into a JavaScript value, and then the dictionary is initialized
with this value by following WebIDL's
JavaScript type mapping.

Note: As a side-effect of how this is implemented it will also add the two
Init methods that would be added by a [GenerateInit]
extended attribute.

`[GenerateToJSON]`

When set on a dictionary it will add ToJSON methods to the generated C++
class with the following signatures:

cpp
bool ToJSON(nsAString& aJSON);
bool ToJSON(nsACString& aJSON);

The method will generate a JSON representation of the dictionary members' values
in aJSON by converting the dictionary to a JavaScript object by following
WebIDL's JavaScript type mapping
and then converting that object to a JSON string.

The same restrictions on types applies as on
[GenerateInitFromJSON].

Note: As a side-effect of how this is implemented it will also add the
ToObjectInternal method that would be added by a
[GenerateConversionToJS] extended attribute.

`[GenerateConversionToJS]`

When set on a dictionary it will add a ToObjectInternal method to the
generated C++ class with the following signature:

cpp
bool ToObjectInternal(JSContext* cx, JS::MutableHandle<JS::Value> rval);

The method will create a JavaScript object by following WebIDL's
JavaScript type mapping.

`[GenerateEqualityOperator]`

When set on a dictionary it will add an equality operator to the generated C++
class.

This is only allowed on dictionaries who only have members (own or inherited)
with string, primitive or enum types.

`[Unsorted]`

When set on a dictionary the dictionary's members will not be sorted in
lexicographic order (which is specified by WebIDL).

This should only ever be used on internal APIs that are not exposed to the Web!

`[ReflectedHTMLAttributeReturningFrozenArray]`

Used to flag a HTML reflected IDL attribute as having a FrozenArray<T>? type,
where T is either Element or an interface that inherits from Element. This
should only be used to implement the algorithms for that kind of reflected IDL
attributes.

When this attribute's getter is called, it will cache the JS reflection of the
returned value on the JS object. The C++ getter will be passed an additional
bool* argument before the result argument. If this argument is not null then
the implementation is supposed to set the bool that this argument is pointing
to to whether the
attr-associated elements
and the
cached attr-associated elements
are equal. If it is not null, and the getter sets the pointee to true then
the cached JS value will be returned, and the result value from the C++ getter
will be ignored (so there is no need to set the result's value). If it is
null, or the getter sets the pointee to false, then the cached value will be
set to the JS reflection of the result value from the C++ getter, and that JS
value will then be returned.

Note that this will not cause the JIT to directly get the cached value from the
slot (as [StoreInSlot] or [Cached] would). The setter will also not clear
the cached value from the slot.

For example, this IDL:

webidl
interface Element {
  [Frozen, ReflectedHTMLAttributeReturningFrozenArray]
  attribute sequence<Element>? reflectedHTMLAttribute;
};

will require the following declarations in Element:

cpp
class Element {
  // …
  void GetReflectedHTMLAttribute(
    bool* aUseCachedValue, Nullable<nsTArray<RefPtr<Element>>>& aResult);
  void SetReflectedHTMLAttribute(
    const Nullable<Sequence<OwningNonNull<Element>>>& aValue);
};

Helper objects

The C++ side of the bindings uses a number of helper objects.

`Nullable`

Nullable<> is a struct declared in
Nullable.h
and exported to mozilla/dom/Nullable.h that is used to represent
nullable values of types that don't have a natural way to represent
null.

Nullable<T> has an IsNull() getter that returns whether null is
represented and a Value() getter that returns a const T& and can
be used to get the value when it's not null.

Nullable<T> has a SetNull() setter that sets it as representing
null and two setters that can be used to set it to a value:
void SetValue(T) (for setting it to a given value) and
T& SetValue() for directly modifying the underlying T&.

`Optional`

Optional<> is a struct declared in
BindingDeclarations.h
and exported to mozilla/dom/BindingDeclarations.h that is used to
represent optional arguments and dictionary members, but only those that
have no default value.

Optional<T> has a WasPassed() getter that returns true if a
value is available. In that case, the Value() getter can be used to
get a const T& for the value.

`NonNull`

NonNull<T> is a struct declared in
BindingUtils.h
and exported to mozilla/dom/BindingUtils.h that is used to represent
non-null C++ objects. It has a conversion operator that produces T&.

`OwningNonNull`

OwningNonNull<T> is a struct declared in
OwningNonNull.h
and exported to mozilla/OwningNonNull.h that is used to represent
non-null C++ objects and holds a strong reference to them. It has a
conversion operator that produces T&.

Typed arrays, arraybuffers, array buffer views

TypedArray.h is exported to mozilla/dom/TypedArray.h and exposes
structs that correspond to the various typed array types, as well as
ArrayBuffer and ArrayBufferView, all in the mozilla::dom
namespace. Each struct has a Data() method that returns a pointer to
the relevant type (uint8_t for ArrayBuffer and
ArrayBufferView) and a Length() method that returns the length
in units of *Data(). So for example, Int32Array has a Data()
returning int32_t* and a Length() that returns the number of
32-bit ints in the array.

By default, the generated bindings reject typed arrays, ArrayBuffer,
and ArrayBufferView objects larger than 2 GB. To allow larger buffers,
use the [AllowLarge] extended attribute.

`Sequence`

Sequence<> is a type declared in
BindingDeclarations.h
and exported to mozilla/dom/BindingDeclarations.h that is used to
represent sequence arguments. It's some kind of typed array, but which
exact kind is opaque to consumers. This allows the binding code to
change the exact definition (e.g., to use auto arrays of different sizes
and so forth) without having to update all the callees.

`CallbackFunction`

CallbackFunction is a type declared in
CallbackFunction.h
and exported to mozilla/dom/CallbackFunction.h that is used as a
common base class for all the generated callback function
representations. This class inherits from nsISupports, and consumers
must make sure to cycle-collect it, since it keeps JS objects alive.

`CallbackInterface`

CallbackInterface is a type declared in
CallbackInterface.h
and exported to mozilla/dom/CallbackInterface.h that is used as a
common base class for all the generated callback interface
representations. This class inherits from nsISupports, and consumers
must make sure to cycle-collect it, since it keeps JS objects alive.

`DOMString`

DOMString is a class declared in
BindingDeclarations.h
and exported to mozilla/dom/BindingDeclarations.h that is used for
Web IDL DOMString return values. It has a conversion operator to
nsString& so that it can be passed to methods that take that type or
nsAString&, but callees that care about performance, have an
StringBuffer available, and promise to hold on to the
StringBuffer at least until the binding code comes off the stack
can also take a DOMString directly for their string return value and
call its SetStringBuffer method with the StringBuffer and its
length. This allows the binding code to avoid extra reference-counting
of the string buffer in many cases, and allows it to take a faster
codepath even if it does end up having to addref the StringBuffer.

`GlobalObject`

GlobalObject is a class declared in
BindingDeclarations.h
and exported to mozilla/dom/BindingDeclarations.h that is used to
represent the global object for static attributes and operations
(including constructors). It has a Get() method that returns the
JSObject* for the global and a GetAsSupports() method that
returns an nsISupports* for the global on the main thread, if such
is available. It also has a Context() method that returns the
JSContext* the call is happening on. A caveat: the compartment of
the JSContext may not match the compartment of the global!

`Date`

Date is a class declared in
BindingDeclarations.h
and exported to mozilla/dom/BindingDeclarations.h that is used to
represent Web IDL Dates. It has a TimeStamp() method returning a
double which represents a number of milliseconds since the epoch, as
well as SetTimeStamp() methods that can be used to initialize it
with a double timestamp or a JS Date object. It also has a
ToDateObject() method that can be used to create a new JS Date.

`ErrorResult`

ErrorResult is a class declared in
ErrorResult.h
and exported to mozilla/ErrorResult.h that is used to represent
exceptions in Web IDL bindings. This has the following methods:

  • Throw: allows throwing an nsresult. The nsresult must be
    a failure code.
  • ThrowTypeError: allows throwing a TypeError with the given
    error message. The list of allowed TypeErrors and corresponding
    messages is in
    dom/bindings/Errors.msg.
  • ThrowJSException: allows throwing a preexisting JS exception
    value. However, the MightThrowJSException() method must be called
    before any such exceptions are thrown (even if no exception is
    thrown).
  • Failed: checks whether an exception has been thrown on this
    ErrorResult.
  • ErrorCode: returns a failure nsresult representing (perhaps
    incompletely) the state of this ErrorResult.
  • operator=: takes an nsresult and acts like Throw if the
    result is an error code, and like a no-op otherwise (unless an
    exception has already been thrown, in which case it asserts). This
    should only be used for legacy code that has nsresult everywhere; we
    would like to get rid of this operator at some point.

Events

Simple Event interfaces can be automatically generated by adding the
interface file to GENERATED_EVENTS_WEBIDL_FILES in the
appropriate dom/webidl/moz.build file. You can also take a simple
generated C++ file pair and use it to build a more complex event (i.e.,
one that has methods).

Event handler attributes

A lot of interfaces define event handler attributes, like:

webidl
attribute EventHandler onthingchange;

If you need to implement an event handler attribute for an interface, in
the definition (header file), you use the handy
"IMPL_EVENT_HANDLER" macro:

cpp
IMPL_EVENT_HANDLER(onthingchange);

The "onthingchange" needs to be added to the StaticAtoms.py file:

py
Atom("onthingchange", "onthingchange")

The actual implementation (.cpp) for firing the event would then look
something like:

cpp
nsresult
MyInterface::DispatchThingChangeEvent()
{
  NS_NAMED_LITERAL_STRING(type, "thingchange");
  EventInit init;
  init.mBubbles = false;
  init.mCancelable = false;
  RefPtr<Event> event = Event::Constructor(this, type, init);
  event->SetTrusted(true);
  ErrorResult rv;
  DispatchEvent(*event, rv);
  return rv.StealNSResult();  // Assuming the caller cares about the return code.
}

`Bindings.conf` details

Write me. In particular, need to describe at least use of concrete,
prefable, and addExternalInterface.

How to get a JSContext passed to a given method

In some rare cases you may need a JSContext* argument to be passed
to a C++ method that wouldn't otherwise get such an argument. To see how
to achieve this, search for implicitJSContext in
dom/bindings/Bindings.conf.

Implementing Web IDL using Javascript

Warning

Implementing Web IDL using Javascript is deprecated. New interfaces
should always be implemented in C++!

It is possible to implement Web IDL interfaces in JavaScript within Gecko
-- however, this is limited to interfaces that are not exposed in Web
Workers
. When the binding occurs, two objects are created:

  • Content-exposed object: what gets exposed to the web page.
  • Implementation object: running as a chrome-privileged script. This
    allows the implementation object to have various APIs that the
    content-exposed object does not.

Because there are two types of objects, you have to be careful about
which object you are creating.

Creating JS-implemented Web IDL objects

To create a JS-implemented Web IDL object, one must create both the
chrome-side implementation object and the content-side page-exposed
object. There are three ways to do this.

Using the Web IDL constructor

If the interface has a constructor, a content-side object can be created
by getting that constructor from the relevant content window and
invoking it. For example:

js
var contentObject = new contentWin.RTCPeerConnection();

The returned object will be an Xray wrapper for the content-side object.
Creating the object this way will automatically create the chrome-side
object using its contractID.

This method is limited to the constructor signatures exposed to
webpages. Any additional configuration of the object needs to be done
methods on the interface.

Creating many objects this way can be slow due to the createInstance
overhead involved.

Using a `_create` method

A content-side object can be created for a given chrome-side object by
invoking the static _create method on the interface. This method
takes two arguments: the content window in which to create the object
and the chrome-side object to use. For example:

js
var contentObject = RTCPeerConnection._create(contentWin, new
MyPeerConnectionImpl());

However, if you are in a JS component, you may only be able to get to
the correct interface object via some window object. In this case, the
code would look more like:

js
var contentObject = contentWin.RTCPeerConnection._create(contentWin,
new MyPeerConnectionImpl());

Creating the object this way will not invoke its __init method or
init method.

By returning a chrome-side object from a JS-implemented Web IDL method

If a JS-implemented Web IDL method is declared as returning a
JS-implemented interface, then a non-Web IDL object returned from that
method will be treated as the chrome-side part of a JS-implemented
WebIdL object and the content-side part will be automatically created.

Creating the object this way will not invoke its __init method or
init method.

Implementing a Web IDL object in JavaScript

To implement a Web IDL interface in JavaScript, first add a Web IDL file,
in the same way as you would for a C++-implemented interface. To support
implementation in JS, you must add an extended attribute
JSImplementation="CONTRACT_ID_STRING" on your interface, where
CONTRACT_ID_STRING is the XPCOM component contract ID of the JS
implementation -- note ";1" is just a Mozilla convention for versioning
APIs. Here's an example:

webidl
[JSImplementation="@mozilla.org/my-number;1"]
interface MyNumber {
  constructor(optional long firstNumber);
  attribute long value;
  readonly attribute long otherValue;
  undefined doNothing();
};

Next, create an XPCOM component that implements this interface. Use
the same contract ID as you specified in the Web IDL file. The class
ID doesn't matter, except that it should be a newly generated one. For
QueryInterface, you only need to implement nsISupports, not
anything corresponding to the Web IDL interface. The name you use for
the XPCOM component should be distinct from the name of the interface,
to avoid confusing error messages.

Web IDL attributes are implemented as properties on the JS object or its
prototype chain, whereas Web IDL methods are implemented as methods on
the object or prototype. Note that any other instances of the interface
that you are passed in as arguments are the full web-facing version of
the object, and not the JS implementation, so you currently cannot
access any private data.

The Web IDL constructor invocation will first create your object. If the
XPCOM component implements nsIDOMGlobalPropertyInitializer, then
the object's init method will be invoked with a single argument:
the content window the constructor came from. This allows the JS
implementation to know which content window it's associated with.
The init method should not return anything. After this, the
content-side object will be created. Then,if there are any constructor
arguments, the object's __init method will be invoked, with the
constructor arguments as its arguments.

Static Members

Static attributes and methods are not supported on JS-implemented Web IDL
(see bug
863952
).
However, with the changes in bug
1172785
you
can route static methods to a C++ implementation on another object using
a StaticClassOverride annotation. This annotation includes the
full, namespace-qualified name of the class that contains an
implementation of the named method. The include for that class must be
found in a directory based on its name.

webidl
[JSImplementation="@mozilla.org/dom/foo;1"]
interface Foo {
  [StaticClassOverride="mozilla::dom::OtherClass"]
  static Promise<undefined> doSomething();
};

Rather than calling into a method on the JS implementation; calling
Foo.doSomething() will result in calling
mozilla::dom::OtherClass::DoSomething().

Checking for Permissions or Preferences

With JS-implemented Web IDL, the init method should only return
undefined. If any other value, such as null, is returned, the
bindings code will assert or crash. In other words, it acts like it has
an "undefined" return type. Preference or permission checking should be
implemented by adding an extended attribute to the Web IDL interface.
This has the advantage that if the check fails, the constructor or
object will not show up at all.

For preference checking, add an extended attribute
Pref="myPref.enabled" where myPref.enabled is the preference
that should be checked. SettingsLock is an example of this.

For permissions or other kinds of checking, add an extended attribute
Func="MyPermissionChecker" where MyPermissionChecker is a
function implemented in C++ that returns true if the interface should be
enabled. This function can do whatever checking is needed. One example
of this is PushManager.

Example

Here's an example JS implementation of the above interface. The
invisibleValue field will not be accessible to web content, but is
usable by the doNothing() method.

js
function MyNumberInner() {
  this.value = 111;
  this.invisibleValue = 12345;
}

MyNumberInner.prototype = {
  classDescription: "Get my number XPCOM Component",
  contractID: "@mozilla.org/my-number;1",
  QueryInterface: ChromeUtils.generateQI([]),
  doNothing: function() {},
  get otherValue() { return this.invisibleValue - 4; },
  __init: function(firstNumber) {
    if (arguments.length > 0) {
      this.value = firstNumber;
    }
  }
}

Finally, add a component and a contract and whatever other manifest
stuff you need to implement an XPCOM component.

Guarantees provided by bindings

When implementing a Web IDL interface in JavaScript, certain guarantees
will be provided by the binding implementation. For example, string or
numeric arguments will actually be primitive strings or numbers.
Dictionaries will contain only the properties that they are declared to
have, and they will have the right types. Interface arguments will
actually be objects implementing that interface.

What the bindings will NOT guarantee is much of anything about
object and any arguments. They will get cross-compartment
wrappers that make touching them from chrome code not be an immediate
security bug, but otherwise they can have quite surprising behavior if
the page is trying to be malicious. Try to avoid using these types if
possible.

Accessing the content object from the implementation

If the JS implementation of the Web IDL interface needs to access the
content object, it is available as a property called __DOM_IMPL__ on
the chrome implementation object. This property only appears after the
content-side object has been created. So it is available in __init
but not in init.

Determining the principal of the caller that invoked the Web IDL API

This can be done by calling
Component.utils.getWebIDLCallerPrincipal().

Throwing exceptions from JS-implemented APIs

There are two reasons a JS implemented API might throw. The first reason
is that some unforeseen condition occurred and the second is that a
specification requires an exception to be thrown.

When throwing for an unforeseen condition, the exception will be
reported to the console, and a sanitized NS_ERROR_UNEXPECTED exception
will be thrown to the calling content script, with the file/line of the
content code that invoked your API. This will avoid exposing chrome URIs
and other implementation details to the content code.

When throwing because a specification requires an exception, you need to
create the exception from the window your Web IDL object is associated
with (the one that was passed to your init method). The binding code
will then rethrow that exception to the web page. An example of how
this could work:

js
if (!isValid(passedInObject)) {
  throw new this.contentWindow.TypeError("Object is invalid");
}

or

js
if (!isValid(passedInObject)) {
  throw new this.contentWindow.DOMException("Object is invalid", "InvalidStateError");
}

depending on which exact exception the specification calls for throwing
in this situation.

In some cases you may need to perform operations whose exception message
you just want to propagate to the content caller. This can be done like
so:

js
try {
  someOperationThatCanThrow();
} catch (e) {
  throw new this.contentWindow.Error(e.message);
}

Inheriting from interfaces implemented in C++

It's possible to have an interface implemented in JavaScript inherit
from an interface implemented in C++. To do so, simply have one
interface inherit from the other and the bindings code will
auto-generate a C++ object inheriting from the implementation of the
parent interface. The class implementing the parent interface will need
a constructor that takes an nsPIDOMWindow* (though it doesn't have
to do anything with that argument).

If the class implementing the parent interface is abstract and you want
to use a specific concrete class as the implementation to inherit from,
you will need to add a defaultImpl annotation to the descriptor for
the parent interface in Bindings.conf. The value of the annotation
is the C++ class to use as the parent for JS-implemented descendants; if
defaultImpl is not specified, the nativeType will be used.

For example, consider this interface that we wish to implement in
JavaScript:

webidl
[JSImplementation="some-contract"]
interface MyEventTarget : EventTarget {
  attribute EventHandler onmyevent;
  undefined dispatchTheEvent(); // Sends a "myevent" event to this EventTarget
}

The implementation would look something like this, ignoring most of the
XPCOM boilerplate:

js
function MyEventTargetImpl() {
}
MyEventTargetImpl.prototype = {
  // QI to nsIDOMGlobalPropertyInitializer so we get init() called on us.
  QueryInterface: ChromeUtils.generateQI(["nsIDOMGlobalPropertyInitializer"]),

  init: function(contentWindow) {
    this.contentWindow = contentWindow;
  },

  get onmyevent() {
    return this.__DOM_IMPL__.getEventHandler("onmyevent");
  },

  set onmyevent(handler) {
    this.__DOM_IMPL__.setEventHandler("onmyevent", handler);
  },

  dispatchTheEvent: function() {
    var event = new this.contentWindow.Event("myevent");
    this.__DOM_IMPL__.dispatchEvent(event);
  },
};

The implementation would automatically support the API exposed on
EventTarget (so, for example, addEventListener). Calling the
dispatchTheEvent method would cause dispatch of an event that
content script can see via listeners it has added.

Note that in this case the chrome implementation is relying on some
[ChromeOnly] methods on EventTarget that were added specifically to
make it possible to easily implement event handlers. Other cases can do
similar things as needed.


Browser Components Pagedata Docs Index (`browser/components/pagedata/docs/index.md`)

PageDataService

The page data service is responsible for collecting additional data about a page. This could include
information about the media on a page, product information, etc. When enabled it will automatically
try to find page data for pages that the user browses or it can be directed to asynchronously look
up the page data for a url.

The PageDataService is an EventEmitter and listeners can subscribe to its notifications via the
on and once methods.

The service can be enabled by setting browser.pagedata.enabled to true. Additional logging can be
enabled by setting browser.pagedata.log to true.

PageData Data Structure

At a high level the page data service can collect many different kinds of data. When queried the
service will respond with a PageData structure which holds some general information about the
page, the time when the data was discovered and a map of the different types of data found. This map
will be empty if no specific data was found. The key of the map is from the
PageDataSchema.DATA_TYPE enumeration. The value is the JSON data which differs in structure
depending on the data type.

text
{
  "url": <url of the page as a string>,
  "date": <epoch based timestamp>,
  "siteName": <a friendly name for the website>,
  "image": <url for an image for the page as a string>,
  "data": <map of data types>,
}

PageData Collection

Page data is gathered in one of two ways.

Page data is automatically gathered for webpages the user visits. This collection is trigged after
a short delay and then updated when necessary. Any data is cached in memory for a period of time.
When page data has been found a page-data event is emitted. The event's argument holds the
PageData structure. The getCached function can be used to access any cached data for a url.

Supported Types of page data

The following types of page data (PageDataSchema.DATA_TYPE) are currently supported:

  • PRODUCT
  • DOCUMENT
  • ARTICLE
  • AUDIO
  • VIDEO

Devtools Docs Contributor Files README (`devtools/docs/contributor/files/README.md`)

Directories Overview

This page provides a very top level overview of what is on each directory in the DevTools source code:

  • devtools/shared: Code shared by both the client (front-end UI) and server. If we are using any third party libraries, or importing external repositories into our tree, those libraries generally live here (eg, devtools/shared/jsbeautify), assuming they are used by both client and server.
    • devtools/shared/client: Code for the Remote Debugging Protocol (RDP) client. You may wonder why this is not in devtools/client below: it's mainly because tests in server also need access to the RDP client.
    • devtools/shared/locales: Strings used in either the server only, or shared with both the client and server.
  • devtools/server: Code for the RDP server and transport layer.
  • devtools/client: Code for the front-end side of our tools. In theory, each directory corresponds to a panel, but this is not always the case. This directory is only shipped with desktop Firefox, as opposed to other directories above, which are shipped with all Gecko products (Firefox for Android, etc.)
    • devtools/client/locales: Strings used in the client front-end.
    • devtools/client/themes: CSS and images used in the client front-end.

Devtools Docs Contributor Tests README (`devtools/docs/contributor/tests/README.md`)

Automated tests

When working on a patch for DevTools, there's almost never a reason not to add a new test. If you are fixing a bug, you probably should write a new test to prevent this bug from occurring again. If you're implementing a new feature, you should write new tests to cover the aspects of this new feature.

Ask yourself:

  • Are there enough tests for my patch?
  • Are they the right types of tests?

We use three suites of tests:

  • xpcshell: Unit-test style of tests. No browser window, only a JavaScript shell. Mostly testing APIs directly.
  • Chrome mochitests: Unit-test style of tests, but with a browser window. Mostly testing APIs that interact with the DOM.
  • DevTools mochitests: Integration style of tests. Fires up a whole browser window with every test and you can test clicking on buttons, etc.

To run all DevTools tests, regardless of suite type:

bash
./mach test devtools/*

Have a look at the child pages for more specific commands for running only a single suite or single test in a suite.


Devtools Docs Contributor Tests Performance Tests Overview (`devtools/docs/contributor/tests/performance-tests-overview.md`)

DevTools Performance Tests overview

This page provides a short overview of the various DevTools performance tests.

damp

DAMP (short for DevTools At Maximum Performance) is the main DevTools performance test suite, based on the talos framework. It mostly runs end to end scenarios, opening the toolbox, various panels and interacting with the UI. It might regress for a wide variety of reasons: DevTools frontend changes, DevTools server changes, platform changes etc. To investigate DAMP regressions or improvements, it is usually necessary to analyze DAMP subtests individually.

See DAMP Performance tests for more details on how to run DAMP, analyze results or add new tests.

debugger-metrics

debugger-metrics measures the number of modules and the overall size of modules loaded when opening the Debugger in DevTools. This test is a mochitest which can be executed locally with:

bash
./mach test devtools/client/framework/test/metrics/browser_metrics_debugger.js --headless

At the end of the test, logs should contain a PERFHERDER_DATA entry containing 4 measures. debugger-modules is the number of debugger-specific modules loaded, debugger-chars is the number of characters in said modules. all-modules is the number of modules loaded including shared modules, all-chars is the number of characters in said modules.

A significant regression or improvement to this test can indicate that modules are no longer lazy loaded, or a new part of the UI is now loaded upfront.

inspector-metrics

See the description for debugger-metrics. This test is exactly the same but applied to the inspector panel. It can be executed locally with:

bash
./mach test devtools/client/framework/test/metrics/browser_metrics_inspector.js --headless

netmonitor-metrics

See the description for debugger-metrics. This test is exactly the same but applied to the netmonitor panel. It can be executed locally with:

bash
./mach test devtools/client/framework/test/metrics/browser_metrics_netmonitor.js --headless

webconsole-metrics

See the description for debugger-metrics. This test is exactly the same but applied to the webconsole panel. It can be executed locally with:

bash
./mach test devtools/client/framework/test/metrics/browser_metrics_webconsole.js --headless

server.pool

server.pool measures the performance of the DevTools Pool class which is intensively used by the DevTools server. This test is a mochitest which can be executed with:

bash
./mach test devtools/client/framework/test/metrics/browser_metrics_pool.js --headless

At the end of the test, logs should contain a PERFHERDER_DATA entry which contain values corresponding to various APIs of the Pool class.

A regression or improvement in this test is most likely linked to a change in a file from devtools/shared/protocol.

toolbox:parent-process

toolbox:parent-process measures the number of objects allocated by DevTools after opening and closing a DevTools toolbox. This test is a mochitest which can be executed with:

bash
./mach test devtools/client/framework/test/allocations/browser_allocations_toolbox.js --headless

The test will record allocations while opening and closing the Toolbox several times. The PERFHERDER_DATA entry in the logs will contain 3 measures. objects-with-stacks is the number of allocated objects for which the allocation site is known and should be easy to fix for developers. You can refer to the allocation tests documentation for a more detailed description of this test and how to use it to investigate and fix memory issues.

A regression here may indicate a leak, for instance a module which no longer cleans its dependencies. It can also indicate that DevTools is loading more singletons or other objects which are not tied to the lifecycle of the DevTools objects.

target:parent-process

target:parent-process measures the number of objects created by DevTools to create a tab target. It does not involve DevTools frontend. This test is a mochitest which can be executed with:

bash
./mach test devtools/client/framework/test/allocations/browser_allocations_target.js --headless

See the description for toolbox:parent-process for more information.

reload:parent-process

target:parent-process measures the number of objects created by DevTools when reloading a page inspected by a DevTools Toolbox. This test is a mochitest which can be executed with:

bash
./mach test devtools/client/framework/test/allocations/browser_allocations_reload.js --headless

See the description for toolbox:parent-process for more information. Note that this test also records another suite, reload:content-process.

reload:content-process

See the description for reload:parent-process.

browser-console:parent-process

browser-console:parent-process measures the number of objects created by DevTools when opening and closing the Browser Console. This test is a mochitest which can be executed with:

bash
./mach test devtools/client/framework/test/allocations/browser_allocations_browser_console.js --headless

See the description for toolbox:parent-process for more information.


Devtools Client Framework Test Allocations Docs Index (`devtools/client/framework/test/allocations/docs/index.md`)

Allocation tests

The allocations folder contains special mochitests which are meant to record data about the memory usage of DevTools.
This uses Spidermonkey's Memory API implemented next to the debugger API.
For more info, see the following doc:
https://searchfox.org/firefox-main/source/js/src/doc/Debugger/Debugger.Memory.md

Test example

javascript
add_task(async function() {
  // Execute preliminary setup in order to be able to run your scenario
  // You would typicaly load modules, open a tab, a toolbox, ...
  ...

  // Run the test scenario first before recording in order to load all the
  // modules. Otherwise they get reported as "still allocated" objects,
  // whereas we do expect them to be kept in memory as they are loaded via
  // the main DevTools loader, which keeps the module loaded until the
  // shutdown of Firefox
  await testScript();

  // Pass alsoRecordContentProcess if you want to record the content process
  // of the current tab. Otherwise it will only record parent process objects.
  await startRecordingAllocations({ alsoRecordContentProcess: true });

  // Now, run the test script. This time, we record this run.
  await testScript(toolbox);

  // This will stop the record and also publish the results to Talos database
  // Second argument will be the name of the test displayed in Talos.
  // Many tests will be recorded, but all of them will be prefixed with this string.
  await stopRecordingAllocations("reload", { alsoRecordContentProcess: true });

  // Then, here you can execute cleanup.
  // You would typically close the tab, toolbox, ...
});

How to run them locally

bash
$ ./mach mochitest --headless devtools/client/framework/test/allocations/

And to only see the results:

bash
$ ./mach mochitest --headless devtools/client/framework/test/allocations/ | grep " test leaked "

Debug leaks

If you are seeing a regression or an improvement, only seeing the number of objects being leaked isn't super helpful.
The tests includes some special debug modes which are printing lots of data to figure out what is leaking and why.

You may run the test with the following env variable to turn debug mode on:

bash
DEBUG_DEVTOOLS_ALLOCATIONS=leak|allocations $ ./mach mochitest --headless devtools/client/framework/test/allocations/the-fault-test.js

DEBUG_DEVTOOLS_ALLOCATIONS can enable two distinct debug output. (Only one can be enabled at a given time)

DEBUG_DEVTOOLS_ALLOCATIONS=allocations will report all allocation sites that have been made
while running your test. This will include allocations which has been freed.
This view is especially useful if you want to reduce allocations in order to reduce GC overload.

DEBUG_DEVTOOLS_ALLOCATIONS=leak will report only the allocations which are still allocated
at the end of your test. Sometimes it will only report allocations with missing stack trace.
Thus making the preview view helpful.

Example

Let's assume we have the following code:

javascript
1:  exports.MyModule = {
 2:    globalArray: [],
 3:    test() {
 3:      // The following object will be allocated but not leaked,
 5:      // as we keep no reference to it anywhere
 6:      const transientObject = {};
 7:
 8:      // The following object will be allocated on this line,
 9:      // but leaked on the following one. By storing a reference
10:      // to it in the global array which is never cleared.
11:      const leakedObject = {};
12:      this.globalArray.push(leakedObject);
13:    },
14:  };

And that, we have a memory test doing this:

javascript
const { MyModule } = require("devtools/my-module");

  await startRecordingAllocations();

  MyModule.test();

  await stopRecordingAllocations("target");

We can first review all the allocations by running:

bash
DEBUG_DEVTOOLS_ALLOCATIONS=allocations $ ./mach mochitest --headless devtools/client/framework/test/allocations/browser_allocation_myTest.js

which will print at the end:

javascript
DEVTOOLS ALLOCATION: all allocations (which may be freed or are still allocated):
[
   {
     "src": "UNKNOWN",
     "count": 80,
     "lines": [
       "?: 80"
     ]
   },
   {
     "src": "resource://devtools/my-module.js",
     "count": 2,
     "lines": [
       "11: 1"
       "6: 1"
     ]
   }
]

The first part, with UNKNOWN can be ignored. This is about objects with missing allocation sites.
The second part of this logs tells us that 2 objects were allocated from my-module.js when running the test.
One has been allocated at line 6, it is transcientObject.
Another one has been allocated at line 11, it is leakedObject.

Now, we can use the second view to focus only on objects that have been kept allocated:

bash
DEBUG_DEVTOOLS_ALLOCATIONS=leaks $ ./mach mochitest --headless devtools/client/framework/test/allocations/browser_allocation_myTest.js

which will print at the end:

javascript
DEVTOOLS ALLOCATION: allocations which leaked:
[
   {
     "src": "UNKNOWN",
     "count": 80,
     "lines": [
       "?: 80"
     ]
   },
   {
     "src": "resource://devtools/shared/commands/commands-factory.js",
     "count": 1,
     "lines": [
       "11: 1"
     ]
   }
]

Similarly, we can focus only on the second part, which tells us that only one object is being leaked
and this object has been originally created from line 11, this is leakedObject.
This doesn't tell us why the object is being kept allocated, but at least we know which one is being kept in memory.

Debug leaks via dominators

This last feature might be the most powerful and isn't bound to DEBUG_DEVTOOLS_ALLOCATIONS.
This is always enabled.
Also, it requires to know which particular object is being leaked and also require to hack
the codebase in order to pass a reference of the suspicious object to the test helper.

You can instruct the test helper to track a given object by doing this:

javascript
1: // Let's say it is some code running from "my-module.js"
 2:
 3: // From a DevTools CommonJS module:
 4: const { track } = require("devtools/shared/test-helpers/tracked-objects.sys.mjs");
 5: // From anything else, JSM, XPCOM module,...:
 6: const { track } = ChromeUtils.importESModule("resource://devtools/shared/test-helpers/tracked-objects.sys.mjs");
 7:
 8: const g = [];
 9: function someFunctionInDevToolsCalledBySomething() {
10:   const myLeakedObject = {};
11:   track(myLeakedObject);
12:
13:   // Simulate a leak by holding a reference to the object in a global `g` array
14:   g.push({ seeMyCustomAttributeHere: myLeakedObject });
15: }

Then, when running the test you will get such output:

bash
0:41.26 GECKO(644653)  # Tracing: Object@my-module:10
 0:40.65 GECKO(644653) ### Path(s) from root:
 0:41.26 GECKO(644653) - other@no-stack:undefined.WeakMap entry value
 0:41.26 GECKO(644653)  \--> [email protected]:160.**UNKNOWN SLOT 1**
 0:41.26 GECKO(644653)  \--> [email protected]:155.g
 0:41.26 GECKO(644653)  \--> [email protected]:8.objectElements[0]
 0:41.26 GECKO(644653)  \--> [email protected]:14.seeMyCustomAttributeHere
 0:41.26 GECKO(644653)  \--> [email protected]:10

This output means that myLeakedObject was originally allocated from my-module.js at line 10.
And is being held allocated because it is kept in an Object allocated from my-module.js at line 14.
This is our custom object we stored in g global Array.
This custom object it hold by the Array allocated at line 8 of my-module.js.
And this array is held allocated from an Object, itself allocated by base-loader.sys.mjs at line 155.
This is the global of the my-module.js's module, created by DevTools loader.
Then we see some more low level object up to another global object, which misses its allocation site.

How to easily get data from try run

bash
$ ./mach try fuzzy devtools/client/framework/test/allocations/ --query "'linux 'chrome-e10s 'opt '64-qr/opt"

You might also pass --rebuild 3 if the test result is having some noise and you want more test runs.

You may try looking at:
https://firefox-dev.tools/performance-dashboard/tools/memory.html

Or at:
https://treeherder.mozilla.org/perfherder/graphs?highlightAlerts=1&highlightChangelogData=1&series=autoland,3887143,1,12&series=mozilla-central,3887737,1,12&series=mozilla-central,3887740,1,12&series=mozilla-central,3887743,1,12&series=mozilla-central,3896204,1,12&timerange=2592000&zoom=1630504360002,1632239562424,0,123469.11111111111

Link that you get from: https://treeherder.mozilla.org/perfherder/graphs
by looking at last year data for "DevTools" in the first dropdown,
and double clicking on the relevant line in "Tests" menulist.

Significant improvements and regressions will be notified through the following dashboard.


Dom Webgpu Tests Cts Checkout Docs Intro README (`dom/webgpu/tests/cts/checkout/docs/intro/README.md`)

Introduction

These documents contains guidelines for contributors to the WebGPU CTS (Conformance Test Suite)
on how to write effective tests, and on the testing philosophy to adopt.

The WebGPU CTS is arguably more important than the WebGPU specification itself, because
it is what forces implementation to be interoperable by checking they conform to the specification.
However writing a CTS is hard and requires a lot of effort to reach good coverage.

More than a collection of tests like regular end2end and unit tests for software artifacts, a CTS
needs to be exhaustive. Contrast for example the WebGL2 CTS with the ANGLE end2end tests: they
cover the same functionality (WebGL 2 / OpenGL ES 3) but are structured very differently:

  • ANGLE's test suite has one or two tests per functionality to check it works correctly, plus
    regression tests and special tests to cover implementation details.
  • WebGL2's CTS can have thousands of tests per API aspect to cover every combination of
    parameters (and global state) used by an operation.

Below are guidelines based on our collective experience with graphics API CTSes like WebGL's.
They are expected to evolve over time and have exceptions, but should give a general idea of what
to do.

Contributing

Testing tasks are tracked in the CTS project tracker.
Go here if you're looking for tasks, or if you have a test idea that isn't already covered.

If contributing conformance tests, the directory you'll work in is src/webgpu/.
This directory is organized according to the goal of the test (API validation behavior vs
actual results) and its target (API entry points and spec areas, e.g. texture sampling).

The contents of a test file (src/webgpu/**/*.spec.ts) are twofold:

  • Documentation ("test plans") on what tests do, how they do it, and what cases they cover.
    Some test plans are fully or partially unimplemented:
    they either contain "TODO" in a description or are .unimplemented().
  • Actual tests.

Please read the following short documents before contributing.

0. [Developing](developing.md)

1. [Life of a Test Change](life_of.md)

2. [Adding or Editing Test Plans](plans.md)

3. [Implementing Tests](tests.md)

[Additional Documentation](../)

Examples

Operation testing of vertex input id generation

This section provides an example of the planning process for a test.
It has not been refined into a set of final test plan descriptions.
(Note: this predates the actual implementation of these tests, so doesn't match the actual tests.)

Somewhere under the api/operation node are tests checking that running GPURenderPipelines on
the device using the GPURenderEncoderBase.draw family of functions works correctly. Render
pipelines are composed of several stages that are mostly independent so they can be split in
several parts such as vertex_input, rasterization, blending.

Vertex input itself has several parts that are mostly separate in hardware:

  • generation of the vertex and instance indices to run for this draw
  • fetching of vertex data from vertex buffers based on these indices
  • conversion from the vertex attribute GPUVertexFormat to the datatype for the input variable
    in the shader

Each of these are tested separately and have cases for each combination of the variables that may
affect them. This means that api/operation/render/vertex_input/id_generation checks that the
correct operation is performed for the cartesian product of all the following dimensions:

  • for encoding in a GPURenderPassEncoder or a GPURenderBundleEncoder
  • whether the draw is direct or indirect
  • whether the draw is indexed or not
  • for various values of the firstInstance argument
  • for various values of the instanceCount argument
  • if the draw is not indexed:
    • for various values of the firstVertex argument
    • for various values of the vertexCount argument
  • if the draw is indexed:
    • for each GPUIndexFormat
    • for various values of the indices in the index buffer including the primitive restart values
    • for various values for the offset argument to setIndexBuffer
    • for various values of the firstIndex argument
    • for various values of the indexCount argument
    • for various values of the baseVertex argument

"Various values" above mean several small values, including 0 and the second smallest valid
value to check for corner cases, as well as some large value.

An instance of the test sets up a draw* call based on the parameters, using point rendering and
a fragment shader that outputs to a storage buffer. After the draw the test checks the content of
the storage buffer to make sure all expected vertex shader invocation, and only these ones have
been generated.


Index (`docs/index.rst`)

================================= Firefox Source Tree Documentation

.. toctree::
:caption: Overview
:maxdepth: 2

{overview_doc}

.. toctree::
:caption: Getting Started
:maxdepth: 1

{setup_doc}

.. toctree::
:caption: Working On Firefox
:maxdepth: 2

{contributing_doc}

.. toctree::
:caption: Firefox User Guide
:maxdepth: 2

{user_guide}

.. toctree::
:caption: Source Code Documentation
:maxdepth: 2

{source_doc}

.. toctree::
:caption: The Firefox Build System
:maxdepth: 1

{build_doc}

.. toctree::
:caption: Testing & Test Infrastructure
:maxdepth: 1

{testing_doc}

.. toctree::
:caption: AI Agent Tools
:maxdepth: 1

{ai_agent_tools_doc}

.. toctree::
:caption: Releases & Updates
:maxdepth: 1

{release_doc}

.. toctree::
:caption: Localization & Internationalization
:maxdepth: 2

{l10n_doc}

.. toctree::
:caption: Firefox and Python
:maxdepth: 1

{python_doc}

.. toctree::
:caption: Metrics Collected in Firefox
:maxdepth: 1

{metrics_doc}

Indices and tables

  • :ref:genindex
  • :ref:modindex
  • :ref:search

Accessible Docs Architecture (`accessible/docs/Architecture.md`)

Architecture

This document provides a high-level overview of how the accessibility code is structured. See the Document Accessibility Lifecycle page for a lower level description of the code.

Process Model

The accessibility component spans multiple processes. In the parent process, it creates an accessibility tree of the Firefox UI and responds to requests from accessibility clients such as screen readers, magnifiers and voice control tools. In content processes, the accessibility component creates accessibility trees from web content.

To respond to accessibility client requests quickly, the accessibility tree from each content process is cached in the parent process.

Accessibility Trees

Accessibility trees can carry different kinds of information: informally, there are "local trees" that represent a document in the current process and "remote trees" that mirror a local tree created in a separate process.

A local tree can only contain nodes in the current process, i.e. you can visit any node in the tab document and its in-process iframes. However, out-of-process iframes appear as a separate local tree in a different process.

A remote tree, on the other hand, unifies these trees: you can visit any node in the tab document and both its in-process and out-of-process iframes.

This means there are multiple accessibility trees for a single tab: one local tree in the content process, one local tree for each out-of-process iframe, and one remote tree in the parent process that mirrors these local trees. The Firefox UI is represented by a single local tree in the parent process.

An accessibility client communicates only with the parent process.
It sees the local tree for the Firefox UI and the remote trees for tabs and iframes as a single, unified tree.

Tree Nodes

An accessibility tree is composed of nodes represented by the Accessible class and its subtypes. Below is an example local accessibility tree from example.com, as printed by a11y::logging::Tree (unfortunately, without type information):

text
A11Y TREE: Initial subtree; 44:14.388
  {
    : 0x107077a00; role: document, name: 'Example Domain', idx: 0, node: 0x105f84800, #document
      : 0x105fb8b30; role: heading, name: 'Example Domain', idx: 0, node: 0x107b048b0, h1
        : 0x105fb8c90; role: text leaf, name: 'Example Domain', idx: 0, node: 0x107b05600, #text
      : 0x105fb8d40; role: paragraph, idx: 1, node: 0x107b04940, p
        : 0x105fb8df0; role: text leaf, name: 'This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.', idx: 0, node: 0x107b05700, #text
      : 0x105fb8ea0; role: paragraph, idx: 2, node: 0x107b049d0, p
        : 0x107922030; role: link, name: 'More information...', idx: 0, node: 0x107b030e0, a [ href="https://www.iana.org/domains/example" ]
          : 0x1079220e0; role: text leaf, name: 'More information...', idx: 0, node: 0x107b05800, #text
  }

Accessible has a direct subtype for different kinds of accessibility trees: LocalAccessible for nodes of local trees and RemoteAccessible for nodes of remote trees. For example, LocalAccessible can be used in content processes for web content and in the parent process for the Firefox UI. The descendants of these two types diverge.

LocalAccessible's direct descendant is AccessibleWrap. By convention, a class that ends in Wrap is a platform-specific implementation so AccessibleWrap contains the platform-specific implementations of Accessible and LocalAccessible. AccessibleWrap's direct and indirect subtypes are representations of HTML and XUL nodes such as HTMLButtonAccessible and HTMLListBulletAccessible. The Document and the root node of the accessibility tree are also represented by the Accessible class: DocAccessible and DocAccessibleWrap as well as RootAccessible and RootAccessibleWrap extend AccessibleWrap.

RemoteAccessible doesn’t have such an extensive type hierarchy. Its primary descendant is DocAccessibleParent which is the Document node of a remote tree located in the parent process: its local tree counterpart in a content process is DocAccessible.

Below is a graph that displays the same relationships described above. In the graph, solid lines represent direct descendants while dotted lines represent indirect descendants:

{mermaid}
flowchart TD
accTitle: Graph of the class hierarchy described above
Accessible --> LocalAccessible[LocalAccessible: local tree] & RemoteAccessible[RemoteAccessible: remote tree]
LocalAccessible --> AccessibleWrap[AccessibleWrap: platform-specific implementation]
AccessibleWrap -.-> DocAccessible & HTMLButtonAccessible & HTMLListBulletAccessible
DocAccessible --> DocAccessibleWrap --> RootAccessible --> RootAccessibleWrap
RemoteAccessible -.-> DocAccessibleParent

Platform-Specific Behavior

Accessibility trees differ by platform. The platform-independent tree, composed of types like LocalAccessible and RemoteAccessible, is marshalled into a platform-specific tree that makes it easier to implement the platform's accessibility API (or APIs). The platform tree is composed of the following node types:


Accessible Docs ColorsAndHighContrastMode (`accessible/docs/ColorsAndHighContrastMode.md`)

Colors and High Contrast Mode

Firefox offers several customisations to improve the accessibility of colors used to render web content and Firefox chrome. This document describes the customisation options available and their behaviour across platforms. It also describes how these options interact with one another. It is intended for developer reference :)

The Contrast Control Settings

In about:preferences > Language and Appearance, you'll find a subsection labeled "Contrast Control". The radio group in this section determines if high contrast mode (HCM) will be used. HCM can either be enabled on the platform level (OS HCM), or forced on in the browser (FF HCM)

The radio buttons alter browser.display.document_color_use. HCM can be enabled automatically with OS settings (OS HCM, document_color_use=0), it can be forced off (document_color_use=1), or forced on (FF HCM, document_color_use=2). When HCM is enabled, either automatically or explicitly, web content is rendered with a predetermined palette to give the user full control of the content's color contrast.

Note: FF HCM only affects web content, so changing the option in this select will only alter color usage for web pages. It will not change FF chrome. Current behaviour on chrome pages (ie. about: pages) is undefined.

User-customisable Colors Dialog

If the user has chosen to explicitly turn on Firefox HCM (document_color_use=2), they may customize the palette in a modal dialog. Users can choose to override background color, foreground color, visited link color, and/or unvisited link color by selecting a new color from the color inputs in the dialog. Modifications to these colors are stored in their corresponding user preference:

  • browser.background_color
  • browser.foreground_color
  • browser.visited_color
  • browser.anchor_color

Color Usage and System Colors

Before we render any Firefox/web content, we need to select a color palette to render that content with. There are three different sets of colors we can use to style Firefox and/or web content:

  • Stand-in colors
  • System colors
  • Colors-dialog colors

Note: Web pages may supply their palette through style sheets. When FF HCM is set to "On", or set to "Use platform's contrast settings" and OS HCM is enabled, the chosen color palette is forced, meaning it cannot be overridden by web pages.

We decide which set of colors to use in PreferenceSheet::Load. If resistFingerprinting is enabled, we use stand-in colors. These colors are pre-defined constants and are not dynamically fetched from the operating system. Check out nsXPLookAndFeel::GetStandinForNativeColor for more information, as well as the constants themselves.

If we aren't using stand-in colors, we'll check the browser.display.document_color_use pref. If HCM is explicitly off (1), or automatically off (0), we will use the system colors as default text and link colors.

System colors are colors queried from the operating system. They help Firefox adapt to OS-level changes that aren't strictly HCM (ie. light/dark themeing). Because these colors are OS-dependent, a user operating Firefox on a Windows machine with system colors enabled will see Firefox differently than a user with system colors enabled on MacOS.

So, how do we get system colors? Our style system has a set of pre-defined ColorID's in ServoStyleConsts.h, which are mapped to platform-specific colors in widget/[cocoa | android | windows | gtk]/LookAndFeel.cpp. Depending on the ColorID queried, we may do a dynamic fetch or simply return a constant. On MacOS, for example, ColorID::TextForeground and ColorID::TextBackground are hard-coded to return black and white respectively. ColorID::Highlight, on the other hand, queries the OS for NSColor.selectedTextBackgroundColor, which is set based on the accent color a user has selected in System Preferences.

Note: The colors we fetch here are theme-relative. If a user has set their OS to a dark theme, we'll fetch colors from that palette, and likewise for a light theme. Windows HCM, though not strictly a "theme", overrides the colors stored for Windows' light theme, leading to some confusing code, like this.

Lastly, if we explicitly turn on HCM (document_color_use=2) AND we are not styling Firefox chrome AND we are not resistFingerprinting, we'll use colors-dialog colors to style web content.

By default, browser.display.document_color_use is set to 2 on Windows. If a user turns on the OS HCM Firefox will automatically go into HCM mode as well.

Note: This is intentional. Windows HCM is the most robust HCM offered among the operating systems we support, and so we cater to it here :)

Users on non-Windows platforms have HCM disabled by default (document_color_use=1). In order to enable Firefox HCM, they will either need to turn
it on explicitly (document_color_use=2), or set it to use the OS HCM mode and palette (document_color_use=0).

For a simplified flow chart of this decision tree, check out our HCM Settings page

High Contrast Mode

Operating System High Contrast Mode (OS HCM)

Operating System HCM (or OS HCM) describes a high contrast customisation that is enabled outside of Firefox, in the settings of a user's operating system. Each of our major desktop operating systems has an OS HCM variant:

  • Windows: Settings > Accessibility > Increase Contrast > (select theme) > Apply
  • MacOS: System Preferences > Accessibility > Display > Increase Contrast
  • Linux: Settings > Themes > High Contrast

The presence of an OS HCM is stored in IntID::UseAccessibilityTheme.


Accessible Docs DocumentAccessibilityLifecycle (`accessible/docs/DocumentAccessibilityLifecycle.md`)

Document Accessibility Lifecycle

1. DocAccessible creation

When a DocAccessible is created, it is initially empty.
A DocAccessible can be created in one of several ways:

Scenario 1: Accessibility service is already started, layout fires an a11y notification for a new document

  1. The layout PresShell gets initialized (PresShell::Initialize).
  2. As part of that, layout inserts content from the root content object down.
  3. This fires an accessibility insertion notification (nsAccessibilityService::ContentRangeInserted).
  4. That gets the DocAccessible (DocManager::GetDocAccessible).
  5. Because it doesn't exist yet, the DocAccessible gets created (DocManager::CreateDocOrRootAccessible).

Scenario 2: Accessibility service is already started, DOM loading completes for a new document

For top level content documents, if the accessibility service is started, layout should fire an a11y notification, resulting in scenario 1 above.
For child documents (e.g. in-process iframes), this might not happen because the container Accessible for the child document might not be created yet.
In that case, we can't create a DocAccessible when the layout notification is fired.
If the container Accessible is created when DOM loading completes for the child document, this scenario can occur.

  1. a11y::DocManager gets notified that the document has stopped loading (DocManager::OnStateChange).
  2. It tries to get an existing DocAccessible, but it doesn't exist yet, so it creates a DocAccessible (DocManager::CreateDocOrRootAccessible).

Scenario 3: Accessibility service is already started, child document is reached while building accessibility tree for parent document

Child document here refers to a child document in the same process; i.e. an in-process iframe or a parent process document such as an about: page.
Note that scenario 1 or 2 could happen for a child document as well.

  1. While building the accessibility tree for the parent document, an OuterDocAccessible is created (e.g. for a XUL browser or iframe).
  2. The OuterDocAccessible constructor gets the DocAccessible for the child document (DocManager::GetDocAccessible).
  3. Because it doesn't exist yet, the DocAccessible gets created (DocManager::CreateDocOrRootAccessible).

Scenario 4: Accessibility service starts after top level document is loaded

  1. When the accessibility service starts, it initializes the ApplicationAccessible (ApplicationAccessible::Init).
  2. As part of that, all documents are iterated.
  3. For each top level document, the DocAccessible is retrieved (DocManager::GetDocAccessible) and thus created (DocManager::CreateDocOrRootAccessible).

Scenario 3 would then apply for any child documents encountered while building the accessibility trees for these top level DocAccessibles.

Scenario 5: Document gets focus before layout begins

It is possible for a document to get focus before layout has begun and before DOM loading is complete.
In that case, there will be a PresShell, but it will have no root frame.
Despite this, it is necessary to create the document because otherwise, a11y focus would go nowhere while the document had DOM focus.

  1. a11y::FocusManager gets notified of a DOM focus change (FocusManager::NotifyOfDOMFocus).
  2. It gets the DocAccessible for the child document (DocManager::GetDocAccessible).
  3. Because it doesn't exist yet, the DocAccessible gets created (DocManager::CreateDocOrRootAccessible).

2. Initial tree creation

  1. When a DocAccessible is created, it creates a refresh observer (NotificationController) which performs various processing asynchronously.
  2. When the NotificationController is created, it schedules processing for the next possible refresh tick.
  3. Once a refresh tick occurs, while there is not an interruptible reflow in progress and there is an initialized PresShell, the DocAccessible's initial update is triggered (DocAccessible::DoInitialUpdate).
  4. For a top level document, the DocAccessibleChild IPC actor is created. See the section on IPC actor creation below.
  5. The DOM tree is walked and the accessibility tree is built for the document down (DocAccessible::CacheChildrenInSubtree).

Note that the document might still have no layout frame if the PresShell still has no frame; see scenario 5 in DocAccessible creation above.
Nevertheless, DoInitialUpdate must be called because otherwise, we wouldn't create the IPC actor, which would in turn mean remote documents in this state couldn't get a11y focus.

3. Child document binding

Child document here refers to a child document in the same process; e.g. an in-process iframe or a parent process document such as an about: page.

Child documents need to be a child of their OuterDocAccessible; e.g. the iframe.
However, the child document might be ready before the parent document is.
To deal with this:

  1. When a DocAccessible is created for a child document (DocManager::CreateDocOrRootAccessible), it is scheduled for binding to its parent (DocAccessible::BindChildDocument).
  2. NotificationController does not handle any updates for child documents until they are bound to their parent.
  3. After the initial tree creation for the parent document, NotificationController binds the document scheduled in 1).

4. IPC actor (DocAccessibleChild/Parent) creation

Scenario 1: Top level document

  1. As the first part of the DocAccessible's initial update (DocAccessible::DoInitialUpdate), if the document is a top level document, it creates a DocAccessibleChild.
  2. It then sends a message to the parent process to construct the DocAccessibleParent (BrowserChild::SendPDocAccessibleConstructor).

Scenario 2: Child document

The DocAccessibleChild for a child document is created when the child document is bound to its parent by NotificationController.
There is also a code path to handle the case where the DocAccessibleChild has already been created.
However, it doesn't seem like this should happen and code coverage information suggests that it doesn't.

5. Document load events

Scenario 1: DocAccessible is already created, DOM loading completes

  1. a11y::DocManager gets notified that the document has stopped loading (DocManager::OnStateChange).
  2. It notifies the DocAccessible (DocAccessible::NotifyOfLoad, passing EVENT_DOCUMENT_LOAD_COMPLETE.
  3. That sets the eDOMLoaded LoadState and mLoadEventType on the DocAccessible.
  4. Something schedules NotificationController processing. This could be the initial update, an insertion, etc.
  5. Because the DocAccessible has been marked as loaded, the initial tree has been built and all child documents are loded, NotificationController calls DocAccessible::ProcessLoad.
  6. ProcessLoad fires the EVENT_DOCUMENT_LOAD_COMPLETE event as set in 3).

Scenario 2: DocAccessible is created some time after DOM loading completed

This can happen if the accessibility service is started late.
It can also happen if a DocAccessible couldn't be created earlier because the PresShell or containre Accessible wasn't created yet.

  1. The DocAccessible is initialized (DocAccessible::Init).
  2. It detects that DOM loading is already complete.
  3. In response, it sets the eDOMLoaded state and mLoadEventType on the DocAccessible.
  4. Something schedules NotificationController processing. This could be the initial update, an insertion, etc.
  5. Because the DocAccessible has been marked as loaded, the initial tree has been built and all child documents are loded, NotificationController calls DocAccessible::ProcessLoad.
  6. ProcessLoad fires the EVENT_DOCUMENT_LOAD_COMPLETE event as set in 3).

Suppression of document load events for parent process iframes

Note that for documents loaded directly in the parent process, ProcessLoad won't fire a load event for a child document whose parent is still loading.
This is old behavior which does not work in the content process and will probably be removed in future.
See bug 1700362.


Accessible Docs GeckoViewThreadTopography (`accessible/docs/GeckoViewThreadTopography.md`)

GeckoView Thread Topography

Unlike conventional Gecko, GeckoView utilizes two main threads in the parent process. A thread called the "UI" thread that runs the native Java event loop, and a "Gecko" thread that spawns an instance of Gecko. Note, this "Gecko" thread is considered the main thread in conventional Gecko and throughout the source is referred to as such. For example NS_IsMainThread() returns true when called on the Gecko thread.

Android's accessibility API's entry point is the UI thread. The most common methods for an accessibility service to query and interact with Gecko have a return value and thus must be performed synchronously. For example performAction() and createAccessibilityNodeInfo().

Thread Safety Concerns

As a rule, every data structure and method in Gecko should be considered unsafe to access from GeckoView's UI thread. For example the default reference counting implementation is not thread safe and should not be used outside the Gecko thread. Cross-process messaging must be done from the Gecko thread as well.

Since the accessibility consumer is in the UI thread we need to either call into the Gecko thread while blocking the UI thread, or make a limited subset of the accessibility API thread safe. We employ both methods for different types of content.

In-Process Content

Content that is rendered in the top-level process is rare and mostly consists of "about" pages that give insight to browser internals, like about:support.

Since our Gecko accessibility API queries DOM and Layout, and includes many complex, thread-unsafe data structures, we call into the Gecko thread to retrieve what is needed and block the UI until we get a response from the Gecko thread. For example, to retrieve a "class name" enum that is calculated for a certain accessible the method will look something like this:

cpp
int SessionAccessibility::GetNodeClassName(int32_t aID) {
  int32_t classNameEnum = java::SessionAccessibility::CLASSNAME_VIEW;
  RefPtr<SessionAccessibility> self(this);
  nsAppShell::SyncRunEvent([this, self, aID, &classNameEnum] {
    if (Accessible* acc = GetAccessibleByID(aID)) {
      classNameEnum = AccessibleWrap::AndroidClass(acc);
    }
  });

  return classNameEnum;
}

Out-of-Process Content

Most web content will be rendered in a child process. Historically, we would cache the accessible tree hierarchy and object roles in the parent process and use synchronous IPC to query individual objects for more properties. We are transitioning to a fully cached approach where all fields are either stored or calculated in remote proxy objects in the parent process.

The "cache" in our definition is any data member associated with the remote Accessible or its subclasses, such as mParent, mChildren and mCachedFields in RemoteAccessibleBase, or mAccessibles in DocAccessibleParent. In addition to all those members the cache includes the accessible/id table in SessionAccessibility.

The cache is initialized and modified exclusively by messages from the child process to the parent process. Since the cache is limited to our module and is relatively well scoped, it is possible to synchronize access to it and allow it to be consumed by the UI thread.

Global Accessibility Thread Monitor

We have global thread monitor that can be acquired by calling nsAccessibilityService::GetAndroidMonitor(). For example, if we were to retrieve the class name enum we would use an RAII wrapped monitor to exclusively access the cache:

cpp
int SessionAccessibility::GetNodeClassName(int32_t aID) {
  MonitorAutoLock mal(nsAccessibilityService::GetAndroidMonitor());
  if (Accessible* acc = GetAccessibleByID(aID)) {
    return AccessibleWrap::AndroidClass(acc);
  }
}

Gecko Thread Access

As a rule, all incoming IPC messages (ie. all DocAccessibleParent::Recv methods) should hold the global monitor. This is because any Recv method may indirectly modify the cache, for example a certain event might invalidate or update a cached property. There are currently no deferred tasks that happen as a result of a Recv method, so holding the monitor at the start of these methods will assure that the cache is being read or written in a synchronized fashion.

UI Thread Access

All methods that are called in via JNI should be assumed are in the UI thread and should acquire the monitor, unless the are annotated with @WrapForJNI(dispatchTo = "gecko"). This assures us that they are synchronized with any potential modifications to the cache happening in the Gecko thread.


Accessible Docs GuidelinesForNewContributors (`accessible/docs/GuidelinesForNewContributors.md`)

Guidelines for New Contributors

Thank you for your interest in contributing to the Gecko accessibility module.
This document provides some brief, high level guidelines to get you started.

Local and Remote Accessibility Trees

Accessibility clients communicate with Gecko's parent process, but web content is isolated in its own content processes.
Therefore, in order for accessibility clients to access web content, the accessibility tree from each content process is cached in the parent process.
See the Architecture page for more details.

This means that when writing patches to change what is exposed to accessibility clients, you need to ensure that:

  1. The data is included in the cache sent to the parent process.
    This might already be the case if you are modifying an existing property, but it most likely won't be if you are adding something new.
    The cache is built in LocalAccessible::BundleFieldsForCache.
  2. An event is fired when the data is changed, if appropriate.
    This is necessary both to update the parent process cache and to notify clients of the change.
    However, not all properties have associated events.
    See the EVENT_* constants in nsIAccessibleEvent for the supported events.
  3. A cache update is queued when the data is changed, if there is no associated event.
    See DocAccessible::QueueCacheUpdate.
  4. The data can be queried via both LocalAccessible and RemoteAccessible methods.

Tests

Ideally, any change to code in this module should be covered by automated tests.

To run a test directory or file, use the command:

./mach test accessible/tests/path

Browser Tests

Browser tests are located in accessible/tests/browser.
This is our preferred test suite, as it supports testing across multiple processes, is supported by our linters, allows for OS specific testing, etc.
Any new tests should be added to this test suite, in the folder which best approximates their behavior.
The one exception is changes related to XUL, as XUL can only run in the parent process.

Test tasks are defined using addAccessibleTask.
addAccessibleTask can be given a markup snippet (normally HTML) to load.
You also pass it an async test function, which should be named to make debugging easier, though many older tests have unnamed functions.
The same test can then optionally be run in a top level remote document ({ topLevel: true }), in the parent process ({ chrome: true }), in a remote in-process iframe ({ iframe: true }) and an out-of-process iframe ({ remoteIframe: true }).
This makes it easy to test both LocalAccessible and RemoteAccessible using the same code.

Tests in accessible/tests/browser/atk and accessible/tests/browser/windows exercise OS specific APIs.
Like all browser tests, they are primarily written in JS, but the runPython function is used to execute snippets of Python code in a separate process, simulating a real accessibility client.
ATK tests use the pyatspi library to make AT-SPI calls.
Windows tests use the Python ctypes and comtypes libraries to make MSAA, IAccessible2 and UI Automation calls.

Tests in accessible/tests/browser/telemetry and accessible/tests/browser/performance are non-standard.
Please do not use them as examples for general test writing.
If you believe your work requires a telemetry or performance test, please reach out to :morgan on matrix or bugzilla.

Mochitests

Mochitests are located in accessible/tests/mochitest.
This is an older, legacy test suite which only supports testing LocalAccessible in a single process.
However, because of the massive number of tests here, many have not yet been ported to browser tests.
Mochitests are also necessary for testing XUL accessibility.
New tests should not be added in this directory except for those related to XUL.
However, any failures introduced in these tests must still be fixed.

Crash Tests

There is another suite of tests located in accessible/tests/crashtests.
However, this test suite is unreliable and thus legacy.
Because the accessibility module runs asynchronously from DOM, it is difficult to guarantee that any potential crash is hit before the test exits.
New tests should not be added in this directory.

To verify a crash fix, you should instead write a browser test as outlined above.
addAccessibleTask explicitly waits until the document's accessibility tree has been built before running the test function.
If the crash was caused by a change to the accessibility tree, you can also wait for a specific accessibility event (or events) to ensure the change has been processed by the accessibility code before the test exits.


Accessible Docs HCMCSSChecklist (`accessible/docs/HCMCSSChecklist.md`)

HCM CSS Self-Check Guide

Use these checks when writing or reviewing CSS that targets high contrast mode (HCM) or Increase Contrast (IC) users.

For background on the media queries and colour systems referenced here, see the documentation on HCM Media Queries and Colors and High Contrast Mode. You should read and understand these documents before moving forward with the checks below.

Note: These checks are ordered intentionally, please complete them in order.


Architecture

Check 1: Have I identified all places where HCM overrides are necessary?

When writing HCM-specific CSS, our goal is to write as little CSS as possible. Our design system is a huge help here. The design system token layer system (toolkit/themes/shared/design-system/dist/tokens-shared.css) includes three cascade layers — tokens-foundation, tokens-prefers-contrast, and tokens-forced-colors — that automatically override token values in contrast modes. Any variable whose value is (or cascades to) a design system token gets HCM adaptation for free.

In addition to the .css files above, you can view the design system tokens table here. Make sure to select "Chrome" or "Content" as is appropriate for your work.

Variables that use design system tokens generally do NOT need explicit forced-colors overrides. For example:

css
/* These adapt automatically in HCM — no override needed */
color: var(--button-text-color);               /* → ButtonText in forced-colors */
background: var(--button-background-color);    /* → ButtonFace in forced-colors */
border-color: var(--button-border-color);      /* → ButtonText in forced-colors */

Variables with raw custom values DO need explicit forced-colors overrides. These are those holding hardcoded hex colors, light-dark() calls, rgba() values, gradients, or references to brand palette tokens (like --color-violet-80) which do not resolve to system colors.

css
/* These do NOT adapt — explicit forced-colors overrides required */
--my-bg: light-dark(var(--color-gray-0), var(--color-gray-80));
--my-accent: var(--color-violet-90);
--my-gradient: linear-gradient(83deg, #5119dc 0.73%, var(--color-violet-30) 98.05%);
--my-hover-bg: rgba(191, 143, 204, 0.2);

Audit step: Scan all CSS custom properties in your :root / :host block. For each one, ask: does this value ultimately resolve to a CSS system color keyword in tokens-forced-colors? If yes, verify the token is appropriate (other checks below still apply). If no, it needs an override. Note that only the keywords listed in the spec are valid system colors — values like inherit, named colors like teal, or transparent are not CSS system colors and will not adapt correctly in HCM. If your component uses no design system tokens at all, pay particularly close attention to ensuring every color property has an explicit override.


Check 2: Am I using the right media query for the right audience?

forced-colors and prefers-contrast are not interchangeable. You can read more about their differences, with examples, in our HCM Media Query documentation.

Query Fires for
forced-colors: active Windows HCM, Firefox HCM
prefers-contrast: more macOS Increase Contrast and most forced-colors users (contrast ratio > 7:1)

It is important to note:: most HCM users also trigger prefers-contrast. A bare @media (prefers-contrast) block applies to both IC and HCM users. If that is not your intent, you must use a more specific media query.

macOS "Increase Contrast" and Linux HCM alone do not trigger forced-colors.

When a component needs distinct treatment for IC and HCM users, the recommended split is:

css
:root {
  @media (prefers-contrast) {
    /* Applies to ALL contrast users (IC + HCM).
       Safe to use here: borders, border-width increases.
       Do NOT use CSS system color keywords here — IC users keep the
       default Firefox color scheme. */
  }

  @media (prefers-contrast) and (not (forced-colors)) {
    /* IC users only.
       Keep original colors. You may optionally improve a foreground
       color for readability here, but only using non-system colors. */
  }

  @media (forced-colors) {
    /* HCM users only.
       Design system tokens that resolve to CSS system colors are
       required here. Do not use system color keywords directly. */
  }
}

A rule that belongs in both IC and HCM (e.g. removing child outlines from a button with both an icon and a label so only the button wrapper shows a focus ring) should use bare @media (prefers-contrast) without the not (forced-colors) exclusion.

IC-specific color improvements: IC users on macOS keep the default Firefox color scheme and should not receive a reduced-palette experience. If a foreground color modification on a control could meaningfully improve contrast for IC users, it can go in the prefers-contrast and (not (forced-colors)) block — but only using non-system color tokens. There are currently no design system tokens specifically for IC color improvements beyond borders.

If you are uncertain which media query applies to your use case, reach out to the accessibility team in #Accessibility for guidance.


Check 3: Am I overriding tokens in the correct places?

Two main rules govern how HCM overrides should be written:

Nest media queries inside :root / :host, not on specific elements. Do not create a separate top-level @media rule wrapping a new :root declaration. Nesting inside the existing block keeps all variable definitions for a component in one place and makes the full cascade visible at a glance.

css
/* WRONG — separate top-level @media rule instead of nesting inside :root */
:root {
  --my-wrong-text-color: rgb(123, 123, 123);
}

@media (forced-colors) {
  :root {
    --my-wrong-text-color: var(--text-color-design-system-token);
  }
}

/* WRONG — @media nested at element level instead of in :root */
.myWrongClass {
  color: var(--my-wrong-text-color);
  @media (forced-colors) {
    color: var(--text-color-design-system-token);
  }
}

/* CORRECT */
:root {
  --my-bg: #ffffff;
  --my-text-color: rgb(123, 123, 123);

  @media (forced-colors) {
    --my-bg: var(--background-design-system-token);
    --my-text-color: var(--text-color-design-system-token);
  }
}

.myClass {
  background-color: var(--my-bg);
  color: var(--my-text-color);
}

Override the existing variable; do not introduce new HCM-specific ones. Do not create -hcm--suffixed variables or other HCM-specific names. Overriding the existing variable means the element rule can stay simple and clean.

css
/* WRONG — introduces an HCM-specific variable; --my-btn-text-color still resolves to the
   light-dark() value in forced-colors, so the element must also carry its own override */
:root {
  --my-wrong-btn-text-color: light-dark(var(--color-violet-80), var(--color-white));

  @media (forced-colors) {
    --my-wrong-btn-hcm-text-color: var(--button-text-color);
  }
}
.myWrongBtn {
  color: var(--my-wrong-btn-text-color); /* still unresolved in forced-colors */

  @media (forced-colors) {
    color: var(--my-wrong-btn-HCM-text-color); /* element-level override now required */
  }
}

/* CORRECT — element-level CSS is unchanged; HCM is handled entirely at :root */
:root {
  --my-btn-text-color: light-dark(var(--color-violet-80), var(--color-white));

  @media (forced-colors) {
    --my-btn-text-color: var(--button-text-color);
  }
}
.myBtn {
  color: var(--my-btn-text-color);
}

Token Selection

These checks apply when you're writing forced-colors overrides. They ensure you pick tokens that are correct, consistent, and safe across all HCM themes.


Check 4: Are my foreground/background pairs correct, and am I mapping them semantically?

When choosing tokens for an element in HCM, identify the semantic role of the element (interactive control, selected item, static page content, link text, disabled content), find the appropriate token family in the tokens table, then use that family consistently across background, text, and border. Do not mix component-specific tokens with generic ones, or tokens from unrelated components.

css
/* WRONG — mixing component families */
--my-wrong-bg: var(--button-background-color-primary);
--my-wrong-text: var(--text-color); /* generic, not button family */
--my-wrong-border var(--border-color-interactive); /* evaluates to a button color, but a better match exists */

/* WRONG — mixing component family types (button general, primary button, ghost button) */
--my-wrong-bg: var(--button-background-color);
--my-wrong-text: var(--button-text-color-primary);
--my-wrong-border: var(--button-border-color-ghost);

/* CORRECT — same family throughout */
--my-bg: var(--button-background-color-primary);
--my-text: var(--button-text-color-primary);
--my-border: var(--button-border-color-primary);

Token families inside our design system tokens set have already been audited for HCM compliance. By sticking with one family, you're guaranteed to avoid pair mismatches.

What is a pair mismatch?

CSS system colors come in guaranteed-contrast pairs. Contrast is only guaranteed within a pair. Mixing a foreground from one pair with a background from another removes that guarantee and can produce unreadable combinations on some themes.

Do not use CSS system color keywords directly. Use design system tokens — they resolve to the correct system colors through the tokens-forced-colors layer. Consult the Firefox design system tokens table to identify which tokens are available and what they resolve to in forced-colors mode.


Check 5: Are my tokens semantically appropriate for the property they set?

A token named background-color should only be used to set backgrounds. A token named text-color should only be used for text (foreground). Do not use a background token to set a text color variable, even if it happens to resolve to the right system color in a specific theme.

css
/* WRONG — background token used to set text color */
--my-wrong-btn-text: var(--button-background-color-primary);
/* In HCM this resolves to ButtonText via --color-accent-primary,
   but the token name says "background" and the usage says "text" */

/* CORRECT */
--my-btn-text: var(--button-text-color-primary);
/* This also resolves to ButtonText, and the token name is
   appropriate and consistent */

Beyond property type, also verify that the token's component matches your use case. When multiple tokens resolve to the same CSS system color, they are not interchangeable — prefer the one whose name most accurately describes the element being styled. A token that resolves correctly but names the wrong component is still a semantic mismatch, and makes the code harder to audit in future.

css
/* WRONG — despite being a background token, this token describes a list item;
   it is not appropriate for a button background */
--my-wrong-button-background: var(--background-color-list-item);

/* CORRECT */
--my-button-background: var(--button-background-color);

If no token exists whose name is a good semantic match for your use case, that is worth noting — it may indicate the design system doesn't yet cover your component. Please reach out to the accessibility team directly in #Accessibility for guidance.


Check 6: Are my tokens from matching interaction states?

Background, text, and border tokens for a given state (hover, active, focus, selected, current, etc.) must all carry the same state suffix. Mixing states produces pairs that may be unreadable on some HCM themes — hover backgrounds and default-state text colors can resolve to the same system color, making content invisible.

css
/* WRONG — hover-state background paired with default-state text */
--my-btn-bg: var(--button-background-color-hover); /* hover state */
--my-wrong-btn-text: var(--button-text-color); /* default state ← mismatch */

/* CORRECT — both hover state */
--my-btn-bg: var(--button-background-color-hover);
--my-btn-text: var(--button-text-color-hover);

Check 7: Does any information rely on color alone to communicate meaning?

HCM reduces the available palette to a small set of system colors. If any information in the component is conveyed by color alone, it will be lost in HCM. This is also a violation of our general a11y guidelines and WCAG. Check that:

  • Selected states remain visually distinct from unselected states, even when both use system colors. A selected item should use the selection token pair rather than only differing from its neighbor by hue or opacity.
  • Disabled/inactive states remain distinct from enabled states. Use disabled tokens (ex. --button-text-color-disabled) for disabled foreground rather than relying on reduced opacity.
  • Status or severity (e.g. error, warning, success) is not indicated only by color. If an icon or label is the only indicator, ensure it is present and its text/icon uses an appropriate foreground token.
css
/* WRONG — selected state differs from default only by color,
   which may become indistinguishable across HCM themes */
:root {
  @media (forced-colors) {
    --my-wrong-item-text: var(--button-text-color);
    --my-wrong-item-bg: var(--button-background-color);
    --my-wrong-item-bg-selected: var(--button-background-color); /* ← no distinction */
    /* no selected foreground color specified */
  }
}

/* CORRECT — selected state uses the dedicated selection token pair */
:root {
  @media (forced-colors) {
    --my-item-text: var(--button-text-color);
    --my-item-bg: var(--button-background-color);
    --my-item-bg-selected: var(--color-accent-primary-selected);
    --my-item-text-selected: var(--text-color-accent-primary-selected);
  }
}

Check 8: Have I verified that my chosen tokens actually have `forced-colors` variants?

Not every design system token has an entry in the tokens-forced-colors layer. A token without a forced-colors override resolves to its foundation or tokens-prefers-contrast value in HCM, which may be a non-system color.

Before using a token in a forced-colors block, look it up in the Firefox design system tokens table. Ensure your chosen token has an entry in the High Contrast Mode column. If it does not, reach out to the accessibility team in #Accessibility for guidance.

In addition, you should build and test your patch on Windows when possible.
Testing chrome patches in Firefox using FF HCM will not produce the same results as testing on Windows with Windows HCM enabled. Please read about the differences between FF HCM and Windows HCM in the Colors and High Contrast Mode in Firefox documentation.


Check 9: Do ghost components have appropriate tokens set in HCM?

The design system's --button-*-ghost-* tokens already have forced-colors overrides that add a visible border in the default state (ghost buttons are borderless by default) and override hover and active states. If a component uses ghost styling in non-HCM, do not override the ghost tokens to non-ghost values in the forced-colors block — that creates a state mismatch between modes. Let the ghost tokens cascade naturally through the design system. If you've chosen custom color values for your ghost component, override those styles with ghost tokens in HCM.

css
/* WRONG — non-HCM uses ghost state, forced-colors switches to default state */
:host {
  --my-wrong-ghost-btn-bg: var(--button-background-color-ghost);

  @media (forced-colors) {
    --my-wrong-ghost-btn-bg: var(--button-background-color); /* ← this will remove the ghost stylinlg, causing a state mismatch */
  }
}

/* CORRECT */
:host {
  --my-ghost-btn-bg: var(--button-background-color-ghost);
}

/* ALSO CORRECT */
:host {
  --my-ghost-btn-bg: color-mix(in srgb, --button-background-color, #fff, 20%);

  @media (forced-colors) {
    --my-ghost-btn-bg: var(--button-background-color-ghost);
  }
}

Elements and Features

These checks address specific UI elements and CSS features that require particular handling in contrast modes.


Check 10: Am I adding borders to all elements that require them, for all contrast users?

Controls, sidebars, toolbars, dialogs, cards, and sections require a solid border of at least 1px in contrast modes. Borders provide visual separation where color alone is insufficient, and are important for both IC and HCM users. Ensure adequate padding around the border so it does not reduce legibility of the content inside.

In HCM, border tokens are supplied by our design system for most token family types and states. In Increase Contrast (IC), border color should match the component's foreground color (often with currentColor).

If the same border is appropriate for both IC and HCM, set it in a bare @media (prefers-contrast) block. The forced-colors block's value will override it for HCM users due to source order:

css
:root {
  --my-item-border-width: 0px;
  --my-item-border-color: transparent;

  @media (prefers-contrast) {
    /* 1px solid border using the component's foreground color, for all contrast users */
    --my-item-border-width: var(--border-width);
    --my-item-border-color: currentColor;
  }

  @media (forced-colors) {
    /* Override to use the token matching the component family */
    /* Keep the border width token above, as it is appropriate for both modes */
    --my-item-border-color: var(--button-border-color);
  }
}

.my-element {
  border: var(--my-item-border-width) solid var(--my-item-border-color);
  padding: var(--space-small);
}

Check 11: Have I removed or replaced visual effects that don't belong in HCM?

Blur effects, drop shadows, semi-opaque surfaces, and gradient backgrounds must be removed or replaced with solid equivalents in HCM. These effects rely on color blending that is meaningless or visually broken against a forced system-color palette.

Effect HCM replacement
Drop shadow 1px solid border using the component's foreground color token
Gradient background Solid background using the appropriate background-color token
Semi-opaque surface Solid background (var(--background-color-box)) with opacity:1;
Blur Remove entirely
css
:root {
  --my-shadow: drop-shadow(-16px -16px red);
  --my-gradient: linear-gradient(135deg, var(--color-violet-50), var(--color-blue-50));
  --my-overlay-bg: rgba(0, 0, 0, 0.5);
  --my-border-width: 0px;
  --my-custom-opacity: 0.1;

  @media (forced-colors) {
    --my-shadow: none;
    --my-gradient: none;
    --my-overlay-bg: var(--background-color-canvas);
    --my-border-width: var(--border-width); /* border replaces shadow */
    --my-custom-opacity: 1;
  }
}

Check 12: Have I handled SVG colors correctly for HCM?

SVGs fall into two categories with different HCM requirements:

Decorative SVGs, or SVGs that duplicate information already available in an accessible format (e.g. a triangle icon next to a text label starting with "Warning"). These SVGs may use colors outside the HCM palette. No override is needed.

Informational or interactive SVGs — those that uniquely communicate information or function as controls — must use only HCM palette colors. An example of an SVG in this category is the down-chevron on a custom accordian element.
Generally, button tokens are appropriate when these items are interactive and traditional background/text tokens are appropriate when they are static. These components should also gain borders in HCM.

css
/* Interactive icon SVG — must adapt in HCM */
:root {
  --my-chevron-fill: var(--color-violet-60);
  --my-chevron-stroke: var(--color-violet-80);

  @media (forced-colors) {
    --my-chevron-fill: var(--button-background-color);
    --my-chevron-stroke: var(--button-border-color);
  }
}

Accessible Docs HCMMediaQueries (`accessible/docs/HCMMediaQueries.md`)

High Contrast Mode (HCM) Media Queries

Firefox supports both the prefers-contrast and forced-colors media queries. These queries detect a user's display settings (in the browser and/or in their OS), and allow authors to adjust content styling accordingly. These queries are not interchangeable, and we should be intentional about using one or the other (or both!) when designing for accessibility.

What activates these queries?

Forced Colors

The forced-colors media query has two values: active and none. The resolved value of this media query is determined by the browser based on user settings (OS and Firefox).

  • The none state indicates documents can use any colors to render content.
  • The active state indicates a user has OS or browser settings that limit the color palette available to the User Agent.

In Firefox's default configuration, the active state is triggered when a user has enabled Windows High Contrast Mode or Firefox High Contrast Mode (FF HCM). Both of these forced-colors modes offer users a limited amount of color customisation. In Windows, users can override seven colors, and with Firefox High Contrast Mode users can override four. MacOS's "Increase Contrast" setting does not trigger forced-colors: active because it does not limit the color palette available to UA's.

NOTE: MacOS's "Increase Contrast" setting will trigger forced-colors: active (in non-chrome web content) if it is enabled in combination with FF HCM's "Only with High Contrast Themes" option. This is also true on Linux. Because FF HCM defaults to "Never" on non-Windows platforms, enabling "Increase Contrast" or Linux High Contrast Themes alone will not trigger forced-colors: active. Similarly, if a user disables FF HCM while Win HCM is enabled, forced-colors (in content) will evaluate to none.

CSS System Colors

Colors that are overridden by the forced-colors modes list above are inherited into the browser's CSS System Colors. Designers must use these colors exclusively in their designs when designing for forced-colors modes. CSS System Colors are intended to be used in pairs: for example the ButtonFace and ButtonText colors should be used together to create styling for interactive controls. The full pairings are listed in the system color pairings section of the CSS spec. Mozilla has additional design guidance for using CSS System Colors in our HCM Design Guide. You can also check out our other docs to learn more about color overriding.

Prefers Contrast

The prefers-contrast media query has four values: more, less, custom, and no-preference.

  • The more state is triggered when a user has macOS's "Increase Contrast" setting enabled, or when a forced-colors mode is active and the ratio between a user's chosen foreground and background is higher than 7:1. This check is done in our style system.
  • The less state is triggered when a forced-colors mode is active and the foreground/background ratio is less than 4.5.
  • When a forced-colors mode is enabled with a ratio between these two values, we return custom.
  • Otherwise, if no forced-colors mode is active, and macOS's "Increase Contrast" is off, the media query resolves to no-preference.

So what do I use?

Generally, this boils down to which operating systems you want your styling to apply to. In the past, we've often written code to target all platforms within prefers-contrast blocks because the kinds of changes we make to target forced-colors mode also benefit "Increase Contrast" users on macOS; they allow system colors to propagate to the UA. The palette that macOS supplies when "Increase Contrast" is enabled is also inherited to CSS System Colors, and may offer improvements over the standard palette for a design. It is still possible that changes made for forced-colors modes benefit "Increase Contrast" users, however we strongly encourage developers to consider whether diversifying our designs for these modes provides better UX.

On macOS, we aren't limited to the OS palette. Instead of modifying a design to use fewer colors, we can simply increase the contrast ratio of the existing colors to 7:1 to satisfy the enhanced contrast criterion of Web Content Accessibility Guidelines (WCAG) for better accessibility. Consider the following designs.

Standard UX on macOS:

UX with increased contrast of existing colors on macOS:

Changes present in this example belong in a prefers-contrast: more block. This is assuming these changes are appropriately overridden in the cascade for forced-colors: active users. If they are not overridden, an additional query like @media (-moz-platform: macos) or .. and (not (forced-colors)) should be combined with prefers-contrast: more to ensure these changes only apply to macOS.
For users who prefer less contrast, we can supply colors that lower the contrast ratios in the existing design and encase those changes in a prefers-contrast: less block.

UX with limited color palette in FF HCM on macOS:

In forced-colors modes, we require that designs reduce their palettes for compatibility. To accomplish this, we use CSS System Colors instead of the original design colors. This allows the overridden palette to "show through", since colors from the various forced-colors modes are inherited into CSS System Colors. It is possible that using CSS System Colors also increases contrast for users on macOS, but this more drastically changes the design at hand, and can detract from the overall user experience for users who are simply looking for more contrast. Designers should consider the additional guidelines on border use, removing gradients, etc. in our HCM Design Guide.

NOTE: Firefox's chrome style sheets are subject to different rules than web-author style sheets.

Firefox's chrome style sheets (including those in our about: pages) are not prevented from using colors that aren't system colors, even if a forced colors mode is enabled. In webpages, however, Firefox forces CSS System Colors regardless of the author's original specification. This is a safety mechanism to ensure pages render appropriately even if no @media (prefers-contrast) or @media (forced-colors) styling was specified. To avoid this overriding, web authors can use the forced-color-adjust: none; CSS property.

Writing Maintainable Frontend Code

Where possible, we prefer color overriding for prefers-contrast and forced-colors take place in one block at the root level rather than in many blocks on an element-by-element basis. We encourage developers to use design systems tokens with semantic naming when overriding. Consider the following.

text
:root {
  --page-background: #cccccc;
  --page-text-color: #000000;

  @media (forced-colors) {
    --page-background: Canvas;
    --page-text-color: CanvasText;
  }
}

body {
  color: var(--page-text-color);
  background-color: var(--page-background);
}

Here, we've defined one set of color variables on :root and subsequently overridden them in a forced-colors block. We don't need to re-write the styling for body within our media query because the vars it references will correctly adapt when forced-colors is active.

Though forced-colors overriding doesn't happen in Firefox chrome style sheets, our style system does force all instances of transparent to the default color for a color attribute (usually CanvasText). This allows us to specify styles that appear only in forced-colors mode without an additional CSS keyword. It is also sometimes beneficial to define vars at the :root level with an initial value (eg. transparent, 0px, none) so the vars exist for HCM overriding later (see: --dialog-border-width).

text
:root {
  /* ... */
  --dialog-background: #ffffff;
  --dialog-color: #bbbbbb;
  --dialog-border-color: transparent;
  --dialog-border-width: 0px;

  @media (forced-colors) {
    /* ... */
    --dialog-background: Canvas;
    --dialog-color: CanvasText;
    /* No override for --dialog-borer-color, since it'll become
    * CanvasText when HCM is enabled, which matches the HCM spec. */
    --dialog-border-width: 1px;
  }
}

.dialog {
  color: var(--dialog-color);
  background-color: var(--dialog-background);
  border: var(--dialog-borer-width) solid var(--dialog-border-color);
}

/* ... */

In general, it is best to do overriding at the :root level, even if additional variables are required. It is not recommended to do overriding on a class-by-class or element-by-element basis, like below:

text
:root {
  /* ... */
  --button-background: #ffffff;
  --button-text-color: #bbbbbb;

  @media (forced-colors) {
    /* ... */
    --button-background: ButtonFace;
    --button-text-color: ButtonText;
    --button-border-color: var(--button-text-color);
  }
}

@media (forced-colors) {
  /* BAD: These rules are generic and should be outside of a @media block */
  .destroyButton {
    color: var(--button-text-color);
    background-color: var(--button-background);
    border: 1px solid var(--button-border-color);
  }
}

@media (not (forced-colors)) {
  /* BAD: Element-level styling should not be placed in media query blocks.
   * See "Scoping token overrides with @media (not (forced-colors))" below
   * for when this pattern IS appropriate. */
  .destroyButton {
    color: var(--light-grey-20);
    background-color: var(--red-60);
  }
}
/*...*/

Scoping token overrides with `@media (not (forced-colors))`

When you introduce a custom override for a CSS variable that already has a @media (forced-colors) value in the design system token layer, wrapping your override in @media (not (forced-colors)) prevents it from replacing that value. When forced-colors is active, the scoped declaration does not apply at all, leaving the token layer's system-color value as the only one in effect — no extra forced-colors handling required.

Consider a variable that already has a forced-colors override in the token layer:

css
:root {
  --page-background: #f0f0f0;

  @media (forced-colors) {
    --page-background: Canvas;
  }
}

A component author later adds a dark-mode-aware override:

text
/* BAD: replaces the token layer's Canvas value for forced-colors users */
:root {
  --page-background: light-dark(#f0f0f0, #1a1a1a);
}

/* GOOD: only applies when forced-colors is not active, so forced-colors
 * users still get the Canvas value from the token layer above */
@media (not (forced-colors)) {
  :root {
    --page-background: light-dark(#f0f0f0, #1a1a1a);
  }
}

When choosing between @media (not (forced-colors)) and @media (not (prefers-contrast)) you need to consider a few things:

  • Do defaults exist for the tokens you're overriding in both the prefers-contrast layer and the forced-colors layer? Or are defaults only specified in a single layer? Remember: the goal of this override strategy is to reveal the defeault token values.
  • Do your new token values increase contrast? If so, they could be more valuable to prefers-contrast users than the existing token defaults. You should consider exempting forced-colors users only.

In most cases, (not (forced-colors)) is the right choice: it leaves the existing token layer's forced-colors handling in effect, while users who have only a contrast preference (and no active forced-colors mode) continue to benefit from non-system-color visual enhancements.

Putting it all together

Let's walk through an example on this sample website.

The majority of our site styling is done via color overriding on the root block.

css
:root {
  /* General */
  --background: #202124;
  --color: #cccccc;
  --border-color: transparent;
  --border-size: 0;
  --table-background: #303134;
  /* Note */
  --note-background: gold;
  --note-color: var(--table-background);
  --note-opacity: .7;
  /* General Controls */
  --control-background: gray;
  --control-color: var(--color);
  --control-border-size: var(--border-size);
  --control-border-color: var(--border-color);
  /* Destructive Button */
  --destructive-button-background: tomato;
  --destructive-button-color: var(--table-background);
}

How might we adapt this website for users who prefer increased contrast? What about for users with forced colors?

Let's start with users who prefer increased contrast. We might decide to make the background and foreground easier to read by making the foreground text lighter, increasing the contrast ratio. We might also remove the note's opacity and darken its text color. We don't need to remove the note's golden background, since prefers-contrast doesn't require a reduced color palette.

text
:root {
  /* ... */
  @media (prefers-contrast) and (not (forced-colors)) {
    /* General */
    --color: white;
    /* Note */
    --note-color: black;
    --note-opacity: 1;
    /* ... */
  }
}

To address these same issues in forced-colors mode, we should replace the colors with the semantically appropriate system color. Unlike our work in the prefers-contrast block above, we do need to modify the note's background, since gold is not a system color. We might end up with something like this:

text
:root {
  /* ... */
  @media (forced-colors) {
    /* General */
    --background: Canvas;
    --color: CanvasText;
    --table-background: var(--background);
    /* Note */
    --note-background: var(--background);
    --note-color: var(--color);
    --note-opacity: 1;
    /* ... */
  }
}

After this change, you'll notice our page background, table background, and note background all share the same color. This makes them difficult to differentiate. To address this, we can add a contrasting border and override the previously transparent --border-color variable and its corresponding --border-size. This var applies to content areas but not controls.

text
:root {
  /* ... */
  @media (forced-colors) {
    /* General */
    --background: Canvas;
    --color: CanvasText;
    --border-color: var(--color);
    --border-size: 1px;
    --table-background: var(--background);
    /* Note */
    --note-background: var(--background);
    --note-color: var(--color);
    --note-opacity: 1;
    /* ... */
  }
}

Next, let's look at the controls this page uses for the web form. We've got an input, a checkbox, a submit button, and a clear button. In the prefers-contrast case, we should ensure the controls contrast from the background as much as possible. It's possible to do this via color alone, but it can help to add borders for additional contrast. Here, again, we don't need to get rid of the clear button's tomato background, but we can update it to something brighter.

text
:root {
  /* ... */
  @media (prefers-contrast) and (not (forced-colors)) {
    /* ... */
    /* General Controls */
    --control-background: color-mix(in srgb, gray, lightgray);
    --control-color: black;
    --control-border-size: 1px;
    --control-border-color: gray;
    /* Destructive Button */
    --destructive-button-background: red;
    --destructive-button-color: white;
    /* ... */
  }
}

Finally, let's style the page's controls for forced-colors. Unlike in prefers-contrast, we can't use color to differentiate between the submit button and the clear form button -- both should inherit from our button CSS system colors.

text
:root {
  /* ... */
  @media (forced-colors) {
    /* General */
    --background: Canvas;
    --color: CanvasText;
    --border-color: var(--color);
    --border-size: 1px;
    --table-background: var(--background);
    /* Note */
    --note-background: var(--background);
    --note-color: var(--color);
    --note-opacity: 1;
    /* General Controls */
    --control-background: ButtonFace;
    --control-color: ButtonText;
    --control-border-color: ButtonText;
    /* Destructive Button */
    --destructive-button-background: var(--control-background);
    --destructive-button-color: var(--control-color);
  }
}

If we wanted to make the submit button stand out as a primary button, we could invert the styling on that button in particular. Something like:

text
:root {
  /* ... */
  @media (forced-colors) {
    /* General */
    --background: Canvas;
    --color: CanvasText;
    --border-color: var(--color);
    --border-size: 1px;
    --table-background: var(--background);
    /* Note */
    --note-background: var(--background);
    --note-color: var(--color);
    --note-opacity: 1;
    /* General Controls */
    --control-background: ButtonFace;
    --control-color: ButtonText;
    --control-border-color: ButtonText;
    /* Destructive Button */
    --destructive-button-background: var(--control-background);
    --destructive-button-color: var(--control-color);
  }

  #submit {
    background: var(--control-color);
    color: var(--control-background);
    border: var(--control-border-size) solid currentColor;
  }
}

Now we've got a site that functions in multiple HCM scenerios :) Visit the live site with HCM or Increase Contrast enabled to test it for yourself.
A few takeaways:

  • prefers-contrast and forced-colors are not mutually exclusive. If you write two independent forced-colors and prefers-contrast media query blocks, they'll both apply when FF HCM is enabled (assuming your foreground/background contrast ratio is high, which it is by default). Adding an and (not (forced-colors)) clause to your @media (prefers-contrast) declaration can help make the two blocks distinct if you'd like mac-centric styling in one and forced-colors styling in the other.
  • prefers-contrast requires specific, case-by-case overriding, whereas forced-colors is largely about inheretince. In the former, page regions that are differentiated with color should stay that way (albeit with more contrasting colors). In forced-colors all page regions that aren't interactive should use Canvas/CanvasText and rely on borders for distinction. Once you've set --background: Canvas; at the root level, for ex. subsequent background vars should inherit from it.
  • Where possible, aim to do overriding at the :root level using CSS variables, this makes it easier to update code in the future.

Accessible Docs HCMSettings (`accessible/docs/HCMSettings.md`)

HCM Settings

Several Firefox settings work together to determine how web content and browser chrome are rendered. They can be hard to keep track of! Use the flowcharts below for quick reference.

Settings that control color usage in browser chrome

  • OS HCM:
    • Windows: High Contrast Mode in OS accessibility settings
    • macOS: Increase Contrast in OS accessibility settings
    • Linux: High Contrast Theme in OS accessibility settings
  • FF Theme (AKA FF Colorway)
    Note: OS HCM settings will only trigger HCM color usage in chrome if a user's FF theme is set to "system auto". If they have a pre-selected colorway or other FF theme (including explicit "Dark" or "Light") they will not see color changes upon enabling OS HCM.
{mermaid}
flowchart TD
A[Is OS HCM enabeld?]
A -->|Yes| B[Is FF's theme set to System Auto?]
B --> |Yes| C[Use OS HCM colors to render browser chrome]
B -->|No| D[Use FF theme colors to render browser chrome]
A -->|No| D

Settings that control color usage in content

  • Colors Dialog (about:preferences > Contrast Control)
  • Extensions like Dark Reader, or changes to user.css, may override author specified colors independent of HCM.
{mermaid}
flowchart TD
A[Which option is selected in 'Contrast Control'?]

A -->|Use platform's contrast settings| B[Is a OS HCM enabled?]
A -->|Off| H
A --->|On| I[Use colors dialog colors to render all content &lpar;HCM&rpar;]

B -->|Yes| C[Use OS colors to render all content &lpar;HCM&rpar;]
B -->|No| H[Use system colors for all unstyled content]

Accessible Docs TaggedPdfOutput (`accessible/docs/TaggedPdfOutput.md`)

Tagged PDF Output

Tagged PDF embeds a semantic structure tree alongside the graphical content in a PDF, enabling screen readers and other assistive technology to interpret the document.
Firefox generates tagged PDFs by leveraging its accessibility engine and Skia's SkPDF backend.

The feature is toggled by the pref accessibility.tagged_pdf_output.enabled.

High Level Architecture

The implementation spans several modules:

  • accessible/base/DocManager: NotifyOfPrintDocument bootstraps the accessibility engine and builds accessibility trees for print documents.
  • accessible/base/nsAccessibilityService: provides an ePdfOutput consumer mode that allows the accessibility engine to run in a stripped-down mode purely for PDF generation.
  • accessible/pdf/PdfStructTreeBuilder: translates the Gecko accessibility tree into an SkPDF::StructureElementNode tree for Skia and maps accessibility node IDs to SkPDF node IDs.
  • gfx/thebes/PrintTargetSkPDF: the Skia PDF print target, which calls PdfStructTreeBuilder to obtain the structure tree and passes it to SkPDF::MakeDocument.
  • layout/generic/nsIFrame + layout/painting/nsDisplayList: layout emits nsDisplayAccessibleId display items to associate painted content with accessibility nodes.
  • gfx/2d/DrawTarget + gfx/2d/DrawTargetSkia: the AccessibleId draw command propagates the association down to Skia, where SkPDF::SetNodeId tags subsequent drawing commands.

Triggering Tagged PDF Generation

When a print job starts, nsPrintJob::SetupToPrintContent calls a11y::DocManager::NotifyOfPrintDocument(doc).

NotifyOfPrintDocument calls GetOrCreateAccService(nsAccessibilityService::ePdfOutput) to ensure the accessibility service is running, then creates a DocAccessible for the print document (a static clone of the live document, so aAllowStatic=true is passed), and immediately calls DoInitialUpdate() to build the accessibility tree synchronously.
In-process iframes embedded in the document are also initialized here in the same way.

For a parent process document, NotifyOfPrintDocument calls PdfStructTreeBuilder::Init directly.
For remote documents in content processes, after the local accessibility tree is built, NotifyOfPrintDocument arranges for PdfStructTreeBuilder::Init(browsingContext) to be called in the parent process (see the next section on IPC).

IPC: Remote Top Level Documents and OOP Iframes

Content can live in content processes, but a PDF can only be generated in the parent process, regardless of where the content lives or where the print job is initiated.
There are two IPC cases.

Remote Top Level Document

nsPrintJob runs in whatever process owns the document, so for a remote tab, NotifyOfPrintDocument runs in the content process.
After building the accessibility tree locally and sending it to the parent process via PDocAccessible, a PDocAccessible::Printing IPDL message is sent to the parent process.
DocAccessibleParent::RecvPrinting handles this message and calls PdfStructTreeBuilder::Init in the parent process.

OOP Iframes

Once PdfStructTreeBuilder::Init runs in the parent process for the top level document as described above, InitInternal walks all descendant BrowserParents and sends a PBrowser::RequestDocAccessibleForPrint IPDL message to each.
In the content process, BrowserChild::RecvRequestDocAccessibleForPrint calls NotifyOfPrintDocument.
As above, this builds the accessibility tree, sends it to the parent process, sends PDocAccessible::Printing and thus calls PdfStructTreeBuilder::Init in the parent process.

PdfStructTreeBuilder tracks how many OOP iframes are pending via mPendingOopIframes.
Each time an OOP iframe's accessibility tree arrives and is registered with the builder via a further call to InitInternal, the counter is decremented.
When it reaches zero, a ReadyPromise is resolved.
The print job awaits this promise before proceeding.

SkPDF requires the complete structure tree at the time the document is opened, so this waiting is necessary before SkPDF::MakeDocument can be called.

Building the Structure Tree

Once the ReadyPromise resolves, PrintTargetSkPDF::BeginPrinting calls PdfStructTreeBuilder::BuildStructTree.
This walks the accessibility tree rooted at the top document — using DocAccessible for in-process documents and DocAccessibleParent for remote ones — and recursively builds a tree of SkPDF::StructureElementNode objects.

For each accessible, BuildStructSubtree:

  • Assigns an SkPDF integer node ID (via GeneratePdfId) and records the mapping in mAccToPdf.
  • Maps the Gecko accessibility role to the corresponding PDF structure type; e.g. roles::HEADING → "H1"–"H6" or "H", roles::PARAGRAPH → "P", roles::TABLE → "Table", etc.
  • Depending on the role, maps Gecko accessibility properties to PDF attributes such as table row/column span, header associations and alt text for figures and headings.

The completed struct tree root is stored in SkPDF::Metadata::fStructureElementTreeRoot before SkPDF::MakeDocument is called.
SkPDF also derives a PDF bookmark outline from heading nodes; headings' accessible names are set as fAlt to provide this text, since Gecko provides glyph indices rather than text runs when drawing.

Associating Painted Content with Structure Nodes

The struct tree alone is not sufficient: each drawing command in the content stream must be tagged with the SkPDF node ID of the structure element it belongs to.

Layout: Emitting `nsDisplayAccessibleId`

During display list construction for a print document, nsIFrame::BuildDisplayListForChild calls the local helper MaybeAddAccId for each child frame.
MaybeAddAccId calls PdfStructTreeBuilder::GetAccId(frame) which looks up the Accessible for the frame's content node and returns a {browsingContextId, accessibleId} pair.
If one is found, an nsDisplayAccessibleId display item is prepended to the content list for that frame.

Painting: The `DrawTarget::AccessibleId` Command

nsDisplayAccessibleId::Paint calls DrawTarget::AccessibleId(browsingContextId, accId).
For parent process content rendered directly to a DrawTargetSkia backed by an SkPDF canvas, DrawTargetSkia::AccessibleId translates the Gecko IDs to a SkPDF integer via PdfStructTreeBuilder::GetPdfId, then calls SkPDF::SetNodeId(mCanvas, pdfId).
All drawing commands issued to the canvas after this point are tagged with that node in the PDF.

Content Process: `DrawTargetRecording`

When content is painted in a content process, it goes through DrawTargetRecording.
DrawTargetRecording::AccessibleId emits a RecordedAccessibleId event into the recording stream .
When the recording is replayed in the parent process on a DrawTargetSkia, RecordedAccessibleId::PlayEvent calls DrawTargetSkia::AccessibleId and the same SkPDF tagging occurs as described above.

Stripped-Down Accessibility Engine (`ePdfOutput` Mode)

Without a dedicated PDF output mode, tagged PDF generation would require an AT client to already be running (or the engine to be force enabled), because normal accessibility engine startup does significant work that is only needed to serve AT clients: walking all existing documents, initialising platform accessibility APIs and activating the service in every content process.
None of this work is necessary to build an accessibility tree for a single document being printed.
The ePdfOutput consumer mode allows the engine to start in a lightweight mode when the only reason it is needed is to generate a tagged PDF.

`ePdfOutput` Consumer Flag

nsAccessibilityService has a bitmask of active consumers.
If only the ePdfOutput bit is set, this indicates that the only reason the service is running is to support PDF generation.
nsAccessibilityService::IsOnlyForPdfOutput() returns true in this case.

Skipped Initialization

When GetOrCreateAccService(ePdfOutput) starts the engine and no other consumer is active, nsAccessibilityService::Init skips three steps that are deferred into FullInit:

  1. ApplicationAccessible::CreateInitialDocs: forces creation of DocAccessibles for all already-open windows.
  2. PlatformInit: initializes platform accessibility APIs (IAccessible2/UIA on Windows, ATK on Linux, etc.).
  3. Activating the accessibility service in every content process.

The a11y-init-or-shutdown notification is fired with the value "pdf" instead of "1" to let observers distinguish this limited startup from a full one.

Suppressing Unrelated `DocAccessible` Creation

While IsOnlyForPdfOutput(), creation of DocAccessibles is suppressed for any document that was not explicitly passed to NotifyOfPrintDocument.
This prevents ordinary browsing documents from consuming resources they do not need.

Promotion to Full Service

If a real AT consumer (e.g. a screen reader) causes GetOrCreateAccService to be called while the service is already running in ePdfOutput-only mode, PromoteFromPdfOutput is called to perform the deferred FullInit work: creating initial document accessibles, running PlatformInit and notifying content processes.

Cache Domains

Print documents use a specific set of cache domains (requested per-document via DocAccessible/DocAccessibleParent) rather than the global gCacheDomains.
This is done so that PDF output does not inadvertently widen the cache domains in use by any other running clients.
This also avoids pushing unnecessary domains for PDF when another client requires a wider set of domains.
Note that a print document is a static clone of the original DOM document, so this doesn't impact the original document being printed.

Lifecycle

When the last print document is removed, the ePdfOutput consumer bit is cleared.
If no other consumers remain, the accessibility service shuts down normally.
PdfStructTreeBuilder::Done is called from nsDeviceContext::EndDocument/AbortDocument to clean up the builder instance after printing completes or is aborted.

Data Flow Summary

text
/* Detailed source-code truncated for AI context efficiency. */

Accessible Docs Index (`accessible/docs/index.rst`)

Accessibility

These pages contain design documents for the accessibility implementation in Gecko.
They live in the mozilla-central repository under the accessible/docs directory.

The Accessibility page on the Mozilla Wiki <https://wiki.mozilla.org/Accessibility>__ contains general information about accessibility and the accessibility team at Mozilla.

The Mochitest FAQ docs <../testing/mochitest-plain/faq.html#how-can-i-run-accessibility-tests-a11y-checks>__ contain guidance on debugging a11y-checks failures and working with AccessibilityUtils when writing frontend test cases.

.. toctree::
:maxdepth: 1

GuidelinesForNewContributors
Architecture
DocumentAccessibilityLifecycle
GeckoViewThreadTopography
ColorsAndHighContrastMode
HCMSettings
HCMMediaQueries
HCMCSSChecklist
TaggedPdfOutput


Browser Docs BrowserStartup (`browser/docs/BrowserStartup.md`)

Browser Startup

Invoking your code on browser startup

The first rule of running code during startup is: don't.

We take performance very seriously and ideally your component/feature should
initialize only when needed.

If you have established that you really must run code during startup, register
a category manager entry in browser/components/BrowserComponents.manifest.
See the category manager indirection docs for
more details on the mechanism.

Available category manager entries (in order)

Categories come in two types: per-application (fired once at startup) and
per-window (fired for each browser window). The following categories
are listed in the order they fire.

Per-application categories (invoked once, not per-window)

Category Notes
browser-before-ui-startup Please don't do it unless absolutely necessary. This will run code before the first browser window appears on the screen and make Firefox seem slow.
browser-first-window-ready After the first browser window's browser-window-delayed-startup call.
browser-idle-startup Preferred entrypoint for most startup code. Runs during a user-idle period after startup.
browser-best-effort-idle-startup Like browser-idle-startup, but your code may not run at all if the browser is shut down quickly.

Per-window categories (invoked for each browser window)

Category Notes
browser-window-before-initial-xul-layout-document-preparation Before XUL layout; before the tab bar visibility update.
browser-window-before-initial-xul-layout Before XUL layout; after the tab bar visibility update and document icon are set.
browser-window-domcontentloaded-before-tabbrowser During DOMContentLoaded, before the Tabbrowser is created.
browser-window-domcontentloaded-tabbrowser During DOMContentLoaded, creates the Tabbrowser. Internal category - do not add consumers here.
browser-window-domcontentloaded During DOMContentLoaded, after the Tabbrowser is created. Preferred entry point for DOMContentLoaded initialization.
browser-window-load-before-sessionstore-init During the window load event, before SessionStore initializes the window. For components that must be ready before session restore runs.
browser-window-load During the window load event, after SessionStore has initialized the window.
browser-window-delayed-startup After the window's first paint, for code that can run after the window is visible.
browser-window-location-change Fires on every XULBrowserWindow.onLocationChange for the window.
browser-window-unload-begin At the very start of window unload, before checking whether the window finished loading. Runs even if the window never fully loaded.
browser-window-unload During window unload, before Tabbrowser is destroyed. Preferred entry point for window unload cleanup.
browser-window-unload-tabbrowser During window unload, destroys the Tabbrowser. Internal category - do not add consumers here.
browser-window-final-unload During window unload, after Tabbrowser is destroyed.

Other useful points in startup are:

  • BrowserGlue's _onWindowsRestored, and/or the observer service's
    sessionstore-windows-restored topic, and/or a category manager call that
    should replace the BrowserGlue list of direct calls. This fires after
    session restore has completed restoring all windows (but before all pages
    that may have been restored have necessarily loaded). Note that this is
    guaranteed to fire even if automatic session restore is not enabled.

How do first run/first startup experiments work?

Why does synchronously reading Nimbus feature values work for
customizing display features like about:welcome onboarding and the
default browser prompt? The key invariant is that the display
decisions wait for sessionstore-windows-restored to show
customizable UI, and therefore we just need Nimbus available to read
at that point. This is arranged either via the --first-startup
flag; or, for subsequent startups, the relevant Nimbus features being
marked isEarlyStartup: true. When isEarlyStartup: true, Nimbus
caches all its feature variables as Gecko preferences, ready to be
read during early startup. (See the early startup
docs
.)

Customizable display features like about:welcome or the default
browser prompt are used in
_maybeShowDefaultBrowserPrompt(),
which is invoked as part of a startup idle task. Startup idle tasks
are scheduled in response to
sessionstore-windows-restored
.

Now, why is sessionstore-windows-restored late enough for a
first startup experiment? The answer is subtle.

During Firefox launch, final-ui-startup is
notified
,
and in response SessionStore is initialized. Additionally,
Nimbus/Normandy initialization is started but not
awaited
.

Then the command line is
handled
.
When --first-startup is passed, we spin the event loop to allow
Nimbus/Normandy time to complete its initialization and first
fetch

before continuing to process the command line. See the
FirstStartup
module
.
(Important caveat: --first-startup is only used on Windows; see Bug
1872934
, for
example.)

This races with SessionStore, which itself waits for the first
browser window to be shown -- in particular, the
sessionstore-windows-restored notification waits for the first
browser window's browser-delayed-startup-finished
notification
.

This first browser-delayed-startup-finished notification is not
guaranteed
to be after --first-startup has spun the event loop!
But, when launched with only --first-startup and flags considered
very early in nsAppRunner.cpp -- as the stub installer
does

-- then the first window is guaranteed to be after the event loop
has been spun, and therefore sessionstore-windows-restored is after
as well. (As a counter-example: try firefox.exe --browser --first-startup and witness the --browser
flag

creating a window before spinning the event loop, inadvertently racing
against sessionstore-windows-restored.) Making this deterministic
is tracked by Bug
1944431
.

Together, this means that first-startup experiments will be loaded in
time to impact display features such as about:welcome and the
default browser prompt, and we should not have a "split brain"
scenario in which the Nimbus feature is intermittently unavailable to
the relevant display features.


Browser Docs BrowserUsageTelemetry (`browser/docs/BrowserUsageTelemetry.rst`)

.. _browserusagetelemetry:

======================= Browser Usage Telemetry

The :searchfox:BrowserUsageTelemetry.sys.mjs module is the main module for measurements regarding the browser usage (e.g. tab and window counts, search counts, ...).

The measurements recording begins right after the SessionStore has finished restoring the session (i.e. restoring tabs/windows after Firefox starts).

Tab and window interactions

The usage telemetry module currently measures these interactions with the browser's tabs and windows:

  • tab and window engagement: counts the number of non-private tabs and windows opened in a subsession, after the session is restored (see e.g. browser.engagement.max_concurrent_tab_count);
  • URI loads: counts the number of page loads (doesn't track and send the addresses, just the counts) directly triggered by the users (see browser.engagement.total_uri_count);
  • navigation events: at this time, this only counts the number of time a page load is triggered by a particular UI interaction (e.g. by searching through the URL bar, see browser.engagement.navigation.urlbar).

Please see :searchfox:Scalars.yaml <toolkit/components/telemetry/Scalars.yaml> for the full list of tracked interactions.

Customizable UI

This telemetry records information about the positions of toolbar items and when
the user interacts with them. It is submitted as scalar values along with the
normal telemetry ping. There are a number of different parts to this telemetry:

UI Areas

For the purposes of this telemetry a set of areas are defined:

  • In the main browser UI:

    • menu-bar - The main menu.
    • menu-toolbar - The normally hidden toolbar that holds the main menu.
    • titlebar - The optional title bar.
    • tabs-bar - The area where tabs are displayed.
    • vertical-tabs-container - The area where vertical tabs are displayed.
    • bookmarks-bar - The bookmarks toolbar.
    • app-menu - The main application (hamburger) menu.
    • tabs-context - The context menu shown from right-clicking a tab.
    • content-context - The context menu shown from right-clicking the web page.
    • widget-overflow-list - Items that have overflowed the available space.
    • pinned-overflow-menu - Items that the user has pinned to the toolbar overflow menu.
    • pageaction-urlbar - Page actions buttons in the address bar.
    • pageaction-panel - The page action (meatball) menu.
    • nav-bar-start - The area of the navigation toolbar before the address bar.
    • nav-bar-end - The area of the navigation toolbar after the address bar.
    • unified-extensions-area - The unified extensions panel.
  • In about:preferences the different categories are used:

    • preferences-paneDownloads
    • preferences-paneGeneral
    • preferences-paneHome
    • preferences-panePrivacy
    • preferences-paneSearch
    • preferences-paneSearchResults
    • preferences-paneSync
    • preferences-paneContainers
    • preferences-paneAccessibility
    • preferences-paneAppearance
    • preferences-paneLanguages
    • preferences-paneAbout
    • preferences-panePermissionsData
    • preferences-paneTabsBrowsing

Widget Identifiers

In order to uniquely identify a visual element a set of heuristics are used:

#. If the element is one of the customizable toolbar items then that item's ID
is used.
#. If the DOM element has an ID set then that is used.
#. If the DOM element's class contains one of bookmark-item,
tab-icon-sound or tab-close-button then that is used.
#. If the DOM element has a preference key, command, observes or
data-l10n-id attribute then that is used.
#. If there is still no identifier then this is repeated for the DOM element's
parent element.

Widget Locations

The keyed scalar browser.ui.toolbar_widgets records the position of widgets in
the UI. At startup the positions of widgets are collected and recorded by
setting the scalar key <widget id>_pinned_<area> to true. The widget ID are
the IDs of the elements in the DOM. The area is one of the areas listed above
from the browser UI that can be customised.

For the areas that can be controlled the scalar keys <area>_<off/on/newtab> are set.
newtab is special to the Bookmarks Toolbar and is used when the toolbar will only
be shown on the New Tab page.

Widget Customization

The scalar browser.ui.customized_widgets records whenever the user moves a
widget around the toolbars or shows or hides some of the areas. When a change
occurs the scalar with the key <widget id>_<action>_<old area>_<new area>_<reason>
is incremented. The action can be one of move, add or remove. Old
area and new area are the previous and now locations of the widget. In the case
of add or remove actions one of the areas will be na. For areas that
can be shown or hidden the areas will be off or on. The reason is a simple
string that indicates what caused the move to happen (drag, context menu, etc.).

UI Interactions

The scalars browser.ui.interaction.<area> record how often the use
interacts with the browser. The area is one of those above with the addition of
keyboard for keyboard shortcuts.

When an interaction occurs the widget's identifier is used as the key and the
scalar is incremented. If the widget is provided by an add-on then the add-on
identifier is dropped and an identifier of the form addonX is used where X
is a number. The number used is stable for a single session. Every time the user
moves or interacts with an add-on the same number is used but then the numbers
for each add-on may change after Firefox has been restarted.

Profile Count

The scalar browser.engagement.profile_count records how many profiles have
been used by the current Firefox installation. It reports a bucketed result,
which will be 0 if there is an error. The raw value will be reported for 1-10,
but above that, it will report 10 for 10-99, 100 for 100-999, 1000 for
1000-9999, and 10000 for any values greater than that.

The profile count data for an installation is stored in the root of the
update directory in a file called profile_count_.json. The
full path to the file will typically look something like
C:\ProgramData\Mozilla\profile_count_5A9E6E2F272F7AA0.json.

This value is meant to be resilient to re-installation, so that file will not
be removed when Firefox is uninstalled.

Context menu entrypoints

Some context menus are re-used in multiple places. By default, we simply count
the number of interactions per item within a context menu, and do not record
the entrypoint that caused the context menu to open.

It is possible to opt-in to recording the entrypoint that caused the context
menu to open. This is done by adding an entry to
ENTRYPOINT_TRACKED_CONTEXT_MENU_IDS, mapping the ID of the context menu
to a keyed Scalar under browser.ui.interaction.. This scalar is recorded
only if an interaction is recorded within the context menu itself.

When the keyed scalar is recorded, the key will be a unique ID for the
trigger node that caused the context menu to open. The value is the count
of openings from that trigger node.


Browser Docs CategoryManagerIndirection (`browser/docs/CategoryManagerIndirection.md`)

Category manager indirection (callModulesFromCategory)

Firefox front-end code uses the category manager as a publish/subscribe
mechanism for dependency injection, so consumers can be notified of interesting
things happening without having to directly talk to the publisher/actor who
decides the interesting thing is happening.

There are 2 parts to this:

  1. Consumers registering with the category manager
  2. Publishers/actors invoking consumers via the category manager.

Consumer registration with the category manager

The category manager is used for various purposes within Firefox; it is more or
less an arbitrary double string-keyed data store.

For this particular usecase, the publisher/consumer have to use the same
primary key (i.e. category name), such as browser-idle-startup.

The secondary key is a full URL to a sys.mjs module. Note that because this
is a key, only one consumer per module & category combination is possible.

The "value" part is an Object.method notation, where the expectation is that
Object is an exported symbol from the module identified as the secondary key,
and method is some method on that object.

At compile-time, registration can happen with an entry in a .manifest file
like BrowserComponents.manifest.
Note that any manifest successfully processed by the build system would do,
we don't need to use BrowserComponents.manifest specifically. In fact, it
would be preferable if components used their own manifest files.

An example registration looks like:

text
category browser-idle-startup moz-src:///browser/components/tabbrowser/TabUnloader.sys.mjs TabUnloader.init

This will ensure that when the browser-idle-startup publisher is invoked,
the TabUnloader.sys.mjs module is loaded and the init method on the exported
TabUnloader object is invoked.

Runtime registration

Runtime registration is less-often used, but can be done using the category
manager's XPCOM API:

js
Services.catMan.addCategoryEntry(
    "browser-idle-startup",
    "moz-src:///browser/components/tabbrowser/TabUnloader.sys.mjs",
    "TabUnloader.init"
)

Publishers/actors invoking consumers

Publishers call BrowserUtils.callModulesFromCategory with a dictionary of
options as the first argument. If provided, any other arguments are passed
straight through to any consumers.

{js:autofunction} browserutils.callmodulesfromcategory

Example:

js
BrowserUtils.callModulesFromCategory({
    categoryName: "my-fancy-category-name",
    profilerMarker: "markMyCategories",
    idleDispatch: true,
    someArgument
});

This will pass someArgument to each consumer registered for
my-fancy-category-name. Each consumer will be invoked via an idle task, and
each task will get a profiler marker (labelled "markMyCategories") in the
Firefox Profiler so it's easy to find in
performance profiles.

You should consider using idleDispatch: true if invocation of the consumers
does not need to happen synchronously.

If you need to care about errors produced by consumers, you can specify
a function for failureHandler and handle any exceptions/errors using your own
logic. Note that it may be invoked asynchronously if the consumers are async.

Caveats

Any errors thrown by consumers are automatically caught and reported via the
Browser Console.

Async functions are not awaited before invoking other consumers. Note that
rejections (exceptions from async code) are still caught and reported to the
console, and that the async duration of a given consumer will be what
determines the length of the profiler marker, if the publisher asks for profiler
markers.

Why not just call consumers directly?

There are a number of benefits over direct method calls and module imports.

Reducing direct dependencies between different parts of the code-base

Code that looks like this:

text
Foo.thingHappened(arg);
Bar.thingHappened(arg);
Baz.thingHappened(arg);

is not only repetitive, it also means that the code in question has to directly
import all the modules that provide Foo, Bar and Baz. It means that if
those modules change or move or are refactored, the "publisher" code has to
be updated, with all the added burdens that comes with (potential for merge
conflicts, more automatically added reviewer groups for trivial changes, easy
to miss if dependencies are widespread).

Avoiding a bootstrap problem in favour of a "just in time" approach

To make sure code is invoked later, when using the observer service, DOM event
listeners, or other mechanisms, it usually needs to add a listener
before the event of interest happens. If not managed carefully, this often leads
to component initialization being front-loaded to make sure not to "miss" it
later. This in turn makes browser startup more heavyweight rather than it needs
to be, because we set up listeners for everything, potentially loading entire
JS modules just to do that.

Unified error-handling, performance inspection, and scheduling

Using the BrowserUtils.callModulesFromCategory API allows specifying error
handling, performance profiler markers, and scheduling (use of idle tasks) in
one place. This abstracts away the fact that we never want observers, event
listeners or other mechanisms like this to break and stop notifying (or worse,
propagate an exception themselves) when one of the consumers breaks.


Browser Docs CommandLineParameters (`browser/docs/CommandLineParameters.rst`)

======================= Command Line Parameters

Firefox recognizes many (many!) command line parameters. Overview
documentation of these parameters lives here.

Known parameters

.. list-table::
:widths: 20 80
:header-rows: 1

    • Parameter
    • Description
    • -osint
    • On Windows, -osint serves two purposes. Most importantly, it signals
      that the command line is untrusted and must be sanitized. Command lines
      with -osint are rejected unless they have a very specific structure,
      usually firefox.exe -osint -url URL or firefox.exe -osint -private-window URL: refer to :searchfox:the EnsureCommandLineSafe function <mozilla-central/rev/ead7da2d9c5400bc7034ff3f06a030531bd7e5b9:toolkit/xre/CmdLineAndEnvUtils.h#196>.
      These command lines are produced by apps delegating to Firefox, and the
      resulting URL may not be correctly quoted. The sanitization process
      ensures that maliciously chosen URLs do not add additional parameters to
      Firefox. Secondarily, the -osint parameter signals that Firefox is
      being invoked by Windows to handle a URL: generally a registered file
      type, e.g., .html, or protocol, e.g., https.

Browser Docs FrontendCodeReviewBestPractices (`browser/docs/FrontendCodeReviewBestPractices.md`)

Frontend Code Review Best Practices

Introduction

Code reviews help ensure that the code solves a specific problem, doesn’t have bugs or regress other functionality, and has adequate test coverage. It also provides an opportunity to ensure correct documentation is added, whether through code comments or documentation of changes. The process of reviewing code also helps spread knowledge about how the code works amongst developers, both as a patch author and as a reviewer.

A review is required before code or tests are added to Mozilla’s repository. Once approved, code is merged to autoland and once tests pass, sheriffs will merge it with other commits to mozilla-central. This guide outlines a set of standards for both patch author and reviewer.

Intended audience and outcomes

This document is primarily intended for engineers on the Firefox Desktop Front end team. The aim of this guide is to align the team around an agreed set of expectations for patch reviews that will reduce confusion, prevent misunderstandings, help land patches more efficiently and to help onboard new team members.

As an engineer, you’ll be in the position of being both a patch author and a reviewer, so having a good understanding of the expectations of both roles is recommended.

What is expected from a frontend code review?

The sections below outline some of the high level expectations when reviewing code. See also the Technologies and Specifics sections for more details on what to look for that are specific to Frontend code.

The basics

A code review and automation will check if this patch:

  • applies cleanly to mozilla-central and can be built.
  • has a good commit message that describes the changes as well as the reason for them where that is not obvious.
    • Adding a longer description in a commit message will be used as the summary in Phabricator.
  • fixes the issue at hand.
  • has automated test coverage where appropriate. Exceptions to this are covered by using the test-exception-* tags in Phabricator. Here are some common exceptions in frontend where [new] test coverage isn’t needed:
    • style/image/l10n-only changes
    • Code that interacts directly with the OS in ways we can’t mock in automated tests.
    • Code that requires very specific external circumstances (OS settings, wall clock time, actions by other programs, etc.) we can’t mock reliably.
    • Refactorings of existing code (where existing test coverage exists)
    • Removing code
  • passes linting and/or automated tests.

If any of these is missing/broken, a reviewer is likely to stop then and there. Before submitting patches, code authors should ensure they have these covered.

Is this necessary and sufficient?

Two useful ways of looking at patches are “is this necessary?” and “is this sufficient?”:

  • Necessary: are all the changes in the patch required? It’s common to find other issues when fixing a bug, but code not necessary to fix this specific bug should be moved to a separate bug. Reviewers will usually flag up:
    • Unrelated code changes
    • Changing unrelated whitespace etc. (mind your editor’s autoformat)
    • Unnecessarily complex or hacky fixes
  • Sufficient: does this fix the issue completely? That is, have we looked at edge cases and is the patch/patchset definitely fixing all of the issue, not just parts of it or a symptom of it?
    • This also means considering what is not in the patch. So e.g. when renaming a method, patch authors and reviewers should not just check if all the replacements in the patch are correct, but also if all occurrences were actually touched in the patch (searchfox should make this relatively straightforward, or you can apply the patch locally and use grep/ack/ag etc).

Expectations for the Reviewer

Progress > Perfection

As noted above, the context for the patch should be provided by the author, however it’s important to try to strike a balance between ensuring we maintain high standards and being able to make progress. If you identify issues that are routinely cropping up that could be covered by automated linting, please file issues for new rules to be added. This helps us to ensure that the time engineers dedicate to review is primarily spent on efficiently ensuring a change addresses what it sets out to and is both a maintainable and safe addition to Firefox.

Language and tone in review comments

  • Take the time to thank and point out good code changes.
  • Focus on the code, not the patch author (avoid wording that sounds like it’s criticizing the author, for example “this doesn’t make sense, why did you do it this way?” versus “I’m curious why you took this approach. Could you please provide some context?”).
  • Framing comments as questions rather than statements can help create an environment conducive to collaboration. Rather than “This doesn’t work when bar is undefined”, “Could you please check if this code is properly handling the case of bar being undefined?” .
  • Using “please” and “what do you think?” goes a long way in making others feel like colleagues, and not subordinates. As a reviewer, double-check your comments. Assume the code author has spent more time thinking about this part of the code than you have and might actually be right, even if you originally thought something was wrong.
  • Be clear about what changes are required to be changed in order to land the patch versus those that are optional.
  • For things that aren’t nits or trivially understood to be improvements, explain why you are requesting a change. Understanding the reasoning behind requested changes helps make sure that you and the patch author share an understanding of what the patch is doing, and helps the patch author learn.
  • Minimize the number of passes required for review and addressing review comments. Where possible provide your review comments in a single pass rather than multiple iterations. This helps to reduce the number of cycles needed to get something through review and any associated context switching for both the reviewer and the patch author. In a case where you don't have time for a full review, mention that your review is currently incomplete and set expectations for when it will be so the author can plan accordingly.
  • When reviewing code on behalf of additional review groups added to a patch, your review should primarily focus on the areas that the review-group is responsible for or interfaces that your group is using. However, if you do spot a non-trivial issue that falls outside this during review, then it would be reasonable to flag it. .

Turnaround time for reviews

  • Aim for a response within 1 business day. This need not be a full review, but could be a comment setting expectations about when you’ll be able to review the patch, pointing to other folks who might be able to review it sooner or would be more appropriate to review the patch.
  • If you’re explicitly asked for review and can’t get to it due to time constraints, it’s always helpful to set expectations for the patch author.

Expectations for the patch author

Communication

There is often more than one way to address an issue, and reviewers and patch authors may disagree about the “right” approach to a bug. What is “complex” or “hacky” to one person may be “correctly architectured” or “efficient” to another. If when working on a bug, you’re unsure about what the “right” approach is (e.g. “just add a nullcheck here and move on” vs. “refactor the calling code so we don’t ever pass null”), talk to your prospective reviewer or other people familiar with the code before deciding, to avoid repeated work when your reviewer suggests an alternative, perhaps because they have other context you weren’t aware of, or to fit the general architecture of the component you’re changing.

When you haven’t talked to your reviewer because you think the approach you chose is obviously correct, it is usually still helpful to outline your reasoning/choices in the extended commit message, a phabricator comment, and/or bugzilla. It doesn’t need to be an essay, but ideally the reviewer should be able to understand the patch and its reasoning from reading the patch and commit message.

Make use of the commit message to offer both a brief, and where necessary a longer explanation of what the change is doing. Reviewers often review dozens of patches each week. Ensuring that the patch contains all the information they need to review the change helps speed up reviews and avoids confusion about what a patch is trying to achieve.

If the patch needs a shorter turnaround time of the review cycle due to a release or uplift deadline (which should also be reflected in the bug priority and severity that’s been set), you should ping blocking reviewers on slack or matrix to raise awareness of this deadline and to confirm they can review your patch as soon as possible. If they are unable to do so, you’ll need to find another reviewer who can. Where possible ask the existing reviewer for a suggestion, or ask someone else in the same review group. If that’s not possible, ask for input from your team/project lead or manager.

When making changes to revisions, using the ‘plan-changes’ action in Phabricator “removes revisions from reviewers’ queues, meaning that they will no longer be visible under “Ready to Review” on their “Active Revisions” dashboards, until a new diff is uploaded”

When making non-trivial changes to patches which are already on Phabricator, use --message (or -m) with your moz-phab submission to explain what you’re changing.

Leave questions or comments in Phabricator about things you were not sure about. Your reviewer might be able to offer answers, or you might have stumbled on deeper underlying problems that need addressing elsewhere. Either way, everyone learns.

Addressing review comments

Except for very small patches it is extremely common for a reviewer to request changes to a patch after their first review. Reviewers are expected to be courteous and clear about what they’re asking you to change and why. While reviewers do have the final sign-off, code review should be considered to be a conversation. Reviewers are not expected to be perfect. If you don’t understand what a reviewer has asked or disagree with their suggestions then respond with your reasoning or ask for clarification. Usually this happens in the code review itself but it is not uncommon to talk with the reviewer directly where that is faster. In this case it is helpful to add a summary of your discussion to the review comment in Phabricator for future code historians.

If you have requested reviews from multiple reviewers and one of them requests changes, the patch is removed from all reviewers' queues until you re-submit the patch with the requested changes, questions for clarification or comments.

Once you’ve addressed everything the reviewer requested, push your patch up for review again and expect that the reviewer will be verifying that you changed everything requested. To help save unnecessary review iterations, where possible avoid putting the patch back into review until you've made all the necessary changes.

Occasionally the reviewer may ask for a small number of changes but still approve the patch. You are expected to make those changes before the patch can land, the reviewer is just indicating that they trust you to make those changes and don’t need to re-review the patch. If those changes turn out to be larger than the reviewer would have reasonably expected then you should re-request review.

You’re within your rights to suggest that some review feedback can be fixed in follow-up bugs and patches, so long as you ensure to get those follow-ups filed in Bugzilla and that they’re addressed in a timely manner. This is particularly true for in-progress features that are being held to Nightly. Features still being developed and held to Nightly should not be expected to land in a perfect state all in one patch.

Code quality

Make sure before submitting a patch that it compiles cleanly and that the tests included all pass.

Consider re-reading the patch you’ve just submitted to Phabricator once you submit it the first time. Often Phabricator’s clear diff view will highlight things to you that you might have missed, especially if you’ve worked on the patch a long time. It can also help highlight changes that aren’t immediately obvious to someone reading the patch for the first time, and might need an explanation.

Avoid whitespace or other trivial changes to code that you don’t need to change to accomplish your goal. Making other, unrelated changes makes the patch harder to review, and makes it difficult to later to find the origin of a change.

Several small patches are easier to review than one monolith that changes lots of files.

Talk to your peers and prospective reviewer(s) before starting big refactors. Firefox’s code base is huge and refactors carry risk, so reviewers are wary of big changes like that and they are usually difficult to review.

Technologies and Specifics

This section covers some frontend-specific aspects of patches that reviewers are likely to look at.

JS/DOM

  • Use existing components to implement feature designs. Do not reimplement custom button/card/toggle/… styling based on the design and vanilla HTML, as it doesn’t scale, is hard to maintain, and will likely miss edge-cases for accessibility, RTL, etc.
    • The inverse is also true: not every new bit of code you work on has to be factored out as a generic, reusable component immediately. When you are the first/only consumer of a bit of code, it is usually not possible to predict what aspects of your code will need to be “generic”, where API boundaries should be, and so on. Trying to do it immediately is doomed to failure, so don’t spend time on it - save it for when the second potential consumer comes along.
  • Lines of code is a flawed metric, and we’re not code golfing - but don’t write several 10-line functions when 2 lines of inline code will do. Balance brevity and readability appropriately.
  • Use DOM properties over attributes where possible.
    • Where it isn’t, toggleAttribute and classList.toggle are often helpful to avoid repetitive if/else blocks.

Styling and CSS, and SVGs

Localization

  • For anything user-facing, use localised strings. Do NOT hardcode English strings in markup.
  • For new code, use fluent. For modifying older code, use what the old code uses (but consider switching to fluent if it’s straightforward, as it provides better translation primitives in other languages).
  • When writing experimental features that need strings for en-US only that are not final yet, use fluent and put the ftl file in a content rather than locale directory and package it accordingly. When strings are final, move them to a regular locale directory and include them as normal but make sure to do so outside string freeze and while allowing reasonable time for our (largely volunteer) localisers to submit translations - don’t just dump dozens of strings into locale a day before string freeze.
  • If the meaning of a string changes, or [in fluent] you add/remove attributes, you must update the message identifier.
  • More detailed fluent review guidelines are available separately.

Accessibility {#accessibility}

  • Write semantic HTML.
  • Anything mouse-accessible should be keyboard-accessible or have a keyboard-accessible equivalent.
  • Ensure things work in high contrast mode and that there is sufficient colour contrast between foreground and background items in non-high-contrast mode and with different themes.
  • Any images that aren’t purely decorative (e.g. toolbar button icons where there is no visible text label) need an alt attribute or aria-label or similar to give it an accessible name, as well as a tooltip for sighted users who might not understand icons.
  • Any images that are purely decorative (e.g. illustrations next to text) should be implemented using one of these options:
    • CSS background images, which have no representation in the accessibility tree
    • HTML img elements that use role=presentation to remove them from the accessibility tree, and do not have an alt attribute.
  • If implementing animations or transitions, do so behind a prefers-reduced-motion media query to ensure people who have epilepsy or other motion-triggered sensitivities are not hurt by our attempts to make things beautiful.
  • The first rule of ARIA is “don’t use ARIA” (see also “Write semantic HTML”) - but it can be a tool where semantic markup is insufficient (e.g. live regions, complex labeling structures).

Performance

  • Avoid style and layout flushes.
  • Use requestIdleCallback and/or workers for anything on the startup path and/or CPU or disk-intensive work that doesn’t actually need to happen immediately.
  • Use IOUtils to do async File IO, rather than nsIFile for synchronous access.
  • Keep complexity in mind and use reasonable data structures
    • e.g. use a Set rather than arrays if they’re big, unordered, and you need to look items up in the collection
    • Bear in mind that some collections/loops may be reasonably sized in the common case, but have pathological edge cases (that person with 3652 tabs is looking at you. You know who I mean!). You shouldn’t need to jump through too many hoops, but use memoization or association (which are O(1) or O(log n)) rather than “just” looping through the list (which is O(n)).
  • Other than that, don’t over-optimize things unless the code is known to be hot/performance-sensitive.
    • As an example, we don’t, as a rule, use for (var i; i < ary.length; i++) style “raw” array loops, instead preferring the more readable for (let item of ary), even though that is slightly less performant.

Security

  • When in doubt, ask the security team, and/or #security on slack.
  • Take care when communicating between processes or with web content. Specifically:
    • We can’t trust web content.
    • We can’t trust web content processes (!). Any information you get via IPC (JSActor messages or similar) could be completely bogus. Use information from the parent process (the CanonicalBrowsingContext and so on) to make security decisions wherever possible.
    • As a corollary, if you have code that wants to navigate or interact with web content, do it entirely within the content process, rather than passing e.g. URIs or similar information to the parent and expecting it to navigate for you. This avoids exposing APIs to (potentially compromised) content processes that let them navigate arbitrarily - the “basic” APIs for that (document.location and so on) will be secured by Gecko itself, and we want to reuse that infrastructure as much as possible.
    • Do not load untrusted content (ie content from the web) in the parent process.
  • XSS and markup related advice:
    • Avoid inline event handlers wherever possible.
    • All about: pages must have a Content Security Policy (CSP). Use one that prevents inline styles and inline script.
    • Do not use innerHTML.
    • Gecko has built in sanitizer APIs - if you have to deal with untrusted HTML, see nsIParserUtils. Do NOT hand-roll sanitizing inputs.
  • Other vectors to take into account:
    • URLs are malleable and not a good way of identifying an origin. Use nsIPrincipal objects. You’ll need this to deal correctly with blob URIs, about:blank, and data URIs.
    • We can’t assume that for something.foo.sometld, something is a subdomain of foo, or that foo.sometld is the “top” domain. Some TLDs (.co.uk and .org.uk and so on are an obvious example, but github.io and s3.dualstack.ap-northeast-1.amazonaws.com, too!) have individually controlled subdomains. Use nsIEffectiveTLDService to work out what the “top” domain is. Do not use manual string manipulation.
    • Spoofing: where an attacker tries to pretend to the user they’re on a different website, usually by overlaying content or markup over the address bar or other trusted UI, or using full screen or similar tricks.
    • Clickjacking/keyjacking: where an attacker encourages users to click or hit keys repeatedly (“win $50 if you hook a duck by clicking this button really fast”), and uses that to bypass security warnings. Typical defence: delay enabling buttons on security-critical dialogs - there’s even a helper for this.
    • Crypto: do not make up your own cryptography, random number generator, password/key management or similar. Talk to experts (some of them work at Mozilla)!

Testing

  • All patches must have automated tests where possible and practical.
    • When writing tests, be sure to see that you’ve seen your test fail. This helps to avoid scenarios where a test always passes even when it shouldn’t.
    • There are some patches where it may be appropriate not to have tests, particularly ones that only touch documentation, styling (CSS/images), or test-only changes.
    • For situations where you can’t write tests, such as with features that interact with the operating system in ways we can’t verify automatically, leave a comment explaining why to the reviewer. It is likely going to be the first question they ask and they should know when one of these situations applies or may know alternate ways to write the test.
  • If you’ve pushed to try, leaving a link to the try push on Phabricator can help avoid duplicating effort (Note: reviewers are not expected to create try pushes by default). If there are unclear test failures that may or may not be intermittent, your reviewer can help work out what is happening.

Documentation

  • Ideally, code should be readable without explanation. Where documentation is required, use code comments for individual pieces of code, and the extended commit message (i.e. the second/third/nth lines of the commit message) to describe the high-level goal of your change.
  • A guideline for code comments is to add them in cases where they provide additional context for why a change is being made, but to avoid adding them if the comment only restates what the code is doing.
  • If the reviewer asks for explanations, this is often a sign that the code should be simplified, it needs more code comments, or the approach in the patch is not right. Prefer code and/or comment changes over communicating only in Phabricator - so that future readers of the code have the same context.
  • Ensure that any existing Firefox Source Docs material is also updated to reflect the change.

Commandeering patches

Patches should only be commandeered by agreement with the original patch author or if the author cannot be expected to respond in a timely fashion (on vacation or sick leave or no longer active in the project).

If you do need to commandeer a patch you can preserve the original author with git commit --amend --author="Other Person " when amending the original commit.

Community Participation Guidelines

Please remember to always abide by the Community Participation Guidelines.

Be generous and inclusive. Always assume good intentions, even where there is a disagreement during the course of the review.

FAQ

What is a Nit?

A nit is a minor defect. This could be a typo or a small issue. These are usually the kind of things that would not result in a “request for changes”, but they should be called out and it’s expected that they would be addressed by the patch author before the patch lands.

How do I file a bug for new lint rules?

If you have an idea for an eslint (JS) or stylelint (CSS) rule you can file a bug here if a more specific component isn’t a better fit.

Further Reading


Browser Docs Index (`browser/docs/index.rst`)

================= Firefox Front-end

This is the documentation for the code powering the Firefox Desktop front-end.

.. toctree::
:maxdepth: 2

how_to/index
urlbar/index
BrowserUsageTelemetry
FrontendCodeReviewBestPractices
CommandLineParameters
BrowserStartup
CategoryManagerIndirection
components/customizableui/docs/index
components/enterprisepolicies/docs/index
components/taskbartabs/docs/index
extensions/formautofill/docs/index
extensions/newtab/docs/index
components/aboutwelcome/docs/index
installer/windows/installer/index
components/attribution/docs/index
/toolkit/mozapps/defaultagent/default-browser-agent/index
components/migration/docs/index
components/pagedata/docs/index
places/index
components/asrouter/docs/index
search/index
base/tabbrowser/index
touchbar/index
components/uitour/docs/index
branding/docs/index
components/storybook/docs/README.storybook.stories
components/storybook/docs/README.reusable-widgets.stories
components/storybook/docs/README.other-widgets.stories
components/storybook/docs/README.lit-guide.stories
components/storybook/docs/README.xul-and-html.stories
components/storybook/docs/README.figma-code-connect.stories
/toolkit/themes/shared/design-system/docs/README.design-tokens.stories
components/backup/docs/index
components/sidebar/docs/index
components/mozcachedohttp/docs/index


Browser Docs Overview (`browser/docs/overview.rst`)

Firefox for Desktop

Desktop architecture

One of the keys to understanding how Firefox is architected is to know that Gecko is used to render
both web content as well as the UI of the browser. This means that, to a large extent, the UI of
Firefox is made using web technologies like HTML, CSS, and JavaScript. For example, the document
chrome://browser/content/browser.xhtml is the markup for a single Firefox browser window. You
can think of it almost like index.html for a webpage.

The decision to use Gecko for rendering the UI was made during an era when HTML was not yet
expressive enough or sufficient to build desktop UIs. A different markup language,
XUL <https://en.wikipedia.org/wiki/XUL>_, was developed for that purpose instead, which Gecko also
knows how to interpret. Since that time, HTML and CSS has evolved to the point where XUL is not
strictly necessary for most use-cases. Where possible, we have been gradually migrating our UI to
use less XUL and more standard HTML and CSS.

Reusable UI Widgets

Many of the UI widgets in use in the user interface are built as web components that can be reused.

:ref:Read more <Reusable UI widgets>

Tabbrowser

The tabbrowser component manages the tabs in a browser window.

:ref:Read more <tabbrowser>

Address Bar

The address bar (varyingly also referred to as the Awesome Bar, or Quantum Bar) handles users
entering web addresses including a popup with suggestions from various sources including history,
bookmarks and search engines.

:ref:Read more <Address Bar>

The search service manages the list of search engines available in the address bar.

:ref:Read more <Search>

Places

The places component includes the database that stores history and bookmarks as well as a set of UI
components that present those to the user.

:ref:Read more

Firefox Sync and Application Services

Application services includes the sync engines and Firefox Accounts integration.

:ref:Read more <Services>

Developer Tools

The developer tools support web developers when building webpages but as the Firefox UI is itself
built using web technologies it is also possible to use the developer tools to debug the Firefox UI.

:ref:Read more <Firefox DevTools Contributor Docs>

Browser Toolbox
###############

The Browser Toolbox is a way to launch the developer tools in a separate process so that they can be
used to debug the main browser UI.

:ref:Read more

Profiler
########

The Firefox Profiler is the way to measure the performance of your code. Go to
profiler.firefox.com <https://profiler.firefox.com>__ to enable the button in Firefox and record a
performance profile. These profiles can be uploaded and shared. It can identify slow parts of the
code, and reveal the underlying behavior of how code runs.

Installer

The Windows installer for Firefox is built with NSIS. There are currently no installers for other
operating systems.

:ref:Read more

Application Update

Application Update is responsible for requesting available updates from the update servers,
downloading them, verifying their integrity and then ultimately installing them. A binary patch tool
(bsdiff) is used to reduce the size of update files and update files are delivered in the
bespoke mar (Mozilla ARchive) format.

:ref:Read more <Application Update>


Build Docs Build Overview (`build/docs/build-overview.rst`)

.. _build_overview:

===================== Build System Overview

This document provides an overview on how the build system works. It is
targeted at people wanting to learn about internals of the build system.
It is not meant for persons who casually interact with the build system.
That being said, knowledge empowers, so consider reading on.

The build system is composed of many different components working in
harmony to build the source tree. We begin with a graphic overview.

.. graphviz::

digraph build_components {
rankdir="LR";
"configure" -> "config.status" -> "build backend" -> "build output"
}

Phase 1: Configuration

Phase 1 centers around the configure script, which is a bash shell script.
The file is generated from a file called configure.in which is written in M4
and processed using Autoconf 2.13 to create the final configure script.
You don't have to worry about how you obtain a configure file: the build
system does this for you.

The primary job of configure is to determine characteristics of the system
and compiler, apply options passed into it, and validate everything looks OK to
build. The primary output of the configure script is an executable file
in the object directory called config.status. configure also produces
some additional files (like autoconf.mk). However, the most important file
in terms of architecture is config.status.

The existence of a config.status file may be familiar to those who have worked
with Autoconf before. However, Mozilla's config.status is different from almost
any other config.status you've ever seen: it's written in Python! Instead of
having our configure script produce a shell script, we have it generating
Python.

Now is as good a time as any to mention that Python is prevalent in our build
system. If we need to write code for the build system, we do it in Python.
That's just how we roll. For more, see :ref:python.

config.status contains 2 parts: data structures representing the output of
configure and a command-line interface for preparing/configuring/generating
an appropriate build backend. (A build backend is merely a tool used to build
the tree - like GNU Make or Tup). These data structures essentially describe
the current state of the system and what the existing build configuration looks
like. For example, it defines which compiler to use, how to invoke it, which
application features are enabled, etc. You are encouraged to open up
config.status to have a look for yourself!

Once we have emitted a config.status file, we pass into the realm of
phase 2.

Phase 2: Build Backend Preparation and the Build Definition

Once configure has determined what the current build configuration is,
we need to apply this to the source tree so we can actually build.

What essentially happens is the automatically-produced config.status Python
script is executed as soon as configure has generated it. config.status
is charged with the task of tell a tool how to build the tree. To do this,
config.status must first scan the build system definition.

The build system definition consists of various moz.build files in the tree.
There is roughly one moz.build file per directory or per set of related directories.
Each moz.build files defines how its part of the build config works. For
example it says I want these C++ files compiled or look for additional
information in these directories.
config.status starts with the moz.build
file from the root directory and then descends into referenced moz.build
files by following DIRS variables or similar.

As the moz.build files are read, data structures describing the overall
build system definition are emitted. These data structures are then fed into a
build backend, which then performs actions, such as writing out files to
be read by a build tool. e.g. a make backend will write a
Makefile.

When config.status runs, you'll see the following output::

Reticulating splines...
Finished reading 1096 moz.build files into 1276 descriptors in 2.40s
Backend executed in 2.39s
2188 total backend files. 0 created; 1 updated; 2187 unchanged
Total wall time: 5.03s; CPU time: 3.79s; Efficiency: 75%

What this is saying is that a total of 1096 moz.build files were read.
Altogether, 1276 data structures describing the build configuration were
derived from them. It took 2.40s wall time to just read these files and
produce the data structures. The 1276 data structures were fed into the
build backend which then determined it had to manage 2188 files derived
from those data structures. Most of them already existed and didn't need
changed. However, 1 was updated as a result of the new configuration.
The whole process took 5.03s. Although, only 3.79s was in
CPU time. That likely means we spent roughly 25% of the time waiting on
I/O.

For more on how moz.build files work, see :ref:mozbuild-files.

Phase 3: Invocation of the Build Backend

When most people think of the build system, they think of phase 3. This is
where we take all the code in the tree and produce Firefox or whatever
application you are creating. Phase 3 effectively takes whatever was
generated by phase 2 and runs it. Since the dawn of Mozilla, this has been
make consuming Makefiles. However, with the transition to moz.build files,
you may soon see non-Make build backends, such as Tup or Visual Studio.

When building the tree, most of the time is spent in phase 3. This is when
header files are installed, C++ files are compiled, files are preprocessed, etc.


Build Docs Build Targets (`build/docs/build-targets.rst`)

.. _build_targets:

============= Build Targets

When you build with mach build, there are some special targets that can be
built. This page attempts to document them.

Partial Tree Targets

The targets in this section only build part of the tree. Please note that
partial tree builds can be unreliable. Use at your own risk.

export
Build the export tier. The export tier builds everything that is
required for C/C++ compilation. It stages all header files, processes
IDLs, etc.

compile
Build the compile tier. The compile tier compiles all C/C++ files.

libs
Build the libs tier. The libs tier performs linking and performs
most build steps which aren't related to compilation.

tools
Build the tools tier. The tools tier mostly deals with supplementary
tools and compiled tests. It will link tools against libXUL, including
compiled test binaries.

binaries:
Recompiles and relinks C/C++ files. Only works after a complete normal
build, but allows for much faster rebuilds of C/C++ code. For performance
reasons, however, it skips nss, nspr, icu and ffi. This is targeted to
improve local developer workflow when touching C/C++ code.

install-manifests
Process install manifests. Install manifests handle the installation of
files into the object directory.

Unless NO_REMOVE=1 is defined in the environment, files not accounted
in the install manifests will be deleted from the object directory.

install-tests
Processes the tests install manifest.

Common Actions

The targets in this section correspond to common build-related actions. Many
of the actions in this section are effectively frontends to shell scripts.
These actions will likely all be replaced by mach commands someday.

buildsymbols
Create a symbols archive for the current build.

This must be performed after a successful build.

check
Run build system tests.


Build Docs Chrome Registration (`build/docs/chrome-registration.rst`)

Chrome Registration

What is chrome?

Chrome is the set of user interface elements of the
application window that are outside the window's content area. Toolbars,
menu bars, progress bars, and window title bars are all examples of
elements that are typically part of the chrome.

chrome.manifest files are used to register XPCOM components and sources for the chrome protocol.
Every application supplies a root chrome.manifest file that Mozilla reads on startup.

Chrome providers

A supplier of chrome for a given window type (e.g., for the browser
window) is called a chrome provider. The providers work together to
supply a complete set of chrome for a particular window, from the images
on the toolbar buttons to the files that describe the text, content, and
appearance of the window itself.

There are three basic types of chrome providers:

Content
The main source file for a window description comes from the content
provider, and it can be any file type viewable from within Mozilla.
It will typically be a XUL file, since XUL is designed for describing
the contents of windows and dialogs. The JavaScript files that define
the user interface are also contained within the content packages.

Locale
Localizable applications keep all their localized information in
locale providers and Fluent FTL files, which are handled separately.
This allows translators to plug in a different
chrome package to translate an application without altering the rest
of the source code. In a chrome provider, localizable files are mostly
Java-style properties files.
Skin
A skin provider is responsible for providing a complete set of files
that describe the visual appearance of the chrome. Typically a skin
provider will provide CSS files and
images.

The chrome registry

The Gecko runtime maintains a service known as the chrome registry that
provides mappings from chrome package names to the physical location of
chrome packages on disk.

This chrome registry is configurable and persistent, and thus a user can
install different chrome providers, and select a preferred skin and
locale. This is accomplished through xpinstall and the extension
manager.

In order to inform the chrome registry of the available chrome, a text
manifest is used: this manifest is "chrome.manifest" in the root of an
extension, or theme, or XULRunner application.

The plaintext chrome manifests are in a simple line-based format. Each
line is parsed individually; if the line is parsable the chrome registry
takes the action identified by that line, otherwise the chrome registry
ignores that line (and prints a warning message in the runtime error
console).

.. code:: text

locale packagename localename path/to/files
skin packagename skinname path/to/files

.. note::

The characters @ # ; : ? / are not allowed in the
packagename.

Manifest instructions

comments

text
.. code:: text

   # this line is a comment - you can put here whatever you want

A line is a comment if it begins with the character '#'. Any following
character in the same line is ignored.

manifest

::

manifest subdirectory/foo.manifest [flags]

This will load a secondary manifest file. This can be useful for
separating component and chrome registration instructions, or separate
platform-specific registration data.

component

text
::

   component {00000000-0000-0000-0000-000000000000} components/mycomponent.js [flags]

Informs Mozilla about a component CID implemented by an XPCOM component
implemented in JavaScript (or another scripting language, if
applicable). The ClassID {0000...} must match the ClassID implemented by
the component. To generate a unique ClassID, use a UUID generator
program or site.

contract
~~~~~~~~

::

   contract @foobar/mycontract;1 {00000000-0000-0000-0000-000000000000} [flags]

Maps a contract ID (a readable string) to the ClassID for a specific
implementation. Typically a contract ID will be paired with a component
entry immediately preceding.

category
~~~~~~~~

::

   category category entry-name value [flags]

Registers an entry in the `category manager`. The
specific format and meaning of category entries depend on the category.

content
~~~~~~~

A content package is registered with the line:

::

   content packagename uri/to/files/ [flags]

This will register a location to use when resolving the URI
``chrome://packagename/content/...``. The URI may be absolute or
relative to the location of the manifest file. Note: it must end with a
'/'.

locale
~~~~~~

A locale package is registered with the line:

.. code:: text

   locale packagename localename uri/to/files/ [flags]

This will register a locale package when resolving the URI
chrome://*packagename*/locale/... . The *localename* is usually a plain
language identifier "en" or a language-country identifier "en-US". If
more than one locale is registered for a package, the chrome registry
will select the best-fit locale using the user's preferences.

skin
~~~~

A skin package is registered with the line:

.. code:: text

   skin packagename skinname uri/to/files/ [flags]

This will register a skin package when resolving the URI
chrome://packagename/skin/... . The *skinname* is an opaque string
identifying an installed skin. If more than one skin is registered for a
package, the chrome registry will select the best-fit skin using the
user's preferences.

style
~~~~~

Style overlays (custom CSS which will be applied to a chrome page) are
registered with the following syntax:

.. code:: text

   style chrome://URI-to-style chrome://stylesheet-URI [flags]

override
~~~~~~~~

In some cases an extension or embedder may wish to override a chrome
file provided by the application or XULRunner. In order to allow for
this, the chrome registration manifest allows for "override"
instructions:

.. code:: text

   override chrome://package/type/original-uri.whatever new-resolved-URI [flags]

Note: overrides are not recursive (so overriding
chrome://foo/content/bar/ with file:///home/john/blah/ will not usually
do what you want or expect it to do). Also, the path inside overridden
files is relative to the overridden path, not the original one (this can
be annoying and/or useful in CSS files, for example).

.. _chrome_manifest_resource:

resource
~~~~~~~~

Aliases can be created using the ``resource`` instruction:

.. code:: text

   resource aliasname uri/to/files/ [flags]

This will create a mapping for ``resource://<aliasname>/`` URIs to the
path given.

.. note::

   **Note:** There are no security restrictions preventing web content
   from including content at resource: URIs, so take care what you make
   visible there.

Manifest flags
--------------

Manifest lines can have multiple, space-delimited flags added at the end
of the registration line. These flags mark special attributes of chrome
in that package, or limit the conditions under which the line is used.

application

Extensions may install into multiple applications. There may be chrome
registration lines which only apply to one particular application. The
flag

.. code:: text

application=app-ID

indicates that the instruction should only be applied if the extension
is installed into the application identified by app-ID. Multiple
application flags may be included on a single line, in which case the
line is applied if any of the flags match.

This example shows how a different overlay can be used for different
applications:

::

overlay chrome://browser/content/browser.xul chrome://myaddon/content/ffOverlay.xul application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
overlay chrome://messenger/content/mailWindowOverlay.xul chrome://myaddon/content/tbOverlay.xul application={3550f703-e582-4d05-9a08-453d09bdfdc6}
overlay chrome://songbird/content/xul/layoutBaseOverlay.xul chrome://myaddon/content/sbOverlay.xul application=[email protected]

appversion

text
Extensions may install into multiple versions of an application. There
may be chrome registration lines which only apply to a particular
application version. The flag

.. code:: text

   appversion=version
   appversion<version
   appversion<=version
   appversion>version
   appversion>=version

indicates that the instruction should only be applied if the extension
is installed into the application version identified. Multiple
``appversion`` flags may be included on a single line, in which case the
line is applied if any of the flags match. The version string must
conform to the `Toolkit version format`.

platformversion

When supporting more then one application, it is often more convenient
for an extension to specify which Gecko version it is compatible with.
This is particularly true for binary components. If there are chrome
registration lines which only apply to a particular Gecko version, the
flag

.. code:: text

platformversion=version
platformversion<version
platformversion<=version
platformversion>version
platformversion>=version

indicates that the instruction should only be applied if the extension
is installed into an application using the Gecko version identified.
Multiple platformversion flags may be included on a single line, in
which case the line is applied if any of the flags match.

contentaccessible

text
Chrome resources can no longer be referenced from within <img>,
<script>, or other elements contained in, or added to, content that was
loaded from an untrusted source. This restriction applies to both
elements defined by the untrusted source and to elements added by
trusted extensions. If such references need to be explicitly allowed,
set the ``contentaccessible`` flag to ``yes`` to obtain the behavior
found in older versions of Firefox. See
`bug 436989 <https://bugzilla.mozilla.org/show_bug.cgi?id=436989>`__.

The ``contentaccessible`` flag applies only to content packages: it is
not recognized for locale or skin registration. However, the matching
locale and skin packages will also be exposed to content.

**n.b.:** Because older versions of Firefox do not understand the
``contentaccessible`` flag, any extension designed to work with both
Firefox 3 and older versions of Firefox will need to provide a fallback.
For example:

::

   content packagename chrome/path/
   content packagename chrome/path/ contentaccessible=yes

os
~~

Extensions (or themes) may offer different features depending on the
operating system on which Firefox is running. The value is compared to
the value of `OS_TARGET` for the platform.

.. code:: text

   os=WINNT
   os=Darwin

osversion
~~~~~~~~~

An extension or theme may need to operate differently depending on which
version of an operating system is running. For example, a theme may wish
to adopt a different look on Mac OS X 10.5 than 10.4:

.. code:: text

   osversion>=10.5

abi
~~~

If a component is only compatible with a particular ABI, it can specify
which ABI/OS by using this directive. The value is taken from the
`nsIXULRuntime` OS and
XPCOMABI values (concatenated with an underscore). For example:

::

   binary-component component/myLib.dll abi=WINNT_x86-MSVC
   binary-component component/myLib.so abi=Linux_x86-gcc3

platform (Platform-specific packages)

Some packages are marked with a special flag indicating that they are
platform specific. Some parts of content, skin, and locales may be
different based on the platform being run. These packages contain three
different sets of files, for Windows and OS/2, Macintosh, and Unix-like
platforms. For example, the order of the "OK" and "Cancel" buttons in a
dialog is different, as well as the names of some items.

The "platform" modifier is only parsed for content registration; it is
not recognized for locale or skin registration. However, it applies to
content, locale, and skin parts of the package, when specified.

process

text
In electrolysis registrations can be set to only apply in either the
main process or any content processes. The "process" flag selects
between these two. This can allow you to register different components
for the same contract ID or ensure a component can only be loaded in the
main process.

::

   component {09543782-22b1-4a0b-ba07-9134365776ee} maincomponent.js process=main
   component {98309951-ac89-4642-afea-7b2b6216bcef} contentcomponent.js process=content

Example chrome manifest
-----------------------

.. list-table::
   :widths: 20 20 20 20


   *  - type
      - engine
      - language
      - url
   *  - content
      - branding
      - browser/content/branding/
      - contentaccessible=yes
   *  - content
      - browser
      - browser/content/browser/
      - contentaccessible=yes
   *  - override
      -
      - chrome://global/content/license.html
      - chrome://browser/content/license.html
   *  - resource
      - payments
      - browser/res/payments/
      -
   *  - skin
      - browser
      - classic/1.0 browser/skin/classic/browser/
      -
   *  - locale
      - branding
      - en-US
      - en-US/locale/branding/
   *  - locale
      - browser
      - en-US
      - en-US/locale/browser/
   *  - locale
      - browser-region
      - en-US
      - en-US/locale/browser-region/

---

### Build Docs Cppeclipse (`build/docs/cppeclipse.rst`)

.. _build_cppeclipse:

=====================
Cpp Eclipse Projects
=====================

For additional information on using Eclipse CDT see
`the MDN page
<https://developer.mozilla.org/en-US/docs/Eclipse_CDT>`_.

The build system contains alpha support for generating C++ Eclipse
project files to aid with development.

Please report bugs to bugzilla and make them depend on bug 973770.

To generate a C++ Eclipse project files, you'll need to have a fully
built tree::

   mach build

Then, simply generate the C++ Eclipse build backend::

   mach build-backend -b CppEclipse

If all goes well, the path to the generated workspace should be
printed.

To use the generated C++ Eclipse project files, you'll need to
have a Eclipse CDT 8.3 (We plan to follow the latest Eclipse release)
`Eclipse CDT plugin
<https://www.eclipse.org/cdt/>`_
installed. You can then import all the projects into Eclipse using
*File > Import ... > General > Existing Projects into Workspace*
-only- if you have not ran the background indexer.

Updating Project Files
======================

As you pull and update the source tree, your C++ Eclipse files may
fall out of sync with the build configuration. The tree should still
build fine from within Eclipse, but source files may be missing and in
rare circumstances Eclipse's index may not have the proper build
configuration.

To account for this, you'll want to periodically regenerate the
C++ Eclipse project files. You can do this by running ``mach build
&& mach build-backend -b CppEclipse`` from the
command line.

Currently, regeneration rewrites the original project files. **If
you've made any customizations to the projects, they will likely get
overwritten.** We would like to improve this user experience in the
future.

---

### Build Docs Cross Compile (`build/docs/cross-compile.rst`)

=================
Cross-compilation
=================

If you are planning to perform cross-compilation e.g. for Linux/Aarch64, you
will probably want to use experimental feature ``--enable-bootstrap`` in your
``.mozconfig``. Then, you just have to specify the the target arch, after which
the build system will automatically set up the sysroot.

For example, cross-compiling for Linux/Aarch64:

.. code-block:: text

    ac_add_options --target=aarch64-linux-gnu
    ac_add_options --enable-bootstrap

---

### Build Docs Defining Binaries (`build/docs/defining-binaries.rst`)

.. _defining_binaries:

======================================
Defining Binaries for the Build System
======================================

One part of what the build system does is compile C/C++ and link the resulting
objects to produce executables and/or libraries. This document describes the
basics of defining what is going to be built and how. All the following
describes constructs to use in moz.build files.


Source files
============

Source files to be used in a given directory are registered in the ``SOURCES``
and ``UNIFIED_SOURCES`` variables. ``UNIFIED_SOURCES`` have a special behavior
in that they are aggregated by batches of 16, requiring, for example, that there
are no conflicting variables in those source files.

``SOURCES`` and ``UNIFIED_SOURCES`` are lists which must be appended to, and
each append requires the given list to be alphanumerically ordered.

.. code-block:: python

   UNIFIED_SOURCES += [
       'FirstSource.cpp',
       'SecondSource.cpp',
       'ThirdSource.cpp',
   ]

   SOURCES += [
       'OtherSource.cpp',
   ]

``SOURCES`` and ``UNIFIED_SOURCES`` can contain a mix of different file types,
for C, C++, and Objective C.


Static Libraries
================

To build a static library, other than defining the source files (see above), one
just needs to define a library name with the ``Library`` template.

.. code-block:: python

   Library('foo')

The library file name will be ``libfoo.a`` on UNIX systems and ``foo.lib`` on
Windows.

If the static library needs to aggregate other static libraries, a list of
``Library`` names can be added to the ``USE_LIBS`` variable. Like ``SOURCES``, it
requires the appended list to be alphanumerically ordered.

.. code-block:: python

   USE_LIBS += ['bar', 'baz']

If there are multiple directories containing the same ``Library`` name, it is
possible to disambiguate by prefixing with the path to the wanted one (relative
or absolute):

.. code-block:: python

   USE_LIBS += [
       '/path/from/topsrcdir/to/bar',
       '../relative/baz',
   ]

Note that the leaf name in those paths is the ``Library`` name, not an actual
file name.

Note that currently, the build system may not create an actual library for
static libraries. It is an implementation detail that shouldn't need to be
worried about.

As a special rule, ``USE_LIBS`` is allowed to contain references to shared
libraries. In such cases, programs and shared libraries linking this static
library will inherit those shared library dependencies.


Intermediate (Static) Libraries
===============================

In many cases in the tree, static libraries are built with the only purpose
of being linked into another, bigger one (like libxul). Instead of adding all
required libraries to ``USE_LIBS`` for the bigger one, it is possible to tell
the build system that the library built in the current directory is meant to
be linked to that bigger library, with the ``FINAL_LIBRARY`` variable.

.. code-block:: python

   FINAL_LIBRARY = 'xul'

The ``FINAL_LIBRARY`` value must match a unique ``Library`` name somewhere
in the tree.

As a special rule, those intermediate libraries don't need a ``Library`` name
for themselves.


Shared Libraries
================

Sometimes, we want shared libraries, a.k.a. dynamic libraries. Such libraries
are defined similarly to static libraries, using the ``SharedLibrary`` template
instead of ``Library``.

.. code-block:: python

   SharedLibrary('foo')

When this template is used, no static library is built. See further below to
build both types of libraries.

With a ``SharedLibrary`` name of ``foo``, the library file name will be
``libfoo.dylib`` on OSX, ``libfoo.so`` on ELF systems (Linux, etc.), and
``foo.dll`` on Windows. On Windows, there is also an import library named
``foo.lib``, used on the linker command line. ``libfoo.dylib`` and
``libfoo.so`` are considered the import library name for, resp. OSX and ELF
systems.

On OSX, one may want to create a special kind of dynamic library: frameworks.
This is done with the ``Framework`` template.

.. code-block:: python

   Framework('foo')

With a ``Framework`` name of ``foo``, the framework file name will be ``foo``.
This template however affects the behavior on all platforms, so it needs to
be set only on OSX.


Executables
===========

Executables, a.k.a. programs, are, in the simplest form, defined with the
``Program`` template.

.. code-block:: python

   Program('foobar')

On UNIX systems, the executable file name will be ``foobar``, while on Windows,
it will be ``foobar.exe``.

Like static and shared libraries, the build system can be instructed to link
libraries to the executable with ``USE_LIBS``, listing various ``Library``
names.

In some cases, we want to create an executable per source file in the current
directory, in which case we can use the ``SimplePrograms`` template

.. code-block:: python

   SimplePrograms([
       'FirstProgram',
       'SecondProgram',
   ])

Contrary to ``Program``, which requires corresponding ``SOURCES``, when using
``SimplePrograms``, the corresponding ``SOURCES`` are implied. If the
corresponding ``sources`` have an extension different from ``.cpp``, it is
possible to specify the proper extension:

.. code-block:: python

   SimplePrograms([
       'ThirdProgram',
       'FourthProgram',
   ], ext='.c')

Please note this construct was added for compatibility with what already lives
in the mozilla tree ; it is recommended not to add new simple programs with
sources with a different extension than ``.cpp``.

Similar to ``SimplePrograms``, is the ``CppUnitTests`` template, which defines,
with the same rules, C++ unit tests programs. Like ``SimplePrograms``, it takes
an ``ext`` argument to specify the extension for the corresponding ``SOURCES``,
if it's different from ``.cpp``.


Linking with system libraries
=============================

Programs and libraries usually need to link with system libraries, such as a
widget toolkit, etc. Those required dependencies can be given with the
``OS_LIBS`` variable.

.. code-block:: python

   OS_LIBS += [
       'foo',
       'bar',
   ]

This expands to ``foo.lib bar.lib`` when building with MSVC, and
``-lfoo -lbar`` otherwise.

For convenience with ``pkg-config``, ``OS_LIBS`` can also take linker flags
such as ``-L/some/path`` and ``-llib``, such that it is possible to directly
assign ``LIBS`` variables from ``CONFIG``, such as:

.. code-block:: python

   OS_LIBS += CONFIG['MOZ_PANGO_LIBS']

(assuming ``CONFIG['MOZ_PANGO_LIBS']`` is a list, not a string)

Like ``USE_LIBS``, this variable applies to static and shared libraries, as
well as programs.


Libraries from third party build system
=======================================

Some libraries in the tree are not built by the moz.build-governed build
system, and there is no ``Library`` corresponding to them.

However, ``USE_LIBS`` allows to reference such libraries by giving a full
path (like when disambiguating identical ``Library`` names). The same naming
rules apply as other uses of ``USE_LIBS``, so only the library name without
prefix and suffix shall be given.

.. code-block:: python

   USE_LIBS += [
       '/path/from/topsrcdir/to/third-party/bar',
       '../relative/third-party/baz',
   ]

Note that ``/path/from/topsrcdir/to/third-party`` and
``../relative/third-party/baz`` must lead under a subconfigured directory (a
directory with an AC_OUTPUT_SUBDIRS in configure.in), or ``security/nss``.


Building both static and shared libraries
=========================================

When both types of libraries are required, one needs to set both
``FORCE_SHARED_LIB`` and ``FORCE_STATIC_LIB`` boolean variables.

.. code-block:: python

   FORCE_SHARED_LIB = True
   FORCE_STATIC_LIB = True

But because static libraries and Windows import libraries have the same file
names, either the static or the shared library name needs to be different
than the name given to the ``Library`` template.

The ``STATIC_LIBRARY_NAME`` and ``SHARED_LIBRARY_NAME`` variables can be used
to change either the static or the shared library name.

.. code-block:: python

  Library('foo')
  STATIC_LIBRARY_NAME = 'foo_s'

With the above, on Windows, ``foo_s.lib`` will be the static library,
``foo.dll`` the shared library, and ``foo.lib`` the import library.

In some cases, for convenience, it is possible to set both
``STATIC_LIBRARY_NAME`` and ``SHARED_LIBRARY_NAME``. For example:

.. code-block:: python

  Library('mylib')
  STATIC_LIBRARY_NAME = 'mylib_s'
  SHARED_LIBRARY_NAME = CONFIG['SHARED_NAME']

This allows to use ``mylib`` in the ``USE_LIBS`` of another library or
executable.

When referring to a ``Library`` name building both types of libraries in
``USE_LIBS``, the shared library is chosen to be linked. But sometimes,
it is wanted to link the static version, in which case the ``Library`` name
needs to be prefixed with ``static:`` in ``USE_LIBS``

::

   a/moz.build:
      Library('mylib')
      FORCE_SHARED_LIB = True
      FORCE_STATIC_LIB = True
      STATIC_LIBRARY_NAME = 'mylib_s'
   b/moz.build:
      Program('myprog')
      USE_LIBS += [
          'static:mylib',
      ]


Miscellaneous
=============

The ``SONAME`` variable declares a "shared object name" for the library. It
defaults to the ``Library`` name or the ``SHARED_LIBRARY_NAME`` if set. When
linking to a library with a ``SONAME``, the resulting library or program will
have a dependency on the library with the name corresponding to the ``SONAME``
instead of the ``Library`` name. This only impacts ELF systems.

::

   a/moz.build:
      Library('mylib')
   b/moz.build:
      Library('otherlib')
      SONAME = 'foo'
   c/moz.build:
      Program('myprog')
      USE_LIBS += [
          'mylib',
          'otherlib',
      ]

On e.g. Linux, the above ``myprog`` will have DT_NEEDED markers for
``libmylib.so`` and ``libfoo.so`` instead of ``libmylib.so`` and
``libotherlib.so`` if there weren't a ``SONAME``. This means the runtime
requirement for ``myprog`` is ``libfoo.so`` instead of ``libotherlib.so``.


Gecko-related binaries
======================

Some programs or libraries are totally independent of Gecko, and can use the
above mentioned templates. Others are Gecko-related in some way, and may
need XPCOM linkage, mozglue. These things are tedious. A set of additional
templates exists to ease defining such programs and libraries. They are
essentially the same as the above mentioned templates, prefixed with "Gecko":

  - ``GeckoProgram``
  - ``GeckoSimplePrograms``
  - ``GeckoCppUnitTests``
  - ``GeckoSharedLibrary``
  - ``GeckoFramework``

All the Gecko-prefixed templates take the same arguments as their
non-Gecko-prefixed counterparts, and can take a few more arguments
for non-standard cases. See the definition of ``GeckoBinary`` in
build/gecko_templates.mozbuild for more details, but most usecases
should not require these additional arguments.

---

### Build Docs Defining Xpcom Components (`build/docs/defining-xpcom-components.rst`)

.. _defining_xpcom_components:

=========================
Defining XPCOM Components
=========================

This document explains how to write a :code:`components.conf` file. For
documentation on the idl format see :ref:`XPIDL`. For a tutorial on writing
a new XPCOM interface, see
:ref:`writing_xpcom_interface`.

Native XPCOM components are registered at build time, and compiled into static
data structures which allow them to be accessed with little runtime overhead.
Each module which wishes to register components must provide a manifest
describing each component it implements, its type, and how it should be
constructed.

Manifest files are Python data files registered in ``moz.build`` files in a
``XPCOM_MANIFESTS`` file list:

.. code-block:: python

    XPCOM_MANIFESTS += [
      'components.conf',
    ]

The files may define any of the following special variables:

.. code-block:: python

    # Optional: A function to be called once, the first time any component
    # listed in this manifest is instantiated.
    InitFunc = 'nsInitFooModule'
    # Optional: A function to be called at shutdown if any component listed in
    # this manifest has been instantiated.
    UnloadFunc = 'nsUnloadFooModule'

    # Optional: A processing priority, to determine how early or late the
    # manifest is processed. Defaults to 50. In practice, this mainly affects
    # the order in which unload functions are called at shutdown, with higher
    # priority numbers being called later.
    Priority = 10

    # Optional: A list of header files to include before calling init or
    # unload functions, or any legacy constructor functions.
    #
    # Any header path beginning with a `/` is loaded relative to the root of
    # the source tree, and must not rely on any local includes.
    #
    # Any relative header path must be exported.
    Headers = [
        '/foo/nsFooModule.h',
        'nsFoo.h',
    ]

    # A list of component classes provided by this module.
    Classes = [
        {
            # ...
        },
        # ...
    ]

    # A list of category registrations
    Categories = {
        'category': {
            'name': 'value',
            'other-name': ('value', ProcessSelector.MAIN_PROCESS_ONLY),
            # ...
        },
        # ...
    }

Class definitions may have the following properties:

``name`` (optional)
  If present, this component will generate an entry with the given name in the
  ``mozilla::components`` namespace in ``mozilla/Components.h``, which gives
  easy access to its CID, service, and instance constructors as (e.g.,)
  ``components::Foo::CID()``, ``components::Foo::Service()``, and
  ``components::Foo::Create()``, respectively.

``cid``
  A UUID string containing this component's CID, in the form
  ``'{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}'``.

``contract_ids`` (optional)
  A list of contract IDs to register for this class.

``categories`` (optional)
  A dict of category entries to register for this component's contract ID.
  Each key in the dict is the name of the category. Each value is either a
  string containing a single entry, or a list of entries.  Each entry is either
  a string name, or a dictionary of the form ``{'name': 'value', 'backgroundtasks':
  BackgroundTasksSelector.ALL_TASKS}``.  By default, category entries are registered
  for **no background tasks**: they have
  ``'backgroundtasks': BackgroundTasksSelector.NO_TASKS``.

``type`` (optional, default=``nsISupports``)
  The fully-qualified type of the class implementing this component. Defaults
  to ``nsISupports``, but **must** be provided if the ``init_method`` property
  is specified, or if neither the ``constructor`` nor ``legacy_constructor``
  properties are provided.

``headers`` (optional)
  A list of headers to include in order to call this component's constructor,
  in the same format as the global ``Headers`` property.

``init_method`` (optional)
  The name of a method to call on newly-created instances of this class before
  returning them. The method must take no arguments, and must return a
  ``nsresult``. If it returns failure, that failure is propagated to the
  ``getService`` or ``createInstance`` caller.

``constructor`` (optional)
  The fully-qualified name of a constructor function to call in order to
  create instances of this class. This function must be declared in one of the
  headers listed in the ``headers`` property, must take no arguments, and must
  return ``already_AddRefed`` where ``iface`` is the interface provided
  in the ``type`` property.

  This property is incompatible with ``legacy_constructor``.

``esModule`` (optional)
  If provided, must be the URL of a
  `JavaScript module <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules>`_
  which contains a JavaScript implementation of the component.
  The ``constructor`` property must contain the name of an exported
  function which can be constructed to create a new instance of the component.


``jsm`` (deprecated, optional)
  Do not use. Use ``esModule`` instead.

``legacy_constructor`` (optional)
  This property is deprecated, and should not be used in new code.

  The fully-qualified name of a constructor function to call in order to
  create instances of this class. This function must be declared in one of the
  headers listed in the ``headers`` property, and must have the signature
  ``nsresult(const nsID& aIID, void** aResult)``, and behave equivalently to
  ``nsIFactory::CreateInstance``.

  This property is incompatible with ``constructor``.

``singleton`` (optional, default=``False``)
  If true, this component's constructor is expected to return the same
  singleton for every call, and no ``mozilla::components::<name>::Create()``
  method will be generated for it.

``overridable`` (optional, default=``False``)
  If true, this component's contract ID is expected to be overridden by some
  tests, and its ``mozilla::components::<name>::Service()`` getter will
  therefore look it up by contract ID for every call. This component must,
  therefore, provide at least one contract ID in its ``contract_ids`` array.

  If false, the ``Service()`` getter will always retrieve the service based on
  its static data, and it cannot be overridden.

  Note: Enabling this option is expensive, and should not be done when it can
  be avoided, or when the getter is used by any hot code.

``external`` (optional, default=``False`` if any ``headers`` are provided, ``True`` otherwise)
  If true, a constructor for this component's ``type`` must be defined in
  another translation unit, using ``NS_IMPL_COMPONENT_FACTORY(type)``. The
  constructor must return an ``already_AddRefed<nsISupports>``, and will be
  used to construct instances of this type.

  This option should only be used in cases where the headers which define the
  component's concrete type cannot be easily included without local includes.

  Note: External constructors may not specify an ``init_method``, since the
  generated code will not have the necessary type information required to call
  it. This option is also incompatible with ``constructor`` and
  ``legacy_constructor``.

``processes`` (optional, default=``ProcessSelector.ANY_PROCESS``)
  An optional specifier restricting which types of process this component may
  be loaded in. This must be a property of ``ProcessSelector`` with the same
  name as one of the values in the ``Module::ProcessSelector`` enum.


Conditional Compilation
=======================

This manifest may run any appropriate Python code to customize the values of
the ``Classes`` array based on build configuration. To simplify this process,
the following globals are available:

``defined``
  A function which returns true if the given build config setting is defined
  and true.

``buildconfig``
  The ``buildconfig`` python module, with a ``substs`` property containing a
  dict of all available build substitutions.


Component Constructors
======================

There are several ways to define component constructors, which vary mostly
depending on how old the code that uses them is:

Class Constructors
------------------

This simplest way to define a component is to include a header defining a
concrete type, and let the component manager call that class's constructor:

.. rstcheck: ignore-languages=python
.. code-block:: python

  'type': 'mozilla::foo::Foo',
  'headers': ['mozilla/Foo.h'],

This is generally the preferred method of defining non-singleton constructors,
but may not be practicable for classes which rely on local includes for their
definitions.

Singleton Constructors
----------------------

Singleton classes are generally expected to provide their own constructor
function which caches a singleton instance the first time it is called, and
returns the same instance on subsequent calls. This requires declaring the
constructor in an included header, and implementing it in a separate source
file:

.. rstcheck: ignore-languages=python
.. code-block:: python

  'type': 'mozilla::foo::Foo',
  'headers': ['mozilla/Foo.h'],
  'constructor': 'mozilla::Foo::GetSingleton',

``Foo.h``

.. code-block:: cpp

    class Foo final : public nsISupports {
     public:
      static already_AddRefed<Foo> GetSingleton();
    };

``Foo.cpp``

.. code-block:: cpp

    already_AddRefed<Foo> Foo::GetSingleton() {
      // ...
    }

External Constructors
---------------------

For types whose headers can't easily be included, constructors can be defined
using a template specialization on an incomplete type:

.. rstcheck: ignore-languages=python
.. code-block:: python

  'type': 'mozilla::foo::Foo',
  'external: True,'

``Foo.cpp``

.. code-block:: cpp

    NS_IMPL_COMPONENT_FACTORY(Foo) {
      return do_AddRef(new Foo()).downcast<nsISupports>();
    }

Legacy Constructors
-------------------

These should not be used in new code, and are left as an exercise for the
reader.


Registering Categories
======================

Classes which need define category entries with the same value as their
contract ID may do so using the following:

.. rstcheck: ignore-languages=python
.. code-block:: python

    'contract_ids': ['@mozilla.org/foo;1'],
    'categories': {
        'content-policy': 'm-foo',
        'Gecko-Content-Viewers': ['image/jpeg', 'image/png'],
    },

This will define each of the following category entries:

* ``"content-policy"`` ``"m-foo",`` ``"@mozilla.org/foo;1"``
* ``"Gecko-Content-Viewers"`` ``"image/jpeg"`` ``"@mozilla.org/foo;1"``
* ``"Gecko-Content-Viewers"`` ``"image/png"`` ``"@mozilla.org/foo;1"``

Some category entries do not have a contract ID as a value. These entries can
be specified by adding to a global ``Categories`` dictionary:

.. code-block:: python

    Categories = {
        'update-timer': {
            'nsUpdateService': '@mozilla.org/updates/update-service;1,getService,background-update-timer,app.update.interval,43200,86400',
        }
    }

It is possible to limit these on a per-process basis by using a tuple as the
value:

.. code-block:: python

    Categories = {
        '@mozilla.org/streamconv;1': {
            '?from=gzip&to=uncompressed': ('', ProcessSelector.ALLOW_IN_SOCKET_PROCESS),
        }
    }

---

### Build Docs Environment Variables (`build/docs/environment-variables.rst`)

.. _environment_variables:

================================================
Environment Variables Impacting the Build System
================================================

Various environment variables have an impact on the behavior of the
build system. This document attempts to document them.

AUTOCLOBBER
   If defines, the build system will automatically clobber as needed.
   The default behavior is to print a message and error out when a
   clobber is needed.

   This variable is typically defined in a :ref:`mozconfig <mozconfig>`
   file via ``mk_add_options``.

REBUILD_CHECK
   If defined, the build system will print information about why
   certain files were rebuilt.

   This feature is disabled by default because it makes the build slower.

MACH_NO_TERMINAL_FOOTER
   If defined, the terminal footer displayed when building with mach in
   a TTY is disabled.

MACH_NO_FUNC_CACHE
   If defined, disables mach's persistent function result cache. This
   cache speeds up operations like configure by avoiding redundant
   expensive computations when input files haven't changed.

MACH_NO_WRITE_TIMES
   If defined, mach commands will not prefix output lines with the
   elapsed time since program start. This option is equivalent to
   passing ``--log-no-times`` to mach.

---

### Build Docs Files Metadata (`build/docs/files-metadata.rst`)

.. _mozbuild_files_metadata:

==============
Files Metadata
==============

:ref:`mozbuild-files` provide a mechanism for attaching metadata to
files. Essentially, you define some flags to set on a file or file
pattern. Later, some tool or process queries for metadata attached to a
file of interest and it does something intelligent with that data.

Defining Metadata
=================

Files metadata is defined by using the
:ref:`Files Sub-Context <mozbuild_subcontext_Files>` in ``moz.build``
files. e.g.::

    with Files('**/Makefile.in'):
        BUG_COMPONENT = ('Firefox Build System', 'General')

This working example says, *for all Makefile.in files in every directory
underneath this one - including this directory - set the Bugzilla
component to Firefox Build System :: General*.

For more info, read the
:ref:`docs on Files <mozbuild_subcontext_Files>`.

How Metadata is Read
====================

``Files`` metadata is extracted in :ref:`mozbuild_fs_reading_mode`.

Reading starts by specifying a set of files whose metadata you are
interested in. For each file, the filesystem is walked to the root
of the source directory. Any ``moz.build`` encountered during this
walking are marked as relevant to the file.

Let's say you have the following filesystem content::

   /moz.build
   /root_file
   /dir1/moz.build
   /dir1/foo
   /dir1/subdir1/foo
   /dir2/foo

For ``/root_file``, the relevant ``moz.build`` files are just
``/moz.build``.

For ``/dir1/foo`` and ``/dir1/subdir1/foo``, the relevant files are
``/moz.build`` and ``/dir1/moz.build``.

For ``/dir2``, the relevant file is just ``/moz.build``.

Once the list of relevant ``moz.build`` files is obtained, each
``moz.build`` file is evaluated. Root ``moz.build`` file first,
leaf-most files last. This follows the rules of
:ref:`mozbuild_fs_reading_mode`, with the set of evaluated ``moz.build``
files being controlled by filesystem content, not ``DIRS`` variables.

The file whose metadata is being resolved maps to a set of ``moz.build``
files which in turn evaluates to a list of contexts. For file metadata,
we only care about one of these contexts:
:ref:`Files <mozbuild_subcontext_Files>`.

We start with an empty ``Files`` instance to represent the file. As
we encounter a *files sub-context*, we see if it is appropriate to
this file. If it is, we apply its values. This process is repeated
until all *files sub-contexts* have been applied or skipped. The final
state of the ``Files`` instance is used to represent the metadata for
this particular file.

It may help to visualize this. Say we have 2 ``moz.build`` files::

    # /moz.build
    with Files('*.cpp'):
        BUG_COMPONENT = ('Core', 'XPCOM')

    with Files('**/*.js'):
        BUG_COMPONENT = ('Firefox', 'General')

    # /foo/moz.build
    with Files('*.js'):
        BUG_COMPONENT = ('Another', 'Component')

Querying for metadata for the file ``/foo/test.js`` will reveal 3
relevant ``Files`` sub-contexts. They are evaluated as follows:

1. ``/moz.build - Files('*.cpp')``. Does ``/*.cpp`` match
   ``/foo/test.js``? **No**. Ignore this context.
2. ``/moz.build - Files('**/*.js')``. Does ``/**/*.js`` match
   ``/foo/test.js``? **Yes**. Apply ``BUG_COMPONENT = ('Firefox', 'General')``
   to us.
3. ``/foo/moz.build - Files('*.js')``. Does ``/foo/*.js`` match
   ``/foo/test.js``? **Yes**. Apply
   ``BUG_COMPONENT = ('Another', 'Component')``.

At the end of execution, we have
``BUG_COMPONENT = ('Another', 'Component')`` as the metadata for
``/foo/test.js``.

One way to look at file metadata is as a stack of data structures.
Each ``Files`` sub-context relevant to a given file is applied on top
of the previous state, starting from an empty state. The final state
wins.

.. _mozbuild_files_metadata_finalizing:

Finalizing Values
=================

The default behavior of ``Files`` sub-context evaluation is to apply new
values on top of old. In most circumstances, this results in desired
behavior. However, there are circumstances where this may not be
desired. There is thus a mechanism to *finalize* or *freeze* values.

Finalizing values is useful for scenarios where you want to prevent
wildcard matches from overwriting previously-set values. This is useful
for one-off files.

Let's take ``Makefile.in`` files as an example. The build system module
policy dictates that ``Makefile.in`` files are part of the ``Build
Config`` module and should be reviewed by peers of that module. However,
there exist ``Makefile.in`` files in many directories in the source
tree. Without finalization, a ``*`` or ``**`` wildcard matching rule
would match ``Makefile.in`` files and overwrite their metadata.

Finalizing of values is performed by setting the ``FINAL`` variable
on ``Files`` sub-contexts. See the
:ref:`Files documentation <mozbuild_subcontext_Files>` for more.

Here is an example with ``Makefile.in`` files, showing how it is
possible to finalize the ``BUG_COMPONENT`` value.::

    # /moz.build
    with Files('**/Makefile.in'):
        BUG_COMPONENT = ('Firefox Build System', 'General')
        FINAL = True

    # /foo/moz.build
    with Files('**'):
        BUG_COMPONENT = ('Another', 'Component')

If we query for metadata of ``/foo/Makefile.in``, both ``Files``
sub-contexts match the file pattern. However, since ``BUG_COMPONENT`` is
marked as finalized by ``/moz.build``, the assignment from
``/foo/moz.build`` is ignored. The final value for ``BUG_COMPONENT``
is ``('Firefox Build System', 'General')``.

Here is another example::

    with Files('*.cpp'):
        BUG_COMPONENT = ('One-Off', 'For C++')
        FINAL = True

    with Files('**'):
        BUG_COMPONENT = ('Regular', 'Component')

For every files except ``foo.cpp``, the bug component will be resolved
as ``Regular :: Component``. However, ``foo.cpp`` has its value of
``One-Off :: For C++`` preserved because it is finalized.

.. important::

   ``FINAL`` only applied to variables defined in a context.

   If you want to mark one variable as finalized but want to leave
   another mutable, you'll need to use 2 ``Files`` contexts.

Guidelines for Defining Metadata
================================

In general, values defined towards the root of the source tree are
generic and become more specific towards the leaves. For example,
the ``BUG_COMPONENT`` for ``/browser`` might be ``Firefox :: General``
whereas ``/browser/components/preferences`` would list
``Firefox :: Preferences``.

---

### Build Docs Flatpak (`build/docs/flatpak.rst`)

.. _flatpak:

=========================
Firefox Flatpak Packaging
=========================

This page explains interactions between Firefox and Flatpak packaging format.

Where is the upstream
=====================

The code reference itself is mozilla-central and the repackaging is under :searchfox:`the mach repackage flatpak command `.

Where to report bugs
====================

All bugs should be reported to Bugzilla in the appropriate component depending on the bug and marked as blocking the ``flatpak`` meta-bug.

Build process
=============

Perform a build and then run ``mach repackage flatpak``, e.g.:

.. code-block:: shell

   $ mach repackage flatpak \
                    --input target.tar.xz \
                    --name org.mozilla.firefox \
                    --arch aarch64 \
                    --version 137.0a1 \
                    --product firefox \
                    --release-type nightly \
                    --flatpak-branch nightly \
                    --template-dir browser/installer/linux/app/flatpak \
                    --langpack-pattern $PWD/langpacks/*.xpi \
                    --output test.flatpak.tar.xz,

Where ``target.tar.xz`` can be a downloaded artifact from try build or built from a local build. You will also want to download `some langpack <https://ftp.mozilla.org/pub/firefox/nightly/latest-mozilla-central-l10n/linux-x86_64/xpi/>`_.

How to hack on try
==================

Pushing to try is basically just:

.. code-block:: shell

    $ mach try fuzzy --full -q "'repackage 'flatpak !shippable"`

This will produce a repackage flatpak task at the end that generates a ``target.flatpak.tar.xz``.

Installing the try build
========================

Download and extract the previously generated ``target.flatpak.tar.xz`` and it will produce a ``./repo`` directory that you can directly use with flatpak:

.. code-block:: shell

    $ flatpak --user --no-gpg-verify remote-add firefox-try ./repo/

This should add you a user-level firefox-try flatpak remote, you can verify with (``flathub`` remote may be a user or a system level remote):

 .. code-block:: shell

    $ flatpak remotes
    Name        Options
    firefox-try user
    flathub     user

Then you can install your local build:

 .. code-block:: shell

    $ flatpak install firefox-try firefox
    Looking for matches…
    Found ref ‘app/org.mozilla.firefox/x86_64/nightly’ in remote ‘firefox-try’ (user).
    Use this ref? [Y/n]: y

    org.mozilla.firefox permissions:
        ipc          network                cups                  fallback-x11            pcsc                         pulseaudio       wayland       x11       devices
        devel        file access [1]        dbus access [2]       bus ownership [3]       system dbus access [4]

        [1] /run/.heim_org.h5l.kcm-socket, xdg-download, xdg-run/speech-dispatcher:ro
        [2] org.a11y.Bus, org.freedesktop.FileManager1, org.gtk.vfs.*
        [3] org.mozilla.firefox.*, org.mozilla.firefox_beta.*, org.mpris.MediaPlayer2.firefox.*
        [4] org.freedesktop.NetworkManager


            ID                                              Branch                 Op            Remote                 Download
     1. [✓] org.freedesktop.Platform.GL.default             24.08                  u             flathub                 67,3 Mo / 156,6 Mo
     2. [✓] org.freedesktop.Platform.GL.default             24.08extra             u             flathub                  3,9 Mo / 156,6 Mo
     3. [✓] org.freedesktop.Platform.Locale                 24.08                  u             flathub                282,1 Ko / 380,3 Mo
     4. [✓] org.freedesktop.Platform                        24.08                  u             flathub                 25,4 Mo / 264,4 Mo
     5. [✓] org.mozilla.firefox.Locale                      nightly                i             firefox-try              1,0 Ko / 1,6 Mo
     6. [✓] org.mozilla.firefox                             nightly                i             firefox-try              1,0 Ko / 111,5 Mo

    Changes complete.

And after that you can just run ``flatpak run org.mozilla.firefox//nightly``.

---

### Build Docs Glossary (`build/docs/glossary.rst`)

Build Glossary
==============

.. glossary::
   :sorted:

   object directory
       A directory holding the output of the build system. The build
       system attempts to isolate all file modifications to this
       directory. By convention, object directories are commonly
       directories under the source directory prefixed with **obj-**.
       e.g. **obj-firefox**.

   mozconfig
       A shell script used to configure the build system.

   configure
       A generated shell script which detects the current system
       environment, applies a requested set of build configuration
       options, and writes out metadata to be consumed by the build
       system.

   config.status
       An executable file produced by **configure** that takes the
       generated build config and writes out files used to build the
       tree. Traditionally, config.status writes out a bunch of
       Makefiles.

   install manifest
       A file containing metadata describing file installation rules.
       A large part of the build system consists of copying files
       around to appropriate places. We write out special files
       describing the set of required operations so we can process the
       actions efficiently. These files are install manifests.

   clobber build
      A build performed with an initially empty object directory. All
      build actions must be performed.

   incremental build
      A build performed with the result of a previous build in an
      object directory. The build should not have to work as hard because
      it will be able to reuse the work from previous builds.

   mozinfo
      An API for accessing a common and limited subset of the build and
      run-time configuration. See :ref:`mozinfo`.

---

### Build Docs Gn (`build/docs/gn.rst`)

.. _gn:

==============================
GN support in the build system
==============================

:abbr:`GN (Generated Ninja)` is a third-party build tool used by chromium and
some related projects that are vendored in mozilla-central. Rather than
requiring ``GN`` to build or writing our own build definitions for these projects,
we have support in the build system for translating GN configuration
files into moz.build files. In most cases these moz.build files will be like any
others in the tree (except that they shouldn't be modified by hand), however
those updating vendored code or building on platforms not supported by
Mozilla automation may need to re-generate these files. This is a per-project
process, described in dom/media/webrtc/third_party_build/gn-configs/README.md for
webrtc. As of writing, it is very specific to webrtc, and likely doesn't work as-is
for other projects.

---

### Build Docs Index (`build/docs/index.rst`)

============
Build System
============

Important Concepts
==================
.. toctree::
   :maxdepth: 1

   glossary
   build-overview
   supported-configurations
   Mozconfig Files <mozconfigs>
   mozbuild-files
   mozbuild-symbols
   files-metadata
   Profile Guided Optimization 
   slow
   environment-variables
   build-targets
   python
   test_manifests
   mozinfo
   preprocessor
   jar-manifests
   defining-binaries
   defining-xpcom-components
   toolchains
   toolchains-update-policy
   locales
   unified-builds
   cross-compile
   rust
   sparse
   Support for projects building with GN <gn>
   telemetry
   sccache-dist
   test_certificates

integrated development environment (IDE)
========================================
.. toctree::
   :maxdepth: 1

   cppeclipse
   visualstudio

mozbuild
========

mozbuild is a Python package containing a lot of the code for the
Mozilla build system.

.. toctree::
   :maxdepth: 1

   mozbuild/index

Snap Package
============

`Snap <https://snapcraft.io/docs>`_ is a packaging format

.. toctree::
   :maxdepth: 1

   snap

Flatpak Package
===============

`Flatpak <https://docs.flatpak.org/en/latest/>`_ is a packaging format

.. toctree::
   :maxdepth: 1

   flatpak

---

### Build Docs Jar Manifests (`build/docs/jar-manifests.rst`)

.. _jar_manifests:

=============
JAR Manifests
=============

JAR Manifests are plaintext files in the tree that are used to package chrome
files into ``.jar`` files and create :ref:`Chrome Registration <Chrome Registration>`
manifests. JAR Manifests are commonly named ``jar.mn``. They are declared in ``moz.build`` files using the ``JAR_MANIFESTS`` variable, which makes up a collection of ``jar.mn`` files.
All files declared in JAR Manifests are processed and installed into ``omni.ja`` files in ``browser/`` and ``toolkit/`` when building Firefox.

``jar.mn`` files are automatically processed by the build system when building a
source directory that contains one. The ``jar.mn`` is run through the
:ref:`preprocessor` before being passed to the manifest processor. In order to
have ``@variables@`` expanded (such as ``@AB_CD@``) throughout the file, add
the line ``#filter substitution`` at the top of your ``jar.mn`` file.

The format of a jar.mn is fairly simple; it consists of a heading specifying
which JAR file is being packaged, followed by indented lines listing files and
chrome registration instructions.

For a simple ``jar.mn`` file, see :searchfox:`toolkit/profile/jar.mn <mozilla-central/rev/5b2d2863bd315f232a3f769f76e0eb16cdca7cb0:toolkit/profile/jar.mn>`. For a much
more complex ``jar.mn`` file, see :searchfox:`toolkit/locales/jar.mn <mozilla-central/rev/5b2d2863bd315f232a3f769f76e0eb16cdca7cb0:toolkit/locales/jar.mn>`. More examples with specific formats and uses are available below.

Shipping Chrome Files
======================
General Format
^^^^^^^^^^^^^^
To ship chrome files in a JAR, an indented line indicates a file to be packaged::

   <jarfile>.jar:
     path/in/jar/file_name.xul     (source/tree/location/file_name.xul)

Note that file path mappings are listed by destination (left) followed by source (right).

Same Directory Omission
^^^^^^^^^^^^^^^^^^^^^^^
If the JAR manifest and packaged files live in the same directory, the source path and parentheses can be omitted.
A sample of a ``jar.mn`` file with omitted source paths and parentheses is :searchfox:`this revision of browser/components/colorways/jar.mn <mozilla-central/rev/5b2d2863bd315f232a3f769f76e0eb16cdca7cb0:browser/components/colorways/jar.mn>`::

   browser.jar:
     content/browser/colorwaycloset.html
     content/browser/colorwaycloset.css
     content/browser/colorwaycloset.js

Writing the following is equivalent, given that the aforementioned files exist in the same directory as the ``jar.mn``. Notice the ``.jar`` file is named ``browser.jar``::

   browser.jar:
     content/browser/colorwaycloset.html (colorwaycloset.html)
     content/browser/colorwaycloset.css  (colorwaycloset.css)
     content/browser/colorwaycloset.js   (colorwaycloset.js)

This manifest is responsible for packaging files needed by Colorway Closet, including
JS scripts, localization files, images (ex. PNGs, AVIFs), and CSS styling. Look at :searchfox:`browser/components/colorways/colorwaycloset.html <mozilla-central/rev/5b2d2863bd315f232a3f769f76e0eb16cdca7cb0:browser/components/colorways/colorwaycloset.html#18>`
to see how a file may be referenced using its chrome URL.

Absolute Paths
^^^^^^^^^^^^^^
The source tree location may also be an absolute path (taken from the top of the source tree).
One such example can be found in :searchfox:`toolkit/components/pictureinpicture/jar.mn <mozilla-central/rev/2005e8d87ee045f19dac58e5bff32eff7d01bc9b:toolkit/components/pictureinpicture/jar.mn>`::

   toolkit.jar:
     * content/global/pictureinpicture/player.xhtml   (content/player.xhtml)
     content/global/pictureinpicture/player.js      (content/player.js)

Asterisk Marker (Preprocessing)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
An asterisk marker (``*``) at the beginning of the line indicates that the file should be processed by the :ref:`preprocessor` before being packaged.
The file :searchfox:`toolkit/profile/jar.mn <mozilla-central/rev/5b2d2863bd315f232a3f769f76e0eb16cdca7cb0:toolkit/profile/jar.mn>` indicates that the file :searchfox:`toolkit/profile/content/profileDowngrade.xhtml <mozilla-central/rev/2005e8d87ee045f19dac58e5bff32eff7d01bc9b:toolkit/profile/content/profileDowngrade.xhtml#34,36>` should be
run through the preprocessor, since it contains ``#ifdef`` and ``#endif`` statements that need to be interpreted::

   * content/mozapps/profile/profileDowngrade.xhtml  (content/profileDowngrade.xhtml)

Base Path, Variables, Wildcards and Localized Files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``.jar`` file location may be preceded with a base path between square brackets.
The file :searchfox:`toolkit/locales/jar.mn <mozilla-central/rev/5b2d2863bd315f232a3f769f76e0eb16cdca7cb0:toolkit/locales/jar.mn>` uses a base path so that the ``.jar`` file is under a ``localization`` directory,
which is a :searchfox:`special directory parsed by mozbuild <mozilla-central/rev/2005e8d87ee045f19dac58e5bff32eff7d01bc9b:python/mozbuild/mozpack/packager/l10n.py#260-265>`.

It is also named according to the value passed by the variable ``@AB_CD@``, normally a locale. Note the use of the preprocessor directive ``#filter substitution`` at the top of the file for replacing the variable with the value::

   #filter substitution

   ...

   [localization] @[email protected]:
     crashreporter                                    (%crashreporter/**/*.ftl)
     toolkit                                          (%toolkit/**/*.ftl)

The percentage sign in front of the source paths designates the locale to target as a source. By default, this is ``en-US``. With this specific example, :searchfox:`/toolkit/locales/en-US <toolkit/locales/en-US>` would be targeted.
Otherwise, the file from an alternate localization source tree ``/l10n/<locale>/toolkit/`` is read if building a localized version.
The wildcards in ``**/*.ftl`` tell the processor to install all Fluent files within the ``crashreporter`` and ``toolkit`` directories, as well as their subdirectories.

Registering Chrome
==================

:ref:`Chrome Registration <Chrome Registration>` instructions are marked with a percent sign (``%``) at the beginning of the
line, and must be part of the definition of a JAR file. Any additional percents
signs are replaced with an appropriate relative URL of the JAR file being
packaged.

There are two possible locations for a manifest file. If the chrome is being
built into a standalone application, the ``jar.mn`` processor creates a
``<jarfilename>.manifest`` next to the JAR file itself. This is the default
behavior.

If the ``moz.build`` specifies ``USE_EXTENSION_MANIFEST = 1``, the ``jar.mn`` processor
creates a single ``chrome.manifest`` file suitable for registering chrome as
an extension.

Example
^^^^^^^

The file :searchfox:`browser/themes/addons/jar.mn <mozilla-central/rev/5b2d2863bd315f232a3f769f76e0eb16cdca7cb0:browser/themes/addons/jar.mn>` registers a ``resource`` chrome package under the name ``builtin-themes``. Its source files are in ``%content/builtin-themes/``::

   browser.jar:
     %  resource builtin-themes %content/builtin-themes/

     content/builtin-themes/alpenglow                 (alpenglow/*.svg)
     content/builtin-themes/alpenglow/manifest.json   (alpenglow/manifest.json)

Notice how other files declare an installation destination using the ``builtin-themes`` resource that is defined. As such, a SVG file ``preview.svg`` for a theme ``Alpenglow`` may be loaded using the resource URL ``resource://builtin-themes/alpenglow/preview.svg``
so that a preview of the theme is available on ``about:addons``. See :ref:`Chrome Registration <Chrome Registration>` for more details on ``resource`` and other manifest instructions.

---

### Build Docs Locales (`build/docs/locales.rst`)

.. _localized-builds:

================
Localized Builds
================

Localization repacks
====================

To save on build time, the build system and automation collaborate to allow
downloading a packaged en-US Firefox, performing some locale-specific
post-processing, and re-packaging a locale-specific Firefox. Such artifacts
are termed "single-locale language repacks". There is another concept of a
"multi-locale language build", which is more like a regular build and less
like a re-packaging post-processing step.

.. note::

  These builds rely on make targets that don't work for
  `artifact builds <https://bugzilla.mozilla.org/show_bug.cgi?id=1387485>`_.

Instructions for single-locale repacks for developers
-----------------------------------------------------

This assumes that ``$AB_CD`` is the locale you want to repack with; you
find the available localizations from `firefox-l10n <https://github.com/mozilla-l10n/firefox-l10n>`_.

#. You must have a built and packaged object directory, or a pre-built
   ``en-US`` package.

   .. code-block:: shell

      ./mach build
      ./mach package

#. Repackage using the locale-specific changes.

   .. code-block:: shell

      ./mach build installers-$AB_CD

You should find a re-packaged build at ``OBJDIR/dist/``, and a runnable binary
in ``OBJDIR/dist/l10n-stage/``. The ``installers`` target runs quite a few
things for you, including getting the localizations from
https://github.com/mozilla-l10n/firefox-l10n (or updating it if already
present). It will clone them into ``~/.mozbuild/l10n-central``. If you prefer to
have the l10n repositories at a different location on your disk, you can point
to the directory via

   .. code-block:: shell

      ac_add_options --with-l10n-base=/make/this/a/absolute/path

This build also packages a language pack.

Instructions for language packs
-------------------------------

Language packs are extensions that contain just the localized resources. Building
them doesn't require an actual build, but they're only compatible with the
``mozilla-central`` source they're built with.


.. code-block:: shell

  ./mach build langpack-$AB_CD

This target shares much of the logic of the ``installers-$AB_CD`` target above,
and does the check-out of the localization repository etc. It doesn't require
a package or a build, though. The generated language pack is in
``OBJDIR/dist/$(MOZ_PKG_PLATFORM)/xpi/``.

.. note::

  Despite the platform-dependent location in the build directory, language packs
  are platform independent, and the content that goes into them needs to be
  built in a platform-independent way.

Instructions for multi-locale builds
------------------------------------

If you want to create a single build with multiple locales, you will do

#. Create a build and package

   .. code-block:: shell

      ./mach build
      ./mach package

#. Create the multi-locale package:

   .. code-block:: shell

      ./mach package-multi-locale --locales de it zh-TW

On Android, this produces a multi-locale GeckoView AAR and multi-locale APKs,
including GeckoViewExample.  You can test different locales by changing your
Android OS locale and restarting GeckoViewExample.  You'll need to install with
the ``MOZ_CHROME_MULTILOCALE`` variable set, like:

   .. code-block:: shell

       env MOZ_CHROME_MULTILOCALE=en-US,de,it,zh-TW ./mach android install-geckoview_example

Multi-locale builds without compiling
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

For deep technical reasons, artifact builds do not support multi-locale builds.
However, with a little work, we can achieve the same effect:

#. Arrange a ``mozconfig`` without a compilation environment but with support
   for the ``RecursiveMake`` build backend, like:

   .. code-block:: shell

      ac_add_options --disable-compile-environment
      export BUILD_BACKENDS=FasterMake,RecursiveMake
      ... other options ...

#. Configure.

   .. code-block:: shell

      ./mach configure

#. Manually provide compiled artifacts.

   .. code-block:: shell

      ./mach artifact install [-v]

#. Build.

   .. code-block:: shell

      ./mach build

#. Produce a multi-locale package.

   .. code-block:: shell

      ./mach package-multi-locale --locales de it zh-TW

This build configuration is fragile and not generally useful for active
development (for that, use a full/compiled build), but it certainly speeds
testing multi-locale packaging.

General flow of repacks
-----------------------

The general flow of the locale repacks is controlled by
``$MOZ_BUILD_APP/locales/Makefile.in`` and ``toolkit/locales/l10n.mk``, plus
the packaging build system. The three main entry points above all trigger
related build flows:

#. Get the localization repository, if needed
#. Run l10n-merge with a prior clobber of the merge dir
#. Copy l10n files to ``dist``, with minor differences here between ``l10n-%`` and ``chrome-%``
#. Repackage and package

Details on l10n-merge are described in its own section below.
The copying of files is mainly controlled by ``jar.mn``, in the few source
directories that include localizable files. ``l10n-%`` is used for repacks,
``chrome-%`` for multi-locale packages. The repackaging is dedicated
Python code in ``toolkit/mozapps/installer/l10n-repack.py``, using an existing
package. It strips existing ``chrome`` l10n resources, and adds localizations
and metadata.

Language packs don't require repackaging. The windows installers are generated
by merely packaging an existing repackaged zip into to an installer.

Exposing strings
================

The localization flow handles a few file formats in well-known locations in the
source tree.

Alongside being built by including the directory in ``$MOZ_BUILD_APP/locales/Makefile.in``
and respective entries in a ``jar.mn``, we also have configuration files tailored
to localization tools and infrastructure. They're also controlling which
files l10n-merge handles, and how.

These configurations are TOML files. They're part of the bigger
localization ecosystem at Mozilla, and `the documentation about the
file format <http://moz-l10n-config.readthedocs.io/en/latest/fileformat.html>`_
explains how to set them up, and what the entries mean. In short, you find

.. code-block:: text

   [paths]
   reference = browser/locales/en-US/**
   l10n = {l}browser/**

to add a directory for all localizations. Changes to these files are best
submitted for review by :Pike or :flod.

These configuration files are the future, and right now, we still have
support for the previous way to configuring l10n, which is described below.

The locations are commonly in directories like

    :file:`browser/`\ ``locales/en-US/``\ :file:`subdir/file.ext`

The first thing to note is that only files beneath :file:`locales/en-US` are
exposed to localizers. The second thing to note is that only a few directories
are exposed. Which directories are exposed is defined in files called
``l10n.ini``, which are at a
`few places <https://searchfox.org/mozilla-central/search?q=path%3Al10n.ini&redirect=true>`_
in the source code.

An example looks like this

.. code-block:: ini

    [general]
    depth = ../..

    [compare]
    dirs = browser
        browser/branding/official

    [includes]
    toolkit = toolkit/locales/l10n.ini

This tells the l10n infrastructure three things:

* resolve the paths against the directory two levels up
* include files in :file:`browser/locales/en-US` and
  :file:`browser/branding/official/locales/en-US`
* load more data from :file:`toolkit/locales/l10n.ini`

For projects like Thunderbird and SeaMonkey in ``comm-central``, additional
data needs to be provided when including an ``l10n.ini`` from a different
.. code-block:: ini

    [include_toolkit]
    type = hg
    mozilla = mozilla-central
    repo = https://hg.mozilla.org/
    l10n.ini = toolkit/locales/l10n.ini

This tells the l10n infrastructure where to find the repository, and where inside
that repository the ``l10n.ini`` file is. This is needed because for local
builds, :file:`mail/locales/l10n.ini` references
:file:`mozilla/toolkit/locales/l10n.ini`, which is where the comm-central
build setup expects toolkit to be.

Now that the directories exposed to l10n are known, we can talk about the
supported file formats.

File formats
------------

The following file formats are known to the l10n tool chains:

Fluent
    Used in Firefox UI, both declarative and programmatically.
Properties
    Used from JavaScript and C++. When used from js, also comes with
    plural support (avoid if possible).
ini
    Used by the crashreporter and updater, avoid if possible.

Adding new formats involves changing various different tools, and is strongly
discouraged.

Exceptions
----------
Generally, anything that exists in ``en-US`` needs a one-to-one mapping in
all localizations. There are a few cases where that's not wanted, notably
around locale configuration and locale-dependent metadata.

For optional strings and files, l10n-merge won't add ``en-US`` content if
the localization doesn't have that content.

For the TOML files, the
`[[filters]] documentation <https://moz-l10n-config.readthedocs.io/en/latest/fileformat.html#filters>`_
is a good reference. In short, filters match the localized source code, optionally
a ``key``, and an action. An example like

.. code-block:: toml

  [filters]
  path = "{l}calendar/chrome/calendar/calendar-event-dialog.properties"
  key = "re:.*Nounclass[1-9].*"
  action = "ignore"

indicates that the matching messages in ``calendar-event-dialog.properties`` are optional.

For the legacy ini configuration files, there's a Python module
``filter.py`` next to the main ``l10n.ini``, implementing :py:func:`test`, with the following
signature

.. code-block:: python

    def test(mod, path, entity = None):
        if does_not_matter:
            return "ignore"
        if show_but_do_not_merge:
            return "report"
        # default behavior, localizer or build need to do something
        return "error"

For any missing file, this function is called with ``mod`` being
the *module*, and ``path`` being the relative path inside
:file:`locales/en-US`. The module is the top-level dir as referenced in
:file:`l10n.ini`.

For missing strings, the :py:data:`entity` parameter is the key of the string
in the en-US file.

l10n-merge
==========

The chrome registry in Gecko doesn't support fallback from a localization to ``en-US`` at runtime.
Thus, the build needs to ensure that the localization as it's built into
the package has all required strings, and that the strings don't contain
errors. To ensure that, we're *merging* the localization and ``en-US``
at build time, nick-named l10n-merge.

For Fluent, we're also removing erroneous messages. For many errors in Fluent,
that's cosmetic, but when a localization has different values or attributes
on a message, that's actually important so that the DOM bindings of Fluent
can apply the translation without having to load the ``en-US`` source to
compare against.

The process can be manually triggered via

.. code-block:: bash

    $> ./mach build merge-$AB_CD

It creates another directory in the object dir, :file:`browser/locales/merge-dir/$AB_CD`, in
which the sanitized files are stored. The actual repackaging process only looks
in the merged directory, so the preparation steps of l10n-merge need to ensure
that all files are generated or copied.

l10n-merge modifies a file if it supports the particular file type, and there
are missing strings which are not filtered out, or if an existing string
shows an error. See the Checks section below for details. If the files are
not modified, l10n-merge copies them over to the respective location in the
merge dir.

Checks
------

As part of the build and other localization tool chains, we run a variety
of source-based checks. Think of them as linters.

The suite of checks is usually determined by file type, i.e., there's a
suite of checks for Fluent files and one for properties files, etc.

Localizations
-------------

Now that we talked in-depth about how to expose content to localizers,
where are the localizations?

We host all locales in a git monorepo. All of our
localizations can be found on https://github.com/mozilla-l10n/firefox-l10n.

You can search inside our localized files on
`Transvision <https://transvision.mozfr.org/>`_.

---

### Build Docs Mozbuild Files (`build/docs/mozbuild-files.rst`)

.. _mozbuild-files:

===============
moz.build Files
===============

``moz.build`` files are the mechanism by which tree metadata (notably
the build configuration) is defined.

Directories in the tree contain ``moz.build`` files which declare
functionality for their respective part of the tree. This includes
things such as the list of C++ files to compile, where to find tests,
etc.

``moz.build`` files are actually Python scripts. However, their
execution is governed by special rules. This is explained below.

moz.build Python Sandbox
========================

As mentioned above, ``moz.build`` files are Python scripts. However,
they are executed in a special Python *sandbox* that significantly
changes and limits the execution environment. The environment is so
different, it's doubtful most ``moz.build`` files would execute without
error if executed by a vanilla Python interpreter (e.g. ``python
moz.build``.

The following properties make execution of ``moz.build`` files special:

1. The execution environment exposes a limited subset of Python.
2. There is a special set of global symbols and an enforced naming
   convention of symbols.
3. Some symbols are inherited from previously-executed ``moz.build``
   files.

The limited subset of Python is actually an extremely limited subset.
Only a few symbols from ``__builtin__`` are exposed. These include
``True``, ``False``, ``None``, ``sorted``, ``int``, and ``set``. Global
functions like ``import``, ``print``, and ``open`` aren't available.
Without these, ``moz.build`` files can do very little. *This is by design*.

The execution sandbox treats all ``UPPERCASE`` variables specially. Any
``UPPERCASE`` variable must be known to the sandbox before the script
executes. Any attempt to read or write to an unknown ``UPPERCASE``
variable will result in an exception being raised. Furthermore, the
types of all ``UPPERCASE`` variables is strictly enforced. Attempts to
assign an incompatible type to an ``UPPERCASE`` variable will result in
an exception being raised.

The strictness of behavior with ``UPPERCASE`` variables is a very
intentional design decision. By ensuring strict behavior, any operation
involving an ``UPPERCASE`` variable is guaranteed to have well-defined
side-effects. Previously, when the build configuration was defined in
``Makefiles``, assignments to variables that did nothing would go
unnoticed. ``moz.build`` files fix this problem by eliminating the
potential for false promises.

After a ``moz.build`` file has completed execution, only the
``UPPERCASE`` variables are used to retrieve state.

The set of variables and functions available to the Python sandbox is
defined by the :py:mod:`mozbuild.frontend.context` module. The
data structures in this module are consumed by the
:py:class:`mozbuild.frontend.reader.MozbuildSandbox` class to construct
the sandbox. There are tests to ensure that the set of symbols exposed
to an empty sandbox are all defined in the ``context`` module.
This module also contains documentation for each symbol, so nothing can
sneak into the sandbox without being explicitly defined and documented.

Reading and Traversing moz.build Files
======================================

The process for reading ``moz.build`` files roughly consists of:

1. Start at the root ``moz.build`` (``<topsrcdir>/moz.build``).
2. Evaluate the ``moz.build`` file in a new sandbox.
3. Emit the main *context* and any *sub-contexts* from the executed
   sandbox.
4. Extract a set of ``moz.build`` files to execute next.
5. For each additional ``moz.build`` file, goto #2 and repeat until all
   referenced files have executed.

From the perspective of the consumer, the output of reading is a stream
of :py:class:`mozbuild.frontend.reader.context.Context` instances. Each
``Context`` defines a particular aspect of data. Consumers iterate over
these objects and do something with the data inside. Each object is
essentially a dictionary of all the ``UPPERCASE`` variables populated
during its execution.

.. note::

   Historically, there was only one ``context`` per ``moz.build`` file.
   As the number of things tracked by ``moz.build`` files grew and more
   and more complex processing was desired, it was necessary to split these
   contexts into multiple logical parts. It is now common to emit
   multiple contexts per ``moz.build`` file.

Build System Reading Mode
-------------------------

The traditional mode of evaluation of ``moz.build`` files is what's
called *build system traversal mode.* In this mode, the ``CONFIG``
variable in each ``moz.build`` sandbox is populated from data coming
from ``config.status``, which is produced by ``configure``.

During evaluation, ``moz.build`` files often make decisions conditional
on the state of the build configuration. e.g. *only compile foo.cpp if
feature X is enabled*.

In this mode, traversal of ``moz.build`` files is governed by variables
like ``DIRS`` and ``TEST_DIRS``. For example, to execute a child
directory, ``foo``, you would add ``DIRS += ['foo']`` to a ``moz.build``
file and ``foo/moz.build`` would be evaluated.

.. _mozbuild_fs_reading_mode:

Filesystem Reading Mode
-----------------------

There is an alternative reading mode that doesn't involve the build
system and doesn't use ``DIRS`` variables to control traversal into
child directories. This mode is called *filesystem reading mode*.

In this reading mode, the ``CONFIG`` variable is a dummy, mostly empty
object. Accessing all but a few special variables will return an empty
value. This means that nearly all ``if CONFIG['FOO']:`` branches will
not be taken.

Instead of using content from within the evaluated ``moz.build``
file to drive traversal into subsequent ``moz.build`` files, the set
of files to evaluate is controlled by the thing doing the reading.

A single ``moz.build`` file is not guaranteed to be executable in
isolation. Instead, we must evaluate all *parent* ``moz.build`` files
first. For example, in order to evaluate ``/foo/moz.build``, one must
execute ``/moz.build`` and have its state influence the execution of
``/foo/moz.build``.

Filesystem reading mode is utilized to power the
:ref:`mozbuild_files_metadata` feature.

Technical Details
-----------------

The code for reading ``moz.build`` files lives in
:py:mod:`mozbuild.frontend.reader`. The Python sandboxes evaluation results
(:py:class:`mozbuild.frontend.context.Context`) are passed into
:py:mod:`mozbuild.frontend.emitter`, which converts them to classes defined
in :py:mod:`mozbuild.frontend.data`. Each class in this module defines a
domain-specific component of tree metadata. e.g. there will be separate
classes that represent a JavaScript file vs a compiled C++ file or test
manifests. This means downstream consumers of this data can filter on class
types to only consume what they are interested in.

There is no well-defined mapping between ``moz.build`` file instances
and the number of :py:mod:`mozbuild.frontend.data` classes derived from
each. Depending on the content of the ``moz.build`` file, there may be 1
object derived or 100.

The purpose of the ``emitter`` layer between low-level sandbox execution
and metadata representation is to facilitate a unified normalization and
verification step. There are multiple downstream consumers of the
``moz.build``-derived data and many will perform the same actions. This
logic can be complicated, so we have a component dedicated to it.

:py:class:`mozbuild.frontend.reader.BuildReader`` and
:py:class:`mozbuild.frontend.reader.TreeMetadataEmitter`` have a
stream-based API courtesy of generators. When you hook them up properly,
the :py:mod:`mozbuild.frontend.data` classes are emitted before all
``moz.build`` files have been read. This means that downstream errors
are raised soon after sandbox execution.

Lots of the code for evaluating Python sandboxes is applicable to
non-Mozilla systems. In theory, it could be extracted into a standalone
and generic package. However, until there is a need, there will
likely be some tightly coupled bits.

---

### Build Docs Mozbuild Symbols (`build/docs/mozbuild-symbols.rst`)

.. _mozbuild_symbols:

========================
mozbuild Sandbox Symbols
========================

.. rstcheck: ignore-directives=mozbuildsymbols
.. mozbuildsymbols:: mozbuild.frontend.context

---

### Build Docs Mozconfigs (`build/docs/mozconfigs.rst`)

.. _mozconfig:

===============
mozconfig Files
===============

mozconfig files are used to configure how a build works.

mozconfig files are actually shell scripts. They are executed in a
special context with specific variables and functions exposed to them.

API
===

Functions
---------

The following special functions are available to a mozconfig script.

ac_add_options
^^^^^^^^^^^^^^

This function is used to declare extra options/arguments to pass into
configure.

e.g.::

    ac_add_options --disable-tests
    ac_add_options --enable-optimize

mk_add_options
^^^^^^^^^^^^^^

This function is used to inject statements into client.mk for execution.
It is typically used to define variables, notably the object directory.

e.g.::

    mk_add_options AUTOCLOBBER=1

Special mk_add_options Variables
--------------------------------

For historical reasons, the method for communicating certain
well-defined variables is via mk_add_options(). In this section, we
document what those special variables are.

MOZ_OBJDIR
^^^^^^^^^^

This variable is used to define the :term:`object directory` for the current
build.

Finding the active mozconfig
============================

Multiple mozconfig files can exist to provide different configuration
options for different tasks. The rules for finding the active mozconfig
are defined in the
:py:func:`mozboot.mozconfig.find_mozconfig` method.

.. automodule:: mozboot.mozconfig
   :members: find_mozconfig

Loading the active mozconfig
----------------------------

.. autoclass:: mozbuild.mozconfig.MozconfigLoader
   :members: read_mozconfig

---

### Build Docs Mozinfo (`build/docs/mozinfo.rst`)

.. _mozinfo:

=======
mozinfo
=======

``mozinfo`` is a solution for representing a subset of build
configuration and run-time data.

``mozinfo`` data is typically accessed through a ``mozinfo.json`` file
which is written to the :term:`object directory` during build
configuration. The code for writing this file lives in
:py:mod:`mozbuild.mozinfo`.

``mozinfo.json`` is an object/dictionary of simple string values.

The attributes in ``mozinfo.json`` are used for many purposes. One use
is to filter tests for applicability to the current build. For more on
this, see :ref:`test_manifests`.

.. _mozinfo_attributes:

mozinfo.json Attributes
=================================

``mozinfo`` currently records the following attributes.

appname
   The application being built.

   Value comes from ``MOZ_APP_NAME`` from ``config.status``.

   Optional.

asan
   Whether address sanitization is enabled.

   Values are ``true`` and ``false``.

   Always defined.

bin_suffix
   The file suffix for binaries produced with this build.

   Values may be an empty string, as not all platforms have a binary
   suffix.

   Always defined.

bits
   The number of bits in the CPU this build targets.

   Values are typically ``32`` or ``64``.

   Universal Mac builds do not have this key defined.

   Unknown processor architectures (see ``processor`` below) may not have
   this key defined.

   Optional.

buildapp
   The path to the XUL application being built.

   For desktop Firefox, this is ``browser``. For Fennec, it's
   ``mobile/android``.

crashreporter
   Whether the crash reporter is enabled for this build.

   Values are ``true`` and ``false``.

   Always defined.

datareporting
   Whether data reporting (MOZ_DATA_REPORTING) is enabled for this build.

   Values are ``true`` and ``false``.

   Always defined.

debug
   Whether this is a debug build.

   Values are ``true`` and ``false``.

   Always defined.

devedition
   Whether this is a devedition build.

   Values are ``true`` and ``false``.

   Always defined.

healthreport
   Whether the Health Report feature is enabled.

   Values are ``true`` and ``false``.

   Always defined.

mozconfig
   The path of the :ref:`mozconfig file <mozconfig>` used to produce this build.

   Optional.

nightly_build
   Whether this is a nightly build.

   Values are ``true`` and ``false``.

   Always defined.

os
   The operating system the build is produced for. Values for tier-1
   supported platforms are ``linux``, ``win``, ``mac``, and
   ``android``. For other platforms, the value is the lowercase version
   of the ``OS_TARGET`` variable from ``config.status``.

   Always defined.

processor
   Information about the processor architecture this build targets.

   Values come from ``TARGET_CPU``, however some massaging may be
   performed.

   If the build is a universal build on Mac (it targets both 32-bit and
   64-bit), the value is ``universal-x86-x86_64``.

   If the value starts with ``arm``, the value is ``arm``.

   If the value starts with a string of the form ``i[3-9]86]``, the
   value is ``x86``.

   Always defined.

release_or_beta
   Whether this is a release or beta build.

   Values are ``true`` and ``false``.

   Always defined.

stylo
   Whether the Stylo styling system is being used.

   Values are ``true`` and ``false``.

   Always defined.

tests_enabled
   Whether tests are enabled for this build.

   Values are ``true`` and ``false``.

   Always defined.

toolkit
   The widget toolkit in case. The value comes from the
   ``MOZ_WIDGET_TOOLKIT`` ``config.status`` variable.

   Always defined.

topsrcdir
   The path to the source directory the build came from.

   Always defined.

topobjdir
   The path to the obj directory the build came from.

   Always defined.

webrender
   Whether or not WebRender is enabled as the Gecko compositor.

   Values are ``true`` and ``false``.

   Always defined.

---

### Build Docs Pgo (`build/docs/pgo.rst`)

.. _pgo:

===========================
Profile Guided Optimization
===========================

:abbr:`PGO (Profile Guided Optimization)` is the process of adding
probes to a compiled binary, running said binary, then using the
run-time information to *recompile* the binary to (hopefully) make it
faster.

How PGO Builds Work
===================

The supported interface for invoking a PGO build is to add ``MOZ_PGO=1`` to
configure flags and then build. e.g. in your mozconfig::

    ac_add_options MOZ_PGO=1

Then::

    $ ./mach build

This is roughly equivalent to::

#. Perform a build with *--enable-profile-generate* in $topobjdir/instrumented
#. Perform a run of the instrumented binaries with build/pgo/profileserver.py
#. Perform a build with *--enable-profile-use* in $topobjdir

---

### Build Docs Preprocessor (`build/docs/preprocessor.rst`)

.. _preprocessor:

=================
Text Preprocessor
=================

The build system contains a text preprocessor similar to the C preprocessor,
meant for processing files which have no built-in preprocessor such as XUL
and JavaScript documents. It is implemented at ``python/mozbuild/mozbuild/preprocessor.py`` and
is typically invoked via :ref:`jar_manifests`.

While used to preprocess CSS files, the directives are changed to begin with
``%`` instead of ``#`` to avoid conflict of the id selectors.

Directives
==========

Variable Definition
-------------------

define
^^^^^^

::

   #define variable
   #define variable value

Defines a preprocessor variable.

Note that, unlike the C preprocessor, instances of this variable later in the
source are not automatically replaced (see #filter). If value is not supplied,
it defaults to ``1``.

Note that whitespace is significant, so ``"#define foo one"`` and
``"#define foo one "`` is different (in the second case, ``foo`` is defined to
be a four-character string).

undef
^^^^^

::

   #undef variable

Undefines a preprocessor variable.

Conditionals
------------

if
^^

::

   #if variable
   #if !variable
   #if variable == string
   #if variable != string

Disables output if the conditional is false. This can be nested to arbitrary
depths. Note that in the equality checks, the variable must come first.

else
^^^^

::

   #else

Reverses the state of the previous conditional block; for example, if the
last ``#if`` was true (output was enabled), an ``#else`` makes it off
(output gets disabled).

endif
^^^^^

::

   #endif

Ends the conditional block.

ifdef / ifndef
^^^^^^^^^^^^^^

::

   #ifdef variable
   #ifndef variable

An ``#if`` conditional that is true only if the preprocessor variable
variable is defined (in the case of ``ifdef``) or not defined (``ifndef``).

elif / elifdef / elifndef
^^^^^^^^^^^^^^^^^^^^^^^^^

::

   #elif variable
   #elif !variable
   #elif variable == string
   #elif variable != string
   #elifdef variable
   #elifndef variable

A shorthand to mean an ``#else`` combined with the relevant conditional.
The following two blocks are equivalent::

   #ifdef foo
     block 1
   #elifdef bar
     block 2
   #endif

::

   #ifdef foo
     block 1
   #else
   #ifdef bar
     block 2
   #endif
   #endif

File Inclusion
--------------

include
^^^^^^^

::

   #include filename

The file specified by filename is processed as if the contents was placed
at this position. This also means that preprocessor conditionals can even
be started in one file and ended in another (but is highly discouraged).
There is no limit on depth of inclusion, or repeated inclusion of the same
file, or self inclusion; thus, care should be taken to avoid infinite loops.

includesubst
^^^^^^^^^^^^

::

   #includesubst @variable@filename

Same as a ``#include`` except that all instances of variable in the included
file is also expanded as in ``#filter`` substitution

expand
^^^^^^

::

   #expand string

All variables wrapped in ``__`` are replaced with their value, for this line
only. If the variable is not defined, it expands to an empty string. For
example, if ``foo`` has the value ``bar``, and ``baz`` is not defined, then::

   #expand This <__foo__> <__baz__> gets expanded

Is expanded to::

   This  <> gets expanded

filter / unfilter
^^^^^^^^^^^^^^^^^

::

   #filter filter1 filter2 ... filterN
   #unfilter filter1 filter2 ... filterN

``#filter`` turns on the given filter.

Filters are run in alphabetical order on a per-line basis.

``#unfilter`` turns off the given filter. Available filters are:

emptyLines
   strips blank lines from the output
dumbComments
    dumbComments: empties out any line that consists of optional whitespace
    followed by a ``//``. Good for getting rid of comments that are on their
    own lines, and being smarter with a simple regexp filter is impossible
substitution
   all variables wrapped in @ are replaced with their value. If the
   variable is not defined, it is a fatal error. Similar to ``#expand``
   and ``#filter``
attemptSubstitution
   all variables wrapped in ``@`` are replaced with their value, or an
   empty string if the variable is not defined. Similar to ``#expand``.

literal
^^^^^^^

::

   #literal string

Output the string (i.e. the rest of the line) literally, with no other fixups.
This is useful to output lines starting with ``#``, or to temporarily
disable filters.

Other
-----

#error
^^^^^^

::

   #error string

Cause a fatal error at this point, with the error message being the
given string.

---

### Build Docs Python (`build/docs/python.rst`)

.. _python:

===========================
Python and the Build System
===========================

The Python programming language is used significantly in the build
system. If we need to write code for the build system or for a tool
related to the build system, Python is typically the first choice.

Python Requirements
===================

The tree requires Python 3.9 or greater to build.
All Python packages not in the Python distribution are included in the
source tree. So all you should need is a vanilla Python install and you
should be good to go.

Only CPython (the Python distribution available from www.python.org) is
supported.

Compiled Python Packages
========================

There are some features of the build that rely on compiled Python packages
(packages containing C source). These features are currently all
optional because not every system contains the Python development
headers required to build these extensions.

We recommend you have the Python development headers installed (``mach
bootstrap`` should do this for you) so you can take advantage of these
features.

Issues with OS X System Python
==============================

The Python that ships with OS X has historically been littered with
subtle bugs and suboptimalities.

OS X 10.8 and below users will be required to install a new Python
distribution. This may not be necessary for OS X 10.9+. However, we
still recommend installing a separate Python because of the history with
OS X's system Python issues.

We recommend installing Python through Homebrew or MacPorts. If you run
``mach bootstrap``, this should be done for you.

Virtual Environments
====================

The build system relies heavily on
`venv <https://docs.python.org/3/library/venv.html>`_. Venv provides
standalone and isolated Python "virtual environments". The problem a venv
solves is that of dependencies across multiple Python components. If two
components on a system relied on different versions of a package, there
could be a conflict. Instead of managing multiple versions of a package
simultaneously, Python and venv take the route that it is easier
to just keep them separate so there is no potential for conflicts.

Very early in the build process, a venv is created inside the
:term:`object directory`. The venv is configured such that it can
find all the Python packages in the source tree. The code for this lives
in ``mach.site``.

Deficiencies
------------

There are numerous deficiencies with the way virtual environments are
handled in the build system.

* mach reinvents the venv.

  There is code in ``build/mach_initialize.py`` that configures ``sys.path``
  much the same way the venv does. There are various bugs tracking
  this. However, no clear solution has yet been devised. It's not a huge
  problem and thus not a huge priority.

* They aren't preserved across copies and packaging.

  If you attempt to copy an entire tree from one machine to another or
  from one directory to another, chances are the venv will fall
  apart. It would be nice if we could preserve it somehow. Instead of
  actually solving portable venv, all we really need to solve is
  encapsulating the logic for populating the venv along with all
  dependent files in the appropriate place.

* .pyc files written to source directory.

  We rely heavily on ``.pth`` files in our venv. A ``.pth`` file
  is a special file that contains a list of paths. Python will take the
  set of listed paths encountered in ``.pth`` files and add them to
  ``sys.path``.

  When Python compiles a ``.py`` file to bytecode, it writes out a
  ``.pyc`` file so it doesn't have to perform this compilation again.
  It puts these ``.pyc`` files alongside the ``.pyc`` file. Python
  provides very little control for determining where these ``.pyc`` files
  go, even in Python 3 (which offers customer importers).

  With ``.pth`` files pointing back to directories in the source tree
  and not the object directory, ``.pyc`` files are created in the source
  tree. This is bad because when Python imports a module, it first looks
  for a ``.pyc`` file before the ``.py`` file. If there is a ``.pyc``
  file but no ``.py`` file, it will happily import the module. This
  wreaks havoc during file moves, refactoring, etc.

  There are various proposals for fixing this. See bug 795995.

Installing Python Manually
==========================

We highly recommend you use your system's package manager or a
well-supported 3rd party package manager to install Python for you. If
these are not available to you, we recommend the following tools for
installing Python:

* `buildout.python <https://github.com/collective/buildout.python>`_
* `pyenv <https://github.com/yyuu/pyenv>`_
* An official installer from http://www.python.org.

If all else fails, consider compiling Python from source manually. But this
should be viewed as the least desirable option.

Common Issues with Python
=========================

Upgrading your Python distribution breaks the venv
--------------------------------------------------------

If you upgrade the Python distribution (e.g. install Python 3.6.15
from 3.6.9), chances are parts of the venv will break.
This commonly manifests as a cryptic ``Cannot import XXX`` exception.
More often than not, the module being imported contains binary/compiled
components.

If you upgrade or reinstall your Python distribution, we recommend
clobbering your build.

Packages installed at the system level conflict with build system's
-------------------------------------------------------------------

It is common for people to install Python packages using ``sudo`` (e.g.
``sudo pip install psutil``) or with the system's package manager
(e.g. ``apt-get install python-mysql``.

A problem with this is that packages installed at the system level may
conflict with the package provided by the source tree. As of bug 907902
and changeset f18eae7c3b27 (September 16, 2013), this should no longer
be an issue since the venv created as part of the build doesn't
add the system's ``site-packages`` directory to ``sys.path``. However,
poorly installed packages may still find a way to creep into the mix and
interfere with our venv.

As a general principle, we recommend against using your system's package
manager or using ``sudo`` to install Python packages. Instead, create
virtual environments and isolated Python environments for all of your
Python projects.

Python on $PATH is not appropriate
----------------------------------

Tools like ``mach`` will look for Python by performing ``/usr/bin/env
python`` or equivalent. Please be sure the appropriate Python 2.7.3+
path is on $PATH. On OS X, this likely means you'll need to modify your
shell's init script to put something ahead of ``/usr/bin``.

---

### Build Docs Rust (`build/docs/rust.rst`)

.. _rust:

==============================
Including Rust Code in Firefox
==============================

This page explains how to add, build, link, and vendor Rust crates.

The `code documentation <../../writing-rust-code>`_ explains how to write and
work with Rust code in Firefox. The
`test documentation <../../testing-rust-code>`_ explains how to test and debug
Rust code in Firefox.

Linking Rust crates into libxul
===============================

Rust crates that you want to link into libxul should be listed in the
``dependencies`` section of
:searchfox:`toolkit/library/rust/shared/Cargo.toml`.
You must also add an ``extern crate`` reference to
:searchfox:`toolkit/library/rust/shared/lib.rs`.
This ensures that the Rust code will be linked properly into libxul as well
as the copy of libxul used for gtests. (Even though Rust 2018 mostly doesn't
require ``extern crate`` declarations, these ones are necessary because the
gkrust setup is non-typical.)

After adding your crate, execute ``cargo update -p gkrust-shared`` to update
the ``Cargo.lock`` file. You will also need to do this any time you change the
dependencies in a ``Cargo.toml`` file. If you don't, you will get a build error
saying **"error: the lock file /home/njn/moz/mc3/Cargo.lock needs to be updated
but --frozen was passed to prevent this"**.

By default, all Cargo packages in the mozilla-central repository are part of
the same
:searchfox:`workspace <toolkit/library/rust/shared/lib.rs>`
and will share the ``Cargo.lock`` file and ``target`` directory in the root of
the repository.  You can change this behavior by adding a path to the
``exclude`` list in the top-level ``Cargo.toml`` file.  You may want to do
this if your package's development workflow includes dev-dependencies that
aren't needed by general Firefox developers or test infrastructure.

The actual build mechanism is as follows. The build system generates a special
'Rust unified library' crate, compiles that to a static library
(``libgkrust.a``), and links that into libxul, so all public symbols will be
available to C++ code. Building a static library that is linked into a dynamic
library is easier than building dynamic libraries directly, and it also avoids
some subtle issues around how mozalloc works that make the Rust dynamic library
path a little wonky.

Linking Rust crates into something else
=======================================

To link Rust code into libraries other than libxul, create a directory with a
``Cargo.toml`` file for your crate, and a ``moz.build`` file that contains:

.. code-block:: python

    RustLibrary('crate_name')

where ``crate_name`` matches the name from the ``[package]`` section of your
``Cargo.toml``. You can refer to :searchfox:`the moz.build file <mozilla-central/rev/603b9fded7a11ff213c0f415198cd637b7c86614:toolkit/library/rust/moz.build#9>` and :searchfox:`the Cargo.toml file <mozilla-central/rev/603b9fded7a11ff213c0f415198cd637b7c86614:toolkit/library/rust/Cargo.toml>` that are used for libxul.

You can then add ``USE_LIBS += ['crate_name']`` to the ``moz.build`` file
that defines the binary as you would with any other library in the tree.

.. important::

    You cannot link a Rust crate into an intermediate library that will be
    eventually linked into libxul. The build system enforces that only a single
    ``RustLibrary`` may be linked into a binary. If you need to do this, you
    will have to add a ``RustLibrary`` to link to any standalone binaries that
    link the intermediate library, and also add the Rust crate to the libxul
    dependencies as in `linking Rust Crates into libxul`_.

Conditional compilation
========================

Edit :searchfox:`tool/library/rust/gkrust-features.mozbuild <toolkit/library/rust/gkrust-features.mozbuild>`
to expose build flags as Cargo features.

Standalone Rust programs
========================

It is also possible to build standalone Rust programs. First, put the Rust
program (including the ``Cargo.toml`` file and the ``src`` directory) in its
own directory, and add an empty ``moz.build`` file to the same directory.

Then, if the standalone Rust program must run on the compile target (e.g.
because it's shipped with Firefox) then add this rule to the ``moz.build``
file:

.. code-block:: python

    RUST_PROGRAMS = ['prog_name']

where *prog_name* is the name of the executable as specified in the
``Cargo.toml`` (and probably also matches the name of the directory).

Otherwise, if the standalone Rust program must run on the compile host (e.g.
because it's used to build Firefox but not shipped with Firefox) then do the
same thing, but use ``HOST_RUST_PROGRAMS`` instead of ``RUST_PROGRAMS``.

Where should I put my crate?
============================

If your crate's canonical home is mozilla-central, you can put it next to the
related code in the appropriate directory.

If your crate is mirrored into mozilla-central from another repository, and
will not be actively developed in mozilla-central, you can simply list it
as a ``crates.io``-style dependency with a version number, and let it be
vendored into the ``third_party/rust`` directory.

If your crate is mirrored into mozilla-central from another repository, but
will be actively developed in both locations, you should send mail to the
dev-builds mailing list to start a discussion on how to meet your needs.

Third-party crate dependencies
==============================

Third-party dependencies for in-tree Rust crates are *vendored* into the
``third_party/rust`` directory of mozilla-central. This means that a copy of
each third-party crate's code is committed into mozilla-central. As a result,
building Firefox does not involve downloading any third-party crates.

If you add a dependency on a new crate you must run ``mach vendor rust`` to
vendor the dependencies into that directory. (Note that ``mach vendor rust``
`may not work as well on Windows <https://bugzilla.mozilla.org/show_bug.cgi?id=1938341>`_
as on other platforms.)

When it comes to checking the suitability of third-party code for inclusion
into mozilla-central, keep the following in mind.

- ``mach vendor rust`` will check that the licenses of all crates are suitable.
- ``mach vendor rust`` will run ``cargo vet`` to ensure that the crates have been audited. If not,
  you will have to audit them using ``mach cargo vet`` to check that the code looks reasonable
  (especially unsafe code) and that there are reasonable tests. All vendored crates must be audited.
- Third-party crate tests aren't run, which means that large test fixtures will
  bloat mozilla-central. Consider working with upstream to mark those test
  fixtures with ``[package] exclude = ...`` as described
  `here <https://doc.rust-lang.org/cargo/reference/manifest.html#the-exclude-and-include-fields>`_.
- If you specify a dependency on a branch, pin it to a specific revision,
  otherwise other people will get unexpected changes when they run ``./mach
  vendor rust`` any time the branch gets updated. See `bug 1612619
  <https://bugzil.la/1612619>`_ for a case where such a problem was fixed.
- Other than that, there is no formal sign-off procedure, but one may be added
  in the future.

Note that all dependencies will be vendored, even ones that aren't used due to
disabled features. It's possible that multiple versions of a crate will end up
vendored into mozilla-central.

Patching third-party crates
===========================

Sometimes you might want to temporarily patch a third-party crate, for local
builds or for a try push.

To do this, first add an entry to the ``[patch.crates-io]`` section of the
top-level ``Cargo.toml`` that points to the crate within ``third_party``. For
example

.. code-block:: toml

    bitflags = { path = "third_party/rust/bitflags" }

Next, run ``cargo update -p $CRATE_NAME --precise $VERSION``, where
``$CRATE_NAME`` is the name of the patched crate, and ``$VERSION`` is its
version number. This will update the ``Cargo.lock`` file.

Then, make the local changes to the crate.

Finally, make sure you don't accidentally land the changes to the crate or the
``Cargo.lock`` file.

For an example of a more complex workflow involving a third-party crate, see
:searchfox:`mp4parse-rust/README.md <media/mp4parse-rust/README.md>`.
It describes the workflow for a crate that is hosted on GitHub, and for which
changes are made via GitHub pull requests, but all pull requests must also be
tested within mozilla-central before being merged.

---

### Build Docs Sccache Dist (`build/docs/sccache-dist.rst`)

.. _sccache_dist:

==================================
Distributed sccache (sccache-dist)
==================================

`sccache <https://github.com/mozilla/sccache>`_ is a ccache-like tool written in
Rust by Mozilla and many contributors.

sccache-dist, its distributed variant, elevates this functionality by enabling
the distribution and caching of Rust compilations across multiple machines.
Please consider using sccache-dist when you have several machines
compiling Firefox on the same network.

The steps for setting up your machine as an sccache-dist server are detailed below.

In addition to improved security properties, distributed sccache offers
distribution and caching of rust compilation, so it should be an improvement
above and beyond what we see with icecc. Build servers run on Linux and
distributing builds is currently supported from Linux, macOS, and Windows.


Steps for distributing a build as an sccache-dist client
========================================================

Start by following the instructions at https://github.com/mozilla/sccache/blob/master/docs/DistributedQuickstart.md#configure-a-client
to configure your sccache distributed client.
*NOTE* If you're distributing from Linux a toolchain will be packaged
automatically and provided to the build server. If you're distributing from
Windows or macOS, start by using the cross-toolchains provided by
``./mach bootstrap`` rather than attempting to use ``icecc-create-env``.
sccache 0.2.12 or above is recommended, and the auth section of your config
must read::

    [dist.auth]
    type = "mozilla"

* If you're compiling from a macOS client, there are a handful of additional
  considerations outlined here:
  https://github.com/mozilla/sccache/blob/master/docs/DistributedQuickstart.md#considerations-when-distributing-from-macos.

  Run ``./mach bootstrap`` to download prebuilt toolchains to
  ``~/.mozbuild/clang-dist-toolchain.tar.xz`` and
  ``~/.mozbuild/rustc-dist-toolchain.tar.xz``. This is an example of the paths
  that should be added to your client config to specify toolchains to build on
  macOS, located at ``~/Library/Application Support/Mozilla.sccache/config``::

    [[dist.toolchains]]
    type = "path_override"
    compiler_executable = "/path/to/home/.rustup/toolchains/stable-x86_64-apple-darwin/bin/rustc"
    archive = "/path/to/home/.mozbuild/rustc-dist-toolchain.tar.xz"
    archive_compiler_executable = "/builds/worker/toolchains/rustc/bin/rustc"

    [[dist.toolchains]]
    type = "path_override"
    compiler_executable = "/path/to/home/.mozbuild/clang/bin/clang"
    archive = "/path/to/home/.mozbuild/clang-dist-toolchain.tar.xz"
    archive_compiler_executable = "/builds/worker/toolchains/clang/bin/clang"

    [[dist.toolchains]]
    type = "path_override"
    compiler_executable = "/path/to/home/.mozbuild/clang/bin/clang++"
    archive = "/path/to/home/.mozbuild/clang-dist-toolchain.tar.xz"
    archive_compiler_executable = "/builds/worker/toolchains/clang/bin/clang"

  Note that the version of ``rustc`` found in ``rustc-dist-toolchain.tar.xz``
  must match the version of ``rustc`` used locally. The distributed archive
  will contain the version of ``rustc`` used by automation builds, which may
  lag behind stable for a few days after Rust releases, which is specified by
  the task definition in
  `this file <https://hg.mozilla.org/mozilla-central/file/tip/taskcluster/kinds/toolchain/dist-toolchains.yml>`_.
  For instance, to specify 1.37.0 rather than the current stable, run
  ``rustup toolchain add 1.37.0`` and point to
  ``/path/to/home/.rustup/toolchains/1.37.0-x86_64-apple-darwin/bin/rustc`` in your
  client config.

  The build system currently requires an explicit target to be passed with
  ``HOST_CFLAGS`` and ``HOST_CXXFLAGS`` e.g.::

    export HOST_CFLAGS="--target=x86_64-apple-darwin16.0.0"
    export HOST_CXXFLAGS="--target=x86_64-apple-darwin16.0.0"

* Compiling from a Windows client is supported but hasn't seen as much testing
  as other platforms. The following example mozconfig can be used as a guide::

    ac_add_options CCACHE="C:/Users//.mozbuild/sccache/sccache.exe"

    export CC="C:/Users//.mozbuild/clang/bin/clang-cl.exe --driver-mode=cl"
    export CXX="C:/Users//.mozbuild/clang/bin/clang-cl.exe --driver-mode=cl"
    export HOST_CC="C:/Users//.mozbuild/clang/bin/clang-cl.exe --driver-mode=cl"
    export HOST_CXX="C:/Users//.mozbuild/clang/bin/clang-cl.exe --driver-mode=cl"

  The client config should be located at
  ``~/AppData/Roaming/Mozilla/sccache/config/config``, and as on macOS custom
  toolchains should be obtained with ``./mach bootstrap`` and specified in the
  client config, for example::

    [[dist.toolchains]]
    type = "path_override"
    compiler_executable = "C:/Users//.mozbuild/clang/bin/clang-cl.exe"
    archive = "C:/Users//.mozbuild/clang-dist-toolchain.tar.xz"
    archive_compiler_executable = "/builds/worker/toolchains/clang/bin/clang"

    [[dist.toolchains]]
    type = "path_override"
    compiler_executable = "C:/Users//.rustup/toolchains/stable-x86_64-pc-windows-msvc/bin/rustc.exe"
    archive = "C:/Users//.mozbuild/rustc-dist-toolchain.tar.xz"
    archive_compiler_executable = "/builds/worker/toolchains/rustc/bin/rustc"

* Add the following to your mozconfig::

    ac_add_options CCACHE=/path/to/home/.mozbuild/sccache/sccache

  If you're compiling from a macOS client, you might need some additional configuration::

    # Set the target flag to Darwin
    export CFLAGS="--target=x86_64-apple-darwin16.0.0"
    export CXXFLAGS="--target=x86_64-apple-darwin16.0.0"
    export HOST_CFLAGS="--target=x86_64-apple-darwin16.0.0"
    export HOST_CXXFLAGS="--target=x86_64-apple-darwin16.0.0"

    # Specify the macOS SDK to use
    ac_add_options --with-macos-sdk=/path/to/MacOSX-SDKs/MacOSX13.3.sdk

  You can get the right macOS SDK by downloading an old version of XCode from
  `developer.apple.com <https://developer.apple.com>`_ and unpacking the SDK
  from it.

* When attempting to get your client running, the output of ``sccache -s`` should
  be consulted to confirm compilations are being distributed. To receive helpful
  logging from the local daemon in case they aren't, run
  ``SCCACHE_NO_DAEMON=1 SCCACHE_START_SERVER=1 SCCACHE_LOG=sccache=trace path/to/sccache``
  in a terminal window separate from your build prior to building. *NOTE* use
  ``RUST_LOG`` instead of ``SCCACHE_LOG`` if your build of ``sccache`` does not
  include `pull request 822
  <https://github.com/mozilla/sccache/pull/822>`_. (``sccache`` binaries from
  ``mach bootstrap`` do include this PR.)

* Run ``./mach build -j<value>`` with an appropriately large ``<value>``.
  ``sccache --dist-status`` should provide the number of cores available to you
  (or a message if you're not connected). In the future this will be integrated
  with the build system to automatically select an appropriate value.

This should be enough to distribute your build and replace your use of icecc.
Bear in mind there may be a few speedbumps, and please ensure your version of
sccache is current before investigating further. Please see the common questions
section below and ask for help if anything is preventing you from using it over
email (dev-builds), on slack in #sccache, or in #build on irc.

Steps for setting up a server
=============================

Build servers must run linux and use bubblewrap 0.3.0+ for sandboxing of compile
processes. This requires a kernel 4.6 or greater, so Ubuntu 18+, RHEL 8, or
similar.

* Run ``./mach bootstrap`` or
  ``./mach artifact toolchain --from-build linux64-sccache`` to acquire a recent
  version of ``sccache-dist``. Please use a ``sccache-dist`` binary acquired in
  this fashion to ensure compatibility with statically linked dependencies.

* The instructions at https://github.com/mozilla/sccache/blob/master/docs/DistributedQuickstart.md#configure-a-build-server
  should contain everything else required to configure and run the server.

  *NOTE* Port 10500 will be used by convention for builders.
  Please use port 10500 in the ``public_addr`` section of your builder config.

  Extra logging may be helpful when setting up a server. To enable logging,
  run your server with
  ``sudo env SCCACHE_LOG=sccache=trace ~/.mozbuild/sccache/sccache-dist server --config ~/.config/sccache/server.conf``
  (or similar). *NOTE* ``sudo`` *must* come before setting environment variables
  for this to work. *NOTE* use ``RUST_LOG`` instead of ``SCCACHE_LOG`` if your
  build of ``sccache`` does not include `pull request 822
  <https://github.com/mozilla/sccache/pull/822>`_. (``sccache`` binaries from
  ``mach bootstrap`` do include this PR.)


Common questions/considerations
===============================

* My build is still slow: scache-dist can only do so much with parts of the
  build that aren't able to be parallelized. To start debugging a slow build,
  ensure the "Successful distributed compilations" line in the output of
  ``sccache -s`` dominates other counts. For a full build, at least a 2-3x
  improvement should be observed.

* My build output is incomprehensible due to a flood of warnings: clang will
  treat some warnings differently when it's fed preprocessed code in a separate
  invocation (preprocessing occurs locally with sccache-dist). Adding
  ``rewrite_includes_only = true`` to the ``dist`` section of your client config
  will improve this; however, setting this will cause build failures with a
  commonly deployed version of ``glibc``. This option will default to ``true``
  once the fix is more widely available. Details of this fix can be found in
  `this patch <https://sourceware.org/ml/libc-alpha/2019-11/msg00431.html>`_.

* My build fails with a message about incompatible versions of rustc between
  dependent crates: if you're using a custom toolchain check that the version
  of rustc in your ``rustc-dist-toolchain.tar.xz`` is the same as the version
  you're running locally.

---

### Build Docs Slow (`build/docs/slow.rst`)

.. _slow:

==================================
Why the Build System might be slow
==================================

A common complaint about the build system is that it can be slow. There are
many reasons contributing to its slowness.
However, on modern hardware, Firefox can be built in less than 10 minutes.

First, it is important to distinguish between a :term:`clobber build`
and an :term:`incremental build`. The reasons for why each are slow can
be different.

The build does a lot of work
============================

It may not be obvious, but the main reason the build system is slow is
because it does a lot of work! The source tree consists of a few
thousand C++ files. On a modern machine, we spend over 120 minutes of CPU
core time compiling files! So, if you are looking for the root cause of
slow clobber builds, look at the sheer volume of C++ files in the tree.

You don't have enough CPU cores and MHz
=======================================

The build should be CPU bound. If the build system maintainers are
optimizing the build system perfectly, every CPU core in your machine
should be 100% saturated during a build. While this isn't currently the
case (keep reading below), generally speaking, the more CPU cores you
have in your machine and the more total MHz in your machine, the better.

**We highly recommend building with no fewer than 4 physical CPU
cores.** Please note the *physical* in this sentence. Hyperthreaded
cores (an Intel Core i7 will report 8 CPU cores but only 4 are physical
for example) only yield at most a 1.25x speedup per core.

This cause impacts both clobber and incremental builds.

You are building with a slow I/O layer
======================================

The build system can be I/O bound if your I/O layer is slow. Linking
libxul on some platforms and build architectures can perform gigabytes
of I/O.

To minimize the impact of slow I/O on build performance, **we highly
recommend building with an SSD.** Power users with enough memory may opt
to build from a RAM disk. Mechanical disks should be avoided if at all
possible.

Some may dispute the importance of an SSD on build times. It is true
that the beneficial impact of an SSD can be mitigated if your system has
lots of memory and the build files stay in the page cache. However,
operating system memory management is complicated. You don't really have
control over what or when something is evicted from the page cache.
Therefore, unless your machine is a dedicated build machine or you have
more memory than is needed by everything running on your machine,
chances are you'll run into page cache eviction and you I/O layer will
impact build performance. That being said, an SSD certainly doesn't
hurt build times. And, anyone who has used a machine with an SSD will
tell you how great of an investment it is for performance all around the
operating system. On top of that, some automated tests are I/O bound
(like those touching SQLite databases), so an SSD will make tests
faster.

This cause impacts both clobber and incremental builds.

You don't have enough memory
============================

The build system allocates a lot of memory, especially when building
many things in parallel. If you don't have enough free system memory,
the build will cause swap activity, slowing down your system and the
build. Even if you never get to the point of swapping, the build system
performs a lot of I/O and having all accessed files in memory and the
page cache can significantly reduce the influence of the I/O layer on
the build system.

**We recommend building with no less than 8 GB of system memory.** As
always, the more memory you have, the better. For a bare bones machine
doing nothing more than building the source tree, anything more than 16
GB is likely entering the point of diminishing returns.

This cause impacts both clobber and incremental builds.

You are building on Windows
===========================

New processes on Windows are about a magnitude slower to spawn than on
UNIX-y systems such as Linux. This is because Windows has optimized new
threads while the \*NIX platforms typically optimize new processes.
Anyway, the build system spawns thousands of new processes during a
build. Parts of the build that rely on rapid spawning of new processes
are slow on Windows as a result. This is most pronounced when running
*configure*. The configure file is a giant shell script and shell
scripts rely heavily on new processes. This is why configure
can run over a minute slower on Windows.

Another reason Windows builds are slower is because Windows lacks proper
symlink support. On systems that support symlinks, we can generate a
file into a staging area then symlink it into the final directory very
quickly. On Windows, we have to perform a full file copy. This incurs
much more I/O. And if done poorly, can muck with file modification
times, messing up build dependencies.

These issues impact both clobber and incremental builds.

make is inefficient
===================

Compared to modern build backends like Tup or Ninja, `make` is slow and
inefficient. We can only make `make` so fast. At some point, we'll hit a
performance plateau and will need to use a different tool to make builds
faster.

Please note that clobber and incremental builds are different. A clobber build
with `make` will likely be as fast as a clobber build with a modern build
system.

C++ header dependency hell
==========================

Modifying a *.h* file can have significant impact on the build system.
If you modify a *.h* that is used by 1000 C++ files, all of those 1000
C++ files will be recompiled.

Our code base has traditionally been sloppy managing the impact of
changed headers on build performance. Bug 785103 tracks improving the
situation.

This issue mostly impacts the times of an :term:`incremental build`.

A search/indexing service on your machine is running
====================================================

Many operating systems have a background service that automatically
indexes filesystem content to make searching faster. On Windows, you
have the Windows Search Service. On OS X, you have Finder.

These background services sometimes take a keen interest in the files
being produced as part of the build. Since the build system produces
hundreds of megabytes or even a few gigabytes of file data, you can
imagine how much work this is to index! If this work is being performed
while the build is running, your build will be slower.

OS X's Finder is notorious for indexing when the build is running. And,
it has a tendency to suck up a whole CPU core. This can make builds
several minutes slower. If you build with ``mach`` and have the optional
``psutil`` package built (it requires Python development headers - see
:ref:`python` for more) and Finder is running during a build, mach will
print a warning at the end of the build, complete with instructions on
how to fix it.

---

### Build Docs Snap (`build/docs/snap.rst`)

.. _snap:

======================
Firefox Snap Packaging
======================

This page explains interactions between Firefox and Snap packaging format.

Where is the upstream
=====================

The code reference itself is mozilla-central, but the packaging is being worked
within the `Canonical's firefox-snap repository <https://github.com/canonical/firefox-snap/>`_.

This packaging includes a few more bits and dependencies, including compiler.
It will also re-download the mercurial repository: this is on purpose.

Where to report bugs
====================

All bugs should be reported to Bugzilla's ``Third Party Packaging`` component,
and marked as blocking ``snap`` meta-bug.

Full build process
==================

There may be a few differences between a simple repack and a real full build of
the Snap, you can find mention of the repackage usage below.

The following steps should be enough, assuming you have properly setup:

 - ``snapcraft`` (see `quickstart doc <https://snapcraft.io/docs/snapcraft-quickstart>`_)
 - ``LXD`` (see `providers doc <https://snapcraft.io/docs/build-providers>`_)

While the documentation still refers to `Multipass`, the Firefox Snap and its
dependency had some requirements that made it better suited to use `LXD`.

When performing the checkout, please keep in mind the branch mapping:

 - `edge` is our `nightly`
 - `beta` is our `beta`
 - `stable` is our `release`
 - `esr` is our `esr`

.. code-block:: shell

    $ git clone https://github.com/canonical/firefox-snap --branch BRANCH
    $ snap run snapcraft

You should end up after some time with two files: ``firefox-XXX.snap`` and
``firefox-XXX.debug``. The first one is the package you will want to ``snap
install`` while the second one holds your debugging symbols.

You can then install the package:

.. code-block:: shell

    $ sudo snap install --name firefox --dangerous ./path/to/firefox-XXX.snap

If you want to have parallel installs, then you can change the `--name firefox`
to something else. This will be the name you use for ``snap run
installed-name``, e.g., ``--name firefox_nightly`` will require you to run
``snap run firefox_nightly``.

`Snap` has a notion of plugs and slots, and some gets automatically connected
in various ways, including depending on the ``Snap Sore`` itself, and if you
manually install as ``firefox`` it should reuse them (but you might do bad
things with your profile). If you install using another name, then the ``Snap
Store`` automatic connection will not happen and this can result in a broken
state. Inspecting ``snap connections firefox`` using a store-installed snap
should get your an accurate list that you can replicate.

Cross-compilation
=================

There is now support for cross-compilation for ``arm64``.
To produce cross-compiled version locally:

 - follow the steps above for building, except you need to pass
   ``--build-for=ARCH`` to ``snapcraft``
 - this needs ``snapcraft`` of at least v8.x
 - make sure you uncomment the ``##CROSS-COMPILATION##`` lines due to Launchpad
   limitations

Builds on Treeherder as well as Try pushes are also available using
cross-compilation. Tests on Treeherder will also be supported when ARM-based
workers will be available, confere `Bug 1855463
<https://bugzilla.mozilla.org/show_bug.cgi?id=1855463>`_.

What CI coverage
================

Currently, there are upstream-like builds on treeherder. They are scheduled as
a cron task daily and includes:

 - building opt/debug versions of the snap
 - building them on all branches
 - running a few selenium-based tests

The build definitions :searchfox:`are based on docker <mozilla-central/rev/3c72de9280ec57dc55c24886c6334d9e340500e8:taskcluster/docker/snap-coreXX-build/Dockerfile>`.

It should be noted that for the moment, all tasks needs to run under docker.
However, this setup is not working for `Snap` since it interacts with `SystemD`
which does not work under `Docker`. This is why the installation is handled by
:searchfox:`the install-snap script <mozilla-central/rev/3c72de9280ec57dc55c24886c6334d9e340500e8:taskcluster/docker/snap-coreXX-build/install-snap.sh>`
rather than plain `sudo snap install`, and also why we need to run `snap` in
`destructive mode` (which is fine since we are within a docker container). This
does not apply to the tests case which relies on newly-available wayland
virtual machines.

Outside the build oddities because of the setup, it should be noted that those
builds are as close as possible to upstream. This means:

 - the mozilla-central hash they run against is not matching the source code it
   builds from, and one should inspect the build log to see the mercurial clone
   step
 - it builds using the clang build within the snap definition

The tests are defined :searchfox:`within the docker subdirectory <mozilla-central/rev/3c72de9280ec57dc55c24886c6334d9e340500e8:taskcluster/docker/snap-coreXX-build/snap-tests/tests.sh>`.
They are using Selenium because this is what was used by pre-existing tests ran
on GitHub Actions from upstream.

Their coverage is ensuring that we get a basic working browser out of builds.
It includes some tests that previously were manually ran by QA.

How to hack on try
==================

Build and test tasks can be explored via ``mach try fuzzy --full`` by searching
for ``'snap 'upstream``. There is a bit of hacking for try to make sure we
actually don't re-download the mercurial repo and directly reuse the clone
generated by `run-task`, handled in the :searchfox:`run.sh script <mozilla-central/rev/3c72de9280ec57dc55c24886c6334d9e340500e8:taskcluster/docker/snap-coreXX-build/run.sh#61-72>`.

So pushing to try is basically just:

.. code-block:: shell

    $ mach try fuzzy --full -q "'snap 'upstream 'local"

Because of the build process, a full opt build will take around 1h45-2h while a
debug build will be around 60 minutes, the difference coming from the use of
PGO on opt builds.

If you need to reuse a package from the Snap Store or from the latest
mozilla-central or a specific successful build, you can use ``USE_SNAP_FROM_STORE_OR_MC`` en
variable ; setting it to ``store`` will download from the Snap Store (warning:
no debug builds on the Snap Store, so whatever ``debug`` variants we have will
be an ``opt`` build in fact), and setting to a TaskCluster index value will
download from the index. Set it to ``latest`` if you want latest, or explore
the TaskCluster index for others. Any ``try`` will be pulled from latest
``nightly`` while others will be fetched from their respective branches.

How to hack locally
===================

After a successful build, you can also build a Snap by performing a repackaging
using the ``mach repackage snap`` tool. This requires a ``snapcraft`` working
installation relying on ``LXD``, which installation steps are
`documented upstream <https://snapcraft.io/docs/build-providers>`_.

---

### Build Docs Sparse (`build/docs/sparse.rst`)

.. _build_sparse:

================
Sparse Checkouts
================

The Firefox repository is large: over 230,000 files. That many files
can put a lot of strain on machines, tools, and processes.

Some version control tools have the ability to only populate a
working directory / checkout with a subset of files in the repository.
This is called *sparse checkout*.

Various tools in the Firefox repository are configured to work
when a sparse checkout is being used.

Sparse Checkouts in Mercurial
=============================

Mercurial 4.3 introduced **experimental** support for sparse checkouts
in the official distribution (a Facebook-authored extension has
implemented the feature as a 3rd party extension for years).

To enable sparse checkout support in Mercurial, enable the ``sparse``
extension::

   [extensions]
   sparse =

The *sparseness* of the working directory is managed using
``hg debugsparse``. Run ``hg help debugsparse`` and ``hg help -e sparse``
for more info on the feature.

When a *sparse config* is enabled, the working directory only contains
files matching that config. You cannot ``hg add`` or ``hg remove`` files
outside the *sparse config*.

.. warning::

   Sparse support in Mercurial 4.3 does not have any backwards
   compatibility guarantees. Expect things to change. Scripting against
   commands or relying on behavior is strongly discouraged.

In-Tree Sparse Profiles
=======================

Mercurial supports defining the sparse config using files under version
control. These are called *sparse profiles*.

Essentially, the sparse profiles are managed just like any other file in
the repository. When you ``hg update``, the sparse configuration is
evaluated against the sparse profile at the revision being updated to.
From an end-user perspective, you just need to *activate* a profile once
and files will be added or removed as appropriate whenever the versioned
profile file updates.

In the Firefox repository, the ``build/sparse-profiles`` directory
contains Mercurial *sparse profiles* files.

Each *sparse profile* essentially defines a list of file patterns
(see ``hg help patterns``) to include or exclude. See
``hg help -e sparse`` for more.

Mach Support for Sparse Checkouts
=================================

``mach`` detects when a sparse checkout is being used and its
behavior may vary to accommodate this.

By default it is a fatal error if ``mach`` can't load one of the
``mach_commands.py`` files it was told to. But if a sparse checkout
is being used, ``mach`` assumes that file isn't part of the sparse
checkout and to ignore missing file errors. This means that
running ``mach`` inside a sparse checkout will only have access
to the commands defined in files in the sparse checkout.

Sparse Checkouts in Automation
==============================

``hg robustcheckout`` (the extension/command used to perform clones
and working directory operations in automation) supports sparse checkout.
However, it has a number of limitations over Mercurial's default sparse
checkout implementation:

* Only supports 1 profile at a time
* Does not support non-profile sparse configs
* Does not allow transitioning from a non-sparse to sparse checkout or
  vice-versa

These restrictions ensure that any sparse working directory populated by
``hg robustcheckout`` is as consistent and robust as possible.

``run-task`` (the low-level script for *bootstrapping* tasks in
automation) has support for sparse checkouts.

TaskGraph tasks using ``run-task`` can specify a ``sparse-profile``
attribute in YAML (or in code) to denote the sparse profile file to
use. e.g.::

   run:
       using: run-command
       command: <command>
       sparse-profile: taskgraph

This automagically results in ``run-task`` and ``hg robustcheckout``
using the sparse profile defined in ``build/sparse-profiles/<value>``.

Pros and Cons of Sparse Checkouts
=================================

The benefits of sparse checkout are that it makes the repository appear
to be smaller. This means:

* Less time performing working directory operations -> faster version
  control operations
* Fewer files to consult -> faster operations
* Working directories only contain what is needed -> easier to understand
  what everything does

Fewer files in the working directory also contributes to disadvantages:

* Searching may not yield hits because a file isn't in the sparse
  checkout. e.g. a *global* search and replace may not actually be
  *global* after all.
* Tools performing filesystem walking or path globbing (e.g.
  ``**/*.js``) may fail to find files because they don't exist.
* Various tools and processes make assumptions that all files in the
  repository are always available.

There can also be problems caused by mixing sparse and non-sparse
checkouts. For example, if a process in automation is using sparse
and a local developer is not using sparse, things may work for the
local developer but fail in automation (because a file isn't included
in the sparse configuration and not available to automation.
Furthermore, if environments aren't using exactly the same sparse
configuration, differences can contribute to varying behavior.

When Should Sparse Checkouts Be Used?
=====================================

Developers are discouraged from using sparse checkouts for local work
until tools for handling sparse checkouts have improved. In particular,
Mercurial's support for sparse is still experimental and various Firefox
tools make assumptions that all files are available. Developers should
use sparse checkout at their own risk.

The use of sparse checkouts in automation is a performance versus
robustness trade-off. Use of sparse checkouts will make automation
faster because machines will only have to manage a few thousand files
in a checkout instead of a few hundred thousand. This can potentially
translate to minutes saved per machine day. At the scale of thousands
of machines, the savings can be significant. But adopting sparse
checkouts will open up new avenues for failures. (See section above.)
If a process is isolated (in terms of file access) and well-understood,
sparse checkout can likely be leveraged with little risk. But if a
process is doing things like walking the filesystem and performing
lots of wildcard matching, the dangers are higher.

---

### Build Docs Supported Configurations (`build/docs/supported-configurations.rst`)

Supported Build Hosts and Targets
=================================

 ..  role:: strikethrough

There are three tiers of supported Firefox build hosts and targets.
These tiers represent the shared engineering priorities of the Mozilla project.

The "build host" is the machine that is performing the build of Firefox, and
the "build target" is the machine that will run the built Firefox application.
For example, if you were building Firefox for Android on your Linux computer, then the
Linux computer would be the "build host".

.. note::

   Sheriffs are in charge of monitoring the tree. Their definition for tiers
   is for automation jobs, which tells a developer what is expected of them when
   they land code. This document is about the tiers of supported build hosts and targets,
   which tells a person compiling/using Firefox what they can expect from Mozilla.
   See the `job tier definition <https://wiki.mozilla.org/Sheriffing/Job_Visibility_Policy#Overview_of_the_Job_Visibility_Tiers>`__ for more information.


.. _build_hosts:

Supported Build Hosts
---------------------

While we want to help users resolve build-related issues on their systems, we
are unable to help resolve build system issues on all possible operating
systems and versions.

.. _tier_1_hosts:

Tier-1 Hosts and Toolchains
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Support is available for the following **host operating systems** and versions
when building for a :ref:`Tier-1 Firefox build target<tier_1_targets>`, including
cross-compilation where available:

* Ubuntu Linux x86_64
    * Current stable release
    * Previous stable release
    * Current LTS release
* Debian Linux x86_64
    * Current stable release
    * Current testing release
* Fedora Linux x86_64
    * Current stable release
    * Previous stable release
* macOS Intel and M1
    * Current major macOS release
    * Previous major macOS release
* Windows x86_64
    * Windows 10 with MozillaBuild Environment
    * Windows 11 with MozillaBuild Environment

Tier-2 Hosts and Toolchains
^^^^^^^^^^^^^^^^^^^^^^^^^^^

In addition to the limitations outlined above in the Tier-1 list, our ability
to provide assistance with build issues using/targeting Tier-2
hosts/targets/compilers is not unbounded.

While we will endeavour to make a best effort to help resolve issues, you may
be referred to the relevant community maintainers for further support.

The Tier-2 hosts are:

* Other Linux x86_64 distributions and/or versions
* Older macOS versions
* Older Windows x86_64 versions

Tier-3 Hosts and Toolchains
^^^^^^^^^^^^^^^^^^^^^^^^^^^

We cannot provide any guarantees of assistance in resolving build issues using
or targeting Tier-3 platforms.


Supported Build Targets
-----------------------

.. _tier_1_targets:

Tier-1 Targets
^^^^^^^^^^^^^^

The term **"Tier-1 platform"** refers to those platforms - CPU
architectures and operating systems - that are the primary focus of
Firefox development efforts. Tier-1 platforms are fully supported by
Mozilla's `continuous integration processes <https://treeherder.mozilla.org/>`__ and the
:ref:`Pushing to Try`. Any proposed change to Firefox on these
platforms that results in build failures, test failures, performance
regressions or other major problems **will be reverted immediately**.


The **Tier-1 Firefox platforms** and their supported compilers are:

-  Android on Linux x86-64, ARMv7 and ARMv8-A (clang)
-  Linux x86-64 (gcc and clang), Linux/AArch64 (clang)
-  macOS 10.15 and later on x86-64 and AArch64 (clang)
-  Windows/x86, x86-64 and AArch64 (clang-cl)

Prior to Firefox 63, Windows/x86 and Windows/x86-64 relied on the MSVC
compiler; from **Firefox 63 onward MSVC is not supported**. Older 32-bit
x86 CPUs without SSE2 instructions such as the Pentium III and Athlon XP
are also **not considered Tier-1 platforms, and are not supported**.
Note also that while Windows/x86 and ARM/AArch64 are supported *as build
targets*, it is not possible to build Firefox *on* Windows/x86 or
Windows/AArch64 systems.

Tier-2 Targets
^^^^^^^^^^^^^^

**Tier-2 platforms** are actively maintained by the Mozilla community,
though with less rigorous requirements. Proposed changes resulting in
breakage or regressions limited to these platforms **may not immediately
result in reversion**. However, developers who break these platforms are
expected to work with platform maintainers to fix problems, and **may be
required to revert their changes** if a fix cannot be found.

The **Tier-2 Firefox platforms** and their supported compilers are:

-  Windows/x86 (mingw-clang) - maintained by Tom Ritter and Jacek Caban
   -

   -  *Note that some features of this platform are disabled, as they
      require MS COM or the w32api project doesn't expose the necessary
      Windows APIs.*

Tier-3 Targets
^^^^^^^^^^^^^^

**Tier-3 platforms** have a maintainer or community which attempt to
keep the platform working. These platforms are **not supported by our
continuous integration processes**, and **Mozilla does not routinely
test on these platforms**, nor do we block further development on the
outcomes of those tests.

At any given time a Firefox built from mozilla-central for these
platforms may or may not work correctly or build at all.

**Tier-3 Firefox platforms** include:

-  Linux on various CPU architectures including ARM variants not listed
   above, PowerPC, and x86 CPUs - maintained by various Linux distributions
-  FreeBSD/x86, x86-64, Aarch64 (clang) - `maintained by [email protected] <https://www.freshports.org/www/firefox/>`__
-  OpenBSD/x86, x86-64 (clang) - maintained by Landry Breuil
-  NetBSD/x86-64 (gcc) - maintained by David Laight
-  Solaris/x86-64, sparc64 (gcc) - maintained by Petr Sumbera
-  :strikethrough:`Windows/x86-64 (mingw-gcc)` - Unsupported due to
   requirements for clang-bindgen

If you're filing a bug against Firefox on a Tier-3 platform (or any
combination of OS, CPU and compiler not listed above) please bear in
mind that Mozilla developers do not reliably have access to non-Tier-1
platforms or build environments. To be actionable bug reports against
non-Tier-1 platforms should include as much information as possible to
help the owner of the bug determine the cause of the problem and the
proper solution. If you can provide a patch, a regression range or
assist in verifying that the developer's patches work for your platform,
that would help a lot towards getting your bugs fixed and checked into
the tree.

---

### Build Docs Telemetry (`build/docs/telemetry.rst`)

.. _buildtelemetry:

===============
Build Telemetry
===============

The build system (specifically, all the build tooling hooked
up to ``./mach``) has been configured to collect metrics data
points and errors for various build system actions. This data
helps drive team planning for the build team and ensure that
resources are applied to build processes that need them most.
You can adjust your telemetry settings by editing your
``~/.mozbuild/machrc`` file.

Glean Telemetry
===============

Mozbuild reports data using `Glean <https://mozilla.github.io/glean/>`_ via
:ref:`mach_telemetry`.  The metrics collected are documented :ref:`here<metrics>`.

Error Reporting
===============

``./mach`` uses `Sentry <https://sentry.io/welcome/>`_
to automatically report errors to `our issue-tracking dashboard
<https://sentry.prod.mozaws.net/operations/mach/>`_.

Information captured
++++++++++++++++++++

Sentry automatically collects useful information surrounding
the error to help the build team discover what caused the
issue and how to reproduce it. This information includes:

* Environmental information, such as the computer name, timestamp, Python runtime and Python module versions
* Process arguments
* The stack trace of the error, including contextual information:

    * The data contained in the exception
    * Functions and their respective source file names, line numbers
    * Variables in each frame
* `Sentry "Breadcrumbs" <https://docs.sentry.io/platforms/python/default-integrations/>`_,
  which are important events that have happened which help contextualize the error, such as:

    * An HTTP request has occurred
    * A subprocess has been spawned
    * Logging has occurred

Note that file paths may be captured, which include absolute paths (potentially including usernames).

---

### Build Docs Test Certificates (`build/docs/test_certificates.rst`)

.. _test_certificates:

===============================
Adding Certificates for Testing
===============================

Sometimes we need to write tests for scenarios that require custom client, server or certificate authority (CA) certificates. For that purpose, you can generate such certificates using ``build/pgo/genpgocert.py``.

The certificate specifications (and key specifications) are located in ``build/pgo/certs/``.

To add a new **server certificate**, add a ``${cert_name}.certspec`` file to that folder.
If it needs a non-default private key, add a corresponding ``${cert_name}.server.keyspec``.

For a new **client certificate**, add a ``${cert_name}.client.keyspec`` and corresponding ``${cert_name}.certspec``.

To add a new **CA**, add a ``${cert_name}.ca.keyspec`` as well as a corresponding ``${cert_name}.certspec`` to that folder.

.. hint::

   * The full syntax for .certspec files is documented at :searchfox:`security/manager/tools/pycert.py`

   * The full syntax for .keyspec files is documented at :searchfox:`security/manager/tools/pykey.py`

Then regenerate the certificates by running:::

   ./mach python build/pgo/genpgocert.py

These commands will modify cert9.db and key4.db, and if you have added a .keyspec file will generate a ``{$cert_name}.client`` or ``{$cert_name}.ca`` file.

**These files need to be committed.**

If you've created a new server certificate, you probably want to modify ``build/pgo/server-locations.txt`` to add a location with your specified certificate:::

   https://my-test.example.com:443           cert=${cert_name}

You will need to run ``./mach build`` again afterwards.

.. important::

   Make sure to exactly follow the naming conventions and use the same ``cert_name`` in all places

---

### Build Docs Test Manifests (`build/docs/test_manifests.rst`)

.. _test_manifests:

==============
Test Manifests
==============

Many test suites have their test metadata defined in files called
**test manifests**.

Test manifests are divided into two flavors: :ref:`manifestparser_manifests`
and :ref:`reftest_manifests`.

Naming Convention
=================

The build system does not enforce file naming for test manifest files.
However, the following convention is used.

mochitest.toml
   For the *plain* flavor of mochitests.

chrome.toml
   For the *chrome* flavor of mochitests.

browser.toml
   For the *browser chrome* flavor of mochitests.

a11y.toml
   For the *a11y* flavor of mochitests.

xpcshell.toml
   For *xpcshell* tests.

.. _manifestparser_manifests:

ManifestParser Manifests
==========================

ManifestParser manifests are essentially toml files that conform to a basic
set of assumptions.

The :doc:`reference documentation </mozbase/manifestparser>`
for manifestparser manifests describes the basic format of test manifests.

In summary, manifests are toml files with section names describing test files::

    ["test_foo.js"]
    ["test_bar.js"]

Keys under sections can hold metadata about each test::

    ["test_foo.js"]
    skip-if = ["os == 'win'"]
    ["test_foo.js"]
    skip-if = ["os == 'linux' && debug"]
    ["test_baz.js"]
    fail-if = [
      "os == 'mac'",
      "os == 'android'",
    ]

There is a special **DEFAULT** section whose keys/metadata apply to all
sections/tests::

    [DEFAULT]
    property = value

    ["test_foo.js"]

In the above example, **test_foo.js** inherits the metadata **property = value**
from the **DEFAULT** section.

Recognized Metadata
-------------------

Test manifests can define some common keys/metadata to influence behavior.
Those keys are as follows:

head
   List of files that will be executed before the test file. (Used in
   xpcshell tests.)

tail
   List of files that will be executed after the test file. (Used in
   xpcshell tests.)

support-files
   List of additional files required to run tests. This is typically
   defined in the **DEFAULT** section.

   Unlike other file lists, *support-files* supports a globbing mechanism
   to facilitate pulling in many files with minimal typing. This globbing
   mechanism is activated if an entry in this value contains a ``*``
   character. A single ``*`` will wildcard match all files in a directory.
   A double ``**`` will descend into child directories. For example,
   ``data/*`` will match ``data/foo`` but not ``data/subdir/bar`` where
   ``data/**`` will match ``data/foo`` and ``data/subdir/bar``.

   Support files starting with ``/`` are placed in a root directory, rather
   than a location determined by the manifest location. For mochitests,
   this allows for the placement of files at the server root. The source
   file is selected from the base name (e.g., ``foo`` for ``/path/foo``).
   Files starting with ``/`` cannot be selected using globbing.

   Some support files are used by tests across multiple directories. In
   this case, a test depending on a support file from another directory
   must note that dependency with the path to the required support file
   in its own **support-files** entry. These use a syntax where paths
   starting with ``!/`` will indicate the beginning of the path to a
   shared support file starting from the root of the srcdir. For example,
   if a manifest at ``dom/base/test/mochitest.toml`` has a support file,
   ``dom/base/test/server-script.sjs``, and a mochitest in
   ``dom/workers/test`` depends on that support file, the test manifest
   at ``dom/workers/test/mochitest.toml`` must include
   ``!/dom/base/test/server-script.sjs`` in its **support-files** entry.

generated-files
   List of files that are generated as part of the build and don't exist in
   the source tree.

   The build system assumes that each manifest file, test file, and file
   listed in **head**, **tail**, and **support-files** is static and
   provided by the source tree (and not automatically generated as part
   of the build). This variable tells the build system not to make this
   assumption.

   This variable will likely go away sometime once all generated files are
   accounted for in the build config.

   If a generated file is not listed in this key, a clobber build will
   likely fail.

dupe-manifest
   Record that this manifest duplicates another manifest.

   The common scenario is two manifest files will include a shared
   manifest file via the ``["include:file"]`` special section. The build
   system enforces that each test file is only provided by a single
   manifest. Having this key present bypasses that check.

   The value of this key is ignored.

skip-if
   Skip this test if the specified condition is true.
   See :ref:`manifest_filter_language`.

   Conditions can be specified on multiple lines, where each line is implicitly
   joined by a logical OR (``||``). This makes it easier to add comments to
   distinct failures. For example:

   .. parsed-literal::

      ["test_foo.js"]
      skip-if = [
          "os == 'mac' && fission",  # bug 123 - fails on fission
          "os == 'windows' && debug",  # bug 456 - hits an assertion
      ]

fail-if
   Expect test failure if the specified condition is true.
   See :ref:`manifest_filter_language`.

   Conditions can be specified on multiple lines (see ``skip-if``).

run-sequentially
   Run test sequentially if the specified condition is true.
   See :ref:`manifest_filter_language`.

   To always run a test sequentially, use ``run-sequentially = ["true"]``.

scheme
   Changes the scheme and domain from which the test runs. (Only used in mochitest suites)

   There are two possible values:
      - ``http`` (default): The test will run from http://mochi.test:8888
      - ``https``: The test will run from https://example.com:443

.. _manifest_filter_language:

Manifest Filter Language
------------------------

Some manifest keys accept a special filter syntax as their values. These
values are essentially boolean expressions that are evaluated at test
execution time.

The expressions can reference a well-defined set of variables, such as
``os`` and ``debug``. These variables are populated from the
``mozinfo.json`` file. For the full list of available variables, see
the :ref:`mozinfo documentation <mozinfo_attributes>`.

See
`the source <https://hg.mozilla.org/mozilla-central/file/default/testing/mozbase/manifestparser/manifestparser/manifestparser.py>`_ for the full documentation of the
expression syntax until it is documented here.

.. rstcheck: ignore-directives=todo
.. todo::

   Document manifest filter language.

.. _manifest_file_installation:

File Installation
-----------------

Files referenced by manifests are automatically installed into the object
directory into paths defined in
:py:func:`mozbuild.frontend.emitter.TreeMetadataEmitter._process_test_manifest`.

Relative paths resolving to parent directory (e.g.
``support-files = ../foo.txt`` have special behavior.

For ``support-files``, the file will be installed to the default destination
for that manifest. Only the file's base name is used to construct the final
path: directories are irrelevant.  Files starting with ``/`` are an exception,
these are installed relative to the root of the destination; the base name is
instead used to select the file..

For all other entry types, the file installation is skipped.

.. _reftest_manifests:

Reftest Manifests
=================

See `MDN <https://developer.mozilla.org/en-US/docs/Creating_reftest-based_unit_tests>`_.

---

### Build Docs Toolchains Update Policy (`build/docs/toolchains-update-policy.rst`)

.. _build_toolchains-update-policy:

========================
Toolchains update policy
========================

We document here the decision making and planning around when we update the
various toolchains used and required to build Firefox.

Rust
====

The Rust update policy is documented in a
:ref:`separate document<Rust Update Policy>`.

Clang
=====

*We ship official stable Firefox with a released Clang.*

As a general rule, we update the Clang compiler version used to build Firefox
Nightly as soon as possible, considering the constraint that the Clang compiler
and the Rust compiler need to use the same version of LLVM.

We don't upgrade the Clang version in the beta or release branches of Firefox.

The following exception applies:

- We may skip the update (or backout the update) if major problems are
  encountered (typically, we’ve had to do so because of build problems, crash
  reporting bustage, or performance issues).

*Local developer builds use the same version as used for the official builds.*

Minimum Supported Clang Version
-------------------------------

*We will update the Minimum Supported Clang Version to match the smallest LLVM
version supported by the Minimum Supported Rust Version.*

That smallest LLVM version can be found in the `check_llvm_version` function in
the `src/bootstrap/src/core/build_steps/llvm.rs` source file in the Rust
compiler source code for the Minimum Supported Rust Version.

Rationale
^^^^^^^^^

Downstreams that need to procure a Rust compiler will also need an LLVM
toolchain, which in practice includes a Clang with the same version. Since Rust
enforces a minimum supported LLVM version, setting our Minimum Supported Clang
Version to match that same baseline makes the requirements straightforward: a
single minimum LLVM version covers both Rust and C/C++ compilation.

This approach strikes a balance between the constraints faced by downstreams in
acquiring and maintaining toolchains, and our own need to use reasonably modern
compilers for C and C++ code.

libstdc++
=========

*We build stable Firefox with a libstdc++ that allows to provide the necessary
binary compatibility*

The binary compatibility is defined by the Firefox system requirements on Linux.
Those can be adjusted but a balance must be made between the breadth of systems
supported by Firefox builds, and the desired C++ features on the development
side. As of writing there isn't a policy describing exactly how the system
requirements are updated, yet.

Tricks may be put in place to guarantee the required binary compatibility with
older versions of libstdc++ than the one used to build.
(see `build/unix/stdc++compat`)

GCC
===

*The Minimum Supported GCC Version matches the version of libstdc++ above*

GCC and libstdc++ are, generally speaking, coupled, and it can be difficult to
use a version of GCC that doesn't match the version of libstdc++. As such, we
don't support building with a version of GCC older than the version of
libstdc++ Firefox is built against by default (from the development sysroot).

---

### Build Docs Toolchains (`build/docs/toolchains.rst`)

.. _build_toolchains:

===========================
Creating Toolchain Archives
===========================

There are various scripts in the repository for producing archives
of the build tools (e.g. compilers and linkers) required to build.

Clang and Rust
==============

To modify the toolchains used for a particular task, you may need several
things:

1. A :searchfox:`build task <mozilla-central/rev/168c45a7acc44e9904cfd4eebcb9eb080e05699c:taskcluster/ci/build/linux.yml#5-45>`

2. Which uses a toolchain task

    - :searchfox:`clang toolchain <mozilla-central/rev/168c45a7acc44e9904cfd4eebcb9eb080e05699c:taskcluster/ci/toolchain/clang.yml#51-72>`
    - :searchfox:`rust toolchain <mozilla-central/rev/168c45a7acc44e9904cfd4eebcb9eb080e05699c:taskcluster/ci/toolchain/rust.yml#57-74>`

3. Which uses a git fetch

    - :searchfox:`clang fetch <mozilla-central/rev/168c45a7acc44e9904cfd4eebcb9eb080e05699c:taskcluster/ci/fetch/toolchains.yml#413-418>`
    - (from-source ``dev`` builds only) :searchfox:`rust fetch <mozilla-central/rev/168c45a7acc44e9904cfd4eebcb9eb080e05699c:taskcluster/ci/fetch/toolchains.yml#434-439>`

4. (clang only) Which uses a :searchfox:`config json <mozilla-central/rev/168c45a7acc44e9904cfd4eebcb9eb080e05699c:build/build-clang/clang-linux64.json>`

5. Which takes :searchfox:`patches <mozilla-central/rev/168c45a7acc44e9904cfd4eebcb9eb080e05699c:build/build-clang/static-llvm-symbolizer.patch>` you may want to apply.

For the most part, you should be able to accomplish what you want by
copying/editing the existing examples in those files.

Clang
-----

Building clang is handled by :searchfox:`build-clang.py `, which uses several resources
in the :searchfox:`build-clang ` directory. Read the :searchfox:`build-clang README ` for more
details.

Note for local builds: build-clang.py can be run on developer machines but its
lengthy multi-stage build process is unnecessary for most local development. The
upstream `LLVM Getting Started Guide`_ has instructions on how to build
clang more directly.

.. _LLVM Getting Started Guide: https://llvm.org/docs/GettingStarted.html

Rust
----

Rust builds are handled by :searchfox:`repack_rust.py <taskcluster/scripts/misc/repack_rust.py>`. The primary purpose of
that script is to download prebuilt tarballs from the Rust project.

It uses the same basic format as `rustup` for specifying the toolchain
(via ``--channel``):

- request a stable build with ``1.xx.y`` (e.g. ``1.47.0``)
- request a beta build with ``beta-yyyy-mm-dd`` (e.g. ``beta-2020-08-26``)
- request a nightly build with ``nightly-yyyy-mm-dd`` (e.g. ``nightly-2020-08-26``)
- request a build from `Rust's ci`_ with ``bors-$sha`` (e.g. ``bors-796a2a9bbe7614610bd67d4cd0cf0dfff0468778``)
- request a from-source build with ``dev``

Rust From Sourc