Technical Documentation: mozilla-firefox/firefox
ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference
Overview (README.md)
Firefox is a fast, reliable and private web browser from the non-profit Mozilla organization.
Contributing
To learn how to contribute to Firefox read the Firefox Contributors' Quick Reference document.
We use bugzilla.mozilla.org as our issue tracker, please file bugs there.
Resources
- Firefox Source Docs is our primary documentation repository
- Nightly development builds can be downloaded from Firefox Nightly page
If you have a question about developing Firefox, and can't find the solution
on Firefox Source Docs, you can try asking your question on Matrix at
chat.mozilla.org in the Introduction channel.
Index (`docs/index.md`)
Firefox Source Tree Documentation
:caption: Overview
:maxdepth: 2
{overview_doc}:caption: Getting Started
:maxdepth: 1
{setup_doc}:caption: Working On Firefox
:maxdepth: 2
{contributing_doc}:caption: Firefox User Guide
:maxdepth: 2
{user_guide}:caption: Source Code Documentation
:maxdepth: 2
{source_doc}:caption: The Firefox Build System
:maxdepth: 1
{build_doc}:caption: Testing & Test Infrastructure
:maxdepth: 1
{testing_doc}:caption: AI Agent Tools
:maxdepth: 1
{ai_agent_tools_doc}:caption: Releases & Updates
:maxdepth: 1
{release_doc}:caption: Localization & Internationalization
:maxdepth: 2
{l10n_doc}:caption: Firefox and Python
:maxdepth: 1
{python_doc}:caption: Metrics Collected in Firefox
:maxdepth: 1
{metrics_doc}Indices and tables
- {{ref}}
genindex - {{ref}}
modindex - {{ref}}
search
Accessible Docs Index (`accessible/docs/index.md`)
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 contains general information about accessibility and the accessibility team at Mozilla.
The Mochitest FAQ docs contain guidance on debugging a11y-checks failures and working with AccessibilityUtils when writing frontend test cases.
:maxdepth: 1
GuidelinesForNewContributors
Architecture
DocumentAccessibilityLifecycle
GeckoViewThreadTopography
ColorsAndHighContrastMode
HCMSettings
HCMMediaQueries
HCMCSSChecklist
TaggedPdfOutputBrowser Docs Index (`browser/docs/index.md`)
Firefox Front-end
This is the documentation for the code powering the Firefox Desktop front-end.
: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
components/sessionstore/docs/index
components/tabbrowser/docs/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
components/storybook/docs/README.typography.stories
/toolkit/themes/shared/design-system/docs/README.design-tokens.stories
components/backup/docs/index
components/sidebar/docs/index
components/mozcachedohttp/docs/index
desktop-launcher/index
app/pbproxy/private-browsing-proxy/index
/installation_dir_layout/indexBrowser Docs Overview (`browser/docs/overview.md`)
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 documentchrome://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, 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.
{doc}Read more <components/storybook/docs/README.reusable-widgets.stories>
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.
{doc}Read more
Search
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.
{doc}Read more
Firefox Sync and Application Services
Application services includes the sync engines and Firefox Accounts integration.
{doc}Read more </services/index>
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.
{doc}Read more </devtools/index>
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.
{doc}Read more </devtools-user/browser_toolbox/index>
Profiler
The Firefox Profiler is the way to measure the performance of your code. Go to
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.
{doc}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.
{doc}Read more </toolkit/mozapps/update/docs/index>
Build Docs Build Overview (`build/docs/build-overview.md`)
(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 ofconfigure 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 upconfig.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 aMakefile.
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 Index (`build/docs/index.md`)
Build System
Important Concepts
:maxdepth: 1
glossary
build-overview
supported-configurations
Mozconfig Files <mozconfigs>
mozbuild-files
mozbuild-symbols
files-metadata
Profile Guided Optimization <pgo>
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_certificatesintegrated development environment (IDE)
:maxdepth: 1
cppeclipse
visualstudiomozbuild
mozbuild is a Python package containing a lot of the code for the
Mozilla build system.
:maxdepth: 1
mozbuild/indexSnap Package
Snap is a packaging format
:maxdepth: 1
snapFlatpak Package
Flatpak is a packaging format
:maxdepth: 1
flatpak
chrome-registrationAi Agent Tools Index (`docs/ai-agent-tools/index.md`)
AI Agent Tools for Firefox Development
This section documents tools and workflows for using AI assistants to interact
with and test Firefox during development.
:maxdepth: 2
firefox-devtools-mcp
code-review-context
skillsBug Mgmt Index (`docs/bug-mgmt/index.md`)
Bug Handling
:maxdepth: 1
guides/index
policies/index
processes/indexRelated documentation
- bugzilla.mozilla.org documentation
- bugzilla.mozilla.org field
definitions - Lando
documentation - Mozilla Phabricator (Code Review)
documentation
Code Quality Index (`docs/code-quality/index.md`)
Code quality
Because Firefox is a complex piece of software, a lot of tools are
executed to identify issues at development phase.
In this document, we try to list these all tools.
:glob: true
:maxdepth: 1
static-analysis/index
lint/index
coding-style/index
typescript/index.. list-table:: C/C++
:header-rows: 1
:widths: 20 20 20 20 20
* - Tools
- Has autofixes
- Meta bug
- More info
- Upstream
* - Custom clang checker
-
-
- :searchfox:`Source <build/clang-plugin>`
-
* - Clang-Tidy
- Yes
- `bug 712350 <https://bugzilla.mozilla.org/show_bug.cgi?id=712350>`__
- :doc:`Static analysis <static-analysis/index>`
- https://clang.llvm.org/extra/clang-tidy/checks/list.html
* - Clang analyzer
-
- `bug 712350 <https://bugzilla.mozilla.org/show_bug.cgi?id=712350>`__
-
- https://clang-analyzer.llvm.org/
* - cpp virtual final
-
-
- :ref:`cpp virtual final <cpp-virtual-final>`
-
* - clang-format
- Yes
- `bug 1188202 <https://bugzilla.mozilla.org/show_bug.cgi?id=1188202>`__
- :doc:`coding-style/format_cpp_code_with_clang-format`
- https://clang.llvm.org/docs/ClangFormat.html.. list-table:: CSS
:widths: 20 20 20 20 20
:header-rows: 1
* - Tools
- Has autofixes
- Meta bug
- More info
- Upstream
* - Stylelint
- Yes
- `bug 1762027 <https://bugzilla.mozilla.org/show_bug.cgi?id=1762027>`__
- :doc:`lint/linters/stylelint`
- https://stylelint.io/
* - Mozilla Stylelint
-
-
- :doc:`lint/linters/stylelint-plugin-mozilla`
-.. list-table:: JavaScript
:widths: 20 20 20 20 20
:header-rows: 1
* - Tools
- Has autofixes
- Meta bug
- More info
- Upstream
* - Eslint
- Yes
- `bug 1229856 <https://bugzilla.mozilla.org/show_bug.cgi?id=1229856>`__
- :doc:`lint/linters/eslint`
- https://eslint.org/
* - Mozilla ESLint
-
- `bug 1229856 <https://bugzilla.mozilla.org/show_bug.cgi?id=1229856>`__
- :doc:`lint/linters/eslint-plugin-mozilla`
-
* - Prettier
- Yes
- `bug 1558517 <https://bugzilla.mozilla.org/show_bug.cgi?id=1558517>`__
- :doc:`coding-style/coding_style_js`
- https://prettier.io/
* - pnpm-audit
-
- `bug 2065363 <https://bugzilla.mozilla.org/show_bug.cgi?id=2065363>`__
- :doc:`lint/linters/pnpm-audit`
- https://pnpm.io/cli/audit.. list-table:: Python
:widths: 20 20 20 20 20
:header-rows: 1
* - Tools
- Has autofixes
- Meta bug
- More info
- Upstream
* - ruff
- Yes
- `bug 1811850 <https://bugzilla.mozilla.org/show_bug.cgi?id=1811850>`__
- :doc:`lint/linters/ruff`
- https://github.com/charliermarsh/ruff
* - black
- Yes
- `bug 1555560 <https://bugzilla.mozilla.org/show_bug.cgi?id=1555560>`__
- :doc:`lint/linters/black`
- https://black.readthedocs.io/en/stable.. list-table:: Rust
:widths: 20 20 20 20 20
:header-rows: 1
* - Tools
- Has autofixes
- Meta bug
- More info
- Upstream
* - Rustfmt
- Yes
- `bug 1454764 <https://bugzilla.mozilla.org/show_bug.cgi?id=1454764>`__
- :doc:`lint/linters/rustfmt`
- https://github.com/rust-lang/rustfmt
* - Clippy
- Yes
- `bug 1361342 <https://bugzilla.mozilla.org/show_bug.cgi?id=1361342>`__
- :doc:`lint/linters/clippy`
- https://github.com/rust-lang/rust-clippy
* - cargo-audit
-
- `bug 1747536 <https://bugzilla.mozilla.org/show_bug.cgi?id=1747536>`__
- :doc:`lint/linters/cargo-audit`
- https://rustsec.org/.. list-table:: Java/Kotlin
:widths: 20 20 20 20 20
:header-rows: 1
* - Tools
- Has autofixes
- Meta bug
- More info
- Upstream
* - Spotless
- Yes
- `bug 1571899 <https://bugzilla.mozilla.org/show_bug.cgi?id=1571899>`__
- :doc:`lint/linters/android-format`
- https://github.com/diffplug/spotless.. list-table:: Others
:widths: 20 20 20 20 20
:header-rows: 1
* - Tools
- Has autofixes
- Meta bug
- More info
- Upstream
* - shellcheck
-
-
-
- https://www.shellcheck.net/
* - Typo detection
- Yes
-
- :doc:`lint/linters/codespell`
- https://github.com/codespell-project/codespell
* - Fluent Lint
- No
-
- :doc:`lint/linters/fluent-lint`
-
* - YAML linter
- No
-
- :doc:`lint/linters/yamllint`
- https://github.com/adrienverge/yamllintContent Security Index (`docs/content-security/index.md`)
Web Security Checks in Gecko
Key Concepts and Terminology
Security Principal (nsIPrincipal)
A Security Principal represents the security context for a piece of code or data. Firefox uses four types of principals:
- ContentPrincipal: Used for typical web pages and can be serialized to an origin URL, e.g., https://example.com/.
- NullPrincipal: Used for pages that are never same-origin with anything else, such as iframes with the sandbox attribute or documents loaded with a data: URI. This is also known as an opaque origin.
- SystemPrincipal: Used for the browser's user interface, commonly referred to as "browser chrome", and various other background services (OCSP requests, fetching favicons). Pages like about:preferences use the SystemPrincipal.
- ExpandedPrincipal: Used by browser extensions that need to assume the security context of a website. An ExpandedPrincipal is best understood as a list of principals.
OriginAttributes
OriginAttributes help in managing and enforcing security policies by distinguishing different security contexts that might otherwise be considered the same based on their Principal. They are used to:
- Isolate data and resources in private browsing mode.
- Implement cache isolation.
- Manage user context identifiers for container tabs.
- Enforce first-party isolation.
Attributes
The OriginAttributes class extends the functionality of dom::OriginAttributesDictionary and includes additional methods for setting and managing various attributes.
Key attributes include:
- FirstPartyDomain: Used to isolate data based on the domain.
- UserContextId: Identifies different user contexts, such as container tabs.
- PrivateBrowsingId: Indicates whether a request is made in private browsing mode.
- PartitionKey: Used to implement cache isolation.
Load Info Object (nsILoadInfo)
The nsILoadInfo object is crucial for security checks. It holds all security-relevant attributes, including security flags indicating what checks need to be performed and the associated Principal.
Attributes
loadingPrincipal: The principal of the document where the result of the load will be used.triggeringPrincipal: The principal that triggered the URL to load.securityFlags: Indicate the type of security checks required.contentPolicyType: Specifies the type of content being loaded, used for security checks like Content Security Policy.
Loading Lifecycle in Firefox
From Request to Response
- Request Initiation: A web page initiates a request.
- nsIChannel Creation: Firefox creates an
nsIChannelobject, representing the request. - nsILoadInfo Attachment: An
nsILoadInfoobject is required for the creation of annsIChanneland holds security-related information. - Security Checks: Security checks are performed using the
ContentSecurityManager. - Request Execution: If all checks pass, the request proceeds.
Role of nsIChannel and nsILoadInfo
- nsIChannel: Manages the transport algorithm (e.g., HTTP, WebSocket).
- nsILoadInfo: Holds security relevant meta information of a network load and determines what security checks need to be enforced.
Security Checks During Loading
Pre-Request Checks
- Same-Origin Policy: Ensures resources are only accessed if they share the same origin.
- Content Security Policy: Enforces content restrictions based on policies defined by the site.
- Mixed Content Blocking: Implements the Mixed Content standard, including blocking and upgrading of insecure (HTTP) content on secure (HTTPS) pages.
ContentSecurityManager and doContentSecurityCheck()
- ContentSecurityManager: Centralized manager for performing security checks.
- PerformSecurityCheck(): Key function that is invoked to perform all relevant security checks before a request is executed.
Subsumes Concept
- Definition: A principal subsumes another if it has access to the same resources.
- Implementation:
aPrincipal->Subsumes(aOtherPrincipal)is used to check access permissions.
Code example:
bool subsumes = principal1->Subsumes(principal2);Subsumption is asymmetrical. One principal subsuming the other does not imply the inverse. A typical example is the SystemPrincipal, which subsumes all other
principals.
References
The interface definitions in source code have a lot of detailed comments:
- The {searchfox}
nsIPrincipal <caps/nsIPrincipal.idl>interface definition. - The {searchfox}
nsILoadInfo <netwerk/base/nsILoadInfo.idl>interface definition. - The {searchfox}
nsIContentSecurityManager <dom/interfaces/security/nsIContentSecurityManager.idl>interface definition
Contributing Index (`docs/contributing/index.md`)
(working-on-firefox)=
Working on Firefox
Welcome to the Firefox codebase. This is the home of the Firefox
development process and source code documentation.
:caption: Making Changes To Firefox
:maxdepth: 1
contribution_quickref
stack_quickref
reviewable-patch-series
phabricator_vs_github
pocket-guide-shipping-firefox
editor
reviews
levelling-up
how_to_submit_a_patch
data-collection
data-review
searchfox
ai-coding:caption: Version control
:maxdepth: 1
jujutsu
git-tricks:caption: Code reviews
:maxdepth: 1
Code_Review_FAQ
reviewer_checklist:caption: Debugging
:maxdepth: 1
debugging/index:caption: Signing
:glob: true
:maxdepth: 1
signing/*:caption: Additional Information
:maxdepth: 1
directory_structure
build/artifact_builds
build/building_mobile_firefox
build/working_with_esr_115
engineering_show_and_tell
filing-good-bugs
helpful-error-messagesCrash Reporting Index (`docs/crash-reporting/index.md`)
Firefox Crash Reporting
Firefox ships with an open-source crash reporting system. This system is
combination of projects:
- Google
Breakpad
client and server libraries - Mozilla-specific crash reporting user interface and bootstrap code
- Socorro Collection
and reporting server
Where did my crash get submitted?
Crash data submitted using the Mozilla Crash Reporter is located on
crash-stats. If you want to find
a specific crash that you submitted, you first need to find the Crash ID
that the server has assigned your crash. Type about:crashes into
your location bar to get a page listing both submitted and unsubmitted
crash reports. For more information, see How to get a stacktrace for a bug report.
Reports and queries
crash-stats has built-in reports of "topcrashes" for each release
grouped by signature. There is also a custom query tool
which allows users to limit searches on more precise information.
Finally, a set of Mozilla employees have access to directly query the
underlying data in either SQL summary or using mapreduce on the storage
cluster. If you are interested in obtaining this advanced access, read
Crash Stats Documentation: Protected Data Access
See also
- Understanding Crash Reports
- A guide to searching crash reports
- crash-stats
- Crash pings (Telemetry) and crash reports (Socorro/Crash
Stats) - Building with Debug Symbols
- {ref}
Environment variables affecting crash reporting <environment-variables-affecting-crash-reporting> - Uploading symbols to Mozilla's symbol server
- Crash Reporter
- Crash Manager
- Crash Ping Lifecycle
:hidden:
:maxdepth: 1
searching_crash_reports
uploading_symbolGlossary Index (`docs/glossary/index.md`)
A Glossary of Common Terms
:::{topic} Content
Usually refers to webpages being rendered, may also be seen as "running in
content" in which case it can include UI privileged code running in a process
that is rendering webpages.
:::
:::{topic} Chrome
Usually the parts of the application UI outside of the rendered webpage
:::
:::{topic} XUL
A proprietary UI definition language that we are slowly phasing out and replacing with standard HTML.
:::
:::{topic} l10n
An abbreviation for Localization.
:::
:::{topic} i18n
An abbreviation for Internationalisation
:::
:::{topic} a11y
An abbreviation for Accessibility
:::
Gtest Index (`docs/gtest/index.md`)
GTest
GTest (googletest) is Google's framework for writing C++ tests on a
variety of platforms (Linux, Mac OS X, Windows, ...).
Based on the xUnit architecture, it supports automatic test
discovery, a rich set of assertions, user-defined assertions, death
tests, fatal and non-fatal failures, value- and type-parameterized
tests, various options for running the tests, and XML test report
generation.
Integration
GTest is run as a standard test task on Win/Mac/Linux and Android, under
treeherder symbol 'GTest'.
Running tests
The Firefox build process will build GTest on supported platforms as
long as you don't disable tests in your mozconfig. However xul-gtest will
only be built when tests are required to save an expensive second
linking process.
To run the unit tests use 'mach gtest' when invoking Gecko.
Running selected tests
Tests can be selected using mach. You can also use environment variables
support by GTest. See Running Test Programs: Running a Subset of the
Tests
for more details.
mach gtest Moz2D.*Configuring GTest
GTest can be controlled from other environment variables. See Running
Test Programs: Advanced
Options
for more details.
Debugging a GTest Unit Test
To debug a gtest, pass --debug to the normal command.
./mach gtest --debug [ Prefix.Test ]If that doesn't work, you can try running the firefox binary under the
debugger with the MOZ_RUN_GTEST environment variable set to 1.
MOZ_RUN_GTEST=1 ./mach run --debug [--debugger gdb]:::{warning}
Don't forget to build + run 'mach gtest' to relink when using
MOZ_RUN_GTEST since it's not part of a top level build.
:::
Note that this will load an alternate libxul - the one which has the
test code built in, which resides in a gtest/subdirectory of your
objdir. This gtest-enabled libxul is not built as part of the regular
build, so you must ensure that it is built before running the above
command. A simple way to do this is to just run "mach gtest" which will
rebuild libxul and run the tests. You can also extract the commands
needed to just rebuild that libxul from
mach
and run those directly. Finally, note that you may have to run through
the tests once for gdb to load all the relevant libraries and for
breakpoint symbols to resolve properly.
Note that you can debug a subset of the tests (including a single test)
by using the GTEST_FILTER environment variable:
GTEST_FILTER='AsyncPanZoom*' MOZ_RUN_GTEST=1 ./mach run --debug [--debugger gdb]Debugging with Xcode
See {doc}/contributing/debugging/debugging_on_macos for initial
setup. You'll likely want to create a separate scheme for running GTest
("Product" > "Scheme" > "New Scheme…"). In addition to GTEST_FILTER, Set
the following environment variables:
MOZ_XRE_DIR=/path-to-object-directory/obj-ff-dbg/dist/bin
MOZ_RUN_GTEST=Trueand under the "Options" tab for the scheme, set the working directory
to:
☑️ Use custom working directory: /path-to-object-directory/obj-ff-dbg/_tests/gtestDebugging with Visual Studio Code
Add a configuration like this to your launch.json file (you can edit it
via Run / Open Configurations):
{
"name": "(gdb) Launch gtest",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/obj-x86_64-pc-linux-gnu/dist/bin/firefox",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}/obj-x86_64-pc-linux-gnu/_tests/gtest",
"environment": [{"name": "MOZ_RUN_GTEST", "value": "True"},
{"name": "GTEST_FILTER", "value": "AsyncPanZoom*"}],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
},Writing a GTest Unit Test
Most of the GTest
documentation
will apply here. The GTest
primer
is a recommended read.
:::{warning}
GTest will run tests in parallel. Don't add unit tests that are not
threadsafe, such as tests that require focus or use specific sockets.
:::
:::{warning}
GTest will run without initializing mozilla services. Initialize and
tear down any dependencies you have in your test fixtures. Avoid
writing integration tests and focus on testing individual units.
:::
See https://hg.mozilla.org/mozilla-central/rev/ed612eec41a44867a for an
example of how to add a simple test.
If you're converting an existing C++ unit test to a GTest, this
commit may
serve as a useful reference.
Setting prefs for a test
If tests cover functionality that is disabled by default, you'll have to
change the relevant preferences either in the individual test:
bool oldPref = Preferences::GetBool(prefKey);
Preferences::SetBool(prefKey, true);
… // test code
Preferences::SetBool(prefKey, oldPref);or, if it applies more broadly, the change can be applied to the whole
fixture (see the GTest
docs,
or
AutoInitializeImageLib
as an example).
Adding a test to the build system
Find a gtest directory appropriate for the module. If none exist create
a directory using the following convention: '
Create a moz.build file (in the newly created directory) with a module
declaration, replacing gfxtest with a unique name, and set
UNIFIED_SOURCES to contain all of the test file names.
What we're doing here is creating a list of source files that will be
compiled and linked only against the gtest version of libxul. This will
let these source files call internal xul symbols without making them
part of the binary we ship to users.
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
Library('gfxtest')
UNIFIED_SOURCES = [
<ListTestFiles>,
]
FINAL_LIBRARY = 'xul-gtest'Update '
subdirectory in:
TEST_DIRS += [
"gtest",
]When adding tests to an existing moz.build file (it has FINAL_LIBRARY =
'xul-gtest'), add the following. That's it--there is no test manifest
required. Your tests will be automatically registered using a static
constructor.
UNIFIED_SOURCES = [
"TestFoo.cpp",
]Notes
The include file for the class you are testing may not need to be
globally exported, but it does need to be made available to the unit
test you are writing. In that case, add something like this to the
Makefile.in inside of the testing directory.
LOCAL_INCLUDES += [
"/gfx/2d",
"/gfx/2d/unittest",
"/gfx/layers",
]Gtests currently run from the test package under the GTest symbol on
Treeherder if you want to verify
that your test is working. Formerly they were run under the B
symbol, during make check.
MozGTestBench
A Mozilla GTest Microbench is just a GTest that reports the test
duration to perfherder. It's an easy way to add low level performance
test. Keep in mind that there's a non-zero cost to monitoring
performance test so use them sparingly. You can still perform test
assertions.
Writing a Microbench GTest
Use 'MOZ_GTEST_BENCH' instead of 'TEST' to time the execution of your
test. Example:
#include "gtest/MozGTestBench.h" // For MOZ_GTEST_BENCH
...
MOZ_GTEST_BENCH(GfxBench, TEST_NAME, []{
// Test to time the execution
});Make sure this file is registered with the file system using the
instructions above. If everything worked correctly you should see this
in the GTest log for your corresponding test:
PERFHERDER_DATA: {"framework": {"name": "platform_microbench"}, "suites": [{"name": "GfxBench", "subtests": [{"name": "CompositorSimpleTree", "value": 252674, "lowerIsBetter": true}]}]}Sheriffing policy
Microbench tests measure the speed of a very specific operation. A
regression in a micro-benchmark may not lead to a user visible
regression and should not be treated as strictly as a Talos regression.
Large changes in microbench scores will also be expected when the code
is directly modified and should be accepted if the developer intended to
change that code. Micro-benchmarks however provide a framework for
adding performance tests for platform code and regression tests for
performance fixes. They will catch unintended regressions in code and
when correlated with a Talos regression might indicate the source of the
regression.
Metrics Index (`docs/metrics/index.md`)
Firefox metrics
The metrics collected by Firefox using the
Glean SDK
are documented in
The Glean Dictionary.
Nspr Index (`docs/nspr/index.md`)
NSPR
NSPR is a legacy library. We do not recommend using it in new projects.
It is maintained primarily for existing Mozilla code that still depends
on it; modern platform and standard-library facilities should be
preferred instead.Netscape Portable Runtime (NSPR) provides a platform-neutral API for
system level and libc-like functions. The API is used in the Mozilla
clients, many of Red Hat's and Oracle's server applications, and other
software offerings.
Documentation
{doc}about_nspr
: This topic describes, in general terms, the goals of NSPR and a bit
about how it does it.
{doc}reference/index
: The reference describes each API public macro, structure and function
in the NSPR API.
{doc}nspr_build_instructions
: How to checkout and build from source.
{doc}nspr_release_procedure
: How to cut a new NSPR release: bumping the version and producing the
distributions.
{doc}listing
: All NSPR pages
(getting-nspr)=
Getting NSPR
NSPR is available in various source and binary packages, depending on
your platform:
Windows: Build the source package, using the {doc}
nspr_build_instructions.Mac: Install the MacPorts nspr
package, or the Homebrew nspr package.Ubuntu: Install the libnspr4-dev package via
apt-get.Debian: Install the libnspr4-dev package via
apt-get.openSUSE Linux: Install one or more of the following via
yast
orzypper:- mozilla-nspr : Binary libraries for your platform
- mozilla-nspr-32bit : Binary libraries needed to run 32-bit
programs on a 64-bit OS - mozilla-nspr-devel : Files needed (in addition to the above
libraries) to compile programs using NSPR - mozilla-nspr-debuginfo : Debug information (including build
symbols) for package mozilla-nspr - mozilla-nspr-debuginfo-32bit : Debug information (including
build symbols) for package mozilla-nspr-32bit - mozilla-nspr-debugsource : Debug sources for all of the above
Community
View Mozilla forums:
(related-topics)=
Related Topics
- {doc}
/networking/index, {doc}/security/nss/index
:hidden:
:maxdepth: 1
listingOverview Index (`docs/overview/index.md`)
A Quick Guide to Mozilla Applications
gecko
/browser/overview
/mobile/android/index
iosPerformance 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.
:hidden:
:glob:
*
memory/index
build_metrics/build_metrics
platform_microbenchmarks/platform_microbenchmarksGeneral Performance references
- Tips on generating valid performance metrics by benchmarking
- GPU Performance Tips for reducing impacts on browser performance in front-end code.
- Automated Performance testing and Sheriffing Information on automated performance testing and sheriffing at Mozilla.
- Performance best practices for Firefox front-end engineers Tips for reducing impacts on browser performance in front-end code.
- Reporting a performance problem A user friendly guide to reporting a performance problem. A development environment is not required.
- Scroll Linked Effects Information on scroll-linked effects, their effect on performance, related tools, and possible mitigation techniques.
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
- JIT Profiling with perf Using perf to collect JIT profiles.
- JIT Profiling with samply Using samply to collect JIT profiles
- Profiling with simpleperf
simpleperfis the Android equivalent of Linux'sperf - Profiling with Instruments How to use Apple's Instruments tool to profile Mozilla code.
- Profiling with xperf How to use Microsoft's Xperf tool to profile Mozilla code.
- Profiling with Concurrency Visualizer How to use Visual Studio's Concurrency Visualizer tool to profile Mozilla code.
- Profiling with Zoom Zoom is a profiler for Linux done by the people who made Shark.
- Adding a new telemetry probe Information on how to add a new measurement to the Telemetry performance-reporting system
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.
Power and power-related measurements
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.
tools/power/rapl: all planes; Linux and Mac.- Intel Power
Gadget: PKG and
PP0 planes; Windows, Mac and Linux. - powermetrics: PKG
plane; Mac. - perf: all planes; Linux.
- turbostat: PKG, PP0 and
PP1 planes; Linux.
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.
Ways to user power-related measurements
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,
ormach poweron 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
- Try turning hardware acceleration on or off; e10s on or off;
- 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.
- For high CPU usage, many profilers can be used: Firefox's dev
- 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.
: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>Setup Index (`docs/setup/index.md`)
Getting Set Up To Work On The Firefox Codebase
This page will help you get set up to build Firefox on your own machine.
Don't hesitate to look at the {doc}Firefox Contributors Quick Reference </contributing/contribution_quickref> to read a quick tutorial.
:caption: Thank you for contributing to Firefox
/contributing/contributing_to_mozillaSetting Up Your Machine
For Firefox Desktop
:maxdepth: 1
windows_build
windows_wsl_build
macos_build
linux_build
linux_32bit_build_on_64bit_OS
common_build_errorsFor Firefox Android
{doc}/mobile/android/index
For Firefox iOS
{doc}/overview/ios
Getting Ready to Contribute
contributing_code
building_with_debug_symbols
configuring_build_options
editing_moz_configureTesting 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 toRUST_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 likensstring and xpcom.
It's also possible to use RUST_TESTS in a different moz.build file. Seetesting/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-gtestsuffix. - Add to the test crate a Rust file, a C++ file containing GTest
TEST()
functions that use FFI to call into the Rust file, aCargo.tomlfile that
references the Rust file, and amoz.buildfile that references the C++
file. - Add an entry to the
[dependencies]section in
toolkit/library/gtest/rust/Cargo.toml. - Add an
extern crateentry 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
OptionandVecis sometimes sub-optimal.
If you see a warning "Missing auto-load script at offset 0 in section.debug_gdb_scripts" when startinggdb, therust-gdbwrapper 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:
RUST_LOG=info firefoxModule-level logging can also be specified, see the documentation for theenv_logger crate for details.
To restrict logging to child processes, use RUST_LOG_CHILD instead ofRUST_LOG.
Gecko logging
Rust logging can also be forwarded to the Gecko logger for capture viaMOZ_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 likeneqo_transport, specify it asneqo_transport::*. For example:
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:
MOZ_LOG=timestamp,sync,neqo_transport::recovery:5 firefox
MOZ_LOG=timestamp,sync,neqo_transport::recovery::*:5 firefoxdebug!andtrace!logs will not appear in non-debug builds. This is due
to our use of therelease_max_level_infofeature in thelogcrate.When using both
MOZ_LOGandRUST_LOG, modules that are specified inMOZ_LOGwill not appear inRUST_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:
- 12.0, all platforms. In this release we added support for distinguishing the running and supported architectures in macOS builds in the update URL.
- 43.0.1, Windows only. This release was preparation for desupporting SHA-1 hashes in our Windows builds.
- 45.0.2, Linux only. We added support for sending the GTK 3 version to the update URL.
- 47.0.2, Windows only. We added CPU instruction set information to the update URL to later allow SSE1 to be deprecated.
- 56.0, Windows only. We added support for sending information about the JAWS accessibility application to the update URL to avoid updating people on crashy versions of it. Additionally, we added support for LZMA compression to the updater and swapped to new MAR signing keys.
- 57.0.4[^2], Linux & Mac only. We added support for LZMA compression to the updater and swapped to new MAR signing keys. (Note: Windows was not required here because they picked up this change in the above 56.0 watershed.)
- 72.0.2, all platforms. This is a required version due to a necessary two-step password database migration.
- 109.0.1, macOS only. This updates the channel-prefs.js file (normally excluded from updates) due to signature issues.
- 127.0, Windows only. The issuer for our code-signing certificate changed, requiring an updated Mozilla Maintenance Service.
[^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
esrchannel - 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:
- (Ancient, desupported at various old versions): Darwin 6, Darwin 7, Darwin 8, Darwin 9, Windows_95, Windows_98, Windows_NT 4, Windows_NT 5.0, Windows_NT 5.1.0, Windows_NT 5.1.1, GTK 2.0., GTK 2.1., GTK 2.2., GTK 2.3., GTK 2.4., GTK 2.5., GTK 2.6., GTK 2.7., GTK 2.8., GTK 2.9., GTK 2.10., GTK 2.11., GTK 2.12., GTK 2.13., GTK 2.14., GTK 2.15., GTK 2.16., GTK 2.17., PPC Architecture
- <46.0: Desupported GTK <3.4
- <49.0: Desupported Darwin 10, 11, and 12 (macOS 10.6, 10.7, 10.8), SSE and MMX instruction sets
- <52.0: Moved Windows XP, Server 2003, and Vista users to esr52
- <53.0: Desupported 32-bit macOS hardware
- <77.0: Moved Darwin 13, 14, and 15 (macOS 10.9, 10.10, and 10.11) to esr78
- <116.0: Moved Darwin 16, 17, and 18 (macOS 10.12, 10.13, and 10.14) to esr115
- <116.0: Moved Windows 7, 8, and 8.1 to esr115
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.
:titlesonly:
:maxdepth: 1
:glob:
*Dom Docs Index (`dom/docs/index.md`)
DOM
These linked pages contain design documents for the DOM implementation in Gecko. They live in-tree under the 'dom/docs' directory.
:maxdepth: 1
handling_shadowDOM
ipc/index
navigation/index
push/index
scriptSecurity/index
scriptSecurity/xray_vision
workersAndStorage/index
webIdlBindings/index
ioutils_migration
fedcm
streams
promise/safe-promise-resolve
use-counters
loggingKeyboardIMEBrowser Branding Docs Index (`browser/branding/docs/index.md`)
Firefox Branding
Firefox has multiple different sets of "branding" that are used to hold channel-specific things such as:
- Logos and other iconography
- Product names (eg: "Mozilla Firefox", "Firefox Developer Edition")
- Channel-specific preferences (eg:
app.update.interval)
Brandings are stored in the {searchfox}branding subdirectory and map to builds as follows:
officialis used for Release and Beta buildsaurorais used for Developer Edition buildsnightlyis used for Nightly and Try buildsunofficialis used when no other branding is specified (eg: local developer builds)
Additional reading
UpdatingMacIconsBrowser Docs How To Index (`browser/docs/how_to/index.md`)
How-To's
This section contains practical guides for common Firefox operations that
often occur when adding features, or changing existing features of the browser.
Getting Started
If you're writing a new how-to guide, copy the {doc}template and follow its
structure to ensure consistency across all guides.
Available Guides
:maxdepth: 1
add_preview_strings
upgrading_profile_dataMore guides will be added here as they are written.
Template
:maxdepth: 1
templateBuild Docs Mozbuild Index (`build/docs/mozbuild/index.md`)
mozbuild
mozbuild is a Python package providing functionality used by Mozilla's
build system.
Modules Overview
- mozbuild.backend -- Functionality for producing and interacting with build
backends. A build backend is an entity that consumes build system metadata
(from mozbuild.frontend) and does something useful with it (typically writing
out files that can be used by a build tool to build the tree). - mozbuild.compilation -- Functionality related to compiling. This
includes managing compiler warnings. - mozbuild.frontend -- Functionality for reading build frontend files
(what defines the build system) and converting them to data structures
which are fed into build backends to produce backend configurations. - mozpack -- Functionality related to packaging builds.
Overview
The build system consists of frontend files that define what to do. They
say things like "compile X" "copy Y."
The mozbuild.frontend package contains code for reading these frontend
files and converting them to static data structures. The set of produced
static data structures for the tree constitute the current build
configuration.
There exist entities called build backends. From a high level, build
backends consume the build configuration and do something with it. They
typically produce tool-specific files such as make files which can be used
to build the tree.
Piecing it all together, we have frontend files that are parsed into data
structures. These data structures are fed into a build backend. The output
from build backends is used by builders to build the tree.
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`)
DevTools 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.
Devtools Docs Contributor Index (`devtools/docs/contributor/index.md`)
:name: devtools-contributor-doc
:hidden:
:maxdepth: 1
Getting started <README.md>
Architecture overview <architecture-overview.md>
Contributing <contributing.md>
Bugs and issues <bugs-issues.md>Firefox DevTools Contributor Docs
This is the contributor documentation for Firefox Developer Tools. If you're looking for help with using the tools, see the user docs. Note that this section only contains technical information specific to Firefox DevTools, make sure to first read the Firefox contributor documentation which explains how to contribute to Firefox in general (setting up the environment, submitting patches, etc.).
Automated tests
:maxdepth: 1
Automated tests <tests/README.md>
xpcshell <tests/xpcshell.md>
Chrome mochitests <tests/mochitest-chrome.md>
DevTools mochitests <tests/mochitest-devtools.md>
Node tests <tests/node-tests.md>
Memory Allocation tests </devtools/tests/memory/index.md>
JavaScript Objects tests<tests/js-object-tests.md>
Writing tests <tests/writing-tests.md>
Debugging intermittent failures </testing/debugging-intermittents/index.md>
Performance tests overview<tests/performance-tests-overview.md>
Backward Compatibility tests <tests/backward-compat-tests.md>
DAMP Performance tests <tests/performance-tests-damp.md>
Writing a new test <tests/writing-perf-tests.md>
Example <tests/writing-perf-tests-example.md>
Advanced tips <tests/writing-perf-tests-tips.md>Files and directories
:maxdepth: 1
Files and directories <files/README.md>
Adding New Files <files/adding-files.md>Tool Architectures
:maxdepth: 1
Inspector Panel Architecture <tools/inspector-panel.md>
Inspector Highlighters <tools/highlighters.md>
Memory <tools/memory-panel.md>
Debugger <tools/debugger-panel.md>
Responsive Design Mode <tools/responsive-design-mode.md>
Console <tools/console-panel.md>
Network </devtools/netmonitor/architecture.md>
Storage <tools/storage.md>
Inspector <tools/inspector.md>
Responsive Design Mode devices <responsive/devices.md>Frontend
:maxdepth: 1
CSS <frontend/css.md>
Panel SVGs <frontend/svgs.md>
React <frontend/react.md>
React Guidelines <frontend/react-guidelines.md>
Redux <frontend/redux.md>
Redux Guidelines <frontend/redux-guidelines.md>
Telemetry <frontend/telemetry.md>
Content Security Policy <frontend/csp.md>Backend
:maxdepth: 1
Remote Debugging Protocol <backend/protocol.md>
Backend Overview <backend/watcher-architecture.md>
Client API <backend/client-api.md>
Debugger API <backend/debugger-api.md>
Backward Compatibility <backend/backward-compatibility.md>
Actors Organization <backend/actor-hierarchy.md>
Writing Actors With protocol.js <backend/protocol.js.md>
Registering A New Actor <backend/actor-registration.md>
Actor Best Practices <backend/actor-best-practices.md>Performance
:maxdepth: 1
Investigating performance issues <performance/performance.md>
Writing efficient React code <performance/react-performance-tips.md>Preferences
:maxdepth: 1
Preferences <preferences.md>Recurring tasks
:maxdepth: 1
Release tasks<release.md>
Performance sheriffing<performance-sheriffing.md>Devtools Docs User Index (`devtools/docs/user/index.md`)
myst:
substitutions:
image1: |-
{image} iframe_button.png :class: center
image2: |-
{image} camera_button.png :class: center
image3: |-
{image} responsive_button.png :class: center
image4: |-
{image} menu_button.png :class: center
image5: |-
{image} close_button.png :class: center
:name: devtools-user-doc
:hidden:
:maxdepth: 1
3d_view/index
about_colon_debugging/index
accessibility_inspector/index
application/index
browser_console/index
browser_toolbox/index
custom_formatters/index
debugger/index
debugger-api/index
deprecated_tools/index
devtoolsapi/index
devtoolscolors/index
dom_property_viewer/index
eyedropper/index
index/index
javascript_tracer/index
json_viewer/index
keyboard_shortcuts/index
local_mode/index
measure_a_portion_of_the_page/index
memory/index
migrating_from_firebug/index
network_monitor/index
page_inspector/index
performance/index
responsive_design_mode/index
rulers/index
settings/index
shader_editor/index
storage_inspector/index
style_editor/index
taking_screenshots/index
tips/index
tools_toolbox/index
validators/index
view_source/index
web_audio_editor/index
web_console/index
working_with_iframes/indexFirefox DevTools User Docs
Firefox Developer Tools is a set of web developer tools built into Firefox. You can use them to examine, edit, and debug HTML, CSS, and JavaScript.
This section contains detailed guides to all of the tools as well as information on how to debug Firefox for Android, how to extend DevTools, and how to debug the browser as a whole.
If you have any feedback on DevTools or want to contribute to the project, you can join the DevTools community.
:::{note}
If you are just getting started with web development and using developer tools, our learning docs will help you — see Getting started with the Web and What are browser developer tools? for good starting points.
:::
The Core Tools
You can open the Firefox Developer Tools from the menu by selecting Tools > Web Developer > Web Developer Tools or use the keyboard shortcut {kbd}Ctrl + {kbd}Shift + {kbd}I or {kbd}F12 on Windows and Linux, or {kbd}Cmd + {kbd}Opt + {kbd}I on macOS.
The ellipsis menu on the right-hand side of Developer Tools contains several commands that let you perform actions or change tool settings.
:::{figure} devtools_layoutmenu.png
:align: center
:::
.. list-table::
:widths: 20 80
* - .. image:: iframe_button.png
- This button only appears when there are multiple iframes on a page. Click it to display a list of the iframes on the current page and select the one with which you want to work.
* - .. image:: camera_button.png
- Click this button to take a screenshot of the current page. (*Note:* This feature is not turned on by default and must be enabled in settings before the icon will appear.)
* - .. image:: responsive_button.png
- Toggles Responsive Design Mode
* - .. image:: menu_button.png
- Opens the menu that includes docking options, the ability to show or hide the split console, and Developer Tools settings. The menu also includes links to the documentation for Firefox Web Tools and the Mozilla Community.
* - .. image:: close_button.png
- Closes the Developer Tools{doc}`Page Inspector `
:alt: The all-new Inspector panel in Firefox 57.
:class: border
:target: /devtools-user/page_inspector/index.htmlView and edit page content and layout. Visualize many aspects of the page including the box model, animations, and grid layouts
{doc}`Web Console `
:alt: The all-new Console panel in Firefox 57.
:class: border
:target: /devtools-user/web_console/index.htmlSee messages logged by a web page and interact with the page using JavaScript.
[JavaScript Debugger](debugger/index.md)
:alt: The all-new Debugger panel in Firefox 57.
:class: border
:target: debuggerStop, step through, and examine the JavaScript running on a page.
{doc}`Network Monitor `
:alt: The Network panel in Firefox 57 DevTools.
:class: border
:target: /devtools-user/network_monitor/index.htmlSee the network requests made when a page is loaded.
[Performance Panel](https://profiler.firefox.com/docs/)
:alt: Performance Panel in Firefox 103 Developer Tools.
:class: border
:target: https://profiler.firefox.com/docs/Analyze your site's general responsiveness, JavaScript, and layout performance.
{doc}`Responsive Design Mode `
:alt: Responsive Design mode in Firefox 57 Developer Tools.
:class: border
:target: /devtools-user/responsive_design_mode/index.htmlSee how your website or app will look and behave on different devices and network types.
{doc}`Accessibility inspector `
:alt: Performance Tools in Firefox 57 Developer Tools.
:class: border
:target: /devtools-user/accessibility_inspector/index.htmlProvides a means to access the page's accessibility tree, allowing you to check what's missing or otherwise needs attention.
[Application panel](application/index.md)
:alt: Performance Tools in Firefox 57 Developer Tools.
:class: border
:target: applicationProvides tools for inspecting and debugging modern web apps (also known as Progressive Web Apps). This includes inspection of service workers and web app manifests
:::{note}
The collective term for the UI inside which the DevTools all live is the {doc}Toolbox <tools_toolbox/index>
:::
More Tools
These developer tools are also built into Firefox. Unlike the "Core Tools" above, you might not use them every day.
.. list-table::
:widths: 25 75
:header-rows: 0
* - :doc:`Memory <memory/index>`
- Figure out which objects are keeping memory in use.
* - :doc:`Storage Inspector <storage_inspector/index>`
- Inspect cookies, local storage, indexedDB, and session storage present in a page.
* - :doc:`DOM Property Viewer <dom_property_viewer/index>`
- Inspect the page's DOM properties, functions, etc.
* - :doc:`Eyedropper <eyedropper/index>`
- Select a color from the page.
* - :doc:`Style Editor <style_editor/index>`
- View and edit CSS styles for the current page.
* - :doc:`Taking screenshot <taking_screenshots/index>`
- Take a screenshot of the entire page or of a single element.
* - :doc:`Measure a portion of the page <measure_a_portion_of_the_page/index>`
- Measure a specific area of a web page.
* - :doc:`Rulers <rulers/index>`
- Overlay horizontal and vertical rulers on a web page
* - :doc:`Custom formatters <custom_formatters/index>`
- Customize the way objects are displayed within the DevTools.
* - :doc:`JavaScript tracer <javascript_tracer/index>`
- Live display all JavaScript function calls.
* - :doc:`Local Mode <local_mode/index>`
- Easily open local files through custom https:// URL.:class: center.. rst-class:: center
For the latest developer tools and features, try Firefox Developer Edition.
`Download Firefox Developer Edition <https://www.mozilla.org/en-US/firefox/developer/>`_AI Tools
| Firefox DevTools MCP | A Model Context Protocol (MCP) server that enables AI assistants to automate and interact with Firefox. |
Connecting the Developer Tools
If you open the developer tools using {ref}keyboard shortcuts <keyboard-shortcuts-opening-and-closing-tools> or the equivalent menu items, they'll target the document hosted by the currently active tab. But you can attach the tools to a variety of other targets, too, both within the current browser and in different browsers or even different devices.
.. list-table::
:widths: 30 70
:header-rows: 0
* - :doc:`about:debugging <about_colon_debugging/index>`
- Debug add-ons, content tabs, and workers running in the browser.
* - :ref:`Connecting to Firefox for Android <about-colon-debugging-connecting-to-a-remote-device>`
- Connect the developer tools to an instance of Firefox running on an Android device.
* - :doc:`Connecting to iframes <working_with_iframes/index>`
- Connect the developer tools to a specific iframe in the current page.Debugging the browser
By default, the developer tools are attached to a web page or web app. But you can also connect them to the browser as a whole. This is useful for browser and add-on development.
.. list-table::
:widths: 30 70
:header-rows: 0
* - :doc:`Browser Console <browser_console/index>`
- See messages logged by the browser itself and by add-ons, and run JavaScript code in the browser's scope.
* - :doc:`Browser Toolbox <browser_toolbox/index>`
- Attach the Developer Tools to the browser itself.Extending DevTools
For information on extending the Firefox DevTools, see Extending the developer tools over in the Browser Extensions section of MDN.
Migrating from Firebug
Firebug has come to the end of its lifespan (see Firebug lives on in Firefox DevTools for details of why), and we appreciate that some people will find migrating to another less familiar set of DevTools to be challenging. To ease a transition from Firebug to the Firefox developer tools, we have written a handy guide — {doc}Migrating from Firebug <./migrating_from_firebug/index>
Contribute
If you want to help improve the developer tools, these resources will get you started.
.. list-table::
:widths: 30 70
:header-rows: 0
* - `Get Involved <https://firefox-dev.tools/>`_
- Our community website explains how to get involved.
* - `codetribute.mozilla.org <https://codetribute.mozilla.org/projects/devtools/>`_
- A tool helping to find bugs to work on.
* - :ref:`Read source docs <devtools-contributor-doc>`
- Firefox DevTools source code documentation.Bug Mgmt Guides Index (`docs/bug-mgmt/guides/index.md`)
Guides
Reference for the fields used to describe a bug and how they are meant to be
set.
:maxdepth: 1
bug-pipeline
bug-types
severity
priority
status-flags
other-metadataBug Mgmt Policies Index (`docs/bug-mgmt/policies/index.md`)
Policies
What each team is expected to do with the bugs it owns.
:maxdepth: 1
triage-bugzilla
new-feature-triage
attention-dashboard
regressions-githubBug Mgmt Processes Index (`docs/bug-mgmt/processes/index.md`)
Processes
Step by step procedures for the bugs that need special handling.
:maxdepth: 1
regressions
fixing-security-bugs
security-approval
accessibility-review
doc-requests
shared-bug-queues
labels
regression-engineering-ownerCode Quality Coding Style Index (`docs/code-quality/coding-style/index.md`)
Coding style
Firefox code is using different programming languages.
For each language, we are enforcing a specific coding style.
Getting Help
If you need help or have questions, please don’t hesitate to contact us via Matrix
in the "Lint and Formatting" room
(#lint:mozilla.org).
:caption: Coding Style User Guide
:glob: true
:maxdepth: 2
*Code Quality Lint Index (`docs/code-quality/lint/index.md`)
Linting
Linters are used in mozilla-central to help enforce coding style and avoid bad practices.
They cover a wide variety of languages and checks.
Getting Help
If you need help or have questions, please don’t hesitate to contact us via Matrix
in the "Lint and Formatting" room
(#lint:mozilla.org).
:caption: Getting Started
:maxdepth: 2
usage:caption: Linter Implementations
:glob: true
:maxdepth: 1
linters/*:caption: Linter Specifics
:maxdepth: 1
mozlint
createCode Quality Static Analysis Index (`docs/code-quality/static-analysis/index.md`)
Static Analysis
Static Analysis is running an analysis of the source code without actually executing the code. For the most part, at Mozilla static analysis refers to the stuff we do with clang-tidy. It uses
checkers in order to prevent different programming errors present in the
code. The checkers that we use are split into 3 categories:
- {searchfox}
Firefox specific checkers. They detect incorrect Gecko programming
patterns which could lead to bugs or security issues. - Clang-tidy checkers. They aim to suggest better programming practices
and to improve memory efficiency and performance. - Clang-analyzer checkers. These checks are more advanced, for example
some of them can detect dead code or memory leaks, but as a typical
side effect they have false positives. Because of that, we have
disabled them for now, but will enable some of them in the near
future.
In order to simplify the process of static-analysis we have focused on
integrating this process with Phabricator and mach. A list of some
checkers that are used during automated scan can be found
{searchfox}here <tools/clang-tidy/config.yaml>.
This documentation is split into two parts:
:glob: true
:maxdepth: 1
existing
writing-new/indexCode 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:
./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.
- Currently no. Whilst we have a TypeScript Linter on CI
- 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.
- As discussed in the note at the top of the page, we are still in the set-up
- 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.
- No. In the past we've worked to avoid processing or compilation steps,
- 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.
- We have a meta bug
Getting Help
The Lint & Formatting channel (#lint:mozilla.org) on Matrix is the best place
to ask questions.
Further Reading
- The TypeScript documentation is very
useful in understanding how TypeScript works and how types may be set up.- The JavaScript section starting here,
is especially useful for firefox-main development.
- The JavaScript section starting here,
:hidden:
:maxdepth: 1
bestPractices
updatingTypesContributing Debugging Index (`docs/contributing/debugging/index.md`)
Debugging Firefox
How to inspect a running Firefox, and how to make sense of a crash or a hang
that already happened.
:caption: Debuggers
:maxdepth: 1
debugging_firefox_with_gdb
debugging_firefox_with_lldb
debugging_firefox_with_rr
debugging_firefox_with_pernosco
debugging_firefox_with_valgrind:caption: Platforms and specific areas
:maxdepth: 1
debugging_on_macos
debugging_on_windows
debugging_a_hang_on_macos
debugging_webrtc_calls:caption: Crash reports and minidumps
:maxdepth: 1
understanding_crash_reports
capturing_minidump
debugging_a_minidump
process_dump_task_manager
stacktrace_report
stacktrace_windbg
local_symbolsNspr Reference Index (`docs/nspr/reference/index.md`)
NSPR API Reference
:maxdepth: 2Introduction to NSPR
{ref}
nspr-naming-conventions{ref}
nspr-threads{ref}
thread-scheduling- {ref}
setting-thread-priorities - {ref}
preempting-threads - {ref}
interrupting-threads
- {ref}
{ref}
nspr-thread-synchronization- {ref}
locks-and-monitors - {ref}
condition-variables
- {ref}
{ref}
nspr-sample-code
NSPR Types
{ref}
calling-convention-types{ref}
algebraic-types{ref}
c-16-2c-and-32-bit-integer-types- {ref}
signed-integers - {ref}
unsigned-integers
- {ref}
{ref}
nspr-types-64-bit-integer-types{ref}
floating-point-number-type{ref}
native-os-integer-types
{ref}
miscellaneous-types- {ref}
size-type - {ref}
pointer-difference-types - {ref}
boolean-types - {ref}
status-type-for-return-values
- {ref}
Threads
{ref}
threading-types-and-constants{ref}
threading-functions- {ref}
creating-2c-joining-2c-and-identifying-threads - {ref}
controlling-thread-priorities - {ref}
controlling-per-thread-private-data - {ref}
interrupting-and-yielding - {ref}
setting-global-thread-concurrency - {ref}
getting-a-thread-27s-scope
- {ref}
Process Initialization
{ref}
identity-and-versioning- {ref}
name-and-version-constants
- {ref}
{ref}
initialization-and-cleanup{ref}
module-initialization
Locks
- {ref}
lock-type - {ref}
lock-functions
Condition_Variables
- {ref}
condition-variable-type - {ref}
condition-variable-functions
Monitors
- {ref}
monitor-type - {ref}
monitor-functions
Cached Monitors
- {ref}
cached-monitors-functions
I/O Types
- {ref}
directory-type - {ref}
file-descriptor-types - {ref}
file-info-types - {ref}
network-address-types - {ref}
types-used-with-socket-options-functions - {ref}
type-used-with-memory-mapped-i-2fo - {ref}
offset-interpretation-for-seek-functions
I/O Functions
- {ref}
functions-that-operate-on-pathnames - {ref}
functions-that-act-on-file-descriptors - {ref}
directory-i-2fo-functions - {ref}
socket-manipulation-functions - {ref}
converting-between-host-and-network-addresses - {ref}
memory-mapped-i-2fo-functions - {ref}
anonymous-pipe-function - {ref}
polling-functions - {ref}
manipulating-layers
Network Addresses
- {ref}
network-address-types-and-constants - {ref}
network-address-functions
Atomic Operations
- {doc}
pr_atomicincrement - {doc}
pr_atomicdecrement - {doc}
pr_atomicset
Interval Timing
- {ref}
interval-time-type-and-constants - {ref}
interval-functions
Date and Time
- {ref}
types-and-constants - {ref}
time-parameter-callback-functions - Functions
Memory_Management Operations
- {ref}
memory-allocation-functions - {ref}
memory-allocation-macros
String Operations
- {doc}
pl_strlen - {doc}
pl_strcpy - {doc}
pl_strdup - {doc}
pl_strfree
Floating Point Number to String Conversion
- {doc}
pr_strtod - {doc}
pr_dtoa - {doc}
pr_cnvtf
Linked Lists
{ref}
linked-list-types- {doc}
prclist
- {doc}
{ref}
linked-list-macros- {doc}
pr_init_clist - {doc}
pr_init_static_clist - {doc}
pr_append_link - {doc}
pr_insert_link - {doc}
pr_next_link - {doc}
pr_prev_link - {doc}
pr_remove_link - {doc}
pr_remove_and_init_link - {doc}
pr_insert_before - {doc}
pr_insert_after
- {doc}
Dynamic Library Linking
{ref}
library-linking-types- {doc}
prlibrary - {doc}
prstaticlinktable
- {doc}
{ref}
library-linking-functions- {doc}
pr_setlibrarypath - {doc}
pr_getlibrarypath - {doc}
pr_getlibraryname - {doc}
pr_freelibraryname - {doc}
pr_loadlibrary - {doc}
pr_unloadlibrary - {doc}
pr_findsymbol - {doc}
pr_findsymbolandlibrary - {ref}
finding-symbols-defined-in-the-main-executable-program
- {doc}
{ref}
platform-notesDynamic Library Search Path- {ref}
exporting-symbols-from-the-main-executable-program
Process Management and Interprocess Communication
{ref}
process-management-types-and-constants- {doc}
prprocess - {doc}
prprocessattr
- {doc}
{ref}
process-management-functions- {ref}
setting-the-attributes-of-a-new-process - {ref}
creating-and-managing-processes
- {ref}
Logging
{ref}
conditional-compilation-and-execution{ref}
log-types-and-variablesPRLogModuleInfo- {doc}
prlogmodulelevel - {doc}
nspr_log_modules - {doc}
nspr_log_file
{ref}
logging-functions-and-macros- {doc}
prlogmoduleinfo PR_SetLogFilePR_SetLogBufferingPR_LogPrintPR_LogFlushPR_LOG_TESTPR_LOG- {doc}
pr_assert PR_NOT_REACHED
- {doc}
{ref}
use-example
Named Shared Memory
- {ref}
shared-memory-protocol - {ref}
named-shared-memory-functions
Anonymous Shared_Memory
- {ref}
anonymous-memory-protocol - {ref}
anonymous-shared-memory-functions
IPC Semaphores
- {ref}
ipc-semaphore-functions
Random Number Generator
- {ref}
random-number-generator-function
Hash Tables
- {ref}
hash-table-types-and-constants - {ref}
hash-table-functions
NSPR Error Handling
- {ref}
error-type - {ref}
error-functions - {ref}
error-codes
Nspr Reference Pr Newthreadprivateindex (`docs/nspr/reference/pr_newthreadprivateindex.md`)
PR_NewThreadPrivateIndex
Returns a new index for a per-thread private data table and optionally
associates a destructor with the data that will be assigned to the
index.
Syntax
#include <prthread.h>
PRStatus PR_NewThreadPrivateIndex(
PRUintn *newIndex,
PRThreadPrivateDTOR destructor);Parameters
{doc}pr_newthreadprivateindex has the following parameters:
newIndex
: On output, an index that is valid for all threads in the process. You
use this index with {doc}pr_setthreadprivate and
{doc}pr_getthreadprivate.
destructor
: Specifies a destructor function {doc}prthreadprivatedtor for the
private data associated with the index. This function can be
specified as NULL.
Returns
The function returns one of the following values:
- If successful,
PR_SUCCESS. - If the total number of indices exceeds 128,
PR_FAILURE.
Description
If {doc}pr_newthreadprivateindex is successful, every thread in the same
process is capable of associating private data with the new index. Until
the data for an index is actually set, the value of the private data at
that index is NULL. You pass this index to {doc}pr_setthreadprivate
and {doc}pr_getthreadprivate to set and retrieve data associated with the
index.
When you allocate the index, you may also register a destructor function
of type {doc}prthreadprivatedtor. If a destructor function is registered
with a new index, it will be called at one of two times, as long as the
private data is not NULL:
- when replacement private data is set with {doc}
pr_setthreadprivate - when a thread exits
The index maintains independent data values for each binding thread. A
thread can get access only to its own thread-specific data. There is no
way to deallocate a private data index once it is allocated.
Performance Memory Index (`docs/performance/memory/index.md`)
Memory profiling and leak detection
Tools for measuring how much memory Firefox uses, and for tracking down memory
that is never released.
:caption: Measuring memory usage
:maxdepth: 1
about_colon_memory
memory_reporting
awsy
bloatview:caption: Leak detection
:maxdepth: 1
leak_hunting_strategies_and_tips
leaked_until_shutdown
refcount_tracing_and_balancing
gc_and_cc_logs:caption: Heap profiling with DMD
:maxdepth: 1
dmd
heap_scan_modeThe DevTools Memory panel
The Memory panel is documented in the DevTools user documentation, under
Memory.
Rust Components Api Index (`docs/rust-components/api/index.md`)
Rust components API References
Choose a language to get started
:hidden:
:maxdepth: 1
js/indexRust 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.
:titlesonly:
:maxdepth: 1
example-component
uniffi
logging
observability
threading
other-desktop-specific-concernsRust Components Topic Guides Index (`docs/rust-components/topic-guides/index.md`)
Topic Guides
Here are the guides on various topics related to Rust components.
: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.
:titlesonly:
:maxdepth: 1
js-and-cpp-layers
lifting-and-lowering
rust-calls
js-callback-interfacesDom Bindings Docs Index (`dom/bindings/docs/index.md`)
WebIDL
WebIDL describes interfaces web browsers are supposed to implement.
The interaction between WebIDL and the build system is somewhat complex.
This document will attempt to explain how it all works.
Overview
.webidl files throughout the tree define interfaces the browser
implements. Since Gecko/Firefox is implemented in C++, there is a
mechanism to convert these interfaces and associated metadata to
C++ code. That's where the build system comes into play.
All the code for interacting with .webidl files lives underdom/bindings. There is code in the build system to deal with
WebIDLs explicitly.
WebIDL source file flavors
Not all .webidl files are created equal! There are several flavors,
each represented by a separate symbol from {ref}mozbuild_symbols.
WEBIDL_FILES
: Refers to regular/static .webidl files. Most WebIDL interfaces
are defined this way.
GENERATED_EVENTS_WEBIDL_FILES
: In addition to generating a binding, these .webidl files also
generate a source file implementing the event object in C++
PREPROCESSED_WEBIDL_FILES
: The .webidl files are generated by preprocessing an input file.
They otherwise behave like WEBIDL_FILES.
TEST_WEBIDL_FILES
: Like WEBIDL_FILES but the interfaces are for testing only and
aren't shipped with the browser.
PREPROCESSED_TEST_WEBIDL_FILES
: Like TEST_WEBIDL_FILES except the .webidl is obtained via
preprocessing, much like PREPROCESSED_WEBIDL_FILES.
GENERATED_WEBIDL_FILES
: The .webidl for these is obtained through an external
mechanism. Typically there are custom build rules for producing these
files.
Producing C++ code
The most complicated part about WebIDLs is the process by which.webidl files are converted into C++.
This process is handled by code in the {py:mod}mozwebidlcodegen
package. {py:class}mozwebidlcodegen.WebIDLCodegenManager is
specifically where you want to look for how code generation is
performed. This includes complex dependency management.
Requirements
This section aims to document the build and developer workflow requirements
for WebIDL.
Parser unit tests
: There are parser tests provided by dom/bindings/parser/runtests.py
that should run as part of make check. There must be a mechanism
to run the tests in human mode so they output friendly error
messages.
The current mechanism for this is mach webidl-parser-test.
Mochitests
: There are various mochitests under dom/bindings/test. They should
be runnable through the standard mechanisms.
Working with test interfaces
: TestExampleGenBinding.cpp calls into methods from the
TestExampleInterface, TestExampleProxyInterface,
TestExampleThrowingConstructorInterface,
and TestExampleWorkerInterface interfaces.
These interfaces need to be generated as part of the build. These
interfaces should not be exported or packaged.
There is a compiletests make target in dom/bindings that
isn't part of the build that facilitates turnkey code generation
and test file compilation.
Minimal rebuilds
: Reprocessing every output for every change is expensive. So we don't
inconvenience people changing .webidl files, the build system
should only perform a minimal rebuild when sources change.
This logic is mostly all handled in
{py:class}mozwebidlcodegen.WebIDLCodegenManager. The unit tests for
that Python code should adequately test typical rebuild scenarios.
Bug 940469 tracks making the existing implementation better.
Explicit method for performing codegen
: There needs to be an explicit method for invoking code generation.
It needs to cover regular and test files.
This is implemented via make export in dom/bindings.
No-op binding generation should be fast
: So developers touching .webidl files are not inconvenienced,
no-op binding generation should be fast. Watch out for the build system
processing large dependency files it doesn't need in order to perform
code generation.
Ability to generate example files
: Any interface can have example .h/.cpp files generated.
There must be a mechanism to facilitate this.
This is currently facilitated through mach webidl-example. e.g.
mach webidl-example HTMLStyleElement.
Dom Docs Navigation Index (`dom/docs/navigation/index.md`)
DOM Navigation
:maxdepth: 1
embedding
BrowsingContext
nav_replaceDom 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.
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 FFirefox 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.
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)]
endThe 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.
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:
- In case the consumer attempts to re-subscribe, storage is used as a cache to serve the URL and the public key
- 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:
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:
dom/push/mobile/shared/components/geckoview/GeckoViewPush.sys.mjsmobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebPush*.java- Under
mobile/android/android-components/components: - Rust Push Component
The following flow diagram describes how different modules interact with each other to provide the push API to consumers.
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)]
endDom Docs ScriptSecurity Index (`dom/docs/scriptSecurity/index.md`)
Script Security
:::{container} summary
This page provides an overview of the script security architecture in
Gecko.
:::
Like any web browser, Gecko can load JavaScript from untrusted and
potentially hostile web pages and run it on the user's computer. The
security model for web content is based on the same-origin policy,
in which code
gets full access to objects from its origin but highly restricted access
to objects from a different origin. The rules for determining whether an
object is same-origin with another, and what access is allowed
cross-origin, are now mostly standardized across browsers.
Gecko has an additional problem, though: while its core is written in
C++, the front-end code is written in JavaScript. This JavaScript code,
which is commonly referred to as chrome code, runs with system
privileges. If the code is compromised, the attacker can take over the
user's computer. Legacy SDK extensions also run with chrome privileges.
Having the browser front end in JavaScript has benefits: it can be much
quicker to develop in JavaScript than in C++, and contributors do not
need to learn C++. However, JavaScript is a highly dynamic, malleable
language, and without help it's difficult to write system-privileged
code that interacts safely with untrusted web content. From the point of
view of chrome code, the script security model in Gecko is intended to
provide that help to make writing secure, system-privileged JavaScript a
realistic expectation.
(security-policy)=
Security policy
Gecko implements the following security policy:
- Objects that are same-origin are able to access each other
freely. For example, the objects associated with a document served
from https://example.org/ can access each other, and they can also
access objects served from https://example.org/foo. - Objects that are cross-origin get highly restricted access to
each other, according to the same-origin policy.
For example, code served from https://example.org/ trying to access
objects from https://somewhere-else.org/ will have restricted
access. - Objects in a privileged scope are allowed complete access to
objects in a less privileged scope, but by default they see a
restricted view
of such objects, designed to prevent them from being tricked by the
untrusted code. An example of this scope is chrome-privileged
JavaScript accessing web content. - Objects in a less privileged scope don't get any access to
objects in a more privileged scope, unless the more privileged scope
explicitly clones those objects.
An example of this scope is web content accessing objects in a
chrome-privileged scope.
(compartments)=
Compartments
Compartments are the foundation for Gecko's script security
architecture. A compartment is a specific, separate area of memory. In
Gecko, there's a separate compartment for every global object. This
means that each global object and the objects associated with it live in
their own region of memory.
Normal content windows are globals, of course, but so are chrome
windows, sandboxes, workers, the ContentFrameMessageManager in a frame
script, and so on.
Gecko guarantees that JavaScript code running in a given compartment is
only allowed to access objects in the same compartment. When code from
compartment A tries to access an object in compartment B, Gecko gives it
a cross-compartment wrapper. This is a proxy in compartment A for the
real object, which lives in compartment B.
Inside the same compartment, all objects share a global and are
therefore same-origin with each other. Therefore there's no need for any
security checks, there are no wrappers, and there is no performance
overhead for the common case of objects in a single window interacting
with each other.
Whenever cross-compartment access happens, the wrappers enable us to
implement the appropriate security policy. Because the wrapper we choose
is specific to the relationship between the two compartments, the
security policy it implements can be static: when the caller uses the
wrapper, there's no need to check who is making the call or where it is
going.
(cross-compartment-access)=
Cross-compartment access
(same-origin)=
Same-origin
As we've already seen, the most common scenario for same-origin access
is when objects belonging to the same window object interact. This all
takes place within the same compartment, with no need for security
checks or wrappers.
When objects share an origin but not a global - for example two web
pages from the same protocol, port, and domain - they belong to two
different compartments, and the caller gets a transparent wrapper to
the target object.
Transparent wrappers allow access to all the target's properties:
functionally, it's as if the target is in the caller's compartment.
(cross-origin)=
Cross-origin
If the two compartments are cross-origin, the caller gets a
cross-origin wrapper.
This denies access to all the object's properties, except for a few
properties of Window and Location objects, as defined by
the same-origin
policy.
(privileged-to-unprivileged-code)=
Privileged to unprivileged code
The most obvious example of this kind of security relation is between
system-privileged chrome code and untrusted web content, but there are
other examples in Gecko. The Add-on SDK runs content scripts in
sandboxes, which are initialized with an expanded
principal,
giving them elevated privileges with respect to the web content they
operate on, but reduced privileges with respect to chrome.
If the caller has a higher privilege than the target object, the caller
gets an Xray wrapper for the object.
Xrays are designed to prevent untrusted code from confusing trusted code
by redefining objects in unexpected ways. For example, privileged code
using an Xray to a DOM object sees only the original version of the DOM
object. Any expando properties are not visible, and if any native DOM properties have been
redefined, they are not visible in the Xray.
The privileged code is able to waive Xrays if it wants unfiltered access to the untrusted object.
See Xray vision for much more information on Xrays.
(unprivileged-to-privileged-code)=
Unprivileged to privileged code
If the caller has lower privileges than the target object, then the
caller gets an opaque wrapper.
An opaque wrapper denies all access to the target object.
However, the privileged target is able to copy objects and functions
into the less privileged scope using the exportFunction() andcloneInto() functions, and the less privileged scope is then able
to use them.
(security-checks)=
Security checks
To determine the security relation between two compartments, Gecko uses
two concepts: security principals and the act of subsuming. To
establish the security relationship between two compartments A and B,
Gecko asks:
Does the security principal for compartment A subsume the security
principal for compartment B, and vice versa?
(subsumes)=
Subsumes
+-----------------------------------+-----------------------------------+
| *A subsumes B* | A has all of the privileges of B, |
| | and possibly more, and therefore |
| | A is allowed to see and do |
| | anything that B can see and do. |
+-----------------------------------+-----------------------------------+
| *A Subsumes B &&* *B Subsumes A* | A and B are same-origin. |
+-----------------------------------+-----------------------------------+
| *A Subsumes B && B !Subsumes A* | A is more privileged than B. |
| | |
| | A gets access to all of B, by |
| | default with Xray vision, which |
| | it may choose to waive. |
| | |
| | B gets no access to A, although A |
| | may choose to export objects to |
| | B. |
+-----------------------------------+-----------------------------------+
| *A !Subsumes B && B !Subsumes A* | A and B are cross-origin. |
+-----------------------------------+-----------------------------------+(security-principals)=
Security principals
There are four types of security principal: the system principal,
content principals, expanded principals, and the null principal.
(system-principal)=
System principal
The system principal passes all security checks. It subsumes itself and
all other principals. Chrome code, by definition, runs with the system
principal, as do frame scripts.
(content-principal)=
Content principal
A content principal is associated with some web content and is defined
by the origin
of the content. For example, a normal DOM window has a content principal
defined by the window's origin. A content principal subsumes only other
content principals with the same origin. It is subsumed by the system
principal, any expanded principals that include its origin, and any
other content principals with the same origin.
(expanded-principal)=
Expanded principal
An expanded principal is specified as an array of origins:
["http://mozilla.org", "http://moz.org"]The expanded principal subsumes every content principal it contains. The
content principals do not subsume the expanded principal, even if the
expanded principal only contains a single content principal.
Thus ["http://moz.org"] subsumes "http://moz.org" but not vice
versa. The expanded principal gets full access to the content principals
it contains, with Xray vision by default, and the content principals get
no access to the expanded principal.
This also enables the script security model to treat compartments that
have expanded principals more like part of the browser than like web
content. This means, for example, that it can run when JavaScript is
disabled for web content.
Expanded principals are useful when you want to give code extra
privileges, including cross-origin access, but don't want to give the
code full system privileges. For example, expanded principals are used
in the Add-on SDK to give content scripts cross-domain privileges for a predefined set of
domains,
and to protect content scripts from access by untrusted web content,
without having to give content scripts system privileges.
(null-principal)=
Null principal
The null principal fails almost all security checks. It has no
privileges and can't be accessed by anything but itself and chrome. It
subsumes no other principals, even other null principals. (This is what
is used when HTML5 and other specs say "origin is a globally unique
identifier".)
(principal-relationships)=
Principal relationships
The diagram below summarizes the relationships between the different
principals. The arrow connecting principals A and B means "A subsumes
B". (A is the start of the arrow, and B is the end.)
(computing-a-wrapper)=
Computing a wrapper
The following diagram shows the factors that determine the kind of
wrapper that compartment A would get when trying to access an object in
compartment B.
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 indom/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 atdom/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 withBinding 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 indom/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 classmozilla::dom::MyInterface that's supposed to implement that
interface, you need to do the following:
If your interface doesn't inherit from any other interfaces, inherit
fromnsWrapperCacheand 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 fromnsISupports, make
sure thensISupportscomes before thensWrapperCachein 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_ENDIf 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 theGetParentObjectchain will eventually get you to a
Window, so that every Web IDL object is associated with a particular
Window.
For example,nsINode::GetParentObjectreturns the node's owner
document. The return type ofGetParentObjectdoesn't matter other
than it must either singly-inherit fromnsISupportsor have a
correspondingToSupports
method that can produce annsISupportsfrom it. (This allows the
return value to be implicitly converted to aParentObject
instance by the compiler via one of that class's non-explicit
constructors.)
If many instances ofMyInterfaceare expected to be created
quickly, the return value ofGetParentObjectshould itself inherit
fromnsWrapperCachefor optimal performance. Returning null fromGetParentObjectis 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 fromGetParentObject
must be defined in a header included from your implementation header,
so that this type's definition is visible to the binding code.Add the Web IDL for
MyInterfaceindom/webidland to the list
indom/webidl/moz.build.Add an entry to
dom/bindings/Bindings.confthat sets some basic
information about the implementation of the interface. If the C++
type is notmozilla::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 (orHeaderFileannotation 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 yourFunc
annotations.Add external interface entries to
Bindings.conffor whatever
non-Web IDL interfaces your new interface has as arguments or return
values.Implement a
WrapObjectoverride onmozilla::dom::MyInterface
that just calls through tomozilla::dom::MyInterface_Binding::Wrap. Note that if your C++
type is implementing multiple distinct Web IDL interfaces, you need
to choose whichmozilla::dom::MyInterface_Binding::Wrapto call
here. SeeAudioContext::WrapObject, for example.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 runningmach webidl-example MyInterface. This will produce two files indom/bindingsin your objdir:MyInterface-example.handMyInterface-example.cpp, which show a basic implementation of the
interface using a class that inherits fromnsISupportsand 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-webidl-constructs)=
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 aconst 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:
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:
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:
- The type of the attribute is nullable.
- The getter can throw.
- 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 namedConstructor. The arguments of this method will be the arguments of
the Web IDL constructor, with aconst 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 aJSContext* is also needed due to some of the argument types, it will
come after the global. The return value of the constructor forMyInterface is exactly the same as that of a method returning an
instance of MyInterface. Constructors are always allowed to throw.
For example, this IDL:
interface MyInterface {
constructor();
constructor(unsigned long someNumber);
};will require the following declarations in MyClass:
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 wrappingNullable<> 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 aconst 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:
anyarguments becomeJS::Handle<JS::Value>. They will be in
the compartment of the passed-in JSContext.anyreturn values become aJS::MutableHandle<JS::Value>out
param appended to the argument list. This comes after all IDL
arguments, but before theErrorResult&, 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.anydictionary members and sequence elements becomeJS::Value. The dictionary members and sequence elements are
guaranteed to be marked by whomever puts the sequence or dictionary
on the stack, usingSequenceRooterandDictionaryRooter.
Methods using any always get a JSContext* argument.
For example, this Web IDL:
interface Test {
attribute any myAttr;
any myMethod(any arg1, sequence<any> arg2, optional any arg3);
};will correspond to these C++ function declarations:
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:
interface Test {
attribute boolean myAttr;
boolean myMethod(optional boolean arg);
};will correspond to these C++ function declarations:
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:
interface Test {
attribute short myAttr;
long long myMethod(unsigned long? arg);
};will correspond to these C++ function declarations:
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:
interface Test {
float myAttr;
double myMethod(unrestricted double? arg);
};will correspond to these C++ function declarations:
float MyAttr();
void SetMyAttr(float value);
double MyMethod(const Nullable<double>& arg);(domstring-c)=
`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 theErrorResult&, if any, for the method. Note that
this allows callees to declare their methods as taking annsAString&ornsString&if desired. - Strings in sequences, dictionaries, owning unions, and variadic
arguments becomensString.
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 aDOMString.
For example, this Web IDL:
interface Test {
DOMString myAttr;
[Throws]
DOMString myMethod(sequence<DOMString> arg1, DOMString? arg2, optional DOMString arg3);
};will correspond to these C++ function declarations:
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 theErrorResult&, if any, for the method. - In sequences, dictionaries owning unions, and variadic arguments it
becomesnsCString.
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:
ByteStringarguments becomeconst nsACString&.ByteStringreturn values become annsCString&out param
appended to the argument list. This comes after all IDL arguments,
but before theErrorResult&, if any, for the method.ByteStringin sequences, dictionaries, owning unions, and
variadic arguments becomesnsCString.
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:
objectarguments becomeJS::Handle<JSObject*>. They will be
in the compartment of the passed-in JSContext.objectreturn values become aJS::MutableHandle<JSObject*>
out param appended to the argument list. This comes after all IDL
arguments, but before theErrorResult&, 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.objectdictionary members and sequence elements becomeJSObject*. The dictionary members and sequence elements are
guaranteed to be marked by whoever puts the sequence or dictionary on
the stack, usingSequenceRooterandDictionaryRooter.
Methods using object always get a JSContext* argument.
For example, this Web IDL:
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:
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 frommozilla::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>orFoo*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 byRefPtr<Foo>if nullable
andOwningNonNull<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 asthis.
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 trailingmozilla::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 theErrorResult and will be reported when the stack unwinds to wherever
the ErrorResult was set up.
For example, this Web IDL:
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:
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 ofMyInterface:
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:
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 thenativeType listed for the external interface in theBindings.conf file. The exact representation
depends on how the type is being used.
- Arguments become
nsIFoo*. - Return values can be
already_AddRefed<nsIFoo>ornsIFoo*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 byRefPtr<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 inBindings.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 avoid* can be stored in the JSObject which can then bereinterpret_cast to any of the classes that correspond to interfaces
the object implements. The C++ type to be used should be thenativeType listed for the interface in theBindings.conf file, ormozilla::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>orFoo*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 byRefPtr<Foo>if nullable andOwningNonNull<Foo>otherwise.
For example, this Web IDL:
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:
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:
interface Test {
undefined passTypedArrayBuffer(ArrayBuffer arg);
undefined passTypedArray(ArrayBufferView arg);
undefined passInt16Array(Int16Array? arg);
}will correspond to these C++ function declarations:
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 asRootedTypedArray<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 aJS::Value in C++ code by invoking their Init() method. Consumers
doing this should declare their dictionary asRootedDictionary<DictionaryName>. When this is done, passing in a
null JSContext* is allowed if the passed-in JS::Value isJS::NullValue(). Likewise, a dictionary struct can be converted to aJS::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:
dictionary Dict {
long foo = 5;
DOMString bar;
};
interface Test {
undefined initSomething(optional Dict arg = {});
};will correspond to this C++ function declaration:
void InitSomething(const Dict& arg);and the Dict struct will look like this:
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:
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:
enum MyEnum {
"something",
"something-else",
"",
"another"
};would lead to this C++ enum declaration:
enum class MyEnum : uint8_t {
Something,
Something_else,
_empty,
Another
};mozilla::dom::GetEnumString is a templated helper function declared inBindingUtils.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 inBindingUtils.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 inBindingIPCUtils.h
exported to mozilla/dom/BindingIPCUtils.h to implement an IPC serializer with
the right validation for WebIDL enums. It uses amozilla::MaxContinuousEnumValue that is generated for every WebIDL enum to
implement the validation.
mozilla::dom::MakeWebIDLEnumeratedRange is a templated helper function inBindingUtils.h
and exported to mozilla/dom/BindingUtils.h that can be used to create amozilla::EnumeratedRange for a WebIDL enum.
Callback function types
Callback functions are represented as an object, inheriting frommozilla::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 thethis value. The second Call method allows passing in an explicitthis 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. IfaReportExceptions 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:
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:
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:
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:
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 byconst 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:
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:
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:
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 aRootedUnion, 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:
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:
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 StringToLongMapBindingsSetlike
Example Interface:
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:
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:
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:
interface StringAndLongIterable {
iterable<DOMString, long>;
};The bindings for this pair value iterator interface require the
following methods be implemented in the C++ object:
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 calledStringify. So, for example, given this IDL:
interface FirstInterface {
stringifier;
};
interface SecondInterface {
stringifier DOMString getStringRepresentation();
};the corresponding C++ would be:
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. AJSContext will be passed if any of the operation arguments need it.
So for example, given this IDL:
interface InterfaceWithCall {
legacycaller long (float arg);
};the corresponding C++ would be:
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
NamedGettermethod. 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
NameIsEnumerablemethod. This takes a property name and
returns a boolean that indicates whether the property is enumerable. - A
GetSupportedNamesmethod. This takes an unsigned integer which
corresponds to the flags passed to theiterateproxy trap and
returns a list of property names. For implementations of this method,
the important flags isJSITER_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 andGetSupportedNames methods need to agree on which names are
supported.
So for example, given this IDL:
interface InterfaceWithNamedGetter {
getter long(DOMString arg);
};the corresponding C++ would be:
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
IndexedGettermethod. 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:
interface InterfaceWithIndexedGetter {
getter long(unsigned long index);
readonly attribute unsigned long length;
};the corresponding C++ would be:
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 theErrorResult& 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 callingThrow().
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, useProcessData(...) 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:
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:
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 namename. 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. TheStaticPrefs 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:
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:
[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)=
`[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:
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++:
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:
[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:
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:
EverythingThis 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.DOMStateThe 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.DeviceStateThe 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.NothingThe 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:
EverythingThis 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.NothingCalling 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 thanEverything, 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
signaturevoid 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)=
`[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:
interface MyInterface {
[Pure, StoreInSlot] attribute long myAttribute;
};the C++ implementation of MyInterface would clear the cached value by
callingmozilla::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 aJSContext.
So for example, given this IDL:
interface MyInterface {
[Pure, Cached] attribute long myAttribute;
};the C++ implementation of MyInterface would clear the cached value by
callingmozilla::dom::MyInterface_Binding::ClearCachedMyAttributeValue(this).
JS-implemented Web IDL can clear the cached value by callingthis.__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 callObject.freeze
on the return value before returning it. This extended attribute is only
allowed on attributes that return sequences, dictionaries andMozMap, 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:
interface InterfaceWithRenamedThings {
[BinaryName="renamedMethod"]
undefined someMethod();
[BinaryName="renamedAttribute"]
attribute long someAttribute;
};the corresponding C++ would be:
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 withisSecureContext: 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:
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:
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 twoInit 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:
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 theToObjectInternal 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:
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 additionalbool* 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 isnull, 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:
interface Element {
[Frozen, ReflectedHTMLAttributeReturningFrozenArray]
attribute sequence<Element>? reflectedHTMLAttribute;
};will require the following declarations in Element:
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-t)=
`Nullable`
Nullable<> is a struct declared inNullable.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) andT& SetValue() for directly modifying the underlying T&.
(optional-t)=
`Optional`
Optional<> is a struct declared inBindingDeclarations.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-t)=
`NonNull`
NonNull<T> is a struct declared inBindingUtils.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-t)=
`OwningNonNull`
OwningNonNull<T> is a struct declared inOwningNonNull.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 asArrayBuffer 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 andArrayBufferView) 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-t)=
`Sequence`
Sequence<> is a type declared inBindingDeclarations.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 tonsString& so that it can be passed to methods that take that type ornsAString&, but callees that care about performance, have anStringBuffer available, and promise to hold on to theStringBuffer 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 theJSObject* 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 theJSContext* 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 aToDateObject() 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 annsresult. Thensresultmust be
a failure code.ThrowTypeError: allows throwing aTypeErrorwith the given
error message. The list of allowedTypeErrors and corresponding
messages is indom/bindings/Errors.msg.ThrowJSException: allows throwing a preexisting JS exception
value. However, theMightThrowJSException()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 thisErrorResult.ErrorCode: returns a failurensresultrepresenting (perhaps
incompletely) the state of thisErrorResult.operator=: takes annsresultand acts likeThrowif 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:
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:
IMPL_EVENT_HANDLER(onthingchange);The "onthingchange" needs to be added to the StaticAtoms.py file:
Atom("onthingchange", "onthingchange")The actual implementation (.cpp) for firing the event would then look
something like:
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)=
`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-webidl-using-javascript)=
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:
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:
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:
var contentObject = contentWin.RTCPeerConnection._create(contentWin,
new MyPeerConnectionImpl());Creating the object this way will not invoke its __init method orinit 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 orinit 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 attributeJSImplementation="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:
[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. ForQueryInterface, 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.
[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; callingFoo.doSomething() will result in callingmozilla::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 attributePref="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 attributeFunc="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. TheinvisibleValue field will not be accessible to web content, but is
usable by the doNothing() method.
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 aboutobject 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 callingComponent.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:
if (!isValid(passedInObject)) {
throw new this.contentWindow.TypeError("Object is invalid");
}or
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:
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; ifdefaultImpl is not specified, the nativeType will be used.
For example, consider this interface that we wish to implement in
JavaScript:
[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:
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 onEventTarget (so, for example, addEventListener). Calling thedispatchTheEvent 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.
Dom Docs WorkersAndStorage Index (`dom/docs/workersAndStorage/index.md`)
DOM Workers & Storage
These linked pages contain design documents for the Workers & Storage implementations in Gecko. They live in-tree under the 'dom/docs/workerAndStorage' directory.
:maxdepth: 1
CodeStyle
PerformanceTesting
WorkerLifeCycleAndWorkerRefsDom Media Docs Index (`dom/media/docs/index.md`)
Media Playback
:maxdepth: 1
MediaFormatReader
review/index
AudioStream
AudioSinkWrapper
SpeechRecognitionBrowser App Desktop Launcher Docs Index (`browser/app/desktop-launcher/docs/index.md`)
Desktop Launcher app
A substantial number of users will upgrade to Windows 11 in a way that leaves no trace of Firefox on their device. To address these cases we will leave
an install entry point in their personal files, which will migrate at a higher rate than the app itself. In particular, files in the Desktop folder are
backed up by OneDrive and other cloud storage products, and likely to find their way back onto a new device.
This app acts as a replacement for the desktop shortcut to Firefox.
When Firefox is installed on the user's machine, when the user launches this app, it finds the path to Firefox in the appropriate Windows Registry keys
and attempts to launch Firefox from that path.
When there is no Firefox installation found, this app will attempt to download and run the Firefox "stub" installer.
As a final fallback, this app will open the Firefox download URL in the default browser.
What controls whether or not Desktop Launcher is installed?
At installation time:
- What kind of installer is this?
: - Stub: install the launcher, do not install shortcuts- Full: Let the user decide whether to get launcher, shortcuts, both, or neither. (Currently the full installer can only select to install the launcher
: using a command-line parameter. Eventually, there will be UI in the full installer. Work tracked by https://bugzilla.mozilla.org/show_bug.cgi?id=1981597) - Other (MSI, MSIX, zip): install shortcuts
- Full: Let the user decide whether to get launcher, shortcuts, both, or neither. (Currently the full installer can only select to install the launcher
At update time:
: - YES: Does this user already have the launcher installed?
: - YES: Then update it with the new version.
- NO: Is this a stub-installed package? (This is stored in installation_telemetry.json, see e.g. [BrowserUsageTelemetry.sys.mjs](https://searchfox.org/firefox-main/rev/cd6acbe9eaa55fb4da4fbdec275db6eddd4833b8/browser/modules/BrowserUsageTelemetry.sys.mjs#1875-1904))
: - NO: Do nothing
: - NO: Did we already install the launcher for the user?
: - YES: Don't install. This is how we avoid re-installing the launcher after a user has removed it.
- NO: Does the user have a desktop shortcut that points to Firefox, either in their own Desktop or the public Desktop?
: - YES: Remove the shortcut and install the launcher into the user's Desktop folder.
- NO: Do nothing
In elevated installer, we will delete the public shortcut and record the event if:
: - It exists
- We haven't deleted it before
- This is a stub installed Firefox
In the unelevated installer, we will delete the user shortcut and record the event if:
: - There is a user shortcut (i.e. this is a personal install)
- We haven't deleted it before
- This is a stub installed Firefox
In the unelevated installer, we will install the desktop launcher and record the event if:
: - It is already installed OR
: - It wasn't previously installed
- There is or was a shortcut (shared or personal)
- The installation type is "stub"
FAQ
Q: I don't like the Desktop Launcher. How can I get rid of it?
A: Delete it from your Desktop folder. It won't be reinstalled by updates, even if you create a new Firefox shortcut there. (We remember that it was previously installed using a Windows registry key.)
Browser App Installation Dir Layout Docs Index (`browser/app/installation_dir_layout/docs/index.md`)
Installation Directory Layout
Rationale
Firefox supports automatic downloading and applying of updates while the user is still using
the browser. However, once the update has been installed, files that the browser relies on
may have changed on disk, which caused the original implementation of update functionality to
force the user to restart the browser after updates. (See
_this bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1891600 for details and discussion.)
In order to let users continue to use the browser after updates are applied, the updater needs
to leave in place the files associated with the running browser, for as long as the browser's process
exists.
The approach we are taking to enable this behavior is a new installation layout called "versioned install directories".
What this involves is:
- Under the "base" install directory, there will be one or more "versioned" install directories,
with names based on the version of Firefox installed in them. - Each versioned directory contains a complete installation of Firefox at the approapriate version.
- In the base install directory, there will be a launcher exectuable that launches the Firefox
: executable in the appropriate versioned directory for the current Firefox version,
Example of "single" layout
This process allows all of the file resolution in Firefox to remain unchanged (for example,
C:\Program Files\Mozilla Firefox\136.0.1a\firefox.exe will load libraries from the directory
C:\Program Files\Mozilla Firefox\136.0.1a\). Most code will have no need to be aware of the change.
However, when applying updates to an installation,
the updater needs to know if it should:
- apply updates to a "single" install directory, and leave a single install directory in place (current behavior)
- apply updates to a single install directory, and migrate it to be a versioned install
- apply updates to a versioned install directory, using the new versioned install behavior
This means that the updater needs a way to know unambiguously whether an installation
is using a single or versioned layout. This is the functionality provided by this module.
Module contents
The installation_dir_layout module provides two different implementations of a library installation_dir_layout.dll
This library has a single function, GetInstallationDirLayoutType, which returns an enumerated type.
The implementation of installation_dir_layout.dll in the single directory returns InstallationDirLayoutType::Single
The implementation of installation_dir_layout.dll in the versioned directory returns InstallationDirLayoutType::Versioned
The interface for both implementations is specified in InstallationDirLayout.h
DLL installation
When Firefox is installed or updated, the installer or updater will choose the appropriate version of installation_dir_layout.dll
to install. This version will be available to firefox.exe and its supporting utilities as a runtime library.
DLL usage
Code that needs to know about the installation directory layout (such as updater and uninstaller) will load the installed
version of the DLL and call GetInstallationDirLayoutType.
Browser App Pbproxy Docs Index (`browser/app/pbproxy/docs/index.md`)
Private Browsing Proxy
On Windows, Firefox ships with a small binary that always launchesfirefox.exe in Private Browsing mode (private_browsing.exe). Its sole
purpose for existing is to allow Private Browsing shortcuts to have their own
Visual Elements. This is most notably seen when pinning a Private Browsing
shortcut to the Start Menu -- Visual Elements are used for the icon there
rather than the shortcut's icon.
In addition to always passing -private-window, private_browsing.exe
will forward any other command line arguments given to it to firefox.exe.
It will also forward shortcut information from the Windows STARTUPINFOW
structure to ensure that Firefox knows how it was started.
Browser Components Aboutwelcome Docs Index (`browser/components/aboutwelcome/docs/index.md`)
Firefox Welcome Experience ()
Files related to the Firefox welcome experience, which includes content that appears on about:welcome, can be found in the browser/components/aboutwelcome directory.
Some of these source files (such as .js, .jsx, and .scss) require an additional build step.
We are working on migrating this to work with mach, but in the meantime, please
follow the following steps if you need to make changes in this directory:
For `.sys.mjs` files (system modules)
No build step is necessary. Use mach and run mochitests according to your regular Firefox workflow.
For `.js`, `.jsx`, `.scss`, or `.css` files
Prerequisites
You will need the following:
- Node.js 10+ (On Mac, the best way to install Node.js is to use the install link on the Node.js homepage)
- npm (packaged with Node.js)
To install dependencies, run the following from the root of the mozilla-central repository.
(Using mach to call npm and node commands will ensure you're using the correct versions of Node and npm.)
(cd browser/components/aboutwelcome && ../../../mach npm install)Which files should you edit?
You should not make changes to .js or .css files in the browser/components/aboutwelcome/content directory. Instead, you should edit the .jsx, .js, and .scss source files
in browser/components/aboutwelcome/content-src directory. These files will be compiled into the .js and .css files.
Building assets and running Firefox
To build assets and run Firefox, run the following from the root of the mozilla-central repository:
./mach npm run bundle --prefix=browser/components/aboutwelcome && ./mach build && ./mach runContinuous development / debugging
Running ./mach npm run watchmc --prefix=browser/components/aboutwelcome will start a process that watches files inaboutwelcome and rebuilds the bundled files when JS or CSS files change.
IMPORTANT NOTE: This task will add inline source maps to help with debugging, which changes the memory footprint.
Do not use the watchmc task for profiling or performance testing!
Running tests
About:welcome unit tests are written using
mocha, and other errors that may show up there are
SCSS issues flagged by
stylelint. These things are all run usingnpm test under the aboutwelcome slug in Treeherder/Try, so if that slug turns
red, these tests are what is failing. To execute them, do this:
./mach npm test --prefix=browser/components/aboutwelcomeWindows isn't currently supported by npm test
(path/invocation difference).
To run tests that aren't covered by mach lint andmach test:
./mach npm run lint:stylelint --prefix=browser/components/aboutwelcome
./mach npm run testmc:build --prefix=browser/components/aboutwelcome
./mach npm run testmc:unit --prefix=browser/components/aboutwelcomeMochitests run normally, using mach test browser/components/aboutwelcome.
Code Coverage
Our testing setup will run code coverage tools in addition to just the unit
tests. It will error out if the code coverage metrics don't meet certain thresholds.
If you see any missing test coverage, you can inspect the coverage report by
running
./mach npm test --prefix=browser/components/aboutwelcome &&
./mach npm run debugcoverage --prefix=browser/components/aboutwelcomeBrowser Components Asrouter Docs Index (`browser/components/asrouter/docs/index.md`)
Messaging System
Vision
Firefox must be an opinionated user agent that keeps folks safe, informed and
effective while browsing the Web. In order to have an opinion, Firefox must
have a voice.
That voice will respect the user’s attention while surfacing contextually
relevant and timely information tailored to their individual needs and choices.
What does Messaging System support?
There are several key windows of opportunity, such as the first-run activation
phase or coordinated feature releases, where Firefox engages with users.
The Firefox Messaging System supports this engagement by targeting messages
exactly to the users who need to see them and enables the development of new
user messages that can be easily tested and deployed. It offers standard
mechanisms to measure user engagement and to perform user messaging experiments
with reduced effort across engineering teams and a faster delivery cycle from
ideation to analysis of results.
This translates to users seeing fewer and more relevant in-product
messages, while supporting fast delivery, experimentation, and protection of
our users time and attention.
Messaging System Overview
At the core of the Firefox Messaging System is the Messaging System Router
(called ASRouter for historical reasons). The router is a generalized Firefox
component and set of conventions that provides:
- Flexible and configurable routing of local or remote Messages to UI
Templates. This allows new message campaigns to be started and controlled
on or off-trains - Traffic Cop message sequencing and intermediation to prevent multiple
messages being concurrently shown - Programmable message targeting language to show the right message to the
right user at the right time - A template library of reusable Message and Notification UIs
- Full compatibility with Normandy pref-flip experiments
- Generalized and privacy conscious event telemetry
- Flexible Frequency Capping to mitigate user message fatigue
- Localized off train Messages
- Powerful development/debugging/QA tools on about:asrouter
Message Routing
The Firefox Messaging System implements a separation-of-concerns pattern for
Messages, UI Templates, and Timing/Targeting mechanisms. This allows us to
maintain a high standard of security and quality while still allowing for
maximum flexibility around content creation.
UI Templates
We have built a library of reusable Notification and Message interfaces which
land in the Firefox codebase and ride the trains. These templates have a
defined schema according to the available design components (e.g. titles, text,
icons) and access to a set of enhanced user actions such as triggering URLs,
launching menus, or installing addons, which can be attached to interactive
elements (such as buttons).
Warning! Before reading, you should consider whether a Messaging Experiment is relevant for your needs.
Current templates include:
% In theory, we ought to be able to use the :glob: directive here to
% automatically generate the list below. For unknown reasons, however,
% mach doc sometimes gets confused and refuses to find patterns like
% *.md.
:maxdepth: 1
action-only
moments-page
feature-callout
about-welcome
infobars
spotlight
private-browsing
multi-message
menu-message
sidebar-chatbot-promoDetailed Docs
Explore key terms in the Messaging System Glossary.
Learn which actions, triggers, and context properties work on which surfaces in Messaging Surface Compatibility.
Learn more about messaging experimentation through Nimbus in the Messaging System: Experimenter Onboarding.
% In theory, we ought to be able to use the :glob: directive here to
% automatically generate the list below. For unknown reasons, however,
% mach doc sometimes gets confused and refuses to find patterns like
% *.md.
:maxdepth: 2
asrouter-newtab-message
asrouter-newtab-multistage-message
building-and-testing
debugging-docs
frequency-caps
first-run
messaging-glossary
messaging-surfaces
remote_cfr
targeting-attributes
targeting-guide
telemetry
skylightBrowser Components Attribution Docs Index (`browser/components/attribution/docs/index.md`)
Installation Attribution
Installation Attribution is a system that allows us to do a few things:
- Gauge the success of marketing campaigns
- Determine (roughly) the origin of an installer that a user ran
- Support the Return to AMO workflow.
We accomplish these things by adding an attribution code to Firefox installers which generally contains information supplied by https://www.mozilla.org (Bedrock and related services). This information is read by Firefox during and after installation, and sent back to Mozilla through Firefox Telemetry.
The following information is supported by this system:
- Traditional UTM parameters (source, medium, campaign, and content)
- experiment
- variation
- ua
- dltoken
- dlsource
- msstoresignedin
- msclkid
Descriptions of each of these can be found in {doc}the Telemetry Environment documentation </toolkit/components/telemetry/data/environment>.
Firefox Windows Installers & macOS DMGs
Installs done through Windows stub or full NSIS installers or macOS DMGs are capable of being attributed. When these packages are created, they are given initial attribution data of dlsource=mozillaci. Users who download their package via https://www.mozilla.org will typically have this attribution data overwritten (unless they have Do-not-track (DNT) enabled), with dlsource=mozorg, a dltoken, and whatever UTM parameters Bedrock deems appropriate.
An additional complication here is that the attribution system is used (or abused, depending on your view) to support the Return to AMO workflow -- forcing the campaign and content UTM parameters to specific values.
The below diagram illustrates the flow of the cases above:
/* Detailed source-code truncated for AI context efficiency. */Windows
Windows attribution is implementing by injecting data into the signature block of NSIS installers at download time. This technique is described in the "Cheating Authenticode" section of this Microsoft blog post.
macOS
macOS attribution is implemented by adding a com.apple.application-instance extended attribute to the .app bundle at download time. This special extended attribute is explicitly not part of the digital signature of the .app bundle as per this Apple technical note.
Microsoft Store
Firefox installs done through the Microsoft Store support extracting campaign IDs that may be embedded into them. This allows us to attribute installs through different channels by providing particular links to the Microsoft Store with attribution data included. For example:
ms-windows-store://pdp/?productid=9NZVDKPMR9RD&cid=source%3Dgoogle.com%26medium%3Dorganic%26campaign%3D(not%20set)%26content%3D(not%20set)
Microsoft Store Ads presents its Ads Campaign ID to installed applications as a uniquely formatted storeBingAd_[uuid], for example storeBingAd_45cbbf091fb541f0ae959d50ffb8c5b8. Firefox records this as msclkid=[uuid], for example msclkid=45cbbf091fb541f0ae959d50ffb8c5b8 in installation attribution.
For more on how custom campaign IDs work in general in the Microsoft Store environment, see Microsoft's documentation.
The Microsoft Store provides a single cid (Campaign ID). Their documentation claims it is limited to 100 characters, although in our own testing we've been able to retrieve the first 208 characters of Campaign IDs. Firefox expects this Campaign ID to follow the same format as stub and full installer attribution codes, which have a maximum of length of 1010 characters. Since Campaign IDs are more limited than what Firefox allows, we need to be a bit more thoughtful about what we include in them vs. stub and full installer attribution. At the time of writing, we've yet to be able to test whether we can reliably pull more than the advertised 100 characters of a Campaign ID in the real world -- something that we should do before we send any crucial information past the first 100 characters.
In addition to the attribution data retrieved through the campaign ID, we also add an extra key to it to indicate whether or not the user was signed into the Microsoft Store when they installed. This msstoresignedin key can have a value of true or false.
There are a couple of other caveats to keep in mind:
- A campaign ID is only set the first time a user installs Firefox through the Store. Subsequent installs will inherit the original campaign ID (even if it was an empty string). This means that only brand new installs will be attributed -- not reinstalls.
- At the time of writing, it is not clear whether or not installs done without being signed into the Microsoft Store will be able to find their campaign ID. Microsoft's documentation claims they can, but our own testing has not been able to verify this.
Browser Components Backup Docs Index (`browser/components/backup/docs/index.md`)
(components-backup)=
Backup Component
The Backup Component is responsible for creating backups of user profile data
into a single file that can be easily restored from.
:maxdepth: 3
architecture
backup-service
backup-resources
backup-ui-actors
archive-encryption
schemasBrowser Components Customizableui Docs Index (`browser/components/customizableui/docs/index.md`)
(components-customizableui)=
CustomizableUI Component
This component is responsible for managing and manipulating the default and
customized state of various UI surfaces in the browser. Most of the logic for
doing this resides in CustomizableUI, but some responsibility is also
delegated to modules like CustomizableWidgets and CustomizeMode.
:maxdepth: 3
customizableui
drag-position-manager
overflowable-toolbar
panelmultiview
search-widget-tracker
toolbar-context-menu
customize-modeBrowser Components Enterprisepolicies Docs Index (`browser/components/enterprisepolicies/docs/index.md`)
Enterprise Policies
Introduction
Enterprise policies control Firefox behavior and let you centrally manage various aspects of Firefox across devices.
Policies can be applied using Group Policy, Microsoft Intune, or by creating a file called policies.json and defining behavior within the JSON.
The reference documentation for each policy, including guides for applying and managing them, is in the Firefox Admin Documentation.
For other resources for deploying Firefox in an organization, see the Firefox Enterprise page.
Kiosk Mode
Firefox Kiosk Mode is a basic full-screen mode intended for environments where the content displayed in the browser is controlled by a kiosk owner.
It's designed for cases where users have no keyboard access or where keyboard access is restricted (particularly Ctrl and Alt).
Kiosk administrators are responsible for ensuring that content displayed on the device cannot unexpectedly navigate users away.
To run Kiosk Mode, start Firefox from the command line with the --kiosk option:
firefox --kiosk
# Or provide a URL
firefox --kiosk 'https://example.com/my-dashboard'To put the kiosk window on a particular monitor, use --kiosk-monitor with the monitor number, instead:
# --kiosk-monitor implies --kiosk
firefox --kiosk-monitor 1 'https://example.com/my-dashboard'Kiosk Mode does three main things:
- Main browser windows (not popup windows) switch to full-screen mode that can't be exited within Firefox.
- The context menu isn't shown.
- Status for URLs and page loading isn't shown.
Two policies that are important for for a kiosk are
UserMessaging and
DisableFirefoxStudies.
Together they stop Firefox from interrupting the kiosk content with recommendations, onboarding, What's New, and studies.
Kiosk mode also won't suppress updates, the notifications and restart prompts for them, block about: pages, developer tools, and other behavior, so you should use policies for controlling these, too.
Policy schema and metadata
For policies, there is a schema file located at {searchfox}policies-schema.json .
Documentation and admin tools read this schema and can describe a policy without having to hardcode details about it beforehand.
The following policies-schema.json members are required for each policy:
description
: The description is written for the admins setting it and covers what the policy does.
x-category
: The category the policy is listed under, such as Security or Bookmarks.
x-compatibility
: Which release channels the policy is available, described below.
x-restart-required
: Whether the policy needs a restart before it's applied. Firefox ignores this since it applies all policies at startup, so set it to true for a new policy. Firefox Enterprise is the only consumer.
examples
: At least one value an admin could set, in the shape the policy accepts.
For each policy, the required members are enforced by a meta file
{searchfox}policies-schema.meta.json ,
which is checked by
{searchfox}test_policies_schema.js xpcshell tests.
Compatibility data
An x-compatibility block states the first version that supports a policy:
"x-compatibility": {
"firefox": { "version_added": "141" },
"firefox_esr": { "version_added": "140.1.0" },
"firefox_enterprise": { "version_added": "149" }
}In an x-compatibility block, all three release channels are required.
A version for each channel is a string of up to three numbers, or false if the channel doesn't support the policy.
An optional notes member can accompany compat information.
Notes as a sibling of all channels apply to every channel, like DisableLaunchOnLogin:
"x-compatibility": {
"firefox": { "version_added": "155" },
"firefox_esr": { "version_added": false },
"firefox_enterprise": { "version_added": "155" },
"notes": [
"Windows support added in 155, macOS support added in 156. Has no effect on Linux."
]
}Notes inside a release channel apply only to that channel:
"x-compatibility": {
"firefox": {
"version_added": "60",
"notes": "The policy accepted an object form in 123, and accepts a boolean form since 134."
},
"firefox_esr": { "version_added": "60" },
"firefox_enterprise": { "version_added": "149" }
}Browser Components Migration Docs Index (`browser/components/migration/docs/index.md`)
(components-migration)=
Migration
The migration component is responsible for bringing data from outside applications running on the same computer into Firefox. This is typically done via a wizard where users can choose what types of data to migrate over.
The migrator is also used during a "Profile Refresh" to pave over a newly created Firefox profile with some data from an older one.
:maxdepth: 3
migration-utils
migrators
migration-wizardBrowser Components Mozcachedohttp Docs Index (`browser/components/mozcachedohttp/docs/index.md`)
moz-cached-ohttp Protocol
The moz-cached-ohttp:// protocol handler enables Firefox to load resources over Oblivious HTTP (OHTTP)
from privileged contexts, including in the privileged about content process. This mechanism provides
privacy-preserving resource loading, and was originally designed for loading images in about:newtab.
:maxdepth: 2
usage
apiOverview
The moz-cached-ohttp protocol implements a cache-first strategy that:
- First attempts to load resources from the HTTP cache to minimize OHTTP requests
- Falls back to loading via OHTTP when resources are not available in cache
- Automatically caches OHTTP responses for future requests
- Respects HTTP cache expiration headers for proper cache management, but
otherwise defaults to 24 hours for the cache expiry.
Supported Contexts
The protocol is restricted to specific contexts for security:
- Privileged about content process: Primary use case is for privacy-preserving image loading on about:newtab
- System principals in parent process: For tests and internal usage
URL Format
The protocol uses a specific URL format to encode the target resource URL:
moz-cached-ohttp://newtab-image/?url=<encoded-url>Where <encoded-url> is the URL-encoded target HTTPS-only image URL.
:::{note}
Only the newtab-image host is currently supported. The host determines which OHTTP configuration and relay will be used for the request. See HOST_MAP in MozCachedOHTTPProtocolHandler.sys.mjs.
:::
:::{warning}
Only HTTPS target URLs are supported for security. HTTP URLs will be rejected.
:::
Example:
moz-cached-ohttp://newtab-image/?url=https%3A%2F%2Fexample.com%2Fimage.jpg:::{note}
The OHTTP Relay and Gateway must both be configured to enable requests. The OHTTP Gateway also needs to have an allowlist that includes the resource endpoint, otherwise requests are likely to return 403 Forbidden responses.
:::
Host-Based Configuration
The protocol uses a host-based configuration system that maps URL hosts to specific OHTTP settings. This design allows different types of resource requests to use different OHTTP configurations in the future.
Currently Supported Hosts
newtab-image: Used for New Tab page image loading
- Gateway Config URL preference:
browser.newtabpage.activity-stream.discoverystream.ohttp.configURL - Relay URL preference:
browser.newtabpage.activity-stream.discoverystream.ohttp.relayURL
- Gateway Config URL preference:
Future Extensibility
The host-based design allows easy addition of new hosts with different OHTTP configurations:
// Future hosts could be added like:
// moz-cached-ohttp://other-service/?url=<encoded-url>
// moz-cached-ohttp://ads-service/?url=<encoded-url>Each host would map to its own set of configuration preferences, allowing different services to use different OHTTP infrastructure.
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 theon 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 thePageDataSchema.DATA_TYPE enumeration. The value is the JSON data which differs in structure
depending on the data type.
{
"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 thePageData 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:
PRODUCTDOCUMENTARTICLEAUDIOVIDEO
Browser Components Places Docs Architecture Overview (`browser/components/places/docs/architecture-overview.md`)
Places architecture overview
Because Mozilla used to ship a framework called XULRunner, Places is split into a Toolkit and a Browser part. The toolkit part is usually made up of product-agnostic APIs, those can be used by any kind of project, not just Web Browsers. The browser part is the one containing code specific to the Firefox browser.
Codebase
Most of the codebase is written in:
: - JavaScript
- C++ (for ex., database initialization code or some of the visit tracking code).
Frontend
The frontend part of the bookmarking experience includes various kind of views:
: - {searchfox}Trees
- {searchfox}
Menus <mozilla-central/rev/4c184ca81b28f1ccffbfd08f465709b95bcb4aa1:browser/components/places/content/browserPlacesViews.js#1990> - {searchfox}
Toolbars <mozilla-central/rev/4c184ca81b28f1ccffbfd08f465709b95bcb4aa1:browser/components/places/content/browserPlacesViews.js#894>
All the views share a common {searchfox}Controller that is responsible to handle operations and commands required by the views. Each view creates a Result object and receives notifications about changes from it.
As an example, removing a bookmark from a view will call into the controller that calls into PlacesTransactions to actually do the removal. The removal will notify a {searchfox}Places event <dom/chrome-webidl/PlacesEvent.webidl>, that is caught by the Result, that will immediately update its internal representation of the bookmarks tree. Then the Result sends a notification to the view that will handle it, updating what the user is seeing. The system works according to the classical Model-View-Controller pattern.
Fronted dialogs and panels are written using xhtml and shadow DOM. The bookmark dialogs in particular are wrappers around a common template, {searchfox}editBookmarkPanel.inc.xhtml , it could be extended or overloaded like an object (overlay, similar to Web Component).
Most of the logic for the edit bookmark overlay lives in the generic script {searchfox}editBookmark.js .
Structure of Frontend
Most part of frontend code is located in : {searchfox}Browser/Components/Places/Content :
- {searchfox}
BookmarkProperties, BookmarkProperties.xhtml - responsible for editBookmarks & newBookmark Dialog. The panel is initialized based on data given in the js object passed aswindow.arguments[0].Window.arguments[0]is set to the guid of the item, if the dialog is accepted. - BookmarksHistoyTooltip.xhtml - code responsible for tooltip
- {searchfox}
BookmarksSidebar, bookmarksSidebar.xhtml - code responsible for sidebar window. Searches through existing bookmarks tree for desired bookmark. - {searchfox}
BrowserPlacesViews- controls most views (menu, panels, toolbox). The base view implements everything that's common to the toolbar and menu views. - {searchfox}
Controller- controller shared by all places views. Connect UI and actual operations. - {searchfox}
EditBookmark, editBookmarkPanel.inc.xhtml - controls edit bookmark panel. Observes changes for bookmarks and connects all UI manipulations with backend. - {searchfox}
HistorySidebar, historySidebar.xhtml - code responsible for history sidebar window. Searches through existing tree for requested History. - {searchfox}
Places-menupopup- custom element definition for Places menus - {searchfox}
Places-tree- classMozPlacesTree- builds a custom element definition for the places tree. This is loaded into all XUL windows. Has to be wrapped in a block to prevent leaking to a window scope. - Places.css, places.js, places.xhtml - responsible for Library window
- PlacesCommands.inc.xhtml - commands for multiple windows
- PlacesContextMenu.inc.xhtml - definition for context menu
- {searchfox}
TreeView- implementation of the tree view
Backend
Because any bookmark operation done by the user in the frontend is undo-able, Firefox usually doesn’t directly invoke the Bookmarks / History API, it instead goes through a wrapper called PlacesTransactions.
The scope of this module is to translate requests for bookmark changes into operation descriptors, and store them in a log. When a bookmark has been modified by the user, PlacesTransactions stores the previous state of it in the log; that state can be restored if the user picks Undo (or CTRL+Z) in the Library window. This prevents data loss in case the user removes bookmarks inadvertently.
Toolkit Places also provides a way to query bookmarks, through Results. This is one of the oldest parts of the codebase that will likely be rewritten in the future. It uses XPCOM (Cross Platform Component Object Model) a Mozilla technology that allows C++ and Javascript to communicate. It’s a declarative system, where interfaces must be defined and documented in XPIDL files. In practice all the available methods and attributes are documented in nsINavHistoryService.idl. Querying bookmarks returns a nsINavHistoryResult object that has a root node. The root node has children representing bookmarks or folders. It works like a tree, containers must be opened and then one can inspect their children. This is the base used by most of the Firefox frontend bookmark views.
Structure of Backend
Most part of backend code is located in : {searchfox}Toolkit/Components/Places <toolkit/components/places>:
- {doc}
Bookmarks- Asynchronous API for managing bookmarks - {doc}
History- Asynchronous API for managing history - {searchfox}
PlacesUtils <toolkit/components/places/PlacesUtils.sys.mjs>- This module exports functions for Sync to use when applying remote records - {doc}
PlacesTransactions- This module serves as the transactions manager for Places
Storage
Places uses SQLite (C-language library with a stable, cross-platform, and backwards compatible file format) as its data storage backend.
All the data is contained in a places.sqlite file, in the roaming Firefox profile folder. The database is accessed using a wrapper of the SQLite library called {searchfox}mozStorage <storage>.
For storing our favicons we use favicons.sqlite which is represented as ATTACH-ed to places.sqlite. That makes it easier to use our two separate sqlites as one single database.
Synchronization
Places works in strict contact with Firefox Sync, to synchronize bookmarks and history across devices, thus you can meet Sync specific code in various parts of the Places codebase. Some of the code may refer to Weave, the old project name for Sync.
Browser Components Places Docs Index (`browser/components/places/docs/index.md`)
Places
This document describes the implementation of the Firefox Places component.
It is a robust system to manage History and Bookmarks through a database on the backend side and a model-view-controller system that connects frontend UI user manipulation.
History and Bookmarks
In Firefox 2, History and Bookmarks used to be kept into separate databases in the Resource Description Framework format (RDF format).
However, Firefox 3 implemented the Places system. It has been done due to multiple reasons, such as:
- Performance: certain search or maintenance operations were very slow
- Reliability: the filesystem facing side of RDF was not so robust, often causing corruption or unexpected states
- Flexibility: being able to cross data allows for interesting features, like the Awesome Bar
- Maintainability: the future of RDF was unclear, while SQLite is actively maintained and used by a large number of applications
Where to Start
For the high-level, non-technical summary of how History and Bookmarks works, read {doc}nontechnical-overview.
For more specific, technical details of implementation, read {doc}architecture-overview.
Governance
See Bookmarks & History (Places)
Table of Contents
:maxdepth: 2
nontechnical-overview
architecture-overview
API for managing bookmarks <Bookmarks>
API for managing history <History>
Transactions Manager <PlacesTransactions>
Observer Notifications <notifyObservers>Browser Components Places Docs Nontechnical Overview (`browser/components/places/docs/nontechnical-overview.md`)
Nontechnical Overview
This document provides a high level, nontechnical overview of Firefox’s Places component (Bookmarks and History).
More information regarding Bookmarks - Bookmarks in Firefox
There are multiple ways to access and manipulate Bookmarks, such as:
:depth: 2Firefox menu bar
To access bookmarks click on Bookmarks link in Firefox menu bar on the top of your screen.
If the Firefox Menu bar is missing, it is usually because Firefox is in full screen mode or it is not the selected application.
In this case you can:
: - Turn off full screen mode
- Select the Firefox application
:::{figure} assets/nontechnical-overview/firefox-bookmarks-menu.png
:align: center
:alt: Image of the Bookmarks Menu in Firefox menu bar
:scale: 50%
Firefox menu bar - Bookmarks Menu
:::
Main application button
:::{figure} assets/nontechnical-overview/firefox-bookmarks-main-application.png
:align: center
:alt: Image of the main Bookmarks application button
:scale: 45%
Firefox - Bookmarks Main Application
:::
Bookmarks Toolbar
:::{figure} assets/nontechnical-overview/firefox-bookmarks-toolbar.png
:align: center
:alt: Image of the Bookmarks Toolbar
:scale: 50%
Firefox - Bookmarks Toolbar
:::
On the top of your Firefox screen just under the search bar - Bookmarks are on the left side.
Firefox's toolbar provides easy access to common features:
: - Click the menu button , click More Tools and choose Customize Toolbar.
- **To turn on the Title bar:** Put a check mark next to `Title Bar` in the lower left.
- **To turn on the Bookmarks toolbar:** Click the Toolbars dropdown menu at the bottom of the screen and select Bookmarks Toolbar.- Click the
Donebutton.
Firefox sidebar
Firefox comes with a convenient Sidebar button which lets you access your bookmarks, history and synced tabs in one click. For using it, you have to:
- Add the sidebar button to your controls.
- Toggle sidebar button on and off for preferable options (for ex., add bookmarks).
The Library window
- Click the
hamburger Menuicon in the upper-right corner of your screen. - In the middle of the drop-down menu select
Library. - In the
Librarymenu selectBookmarks. - Press
Show All Bookmarkbutton.
Keyboard shortcuts
- Show / Manage Bookmarks (Library Window) - {kbd}
Shift+ {kbd}Ctrl/ {kbd}Cmd+ {kbd}O - Add / Edit Bookmark - {kbd}
Ctrl/ {kbd}Cmd+ {kbd}D - Bookmark all tabs into 1 bookmark folder - {kbd}
Shift+ {kbd}Ctrl/ {kbd}Cmd+ {kbd}D - Delete bookmark / Bookmarks / Bookmarks folder - {kbd}
Delete - Show / Hide the Bookmarks toolbar - {kbd}
Shift+ {kbd}Ctrl/ {kbd}Cmd+ {kbd}B - Focus Next Bookmark/Folder whose name (or sorted property) starts with a given character or character sequence - Type the character or quickly type the character sequence - in Bookmarks Library, Bookmarks Toolbar, Bookmarks Menu, Bookmarks Sidebar
Firefox Context Menu
Single // Multiple bookmarks on selection will allow you to perform different manipulations, such as:
- Open (Open / Open in New Tab / Open in New Window / Open in New Private Window)
- Delete
- Edit (Cut / Copy / Paste)
- Add (Bookmark / Folder / Separator)
:::{figure} assets/nontechnical-overview/bookmark-folder-menu.png
:align: center
:alt: Image of the Bookmark Menu
:scale: 50%
Firefox - Bookmark Menu
:::
Undo / Redo
Undo / Redo options available In Library Window and Sidebar Panel.
You can reverse your commands (creating bookmark, deleting bookmark, copy/paste etc.) with:
Keyboard combinations:
- Undo - {kbd}
Ctrl/ {kbd}Cmd+ {kbd}Z - Redo - {kbd}
Shift+ {kbd}Ctrl/ {kbd}Cmd+ {kbd}Z
- Undo - {kbd}
Choosing option in Menu - Edit - Undo / Redo
:::{figure} assets/nontechnical-overview/bookmark-undo-redo.png
:align: center
:alt: Image of the Undo/Redo options for Bookmark
:scale: 50%
Firefox - Undo / Redo for bookmark
:::
Import Bookmarks
There are various options to import bookmarks to Firefox. Some of them are:
Restore Bookmarks
Firefox automatically creates backups of your bookmarks and saves the last 15 backups for safekeeping.
To restore your bookmarks:
Click on hamburger menu button to open the Menu panel.
Go to Bookmarks - Manage Bookmarks.
Select the backup from which you want to restore:
- The dated entries are automatic bookmark backups.
- From a manual backup ( Choose file… ).
After selecting the option and confirming your choice your bookmarks would be restored.
For manually add backup:
- Click on hamburger menu button to open the Menu panel.
- Go to Bookmarks - Manage Bookmarks.
- In the Library window, click the button and then select Backup….
- In the Bookmarks backup filename window that opens, choose a location to save the file, which is named
bookmarks-date.jsonby default. The desktop is usually a good spot, but any place that is easy to remember will work. - Save the bookmarks json file. The Bookmarks backup filename window will close and then you can close the Library window.
Browser Components Search Docs Index (`browser/components/search/docs/index.md`)
(browser-search)=
Search UI
This document describes the implementation of parts of Firefox's search interfaces.
The search area covers:
- Search bar on the toolbar
- In-content search
- One-off search buttons on both the search and address bars
Search Engine handling is taken care of with the toolkit Search Service.
Most of the search code lives in {searchfox}browser/components/search.
application-search-engines
Preferences
telemetryBrowser Components Sessionstore Docs Index (`browser/components/sessionstore/docs/index.md`)
(sessionstore)=
Session Restore
Session restore keeps track of the windows, tabs and tab groups a user has open
or recently closed, along with state information for each tab (history, scroll
position, form data, etc.). It persists that state to disk, and puts it back
when Firefox starts again or when the user reopens something they closed.
SessionStore is the component's entry point. It observes browser windows and
their tabs, holds the collected state in memory, and exposes the API that the
rest of the front-end uses to read state, to reopen closed tabs, windows and tab
groups, and to save and restore whole sessions. The remaining modules in
{searchfox}browser/components/sessionstore support it:
SessionStartup
: Reads the session file at startup and decides whether the previous session
should be restored.
SessionSaver, SessionFile and SessionWriter
: Schedule and perform the disk I/O that persists the session state.
TabState, TabStateCache and TabStateFlusher
: Collect per-tab state, cache it, and let callers wait for a tab's latest data.
RunState
: Tracks whether session restore is stopped, running or quitting.
GlobalState, SessionCookies, TabAttributes and TabGroupState
: Hold the parts of the session state that aren't per-tab.
:maxdepth: 1
events
apiBrowser Components Sidebar Docs Index (`browser/components/sidebar/docs/index.md`)
(components-sidebar)=
Sidebar
The new sidebar builds on existing legacy sidebar code treating browser-sidebar.js as a SidebarController. As part of the new sidebar and vertical tabs project, we've added new components including top-level system module SidebarManager.sys.mjs and a per window state manager, SidebarState.sys.ms. We've added new UI components that use a combination of moz components and custom lit components. The sidebar team maintains the existing synced tabs and history panels.
Introducing a new panel
Every panel that is registered and enabled in browser-sidebar.js` and the toolsNameMap map will show as an option in the Customize Sidebar menu (which is a sidebar panel that contains settings).
The launcher is a container for tools (ie, icons that when clicked open or close the associated panel). Registering a panel - which should be behind a pref until it is ready to be introduced - does not automatically add a new icon to the launcher.
A tool can be added once for all users by adding it to the designated pref branch sidebar.newTool.migration. in profile/firefox.js. So an example would be pref("sidebar.newTool.migration.bookmarks", '{}'). The pref suffix (bookmarks in this example) is the toolID that should match what you added as the value portion of the relevant entry in the toolsNameMap map in browser-sidebar.js. It's important to note that if you have a pref governing the visibility of your sidebar panel, it will need to be enabled at the same time in order to be shown in a user's launcher - either via a nimbus rollout or in-tree.
If you only want to add this item if the pref governing visibility is true, you can pass the pref you want to observe, e.g. pref("sidebar.newTool.migration.reviewchecker", '{ "visibilityPref": "browser.shopping.experience2023.integratedSidebar"}') where browser.shopping.experience2023.integratedSidebar is the pref controlling the visibility of the review checker panel.
In both cases, the tool will be introduced to the launcher one time (appended to a user's customized list of tools) and any customization after that (ie, removing it) takes precedence. If it's not removed, it will persist after that session.
If you only want to introduce a tool to new users, you can do so by adding it to the DEFAULT_LAUNCHER_TOOLS list in SidebarManager and the toolsNameMap. You can do this even if you have previously introduced a tool via a pref branch migration as there is logic that will prevent a tool from being added twice, however the expectation is that when adding it to defaultTools the pref governing panel visibility is also enabled in-tree.
State Management
The sidebar includes a variety of options that users can customize, such as:
- Sidebar visibility (e.g., expand on hover, hide tabs and sidebar)
- Sidebar position (left or right)
- Tab strip orientation (vertical or horizontal)
- Available tools (which can be enabled or disabled)
These options are stored internally as preference values, meaning they persist across
browser windows. For example, if you have two windows open and move the sidebar to the
right in one of them, the other window's sidebar will also move to the right.
In addition to these preferences, there are also state values that depend on user
interaction, such as:
- Whether the launcher is expanded, collapsed, or hidden
- Which panel is currently open
- The width of the launcher and panel
These state values are usually stored in SessionStore. However, if the user has
disabled session restore (e.g., via permanent private browsing mode), they are serialized
and stored under the sidebar.backupState preference instead.
State values are per-window and do not carry over between windows. For example, if you
load a panel in one window, other windows will not display that same panel.
SidebarState: Per-Window State
SidebarState tracks and updates sidebar-related UI state within a specific browser
window. It acts as the single source of truth for the sidebar's current state in that
window. In practice, it functions as a "reactive controller," handling user interactions,
maintaining internal state values, and determining the appropriate DOM updates.
When state values are changed, SidebarState immediately applies corresponding
adjustments to the UI. For example:
- When
launcherVisibleis set tofalse, the launcher is hidden, and the sidebar's
inline padding is adjusted accordingly. - When
launcherWidthorpanelWidthare updated, inline CSS is modified to ensure
that the sidebar does not occupy more than 75% of the browser's width.
SidebarManager: Global State
SidebarManager handles listening to preference values, global events, and loading the
"backup state" if necessary. When such handlers are triggered, SidebarManager delegates
tasks to each instance of SidebarController (a per-window module).
Use cases for SidebarManager include:
- Updating visibility preferences when the tab orientation changes.
- Managing the default set of tools for new sidebar users.
- Detecting when the sidebar button is removed from
CustomizableUI, thereby signaling
allSidebarControllerinstances to close the sidebar if it is open.
:::{note}SidebarManager should also be responsible for updating the customize panel when
preferences are changed from another source, but that is currently not the case. This
should be addressed in Bug 1945530.
:::
Example Workflows
Per-Window State Change
Suppose a user clicks the toolbar button to show the sidebar. This is how the interaction
is handled:
SidebarController.handleToolbarButtonClick()is called, which setsstate.launcherVisible.SidebarStatecalls the setter forlauncherVisible, removing thehidden
attribute from the launcher element.
Global State Change
Suppose a user removes the toolbar button. Since CustomizableUI changes are synced
across windows, this is treated as a global state change. The interaction is handled as
follows:
CustomizableUInotifies listeners (includingSidebarManager) about a widget
removal.SidebarManager.onWidgetRemoved()is called to handle the event.onWidgetRemovedcalls thehide()function on everySidebarControllerinstance.
Browser Components Tabbrowser Docs Index (`browser/components/tabbrowser/docs/index.md`)
(tabbrowser)=
Tabbed Browser
gBrowser displays and manages the contents of a window's tabs. Older code and documentation often call it <xul:tabbrowser>, after the DOM element that used to fill this role. That element no longer exists, but the name is still used synonymously with gBrowser, so you will meet it.
:maxdepth: 1
gbrowser
opening-tabs
api
tab-events
progress-listeners
async-tab-switcher
lazy-browsers
tab-unloadingBrowser Components Taskbartabs Docs Index (`browser/components/taskbartabs/docs/index.md`)
Web Apps in Firefox
Web Apps in Firefox — also referred to as Taskbar Tabs in-source — is a feature that allows pinning a simplified and site stylized browser window to the taskbar (or system equivalent). This is analagous to what is often referred to as Progressive Web Apps (PWAs).
The feature is enabled by the preference browser.taskbarTabs.enabled, which is currently enabled by default on Windows. To create a web app, click on the 'Add tab to taskbar' button on the URL bar, which will create a new window and prompt to pin it to your taskbar. Remove the web app by clicking the 'Remove tab from taskbar' button, which'll turn it back into a normal tab and (if that was the last window) unpin it from your taskbar.
:::{note}
Currently, Web Apps are available on Windows (both MSIX and non-MSIX, enabled by default) and Linux (unsandboxed and under Flatpak, disabled by default).
macOS support is not currently available. macOS assumes that two different visible applications will be in two different processes; however, web apps are in the same profile and process as the rest of the browser, so the Dock isn't able to distinguish them. There are some workarounds, like creating the window in a different process and ferrying events across, but it's a sufficient challenge that it hasn't been done yet.
:::
Internally, they're called 'taskbar tabs' after the initial design which made an analogy to pinned tabs being on your taskbar. The feature is called 'web apps' instead of PWAs (Progressive Web Apps) as implemented in Chromium for two reasons:
- 'PWA' is a vague term, referring to both APIs to support web apps (many of which Firefox supports) and the ability to install them.
- Firefox Web Apps, by design, still appear like a browser instead of appearing as a completely separate application like most PWA implementations.
Firefox Web Apps keeps information about each web app in taskbartabs/taskbartabs.json inside the user's profile. This file is intended for use internally by Firefox; if you change it, things might not work properly. It follows the JSON schema in {searchfox}TaskbarTabs.schema.1.json . Refer to {searchfox}TaskbarTabsRegistry.sys.mjs for information on what each property is used for.
:maxdepth: 1
architectureExternal Interactions
Web Apps and Profiles
Web Apps are tied to the profile they are created with, therefore web app pages have the same access, controls, and add-ons as a normal tab.
Web Apps and Containers
Web apps are tied to the container — also referred to as Contextual Identity in-source — they are created with. When launching a Web App via the taskbar it will reopen in this tied to container. This affords users the ability to isolate sites without requiring a new profile per Web App.
Web Apps and Session Restore
Web Apps are similar to Private Windows in that they are not tied to the lifetime of normal browser session restore. Web App windows are not restore for users who have enabled "Open previous windows and tabs", and will not prevent the restoration of windows restored by session restore.
Browser Components Touchbar Docs Index (`browser/components/touchbar/docs/index.md`)
Touch Bar
The Touch Bar is a hardware component on some MacBook Pros released from 2016.
It is a display above the keyboard that allows more flexible types of
input than is otherwise possible with a normal keyboard. Apple offers Touch Bar
APIs so developers can extend the Touch Bar to display inputs specific to their
application. Firefox consumes these APIs to offer a customizable row of inputs
in the Touch Bar.
In Apple's documentation, the term "the Touch Bar" refers to the hardware.
The term "a Touch Bar" refers not to the hardware but to a collection of inputs
shown on the Touch Bar. This means that there can be multiple "Touch Bars" that
switch out as the user switches contexts. The same naming convention is used in
this document.
In this document and in the code, the word "input" is used to refer to
an interactive element in the Touch Bar. It is often interchangeable with
"button", but "input" can also refer to any element displayed in the Touch Bar.
The Touch Bar should never offer functionality unavailable to Firefox users
without the Touch Bar. Most macOS Firefox users do not have the Touch Bar and
some choose to disable it. Apple's own Human Interface Guidelines (HIG)
forbids this kind of Touch Bar functionality. Please read the HIG for more
design considerations before you plan on implementing a new Touch Bar feature.
If you have questions about the Touch Bar that are not answered in this
document, feel free to reach out to Harry Twyford (:harry on Slack).
He wrote this document and Firefox's initial Touch Bar implementation.
Overview
Firefox's Touch Bar implementation is equal parts JavaScript and Cocoa
(Objective-C++). The JavaScript code lives in browser/components/touchbar
and the Cocoa code lives in widget/cocoa, mostly in nsTouchBar.mm. The
Cocoa code is a consumer of Apple's Touch Bar APIs and defines what types of
Touch Bar inputs are available to its own consumers. The JS code inbrowser/components/touchbar provides services to nsTouchBar.mm and
defines what inputs the user actually sees in the Touch Bar. There is two-way
communication between the JS and the Cocoa: the Cocoa code asks the JS what
inputs it should display, and the JS asks the Cocoa code to update those inputs
when needed.
JavaScript API
browser/components/touchbar/MacTouchBar.sys.mjs defines what specific inputs are
available to the user, what icon they will have, what action they will perform,
and so on. Inputs are defined in the gBuiltInInputs object {searchfox}in that file <mozilla-central/rev/669fac9888b173c02baa4c036e980c0c204dfe02:browser/components/touchbar/MacTouchBar.sys.mjs#76>.
When creating a new object in gBuiltInInputs, the available properties are
documented in the JSDoc for TouchBarInput:
/**
* A representation of a Touch Bar input.
* @param {string} input.title
* The lookup key for the button's localized text title.
* @param {string} input.image
* A URL pointing to an SVG internal to Firefox.
* @param {string} input.type
* The type of Touch Bar input represented by the object.
* Must be a value from kInputTypes.
* @param {Function} input.callback
* A callback invoked when a touchbar item is touched.
* @param {string} [input.color]
* A string in hex format specifying the button's background color.
* If omitted, the default background color is used.
* @param {bool} [input.disabled]
* If `true`, the Touch Bar input is greyed out and inoperable.
* @param {Array} [input.children]
* An array of input objects that will be displayed as children of
* this input. Available only for types KInputTypes.POPOVER and
* kInputTypes.SCROLLVIEW.
*/Clarification on some of these properties is warranted.
titleis the key to a Fluent translation defined inbrowser/locales/<LOCALE>/browser/touchbar/touchbar.ftl.typemust be a value from thekInputTypesenum inMacTouchBar.sys.mjs.
For example,kInputTypes.BUTTON. More information on input types follows
below.callbackpoints to a JavaScript function. Any chrome-level JavaScript can
be executed.execCommandis a convenience method inMacTouchBar.sys.mjs
that takes a XUL command as a string and executes that command. For instance,
one input setscallbacktoexecCommand("Browser:Back").childrenis an array of objects with the same properties as members ofgBuiltInInputs. When used with an input of typekInputTypes.SCROLLVIEW,childrencan only contain inputs of typekInputTypes.BUTTON. When used with an input of typekInputTypes.POPOVER, any input type except anotherkInputTypes.POPOVER
can be used.
Input types
Button
: A simple button. If image is not specified, the buttons displays the text
label from title. If both image and title are specified, only the
image is shown. The action specified in callback is executed when the
button is pressed.
:::{caution}
Even if the title will not be shown in the Touch Bar, you must still
define a title property.
:::
Main Button
: Similar to a button, but displayed at double the width. A main button
displays both the string in title and the icon in image. Only one
main button should be shown in the Touch Bar at any time, although this is
not enforced.
Label
: A non-interactive text label. This input takes only the attributes title
and type.
Popover
: Initially represented in the Touch Bar as a button, a popover will display an
entirely different set of inputs when pressed. These different inputs should
be defined in the children property of the parent. Popovers can also be
shown and hidden programmatically, by calling
gTouchBarUpdater.showPopover(
TouchBarHelper.baseWindow,
[POPOVER],
{true | false}
); where the second argument is a reference to a popover TouchBarInput and
the third argument is whether the popover should be shown or hidden.
Scroll View
: A Scroll View is a scrolling list of buttons. The buttons should be defined
in the Scroll View's children array.
:::{note}
In Firefox, a list of search shortcuts appears in the Touch Bar when the
address bar is focused. This is an example of a ScrollView contained within
a popover. The popover is opened programmatically with
gTouchBarUpdater.showPopover when the address bar is focused and it is
hidden when the address bar is blurred.
:::
Examples
Some examples of gBuiltInInputs objects follow.
A simple button
Back: {
title: "back",
image: "chrome://browser/skin/back.svg",
type: kInputTypes.BUTTON,
callback: () => execCommand("Browser:Back", "Back"),
},A button is defined with a title, icon, type, and a callback. The callback
simply calls the XUL command to go back.
The search popover
: This is the input that occupies the Touch Bar when the address bar is focused.
SearchPopover: {
title: "search-popover",
image: "chrome://global/skin/icons/search-glass.svg",
type: kInputTypes.POPOVER,
children: {
SearchScrollViewLabel: {
title: "search-search-in",
type: kInputTypes.LABEL,
},
SearchScrollView: {
key: "search-scrollview",
type: kInputTypes.SCROLLVIEW,
children: {
Bookmarks: {
title: "search-bookmarks",
type: kInputTypes.BUTTON,
callback: () =>
gTouchBarHelper.insertRestrictionInUrlbar(
UrlbarShared.RESTRICT_TOKENS.BOOKMARK
),
},
History: {
title: "search-history",
type: kInputTypes.BUTTON,
callback: () =>
gTouchBarHelper.insertRestrictionInUrlbar(
UrlbarShared.RESTRICT_TOKENS.HISTORY
),
},
OpenTabs: {
title: "search-opentabs",
type: kInputTypes.BUTTON,
callback: () =>
gTouchBarHelper.insertRestrictionInUrlbar(
UrlbarShared.RESTRICT_TOKENS.OPENPAGE
),
},
Tags: {
title: "search-tags",
type: kInputTypes.BUTTON,
callback: () =>
gTouchBarHelper.insertRestrictionInUrlbar(
UrlbarShared.RESTRICT_TOKENS.TAG
),
},
},
},
},
}, At the top level, a Popover is defined. This allows a collection of children
to be shown in a separate Touch Bar. The Popover has two children: a Label,
and a Scroll View. The Scroll View displays five similar buttons that call a
helper method to insert search shortcut symbols into the address bar.
Adding a new input
Adding a new input is easy: just add a new object to gBuiltInInputs. This
will make the input available in the Touch Bar customization window (accessible
from the Firefox menu bar item).
If you want to to add your new input to the default set, add its identifier
{searchfox}here <mozilla-central/rev/ebe492edacc75bb122a2b380e4cafcca3470864c:widget/cocoa/nsTouchBar.mm#100>, where type is a value from kAllowedInputTypes in that
file and key is the value you set for title in gBuiltInInputs.
You should request approval from UX before changing the default set of inputs.
If you are interested in adding new features to Firefox's implementation of the
Touch Bar API, read on!
Cocoa API
Firefox implements Apple's Touch Bar API in its Widget: Cocoa code with annsTouchBar class. nsTouchBar interfaces between Apple's Touch Bar API
and the TouchBarHelper JavaScript API.
The best resource to understand the Touch Bar API is Apple's
official documentation. This documentation will cover how Firefox implements
these APIs and how one might extend nsTouchBar to enable new Touch Bar
features.
Every new Firefox window initializes nsTouchBar ({searchfox}link <mozilla-central/rev/ebe492edacc75bb122a2b380e4cafcca3470864c:widget/cocoa/nsCocoaWindow.mm#2877>). The functionmakeTouchBar is looked for automatically on every new instance of anNSWindow*. If makeTouchBar is defined, that window will own a new
instance of nsTouchBar.
At the time of this writing, every window initializes nsTouchBar with a
default set of inputs. In the future, Firefox windows other than the main
browser window (such as the Library window or DevTools) may initializensTouchBar with a different set of inputs.
nsTouchBar has two different initialization methods: init andinitWithInputs. The former is a convenience method for the latter, callinginitWithInputs with a nil argument. When that happens, a Touch Bar is
created containing a default set of inputs. initWithInputs can also take anNSArray<TouchBarInput*>*. In that case, a non-customizable Touch Bar will be
initialized with only those inputs available.
NSTouchBarItemIdentifiers
The architecture of the Touch Bar is based largely around an NSString*
wrapper class called NSTouchBarItemIdentifier. Every input in the Touch Bar
has a unique NSTouchBarItemIdentifier. They are structured in reverse-URI
format like so:
com.mozilla.firefox.touchbar.[TYPE].[KEY]
[TYPE] is a string indicating the type of the input, e.g. "button". If an
input is a child of another input, the parent's type is prepended to the child's
type, e.g. "scrubber.button" indicates a button contained in a scrubber.
[KEY] is the title attribute defined for that input on the JS side.
If you need to generate an identifier, use the convenience method[TouchBarInput nativeIdentifierWithType:withKey:].
:::{caution}
Do not create a new input that would have the same identifier as any other
input. All identifiers must be unique.
:::
:::{warning}NSTouchBarItemIdentifier {searchfox}is used in one other place <mozilla-central/rev/ebe492edacc75bb122a2b380e4cafcca3470864c:widget/cocoa/nsTouchBar.mm#71>: settingcustomizationIdentifier. Do not ever change this string. If it is changed,
any customizations users have made to the layout of their Touch Bar in Firefox
will be erased.
:::
Each identifier is tied to a TouchBarInput. TouchBarInput is a class
that holds the properties specified for each input in gBuiltInInputs.nsTouchBar uses them to create instances of NSTouchBarItem
which are the actual objects used by Apple's Touch Bar API and displayed in the
Touch Bar. It is important to understand the difference betweenTouchBarInput and NSTouchBarItem!
TouchBarInput creation flow
Creating a Touch Bar and its TouchBarInputs flows as follows:
[nsTouchBar init]is called from[NSWindow makeTouchBar].initpopulates two NSArrays:customizationAllowedItemIdentifiersanddefaultItemIdentifiers. It also initializes aTouchBarInputobject
for every element in the union of the two arrays and stores them inNSMutableDictionary<NSTouchBarItemIdentifier, TouchBarInput*>* mappedLayoutItems.touchBar:makeItemForIdentifier:is called for every element in the union
of the two arrays of identifiers. This method retrieves theTouchBarInput
for the given identifier and uses it to initialize aNSTouchBarItem.touchBar:makeItemForIdentifier:reads thetypeattribute from theTouchBarInputto determine whatNSTouchBarItemsubclass should be
initialized. Our Touch Bar code currently supportsNSCustomTouchBarItem
(buttons, main buttons);NSPopoverTouchBarItem(popovers);NSTextField(labels); andNSScrollView(ScrollViews).- Once the
NSTouchBarItemis initialized, its properties are populated with
an assortment of "update" methods. These includeupdateButton,updateMainButton,updateLabel,updatePopover, andupdateScrollView. - Since the localization of
TouchBarInputtitles happens asynchronously in
JavaScript code, the l10n callback executes[nsTouchBarUpdater updateTouchBarInputs:]. This method reads the
identifier of the input(s) that need to be updated and calls their respective
"update" methods. This method is most often used to updatetitleafter
l10n is complete. It can also be used to update any property of aTouchBarInput; for instance, one might wish to changecolor
when a specific event occurs in the browser.
Browser Components Uitour Docs Index (`browser/components/uitour/docs/index.md`)
UITour
UITour-lib:members: noneBrowser Components Urlbar Docs Index (`browser/components/urlbar/docs/index.md`)
Address Bar and Search Bars
This document describes the implementation of Firefox's address bar, also known
as the quantumbar or urlbar. The address bar was also called the awesomebar
until Firefox 68, when it was substantially rewritten.
The same code also runs the search bar in the toolbar and the search bar on the
New Tab page, so most of these pages apply to all three.
The address bar is a specialized search access point that aggregates data from
several different sources, including:
- Places (Firefox's history and bookmarks system)
- Search engines (including search suggestions)
- WebExtensions
- Open tabs
Where to Start
If you want a high level, nontechnical summary of how the address bar works,
read {doc}nontechnical-overview.
If you are interested in the technical details, you might want to skip ahead to
{doc}overview.
Codebase
The code lives in {searchfox}browser/components/urlbar ,
which is where the often-used urlbar shorthand comes from.
Table of Contents
nontechnical-overview
overview
lifetime
process-boundary
message-path
utilities
telemetry
firefox-suggest-telemetry
debugging
ranking
dynamic-result-types
adding-a-search-bar
preferences
testing
contactAPI Reference
ProvidersManager
UrlbarChildController
UrlbarInputBase
UrlbarMuxer
UrlbarParentController
UrlbarProvider
UrlbarQueryContext
UrlbarResult
UrlbarViewBrowser Components Urlbar Docs Nontechnical Overview (`browser/components/urlbar/docs/nontechnical-overview.md`)
(urlbar-nontechnical-overview)=
Nontechnical Overview
This document provides a high level, nontechnical overview of Firefox's address
bar, with a focus on the different types of results it shows and how it chooses
them.
:depth: 2Terminology
This document uses a small number of terms of art that would be helpful to
understand up front.
Input
: The text box component of the address bar. In contrast, we use "address bar"
to refer to the whole system comprising the input, the view, and the logic
that determines the results that are shown in the view based on the text in
the input.
Result
: An individual item that is shown in the view. There are many different types
of results, including bookmarks, history, open tabs, and search suggestions.
View
: The panel that opens below the input when the input is focused. It contains
the results.
Maximum Result Count
The view shows a maximum of 10 results by default. This number is controlled by
a hidden preference, browser.urlbar.maxRichResults.
Search Strings
If the user has not modified the text in the input or the text in the input is
empty, we say that the user's search string is empty, or in other words,
there is no search string. In contrast, when the user has modified the text in
the input and the text is non-empty, then the search string is that non-empty
text.
:::{figure} assets/nontechnical-overview/empty-url.png
:align: center
:alt: Image of the address bar input showing a URL
:scale: 50%
Empty search string: The input text has not been modified
:::
:::{figure} assets/nontechnical-overview/empty-placeholder.png
:align: center
:alt: Image of the address bar input showing its placeholder text
:scale: 50%
Empty search string: The input text is empty (and the input is showing its
placeholder text)
:::
:::{figure} assets/nontechnical-overview/non-empty.png
:align: center
:alt: Image of the address bar input showing "porcupines" text
:scale: 50%
Non-empty search string: The input text has been modified and is non-empty
:::
The distinction between empty and non-empty search strings is helpful to
understand for the following sections.
Top Sites
When the search string is empty and the user focuses the input, the view opens
and shows the user's top sites. They are the same top sites that appear on the
new-tab page except their number is capped to the maximum number of address bar
results (10). If the user has fewer top sites than the maximum number of results
(as is the case in a new profile), then only that number of results is shown.
:::{figure} assets/nontechnical-overview/top-sites.png
:align: center
:alt: Image of the address bar view showing top sites
:scale: 50%
Top sites on a new en-US profile
:::
This behavior can be turned off by going to about:preferences#privacy and
unchecking “Shortcuts” in the “Address Bar” section. In that case, the view
closes when the search string is empty.
Searches
When the search string is non-empty, the address bar performs a search and
displays the matching results in the view. Multiple separate searches of
different sources are actually performed, and the results from each source are
combined, sorted, and capped to the maximum result count to display the final
list of results. In address bar terminology, each source is called a
provider.
Each provider produces one or more types of results based on the search
string. The most common result types include the following (not exhaustive):
:::{figure} assets/nontechnical-overview/search-suggestion.png
:align: center
:alt: Image of a search suggestion result with text "porcupine meatballs"
:scale: 50%
Search suggestions from the user's default engine (magnifying glass icon)
:::
:::{figure} assets/nontechnical-overview/form-history.png
:align: center
:alt: Image of a previous search result with text "porcupines"
:scale: 50%
Previous searches the user has performed from the address bar and search bar
(clock icon)
:::
:::{figure} assets/nontechnical-overview/bookmark.png
:align: center
:alt: Image of a bookmark result with text "Porcupine - Wikipedia"
:scale: 50%
Bookmarks
:::
:::{figure} assets/nontechnical-overview/history.png
:align: center
:alt: Image of a history result with text "Porcupines | National Geographic"
:scale: 50%
History
:::
:::{figure} assets/nontechnical-overview/open-tab.png
:align: center
:alt: |-
: Image of an open tab result with text "Porcupines | San Diego Zoo
: Animals & Plants"
:scale: 50%
Open tabs (switch to tab)
:::
:::{figure} assets/nontechnical-overview/remote-tab.png
:align: center
:alt: |-
: Image of a remote tab result with text "Porcupine | rodent |
: Britannica"
:scale: 50%
Remote tabs (via Sync)
:::
How the address bar combines and sorts results from different providers is
discussed below in [Result Composition].
The Heuristic Result
The first result in the view is special and is called the heuristic
result. As the user types each character in their search string, the heuristic
result is updated and automatically selected, and its purpose is to show the
user what will happen when they press the enter key without first selecting a
(non-heuristic) result. The heuristic result is so called because it shows
Firefox's best guess for what the user is trying to do based on their search
string.
The heuristic result is determined by running through a number of different
heuristics and picking the one that first matches the search string. The most
important heuristics in the order that Firefox runs through them are:
Is the search string...
An omnibox extension keyword? Extensions using the omnibox API can register
keywords by which they become activated.A bookmark keyword? The user can associate a keyword with each bookmark.
Typing a bookmark keyword plus an optional search string and pressing enter
will visit the bookmark.:::{figure} assets/nontechnical-overview/bookmark-keyword.png
:align: center
:alt: |-
: Image of the address bar input with text "bug 1677126" and a
: bookmark keyword heuristic result
:scale: 50%Typing "bug" triggers a Bugzilla bookmark with the keyword "bug"
:::A domain name or URL that should be autofilled? Autofill is the name of
the feature where the input completes the domain names and URLs of bookmarks
and frequently visited sites as the user is typing them. (Firefox autofills
“to the next slash”, meaning it first autofills domain names and then partial
paths.):::{figure} assets/nontechnical-overview/autofill.png
:align: center
:alt: |-
: Image of the address bar input with text "mozilla.org/" with
: "illa.org/" selected and an autofill heuristic result
:scale: 50%After typing "moz", the rest of mozilla.org is automatically completed
:::A valid URL? If so, visit the URL. (This includes fixing common typos like
“mozilla..org” and “mozilla.ogr”. Valid URLs are based on the Public Suffix
List. The user can also specify an allow-list using hidden preferences to
support domains like localhost.):::{figure} assets/nontechnical-overview/visit.png
:align: center
:alt: |-
: Image of the address bar input with text "porcupine-fancy.org" and a
: visit heuristic result
:scale: 50%Typing a URL that isn't bookmarked or in history
:::Ultimately fall back to performing a search using the default engine. (The
user can opt out of this fallback by setting the hidden preferencekeyword.enabledto false. In that case, Firefox stops at the previous
step and attempts to visit the user's search string as if it were a URL.):::{figure} assets/nontechnical-overview/search-heuristic.png
:align: center
:alt: |-
: Image of the address bar input with text "porcupines" and a search
: heuristic result
:scale: 50%Typing a string that will perform a search using the default engine
:::
Result Composition
For a given search string, the address bar performs multiple separate searches
of different providers and then combines their results to display the final
list. The way in which results are combined and sorted is called result
composition. Result composition is based on the concept of result groups, one
group after another, with different types of results in each group.
The default result composition is described next, starting with the first
result.
1. Heuristic Result
The first result is always the heuristic result.
2. Extension Omnibox Results
The next group of results is those provided by extensions using the omnibox
API. Most users never encounter these results because they are provided only by
extensions that use this feature, and even then the user must type certain
extension-defined keywords to trigger them. There are at most 6 results in this
group.
3. Search Suggestions
The next group is search suggestions. Typically this group contains 6 results,
but the exact number depends on certain factors described later in Result
Composition Nuances. There are actually three types of search suggestions:
Previous searches the user has performed from the address bar and search bar
(denoted with a clock icon):{image} assets/nontechnical-overview/form-history.png:align: center :alt: Image of a previous search result with text "porcupines" :scale: 50%This is the only type of search suggestion that is generated by Firefox alone,
without the help of a search engine. When the user performs a search using an
engine from the address bar or search bar (and only the address bar and search
bar), Firefox stores the search string, and then when the user starts to type
it again, Firefox includes it as a result to make it easy to perform past
searches. (Firefox does not store search strings used within web pages like
google.com.)Suggestions from the user's default engine (denoted with a magnifying glass
icon):{image} assets/nontechnical-overview/search-suggestion.png:align: center :alt: Image of a search suggestion result with text "porcupine meatballs" :scale: 50%These are fetched from the engine if the engine provides the necessary access
point. The ordering and total number of these suggestions is determined by the
engine.Google-specific "tail" suggestions, which look like "... foo" and are provided
for long and/or specific queries to help the user narrow their search:{image} assets/nontechnical-overview/tail-suggestions.png:align: center :alt: |- : Image of a tail suggestion results with text "porcupine abc def" in : the input and two suggestions with text "... definition " and : "... defense" :scale: 50%These are fetched from Google when Google is the user's default engine. The
ordering and total number of these suggestions is determined by Google.
The search suggestions group typically contains two previous searches followed
by four engine suggestions, but the exact numbers depend on the number of
matching previous searches and engine suggestions. Previous searches are limited
in number so that they don’t dominate this group, allowing remote suggestions to
provide content discovery benefits. Tail suggestions are shown only when there
are no other suggestions.
The user can opt out of showing search suggestions in the address bar by
visiting about:preferences#search and unchecking "Provide search suggestions" or
"Show search suggestions in address bar results".
4. General Results
The final group of results is a general group that includes the following types:
- Bookmarks
- History
- Open tabs (switch to tab)
- Remote tabs (via Sync)
- Sponsored and Firefox Suggest results (part of the Firefox Suggest feature)
This general group is labeled "Firefox Suggest" in the Firefox Suggest feature.
Typically this group contains 3 results, but as with search suggestions, the
exact number depends on certain factors (see [Result Composition Nuances]).
Most results within this group are first matched against the search string on
their titles and URLs and then sorted by a metric called frecency, a
combination of how frequently and how recently a page is visited. The top three
results are shown regardless of their specific types.
This is the only group that is sorted by frecency.
A few important complexities of this group are discussed in the next
subsections. The final subsection describes frecency in more detail.
Adaptive History
The first few bookmark and history results in the general group may come from
adaptive history, a system that associates specific user search strings with
URLs. (It's also known as input history.) When the user types a search
string and picks a result, Firefox stores a database record that associates the
string with the result's URL. When the user types the string or a part of it
again, Firefox will try to show the URL they picked last time. This allows
Firefox to adapt to a user's habit of visiting certain pages via specific search
strings.
This mechanism is mostly independent of frecency. URLs in the adaptive history
database have their own sorting score based on how many times they have been
used in the past. The score decays daily so that infrequently used search
strings and URLs aren't retained forever. (If two adaptive history results have
the same score, they are secondarily sorted by frecency.)
Within the general group, the number of adaptive history results is not limited,
but typically there aren't many of them for a given search string.
Open and Remote Tabs
Unlike bookmarks and history, open and remote tabs don't have a "natural"
frecency, meaning a frecency that's updated in response to user actions as
described below in [Frecency]. Tabs that match the search string are assigned
constant frecencies so they can participate in the sorting within the general
group. Open tabs are assigned a frecency of 1000, and remote tabs are assigned a
frecency of 1001. Picking appropriate frecencies is a bit of an art, but Firefox
has used these values for some time.
Sponsored and Firefox Suggest Results
Sponsored and Firefox Suggest results are an exception within this group. They
are matched on predetermined keywords, and when present, they always appear last
in the general group. Frecency isn't involved at all.
Frecency
Frecency is a complex topic on its own, but in summary, each URL stored in
Firefox's internal history database has a numeric score, the frecency,
associated with it. Larger numbers mean higher frecencies, and URLs with higher
frecencies are more likely to be surfaced to the user via the address bar. Each
time the user visits a URL, Firefox increases its frecency by a certain "boost"
amount that depends on how the visit is performed -- whether the user picked it
in the address bar, clicked its link on a page, clicked it in the history
sidebar, etc. In order to prevent frecencies from growing unbounded and to
penalize URLs that haven't been visited in a while, Firefox decays the
frecencies of all URLs over time.
For details on frecency, see The Frecency Algorithm.
Preferences that Affect Result Composition
There are a number of options in about:preferences that affect result
composition.
The user can opt out of showing search suggestions in the address bar by
unchecking "Provide search suggestions" or "Show search suggestions in address
bar results" in about:preferences#search. (The first checkbox applies to both
the address bar and search bar, so it acts as a global toggle.)
:::{figure} assets/nontechnical-overview/prefs-show-suggestions.png
:align: center
:alt: |-
: Image of the preferences UI that allows the user to opt out of search
: suggestions
:scale: 50%
Preferences allowing the user to opt out of search suggestions
:::
By default, the search suggestions group is shown before the general results
group, but unchecking "Show search suggestions ahead of browsing history in
address bar results" in about:preferences#search does the opposite. In that
case, typically the general results group will contain at most 6 results and the
search suggestions group will contain at most 3. In other words, regardless of
which group comes first, typically the first will contain 6 results and the
second will contain 3.
:::{figure} assets/nontechnical-overview/prefs-suggestions-first.png
:align: center
:alt: |-
: Image of the preferences UI that allows the user to choose whether
: search suggestions are shown before general results
:scale: 50%
Preference allowing the user to choose which group is shown first
:::
The “Address Bar” section in about:preferences#privacy has several checkboxes
that allow for finer control over the types of results that appear in the view.
The top sites feature can be turned off by unchecking “Shortcuts” in this
section.
:::{figure} assets/nontechnical-overview/prefs-privacy.png
:align: center
:alt: |-
: Image of the preferences UI that allows the user to choose which
: results are shown
:scale: 50%
Preferences allowing the user to choose which results are shown
:::
Result Composition Nuances
Among the search suggestions and general results groups, the group that's shown
first typically contains 6 results and the other group contains 3 results. The
exact number in each group depends on several factors:
The total maximum result count (controlled by the
browser.urlbar.maxRichResultshidden preference).The total number of results in the two groups scales up and down to
accommodate this number so that the view is always full of results.The number of extension results.
The extension results group comes before both groups, so if there are any
extension results, there are fewer available slots for search suggestions and
general results.The number of matching results.
The search string may match only one or two search suggestions or general
results, for example.The number of results in the other group.
The first group will try to contain 6 results and the second will try to
contain 3, but if either one is unable to fill up, then the other group will
be allowed to grow to make up the difference.
Other Result Types
The most common result types are discussed above. This section walks through the
other types.
An important trait these types have in common is that they do not belong to any
group. Most of them appear at specific positions within the view.
Search Interventions
Search interventions help the user perform a task based on their search string.
There are three kinds of interventions, and each is triggered by typing a
certain set of {searchfox}phrases <firefox-main/rev/88b0f8e6a5925058755d2671bdac5a76d84bd224:browser/components/urlbar/UrlbarProviderInterventions.sys.mjs#171> in the input. They always appear as the second result,
after the heuristic result.
The three kinds of interventions are:
:::{figure} assets/nontechnical-overview/intervention-clear.png
:align: center
:alt: |-
: Image of the clear intervention result with text "Clear your cache,
: cookies, history and more"
:scale: 50%
Clear history, cache, and other data search intervention
:::
:::{figure} assets/nontechnical-overview/intervention-refresh.png
:align: center
:alt: |-
: Image of the refresh intervention result with text "Restore default
: settings and remove old add-ons for optimal performance"
:scale: 50%
Refresh Firefox search intervention
:::
:::{figure} assets/nontechnical-overview/intervention-update.png
:align: center
:alt: |-
: Image of the update intervention result with text "The latest Firefox
: is downloaded and ready to install"
:scale: 50%
Update Firefox search intervention
:::
Currently this feature is limited to English-speaking locales, but work is
ongoing to build a more sophisticated intent-matching platform to support other
locales, more complex search strings, and more kinds of interventions.
Search Tips
Search tips inform the user they can perform searches directly from the
address bar. There are two kinds of search tips:
:::{figure} assets/nontechnical-overview/search-tip-onboard.png
:align: center
:alt: |-
: Image of the onboarding search tip with text "Type less, find more:
: Search Google right from your address bar"
:scale: 50%
Onboarding search tip: Appears on the new-tab page
:::
:::{figure} assets/nontechnical-overview/search-tip-redirect.png
:align: center
:alt: |-
: Image of the redirect search tip with text "Start your search in the
: address bar to see suggestions from Google and your browsing history"
:scale: 50%
Redirect search tip: Appears on the home page of the user's default engine
(only for Google, Bing, and DuckDuckGo)
:::
In each case, the view automatically opens and shows the tip even if the user is
not interacting with the address bar. Each tip is shown at most four times, and
the user can stop them from appearing altogether by interacting with the address
bar or clicking the "Okay, Got It" button.
Tab to Search
Tab to search allows the user to press the tab key to enter [search mode] while
typing the domain name of a search engine. There are two kinds of tab-to-search
results, and they always appear as the second result:
:::{figure} assets/nontechnical-overview/tab-to-search-onboard.png
:align: center
:alt: Image of the tab-to-search result with text "Search with Google"
:scale: 50%
Onboarding tab to search
:::
:::{figure} assets/nontechnical-overview/tab-to-search-regular.png
:align: center
:alt: Image of the tab-to-search result with text "Search with Google"
:scale: 50%
Regular tab to search
:::
The onboarding type is shown until the user has interacted with it three times
over a period of at least 15 minutes, and after that the regular type is shown.
Search Engine Offers
Typing a single “@” shows a list of search engines. Selecting an engine enters
[search mode].
:::{figure} assets/nontechnical-overview/search-offers.png
:align: center
:alt: Image of the view showing search offer results
:scale: 50%
Search engine offers after typing “@”
:::
:::{figure} assets/nontechnical-overview/search-offers-selected.png
:align: center
:alt: Image of the view showing search offer results with one selected
:scale: 50%
After pressing the down arrow key to select Google
:::
Search Mode
Search mode is a feature that transforms the address bar into a search-only
access point for a particular engine. During search mode, search suggestions are
the only results shown in the view, and for that reason its result composition
differs from the usual composition.
:::{figure} assets/nontechnical-overview/search-mode.png
:align: center
:alt: Image of the view showing search mode
:scale: 50%
Search mode with Google as the selected engine
:::
Firefox shows suggestions in search mode even when the user has otherwise opted
out of them. Our rationale is that by entering search mode, the user has taken
an action that overrides their usual opt out. This allows the user to opt out
generally but opt back in at specific times.
Search mode is an effective replacement for the legacy search bar and may
provide a good path forward for deprecating it.
The user can enter search mode in many ways:
- Picking a search shortcut button at the bottom of the view
- Typing an engine's keyword (which can be set in about:preferences#search, and
built-in engines have default keywords) - Typing a single "?" followed by a space (to enter search mode with the default
engine) - Typing a single "@" to list all engines and then picking one
- If the search bar is not also shown, pressing Ctrl+K (to enter search mode
with the default engine)
To exit search mode, the user can backspace over the engine chiclet or click its
close button.
Browser Components Urlbar Docs Overview (`browser/components/urlbar/docs/overview.md`)
(urlbar-architecture-overview)=
Architecture
The address bar and the search bars are implemented as a
model-view-controller (MVC) system. One of the scopes of this architecture is
to allow easy replacement of its components, for easier experimentation.
Each search is represented by a unique object, the UrlbarQueryContext. This
object, created by the View, describes the search and is passed through all of
the components, along the way it gets augmented with additional information.
The UrlbarQueryContext is passed to the Controller, and finally to the
Model. The model appends results to a property of UrlbarQueryContext in
chunks, it sorts them through a Muxer and then notifies the Controller.
See the specific components below, for additional details about each one's tasks
and responsibilities.
The UrlbarQueryContext
The UrlbarQueryContext object describes a single instance of a search.
It is augmented as it progresses through the system, with various information.
{doc}UrlbarQueryContext lists its properties.
The Model
The Model is the component responsible for retrieving search results based on
the user's input, and sorting them accordingly to their importance.
At the core is the {searchfox}ProvidersManager ,
a component tracking all the available search providers, and managing searches
across them.
The ProvidersManager is a singleton, it registers internal providers on
startup and can register/unregister providers on the fly.
It can manage multiple concurrent queries, and tracks them internally as
separate Query objects.
The Controller starts and stops queries through the ProvidersManager.
It's possible to wait for the promise returned by startQuery to know when no
more results will be returned, it is not mandatory though.
Queries can be canceled.
:::{note}
Canceling a query will issue an interrupt() on the database connection,
terminating any running and future SQL query, unless a query is running inside
a runInCriticalSection task.
:::
The searchString gets tokenized by the {searchfox}UrlbarTokenizer
component into tokens, some of these tokens have a special meaning and can be
used by the user to restrict the search to specific result type (See the
UrlbarTokenizer::TYPE enum).
:::{caution}
The tokenizer uses heuristics to determine each token's type, as such the
consumer may want to check the value before applying filters.
:::
{doc}ProvidersManager documents the ProvidersManager API.
UrlbarProvider
A provider is specialized into searching and returning results from different
information sources. Internal providers are usually implemented in separate
sys.mjs modules with a UrlbarProvider name prefix. External providers can be
registered as Objects through the ProvidersManager.
Each provider is independent and must satisfy a base API, while internal
implementation details may vary deeply among different providers.
:::{important}
Providers are singleton, and must track concurrent searches internally, for
example mapping them by UrlbarQueryContext.
:::
:::{note}
Internal providers can access the Places database through the
PlacesUtils.promiseLargeCacheDBConnection utility.
:::
{doc}UrlbarProvider documents the API a provider implements.
UrlbarMuxer
The Muxer is responsible for sorting results based on their importance and
additional rules that depend on the UrlbarQueryContext. The muxer to use is
indicated by the UrlbarQueryContext.muxer property.
:::{caution}
The Muxer is a replaceable component, as such what is described here is a
reference for the default View, but may not be valid for other implementations.
:::
{doc}UrlbarMuxer documents the API a muxer implements.
The Controller
The controller is responsible for reacting to the user's input, by communicating
the proper course of action to the Model (e.g. starting/stopping a query) and the
View (e.g. showing/hiding a panel). It is also responsible for reporting Telemetry.
It is split into two classes:
- {searchfox}
UrlbarParentController
runs in the parent process. It owns the ProvidersManager, drives the query
lifecycle, and reports Telemetry. - {searchfox}
UrlbarChildController
lives alongside the View (in a content process for about:newtab, or in the
parent process for the toolbar). The Input and View talk to it; it forwards
query work to the UrlbarParentController and dispatches result notifications
to listeners.
:::{note}
Each View has a different controller instance.
:::
{doc}UrlbarParentController and {doc}UrlbarChildController document the
two classes.
Direct path and message path
The UrlbarChildController reaches its UrlbarParentController in one of two
ways, chosen when the controller is created:
- Direct path. Both controllers live in the parent process, so the child
controller creates the parent controller itself and calls it directly. The
address bar and the search bar in the toolbar use this path. - Message path. The child controller holds a
{searchfox}UrlbarParentControllerProxy
instead, which sends each call to the parent process as a message over the
Urlbar JSWindowActor pair.
{searchfox}UrlbarParent
creates the real controller on the other side and sends its notifications
back. A search bar in a content process, such as the one on about:newtab, uses
this path.
Both paths give the child controller the same interface, but on the message path
every call and notification is asynchronous. Settingbrowser.urlbar.ipc.chromeMessagePassing to true puts the toolbar's inputs on
the message path too, which lets tests exercise it in the parent process.
On the message path the parent keeps one controller per input. It drops the
controller when the input is garbage collected, or when the input's window
global goes away.
The View
The View is the component responsible for presenting search results to the
user and handling their input.
% caution
%
% The View is a replaceable component, as such what is described here is a
% reference for the default View, but may not be valid for other implementations.
{searchfox}`UrlbarInputBase.mjs `
Implements an input box View, owns an UrlbarView. Each input is a custom
element extending UrlbarInputBase: UrlbarInput (<moz-urlbar>) and
SearchbarInput (<moz-searchbar>). {doc}UrlbarInputBase documents its API.
{searchfox}`UrlbarView.mjs `
Represents the base View implementation, communicates with the Controller.
{doc}UrlbarView documents its API.
UrlbarResult
An {searchfox}UrlbarResult
instance represents a single search result with a result type, that
identifies specific kind of results.
Each kind has its own properties, that the View may support, and a few common
properties, supported by all of the results.
:::{note}
Result types are also enumerated by UrlbarShared.RESULT_TYPE.
:::
{doc}UrlbarResult documents its properties.
The following RESULT_TYPEs are supported:
// An open tab.
// Payload: { icon, url, userContextId }
TAB_SWITCH: 1,
// A search suggestion or engine.
// Payload: { icon, suggestion, keyword, query, providesSearchMode, inPrivateWindow, isPrivateEngine }
SEARCH: 2,
// A common url/title tuple, may be a bookmark with tags.
// Payload: { icon, url, title, tags }
URL: 3,
// A bookmark keyword.
// Payload: { icon, url, keyword, postData }
KEYWORD: 4,
// A WebExtension Omnibox result.
// Payload: { icon, keyword, title, content }
OMNIBOX: 5,
// A tab from another synced device.
// Payload: { icon, url, device, title }
REMOTE_TAB: 6,
// An actionable message to help the user with their query.
// Payload: { buttons, helpL10n, helpUrl, icon, titleL10n, type }
TIP: 7,
// A type of result which layout is defined at runtime.
// Payload: { dynamicType }
DYNAMIC: 8,Browser Extensions Formautofill Docs Index (`browser/extensions/formautofill/docs/index.md`)
Form Autofill
Introduction
Form Autofill saves users time and effort when making online purchases by storing their personal information in a profile and automatically populating form fields when the user requires it.
Our objective is to increase user engagement, satisfaction and retention for frequent online shoppers (those who make an online purchase at least once per month). We believe this can be achieved by enabling users to complete forms and “check out” in e-commerce flows as quickly and securely as possible.
Form Autofill handles filling in addresses and credit cards into forms. While the filling aspect of this is straightforward and uses the same mechanism as other autocomplete types, much of the additional work involves analyzing and classifying the form to determine which form field corresponds to which type of data. For instance, text boxes are classified into different types of address data.
For historical reasons, part of the form autofill is implemented using an extension, located in {searchfox}browser/extensions/formautofill. It is this extension which adds the form autofill actors used to handle the search for possible results. However, most of the work is done via code in {searchfox}toolkit/components/formautofill.
Form Autofill uses the autocomplete popup mechanism to show a list of suggestions to the user based on what they have typed so far. The user can also press the cursor key or tab key to open the autocomplete popup while the focus is within a field.
For more information about autocomplete, see {doc}Autocomplete </toolkit/components/autocomplete/docs/index>.
How Form Autofill Works
The form fill actor FormAutofillChild waits for form fields to be focused. When a field is focused, it starts the process of analyzing the form and picking out which fields might be address or credit card related. This process is primarily done by the getFormInfo function within {searchfox}FormAutofillHeuristics.sys.mjs <toolkit/components/formautofill/shared/FormAutofillHeuristics.sys.mjs>. This process is separate from the mechanism used to trigger an autocomplete popup.
Form Autofill can handle filling in , <textarea> and <select> elements.
There are three mechanisms that can be used to identify a field:
- autocomplete attributes: authors may place an autocomplete attribute on a form field to identify its purpose. This is most likely to be correct although sometimes authoring errors will occur and we attempt to fix some common cases.
- fathom: Fathom is a simple learning system that uses a selection of rules to identify credit card related fields. It currently is used to detect the credit card name and number fields (
cc-nameandcc-number) but does not detect other credit card fields or operate on address fields. - regular expressions: a large list of regular expressions located in {searchfox}
HeuristicsRegExp.sys.mjs <toolkit/components/formautofill/shared/HeuristicsRegExp.sys.mjs>that is used to match the ids, names, placeholders and labels associated with form elements. This is where most of the analysis of form fields is done for addresses.
The element.getAutocompleteInfo() function provides the parsed result of autocomplete attribute which includes the field name and section information defined in autofill spec
Each field in a form is classified into a number of different field types, for example: email, address-line1, country and so on. Many fields will not be able to be placed into a definite type, and many forms will have multiple fields classified with the same type. Work is ongoing to reduce the number of errors made in classifying fields.
After fields are classified, some additional heuristics are run (within the parseAndUpdateFieldNamesParent function in {searchfox}FormAutofillHeuristics.sys.mjs <toolkit/components/formautofill/shared/FormAutofillHeuristics.sys.mjs>). These are responsible for further checking for common field classification issues. For example, when multiple address line fields appear in a row, it is likely that they represent a separate line of the address (street, apartment number, building, etc) and appear in order. Another example is that it is common on Japanese web sites to have a separate set of name fields to indicate the pronounciation of one's name; heuristics are included to recognize this situation.
Note that the heuristics within parseAndUpdateFieldNamesParent are done within the parent browser process so no longer have access to the form fields directly, so any information needed will need to be stored in the field data (usually called fieldDetails within the code).
However, there are a few heuristics in parseAndUpdateFieldNamesContent that are done in the web page process beforehand. Most processing happens in the parent process afterwards because all of the form fields across different subframes (iframes) can be searched and collected together as a single form. There are a number of web sites that break up each field into separate child iframes.
Once fields have been identified, they are split into sections. Some sites will have multiple sections for addresses, one for a billing address and one for a shipping address. This handling is done by groupFields within {searchfox}FormAutofillSection.sys.mjs <toolkit/components/formautofill/shared/FormAutofillSection.sys.mjs>. The autocomplete attribute may be used on a field in a web page to be explicit about which section to use for that field, but otherwise the heuristics try to determine this automatically.
Once the fields are identified, a message is sent back to the child process so that markAsAutoCompletableField() may be called on each detected field, allowing the autocomplete actor to recognize that the form fill actor is able to provide results for that form field. In addition, the section and form field details are saved in the field sectionsByRootId within FormAutofillParent to that they may be retreived when the autocomplete is performed.
Once markAsAutoCompletableField() is called for a field, form autofill is available for that field and the user's saved address and credit card information will be examined to see if they apply as possible suggestions in the autocomplete dropdown popup when the user enters or types into that field.
Additional Cases
- Some fields do not exist in <form> elements. In this case, the entire document is used as if it was a form.
- Sometimes a set of fields will be split across multiple child iframes. These forms are processed together and explains why some heuristics are performed in the browser process after all of the frames have been analyzed, instead of in the web page child process.
- Often a web site will change the form in response to a user change. For example, changing the country in a form will change other fields to correspond to fields specific to that country. This is referred to as a dynamic form and is handled by rescanning the form and picking out any differences.
Country Meta Data
The specifics for each region is defined in the file {searchfox}AddressMetaData.sys.mjs <toolkit/components/formautofill/shared/AddressMetaData.sys.mjs>. This file contains information about the regions in each country, postal code formats, languages used in each region and so forth. This file contains links to documentation about the format of this data and is a good place to look for information that might be country specific. For example, when we look at data for Brazil, we can see a list of states (federative units), and also see that Brazil has defined a "sublocality_name_type" field which indicates a third level of region besides state and city, used for the neighborhood. The neighborhood appears in the address preference dialog when adding Brazilian addresses and can be autofilled as needed. Most other regions do not include a neighborhood field.
Form Submission
When a form is submitted, a prompt may be show asking the user if they wish to save the address or credit card information. This helps the user realize that the autofill capability is available. The filled in data on the form can optionally be automatically saved as a new address or credit card. This is done within the onFormSubmit function of {searchfox}FormAutofillParent <toolkit/components/formautofill/FormAutofillParent.sys.mjs>.
In general, however, we do not show the prompt to save a new address or credit card if the user has not filled in enough fields, fillin is disabled in the user's region, or the form does not contain the right fields. Which fields are necessary is dependent on the region. For example, typically, a street, city and postal code is required. The specific data needed to save the form data is determined from the {searchfox}AddressMetaData.sys.mjs <toolkit/components/formautofill/shared/AddressMetaData.sys.mjs> as described above.
If an address is determined to be the same as an existing saved address, the prompt does not appear. Some heuristics within
{searchfox}AddressParser.sys.mjs <toolkit/components/formautofill/shared/AddressParser.sys.mjs> are used to determine if the address is the same as an existing saved address, because this can be inexact matching, for example, 'Floor 2' and '2nd floor' are different strings but refer to the same thing. This ensures that the amount of times the user is prompted is reduced when the address is similar.
Report Issues
If you find any issues about filling a form with incorrect values, please file a new bug to Toolkit::Form Autofill component.
Browser Extensions Newtab Docs Index (`browser/extensions/newtab/docs/index.md`)
Firefox Home (New Tab)
All files related to Firefox Home, which includes content that appears on about:home andabout:newtab, can be found in the browser/extensions/newtab directory.
Some of these source files (such as .js, .jsx, and .scss) require an additional build step.
We are working on migrating this to work with mach, but in the meantime, please
follow the following steps if you need to make changes in this directory:
For `.sys.mjs` files (system modules)
No build step is necessary. Use mach and run mochitests according to your regular Firefox workflow.
For `.js`, `.jsx`, `.scss`, or `.css` files
Prerequisites
You will need the following:
- Node.js 10+ (On Mac, the best way to install Node.js is to use the install link on the Node.js homepage)
- npm (packaged with Node.js)
To install node dependencies, run the following from the root of the mozilla-central repository.
(This command uses mach to call npm and node commands to ensure the correct versions of Node and npm are being referenced.)
./mach newtab installIMPORTANT NOTE: If you're using Windows, you may need to run the install command differently:
(cd browser/extensions/newtab && ../../../mach npm install)Which files should you edit?
You should not make changes to .js or .css files in browser/extensions/newtab/css orbrowser/extensions/newtab/data directory. Instead, you should edit the .jsx, .js, and .scss source files
in browser/extensions/newtab/content-src directory. These files will be compiled into the .js and .css files.
Building assets and running Firefox
To build assets and run Firefox, run the following from the root of the mozilla-central repository:
./mach newtab bundle && ./mach build && ./mach runContinuous development / debugging
For near real-time reloading, run the following commands in two separate terminals to automatically rebuild bundled files whenever JSX or SCSS files change. After making a change, restart your local instance to apply the updates. Run the following terminal commands:
./mach newtab watch./mach runIMPORTANT NOTE: This task will add inline source maps to help with debugging, which changes the memory footprint. Do not use the watch task for profiling or performance testing! After finishing your work, be sure to stop the watch process. When stopped, it will automatically run a final bundle step to remove the temporary inline source maps.
Pre-commit git hook
A pre-commit hook is available in tools/lint/hooks_newtab.py. When installed,
it runs the following checks in order, stopping at the first failure:
- Bundle — if newtab source or bundle output files are staged, runs
./mach newtab bundleand blocks the commit if the output files differ
from what is staged. - Lint — runs mozlint
on staged files and blocks the commit if there are errors. - Tests — optionally runs unit tests (configurable, disabled by default).
To install the hook, run the following from the root of the mozilla-central repository:
ln -sf "$(git rev-parse --show-toplevel)/tools/lint/hooks_newtab.py" \
"$(git rev-parse --show-toplevel)/.git/hooks/pre-commit"By default, no tests are run on commit. To configure which tests run, usegit config newtab.pre-commit.tests with one of the following values:
git config newtab.pre-commit.tests jest # Jest only (~30 seconds)
git config newtab.pre-commit.tests all # all tests including xpcshell and browser (10+ minutes)
git config newtab.pre-commit.tests none # skip tests (default)To commit despite failing tests, use git commit --no-verify to bypass the hook entirely.
Running tests
New Tab unit tests are written using Jest and
React Testing Library,
and other errors that may show up there are
SCSS issues flagged by
stylelint. These things are all run usingnpm test under the node(newtab) slug in Treeherder/Try, so if that slug turns
red, these tests are what is failing. To execute them, do this:
./mach npm test --prefix=browser/extensions/newtabThese tests are not currently run by mach test, but there's a
task filed to fix that.
Windows isn't currently supported by npm test
(path/invocation difference).
To run newtab specific tests that aren't covered by mach lint andmach test:
./mach npm run lint:stylelint --prefix=browser/extensions/newtab
./mach npm run testmc:jest --prefix=browser/extensions/newtabMochitests and xpcshell tests run normally, using mach test.
Code Coverage
CI collects Jest code coverage for the unit tests and reports it to the code
coverage tools and Searchfox. There are no coverage thresholds.
To inspect the coverage report locally, run
./mach npm run testmc:jest:coverage --prefix=browser/extensions/newtab &&
./mach npm run debugcoverage --prefix=browser/extensions/newtabDiscovery Stream Developer tools
You can access the developer tools for the Discovery Stream components of about:newtab by
visiting about:config and setting browser.newtabpage.activity-stream.asrouter.devtoolsEnabled
to true.
Then, go to any about:newtab page and click on the wrench icon in the top-right corner.
Detailed Docs
:glob: true
:titlesonly: true
v2-system-addon/*Browser Installer Windows Docs Index (`browser/installer/windows/docs/index.md`)
Installer
The main role of the Firefox installer is to get a user running Firefox as quickly and reliably as possible, while taking all necessary steps to make Firefox an integrated part of the system.
It turns out that the only platform where we need an installer in order to accomplish all of that is Windows. So we only develop and ship and installer for Windows, and on other platforms we distribute a package in a non-executable format typical of applications distributed on that platform.
Currently, the installers are built on the NSIS installer framework. This is a Windows-only framework which compiles scripts written in its custom language (along with some native plugins) into an executable installer.
We build four different kinds of installers, the {doc}Stub Installer <StubInstaller>, the {doc}Full Installer <FullInstaller>, an {doc}MSI package <MSI> which wraps the full installer, and an {doc}MSIX package <MSIX>. The stub is the default installer intended for most individual users, the full installer and MSI are aimed at power users and administrators who need more control, and the MSIX is aimed at enterprise users who need to control deployment.
There's also another installer-related program, which is called {doc}helper.exe <Helper>. It's also written in NSIS and has a few different jobs that involve maintaining things that the installer sets up, including the uninstaller and a post-update routine.
InstallerBuild
StubInstaller
FullInstaller
MSI
MSIX
Helper
NSISPluginsDevtools 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 indevtools/clientbelow: 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/server/actors: RDP Actors. Note that if you're modifying actors, you may need to worry about backwards compatibility with older clients.
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:
./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:
./mach test devtools/client/framework/test/metrics/browser_metrics_debugger.js --headlessAt 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:
./mach test devtools/client/framework/test/metrics/browser_metrics_inspector.js --headlessnetmonitor-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:
./mach test devtools/client/framework/test/metrics/browser_metrics_netmonitor.js --headlesswebconsole-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:
./mach test devtools/client/framework/test/metrics/browser_metrics_webconsole.js --headlessserver.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:
./mach test devtools/client/framework/test/metrics/browser_metrics_pool.js --headlessAt 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:
./mach test devtools/client/framework/test/allocations/browser_allocations_toolbox.js --headlessThe 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:
./mach test devtools/client/framework/test/allocations/browser_allocations_target.js --headlessSee 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:
./mach test devtools/client/framework/test/allocations/browser_allocations_reload.js --headlessSee 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:
./mach test devtools/client/framework/test/allocations/browser_allocations_browser_console.js --headlessSee the description for toolbox:parent-process for more information.
Devtools Docs User 3d View Index (`devtools/docs/user/3d_view/index.md`)
3D view
:::{warning}
From Firefox 47 onwards, 3D view is no longer available.
:::
When you click on the 3D view button, the page goes into 3D view mode; in this mode, you can see your page presented in a 3D view in which nested blocks of HTML are increasingly "tall," projecting outward from the bottom of the page. This view makes it easy to visualize the nesting of your content.
:class: centerBy clicking and dragging the view, you can rotate and re-orient the 3D presentation of the DOM hierarchy of your page to see it from different angles, to better examine its structure. Off-screen elements become visible, so that you can see where your elements are located in relation to the visible content. You can click on elements to see their HTML in the {ref}HTML panel or the {ref}Style panel. Conversely, you can click on elements in the breadcrumb bar to change which element is selected in the 3D view.
If you do not see the 3D button in the page inspector, it is possible that your graphics driver needs to be updated. See the blocklisted drivers page for more information.
Controlling the 3D view
There are keyboard shortcuts and mouse controls available for the 3D view.
.. list-table::
:widths: 20 20 60
:header-rows: 1
* - Function
- Keyboard
- Mouse
* - Zoom in/out
- :kbd:`+` / :kbd:`-`
- Scroll wheel up/down
* - Rotate left/right
- :kbd:`a` / :kbd:`d`
- Mouse left/right
* - Rotate up/down
- :kbd:`w` / :kbd:`s`
- Mouse up/down
* - Pan left/right
- :kbd:`←` / :kbd:`→`
- Mouse left/right
* - Pan up/down
- :kbd:`↑` / :kbd:`↓`
- Mouse up/down
* - Reset zoom level
- :kbd:`0`
- Resets the zoom level to the default
* - Focus on selected node
- :kbd:`f`
- Makes sure the currently selected node is visible
* - Reset view
- :kbd:`r`
- Resets zoom, rotation, and panning to the default
* - Hide current node
- :kbd:`x`
- Makes the currently selected node invisible; this can be helpful if you need to get at a node that's obscuredUse cases for the 3D view
There are a variety of ways the 3D view is useful:
- If you have broken HTML causing layout problems, looking at the 3D view can help find where you've gone wrong. Often, layout problems are caused by improper nesting of content. This can become much more obvious when looking at the 3D view and seeing where your elements are nested wrong.
- If content isn't displaying, you may be able to figure out why; since the 3D view lets you zoom out to see elements that are rendering outside the visible area of the page, you can find stray content this way.
- You can get a look at how your page is structured to see if there may be ways to optimize your layout.
- And, of course, it looks awesome.
See also
- {doc}
Page Inspector <../page_inspector/index> - {ref}
HTML panel - {ref}
Style panel - {doc}
Tools <../index>
Devtools Docs User About Colon Debugging Index (`devtools/docs/user/about_colon_debugging/index.md`)
The about:debugging page provides a single place from which you can attach the Firefox Developer Tools to a number of debugging targets. At the moment it supports three main sorts of targets: restartless add-ons, tabs, and workers.
This is also the main entry point to remotely debug Firefox, in particular Firefox for Android.
Opening the page
There are two ways to open about:debugging:
- Type
about:debuggingin the Firefox URL bar. - In the Tools > Browser Tools menu, click Remote Debugging.
When about:debugging opens, on the left-hand side, you'll see a sidebar with two options and information about your remote debugging setup:
Setup
: Use the Setup tab to configure the connection to your remote device.
This Firefox
: Provides information about temporary extensions you have loaded for debugging, extensions that are installed in Firefox, the tabs that you currently have open, and service workers running on Firefox.
:class: borderIf your about:debugging page is different from the one displayed here, go to about:config, find and set the option devtools.aboutdebugging.new-enabled to true.
Setup tab
(about-colon-debugging-connecting-to-a-remote-device)=
Connecting to a remote device
Firefox supports debugging over USB with Android devices, using the about:debugging page.
Before you connect:
- Ensure clicking once on "Enable USB Devices" in about:debugging homepage.
:class: border- Enable Developer settings on your Android device.
Press 7 times on "Build Number" from your "About your phone" in the device settings app. - Enable "USB debugging" in the Android Developer settings.
Detailed guide for 1. and 2.
:class: border- Enable Remote Debugging via USB in the Advanced Settings in Firefox on the Android device.
:class: border- Connect the Android device to your computer using a USB cable.
If a USB cable is not available, {ref}connect to Android over Wi-Fi <about-colon-debugging-connecting-to-android-over-wi-fi>.
If your device doesn't appear in the lefthand side of the about:debugging page, try clicking the Refresh devices button.
If it still doesn't appear, it may be because the link between your Android device and your computer is not authorized yet. First make sure you have installed Android Debug Bridge from Android Tools on your computer in order for it to be able to connect to your device. Next, disable every debugging setting already activated and repeat the steps described before. Your device should show a popup to authorize your computer to connect to it — accept this and then click the Refresh devices button again. The device should appear.
:::{note}
You do not need to install the full Android Studio SDK. Only adb is needed.
:::
To start a debugging session, first open the page that you wish to debug and then click Connect next to the device name to open a connection to it. If the connection was successful, you can now click the name of the device to switch to a tab with information about the device.
:alt: Screenshot of the debugging page for an Android device
:class: borderThe information on this page is the same as the information on the This Firefox tab, but instead of displaying information for your computer, it displays the information for the remote device with the addition of a Tabs section with an entry for each of the tabs open on the remote device.
Note: If the version of Firefox on your remote device is more than one major version older than the version running on your computer, you may see a message like the following:
:alt: The connected browser has an old version (68.2.0). The minimum supported version
: (69.0a1). This is an unsupported setup and may cause DevTools to fail. Please update
: the connected browser.
:class: centerThe message can look like the following:
:alt: This version of Firefox cannot debug Firefox for Android (68). We recommend installing
: Firefox for Android Nightly on your phone for testing. More details
:class: centerSee Connection for Firefox for Android 68 for more information.
In the image above, there are three tabs open: Network or cache Recipe, Nightly Home, and About Nightly. To debug the contents of one of these tabs, click the Inspect button next to its title. When you do, the Developer Tools open in a new tab.
:alt: Screenshot showing the remote debugging window, with the editable URL bar
:class: borderAbove the usual list of tools, you can see information about the device you are connected to, including the fact that you are connected (in this example) via USB, to Firefox Preview, on a Pixel 2, as well as the title of the page that you are debugging, and the address of the page.
The URL bar is editable, so that you can change the URL used by the browser on the remote device, by typing in Firefox for Desktop. You can also reload the page by clicking the Reload button next to the URL bar, and navigate backward or forward in the browsing history with the Back and Forward buttons.
(about-colon-debugging-connecting-to-android-over-wi-fi)=
Connecting to Android over Wi-Fi
Firefox can debug Firefox for Android through adb and the "Wireless debugging" feature of Android 11+, without requiring any USB cable.
Prerequisites:
- Device must run Android 11 or later.
- The adb program is available. You do not need Android Studio nor the full Android SDK.
- The Android device and the computer with
about:debuggingare in the same network.
Steps to connect wirelessly with the Android device:
Determine the IP address of your Android device on your local network. For example by locating the Internet/Wi-Fi setting and viewing details of the current (Wi-Fi) network.
Enable Developer options on your Android device.
Enable Wireless debugging by tapping on the toggle at the "Wireless debugging" bar at the Developer options, then tap on the "Wireless debugging" bar (before the toggle) to open the "Wireless debugging" screen.
- An alternative to the previous step is to open "Quick settings developer tiles" at Developer options, and enabling the "Wireless debugging" tile. After this, you can long-press the "Wireless debugging" tile from the Quick Settings panel to launch the "Wireless debugging" screen.
Tap on "Pair device with pairing code" in the "Wireless debugging" screen. This displays a six-digit code and an IP address and port. The port is unique to the pairing setup.
From the terminal, run
adb pair [ip address from step 1]:[port from step 4]and enter the six-digit code from step 4.To finally connect wirelessly, look up the (random) port at the "IP address & Port" section of the "Wireless debugging" screen. The port is distinct from step 4. Run
adb connect [ip address from step 1]:[port from step 6]to connect.
Now, the adb server on your computer is connected with the adb daemon on the Android device. All Firefox apps with the "Remote Debugging via USB" setting enabled will now appear in about:debugging.
If you do not see any Firefox for Android debugging target:
- Confirm that adb is connected by running
adb devices. - Confirm that the Firefox app is running and that the "Remote Debugging via USB" setting is checked.
Connecting over the Network
:::{note}
The steps below do not work for Android. Follow the instructions at {ref}Connecting to Android over Wi-Fi <about-colon-debugging-connecting-to-android-over-wi-fi> instead.
:::
You can connect to a Firefox Debug server on your network, or on your debugging machine using the Network Location settings of the about:debugging page.
:class: centerEnter the location and port on which the debugger server is running. When you do, it is added to the Network locations list along with the devices, as shown below:
:class: centerThis Firefox
The This Firefox tab combines the features of Extensions, Tabs, and Workers into a single tab with the following sections:
Temporary Extensions
: Displays a list of the extensions that you have loaded using the Load Temporary Add-on button.
Extensions
: This section lists information about the extensions that you have installed on your system.
Service Workers, Shared Workers, and Other Workers
: There are three sections on this page that deal with Service Workers, Shared Workers, and Other Workers.
:class: borderWhether internal extensions appear in the list on this page depends on the setting of the devtools.aboutdebugging.showHiddenAddons preference. If you need to see these extensions, navigate to about:config and make sure that the preference is set to true.
Extensions
Loading a temporary extension
With the Load Temporary Add-on button you can temporarily load a WebExtension from a directory on disk. Click the button, navigate to the directory containing the add-on and select its manifest file. The temporary extension is then displayed under the Temporary Extensions header.
You don't have to package or sign the extension before loading it, and it stays installed until you restart Firefox.
The major advantages of this method, compared with installing an add-on from an XPI, are:
- You don't have to rebuild an XPI and reinstall when you change the add-on's code;
- You can load an add-on without signing it and without needing to disable signing.
Once you have loaded a temporary extension, you can see information about it and perform operations on it.
:alt: Screenshot of the debugging information panel for a temporary extension
:class: centerYou can use the following buttons:
Inspect
: Loads the extension in the debugger.
Reload
: Reloads the temporary extension. This is handy when you have made changes to the extension.
Remove
: Unloads the temporary extension.
Other information about the extension is displayed:
Location
: The location of the extension's source code on your local system.
Extension ID
: The temporary ID assigned to the extension.
Internal UUID
: The internal UUID assigned to the extension.
Manifest URL
: If you click the link, the manifest for this extension is loaded in a new tab.
Updating a temporary extension
If you install an extension in this way, what happens when you update the extension?
If you change files that are loaded on demand, like content scripts or popups, then changes you make are picked up automatically, and you'll see them the next time the content script is loaded or the popup is shown.
For other changes, click the Reload button. This does what it says:
- Reloads any persistent scripts, such as background scripts
- Parses the
manifest.jsonfile again, so changes to permissions, content_scripts, browser_action or any other keys take effect
Installed Extensions
The permanently installed extensions are listed in the next section, Extensions. For each one, you see something like the following:
:alt: Screenshot of the debugging information panel for an installed extension
:class: centerThe Inspect button, and the Extension ID and Internal UUID fields are the same as for temporary extensions.
Just as it does with temporarily loaded extensions, the link next to Manifest URL opens the loaded manifest in a new tab.
:::{note}
It's recommended that you use the Browser Toolbox, not the Add-on Debugger, for debugging WebExtensions. See Debugging WebExtensions for all the details.
:::
The Add-ons section in about:debugging lists all WebExtensions that are currently installed. Next to each entry is a button labeled Inspect.
:::{note}
This list may include add-ons that came preinstalled with Firefox.
:::
If you click Inspect, the Add-on Debugger will start in a new tab.
<iframe width="560" height="315" src="https://www.youtube.com/embed/efCpDNuNg_c" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<br/>
<br/>Workers
The Workers section shows all the workers you've got registered on your Firefox, categorized as follows:
- All registered Service Workers
- All registered Shared Workers
- Other workers, including Chrome Workers and Dedicated Workers
You can connect the developer tools to each worker, and send push notifications to service workers.
:class: borderService worker state
The list of service workers shows the state of the service worker in its lifecycle. Three states are possible:
- Registering: this covers all states between the service worker's initial registration, and its assuming control of pages. That is, it subsumes the installing, activating, and waiting states.
- Running: the service worker is currently running. It's installed and activated, and is currently handling events.
- Stopped: the service worker is installed and activated, but has been terminated after being idle.
:alt: Screenshot of the debugging panel for a service worker that is in the Running
: state
:class: centerThis section uses a simple ServiceWorker demo, hosted at https://serviceworke.rs/push-simple/.
:::{note}
You can access similar information on the Service Workers registered on a particular domain by going to the Firefox DevTools {doc}Application panel <../application/index>.
:::
Unregistering service workers
Click the Unregister button to unregister the service worker.
Sending push events to service workers
To debug push notifications, you can set a breakpoint in the push event listener. However, you can also debug push notifications locally, without needing the server. Click the Push button to send a push event to the service worker.
Service workers not compatible
A warning message is displayed at the top of the This Firefox tab if service workers are incompatible with the current browser configuration, and therefore cannot be used or debugged.
:class: centerService workers can be unavailable if the dom.serviceWorkers.enable preference is set to false in about:config.
Connection to Firefox for Android 68
Releases of Firefox for Android that are based on version 68 cannot be debugged from desktop Firefox versions 69 or later, because of the difference in release versions. Until such time as Firefox for Android is updated to a newer major release, in synch with desktop Firefox, you should use one of the following Firefox for Android versions:
- Firefox Preview, if your desktop Firefox is the main release or Developer Edition
- Firefox for Android Nightly
If you prefer to test with the main release of Firefox for Android (i.e., based on release 68), you can do so with the desktop Firefox Extended Support Release (ESR), which is also based on version 68.
Note that about:debugging is not enabled by default in Firefox ESR. To enable it, open the Configuration Editor (about:config) and set devtools.aboutdebugging.new-enabled to true.
If you used a higher version of Firefox prior to installing Firefox ESR, you will be prompted to create a new user profile, in order to protect your user data. For more information, see What happens to my profile if I downgrade to a previous version of Firefox?
Devtools Docs User Accessibility Inspector Index (`devtools/docs/user/accessibility_inspector/index.md`)
Accessibility Inspector
The Accessibility Inspector provides a means to access important information exposed to assistive technologies on the current page via the accessibility tree, allowing you to check what's missing or otherwise needs attention. This article takes you through the main features of the Accessibility Inspector and how to use it.
A (very) brief guide to accessibility
Accessibility is the practice of making your websites usable by as many people as possible. This means trying your best to not lock anyone out of accessing information because of any disability they may have, or any other personal circumstances such as the device they are using, the speed of their network connection, or their geographic location or locale. You can find more extensive information in the Accessibility section of MDN Web Docs.
Here we are mainly talking about exposing information to people with visual disabilities — this is done via the accessibility APIs available inside web browsers, which expose information on what roles the different elements on your page play (e.g., are they just text, or are they buttons, links, form elements, etc.?).
Semantic DOM elements have roles assigned to them by default that hint at what their purpose is. Sometimes, however, you need to use some non-semantic markup (e.g., div s) to build a complex custom control, and the control won't have a default role that reflects its purpose. In such a situation, you can use WAI-ARIA role attributes to provide your own roles.
Roles and other information exposed by browser accessibility APIs are presented in a hierarchical structure called the accessibility tree. This is a bit like the DOM tree, except that it contains a more limited set of elements and slightly different information about them.
Assistive technologies like screenreaders use this information to find out what's on a web page, tell their users what's there, and enable them to interact with the page. The Accessibility Inspector also uses this information to provide valuable accessibility debugging capabilities in the DevTools.
Accessing the Accessibility Inspector
When you first open any of the other Developer Tools, the accessibility features are turned off (unless you've already got them turned on in another browser tab, or got the Firefox accessibility engine started already, e.g., you might be a screenreader user or tester).
The accessibility inspector is automatically enabled when you do one of the following:
- Choose Accessibility in the Tools > Browser Tools menu.
- Select the Accessibility tab in the Developer Tools toolbox.
- Right-click in the main browser window, and choose Inspect Accessibility Properties in the context menu.
- Right-click an item in the HTML pane of the {doc}
Page Inspector <../page_inspector/index>, and choose Show Accessibility Properties in the context menu.
Once activated, the accessibility engine remains running until you close the Developer Tools toolbox.
:::{note}
The accessibility engine runs in the background when the accessibility features are turned on. When enabled it may affect the metrics from other panels such as {doc}Memory <../memory/index> and {doc}Performance <../performance/index>, and have some impact onoverall browser performance.
:::
If you don't wish to allow the accessibility features to be automatically enabled, you can use the Configuration Editor (also known as about:config) to define the preference devtools.accessibility.auto-init.enabled, and set it to False.
If you don't wish to use the accessibility features at all, you can use the Configuration Editor to set the preference devtools.accessibility.enabled to False. If you do this, the methods listed above for activating the Accessibility Inspector do nothing.
Features of the Accessibility panel
The enabled accessibility panel looks like so:
:alt: Shows issue checker toolbar with "contrast" and "text label" options
:class: borderOn the left-hand side, there is a tree diagram representing all the items in the accessibility tree for the current page. Items with nested children have arrows that can be clicked to reveal the children, so you can move deeper into the hierarchy. Each item has two properties listed:
- Role — the role this item has on the page (e.g.,
pushbutton, orfooter). This can be either a default role provided by the browser, or a role given to it via a WAI-ARIAroleattribute. - Name — the name this item has on the page. The name depends on the element; for example, the name of most text elements is their
textContent, whereas form elements' names are the contents of their associated label.
On the right-hand side, you can see further information about the currently selected item. The listed properties are as follows:
name — the item's name, as described above.
role — the item's role, as described above.
actions — a list of actions that can be performed on the item, for example, a pushbutton would have "Press" listed, while a link would have "Jump" listed.
value — the value of the item. This can mean different things depending on the type of the item; for example, a form input (role: entry) would have a value of whatever is entered in the input, whereas a link's value would be the URL in the corresponding
<a>element'shref.DOMNode — the type of DOM node that the item in the accessibility tree represents. You can click on the "target" icon that comes after it to select the node in the {doc}
Page Inspector <../page_inspector/index>. Hovering over the "target" icon highlights the DOM node in the page content.{image} dom-node-target-icon.png:alt: DOMNode property in accessibility inspector with target icon highlighteddescription — any further description provided on the element, usually by the content of a title attribute.
keyboardShortcut — any keyboard shortcut that is available to activate the element, as specified in an
accessKeyattribute.childCount — the number of child items the current item has in the accessibility tree hierarchy.
indexInParent — an index value indicating what number child the item is, inside its parent. If the item is the first item inside its parent, it has a value of 0. If it is the second, it has a value of 1. And so on.
states — a list of the different accessibility-relevant states that can apply to the current item. For example, one of the links in one demo has states of focusable, linked, selectable text, opaque, enabled, and sensitive. For a full list of internal states, see Gecko states.
relations — a list of the accessibility-relevant relationships between this item and other items. For example, in a form, an entry item could have a "labelled by" relation with a label item, which in turn has a "label for" relation to the entry item.
attributes — a list of all the accessibility-relevant attributes that are applied to the item. This can include style-related attributes such as margin-left and text-indent, and other useful states for accessibility information, such as draggable and level (e.g., what heading level is it, in the case of headings). For a full list of possible attributes, see Gecko object attributes.
:::{note}
The exposed information is the same across all platforms — the inspector exposes Gecko's accessibility tree, rather than information from the platform accessibility layer.
:::
Keyboard controls
The Accessibility tab is fully keyboard-accessible:
- You can tab between Check for Issues, Simulate, Show tabbing order, and left and right panels.
- When one of the panels is focused, you can move the focus up and down items using the up and down arrow keys, and use the left and right arrow keys to expand and collapse expandable rows (e.g., different hierarchy levels of the accessibility tree).
Print accessibility tree to JSON
You can print the contents of the accessibility tree to JSON by right-clicking on an entry in the Accessibility tab and selecting Print to JSON:
:alt: Print to JSON right-click menu in left panel
:class: borderWhen you do, you will get a new tab with the selected accessibility tree loaded into the JSON viewer:
:alt: Accessibility tree loaded in new tab JSON viewer
:class: centerOnce opened, you can save or copy the data as necessary. The JSON viewer can also show you the raw JSON data on a separate tab in the viewer.
Show web page tabbing order
People who are unable to navigate a page with the mouse or a trackpad can use the {kbd}tab key to toggle through focusable items on the page (i.e. buttons, links, form controls).The order that items are focused is one of the most important aspects of web accessibility, as it allows keyboard users to properly navigate a web page — if the tab order is incorrect, the page may be confusing!
Firefox can enable a visual overlay showing the tabbing order. This provides a high-level overview of how the page will be navigated using the {kbd}tab key, which may highlight problems more effectively than tabbing through the elements. The overlay is toggled on/off using the**Show Tabbing Order** checkbox.
:alt: Accessibility inspector and page with checkbox Show tab order selected.
:class: borderAll focusable items have a numbered marker and the currently focused item is highlighted in a different color. In some cases the marker may be hidden by other elements, as is true for items 1 and 2 in the page below.
:alt: A page where some of the markers for selection items are hidden
:class: centerThese become visible in the overlay when the item is the current item.
:alt: Shows a hidden selection item in the tabbing order overlay when it is selected.
:class: center:::{note}
The overlay reflects the tab order at the time that the checkbox is selected (i.e. it is not dynamic). If a user does anything that adds items to the tab order (e.g. opens a visual element that contains more links), these new items will not be reflected in the overlay until the Accessibility Inspector is re-launched.
:::
Check for accessibility issues
You can check for accessibility issues by clicking the drop-down menu next to: Check for issues. The available menu items include:
- None — Don't show the possible list of issues.
- All Issues — Check for all types of issues.
- Contrast — Check for issues with visual contrast.
- Keyboard — Check for issues with navigating via a keyboard.
- Text Labels — Check for issues with missing text labels.
When you select one of the menu items, Firefox scans your document for the type of issues you selected. Depending on the size and complexity of your document, this may take a few seconds. When the scan is complete, the left side of the Accessibility Inspector panel displays only the items that have that type of issue. In the right side of the panel, the Checks subpanel lists the specific issue with the selected node. For each type of issue, there is a Learn more link to further information on MDN Web Docs about the issue.
:alt: Accessibility Inspector - Showing the options when you select the Check for Issues
: button
:class: borderThe menu items act as toggles. Select the item to view that type of issue; select the item again to clear the display of issues of that type.
Issues with a particular item are always displayed in the Checks subpanel as you browse the tree. The Check for issues menuitems are a quick way to view all and only those items that have issues.
Simulate
The Accessibility Inspector offers, a {doc}simulator <simulation/index> that lets you see what a web page would look like to users with various forms of color vision deficiency (better known as "color blindness"), as well as contrast sensitivity loss.
Notable related features
When the accessibility features are turned on, there are a number of useful additional features available in the DevTools, which are detailed below:
Context menu options
An extra context menu option is added, both for the general context menu on the web page when right-clicking a UI feature, and the HTML pane of the page inspector when right-clicking a DOM element:
:alt: 'context menu in the browser viewport, with a highlighted option: Inspect Accessibility
: Properties'
:class: border:alt: 'context menu in the DOM inspector, with a highlighted option: Show Accessibility
: Properties'
:class: borderWhen you choose the Inspect Accessibility Properties/Show Accessibility Properties context menu options, the Accessibility tab is immediately opened to show the corresponding accessibility tree item and its properties.
:::{note}
Some DOM elements do not have accessibility properties — in that case, the Inspect Accessibility Properties/Show Accessibility Properties context menu item is grayed out.
:::
Highlighting of UI items
In the Accessibility tab, when the mouse hovers over accessibility items, you can see a semi-transparent highlight appear over the UI items they relate to, if appropriate. The role and name of the item will be shown in a small information bar along with color contrast information if appropriate. This is useful for determining how the items in the accessibility tree relate to the UI items on the actual page.
In the following example, you can see that the image has been highlighted and its role, graphic, name, "Road, Asphalt, Sky, Clouds, Fall", and the color contrast ratio, 3.46, appears in the information bar above it.
:alt: image has been highlighted and graphic, "Road, Asphalt, Sky, Clouds, Fall", and
: Contrast:3.46 warning sign, appears in the information bar above it
:class: borderColor contrast
Contrast ratio information is particularly useful when you are designing the color palette for your website because if the contrast is not sufficient, readers with visual impairments such as low vision or color blindness will be unable to read the text. See Color contrast for details about recommended contrast ratios.
For example:
:alt: A screenshot of color contrast highlighter with warning sign where text contrast
: if below the AA WCAG threshold.
:class: centerThe color contrast in the image above is 2.86, so potentially not enough contrast to make it easy to read. Notice the warning symbol that indicates that the contrast fails to meet the acceptable contrast ratio.
Viewing this information for some foreground text that has a complex background image (e.g. a gradient) gives you a range of color contrast values. For example:
:alt: A screenshot of color contrast highlighter with checked sign where for text over
: gradient background with contrast satisfying the AAA WCAG guidelines.
:class: centerIn this example, the contrast ranges from 4.72 to 5.98. The numbers are followed by AAA and a checkmark in green, indicating that the large text has a contrast ratio of 4.5:1 or more, meeting the criteria for enhanced contrast, or Level AAA.
See Color contrast for more information on color contrast.
Accessibility picker
Like the element picker button on the {ref}Page Inspector , the Accessibility tab's element picker button allows you to hover and select UI items on the current page to highlight objects in the accessibility tree.
The accessibility tab element picker looks slightly different from the Page Inspector HTML pane picker, as shown below:
:alt: highlighted DOM inspector picker button, with a tooltip saying Pick an element
: from the page
:class: border:alt: highlighted accessibility inspector button, with a tooltip saying Pick accessible
: object from the page
:class: borderWhen you "perform a pick", you see the accessibility object highlighted in the accessibility tree, and the picker is then deactivated. Note, however, that if you hold the {kbd}Shift key down when "performing a pick", you can "preview" the accessibility object in the tree (and its properties in the right-hand pane), but then continue picking as many times as you like(the picker does not get cancelled) until you release the {kbd}Shift key.
When the picker is activated, you can also deactivate it by pressing the picker button a second time, or pressing the {kbd}Esc key.
Typical use cases
The Accessibility Inspector is very useful for spotting accessibility problems at a glance. For a start, you can investigate items that don't have a proper text equivalent — images without alt text and form elements without proper labels have a name property of null, for example.
:alt: "A form input highlighted in the UI, with information about it shown in the accessibility\
: \ inspector to reveal that it has no label \u2014 it has a name property of null"
:class: borderIt is also very handy for verifying semantics — you can use the Inspect Accessibility Properties context menu option to quickly see whether an item has the correct role set on it (e.g., whether a button is really a button, or a link is really a link).
:alt: A UI element that looks like a button, with information about it shown in the
: accessibility inspector to reveal that it isn't a button, it is a section element.
: It has a name property of null
:class: borderSee also
- Accessibility tutorials
- Web accessibility overview
- Practical debugging information
- Understanding WCAG
- WAI-ARIA basics
- Accessibility APIs: A Key To Web Accessibility by Léonie Watson
:hidden:
:maxdepth: 1
simulation/indexDevtools Docs User Application Index (`devtools/docs/user/application/index.md`)
Application
The Application panel provides tools for inspecting and debugging modern web apps (also known as Progressive Web Apps). This includes inspection of service workers and web app manifests.
:alt: the firefox application panel zoomed out view showing a picture of two arctic
: foxes
:class: borderAccessing the Application panel
The Application panel is available on the standard DevTools tab menu under Application. If you can’t see it there, you can enable it by going to the "three dot" menu and selecting Settings (also accessible by pressing F1), then checking the Application checkbox under Default Developer Tools.
Finding an example
If you want to test this functionality and you don't have a handy PWA available, you can grab one of our simple examples to use:
- Add to homescreen demo: Shows pictures of foxes (source code | live version)
- Js13kpwa demo: Show information on entries to the JS13K annual competition (source code | live version)
How to
- {doc}
Debug service workers <service_workers/index> - {doc}
Inspect web app manifests <manifests/index>
:hidden:
:maxdepth: 1
manifests/index
service_workers/indexDevtools Docs User Browser Console Index (`devtools/docs/user/browser_console/index.md`)
Browser Console
The Browser Console is like the {doc}Web Console <../web_console/index>, but applied to the whole browser rather than a single content tab.
So it logs the same sorts of information as the Web Console - network requests, JavaScript, CSS, and security errors and warnings, and messages explicitly logged by JavaScript code. However, rather than logging this information for a single content tab, it logs information for all content tabs, for add-ons, and for the browser's own code.
If you also want to use the other web developer tools in the regular Web {doc}Toolbox <../tools_toolbox/index> with add-on or browser code, consider using the {doc}Browser Toolbox<../browser_toolbox/index>.
Similarly, you can execute JavaScript expressions using the Browser Console. But while the Web Console executes code in the page window scope, the Browser Console executes them in the scope of the browser's chrome window. This means you can interact with all the browser's tabs using the gBrowser global, and even with the XUL used to specify the browser's user interface.
:::{container} block_quote
NB: The Browser Console command line (to execute JavaScript expressions) is disabled by default. To enable it set the devtools.chrome.enabled preference to true in about:config, or set the "Enable browser chrome and add-on debugging toolboxes" option in the {doc}developer tool settings <../settings/index>.
:::
Opening the Browser Console
You can open the Browser Console in one of two ways:
- from the menu: select "Browser Console" from the Browser Tools submenu in the Firefox Menu (or Tools menu if you display the menu bar or are on macOS).
- from the keyboard: press {kbd}
Ctrl+ {kbd}Shift+ {kbd}J(or {kbd}Cmd+ {kbd}Shift+ {kbd}Jon a Mac).
You can also start the Browser Console by launching Firefox from the command line and passing the -jsconsole argument:
/Applications/FirefoxAurora.app/Contents/MacOS/firefox -jsconsoleThe Browser Console looks like this:
You can see that the Browser Console looks and behaves very much like the {doc}Web Console <../web_console/index>:
- most of the window is occupied by a {doc}
pane that display messages <../web_console/console_messages/index> - at the top, a {ref}
toolbar <web-console-ui-tour-toolbar>enables you to filter the messages that appear. - at the bottom, a {doc}
command line interpreter <../web_console/the_command_line_interpreter/index>enables you to evaluate JavaScript expressions.
The Browser Console allows you to show or hide messages from the content process (i.e. the messages from scripts in all the opened pages) by setting or clearing the checkbox labeled Show Content Messages. The following image shows the browser console focused on the same page as above after clicking on the Show Content Messages checkbox.
Browser Console logging
The Browser console logs the same sorts of messages as the Web Console:
- {ref}
HTTP requests <web-console-console-messages> - {doc}
Warnings and errors <../web_console/console_messages/index>(including JavaScript, CSS, security warnings and errors, and messages explicitly logged by JavaScript code using the Console API - {ref}
Input/output messages <web-console-console-messages-interpreter-io>commands send to the browser via the command line, and the result of executing them
However, it displays such messages from:
- web content hosted by all browser tabs
- the browser's own code
- add-ons
Messages from add-ons
The Browser Console displays messages logged by all Firefox add-ons.
Console.sys.mjs
To use the console API from a traditional or bootstrapped add-on, get it from the Console module.
One exported symbol from Console.sys.mjs is console. Below is an example of how to access it, which adds a message to the Browser Console.
const { console } = ChromeUtils.importESModule("resource://gre/modules/Console.sys.mjs");
console.log("Hello from Firefox code"); //output messages to the consoleLearn more:
- Console API reference
- {searchfox}
Console.sys.mjs source code <toolkit/modules/Console.sys.mjs>
Browser Console command line
:::{container} block_quote
The Browser Console command line is disabled by default. To enable it set the devtools.chrome.enabled preference to true in about:config, or set the "Enable chrome debugging" option in the {doc}developer tool settings <../settings/index>.
:::
Like the Web Console, the command line interpreter enables you to evaluate JavaScript expressions in real time:
Also like the Web Console's command line interpreter, this command line supports autocomplete, history, and various {ref}keyboard shortcuts <keyboard-shortcuts-web-console> and {doc}helper commands <../web_console/helpers/index>. If the result of a command is an object, you can click on the object to see its details.
But while the Web Console executes code in the scope of the content window it's attached to, the browser console executes code in the scope of the chrome window of the browser. You can confirm this by evaluating window:
This means you can control the browser: opening, closing tabs and windows and changing the content that they host, and modify the browser's UI by creating, changing and removing XUL elements.
Controlling the browser
The command line interpreter gets access to the tabbrowser object, through the gBrowser global, and that enables you to control the browser through the command line. Try running this code in the Browser Console's command line (remember that to send multiple lines to the Browser Console, use {kbd}Shift + {kbd}Enter):
var newTabBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
newTabBrowser.addEventListener("load", function() {
newTabBrowser.contentDocument.body.innerHTML = "<h1>this page has been eaten</h1>";
}, true);
newTabBrowser.contentDocument.location.href = "https://mozilla.org/";It adds a listener to the currently selected tab's load event that will eat the new page, then loads a new page.
:::{note}
You can restart the browser with the command {kbd}Ctrl + {kbd}Alt + {kbd}R (Windows, Linux) or {kbd}Cmd + {kbd}Alt + {kbd}R (Mac) This command restarts the browser with the same tabs open as before the restart.
:::
Modifying the browser UI
Since the global window object is the browser's chrome window, you can also modify the browser's user interface. On Windows, the following code will add a new item to the browser's main menu:
var parent = window.document.getElementById("appmenuPrimaryPane");
var makeTheTea = gBrowser.ownerDocument.defaultView.document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menuitem");
makeTheTea.setAttribute("label", "A nice cup of tea?");
parent.appendChild(makeTheTea);On macOS, this similar code will add a new item to the Tools menu:
var parent = window.document.getElementById("menu_ToolsPopup");
var makeTheTea = gBrowser.ownerDocument.defaultView.document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menuitem");
makeTheTea.setAttribute("label", "A nice cup of tea?");
parent.appendChild(makeTheTea);Devtools Docs User Browser Toolbox Index (`devtools/docs/user/browser_toolbox/index.md`)
myst:
substitutions:
image1: |-
{image} 2014-01-10-13-08-08-f52b8c.png :alt: new fx menu
Browser Toolbox
The Browser Toolbox enables you to debug add-ons and the browser's own JavaScript code rather than just web pages like the normal {doc}Toolbox <../tools_toolbox/index>. The Browser Toolbox's context is the whole browser rather than justsingle page on a single tab.
Enabling the Browser Toolbox
The Browser Toolbox is not enabled by default. To enable it you need to check the settings "Enable chrome and addon debugging" and "Enable remote debugging".
To do this, open the Developer Tools {doc}Settings <../settings/index>, go to the section {ref}Advanced Settings <settings-advanced-settings>, and check the settings "Enable browser chrome and add-on debugging toolboxes" and "Enable remote debugging".
:alt: Developer Tools Settings
:class: borderOpening the Browser Toolbox
Open the Browser Toolbox through the menu button {{ image1 }} and the menu items "Developer" then "Browser Toolbox".
You can also open it with the {kbd}Ctrl + {kbd}Alt + {kbd}Shift + {kbd}I key combination ({kbd}Cmd + {kbd}Opt + {kbd}Shift + {kbd}I on a Mac).
You will be presented with a dialog like this (it can be removed by setting the devtools.debugger.prompt-connection property to false):
Click OK, and the Browser Toolbox will open in its own window:
You'll be able to inspect the browser's chrome windows and see, and be able to debug, all the JavaScript files loaded by the browser itself and by any add-ons that are running. Altogether you will have access to the following developer tools:
- {doc}
Debugger <../debugger/index> - {doc}
Console <../browser_console/index> - {doc}
Style Editor <../style_editor/index> - {doc}
Performance <../performance/index> - {doc}
Network Monitor <../network_monitor/index> - {doc}
Page Inspector <../page_inspector/index> - {doc}
Accessibility Inspector <../accessibility_inspector/index>
You can debug chrome: and about: pages using the normal {doc}Debugger <../debugger/index>, just as if they were ordinary content pages.
Targeting a document
In the normal toolbox, there's a {doc}button in the toolbar enabling you to target specific iframes in the document <../working_with_iframes/index>. The same button appears in the browser toolbox where it lists all the top-level chrome and content windows as well as any iframes they contain. This enables you to inspect documents in individual chrome windows and popups, as well as in content tabs.
For example, here's what the frame selection popup lists when there are two browser windows open, one with one content tab, and one with two:
Debugging popups
It's hard to debug popups, because the browser hides them as soon as you click outside them. There is a way to disable this behavior. Click the toolbox menu and select Disable popup auto-hide.
:class: centerNow when you open any popup, it will stay open until you press the {kbd}Esc key. You can use the Inspector's node picker to select that panel, and examine and modify its content.
You can use the same technique to debug popups created by add-ons.
:::{note}
This change is not persistent across browser restarts. When you close the browser toolbox, the setting will be cleared.
:::
Devtools Docs User Debugger Api Index (`devtools/docs/user/debugger-api/index.md`)
Debugger-API
The `Debugger` Interface
Mozilla’s JavaScript engine, SpiderMonkey, provides a debugging interface named Debugger which lets JavaScript code observe and manipulate the execution of other JavaScript code. Both Firefox’s built-in developer tools and the Firebug add-on use Debugger to implement their JavaScript debuggers. However, Debugger is quite general, and can be used to implement other kinds of tools like tracers, coverage analysis, patch-and-continue, and so on.
Debugger has three essential qualities:
- It is a source level interface: it operates in terms of the JavaScript language, not machine language. It operates on JavaScript objects, stack frames, environments, and code, and presents a consistent interface regardless of whether the debuggee is interpreted, compiled, or optimized. If you have a strong command of the JavaScript language, you should have all the background you need to use
Debuggersuccessfully, even if you have never looked into the language’s implementation. - It is for use by JavaScript code. JavaScript is both the debuggee language and the tool implementation language, so the qualities that make JavaScript effective on the web can be brought to bear in crafting tools for developers. As is expected of JavaScript APIs,
Debuggeris a sound interface: using (or even misusing)Debuggershould never cause Gecko to crash. Errors throw proper JavaScript exceptions. - It is an intra-thread debugging API. Both the debuggee and the code using
Debuggerto observe it must run in the same thread. Cross-thread, cross-process, and cross-device tools must useDebuggerto observe the debuggee from within the same thread, and then handle any needed communication themselves. (Firefox’s builtin tools have a protocol defined for this purpose.)
In Gecko, the Debugger API is available to chrome code only. By design, it ought not to introduce security holes, so in principle it could be made available to content as well; but it is hard to justify the security risks of the additional attack surface.
The Debugger API cannot currently observe self-hosted JavaScript. This is not inherent in the API’s design, but that the self-hosting infrastructure isn’t prepared for the kind of invasions the Debugger API can perform.
Debugger Instances and Shadow Objects
Debugger reflects every aspect of the debuggee’s state as a JavaScript value—not just actual JavaScript values like objects and primitives, but also stack frames, environments, scripts, and compilation units, which are not normally accessible as objects in their own right.
Here is a JavaScript program in the process of running a timer callback function:
:alt: A running JavaScript program and its Debugger shadows
:class: centerA running JavaScript program and its Debugger shadows
This diagram shows the various types of shadow objects that make up the Debugger API (which all follow some general conventions):
- A {doc}
Debugger.Object <debugger.object/index>represents a debuggee object, offering a reflection-oriented API that protects the debugger from accidentally invoking getters, setters, proxy traps, and so on. - A {doc}
Debugger.Script <debugger.script/index>represents a block of JavaScript code—either a function body or a top-level script. Given aDebugger.Script, one can set breakpoints, translate between source positions and bytecode offsets (a deviation from the “source level” design principle), and find other static characteristics of the code. - A {doc}
Debugger.Frame <debugger.frame/index>represents a running stack frame. You can use these to walk the stack and find each frame’s script and environment. You can also setonStepandonPophandlers on frames. - A {doc}
Debugger.Environment <debugger.environment/index>represents an environment, associating variable names with storage locations. Environments may belong to a running stack frame, captured by a function closure, or reflect some global object’s properties as variables.
The {doc}Debugger <debugger/index> instance itself is not really a shadow of anything in the debuggee; rather, it maintains the set of global objects which are to be considered debuggees. A Debugger observes only execution taking place in the scope of these global objects. You can set functions to be called when new stack frames are pushed; when new code is loaded; and so on.
Omitted from this picture are {doc}Debugger.Source <debugger.source/index> instances, which represent JavaScript compilation units. A Debugger.Source can furnish a full copy of its source code, and explain how the code entered the system, whether via a call to eval, a <script> element, or otherwise. A Debugger.Script points to the Debugger.Source from which it is derived.
Also omitted is the Debugger’s {doc}Debugger.Memory <debugger.memory/index> instance, which holds methods and accessors for observing the debuggee’s memory use.
All these types follow some general conventions, which you should look through before drilling down into any particular type’s specification.
All shadow objects are unique per Debugger and per referent. For a given Debugger, there is exactly one Debugger.Object that refers to a particular debuggee object; exactly one Debugger.Frame for a particular stack frame; and so on. Thus, a tool can store metadata about a shadow’s referent as a property on the shadow itself, and count on finding that metadata again if it comes across the same referent. And since shadows are per-Debugger, tools can do so without worrying about interfering with other tools that use their own Debugger instances.
Examples
Here are some things you can try out yourself that show off some of Debugger’s features:
- {doc}
Setting a breakpoint <tutorial-breakpoint/index>in a page, running a handler function when it is hit that evaluates an expression in the page’s context. - {doc}
Showing how many objects different call paths allocate. <tutorial-allocation-log-tree/index>
Gecko-specific features
While the Debugger core API deals only with concepts common to any JavaScript implementation, it also includes some Gecko-specific features:
- {doc}
Global tracking <debugger/index>supports debugging all the code running in a Gecko instance at once—the ‘chrome debugging’ model. - {doc}
Object wrapper <debugger.object/index>functions help manipulate object references that cross privilege boundaries.
Source Metadata
Generated from file:
: js/src/doc/Debugger/Debugger-API.md
Watermark:
: sha256:6ee2381145a0d2e53d2f798f3f682e82dd7ab0caa0ac4dd5e56601c2e49913a7
Changeset:
:hidden:
:maxdepth: 1
debugger/index
debugger.environment/index
debugger.frame/index
debugger.memory/index
debugger.object/index
debugger.script/index
debugger.source/index
tutorial-allocation-log-tree/index
tutorial-breakpoint/indexDevtools Docs User Debugger Index (`devtools/docs/user/debugger/index.md`)
The Firefox JavaScript Debugger
The JavaScript Debugger enables you to step through JavaScript code and examine or modify its state to help track down bugs.
<iframe width="560" height="315" src="https://www.youtube.com/embed/QK4hKWmJVLo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<br/>
<br/>You can use it to debug code running locally in Firefox or running remotely, for example on an Android device running Firefox for Android. See {doc}about debugging <../about_colon_debugging/index> to learn how to connect the debugger to a remote target.
To find your way around the debugger, here's a {doc}quick tour of the UI.
How to
To find out what you can do with the debugger, refer to the following how-to guides.
- {doc}
Open the debugger <how_to/open_the_debugger/index> - {doc}
Pretty-print a minified file <how_to/pretty-print_a_minified_file/index> - {doc}
Search <how_to/search/index> - {doc}
Use a source map <how_to/use_a_source_map/index> - Debug worker threads
Pause execution
You probably want to pause the execution of your code, in order to see what is going on at various points. There are multiple ways to tell the Debugger how and when to pause:
- {doc}
Set a breakpoint <how_to/set_a_breakpoint/index> - {doc}
Set a conditional breakpoint <how_to/set_a_conditional_breakpoint/index> - {doc}
Set an XHR breakpoint <set_an_xhr_breakpoint/index> - {doc}
Set event listener <set_event_listener_breakpoints/index> - {doc}
Break on exceptions <how_to/breaking_on_exceptions/index> - {doc}
Use watchpoints for property reads and writes <how_to/use_watchpoints/index> - {doc}
Break on DOM Mutation - {doc}
Disable breakpoints <how_to/disable_breakpoints/index>
Control execution
What can you do after execution pauses?
- {doc}
Step through code <how_to/step_through_code/index> - {doc}
Ignoring sources <how_to/ignoring_sources/index> - Debug worker threads
- {doc}
Debug eval sources <how_to/debug_eval_sources/index>
Look at values
You probably want to see the value of variables or expressions, either during execution or when it is paused.
- {doc}
Set a logpoint <set_a_logpoint/index> - {doc}
Set watch expressions <how_to/set_watch_expressions/index>
Reference
- {ref}
Keyboard shortcuts <keyboard-shortcuts-debugger> - {doc}
Source map errors
:hidden:
:maxdepth: 1
break_on_dom_mutation/index
how_to/index
set_a_logpoint/index
set_an_xhr_breakpoint/index
set_event_listener_breakpoints/index
source_map_errors/index
ui_tour/index
using_the_debugger_map_scopes_feature/indexDevtools Docs User Deprecated Tools Index (`devtools/docs/user/deprecated_tools/index.md`)
Deprecated tools
Over the course of DevTools development, we have added several experimental panels to try out new ideas. Not all of these have had wide adoption, and due to the cost of maintenance, seldom used panels are eventually removed.
We have created this list of deprecated or removed panels. This page documents the deprecated panels and the bugs that track their removal. Although these panels have been removed, you still have access to the old code, and there are alternative webextensions that you can try to get similar functionality.
When we deprecate a panel, we begin by getting feedback from the community to determine the impact of removing that panel. Once we have decided to remove the panel, we will provide a warning message, and finally, we will remove the panel from the codebase.
You may see a warning message, as in the following image, when trying to activate a deprecated panel:
:class: borderIn addition, if you open the panel for one of these tools, you will also see a warning message about its removal.
:class: borderScratchpad
Scratchpad was removed in Firefox 72 (bug 1519103).
Description
Scratchpad provided an environment for experimenting with JavaScript code. You can write, run, and examine the result of code that interacts with the web page.
:alt: Screenshot of the Scratchpad window with a deprecation messageAlternatives
You can write multi-line JavaScript code in the Web Console Editor Mode, making it similar to the Scratchpad. The Editor Mode can be triggered clicking on the icon on the right of the console input, or with {kbd}Ctrl + {kbd}B ({kbd}Cmd + {kbd}B on macOS)
:alt: Screenshot of the Webconsole in inline mode, with the editor mode icon displayed
: on the right of the console inputWhen in Editor Mode, the {kbd}Enter key adds a new line in the input, and you can evaluate the expression using {kbd}Ctrl + {kbd}Enter ({kbd}Cmd + {kbd}Enter on macOS).
:alt: Screenshot of the Webconsole multiline input, showing an evaluation with a Syntax
: Error and another, correct one.When evaluating, the input isn't cleared, which makes it possible to quickly iterate over a snippet of code.
The results are displayed in the console output, to the right of the input, providing immediate feedback. Unlike in Scratchpad, errors are properly displayed in the output with an expandable stacktrace, making it easier to debug the code you're currently writing.
You can import a Javascript file content in the console input with {kbd}Ctrl + {kbd}O ({kbd}Cmd + {kbd}O on macOS), as well as saving the console input content to a file using {kbd}Ctrl + {kbd}S ({kbd}Cmd + {kbd}S on macOS).
WebIDE and Connect page
WebIDE was removed as of Firefox 71 (bug 1539462).
Description
WebIDE allowed you to connect the Firefox Developer Tools to remote browsers, such as Firefox for Android. It was also intended to support application development for Firefox OS.
Alternatives
Remote debugging is available in about:debugging. Features not ported to about:debugging are: WiFi debugging for Firefox for Android, application development. Features that are planned but not ported yet: remote browser screenshots and edit remote browser configuration. More details on the mailing-list thread.
Wireless debugging over Wi-Fi is possible and documented at {ref}about-colon-debugging-connecting-to-android-over-wi-fi.
Canvas debugger
Bugzilla issue: bug 1403938
Removed as of Firefox 67
Description
Canvas Debugger allowed users to inspect the canvas element and see how frequently a given function is called. It was deprecated due to lack of use.
We do not have dedicated documentation for the Canvas Debugger.
Alternatives
Spector.js is a WebExtension that can provide these features with 3D contexts.
Web Audio editor
Bugzilla issue: bug 1403944
Removed as of Firefox 67
Description
The Web Audio Editor allowed you to examine an audio context constructed in the page and provided a visualization of its graph. This gave a high-level view of its operation, and enabled you to ensure that all the nodes are connected in the way you expect. It was possible to edit the AudioParam properties for each node in the graph. Some non-AudioParam properties, like an OscillatorNode's type property, were displayed and editable as well. It was deprecated due to lack of use.
More details about the {doc}Web Audio Editor <../web_audio_editor/index>
:class: borderAlternatives
Alternatives include the AudioN and https://github.com/spite/WebAudioExtension WebExtensions.
Shader editor
Bugzilla issue: bug 1342237
Removed as of Firefox 67
Description
The Shader Editor allowed users to examine and edit the source of the WebGL vertex and fragment shaders. It was deprecated due to low usage and maintenance costs.
{doc}Shader Editor <../shader_editor/index>
:class: borderAlternatives
An alternative to this panel is this extension: https://github.com/spite/ShaderEditorExtension, or Spector.js also supports a Shader Editor that requires a library to use a shader reloader hook. Currently only the Babylon library does.
Devtools Docs User Devtoolsapi Index (`devtools/docs/user/devtoolsapi/index.md`)
DevTools API
:::{warning}
Deprecated: This feature is no longer recommended. Though some browsers might still support it, it may have already been removed from the relevant web standards, may be in the process of being dropped, or may only be kept for compatibility purposes. Avoid using it, and update existing code if possible; see the compatibility table at the bottom of this page to guide your decision. Be aware that this feature may cease to work at any time.
:::
:::{warning}
The DevTools API is still WIP. If you notice any inconsistency, please let The Firefox Developer Tools Team know.
:::
While this api is currently a work-in-progress, there are usable portions of {doc}page inspector <../page_inspector/index> and {doc}debugger <../debugger/index> that may be used currently.
Introduction
The DevTools API provides a way to register and access developer tools in Firefox.
In terms of User Interface, each registered tool lives in its own tab (we call one tab a panel). These tabs are located in a box we call a Toolbox. A toolbox can be hosted within a browser tab (at the bottom or on the side), or in its own window (we say that the toolbox is undocked). A Toolbox (and all the tools it contains) is linked to a Target, which is the object the tools are debugging. A target is usually a web page (a tab), but can be other things (a chrome window, a remote tab,…).
In terms of code, each tool has to provide a ToolDefinition object. A definition is a JS light object that exposes different information about the tool (like its name and its icon), and a build method that will be used later-on to start an instance of this tool. The gDevTools global object provides methods to register a tool definition and to access tool instances. An instance of a tool is called a ToolPanel. The ToolPanel is built only when the tool is selected (not when the toolbox is opened). There is no way to "close/destroy" a ToolPanel. The only way to close a toolPanel is to close its containing toolbox. All these objects implement the EventEmitter interface.
API
gDevTools
The gDevTools API can be used to register new tools, themes and handle toolboxes for different tabs and windows. To use the gDevTools API from an add-on, it can be imported with following snippet
const { gDevTools } = require("resource://devtools/client/framework/devtools.js");Methods
registerTool(toolDefinition)
: Registers a new tool and adds a tab to each existing toolbox.
Parameters:
toolDefinition {ToolDefinition}- An object that contains information about the tool. See {ref}ToolDefinition <devtoolsapi-tool-definition>for details.
unregisterTool(toolId)
: Unregisters the given tool and removes it from all toolboxes.
Parameters:
tool {ToolDefinition|String}- The tool definition object or the id of the tool to unregister.
registerTheme(themeDefinition)
: Registers a new theme.
Parameters:
themeDefinition {ThemeDefinition}- An object that contains information about the theme.
unregisterTheme(theme)
: Unregisters the given theme.
Parameters:
theme {ThemeDefinition|String}- The theme definition object or the theme identifier.
showToolbox(commands[, toolId [, hostType [, hostOptions]]])
: Opens a toolbox for given target either by creating a new one or activating an existing one.
Parameters:
commands {Object}- The commands object designating which debugging context the toolbox will debug.toolId {String}- The tool that should be activated. If unspecified the previously active tool is shown.hostType {String}- The position the toolbox will be placed. One ofbottom,side,window,custom. See {ref}HostType <devtoolsapi-host-type>for details.hostOptions {Object}- An options object passed to the selected host. See {ref}HostType <devtoolsapi-host-type>for details.Return value:
A Promise that is fulfilled with the {ref}Toolbox <devtoolsapi-toolbox>instance once it has been initialized and the selected tool is loaded.
getToolbox(target)
: Fetch the {ref}Toolbox <devtoolsapi-toolbox> object for the given target.
Parameters:
target {Target}- The target the toolbox is debugging.Return value:
{ref}Toolbox <devtoolsapi-toolbox>object or undefined if there's no toolbox for the given target..
closeToolbox(target)
: Closes the toolbox for given target.
Parameters:
target {Target}- The target of the toolbox that should be closed.Return value:
A Promise that is fulfilled once the toolbox has been destroyed.
getDefaultTools()
: Returns an Array of {ref}ToolDefinition <devtoolsapi-tool-definition> objects for the built-in tools.
getAdditionalTools()
: Returns an Array of {ref}ToolDefinition <devtoolsapi-tool-definition> objects for tools added by addons.
getToolDefinition(toolId)
: Fetch the {ref}ToolDefinition <devtoolsapi-tool-definition> object for a tool if it exists and is enabled.
Parameters:
toolId {String}- The ID of the tool.Return value:
A {ref}ToolDefinition <devtoolsapi-tool-definition>if a tool with the given ID exists and is enabled, null otherwise.
getToolDefinitionMap()
: Returns a toolId → {ref}ToolDefinition <devtoolsapi-tool-definition> map for tools that are enabled.
getToolDefinitionArray()
: Returns an Array of {ref}ToolDefinition <devtoolsapi-tool-definition> objects for enabled tools sorted by the order they appear in the toolbox.
getThemeDefinition(themeId)
: Fetch the ThemeDefinition object for the theme with the given id.
Parameters:
themeId {String}- The ID of the theme.Return value:
AThemeDefinitionobject if the theme exists, null otherwise.
getThemeDefinitionMap()
: Returns a toolId → ThemeDefinition map for available themes.
getThemeDefinitionArray()
: Returns an Array of ThemeDefinition objects for available themes.
Events
Following events are emitted by the gDevTools object via the {ref}EventEmitter <devtoolsapi-event-emitter> interface.
tool-registered (toolId)
: A new tool has been registered.
tool-unregistered(tool)
: A tool has been unregistered. The parameter is a {ref}ToolDefinition <devtoolsapi-tool-definition> object.
theme-registered(themeId)
: A new theme has been registered.
theme-unregistered(theme)
: A theme has been unregistered. The parameter is a ThemeDefinition object.
toolbox-ready(toolbox)
: A new toolbox has been created and is ready to use. The parameter is a {ref}Toolbox <devtoolsapi-toolbox> object instance.
toolbox-destroy(target)
: The toolbox for the specified target is about to be destroyed.
toolbox-destroyed(target)
: The toolbox for the specified target has been destroyed.
{toolId}-init(toolbox, iframe)
: A tool with the given ID has began to load in the given toolbox to the given frame.
{toolId}-build(toolbox, panel)
: A tool with the given ID has began to initialize in the given toolbox. The panel is the object returned by the ToolDefinition.build() method.
{toolId}-ready(toolbox, panel)
: A tool with the given ID has finished its initialization and is ready to be used. The panel is the object returned by the ToolDefinition.build() method.
{toolId}-destroy(toolbox, panel)
: A tool with the given ID is about to be destroyed. The panel is the object returned by the ToolDefinition.build() method.
(devtoolsapi-toolbox)=
Toolbox
A Toolbox is a frame for the {ref}ToolPanel <devtoolsapi-tool-panel> that is debugging a specific target.
Properties
target
: Target. The Target this toolbox is debugging.
hostType
: Toolbox.HostType. The type of the host this Toolbox is docked to. The value is one of the Toolbox.HostType constants.
zoomValue
: The current zoom level of the Toolbox.
Constants
The Toolbox constructor contains following constant properties.
Toolbox.HostType.BOTTOM
: Host type for the default toolbox host at the bottom of the browser window.
Toolbox.HostType.SIDE
: Host type for the host at the side of the browser window.
Toolbox.HostType.WINDOW
: Host type for the separate Toolbox window.
Toolbox.HostType.CUSTOM
: Host type for a custom frame host.
Methods
getCurrentPanel()
: Get the currently active {ref}ToolPanel <devtoolsapi-tool-panel>.
Return value:
The {ref}ToolPanel <devtoolsapi-tool-panel> object that was returned from ToolPanel.build().
getPanel(toolId)
: Get the {ref}ToolPanel <devtoolsapi-tool-panel> for given tool.
Parameters:
toolId {String}- The tool identifier.Return value:
The {ref}ToolPanel <devtoolsapi-tool-panel>object if the tool with the giventoolIdis active, otherwiseundefined.
getPanelWhenReady(toolId)
: Similar to getPanel() but waits for the tool to load first. If the tool is not already loaded or currently loading the returned Promise won't be fulfilled until something triggers the tool to load.
Parameters:
toolId {String}- The tool identifier.Return value:
A Promise that is fulfilled with the {ref}ToolPanel <devtoolsapi-tool-panel>object once the tool has finished loading.
getToolPanels()
: Returns a toolId → {ref}ToolPanel <devtoolsapi-tool-panel> Map for currently loaded tools.
getNotificationBox()
: Returns a XULElem("notificationbox") element for the Toolbox that can be used to display notifications to the user.
loadTool(toolId)
: Loads the tool with the given toolId in the background but does not activate it.
Parameters:
toolId {String}- The tool identifier.Return value:
A Promise that is fulfilled with the {ref}ToolPanel <devtoolsapi-tool-panel>object of the loaded panel once the tool has loaded.
selectTool(toolId)
: Selects the tool with the given toolId.
Parameters:
toolId {String}- The tool identifier.Return value:
A Promise that is fulfilled with the {ref}ToolPanel <devtoolsapi-tool-panel>object of the selected panel once the tool has loaded and activated.
selectNextTool()
: Selects the next tool in the Toolbox.
Return value:
A Promise that is fulfilled with the {ref}ToolPanel <devtoolsapi-tool-panel> object of the selected panel.
selectPreviousTool()
: Selects the previous tool in the Toolbox.
Return value:
A Promise that is fulfilled with the {ref}ToolPanel <devtoolsapi-tool-panel> object of the selected panel.
highlightTool(toolId)
: Highlights the tab for the given tool.
Parameters:
toolId {String}- The tool to highlight.
unhighlightTool(toolId)
: Unhighlights the tab for the given tool.
Parameters:
toolId {String}- The tool to unhighlight.
openSplitConsole()
: Opens the split Console to the bottom of the toolbox.
Return value:
A Promise that is fulfilled once the Console has loaded.
closeSplitConsole()
: Closes the split console.
toggleSplitConsole()
: Toggles the state of the split console.
Return value:
A Promise that is fulfilled once the operation has finished.
switchHost(hostType)
: Switches the location of the toolbox
Parameters:
hostType {Toolbox.HostType}- The type of the new host.Return value:
A Promise that is fulfilled once the new host is ready.
reloadTarget(force)
: Reloads the current target of the toolbox.
Parameters:
force {Boolean} -If true the target is shift-reloaded i.e. the cache is bypassed during the reload.
zoomIn()
: Increases the zoom level of the Toolbox document.
zoomOut()
: Decreases the zoom level of the Toolbox document.
zoomReset()
: Resets the zoom level of the Toolbox document.
setZoom(value)
: Set the zoom level to an arbitrary value.
Parameters:
value {Number}- The zoom level such as1.2.
destroy()
: Closes the toolbox.
Return value:
A Promise that is resolved once the Toolbox is destroyed.
Events
The Toolbox object emits following events via the {ref}EventEmitter <devtoolsapi-event-emitter> interface.
host-changed
: The Host for this Toolbox has changed.
ready
: The Toolbox is ready to use.
select(toolId)
: A tool has been selected. This event is emitted before the corresponding {toolId}-selected event.
{toolId}-init(frame)
: A tool is about to be loaded. The frame is the iframe element that has been created for the tool.
{toolId}-build(panel)
: The frame for a tool has loaded and the ToolPanel.build() method has been called but the asynchronous initialization has not started. The parameter is a {ref}ToolPanel <devtoolsapi-tool-panel> object.
{toolId}-ready(panel)
: The asynchronous initialization for a tool has completed and it is ready to be used. The parameter is a {ref}ToolPanel <devtoolsapi-tool-panel> object.
{toolId}-selected(panel)
: A tool has been selected. The parameter is a {ref}ToolPanel <devtoolsapi-tool-panel> object.
{toolId}-destroy(panel)
: A tool is about to be destroyed. The parameter is a {ref}ToolPanel <devtoolsapi-tool-panel> object.
destroy
: The Toolbox is about to be destroyed.
destroyed
: The Toolbox has been destroyed.
(devtoolsapi-tool-definition)=
ToolDefinition
A ToolDefinition object contains all the required information for a tool to be shown in the toolbox.
Methods
isToolSupported(toolbox)
: A method that is called during toolbox construction to check if the tool supports debugging the given target of the given toolbox.
Parameters:
toolbox {Toolbox}- The toolbox where the tool is going to be displayed, if supported.Return value:
A boolean indicating if the tool supports the given toolbox's target.
build(window, toolbox)
: A method that builds the {ref}ToolPanel <devtoolsapi-tool-panel> for this tool.
Parameters:
window {Window}- The Window object for frame the tool is being built into.toolbox {Toolbox}- The {ref}Toolbox <devtoolsapi-toolbox>the tool is being built for.Return value:
A {ref}ToolPanel <devtoolsapi-tool-panel>for the tool.
onKey(panel, toolbox)
: Optional. A method that is called when the keyboard shortcut for the tool is activated while the tool is the active tool.
Parameters:
panel {ToolPanel}- The {ref}ToolPanel <devtoolsapi-tool-panel>for the tool.toolbox {Toolbox}- The toolbox for the shortcut was triggered for.Return value:
Undefined.
Properties
The ToolDefinition object can contain following properties. Most of them are optional and can be used to customize the presence of the tool in the Browser and the Toolbox.
id
: String, required. An unique identifier for the tool. It must be a valid id for an HTML Element.
url
: String, required. An URL of the panel document.
label
: String, optional. The tool's name. If undefined the icon should be specified.
tooltip
: String, optional. The tooltip for the tool's tab.
panelLabel
: String, optional. An accessibility label for the panel.
ordinal
: Integer, optional. The position of the tool's tab within the toolbox. Default: 99
visibilityswitch
: String, optional. A preference name that controls the visibility of the tool. Default: devtools.{id}.enabled
icon
: String, optional. An URL for the icon to show in the toolbox tab. If undefined the label should be defined.
highlightedicon
: String, optional. An URL for an icon that is to be used when the tool is highlighted (see e.g. paused, inactive debugger). Default: {icon}
iconOnly
: Boolean, optional. If true, the label won't be shown in the tool's tab. Default: false
invertIconForLightTheme
: Boolean, optional. If true the colors of the icon will be inverted for the light theme. Default: false
key
: String, optional. The key used for keyboard shortcut. Either key or keycode value.
modifiers
: String, optional. modifiers for the keyboard shortcut.
preventClosingOnKey
: Boolean, optional. If true the tool won't close if its keybinding is pressed while it is active. Default: false
inMenu
: Boolean, optional. If true the tool will be shown in the Developer Menu. Default: false
menuLabel
: String, optional. A label for the Developer Menu item. Default: {label}
accesskey
: String, optional. accesskey for the Developer Menu xul:menuitem.
Example
Here's a minimal definition for a tool.
let def = {
id: "my-tool",
label: "My Tool",
icon: "chrome://browser/skin/devtools/tool-webconsole.svg",
url: "about:blank",
isToolSupported: toolbox => true,
build: (window, toolbox) => new MyToolPanel(window, toolbox)
};
// Register it.
gDevTools.registerTool(def);(devtoolsapi-target-type)=
TargetType
FIXME:
(devtoolsapi-host-type)=
HostType
FIXME
(devtoolsapi-tool-panel)=
ToolPanel
The ToolPanel is an interface the toolbox uses to manage the panel of a tool. The object that ToolDefinition.build() returns should implement the methods described below.
Methods
open()
: Optional. A method that can be used to perform asynchronous initialization. If the method returns a Promise, many operations (e.g. gDevTools.showToolbox() or toolbox.selectTool()) and events (e.g. toolbox-ready are delayed until the promise has been fulfilled.
Return value:
The method should return a Promise that is resolved with the ToolPanel object once it's ready to be used.
destroy()
: A method that is called when the toolbox is closed or the tool is unregistered. If the tool needs to perform asynchronous operations during destruction the method should return a Promise that is resolved once the process is complete.
Return value:
A Promise if the function performs asynchronous operations, otherwise undefined.
Example
Here's a basic template for a ToolPanel implementation.
// In the ToolDefinition object, do
// build: (window, target) => new MyPanel(window, target),
class MyPanel {
constructor(window, target) {
// The window object that has loaded the URL defined in the ToolDefinition
this.window = window;
// The Target this toolbox is debugging.
this.target = target;
// Do synchronous initialization here.
window.document.body.addEventListener("click", this.handleClick);
}
open() {
// Any asynchronous operations should be done here.
return this.doSomethingAsynchronous()
.then(() => this);
}
destroy() {
// Synchronous destruction.
this.window.document.body.removeEventListener("click", this.handleClick);
// Async destruction.
return this.destroySomethingAsynchronously()
.then(() => console.log("destroyed"));
}
handleClick: function(event) {
console.log("Clicked", event.originalTarget);
}
}(devtoolsapi-event-emitter)=
EventEmitter
EventEmitter is an interface many Developer Tool classes and objects implement and use to notify others about changes in their internal state.
When an event is emitted on the EventEmitter, the listeners will be called with the event name as the first argument and the extra arguments are spread as the remaining parameters.
:::{note}
Some components use Add-on SDK event module instead of the DevTools EventEmitter. Unfortunately, their API's are a bit different and it's not always evident which one a certain component is using. The main differences between the two modules are that the first parameter for Add-on SDK events is the first payload argument instead of the event name and the once method does not return a Promise. The work for unifying the event paradigms is ongoing in bug 952653.
:::
Methods
The following methods are available on objects that have been decorated with the EventEmitter interface.
emit(eventName, ...extraArguments)
: Emits an event with the given name to this object.
Parameters:
eventName {String}- The name of the event.extraArguments {...Any}- Extra arguments that are passed to the listeners.
on(eventName, listener)
: Adds a listener for the given event.
off(eventName, listener)
: Removes the previously added listener from the event.
once(eventName, listener)
: Adds a listener for the event that is removed after it has been emitted once.
Return value:
A Promise that is fulfilled with the first extra argument for the event when then event is emitted. If the event contains multiple payload arguments, the rest are discarded and can only be received by providing the listener function to this method.
Examples
Here's a few examples using the gDevTools object.
let onInit = (eventName, toolbox, netmonitor) => console.log("Netmonitor initialized!");
// Attach a listener.
gDevTools.on("netmonitor-init", onInit);
// Remove a listener.
gDevTools.off("netmonitor-init", onInit);
// Attach a one time listener.
gDevTools.once("netmonitor-init", (eventName, toolbox, netmonitor) => {
console.log("Network Monitor initialized once!", toolbox, netmonitor);
});
// Use the Promise returned by the once method.
gDevTools.once("netmonitor-init").then(toolbox => {
// Note that the second argument is not available here.
console.log("Network Monitor initialized to toolbox", toolbox);
});ToolSidebar
To build a sidebar in your tool, first, add a xul:tabbox where you want the sidebar to live:
<splitter class="devtools-side-splitter"/>
<tabbox id="mytool-sidebar" class="devtools-sidebar-tabs" hidden="true">
<tabs/>
<tabpanels flex="1"/>
</tabbox>A sidebar is composed of tabs. Each tab will hold an iframe. For example, in the Inspector, there are 3 tabs (Computed View, Rule View, Layout View). The user can select the tab they want to see.
If the availability of the tabs depends on some tool-related conditions, we might want to not let the user select a tab. This API provides methods to hide the tabstripe. For example, in the Web Console, there are 2 views (Network View and Object View). These views are only available in certain conditions controlled by the WebConsole code. So it's up the WebConsole the hide and show the sidebar, and select the correct tab.
If the loaded document exposes a window.setPanel(ToolPanel) function, the sidebar will call it once the document is loaded.
.. list-table:: Methods
:widths: 70 30
:header-rows: 1
* - Method
- Description
* - ``new ToolSidebar(xul:tabbox, ToolPanel, showTabstripe=true)``
- ToolSidebar constructor
* - ``void addTab(tabId, url, selected=false)``
- Add a tab in the sidebar
* - ``void select(tabId)``
- Select a tab
* - ``void hide()``
- Hide the sidebar
* - ``void show()``
- Show the sidebar
* - ``void toggle()``
- Toggle the sidebar
* - ``void getWindowForTab(tabId)``
- Get the iframe containing the tab content
* - ``tabId getCurrentTabID()``
- Return the id of tabId of the current tab
* - ``tabbox getTab(tabId)``
- Return a tab given its id
* - ``destroy()``
- Destroy the ToolSidebar object.. list-table:: Events
:widths: 70 30
:header-rows: 1
* - Events
- Description
* - ``new-tab-registered``
- A new tab has been added
* - ``{tabId}-ready``
- Tab is loaded and can be used
* - ``{tabId}-selected``
- Tab has been selected and is visible
* - ``show``
- The sidebar has been opened.
* - ``hide``
- The sidebar has been closed.Examples
Register a tool
gDevTools.registerTool({
// FIXME: missing key related properties.
id: "inspector",
icon: "chrome://browser/skin/devtools/inspector-icon.png",
url: "chrome://browser/content/devtools/inspector/inspector.xul",
get label() {
let strings = Services.strings.createBundle("chrome://browser/locale/devtools/inspector.properties");
return strings.GetStringFromName("inspector.label");
},
isToolSupported: function(toolbox) {
return toolbox.commands.descriptorFront.isLocalTab;
},
build: function(iframeWindow, toolbox, node) {
return new InspectorPanel(iframeWindow, toolbox, node);
}
});Open a tool, or select it if the toolbox is already open:
let target = TargetFactory.forTab(gBrowser.selectedTab);
let toolbox = gDevTools.openToolbox(target, null, "inspector");
toolbox.once("inspector-ready", function(event, panel) {
let inspector = toolbox.getToolPanels().get("inspector");
inspector.selection.setNode(target, "browser-context-menu");
});Add a sidebar to an existing tool:
let sidebar = new ToolSidebar(xulTabbox, toolPanel);
sidebar.addTab("tab1", "chrome://browser/content/.../tab1.xhtml", true);
sidebar.addTab("tab2", "chrome://browser/content/.../tab2.xhtml", false);
sidebar.show();Devtools Docs User Devtoolscolors Index (`devtools/docs/user/devtoolscolors/index.md`)
myst:
substitutions:
br: |-
{raw} html <br/><br/>
DevToolsColors
:::{warning}
Firefox developers: Don't change any of these values without UX approval. If any of these values need to be changed, you will need to change some CSS code in /browser/themes/*/devtools/. File a DevTools bug accordingly.
:::
This chart lists colors and CSS variables as implemented in the dark theme and light theme for developer tools.
/* Detailed source-code truncated for AI context efficiency. */:::{warning}
Not yet finalized. See bug 916766 for progress.
:::
Devtools Docs User Dom Property Viewer Index (`devtools/docs/user/dom_property_viewer/index.md`)
DOM Property Viewer
:::{container} block_quote
The DOM Property Viewer is disabled by default. Enable it in the {ref}Developer Tools Settings <tool-toolbox-settings>
:::
The DOM Property Viewer lets you inspect the properties of the DOM as an expandable tree structure, starting from the window object of the current page or the {doc}selected iframe <../working_with_iframes/index>.
:class: centerEnabling the DOM Property Viewer
The DOM Property Viewer is not enabled by default. To enable it, open the {ref}developer tools settings <tool-toolbox-settings> and check the "DOM" box under "Default Firefox Developer Tools".
Opening the DOM Property Viewer
Once enabled, you can select the DOM panel in the Web Developer Tools, accessible from the Browser Tools submenu
The {doc}Toolbox <../tools_toolbox/index> will appear at the bottom of the browser window, with the DOM Property Viewer activated. It's just called "DOM" in the Toolbox.
DOM Property Viewer user interface
DOM tree
The different properties of the DOM are displayed as an expandable tree. The left-hand side shows the property's name, and the right-hand side shows its value. Up to three properties of an object and items of an array are displayed. If a property has more elements than this, you'll see a "more..." annotation, and will need to click the property to see all elements. A lock icon indicates that a property is not writable.
Refreshing the display
If the DOM changes you can hit the Refresh button to update the display:
:alt: Button to update the DOM Inspector display
:class: centerFiltering
There is a search box within the toolbar:
:class: centerThis filters the list to show only items which match the search term. Items match the search term if their name contains the search term. Matching is case-sensitive.
--- METRICS ---
- Files Extracted: 98
- Estimated Token Budget: ~120887 tokens
- Canonical Reference: https://codewiki.google/github.com/mozilla-firefox/firefox