Firefox code memo
- General
- base points
- flow
- caveats / glossary
- Rendering
- base points
- flow
- basic flow
- frame lifecycle in Gecko
- code patterns
- Variant Matching
- caveats / glossary
- Servo
- base points
- flow
- Who parses and styles?
- caveats / glossary
- APZ
- base points
- flow
- Rendering flow
- How are scrolls happened on the APZ side reflected on the content process?
- caveats / glossary
- IPDL
- base points
- flow
- caveats / glossary
I leave findings about the Firefox code here for future reference.
General
base points
-
nsGlobalWindowInner, nsGlobalWindowOuter
- Each represents the Window and WindowProxy.
- https://searchfox.org/firefox-main/rev/5aef16c9b58b3e5791f849bdabbf9affb4a96844/dom/base/nsGlobalWindowOuter.h#139
- ref: https://wiki.mozilla.org/Gecko:Overview#Docshell
-
nsIWebNavigation.idl
- The IDL file containing navigation APIs.
- https://searchfox.org/firefox-main/rev/5aef16c9b58b3e5791f849bdabbf9affb4a96844/docshell/base/nsIWebNavigation.idl
-
function GS_handleEvent()
- Chrome code handling swipe gesture.
- https://searchfox.org/firefox-main/rev/5aef16c9b58b3e5791f849bdabbf9affb4a96844/browser/base/content/browser-gestureSupport.js#61
flow
caveats / glossary
-
There are several processes other than the parent, the content, and the GPU.
- You can check them using about:processes.
-
IPDL can define message priority.
Rendering
base points
-
nsIFrame::Reflow()
- Reflow is a recursive process. Reflow roots call their Reflow().
- https://searchfox.org/firefox-main/rev/7f451c7918ffe36840b0ef31dfc2272ded671f81/layout/generic/nsIFrame.h#3204
- https://firefox-source-docs.mozilla.org/layout/LayoutOverview.html
-
NS_FRAME_REFLOW_ROOT
- The constant with which a frame can be the root for reflow.
- "Reflow roots must obey the invariant that a change inside one of their descendants never changes their rect or overflow areas".
- https://firefox-source-docs.mozilla.org/layout/LayoutOverview.html#where-does-reflow-start-how-do-we-avoid-reflowing-the-world-every-time
- https://firefox-source-docs.mozilla.org/layout/LayoutOverview.html
-
nsPresContext::UpdateContainerQueryStylesAndAnchorPosLayout()
- Triggers restyle of subtrees of query containers and also resolves anchor pos.
- https://searchfox.org/firefox-main/rev/45135a4adb3c83c65c090e9c613775a5e193aba5/layout/base/nsPresContext.cpp#1048
-
layers.gpu-process.enabled
-
The pref enabling a gpu process.
flow
basic flow
- Parse
- Style (Servo)
- selector matching
- cascade
- Layout
- Frame Construction
- Frame represents a rectangle, "the outside edge of the border (or the inside edge of the margin)".
- Frame is constructed considering its style. E.g. An element with display:none has NO frame.
- Reflow
- "the process of computing the positions and sizes of frames".
- Restyle is triggered under some conditions. (e.g. size container query)
- Display List Construction
- DL = "exactly what to render where, what goes on top of what (layering and blending) and at what pixel coordinate".
- This is used for hit test! (See APZ base points below.)
- WebRenderer Display List Construction
- DL is converted into the form for WR.
- Rendering by WebRender
- Scene Construction
- Scene has more than simply visible elements. WR receives "Web Render Display list" and "Web Render Scroll Data" (and perhaps additional something), then creates Scene.
- Frame Construction
- Frame is roughly what Scene is culled.
- Frame is what is rendered by GPU.
- This "Frame" is different from the "Frame" in Gecko.
reference
- https://hacks.mozilla.org/2017/08/inside-a-super-fast-css-engine-quantum-css-aka-stylo/
- https://firefox-source-docs.mozilla.org/layout/LayoutOverview.html
- https://firefox-source-docs.mozilla.org/gfx/RenderingOverview.html
frame lifecycle in Gecko
- created by nsCSSFrameConstructor.
- destroyed via nsIFrame::Destroy().
reference
code patterns
Variant Matching
auto requests = std::move(mPendingRequestQueue);
[...]
while (!requests.empty()) {
struct RequestProcessor {
GeckoContentController* mController;
void operator()(const RepaintRequest& aRequest) {
mController->RequestContentRepaint(aRequest);
}
void operator()(const APZStateChangeRequest& aRequest) {
mController->NotifyAPZStateChange(aRequest.mGuid, aRequest.mChange,
aRequest.mArg,
aRequest.mInputBlockId);
}
};
requests.front().match(RequestProcessor{controller.get()});
requests.pop_front();
}
caveats / glossary
-
"Primary Frame" and "Continuous Frame"
- A page break, a line break, and so on trigger "fragmentation".
- The first frame of fragmented frames is called "primary frame".
- The following frames are called "continuous frame".
- There are two types of "continuous frame": "fixed" and "fluid".
- "fluid": created for the sake of reflow. (e.g. line break)
- "fixed": created for inevitable fragmentation. (e.g. bidi)
- https://firefox-source-docs.mozilla.org/layout/LayoutOverview.html#layout-fragmentation
-
"frame budget"
- time duration between frame generations. E.g. 16.7ms under 60fps.
-
"RenderBackend"
- In Firefox, it is WebRenderer.
- https://hacks.mozilla.org/2017/10/the-whole-web-at-maximum-fps-how-webrender-gets-rid-of-jank/#:~:text=RenderBackend
-
Unlike other browsers (maybe), WebRenderer don't distinguish paint and composite.
-
For WR's frame generation, this seems a good reference: https://hacks.mozilla.org/2017/10/the-whole-web-at-maximum-fps-how-webrender-gets-rid-of-jank/#:~:text=How WebRender works with the GPU
Servo
base points
-
Stylesheet::parse_rules()
- The entry point of CSS style sheet parse.
- https://searchfox.org/firefox-main/rev/45135a4adb3c83c65c090e9c613775a5e193aba5/servo/components/style/stylesheets/stylesheet.rs#420
-
servo/components/style/properties/shorthands.toml, servo/components/style/properties/longhands.toml
- Registers CSS properties for Servo to parse them.
- These files are used for generating ServoCSSPropList.h, ServoStyleConsts.h for Gecko.
-
AtRulePrelude
- The list of preludes of "at rule". (e.g. @container)
- https://searchfox.org/firefox-main/rev/45135a4adb3c83c65c090e9c613775a5e193aba5/servo/components/style/stylesheets/rule_parser.rs#250
-
AtRuleParser::parse_block()
- Parses "at rule"'s block.
- You can find various parts compositing "at rules" here, e.g. ContainerConditions.
- parse_prelude() -> parse_block().
- https://searchfox.org/firefox-main/source/servo/components/style/stylesheets/rule_parser.rs#822
-
TElement::query_container_size()
- Servo queries container's size to Gecko for fixing the style using container query.
- https://searchfox.org/firefox-main/rev/45135a4adb3c83c65c090e9c613775a5e193aba5/servo/components/style/gecko/wrapper.rs#1113
flow
Who parses and styles?
- cssparser parses CSS.
- stylist does styling such as selector matching, cascade, and so on.
caveats / glossary
APZ
base points
-
scrollWheel:(NSEvent*)theEvent()
- A native scroll event comes from here.
- https://searchfox.org/firefox-main/rev/fdd583cd5a10d051053acda8b760c3bd5d800034/widget/cocoa/nsCocoaWindow.mm#2699
-
nsIWidget::MayStartSwipeForAPZ()
- After APZ processes an event, this determines swipe-to-navigation should be triggered.
- https://searchfox.org/firefox-main/rev/fdd583cd5a10d051053acda8b760c3bd5d800034/widget/nsIWidget.cpp#2337
-
nsRefreshDriver::Tick()
- nsRefreshDriver is initialized in nsPresContext::Init().
- A document tree in one process may have one nsRefreshDriver, i.e. the top document and the same site iframes share one nsRefreshDriver.
- This is synced with vsync and triggers "updating the rendering".
- At the beginning, APZ scrolls are synced.
- https://searchfox.org/firefox-main/rev/fdd583cd5a10d051053acda8b760c3bd5d800034/layout/base/nsRefreshDriver.cpp#2278
- nsRefreshDriver is initialized in nsPresContext::Init().
-
RemoteContentController::RequestContentRepaint()
- This syncs a scroll happened in APZ with the relevant content process.
- https://searchfox.org/firefox-main/rev/fdd583cd5a10d051053acda8b760c3bd5d800034/gfx/layers/ipc/RemoteContentController.cpp#54
-
ScrollContainerFrame::mApzScrollPos
- The latest scroll position we've sent or received from APZ.
- https://searchfox.org/firefox-main/rev/b333f4353e8b4908bf3375e110f293aae894295a/layout/generic/ScrollContainerFrame.h#1466
-
nsDisplayList::HitTest()
- Gecko uses a display list for hit testing. This is the entry point for hit test on the Gecko side.
- https://searchfox.org/firefox-main/rev/45135a4adb3c83c65c090e9c613775a5e193aba5/layout/painting/nsDisplayList.cpp#2402
-
AsyncPanZoomController.cpp
- There is an exhaustive list of APZ-related prefs.
- https://searchfox.org/firefox-main/rev/b0bc20aac45f7cb55b18adbf4d2313457659d140/gfx/layers/apz/src/AsyncPanZoomController.cpp#140
flow
Rendering flow
See above.
How are scrolls happened on the APZ side reflected on the content process?
- APZ controller on the compositor thread calls RemoteContentController::RequestContentRepaint().
- Via IPC, that makes APZ child on the main thread put an early runner.
- The early runner is processed at the beginning of nsRefreshDriver::Tick(), which is almost equivalent to "update the rendering".
- The early runner eventually calls ScrollContainerFrame::ScrollToImpl() and it sets the received APZ scroll info to ScrollContainerFrame::mApzScrollPos.
caveats / glossary
-
"Layer Tree" is a legacy module, which was the final output on the side of content process.
- Nowadays, the final output of a content process is WebRender Display List.
-
"ASR" means "Active Scrolled Root". An element's ASR is, roughly speaking, its scroll container.
- This can be defined arbitrary if you want. For instance, the implementation of CSS anchor positioning takes advantage of it.
IPDL
base points
flow
caveats / glossary
-
Actors are basically refcounted unless legacy ManualDealloc is used.
-
An actor is bound to a perticular thread.