# Engine Source & Modifications (MPL-2.0 compliance) *cavekit-licensing-branding R3 / R4 — engine origin, patches, and branding strip. Brought up to date 2026-10-08 (it had listed four patches under old names).* Jihad Browser renders with the **UXP / Goanna** web engine (MPL-2.0). This document records the engine's origin and every modification made to it, so the MPL-2.0 obligation to keep modified files under the MPL with their source available is met. ## Origin - **Upstream:** UXP — https://repo.palemoon.org/MoonchildProductions/UXP, pristine at the release `RB_20261027` (`6b18be917d462369593bfe611230a7003fd7d945`, 2026-10-26) — `UXP_TAG` / `UXP_BASE` in `build/engine/engine-version.env`. (Until 2026-11-03: `RB_20261006`, `5f290d1`, 2026-10-04; until 2026-10-12: master `b2594a4`, 2026-06-30.) - **Our modified engine:** the branch `jihad/uxp-RB_20261027` of the fork `NotAlexNoyle/UXP-Jihad`, at `UXP_PIN` (`52ad9ab66ebbc1c28133a330ee2f35819565d61e`), present in this repository as the submodule `third_party/uxp`. The device build compiles that tree. - **The modifications as patches:** `build/desktop/patches/` holds every change as a patch against `UXP_BASE`. `build/engine/patch-queue.sh --check` proves the patches, applied in order, produce exactly the `UXP_PIN` tree. How the two are kept in step: `docs/ENGINE.md` §2. ## Modifications to the engine (all MPL-2.0, source here) Every modified UXP file stays under the MPL-2.0. These patches are the source of the modifications; the same changes are the commits of `jihad/uxp-RB_20261027`, one per patch. | Patch | Files | What it changes | |-------|-------|-----------------| | `0001-js-format-overflow.patch` | `js/src/jit/x64/BaseAssembler-x64.h` | GCC 9: source pragma for -Wformat-overflow (js/src re-escalates it) | | `0002-configure-warnings.patch` | `build/moz.configure/warnings.configure` | GCC 9: warnings.configure adjustment | | `0003-gfx-init-and-omtc.patch` | `gfx/thebes/gfxPlatform.cpp`, `gfx/thebes/gfxPlatformGtk.cpp`, `toolkit/xre/nsEmbedFunctions.cpp` | JIHAD_DISABLE_OMTC forces the in-process BasicLayerManager; gfx started inside XRE_InitEmbedding2 | | `0004-gtk-headless-guards.patch` | `widget/gtk/gtk2drawing.c`, `widget/gtk/nsLookAndFeel.cpp`, `widget/gtk/nsNativeThemeGTK.cpp` | GTK realize/theme/look-and-feel paths guarded so libxul runs with no X server | | `0005-puppetwidget-offscreen-zoom.patch` | `widget/PuppetWidget.cpp`, `widget/PuppetWidget.h` | PuppetWidget offscreen render, zoom and damage tracking; the jihad_offscreen_* exports | | `0006-headless-toolkit.patch` | `embedding/components/printingui/moz.build`, `gfx/2d/2D.h`, `gfx/2d/Factory.cpp` (+19 more) | MOZ_WIDGET_TOOLKIT=headless: gfxPlatformHeadless, widget/headless, build wiring | | `0007-nss-mainthread-marshal.patch` | `security/manager/ssl/nsNSSComponent.cpp` | NSS EnsureNSSInitialized main-thread fast path; the jihad_init_nss export | | `0008-plugin-headless-nativehandle.patch` | `dom/plugins/ipc/PluginInstanceChild.cpp`, `dom/plugins/ipc/PluginInstanceParent.cpp`, `dom/plugins/ipc/PluginMessageUtils.h` | NativeWindowHandle for the headless platform so plugin IPC compiles | | `0009-misc-headless.patch` | `ipc/chromium/src/base/message_loop.cc`, `toolkit/xre/nsXREDirProvider.cpp` | Headless build fixes (message loop, XRE directory provider) | | `0010-branding-strip.patch` | `docshell/base/nsAboutRedirector.cpp`, `modules/libpref/init/all.js`, `toolkit/xre/nsAppRunner.cpp` | Pale Moon / Basilisk / Moonchild branding stripped (cavekit-licensing-branding R3) | | `0011-appcompat-guid.patch` | `xulrunner/configure.in`, `xulrunner/confvars.sh` | The AppCompat GUID (xulrunner configure) | | `0012-popup-instrumentation.patch` | `layout/xul/nsXULPopupManager.cpp` | XUL popup instrumentation and offscreen compositing of popups | | `0013-xpi-install-embedding.patch` | `toolkit/mozapps/extensions/AddonManager.jsm`, `toolkit/mozapps/extensions/amInstallTrigger.js` | AddonManager / amInstallTrigger work without a browser element | | `0014-badcertlistener-embedding.patch` | `docshell/base/nsDocShell.cpp`, `embedding/browser/nsDocShellTreeOwner.cpp` | Certificate errors reach the embedder (bad-cert listener) | | `0015-find-embedder-no-jscontext.patch` | `embedding/components/find/nsWebBrowserFind.cpp` | Find-in-page without a JS context | | `0016-npapi-windowless-headless.patch` | `dom/plugins/base/nsNPAPIPlugin.cpp` | NPAPI windowless plugins under the headless toolkit | | `0017-npapi-webos-palm-host.patch` | `dom/plugins/ipc/JihadNPNInterpose.cpp`, `dom/plugins/ipc/PluginInstanceChild.cpp`, `dom/plugins/ipc/PluginInstanceChild.h` (+2 more) | The webOS (Palm) NPAPI host: NPEvent union, JihadNPNInterpose | | `0018-npapi-child-process-loader.patch` | `ipc/glue/GeckoChildProcessHost.cpp` | The plugin child process launched through our loader | | `0019-bhm-null-manager-guard.patch` | `xpcom/threads/BackgroundHangMonitor.cpp` | BackgroundHangMonitor null-manager guard | | `0020-npapi-composite-without-imagebridge.patch` | `dom/plugins/ipc/PluginInstanceParent.cpp` | Plugin compositing without ImageBridge | | `0021-npapi-windowless-invalidate-offscreen.patch` | `dom/plugins/base/nsPluginInstanceOwner.cpp` | Windowless plugin invalidation into the offscreen widget | | `0022-npapi-recvshow-copy-frameid.patch` | `dom/plugins/ipc/PluginInstanceParent.cpp` | Plugin RecvShow copies the frame id | | `0023-npapi-operational-logging.patch` | `dom/base/nsObjectLoadingContent.cpp`, `dom/plugins/base/nsNPAPIPlugin.cpp`, `dom/plugins/base/nsPluginHost.cpp` (+5 more) | Plugin operational logging | | `0024-npapi-webos-plugin-input.patch` | `dom/plugins/base/npapi.h`, `dom/plugins/base/nsPluginHost.cpp`, `dom/plugins/base/nsPluginHost.h` (+6 more) | webOS plugin input, the frozen plugin YAP commands, the frame path | | `0025-npapi-pmlog-named-semaphore-abi.patch` | `ipc/app/moz.build`, `ipc/contentproc/JihadPmLogSem.c`, `ipc/contentproc/moz.build` (+1 more) | PmLog named-semaphore ABI shim for the plugin container | | `0026-npapi-plugin-repaint-rate.patch` | `dom/plugins/ipc/PluginInstanceChild.cpp` | Plugin child repaint rate (frame clock) | | `0027-npapi-plugin-cpu-boost.patch` | `dom/plugins/ipc/PluginModuleParent.cpp` | CPU boost while a plugin plays | | `0028-npapi-plugin-frame-seq.patch` | `dom/plugins/ipc/PluginInstanceParent.cpp` | Plugin frame counter export (jihad_plugin_frame_seq) | | `0029-npapi-plugin-pull-frame.patch` | `dom/plugins/ipc/PPluginInstance.ipdl`, `dom/plugins/ipc/PluginInstanceChild.cpp`, `dom/plugins/ipc/PluginInstanceChild.h` (+1 more) | Plugin frames pulled from the daemon's clock (JihadRequestFrame IPDL) | | `0030-cubeb-pulse-webos-virtual-sink.patch` | `media/libcubeb/src/cubeb_pulse.c` | cubeb Pulse: the webOS virtual sink (JIHAD_PULSE_SINK) | | `0031-npapi-JIHAD_PLUGIN_SELF_DRIVE-0-turns-the-plugin-chi.patch` | `dom/plugins/ipc/PluginInstanceChild.cpp` | JIHAD_PLUGIN_SELF_DRIVE=0 turns the plugin child's own repaint timer off | | `0032-videocontrols-fix-scrubber-flicker-settle-interpolat.patch` | `toolkit/content/widgets/videocontrols.xml` | Video controls: scrubber flicker and settle, interpolated thumb | | `0033-videocontrols-surface-media-errors-for-audio-only-co.patch` | `toolkit/content/widgets/videocontrols.xml` | Video controls: media errors shown for audio-only content | | `0034-cubeb-classify-media-streams-export-a-playing-stream.patch` | `media/libcubeb/src/cubeb_pulse.c` | cubeb: media.role classification; jihad_pulse_active_streams export | | `0035-gfx-BasicPlanarYCbCrImage-CopyData-must-not-report-f.patch` | `gfx/layers/basic/BasicImages.cpp` | gfx: BasicPlanarYCbCrImage::CopyData no longer reports failure under delayed conversion | | `0036-extensions-a-link-or-navigation-to-an-.xpi-must-reac.patch` | `toolkit/mozapps/extensions/amContentHandler.js` | A link or navigation to an .xpi reaches the install flow without a browser window | | `0037-plugins-an-instance-with-no-window-to-be-given-is-wi.patch` | `dom/plugins/base/nsPluginInstanceOwner.cpp` | A plugin instance with no window is windowless instead of a null dereference | | `0038-plugin-container-do-not-hand-the-bundled-library-pat.patch` | `ipc/contentproc/plugin-container.cpp` | plugin-container does not hand the bundled library path to what the plugin runs | | `0039-addons-an-add-on-naming-both-the-AppCompat-GUID-and-.patch` | `toolkit/mozapps/extensions/internal/XPIProvider.jsm` | XPIProvider: an add-on naming the AppCompat GUID and the toolkit matches the entry that fits | | `0040-gpu-compositor-an-in-process-OpenGL-compositor-behin.patch` | `gfx/layers/client/ClientPaintedLayer.cpp`, `gfx/layers/composite/LayerManagerComposite.{h,cpp}`, `gfx/layers/ipc/CompositorBridgeParent.{h,cpp}`, `gfx/layers/opengl/CompositingRenderTargetOGL.{h,cpp}`, `gfx/layers/opengl/CompositorOGL.{h,cpp}`, `gfx/layers/opengl/TextureHostOGL.cpp`, `gfx/thebes/gfxPlatform.cpp`, `gfx/thebes/gfxPlatformHeadless.{h,cpp}`, `gfx/thebes/gfxPrefs.h`, `modules/libpref/init/all.js`, `widget/PuppetWidget.{h,cpp}` | T-502: with `JIHAD_GPU_COMPOSITOR` set, an in-process OpenGL compositor (an EGL pbuffer, two renderbuffer window targets) behind the offscreen widget, pulled a frame at a time by the daemon (`jihad_offscreen_compose_start/_poll/_forget`, `jihad_offscreen_compositor_seq`, `jihad_offscreen_set_view`); the layer tree's own diff drives band readbacks and scissored partial composites; the window's flipped view kept and the rows reversed in the read; tiled content layers on by default (`layers.enable-tiles`); the read thread, the GPU swizzle pass and the snapshot road are opt-in (`docs/RENDERING-OPTIONS.md`); nothing changes without the env | | `0041-gl-the-Adreno-220-whole-texture-uploads-BGRA-uploads.patch` | `gfx/gl/GLContext.{h,cpp}`, `gfx/gl/GLContextEGL.h`, `gfx/gl/GLContextProviderEGL.cpp`, `gfx/gl/GLTextureImage.{h,cpp}`, `gfx/gl/GLUploadHelpers.cpp` | `GLRenderer::AdrenoTM220`; `CanUploadSubTextures()` false for the Adreno 2xx "(TM)" spellings and the 220 (a sub-image update costs 16x a whole upload); an EGL context prefers BGRA uploads where `GL_EXT_texture_format_BGRA8888` exists, with GLES-legal types (4x faster than RGBA when the GPU is idle); `GLContextEGL::JihadCreateSharedContext` (a 1x1 pbuffer context sharing the compositor's objects, for a readback thread); fresh texture names per upload opt-in (`JIHAD_GPU_FRESH_TEX=1`) | | `0042-gpu-compositor-the-card-s-scroll-applied-in-the-comp.patch` | `gfx/gl/GLContext.h`, `gfx/gl/GLContextEGL.h`, `gfx/gl/GLContextProviderEGL.cpp`, `gfx/layers/LayerTreeInvalidation.{h,cpp}`, `gfx/layers/Layers.cpp`, `gfx/layers/composite/AsyncCompositionManager.{h,cpp}`, `gfx/layers/composite/LayerManagerComposite.{h,cpp}`, `gfx/layers/ipc/CompositorBridgeParent.{h,cpp}`, `gfx/layers/opengl/CompositorOGL.{h,cpp}`, `layout/base/FrameLayerBuilder.cpp`, `layout/base/nsDisplayList.cpp`, `layout/base/nsLayoutUtils.cpp`, `layout/generic/nsGfxScrollFrame.cpp`, `widget/PuppetWidget.{h,cpp}` | T-502: the card's scroll applied by the composition manager as APZ would (root scroll metadata and the scrollport as a scroll clip for a root scroll frame with a displayport, the displayport set from layout, no intermediate surface for a scaled container); the context's pbuffer at the frame's size (the Adreno 220 bins an FBO render by the surface's size); scroll-only frames composed band by band on their own 768x256 pbuffer and FBO with the row shift behind the GPU; a done-fd that wakes the daemon when a job finishes; the diff treats the root-content layer's scroll as a shift and is scaled to frame pixels | | `0043-npapi-the-Palm-event-paths-only-where-npapi.h-define.patch` | `dom/plugins/ipc/PluginInstanceChild.cpp`, `dom/plugins/base/nsPluginHost.cpp` | T-387: the Palm gain-focus system event and the spotlight export built only where npapi.h defines Palm's NPEvent (the headless toolkit the device builds), so the desktop GTK engine builds again for the desktop tests; the desktop spotlight export returns 0 | | `0044-gpu-compositor-tile-textures-converted-at-1x1-and-ke.patch` | `gfx/gl/GLTextureImage.{h,cpp}`, `gfx/layers/opengl/CompositorOGL.cpp` | T-504: on the GPU path a new tile texture is converted while it is 1x1 (a framebuffer clear and a 1x1 write) and a texture image's texture goes to a pool instead of being deleted: the Adreno 220 converts a texture's storage on its first write after its first draw (~18 ms a 256x256 tile, measured in `tools/device/gpu-bench.c` sections 12-15), which every new tile paid on its first change | | `0045-gpu-compositor-no-edge-antialiasing-for-an-axis-alig.patch` | `gfx/layers/opengl/CompositorOGL.cpp`, `gfx/layers/ipc/CompositorBridgeParent.cpp` | T-504: on the GPU path an axis-aligned scale gets no edge antialiasing (its shader variants compiled on first use, ~150 ms each, in the first frame of a zoom); `JIHAD_GPU_PHASES` also logs each slow composite's phases and each slow draw | | `0046-gpu-compositor-the-root-scroll-frame-s-clip-widened-.patch` | `layout/base/nsLayoutUtils.{h,cpp}`, `layout/generic/nsGfxScrollFrame.cpp` | T-505: `jihad_layout_set_overscan` widens the root scroll frame's clip on the GPU path by the rows the daemon's frame carries above and below what the card shows (overscan), so the card has content to pan into between frames | | `0047-gpu-compositor-a-given-up-frame-writes-nothing-test-.patch` | `gfx/layers/ipc/CompositorBridgeParent.cpp`, `gfx/layers/opengl/CompositorOGL.{h,cpp}`, `widget/PuppetWidget.cpp` | T-509: a compose job the daemon forgot writes nothing into its slot (`cancelled`); test switches `JIHAD_GPU_TEST_NO_EGL` (no GL context, as an EGL failure) and `JIHAD_GPU_TEST_STALL` (a job held 6 s) | | `0048-gpu-compositor-the-frame-s-paint-and-its-compose-pos.patch` | `widget/PuppetWidget.{h,cpp}` | T-515: the frame's layer paint (`jihad_offscreen_paint_layers`, the main thread) and its compose job (`jihad_offscreen_compose_post`, any thread, at a view and scroll it is given) apart, so the daemon's express lane composes and publishes frames while the main thread runs the page's script; the job list under a mutex (a poll without a wait holds it throughout); `jihad_offscreen_compose_peek` (a job's state without its result); a forgotten job's cancelled flag only with abandoned | | `0049-layers-a-composite-acknowledged-after-the-widget-is-.patch` | `gfx/layers/client/ClientLayerManager.cpp` | T-515: `DidComposite` returns when the widget is gone (a card closed while a compose job it had asked for was waited out; its acknowledgement reached the main thread after the page was torn down: SIGSEGV at 0) | | `0050-gpu-compositor-every-compose-job-compose-and-read-on.patch` | `widget/PuppetWidget.cpp`, `gfx/layers/ipc/CompositorBridgeParent.cpp`, `gfx/layers/opengl/CompositorOGL.cpp` | T-516: with `JIHAD_GPU_TIMELINE=1` every compose job, compose and read logged with a timestamp on the daemon's clock (otherwise sampled), so a slow frame's time can be placed | | `0051-webgl-contexts-on-the-device-s-GPU-on-the-GPU-path-s.patch` | `dom/canvas/WebGLContext.cpp`, `dom/canvas/WebGLContextValidate.cpp`, `widget/headless/GfxInfo.cpp`, `gfx/gl/GLContextEGL.h`, `gfx/gl/GLContextProviderEGL.cpp`, `gfx/gl/SharedSurface.cpp`, `gfx/layers/client/ClientCanvasLayer.cpp` | T-511: WebGL on the GPU path asks EGL for its context (the headless default provider is null) and is not blocklisted there (headless GfxInfo); the Adreno 220's `GL_INVALID_ENUM` for `GL_STENCIL_BACK_WRITEMASK` queried in its own error scope; every pbuffer context on the GPU path in one share group under a 1x1 root, a WebGL canvas handing the compositor its texture (`SurfaceFactory_GLTexture`, zero copy; `JIHAD_GPU_NO_SHARE=1`: unshared, read back through a canvas-sized pbuffer); a context released from its thread before it is destroyed (the next teardown faulted in libGLESv2) | | `0055-gpu-compositor-a-band-frame-s-regions-composed-in-on.patch` | `gfx/layers/composite/LayerManagerComposite.{h,cpp}`, `gfx/layers/ipc/CompositorBridgeParent.cpp` | T-517: a band frame's bands and column chunks composed as regions of one composite (`JihadSetRegions`: the transaction and BeginFrame/EndFrame once, per region its world, `Prepare` and `RenderLayer`); `JIHAD_GPU_PASS_PER_REGION=1` as before | | `0056-layers-a-tile-wholly-outside-the-clip-is-not-locked-.patch` | `gfx/layers/composite/TiledContentHost.cpp` | T-517: a tile whose transformed bounds miss the clip (in the render target's coordinates) is skipped before its texture is locked and bound; `JIHAD_GPU_NO_TILE_CULL=1` for A/B | | `0057-gpu-diagnostics-off-by-default-behind-JIHAD_GPU_LOG-.patch` | `gfx/2d/JihadGpuLog.h` (new, exported), `gfx/2d/moz.build`, the GPU path's files in `gfx/gl`, `gfx/layers`, `layout/base/nsLayoutUtils.cpp`, `widget/PuppetWidget.cpp` | T-512: the `[jihad-gpu]` diagnostics behind one gate (`JIHAD_GPU_LOG=1`, or a device round's `JIHAD_GPU_TIMELINE`/`VERIFY`/`DUMP_EVERY`), failures and fallbacks unconditional; T-517: the page's layer transactions and every compose job's tile uploads on `JIHAD_GPU_TIMELINE` | | `0058-gpu-compositor-the-review-of-Tier-87-fixed-scratch-p.patch` | `gfx/gl/GLContextProviderEGL.cpp`, `gfx/layers/composite/AsyncCompositionManager.{h,cpp}`, `gfx/layers/ipc/CompositorBridgeParent.cpp`, `gfx/layers/opengl/CompositorOGL.{h,cpp}`, `gfx/layers/opengl/TextureHostOGL.cpp`, `widget/PuppetWidget.cpp` | T-513: the review of Tier 87 (`context/impl/impl-review-findings-gpu-2.md` E1-E7 and Codex's C1): the band scratch is each compositor's own (two cards shared one and overran it); a closed card's frame-sized and band pbuffers and the window targets', band target's and swizzle pass's GL objects are freed (16 MB of GPU memory a card before); a band frame of 257-320 rows stacked in the frame-sized target makes that surface current first; a WebGL canvas's texture name is the producer's to delete; the reads carry their request's cancel flag (`JihadSetCancel`), so a read given up past the daemon's bound stops after `glReadPixels` and never copies into the slot, on the opt-in scratch, swizzle and read-thread paths too, counted by `jihad_offscreen_late_writes()`; a frame whose chunks pass the 12-band cap takes the whole path; a sticky layer's stuck probe reaches twice the composite's scroll step | | `0059-layout-the-GPU-path-s-root-displayport-and-clip-at-a.patch` | `layout/base/nsLayoutUtils.cpp`, `layout/generic/nsGfxScrollFrame.cpp` | T-524: once the pres shell has a resolution the root's displayport base and clip are layout device px: `jihad_layout_set_displayport2` takes the card's shift and gives the base and margins times the resolution, and the root's display-list clip (the scroll port) is no longer divided by it (desktop Wikipedia at 2.33: the card's right third white, nothing past 479 CSS px hit-testable) | | *(0060 until 2026-11-03: `security-the-built-in-roots-rolled-forward-to-UXP-release`, T-529's `certdata.txt` from the release branch at 037cc5f614)* | `security/nss/lib/ckfw/builtins/certdata.txt` | DROPPED at the move to RB_20261027 (the owner, 2026-11-02): the tag ships that very file (byte-identical: `[NSS] Update certdata to Sept 2026 status` 4a68bbbd53 and `[NSS] Remove emSign roots (eMudhra compromise)` 037cc5f614 are in the base), so the built-in roots are the base's; `audit-roots.py` checks them against it. The patches after it moved up one number | | `0060-security-a-certificate-error-is-not-TLS-intolerance-.patch` | `security/manager/ssl/nsNSSIOLayer.cpp` | T-534: a SEC_ERROR_* / mozilla::pkix / bad-cert-domain failure is never retried at a lower TLS version (the retry tripped a TLS 1.3 server's downgrade sentinel and a revoked certificate read "SSL_ERROR_RX_MALFORMED_SERVER_HELLO") | | `0061-layout-the-GPU-path-s-root-displayport-base-is-the-d.patch` | `layout/base/nsLayoutUtils.{h,cpp}`, `layout/generic/nsGfxScrollFrame.cpp` | T-527: on the GPU path the root's displayport base set by the daemon (0059's `jihad_layout_set_displayport2`) is kept by the paint (`nsLayoutUtils::JihadKeepsDisplayPortBase`): `nsLayoutUtils::PaintFrame`'s `DecideScrollableLayer` replaced it on every paint with the composition size at the origin in CSS px, and a zoomed-in card's first paint without margins covered 660 of the 531..861 CSS px shown (`docs/rounds/t527-2026-10-25/notes.txt`) | | `0062-gpu-compositor-a-tall-band-surface-for-a-change-that.patch` | `gfx/gl/GLContextEGL.h`, `gfx/gl/GLContextProviderEGL.cpp`, `gfx/layers/ipc/CompositorBridgeParent.cpp`, `gfx/layers/opengl/CompositorOGL.{h,cpp}` | T-527 (R8): a change that does not fit the 256-row band surface takes a second, 512-row band surface (`JIHAD_GPU_BAND_TALL`, its own pbuffer and target) instead of the frame-sized target; frames are packed for the band surface first. The 480 px WebGL cube's job 15-30 ms where it took ~45 | | `0063-widget-a-GPU-path-layer-paint-with-nothing-pending-i.patch` | `widget/PuppetWidget.{h,cpp}`, `layout/base/nsLayoutUtils.cpp` | T-527: the daemon's layer paint returns at once after the first when nothing is pending (no invalid region, no paint task, no view-manager flush owed): the display list is not built again for nothing (`JIHAD_GPU_PAINT_ALWAYS=1`: every time); a moved displayport base schedules the root's paint (the margins' comparison saw no change). Desktop Wikipedia's pan 23.6 fps and the long page's 33.1, verify 0 rows wrong: the compositor thread stays the bound | | `0064-gpu-compositor-a-band-surface-that-cannot-be-made-at.patch` | `gfx/layers/opengl/CompositorOGL.{h,cpp}` | T-527 (review): a band surface or its target that cannot be made at a width is not made again every band frame (a line each into /var); the frame's own surface does the pass | | `0065-widget-the-layer-paint-skip-repaints-after-a-resolut.patch` | `widget/PuppetWidget.{h,cpp}`, `gfx/layers/opengl/CompositorOGL.{h,cpp}` | T-527 (review 2026-10-26): 0064's skip repaints when the pres shell's resolution differs from the one painted (SetResolution schedules no paint, and a page with no root scroll frame — about:addons — stayed at the old resolution after a zoom across 1.1) and asks the whole widget chain (invalidations land on the child); 0065's failed band surface is tried again after 30 s | | `0066-gpu-compositor-a-compose-that-asks-for-its-bands-onl.patch` | `widget/PuppetWidget.cpp`, `gfx/layers/opengl/CompositorOGL.h`, `gfx/layers/ipc/CompositorBridgeParent.cpp` | T-516: compose flag 16 — read only the bands asked for, not the rows the tree changed (still reported); the daemon's first frame at a new zoom reads the card's view alone (942 of 1224 rows): double taps by finger 40/40 within 250 ms, the slowest 227 ms where 276-301 | | `0067-gpu-compositor-a-frame-s-fixed-and-stuck-rects-go-ba.patch` | `widget/PuppetWidget.{h,cpp}`, `gfx/layers/opengl/CompositorOGL.h`, `gfx/layers/ipc/CompositorBridgeParent.cpp` | T-544: `jihad_offscreen_compose_poll2` returns a frame's fixed and stuck rects with its poll; the daemon passes them to the card (`JihadStuckBlock`), which holds desktop Wikipedia's sticky sidebars still between frames of a pan (they moved with the page and jumped back) | | `0068-gpu-compositor-the-overview-s-windows-and-parts-the-.patch` | `widget/PuppetWidget.cpp`, `gfx/layers/opengl/CompositorOGL.{h,cpp}`, `gfx/layers/ipc/CompositorBridgeParent.cpp`, `gfx/layers/composite/AsyncCompositionManager.{h,cpp}` | T-504: compose flags 32 and 64 (`jihad_offscreen_overview_ok`) — an overview window (fixed and stuck layers at opacity 0, cleared transparent, read with its alpha, so rows no tile covered read alpha 0) and the overview's parts (only the fixed and stuck layers, with their alpha); a fixed sticky probe for both, and the verify guard keeps the probe's state; the daemon stitches a half-size picture of the page around a zoom-in point for a double tap out after a pan | | `0069-gpu-compositor-a-frame-without-its-parts-flag-128-an.patch` | `widget/PuppetWidget.cpp`, `gfx/layers/opengl/CompositorOGL.h`, `gfx/layers/ipc/CompositorBridgeParent.{h,cpp}`, `gfx/layers/ipc/CompositableTransactionParent.cpp` | T-505: compose flag 128 (`jihad_offscreen_overview_ok` answers 2) — a frame without its parts: every fixed and sticky layer at opacity 0 in the composite and the diff, no fixed rows, keeps or columns, each part reported as its layer's whole rect; the parts' generation (compositable updates under a fixed or sticky layer) as the poll's thirtieth int; `JIHAD_GPU_REQLOG=1` names each composite request's source | | `0070-gpu-compositor-the-diff-leaves-the-card-s-scroll-out.patch` | `gfx/layers/ipc/CompositorBridgeParent.cpp` | T-505: the diff leaves the card's scroll out of a frame with no base to copy (built on its slot's own frame) too, kept only when the shift it measured is the card's since the last composite; a layer transaction during a pan is no longer the whole frame changed for such frames | | `0071-gpu-compositor-the-parts-picture-in-the-frame-s-own-.patch` | `widget/PuppetWidget.{h,cpp}`, `gfx/layers/opengl/CompositorOGL.{h,cpp}`, `gfx/layers/ipc/CompositorBridgeParent.{h,cpp}`, `gfx/layers/composite/LayerManagerComposite.{h,cpp}` | T-505 (E2): `jihad_offscreen_compose_post2`/`start2` (`overview_ok` answers 3): a frame without its parts reads the parts' picture in its own job when their signature (layers, content, attributes, sizes) is not the daemon's — the parts alone, packed on the band surface, read with their alpha; the poll's 49 ints (signature, the pass's bytes, flags: a content layer above a part / too big, the card's hold set); no column reads without the parts; 0071 only without the parts or without fixed rects | | `0072-gpu-compositor-a-frame-without-its-parts-composes-th.patch` | `gfx/layers/composite/LayerManagerComposite.{h,cpp}`, `gfx/layers/ipc/CompositorBridgeParent.{h,cpp}` | T-505: a frame without its parts reads the changed rows whole, so its diff-driven partial composite covers them across the frame's width (`JihadWholeRows`; the columns beside a narrow change used to be the window target's last composite: the long page's wrong verify frame, 2026-11-02); the inspector's review fixes: one sample time per job, fixed rects joined again after the reduction, the parts' signature over a cut part's slice, every part's clip and mask, blend modes as covered; the parts pass under the job's cancel flag | | `0073-gpu-compositor-the-parts-picture-by-part-each-rect-i.patch` | `gfx/layers/ipc/CompositorBridgeParent.{h,cpp}`, `gfx/layers/ipc/CompositableTransactionParent.cpp`, `gfx/layers/opengl/CompositorOGL.h`, `widget/PuppetWidget.{h,cpp}` | T-505 (the owner's "cheaper part pictures", 2026-11-03): each rect of a frame's parts list carries a signature of its own (its outermost fixed or sticky layer's subtree, every subtree layer's last paint as the stamp of one counter that only goes up — every compositable update stamps its layer, part or not — the part's scale and quarter-pixel phase, where it sits inside the rect and its size; a rect no part's rect meets takes every part's with its index and place); `jihad_offscreen_compose_post3`/`start3` (`overview_ok` 4) take the list of signatures the daemon holds and the pass composes and reads only the rects not in it, packed in rect order; the poll's 54 ints carry each rect's signature and the rects read. The whole signature keeps post2/start2's meaning. The inspector's review 3 (F2, F3, F6) folded in | | `0054-gpu-compositor-kept-rects-all-saved-before-any-is-wr.patch` | `gfx/layers/opengl/CompositorOGL.cpp`, `widget/PuppetWidget.cpp`, `dom/canvas/WebGLContext.cpp`, `widget/headless/GfxInfo.cpp` | T-517/T-511 review: a window-moved shift saves every kept rect before writing any; `jihad_offscreen_gpu_given_up()` / `jihad_gpu_compositor_on()`, so WebGL makes no EGL contexts once the daemon has given the GPU path up | | `0053-gpu-compositor-a-shift-that-is-the-daemon-s-window-m.patch` | `gfx/layers/opengl/CompositorOGL.{h,cpp}`, `widget/PuppetWidget.cpp` | T-517: a compose job's shift may be the daemon's move of the frame's window in its segment (flag 8): the rows are in place, only the kept rects are copied from where they were | | `0052-gpu-compositor-the-frame-s-bands-read-as-one-column-.patch` | `widget/PuppetWidget.{h,cpp}`, `gfx/layers/ipc/CompositorBridgeParent.cpp`, `gfx/layers/opengl/CompositorOGL.{h,cpp}` | T-511: a compose job may give its bands' stale columns (flag 4); with no shift, kept rows or fixed columns, the bands are read as the one column the change and they span when it is under three quarters of the width; the poll reports the change's columns (twelve ints); `JIHAD_GPU_NO_COLUMN_READ=1` reads whole rows | ### The move to RB_20261027 (2026-11-03) `update-engine.sh RB_20261027` / `--finish` (docs/ENGINE.md §6): 12 upstream commits since RB_20261006, 11 files, one overlapping the queue (`certdata.txt`, patch 0060, byte-identical — dropped, above). The owner's word (2026-11-02): the certificate and HTTPS changes get special attention. Each commit and its disposition: | Upstream commit | What it changes | Disposition | |---|---|---| | `037cc5f614` `[NSS] Remove emSign roots (eMudhra compromise)` | `security/nss/lib/ckfw/builtins/certdata.txt` | certificate: taken with the base; the device had it since 2026-10-25 through patch 0060 (now dropped); `audit-roots.py` 0 findings against the base | | `4a68bbbd53` `[NSS] Update certdata to Sept 2026 status` | `certdata.txt` | certificate: the same | | `6b18be917d` `[js] Avoid OOB array copy` | `js/src/vm/SelfHosting.cpp` | memory safety: taken; the desktop JS-driven tests and the device checklist | | `d42616bb12` Remove the `URI_LOADABLE_BY_ANYONE` flag from the `jar:` protocol | `modules/libjar/nsJARProtocolHandler.cpp` | security hardening: taken; Jihad's own `jar:` pages (about:settings, about:personas, the start pages, the add-on pane) checked on the device | | `bae7a6ec8f` `[gfx] Prevent feTile rect calculations from overflowing` | `gfx/2d/FilterNodeSoftware.cpp` | memory safety: taken; an SVG filter page on the device | | `8fea2ad823` `[layout] Ensure frame table is valid after adjusting selection` | `layout/generic/nsSelection.cpp` | memory safety: taken; selection on the device | | `c4339b14dc` Use strong ref for animation mutation observer batch targets | `dom/base/nsDOMMutationObserver.h` | memory safety: taken | | `e86caa48f5` `[XPCOM] Lock during nsComponentManager memory reports` | `xpcom/components/nsComponentManager.{h,cpp}` | taken | | `5762097bc2` Update SQLite lib to 3.54.1 | `db/sqlite3/src/sqlite3.{c,h}` | taken; cookies and history across the update checked on the device | | `612a8991df`, `38e09d2368`, `5c991eadc0` the executable extensions list | `xpcom/io/nsLocalFileWin.cpp` | Windows only: no effect here | No PSM, TLS protocol, HSTS or certificate-UI change is in the range; Jihad's TLS floor (patch 0060, formerly 0061) and the Trust dialog's error gate apply unchanged. ### Branding strip (cavekit-licensing-branding R3) — patch 0010 Part of the engine branch since the patch series was committed (patch 0010; it was once a `sed` step in `build-goanna.sh`). The UA product is already `Goanna` (`netwerk/protocol/http/nsHttpHandler.cpp` `mProduct`); this removes the residual Pale Moon / Basilisk / Moonchild strings so a `strings(1)` scan of the shipped artifacts is clean: | File | Change | |------|--------| | `modules/libpref/init/all.js` | `extensions.blocklist.url` (basilisk-browser.org) → `about:blank`; `captivedetect.canonicalURL` (detectportal.palemoon.org) → example.com; two comment URLs neutralized | | `docshell/base/nsAboutRedirector.cpp` | `about:credits` target (palemoon.org Contributors) → the Jihad credits URL | | `toolkit/xre/nsAppRunner.cpp` | dead `MOZ_APP_NAME == "basilisk"/"palemoon"` literals (always false for the `xulrunner` app) → `"n/a"` — behavior identical, literals removed | **How the strip is verified**, and its result, is an acceptance criterion — `context/kits/cavekit-licensing-branding.md` R3. The check itself is a `strings` scan of `libxul.so`, `jihad-browserserver` and `goanna.js` for `basilisk`/`palemoon`/`moonchild`. ## Trademark note Per the UXP redistribution terms, an engine build shipped under a name other than Pale Moon / Basilisk must strip that project's branding. "Jihad Browser" is the product name of this fork and implies no endorsement by any upstream. See the top-level `LICENSE` for the full component/license breakdown and the Apache-2.0 ↔ MPL-2.0 compatibility statement.