Compare commits

...
Author SHA1 Message Date
NotAlexNoyleandClaude Fable 5.1 1f54df3762 gpu-compositor: a frame without its parts composes the changed rows whole, as it reads them; the review's fixes
T-505, the long page's one wrong verify frame (2026-11-02) and the inspector's review of E2:
- F1: LayerManagerComposite::UpdateAndRender makes a composite whose tree change is smaller than the
  frame a partial one, clipped and cleared to the change's bounds (the load's 4 px strip at x 764..768,
  an image arriving), while a frame without its parts reads the changed rows whole (review D4 of 0072
  turned its column read off). The columns beside the change came from the window target's last
  composite: in a verify run the whole reference with the parts, so the header passed for the page
  beneath it, the daemon recorded it as what lay beneath, and the first shift put it back where the
  old header landed. JihadWholeRows, set by the job's content-only scope: the diff-driven partial
  composite of such a job covers the changed rows across the frame's width, and reports them so.
- F2: one sample time for the job (mTestTime, the test API's mechanism, restored after): an animated
  part is measured, pictured and composed at the same instant.
- F3: JihadMergeFixed joins rects again after the reduction's unions, so no two overlap.
- F5: the parts' signature mixes where a part cut by the frame's edge starts, every part's clip rect
  and the mask layer's identity and bounds; a mix-blend-mode part marks the frame covered.
- F6: the parts pass runs under the job's cancel flag.

Verified on the device: the long page's scripted pan with JIHAD_GPU_VERIFY=1, where the frame built on
the load's strip composite used to carry the header beneath (pan-v2, pan-v3: 2 wrong frames each),
85 frames verified, 78 shifted, 0 wrong rows (docs/rounds/t505-2026-11-02/notes.txt).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-02 20:30:15 -05:00
NotAlexNoyleandClaude Opus 5.5 446b22790a gpu-compositor: the parts' picture in the frame's own job, from the same tree state (E2)
T-505, after two adversarial reviews of the parts on the CPU (the inspector's design E2): a frame
composed without its parts (flag 128) and posted with compose_post2/start2 (overview_ok answers 3)
carries a parts buffer and the signature of the picture the daemon holds.
- In the job, before the frame's compose: the parts' list (every fixed and sticky layer, whole
  rects), their signature (each part subtree's layers: identity, type, opacity, content flags,
  mask, visible region; inside a part its transform and clip; a colour layer's colour; an
  animation every composite; the paints under a part; the parts' sizes), the card's hold set
  (fixed and stuck layers, T-544's meaning) and a cover flag (a content leaf drawn above a part
  whose pixels meet it). When the signature is not the daemon's, the parts alone are composed on
  the band surface, packed in shelves, and read with their alpha into the buffer (a verify guard
  holds the diff baseline, the probe, the last scroll and view). Flag 2: the parts too big.
- The poll's 49 ints: the signature, the pass's bytes, the flags, the hold set.
- Review fixes: no column reads in a frame without its parts (the daemon restores what lay beneath
  them by whole rows); 0071's own-slot compensation only without the parts or with no fixed rects.
- LayerManagerComposite::JihadPrepareOnly (visible regions and effective transforms without the
  diff), CompositorOGL::JihadReadPacked (a packed read that keeps the alpha).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XtfxSpM1w2uiVKeLKoV3g3
2026-10-26 14:42:39 -04:00
NotAlexNoyleandClaude Opus 5.5 ffb0cb8ae1 gpu-compositor: the diff leaves the card's scroll out of a frame built on its own slot
A frame with no base to copy (the daemon's frame built on its slot's own older frame, its window moved or
its rows shifted in place) had no scroll compensation in the diff: compensation was on only for a frame
copied from the newest one (src with engineShift). Any layer transaction during a pan was then the whole
frame changed for it (the scrolled content's translation), a whole read, and the daemon's other two slots
stale whole. Such frames are the rule for a page without fixed layers and for the frames without their
parts (T-505); on desktop Wikipedia with the parts on the CPU, whole tree changes went 30 -> 9 and the rows
read 96k -> 57k a round, the long static page 32 -> 10 and 90k -> 43k.

The compensation is kept only when the shift the diff measured is the card's own since the last composite
(the request's scroll against the last one's): a scroll the page made itself (scroll anchoring) is the whole
frame changed, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XtfxSpM1w2uiVKeLKoV3g3
2026-10-26 13:43:37 -04:00
NotAlexNoyleandClaude Opus 5.5 d14fbe3f68 gpu-compositor: a frame without its parts (flag 128) and the parts' generation
T-505, the owner's CPU/GPU split ("both, parts first"): the daemon draws a page's fixed and sticky parts
over each frame on the CPU, from a picture of the parts alone, so the GPU composes and reads only the
scrolled content (no fixed rows, keeps or columns for the see-through sidebars).
- flag 128 of jihad_offscreen_compose_post/start: every fixed and every sticky layer (stuck or not) at
  shadow opacity 0 in the composite and in the diff-first step; no fixed rows, keeps or columns; the
  parts' rects still reported with the poll (each part its layer's whole rect, no keeps: the same in a
  frame, where the parts are at opacity 0, and in the parts' picture, flags 64|128, where they are shown;
  the keep split made them differ and the daemon's picture never matched);
- the parts' generation: a count of compositable updates under a fixed or sticky layer, the poll's
  thirtieth int (jihad_offscreen_overview_ok answers 2), so the daemon knows when its picture is old;
- JIHAD_GPU_REQLOG=1 (diagnostic): each composite request's source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XtfxSpM1w2uiVKeLKoV3g3
2026-10-26 13:43:37 -04:00
NotAlexNoyleandClaude Opus 5.5 c05685f43f gpu-compositor: the overview's windows and parts: the scrolled content alone or the fixed parts alone, with their alpha
T-504 (flags 32 and 64 of jihad_offscreen_compose_post; jihad_offscreen_overview_ok says the engine takes them,
and answers 0 with the swizzle pass, whose shader forces the alpha). The daemon stitches a half-size picture
of the page around a zoom-in point from windows composed at other scrolls, and draws the page's fixed and
stuck parts over it where they sit at the card's new position:
- flag 32, a window: fixed and stuck layers at shadow opacity 0 (their rects still reported, at the window's
  scroll), the frame cleared to transparent black and read with its alpha kept (every other read forces it
  to 0xFF), so the rows no tile covered (past the displayport or the page) read alpha 0 and are left out;
- flag 64, the parts: every leaf layer outside a fixed or stuck one at opacity 0, the same clear and read, so
  the parts come back with their own alpha (see-through sidebars drawn over the new position's content, not
  the old one's);
- both: a fixed sticky probe of 1024 px (every window lists the same sticky layers), and the verify guard now
  keeps the probe's state, so the next real frame does not start from a window's scroll step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XtfxSpM1w2uiVKeLKoV3g3
2026-10-26 09:37:09 -04:00
NotAlexNoyle 078a09428d gpu-compositor: a frame's fixed and stuck rects go back with its poll, for the card to hold them still between frames
T-544: jihad_offscreen_compose_poll2 returns, past the twelve ints, the rects the last
JihadUpdateLastFixed found (fixed layers and stuck sticky ones, frame px); the daemon puts them in
the segment for the card, which draws them where the frame did while it moves the frame for a pan.
2026-10-26 07:00:31 -04:00
NotAlexNoyleandClaude Opus 5.5 468941678e gpu-compositor: a compose that asks for its bands only reads them alone, not the rows the tree changed
T-516 (flag 16 of jihad_offscreen_compose_post). The daemon's first frame at a new zoom reads the card's
view (942 of 1224 rows): the zoom changes every row, and the whole read and its conversion ran 200+ ms
on one core with the second unplugged after a pause. The change is still reported for the daemon's
records; the columns of the change do not narrow such a read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 05:19:11 -04:00
NotAlexNoyleandClaude Opus 5.5 2f7898f067 widget: the layer-paint skip repaints after a resolution change and asks the child widget; a failed band surface is tried again after 30 s
T-527 (review 2026-10-26). SetResolution schedules no paint, and on a page with no root scroll
frame (about:addons) nothing else did: a zoom across 1.1 stayed painted at the old resolution. The
skip now compares the pres shell's resolution with the one painted and asks the whole widget chain
(invalidations land on the child). A band surface that could not be made is tried again 30 s later
instead of never (a failure may be another app holding the GPU's memory).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 03:00:53 -04:00
NotAlexNoyleandClaude Opus 5.5 f4fefca0d2 gpu-compositor: a band surface that cannot be made at a width is not tried again every frame
T-527 (review). A pbuffer or render target that failed at a width was re-created, and a line logged,
on every band frame (~25 a second into the device's small /var). The width it failed at is kept per
surface and the frame's own surface does the pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 00:01:48 -04:00
NotAlexNoyleandClaude Opus 5.5 247e10f4ba widget: a GPU-path layer paint with nothing pending is skipped; a moved displayport base schedules a paint
T-527. JihadPaintLayers returns at once after the first paint when the widget has no invalid region,
no paint task pending and the refresh driver owes no view-manager flush: the layer tree is current
and a paint would only build the display list again (JIHAD_GPU_PAINT_ALWAYS=1 paints every time).
jihad_layout_set_displayport2 schedules a paint of the root scroll frame when the base moved
(SetDisplayPortMargins compares displayports computed with the new base on both sides).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 00:01:48 -04:00
NotAlexNoyleandClaude Opus 5.5 bda3141209 gpu-compositor: a tall band surface for a change that does not fit the band surface
cavekit-gpu-rendering.md R8 / T-527. A frame whose change does not fit the 256-row band surface took the
whole path: the frame-sized target (768x1224) cleared, drawn and resolved on the Adreno 220 every frame, and
the read waited for all of it. A 480 px WebGL canvas changes 354-482 rows a frame, so every frame of the
spinning cube went that way (the job ~45 ms, the card 16.6-22.0 fps while the page drew 22-24). A second,
taller band surface (JIHAD_GPU_BAND_TALL rows, default 512, 0 off; its own pbuffer and target, freed with
the context like the band surface's) takes such a frame; frames are packed for the band surface first, so
one that fits it never pays the tall one (desktop Wikipedia's chunked pan frames stay where they were). The
cube's job 15-30 ms; with the daemon's partial invalidation the card shows 25.3-28.0 fps at 480 px.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 22:02:16 -04:00
NotAlexNoyleandClaude Opus 5.5 63c20e39de layout: the GPU path's root displayport base is the daemon's — no longer replaced on every paint
cavekit-gpu-rendering.md R6 / T-527. nsLayoutUtils::PaintFrame asks the root scroll frame's
DecideScrollableLayer with aAllowCreateDisplayPort, and for the root content document that set the
displayport base to the composition size at the origin, in CSS px, on every paint. So the base the
daemon sets with jihad_layout_set_displayport2 (what the card shows, at the compositor's shift, in
layout device px: patch 0059) never reached a paint: a zoomed-in card's displayport covered only
what the margins and the clamp into the scrollable rect happened to reach. With no margins (the
daemon's first paint after a zoom, what the card shows only) desktop Wikipedia at 2.33 painted 660
of the 531..861 CSS px the card showed and the rest of the view stayed white (frame dumps,
2026-10-25: the painted edge at 1536 screen px, the aligned width of a base 1116 px wide at
resolution 1). On the GPU path, once the daemon has set the root's base
(nsLayoutUtils::JihadKeepsDisplayPortBase: the frame carries the shown size), the paint keeps it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 21:10:54 -04:00
NotAlexNoyleandClaude Fable 5.1 ec8f0ed7e3 security: a certificate error is not TLS intolerance — no version fallback on it
cavekit-certificate-trust.md R4 / T-534. retryDueToTLSIntolerance remembered ANY handshake error not on its
short exclusion list as intolerance at the connection's maximum version and retried one version lower. With
TLS 1.3 on (security.tls.version.max 4) that turns every certificate-verification failure against a TLS 1.3
server into a second attempt at TLS 1.2, which trips the server's downgrade sentinel (RFC 8446 §4.1.3), so
NSS reports SSL_ERROR_RX_MALFORMED_SERVER_HELLO — and the user reads "malformed Server Hello" for a revoked
certificate (ssl.com's and DigiCert's revoked demo hosts, measured 2026-10-25; the same hosts at a TLS 1.2
cap say SEC_ERROR_REVOKED_CERTIFICATE; badssl.com, a TLS 1.2 server, never showed it). The retried socket
also carries no certificate verdict (nsITransportSecurityInfo.errorCode 0), so an embedder cannot recover
the real error either. Now a SEC_ERROR_* / mozilla::pkix / SSL_ERROR_BAD_CERT_DOMAIN failure is never a
reason to retry lower.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-25 10:09:41 -04:00
NotAlexNoyleandClaude Fable 5.1 2212143d4f security: the built-in roots rolled forward to UXP release (037cc5f614, 2026-10-24: certdata at the September 2026 status, the emSign roots removed after the eMudhra compromise)
cavekit-certificate-trust.md R2 (T-529). The RB_20261006 branch carried the roll of 2025-06-23: 177
certificates, 150 trusted for server authentication, among them 24 that Mozilla has since removed
(Entrust after its 2024 distrust and the four AffirmTrust roots it owns, GLOBALTRUST 2020, the four
CommScope roots, Secure Global / SecureTrust / XRamp / the three Trustwave Global roots now SSL.com's,
TeliaSonera v1, certSIGN, ePKI, SecureSign CA12, FIRMAPROFESIONAL ROOT-A WEB, the three emSign roots),
and lacking 19 current ones (OISTE, SECOM 2024, SwissSign TLS 2022, Telia v3, TrustAsia, e-Szigno 2023,
SecureSign CA16). UXP's release branch — what Pale Moon and Basilisk ship — carries Mozilla central's
file byte for byte: 169 certificates, 118 trusted for server authentication, the old-root sunsets as
Mozilla sets them. This is that file; nssckbi.h stays at 2.76 as upstream left it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-25 08:57:34 -04:00
NotAlexNoyleandClaude Fable 5.1 c79d16f87b layout: the GPU path's root displayport and clip at a resolution — the base in layout device px at the card's shift (jihad_layout_set_displayport2), the scroll port as the root's display-list clip
T-524 (2026-10-24), found with the emulated finger on desktop Wikipedia (laid out 1116x1374, the card's
view 330 CSS px wide at a zoom of 2.33, 531 px from the engine's scroll, which has no sideways range):

1. GetDisplayPortFromMarginsData takes the root's base rect in layout device px: it scales it by the
   parent's resolution (1 for the root content document) and divides base + margins by the cumulative
   resolution. jihad_layout_set_displayport set the scroll port in CSS px as the base, so at 2.33 the
   1116 px base became 479 CSS px and the 165 px margins 71: the displayport ended 550 px from the
   engine's scroll, the card's right third was white at 2.33, two thirds at 2.71, all of it from 2.98.
   jihad_layout_set_displayport2 takes where the card's view sits (the compositor's shift) and makes
   the base what the card shows, at the shift, times the resolution, the margins times the resolution.
   The old entry calls it with no shift. The daemon passes the shift and sets the displayport again when
   the shift leaves the re-anchor margin or the zoom changes.

2. nsGfxScrollFrame divided the root content document's display-list clip by the resolution. Gecko's
   composition size for that root is the widget's device px; the GPU path's (CalculateCompositionSizeForFrame's
   Jihad branch) is the scroll port or what the card shows, in CSS px, so the clip became 479 CSS px wide
   at 2.33 and a tap on anything beyond it hit only <html> (the infobox's links). The port is the clip on
   the GPU path; the overscan rows are CSS px too.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-24 18:34:10 -04:00
NotAlexNoyleandClaude Opus 5.5 7a872e8f08 gpu compositor: the review of Tier 87 fixed (scratch per compositor, GL objects freed per card, late reads)
T-513, the review of the GPU path (two inspectors; context/impl/impl-review-findings-gpu-2.md, E1-E7):

- E1: the band scratch's size is the compositor's own (mJihadBandScratchSize), not a function-static
  shared by all: with two cards one was handed a buffer another had outgrown and glReadPixels wrote
  past it.
- E2: a closed card's frame-sized and band pbuffers are destroyed with its context, and
  CompositorOGL::CleanupResources deletes the window targets', the band target's and the swizzle
  pass's renderbuffers, framebuffers, texture and program: in the process-long share group each closed
  card left ~13-16 MB of GPU memory. Twenty open/close cycles now add 76 KB.
- E3: a band frame of 257-320 rows stacked in the frame-sized target makes that surface current first
  (on the Adreno 220 every target must match the current surface).
- E4: a WebGL canvas's texture source is externally owned (the producer's SharedSurface deletes the
  name; in one share group the second delete could hit a name handed out again).
- E5: the reads carry their request's cancel flag (JihadSetCancel): a read given up past the daemon's
  bound stops after glReadPixels, before the swizzle and any copy into the slot; a whole read (straight
  into the slot) is counted, jihad_offscreen_late_writes(), and the daemon then paints every slot whole.
- E6: a frame whose chunks would pass the 12-band cap of one composite takes the whole path instead
  of reading chunks it did not compose.
- E7: a sticky layer's stuck probe reaches twice the composite's scroll step (64 to 1024 px), so a fast
  flick's step no longer slides its old pixels with the content.

Codex on the fixes (2026-10-24, C1): the opt-in read paths stop for a given-up frame as well: the
scratch read before its copy into the slot, the swizzle pass and the read thread after their read
(counted as late writes), the read thread also before it, and a cancelled read-thread frame is not
reported good.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-24 13:48:59 -04:00
NotAlexNoyle baaefa5889 gpu diagnostics: off by default behind JIHAD_GPU_LOG; the page's transactions on the timeline
T-512: the GPU path's [jihad-gpu] diagnostics print only with JIHAD_GPU_LOG=1, or in a device round's
JIHAD_GPU_TIMELINE, JIHAD_GPU_VERIFY or JIHAD_GPU_DUMP_EVERY (one gate, gfx/2d/JihadGpuLog.h, exported
as mozilla/gfx/JihadGpuLog.h); failures and fallbacks print anyway. A daemon on the GPU path now logs
three startup lines from the engine instead of hundreds.

T-517: with JIHAD_GPU_TIMELINE a layer transaction that holds the compositor thread 3 ms or more is
logged with its parts (compositable ops and their tile uploads, layers updated, end), and every compose
job with its uploads: the express lane's frames queue behind the page's transactions.
2026-10-19 14:22:21 -04:00
NotAlexNoyle dba5c890ab layers: a tile wholly outside the clip is not locked, bound or drawn
T-517. TiledContentHost::RenderLayerBuffer gave every tile of the layer to RenderTile, which locks and
binds its texture and makes an effect before the compositor drops the quad for lying outside the
clip. A band frame's regions each met every tile of the page (desktop Wikipedia: five regions, ~30
tiles). A tile whose transformed bounds miss the clip (in the current render target's coordinates,
its origin added, as CompositorOGL::DrawQuad compares) is skipped first: chunked Wikipedia frames
composed in 10.6 ms where they took 16.9, a simple page's 3.9 where 5.9. JIHAD_GPU_NO_TILE_CULL=1
for A/B.
2026-10-19 12:45:37 -04:00
NotAlexNoyle aea4e86a4b gpu compositor: a band frame's regions composed in one frame
T-517. A band frame (a pan step: the entering bands and the fixed layers' column chunks, stacked on
the band surface) was one full composite per region: the transaction, the diff, BeginFrame and
EndFrame and the layer tree's render each time, ~5 ms of CPU whatever the region drew, four or five
regions a desktop Wikipedia frame. LayerManagerComposite::JihadSetRegions gives the regions (each a
world transform and a rect on the target) to one composite: the transaction and the frame once, and
for each region the effective transforms at its world, Prepare and RenderLayer inside its rect.
PostProcessLayers works in layer space and is shared. Chunked Wikipedia frames composed in 16-17 ms
where they took 22.5. JIHAD_GPU_PASS_PER_REGION=1 composes each region on its own as before.
2026-10-19 12:45:37 -04:00
NotAlexNoyle 66180dfea4 gpu compositor: kept rects all saved before any is written; WebGL off once the GPU path is given up
Review of the T-511/T-517 work. With the daemon's window move (flag 8) the kept rects were copied
one at a time, each saved and written before the next was read: a rect's old rows can be another's
new ones (two stacked sticky bars), which then got the other bar's pixels. All are saved first now,
then all written, as the in-place shift does.

jihad_offscreen_gpu_given_up() (the daemon calls it when it gives the GPU path up) and
jihad_gpu_compositor_on(), which WebGL's EGL choice and the headless GfxInfo now ask: a daemon that
fell back to the software path after a GPU stall made new WebGL contexts on the abandoned GPU. The
environment is left as it is (other threads read it).
2026-10-19 11:12:42 -04:00
NotAlexNoyle a563423cac gpu compositor: a shift that is the daemon's window move copies only the kept rects
T-517. A compose job may say (flag 8) that its shift is already done: the daemon moved the frame's
window within its shared segment by the scroll instead of having 3.7 MB of rows moved (the frame
then starts that many rows further into the segment, and the rows are where the shift would have put
them). The engine then copies only the kept rects (opaque stuck layers that held still) from where
they were, the shift's rows back, and everything else about the shift (the entering rows, the fixed
layers' columns) is as before. On a Wikipedia pan the compositor thread's shift went from 6.5-9.7 ms
to 1.2-1.9.
2026-10-19 09:41:09 -04:00
NotAlexNoyle 8e117bab07 gpu compositor: the frame's bands read as one column when only it changed
T-511. A compose job may say which columns its bands are stale in (flag 4 and two more arguments to
jihad_offscreen_compose_start and _post; a daemon from before passes neither). When nothing else asks
for whole rows (no shift, no rows kept from another frame, no fixed columns) and the column the change
and the stale columns span is under three quarters of the width, the bands are read as that column,
in the whole path and in a band pass of one band. The poll reports the columns the composite changed
(twelve ints for such a job), so the daemon keeps each slot's stale columns as it keeps its rows.

A 480 px WebGL canvas on a 768 px card changes 482 rows a frame, and every one was read whole and
swizzled: the compositor job 44 ms against 47. JIHAD_GPU_NO_COLUMN_READ=1 reads whole rows.
2026-10-19 07:42:05 -04:00
NotAlexNoyle 6ea0ae9f54 webgl: contexts on the device's GPU on the GPU path, shared with the compositor
T-511. On the GPU path (JIHAD_GPU_COMPOSITOR) WebGL asks EGL for its context: the headless build's
default GL provider is the null one, and the headless GfxInfo answered UNKNOWN for WebGL's OpenGL
feature, which reads as blocklisted. On the software path nothing changes and WebGL stays off.

The Adreno 220 driver answers GL_INVALID_ENUM for GL_STENCIL_BACK_WRITEMASK, and the error left
behind failed the context's init; it is queried in its own error scope, the front mask standing in.

Every pbuffer context on the GPU path, the compositor's and each canvas's, joins one share group
under a 1x1 root that lives as long as the process, and a WebGL canvas hands the compositor its
texture (the shared GL texture surface): no readback, no upload. A 480 px spinning cube draws at
21.5-25 fps where the readback from its texture framebuffer gave 8-9 (the driver has no EGLImage from
a GL texture). JIHAD_GPU_NO_SHARE=1 keeps the contexts unshared; their frames are then read back
through a pbuffer as large as a canvas on this screen (16-17 fps), not the texture framebuffer.

A context is released from its thread before it is destroyed: left current, the driver kept pointers
into its framebuffers and the next context's teardown on that thread faulted in libGLESv2
(set_framebuffer) when a second WebGL page closed, shared or not.
2026-10-19 07:42:04 -04:00
NotAlexNoyle a3b614056c gpu compositor: every compose job, compose and read on the daemon's timeline (JIHAD_GPU_TIMELINE)
T-516 device rounds. With JIHAD_GPU_TIMELINE=1 every compose job logs its queue and compose time
with a timestamp on the daemon's clock, and every compose and read logs its breakdown (otherwise
sampled), so a slow frame's time can be placed: the queue, the composite, the readback's wait for
the GPU, the CPU swizzle. The slow first frames after a pause were the readback and the swizzle
(the clocks), not the draws.
2026-10-19 04:46:23 -04:00
NotAlexNoyle 2cc21a9a5e layers: a composite acknowledged after the widget is gone tells nobody
ClientLayerManager::DidComposite dereferenced mWidget, which the widget's teardown nulls. The
embedder's offscreen compose jobs can be acknowledged after that: a Jihad card closed while a job it
had asked for was waited out, the job composed, and its DidComposite reached the main thread after
the page was gone (SIGSEGV at address 0 in a device round, 2026-10-19). Nothing is left to tell then.
2026-10-19 03:52:26 -04:00
NotAlexNoyle 40c3319eae gpu compositor: the frame's paint and its compose posted apart; compose jobs from any thread
T-515, frames made off the main thread. JihadComposeStart was the layer paint (main thread) and the
compose job's post in one call. They are now apart: jihad_offscreen_paint_layers(widget, docshell)
flushes and paints the layers, as Start does first; jihad_offscreen_compose_post(...) posts the
compose and read of the layer tree as it stands, from any thread, at a view and scroll it is given
(or the ones last set). The daemon's express lane posts its frames from a thread of its own while
the main thread runs the page's script or a layer paint.

The job list is shared with that thread, so it is under a mutex: start, post, forget and abandon
take it; a poll without a wait holds it for the whole poll (a forget between the find and the
job's monitor would let the compositor task free the job under it). jihad_offscreen_compose_peek
reads a job's state without taking its result (1 done, 2 composed and being read, 0 pending).
A forgotten job's cancelled flag was set even when the job was done; it is set only with abandoned.
2026-10-19 03:21:16 -04:00
NotAlexNoyle 53e50a5fe0 gpu compositor: a given-up frame writes nothing; test switches for an EGL failure and a stalled job
A compose job the daemon forgets (its bound passed, or the GPU path given up) is marked cancelled:
the compositor composes nothing more for it and writes nothing into its destination, a shared slot
the software path may be painting by then. Two device-test switches: JIHAD_GPU_TEST_NO_EGL=1 gives
the compositor no GL context, as an EGL failure would; JIHAD_GPU_TEST_STALL=<n> holds the
compositor thread 6 s on the nth job, as a GPU wait that does not return would.
2026-10-19 01:21:07 -04:00
NotAlexNoyle fe33f7f6ae gpu compositor: the root scroll frame's clip widened by the card's overscan
The GPU path's frame now carries rows above and below what the card shows, so the card has content
to pan into between frames and while the main thread is busy (it showed grey past a view-sized
frame's edges). jihad_layout_set_overscan(docshell, top, bottom) sets them (CSS px) as a frame
property on the root scroll frame; with JIHAD_GPU_COMPOSITOR its clip in BuildDisplayList is widened
by them (over the resolution, as the composition size is).
2026-10-18 23:02:15 -04:00
NotAlexNoyle e49cd4cc72 gpu compositor: no edge antialiasing for an axis-aligned scale; slow composites and draws logged (JIHAD_GPU_PHASES)
Gecko turns DEAA on for any transform that is not an integer translation, a plain scale included.
Its shader variants are compiled on their first use, ~150 ms each on the Adreno 220: with the
layers painted at the zoom's resolution the fit zoom drew every tile 1:1, so the first frame of a
zoom compiled two of them (300-385 ms). On the GPU path (JIHAD_GPU_COMPOSITOR) an axis-aligned
scale gets no DEAA (its edges stay axis-aligned); rotated and skewed layers keep it;
JIHAD_GPU_DEAA=1 restores Gecko's rule. With JIHAD_GPU_PHASES a composite of 80 ms or more logs its
own phases and a draw of 5 ms or more logs its effect, texture and size (bounded).
2026-10-18 21:31:29 -04:00
NotAlexNoyle 72060b08ba gpu compositor: tile textures converted at 1x1 and kept in a pool (the Adreno 220's first write after a draw)
On the TouchPad's Adreno 220 the first write into a texture after its first draw costs ~18 ms for a
256x256 tile (~75 ms 512x512, ~285 ms 1024x1024: the driver converts the storage at about 14 MB/s),
whatever the format, size parity, filter or wrap; every later write costs ~1 ms, under a queued draw
too. The conversion survives a re-specification at another size, and a clear of the texture through
a framebuffer triggers it without waiting. So on the GPU path (JIHAD_GPU_COMPOSITOR) each new
BasicTextureImage texture is converted while it is 1x1 (~1.1 ms on the device), and a texture image
that had storage gives its texture to a pool (JIHAD_GPU_TEX_POOL, 48) instead of deleting it.
Desktop Wikipedia, a pinch in and out: re-uploads slower than 8 ms went from 55-59 a run (24-37 ms
average) to one. JIHAD_GPU_NO_TEX_CONVERT=1 skips the conversion for an A/B.
2026-10-18 19:52:46 -04:00
NotAlexNoyle aa267e212c npapi: the Palm event paths only where npapi.h defines Palm's NPEvent
The gain-focus system event (PluginInstanceChild) and the spotlight export (nsPluginHost) built
Palm's NPEvent fields unconditionally. That union exists only for the headless toolkit the device
builds; the desktop GTK build has X11's NPEvent and failed to compile. Both are now guarded the
way npapi.h is (XP_UNIX && MOZ_WIDGET_HEADLESS); the desktop spotlight export returns 0.
(Jihad T-387, cavekit-engine-update R6: the desktop engine on RB_20261006 for the desktop tests.)
2026-10-18 18:52:35 -04:00
NotAlexNoyle 94577ddad7 gpu compositor: the card's scroll applied in the compositor; frame-sized surfaces; band frames on their own surface
T-502 (2026-10-18). Without APZ a scroll was a main-thread scroll: every step repainted the
newly exposed strip and re-uploaded the content layer. The daemon now sends the card's scroll
(jihad_offscreen_set_scroll) and AsyncCompositionManager applies it as an async transform on the
layer carrying the root content metrics, the way APZ would, with AlignFixedAndStickyLayers keeping
fixed and sticky layers still. For that, without APZ: root scroll metadata and the scrollport as a
scroll clip for a root scroll frame with a displayport (nsDisplayList, nsGfxScrollFrame), the
displayport set from layout (jihad_layout_set_displayport), and no intermediate surface for a
container under an axis-aligned scale+translate (Layers.cpp).

The Adreno 220 driver bins an FBO render by the current EGL surface's size: a 942-row frame in a
1400-row pbuffer lost its bottom 458 GL rows in some composites. The context's pbuffer is made the
frame's size (GLContextEGL::JihadUsePBufferOfSize) and the window targets with it. Scroll-only
frames (no composite request since the last composite) compose their bands stacked on their own
768x256 pbuffer and FBO, which stays current between band frames (the switch into it costs
11-13 ms); the rows kept are moved while the GPU works; one read takes the stack. A done-fd
(jihad_offscreen_set_done_fd) wakes the daemon the moment a job finishes. Nothing touches a job
after its hand-off.
2026-10-18 17:44:22 -04:00
NotAlexNoyle e0c04228c9 gl: the Adreno 220 — whole-texture uploads, BGRA uploads on EGL, a shared pbuffer context
The Adreno 220 ("Adreno (TM) 220") is an Adreno 2xx for the sub-texture upload workaround
(glTexSubImage2D into a big texture is 16 times slower than a whole glTexImage2D on it). An EGL
context prefers BGRA for 32-bit surfaces where GL_EXT_texture_format_BGRA8888 is present, with
the GLES-legal type and internal format (an RGBA upload of a 768x942 layer costs 35 ms, a BGRA
one 8; as RGBA the CPU swizzled every tile first). GLContextEGL::JihadCreateSharedContext makes
a 1x1 pbuffer context sharing a compositor context's objects, for a readback thread. Opt-in and
measured as no gain: a fresh texture name per upload with the retired names deleted once the GPU
is idle (JIHAD_GPU_FRESH_TEX=1; the driver waits for pending GPU work on any upload).
2026-10-18 02:41:07 -04:00
NotAlexNoyle fa8cf84275 gpu compositor: an in-process OpenGL compositor behind the offscreen widget (JIHAD_GPU_COMPOSITOR)
T-502 (2026-10-17). With JIHAD_GPU_COMPOSITOR in the daemon's environment the headless platform
lists the OpenGL layers backend, off-main-thread composition is forced on over the bundle's
force-disabled pref, and the offscreen PuppetWidget creates an in-process CompositorBridgeParent
whose CompositorOGL draws into an EGL pbuffer context with two renderbuffer window targets (a
texture-backed one costs 370-640 ms a readback on the Adreno 220).

The frame is pulled, not pushed: the vsync scheduler only counts composite requests, the daemon
reads the count (jihad_offscreen_compositor_seq) and asks for a frame in two halves
(jihad_offscreen_compose_start / _poll / _forget): the layer paint on the main thread, then the
compose and the readback on the compositor thread into the daemon's shared buffer, with the
card's zoom and the residual scroll offset as a world transform on the layer tree
(jihad_offscreen_set_view, LayerManagerComposite::JihadSetWorldTransform). The compositor keeps
the window's flipped view on the borrowed target (the intermediate-surface draw cancels a flip
that must exist) and reverses the rows in the readback; the render bounds are the frame's size.
The readback is a band: the layer tree's own diff says what changed (JihadLastChanged) and the
daemon asks for the rows its slot has fallen behind by; the composite is scissored to the rows
read. Opt-in and measured as no gain: a read thread with a shared context, EGL fences and the
two targets used in turn (JIHAD_GPU_READ_THREAD=1), a GPU swizzle pass (JIHAD_GPU_PASS=1), the
round-5 snapshot road (JIHAD_GPU_SNAPSHOT=1).

Tiled content layers are on by default (layers.enable-tiles in all.js: the bundle's goanna.js is
read after the once-only gfx prefs are snapshotted).
2026-10-18 02:41:07 -04:00
NotAlexNoyleandClaude Fable 5.1 706d4782ba addons: an add-on naming both the AppCompat GUID and the toolkit is matched by the entry that fits
matchingTargetApplication prefers, in order: this application's own id, the
AppCompat GUID (extensions.guid.appCompatId, the Firefox GUID), the toolkit.
The AppCompat entry was taken whenever present, whatever its version range.

An add-on can name both for different reasons: the GUID entry for the
application that owns that GUID, at that application's versions (Basilisk is
{ec8030f7-...} at 52.9.x), and a toolkit entry meaning "any other application
on this platform". For an application that is neither, with an AppCompat
version of 56.9, the GUID entry "52.9.0 - 52.9.*" under strict compatibility
does not fit - and because it was preferred, the toolkit entry that does
describe the application was never looked at. The add-on was installed and
immediately disabled as incompatible.

Now the AppCompat entry is used only if it admits the AppCompat version (both
bounds under strict compatibility, the lower bound otherwise - the rule
isCompatibleWith applies) or if there is no toolkit entry to fall back to.
Nothing changes for an add-on that names one of the two, or whose GUID entry
fits.

Found with Palefill 1.30 (toolkit@mozilla.org 4.8.2 - 10.*, platform 6.9.0),
which now installs enabled and applies its fixes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LcrVQFRMC2ANGDfVaRG9Ed
2026-10-12 19:28:53 -04:00
NotAlexNoyleandClaude Fable 5.1 75d346ab0d plugin-container: do not hand the bundled library path to what the plugin runs
The plugin child is started through the bundled loader with an explicit
--library-path, which is what its own dlopen()s search; the LD_LIBRARY_PATH it
also inherits is not needed by it, but is inherited again by anything the
plugin spawns. Flash for Linux runs sh -c "ps x | grep netscape" at start-up:
the device's own /bin/sh (glibc 2.8) then loaded the bundled glibc 2.23 and
died with SIGSEGV, leaving a crash report for every page with Flash on it.

Unset it at child start-up, only when the bundled loader is in use
(MOZ_CHILD_PROCESS_LOADER), so a desktop build keeps its environment.

On the device: a Flash page loads and plays, and no report is written.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LcrVQFRMC2ANGDfVaRG9Ed
2026-10-12 19:28:53 -04:00
NotAlexNoyleandClaude Fable 5.1 9b2556a56c plugins: an instance with no window to be given is windowless, not a null dereference
nsPluginInstanceOwner::CreateWidget() creates a child-window widget for a
windowed plugin and then calls Create() on it without checking that the widget
exists. A build with no child-window widget (the offscreen embedding registers
none for kWidgetCID) got null back and crashed with SIGSEGV on every page whose
Flash movie was embedded the ordinary way: a plugin is windowed unless it asks
otherwise, and Flash asks only for wmode=opaque or transparent.

With no widget to create, mark the instance windowless and carry on down the
windowless path. That is what webOS's own browser did - it had no plugin
windows and handed every plugin a drawable - and the webOS Flash build draws
through the Palm window structure in both modes.

Found on the device: two "Flash test" pages reached from a search results page
killed the daemon in a loop (the card reconnects and reopens the address).
After the change both render their movies and the daemon keeps its PID.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LcrVQFRMC2ANGDfVaRG9Ed
2026-10-12 19:28:53 -04:00
NotAlexNoyle c449e942b3 extensions: a link or navigation to an .xpi must reach the install flow in a chrome-less embedding
amContentHandler cancels the load and then hands the install to either a
chrome-privileged frameElement above the page or the content frame message
manager. This embedding has neither, so the hand-off threw after the load had
already been cancelled: following a plain link to an .xpi, or typing its
address, did nothing — no prompt, no error. InstallTrigger.install() was fixed
the same way earlier; call the add-ons integration service directly here too.
2026-10-12 19:28:53 -04:00
NotAlexNoyle 7dbbdd65ac gfx: BasicPlanarYCbCrImage::CopyData must not report failure under delayed conversion
BasicImageLayer::Paint swaps the BasicLayerManager's image factory into the
video ImageContainer for the duration of a paint. A decoder thread that calls
CreatePlanarYCbCrImage() inside that window gets a BasicPlanarYCbCrImage, and
VideoData::SetVideoDataToImage always requests delayed conversion before
CopyData(). CopyData copied the planes and then returned false, so
CreateAndCopyData returned null and the decoder reported
NS_ERROR_OUT_OF_MEMORY -> MEDIA_ERR_DECODE.

With OMTC off a software paint on the TouchPad takes 40-160 ms, so a decode
landed in the window within the first 10-60 frames of every clip.

Return the base copy's result, and true when conversion is delayed: the
image is fully usable, GetAsSourceSurface() converts on demand.
2026-10-12 19:28:53 -04:00
NotAlexNoyleandClaude Opus 4.8 cf7f9ede29 cubeb: classify media streams + export a playing-stream count for the daemon
Set media.role=music by default (tunable/disable via $JIHAD_STATE_DIR/pulse.props) so the
stream takes the webOS media-policy path (pmedia), and maintain an exported
jihad_pulse_active_streams() count (visibility(default), like MOZ_EXPORT) that the daemon polls
to hold the audiod media scenario + force the speaker route while audio plays. Per-stream flag
inc/dec on play/stop/destroy; calloc zero-inits it. UNVERIFIED by ear — see impl-audio-backend.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-12 19:28:53 -04:00
NotAlexNoyleandClaude Opus 4.8 29ce1a45ce videocontrols: surface media errors for audio-only content
setupStatusFader hid the status overlay for isAudioOnly unconditionally, which also hid
the ERROR state — so an <audio> whose format cannot be decoded (MP3/AAC have no decoder
in this build; err=4 MEDIA_ERR_SRC_NOT_SUPPORTED) rendered a live-looking control bar with
no failure shown (the forbidden works-looking-but-silent shape, gre-widgets R1). Keep the
throbber/loading suppression but let a genuine, non-suppressed video.error surface for
audio-only too. Normal decodable audio is untouched. Device-verified: MP3 <audio> now shows
the X + 'format is not supported' overlay.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-12 19:28:53 -04:00
NotAlexNoyleandClaude Opus 4.8 b708aa8f14 videocontrols: fix scrubber flicker/settle + interpolate the thumb
On the offscreen webOS surface the media-controls scrubber had three defects, all fixed
here (the flicker root cause was the daemon's per-buffer damage, fixed separately):

- showDuration ran every timeupdate, re-setting scrubber.max (relayout) and the thumb's
  showhours attr (restyle) each tick -> jitter + a flashing time bubble. Dedup on the
  finite duration so it runs once.
- 'ended' snapped the thumb to the throttled currentTime, a few ms short of the end, so it
  never came to rest at the clip end. Snap to duration for finite durations.
- timeupdate fires ~4x/sec, so the thumb stepped forward in visible jumps. A 40ms interval
  (25fps) drives the thumb position from the live currentTime clock while playing. 40ms is
  the ceiling: 25ms/40fps overruns the adapter's composite-and-return round-trip and stalls
  (checked against Atlas BrowserServer, which uses the same double-buffer + wait-for-return
  flow control with fewer buffers). Only nudges scrubber.value; duration stays owned by the
  event path; guarded on a known finite duration so it never runs before metadata.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-12 19:28:52 -04:00
NotAlexNoyle 41a5c06ed2 npapi child self drive switch
Subject: [PATCH 0031] npapi: JIHAD_PLUGIN_SELF_DRIVE=0 turns the plugin child's own repaint timer off

Part of the squashed engine commit 07259a27f0 that the per-subsystem queue (0001-0030) never
carried. The daemon sets JIHAD_PLUGIN_SELF_DRIVE=0 (EngineHost.cpp) so the host pull is the only
frame clock. Regenerated 2026-10-08 so that the queue reproduces the engine branch exactly
(build/engine/patch-queue.sh --check).
---

Imported from build/desktop/patches/0031-npapi-child-self-drive-switch.patch.
2026-10-12 19:28:52 -04:00
NotAlexNoyle 7c4c383e41 cubeb pulse webos virtual sink
(no description in the patch)

Imported from build/desktop/patches/0030-cubeb-pulse-webos-virtual-sink.patch.
2026-10-12 19:28:52 -04:00
NotAlexNoyle b55fad54f9 npapi plugin pull frame
Jihad Browser — pull the NPAPI plugin from the daemon's clock instead of sampling it.

WHY. Patch 0028 made card delivery 1:1 with the plugin but left TWO clocks running: the plugin
child re-posts its own repaint task 16 ms AFTER its work finishes, so its period is 16+work and
drifts, while the daemon ticks on its own timer. A frame landing just after maybePaint() waits a
whole tick, and since neither clock is locked to the other that wait varies frame to frame.
Device-measured with 0028 alone on a 30 fps SWF: 1:1 delivery, deferred=0, a healthy 29-32 fps
average — and a gap spread of 9-62 ms around a 33 ms target. That spread is the "smoother in the
stock browser" report, and the average cannot see it.

WHAT IT DOES. A new async parent->child JihadRequestFrame; the child answers it with its existing
JihadPalmRepaintTick(). The child's own timer stands down while host requests keep arriving, on a
LEASE rather than a latch — the daemon can stop asking at any moment (card backgrounded,
navigation, daemon stopped or crashed) and a latched plugin would then never paint again. The
daemon asks once per whole-tick grid slot and never stacks a second request while one is
outstanding. The parent exports jihad_plugin_request_frame(), weak-linked exactly like
jihad_plugin_frame_seq (0028), over a file-static list of live PluginInstanceParent actors; the
dtor leaves that list FIRST, because anything below it can spin the loop and a request delivered
to a half-destroyed actor is a use-after-free rather than a dropped frame.

MEASURED, AND IT IS NOT YET A WIN — read this before building on it. Device 2026-08-10, clean
restarts of jihad-anim.swf at JIHAD_TICK_MS=16:

                     0028 (sample)        0029 (pull)
  daemon done        29.4-31.9 fps        32.8-34.0 fps
  frame gap avg      31-34 ms             29-30 ms
  frame gap max      47-62 ms             45-55 ms
  gap hist <16 ms    1-4 of ~60           5-8 of ~68     <-- WORSE
  deferred           0                    0

Average and max improve; the HISTOGRAM gets flatter, which is the metric that matters. Two
measured reasons, and the instrumentation that found them is part of this patch:

1. THE LEASE FLAPPED. The daemon waits kJihadPluginReqTimeoutMs (250 ms) before re-asking for a
   late frame, but the lease was 150 ms — SHORTER — so one late frame dropped it and the child's
   timer restarted. The child logged HOST -> SELF -> HOST and the invalidate count split almost
   exactly in half. Fixed by an invariant rather than a tuned number: lease > request timeout +
   one grid period + margin. Verified: one "-> HOST" and no fallback for a whole run.
2. PATCH 0026's FOUNDING PREMISE IS FALSE, and this is the important one. With the lease fixed,
   1344 host requests still did not account for 2662 invalidates. Splitting the counter at the
   funnel by whether JihadPalmRepaintTick is on the stack gives hostinval ~27/s against
   plugininval ~22/s: THE PLUGIN INVALIDATES ITSELF CONSTANTLY. Three sessions believed otherwise
   because gJihadNPNInvalidateRectCalls — the counter 0026 reads — only sees calls that bind the
   NPN_InvalidateRect SYMBOL, while an ordinary NPAPI plugin calls through the NPNetscapeFuncs
   table into PluginModuleChild::_invalidaterect (:986, :1302-1310), which never touches the
   interpose. It can read 0 forever while the plugin invalidates 22 times a second.

So the remaining defect is TWO PRODUCERS BEATING, ours and Flash's, funnelled into one coalescing
path (~49 invalidates/s collapsing to ~32 draws/s). Whether this message should exist at all for a
self-invalidating plugin is open. The next experiment needs one more child-side kill switch:
JIHAD_PLUGIN_FRAME_MS=0 stops the pull but lets the lease expire and the timer take over, which is
just 0026 again.

Also here: the per-call-site draw counters (`show req:`) that made all of the above visible, and
that refuted the first hypothesis — the RecvUpdateBackground paths measured exactly zero.

Imported from build/desktop/patches/0029-npapi-plugin-pull-frame.patch.
2026-10-12 19:28:52 -04:00
NotAlexNoyle c24580c0af npapi plugin frame seq
Jihad Browser — export a plugin frame counter so the embedder can be 1:1 with the plugin.

WHY. The daemon's only signal that something changed is PuppetWidget's sticky dirty boolean,
and the refresh driver and ordinary page damage set the same flag, so "there is damage" cannot
answer "did the plugin draw again". With no way to tell a new plugin frame from a repeat, BOTH
publish policies are wrong, and both were measured on device 2026-08-10 with a 30 fps SWF:
publishing on every dirty tick sent ~78 card frames for ~60 plugin frames (duplicates, and
deferred 22-44 because the adapter could not drain that rate), while pacing on a fixed 33 ms
grid sent ~57 for ~68 and DROPPED frames, so the animation stepped two positions at once.

The stock webOS host never had to choose: PluginViewPalm pulls the plugin synchronously inside
the page paint, so it is 1:1 by construction. This counter is the minimum needed to get the same
property while still sampling: the daemon compares it against the value it saw at its last
publish. Measured with it: done=91 against palm draw=92, deferred=0.

Weak-linked on the daemon side exactly like jihad_offscreen_take_dirty, so a libxul without it
degrades to the old dirty-flag behaviour rather than failing to load.

Imported from build/desktop/patches/0028-npapi-plugin-frame-seq.patch.
2026-10-12 19:28:52 -04:00
NotAlexNoyle 9545d4bf1b npapi plugin cpu boost
(no description in the patch)

Imported from build/desktop/patches/0027-npapi-plugin-cpu-boost.patch.
2026-10-12 19:28:52 -04:00
NotAlexNoyle d561a4ce2e npapi plugin repaint rate
(no description in the patch)

Imported from build/desktop/patches/0026-npapi-plugin-repaint-rate.patch.
2026-10-12 19:28:52 -04:00
NotAlexNoyle fc3d98651d npapi pmlog named semaphore abi
(no description in the patch)

Imported from build/desktop/patches/0025-npapi-pmlog-named-semaphore-abi.patch.
2026-10-12 19:28:52 -04:00
NotAlexNoyle de345f9ce8 npapi webos plugin input
Jihad Browser — webOS NPAPI plugin INPUT, the frozen plugin YAP commands, and the frame path
that makes ANIMATED plugin content run (addons R7).

Applies on top of 0005, 0008 and 0016-0023. Supersedes the earlier 0024, which carried only the
input half.

── INPUT ───────────────────────────────────────────────────────────────────────────────────
1. npapi.h — NPEvent becomes Palm's real 48-byte event union on a headless XP_UNIX build
   instead of `typedef void*`. That typedef was not a harmless placeholder: NPRemoteEvent is a
   raw memcpy of sizeof(NPEvent), so the parent shipped four bytes of its own address space to
   the child. No event could ever have carried a payload. With a real POD the stock
   NPP_HandleEvent path carries a Palm event unmodified, with no paramtraits change.
2. nsPluginInstanceOwner.cpp — ProcessEvent gains the arm this toolkit never had. Its whole
   body was inside XP_MACOSX / XP_WIN / MOZ_X11, so on cairo-headless it reduced to
   `return eIgnore` and a windowless plugin got nothing for its entire lifetime. Mouse maps to
   npPalmPen{Down,Up,Move,Click,DoubleClick}, keys to npPalmKey{Down,Up,Press}, focus/blur to
   the npPalmSystemEvent pair, reusing the MOZ_X11 arm's plugin-local coordinate recipe and
   adding no zoom or scroll arithmetic of its own — which is what makes plugin input land where
   page content does.
3. PluginInstanceChild.{cpp,h} — drops the truncated private JihadNpPalm* mirrors for that
   NPEvent, asserts every offset against the libWebKitLuna address it was read from, and adds a
   capped input-delivery breadcrumb.
4. nsPluginHost.{cpp,h} — jihad_plugin_palm_spotlight, a MOZ_EXPORT'd C entry point (the
   jihad_offscreen_* precedent) so the daemon can deliver npPalmSpotlightStart/EndEvent for the
   frozen asyncCmdPluginSpotlight* commands. nsNPAPIPluginInstance::HandleEvent is neither
   exported nor virtual, so there is no other route.

── ANIMATION ───────────────────────────────────────────────────────────────────────────────
5. nsPluginInstanceOwner.cpp — the windowless invalidate now names the PLUGIN's box instead of
   the whole widget. 0021 invalidated nearest->GetBounds() on the reasoning that the daemon
   repainted everything anyway; once the daemon learned to repaint only damaged rows, that
   reasoning inverted and a full-viewport damage box forced the expensive path on every frame.
6. PuppetWidget.{cpp,h} — accumulate the bounding box of everything invalidated since the last
   drain, exposed as jihad_offscreen_take_dirty_rect beside the existing flag, so the daemon can
   repaint 320x240 (~2 ms) instead of the whole viewport (~38 ms).
7. PluginInstanceChild.cpp — the Palm draw event always covers the WHOLE plugin surface. The
   PGContext is built for the full surface, so pairing it with a dstBuffer offset into the
   middle of that surface made the plugin's blit run off the end — SIGBUS in the plugin child
   the moment the host started sending partial invalidations. Palm's own host never sent a
   partial rect either.
8. PluginInstanceParent.cpp — a bounded RecvShow frame-rate line, so the rate frames actually
   cross the process boundary can be compared against the rate the plugin was asked to draw.

Device-measured with a purpose-built 30fps SWF (render/goanna/test/make-anim-swf.py): the
plugin draws at 27-31 fps, every frame crosses IPC, and the card composites at 28.3 fps with an
average frame gap of 31-35 ms. Before this work the same content drew at 30 fps inside the
plugin and reached the screen 5 times in 25 seconds.

Imported from build/desktop/patches/0024-npapi-webos-plugin-input.patch.
2026-10-12 19:28:51 -04:00
NotAlexNoyle af703129f0 npapi operational logging
(no description in the patch)

Imported from build/desktop/patches/0023-npapi-operational-logging.patch.
2026-10-12 19:28:51 -04:00
NotAlexNoyle 924c474b07 npapi recvshow copy frameid
(no description in the patch)

Imported from build/desktop/patches/0022-npapi-recvshow-copy-frameid.patch.
2026-10-12 19:28:51 -04:00
NotAlexNoyle c378bf4ddc npapi windowless invalidate offscreen
(no description in the patch)

Imported from build/desktop/patches/0021-npapi-windowless-invalidate-offscreen.patch.
2026-10-12 19:28:51 -04:00
NotAlexNoyle bf56c41bf2 npapi composite without imagebridge
(no description in the patch)

Imported from build/desktop/patches/0020-npapi-composite-without-imagebridge.patch.
2026-10-12 19:28:51 -04:00
NotAlexNoyle 7725af0346 bhm null manager guard
(no description in the patch)

Imported from build/desktop/patches/0019-bhm-null-manager-guard.patch.
2026-10-12 19:28:51 -04:00
NotAlexNoyle 05d50a1f5a npapi child process loader
(no description in the patch)

Imported from build/desktop/patches/0018-npapi-child-process-loader.patch.
2026-10-12 19:28:51 -04:00
NotAlexNoyle 7768282869 npapi webos palm host
(no description in the patch)

Imported from build/desktop/patches/0017-npapi-webos-palm-host.patch.
2026-10-12 19:28:51 -04:00
NotAlexNoyle a93ef42dce npapi windowless headless
(no description in the patch)

Imported from build/desktop/patches/0016-npapi-windowless-headless.patch.
2026-10-12 19:28:50 -04:00
NotAlexNoyle 7169e40ddf find embedder no jscontext
(no description in the patch)

Imported from build/desktop/patches/0015-find-embedder-no-jscontext.patch.
2026-10-12 19:28:50 -04:00
NotAlexNoyle 956f449055 badcertlistener embedding
(no description in the patch)

Imported from build/desktop/patches/0014-badcertlistener-embedding.patch.
2026-10-12 19:28:50 -04:00
NotAlexNoyle 9083b311f2 xpi install embedding
(no description in the patch)

Imported from build/desktop/patches/0013-xpi-install-embedding.patch.
2026-10-12 19:28:50 -04:00
NotAlexNoyle 4222d1281e popup instrumentation
(no description in the patch)

Imported from build/desktop/patches/0012-popup-instrumentation.patch.
2026-10-12 19:28:50 -04:00
NotAlexNoyle c79165e512 appcompat guid
(no description in the patch)

Imported from build/desktop/patches/0011-appcompat-guid.patch.
2026-10-12 19:28:50 -04:00
NotAlexNoyle 539fe249de branding strip
Licensing/branding (cavekit-licensing-branding R3): strip Pale Moon / Basilisk / Moonchild branding URLs from the engine defaults; about:credits -> Jihad project page.

Generated as a clean diff against UXP upstream  (Pale Moon); applies
independently (distinct files) to the pristine third_party/uxp submodule.

Imported from build/desktop/patches/0010-branding-strip.patch.
2026-10-12 19:28:50 -04:00
NotAlexNoyle c0ae14fe34 misc headless
Misc headless build fixes (message_loop, XRE dir provider).

Generated as a clean diff against UXP upstream  (Pale Moon); applies
independently (distinct files) to the pristine third_party/uxp submodule.

Imported from build/desktop/patches/0009-misc-headless.patch.
2026-10-12 19:28:50 -04:00
NotAlexNoyle 1a20e65e4e plugin headless nativehandle
dom/plugins/ipc: define a NativeWindowHandle for the headless/PGContext platform so plugin IPC compiles.

Generated as a clean diff against UXP upstream  (Pale Moon); applies
independently (distinct files) to the pristine third_party/uxp submodule.

Imported from build/desktop/patches/0008-plugin-headless-nativehandle.patch.
2026-10-12 19:28:50 -04:00
NotAlexNoyle fcd8fe2598 nss mainthread marshal
NSS EnsureNSSInitialized main-thread marshaling fast-path (return once haveLoaded) so https-heavy pages don't flood the main thread.

Generated as a clean diff against UXP upstream  (Pale Moon); applies
independently (distinct files) to the pristine third_party/uxp submodule.

Imported from build/desktop/patches/0007-nss-mainthread-marshal.patch.
2026-10-12 19:28:49 -04:00
NotAlexNoyle ee1adb7fb1 headless toolkit
MOZ_WIDGET_TOOLKIT=headless: gfxPlatformHeadless + widget/headless backend + build wiring so libxul can link with no GTK/X (spike; Stage-1 GTK-bundled remains the shipping fallback).

Generated as a clean diff against UXP upstream  (Pale Moon); applies
independently (distinct files) to the pristine third_party/uxp submodule.

Imported from build/desktop/patches/0006-headless-toolkit.patch.
2026-10-12 19:28:49 -04:00
NotAlexNoyle f7ea599ff4 puppetwidget offscreen zoom
(no description in the patch)

Imported from build/desktop/patches/0005-puppetwidget-offscreen-zoom.patch.
2026-10-12 19:28:49 -04:00
NotAlexNoyle a01fdc5f31 gtk headless guards
Guard gtk realize/theme/look-and-feel paths so libxul runs with NO X server (headless offscreen render).

Generated as a clean diff against UXP upstream  (Pale Moon); applies
independently (distinct files) to the pristine third_party/uxp submodule.

Imported from build/desktop/patches/0004-gtk-headless-guards.patch.
2026-10-12 19:28:49 -04:00
NotAlexNoyle 2cd29aa972 gfx init and omtc
Force in-process BasicLayerManager (JIHAD_DISABLE_OMTC) + init gfxPlatform in XRE_InitEmbedding2 so gfxVars/gfxConfig are ready before first paint.

Generated as a clean diff against UXP upstream  (Pale Moon); applies
independently (distinct files) to the pristine third_party/uxp submodule.

Imported from build/desktop/patches/0003-gfx-init-and-omtc.patch.
2026-10-12 19:28:49 -04:00
NotAlexNoyle 24595cf058 configure warnings
Minor warnings.configure adjustment for the Jihad build.

Generated as a clean diff against UXP upstream  (Pale Moon); applies
independently (distinct files) to the pristine third_party/uxp submodule.

Imported from build/desktop/patches/0002-configure-warnings.patch.
2026-10-12 19:28:49 -04:00
NotAlexNoyle 7ae460b17a js format overflow
js/src appends -Werror=format after the warnings list, re-escalating -Wno-error=format-overflow; a source pragma is the only fix that wins.

Generated as a clean diff against UXP upstream  (Pale Moon); applies
independently (distinct files) to the pristine third_party/uxp submodule.

Imported from build/desktop/patches/0001-js-format-overflow.patch.
2026-10-12 19:28:49 -04:00
Moonchild 5f290d1097 Disable :has() pseudo on release by default
Since we don't have a solution for the performance issues for this yet,
and the perf issues are a serious QoL problem for all users on many sites.
2026-10-04 02:23:25 +02:00
Moonchild a0b10f4375 Issue #3197 - Make strict subtree form element checking preffed.
Resolves #3197
2026-10-03 21:22:00 +02:00
Moonchild 1d7ba07673 Issue #3196 - Handle BigInt objects in js::Unbox()
Resolves #3196
2026-10-03 21:21:53 +02:00
Moonchild f51bc72a14 [DOM] Don't leak elements with animated classes. 2026-10-03 21:21:46 +02:00
Moonchild e8644b494f [network] Prevent NTLM login attempt with empty credentials. 2026-10-03 21:21:38 +02:00
Andrew McCreight 0acf5cb1a1 Bug 2068346 - Unwrap a copy in GetJSValFromKeyPathString. 2026-10-03 21:21:31 +02:00
Moonchild f2d027343a Backport an upstream libvpx VP8 fix 2026-10-03 21:21:26 +02:00
Moonchild eaf2a4ac4b Minor formatting cleanup. 2026-10-03 21:21:16 +02:00
Moonchild aa6a599aa4 [network] Modernize MIME header parsing module.
- Use nsCStrings instead of char*
- More thorough checking for NUL characters
- Use the more modern utility includes
2026-10-03 21:21:05 +02:00
Moonchild f385a5e06c No issue - Add sanity check to JSScript::traceChildren
This verifies if objects to be traced are still valid, to prevent
GC barriers on dead/released objects. This should avoid some crashes.
2026-10-03 21:20:50 +02:00
Moonchild 559e0dbdc5 Issue #3192 - Add null check on group_ for isSingleton()
The value being monitored is a valid object, but its associated
ObjectGroup might have become invalid.

Resolves #3192
2026-10-03 21:20:42 +02:00
Moonchild e59e88bfd5 [DOM] Fix XSLT children processing.
This was an off-by-1 placement resulting in XSLT children processing
not working.
2026-09-21 11:26:39 +02:00
Moonchild 7e3d96909f [js] Fix issues in WeakRef deref() leading to crashes.
On rare occasions, reloading busy sites with WeakRef API usage would cause
CTDs. Digging into this it seems because of early teardown and/or dangling
pointers on WeakRef objects, causing `deref()` to crash.

This adds some null checks and avoids barriers on potentially invalid
WeakRef objects in the `deref()` implementation.
2026-09-19 14:51:09 +02:00
Maurice Dauer d294c31da1 Bug 2058069 - Compare formats before adopting a managed surface in Image9. 2026-09-19 14:51:02 +02:00
Jan-Niklas Jaeschke d699633e82 Bug 2058417 - Use the normalized format consistently in DataTransfer::SetDataAtInternal. 2026-09-19 14:50:55 +02:00
Moonchild 7079db6476 [embedding] Fix ChromeTooltipListener. 2026-09-19 14:50:48 +02:00
Moonchild e938cb015b [widget] Hold a reference to nsDataObj in callbacks.
As the comment in `WaitForCompletion` explains, it does a SpinEventLoopUntil
as part of CStream callbacks, and the CStream can be unregistered during that,
which is fine, but we need to hold a strong reference first since we use
the object afterward.  The reference in `WaitForCompletion` is technically
redundant but makes future uses safer and admits a comment that future clients
may actually heed.

This also adds an unrelated missing null check while we're here.
2026-09-19 14:50:42 +02:00
Moonchild 15893d9ebc [DOM] Bail on unexpected structural errors. 2026-09-19 14:50:35 +02:00
Moonchild 0f45bf39af [network] NTLM should always prompt for credentials if the host is not in trusted-uris. 2026-09-19 14:50:29 +02:00
Moonchild 23398d176b [a11y] Uncache subtree of hidden accessible when it is coalesced. 2026-09-19 14:50:23 +02:00
Basilisk-Dev 7809ecf653 Issue #3176 - Fix excessive :has() restyles when typing
Avoid restyling entire parent subtrees for changes that only affect a
child or sibling selector. Skip unrelated class changes, cache selector
dependencies, and avoid searching sibling subtrees that cannot match.

This improves typing performance on Gitea.
2026-09-19 14:49:44 +02:00
Basilisk-Dev 43d19989d4 No Issue - Fix out-of-range float to int32 conversions
Check the range before casting to int32_t. The old code had undefined
behavior that caused incorrect JavaScript numbers on LoongArch and broke
Anubis challenges.
2026-09-19 14:49:37 +02:00
Moonchild 81fce269f5 Revert "Issue #3176 - Pref off :has() by default on release"
This reverts commit aa066876a0.
2026-09-12 15:38:01 +02:00
Basilisk-Dev 03bdba053e Issue #3176 - Avoid :has() restyles for unrelated attribute changes
Track attribute names and class tokens used by relative selectors. Check classes before and after attribute updates so removing a watched class still invalidates its anchors, while unrelated changes avoid broad subtree restyles.

Preserve conservative handling of implicit pseudo-class attribute dependencies and explicit attribute selectors. Validated with a full build, runtime restyle counts, and 22 correctness checks.
2026-09-12 15:37:42 +02:00
Basilisk-Dev 5088774087 Issue #3176 - Reduce :has() restyle and selector matching overhead
Track state dependencies inside relative selectors to avoid restyling for unrelated state changes. Restrict parent dependency markers to sibling selectors while preserving outer sibling invalidation, and limit simple child and sibling searches to their candidate elements.
2026-09-12 15:37:24 +02:00
Andy c4d42aaeff Drop Dangling Plus Sign from 4c097ec9 2026-09-11 08:19:20 +02:00
Andy 5b5d7841a6 Remove Georgian Special Casing Skip
Cherry-Picked from BZ 1716482 and BZ 2000225 part 12.
2026-09-11 08:19:11 +02:00
Andy b5e48c5458 Include Cleanup
Cherry-picked from BZ 1999722.
2026-09-11 08:19:05 +02:00
Andy 714c06d255 Update ICU Build Flags
Skip BREAK_ITERATION and MF2.
MF2 Cherry-picked from BZ 1927706 Part 3.
2026-09-11 08:19:00 +02:00
Andy 42c59e0781 Update Likely Subtags for UTS 35
Cherry-picked from BZ 1927706 Part 6.
2026-09-11 08:18:55 +02:00
Andy a877a69089 Add RW fallback for non Gnu-C Compilers or Solaris 2026-09-11 08:18:47 +02:00
Andy 98a7463135 Move ICU Data to ReadOnly Section
This is adapted from BZ 1970788 (for Windows) and... some prior bug for Lin/Mac.
2026-09-11 08:18:41 +02:00
Basilisk-Dev 6cdcc60623 Improve typing performance on complex pages
Avoid redundant line lookups and preserve cached inline background state while painting fragmented inline content. This prevents per-keystroke repaint work from growing badly on long pages.

Ported from aab43246c5 (Mozilla bug 1539366).
2026-09-11 08:17:27 +02:00
Amelia Hart c4e2909bdc Remove obsoleted NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED 2026-09-11 08:17:10 +02:00
Amelia Hart 8f1b4387b4 Prevent potential leak of IndexedDB mDatabaseActor 2026-09-11 08:17:03 +02:00
Amelia Hart a7bc4e7c97 Prevent Fetch Request/Response from leaking mSignal 2026-09-11 08:16:56 +02:00
Amelia Hart 62e29a58b0 Make cycle collector aware of Timeout's mTimer. 2026-09-11 08:16:50 +02:00
Amelia Hart 3ede95de79 Implement cycle collection support for the Visual Viewport API 2026-09-11 08:16:44 +02:00
Amelia Hart fce465d3a6 Avoid triggering read barrier in DumpHeap and when collecting stats 2026-09-11 08:16:38 +02:00
Amelia Hart 71edc1fbf5 Assert GCRuntime::enter/leaveUnsafe region is main-thread only 2026-09-11 08:16:25 +02:00
Amelia Hart 53e4ec00ef Allow incremental GC when keepAtoms is set
This is a port of BZ 1213977 that should improve performance when parsing
large web-sites by reducing the amount of non-incremental (large) GCing.
2026-09-11 08:16:19 +02:00
Moonchild aa066876a0 Issue #3176 - Pref off :has() by default on release 2026-09-11 08:14:52 +02:00
Moonchild ae54d6c3d2 Issue #2473 - Follow-up: Pref the :has() selector. 2026-09-11 08:13:29 +02:00
Moonchild f69237e99c Merge branch 'master' into release 2026-09-03 15:26:51 +02:00
Moonchild a8fdbd677e [editor] Hold a strong ref. 2026-09-03 11:12:41 +02:00
Moonchild 5316be7d85 [DOM] Hold a strong ref to the composed document in nsFocusManager. 2026-09-02 19:37:51 +02:00
Moonchild ea9d3699b0 [network] Reject NUL bytes in chunked trailer and chunk-size lines.
Compliance with RFC 9110 section 5.5 - NUL is illegal in a chunk-size or
trailer field line.
2026-09-02 13:29:36 +02:00
Moonchild d0c059a3fd [widget] Only resolve non-filesystem picker results as shell libraries.
A genuine shell library is a virtual item with no filesystem path.  A
.library-ms file is an ordinary file whose XML can name any local directory.

filedialog::GetFolderResults was passing whatever IFileDialog::GetResult
returned to IShellLibrary::LoadLibraryFromItem and, on success, replacing it
with the library's embedded default save folder.

Gating the resolution on the item being affirmatively not a filesystem object
keeps real libraries selectable and resolving as before, while a .library-ms
file "resolves" to itself -- the .library-ms file, not its target.
2026-09-02 12:04:07 +02:00
Moonchild 3a285b8da5 Issue #3172 - Correct the issue reference in code.
See commit 0f0cbed455 for the code changes.
2026-09-02 11:03:37 +02:00
Moonchild d823df1bbb [DOM media] Reset CORS mode as-appropriate. 2026-09-02 00:35:43 +02:00
Moonchild a45c04623e Merge branch 'master' into release
# Conflicts:
#	devtools/client/jsonview/converter-child.js
#	js/src/jsprf.cpp
#	security/nss/coreconf/coreconf.dep
#	security/nss/lib/nss/nss.h
#	security/nss/lib/softoken/softkver.h
#	security/nss/lib/util/nssutil.h
2026-09-01 16:46:52 +02:00
Moonchild 0f0cbed455 Issue #3050 - Reduce parsing contention by limiting JS parser threads to 2. 2026-09-01 16:21:58 +02:00
Moonchild a7a133659a [widget] Set file picker default response to cancel.
While this apparently doesn't work in all flavors of GTK+, it's beneficial
if it does work, so it can't hurt to attempt, just to try and do what
we can about some wetware failure cases.
2026-09-01 16:18:26 +02:00
Moonchild 3a5a5501b9 Merge branch 'nss-3.126-port' 2026-08-27 13:55:59 +02:00
Moonchild 6b6b1828b9 NSS version bump to 3.90.14.0 (UXP) 2026-08-27 13:55:37 +02:00
John Schanck c42c56f40e Bug 2027388 - add defensive check on pk11_HandUnwrap key size. 2026-08-27 13:53:08 +02:00
Moonchild bada47c3e0 Bug 2029794 - handle NSSCertificate identity changing in __CERT_AddTempCertToPerm 2026-08-27 13:47:05 +02:00
Benjamin Beurdouche 896bdd4e87 Bug 2029750 - Reject undersized IV and key SECItems in PBES2 cipher dispatchers. 2026-08-27 12:43:11 +02:00
Benjamin Beurdouche 5faff628ca Bug 2029289 - fix off-by-one offset in pk11_buildNickname cert_id branch. 2026-08-27 12:37:01 +02:00
Moonchild 331f1d1716 Bug 2027380 - pass offset-adjusted pointer to SEC_ASN1GetSubtemplate in QuickDER call sites. 2026-08-27 09:40:51 +02:00
Moonchild 4c19b0c79b [DOM] Clear mDocumentChildren after XSLT branch consumes it in DidBuildModel. 2026-08-26 23:02:13 +02:00
Moonchild bb777d838d [DOM] Remove content from parent node before appending.
SetDocElement needs to do the same.
2026-08-26 22:57:42 +02:00
Moonchild cfd6c45250 [DOM] Remove content from parent node before appending. 2026-08-26 18:52:13 +02:00
Moonchild 04cc0dbd19 No issue - remove duplicate HTMLWin32ObjectAccessible from build.
This removes the make warnings when building. We shouldn't need this if
the plugin system is disabled.
Verified this builds correctly when NPAPI is disabled in mozconfig.
2026-08-26 15:18:00 +02:00
Olli Pettay 8e1b937e5f Bug 2058622 - Validate selected options entries. 2026-08-26 12:03:27 +02:00
Moonchild 51e966f1c1 [parser] Only check for high surrogates when intending to avoid split pair. 2026-08-26 10:45:06 +02:00
Moonchild f69570b516 [gfx] Skia: Port grey mode pixelspace fix. 2026-08-25 20:54:32 +02:00
Moonchild fb39488301 Merge pull request 'Resolve various assertions in debug builds' (#3171) from Jazzzny/UXP:assertions into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3171
2026-08-25 14:27:53 +00:00
Moonchild 5a3c14e2d3 [DOM] Improve MediaInfo/Data a little.
Only use ImageRect if explicitly set.
Reset the picture region when the decoder adopts a new image size from the stream.
Constrain the picture rectangle to the image buffer when building a video frame.
2026-08-24 15:02:06 +02:00
Moonchild a203222136 Merge pull request 'Prevent recursion of callbacks in PressShell.' (#3169) from restyle-recursion-fix into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3169
2026-08-24 01:51:42 +00:00
Moonchild f77b3dad07 Merge pull request 'Improve LoongArch64 Ion JIT and add SIMD groundwork' (#3170) from Basilisk-Dev/UXP-contrib:loongarch-jit-simd into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3170
2026-08-23 22:28:46 +00:00
Jazzzny 7d622afa70 Resolve various assertions in debug builds 2026-08-22 13:32:31 -04:00
Moonchild c22826727d [image] Simplify and further improve handling of destroying raster images.
Follow-up to [1842de878f]
2026-08-22 12:23:46 +02:00
Moonchild 8beee33f4c Bug 2057204 - use the right AddSystemEventListener variant with nsFileControlFrame::mMouseListener 2026-08-22 11:32:02 +02:00
Basilisk-Dev 0f0aeca2d5 Issue #3049 - Pass LoongArch64 SIMD args in vector registers 2026-08-21 22:41:08 -04:00
Basilisk-Dev 7e68ab76c8 Issue #3049 - Enable LoongArch64 SIMD codegen support 2026-08-21 22:41:08 -04:00
Basilisk-Dev 3984aba71e Issue #3049 - Add LoongArch64 LSX float vector helpers 2026-08-21 22:41:08 -04:00
Basilisk-Dev 81b9be16b3 Issue #3049 - Add LoongArch64 LSX compare and shift helpers 2026-08-21 22:41:08 -04:00
Basilisk-Dev cc636f5606 Issue #3049 - Add LoongArch64 LSX lane helpers 2026-08-21 22:41:08 -04:00
Basilisk-Dev 67716d3e77 Issue #3049 - Add LoongArch64 LSX arithmetic helpers 2026-08-21 22:41:08 -04:00
Basilisk-Dev 47671c9622 Issue #3049 - Add LoongArch64 SIMD constant loads 2026-08-21 22:41:07 -04:00
Basilisk-Dev 5f19acf3dc Issue #3049 - Track LoongArch64 SIMD return registers 2026-08-21 22:41:07 -04:00
Basilisk-Dev 271789ceff Issue #3049 - Handle LoongArch64 SIMD moves 2026-08-21 22:41:07 -04:00
Basilisk-Dev 124c914f35 Issue #3049 - Add LoongArch64 LSX vector move helpers 2026-08-21 22:41:07 -04:00
Basilisk-Dev 8499ba651d Issue #3049 - Add LoongArch64 LSX vector load stores 2026-08-21 22:41:07 -04:00
Basilisk-Dev 4a825adf7d Issue #3049 - Account for LoongArch64 SIMD FP aliases 2026-08-21 22:41:07 -04:00
Basilisk-Dev e6ff828ac7 Issue #3049 - Represent LoongArch64 SIMD register aliases 2026-08-21 22:41:07 -04:00
Basilisk-Dev 90031251c1 Issue #3049 - Make LoongArch64 FP saves SIMD-ready 2026-08-21 22:41:07 -04:00
Basilisk-Dev 059e6407d3 Issue #3049 - Prepare LoongArch64 ABI for SIMD arguments 2026-08-21 22:41:06 -04:00
Basilisk-Dev 46d37a2d26 Issue #3049 - Honor LoongArch64 FP ABI register fallback 2026-08-21 22:41:06 -04:00
Basilisk-Dev 3b5f764740 Issue #3049 - Improve LoongArch64 branch and trap handling 2026-08-21 18:07:08 -04:00
Basilisk-Dev 934d61ba05 Issue #3049 - Handle LoongArch64 subtract overflow edge case 2026-08-21 17:49:20 -04:00
Basilisk-Dev d609be5e04 Issue #3049 - Implement LoongArch64 int64 high-word wrapping 2026-08-21 17:48:07 -04:00
Moonchild a9b7af2c28 [layout] Prevent recursion of callbacks in PressShell. 2026-08-21 21:18:20 +02:00
Moonchild 501212e324 [gfx] Clean up cairo-win32-printing-surface.c
- Reformat code for readability.
- Check allocations in _cairo_win32_printing_surface_paint_linear_pattern.
2026-08-21 15:46:36 +02:00
Moonchild 7158edf5c8 [gfx fonts] Check format 4 subtable length and Zero newly-allocated range. 2026-08-20 15:45:42 +02:00
Moonchild fcc96573dd [gfx] Add buffer integer limit check to NVImage::GetAsSourceSurface. 2026-08-20 15:13:25 +02:00
Moonchild 79c57f2dab Merge pull request 'Restore the ability to compile on MIPS targets' (#3166) from Basilisk-Dev/UXP-contrib:mips-fix into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3166
2026-08-19 15:31:24 +00:00
Moonchild ed63bc8a89 [gfx] Hold a strong ref to platform font entry. 2026-08-19 15:24:35 +02:00
Moonchild 1de3a27f36 [DOM] Keep resized windows within reasonable bounds.
The size is now clamped to twice the available area of the screen the
window is on. Twice rather than exactly the screen, because the size we
get for a screen is not always accurate, on Wayland in particular... (¬_¬)
2026-08-19 11:18:02 +02:00
Moonchild e9d47c2c07 Merge pull request 'K.I.S.S.: Spot-fix jsprf for OS X 10.5 and 10.6' (#3164) from strnlen-kiss into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3164
2026-08-19 08:36:02 +00:00
Basilisk-Dev 1ba68a43cd Issue #3062 - Fix sspidermonkey and JIT issues when compiling on MIPS 2026-08-18 10:24:05 -04:00
Basilisk-Dev e60dbff022 Issue #3062 - Fix GNU assembler issues in libvpx on MIPS 2026-08-18 10:24:05 -04:00
Basilisk-Dev b3aad357ab Issue #3062 - Fix MIPS compilation in ffvpx 2026-08-18 10:24:00 -04:00
Moonchild 4c346cc711 Replace strnlen with memchr. See code comment. 2026-08-15 10:22:56 +02:00
Moonchild ca36b1f452 Merge pull request 'Implement support for adoptedStyleSheets' (#3161) from Basilisk-Dev/UXP-contrib:adoptedstylesheets into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3161
2026-08-13 13:05:05 +00:00
Basilisk-Dev 27195b1e7a Issue #3157 - Implement support for adoptedStyleSheets 2026-08-12 08:58:52 -04:00
Moonchild 948559c22c Revert "[parser] Restrict subtree root check to DOM image elements only."
As it turns out, the reported regression was actually noncompliant HTML
and the initial implementation was correct.

This reverts commit fc25f50e5f.
2026-08-11 17:39:55 +02:00
Moonchild 8e2a07c696 Revert "[parser] Restrict subtree root check to DOM image elements only."
As it turns out, the reported regression was actually noncompliant HTML
and the initial implementation was correct.

This reverts commit 9aa9d182c7.
2026-08-11 17:38:31 +02:00
Moonchild 9aa9d182c7 [parser] Restrict subtree root check to DOM image elements only.
This was too broadly applied, resulting in named form elements not being
accessible through the DOM tree if not in the same subtree root.
2026-08-11 07:43:56 +02:00
Moonchild b4bb6051e9 Revert "Bug 2033848 - Use non-default response ID for GTK file picker accept button. r=stransky"
This reverts commit 789e976ace.
2026-08-11 07:37:29 +02:00
Moonchild 5d7a1ca5a9 Merge pull request 'Several Python 3-related fixes to the build system' (#3160) from FranklinDM/UXP-contrib:work_python3-fixes-build1 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3160
2026-08-10 12:40:05 +00:00
Francis Dominic Fajardo 613443c5eb No issue - Remove old Python 2 workaround that encodes environment vars in bytes
This should fix installer packaging.
2026-08-10 19:10:18 +08:00
Basilisk-Dev d7884bb96c No issue - Fix faster build packaging on Python 3 2026-08-10 19:10:11 +08:00
Moonchild fc25f50e5f [parser] Restrict subtree root check to DOM image elements only.
This was too broadly applied, resulting in named form elements not being
accessible through the DOM tree if not in the same subtree root.
2026-08-09 18:50:50 +02:00
Moonchild b70b3a5aa1 Merge pull request 'Clean up NSIS scripting.' (#3121) from nsis-cleanup into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3121
2026-08-06 13:50:39 +00:00
Moonchild 88ae39ed04 Merge pull request 'Implement :has() CSS pseudo class' (#3152) from Basilisk-Dev/UXP-contrib:css-has into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3152
2026-08-06 06:34:14 +00:00
Basilisk-Dev d893526f82 Issue #2473 - Inline functions in CSS :has() implementation 2026-07-29 16:48:12 -04:00
Moonchild 53bf5b5a21 Bump NSS (UXP) patch level. 2026-07-28 15:51:54 +02:00
John Schanck 07b2881965 Bug 2043887 - guard against integer overflow in CERT_Hexify. 2026-07-28 15:51:45 +02:00
Benjamin Beurdouche ca1b7c2595 Bug 2027353 - clamp input.len to testString size in pk11_mergeSecretKey. 2026-07-28 15:51:41 +02:00
Benjamin Beurdouche a0d8eeb768 Bug 2029433 - Bounds-check wrap index in PK11_GetWrapKey to match PK11_SetWrapKey. 2026-07-28 15:51:34 +02:00
Anna Weine 278ce9a272 Bug 2028954 - CERT_DecodeAVAValue — Integer Overflow in Output Buffer Sizing. 2026-07-28 15:51:29 +02:00
Moonchild 9367b64f2a Bug 2027364 - Set tail pointer to null in static slot lists when deallocating. 2026-07-28 15:51:24 +02:00
John Schanck 080247cf2f Bug 2032110 - fix two integer overflows on LLP64 systems. 2026-07-28 15:51:19 +02:00
John Schanck 95bf9478c7 Bug 2030102 - avoid leaving a dangling ss->sec.ci.sid on allocation failure. 2026-07-28 15:51:13 +02:00
Maurice Dauer 4ae3149d2e Bug 2027325 - Reject empty nickname in PK11_TraverseCertsForNicknameInSlot. 2026-07-28 15:51:08 +02:00
Moonchild 9bf01636f1 Bug 2030563 - Validate CKA_CERTIFICATE_TYPE ulValueLen in nss_cert_type_from_ck_attrib. 2026-07-28 15:51:03 +02:00
Benjamin Beurdouche e48fe8e307 Bug 2029807 - Guard padding read against empty output in SEC_PKCS7DecryptContents. 2026-07-28 15:50:56 +02:00
Benjamin Beurdouche 27c12ad698 Bug 2027346 - validate encoded EC params length and tag in SECKEY_ECParamsToKeySize/BasePointOrderLen. 2026-07-28 15:50:51 +02:00
Benjamin Beurdouche 612ddb64e5 Bug 2027371 - rewrite labelLen bound in tls13_HkdfExpandLabelGeneral to avoid unsigned overflow. 2026-07-28 15:50:46 +02:00
Benjamin Beurdouche c6c8421a2a Bug 2027373 - guard space subtraction in ssl_CallCustomExtensionSenders. 2026-07-28 15:50:41 +02:00
Benjamin Beurdouche f9859d226c Bug 2029901 - Guard against keySize overflow in IKE PRF/PRF+ output sizing. 2026-07-28 15:50:36 +02:00
Benjamin Beurdouche 7c0e60c4f1 Bug 2027362 - bound usageCount in PK11_UnwrapPrivKey to keyTemplate capacity. 2026-07-28 15:50:27 +02:00
Benjamin Beurdouche e06ef010c4 Bug 2027349 - reject empty nickname in PK11_TraverseCertsForNicknameInSlot. 2026-07-28 15:50:20 +02:00
Moonchild 3935cd9ed3 [network] Fix CacheEntry::mDoomCallback data race. 2026-07-28 15:49:52 +02:00
Moonchild f781824676 [layout] Fix nsFrameSetFrame primary frame handling of replicated children. 2026-07-28 15:49:40 +02:00
Moonchild 5a231d5bf9 [DOM media] Perform more thorough checks on video regions. 2026-07-28 15:49:19 +02:00
az 02302031dd Bug 2045742 2026-07-28 15:49:11 +02:00
Andrew McCreight b59b350424 Bug 2049523 - Make ToJSValue for float consistent with double. 2026-07-28 15:48:56 +02:00
Moonchild 99b8669d0a Fix comment (nit) 2026-07-28 15:48:49 +02:00
Randell Jesup 919fbff2ec Bug 2029734: Flush before calling sctp_process_init() 2026-07-28 15:48:10 +02:00
Moonchild 4977713834 [image] Make sure the image was fully and cleanly decoded before finalizing its animation state as complete. 2026-07-28 15:48:01 +02:00
Moonchild 1f8bd8cf45 [parser] Associate image elements with form only if the form and the intended parent are in the same tree. 2026-07-28 15:47:55 +02:00
Moonchild 8f6bacf33e [DOM media] Stop accepting audio samples with too low sample rates.
This sets the floor to 8kHz audio, which is generally considered to be
the lowest acceptable "phone quality"/"walkie-talkie" audio rate.
Audio outside the range will refuse to decode after this commit and give
a console error.
This avoids a whole class of potential bugs.
2026-07-28 15:47:27 +02:00
Moonchild a79a1b55a1 [layout] Add corner-case correctness check in DottedCornerFinder::FindBestOverlap. 2026-07-28 15:47:21 +02:00
Moonchild fa4d389b91 [network] Add usrsctp TSN gap check. 2026-07-28 15:47:08 +02:00
Moonchild 36b884ff7f [js] Clamp length of regexp captures array for dollar substitution. 2026-07-28 15:46:52 +02:00
Moonchild f3a7e60608 [js] Initialize BaselineFrame return value slot in OnLeaveBaselineFrame. 2026-07-28 15:46:45 +02:00
Moonchild a8405c5667 [DOM] Make parser update form owner properly 2026-07-28 15:46:39 +02:00
Moonchild 829354fb65 [gfx] Hold a strong ref during GetFontAt lookup. 2026-07-28 15:46:33 +02:00
Moonchild 4be7883908 [gfx] Add bounds checks and limit reverse scanning of ligature data. 2026-07-28 15:46:27 +02:00
Moonchild 2f77b246b3 No issue - Use strnlen instead of strnlen_s.
Apparently, GCC doesn't like the _s variants.
2026-07-28 15:46:08 +02:00
Moonchild ddf950f5ed [js] Guard against OOB string sizes in internal Printf 2026-07-28 15:45:28 +02:00
Basilisk-Dev 7341809f67 Issue #2473 - implement :has() CSS pseudo class 2026-07-26 14:35:40 -04:00
Basilisk-Dev ad98fe5130 Issue #3140 - implement URL.parse() 2026-07-14 23:08:55 +02:00
Moonchild 659c690d5b Issue #3129 - Add palette_neon_intrinsics.c to moz.build 2026-06-23 08:11:16 +02:00
Moonchild f1dc542b0b Issue #3122 - Put base paths in the json viewer client deps.
The dependency modules are requested early. Seems CSP can block baseURL
on these networking requests, so add the base manually to the resource
paths to prevent network requests before the html base element is
resolved and active.
2026-06-22 18:54:00 +02:00
Moonchild 0c5437c80b Apply (hopefully for the last time before 2.0.x) APNG support code.
This commit also removes MOZCHANGES (old and irrelevant information)
This commit also adds a new readme.
2026-06-21 14:23:55 +02:00
Moonchild db9881b854 Fresh import of libpng 1.6.58 2026-06-21 14:23:47 +02:00
Moonchild c5a37cad2e Bump NSS version for adopted changes. 2026-06-21 14:23:40 +02:00
Moonchild dd97244289 [DOM] Clean up WebGL transform feedback validation. 2026-06-21 14:23:07 +02:00
John Schanck 5372fed15c Bug 2030564 - add defensive input validation to sftk_compute_ANSI_X9_63_kdf. 2026-06-21 14:22:56 +02:00
John Schanck 37a8909357 Bug 2030366 - avoid race with module unloading in NSSTrustDomain_FindTokensByURI. 2026-06-21 14:22:48 +02:00
John Schanck 18f4069d8d Bug 2029403 - avoid PORT_Strdup in ssl_DecodeResumptionToken. 2026-06-21 14:22:27 +02:00
Julian Descottes 78c01f1b3f [devtools] Consistently show filepicker on first save action from StyleEditor.
Bug 2038133
2026-06-21 14:22:18 +02:00
Moonchild f946c969a2 Issue #3127 - Add trademark notice to the tree.
Resolves #3127
2026-06-21 14:22:11 +02:00
Moonchild 2dfa2b7c19 [network] Make HttpBaseChannel::mLoadFlags atomic. 2026-06-21 14:21:44 +02:00
Moonchild 8b88dd736a [gfx] Check more offsets during CFF subsetting.
Also fixes a bunch of whitespace (TAB -> spaces)
2026-06-21 14:21:33 +02:00
Moonchild b9fd964fec [DOM] Avoid over-optimizing some getter/function calls. 2026-06-21 14:21:25 +02:00
Moonchild 9c74a819e4 [parser] Better align with spec definition of adding nodes. 2026-06-21 14:21:18 +02:00
Moonchild f700453cb1 No issue - Use ImmGCPtr for module meta data visits.
This should make module GCs less touchy.
2026-06-21 14:20:42 +02:00
Moonchild 4ea0375575 [DOM media] Zero-initialize ThreadSharedFloatArrayBufferList. 2026-06-21 14:20:33 +02:00
Kui-Feng Lee 7071894a52 Bug 2033848 - Use non-default response ID for GTK file picker accept button. r=stransky
Replace GTK_RESPONSE_ACCEPT (-3) with a non-negative application-defined
response ID (kFilePickerAccept = 0) for the accept button in the GTK file
chooser dialog, and remove the gtk_dialog_set_default_response() call.

GTK treats buttons with negative built-in response IDs as candidates for
the dialog's default widget, which activates on Enter key press. By using
a non-negative ID and not calling set_default_response(), the accept button
is no longer pre-selected, preventing a page from tricking the user into
confirming a file upload by holding Enter before the dialog appears.

GTK's file chooser internally emits GTK_RESPONSE_ACCEPT via file_activated_cb
when the user double-clicks a file, so we keep that case in DoneNonPortal()
alongside kFilePickerAccept.
2026-06-21 14:20:22 +02:00
John Schanck 0f471cfde7 Bug 2023478 - improve handling of escape sequences in pk11uri_ParseAttributes. 2026-06-21 14:20:15 +02:00
Moonchild a8cc198e79 [DOM] Reject too large mLength in MutableBlobStorage::WriteRunnable. 2026-06-21 14:20:09 +02:00
John Schanck 477b1010fe Bug 2030570 - use correct data for ID comparison in transfer_uri_certs_to_collection. 2026-06-21 14:20:02 +02:00
Moonchild 8722bc3693 [network] Make keep-alive pref Atomic. 2026-06-21 14:19:53 +02:00
John Schanck e31e3802a0 Bug 2029765 - avoid refcount over-release in nssTokenObjectCache error path [@ nssToken_Destroy]. 2026-06-21 14:19:46 +02:00
Nicolas B. Pierron 723d95295e Bug 2029066 - Remove Sinking of Live instructions.
Instruction sinking was made possible by the introduction of recover
instructions, which are moving instructions to be executed on bailout, but this
is only possible for instructions which are not used.

This feature, which is now removed, was made to sink instructions which are
live, but only in a small set of branches, by moving the computation of these
instructions to bailout paths, and to the concerned if branches.

The current implementation never delivered and remained as dead-code for
multiple years, without having a firm benefit on performance oriented
benchmarks.

Thus, this change removes the part of the Sink optimization which deals with
live instructions but keeps the part of the Sink optimization which deals with
instructions which are only used on bailout paths.
2026-06-21 14:19:37 +02:00
John Schanck 91b3b6fdc8 Bug 2029803 - add defensive info->len check in PK11_HPKE_SetupS and PK11_HPKE_SetupR. 2026-06-21 14:19:18 +02:00
Moonchild 34a901430d Issue #3122 - Exclude local resources from <base> CSP checks.
This avoids local-resource <base> URLs being restricted/nullified by
remote CSP. This aligns the CSP handling with direct requests.

Resolves #3122
2026-06-14 10:52:53 +02:00
Moonchild 21743e0b7c Issue #3120 - Clean up NSIS scripting.
Removes Quicklaunch shortcut code, UAC guards (always supported on target
OSes) and LSP guards (ditto).

Resolves #3120
2026-06-13 12:19:53 +02:00
Moonchild 83826f1f34 Issue #3111 - Clean up logic in SweepFinalizationRegistries.
Resolves #3111
2026-06-09 18:07:37 +02:00
Moonchild 3562ba1235 [DOM] Provide more silent audio processing frames. 2026-06-05 12:39:58 +02:00
Moonchild 1cc002018f Revert "Bug 2027433 Treat null input channels as zero in InterleaveAndConvertBuffer()"
This reverts commit e76fc5637a.
2026-06-05 11:38:27 +02:00
Moonchild 352863cab4 Revert "Bug 2027433 Treat null input channels as zero in AudioChannelsDownMix()"
This reverts commit ddd016a6f8.
2026-06-05 11:38:22 +02:00
Moonchild d69570b62b Revert "Bug 2027433 use nullptr for silent up-mix channels"
This reverts commit 5309640d6c.
2026-06-05 11:38:14 +02:00
Moonchild 26c44d4869 Issue #3109 - Use CSS' internal length clamp value instead. 2026-05-30 10:44:40 +02:00
Moonchild f10fc4489c Issue #3109 - Clamp border-radius value to Int32.MaxValue
This avoids artifacts from out-of-bounds values.
Resolves #3109
2026-05-30 10:44:32 +02:00
Moonchild 3450ed2282 Merge branch 'master' into release 2026-05-26 14:16:41 +02:00
Moonchild 967e985c5f Merge branch 'master' into release 2026-05-26 09:32:40 +02:00
Moonchild d6915b9014 Merge branch 'master' into release 2026-05-25 06:08:13 +02:00
Moonchild 304e6d045d Merge branch 'master' into release
# Conflicts:
#	dom/media/webm/WebMDemuxer.cpp
2026-05-24 10:11:40 +02:00
Moonchild 4dea7f04dc [gfx] Add sanity checks in ANGLE D3D11 renderer. 2026-04-29 15:06:03 +02:00
Moonchild 7cc35f1195 [DOM] Do not interrupt worker execution if already scheduled. 2026-04-29 15:05:56 +02:00
Moonchild afd0648631 [DOM] Validate size in FileReader. 2026-04-29 15:05:17 +02:00
Moonchild 6524bfee21 [DOM/media] Add some sanity checks to MP3 demuxer.
Note: `vbr.NumAudioFrames()` is already checked in `vbr.IsComplete()`
2026-04-29 15:05:11 +02:00
Iain Ireland de8c2d1762 Bug 2029806: Handle ill-formed UTF16 2026-04-29 15:05:06 +02:00
Karl Tomlinson 5309640d6c Bug 2027433 use nullptr for silent up-mix channels 2026-04-29 15:05:01 +02:00
Karl Tomlinson ddd016a6f8 Bug 2027433 Treat null input channels as zero in AudioChannelsDownMix() 2026-04-29 15:04:55 +02:00
Karl Tomlinson e76fc5637a Bug 2027433 Treat null input channels as zero in InterleaveAndConvertBuffer()
The loop nesting is inverted so as not to add a null check to the inner
loop, but this change would also have some impact on cache use:

* The loop ordering might perhaps not be the ideal for two channels and
large sample counts, for example, because it means going through the
output/largest buffer twice.
* It does, however, avoid pathological situations of iterating across
planar channel buffers, likely to load set-associative cache lines if
the channel buffers are page aligned, due to having 1024 (or somewhat
fewer) floats, for example.
2026-04-29 15:04:49 +02:00
Moonchild 62110dcf7f Revert "[DOM] Ensure the GC sees consistent states while adopting DOM nodes."
This reverts commit 7664a83451.
2026-04-28 17:39:16 +02:00
Moonchild c597f4de77 [NSS] Restore dropped 'S' :P 2026-04-26 17:06:16 +02:00
Moonchild fe4b55154b [NSS] Update NSS version for release.
Add (UXP) to the version display string to signify this is our variant of
NSS 3.90 to avoid confusion with the 3.90 branch used in Firefox 115 ESR.
This version has backported considerably more fixes than Mozilla's NSS.
2026-04-26 15:56:47 +02:00
Moonchild d9f4319bfd [parser] Handle foster parenting properly. 2026-04-26 15:56:36 +02:00
Moonchild ec7baced6c [media] Spot-fix for ffvpx handling of bad video data. 2026-04-26 15:56:28 +02:00
Moonchild 5ed591c3d7 [image] Don't do unnecessary work if the image is being destroyed. 2026-04-26 15:56:21 +02:00
Iain Ireland 32859868d6 Bug 2029727: Update RegExpStatics data after realloc 2026-04-26 15:56:09 +02:00
Moonchild 4ab80fceb4 [gfx] OTS/HB: Correct bounds checks. 2026-04-26 15:56:00 +02:00
Moonchild 4e25cc130f [js] Use isElement in UnmappedArgSetter to check if the argument was marked as deleted.
This is more consistent with `UnmappedArgGetter` and better handles the
case where the property was marked deleted in `RareArgumentsData` but not
actually deleted from the object due to OOM. Unfortunately this scenario
is hard to prevent because the property is marked as deleted in the
`ArgumentsObject::obj_delProperty` class hook and after that
`NativeDeleteProperty` tries to remove the property and this can fail.
2026-04-26 15:55:52 +02:00
Dennis Jackson f1b56f6512 Bug 2029323 - Improve size calculations in CMS content buffering 2026-04-26 15:55:38 +02:00
John Schanck b5d6c427ad Bug 2029425 - Heap use-after-free in cert_VerifyCertChainOld via dangling certsList[] entry on NameConstraints violation. 2026-04-26 15:55:29 +02:00
Moonchild 9a900503ea [image] Hold a strong ref on mInnerImage when requesting a refresh. 2026-04-26 15:55:22 +02:00
Moonchild f6296891bf [DOM] Add some death grips to TextTrackManager. 2026-04-26 15:55:17 +02:00
Moonchild bbd16ed644 [DOM/media] Use extended channel data as-appropriate. 2026-04-26 15:55:11 +02:00
John Schanck 8f6cd1cfcd Bug 2030135 - improve error handling in PK11_ImportPrivateKeyInfoAndReturnKey 2026-04-26 15:55:06 +02:00
Moonchild 70a3532f49 Revert "[gfx] Use local statics for harfbuzz callback pointers"
This reverts commit 60a96d9cd2.
2026-04-26 15:54:57 +02:00
Moonchild c160edb49b No issue - Update our in-tree brotli library to 1.2.0+
This includes a minor patch to encode.c to work around the "static init"
check that actually doesn't do anything in its default state, but, due to
compiler subtleties in handling duplicate object names, would not be able
to link brotli.exe because it would refuse to expose all symbols for
duplicate objects (a later one would just be ignored).
Unsure how clang does this but it's not portable across compilers.
(we need the brotli.exe tool for resource package compression)
2026-04-26 15:54:50 +02:00
John Schanck 32f0e6d1e6 Bug 2029462 - store email on subject cache_entry in NSS trust domain.
remove_email_entry used cert->email of the last-destroyed cert to locate
the hash entry to clean up. If that cert had no email, the entry was
silently skipped, leaving a dangling subjectList pointer after the arena
was freed. Store the registration-time email on the subject cache_entry
(mirroring ce->nickname) and thread it through remove_subject_entry so
removal always uses the correct email regardless of destruction order.
2026-04-26 15:54:36 +02:00
Moonchild 8c6098ed9e [security] Ensure DispatchToMainThreadAndWait isn't interrupted.
In some cases, `lock.wait()` can be interrupted by spurious wake-ups
before processing is done. To ensure things are, in fact, synchronous,
loop over `wait()` until it is actually done.
2026-04-26 15:54:26 +02:00
Timothy Nikkel 5f70302bfc Bug 2029291. 2026-04-26 15:54:16 +02:00
Jan de Mooij f1cc25409a Bug 2029317 - Create RareArgumentsData before mutating the arguments object in MappedArgumentsObject::obj_defineProperty. 2026-04-26 15:54:10 +02:00
Jan-Ivar Bruaroey 1bb67f87d1 Bug 2029423 - Reset post_proc state. 2026-04-26 15:53:55 +02:00
Andy Leiserson 6f89be191d Bug 2029427 - Fix format string 2026-04-26 15:53:50 +02:00
Moonchild f453aac0eb [gfx] Explicitly cast calculation to int32. 2026-04-26 15:53:42 +02:00
Moonchild abc2e56e6a [gfx] Port libyuv upstream bounds check. 2026-04-26 15:53:31 +02:00
Simon Farre 2f2c86599f Bug 2025973 - Use value-semantics for txExecutionState::TemplateRule
TemplateRule is a wrapper around references mostly and can for the
purposes of this function be copied to the stack, given that
TemplateRule::mModeNsId is not mutated there.
2026-04-26 15:53:24 +02:00
Dennis Jackson a52e68f04d [NSS] Clarify extension negotiation mechanism for TLS Handshakes. 2026-04-26 15:53:16 +02:00
Moonchild ee256eda09 [js] Only allow strings as function name. 2026-04-26 15:53:07 +02:00
Olli Pettay adbedd87a3 Bug 2025370 - Properly handle error case in EventListenerManager::GetTypedEventHandler 2026-04-26 15:52:46 +02:00
Moonchild 4f94981ad9 [DOM/XSLT] Don't use txXPathNode by reference.
Follow-up to previous XSLT fixes.
2026-04-26 15:52:36 +02:00
Moonchild fb15e11ef3 [gfx] Stop using binary arithmetic in software filtering.
There was some weird binary arithmetic to artificially clamp values in
calculations for dot products. (multiply by (x >= 0)...)
Switch to `std::clamp()` on the initial value instead.
2026-04-26 15:52:31 +02:00
Tom Schuster b0e1570535 Bug 2025332 - ErrorResult should call ClearUnionData more. 2026-04-26 15:52:26 +02:00
Karl Tomlinson b370042040 Bug 2025483 update mBeginProcessing even on speex_resampler_set_rate() error 2026-04-26 15:52:20 +02:00
Moonchild 60daf77274 [NSS] Deep copy profile data in CERT_FindSMimeProfile. 2026-04-26 15:52:15 +02:00
Moonchild 4f9ed77789 [DOM/XSLT] Prevent circular indexing
Added additional flag to txIndexedKeyHashEntry to signal whether or not
this entry is already in the process of indexing.

The XSL specs 3.0 talk about recursion being fine, but circularity not
being ok, which is the case when a key is already being looked up.
2026-04-26 15:52:04 +02:00
Moonchild c819a0b3c8 No issue - Deduplicate HTMLAllCollection::GetSupportedNames code.
This was duplicated with a minor difference from the code present in
nsContentList::GetSupportedNames.
2026-04-26 15:51:57 +02:00
Moonchild 104f493044 [NSS] Reject excessively large ASN.1 SEQUENCE OF in quickder. 2026-04-26 15:51:14 +02:00
Moonchild ccfb3fc5db [DOM] Avoid leaks in nsXMLPrettyPrinter. 2026-04-26 15:51:05 +02:00
Moonchild 9fa543c9f4 [DOM/WebCrypto] Reject absurdly large salt values. 2026-04-26 15:51:00 +02:00
Moonchild 1d18178eda [DOM] Add a death grip and use locals in BaseMediaResource::ModifyLoadFlags. 2026-04-26 15:50:54 +02:00
Moonchild 8a6b1f309b [DOM] Add a SequenceRooter to ConsoleProfile. 2026-04-26 15:50:48 +02:00
Moonchild a60ab0def7 [widget] Improve clearing of data during clipboard operations. 2026-04-26 15:50:40 +02:00
Daniel Holbert 6276177e20 Bug 2026293: Block scripts when initiating async scrollbar activity. 2026-04-26 15:50:33 +02:00
Moonchild 6c4e8f1466 [accessibility] Hold a strong ref to mParent in AccIterator. 2026-04-26 15:50:22 +02:00
Moonchild 19a4ae248b [gfx] Don't return dummy surfaces. 2026-04-26 15:50:16 +02:00
Moonchild 744212dbf3 [webrtc] Fix off-by-one comparison. 2026-04-26 15:50:10 +02:00
Simon Farre a46fbd6ead Bug 2025971 - Use txSingleNodeContext getter of owned txXPathNode.
eContext gets a copy of aNode. The function should use that one's member
as it's not a shared reference, which we can't know the life time of.
2026-04-26 15:50:04 +02:00
Moonchild bb39100caf Bug 2025976 - Follow-up: Make txXPathNode() a public class member. 2026-04-26 15:49:51 +02:00
Moonchild a27a4e4b60 [DOM/XSLT] Re-fetch index entry. 2026-04-26 15:49:45 +02:00
Simon Farre 490cf03fba Bug 2025976 - Make txxPathNode be a value instead of reference.
txxPathNode has value semantics (it's a smart pointer + uint32_t index;
two different objects of this instance with the same contents are the same
thing).

Increase correctness by making a copy instead of a reference.
2026-04-26 15:49:40 +02:00
Moonchild e93191409e [NSS] Improve input validation in DSAU signature decoding 2026-04-26 15:49:33 +02:00
Moonchild 5cfdaf4ad4 [image] Hold a strong ref on error. 2026-04-26 15:49:28 +02:00
Moonchild 7664a83451 [DOM] Ensure the GC sees consistent states while adopting DOM nodes.
This should prevent some intermittent CC crashes when the wrapper cache
has an incorrect state.
2026-04-26 15:49:22 +02:00
Moonchild f449e1fd7d [DOM] Improve CC/WrapperCache for nursery objects. 2026-04-26 15:49:16 +02:00
Moonchild bbd4a99be2 [network] Ensure UDPSocket remains alive during CloseWithReason. 2026-04-26 15:49:11 +02:00
Moonchild 4ae471baf9 [network] Hold strong ref in nsSyncStreamListener::Available. 2026-04-26 15:49:01 +02:00
Moonchild 4d41b5df11 [network] Force NUL termination in ToStringBuffer AF_LOCAL.
Also reject AF_LOCAL in IPC reader (just in case).
2026-04-26 15:48:54 +02:00
Moonchild 01188c1465 [webrtc] Hold a self-ref on behalf of sigslot, just in case.
Also, stop using these PC_AUTO_ENTER_API_CALL... macros
in functions that aren't actually JS API.
2026-04-26 15:48:41 +02:00
Moonchild 7eac3090a5 [DOM] Fix access to shared RuntimeService::mNavigatorProperties. 2026-04-26 15:48:28 +02:00
Moonchild e9bb602131 Issue #3060 - Align cookie magic prefix handling with the updated spec.
This adds `__Http-` and `__Host-Http-` magic prefixes, and aligns
our checks with RFC6265bis.

Resolves #3060
2026-04-26 15:48:16 +02:00
Moonchild ddc8b21705 [network] Handle WebSocketChannel::IsPersistentFramePtr correctly. 2026-04-26 15:47:59 +02:00
Moonchild 6209d33f4e [network] Hold strong ref in nsDownloader::OnDataAvailable. 2026-04-26 15:47:50 +02:00
Moonchild cbaace24c0 [DOM] Add a death grip. 2026-04-26 15:47:44 +02:00
Moonchild 051951ef00 [network] Use locals for VisitHeader 2026-04-26 15:47:38 +02:00
Moonchild a9062b8710 [DOM] Update some DOM canvas checks. 2026-04-26 15:47:14 +02:00
Moonchild 18c656ebba Issue #3058 - Part 1: Fix arithmetic issue in ConvertYCbCrToRGB32
The more complex part can be landed later.
2026-04-26 15:46:58 +02:00
Moonchild 9220d05de2 [NSS] Fix memory leak in NSC_GenerateKey error path. 2026-04-26 15:46:43 +02:00
Moonchild fdd286d190 [NSS] Protect rwSessionCount with slotLock.
Previously, SFTKSlot.rwSessionCount was incremented and decremented
atomically, which meant that there was no way to synchronize reads from it
in NSC_GetTokenInfo. This patch removes the atomic operations but protects
rwSessionCount with SFTKSlot.slotLock.
SFTKSlot.sessionCount is already protected in this way, so this should
have no performance impact.
2026-04-26 15:46:29 +02:00
Moonchild 4fa8a8ce1d [NSS] Fix potential integer underflow in tls 1.3.
Fix integer underflow in tls13_AEAD when ciphertext is shorter than tag.
2026-04-26 15:46:24 +02:00
Moonchild d5e853a25b [media] Check alpha data pointer instead of length.
`nestegg_packet_additional_data()` can return a non-zero length with a
null-pointer after failure to parse an ID_BLOCK_ADDITIONAL element.
See upstream bug https://github.com/mozilla/nestegg/issues/76
2026-04-26 15:46:18 +02:00
Moonchild 6ea3635847 [network] use nsCOMPtr for mRequest in Base Channel's ScopedRequestSuspender 2026-04-26 15:46:09 +02:00
Moonchild 0ea3d42a38 Issue #2946 - Follow-up: Sanity-check WMF video properties.
Not sure where else to put this under, but it's a WMF HWA related check,
so filing it as a follow-up here to recent work.
Also tag #2949
2026-04-26 15:45:50 +02:00
Moonchild a024df6124 [DOM] More consistently use already-calculated image properties. 2026-04-26 15:45:33 +02:00
Moonchild 11a80021f4 [layout] Minor frame scroll improvements. 2026-04-26 15:45:26 +02:00
Moonchild 301873c751 [XPCOM] Update list of executable extensions on Windows. 2026-04-26 15:45:18 +02:00
Moonchild 90986caee8 [NSS] ensure permittedSubtrees don't match wildcards that could be outside
the permitted tree.
2026-04-26 15:45:12 +02:00
Moonchild 778d93ac49 [network] Ignore non-compliant http server header. 2026-04-03 07:38:32 +02:00
Moonchild f9ba08fa11 [NSS] Update NSS to 3.90.9.1 (custom) 2026-04-03 07:38:24 +02:00
Moonchild 95911aa2ce [gfx] Use local statics for harfbuzz callback pointers
This ensures thread-safe initialization.
2026-04-03 07:38:10 +02:00
Moonchild ccbea05142 [XPCOM] Add more validation to SnappyUncompressInputStream 2026-04-03 07:37:56 +02:00
Moonchild 867c957ceb No issue - Add convolver sanity check 2026-04-03 07:37:41 +02:00
Moonchild 0d2ff3ee65 Merge branch 'master' into release 2026-03-28 19:02:37 +01:00
Moonchild 14122475be Issue #2981 - Add nullcheck in GetPointerCapabilities (uplift)
Uplift to release.
2026-03-09 11:32:39 +01:00
Moonchild d881e7ed56 Merge branch 'master' into release 2026-03-01 23:37:59 +01:00
Moonchild 9b0054c55f Merge branch 'master' into release 2026-02-27 19:28:35 +01:00
Moonchild baeae97784 Merge branch 'master' into release 2026-02-27 07:08:35 +01:00
Moonchild 0324bfa219 Re-sync master to release.
Post-merge synchronization to bypass rebase-shenanigans after backouts.
2026-02-24 17:25:53 +01:00
Moonchild b279fd025b Merge branch 'master' into release
# Conflicts:
#	js/src/jit/CodeGenerator.cpp
#	js/src/jit/arm/Lowering-arm.cpp
#	js/src/jit/arm64/Lowering-arm64.cpp
#	js/src/jit/mips32/Lowering-mips32.cpp
#	js/src/jit/mips64/Lowering-mips64.cpp
#	js/src/jit/shared/LIR-shared.h
#	js/src/jit/x64/Lowering-x64.cpp
#	js/src/jit/x86/Lowering-x86.cpp
#	mfbt/Xoroshiro128PlusPlusRNG.h
#	parser/expat/lib/xmlparse.c
2026-02-24 14:37:42 +01:00
Francis Dominic Fajardo f31546817a Issue #2828 - Follow-up: Simplify rule node tracking and ensure rule walker state isn't reset for the first child processor (uplift)
Styles contained in NAC shouldn't be tracked with their own rule node (as opposed to what was done in https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2859) because it causes precedence issues. This should now more closely imitate the original behavior where NAC and regular document styles (at least, the "unlayered" layer) are grouped together.

This also gets rid of the manual last rule node checks against null, since they are now consistently handled by the separate function.
2026-01-25 14:44:49 +01:00
Moonchild f272382a9c Revert "Issue #2895 - Part 1: Replace XorShift128+ with Xoroshiro128++"
This reverts commit c90df0c332.
2026-01-21 10:18:46 +01:00
Moonchild aa8af9d7f8 Revert "Issue #2895 - Part 2: Remove incorrect debug asserts."
This reverts commit 97786271f9.
2026-01-21 10:18:38 +01:00
Moonchild e1f03ae019 Revert "Issue #2895 - Part 1b: Update license block."
This reverts commit 12821ae90a.
2026-01-21 10:18:08 +01:00
Moonchild f316bc6535 Revert "Issue #2895 - Follow-up: Fix JIT code generator for 32-bit targets."
This reverts commit 8112ed2e6c.
2026-01-21 10:17:51 +01:00
Moonchild 82e4c66520 Revert "Issue #2889 - Part 0: Relocate Mozilla-specific files from Expat source."
This reverts commit f93d0fadf2.
2026-01-21 10:04:52 +01:00
Moonchild 3c923e0467 Revert "Issue #2889 - Part 1: Prepare Mozilla's changes and extensions for Expat 2.6.4."
This reverts commit 6c7850482f.
2026-01-21 10:04:44 +01:00
Moonchild 866985ac88 Revert "Issue #2889 - Part 2: Import Expat 2.6.4 source."
This reverts commit e7cacf4642.
2026-01-21 10:04:37 +01:00
Moonchild ba772b40ad Revert "Issue #2889 - Part 3: Apply Mozilla's patches to Expat 2.6.4."
This reverts commit 2ae8833092.
2026-01-21 10:04:29 +01:00
Moonchild 7a86f0e1b7 Revert "Issue #2889 - Part 4: Fix build and runtime issues."
This reverts commit ef1532cab2.
2026-01-21 10:04:22 +01:00
Moonchild 7e9286f2d8 Revert "Issue #2889 - Follow-up: Avoid conflicts with system version of libexpat"
This reverts commit e284ffab6c.
2026-01-21 10:04:14 +01:00
Moonchild b0d1e365ec Revert "Issue #2889 - Follow-up: void methods shouldn't return a value."
This reverts commit 647a1ab5f0.
2026-01-21 10:04:07 +01:00
Moonchild dbd5a2cbf4 Revert "Issue #2889 - Part 5: Rewrite patches for Expat 2.7.3."
This reverts commit 0f1faad9a3.
2026-01-21 10:03:58 +01:00
Moonchild d60fb1d5c0 Revert "Issue #2889 - Part 6: Import Expat 2.7.3 source."
This reverts commit 627fdf8fe4.
2026-01-21 10:03:49 +01:00
Moonchild 29c91fcdba Revert "Issue #2889 - Part 7: Apply patches to Expat 2.7.3."
This reverts commit 112abdc25a.
2026-01-21 10:03:40 +01:00
Moonchild fe65674f3f Revert "Issue #2889 - Follow-up: Allow generate_hash_secret_salt to be used." 2026-01-21 10:03:24 +01:00
Moonchild a3a6b5ed7e Revert "Issue #2889 - Follow-up: Adjust Expat 2.7.3 local patches for removal of 3rd patch."
This reverts commit 073378ec92.
2026-01-21 10:01:44 +01:00
Moonchild d2de8658a7 Revert "Issue #2889 - Follow-up: Remove fix for BZ 569229."
This reverts commit a22613d3e0.
2026-01-21 10:01:37 +01:00
Moonchild be785b4783 Merge branch 'master' into release
This resyncs platform to master, overwriting more recent backouts from
the release branch.
2026-01-16 23:16:32 +01:00
Moonchild 70e34941c4 [devtools] Remove newline kludge from "Copy as cURL" on Windows 2025-10-15 19:46:52 +02:00
Moonchild 545d52572d Revert "Issue #2828 - Part 1: Build and store the array of layer name tokens in the layer at-rules"
This reverts commit 253ec6706a.
2025-10-08 23:24:27 +02:00
Moonchild dfa0736b49 Revert "Issue #2828 - Part 2: Collect and hold rule cascade data per cascade layer"
This reverts commit a91b385f68.
2025-10-08 23:24:20 +02:00
Moonchild c7bb5664d9 Revert "Issue #2828 - Part 3: Refactor selector matching and rule cascade data into separate files/classes"
This reverts commit 211aa6d652.
2025-10-08 23:24:13 +02:00
Moonchild 6bbc6f3417 Revert "Issue #2828 - Part 4: Move cache key storage to ResolvedRuleCascades"
This reverts commit 202e354f87.
2025-10-08 23:24:07 +02:00
Moonchild 631169a312 Revert "Issue #2828 - Part 5: Implement child rule processors"
This reverts commit bc45ec4f57.
2025-10-08 23:24:02 +02:00
Moonchild 427b3312a6 Revert "Issue #2828 - Part 6: Assert rules were added to the rule cascade data"
This reverts commit be7a231579.
2025-10-08 23:23:56 +02:00
Moonchild 2287b0b57a Revert "Issue #2828 - Part 7: Walk child rule processors separately and ensure inverted cascade layer order is enforced for important rules"
This reverts commit c3e12fe822.
2025-10-08 23:23:50 +02:00
Moonchild 56aaba09b1 Revert "Issue #2828 - Part 8: Extract RuleProcessorGroup (formerly ResolvedRuleCascades) into separate file"
This reverts commit 5fda071898.
2025-10-08 23:23:45 +02:00
Moonchild 332938fef3 Revert "Issue #2828 - Part 9: Rename CascadeEnumData to CascadeLayer"
This reverts commit ebb0ae456c.
2025-10-08 23:23:39 +02:00
Moonchild 13710f7a06 Revert "Issue #2828 – Part 10: Clean up cascade layer constructor"
This reverts commit 047458a002.
2025-10-08 23:23:33 +02:00
Moonchild 530693099b Revert "Issue #2828 - Part 11: Detach weighted rule data from cascade layer"
This reverts commit b1c19137ad.
2025-10-08 23:23:28 +02:00
Moonchild f68aa7ea88 Revert "Issue #2828 - Part 12: Implement cascade layer SizeOfIncludingThis"
This reverts commit 5ef79e303f.
2025-10-08 23:23:23 +02:00
Moonchild 5bdaee5e40 Revert "Issue #2828 - Part 13: Exclude strong layers-related code from release builds"
This reverts commit e82fa3450a.
2025-10-08 23:23:18 +02:00
Moonchild 1b465bc2e2 Revert "Issue #2828 - Part 14: Clobber required for CSS rule processor refactoring"
This reverts commit 038c5a95fc.
2025-10-08 23:23:12 +02:00
Moonchild e455021bea Revert "Issue #2835 - Part 1: Expose nsCSSRuleProcessor::CascadeSheet"
This reverts commit 618f62e753.
2025-10-08 23:23:02 +02:00
Moonchild 4fe1246bcc Revert "Issue #2835 - Part 2: Implement processing of import rules based on order of appearance"
This reverts commit 2ba24302d9.
2025-10-08 23:22:57 +02:00
Moonchild 59b4ac4d5f Revert "Issue #2835 - Follow-up: Guard against import rules with no attached style sheet"
This reverts commit 5fccc6ec3d.
2025-10-08 23:22:42 +02:00
Moonchild de641fedfe Merge branch 'master' into release 2025-10-02 21:21:39 +02:00
Moonchild cb99fabcc0 Merge branch 'master' into release 2025-09-24 10:33:48 +02:00
Moonchild f996ea12c2 Merge branch 'master' into release 2025-09-19 21:04:01 +02:00
Moonchild 4e7fb3e0ea Merge branch 'master' into release 2025-09-18 13:15:14 +02:00
Moonchild e7cbbbef0f Merge branch 'master' into release 2025-09-14 11:54:15 +02:00
Moonchild a181078981 Revert "[gfx] Guard against possible race via gfxFontEntry::GetFontTable."
This reverts commit 98ddf30155.
2025-08-27 15:54:15 +02:00
Moonchild 987a662b51 [NSS] Avoid leak in pkcs12 decoder. 2025-08-20 16:26:17 +02:00
Moonchild 77e3e14e55 [js] Error-check pthread calls
These calls return error states (int) that weren't checked for success.
Failures here are fatal, so using MOZ_RELEASE_ASSERT to safely crash.
2025-08-20 16:26:10 +02:00
Moonchild 98ddf30155 [gfx] Guard against possible race via gfxFontEntry::GetFontTable. 2025-08-20 16:26:03 +02:00
Moonchild 83da5c58a2 Issue #2850 - Alias :focus-visible to :-moz-focusring
Band-aid to have it be parsed as valid with reasonably-expected behaviour.
2025-08-17 10:46:32 +02:00
Moonchild 7136ae45a7 [DOM] Simplify <object> scheme check code and fix plugin handling.
Trying to do a positive check on nested URIs apparently doesn't work,
but the handling could be simplified to just check for non-null mURI
instead - this also fixes plugin loading (which broke with the previous
check).
2025-07-31 10:44:08 +02:00
Moonchild 97d3d61749 [DOM] Fix crash in <object> scheme checking code.
If a website would nor supply a URI for object loading code, the browser
would crash on a null deref.
This reintroduces the nestedURI check to make sure we have a valid URI.
2025-07-30 09:29:51 +02:00
Sergey Larin 9c8bf1fe5d No Issue - Disable VSX extensions (uplift)
There is no detection script for them as for AltiVec, and
it's breaking older machines (PowerMac G5 in particular).
2025-07-25 16:57:09 +02:00
Sergey Larin d1cc6ff3cb Issue #2777 - Fix ffvpx build on PPC64 (uplift) 2025-07-25 16:55:27 +02:00
Moonchild db76d74820 [DOM] Make object loading use an explicit scheme whitelist. 2025-07-25 14:23:45 +02:00
Moonchild 8fdd9d52f9 [network] Stop accepting nameless cookies. 2025-07-25 14:23:34 +02:00
Moonchild d42797f587 [js] Align br_table limits with V8/Gecko. 2025-07-25 14:23:18 +02:00
Moonchild 6b9c1f6ab8 [gfx] Hold a stronger reference to gfxFontEntry. 2025-07-25 14:23:10 +02:00
Moonchild 4aedc96db2 No issue - Adjust CSP URI reporting more closely with the spec.
According to the W3C discussion we should allow websocket URIs to be
reported aside from http/https/ftp ones.
This rewrites things slightly and updates comments to clarify.
We do retain the non-standard reduction to origin only in case the
report is for cross-origin URIs (stops leaking full URIs to the CSP
reported destination).
See https://github.com/w3c/webappsec-csp/issues/735
2025-07-25 14:22:58 +02:00
Francis Dominic Fajardo 234830da1e Issue #2826 - Set up fontconfig on XRE startup (GTK only) 2025-07-25 14:22:35 +02:00
Moonchild 244b95968f Issue #2720 - Follow-up: Use temp value for duplicate color stop 2025-07-25 14:20:13 +02:00
Moonchild 810cd553b5 [devtools] Further improve special character escaping in "copy as curl".
Follow-up to 15335ce39d

Trying to cross-platform sanitize causes issues escaping too much and
as a result mangling the curl commands that get spit out.
This reverts previously added Windows-specific escaping on POSIX and
vice versa.
Since we do not offer cross-platform copying as a curl command in devtools
anyway, it makes little sense to sanitize for the O.S. we're not running on
as we would not be using the command processor in such environments that
could trip over characters for the other O.S. This was previously added
as a defense-in-depth in case we would start offering this, but I see no
real reason to do so, anyway.

Also decided to in-line comments for readability instead of a bulleted
list in the function head.

Mozilla has taken similar steps because of fall-out, but they do offer
cross-platform "copy as curl" for corner cases, so they will have to
find solutions for a problem we won't have.
2025-07-08 22:57:28 +02:00
Basilisk-dev e52eaa961c Issue #2773 - Allow building FFVPX on all architectures (uplift)
Resolves build bustage.
2025-07-03 20:16:10 +02:00
Moonchild b7827091b8 Merge branch 'master' into release 2025-06-26 14:26:02 +02:00
Moonchild 2e344377b5 Merge branch 'master' into release
# Conflicts:
#	devtools/client/shared/curl.js
#	security/nss/lib/ckfw/builtins/certdata.txt
#	security/nss/lib/nss/nss.h
#	security/nss/lib/softoken/softkver.h
#	security/nss/lib/util/nssutil.h
2025-06-24 17:08:59 +02:00
Moonchild 15335ce39d [devtools] Improve special character escaping for curl 2025-05-29 17:28:44 +02:00
Moonchild 14b03e1f8c No issue - Set device contrast to an acceptable value if OOB.
On Mac and Win+DW, enhanced device contrast can possibly not be set.
This throws Skia for a loop by passing in an OOB scalar to its init.
Work around this by setting an accepted average value that helps
prevent font wash-out while not causing fringing.
2025-05-29 17:28:30 +02:00
Moonchild 0968b94e5c No issue - Force C++ run-time type information on protobuf (uplift)
Protobuf uses `dynamic_cast` on polymorphic types which cannot be
inferred properly at compile-time, which can lead to unexpected behavior.
As a code safety measure, enable C++ RTTI for protobuf.
2025-05-29 17:27:29 +02:00
Moonchild ba6b2258aa No issue - Don't support modulo math space in ExtractLinearSum. (uplift) 2025-05-20 00:56:35 +02:00
Moonchild 1e1715ff11 No issue - Fix promise combinator function state. (uplift) 2025-05-19 22:50:48 +02:00
Brian Smith c93381fa79 No Issue - Fixes for building with LLVM 19 (uplift).
Fix a conflict with libc++ 19 and the old Mozilla (re)alloc macros.
LLVM 18+ does not allow std::char_traits<unsigned char> so avoid it.
https://bugzilla.mozilla.org/show_bug.cgi?id=1849070
Partial NSS upgrade to replace ByteString with a class.
https://bugzilla.mozilla.org/show_bug.cgi?id=1851092
2025-05-07 13:01:33 +02:00
Moonchild 65b0a59757 [devtools] Escape some more characters for copying as cURL on Posix. 2025-04-30 15:01:54 +02:00
Moonchild c785639043 [NSS] Update NSS version to 3.90.7 2025-04-30 15:01:48 +02:00
Moonchild 512c259822 [NSS] Update built-in data 2025-04-30 15:01:42 +02:00
Moonchild 90fea6f0d4 [NSS] Improve locking in nssPKIObject_GetInstances. 2025-04-30 15:01:35 +02:00
Moonchild d892468fd0 Issue #2731 - Fix crashes on unknown BigInt types in JIT (uplift)
This only works around the unknown type crashes but doesn't actually fix
attempts at using 64-bit BigInts in Ion.
Resolves #2731
2025-04-22 15:27:34 +02:00
Moonchild 81ab98b329 Merge branch 'master' into release 2025-04-04 20:37:42 +02:00
Moonchild 3f1cacd3e6 Merge branch 'master' into release 2025-04-03 10:22:24 +02:00
Moonchild 6e41e01a29 No issue - fix some minor link issues in about:rights
Privacy was moved to a subdir. Also replacing http with https because
that is what everyone expects by default.
2025-03-07 15:43:13 +01:00
Moonchild 9ce81488d4 No issue - Update Twemoji font to unicode 15.1.3 2025-03-07 02:06:25 +01:00
Moonchild 25bc2630d9 [js] Disable potentially unsafe attempts at recovering JIT operations. 2025-03-06 20:18:39 +01:00
Moonchild e5b69418a0 No Issue - NULL crash fix in nsExternalResourceMap::PendingLoad::OnDataAvailable
Curiously, we should have had this at our fork point (as it was backported
by Mozilla to 52.5.2) by apparently Tobin's import wasn't actually 52.6.0.
:-/
2025-03-06 20:18:24 +01:00
Shadow 229a69be5f Update js/src/wasm/WasmIonCompile.cpp
Bug 1328639 , wasm , Simplify block-value popping in Ion compilation
2025-03-06 20:18:07 +01:00
Moonchild 7f2561312a [layout] Always reserve 64 bits for frame property value
This ensures frame property values can always be stored even in edge cases
on 32-bit machines (where a void ptr is half the width).
2025-02-18 21:42:59 +01:00
Moonchild 93d11a07f9 Issue #2694 - Improve nested grid layout performance by caching.
This improves performance by caching the grid items' block axis
measurement, avoiding potentially exponential calculations and reflows.
Resolves #2694
2025-02-18 16:57:20 +01:00
Moonchild 8e5e24c4c6 Issue #2693 - Disable CSP reporting by default in the platform.
This is a temporary measure to work around CF OOM situations.
Reporting is desirable normally so webmasters get alerted to CSP issues,
and this should be flipped back on once we can.
2025-02-18 10:13:35 +01:00
Moonchild 517ee6754c [DOM] Honor security.csp.reporting.enabled pref in more places. 2025-02-18 10:13:28 +01:00
Moonchild 47690c287c No issue - avoid potential underflow in StructuredClone.
Prevents potential loop-around if there's bogus internal Map data.
2025-02-18 10:13:19 +01:00
Moonchild 364b95170e Merge branch 'master' into release 2025-02-05 23:36:07 +01:00
Moonchild 407006d673 Merge branch 'master' into release 2025-02-05 18:33:29 +01:00
Moonchild 2d60605cc6 Merge branch 'master' into release
# Conflicts:
#	netwerk/cookie/nsCookieService.cpp
2025-02-03 19:13:42 +01:00
Moonchild 2d1129eb7e [network] Don't try to use non-existing connections. 2025-01-13 20:29:31 +01:00
Moonchild 495b4980e7 [DOM] Convert cleanup of FlushCurrentWord() to a ScopeExit task.
Ensures consistent cleanup even if early exit due to OOM.
2025-01-10 15:55:10 +01:00
Moonchild ad480be112 [DOM] Slightly extend lifetime of data in Structured Clone operations. 2025-01-10 15:54:44 +01:00
Moonchild a06001c022 [network] Verify connection NPN against negotiated NPN. 2025-01-10 15:54:35 +01:00
Moonchild 6cbda74aeb Issue #2670 - Compute baseDomain when cookies are read from the database
baseDomain is used as a key for cookies in a hashmap. For cookie
operations to work properly, the baseDomain generation must be reliable.
This is, however, not the case, because the result can change by updates
to the public suffix list (PSL).

Since the stored baseDomain is not reliable, the value must be recomputed
when the database is read. This causes a minor performance hit but is
needed if we want to keep abreast of PSL changes without clobbering the
cookies database.

Resolves #2670
2024-12-24 22:12:33 +01:00
Moonchild 576fbdf490 Issue #2672 - Follow-up: Remove unused telemetry variable. 2024-12-24 22:12:24 +01:00
Moonchild 52b00c38ea Issue #2672 - Part 4: Prevent db access while rebuilding is underway. 2024-12-24 22:12:15 +01:00
Moonchild 8ec56f459b Issue #2672 - Part 3: Ensure thread lifetimes are in tandem. 2024-12-24 22:12:05 +01:00
Moonchild 5cbe423461 Issue #2672 - Part 2: Auto-close syncConn for edge cases. 2024-12-24 22:11:59 +01:00
Moonchild 369fbba750 Issue #2672 - Part 1: Load nsCookieService OMT and use sync reads.
No more lazy-loading on the main thread, thanks. Everyone needs this.
2024-12-24 22:11:52 +01:00
Martok 8e3c35efc6 Issue #1787 - Follow-up: remove no longer used AppClearDataObserver. 2024-12-24 22:11:37 +01:00
Moonchild b3b852b877 Merge branch 'master' into release 2024-12-04 11:10:21 +01:00
Moonchild d5c6e20e9e Merge branch 'master' into release 2024-12-01 20:52:12 +01:00
Moonchild 89b36775fb Merge branch 'master' into release 2024-11-29 10:21:36 +01:00
Karl Tomlinson df16df5693 Bug 1920800 - Remove oldImages from check for flushed old principal handle
The logic should be equivalent when frame IDs on aImages are contiguously
increasing from IDs on previously set frames.

There are currently no callers passing empty aImages, but the logic in this
case would now be as described in the documentation of
UpdatePrincipalHandleForFrameID():

> We will notify mElement that aPrincipalHandle has been applied when all
> FrameIDs prior to aFrameID have been flushed out.
2024-10-31 11:44:56 +01:00
Moonchild aa1fd576ac Issue #2648 - Inherit the content disposition of the multipart response 2024-10-30 10:54:11 +01:00
Moonchild 2512188ca7 Issue #2648 - Apply CSP to documents sent through multipart/x-mixed-replace 2024-10-30 10:54:04 +01:00
Moonchild 89e88ca6a0 Merge branch 'master' into release 2024-10-02 19:45:47 +02:00
Moonchild 2697dd162f [js xpconnect] Fix error handling in xpc::CreateSandboxObject 2024-09-05 10:13:09 +02:00
Moonchild 53a4179c4a [js] Simplify with-env handling in FetchName 2024-09-05 10:13:01 +02:00
Moonchild a120731ddd [DOM] Stop exposing NotifyPaintEvent to web content.
There's no reason this should be available to the web, as it's an
indicator of browser internals.
2024-09-05 10:12:55 +02:00
Moonchild bda611a41a Revert "Issue #2523 - Part 1 - Import headers from FFmpeg 7.0"
This reverts commit 27bb48deaf.
2024-09-03 13:03:20 +02:00
Moonchild 5a02a4a1a4 Revert "Issue #2523 - Part 2 - Update audio & video decoders to work with FFmpeg 7.0"
This reverts commit 7dbc24a739.
2024-09-03 13:03:12 +02:00
Moonchild e59f358b45 Revert "Issue #2527 - Part 1 - Remove old FFmpeg and LibAV headers"
This reverts commit b970fc412a.
2024-09-03 13:02:55 +02:00
Moonchild 90c9535b39 Revert "Issue #2527 - Part 2 - Remove support for libavcodec < 58"
This reverts commit 738c6a740a.
2024-09-03 13:02:46 +02:00
Moonchild ad778bbfdb Revert "Issue #2527 - Part 3 - Remove additional checks for LibAV"
This reverts commit b0f872c919.
2024-09-03 13:02:31 +02:00
Moonchild 8868552b24 Merge branch 'master' into release 2024-08-09 19:35:34 +02:00
Moonchild 66826eb487 Merge branch 'master' into release 2024-08-09 19:18:02 +02:00
Moonchild 39127b5ee9 Merge branch 'master' into release 2024-08-09 16:18:50 +02:00
Moonchild 80cff816a8 Merge branch 'master' into release 2024-08-09 15:56:36 +02:00
Moonchild e9dda8dafa Merge branch 'master' into release
# Conflicts:
#	security/nss/doc/rst/releases/index.rst
#	security/nss/lib/nss/nss.h
#	security/nss/lib/softoken/softkver.h
#	security/nss/lib/util/nssutil.h
2024-08-07 20:13:00 +02:00
Moonchild 11fc818dfb [DOM/network] Disable DNS prefetching if document nodePrincipal is systemPrincipal 2024-07-10 10:54:53 +02:00
Moonchild 84ed844e3f [IPC] Clean up control flow in WaitableEvent. 2024-07-10 10:54:43 +02:00
Moonchild 50af804f1c [network] Add additional cookie setting checks.
Added checks for sub-document navigations from cross-site to same-site in
third-party checks when setting a cookie.
2024-07-10 10:54:37 +02:00
Moonchild 82ce93bce9 No issue - Update SQLite to 3.46.0 2024-07-10 10:54:24 +02:00
Moonchild 228abc8259 No issue - Update NSS to 3.90.3 2024-07-10 10:54:17 +02:00
Moonchild 1692fa5291 Issue #2045 - Temporarily force hidden elements to be actually hidden.
For the time being, because we don't have `revert` yet, we should force
normally hidden elements to be hidden, so they aren't revealed by sites
using the bad practice of `*{ }` style blanking rules but then using
`revert` to re-hide them.
2024-07-10 10:54:02 +02:00
Moonchild bb58c6ae38 Issue #2541 - Deal with empty LineNameList in CSS grid templates.
Resolves #2541
2024-07-02 01:39:01 +02:00
Moonchild 4f58dc27f9 Re-synchronize branches, picking up 2 commits that were not correctly merged. 2024-06-16 12:32:02 +02:00
Moonchild fc5324b9f7 Issue #2532 - Align dialog submission triggered by form.submit() with the spec.
Submission in click handler of submit button should not be deferred
per https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#submit-dialog

See Bug 1719872
2024-06-15 17:56:37 +02:00
Moonchild 561f65aabf Issue #2532 - Prevent unwanted text selection when backdrop is clicked. 2024-06-15 17:56:31 +02:00
Moonchild 9acfe36b95 Issue #2532 - Don't do PreventDefault for escape key if <select> dropdown is not shown
We always use PreventDefault for <select> element, which is problematic if modal
dialog is on as it prevents cancelling the dialog. We fix it by not blocking the
default action if <select> is not shown.

See Bug 1649278
2024-06-15 17:56:25 +02:00
Moonchild ce495cbd85 Issue #2532 - Fix a null pointer crash while doing dialog form submission
See Bug 1652699
2024-06-15 17:56:20 +02:00
Moonchild c44020f188 Issue #2532 - Default pref check to true 2024-06-15 17:56:15 +02:00
Moonchild 35e7a695af Issue #2532 - Implement form[method=dialog]
See bug 1557303
2024-06-15 17:56:08 +02:00
Moonchild 7a55055d22 Merge branch 'master' into release 2024-06-13 21:31:39 +02:00
Moonchild 061900b87f [gfx] Use calloc for cairo font-creation functions. 2024-05-23 13:48:18 +02:00
Moonchild abe32f7309 [gfx] Ensure font entry's unitsPerEm and font extents are initialized when gfxFont is created. 2024-05-23 13:48:11 +02:00
Moonchild 7bfd4c7fe7 [DOM] Clean up ReportLoadError and normalize error messages. 2024-05-23 13:48:04 +02:00
Moonchild 859d6a3e2c [gfx] Clear mSharedBlobData if blob creation failed. 2024-05-23 13:47:58 +02:00
Moonchild c2f05f99af [network] Make http digest auth cnonce length configurable. 2024-05-23 13:47:50 +02:00
Moonchild 55b33fb02b Merge branch 'master' into release 2024-04-19 22:05:10 +02:00
Moonchild c247e40d41 Revert "Update NSS to 3.90.2"
This reverts commit b1cb7e0a8f.
2024-03-23 07:45:56 +01:00
Moonchild 05c58f159d Revert "Undo build system change from NSS update to fix missing command-line utils."
This reverts commit 67d5fefcf2.
2024-03-23 07:45:40 +01:00
Moonchild 67d5fefcf2 Undo build system change from NSS update to fix missing command-line utils. 2024-03-21 21:53:57 +01:00
Moonchild aad017be9e [MFBT] Make move assignment of RefPtr have the same behavior as nsCOMPtr 2024-03-20 19:52:30 +01:00
Moonchild 4543dbf3ff [parser] Specialize AddAttributes for <html>/<body>. 2024-03-20 19:52:24 +01:00
Moonchild b1cb7e0a8f Update NSS to 3.90.2 2024-03-20 19:52:08 +01:00
Moonchild 1c6d21c97d [network] Block set-cookie from multipart/x-mixed-replace 2024-02-22 23:20:07 +01:00
Eitan Isaacson fc42fb38c9 [layout] Process pairs in coord list in PolyArea.
Range -1 assures the array is even with a step size of 2, avoiding lone
value processing.
2024-02-22 23:19:59 +01:00
Jens Stutte 618068c15b [DOM] Check if WorkerRunnable::Run runs on top of WorkerThreadPrimaryRunnable::Run in a worker thread. 2024-02-22 23:19:53 +01:00
FranklinDM 808516a0a8 No issue - Replacing location might throw NS_ERROR_UNEXPECTED while the developer tools window is being destroyed 2024-02-22 23:19:45 +01:00
FranklinDM 7d6b806040 No issue - Remove leftover doorhanger code from the developer tools
Partially based on reverting https://bugzilla.mozilla.org/show_bug.cgi?id=1078539
2024-02-22 23:19:38 +01:00
Martok 6b4e2c9d73 Issue #2453 - Follow-Up: Use hard-coded minimum timer interval in workers.
From the spec: "If nesting level is greater than 5, and timeout is less than 4, then set timeout to 4.",
therefore not having it user-configurable doesn't really break anything.
2024-02-22 23:19:20 +01:00
Moonchild 787883f6a4 Disable URL-paste content loading by default.
See https://repo.palemoon.org/MoonchildProductions/Pale-Moon/issues/1957
2024-02-22 23:18:36 +01:00
Moonchild 7f02753c04 Issue #2465 - Do not use our in-tree metrics hints if using system-cairo
Use a somewhat equivalent font-options instance when using the
system-supplied cairo lib, instead of our in-tree extension.

Resolves #2465
2024-02-07 21:40:55 +01:00
Moonchild 8fa38b3445 Issue #618 - Follow-up: Fix missed constant refactor preventing ExportEntries from working. 2024-02-07 21:40:29 +01:00
Moonchild 541c5f9f45 Merge branch 'master' into release 2024-01-25 15:55:20 +01:00
Moonchild 4b6bd4976a Merge branch 'master' into release
# Conflicts:
#	modules/libpref/init/all.js
2024-01-25 09:09:51 +01:00
Moonchild a0843d52b4 Revert "[XPCOM] Compare return value of readlink in nsLocalFileUnix::GetNativeTarget"
This reverts commit 188f61505f.
2023-12-21 14:03:31 +01:00
Kershaw Chang 977a8cbed8 Bug 1736385 - Make sure thread is alive in CacheIOThread::ThreadFunc 2023-12-21 11:44:50 +01:00
Moonchild 1e85085305 [dom] Better handling of aborted websocket workers.
Catch the case where we are in worker-shutdown but are still connecting
and make filing and closing connections a bit more robust with a RefPtr.
2023-12-21 11:44:42 +01:00
Barret Rennie 188f61505f [XPCOM] Compare return value of readlink in nsLocalFileUnix::GetNativeTarget 2023-12-21 11:44:32 +01:00
Moonchild a514d7f6a4 [layout] Always check against fragment length in nsTextFrame 2023-12-21 11:44:21 +01:00
Moonchild 47c2c75ceb Bug 1868901 2023-12-21 11:44:12 +01:00
Moonchild 7082ec8a9a No issue - Allow redirects for requests that require preflight
Spec update, see Bug 1312864
2023-12-21 11:43:58 +01:00
Brian Smith 2907a84362 Issue #2387 - Remove a missed AddRef() which could cause leaks.
Update comments explaining how the reference counting works.
2023-12-10 23:58:08 +01:00
Brian Smith b8d1ee05c3 Issue #2387 - Collection of fixes related to a crash while canceling a dynamic import.
Add AddRef/Release hooks for embedding's script or module private value and set this script source object where appropriate.
https://bugzilla.mozilla.org/show_bug.cgi?id=1519140 Partial, no Value passing changes.
Clear the list of dynamic import requests after cancelling them in ScriptLoader::ParsingComplete as we do for other requests.
https://bugzilla.mozilla.org/show_bug.cgi?id=1291535
ScriptLoader::OnStreamComplete never returns a failure.
https://bugzilla.mozilla.org/show_bug.cgi?id=1627275
Also cancel the correct kind of parser for Modules.
2023-12-10 23:57:54 +01:00
Moonchild 0b625e624a [DOM] Fix double-free crash in MessagePort.cpp 2023-12-10 17:02:28 +01:00
Moonchild a4da712f91 Issue #2281 - Exclude throw wrapping on modern libcpp.
As discussed.
2023-11-25 18:17:35 +01:00
Moonchild 185f124e87 Issue #2381 - Remove system-nspr/nss leftovers (release port) 2023-11-25 17:15:01 +01:00
Moonchild 8633077691 [WebGL] Flip the validation state for gl_KHR_no_validation.
The original state was inverted due to confusion due to a double
negative (not:no_error).
This validation should only be enabled on Windows (for now).
Future tracking and discussion in BZ 1862039
2023-11-24 12:24:55 +01:00
Moonchild 39a1899045 [DOM] Improve MessagePort state machine. 2023-11-24 12:24:32 +01:00
Moonchild 4dc011a187 [Network] Fix relative URL path starting with multiple slashes 2023-11-24 12:24:19 +01:00
Moonchild ccb12e1dda [DOM] Check if rootDoc is secure context for web compat 2023-11-24 12:24:04 +01:00
Moonchild 63f0d3e295 [WebGL] Turn on more validation/error checking in webgl (when not on Win) 2023-11-24 12:23:49 +01:00
Moonchild 09d598c496 Revert "No Issue - add mutex in EventSource"
This reverts commit 10b3237e52.

Apparently causes deadlocks in Linux.
2023-11-15 12:22:11 +01:00
Moonchild 7e60482d80 No issue - Stop supporting data: scheme in SVG <use> elements. 2023-11-14 12:42:58 +01:00
Moonchild 10b3237e52 No Issue - add mutex in EventSource
Potentially avoids a gc crash when load is high.
2023-11-14 12:42:26 +01:00
athenian200 99af7cc028 Issue #1824 - Support SunOS Linker mapfiles.
Generating OS-appropriate mapfiles from a provided SYMBOL_FILE is
apparently required to work with newer ffvpx. Nothing else in our
codebase actually seemed to require it. Also seems to reduce the amount
of console spam I see relating to symbol visibility during the build
process, and I think it even makes libxul.so link a bit faster.
2023-11-04 01:47:00 -05:00
athenian200 76b360b5d1 Issue #1824 - Move to GCC 10.
It seems to work, but it is a lot slower than compiling with GCC 7.
2023-11-04 01:38:20 -05:00
Moonchild 4001b58a3e [DOM] For now, use C++11 static_asserts only.
Single-param static_assert is C++17 or later.
Follow-up to 3d92b82125
2023-10-27 14:20:10 +02:00
Moonchild 134a8aac87 Issue #35 - Follow-up: undo locale changes so they aren't pre-processed.
Pre-processing loses our localization notes and licensing headers for
l10n which is not a good thing. It's not a big deal having a few unused
strings in these files in the resulting locales.
2023-10-26 22:47:13 +02:00
Moonchild 3e2e48872a Merge branch 'master' into release 2023-10-25 22:51:58 +02:00
Moonchild 622b43cbc5 Merge branch 'master' into release 2023-10-25 22:49:37 +02:00
Moonchild 75b44ef620 Merge branch 'master' into release
# Conflicts:
#	js/src/wasm/WasmBinaryIterator.cpp
#	media/libvpx/vp8/encoder/onyx_if.c
2023-10-05 23:43:10 +02:00
Basilisk-Dev 00084ea49c Cherry-pick upstream libvpx fix
Backport of https://hg.mozilla.org/releases/mozilla-esr115/rev/5241232a3292943bd59ff1704eab60fee3cbc9d1
Addresses CVE-2023-5217
2023-09-28 16:18:01 +02:00
Moonchild b6fae24296 [network] Refactor TransactionObserver::OnDataAvailable() 2023-09-27 21:55:28 +02:00
André Bargull 13c6b7422d [js] Handle dead wrappers 2023-09-27 21:55:19 +02:00
Moonchild 24f2e663cd Restore incorrect SIMD Op removals. 2023-09-25 10:48:42 +02:00
Brian Smith f96b155988 Issue #2313 - Implement WebAssembly sign extension opcodes. (uplift) 2023-09-25 10:46:25 +02:00
Brian Smith d5cc24e916 Issue #2308 & #1240 Follow-up - Fill in missing JSOP_INC/DEC cases for Doubles in Ion. 2023-09-20 03:34:06 +02:00
Brian Smith 8eba271c5f Issue #2308 & #1240 Follow-up - Replace JSOP_POS in ++/-- with JSOP_TONUMERIC.
https://bugzilla.mozilla.org/show_bug.cgi?id=1519135
2023-09-20 03:33:57 +02:00
Brian Smith 19955c82b3 Issue #2308 & #1240 Follow-up - Fill in missing JSOP_INC/DEC cases for Ion on Intel32/64. 2023-09-20 03:33:50 +02:00
Brian Smith 80ae8aec7c Issue #2308 & #1240 Follow-up - Add BigInt support to JSOP_INC and JSOP_DEC.
https://bugzilla.mozilla.org/show_bug.cgi?id=1526309
2023-09-20 03:33:41 +02:00
Brian Smith d8441d7c81 Issue #2308 & #1240 Follow-up - Introduce new increment and decrement operations.
https://bugzilla.mozilla.org/show_bug.cgi?id=1508521
2023-09-20 03:33:33 +02:00
Brian Smith c2446f2478 Issue #2308 - Fix JSON BigInt regressions.
https://bugzilla.mozilla.org/show_bug.cgi?id=1522433
2023-09-20 03:33:23 +02:00
Brian Smith 6efb7a1904 Issue #2282 - Performance observer safety checks.
Both fixes from later revisions, without the Dispatch API changes.
2023-09-20 03:33:14 +02:00
Brian Smith fa0b03a10f Issue #2026 Follow-up: Fill in missing BigInt64 cases in js::IsTypedArrayConstructor().
Hopefully fixes RSA errors on ProtonMail.
2023-09-20 03:32:41 +02:00
Moonchild 3ae2972950 Issue #2309 - Cherry-pick upstream libwebp fix.
Backport of: https://chromium.googlesource.com/webm/libwebp.git/+/2af26267cdfcb63a88e5c74a85927a12d6ca1d76

Resolves #2309
2023-09-13 10:22:50 +02:00
Moonchild 2d48de9998 Merge branch 'master' into release 2023-09-01 15:44:29 +02:00
Moonchild 3b029cdfe4 Merge branch 'master' into release 2023-07-15 16:01:39 +02:00
Moonchild ea9077a8a5 Merge branch 'master' into release 2023-07-07 19:41:06 +02:00
Moonchild b4af6b6265 No issue - Set the default for incremental cycle collector to be off.
Negative performance impact if enabled.
2023-06-05 21:17:24 +02:00
Moonchild ae1d53ceb1 Issue #2257 - Remove rematerialized frames after bailouts and exceptions.
This ensures that rematerialized frames used by the devtools debugger
are properly removed so that no stale data is used during bailouts.
2023-06-05 21:17:13 +02:00
Brian Smith c3f4709d5e Issue #2252 - Prevent crash when attempting to load a script with execution disallowed.
This issue is due to the ExecutionContext added in Issue #1691 not handling GetScript()
in a context where script execution is not allowed.  This expressed itself in crashes when
playing MP4s with the NoScript extension installed and enabled.
2023-06-05 21:16:57 +02:00
FranklinDM a7bb3fc175 Issue #1592 - Follow-up: Ensure topmost scope marker is cleaned up 2023-06-05 21:16:43 +02:00
FranklinDM 6a0203f25f Issue #2250 - Part 2: Ignore the ancestor filter assertion if rule matching is restricted or if the current element is under a shadow host
This only affects debug builds.
2023-06-05 21:16:31 +02:00
FranklinDM b0dfcb147f Issue #2250 - Part 1: Return early if the element being tested for is likely an ancestor and does not have an assigned slot 2023-06-05 21:16:22 +02:00
Job Bautista 06fd4c9357 Issue #2221 - Follow-up: Simplify jit_ioncheck{1|2|3}_deunified_sources assignment. 2023-06-05 21:15:52 +02:00
Job Bautista b9ea7fd9ee Issue #2221 - Follow-up: Ensure jit_ioncheck{1|2|3}_deunified_sources is defined.
Should fix build bustage in armhf, as well as prevent bustage in mips32.
2023-06-05 21:15:33 +02:00
Moonchild 58308a5c7a Merge branch 'master' into release
# Conflicts:
#	python/mozbuild/mozpack/dmg.py
2023-05-11 17:35:14 +02:00
Brian Smith 88c7d54975 No Issue - Fix FreeBSD build failure with WebRTC enabled. (release uplift)
Tag #2227
2023-05-01 22:12:11 +02:00
Timothy Valldeperas eadb5678b3 Issue #2175 - Fix build bustage in WebRTC. (release uplift)
Resolves #2227
2023-05-01 19:04:57 +02:00
Moonchild 54e3e60796 Revert "[devtools] Don't allow sourcemap URLs to redirect"
This reverts commit 2a05494abe.
2023-04-17 10:25:45 +02:00
Moonchild 2a05494abe [devtools] Don't allow sourcemap URLs to redirect 2023-04-13 10:54:34 +02:00
Moonchild bc89e58def [network] Improve checks while parsing MIME parameters. 2023-04-13 10:54:27 +02:00
Moonchild 3a009b97f6 Issue #1911 - Follow-up: Filter out illegal characters in more locations. 2023-04-13 10:54:10 +02:00
Moonchild a105f6d5e9 No issue - Fix off-by-one of kLargeDatasetSize 2023-04-13 10:54:02 +02:00
Sandra 5db241c0c0 Increase size of data over which we write the data to disk rather than keep it around in memory 2023-04-13 10:53:53 +02:00
Sandra d38dca10e5 Use nsAnonymousTemporaryFile for clipboard cache
Base on https://github.com/mozilla/gecko-dev/commit/ecc04a9245b409d7eed7df63ba733cd2073180de
2023-04-13 10:53:14 +02:00
Moonchild 54fc723126 Issue #2180 - Follow-up: Move sentinel check up a bit. 2023-04-02 15:39:05 +02:00
Moonchild 9b8ca17ee4 Issue #2180 - Add pref to control NSS TLS 1.3 protocol downgrade sentinel 2023-04-02 15:38:57 +02:00
Moonchild cddc95b39b Issue #2176 - Don't reconstruct the parent when tearing down
display:contents nodes with pseudo-elements.

We need to use StyleChildrenIterator which iterates over them, instead.
This is a bit of a hack but we can't always have our cake.

We need to be a bit careful though, since ::before and ::after are owned
by their own frame, and thus could be unbound from the tree or even dead
after removing the frame.

This basically ports bugs 1435566 and 1438467
2023-04-02 15:38:31 +02:00
Moonchild 5676529793 Issue #2171 - Skip over shadow nodes that don't have an owning node.
Resolves #2171
2023-04-02 15:37:44 +02:00
Moonchild ce68156cf4 Revert "[widget] Linux GTK3: Detach accessible from moz_container before it's deleted"
This reverts commit 465a18f342.
Resolves #2168
2023-03-18 19:57:56 +01:00
Moonchild 5032ad9593 Issue #2117 - Follow-up: Run precomplete cmd during package staging
We rely on this for all OSes except Mac where precomplete should not
be in the root (it uses Mozilla's fallback packaging that places it in
$RESPATH)
2023-03-17 22:11:30 +01:00
Moonchild b55f765f2e Issue #1911 - Follow-up: Filter out illegal file extensions also.
We already did this for file names, just not extensions.
2023-03-17 12:02:55 +01:00
Moonchild 856078d435 [widget] Linux GTK3: Detach accessible from moz_container before it's deleted 2023-03-17 12:02:46 +01:00
Moonchild c74c262d2f [GFX] Add some sanity checks and clamps to SurfaceData calculations. 2023-03-17 12:02:38 +01:00
Moonchild 787e29e374 No Issue - Ensure more OsiSpace
ensureOsiSpace(); was very much under-used. This adds more instances
where it makes sense to ensure Osi space before placing masm calls.
2023-03-17 12:02:31 +01:00
FranklinDM e439896c9b Issue #2148 - Shrink Vector from (usually) four pointers in size to three
when no inline storage is used.

See Bug 1338374
2023-03-17 12:02:20 +01:00
FranklinDM 15b508f1fb Issue #2148 - Make Vector not use AlignedStorage for its inline element storage
See Bug 1338374 1/2
2023-03-17 12:02:12 +01:00
Job Bautista 5651ebfc76 Issue #2148 - Discard RegExpShared data tables when discarding regexp JIT code.
Based on Mozilla bug 1378736's part 2.
Should fix the double-free.
Follow-up for #2083
2023-03-17 12:02:04 +01:00
Job Bautista 593bfc1ce8 Issue #2148 - Don't null out RegExpObject -> RegExpShared pointer on GC.
Follow-up for issue #2083.
Taken from Mozilla bug 1378736.
2023-03-17 12:01:50 +01:00
Brian Smith 28953cda7a Issue #2160 - Initial support for notarizing during DMG package.
Added --with-macbundle-idenity configure option to set a codesign identity.
If no identity is set or cross-compiling from Linux no codesigning will be
done. Currently doing a full deep bundle v2 sign, instead of limited v1.
2023-03-15 15:10:52 +01:00
Moonchild 516f3f545d Merge branch 'master' into release
# Conflicts:
#	CLOBBER
#	js/src/vm/RegExpObject.cpp
#	security/nss/lib/nss/nss.h
#	security/nss/lib/pkcs12/p12d.c
#	security/nss/lib/softoken/softkver.h
#	security/nss/lib/util/nssutil.h
2023-03-13 13:11:20 +01:00
Moonchild 83aff65a42 Force clobber 2023-02-19 17:53:31 +01:00
Moonchild 5bd97df957 [NSS] Update NSS to 3.52.9 to pick up fixes. 2023-02-19 17:51:26 +01:00
Moonchild 8772711181 [DOM] Check whether module load request was already cancelled when a load fails 2023-02-19 17:51:18 +01:00
Moonchild dc9526f4c6 [widget] Properly test for and handle errors in target-surface creation
and mapping.
2023-02-19 17:51:10 +01:00
Moonchild 9ab36e7ae0 Issue #2103 - Fix typo in RegExp Parser
This corrects the typo where the left-hand character would determine if
the right-hand character would be added or not.

Resolves #2103
2023-02-02 10:50:47 +01:00
Job Bautista e8d30841e7 Issue #2091 - Parse \p{Extended_Pictographic} too.
This is essentially a follow up to Issue #1286. We already have
 UCHAR_EXTENDED_PICTOGRAPHIC in our in-tree ICU, so there's no reason to comment
 this case out.
2023-01-27 05:01:53 +01:00
Martok 9faf29374e Issue #2093 - Trace HeapPtr<RegExpShared::groupsTemplate_> for GC move/compact events, regression from #2072 2023-01-26 20:11:28 +01:00
Moonchild 75e4818d36 Merge branch 'master' into release 2023-01-19 00:42:00 +01:00
Moonchild a65144e9e0 Fix merge conflicts. 2023-01-13 12:55:52 +01:00
Moonchild 4f29548526 Merge branch 'master' into release
# Conflicts:
#	image/decoders/nsJXLDecoder.cpp
#	js/src/irregexp/NativeRegExpMacroAssembler.cpp
#	js/src/irregexp/RegExpAST.h
#	js/src/irregexp/RegExpEngine.cpp
#	js/src/irregexp/RegExpParser.cpp
#	js/src/irregexp/RegExpParser.h
#	xpcom/io/nsLocalFileUnix.cpp
2023-01-13 12:11:56 +01:00
Moonchild 528db2cbd8 Issue #1818 - Remove obsolete path hack in widget code. 2022-12-16 09:13:48 +00:00
Moonchild 84e6bcc1e6 [network] Align cookie checks with RFC 6265 (bis) 2022-12-16 09:13:38 +00:00
Moonchild 0dc9ff518d [libjar] Add some extra sanity checks to our Zip reader. 2022-12-16 09:13:25 +00:00
Moonchild a2e3bd44aa [network] move some generic websocket code to the baseclass 2022-12-16 09:13:09 +00:00
Moonchild 163a0e7caf Revert "Issue #1279 - Implement regular expressions lookbehind (v2)"
This reverts commit d10e8a5b06.
2022-12-15 09:11:02 +00:00
Moonchild 49a86db5f3 Issue #2040 - Pre-multiply the alpha values in our JXL decode buffer. (uplift)
Using selective calculation (only if not opaque) and fast integer
math here should optimize well in compilers.
2022-12-15 09:09:19 +00:00
Moonchild 2640953d8b Issue #2019 - Follow-up: Make nsPluginInstanceOwner also listen to keypress events in the system event group.
nsPluginInstanceOwner only listens to keypress events in the default event group.
However, in our changed operating mode, keypress events are not fired in the
default event group if the key does not result in something printable.
This means that nsPluginInstanceOwner should also listen to keypress events
in the system event group and should handle each keypress that way, but
only once. I.e., if a printable keypress event is received in the system event
group, it should be ignored, since it would've already been handled in the
default event group in that case.
2022-11-26 18:18:09 +00:00
Moonchild 7eb7d67f7a Issue #2033 - Temporary fix of R<->B channel swap.
We have a BGR/RGB channel ordering mismatch here. to at least
provide proper display, a quick&dirty byte swap on the output
buffer will fix this for now, but we should look into seeing where
the surface mismatch is caused.
std::swap() should optimize pretty well in any of the used
compilers, but if necessary, a full buffer ASM routine can be
slotted in (although on current hardware I doubt this will be
even noticeable as it is)
2022-11-26 02:43:18 +00:00
Moonchild e28860ba7f Revert "[XPCOM] Deal with lstat potentially lying in nsLocalFileUnix."
This reverts commit c127f58ef3.
2022-11-20 14:14:48 +00:00
Moonchild 49a96b1d91 Merge branch 'master' into release 2022-11-19 20:15:23 +00:00
Moonchild 3130812693 Merge branch 'master' into release 2022-11-12 18:34:07 +00:00
Moonchild 71ae69aea8 [WebGL] Implement webgl.max-size-per-texture-mib 2022-10-26 14:50:05 +00:00
Moonchild 9e34d697c7 [XPCOM] Fix Base64 off-by-one issue and safeguard against this mistake in the future. 2022-10-26 14:49:55 +00:00
Moonchild 8fa9125d02 [No issue] Hold some strong references on nsRefreshDriver 2022-10-26 14:49:46 +00:00
Brian Smith 4b4488c3e4 Issue #2022 - Part 2 - Add Ventura version detection.
Also add Monterey and Ventura to the graphics driver blocklist.
2022-10-26 14:49:33 +00:00
Brian Smith 248db7d301 Issue #2022 - Part 1 - Fix transparent windows on MacOS 13 Ventura.
During the BaseWindow creation contenView is nil on Ventura...
So create a NSView with the requested dimensions and set is as the contenView.
2022-10-26 14:49:23 +00:00
Moonchild e199f2949b [No issue] Ensure LockImpl::Try() returns the correct bool value. 2022-10-26 14:45:39 +00:00
Moonchild 456b5450a4 Issue #2010 - Ensure raw tagnames are safe exiting internalEntityParser
This resolves #2010
2022-09-28 13:50:10 +00:00
Moonchild d8e629c4a3 Merge branch 'master' into release 2022-09-27 20:12:40 +00:00
Moonchild 4898c4f297 Merge branch 'master' into release 2022-09-24 12:16:59 +00:00
Moonchild 7cd578bbc6 Merge branch 'master' into release 2022-09-22 13:16:48 +00:00
Moonchild 1e91df628a Merge branch 'master' into release 2022-09-22 11:52:16 +00:00
Moonchild b110549cbd Merge branch 'master' into release 2022-07-27 06:07:45 +00:00
Moonchild 971047835a Merge branch 'master' into release
# Conflicts:
#	config/milestone.txt
#	toolkit/mozapps/extensions/internal/XPIProvider.jsm
2022-07-25 20:47:06 +00:00
Moonchild dd4d9eb032 [XPCOM] Crash safely when TArray replacements are OOB.
In the unlikely event of TArray element replacement calls are OOB, crash safely
with a debug breakpoint instead of corrupting memory.
2022-07-03 15:49:44 +00:00
Moonchild 8b94f1e480 [DOM] use the sanitizer to restrict href in svg:use to fragment-only URLs 2022-07-03 15:49:34 +00:00
Moonchild c89610a5c7 [network] Clear PAC loader when the load failed 2022-07-03 15:49:23 +00:00
Moonchild 217963cbed Update NSS to 3.52.7 2022-07-03 15:49:14 +00:00
Moonchild c4f4e18340 [DOM media] Remove potentially unsafe type accesses when debug logging 2022-07-03 15:49:04 +00:00
Moonchild 8a7c0e7345 [network] Clean up and update the list of external protocol handlers. 2022-07-03 15:48:54 +00:00
Moonchild 52e304d450 Issue #1053 - Follow-up: Correct conditional define on POSIX systems. (uplift)
This conditional was incorrectly changed when removing Android support.
This potentially causes issues on Linux systems by not using pthreads correctly,
which may lead to high idle CPU usage.
2022-06-28 13:28:20 +00:00
Moonchild cfc0eeca53 Revert "Issue #1909 - Guard against empty update manifest URL"
This reverts commit d7fadcdef9.
2022-06-07 11:59:07 +00:00
Moonchild ebd3dd9228 Merge branch 'master' into release 2022-06-03 21:50:44 +00:00
Moonchild cb40e4e7ef Merge branch 'master' into release 2022-06-01 13:54:11 +00:00
Moonchild 662dba55fd Merge branch 'master' into release 2022-05-29 11:13:44 +00:00
Moonchild 8760ce023c Issue #1895 - Implement queueMicroTask(callback()) (uplift) 2022-05-07 14:40:14 +00:00
Moonchild b86e148bb7 Roll back milestone version to release. 2022-05-06 12:43:43 +00:00
Moonchild 9e83721e5e Merge branch 'master' into release 2022-05-06 12:43:00 +00:00
Moonchild dc2d6c2e60 Revert "No Issue - Make content-type on JAR channels behave the same as HTTP channels."
This reverts commit 425677ada7.
2022-05-03 17:38:19 +00:00
Moonchild 4ada6f6762 Update 7zSD for v31 2022-05-03 17:38:12 +00:00
263 changed files with 17833 additions and 5642 deletions

No files matched your search

@@ -276,6 +276,7 @@ NotificationController::DropMutationEvent(AccTreeMutationEvent* aEvent)
MOZ_ASSERT(hideEvent);
if (hideEvent->NeedsShutdown()) {
mDocument->UncacheChildrenInSubtree(aEvent->GetAccessible());
mDocument->ShutdownChildrenInSubtree(aEvent->GetAccessible());
}
}
+2
View File
@@ -1307,6 +1307,8 @@ DocAccessible::UnbindFromDocument(Accessible* aAccessible)
{
NS_ASSERTION(mAccessibleCache.GetWeak(aAccessible->UniqueID()),
"Unbinding the unbound accessible!");
MOZ_ASSERT(!mARIAOwnsHash.Contains(aAccessible),
"Container still lingering in mARIAOwnsHash");
// Fire focus event on accessible having DOM focus if active item was removed
// from the tree.
-1
View File
@@ -23,7 +23,6 @@ SOURCES += [
'DocAccessibleWrap.cpp',
'EnumVariant.cpp',
'HTMLTableAccessibleWrap.cpp',
'HTMLWin32ObjectAccessible.cpp',
'HyperTextAccessibleWrap.cpp',
'ImageAccessibleWrap.cpp',
'IUnknownImpl.cpp',
+5
View File
@@ -88,6 +88,11 @@ check_and_add_gcc_warning('-Wno-error=deprecated-declarations')
# false positives depending on optimization
check_and_add_gcc_warning('-Wno-error=array-bounds')
# GCC 9+ value-range analysis trips -Wformat-overflow on null %s args in debug
# spew (e.g. js/src/jit/x64/BaseAssembler-x64.h:595); harmless for our build,
# and js/src forces -Werror=format so this must be downgraded here to reach it.
check_and_add_gcc_warning('-Wno-error=format-overflow')
# can't get rid of those PGO warnings
check_and_add_gcc_warning('-Wno-error=coverage-mismatch', when='MOZ_PGO')
+1 -1
View File
@@ -26,6 +26,6 @@
global DATA_SYMBOL
%endif
SECTION .rodata align=16
SECTION .rodata data readable align=16
DATA_SYMBOL:
incbin ICU_DATA_FILE
+6
View File
@@ -6,7 +6,13 @@
.section .note.GNU-stack,"",%progbits
#endif
.global ICU_DATA_SYMBOL
#if defined(__APPLE__)
.const
#elif defined(__GNUC__) && !defined(XP_SOLARIS)
.section .rodata
#else
.data
#endif
.balign 16
ICU_DATA_SYMBOL:
.incbin ICU_DATA_FILE
+2
View File
@@ -17,6 +17,8 @@ DEFINES.update(
UCONFIG_NO_LEGACY_CONVERSION = True,
UCONFIG_NO_TRANSLITERATION = True,
UCONFIG_NO_REGULAR_EXPRESSIONS = True,
UCONFIG_NO_BREAK_ITERATION = True,
UCONFIG_NO_MF2 = True,
# We don't need to pass data to and from legacy char* APIs.
U_CHARSET_IS_UTF8 = True,
+1 -1
View File
@@ -81,7 +81,7 @@ $(addprefix install-,$(INSTALL_MANIFESTS)): install-%: $(addprefix $(TOPOBJDIR)/
--track install_$(subst /,_,$*).track \
$(TOPOBJDIR)/$* \
-DAB_CD=en-US \
-DBOOKMARKS_INCLUDE_DIR=$(TOPSRCDIR)/browser/locales/en-US/profile \
-DBOOKMARKS_INCLUDE_DIR=$(TOPSRCDIR)/$(MOZ_BUILD_APP)/locales/en-US/profile \
$(ACDEFINES) \
install_$(subst /,_,$*)
+1 -1
View File
@@ -52,7 +52,7 @@ static RedirEntry kRedirMap[] = {
{ "config", "chrome://global/content/config.xul", 0 },
{ "console", "chrome://global/content/console.xul", 0 },
{
"credits", "http://www.palemoon.org/Contributors.shtml",
"credits", "https://net.riverstonerelay.jihad-browser/credits",
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
nsIAboutModule::MAKE_LINKABLE
},
+28
View File
@@ -199,6 +199,7 @@
#include "nsICommandManager.h"
#include "nsIDOMNode.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIBadCertListener2.h" // JIHAD: route cert errors to the embedder chrome
#include "nsIHttpChannel.h"
#include "nsIIDNService.h"
#include "nsIInputStreamChannel.h"
@@ -1074,6 +1075,33 @@ nsDocShell::GetInterface(const nsIID& aIID, void** aSink)
} else if (aIID.Equals(NS_GET_IID(nsITabChild))) {
*aSink = GetTabChild().take();
return *aSink ? NS_OK : NS_ERROR_FAILURE;
} else if (aIID.Equals(NS_GET_IID(nsIBadCertListener2))) {
// JIHAD: hand the embedder's chrome the certificate error.
//
// NSS asks the channel's notification callbacks for nsIBadCertListener2
// (SSLServerCertVerification.cpp, CertErrorRunnable::CheckCertOverrides) and passes
// it the nsISSLStatus carrying the SERVER CERTIFICATE. That call is the one and only
// place an embedder is handed the cert while it still exists — the same shape the
// Atlas browser gets for free from WebKit's load-failed-with-tls-errors signal, which
// delivers the GTlsCertificate as a signal argument.
//
// Without this hop nothing answers: the docShell's fallthrough is
// nsDocLoader::GetInterface, which Queries the docloader ITSELF, so the request never
// reaches nsIWebBrowserChrome. The embedder is then left trying to recover the cert
// afterwards, and there is no way to: the failed channel's securityInfo has a null
// SSLStatus, and UXP has no nsIRecentBadCerts service. Measured 2026-08-04 — the
// SSL-confirm dialog worked, the user accepted, and the accept could do nothing
// because RememberValidityOverride had no nsIX509Cert to take.
//
// Routed through the tree owner, exactly as nsIWebBrowserChromeFocus and nsIPrompt
// already are (nsDocShellTreeOwner::GetInterface).
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
GetTreeOwner(getter_AddRefs(treeOwner));
nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(treeOwner));
if (req) {
return req->GetInterface(aIID, aSink);
}
return NS_NOINTERFACE;
} else if (aIID.Equals(NS_GET_IID(nsIContentFrameMessageManager))) {
nsCOMPtr<nsITabChild> tabChild =
do_GetInterface(static_cast<nsIDocShell*>(this));
+1
View File
@@ -31,6 +31,7 @@ public:
void
Unfollow();
/* Should this be WeakRef? */
RefPtr<AbortSignal> mFollowingSignal;
};
+99
View File
@@ -5,13 +5,19 @@
#include "DocumentOrShadowRoot.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/CSSStyleSheet.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/CSSStyleSheetBinding.h"
#include "mozilla/dom/StyleSheetList.h"
#include "mozilla/dom/ToJSValue.h"
#include "nsDocument.h"
#include "nsFocusManager.h"
#include "ShadowRoot.h"
#include "XULDocument.h"
#include "nsLayoutUtils.h"
#include "nsSVGUtils.h"
#include "jsapi.h"
class nsINode;
class nsIDocument;
@@ -43,6 +49,99 @@ DocumentOrShadowRoot::EnsureDOMStyleSheets()
return *mDOMStyleSheets;
}
void
DocumentOrShadowRoot::GetAdoptedStyleSheets(
JSContext* aCx,
JS::MutableHandle<JSObject*> aResult,
ErrorResult& aRv) const
{
JS::Rooted<JS::Value> value(aCx);
if (!ToJSValue(aCx, mAdoptedStyleSheets, &value)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
MOZ_ASSERT(value.isObject());
aResult.set(&value.toObject());
}
void
DocumentOrShadowRoot::SetAdoptedStyleSheets(
JSContext* aCx,
JS::Handle<JSObject*> aSheets,
ErrorResult& aRv)
{
bool isArray = false;
if (!JS_IsArrayObject(aCx, aSheets, &isArray)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
if (!isArray) {
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(
NS_LITERAL_STRING("DocumentOrShadowRoot.adoptedStyleSheets"));
return;
}
uint32_t length = 0;
if (!JS_GetArrayLength(aCx, aSheets, &length)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsIDocument* document = AsNode().OwnerDoc();
nsTArray<RefPtr<CSSStyleSheet>> newSheets;
if (!newSheets.SetCapacity(length, fallible)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
JS::Rooted<JS::Value> value(aCx);
for (uint32_t i = 0; i < length; ++i) {
if (!JS_GetElement(aCx, aSheets, i, &value)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
if (!value.isObject()) {
aRv.ThrowTypeError<MSG_DOES_NOT_IMPLEMENT_INTERFACE>(
NS_LITERAL_STRING("Element of DocumentOrShadowRoot.adoptedStyleSheets"),
NS_LITERAL_STRING("CSSStyleSheet"));
return;
}
RefPtr<CSSStyleSheet> sheet;
nsresult rv = UnwrapObject<prototypes::id::CSSStyleSheet,
CSSStyleSheet>(&value.toObject(), sheet);
if (NS_FAILED(rv)) {
aRv.ThrowTypeError<MSG_DOES_NOT_IMPLEMENT_INTERFACE>(
NS_LITERAL_STRING("Element of DocumentOrShadowRoot.adoptedStyleSheets"),
NS_LITERAL_STRING("CSSStyleSheet"));
return;
}
if (!sheet->IsConstructed() || sheet->ConstructorDocument() != document) {
aRv.Throw(NS_ERROR_DOM_NOT_ALLOWED_ERR);
return;
}
newSheets.AppendElement(sheet);
}
nsTArray<RefPtr<CSSStyleSheet>> oldSheets;
oldSheets.SwapElements(mAdoptedStyleSheets);
mAdoptedStyleSheets.SwapElements(newSheets);
if (mKind == Kind::Document) {
static_cast<nsDocument&>(AsNode()).AdoptedStyleSheetsChanged(oldSheets,
mAdoptedStyleSheets);
return;
}
static_cast<ShadowRoot&>(AsNode()).AdoptedStyleSheetsChanged(oldSheets,
mAdoptedStyleSheets);
}
Element*
DocumentOrShadowRoot::GetElementById(const nsAString& aElementId)
{
+16
View File
@@ -11,11 +11,14 @@
#include "nsContentListDeclarations.h"
#include "nsNameSpaceManager.h"
#include "mozilla/dom/NameSpaceConstants.h"
#include "js/RootingAPI.h"
class nsContentList;
class nsINode;
namespace mozilla {
class CSSStyleSheet;
class ErrorResult;
class StyleSheet;
namespace dom {
@@ -83,6 +86,18 @@ public:
StyleSheetList& EnsureDOMStyleSheets();
void GetAdoptedStyleSheets(JSContext* aCx,
JS::MutableHandle<JSObject*> aResult,
mozilla::ErrorResult& aRv) const;
void SetAdoptedStyleSheets(JSContext* aCx,
JS::Handle<JSObject*> aSheets,
mozilla::ErrorResult& aRv);
const nsTArray<RefPtr<mozilla::CSSStyleSheet>>& AdoptedStyleSheets() const
{
return mAdoptedStyleSheets;
}
Element* GetElementById(const nsAString& aElementId);
/**
@@ -151,6 +166,7 @@ protected:
Element* GetRetargetedFocusedElement();
nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheets;
nsTArray<RefPtr<mozilla::CSSStyleSheet>> mAdoptedStyleSheets;
RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
/*
+53 -4
View File
@@ -18,6 +18,7 @@
#include "mozilla/dom/StyleSheetList.h"
#include "nsXBLPrototypeBinding.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/CSSStyleSheet.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
@@ -30,6 +31,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
DocumentFragment)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAdoptedStyleSheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAssociatedBinding)
for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done();
iter.Next()) {
@@ -42,6 +44,10 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
tmp->GetHost()->RemoveMutationObserver(tmp);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
for (CSSStyleSheet* sheet : tmp->mAdoptedStyleSheets) {
sheet->RemoveAdopter(tmp);
}
tmp->mAdoptedStyleSheets.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAssociatedBinding)
tmp->mIdentifierMap.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
@@ -90,6 +96,11 @@ ShadowRoot::~ShadowRoot()
host->RemoveMutationObserver(this);
}
for (CSSStyleSheet* sheet : mAdoptedStyleSheets) {
sheet->RemoveAdopter(this);
}
mAdoptedStyleSheets.Clear();
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
// nsINode destructor expects mSubtreeRoot == this.
@@ -270,15 +281,20 @@ ShadowRoot::InsertSheet(StyleSheet* aSheet,
linkingElement->SetStyleSheet(aSheet); // This sets the ownerNode on the sheet
MOZ_DIAGNOSTIC_ASSERT(mProtoBinding->SheetCount() == DocumentOrShadowRoot::SheetCount());
MOZ_DIAGNOSTIC_ASSERT(mProtoBinding->SheetCount() ==
DocumentOrShadowRoot::SheetCount() +
mAdoptedStyleSheets.Length());
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
// FIXME(emilio, bug 1425759): For now we keep them duplicated, the proto
// binding will disappear soon (tm).
// FIXME(emilio, bug 1425759): For now we keep regular sheets duplicated;
// adopted sheets are stored as a suffix on the proto binding only.
{
size_t i = 0;
for (RefPtr<StyleSheet>& sheet : mStyleSheets) {
MOZ_DIAGNOSTIC_ASSERT(sheet.get() == mProtoBinding->StyleSheetAt(i++));
}
for (RefPtr<CSSStyleSheet>& sheet : mAdoptedStyleSheets) {
MOZ_DIAGNOSTIC_ASSERT(sheet.get() == mProtoBinding->StyleSheetAt(i++));
}
}
#endif
@@ -287,7 +303,7 @@ ShadowRoot::InsertSheet(StyleSheet* aSheet,
for (size_t i = 0; i <= SheetCount(); i++) {
if (i == SheetCount()) {
AppendStyleSheet(*aSheet);
mProtoBinding->AppendStyleSheet(aSheet);
mProtoBinding->InsertStyleSheetAt(i, aSheet);
break;
}
@@ -322,6 +338,39 @@ ShadowRoot::RemoveSheet(StyleSheet* aSheet)
}
}
void
ShadowRoot::AdoptedStyleSheetsChanged(
const nsTArray<RefPtr<CSSStyleSheet>>& aOldSheets,
const nsTArray<RefPtr<CSSStyleSheet>>& aNewSheets)
{
OwnerDoc()->BeginUpdate(UPDATE_STYLE);
bool applicableChange = false;
for (size_t i = 0; i < aOldSheets.Length(); ++i) {
CSSStyleSheet* sheet = aOldSheets[i];
if (aOldSheets.IndexOf(sheet) == i) {
mProtoBinding->RemoveStyleSheet(sheet);
}
applicableChange = applicableChange || sheet->IsApplicable();
sheet->RemoveAdopter(this);
}
for (size_t i = 0; i < aNewSheets.Length(); ++i) {
CSSStyleSheet* sheet = aNewSheets[i];
sheet->AddAdopter(this);
if (aNewSheets.IndexOf(sheet) == i) {
mProtoBinding->AppendStyleSheet(sheet);
}
applicableChange = applicableChange || sheet->IsApplicable();
}
if (applicableChange) {
StyleSheetChanged();
}
OwnerDoc()->EndUpdate(UPDATE_STYLE);
}
void
ShadowRoot::AddToIdTable(Element* aElement, nsIAtom* aId)
{
+4 -1
View File
@@ -21,6 +21,7 @@ class nsXBLPrototypeBinding;
namespace mozilla {
class CSSStyleSheet;
class EventChainPreVisitor;
namespace dom {
@@ -59,6 +60,9 @@ public:
// [deprecated] Shadow DOM v0
void InsertSheet(StyleSheet* aSheet, nsIContent* aLinkingContent);
void RemoveSheet(StyleSheet* aSheet);
void AdoptedStyleSheetsChanged(
const nsTArray<RefPtr<mozilla::CSSStyleSheet>>& aOldSheets,
const nsTArray<RefPtr<mozilla::CSSStyleSheet>>& aNewSheets);
StyleSheetList* StyleSheets()
{
return &DocumentOrShadowRoot::EnsureDOMStyleSheets();
@@ -173,4 +177,3 @@ protected:
} // namespace mozilla
#endif // mozilla_dom_shadowroot_h__
+2
View File
@@ -40,12 +40,14 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(Timeout)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Timeout)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTimer)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrincipal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mScriptHandler)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Timeout)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimer)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptHandler)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+16
View File
@@ -25,6 +25,22 @@ VisualViewport::~VisualViewport()
{
}
NS_IMPL_CYCLE_COLLECTION_CLASS(VisualViewport)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(VisualViewport,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(VisualViewport,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(VisualViewport)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(VisualViewport, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(VisualViewport, DOMEventTargetHelper)
/* virtual */
JSObject*
VisualViewport::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+3
View File
@@ -21,6 +21,9 @@ class VisualViewport final: public mozilla::DOMEventTargetHelper
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(VisualViewport, DOMEventTargetHelper)
explicit VisualViewport(nsPIDOMWindowInner* aWindow);
explicit VisualViewport(nsIGlobalObject* aGlobal);
+19 -6
View File
@@ -695,7 +695,7 @@ nsContentList::ContentAppended(nsIDocument* aDocument, nsIContent* aContainer,
!MayContainRelevantNodes(aContainer) ||
(!aFirstNewContent->HasChildren() &&
!aFirstNewContent->GetNextSibling() &&
!MatchSelf(aFirstNewContent))) {
!MatchSelf<MatchSelfMode::Insertion>(aFirstNewContent))) {
return;
}
@@ -731,7 +731,7 @@ nsContentList::ContentAppended(nsIDocument* aDocument, nsIContent* aContainer,
// The new stuff is somewhere in the middle of our list; check
// whether we need to invalidate
for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
if (MatchSelf(cur)) {
if (MatchSelf<MatchSelfMode::Insertion>(cur)) {
// Uh-oh. We're gonna have to add elements into the middle
// of our list. That's not worth the effort.
SetDirty();
@@ -788,7 +788,7 @@ nsContentList::ContentInserted(nsIDocument *aDocument,
if (mState != LIST_DIRTY &&
MayContainRelevantNodes(NODE_FROM(aContainer, aDocument)) &&
nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild) &&
MatchSelf(aChild)) {
MatchSelf<MatchSelfMode::Insertion>(aChild)) {
SetDirty();
}
@@ -808,7 +808,7 @@ nsContentList::ContentRemoved(nsIDocument *aDocument,
if (mState != LIST_DIRTY &&
MayContainRelevantNodes(NODE_FROM(aContainer, aDocument)) &&
nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild) &&
MatchSelf(aChild)) {
MatchSelf<MatchSelfMode::Removal>(aChild)) {
SetDirty();
}
@@ -853,6 +853,7 @@ nsContentList::Match(Element *aElement)
ni->Equals(mXMLMatchAtom, mMatchNameSpaceId);
}
template <nsContentList::MatchSelfMode Mode>
bool
nsContentList::MatchSelf(nsIContent *aContent)
{
@@ -864,8 +865,20 @@ nsContentList::MatchSelf(nsIContent *aContent)
return false;
}
if (Match(aContent->AsElement()))
auto matches = [&](Element* aElement) {
if (Match(aElement)) {
return true;
}
if constexpr (Mode == MatchSelfMode::Removal) {
return mFunc == nsContentUtils::MatchClassNames &&
aElement->IsSVGElement() && aElement->MayHaveClass();
}
return false;
};
if (matches(aContent->AsElement())) {
return true;
}
if (!mDeep)
return false;
@@ -873,7 +886,7 @@ nsContentList::MatchSelf(nsIContent *aContent)
for (nsIContent* cur = aContent->GetFirstChild();
cur;
cur = cur->GetNextNode(aContent)) {
if (cur->IsElement() && Match(cur->AsElement())) {
if (cur->IsElement() && matches(cur->AsElement())) {
return true;
}
}
+10
View File
@@ -367,6 +367,15 @@ protected:
* @return whether we match
*/
bool Match(mozilla::dom::Element *aElement);
enum class MatchSelfMode : uint8_t {
Insertion,
// Also accept SVG elements that may have a class. SMIL can change their
// class without notification, so they can be in the list without
// matching now. Needed when aContent leaves the subtree.
Removal,
};
/**
* See if anything in the subtree rooted at aContent, including
* aContent itself, matches our criterion.
@@ -374,6 +383,7 @@ protected:
* @param aContent the root of the subtree to match against
* @return whether we match something in the tree rooted at aContent
*/
template <MatchSelfMode Mode>
bool MatchSelf(nsIContent *aContent);
/**
+4 -3
View File
@@ -2073,6 +2073,10 @@ public:
aClasses);
}
static bool MatchClassNames(mozilla::dom::Element* aElement,
int32_t aNamespaceID,
nsIAtom* aAtom, void* aData);
/**
* Returns a presshell for this document, if there is one. This will be
* aDoc's direct presshell if there is one, otherwise we'll look at all
@@ -3012,9 +3016,6 @@ private:
static void DropFragmentParsers();
static bool MatchClassNames(mozilla::dom::Element* aElement,
int32_t aNamespaceID,
nsIAtom* aAtom, void* aData);
static void DestroyClassNameArray(void* aData);
static void* AllocClassMatchingInfo(nsINode* aRootNode,
const nsString* aClasses);
+60
View File
@@ -13,6 +13,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/BinarySearch.h"
#include "mozilla/CSSStyleSheet.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/EffectSet.h"
#include "mozilla/IntegerRange.h"
@@ -1402,6 +1403,10 @@ nsDocument::~nsDocument()
for (StyleSheet* sheet : mStyleSheets) {
sheet->ClearAssociatedDocument();
}
for (CSSStyleSheet* sheet : mAdoptedStyleSheets) {
sheet->RemoveAdopter(this);
}
mAdoptedStyleSheets.Clear();
for (auto& sheets : mAdditionalSheets) {
for (StyleSheet* sheet : sheets) {
sheet->ClearAssociatedDocument();
@@ -1635,6 +1640,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
// Traverse all our nsCOMArrays.
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAdoptedStyleSheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnDemandBuiltInUASheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages)
@@ -1740,6 +1746,11 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
for (CSSStyleSheet* sheet : tmp->mAdoptedStyleSheets) {
sheet->RemoveAdopter(tmp);
}
tmp->mAdoptedStyleSheets.Clear();
if (tmp->mStyleSheetSetList) {
tmp->mStyleSheetSetList->Disconnect();
tmp->mStyleSheetSetList = nullptr;
@@ -2205,6 +2216,12 @@ nsDocument::FillStyleSet(nsStyleSet* aStyleSet)
AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAuthorSheet],
SheetType::Doc);
for (CSSStyleSheet* sheet : mAdoptedStyleSheets) {
if (sheet->IsApplicable()) {
aStyleSet->AppendStyleSheet(SheetType::Doc, sheet);
}
}
mStyleSetFilled = true;
}
@@ -3872,6 +3889,37 @@ nsDocument::RemoveStyleSheetFromStyleSets(StyleSheet* aSheet)
}
}
void
nsDocument::AdoptedStyleSheetsChanged(
const nsTArray<RefPtr<CSSStyleSheet>>& aOldSheets,
const nsTArray<RefPtr<CSSStyleSheet>>& aNewSheets)
{
BeginUpdate(UPDATE_STYLE);
nsCOMPtr<nsIPresShell> shell = GetShell();
nsStyleSet* styleSet = shell ? shell->StyleSet() : nullptr;
for (size_t i = 0; i < aOldSheets.Length(); ++i) {
CSSStyleSheet* sheet = aOldSheets[i];
if (styleSet && sheet->IsApplicable() &&
aOldSheets.IndexOf(sheet) == i) {
styleSet->RemoveStyleSheet(SheetType::Doc, sheet);
}
sheet->RemoveAdopter(this);
}
for (size_t i = 0; i < aNewSheets.Length(); ++i) {
CSSStyleSheet* sheet = aNewSheets[i];
sheet->AddAdopter(this);
if (styleSet && sheet->IsApplicable() &&
aNewSheets.IndexOf(sheet) == i) {
styleSet->AppendStyleSheet(SheetType::Doc, sheet);
}
}
EndUpdate(UPDATE_STYLE);
}
void
nsDocument::RemoveStyleSheet(StyleSheet* aSheet)
{
@@ -3961,6 +4009,18 @@ nsDocument::SetStyleSheetApplicableState(StyleSheet* aSheet,
} else {
RemoveStyleSheetFromStyleSets(aSheet);
}
} else if (mAdoptedStyleSheets.IndexOf(aSheet->AsConcrete()) !=
mAdoptedStyleSheets.NoIndex) {
nsCOMPtr<nsIPresShell> shell = GetShell();
if (shell) {
if (aApplicable) {
shell->StyleSet()->AppendStyleSheet(SheetType::Doc,
aSheet->AsConcrete());
} else {
shell->StyleSet()->RemoveStyleSheet(SheetType::Doc,
aSheet->AsConcrete());
}
}
}
// We have to always notify, since this will be called for sheets
+4
View File
@@ -95,6 +95,7 @@ class nsISecurityConsoleMessage;
class nsPIBoxObject;
namespace mozilla {
class CSSStyleSheet;
class EventChainPreVisitor;
namespace dom {
class BoxObject;
@@ -471,6 +472,9 @@ public:
nsTArray<RefPtr<mozilla::StyleSheet>>& aNewSheets) override;
virtual void AddStyleSheetToStyleSets(mozilla::StyleSheet* aSheet);
virtual void RemoveStyleSheetFromStyleSets(mozilla::StyleSheet* aSheet);
void AdoptedStyleSheetsChanged(
const nsTArray<RefPtr<mozilla::CSSStyleSheet>>& aOldSheets,
const nsTArray<RefPtr<mozilla::CSSStyleSheet>>& aNewSheets);
virtual void InsertStyleSheetAt(mozilla::StyleSheet* aSheet,
size_t aIndex) override;
+2 -1
View File
@@ -1738,8 +1738,9 @@ nsFocusManager::Blur(nsPIDOMWindowOuter* aWindowToClear,
if (mActiveWindow)
window->UpdateCommands(NS_LITERAL_STRING("focus"), nullptr, 0);
nsCOMPtr<nsIDocument> doc = content->GetComposedDoc();
SendFocusOrBlurEvent(eBlur, presShell,
content->GetComposedDoc(), content, 1,
doc, content, 1,
false, false, aContentToFocus);
}
+1
View File
@@ -444,6 +444,7 @@ GK_ATOM(handheldFriendly, "HandheldFriendly")
GK_ATOM(handler, "handler")
GK_ATOM(handlers, "handlers")
GK_ATOM(HARD, "HARD")
GK_ATOM(hasSelectorDependency, "has-selector-dependency")
GK_ATOM(hasSameNode, "has-same-node")
GK_ATOM(hbox, "hbox")
GK_ATOM(head, "head")
+21 -3
View File
@@ -2176,6 +2176,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistory)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomElements)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVisualViewport)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
@@ -2254,6 +2255,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHistory)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomElements)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mVisualViewport)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage)
if (tmp->mApplicationCache) {
@@ -6162,7 +6164,6 @@ nsGlobalWindow::CheckSecurityWidthAndHeight(int32_t* aWidth, int32_t* aHeight, b
// This one is easy. Just ensure the variable is greater than 100;
if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
// Check security state for use in determing window dimensions
if (!nsContentUtils::IsCallerChrome()) {
//sec check failed
if (aWidth && *aWidth < 100) {
@@ -6173,6 +6174,21 @@ nsGlobalWindow::CheckSecurityWidthAndHeight(int32_t* aWidth, int32_t* aHeight, b
}
}
}
// Check for the screen dimensions and keep the size in the range of the
// screen size the window is on. We allow twice the screen size because the
// size we get for a screen is not always accurate, on Wayland in particular,
// and all we need is to keep the size in a reasonable range.
nsCOMPtr<nsIDOMScreen> screen = GetScreen();
int32_t screenWidth, screenHeight;
screen->GetAvailWidth(&screenWidth);
screen->GetAvailHeight(&screenHeight);
if (aWidth && *aWidth > 2 * screenWidth) {
*aWidth = 2 * screenWidth;
}
if (aHeight && *aHeight > 2 * screenHeight) {
*aHeight = 2 * screenHeight;
}
}
// NOTE: Arguments to this function should have values in device pixels
@@ -8091,8 +8107,10 @@ nsGlobalWindow::ResizeByOuter(int32_t aWidthDif, int32_t aHeightDif,
nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
cssSize.width += aWidthDif;
cssSize.height += aHeightDif;
// The deltas come from content and can be large enough to overflow a 32-bit
// add, so do the arithmetic in 64 bits and keep the result in range.
cssSize.width = int32_t(std::clamp<int64_t>(int64_t(cssSize.width) + aWidthDif, 0, INT32_MAX));
cssSize.height = int32_t(std::clamp<int64_t>(int64_t(cssSize.height) + aHeightDif, 0, INT32_MAX));
CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerIsChrome);
+3
View File
@@ -46,6 +46,9 @@ nsIDocument::FindDocStyleSheetInsertionPoint(
break;
}
}
if (sheet->IsConstructed()) {
break;
}
if (sheet == GetFirstAdditionalAuthorSheet()) {
break;
}
+33 -5
View File
@@ -787,6 +787,12 @@ nsresult
nsObjectLoadingContent::InstantiatePluginInstance(bool aIsLoading)
{
#ifdef MOZ_ENABLE_NPAPI
// JIHAD DIAGNOSTIC (R7): entry + the four early-out conditions. If this line never appears the
// plugin was never asked for at all (no nsPluginFrame -> no HasNewFrame), which is a different
// bug from being asked for and refused.
fprintf(stderr, "[jihad-npapi] InstantiatePluginInstance(aIsLoading=%d) owner=%d type=%d "
"mIsLoading=%d instantiating=%d\n", (int)aIsLoading, (int)!!mInstanceOwner,
(int)mType, (int)mIsLoading, (int)mInstantiating);
if (mInstanceOwner || mType != eType_Plugin || (mIsLoading != aIsLoading) ||
mInstantiating) {
// If we hit this assertion it's probably because LoadObject re-entered :(
@@ -822,10 +828,12 @@ nsObjectLoadingContent::InstantiatePluginInstance(bool aIsLoading)
NS_ENSURE_TRUE(mInstantiating, NS_OK);
if (!thisContent->GetPrimaryFrame()) {
// JIHAD DIAGNOSTIC (R7): a silent NS_OK return — the single most likely place for a plugin
// to "do nothing" with no error anywhere.
fprintf(stderr, "[jihad-npapi] NO PRIMARY FRAME -> not instantiating\n");
LOG(("OBJLC [%p]: Not instantiating plugin with no frame", this));
return NS_OK;
}
nsresult rv = NS_ERROR_FAILURE;
RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
@@ -846,6 +854,8 @@ nsObjectLoadingContent::InstantiatePluginInstance(bool aIsLoading)
rv = pluginHost->InstantiatePluginInstance(mContentType,
mURI.get(), this,
getter_AddRefs(newOwner));
fprintf(stderr, "[jihad-npapi] pluginHost->InstantiatePluginInstance rv=0x%x owner=%d\n",
(unsigned)rv, (int)!!newOwner);
// XXX(johns): We don't suspend native inside stopping plugins...
if (appShell) {
@@ -2378,6 +2388,11 @@ nsObjectLoadingContent::LoadObject(bool aNotify,
FallbackType clickToPlayReason;
if (!mActivated && (mType == eType_Null || mType == eType_Plugin) &&
!ShouldPlay(clickToPlayReason, false)) {
// JIHAD DIAGNOSTIC (R7): this is where a plugin that resolved fine is silently demoted to
// eType_Null. Every path out of ShouldPlay that returns false lands here, so one line here
// names the reason instead of instrumenting each exit.
fprintf(stderr, "[jihad-npapi] demoted to fallback: mType=%d fallbackReason=%d\n",
(int)mType, (int)clickToPlayReason);
LOG(("OBJLC [%p]: Marking plugin as click-to-play", this));
mType = eType_Null;
fallbackType = clickToPlayReason;
@@ -2887,9 +2902,16 @@ nsObjectLoadingContent::GetTypeOfContent(const nsCString& aMIMEType)
#ifdef MOZ_ENABLE_NPAPI
RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
if ((caps & eSupportPlugins) &&
pluginHost &&
pluginHost->HavePluginForType(aMIMEType, nsPluginHost::eExcludeNone)) {
bool jihadHave = pluginHost &&
pluginHost->HavePluginForType(aMIMEType, nsPluginHost::eExcludeNone);
// JIHAD DIAGNOSTIC (R7 windowless port): says, for one MIME type, whether the element
// advertised plugin capability and whether the host has a plugin — the two facts that decide
// if the NPAPI subsystem is entered at all. Added because a plugin that never instantiates
// produces NO plugin logging whatsoever, which is indistinguishable from one that was never
// asked for.
fprintf(stderr, "[jihad-npapi] GetTypeOfContent mime=%s caps=0x%x supportsPlugins=%d have=%d\n",
nsCString(aMIMEType).get(), caps, (int)!!(caps & eSupportPlugins), (int)jihadHave);
if ((caps & eSupportPlugins) && jihadHave) {
// ShouldPlay will handle checking for disabled plugins
return eType_Plugin;
}
@@ -3486,9 +3508,15 @@ nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentTyp
aReason = eFallbackClickToPlay;
uint32_t enabledState = nsIPluginTag::STATE_DISABLED;
pluginHost->GetStateForType(mContentType, nsPluginHost::eExcludeNone,
nsresult jihadStateRv = pluginHost->GetStateForType(mContentType, nsPluginHost::eExcludeNone,
&enabledState);
// JIHAD DIAGNOSTIC (R7): note that enabledState is pre-set to STATE_DISABLED and the rv of
// GetStateForType is NOT checked upstream, so a failing lookup silently blocks the plugin
// with no other trace. Log the rv as well as the value.
fprintf(stderr, "[jihad-npapi] ShouldPlay type=%s enabledState=%u rv=0x%x\n",
mContentType.get(), enabledState, (unsigned)jihadStateRv);
if (nsIPluginTag::STATE_DISABLED == enabledState) {
fprintf(stderr, "[jihad-npapi] ShouldPlay -> FALSE (eFallbackDisabled)\n");
aReason = eFallbackDisabled;
return false;
}
+7 -1
View File
@@ -80,6 +80,8 @@
#include "mozilla/dom/WebGLRenderingContextBinding.h"
extern "C" bool jihad_gpu_compositor_on(); // Jihad T-511: widget/PuppetWidget.cpp
namespace mozilla {
using namespace mozilla::dom;
@@ -712,7 +714,11 @@ WebGLContext::CreateAndInitGL(bool forceEnabled,
//////
const bool useEGL = PR_GetEnv("MOZ_WEBGL_FORCE_EGL");
// Jihad (T-511): on the GPU path (JIHAD_GPU_COMPOSITOR) the headless build's default GL provider
// is the null one; the device's GPU is reached through EGL, as the compositor reaches it. On the
// software path, and once the daemon has given the GPU path up, the default provider fails and
// WebGL stays off.
const bool useEGL = PR_GetEnv("MOZ_WEBGL_FORCE_EGL") || jihad_gpu_compositor_on();
bool tryNativeGL = true;
bool tryANGLE = false;
+12 -1
View File
@@ -508,7 +508,18 @@ WebGLContext::InitAndValidateGL(FailureReason* const out_failReason)
gl->GetUIntegerv(LOCAL_GL_STENCIL_VALUE_MASK, &mStencilValueMaskFront);
gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_VALUE_MASK, &mStencilValueMaskBack);
gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK, &mStencilWriteMaskFront);
gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &mStencilWriteMaskBack);
// Jihad (T-511): the Adreno 220's GLES 2.0 driver answers GL_INVALID_ENUM for the back write
// mask (valid in GLES 2.0), and the error left behind failed the whole context's init below
// ("GL error 0x500 occurred during WebGL context initialization"). Queried in its own error
// scope; the front mask stands in (both start as all ones).
{
GLint backWriteMask = 0;
if (gl->GetPotentialInteger(LOCAL_GL_STENCIL_BACK_WRITEMASK, &backWriteMask)) {
mStencilWriteMaskBack = GLuint(backWriteMask);
} else {
mStencilWriteMaskBack = mStencilWriteMaskFront;
}
}
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK, mStencilValueMaskFront);
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, mStencilValueMaskBack);
+6 -3
View File
@@ -682,16 +682,19 @@ DataTransfer::SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData,
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
nsAutoString format;
GetRealFormat(aFormat, format);
// Don't allow the custom type to be assigned.
if (aFormat.EqualsLiteral(kCustomTypesMime)) {
if (format.EqualsLiteral(kCustomTypesMime)) {
return NS_ERROR_TYPE_ERR;
}
if (!PrincipalMaySetData(aFormat, aData, aSubjectPrincipal)) {
if (!PrincipalMaySetData(format, aData, aSubjectPrincipal)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
return SetDataWithPrincipal(aFormat, aData, aIndex, aSubjectPrincipal);
return SetDataWithPrincipal(format, aData, aIndex, aSubjectPrincipal);
}
void
+2 -1
View File
@@ -29,18 +29,19 @@ using namespace workers;
NS_IMPL_CYCLE_COLLECTING_ADDREF(Request)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Request)
NS_IMPL_CYCLE_COLLECTION_CLASS(Request)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Request)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHeaders)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSignal)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Request)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHeaders)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSignal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Request)
+2 -1
View File
@@ -30,12 +30,12 @@ namespace dom {
NS_IMPL_CYCLE_COLLECTING_ADDREF(Response)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Response)
NS_IMPL_CYCLE_COLLECTION_CLASS(Response)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Response)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHeaders)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSignal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchStreamReader)
tmp->mReadableStreamBody = nullptr;
@@ -47,6 +47,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Response)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHeaders)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSignal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchStreamReader)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+4
View File
@@ -1132,6 +1132,7 @@ void HTMLMediaElement::AbortExistingLoads()
RemoveMediaElementFromURITable();
mLoadingSrc = nullptr;
mCORSMode = CORS_NONE;
mMediaSource = nullptr;
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING ||
@@ -1370,6 +1371,9 @@ void HTMLMediaElement::SelectResource()
// If we have a 'src' attribute, use that exclusively.
nsAutoString src;
if (mSrcAttrStream) {
// Media provider objects use local mode, so a previous URL load's CORS
// mode does not apply.
mCORSMode = CORS_NONE;
SetupSrcMediaStreamPlayback(mSrcAttrStream);
} else if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
nsCOMPtr<nsIURI> uri;
+5 -5
View File
@@ -117,11 +117,6 @@ public:
int32_t Index();
protected:
virtual ~HTMLOptionElement();
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
/**
* Get the select content element that contains this option, this
* intentionally does not return nsresult, all we care about is if
@@ -129,6 +124,11 @@ protected:
*/
HTMLSelectElement* GetSelect();
protected:
virtual ~HTMLOptionElement();
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
bool mSelectedChanged;
bool mIsSelected;
+3 -3
View File
@@ -732,10 +732,10 @@ bool
HTMLSelectElement::MatchSelectedOptions(Element* aElement,
int32_t /* unused */,
nsIAtom* /* unused */,
void* /* unused*/)
void* aData)
{
HTMLOptionElement* option = HTMLOptionElement::FromContent(aElement);
return option && option->Selected();
return option && option->Selected() && option->GetSelect() == static_cast<HTMLSelectElement*>(aData);
}
nsIHTMLCollection*
@@ -743,7 +743,7 @@ HTMLSelectElement::SelectedOptions()
{
if (!mSelectedOptions) {
mSelectedOptions = new nsContentList(this, MatchSelectedOptions, nullptr,
nullptr, /* deep */ true);
this, /* deep */ true);
}
return mSelectedOptions;
}
+25
View File
@@ -1415,6 +1415,7 @@ BackgroundFactoryRequestChild::BackgroundFactoryRequestChild(
uint64_t aRequestedVersion)
: BackgroundRequestChildBase(aOpenRequest)
, mFactory(aFactory)
, mDatabaseActor(nullptr)
, mRequestedVersion(aRequestedVersion)
, mIsDeleteOp(aIsDeleteOp)
{
@@ -1439,6 +1440,15 @@ BackgroundFactoryRequestChild::GetOpenDBRequest() const
return static_cast<IDBOpenDBRequest*>(mRequest.get());
}
void
BackgroundFactoryRequestChild::SetDatabaseActor(BackgroundDatabaseChild* aActor)
{
AssertIsOnOwningThread();
MOZ_ASSERT(!aActor || !mDatabaseActor);
mDatabaseActor = aActor;
}
bool
BackgroundFactoryRequestChild::HandleResponse(nsresult aResponse)
{
@@ -1450,6 +1460,11 @@ BackgroundFactoryRequestChild::HandleResponse(nsresult aResponse)
DispatchErrorEvent(mRequest, aResponse);
if (mDatabaseActor) {
mDatabaseActor->ReleaseDOMObject();
MOZ_ASSERT(!mDatabaseActor);
}
return true;
}
@@ -1468,6 +1483,7 @@ BackgroundFactoryRequestChild::HandleResponse(
IDBDatabase* database = databaseActor->GetDOMObject();
if (!database) {
databaseActor->EnsureDOMObject();
MOZ_ASSERT(mDatabaseActor);
database = databaseActor->GetDOMObject();
MOZ_ASSERT(database);
@@ -1475,6 +1491,8 @@ BackgroundFactoryRequestChild::HandleResponse(
MOZ_ASSERT(!database->IsClosed());
}
MOZ_ASSERT(mDatabaseActor == databaseActor);
if (database->IsClosed()) {
// If the database was closed already, which is only possible if we fired an
// "upgradeneeded" event, then we shouldn't fire a "success" event here.
@@ -1487,6 +1505,7 @@ BackgroundFactoryRequestChild::HandleResponse(
}
databaseActor->ReleaseDOMObject();
MOZ_ASSERT(!mDatabaseActor);
return true;
}
@@ -1507,6 +1526,8 @@ BackgroundFactoryRequestChild::HandleResponse(
DispatchSuccessEvent(&helper, successEvent);
MOZ_ASSERT(!mDatabaseActor);
return true;
}
@@ -1737,6 +1758,8 @@ BackgroundDatabaseChild::EnsureDOMObject()
mDatabase = mTemporaryStrongDatabase;
mSpec.forget();
mOpenRequestActor->SetDatabaseActor(this);
}
void
@@ -1748,6 +1771,8 @@ BackgroundDatabaseChild::ReleaseDOMObject()
MOZ_ASSERT(mOpenRequestActor);
MOZ_ASSERT(mDatabase == mTemporaryStrongDatabase);
mOpenRequestActor->SetDatabaseActor(nullptr);
mOpenRequestActor = nullptr;
// This may be the final reference to the IDBDatabase object so we may end up
+17
View File
@@ -254,6 +254,20 @@ class BackgroundFactoryRequestChild final
friend class PermissionRequestParent;
RefPtr<IDBFactory> mFactory;
// Normally when opening of a database is successful, we receive a database
// actor in request response, so we can use it to call ReleaseDOMObject()
// which clears temporary strong reference to IDBDatabase.
// However, when there's an error, we don't receive a database actor and
// IDBRequest::mTransaction is already cleared (must be). So the only way how
// to call ReleaseDOMObject() is to have a back-reference to database actor.
// This creates a weak ref cycle between
// BackgroundFactoryRequestChild (using mDatabaseActor member) and
// BackgroundDatabaseChild actor (using mOpenRequestActor member).
// mDatabaseActor is set in EnsureDOMObject() and cleared in
// ReleaseDOMObject().
BackgroundDatabaseChild* mDatabaseActor;
const uint64_t mRequestedVersion;
const bool mIsDeleteOp;
@@ -271,6 +285,9 @@ private:
// Only destroyed by BackgroundFactoryChild.
~BackgroundFactoryRequestChild();
void
SetDatabaseActor(BackgroundDatabaseChild* aActor);
bool
HandleResponse(nsresult aResponse);
+3 -1
View File
@@ -138,7 +138,9 @@ GetJSValFromKeyPathString(JSContext* aCx,
// only through getters but we still want to support them for key
// extraction. So they need to be handled manually.
Blob* blob;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) {
// UNWRAP_OBJECT calls might mutate this.
JS::Rooted<JSObject*> blobObj(aCx, obj);
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &blobObj, blob))) {
if (token.EqualsLiteral("size")) {
ErrorResult rv;
uint64_t size = blob->GetSize(rv);
+4
View File
@@ -265,6 +265,10 @@ VideoData::SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
return false;
}
if (!ValidateBufferAndPicture(aBuffer, aPicture)) {
return false;
}
PlanarYCbCrData data = ConstructPlanarYCbCrData(aInfo, aBuffer, aPicture);
aVideoImage->SetDelayedConversion(true);
+21 -7
View File
@@ -187,7 +187,7 @@ public:
{
}
explicit VideoInfo(int32_t aWidth, int32_t aHeight)
VideoInfo(int32_t aWidth, int32_t aHeight)
: VideoInfo(nsIntSize(aWidth, aHeight))
{
}
@@ -201,7 +201,6 @@ public:
, mCodecSpecificConfig(new MediaByteBuffer)
, mExtraData(new MediaByteBuffer)
, mRotation(kDegree_0)
, mImageRect(nsIntRect(nsIntPoint(), aSize))
{
}
@@ -263,15 +262,28 @@ public:
nsIntRect ImageRect() const
{
if (mImageRect.width < 0 || mImageRect.height < 0) {
if (!mImageRect) {
return nsIntRect(0, 0, mImage.width, mImage.height);
}
return mImageRect;
return *mImageRect;
}
void SetImageRect(const nsIntRect& aRect)
{
mImageRect = aRect;
mImageRect = Some(aRect);
}
void ResetImageRect() {
mImageRect.reset();
}
// Adopts an image size decoded from the bitstream. The picture rectangle is
// expressed relative to the image size, so a change in size invalidates it
// and it is discarded; an unchanged size keeps the existing rectangle.
void AdoptImageSize(const gfx::IntSize& aImage) {
if (mImage != aImage) {
ResetImageRect();
}
mImage = aImage;
}
// Returned the crop rectangle scaled to aWidth/aHeight size relative to
@@ -332,9 +344,11 @@ public:
uint8_t mBitDepth = 8;
private:
friend struct IPC::ParamTraits<VideoInfo>;
// mImage may be cropped; currently only used with the WebM container.
// A negative width or height indicate that no cropping is to occur.
nsIntRect mImageRect;
// If unset, no cropping is to occur.
Maybe<nsIntRect> mImageRect;
// Indicates whether or not frames may contain alpha information.
bool mAlphaPresent = false;
+2 -3
View File
@@ -25,7 +25,7 @@ namespace IPC {
WriteParam(aMsg, aParam.mDisplay);
WriteParam(aMsg, aParam.mStereoMode);
WriteParam(aMsg, aParam.mImage);
WriteParam(aMsg, aParam.ImageRect());
WriteParam(aMsg, aParam.mImageRect);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
@@ -35,8 +35,7 @@ namespace IPC {
ReadParam(aMsg, aIter, &aResult->mDisplay) &&
ReadParam(aMsg, aIter, &aResult->mStereoMode) &&
ReadParam(aMsg, aIter, &aResult->mImage) &&
ReadParam(aMsg, aIter, &imageRect)) {
aResult->SetImageRect(imageRect);
ReadParam(aMsg, aIter, &aResult->mImageRect)) {
return true;
}
return false;
@@ -847,12 +847,15 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
RefPtr<layers::PlanarYCbCrImage> image =
new IMFYCbCrImage(buffer, twoDBuffer);
VideoData::SetVideoDataToImage(image,
mVideoInfo,
b,
pictureRegion,
false);
if (!VideoData::SetVideoDataToImage(image,
mVideoInfo,
b,
pictureRegion,
false)) {
LOG("CreateBasicVideoFrame: failed to set video data to image (shmem path)");
return E_FAIL;
}
RefPtr<VideoData> v =
VideoData::CreateFromImage(mVideoInfo,
aStreamOffset,
@@ -307,8 +307,7 @@ H264Converter::UpdateConfigFromExtraData(MediaByteBuffer* aExtraData)
if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata) &&
spsdata.pic_width > 0 && spsdata.pic_height > 0) {
mp4_demuxer::H264::EnsureSPSIsSane(spsdata);
mCurrentConfig.mImage.width = spsdata.pic_width;
mCurrentConfig.mImage.height = spsdata.pic_height;
mCurrentConfig.AdoptImageSize(gfx::IntSize(spsdata.pic_width, spsdata.pic_height));
mCurrentConfig.mDisplay.width = spsdata.display_width;
mCurrentConfig.mDisplay.height = spsdata.display_height;
}
+160
View File
@@ -577,6 +577,166 @@ typedef struct _NPEvent
} NPEvent;
#elif defined(XP_UNIX) && defined(MOZ_X11)
typedef XEvent NPEvent;
#elif defined(XP_UNIX) && defined(MOZ_WIDGET_HEADLESS)
/*
* JIHAD (webOS, cavekit-addons-extensions.md R7) — THE PALM EVENT PROTOCOL.
*
* webOS plugins do not speak X11. Palm's own npapi.h defines NPEvent, under XP_WEBOS, as the
* union below; the device's Adobe Flash was compiled against exactly that header and its
* NPP_HandleEvent reads these fields. Reproduced here from the webOS WebKit fork's
* WebCore/plugins/npapi.h (the XP_WEBOS block, NpPalmEventsEnum through the NPEvent union),
* so that the shape crossing our NPAPI boundary is the shape the plugin was built to read.
*
* This replaces `typedef void* NPEvent` for the headless toolkit, and that arm was not merely
* a placeholder — it was load-bearing in the wrong direction. NPRemoteEvent is a raw memcpy of
* sizeof(NPEvent) (dom/plugins/ipc/NPEventUnix.h), so with a void* NPEvent the parent shipped
* four bytes of its own address space to the child and the child handed the plugin a pointer
* into a foreign process. No event could ever have carried a payload. Making NPEvent a real
* POD is what lets the whole existing NPP_HandleEvent path work unmodified, parent to child.
*
* Gated on MOZ_WIDGET_HEADLESS because that is precisely the configuration this port builds
* (--enable-default-toolkit=cairo-headless, no X anywhere in the bundle) and the only one that
* reaches this arm. A non-webOS headless embedding would get these structs too; that is
* harmless, since the alternative it loses is an NPEvent that could not carry an event.
*
* POINTER-BEARING MEMBERS DO NOT SURVIVE IPC. dstBuffer/graphicsContext (draw),
* touches (touch) and reserved (system) are process-local. Pen, key and system events use
* none of them; the draw event is built inside the child (PluginInstanceChild.cpp) and never
* crosses the boundary, which is why it stays valid.
*
* One deliberate omission from Palm's union: NpPalmAccelerometerEvent. It is 16 bytes against
* NpPalmDrawEvent's 44, so leaving it out changes sizeof(NPEvent) by nothing — and the union
* is only ever read through the plugin's OWN copy of this declaration, so an unused member
* here is unobservable. It is left out rather than copied because it carries a struct-scoped
* `enum Orientation` whose tag would leak to file scope, for no gain.
*/
typedef enum NpPalmEventsEnum
{
npPalmPenDownEvent = 1 << 0,
npPalmPenUpEvent = 1 << 1,
npPalmPenMoveEvent = 1 << 2,
npPalmKeyDownEvent = 1 << 3,
npPalmKeyUpEvent = 1 << 4,
npPalmKeyRepeatEvent = 1 << 5,
npPalmKeyPressEvent = 1 << 6,
npPalmDrawEvent = 1 << 7,
npPalmSystemEvent = 1 << 8,
npPalmGestureEvent = 1 << 9,
npPalmAccelerometerEvent = 1 << 10,
npPalmTouchStartEvent = 1 << 11,
npPalmTouchMoveEvent = 1 << 12,
npPalmTouchEndEvent = 1 << 13,
npPalmTouchCancelledEvent = 1 << 14,
npPalmPenDoubleClickEvent = 1 << 15,
npPalmPenClickEvent = 1 << 16
} NpPalmEventsEnum;
typedef enum NpPalmSystemEventsEnum
{
npPalmPauseEvent = 1,
npPalmResumeEvent = 2,
npPalmGainFocusEvent = 3,
npPalmLoseFocusEvent = 4,
npPalmDimmedEvent = 5,
npPalmSetFullScreenEvent = 6,
npPalmUnsetFullScreenEvent = 7,
npPalmPageLoadingEvent = 8,
npPalmPageLoadCompleteEvent = 9,
npPalmViewPortChangedEvent = 10,
npPalmSpotlightStartEvent = 11,
npPalmSpotlightEndEvent = 12
} NpPalmSystemEventsEnum;
typedef enum NpPalmKeyModifiersEnum
{
npPalmCtrlKeyModifier = 1 << 0,
npPalmAltKeyModifier = 1 << 1,
npPalmShiftKeyModifier = 1 << 2,
npPalmMetaKeyModifier = 1 << 3
} NpPalmKeyModifiersEnum;
typedef struct NpPalmKeyEvent
{
int32_t chr; /* 32-bit so any Unicode character fits */
int32_t modifiers;
int32_t rawkeyCode;
int32_t rawModifier;
} NpPalmKeyEvent;
typedef struct NpPalmPenEvent
{
int32_t xCoord, yCoord; /* plugin-local, in the plugin's own unscaled pixels */
int32_t modifiers;
} NpPalmPenEvent;
typedef struct NpPalmTouchPoint
{
int32_t xCoord, yCoord;
} NpPalmTouchPoint;
typedef struct NpPalmTouchEvent
{
int32_t touchCount;
NpPalmTouchPoint* touches; /* process-local — never send over IPC */
int32_t modifiers;
} NpPalmTouchEvent;
typedef struct NpPalmDrawEvent
{
void* dstBuffer; /* process-local; API 1.0 raster destination */
uint32_t dstRowBytes;
int32_t srcLeft;
int32_t srcRight;
int32_t srcTop;
int32_t srcBottom;
void* graphicsContext; /* process-local; the Piranha PGContext, API 2.0 */
int32_t dstLeft;
int32_t dstRight;
int32_t dstTop;
int32_t dstBottom;
} NpPalmDrawEvent;
typedef struct NpPalmSystemEvent
{
NpPalmSystemEventsEnum type;
int32_t value;
int32_t viewLeft;
int32_t viewRight;
int32_t viewTop;
int32_t viewBottom;
void* reserved; /* process-local */
} NpPalmSystemEvent;
typedef enum NpPalmGestureEventEnum
{
npPalmGestureStartEvent = 1,
npPalmGestureChangeEvent = 2,
npPalmGestureEndEvent = 3,
npPalmGestureSingleTapEvent = 4
} NpPalmGestureEventEnum;
typedef struct NpPalmGestureEvent
{
NpPalmGestureEventEnum type;
int32_t x, y;
float scale, rotate;
int32_t center_x, center_y;
int32_t modifiers;
} NpPalmGestureEvent;
typedef struct NPEvent
{
NpPalmEventsEnum eventType;
union {
NpPalmKeyEvent keyEvent;
NpPalmPenEvent penEvent;
NpPalmDrawEvent drawEvent;
NpPalmSystemEvent systemEvent;
NpPalmGestureEvent gestureEvent;
NpPalmTouchEvent touchEvent;
} data;
} NPEvent;
#else
typedef void* NPEvent;
#endif
+15 -1
View File
@@ -341,6 +341,10 @@ nsNPAPIPlugin::CreatePlugin(nsPluginTag *aPluginTag, nsNPAPIPlugin** aResult)
RefPtr<nsNPAPIPlugin> plugin = new nsNPAPIPlugin();
PluginLibrary* pluginLib = GetNewPluginLibrary(aPluginTag);
// JIHAD DIAGNOSTIC (R7): GetNewPluginLibrary is where the OOP decision is made —
// RunPluginOOP() ? PluginModuleParent::LoadModule (launches plugin-container) : a
// PluginPRLibrary loaded in-process. A null here is the plugin-container launch failing.
fprintf(stderr, "[jihad-npapi] GetNewPluginLibrary lib=%d\n", (int)!!pluginLib);
if (!pluginLib) {
return NS_ERROR_FAILURE;
}
@@ -386,6 +390,7 @@ nsNPAPIPlugin::CreatePlugin(nsPluginTag *aPluginTag, nsNPAPIPlugin** aResult)
#else
NPError pluginCallError;
nsresult rv = pluginLib->NP_Initialize(&sBrowserFuncs, &plugin->mPluginFuncs, &pluginCallError);
fprintf(stderr, "[jihad-npapi] NP_Initialize rv=0x%x npErr=%d\n", (unsigned)rv, (int)pluginCallError);
if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) {
return NS_ERROR_FAILURE;
}
@@ -1939,7 +1944,16 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
}
case NPNVSupportsWindowless: {
#if defined(XP_WIN) || defined(XP_MACOSX) || \
// MOZ_WIDGET_HEADLESS added for Jihad Browser. This list enumerates the toolkits that can
// host a windowless plugin, and it was written before a headless toolkit existed — so a
// cairo-headless build answered "windowless unsupported" to every plugin, which is the
// opposite of the truth. Headless is the toolkit that MOST needs windowless: there is no X
// server, no Drawable and no XEmbed, so windowed hosting is impossible and drawing into a
// memory bitmap we own is the only thing that can work. gfxPlatformHeadless already returns
// true from SupportsPluginDirectBitmapDrawing(), i.e. the drawing model this unlocks
// (NPDrawingModelAsyncBitmapSurface) is implemented for this platform; only this
// advertisement was missing, and with it false no plugin would ever choose windowless.
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_HEADLESS) || \
(defined(MOZ_X11) && defined(MOZ_WIDGET_GTK))
*(NPBool*)result = true;
#else
+71 -1
View File
@@ -843,6 +843,9 @@ nsPluginHost::InstantiatePluginInstance(const nsACString& aMimeType, nsIURI* aUR
}
rv = SetUpPluginInstance(aMimeType, aURL, instanceOwner);
// JIHAD DIAGNOSTIC (R7): the real rv is flattened to NS_ERROR_FAILURE below, which is what
// made this failure opaque from the caller's side.
fprintf(stderr, "[jihad-npapi] SetUpPluginInstance rv=0x%x\n", (unsigned)rv);
if (NS_FAILED(rv)) {
instanceOwner->Destroy();
return NS_ERROR_FAILURE;
@@ -961,7 +964,12 @@ nsPluginHost::TrySetUpPluginInstance(const nsACString &aMimeType,
#endif
RefPtr<nsNPAPIPlugin> plugin;
GetPlugin(aMimeType, getter_AddRefs(plugin));
nsresult jihadGetRv = GetPlugin(aMimeType, getter_AddRefs(plugin));
// JIHAD DIAGNOSTIC (R7): GetPlugin -> CreateNPAPIPlugin -> nsNPAPIPlugin::CreatePlugin, which
// for an OOP build is PluginModuleParent::LoadModule (the plugin-container launch). Its rv is
// DISCARDED here; only the null check survives, so a launch failure is invisible.
fprintf(stderr, "[jihad-npapi] GetPlugin rv=0x%x plugin=%d\n",
(unsigned)jihadGetRv, (int)!!plugin);
if (!plugin) {
return NS_ERROR_FAILURE;
}
@@ -987,6 +995,7 @@ nsPluginHost::TrySetUpPluginInstance(const nsACString &aMimeType,
// except in some cases not Java, see bug 140931
// our COM pointer will free the peer
nsresult rv = instance->Initialize(plugin.get(), aOwner, aMimeType);
fprintf(stderr, "[jihad-npapi] instance->Initialize rv=0x%x\n", (unsigned)rv);
if (NS_FAILED(rv)) {
mInstances.RemoveElement(instance.get());
aOwner->SetInstance(nullptr);
@@ -4201,3 +4210,64 @@ PluginDestructionGuard::DelayDestroy(nsNPAPIPluginInstance *aInstance)
return false;
}
// ── JIHAD (webOS, cavekit-addons-extensions.md R7) ────────────────────────────────────────
//
// A C entry point for the render daemon, following the jihad_offscreen_* precedent in
// widget/PuppetWidget.cpp: the daemon links against libxul but cannot see internal classes,
// and nsNPAPIPluginInstance::HandleEvent is neither exported nor virtual, so there is no
// other way to reach a plugin from outside.
//
// This exists for the frozen YAP command pair asyncCmdPluginSpotlightStart/End. The card
// scrims and smart-zooms to a plugin, then tells the server the rect it settled on; the
// server's job is to pass that on to the plugin as Palm's npPalmSpotlightStartEvent(11) /
// npPalmSpotlightEndEvent(12). It is not cosmetic: Flash routes 11 to the same handler as
// npPalmSetFullScreenEvent(6) and 12 to the same as npPalmUnsetFullScreenEvent(7)
// (libflashplayer.so jump table at 0x44e0c — entries 10 and 11 target 0x44fa0/0x44e80,
// identical to entries 5 and 6), so this is how a plugin is told it went fullscreen.
//
// Broadcast to every running instance rather than targeting one: the spotlight is a
// page-level, one-plugin-at-a-time state, this daemon serves a single card, and the
// alternative — matching the rect against each instance's frame — would invent a
// disambiguation rule that the contract does not define. Returns how many instances were
// told, so a caller can tell "no plugin" from "delivered".
extern "C" MOZ_EXPORT int
jihad_plugin_palm_spotlight(int aOn, int aLeft, int aTop, int aRight, int aBottom)
{
// Palm's NPEvent exists only where npapi.h defines it: the headless toolkit the device builds
// (the desktop GTK build has the X11 one and no Palm plugin to tell; T-387)
#if defined(MOZ_ENABLE_NPAPI) && defined(XP_UNIX) && defined(MOZ_WIDGET_HEADLESS)
RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
if (!host) {
return 0;
}
NPEvent ev;
memset(&ev, 0, sizeof(ev));
ev.eventType = npPalmSystemEvent;
ev.data.systemEvent.type = aOn ? npPalmSpotlightStartEvent : npPalmSpotlightEndEvent;
// Palm's host leaves systemEvent.value uninitialised here and fills only the rect
// (libWebKitLuna handlePluginSpotlightStart 0x4e6cec-0x4e6d24, which never writes [sp+8]).
// The memset above zeroes it, which is strictly tidier and observably the same.
ev.data.systemEvent.viewLeft = aLeft;
ev.data.systemEvent.viewTop = aTop;
ev.data.systemEvent.viewRight = aRight;
ev.data.systemEvent.viewBottom = aBottom;
int delivered = 0;
// Copy the instance list first: HandleEvent re-enters the plugin, which may run script and
// tear an instance down underneath us.
nsTArray<RefPtr<nsNPAPIPluginInstance>> instances(host->JihadRunningInstances());
for (uint32_t i = 0; i < instances.Length(); ++i) {
int16_t response = kNPEventNotHandled;
if (NS_SUCCEEDED(instances[i]->HandleEvent(&ev, &response,
NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO))) {
delivered++;
}
}
return delivered;
#else
(void)aOn; (void)aLeft; (void)aTop; (void)aRight; (void)aBottom;
return 0;
#endif
}
+7
View File
@@ -274,6 +274,13 @@ public:
InfallibleTArray<nsCString>& result,
bool firstMatchOnly);
// Jihad R7 (webOS): a snapshot of the live instances, for jihad_plugin_palm_spotlight.
// A COPY, not a reference: dispatching an event re-enters the plugin, which can run script
// and destroy an instance, and mInstances is mutated by that teardown.
const nsTArray<RefPtr<nsNPAPIPluginInstance>>& JihadRunningInstances() const {
return mInstances;
}
private:
friend class nsPluginUnloadRunnable;
+216 -14
View File
@@ -569,6 +569,75 @@ NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(NPRect *invalidRect)
GetContentsScaleFactor(&scaleFactor);
rect.ScaleRoundOut(scaleFactor);
mPluginFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN, &rect);
// JIHAD (2026-08-09): drive the offscreen daemon's re-capture for WINDOWLESS plugins.
//
// A windowless plugin has no mWidget, so the mWidget->Invalidate() branch above (which is what
// ultimately reaches PuppetWidget::Invalidate and sets the daemon's mJihadDirty flag) never
// runs. InvalidateLayer() alone only marks the plugin's ImageLayer for recomposition; with the
// in-process BasicLayerManager and no separate compositor, that repaints the widget's own layer
// backbuffer but never triggers jihad_offscreen_render_region, the path that actually renders a
// frame into the adapter's shared buffer for the card. Measured: Flash pushes a fresh magenta
// frame into its ImageContainer ~15x/s and BasicImageLayer::Paint runs on each, yet
// render_region fired ONCE (at load) so the card froze on the pre-content frame. The control
// plugin only appeared to work because its static fill was already present at that single
// capture. Invalidate the nearest real widget here so every async plugin frame marks the daemon
// dirty and gets composited to the card.
//
// THE RECT MATTERS, and the first version of this got it wrong. It invalidated
// nearest->GetBounds() — the WIDGET's bounds, i.e. the whole viewport — on the reasoning
// that the daemon re-renders the whole document per capture anyway. That reasoning stopped
// being true when the daemon learned to repaint only the damaged rows: a whole-viewport
// software render costs ~40 ms on this hardware against ~4 ms for a 320x240 plugin box, and
// a full-viewport damage box silently forced the expensive path on every single frame.
// Measured: an animated SWF ran at 19 fps with 1 partial repaint in 39, and the damage box
// logged as 768x942 with the plugin's own 320x240 unioned uselessly into it.
//
// So invalidate the plugin's own area, translated from plugin-local into the widget's
// coordinates the same way the rest of this file does it: content-box origin relative to the
// frame, offset to the widget, in device px.
if (!mWidget) {
nsIWidget* nearest = mPluginFrame->GetNearestWidget();
if (nearest) {
nsIntRect widgetRect = rect;
nsPresContext* pc = mPluginFrame->PresContext();
// Offset to the ROOT frame, which is what the widget's coordinates are relative to.
// GetReferenceFrame() was the first attempt and it is wrong here: for a plugin it
// resolves to a frame that makes the offset come out 0, so every invalidation landed at
// the viewport's top-left corner instead of on the plugin. That is not a small error —
// the damage-only repaint then faithfully refreshed the wrong 320x240 box and the
// plugin's own area never updated again, which reads on screen as the animation
// freezing after its first frame. This is the same offset nsPluginFrame itself uses to
// build NPWindow.x/y.
nsIFrame* rootFrame = nullptr;
if (nsIPresShell* ps = mPluginFrame->PresContext()->GetPresShell()) {
rootFrame = ps->GetRootFrame();
}
nsPoint origin = mPluginFrame->GetContentRectRelativeToSelf().TopLeft() +
(rootFrame ? mPluginFrame->GetOffsetToCrossDoc(rootFrame) : nsPoint());
widgetRect.MoveBy(pc->AppUnitsToDevPixels(origin.x),
pc->AppUnitsToDevPixels(origin.y));
// A plugin is entitled to report an invalid rect larger than itself, and an empty one
// would invalidate nothing at all; clamp to the plugin's own box, and fall back to the
// widget bounds if that leaves nothing (correctness before speed).
nsIntRect pluginBox(pc->AppUnitsToDevPixels(origin.x),
pc->AppUnitsToDevPixels(origin.y),
pc->AppUnitsToDevPixels(
mPluginFrame->GetContentRectRelativeToSelf().width),
pc->AppUnitsToDevPixels(
mPluginFrame->GetContentRectRelativeToSelf().height));
widgetRect = widgetRect.Intersect(pluginBox);
if (widgetRect.IsEmpty()) {
widgetRect = pluginBox;
}
if (widgetRect.IsEmpty()) {
nearest->Invalidate(nearest->GetBounds());
} else {
nearest->Invalidate(LayoutDeviceIntRect(widgetRect.x, widgetRect.y,
widgetRect.width, widgetRect.height));
}
}
}
return NS_OK;
}
@@ -2530,6 +2599,122 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
rv = nsEventStatus_eConsumeNoDefault;
#endif
// Guard MUST match the one npapi.h uses to define NPEvent as Palm's union. Any other
// predicate compiles this against `typedef void* NPEvent` and does not build.
#if defined(XP_UNIX) && defined(MOZ_WIDGET_HEADLESS)
// JIHAD (webOS, cavekit-addons-extensions.md R7) — DELIVER INPUT IN THE PALM PROTOCOL.
//
// Everything above this point is a platform arm: XP_MACOSX, XP_WIN, MOZ_X11. A
// cairo-headless build matches none of them, so this function used to reduce to
// `return nsEventStatus_eIgnore;` and a windowless plugin received no mouse, key, focus or
// blur event in its whole lifetime. Measured on the TouchPad before this branch existed: a
// tap hit-tested the <EMBED>, the daemon logged `mouseSend <EMBED> ... : down`, and the
// plugin's NPP_HandleEvent was called exactly once ever — for the child's own gain-focus
// injection. Nothing upstream is at fault; the DOM listeners, the hit test, the windowless
// guards and the IPC hop are all live and correct (see the Dispatch*ToPlugin callers).
//
// The event shape is Palm's, because NPEvent on this platform IS Palm's union (npapi.h) and
// the device's Flash was compiled against that declaration.
{
NPEvent pluginEvent;
memset(&pluginEvent, 0, sizeof(pluginEvent));
if (anEvent.mClass == eMouseEventClass) {
const WidgetMouseEvent& mouseEvent = *anEvent.AsMouseEvent();
switch (anEvent.mMessage) {
case eMouseDown: pluginEvent.eventType = npPalmPenDownEvent; break;
case eMouseUp: pluginEvent.eventType = npPalmPenUpEvent; break;
case eMouseMove: pluginEvent.eventType = npPalmPenMoveEvent; break;
// The synthesized click/dblclick that follows a down/up pair. Palm's host sends these
// as their own event types rather than swallowing them (libWebKitLuna
// handleMouseEvent 0x4e946c-0x4e94d8 maps click -> 65536 and dblclick -> 32768, in
// ADDITION to the down/up pair, not instead of it), so this is what a plugin written
// for webOS was built to see. The X11 arm above drops them instead, which is right
// for X11 and wrong here.
//
// Flash itself ignores both: its NPP_HandleEvent jump table (libflashplayer.so
// 0x4514c-0x4522c) compares only against 1/2/4/8/16/64/128/256/512, and anything
// else falls through to "not handled" — confirmed on device, where a tap logs
// `palm event 0x10000 ... handled=0` between two handled pen events. Sending them
// anyway is deliberate: the contract is the host's, not this one plugin's, and a
// plugin that acts only on the click is otherwise silently unusable.
case eMouseClick: pluginEvent.eventType = npPalmPenClickEvent; break;
case eMouseDoubleClick: pluginEvent.eventType = npPalmPenDoubleClickEvent; break;
default: break; // over/out/wheel/aux: no Palm equivalent, drop
}
if (pluginEvent.eventType) {
// The plugin-local point, computed exactly as the MOZ_X11 arm above computes it. This
// is also what Palm's own host does — PluginView's webOS block uses the renderer's
// absoluteToLocal() on the same absolute location — so the two hosts agree on the
// space without either being ported to the other.
//
// Deliberately NO zoom or scroll arithmetic here. The card's fit-zoom is not an engine
// zoom (it is applied when the daemon scales the capture context), layout.css.
// devPixelsPerPx is pinned to 1.0, and the daemon has already mapped card px to CSS
// viewport px before dispatching. Adding a factor here is how plugin input drifts away
// from where page content thinks it was clicked; the criterion is that both go through
// the same transform, and they do precisely because this arm adds none.
const nsPresContext* presContext = mPluginFrame->PresContext();
nsPoint appPoint =
nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) -
mPluginFrame->GetContentRectRelativeToSelf().TopLeft();
pluginEvent.data.penEvent.xCoord =
presContext->AppUnitsToDevPixels(appPoint.x);
pluginEvent.data.penEvent.yCoord =
presContext->AppUnitsToDevPixels(appPoint.y);
pluginEvent.data.penEvent.modifiers =
(mouseEvent.IsControl() ? npPalmCtrlKeyModifier : 0) |
(mouseEvent.IsAlt() ? npPalmAltKeyModifier : 0) |
(mouseEvent.IsShift() ? npPalmShiftKeyModifier : 0) |
(mouseEvent.IsMeta() ? npPalmMetaKeyModifier : 0);
}
} else if (anEvent.mClass == eKeyboardEventClass) {
const WidgetKeyboardEvent& keyEvent = *anEvent.AsKeyboardEvent();
switch (anEvent.mMessage) {
case eKeyDown: pluginEvent.eventType = npPalmKeyDownEvent; break;
case eKeyUp: pluginEvent.eventType = npPalmKeyUpEvent; break;
case eKeyPress: pluginEvent.eventType = npPalmKeyPressEvent; break;
default: break;
}
if (pluginEvent.eventType) {
// There is no native key event to copy from on this platform (mPluginEvent is a
// Windows concept), so the Palm fields are synthesized from the widget event.
// rawkeyCode/rawModifier are Palm's "pass the unprocessed event through" pair, which
// for a synthesized event is the same key code and modifier set.
int32_t mods =
(keyEvent.IsControl() ? npPalmCtrlKeyModifier : 0) |
(keyEvent.IsAlt() ? npPalmAltKeyModifier : 0) |
(keyEvent.IsShift() ? npPalmShiftKeyModifier : 0) |
(keyEvent.IsMeta() ? npPalmMetaKeyModifier : 0);
pluginEvent.data.keyEvent.chr =
static_cast<int32_t>(keyEvent.PseudoCharCode());
pluginEvent.data.keyEvent.modifiers = mods;
pluginEvent.data.keyEvent.rawkeyCode = static_cast<int32_t>(keyEvent.mKeyCode);
pluginEvent.data.keyEvent.rawModifier = mods;
}
} else if (anEvent.mMessage == eFocus || anEvent.mMessage == eBlur) {
// Focus arrives as a bare WidgetGUIEvent with a null widget (see DispatchFocusToPlugin),
// so it must not touch the coordinate path above.
pluginEvent.eventType = npPalmSystemEvent;
pluginEvent.data.systemEvent.type =
(anEvent.mMessage == eFocus) ? npPalmGainFocusEvent : npPalmLoseFocusEvent;
}
if (pluginEvent.eventType) {
int16_t response = kNPEventNotHandled;
mInstance->HandleEvent(&pluginEvent, &response,
NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
if (response == kNPEventHandled) {
rv = nsEventStatus_eConsumeNoDefault;
}
}
}
#endif
return rv;
}
@@ -2977,23 +3162,40 @@ NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void)
if (!mWidget) {
// native (single process)
mWidget = do_CreateInstance(kWidgetCID, &rv);
nsWidgetInitData initData;
initData.mWindowType = eWindowType_plugin;
initData.mUnicode = false;
initData.clipChildren = true;
initData.clipSiblings = true;
rv = mWidget->Create(parentWidget.get(), nullptr,
LayoutDeviceIntRect(0, 0, 0, 0), &initData);
if (NS_FAILED(rv)) {
mWidget->Destroy();
mWidget = nullptr;
return rv;
if (!mWidget) {
// JIHAD (2026-10-05): A BUILD WITH NO CHILD-WINDOW WIDGET HAS NO WINDOWED PLUGINS.
// The offscreen embedding registers no widget for kWidgetCID, so this came back
// null and the Create() call below dereferenced it: the daemon died with SIGSEGV on
// every page whose Flash movie was embedded the ordinary way. A plugin is windowed
// unless it asks otherwise, and Flash asks only for wmode=opaque/transparent — the
// default, wmode=window, is what most of the web uses (found on two "Flash test"
// sites; every test page of ours had wmode=opaque). webOS's own browser never had
// plugin windows either and handed every plugin a drawable; its Flash build draws
// through the Palm window structure in both modes. So do the same: with no window
// to give, the instance is windowless.
mInstance->SetWindowless(true);
windowless = true;
} else {
nsWidgetInitData initData;
initData.mWindowType = eWindowType_plugin;
initData.mUnicode = false;
initData.clipChildren = true;
initData.clipSiblings = true;
rv = mWidget->Create(parentWidget.get(), nullptr,
LayoutDeviceIntRect(0, 0, 0, 0), &initData);
if (NS_FAILED(rv)) {
mWidget->Destroy();
mWidget = nullptr;
return rv;
}
}
}
mWidget->EnableDragDrop(true);
mWidget->Show(false);
mWidget->Enable(false);
if (mWidget) {
mWidget->EnableDragDrop(true);
mWidget->Show(false);
mWidget->Enable(false);
}
}
if (mPluginFrame) {
+11 -1
View File
@@ -133,6 +133,12 @@ BrowserStreamChild::RecvNPP_DestroyStream(const NPReason& reason)
{
PLUGIN_LOG_DEBUG_METHOD;
// Jihad R7: end-of-stream is what tells a Flash player the movie is complete. A player that
// is never told stops on frame zero, which looks exactly like a player that cannot draw.
fprintf(stderr, "[jihad-npapi-child] RecvNPP_DestroyStream reason=%d state=%d\n",
(int)reason, (int)mState);
fflush(stderr);
if (ALIVE != mState)
NS_RUNTIMEABORT("Unexpected state: recevied NPP_DestroyStream twice?");
@@ -232,8 +238,12 @@ BrowserStreamChild::Deliver()
if (kStreamOpen == mStreamStatus)
mStreamStatus = NPRES_DONE;
(void) mInstance->mPluginIface
NPError dsrv = mInstance->mPluginIface
->destroystream(&mInstance->mData, &mStream, mStreamStatus);
// Jihad R7: the delivery site, as opposed to RecvNPP_DestroyStream which only queues it.
fprintf(stderr, "[jihad-npapi-child] NPP_DestroyStream status=%d rv=%d\n",
(int)mStreamStatus, (int)dsrv);
fflush(stderr);
}
if (DESTROYED == mDestroyPending && mNotifyPending) {
NS_ASSERTION(mStreamNotify, "mDestroyPending but no mStreamNotify?");
+74
View File
@@ -0,0 +1,74 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 http://mozilla.org/MPL/2.0/. */
/*
* NPN entry points exported as GLOBAL SYMBOLS, for plugins that expect the old Netscape
* convention where the host browser exports them rather than only passing an NPNetscapeFuncs
* table to NP_Initialize.
*
* WHY THIS IS ITS OWN TRANSLATION UNIT. The obvious place for these is PluginModuleChild.cpp,
* and it does not work: npapi.h already declares NPN_InvalidateRect, and every header in this
* build is compiled under `-include config/gcc_hidden.h`, which pushes hidden visibility. GCC
* takes visibility from the FIRST declaration it sees, so a later definition carrying
* __attribute__((visibility("default"))) is silently ignored and the symbol lands in the
* object as GLOBAL HIDDEN — present to `nm`, absent from the dynamic table, and therefore
* impossible to interpose. Verified with readelf. This file deliberately includes no NPAPI
* headers at all and describes the functions with void* so there is no prior declaration to
* inherit hidden visibility from.
*
* WHY IT MATTERS. webOS's Flash imports NPN_CreateObject and NPN_InvalidateRect as undefined
* dynamic symbols. Left alone they bind into libWebKitLuna.so — another browser engine that
* is in this process because Flash (and our Piranha drawing path) pull it in. Two consequences,
* both measured:
* 1. Flash's repaint requests go to LunaSysMgr's WebKit and never reach our engine, so the
* plugin is only ever painted when something else happens to invalidate it. That alone
* makes an animating plugin look frozen.
* 2. It is a latent crash: UXP stores a PluginInstanceChild* in NPP::ndata, while
* libWebKitLuna's NPN_InvalidateRect casts that same field to a WebCore::PluginView* and
* makes a virtual call on it — a wild vtable dispatch on the first repaint.
*
* The forwarding pointers are installed by PluginModuleChild once the browser function table
* exists; until then these are safe no-ops.
*/
#include <stdio.h>
extern "C" {
void (*gJihadNPNInvalidateRect)(void* aNPP, void* aRect) = 0;
void* (*gJihadNPNCreateObject)(void* aNPP, void* aClass) = 0;
// Read by the host repaint clock in PluginInstanceChild.cpp: while this is zero the plugin has
// never asked to be repainted, so the host has to drive it.
unsigned gJihadNPNInvalidateRectCalls = 0;
__attribute__((visibility("default"))) void
NPN_InvalidateRect(void* aNPP, void* aRect)
{
// The first call is the signal that the plugin's frame clock is finally running; without
// it the plugin is only ever painted by an unrelated invalidation, which is
// indistinguishable on screen from a plugin that draws nothing. Log it once, and log the
// no-forwarder case too — arriving before PluginModuleChild installs the pointers is a
// dropped repaint, not a no-op.
gJihadNPNInvalidateRectCalls++;
static int sLogged = 0;
if (sLogged < 8) {
sLogged++;
fprintf(stderr, "[jihad-npapi-child] NPN_InvalidateRect npp=%p rect=%p fwd=%p\n",
aNPP, aRect, (void*)gJihadNPNInvalidateRect);
fflush(stderr);
}
if (gJihadNPNInvalidateRect) {
gJihadNPNInvalidateRect(aNPP, aRect);
}
}
__attribute__((visibility("default"))) void*
NPN_CreateObject(void* aNPP, void* aClass)
{
return gJihadNPNCreateObject ? gJihadNPNCreateObject(aNPP, aClass) : 0;
}
} // extern "C"
+23
View File
@@ -125,6 +125,29 @@ child:
// of its parent has changed
async ContentsScaleFactorChanged(double aContentsScaleFactor);
// Jihad (webOS, cavekit-addons-extensions.md R7): ask the plugin for ONE frame, now.
//
// Palm's host issued npPalmDrawEvent every time the PAGE painted, so Flash can sit on its own
// frame clock and expect to be asked. Patch 0026 got it drawing by giving the CHILD a timer,
// but that timer free-runs against the daemon's tick, so a frame lands at a drifting phase and
// waits up to a whole tick to be published. Measured on device with a 30 fps SWF: 1:1 delivery
// and a 31-34 ms average, but a gap spread of 9-62 ms, which is what the eye reads as stutter.
//
// CAUTION, measured 2026-08-10 and it contradicts what 0026 assumed: the plugin DOES invalidate
// itself, ~22 times a second, alongside our ~27. The counter 0026 reads to conclude otherwise
// (gJihadNPNInvalidateRectCalls) only sees calls that bind the NPN_InvalidateRect SYMBOL, and
// an ordinary NPAPI plugin goes through the NPNetscapeFuncs table instead. So this message is
// currently a SECOND producer rather than the only one, and whether it should exist at all for
// a self-invalidating plugin is open — see the R7 frame-rate criterion.
//
// This is the pull that removes the second clock. ASYNC on purpose: the stock host pulls the
// plugin synchronously inside its page paint (PluginViewPalm), but out-of-process that shape
// is intr NPP_HandleEvent, which would block the daemon's main thread — and therefore its
// tick and its YAP socket — for a full IPC round trip plus a Flash paint on every frame.
// Async keeps the phase lock and costs nothing: the child coalesces duplicate requests via
// mCurrentInvalidateTask, so an extra request while one is in flight is a no-op.
async JihadRequestFrame();
// ********************** Async plugins rendering
// see https://wiki.mozilla.org/Gecko:AsyncPluginPainting
// **********************
+848 -3
View File
@@ -31,6 +31,7 @@ using mozilla::gfx::SharedDIBSurface;
#endif
#endif
#include "gfxSharedImageSurface.h"
#include <dlfcn.h> // Jihad R7: reach the plugin's own glib for npPalmEventLoopValue
#include "gfxUtils.h"
#include "gfxAlphaRecovery.h"
@@ -50,6 +51,61 @@ using namespace mozilla::gfx;
using namespace mozilla::widget;
using namespace std;
// Defined next to JihadPumpGlib, far below; declared here because DoNPP_New starts it.
static void JihadStartGlibPump(PluginInstanceChild* aInstance);
// The instance the host clock repaints, and the count of repaints the PLUGIN asked for. Both
// live here rather than on the instance because the pump is a process-wide free function.
// Cleared in ~PluginInstanceChild so the clock cannot outlive what it points at.
static PluginInstanceChild* sJihadPalmInstance = nullptr;
static uint64_t gJihadPalmDrawEvents = 0;
// Defined in JihadNPNInterpose.cpp, which deliberately includes no NPAPI headers.
extern "C" unsigned gJihadNPNInvalidateRectCalls;
// ── WHICH CALL SITE ACTUALLY DRIVES PLUGIN DRAWS (Jihad, addons R7) ──────────────────────
//
// Three sessions have now attributed the plugin's draw rate to a specific clock by READING the
// code, and every attribution was wrong. Patch 0029 finally put a counter on the request side
// and the numbers did not agree with any of them: 3988 draws against 3072 host requests, with
// the child's own timer provably stood down (one "frame clock -> HOST" transition, no fallback)
// and Flash provably not self-invalidating (gJihadNPNInvalidateRectCalls stays 0). So roughly a
// quarter of all draws come from a fourth place, and at an 8 ms tick that share DOMINATES.
//
// Every path to a draw funnels through AsyncShowPluginFrame, so tagging its call sites answers
// the question directly rather than by elimination. Reported next to `palm draw`, which is the
// count these have to add up to. Declared up here with the other file statics because the first
// tagged site is in AnswerNPP_SetWindow, well above the frame-clock block further down.
enum {
kJihadShowSetWindow = 0, // AnswerNPP_SetWindow / AsyncSetWindow, accumulated rect
kJihadShowInvalidate, // InvalidateRect reached from OUR host repaint tick
kJihadShowPluginSelf, // InvalidateRect reached from the PLUGIN's own NPN_InvalidateRect
kJihadShowRetry, // InvalidateRectDelayed's retry when ShowPluginFrame refused
kJihadShowBgUpdate, // RecvUpdateBackground, background changed
kJihadShowBgUpdateTail, // RecvUpdateBackground, unconditional tail
kJihadShowBgDestroy, // background destroyer
kJihadShowSites
};
static uint32_t gJihadShowFrom[kJihadShowSites];
static const char* const kJihadShowNames[kJihadShowSites] = {
"setwin", "hostinval", "plugininval", "retry", "bgupd", "bgtail", "bgdestroy"
};
// True only while JihadPalmRepaintTick's own InvalidateRect call is on the stack, so the two
// producers can be told apart AT the shared funnel.
//
// WHY THIS EXISTS, and it invalidates a premise the port has carried since patch 0026:
// gJihadNPNInvalidateRectCalls — the counter used to decide "the plugin never asks to be
// repainted, so the host must drive it" — is STRUCTURALLY BLIND. It lives in
// JihadNPNInterpose.cpp and only counts calls that bind the NPN_InvalidateRect SYMBOL. An
// ordinary NPAPI plugin calls through the NPNetscapeFuncs table instead, which
// PluginModuleChild fills with its own _invalidaterect (PluginModuleChild.cpp:986); that
// forwards straight to InstCast(aNPP)->InvalidateRect (:1302-1310) and never touches the
// interpose. So the counter can read 0 for the whole run while the plugin invalidates
// constantly — which is exactly what was measured: 1344 host requests against 2662 invalidates
// with the child's timer provably off (one "frame clock -> HOST", no fallback).
static bool sJihadInHostRepaint = false;
#ifdef MOZ_WIDGET_GTK
#include <gtk/gtk.h>
@@ -193,6 +249,8 @@ PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface,
#endif
, mAccumulatedInvalidRect(0,0,0,0)
, mIsTransparent(false)
, mJihadSentPalmGainFocus(false)
, mJihadInputEventsLogged(0)
, mSurfaceType(gfxSurfaceType::Max)
, mPendingPluginCall(false)
, mDoAlphaExtraction(false)
@@ -231,6 +289,11 @@ PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface,
PluginInstanceChild::~PluginInstanceChild()
{
// The host repaint clock outlives any single instance (it is bound to the process-wide
// GMainLoop), so it must not be left holding this pointer.
if (sJihadPalmInstance == this) {
sJihadPalmInstance = nullptr;
}
#if defined(OS_WIN)
NS_ASSERTION(!mPluginWindowHWND, "Destroying PluginInstanceChild without NPP_Destroy?");
if (GetQuirks() & QUIRK_UNITY_FIXUP_MOUSE_CAPTURE) {
@@ -260,6 +323,65 @@ PluginInstanceChild::~PluginInstanceChild()
#endif
}
// ── THE webOS PLUGIN ABI (Jihad, addons R7) ───────────────────────────────────────────────
//
// None of this is in our npapi.h; it is Palm's XP_WEBOS block, and every layout below was
// checked TWICE — against WebKit/Source/WebCore/plugins/npapi.h, and against the machine code
// of the host that actually shipped on the device. That host is NOT the Qt one in our WebKit
// checkout (PluginViewQt.cpp passes a QPainter* and Flash has no Qt dependency at all); it is
// WebCore::PluginView compiled from PluginViewPalm.cpp into /usr/lib/libWebKitLuna.so, which
// is unstripped on the device and can simply be read. Offsets cited below are into that
// library. Get these wrong and the plugin reads garbage, silently.
//
// The event union itself now lives in npapi.h as the real `NPEvent` for this platform, so the
// parent (nsPluginInstanceOwner::ProcessEvent) and the child cannot drift and the type survives
// the NPRemoteEvent memcpy. What used to be here was a TRUNCATED private mirror —
// systemEvent held only `type`, which is enough for gain-focus and silently wrong for a
// spotlight event, whose rect lives in the four fields the mirror did not have.
//
// These assertions are the actual contract. Each offset was read out of the shipped host's
// machine code, and a mismatch here means the plugin reads a different field than the one
// written — a failure with no symptom other than wrong behaviour.
#if defined(XP_UNIX) && defined(MOZ_WIDGET_HEADLESS)
static_assert(sizeof(NPEvent) == 48, "webOS NPEvent is 48 bytes");
static_assert(offsetof(NPEvent, data) == 4, "eventType is a 4-byte field at 0");
// PluginView::handleMouseEvent (libWebKitLuna 0x4e9458/0x4e9460/0x4e9464) stores x, y and
// modifiers to [sp+4], [sp+8], [sp+12] with eventType at [sp].
static_assert(offsetof(NPEvent, data.penEvent.xCoord) == 4, "penEvent.xCoord @4");
static_assert(offsetof(NPEvent, data.penEvent.yCoord) == 8, "penEvent.yCoord @8");
static_assert(offsetof(NPEvent, data.penEvent.modifiers) == 12, "penEvent.modifiers @12");
// PluginView::handleKeyboardEvent (0x4e8ebc/0x4e8e80/0x4e8ef4/0x4e8f04).
static_assert(offsetof(NPEvent, data.keyEvent.chr) == 4, "keyEvent.chr @4");
static_assert(offsetof(NPEvent, data.keyEvent.modifiers) == 8, "keyEvent.modifiers @8");
static_assert(offsetof(NPEvent, data.keyEvent.rawkeyCode) == 12, "keyEvent.rawkeyCode @12");
static_assert(offsetof(NPEvent, data.keyEvent.rawModifier) == 16, "keyEvent.rawModifier @16");
// PluginView::handlePluginSpotlightStart (0x4e6cec-0x4e6d20) writes 0x100 at [sp], 11 at
// [sp+4], then left/right/top/bottom at [sp+12]/[sp+16]/[sp+20]/[sp+24] — note it never
// initialises `value` at [sp+8].
static_assert(offsetof(NPEvent, data.systemEvent.type) == 4, "systemEvent.type @4");
static_assert(offsetof(NPEvent, data.systemEvent.viewLeft) == 12, "systemEvent.viewLeft @12");
static_assert(offsetof(NPEvent, data.systemEvent.viewRight) == 16, "systemEvent.viewRight @16");
static_assert(offsetof(NPEvent, data.systemEvent.viewTop) == 20, "systemEvent.viewTop @20");
static_assert(offsetof(NPEvent, data.systemEvent.viewBottom) == 24, "systemEvent.viewBottom @24");
// PluginView::paint (0x4e7e30-0x4e7e44) stores platformContext() at frame+52 and the four
// scaled dst coords at +56/+60/+64/+68, i.e. +24/+28/+32/+36 inside the draw member.
static_assert(offsetof(NPEvent, data.drawEvent.graphicsContext) == 28, "drawEvent.gc @28");
static_assert(offsetof(NPEvent, data.drawEvent.dstLeft) == 32, "drawEvent.dstLeft @32");
#endif // XP_UNIX && MOZ_WIDGET_HEADLESS
// NPWindow.window for a webOS plugin. Palm's host never calls setwindow without one:
// PluginView::setNPWindowRect (libWebKitLuna 0x4e74e0) builds it as a STACK LOCAL, points
// m_npWindow.window at it (0x4e7570 `str sp, [r4, #520]`), calls setwindow, and immediately
// re-nulls the pointer (0x4e7614) so the dangling stack address is never left behind.
// Field offsets read straight off that function: visible is a byte at +0 (0x4e755c
// `strbne r3, [sp]`), bpp is 32 at +4 (0x4e75dc `mov ip,#32; str ip,[sp,#4]`), and scaleFactor
// is the double from ScrollView::getScale() at +8 (0x4e7588 `strd r6, [sp, #8]`).
struct JihadNpPalmWindow {
bool visible;
uint32_t bpp;
double scaleFactor;
};
NPError
PluginInstanceChild::DoNPP_New()
{
@@ -286,6 +408,44 @@ PluginInstanceChild::DoNPP_New()
return rv;
}
// WEBOS EVENT LOOP (Jihad, addons R7).
//
// Palm's own host does this right after NPP_New and before anything else
// (WebKit/Source/WebCore/plugins/qt/PluginViewQt.cpp, PluginView::platformStart):
// it hands the plugin a GMainLoop* through npPalmEventLoopValue. A webOS plugin drives
// its own frame scheduling off that loop, so a plugin that never receives one is a
// plugin that instantiates and then never asks to paint — exactly the symptom this port
// had.
//
// glib is not linked into this process; it arrives as a dependency of the plugin, so it
// can only be reached by name once the plugin is loaded — which it is by now. A plugin
// that does not know the variable just returns an error, so this is safe for any plugin.
if (mPluginIface->setvalue) {
static void* sMainLoop = nullptr;
if (!sMainLoop) {
if (void* glib = dlopen("libglib-2.0.so.0", RTLD_NOW | RTLD_GLOBAL)) {
typedef void* (*GMainLoopNewFn)(void*, int);
GMainLoopNewFn newLoop = (GMainLoopNewFn)dlsym(glib, "g_main_loop_new");
if (newLoop) {
sMainLoop = newLoop(nullptr, 1 /* is_running */);
}
}
}
if (sMainLoop) {
const uint32_t kNpPalmEventLoopValue = 10000;
NPError lerr = mPluginIface->setvalue(npp, (NPNVariable)kNpPalmEventLoopValue,
sMainLoop);
fprintf(stderr, "[jihad-npapi-child] npPalmEventLoopValue loop=%p err=%d\n",
sMainLoop, (int)lerr);
// The plugin now has a loop to hang sources off; start running it. See
// JihadStartGlibPump for why this cannot wait for the first paint.
JihadStartGlibPump(this);
} else {
fprintf(stderr, "[jihad-npapi-child] npPalmEventLoopValue: no glib main loop\n");
}
fflush(stderr);
}
Initialize();
#if defined(XP_MACOSX) && defined(__i386__)
@@ -717,8 +877,8 @@ PluginInstanceChild::NPN_SetValue(NPPVariable aVar, void* aValue)
// on the chrome process. This is because our audio
// API calls should run the chrome proc, not content.
NPError rv = NPERR_GENERIC_ERROR;
PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome();
if (chromeInstance) {
PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome();
if (chromeInstance) {
rv = chromeInstance->PluginRequiresAudioDeviceChanges(this,
(NPBool)(intptr_t)aValue);
}
@@ -964,6 +1124,35 @@ PluginInstanceChild::AnswerNPP_HandleEvent(const NPRemoteEvent& event,
else
*handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy));
// Guard MUST match the one npapi.h uses to define NPEvent as Palm's union. Any other
// predicate compiles this against `typedef void* NPEvent` and does not build.
#if defined(XP_UNIX) && defined(MOZ_WIDGET_HEADLESS)
// JIHAD (webOS R7): the only field-visible evidence that host input reached the plugin.
// A closed-source plugin acknowledges nothing — Flash returns its `handled` flag before it
// even looks at the event (its NPP_HandleEvent sets the return, then dispatches), so this
// line proves DELIVERY and nothing more. Capped, because a pen-move stream would otherwise
// flood the daemon log, which is the only channel this device has.
if (mJihadInputEventsLogged < 24) {
mJihadInputEventsLogged++;
if (evcopy.eventType == npPalmKeyDownEvent ||
evcopy.eventType == npPalmKeyUpEvent ||
evcopy.eventType == npPalmKeyPressEvent) {
fprintf(stderr, "[jihad-npapi-child] palm key 0x%x chr=%d raw=%d mods=0x%x "
"handled=%d\n",
(unsigned)evcopy.eventType, (int)evcopy.data.keyEvent.chr,
(int)evcopy.data.keyEvent.rawkeyCode,
(unsigned)evcopy.data.keyEvent.modifiers, (int)*handled);
} else {
fprintf(stderr, "[jihad-npapi-child] palm event 0x%x at %d,%d mods=0x%x "
"handled=%d\n",
(unsigned)evcopy.eventType, (int)evcopy.data.penEvent.xCoord,
(int)evcopy.data.penEvent.yCoord,
(unsigned)evcopy.data.penEvent.modifiers, (int)*handled);
}
fflush(stderr);
}
#endif
#ifdef XP_MACOSX
// Release any reference counted objects created in the child process.
if (evcopy.type == NPCocoaEventKeyDown ||
@@ -1449,6 +1638,8 @@ PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
if (mPluginIface->setwindow)
(void) mPluginIface->setwindow(&mData, &mWindow);
#elif defined(MOZ_WIDGET_HEADLESS)
// Jihad headless: no windowed plugins; nothing to do.
#else
# error Implement me for your OS
#endif
@@ -2827,6 +3018,12 @@ PluginInstanceChild::DoNPP_NewStream(BrowserStreamChild* actor,
AssertPluginThread();
AutoStackHelper guard(this);
NPError rv = actor->StreamConstructed(mimeType, seekable, stype);
// JIHAD DIAGNOSTIC (R7): does content actually reach the plugin? A plugin that was
// never handed its stream draws nothing for a completely different reason than a
// plugin that cannot draw, and on screen the two are identical (an empty box).
fprintf(stderr, "[jihad-npapi-child] NPP_NewStream mime=%s seekable=%d rv=%d stype=%d\n",
mimeType.get(), (int)seekable, (int)rv, (int)*stype);
fflush(stderr);
return rv;
}
@@ -3417,6 +3614,7 @@ PluginInstanceChild::DoAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
#endif
if (!mAccumulatedInvalidRect.IsEmpty()) {
gJihadShowFrom[kJihadShowSetWindow]++;
AsyncShowPluginFrame();
}
}
@@ -3741,10 +3939,471 @@ PluginInstanceChild::UpdateWindowAttributes(bool aForceSetWindow)
mWindow.clipRect.left, mWindow.clipRect.top, mWindow.clipRect.right, mWindow.clipRect.bottom));
if (mPluginIface->setwindow) {
// WEBOS: hand the plugin an NpPalmWindow, exactly as Palm's host does.
//
// Out of the box this embedder passes NPWindow.window = nullptr for every windowless
// plugin (DoAsyncSetWindow hard-nulls it, and the MOZ_WIDGET_HEADLESS branch of
// AnswerNPP_SetWindow is a no-op), which is correct for an X11 windowless plugin — the
// slot means "native window handle" there, and there isn't one. On webOS the same slot
// means something completely different: it carries the plugin's visibility, the
// surface depth and the page scale. A webOS plugin told window=NULL has been told
// nothing about the surface it is supposed to draw into.
//
// Scoped to the call and re-nulled afterwards, because this is a stack address and
// Palm's host is careful about exactly that (libWebKitLuna 0x4e7570 / 0x4e7614).
//
// scaleFactor is 1.0 rather than the card's fit-zoom: Palm passes ScrollView::getScale()
// because its plugin drew into the page's own scaled surface, whereas here the plugin
// owns an unscaled CSS-sized buffer and the compositor applies the zoom afterwards.
JihadNpPalmWindow palmWindow;
palmWindow.visible = true;
palmWindow.bpp = 32;
palmWindow.scaleFactor = 1.0;
void* savedWindow = mWindow.window;
mWindow.window = &palmWindow;
mPluginIface->setwindow(&mData, &mWindow);
mWindow.window = savedWindow;
static int sLoggedSetWindow = 0;
if (sLoggedSetWindow < 3) {
sLoggedSetWindow++;
fprintf(stderr, "[jihad-npapi-child] NPP_SetWindow %dx%d at %d,%d type=%d "
"palmWindow{visible=1 bpp=32 scale=1.0}\n",
(int)mWindow.width, (int)mWindow.height, (int)mWindow.x, (int)mWindow.y,
(int)mWindow.type);
fflush(stderr);
}
// WEBOS: the last thing Palm's PluginView::platformStart does is tell the plugin it has
// focus — handlePageGainFocus (libWebKitLuna 0x4e6df0) builds
// {eventType = 0x100 (npPalmSystemEvent), systemEvent.type = 3 (npPalmGainFocusEvent)}
// and dispatches it. A plugin that is never told it is focused and visible has no
// reason to start animating.
//
// Only gain-focus: Flash's own system-event dispatcher (libflashplayer.so 0x44da0)
// routes npPalmPageLoadingEvent(8), npPalmPageLoadCompleteEvent(9) and
// npPalmViewPortChangedEvent(10) to a bare `mov r0,#0; pop {pc}`, so those three are
// inert in this build and sending them would prove nothing.
//
// After setwindow, not before, and once: the plugin needs its geometry first, and
// UpdateWindowAttributes runs on every resize and every scroll.
// (Palm's NPEvent exists only where npapi.h defines it: the headless toolkit the device
// builds; the desktop GTK build has the X11 one, T-387)
#if defined(XP_UNIX) && defined(MOZ_WIDGET_HEADLESS)
if (mPluginIface->event && !mJihadSentPalmGainFocus) {
mJihadSentPalmGainFocus = true;
NPEvent ev;
memset(&ev, 0, sizeof(ev));
ev.eventType = npPalmSystemEvent;
ev.data.systemEvent.type = npPalmGainFocusEvent;
int16_t handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&ev));
fprintf(stderr, "[jihad-npapi-child] npPalmSystemEvent gainFocus handled=%d\n",
(int)handled);
fflush(stderr);
}
#endif
}
}
// Run any work the plugin scheduled on glib.
//
// A webOS plugin is handed a GMainLoop through npPalmEventLoopValue and hangs its timers and
// idle sources off it — but this process's main loop is chromium's MessageLoop, so unless
// glib is pumped explicitly those sources NEVER RUN. The visible symptom is a plugin that
// initialises, clears its stage, and then sits on frame zero forever: it is not stuck, it is
// simply never being given the chance to advance.
//
// Bounded so a busy plugin cannot starve the paint it is being pumped for.
static int
JihadPumpGlib(int aMaxIterations)
{
typedef int (*GMainContextIterationFn)(void*, int);
typedef int (*GMainContextPendingFn)(void*);
static bool sTried = false;
static GMainContextIterationFn sIterate = nullptr;
static GMainContextPendingFn sPending = nullptr;
if (!sTried) {
sTried = true;
if (void* glib = dlopen("libglib-2.0.so.0", RTLD_NOW | RTLD_GLOBAL)) {
sIterate = (GMainContextIterationFn)dlsym(glib, "g_main_context_iteration");
sPending = (GMainContextPendingFn)dlsym(glib, "g_main_context_pending");
}
fprintf(stderr, "[jihad-npapi-child] glib pump iterate=%p pending=%p\n",
(void*)sIterate, (void*)sPending);
fflush(stderr);
}
if (!sIterate) {
return 0;
}
int n = 0;
while (n < aMaxIterations) {
if (sPending && !sPending(nullptr)) {
break;
}
sIterate(nullptr, 0 /* may_block = FALSE */);
n++;
}
return n;
}
// ── RUN THE PLUGIN'S EVENT LOOP CONTINUOUSLY (Jihad, addons R7) ───────────────────────────
//
// Pumping glib only just before a paint deadlocks a webOS plugin, because its startup is
// asynchronous: Flash registers com.palm.flashgraphics on the LS2 bus, attaches that socket to
// the loop it was handed, and then waits on round-trips to com.palm.systemservice
// (getPreferences), com.palm.display (status) and com.palm.db (find) before it starts its frame
// clock. Until the clock runs it never calls NPN_InvalidateRect, so nothing ever asks it to
// paint — and the only pump was on the paint path. No paint, no pump; no pump, no paint.
//
// So the pump has to be independent of painting. This reposts itself on the child's own
// MessageLoop, which is the SAME thread every other NPAPI call into the plugin runs on — the
// arrangement Palm's host gave it, since BrowserServer's main loop simply WAS a GMainLoop.
// g_main_loop_run() on a dedicated thread would be the wrong shape: the plugin's timer
// callbacks would then fire off the NPAPI thread and reenter us from it.
//
// MEASURED: before the LS2 role allowed com.palm.flashgraphics, LSRegisterPalmService failed
// with -1027, nothing was ever attached to the loop, and g_main_context_pending() returned
// FALSE forever. That is fixed in packaging/gen-variant-scripts.sh; the pump only has anything
// to run because of it.
static const int kJihadGlibPumpIntervalMs = 16; // ~60Hz, the rate a frame clock wants
static const int kJihadGlibPumpMaxIters = 20; // bounded: never starve the MessageLoop
// Host-driven repaint divisor: one repaint every Nth 16 ms tick. 2 is ~30 Hz, which is what
// ordinary Flash content is authored at; 4 was ~15 Hz and was the measured ceiling on the
// WHOLE pipeline — device 2026-08-10, single instance: plugin draw 21.6-24 fps and RecvShow
// 21.3-24.2 fps while the daemon was already compositing 28.4-29.4 fps, i.e. the host was
// asking for frames more slowly than it could consume them.
//
// Env-tunable because the right value is a property of the device under load, not of the
// source, and a rebuild per candidate costs a 44 MB push. Clamped: 0 or a negative divisor
// would be a modulo-by-zero, and anything past 8 is slower than the pump itself.
// Disable the child's OWN repaint timer entirely. $JIHAD_PLUGIN_SELF_DRIVE=0.
//
// This exists to isolate ONE producer. Measured 2026-08-10, there are two: our host pull and the
// plugin invalidating itself (~26/s and ~23/s). Turning off only the daemon's pull
// (JIHAD_PLUGIN_PULL=0) does NOT isolate the plugin, because the child's host-drive lease then
// expires and this timer takes over — that run reproduces patch 0026 rather than answering the
// question, and it measured WORSE than the pull on both rate (24-29 vs 30-33 fps) and spread.
// With both switches off the plugin's own NPN_InvalidateRect is the only frame source left, which
// is the experiment that decides whether a host clock should exist here at all.
static bool JihadChildSelfDriveEnabled()
{
static int s_on = -1;
if (s_on < 0) {
const char* e = getenv("JIHAD_PLUGIN_SELF_DRIVE");
s_on = (e && *e && atoi(e) == 0) ? 0 : 1; // default ON; only an explicit 0 disables
fprintf(stderr, "[jihad-npapi-child] self-drive timer %s\n", s_on ? "enabled" : "DISABLED");
fflush(stderr);
}
return s_on != 0;
}
static int JihadRepaintEveryTicks()
{
static int sDiv = 0;
if (!sDiv) {
sDiv = 2;
const char* e = getenv("JIHAD_PLUGIN_REPAINT_DIV");
if (e && *e) {
int v = atoi(e);
if (v >= 1 && v <= 8) sDiv = v;
}
fprintf(stderr, "[jihad-npapi-child] host repaint divisor=%d (~%d Hz)\n",
sDiv, 1000 / (kJihadGlibPumpIntervalMs * sDiv));
fflush(stderr);
}
return sDiv;
}
// ── REPAINT A webOS PLUGIN FROM THE HOST'S CLOCK (Jihad, addons R7) ──────────────────────
//
// Gecko paints a windowless plugin only when something invalidates it, and for an ordinary
// NPAPI plugin that is the plugin itself calling NPN_InvalidateRect. A webOS plugin is under
// no such obligation, because the host it was written for never made it one: Palm's
// PluginView::paint (libWebKitLuna 0x4e7a3c) issues npPalmDrawEvent every time the PAGE
// paints, and BrowserServer's compositor painted continuously. Flash on that host could sit
// on its frame clock and simply expect to be asked.
//
// So this drives the repaint until the plugin proves it drives itself, then gets out of the
// way — a plugin that calls NPN_InvalidateRect gets Gecko's normal damage-driven painting and
// none of this cost. Measured: with no host clock, Flash produced exactly 3 draw events in
// 30 s and 0 invalidates.
void
PluginInstanceChild::JihadPalmRepaintTick()
{
if (!mLayersRendering || mWindow.width <= 0 || mWindow.height <= 0) {
return;
}
NPRect windowRect = { 0, 0,
uint16_t(mWindow.height), uint16_t(mWindow.width) };
sJihadInHostRepaint = true;
InvalidateRect(&windowRect);
sJihadInHostRepaint = false;
}
// ── HOST-DRIVEN FRAME CLOCK (Jihad, addons R7) ───────────────────────────────────────────
//
// When the daemon is pulling (it calls jihad_plugin_request_frame after each card frame it
// publishes), the timer above must get out of the way, or the plugin has TWO drivers and the
// extra draws are exactly the drift the pull exists to remove.
//
// The handoff is timestamp-based rather than a latch because there is no unregister: the daemon
// can stop asking at any moment — the card is backgrounded (BrowserPageGoanna::freeze returns
// early from maybePaint), the page navigates, the daemon is stopped or crashes — and a latched
// plugin would then never paint again. So host-driven is a LEASE that must be renewed. If no
// request arrives for kJihadHostDriveLeaseMs the timer resumes on its own.
//
// THE LEASE MUST EXCEED THE DAEMON'S WORST-CASE GAP BETWEEN REQUESTS, and the first version of
// this got that wrong in a way that is worth keeping written down, because the symptom looked
// like a mysterious third party rather than like a bug.
//
// The daemon does not ask again while a request is outstanding; it waits out
// kJihadPluginReqTimeoutMs (250 ms) before re-asking. The lease here was 150 ms — SHORTER — so a
// single late frame guaranteed the lease expired, the child resumed self-driving, and the two
// clocks this patch exists to collapse were both running again. Measured on device before the
// fix: the child logged HOST -> SELF -> HOST, and the invalidate counter split almost exactly in
// half, 1856 requests from the host against 1846 from the child's own timer, summing to the 3702
// total. The 23% of "unexplained" draws that sent an earlier session hunting through
// RecvUpdateBackground were this, and the background paths were measured at exactly ZERO.
//
// So the invariant, not a tuned number: lease > request timeout + one grid period + margin.
// 500 ms is 250 + 33 + slack. A card that really stopped publishing still resumes self-drawing
// in half a second, which is well inside what a resume can absorb.
static const uint32_t kJihadHostDriveLeaseMs = 500;
static uint32_t sJihadLastHostRequestMs = 0;
static bool sJihadEverHostDriven = false;
static bool JihadHostIsDrivingFrames()
{
bool driving = false;
if (sJihadEverHostDriven) {
uint32_t nowMs = uint32_t(PR_IntervalToMilliseconds(PR_IntervalNow()));
// Unsigned subtraction, so the 32-bit PR_IntervalNow wrap is handled without a signed
// compare that would read as "lease expired" for one interval every wrap.
driving = (nowMs - sJihadLastHostRequestMs) < kJihadHostDriveLeaseMs;
}
// LOG EVERY TRANSITION. A watchdog that silently resumes self-driving would make a BROKEN
// pull look like "no change" in the frame numbers instead of "the feature is off" — the same
// trap family as an empty log passing every grep, and a wedged plugin reading as a pacing
// regression. Both of those cost real time in this tree already; this one is cheap to close.
static bool sWas = false;
if (driving != sWas) {
sWas = driving;
fprintf(stderr, "[jihad-npapi-child] frame clock -> %s\n",
driving ? "HOST (daemon pull)" : "SELF (timer; host lease expired)");
fflush(stderr);
}
return driving;
}
bool
PluginInstanceChild::RecvJihadRequestFrame()
{
sJihadEverHostDriven = true;
sJihadLastHostRequestMs = uint32_t(PR_IntervalToMilliseconds(PR_IntervalNow()));
// A plugin that drives itself gets Gecko's normal damage-driven painting, exactly as the
// timer path decides below; asking such a plugin for frames would double its draw rate.
if (gJihadNPNInvalidateRectCalls != 0) {
return true;
}
static uint64_t sHostFrames = 0;
static uint32_t sReportMs = 0;
if (!(++sHostFrames % 64)) {
uint32_t nowMs = uint32_t(PR_IntervalToMilliseconds(PR_IntervalNow()));
if (sReportMs) {
fprintf(stderr, "[jihad-npapi-child] host-driven: 64 requests in %ums\n",
nowMs - sReportMs);
fflush(stderr);
}
sReportMs = nowMs;
}
JihadPalmRepaintTick();
return true;
}
namespace {
class JihadGlibPumpTask final : public Runnable
{
public:
NS_IMETHOD Run() override
{
int n = JihadPumpGlib(kJihadGlibPumpMaxIters);
// The pump itself keeps running at 16 ms whatever drives the frames — Flash's LS2
// socket, its timers and its audio sources all live on this GMainLoop, and starving
// them is what deadlocked startup before patch 0026. Only the REPAINT defers.
static uint64_t sRepaintTicks = 0;
if (sJihadPalmInstance && gJihadNPNInvalidateRectCalls == 0 &&
JihadChildSelfDriveEnabled() && !JihadHostIsDrivingFrames() &&
(++sRepaintTicks % JihadRepaintEveryTicks()) == 0) {
sJihadPalmInstance->JihadPalmRepaintTick();
}
// One-shot liveness, because "the plugin is idle" and "the pump died" look
// identical on screen. Report the first tick that actually ran a source.
static bool sSawFirstSource = false;
static uint64_t sTicks = 0;
sTicks++;
if (n && !sSawFirstSource) {
sSawFirstSource = true;
fprintf(stderr, "[jihad-npapi-child] glib pump: first source ran on tick %llu\n",
(unsigned long long)sTicks);
fflush(stderr);
}
MessageLoop::current()->PostDelayedTask(
RefPtr<Runnable>(new JihadGlibPumpTask()).forget(),
kJihadGlibPumpIntervalMs);
return NS_OK;
}
};
} // namespace
// Idempotent: several plugin instances share one GMainLoop, so they share one pump.
static void
JihadStartGlibPump(PluginInstanceChild* aInstance)
{
sJihadPalmInstance = aInstance;
static bool sStarted = false;
if (sStarted) {
return;
}
MessageLoop* loop = MessageLoop::current();
if (!loop) {
fprintf(stderr, "[jihad-npapi-child] glib pump: no MessageLoop, not starting\n");
fflush(stderr);
return;
}
sStarted = true;
fprintf(stderr, "[jihad-npapi-child] glib pump: starting, every %dms\n",
kJihadGlibPumpIntervalMs);
fflush(stderr);
loop->PostDelayedTask(RefPtr<Runnable>(new JihadGlibPumpTask()).forget(),
kJihadGlibPumpIntervalMs);
}
// ── PIRANHA CONTEXT FOR A WEBOS PLUGIN (Jihad, addons R7) ────────────────────────────────
//
// webOS plugins that answer npPalmUseGraphicsContext=true expect NpPalmDrawEvent to carry a
// Piranha PGContext* rather than a raster pointer. Piranha ships on the device inside
// libWebKitLuna.so (PGContext/PGSurface) and libPiranha.so; neither is linked into this
// process, so everything is resolved by dlsym on the mangled names — no webOS headers, and
// nothing breaks on a desktop build where the libraries simply are not there.
//
// Feasibility was established separately before any of this was written; see
// render/goanna/test/piranha_offscreen_probe.c, which does exactly this sequence in a bare
// process and confirms the pixels land in caller-owned memory.
//
// The context is cached per (buffer,size) because a plugin repaints constantly and both
// objects would otherwise leak once per frame.
static void*
JihadPiranhaContextFor(unsigned char* aData, int aWidth, int aHeight, int aStride)
{
// PGSurface::wrap() has no stride parameter, so it can only describe tightly packed
// rows. Refuse rather than hand Piranha a buffer it would misread into a sheared image.
if (!aData || aWidth <= 0 || aHeight <= 0 || aStride != aWidth * 4) {
static bool sWarnedStride = false;
if (!sWarnedStride) {
sWarnedStride = true;
fprintf(stderr, "[jihad-npapi-child] piranha: stride %d != %d*4, not wrapping\n",
aStride, aWidth);
fflush(stderr);
}
return nullptr;
}
typedef void* (*PGSurfaceWrapFn)(unsigned, unsigned, const unsigned char*, bool);
typedef void* (*PGContextCreateFn)(void);
typedef void (*PGContextSetSurfaceFn)(void*, void*);
static bool sTried = false;
static PGSurfaceWrapFn sWrap = nullptr;
static PGContextCreateFn sCreate = nullptr;
static PGContextSetSurfaceFn sSetSurface = nullptr;
if (!sTried) {
sTried = true;
// g_thread_init() MUST run before libWebKitLuna loads or its constructors abort with
// "GLib-ERROR **: The thread system is not yet initialized". It lives in
// libgthread-2.0.so.0, NOT libglib-2.0.so.0. Measured, not guessed.
if (void* gthread = dlopen("libgthread-2.0.so.0", RTLD_NOW | RTLD_GLOBAL)) {
typedef void (*GThreadInitFn)(void*);
if (GThreadInitFn init = (GThreadInitFn)dlsym(gthread, "g_thread_init")) {
typedef int (*GThreadGetInitFn)(void);
GThreadGetInitFn got =
(GThreadGetInitFn)dlsym(gthread, "g_thread_get_initialized");
if (!got || !got()) {
init(nullptr);
}
}
}
void* wk = dlopen("libWebKitLuna.so", RTLD_NOW | RTLD_GLOBAL);
if (!wk) {
fprintf(stderr, "[jihad-npapi-child] piranha: no libWebKitLuna (%s)\n", dlerror());
fflush(stderr);
} else {
sWrap = (PGSurfaceWrapFn)dlsym(wk, "_ZN9PGSurface4wrapEjjPKhb");
sCreate = (PGContextCreateFn)dlsym(wk, "_ZN9PGContext6createEv");
sSetSurface = (PGContextSetSurfaceFn)dlsym(wk, "_ZN9PGContext10setSurfaceEP9PGSurface");
fprintf(stderr, "[jihad-npapi-child] piranha syms wrap=%p create=%p setSurface=%p\n",
(void*)sWrap, (void*)sCreate, (void*)sSetSurface);
fflush(stderr);
}
}
if (!sWrap || !sCreate || !sSetSurface) {
return nullptr;
}
// A SET of cached contexts, not one. Palm got away with a single context because its
// buffer was one process-global screen-sized allocation that never moved; here the child
// rotates between a front and a back gfxSharedImageSurface, so a one-entry cache keyed on
// the buffer address misses on EVERY frame. That was invisible while the plugin was only
// painted twice, and turned into a PGSurface + PGContext leaked per frame the moment the
// host started driving repaints at 15Hz.
//
// Four entries: two buffers is the observed case, and a small fixed array keeps this
// allocation-free and bounded even if the surface pool grows. On overflow the oldest entry
// is dropped — leaking that one context rather than freeing an object the plugin may still
// be holding, which is the safer of the two mistakes and is bounded by the buffer count.
struct CacheEntry { unsigned char* data; int w, h; void* ctx; };
static CacheEntry sCache[4] = {};
static unsigned sCacheNext = 0;
for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sCache); ++i) {
if (sCache[i].ctx && sCache[i].data == aData &&
sCache[i].w == aWidth && sCache[i].h == aHeight) {
return sCache[i].ctx;
}
}
void* surf = sWrap((unsigned)aWidth, (unsigned)aHeight, aData, true);
void* ctx = surf ? sCreate() : nullptr;
if (ctx) {
sSetSurface(ctx, surf);
}
// Rate-limited: this is now a cache MISS log, and a miss storm is exactly the symptom
// worth seeing — but only the first few, or it floods the daemon log at frame rate.
static int sLoggedCtx = 0;
if (sLoggedCtx < 8) {
sLoggedCtx++;
fprintf(stderr, "[jihad-npapi-child] piranha ctx %dx%d buf=%p surface=%p context=%p\n",
aWidth, aHeight, aData, surf, ctx);
fflush(stderr);
}
CacheEntry& slot = sCache[sCacheNext % MOZ_ARRAY_LENGTH(sCache)];
sCacheNext++;
slot.data = aData; slot.w = aWidth; slot.h = aHeight; slot.ctx = ctx;
return ctx;
}
void
PluginInstanceChild::PaintRectToPlatformSurface(const nsIntRect& aRect,
gfxASurface* aSurface)
@@ -3799,7 +4458,187 @@ PluginInstanceChild::PaintRectToPlatformSurface(const nsIntRect& aRect,
::IntersectClipRect((HDC) mWindow.window, rect.left, rect.top, rect.right, rect.bottom);
mPluginIface->event(&mData, reinterpret_cast<void*>(&paintEvent));
#else
NS_RUNTIMEABORT("Surface type not implemented.");
// No platform surface to paint onto.
//
// This is the CLASSIC windowless paint path, and on Unix it is X11 and nothing else: the
// browser hands the plugin a Drawable and sends it an XGraphicsExposeEvent. A build with
// no X (a headless toolkit) has nothing it can hand over, and NPAPI defines no
// alternative for Unix — a plugin that wants to draw without X has to opt into a bitmap
// drawing model (NPDrawingModelAsyncBitmapSurface), which is a different path entirely
// and is fully supported here.
//
// Aborting is wrong for an embedder: the plugin process dies, the parent respawns it,
// and the whole cycle repeats for every paint, so one plugin that cannot draw becomes an
// endless crash loop. Warn once and leave the surface untouched instead — the plugin
// stays loaded and scriptable and simply shows nothing, which is a bounded failure the
// embedder can report.
// fprintf, not NS_WARNING: NS_WARNING compiles to nothing in a release build, and this is
// the ONLY signal distinguishing "the plugin drew nothing" from "the plugin was never
// asked to draw" — a distinction that is invisible on screen (both are a blank box).
// WEBOS RASTER DRAW EVENT (Jihad, addons R7).
//
// webOS plugins do not use the X11 protocol at all — they are painted by an
// npPalmDrawEvent, and NpPalmDrawEvent carries BOTH a raster destination (dstBuffer +
// dstRowBytes, "only valid in API version 1.0") and a Piranha PGContext
// ("must be used to draw in API version 2.0"). See Palm's own npapi.h, XP_WEBOS block.
//
// The device's Flash answers npPalmUseGraphicsContext = true, which per that header means
// the HOST may then pass a null raster — it is a statement about host behaviour, NOT a
// promise that the plugin refuses a non-null dstBuffer. There is no API-version
// negotiation anywhere in the contract, so the only way to find out whether a plugin
// honours the raster path is to hand it one and look. That is what this does.
//
// The surface here is already an ordinary shared-memory image (gfxSharedImageSurface,
// created a few hundred lines up), living in this process, whose pixels the parent
// already composites — so the raster the plugin needs costs nothing to produce.
if (aSurface->GetType() == gfxSurfaceType::Image) {
gfxImageSurface* img = static_cast<gfxImageSurface*>(aSurface);
uint8_t* data = img->Data();
int32_t stride = img->Stride();
if (data && stride > 0) {
// NPEvent is Palm's own event union on this platform (npapi.h); the offsets it
// depends on are asserted at the top of this file against libWebKitLuna.
// THE DRAW ALWAYS COVERS THE WHOLE SURFACE, whatever sub-rect was requested.
//
// Two things forced this. The PGContext below is built for the FULL surface
// (PGSurface::wrap takes width/height and assumes tightly packed rows), so pairing
// it with a dstBuffer offset into the middle of that surface makes the plugin's
// blit start partway in and run off the end — measured as `FAULT sig=7` (SIGBUS)
// in the plugin child the moment the host began sending partial invalidations.
// And Palm's own host never sent a partial rect either: PluginView::paint passes
// the plugin's whole frame rect, which is why a 2.0 plugin is entitled to assume
// the two agree. Redrawing the whole plugin box costs the plugin nothing it was
// not already doing every frame.
nsIntRect drawRect(0, 0, img->Width(), img->Height());
NPEvent ev;
memset(&ev, 0, sizeof(ev));
ev.eventType = npPalmDrawEvent;
// "points to top-left of area to paint"
ev.data.drawEvent.dstBuffer = data;
ev.data.drawEvent.dstRowBytes = (uint32_t)stride;
ev.data.drawEvent.srcLeft = drawRect.x;
ev.data.drawEvent.srcTop = drawRect.y;
ev.data.drawEvent.srcRight = drawRect.XMost();
ev.data.drawEvent.srcBottom = drawRect.YMost();
ev.data.drawEvent.dstLeft = ev.data.drawEvent.srcLeft;
ev.data.drawEvent.dstTop = ev.data.drawEvent.srcTop;
ev.data.drawEvent.dstRight = ev.data.drawEvent.srcRight;
ev.data.drawEvent.dstBottom = ev.data.drawEvent.srcBottom;
// API 2.0: a real Piranha PGContext bound to the very same pixels.
//
// The device's Flash answers npPalmUseGraphicsContext = true, and although it
// accepts a raster draw event (returns handled=1) it writes nothing into the
// buffer — so "handled" evidently means "consumed", not "drew". This gives it
// what it actually asked for. Proven possible by
// render/goanna/test/piranha_offscreen_probe.c: a PGContext can be created over
// wrapped memory in an ordinary process with no display and no compositor.
//
// PGSurface::wrap() takes no stride, so it assumes tightly-packed w*4 rows. That
// holds here (a 320-wide surface has stride 1280) but is asserted rather than
// assumed, because a padded stride would silently shear the image.
ev.data.drawEvent.graphicsContext = JihadPiranhaContextFor(data, img->Width(),
img->Height(), stride);
// BOTH fields stay populated, including for a plugin that answered
// npPalmUseGraphicsContext = true.
//
// npapi.h says the raster pointer "is then passed in as null" for such plugins, and
// this code used to believe it. The host that actually shipped does not: PluginView
// ::paint (libWebKitLuna 0x4e7c70 / 0x4e7c5c) stores a live dstBuffer and a live
// dstRowBytes into the event on the SAME branch that stores the PGContext — the
// graphics-context case is precisely the one where it computes
// dstBuffer = <shared buffer> + (y*screenWidth + x)*4 and
// dstRowBytes = screenWidth*4 (0x4e7e04-0x4e7e18). The header comment describes
// what a 2.0 plugin is expected to USE, not what the host is allowed to omit, and
// handing Flash a null raster is a difference from the reference host that costs
// nothing to remove.
// Let the plugin's own scheduled work run before we ask it to draw, so the
// frame it paints is current rather than whatever it had at instantiation.
JihadPumpGlib(50);
int16_t handled = mPluginIface->event
? mPluginIface->event(&mData, reinterpret_cast<void*>(&ev)) : -1;
gJihadPalmDrawEvents++;
static int sLogged = 0;
// FRAME-RATE READOUT. A static SWF and a 30fps game are indistinguishable from
// a per-event log (capped) or a screenshot (one instant), and the difference is
// the whole question for animated content. One line every 2s costs nothing and
// is the only way to see the plugin's real cadence in the field.
{
static uint32_t sDraws = 0;
static uint32_t sLastReport = 0;
sDraws++;
uint32_t nowMs = uint32_t(PR_IntervalToMilliseconds(PR_IntervalNow()));
if (!sLastReport) {
sLastReport = nowMs;
} else if (nowMs - sLastReport >= 2000) {
fprintf(stderr, "[jihad-npapi-child] palm draw: %u in %ums (%.1f fps)\n",
sDraws, nowMs - sLastReport,
sDraws * 1000.0 / double(nowMs - sLastReport));
// WHICH SITE ASKED FOR THOSE DRAWS. These are requests to draw, not draws:
// AsyncShowPluginFrame coalesces while an invalidate task is already pending,
// so the sum is an UPPER bound on sDraws and the interesting number is the
// SHARE each site holds, not the total. Printed on the same 2 s boundary so a
// reader can line them up without correlating timestamps.
{
char buf[192];
size_t n = 0;
buf[0] = '\0';
for (int i = 0; i < kJihadShowSites; ++i) {
// Clamp rather than trust the running total: snprintf returns the
// length it WANTED, so an overflow would make the next call pass a
// negative size as size_t and write off the end.
if (n < sizeof(buf) - 1) {
int w = snprintf(buf + n, sizeof(buf) - n, " %s=%u",
kJihadShowNames[i], gJihadShowFrom[i]);
if (w > 0) {
n += size_t(w);
if (n >= sizeof(buf)) n = sizeof(buf) - 1;
}
}
gJihadShowFrom[i] = 0;
}
fprintf(stderr, "[jihad-npapi-child] show req:%s\n", buf);
}
fflush(stderr);
sDraws = 0;
sLastReport = nowMs;
}
}
if (sLogged < 3) {
sLogged++;
// handled= is reported but means nothing on its own: Flash's NPP_HandleEvent
// sets its return to 1 (libflashplayer.so 0x45274) BEFORE calling the draw
// handler and returns it unconditionally, so handled=1 is emitted even when
// the handler bails without touching the surface. Only pixels are evidence.
fprintf(stderr, "[jihad-npapi-child] npPalmDrawEvent %s %d,%d %dx%d "
"stride=%d ctx=%p handled=%d\n",
ev.data.drawEvent.graphicsContext ? "pgcontext" : "raster",
drawRect.x, drawRect.y, drawRect.width, drawRect.height,
(int)stride, ev.data.drawEvent.graphicsContext, (int)handled);
fflush(stderr);
}
return;
}
}
// Nothing we can paint onto at all.
//
// Aborting is wrong for an embedder: the plugin process dies, the parent respawns it,
// and the whole cycle repeats for every paint, so one plugin that cannot draw becomes an
// endless crash loop. Warn once and leave the surface untouched instead.
// fprintf, not NS_WARNING: NS_WARNING compiles to nothing in a release build, and this is
// the ONLY signal distinguishing "the plugin drew nothing" from "the plugin was never
// asked to draw" — a distinction that is invisible on screen (both are a blank box).
static bool sWarned = false;
if (!sWarned) {
sWarned = true;
fprintf(stderr, "[jihad-npapi-child] no paintable surface for this windowless "
"plugin (type=%d); it will NOT paint.\n", (int)aSurface->GetType());
fflush(stderr);
}
#endif
}
@@ -4264,6 +5103,7 @@ PluginInstanceChild::InvalidateRectDelayed(void)
}
if (!ShowPluginFrame()) {
gJihadShowFrom[kJihadShowRetry]++;
AsyncShowPluginFrame();
}
}
@@ -4317,6 +5157,8 @@ PluginInstanceChild::InvalidateRect(NPRect* aInvalidRect)
mAccumulatedInvalidRect.UnionRect(r, mAccumulatedInvalidRect);
// If we are able to paint and invalidate sent, then reset
// accumulated rectangle
gJihadShowFrom[sJihadInHostRepaint ? kJihadShowInvalidate
: kJihadShowPluginSelf]++;
AsyncShowPluginFrame();
return;
}
@@ -4360,6 +5202,7 @@ PluginInstanceChild::RecvUpdateBackground(const SurfaceDescriptor& aBackground,
IntSize bgSize = mBackground->GetSize();
mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect,
nsIntRect(0, 0, bgSize.width, bgSize.height));
gJihadShowFrom[kJihadShowBgUpdate]++;
AsyncShowPluginFrame();
return true;
}
@@ -4369,6 +5212,7 @@ PluginInstanceChild::RecvUpdateBackground(const SurfaceDescriptor& aBackground,
// This must be asynchronous, because we may be nested within RPC messages
// which do not expect to receiving paint events.
gJihadShowFrom[kJihadShowBgUpdateTail]++;
AsyncShowPluginFrame();
return true;
@@ -4401,6 +5245,7 @@ PluginInstanceChild::RecvPPluginBackgroundDestroyerConstructor(
// NB: we don't have to XSync here because only ShowPluginFrame()
// uses mBackground, and it always XSyncs after finishing.
mBackground = nullptr;
gJihadShowFrom[kJihadShowBgDestroy]++;
AsyncShowPluginFrame();
}
+20
View File
@@ -141,6 +141,10 @@ protected:
virtual bool
RecvContentsScaleFactorChanged(const double& aContentsScaleFactor) override;
// Jihad: the host is driving the frame clock — draw one now. See PPluginInstance.ipdl.
virtual bool
RecvJihadRequestFrame() override;
virtual bool
AnswerNPP_Destroy(NPError* result) override;
@@ -641,6 +645,22 @@ private:
// and p->getvalue return always false
bool mIsTransparent;
// Jihad R7 (webOS): npPalmGainFocusEvent is a once-per-instance startup signal, but the
// setwindow that carries it runs again on every resize and scroll.
bool mJihadSentPalmGainFocus;
// Jihad R7 (webOS): cap on the input-delivery breadcrumb in AnswerNPP_HandleEvent. A
// pen-move stream is unbounded; the daemon log is the only field-debug channel there is.
uint32_t mJihadInputEventsLogged;
public:
// Jihad R7 (webOS): repaint this instance from the host's own clock. See
// JihadGlibPumpTask::Run — a webOS plugin is not obliged to ask for repaints, because the
// host it was written for painted it as part of every page paint.
void JihadPalmRepaintTick();
private:
// Surface type optimized of parent process
gfxSurfaceType mSurfaceType;
+224 -7
View File
@@ -115,6 +115,16 @@ PluginInstanceParent::LookupPluginInstanceByID(uintptr_t aId)
}
#endif
// Jihad: every live instance, so a C entry point can reach one. jihad_plugin_frame_seq needs no
// instance because it only counts; a frame REQUEST has to be sent on an actual actor.
//
// A plain file-static array maintained in the ctor/dtor below, not a hashtable: this is at most a
// couple of entries on a single-card embedding, it is only ever touched on the main thread (the
// daemon calls the export from inside its own tick, on that same thread), and the alternative —
// walking nsPluginHost's nsNPAPIPluginInstance list the way jihad_plugin_palm_spotlight does —
// would still have to get from there to the PluginInstanceParent actor to call Send on it.
static nsTArray<PluginInstanceParent*>* gJihadLiveInstances = nullptr;
PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
NPP npp,
const nsCString& aMimeType,
@@ -145,10 +155,24 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
sPluginInstanceList = new nsClassHashtable<nsVoidPtrHashKey, PluginInstanceParent>();
}
#endif
// Jihad: join the live list that jihad_plugin_request_frame walks. Leaked on purpose — it
// outlives every instance and there is no shutdown hook here that is guaranteed to run
// after the last dtor.
if (!gJihadLiveInstances) {
gJihadLiveInstances = new nsTArray<PluginInstanceParent*>();
}
gJihadLiveInstances->AppendElement(this);
}
PluginInstanceParent::~PluginInstanceParent()
{
// Jihad: leave the live list FIRST. Anything below can run script or spin the loop, and a
// frame request delivered to a half-destroyed actor is a use-after-free rather than a
// dropped frame.
if (gJihadLiveInstances) {
gJihadLiveInstances->RemoveElement(this);
}
if (mNPP)
mNPP->pdata = nullptr;
@@ -269,6 +293,8 @@ PluginInstanceParent::AnswerNPN_GetValue_NPNVnetscapeWindow(NativeWindowHandle*
XID id;
#elif defined(XP_DARWIN)
intptr_t id;
#elif defined(MOZ_WIDGET_HEADLESS)
intptr_t id; // Jihad headless: no native window id
#else
#warning Implement me
#endif
@@ -769,6 +795,51 @@ PluginInstanceParent::RecvShowDirectBitmap(Shmem&& buffer,
return false;
}
// NO COMPOSITOR PROCESS: composite the plugin's bitmap directly.
//
// Everything below this point routes the plugin's pixels through a TextureClient to a
// compositor, and that requires ImageBridgeChild — which only exists with off-main-thread
// composition. This embedder deliberately runs OMTC off (the offscreen renderer uses the
// in-process BasicLayerManager and hands finished frames to the browser adapter itself),
// so ImageBridgeChild::GetSingleton() is null and TextureClientRecycleAllocator is built
// around a null KnowsCompositor. The first plugin paint then dereferenced it and took the
// whole daemon down with it — upstream never sees this because the DXGI path a few
// hundred lines up checks the forwarder and the direct-bitmap path does not.
//
// A BasicLayerManager does not need a TextureClient at all: it draws an ImageLayer from
// the image's own SourceSurface. So wrap the pixels in a plain SourceSurfaceImage and
// hand that to the container.
//
// The pixels are COPIED, not wrapped. `source` above wraps the shmem the plugin drew
// into, and the plugin owns that buffer and may draw the next frame into it as soon as
// this call returns; the texture path's UpdateFromSurface copies for the same reason.
if (!ImageBridgeChild::GetSingleton()) {
RefPtr<gfx::DataSourceSurface> copy =
gfx::Factory::CreateDataSourceSurface(size, format);
if (!copy) {
NS_WARNING("Could not allocate a surface for plugin bitmap!");
return false;
}
{
gfx::DataSourceSurface::ScopedMap srcMap(source, gfx::DataSourceSurface::READ);
gfx::DataSourceSurface::ScopedMap dstMap(copy, gfx::DataSourceSurface::WRITE);
if (!srcMap.IsMapped() || !dstMap.IsMapped()) {
return false;
}
const int32_t bpp = BytesPerPixel(format);
const int32_t rowBytes = size.width * bpp;
for (int32_t y = 0; y < size.height; y++) {
memcpy(dstMap.GetData() + (ptrdiff_t)y * dstMap.GetStride(),
srcMap.GetData() + (ptrdiff_t)y * srcMap.GetStride(),
rowBytes);
}
}
RefPtr<SourceSurfaceImage> image = new SourceSurfaceImage(size, copy);
SetCurrentImage(image);
return true;
}
// Allocate a texture for the compositor.
RefPtr<TextureClientRecycleAllocator> allocator = mParent->EnsureTextureAllocatorForDirectBitmap();
RefPtr<TextureClient> texture = allocator->CreateOrRecycle(
@@ -864,6 +935,55 @@ PluginInstanceParent::RecvShowDirectDXGISurface(const WindowsHandle& handle,
}
#endif // MOZ_ENABLE_NPAPI
// Jihad: monotonic count of plugin frames that have reached the parent. Process-wide rather
// than per-instance, matching how the daemon consumes it — the embedding is single-page and the
// question it answers is "has ANY plugin produced a new frame since I last published". A plain
// uint32_t incremented and read on the same (main) thread; the daemon reads it from the same
// thread inside its tick, so no atomics are needed and none are used elsewhere in this bridge.
static uint32_t gJihadPluginFrameSeq = 0;
extern "C" {
// Weak-linked from the daemon (render/goanna/GoannaRenderPage.cpp), the same way
// jihad_offscreen_take_dirty is: an older libxul simply does not export it, and the daemon then
// falls back to its dirty-flag behaviour instead of failing to load.
MOZ_EXPORT uint32_t jihad_plugin_frame_seq(void)
{
return gJihadPluginFrameSeq;
}
}
extern "C" {
// Ask every live plugin for one frame. Returns how many were asked, so the daemon can tell "no
// plugin" from "delivered" — the same contract as jihad_plugin_palm_spotlight.
//
// WEAK on the daemon side: a libxul without this symbol keeps the child's own timer as the frame
// clock (patch 0026 behaviour), which is slower to settle but never wrong.
MOZ_EXPORT int jihad_plugin_request_frame(void)
{
#ifdef MOZ_ENABLE_NPAPI
if (!gJihadLiveInstances) {
return 0;
}
// Copy first: SendJihadRequestFrame can fail and tear the actor down, which would mutate the
// array underneath the loop. Same reasoning as the instance-list copy in
// jihad_plugin_palm_spotlight (nsPluginHost.cpp).
nsTArray<PluginInstanceParent*> snap(*gJihadLiveInstances);
int asked = 0;
for (uint32_t i = 0; i < snap.Length(); ++i) {
if (!gJihadLiveInstances->Contains(snap[i])) {
continue; // torn down by an earlier Send in this same loop
}
if (snap[i]->SendJihadRequestFrame()) {
asked++;
}
}
return asked;
#else
return 0;
#endif
}
}
bool
PluginInstanceParent::RecvShow(const NPRect& updatedRect,
const SurfaceDescriptor& newSurface,
@@ -877,6 +997,27 @@ PluginInstanceParent::RecvShow(const NPRect& updatedRect,
MOZ_ASSERT(!IsUsingDirectDrawing());
// FRAME-RATE READOUT, parent side. Paired with the child's `palm draw:` line: the child
// reports how often the plugin was ASKED to draw, this reports how many of those frames
// actually crossed the process boundary. A gap between the two numbers is the difference
// between "the plugin is slow" and "we are dropping its frames", which are opposite bugs.
{
static uint32_t sShows = 0;
static uint32_t sLastReport = 0;
sShows++;
uint32_t nowMs = uint32_t(PR_IntervalToMilliseconds(PR_IntervalNow()));
if (!sLastReport) {
sLastReport = nowMs;
} else if (nowMs - sLastReport >= 2000) {
fprintf(stderr, "[jihad-npapi] RecvShow: %u in %ums (%.1f fps)\n",
sShows, nowMs - sLastReport,
sShows * 1000.0 / double(nowMs - sLastReport));
fflush(stderr);
sShows = 0;
sLastReport = nowMs;
}
}
// XXXjwatt rewrite to use Moz2D
RefPtr<gfxASurface> surface;
if (newSurface.type() == SurfaceDescriptor::TShmem) {
@@ -959,14 +1100,75 @@ PluginInstanceParent::RecvShow(const NPRect& updatedRect,
updatedRect.bottom - updatedRect.top);
surface->MarkDirty(ur);
bool isPlugin = true;
RefPtr<gfx::SourceSurface> sourceSurface =
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr, surface, isPlugin);
RefPtr<SourceSurfaceImage> image = new SourceSurfaceImage(surface->GetSize(), sourceSurface);
// JIHAD (2026-08-09): route the legacy windowless show through the SAME
// representation the direct-bitmap path uses, for the SAME reasons.
//
// Background: the webOS npPalmDrawEvent path (PaintRectToPlatformSurface) makes Flash
// blit its stage into mCurrentSurface — measured full-magenta in the child — and ships
// it here via SendShow. The control plugin's pixels reach the screen through
// RecvShowDirectBitmap; Flash's did not, although both feed the one mImageContainer the
// BasicLayerManager reads. Two concrete differences made the legacy path invisible:
// 1. It WRAPPED the shmem (GetSourceSurfaceForSurface(nullptr,…)) instead of copying.
// The child double-buffers and SwapSurfaces() immediately after SendShow returns,
// so a wrapped front buffer is the very buffer the child repaints next — the image
// the layer later samples is racing the child. RecvShowDirectBitmap copies for
// exactly this reason ("the plugin owns that buffer and may draw the next frame
// into it as soon as this call returns").
// 2. It stamped no frameID. SetCurrentImage() on the working path assigns a monotonic
// ++mFrameID; the ImageContainer/ImageLayer treats a repeated frameID as "no new
// frame". A fixed 0 can be coalesced away.
// Copying into a fresh DataSourceSurface and stamping a monotonic frameID makes this
// path identical in substance to the one already proven to composite here.
IntSize ssize = surface->GetSize();
RefPtr<Image> image;
RefPtr<gfxImageSurface> imgSurf = surface->GetAsImageSurface();
if (imgSurf) {
// Always present the copy as B8G8R8A8, and force the alpha channel opaque when the
// source carries no alpha (RGB24 / B8G8R8X8). This is Bug 1196927 in this file's own
// words (see PluginInstanceChild::PaintRectToSurface): Cairo/Skia leave the X byte of
// a BGRX surface zeroed, and a BasicImageLayer then composites those pixels multiplied
// by alpha 0 — i.e. fully transparent. That is exactly why Flash's magenta stage
// arrived here (RecvShow logged px0=0xffff00ff) yet BasicImageLayer::Paint drew
// nothing visible, while the control plugin — which ships B8G8R8A8 — composited fine
// through the identical layer path. webOS windowless plugins are opaque
// (wmode=opaque forces the windowless instance in the first place), so forcing alpha
// opaque is correct here.
const SurfaceFormat srcFmt = surface->GetSurfaceFormat();
const bool srcHasAlpha =
srcFmt != SurfaceFormat::B8G8R8X8 &&
srcFmt != SurfaceFormat::R8G8B8X8;
RefPtr<gfx::DataSourceSurface> copy =
gfx::Factory::CreateDataSourceSurface(ssize, SurfaceFormat::B8G8R8A8);
if (copy) {
gfx::DataSourceSurface::ScopedMap dstMap(copy, gfx::DataSourceSurface::WRITE);
if (dstMap.IsMapped()) {
const int32_t rowBytes = ssize.width * 4;
for (int32_t y = 0; y < ssize.height; y++) {
uint8_t* dstRow = dstMap.GetData() + (ptrdiff_t)y * dstMap.GetStride();
memcpy(dstRow, imgSurf->Data() + (ptrdiff_t)y * imgSurf->Stride(),
rowBytes);
if (!srcHasAlpha) {
for (int32_t x = 0; x < ssize.width; x++) {
dstRow[x * 4 + 3] = 0xff; // BGRA: byte 3 is alpha
}
}
}
image = new SourceSurfaceImage(ssize, copy);
}
}
}
if (!image) {
// Fallback to the original wrap if the copy path could not be taken.
bool isPlugin = true;
RefPtr<gfx::SourceSurface> sourceSurface =
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr, surface, isPlugin);
image = new SourceSurfaceImage(ssize, sourceSurface);
}
ImageContainer::NonOwningImage holder(image);
holder.mFrameID = ++mFrameID;
AutoTArray<ImageContainer::NonOwningImage,1> imageList;
imageList.AppendElement(
ImageContainer::NonOwningImage(image));
imageList.AppendElement(holder);
ImageContainer *container = GetImageContainer();
container->SetCurrentImages(imageList);
@@ -976,6 +1178,17 @@ PluginInstanceParent::RecvShow(const NPRect& updatedRect,
}
mFrontSurface = surface;
// Jihad: count DELIVERED plugin frames so the embedder can tell a new one from a repeat.
// The daemon's only frame signal is PuppetWidget's sticky dirty boolean, which carries no
// identity: the refresh driver and ordinary page damage set the same flag, so "there is
// damage" cannot answer "did the plugin draw again". Measured 2026-08-10 on a 30 fps SWF,
// that ambiguity is what made both available policies wrong — publishing on every dirty
// tick sent ~78 card frames for ~60 plugin frames (duplicates, and 22-44 deferred because
// the adapter could not drain them), while pacing on a fixed 33 ms grid sent ~57 for ~68
// (dropped frames, so the animation stepped two positions at once). The stock webOS host
// never had to choose: it pulls the plugin synchronously inside the page paint, so it is
// 1:1 by construction. This counter is what lets the daemon be 1:1 too.
++gJihadPluginFrameSeq;
RecvNPN_InvalidateRect(updatedRect);
PLUGIN_LOG_DEBUG((" (RecvShow invalidated for surface %p)",
@@ -1301,7 +1514,11 @@ PluginInstanceParent::GetImageContainer()
return mImageContainer;
}
if (IsUsingDirectDrawing()) {
if (IsUsingDirectDrawing() && ImageBridgeChild::GetSingleton()) {
// ASYNCHRONOUS means "shared with the compositor through ImageBridge". Without an
// ImageBridge the async container silently gets no image client and never publishes
// anything, so with OMTC off this has to be an ordinary local container — which is
// what the BasicLayerManager reads from. See RecvShowDirectBitmap.
mImageContainer = LayerManager::CreateImageContainer(ImageContainer::ASYNCHRONOUS);
} else {
mImageContainer = LayerManager::CreateImageContainer();
+2
View File
@@ -117,6 +117,8 @@ typedef HWND NativeWindowHandle;
typedef XID NativeWindowHandle;
#elif defined(XP_DARWIN)
typedef intptr_t NativeWindowHandle; // never actually used, will always be 0
#elif defined(MOZ_WIDGET_HEADLESS)
typedef intptr_t NativeWindowHandle; // Jihad headless: no native window handle
#else
#error Need NativeWindowHandle for this platform
#endif
+44 -1
View File
@@ -60,6 +60,9 @@ using namespace mozilla::ipc;
using namespace mozilla::plugins;
using namespace mozilla::widget;
// Defined at the bottom of this file; see the NPN SYMBOL INTERPOSITION block there.
namespace mozilla { namespace plugins { void JihadInstallNPNInterposition(); } }
#if defined(XP_WIN)
const wchar_t * kFlashFullscreenClass = L"ShockwaveFlashFullScreen";
const wchar_t * kMozillaWindowClass = L"MozillaWindowClass";
@@ -232,6 +235,10 @@ PluginModuleChild::InitForChrome(const std::string& aPluginFilename,
{
NS_ASSERTION(aChannel, "need a channel");
// Point the exported NPN_* globals at the real implementations before any plugin can be
// loaded, so a plugin that resolves them as symbols reaches us rather than libWebKitLuna.
JihadInstallNPNInterposition();
if (!InitGraphics())
return false;
@@ -251,7 +258,11 @@ PluginModuleChild::InitForChrome(const std::string& aPluginFilename,
nsPluginFile pluginFile(localFile);
nsPluginInfo info = nsPluginInfo();
if (NS_FAILED(pluginFile.GetPluginInfo(info, &mLibrary))) {
nsresult jihadRv = pluginFile.GetPluginInfo(info, &mLibrary);
fprintf(stderr, "[jihad-npapi-child] GetPluginInfo rv=0x%x lib=%d\n",
(unsigned)jihadRv, (int)!!mLibrary);
fflush(stderr);
if (NS_FAILED(jihadRv)) {
return false;
}
@@ -1843,6 +1854,8 @@ bool
PluginModuleChild::AnswerNP_Initialize(const PluginSettings& aSettings, NPError* rv)
{
*rv = DoNP_Initialize(aSettings);
fprintf(stderr, "[jihad-npapi-child] AnswerNP_Initialize rv=%d\n", (int)*rv);
fflush(stderr);
return true;
}
@@ -1882,6 +1895,8 @@ PluginModuleChild::DoNP_Initialize(const PluginSettings& aSettings)
# error Please implement me for your platform
#endif
fprintf(stderr, "[jihad-npapi-child] DoNP_Initialize plugin returned %d\n", (int)result);
fflush(stderr);
return result;
}
@@ -2617,3 +2632,31 @@ PluginModuleChild::RecvNPP_SetValue_NPNVaudioDeviceChangeDetails(
#endif
}
#endif // MOZ_ENABLE_NPAPI
// ── NPN SYMBOL INTERPOSITION (Jihad, addons R7) ──────────────────────────────────────────
//
// The exported NPN_* globals themselves live in JihadNPNInterpose.cpp (they must, to escape
// hidden visibility — see the long comment there). All that is needed here is to point them
// at the same implementations the browser function table uses, which is done once the table
// exists. Installed from a static initializer-free helper called by the child at startup.
extern "C" {
extern void (*gJihadNPNInvalidateRect)(void*, void*);
extern void* (*gJihadNPNCreateObject)(void*, void*);
}
namespace mozilla {
namespace plugins {
void JihadInstallNPNInterposition()
{
const NPNetscapeFuncs& f = PluginModuleChild::sBrowserFuncs;
gJihadNPNInvalidateRect = (void(*)(void*, void*))f.invalidaterect;
gJihadNPNCreateObject = (void*(*)(void*, void*))f.createobject;
fprintf(stderr, "[jihad-npapi-child] NPN interposition installed invalidaterect=%p "
"createobject=%p\n",
(void*)f.invalidaterect, (void*)f.createobject);
fflush(stderr);
}
} // namespace plugins
} // namespace mozilla
+190 -1
View File
@@ -444,6 +444,8 @@ PluginModuleChromeParent::LoadModule(const char* aFilePath, uint32_t aPluginId,
parent->mSubprocess->SetCallRunnableImmediately(!parent->mIsStartingAsync);
bool launched = parent->mSubprocess->Launch(Move(onLaunchedRunnable),
aPluginTag->mSandboxLevel);
fprintf(stderr, "[jihad-npapi] LoadModule path=%s async=%d launched=%d\n",
aFilePath, (int)parent->mIsStartingAsync, (int)launched);
if (!launched) {
// We never reached open
parent->mShutdown = true;
@@ -455,7 +457,10 @@ PluginModuleChromeParent::LoadModule(const char* aFilePath, uint32_t aPluginId,
parent->mIsBlocklisted = NS_FAILED(rv) || blocklistState != 0;
if (!parent->mIsStartingAsync) {
int32_t launchTimeoutSecs = Preferences::GetInt(kLaunchTimeoutPref, 0);
if (!parent->mSubprocess->WaitUntilConnected(launchTimeoutSecs * 1000)) {
bool connected = parent->mSubprocess->WaitUntilConnected(launchTimeoutSecs * 1000);
fprintf(stderr, "[jihad-npapi] LoadModule WaitUntilConnected(%ds) = %d\n",
(int)launchTimeoutSecs, (int)connected);
if (!connected) {
parent->mShutdown = true;
return nullptr;
}
@@ -1134,9 +1139,20 @@ PluginModuleChromeParent::OnHangUIContinue()
}
#endif // XP_WIN
// Defined with the rest of the Jihad CPU-boost helpers further down this file.
namespace { void JihadCpuBoostReleaseAll(); }
void
PluginModuleParent::ActorDestroy(ActorDestroyReason why)
{
// Release the CPU boost here as well as in NPP_Destroy, because on this port NPP_Destroy is
// NOT the path a plugin usually leaves by: navigating away from a Flash page ends in the
// child's own mozalloc_abort, so the instance never gets an orderly destroy and the boost
// would leak — device-observed 2026-08-10, tunables still at 40/50000 after navigation with
// no release logged. This runs for every ActorDestroyReason, normal and abnormal, which also
// covers a plugin crash.
JihadCpuBoostReleaseAll();
switch (why) {
case AbnormalShutdown: {
mShutdown = true;
@@ -1271,6 +1287,172 @@ NP_BEGIN_MACRO \
return i->func; \
NP_END_MACRO
// ── Jihad: hold a CPU-frequency boost while a plugin instance is alive ──────────────────────
//
// WHY. The TouchPad's governor is Palm's `ondemandtcl`, whose stock `up_threshold` is 95 — it
// only raises the clock when a single core exceeds 95% load. Flash never gets there: measured on
// device, the daemon runs ~26% and plugin-container ~11% of two cores, so a passively-watched
// animation sits at the FLOOR. Sampling `scaling_cur_freq` once a second during playback gave
// 192000-384000 out of a 1188000 maximum, snapping back to 1188000 the moment the page was
// navigated away. The whole system was only 69% busy, so this was never a capacity wall.
//
// Dropping `up_threshold` to 40 and `sampling_rate` to 50000 pins 1188000 and lifts the card
// composite from 20.4-27.5 fps to 30.7-35.2, daemon paints 24.0-28.7 to 31.4-33.0, and the frame
// gap MAXIMUM — the number that reads as stutter — from 63-81 ms to 49-56. It also clears the
// audio xruns, because MP3 decode at 192 MHz underruns.
//
// NEVER WRITE `scaling_governor`. Switching away from `ondemandtcl` DEADLOCKS cpufreq in the
// kernel: every later reader of any cpufreq node blocks in unkillable D state — the daemon,
// `powerlog`, and the restore path itself — so the boost is never released and only a reboot
// clears it (and a clean `reboot` will not run, because init waits on those D-state tasks).
// Governor TUNABLE writes, which is all this does, are safe and return instantly.
//
// These are SYSTEM-WIDE tunables, so they are held only while a plugin instance exists and the
// ORIGINAL values are read back and restored on teardown. The upstart job restores them again
// from `post-stop`, because a daemon that dies holding the boost would otherwise leave the whole
// device tuned for battery burn. Both hooks run on the main thread, so the counter needs no lock.
namespace {
const char kJihadOndemandDir[] = "/sys/devices/system/cpu/cpufreq/ondemandtcl";
// The stock values, used ONLY as the restore fallback when the current value already equals what
// we are about to write — which happens when another variant's daemon is holding the boost.
// Saving the boosted value as "original" there would make the last release pin the device.
const char kJihadStockUpThreshold[] = "95";
const char kJihadStockSamplingRate[] = "200000";
// The instances that actually TOOK a boost, not a bare count. NPP_Destroy also runs for instances
// that failed before the boost was taken, and decrementing a count there would release the boost
// out from under a plugin that is still playing.
nsTArray<NPP> gJihadBoostedInstances;
bool gJihadBoostHeld = false;
char gJihadSavedUpThreshold[32];
char gJihadSavedSamplingRate[32];
bool
JihadReadTunable(const char* aName, char* aOut, size_t aOutLen)
{
char path[256];
snprintf(path, sizeof(path), "%s/%s", kJihadOndemandDir, aName);
FILE* f = fopen(path, "r");
if (!f) return false;
char* got = fgets(aOut, aOutLen, f);
fclose(f);
if (!got) return false;
// Trim the trailing newline so a value read back can be compared and rewritten verbatim.
size_t n = strlen(aOut);
while (n > 0 && (aOut[n - 1] == '\n' || aOut[n - 1] == '\r')) aOut[--n] = '\0';
return n > 0;
}
bool
JihadWriteTunable(const char* aName, const char* aValue)
{
char path[256];
snprintf(path, sizeof(path), "%s/%s", kJihadOndemandDir, aName);
FILE* f = fopen(path, "w");
if (!f) return false;
bool ok = fputs(aValue, f) >= 0;
ok = (fclose(f) == 0) && ok;
return ok;
}
// Env-tunable for the same reason the repaint divisor is: the right value is a property of the
// device under load, not of the source, and a rebuild per candidate costs a 44 MB push.
void
JihadCpuBoostTargets(const char** aUpThreshold, const char** aSamplingRate)
{
static char sUp[32] = "40";
static char sRate[32] = "50000";
static bool sInit = false;
if (!sInit) {
sInit = true;
const char* e = getenv("JIHAD_PLUGIN_CPU_UP_THRESHOLD");
if (e && *e) {
int v = atoi(e);
if (v >= 5 && v <= 95) snprintf(sUp, sizeof(sUp), "%d", v);
}
e = getenv("JIHAD_PLUGIN_CPU_SAMPLING_RATE");
if (e && *e) {
int v = atoi(e);
if (v >= 10000 && v <= 1000000) snprintf(sRate, sizeof(sRate), "%d", v);
}
}
*aUpThreshold = sUp;
*aSamplingRate = sRate;
}
bool
JihadCpuBoostEnabled()
{
const char* e = getenv("JIHAD_PLUGIN_CPU_BOOST");
return !(e && e[0] == '0' && e[1] == '\0');
}
void
JihadCpuBoostAcquire(NPP aInstance)
{
if (!JihadCpuBoostEnabled() || gJihadBoostedInstances.Contains(aInstance)) return;
gJihadBoostedInstances.AppendElement(aInstance);
if (gJihadBoostedInstances.Length() != 1 || gJihadBoostHeld) return;
const char* wantUp;
const char* wantRate;
JihadCpuBoostTargets(&wantUp, &wantRate);
if (!JihadReadTunable("up_threshold", gJihadSavedUpThreshold,
sizeof(gJihadSavedUpThreshold)) ||
!strcmp(gJihadSavedUpThreshold, wantUp)) {
strcpy(gJihadSavedUpThreshold, kJihadStockUpThreshold);
}
if (!JihadReadTunable("sampling_rate", gJihadSavedSamplingRate,
sizeof(gJihadSavedSamplingRate)) ||
!strcmp(gJihadSavedSamplingRate, wantRate)) {
strcpy(gJihadSavedSamplingRate, kJihadStockSamplingRate);
}
bool ok = JihadWriteTunable("up_threshold", wantUp);
ok = JihadWriteTunable("sampling_rate", wantRate) && ok;
gJihadBoostHeld = ok;
fprintf(stderr, "[jihad-npapi] cpu boost acquire: up_threshold %s->%s sampling_rate %s->%s%s\n",
gJihadSavedUpThreshold, wantUp, gJihadSavedSamplingRate, wantRate,
ok ? "" : " FAILED (not root, or no ondemandtcl)");
fflush(stderr);
}
void
JihadCpuBoostRelease(NPP aInstance)
{
if (!gJihadBoostedInstances.RemoveElement(aInstance)) return;
if (!gJihadBoostedInstances.IsEmpty() || !gJihadBoostHeld) return;
JihadWriteTunable("up_threshold", gJihadSavedUpThreshold);
JihadWriteTunable("sampling_rate", gJihadSavedSamplingRate);
gJihadBoostHeld = false;
fprintf(stderr, "[jihad-npapi] cpu boost release: up_threshold=%s sampling_rate=%s\n",
gJihadSavedUpThreshold, gJihadSavedSamplingRate);
fflush(stderr);
}
// Drop every outstanding boost at once. Used when the plugin module itself goes away, which on
// this port is the NORMAL exit path (see ActorDestroy), not just the crash path.
void
JihadCpuBoostReleaseAll()
{
if (gJihadBoostedInstances.IsEmpty()) return;
gJihadBoostedInstances.Clear();
if (!gJihadBoostHeld) return;
JihadWriteTunable("up_threshold", gJihadSavedUpThreshold);
JihadWriteTunable("sampling_rate", gJihadSavedSamplingRate);
gJihadBoostHeld = false;
fprintf(stderr, "[jihad-npapi] cpu boost release (module gone): up_threshold=%s sampling_rate=%s\n",
gJihadSavedUpThreshold, gJihadSavedSamplingRate);
fflush(stderr);
}
} // anonymous namespace
NPError
PluginModuleParent::NPP_Destroy(NPP instance,
NPSavedData** saved)
@@ -1296,6 +1478,7 @@ PluginModuleParent::NPP_Destroy(NPP instance,
instance->pdata = nullptr;
Unused << PluginInstanceParent::Call__delete__(parentInstance);
JihadCpuBoostRelease(instance);
return retval;
}
@@ -2292,6 +2475,12 @@ PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance,
UpdatePluginTimeout();
// Taken ONLY here, on the single success path, and released in NPP_Destroy. Every failure
// return above this point either deletes |parentInstance| itself or hands it to NPP_Destroy,
// and a boost acquired on one of those paths would never be released — which on this device
// means leaving the WHOLE system tuned for battery burn with nothing owning it.
JihadCpuBoostAcquire(instance);
return NS_OK;
}
+5
View File
@@ -111,9 +111,14 @@ PluginProcessChild::Init()
return false;
}
fprintf(stderr, "[jihad-npapi-child] InitForChrome plugin=%s parentPid=%d\n",
pluginFilename.c_str(), (int)ParentPid());
fflush(stderr);
bool retval = mPlugin.InitForChrome(pluginFilename, ParentPid(),
IOThreadChild::message_loop(),
IOThreadChild::channel());
fprintf(stderr, "[jihad-npapi-child] InitForChrome = %d\n", (int)retval);
fflush(stderr);
#if defined(XP_MACOSX)
if (nsCocoaFeatures::OnYosemiteOrLater()) {
// Explicitly turn off CGEvent logging. This works around bug 1092855.
+4
View File
@@ -88,6 +88,10 @@ UNIFIED_SOURCES += [
]
SOURCES += [
# Jihad: must NOT be unified — it deliberately includes no NPAPI headers so its exported
# NPN_* symbols escape the hidden-visibility pragma. Merging it with a TU that includes
# npapi.h would reintroduce the prior hidden declaration and silently un-export them.
'JihadNPNInterpose.cpp',
'PluginInstanceChild.cpp', # 'PluginThreadCallback' : ambiguous symbol
'PluginModuleChild.cpp', # Redefinition of mozilla::WindowsDllInterceptor sUser32Intercept
]
+2
View File
@@ -18,6 +18,8 @@ interface mixin DocumentOrShadowRoot {
readonly attribute Element? activeElement;
readonly attribute StyleSheetList styleSheets;
[Throws]
attribute object adoptedStyleSheets;
readonly attribute Element? pointerLockElement;
[LenientSetter, Func="nsDocument::IsUnprefixedFullscreenEnabled"]
+14 -2
View File
@@ -295,11 +295,11 @@ nsXMLContentSink::DidBuildModel(bool aTerminated)
}
mXSLTProcessor->SetSourceContentModel(mDocument, mDocumentChildren);
mDocumentChildren.Clear();
// Since the processor now holds a reference to us we drop our reference
// to it to avoid owning cycles
mXSLTProcessor = nullptr;
}
else {
} else {
// Kick off layout for non-XSLT transformed documents.
// Check if we want to prettyprint
@@ -881,6 +881,12 @@ nsXMLContentSink::SetDocElement(int32_t aNameSpaceID,
if (!mDocumentChildren.IsEmpty()) {
for (nsIContent* child : mDocumentChildren) {
if (MOZ_UNLIKELY(child->GetParentNode())) {
child->Remove();
if (MOZ_UNLIKELY(child->GetParentNode())) {
return false;
}
}
mDocument->AppendChildTo(child, false);
}
mDocumentChildren.Clear();
@@ -991,6 +997,12 @@ nsXMLContentSink::HandleStartElement(const char16_t *aName,
if (!SetDocElement(nameSpaceID, localName, content) && appendContent) {
NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
if (MOZ_UNLIKELY(content->GetParentNode())) {
content->Remove();
if (MOZ_UNLIKELY(content->GetParentNode())) {
return NS_ERROR_UNEXPECTED;
}
}
parent->AppendChildTo(content, false);
}
}
+1 -1
View File
@@ -5159,7 +5159,7 @@ HTMLEditor::IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent)
// If the event is a mouse event, we need to check if the target content is
// the focused editing host or its descendant.
if (aGUIEvent->AsMouseEventBase()) {
nsIContent* editingHost = GetActiveEditingHost();
RefPtr<nsIContent> editingHost = GetActiveEditingHost();
// If there is no active editing host, we cannot handle the mouse event
// correctly.
if (!editingHost) {
+15 -2
View File
@@ -5,6 +5,7 @@
// Local Includes
#include "nsDocShellTreeOwner.h"
#include "nsIBadCertListener2.h" // JIHAD: route cert errors to the embedder chrome
#include "nsWebBrowser.h"
// Helper Classes
@@ -143,6 +144,15 @@ nsDocShellTreeOwner::GetInterface(const nsIID& aIID, void** aSink)
return NS_OK;
}
if (aIID.Equals(NS_GET_IID(nsIBadCertListener2))) {
// JIHAD: the embedder's chrome is what implements this — see the matching comment in
// nsDocShell::GetInterface. Same forwarding shape as nsIWebBrowserChromeFocus below.
if (mWebBrowserChromeWeak != nullptr) {
return mWebBrowserChromeWeak->QueryReferent(aIID, aSink);
}
return mOwnerWin ? mOwnerWin->QueryInterface(aIID, aSink) : NS_NOINTERFACE;
}
if (aIID.Equals(NS_GET_IID(nsIWebBrowserChromeFocus))) {
if (mWebBrowserChromeWeak != nullptr) {
return mWebBrowserChromeWeak->QueryReferent(aIID, aSink);
@@ -1082,6 +1092,9 @@ ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser* aInBrowser,
ChromeTooltipListener::~ChromeTooltipListener()
{
if (mTooltipTimer) {
mTooltipTimer->Cancel();
}
}
// Hook up things to the chrome like context menus and tooltips, if the chrome
@@ -1329,7 +1342,7 @@ void
ChromeTooltipListener::sTooltipCallback(nsITimer* aTimer,
void* aChromeTooltipListener)
{
auto self = static_cast<ChromeTooltipListener*>(aChromeTooltipListener);
RefPtr<ChromeTooltipListener> self = static_cast<ChromeTooltipListener*>(aChromeTooltipListener);
if (self && self->mPossibleTooltipNode) {
// The actual coordinates we want to put the tooltip at are relative to the
// toplevel docshell of our mWebBrowser. We know what the screen
@@ -1374,7 +1387,7 @@ ChromeTooltipListener::sTooltipCallback(nsITimer* aTimer,
self->mPossibleTooltipNode, getter_Copies(tooltipText),
getter_Copies(directionText), &textFound);
if (textFound) {
if (self->mPossibleTooltipNode && textFound) {
nsString tipText(tooltipText);
nsString dirText(directionText);
LayoutDeviceIntPoint screenDot = widget->WidgetToScreenOffset();
+36 -3
View File
@@ -390,6 +390,14 @@ nsWebBrowserFind::SetSelectionAndScroll(nsPIDOMWindowOuter* aWindow,
nsCOMPtr<nsISelection> selection;
// JIHAD: frame->GetSelectionController can leave selCon NULL, and this dereferenced it
// unconditionally — a null deref that took the whole process down. It is reachable in an
// offscreen embedding with no chrome: this is the ONLY thing that made find-in-page
// unusable there (faultaddr=0x0, measured repeatedly). Guarding costs nothing and the
// rest of the function already tolerates a null `selection`.
if (!selCon) {
return;
}
selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
getter_AddRefs(selection));
@@ -707,7 +715,24 @@ nsWebBrowserFind::SearchInFrame(nsPIDOMWindowOuter* aWindow, bool aWrapping,
return NS_ERROR_FAILURE;
}
if (!nsContentUtils::SubjectPrincipal()->Subsumes(theDoc->NodePrincipal())) {
// JIHAD: this same-origin check is why find-in-page took the whole process down in this
// embedding, and the engine says why itself. nsContentUtils::SubjectPrincipal() begins:
// JSContext* cx = GetCurrentJSContext();
// if (!cx) {
// MOZ_CRASH("Accessing the Subject Principal without an AutoJSAPI on the stack is forbidden");
// }
// An EMBEDDER calls nsIWebBrowserFind::FindNext from C++ with no script on the stack, so
// there is no JSContext and MOZ_CRASH fires — a deliberate abort that presents as SIGSEGV at
// address 0, which is precisely the fault this port recorded for two weeks and attributed to
// "a frame-selection controller the offscreen browser doesn't set up". That was wrong: the
// selection machinery is fine and the crash happens BEFORE any of it, on the security check.
//
// The check is meaningful only when there IS a caller to check. With no JS on the stack the
// caller is native embedding code, which is already fully trusted — it is inside libxul's own
// process, holding the nsIWebBrowserFind for that very docShell. So: consult the subject
// principal only when a JSContext exists, and otherwise proceed.
if (nsContentUtils::GetCurrentJSContext() &&
!nsContentUtils::SubjectPrincipal()->Subsumes(theDoc->NodePrincipal())) {
return NS_ERROR_DOM_PROP_ACCESS_DENIED;
}
@@ -809,8 +834,11 @@ nsWebBrowserFind::GetFrameSelection(nsPIDOMWindowOuter* aWindow)
nsCOMPtr<nsISelection> sel;
if (frame) {
frame->GetSelectionController(presContext, getter_AddRefs(selCon));
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
getter_AddRefs(sel));
// JIHAD: same unguarded deref as above — GetSelectionController can yield null.
if (selCon) {
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
getter_AddRefs(sel));
}
if (sel) {
int32_t count = -1;
sel->GetRangeCount(&count);
@@ -820,7 +848,12 @@ nsWebBrowserFind::GetFrameSelection(nsPIDOMWindowOuter* aWindow)
}
}
// JIHAD: and the fallback QI is not guaranteed either — if the presShell does not answer
// nsISelectionController we must return nothing rather than crash.
selCon = do_QueryInterface(presShell);
if (!selCon) {
return nullptr;
}
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
getter_AddRefs(sel));
return sel.forget();
+2 -1
View File
@@ -12,5 +12,6 @@ if CONFIG['NS_PRINTING']:
DIRS += ['win']
elif toolkit == 'cocoa':
DIRS += ['mac']
elif CONFIG['MOZ_PDF_PRINTING']:
elif CONFIG['MOZ_PDF_PRINTING'] or toolkit == 'headless':
# Jihad headless: reuse the gtk-free PDF printing prompt service.
DIRS += ['unixshared']
+1 -1
View File
@@ -1374,7 +1374,7 @@ public:
static already_AddRefed<ScaledFont>
CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize);
#ifdef MOZ_WIDGET_GTK
#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_HEADLESS)
static already_AddRefed<ScaledFont>
CreateScaledFontForFontconfigFont(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern, Float aSize);
#endif
+2 -2
View File
@@ -30,7 +30,7 @@
#include "NativeFontResourceMac.h"
#endif
#ifdef MOZ_WIDGET_GTK
#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_HEADLESS)
#include "ScaledFontFontconfig.h"
#endif
@@ -584,7 +584,7 @@ Factory::CreateScaledFontWithCairo(const NativeFont& aNativeFont, Float aSize, c
#endif
}
#ifdef MOZ_WIDGET_GTK
#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_HEADLESS)
already_AddRefed<ScaledFont>
Factory::CreateScaledFontForFontconfigFont(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern, Float aSize)
{
+21
View File
@@ -0,0 +1,21 @@
/* 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 http://mozilla.org/MPL/2.0/. */
// Jihad (T-512): the GPU path's diagnostics print only with JIHAD_GPU_LOG=1, or in a device round's
// JIHAD_GPU_TIMELINE, JIHAD_GPU_VERIFY or JIHAD_GPU_DUMP_EVERY; failures and fallbacks print anyway
// (plain fprintf). An expression, its switch read once at each place, so it stands anywhere a call
// does. The daemon has the same gate (render/goanna/JihadGpuLog.h in Jihad Browser).
#ifndef MOZILLA_GFX_JIHADGPULOG_H_
#define MOZILLA_GFX_JIHADGPULOG_H_
#include <stdio.h>
#include <stdlib.h>
#define JIHAD_GPU_LOG(...) \
([]() { static const bool sJihadGpuLogOn = getenv("JIHAD_GPU_LOG") || getenv("JIHAD_GPU_TIMELINE") || \
getenv("JIHAD_GPU_VERIFY") || getenv("JIHAD_GPU_DUMP_EVERY"); \
return sJihadGpuLogOn; }() ? fprintf(stderr, __VA_ARGS__) : 0)
#endif // MOZILLA_GFX_JIHADGPULOG_H_
+4 -3
View File
@@ -57,6 +57,7 @@ EXPORTS.mozilla.gfx += [
]
EXPORTS.mozilla.gfx += ['ssse3-scaler.h']
EXPORTS.mozilla.gfx += ['JihadGpuLog.h'] # Jihad (T-512): the GPU path's diagnostics gate
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('cocoa', 'uikit'):
EXPORTS.mozilla.gfx += [
@@ -91,7 +92,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'windows':
'JobScheduler_posix.cpp',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'):
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'headless'):
SOURCES += [
'ScaledFontFontconfig.cpp',
]
@@ -209,12 +210,12 @@ FINAL_LIBRARY = 'xul'
for var in ('USE_CAIRO', 'MOZ2D_HAS_MOZ_CAIRO'):
DEFINES[var] = True
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'):
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'headless'):
DEFINES['MOZ_ENABLE_FREETYPE'] = True
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'):
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'headless'):
CXXFLAGS += CONFIG['CAIRO_FT_CFLAGS']
LOCAL_INCLUDES += CONFIG['SKIA_INCLUDES']
@@ -358,7 +358,8 @@ gl::Error Image9::setManagedSurface(IDirect3DSurface9 *surface)
surface->GetDesc(&desc);
ASSERT(desc.Pool == D3DPOOL_MANAGED);
if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight)
if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight &&
desc.Format == mD3DFormat)
{
if (mSurface)
{
File diff suppressed because it is too large. Load diff
+1
View File
@@ -812,6 +812,7 @@ GLContext::InitWithPrefixImpl(const char* prefix, bool trygl)
"Adreno 205",
"Adreno (TM) 200",
"Adreno (TM) 205",
"Adreno (TM) 220",
"Adreno (TM) 305",
"Adreno (TM) 320",
"Adreno (TM) 330",
+8
View File
@@ -172,6 +172,7 @@ enum class GLRenderer {
Adreno205,
AdrenoTM200,
AdrenoTM205,
AdrenoTM220, // Jihad: the TouchPad's GPU (Adreno (TM) 220)
AdrenoTM305,
AdrenoTM320,
AdrenoTM330,
@@ -1232,6 +1233,13 @@ private:
}
public:
// Jihad T-502 diagnostic: the driver's own scissor box and viewport against this context's
// cache of them (fScissor/fViewport skip a call that matches the cache)
void JihadRawAndCached(GLint* aRawScissor, GLint* aCachedScissor, GLint* aRawViewport, GLint* aCachedViewport) {
raw_fGetIntegerv(LOCAL_GL_SCISSOR_BOX, aRawScissor);
raw_fGetIntegerv(LOCAL_GL_VIEWPORT, aRawViewport);
for (int i = 0; i < 4; i++) { aCachedScissor[i] = mScissorRect[i]; aCachedViewport[i] = mViewportRect[i]; }
}
void fGetIntegerv(GLenum pname, GLint* params);
+35
View File
@@ -38,6 +38,18 @@ public:
~GLContextEGL();
virtual GLContextType GetContextType() const override { return GLContextType::EGL; }
// Jihad T-502: upload 32-bit surfaces as BGRA where the driver takes them (the content is
// BGRA already). On the Adreno 220 an RGBA upload of a 768x942 layer costs 35 ms and a
// BGRA_EXT one 8 (tools/device/gpu-bench.c, 2026-10-17); as RGBA the CPU swizzled every
// tile first and the driver swizzled it back.
virtual GLenum GetPreferredARGB32Format() const override {
return IsExtensionSupported(EXT_texture_format_BGRA8888) ? LOCAL_GL_BGRA : LOCAL_GL_RGBA;
}
// Jihad T-502: a 1x1 pbuffer context sharing aShare's objects (the compositor's
// renderbuffers), made on and for the readback thread.
static already_AddRefed<GLContextEGL>
JihadCreateSharedContext(GLContextEGL* aShare, nsACString* const out_failureId);
static GLContextEGL* Cast(GLContext* gl) {
MOZ_ASSERT(gl->GetContextType() == GLContextType::EGL);
@@ -76,6 +88,23 @@ public:
void SetEGLSurfaceOverride(EGLSurface surf);
// Jihad T-502 round 104: make a pbuffer of exactly this size current in place of the
// context's own (the Adreno 220 driver bins an FBO render by the window surface's height:
// a 942-row frame in a 1400-row pbuffer lost its bottom 458 rows in some composites).
// Returns false (and keeps the current surface) when the pbuffer cannot be made.
bool JihadUsePBufferOfSize(int aWidth, int aHeight);
EGLSurface mJihadPbOverride = nullptr;
// Round 106: a band-sized pbuffer made current for the band composites of a scroll-only
// frame, then the frame's pbuffer again. false when the band pbuffer cannot be made.
// T-527: aTall picks a second pbuffer of its own (the tall band surface), so a frame that needs
// the tall one and the next that needs the short one do not remake either
bool JihadUseBandPBuffer(int aWidth, int aHeight, bool aTall = false);
void JihadUseFramePBuffer();
EGLSurface mJihadBandPb = nullptr;
int mJihadBandPbW = 0, mJihadBandPbH = 0;
EGLSurface mJihadBandPbTall = nullptr;
int mJihadBandPbTallW = 0, mJihadBandPbTallH = 0;
virtual bool MakeCurrentImpl(bool aForce) override;
virtual bool IsCurrent() override;
@@ -111,6 +140,8 @@ public:
const gfx::IntSize& size,
const SurfaceCaps& minCaps,
nsACString* const out_FailureId);
// Jihad (T-511): the share root of the GPU path's pbuffer contexts (JIHAD_GPU_NO_SHARE=1: none)
static GLContextEGL* JihadShareRoot(CreateContextFlags flags, const SurfaceCaps& minCaps);
protected:
friend class GLContextProviderEGL;
@@ -119,6 +150,10 @@ public:
const EGLConfig mConfig;
protected:
EGLSurface mSurface;
public:
// Jihad (T-511): the size of this context's own pbuffer surface (0x0 when it has none)
mozilla::gfx::IntSize mJihadPbSize;
protected:
public:
const EGLContext mContext;
protected:
+161 -1
View File
@@ -84,6 +84,7 @@
#include "GLContextProvider.h"
#include "GLLibraryEGL.h"
#include "GLScreenBuffer.h"
#include "mozilla/StaticMutex.h" // Jihad T-511: the share root
#include "mozilla/ArrayUtils.h"
#include "mozilla/Preferences.h"
#include "mozilla/widget/CompositorWidget.h"
@@ -93,6 +94,8 @@
#include "ScopedGLHelpers.h"
#include "TextureImageEGL.h"
#include "mozilla/gfx/JihadGpuLog.h" // Jihad (T-512): JIHAD_GPU_LOG
using namespace mozilla::gfx;
namespace mozilla {
@@ -246,9 +249,22 @@ GLContextEGL::~GLContextEGL()
printf_stderr("Destroying context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
#endif
// Jihad (T-511): released from this thread before it is destroyed. MarkDestroyed() above leaves it
// current, and the Adreno 220 driver then kept pointers into its framebuffers: the next context's
// teardown on this thread faulted in set_framebuffer (libGLESv2 gl2_surface_update_writeonly_flag)
// on the second WebGL page closed, every time (device rounds 290-296)
if (getenv("JIHAD_GPU_COMPOSITOR") && sEGLLibrary.fGetCurrentContext() == mContext) {
sEGLLibrary.fMakeCurrent(EGL_DISPLAY(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
sEGLLibrary.fDestroyContext(EGL_DISPLAY(), mContext);
sEGLLibrary.UnsetCachedCurrentContext();
// Jihad (T-513 review): the frame-sized and the band pbuffers made for this context
if (mJihadBandPb && mJihadBandPb != mSurface) DestroySurface(mJihadBandPb);
if (mJihadBandPbTall && mJihadBandPbTall != mSurface) DestroySurface(mJihadBandPbTall); // T-527
if (mJihadPbOverride && mJihadPbOverride != mSurface && mJihadPbOverride != mJihadBandPb &&
mJihadPbOverride != mJihadBandPbTall) DestroySurface(mJihadPbOverride);
mJihadBandPb = mJihadBandPbTall = mJihadPbOverride = nullptr;
DestroySurface(mSurface);
}
@@ -336,6 +352,66 @@ GLContextEGL::SetEGLSurfaceOverride(const EGLSurface surf) {
MOZ_ALWAYS_TRUE(MakeCurrent(true));
}
bool
GLContextEGL::JihadUsePBufferOfSize(int aWidth, int aHeight)
{
if (aWidth <= 0 || aHeight <= 0) {
return false;
}
const EGLint attrs[] = { LOCAL_EGL_WIDTH, aWidth, LOCAL_EGL_HEIGHT, aHeight, LOCAL_EGL_NONE };
EGLSurface surf = sEGLLibrary.fCreatePbufferSurface(EGL_DISPLAY(), mConfig, attrs);
if (!surf) {
fprintf(stderr, "[jihad-gpu] a %dx%d pbuffer could not be made (0x%x); the context keeps its surface\n",
aWidth, aHeight, sEGLLibrary.fGetError());
return false;
}
EGLSurface old = mJihadPbOverride;
SetEGLSurfaceOverride(surf);
mJihadPbOverride = surf;
if (old) {
sEGLLibrary.fDestroySurface(EGL_DISPLAY(), old);
}
return true;
}
bool
GLContextEGL::JihadUseBandPBuffer(int aWidth, int aHeight, bool aTall)
{
EGLSurface& pb = aTall ? mJihadBandPbTall : mJihadBandPb;
int& pbW = aTall ? mJihadBandPbTallW : mJihadBandPbW;
int& pbH = aTall ? mJihadBandPbTallH : mJihadBandPbH;
if (!pb || pbW != aWidth || pbH != aHeight) {
if (pb) {
if (mSurfaceOverride == pb) JihadUseFramePBuffer();
sEGLLibrary.fDestroySurface(EGL_DISPLAY(), pb);
pb = nullptr;
}
const EGLint attrs[] = { LOCAL_EGL_WIDTH, aWidth, LOCAL_EGL_HEIGHT, aHeight, LOCAL_EGL_NONE };
pb = sEGLLibrary.fCreatePbufferSurface(EGL_DISPLAY(), mConfig, attrs);
if (!pb) {
fprintf(stderr, "[jihad-gpu] a %dx%d band pbuffer could not be made (0x%x)\n", aWidth, aHeight, sEGLLibrary.fGetError());
return false;
}
pbW = aWidth; pbH = aHeight;
JIHAD_GPU_LOG("[jihad-gpu] band pbuffer %dx%d made%s\n", aWidth, aHeight, aTall ? " (the tall one)" : "");
}
if (mSurfaceOverride != pb) {
mSurfaceOverride = pb;
MakeCurrent(true);
}
return true;
}
void
GLContextEGL::JihadUseFramePBuffer()
{
EGLSurface frame = mJihadPbOverride ? mJihadPbOverride : EGL_NO_SURFACE;
if (mSurfaceOverride != frame) {
mSurfaceOverride = frame;
MakeCurrent(true);
}
}
bool
GLContextEGL::MakeCurrentImpl(bool aForce) {
if (IsDestroyed()) {
@@ -857,6 +933,49 @@ ChooseConfig(GLLibraryEGL* egl, CreateContextFlags flags, const SurfaceCaps& min
return config;
}
// Jihad (T-511): every pbuffer context on the GPU path, the compositor's and each WebGL canvas's, in
// one share group under a 1x1 root that lives as long as the process, so a WebGL frame reaches the
// compositor as a texture it samples (the shared GL texture surface) with no readback: 23.7-25 fps
// for a 480 px canvas, where the readback through the pbuffer gave 16 and through its texture
// framebuffer 8-9. The driver has no EGLImage from a GL texture (EGL_BAD_PARAMETER, gpu-bench.c
// section 17). JIHAD_GPU_NO_SHARE=1: unshared contexts, the readback through the pbuffer.
static StaticMutex sJihadShareLock;
static GLContextEGL* sJihadShareRoot = nullptr; // leaked on purpose: no teardown order to get wrong
static bool sJihadShareTried = false;
/*static*/ GLContextEGL*
GLContextEGL::JihadShareRoot(CreateContextFlags flags, const SurfaceCaps& minCaps)
{
if (!getenv("JIHAD_GPU_COMPOSITOR") || getenv("JIHAD_GPU_NO_SHARE")) {
return nullptr;
}
StaticMutexAutoLock lock(sJihadShareLock);
if (sJihadShareTried) {
return sJihadShareRoot;
}
sJihadShareTried = true;
SurfaceCaps configCaps;
EGLConfig config = ChooseConfig(&sEGLLibrary, flags, minCaps, &configCaps);
if (config == EGL_NO_CONFIG) {
return nullptr;
}
mozilla::gfx::IntSize one(1, 1);
EGLSurface surface = CreatePBufferSurfaceTryingPowerOfTwo(config, LOCAL_EGL_NONE, one);
if (!surface) {
return nullptr;
}
nsCString failureId;
RefPtr<GLContextEGL> gl = CreateGLContext(flags, configCaps, nullptr, true, config, surface, &failureId);
if (!gl) {
sEGLLibrary.fDestroySurface(sEGLLibrary.Display(), surface);
fprintf(stderr, "[jihad-gpu] share root: no context (%s): contexts unshared\n", failureId.get());
return nullptr;
}
sJihadShareRoot = gl.forget().take();
JIHAD_GPU_LOG("[jihad-gpu] share root made: the compositor's and WebGL's contexts share textures\n");
return sJihadShareRoot;
}
/*static*/ already_AddRefed<GLContextEGL>
GLContextEGL::CreateEGLPBufferOffscreenContext(CreateContextFlags flags,
const mozilla::gfx::IntSize& size,
@@ -890,7 +1009,7 @@ GLContextEGL::CreateEGLPBufferOffscreenContext(CreateContextFlags flags,
return nullptr;
}
RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(flags, configCaps, nullptr,
RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(flags, configCaps, JihadShareRoot(flags, minCaps),
true, config, surface,
out_failureId);
if (!gl) {
@@ -898,16 +1017,57 @@ GLContextEGL::CreateEGLPBufferOffscreenContext(CreateContextFlags flags,
sEGLLibrary.fDestroySurface(sEGLLibrary.Display(), surface);
return nullptr;
}
gl->mJihadPbSize = pbSize; // Jihad T-511
return gl.forget();
}
/* static */ already_AddRefed<GLContextEGL>
GLContextEGL::JihadCreateSharedContext(GLContextEGL* aShare, nsACString* const out_failureId)
{
if (!sEGLLibrary.EnsureInitialized(false, out_failureId)) {
return nullptr;
}
SurfaceCaps configCaps;
EGLConfig config = ChooseConfig(&sEGLLibrary, CreateContextFlags::REQUIRE_COMPAT_PROFILE,
SurfaceCaps::ForRGBA(), &configCaps);
if (config == EGL_NO_CONFIG) {
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_NO_CONFIG");
return nullptr;
}
mozilla::gfx::IntSize pbSize(1, 1);
EGLSurface surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config, LOCAL_EGL_NONE, pbSize);
if (!surface) {
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_POT");
return nullptr;
}
RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(CreateContextFlags::REQUIRE_COMPAT_PROFILE, configCaps,
aShare, true, config, surface, out_failureId);
if (!gl) {
sEGLLibrary.fDestroySurface(sEGLLibrary.Display(), surface);
return nullptr;
}
return gl.forget();
}
/*static*/ already_AddRefed<GLContext>
GLContextProviderEGL::CreateHeadless(CreateContextFlags flags,
nsACString* const out_failureId)
{
mozilla::gfx::IntSize dummySize = mozilla::gfx::IntSize(16, 16);
SurfaceCaps dummyCaps = SurfaceCaps::Any();
// Jihad (T-511): on the GPU path an offscreen context (a WebGL canvas's) whose frames are read
// back (no share group: JIHAD_GPU_NO_SHARE=1, or no root could be made) gets a pbuffer as large
// as a canvas on this screen is, RGBA: they are read back through it (ScopedReadbackFB), where a
// read from its texture framebuffer ran ~10x slower on the Adreno 220 (8-9 fps for a 480 px
// canvas, 16 through the pbuffer). 4 MB of GPU memory a context, so not when the compositor
// samples the canvas's texture (no difference measured there, rounds 301).
// JIHAD_GPU_NO_PB_READ=1: the 16x16 one, as before.
if (getenv("JIHAD_GPU_COMPOSITOR") && !getenv("JIHAD_GPU_NO_PB_READ") &&
!GLContextEGL::JihadShareRoot(flags, SurfaceCaps::ForRGBA())) {
dummySize = mozilla::gfx::IntSize(1024, 1024);
dummyCaps = SurfaceCaps::ForRGBA();
}
return GLContextEGL::CreateEGLPBufferOffscreenContext(flags, dummySize, dummyCaps,
out_failureId);
}
+232 -6
View File
@@ -4,6 +4,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GLTextureImage.h"
#include <utility> // Jihad: std::swap
#include <vector>
#include "mozilla/TimeStamp.h"
#include "mozilla/StaticMutex.h"
#include "GLContext.h"
#include "gfxContext.h"
#include "gfxPlatform.h"
@@ -16,6 +20,8 @@
#include "TextureImageEGL.h"
#include "mozilla/gfx/JihadGpuLog.h" // Jihad (T-512): JIHAD_GPU_LOG
using namespace mozilla::gfx;
namespace mozilla {
@@ -116,10 +122,216 @@ BasicTextureImage::~BasicTextureImage()
// then they went away when the contex was deleted, because it
// was the only one that had access to it.
if (ctx && ctx->MakeCurrent()) {
// Jihad T-504: a texture with storage goes to the pool instead (JihadPoolTexture)
if (ctx == mGLContext && !mTexture2 && mTextureState != Created &&
JihadPoolTexture(ctx, mTexture, mSize)) {
return;
}
ctx->fDeleteTextures(1, &mTexture);
if (mTexture2) {
ctx->fDeleteTextures(1, &mTexture2);
}
}
}
// ---- Jihad T-504: the GPU path's tile textures are kept and reused, not deleted -----------------
//
// On the TouchPad's Adreno 220 the first write into a texture after its first draw costs ~18 ms for
// 256x256 (~75 ms for 512x512, ~285 ms for 1024x1024: the driver converts the texture's storage at
// about 14 MB/s), whatever the format, size parity, filter or wrap; every write after that costs
// ~1 ms, under a queued draw that reads the texture too; a deleted and regenerated name pays again
// (tools/device/gpu-bench.c sections 12 and 13, 2026-10-18). The compositor deletes a tile's texture
// with the tile, so every new tile paid the 18 ms on its first change: on desktop Wikipedia ~50 a
// zoom, a second of the compositor thread with no frame (the daemon logged 59 re-uploads at 37 ms
// average, the first uploads 1.5 ms). So on the GPU path the textures of BasicTextureImages that had
// storage go to this pool, up to JIHAD_GPU_TEX_POOL (48: 12 MB of 256x256 tiles), and the next
// texture image takes one, whatever its size: its uploads are the fast kind. A texture the pool
// cannot give is converted while it is 1x1 (JihadConvertTexture; JIHAD_GPU_NO_TEX_CONVERT=1 skips
// it for an A/B).
namespace {
struct JihadPooledTexture {
GLContext* gl;
GLuint tex;
gfx::IntSize size;
};
mozilla::StaticMutex sJihadPoolLock;
std::vector<JihadPooledTexture> sJihadPool;
size_t JihadPoolCap()
{
static const size_t cap = !getenv("JIHAD_GPU_COMPOSITOR") ? 0
: getenv("JIHAD_GPU_TEX_POOL") ? (size_t)atoi(getenv("JIHAD_GPU_TEX_POOL")) : 48;
return cap;
}
uint32_t sJihadPoolHits = 0, sJihadPoolMisses = 0, sJihadPoolKept = 0, sJihadPoolFull = 0;
GLContext* sJihadConvertGL = nullptr;
GLuint sJihadConvertFb = 0;
uint32_t sJihadConverted = 0;
double sJihadConvertMs = 0.0;
// A new texture converted while it is 1x1: a 1x1 image, a clear of it through a framebuffer, a 1x1
// write. The conversion stays when the texture is re-specified at any size, and costs ~1-3 ms
// against ~18 for a 256x256 tile's first write after its first draw (gpu-bench.c sections 14-15:
// a draw that samples the texture converts it only once the draw has finished; a clear does
// without a finish). The scissor test is off for the clear and the framebuffer binding restored.
void JihadConvertTexture(GLContext* aGL, GLuint aTexture)
{
const mozilla::TimeStamp t0 = mozilla::TimeStamp::Now();
if (sJihadConvertGL != aGL) {
sJihadConvertGL = aGL;
sJihadConvertFb = 0;
aGL->fGenFramebuffers(1, &sJihadConvertFb);
}
if (!sJihadConvertFb) {
return;
}
const uint32_t px = 0xffffffff;
ScopedBindTexture bind(aGL, aTexture);
aGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_BGRA, 1, 1, 0, LOCAL_GL_BGRA, LOCAL_GL_UNSIGNED_BYTE, &px);
{
ScopedBindFramebuffer fb(aGL, sJihadConvertFb);
ScopedGLState scissor(aGL, LOCAL_GL_SCISSOR_TEST, false);
aGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_TEXTURE_2D, aTexture, 0);
static int sStatusLogged = 0;
if (sStatusLogged++ < 1) {
JIHAD_GPU_LOG("[jihad-gpu] texture conversion: framebuffer status 0x%x\n", aGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER));
}
aGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
aGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_TEXTURE_2D, 0, 0);
}
aGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0, 1, 1, LOCAL_GL_BGRA, LOCAL_GL_UNSIGNED_BYTE, &px);
sJihadConvertMs += (mozilla::TimeStamp::Now() - t0).ToMilliseconds();
sJihadConverted++;
}
}
bool JihadPoolTexture(GLContext* aGL, GLuint aTexture, const gfx::IntSize& aSize)
{
if (!JihadPoolCap() || !aTexture) {
return false;
}
mozilla::StaticMutexAutoLock lock(sJihadPoolLock);
if (sJihadPool.size() >= JihadPoolCap()) {
sJihadPoolFull++;
return false;
}
sJihadPool.push_back(JihadPooledTexture{aGL, aTexture, aSize});
sJihadPoolKept++;
return true;
}
GLuint JihadTakePooledTexture(GLContext* aGL, const gfx::IntSize& aSize)
{
if (!JihadPoolCap()) {
return 0;
}
GLuint tex = 0;
{
mozilla::StaticMutexAutoLock lock(sJihadPoolLock);
for (size_t i = sJihadPool.size(); i-- > 0;) {
if (sJihadPool[i].gl == aGL) { // any size: the conversion survives a re-specification
tex = sJihadPool[i].tex;
sJihadPool.erase(sJihadPool.begin() + i);
break;
}
}
if (tex) sJihadPoolHits++; else sJihadPoolMisses++;
const uint32_t n = sJihadPoolHits + sJihadPoolMisses;
if (n <= 4 || (n % 50) == 0) {
JIHAD_GPU_LOG("[jihad-gpu] texture pool: %u taken from the pool, %u new (%u converted, %.1f ms each), %u kept, %u deleted (pool full), %zu in the pool\n",
sJihadPoolHits, sJihadPoolMisses, sJihadConverted, sJihadConverted ? sJihadConvertMs / sJihadConverted : 0.0,
sJihadPoolKept, sJihadPoolFull, sJihadPool.size());
}
}
return tex;
}
void JihadDropPooledTextures(GLContext* aGL, bool aDelete)
{
std::vector<GLuint> mine;
{
mozilla::StaticMutexAutoLock lock(sJihadPoolLock);
for (size_t i = 0; i < sJihadPool.size();) {
if (sJihadPool[i].gl == aGL) {
mine.push_back(sJihadPool[i].tex);
sJihadPool.erase(sJihadPool.begin() + i);
} else {
++i;
}
}
}
if (aDelete && !mine.empty() && aGL && aGL->MakeCurrent()) {
aGL->fDeleteTextures((GLsizei)mine.size(), mine.data());
}
if (sJihadConvertGL == aGL) {
if (aDelete && sJihadConvertFb && aGL && aGL->MakeCurrent()) {
aGL->fDeleteFramebuffers(1, &sJihadConvertFb);
}
sJihadConvertGL = nullptr;
sJihadConvertFb = 0;
}
}
// ---- Jihad T-502: fresh texture names per upload, retired names deleted when the GPU is idle --
namespace {
mozilla::StaticMutex sJihadRetireLock;
std::vector<std::pair<GLContext*, GLuint>> sJihadRetired;
}
void JihadRetireTexture(GLContext* aGL, GLuint aTexture)
{
mozilla::StaticMutexAutoLock lock(sJihadRetireLock);
sJihadRetired.push_back(std::make_pair(aGL, aTexture));
}
void JihadFlushRetiredTextures(GLContext* aGL)
{
std::vector<GLuint> mine;
{
mozilla::StaticMutexAutoLock lock(sJihadRetireLock);
for (size_t i = 0; i < sJihadRetired.size();) {
if (sJihadRetired[i].first == aGL) {
mine.push_back(sJihadRetired[i].second);
sJihadRetired.erase(sJihadRetired.begin() + i);
} else {
++i;
}
}
}
if (mine.empty() || !aGL || !aGL->MakeCurrent()) {
return;
}
const mozilla::TimeStamp t0 = mozilla::TimeStamp::Now();
aGL->fDeleteTextures((GLsizei)mine.size(), mine.data());
static uint32_t sN = 0;
const double ms = (mozilla::TimeStamp::Now() - t0).ToMilliseconds();
if (sN++ < 10 || ms >= 3.0) {
if (sN < 200) JIHAD_GPU_LOG("[jihad-gpu] retired textures: %u deleted in %.1f ms\n", (unsigned)mine.size(), ms);
}
}
void
BasicTextureImage::JihadSwapTextures()
{
// Off unless asked for (JIHAD_GPU_FRESH_TEX=1): measured 2026-10-17 (run 86) the first upload
// into a fresh name waits just as the re-upload did (21 ms a tile), so the driver waits for
// the pending GPU work, not for the name; the fresh names only added allocation churn.
static const bool sFresh = getenv("JIHAD_GPU_COMPOSITOR") && getenv("JIHAD_GPU_FRESH_TEX");
if (!sFresh) {
return;
}
if (mTextureState == Created) {
return; // never drawn with: the current name is as fresh as a new one
}
JihadRetireTexture(mGLContext, mTexture);
mGLContext->fGenTextures(1, &mTexture);
ScopedBindTexture bind(mGLContext, mTexture);
mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, mTexFilter);
mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, mTexFilter);
mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, mWrapMode);
mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, mWrapMode);
mTextureState = Created;
}
void
BasicTextureImage::BindTexture(GLenum aTextureUnit)
{
@@ -131,6 +343,7 @@ BasicTextureImage::BindTexture(GLenum aTextureUnit)
bool
BasicTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0, 0) */)
{
JihadSwapTextures(); // Jihad T-502: the name the last composite is not reading
nsIntRegion region;
if (mTextureState == Valid) {
region = aRegion;
@@ -166,10 +379,16 @@ BasicTextureImage::Resize(const gfx::IntSize& aSize)
// we avoid mixing formats.
GLenum format;
GLenum type;
GLenum internalFormat = LOCAL_GL_RGBA;
if (mGLContext->GetPreferredARGB32Format() == LOCAL_GL_BGRA) {
MOZ_ASSERT(!mGLContext->IsGLES());
format = LOCAL_GL_BGRA;
type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
if (mGLContext->IsGLES()) {
// Jihad: BGRA8888 on GLES takes UNSIGNED_BYTE and the same internal format
type = LOCAL_GL_UNSIGNED_BYTE;
internalFormat = LOCAL_GL_BGRA;
} else {
type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
}
} else {
format = LOCAL_GL_RGBA;
type = LOCAL_GL_UNSIGNED_BYTE;
@@ -177,7 +396,7 @@ BasicTextureImage::Resize(const gfx::IntSize& aSize)
mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
0,
LOCAL_GL_RGBA,
internalFormat,
aSize.width,
aSize.height,
0,
@@ -215,7 +434,9 @@ BasicTextureImage::BasicTextureImage(GLuint aTexture,
, mTexture(aTexture)
, mTextureState(Created)
, mGLContext(aContext)
{}
{
mTexFilter = (aFlags & TextureImage::UseNearestFilter) ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
}
static bool
WantsSmallTiles(GLContext* gl)
@@ -500,8 +721,13 @@ CreateBasicTextureImage(GLContext* aGL,
return nullptr;
}
GLuint texture = 0;
aGL->fGenTextures(1, &texture);
GLuint texture = JihadTakePooledTexture(aGL, aSize); // Jihad T-504
if (!texture) {
aGL->fGenTextures(1, &texture);
if (JihadPoolCap() && !getenv("JIHAD_GPU_NO_TEX_CONVERT")) {
JihadConvertTexture(aGL, texture);
}
}
ScopedBindTexture bind(aGL, texture);
+21
View File
@@ -181,6 +181,18 @@ protected:
* convert the update surface's pixels into an image on which we can
* glTexSubImage2D().
*/
// Jihad T-502: on the Adreno 220 a glTexImage2D into a name the GPU has drawn with waits for
// the pending GPU work (18-78 ms a tile, 2026-10-17 run 83); a never-drawn name takes the
// upload at once. So under JIHAD_GPU_COMPOSITOR every upload goes into a fresh name and the
// old one is retired here, to be deleted by the compositor once the GPU is idle (deleting a
// name in use waits too).
void JihadRetireTexture(GLContext* aGL, GLuint aTexture);
// Jihad T-504: the GPU path's pool of tile textures (GLTextureImage.cpp explains why)
bool JihadPoolTexture(GLContext* aGL, GLuint aTexture, const gfx::IntSize& aSize);
GLuint JihadTakePooledTexture(GLContext* aGL, const gfx::IntSize& aSize);
void JihadDropPooledTextures(GLContext* aGL, bool aDelete);
void JihadFlushRetiredTextures(GLContext* aGL);
class BasicTextureImage
: public TextureImage
{
@@ -206,6 +218,15 @@ public:
protected:
GLuint mTexture;
TextureState mTextureState;
// Jihad T-502: a second GL name, used in turn with the first, under JIHAD_GPU_COMPOSITOR.
// On the Adreno 220 binding a texture the last composite still reads waits that
// composite out (~11 ms for a 256x256 tile, 2026-10-17 run 77); the name the composite is
// not reading takes the upload without waiting. Every upload on that path is a whole one
// (GLUploadHelpers: no sub-texture uploads on this GPU), so alternating names is sound.
GLuint mTexture2 = 0; // unused since the fresh-name scheme (kept for the destructor)
TextureState mTextureState2 = Created;
GLint mTexFilter = 0x2601; // GL_LINEAR
void JihadSwapTextures(); // now: retire the name and take a fresh one
RefPtr<GLContext> mGLContext;
};
+44 -5
View File
@@ -4,6 +4,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GLUploadHelpers.h"
#include "mozilla/TimeStamp.h" // Jihad T-502 device rounds
#include <atomic> // Jihad T-517
#include "GLContext.h"
#include "mozilla/gfx/2D.h"
@@ -13,6 +15,8 @@
#include "GfxTexturesReporter.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/JihadGpuLog.h" // Jihad (T-512): JIHAD_GPU_LOG
namespace mozilla {
using namespace gfx;
@@ -90,8 +94,14 @@ CanUploadSubTextures(GLContext* gl)
// There are certain GPUs that we don't want to use glTexSubImage2D on
// because that function can be very slow and/or buggy
// The "(TM)" spellings and the 220 included: on the TouchPad's Adreno 220 twelve 256x256
// glTexSubImage2D updates of a 1024x768 texture cost 160 ms against 10 ms for one whole
// glTexImage2D (Jihad, tools/device/gpu-bench.c, 2026-10-17).
if (gl->Renderer() == GLRenderer::Adreno200 ||
gl->Renderer() == GLRenderer::Adreno205)
gl->Renderer() == GLRenderer::Adreno205 ||
gl->Renderer() == GLRenderer::AdrenoTM200 ||
gl->Renderer() == GLRenderer::AdrenoTM205 ||
gl->Renderer() == GLRenderer::AdrenoTM220)
{
return false;
}
@@ -402,6 +412,10 @@ TexImage2DHelper(GLContext* gl,
}
}
// Jihad (T-517): every upload's count and time (us), for the timeline's transaction and job lines
std::atomic<uint32_t> gJihadUploads(0);
std::atomic<uint64_t> gJihadUploadUs(0);
SurfaceFormat
UploadImageDataToTexture(GLContext* gl,
unsigned char* aData,
@@ -415,9 +429,22 @@ UploadImageDataToTexture(GLContext* gl,
GLenum aTextureUnit,
GLenum aTextureTarget)
{
// Jihad T-502 device rounds: the steps before the GL upload call, timed
const mozilla::TimeStamp jihadE0 = mozilla::TimeStamp::Now();
gl->MakeCurrent();
const mozilla::TimeStamp jihadE1 = mozilla::TimeStamp::Now();
gl->fActiveTexture(aTextureUnit);
gl->fBindTexture(aTextureTarget, aTexture);
const mozilla::TimeStamp jihadE2 = mozilla::TimeStamp::Now();
struct JihadPreLog { const mozilla::TimeStamp &e0, &e1, &e2; ~JihadPreLog() {
static uint32_t sN = 0;
const double all = (mozilla::TimeStamp::Now() - e0).ToMilliseconds();
++gJihadUploads;
gJihadUploadUs += (uint64_t)(all * 1000.0);
if (all >= 8.0 && sN++ < 60)
JIHAD_GPU_LOG("[jihad-gpu] upload steps: make current %.1f ms, bind %.1f ms, the rest %.1f ms (all %.1f)\n",
(e1 - e0).ToMilliseconds(), (e2 - e1).ToMilliseconds(), all - (e2 - e0).ToMilliseconds(), all);
} } jihadPreLog{jihadE0, jihadE1, jihadE2};
GLenum format = 0;
GLenum internalFormat = 0;
@@ -433,7 +460,7 @@ UploadImageDataToTexture(GLContext* gl,
if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) {
format = LOCAL_GL_BGRA;
surfaceFormat = SurfaceFormat::R8G8B8A8;
type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
type = gl->IsGLES() ? LOCAL_GL_UNSIGNED_BYTE : LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; // Jihad: GLES has no 8_8_8_8_REV; BGRA_EXT takes UNSIGNED_BYTE
} else {
format = LOCAL_GL_RGBA;
surfaceFormat = SurfaceFormat::B8G8R8A8;
@@ -447,7 +474,7 @@ UploadImageDataToTexture(GLContext* gl,
if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) {
format = LOCAL_GL_BGRA;
surfaceFormat = SurfaceFormat::R8G8B8X8;
type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
type = gl->IsGLES() ? LOCAL_GL_UNSIGNED_BYTE : LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; // Jihad: GLES has no 8_8_8_8_REV; BGRA_EXT takes UNSIGNED_BYTE
} else {
format = LOCAL_GL_RGBA;
surfaceFormat = SurfaceFormat::B8G8R8X8;
@@ -460,7 +487,7 @@ UploadImageDataToTexture(GLContext* gl,
// Upload our RGBA as BGRA, but store that the uploaded format is
// BGRA. (sample from R to get B)
format = LOCAL_GL_BGRA;
type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
type = gl->IsGLES() ? LOCAL_GL_UNSIGNED_BYTE : LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; // Jihad: GLES has no 8_8_8_8_REV; BGRA_EXT takes UNSIGNED_BYTE
surfaceFormat = SurfaceFormat::B8G8R8A8;
} else {
format = LOCAL_GL_RGBA;
@@ -474,7 +501,7 @@ UploadImageDataToTexture(GLContext* gl,
// format used.
if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) {
format = LOCAL_GL_BGRA;
type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
type = gl->IsGLES() ? LOCAL_GL_UNSIGNED_BYTE : LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; // Jihad: GLES has no 8_8_8_8_REV; BGRA_EXT takes UNSIGNED_BYTE
surfaceFormat = SurfaceFormat::B8G8R8X8;
} else {
format = LOCAL_GL_RGBA;
@@ -497,6 +524,9 @@ UploadImageDataToTexture(GLContext* gl,
default:
MOZ_ASSERT_UNREACHABLE("Unhandled image surface format!");
}
if (gl->IsGLES() && (format == LOCAL_GL_BGRA || format == LOCAL_GL_RGBA)) {
internalFormat = format; // Jihad: GLES2 wants them equal (TexImage2DHelper asserts it)
}
if (aOutUploadSize) {
*aOutUploadSize = 0;
@@ -506,6 +536,15 @@ UploadImageDataToTexture(GLContext* gl,
return gfx::SurfaceFormat::UNKNOWN;
}
// Jihad T-502 device rounds: the format this upload goes up as, and the call's own time
static uint32_t sJihadUploads = 0;
const mozilla::TimeStamp jihadT0 = mozilla::TimeStamp::Now();
struct JihadUpLog { const mozilla::TimeStamp& t0; GLenum fmt; GLenum type; int w, h; bool init; ~JihadUpLog() {
const double ms = (mozilla::TimeStamp::Now() - t0).ToMilliseconds();
if (sJihadUploads++ < 40 || ms >= 8.0) {
if (sJihadUploads < 400) JIHAD_GPU_LOG("[jihad-gpu] upload call %dx%d format 0x%x type 0x%x init %d: %.1f ms\n", w, h, (unsigned)fmt, (unsigned)type, (int)init, ms);
}
} } jihadUpLog{jihadT0, format, type, aSize.width, aSize.height, aNeedInit};
if (aNeedInit || !CanUploadSubTextures(gl)) {
// If the texture needs initialized, or we are unable to
// upload sub textures, then initialize and upload the entire
+16 -3
View File
@@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SharedSurface.h"
#include "GLContextEGL.h" // Jihad T-511: the pbuffer readback
#include "../2d/2D.h"
#include "GLBlitHelper.h"
@@ -421,11 +422,23 @@ ScopedReadbackFB::ScopedReadbackFB(SharedSurface* src)
}
case AttachmentType::GLTexture:
{
mGL->fGenFramebuffers(1, &mTempFB);
mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mTempFB);
GLuint tex = src->ProdTexture();
GLenum texImageTarget = src->ProdTextureTarget();
// Jihad (T-511): on the GPU path, a canvas frame is drawn onto the context's own pbuffer
// and read from there: the Adreno 220 reads a pbuffer ~10x faster than a texture
// framebuffer (the WebGL canvas's frame every frame)
if (getenv("JIHAD_GPU_COMPOSITOR") && !getenv("JIHAD_GPU_NO_PB_READ") &&
mGL->GetContextType() == GLContextType::EGL && texImageTarget == LOCAL_GL_TEXTURE_2D) {
const gfx::IntSize pb = GLContextEGL::Cast(mGL)->mJihadPbSize;
if (mGL->Screen() && src->mSize.width <= pb.width && src->mSize.height <= pb.height) {
mGL->BlitHelper()->BlitTextureToFramebuffer(tex, 0, src->mSize, src->mSize,
texImageTarget, true);
mGL->Screen()->BindReadFB_Internal(0); // the pbuffer itself, not the screen's FBO
break;
}
}
mGL->fGenFramebuffers(1, &mTempFB);
mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mTempFB);
mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_COLOR_ATTACHMENT0,
texImageTarget, tex, 0);
+7 -3
View File
@@ -632,9 +632,13 @@ NVImage::GetAsSourceSurface()
// Convert the current NV12 or NV21 data to YUV420P so that we can follow the
// logics in PlanarYCbCrImage::GetAsSourceSurface().
const int bufferLength = mData.mYSize.height * mData.mYStride +
mData.mCbCrSize.height * mData.mCbCrSize.width * 2;
uint8_t* buffer = new uint8_t[bufferLength];
auto bufferLength = CheckedInt<uint32_t>(mData.mYSize.height) * mData.mYStride +
CheckedInt<uint32_t>(mData.mCbCrSize.height) * mData.mCbCrSize.width * 2;
if (!bufferLength.isValid()) {
NS_ERROR("Image buffer length exceeds integer limits.");
return nullptr;
}
uint8_t* buffer = new uint8_t[bufferLength.value()];
Data aData = mData;
aData.mCbCrStride = aData.mCbCrSize.width;
+79
View File
@@ -3,6 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <cmath> // Jihad T-502: roundf, fabsf
#include "LayerTreeInvalidation.h"
#include <stdint.h> // for uint32_t
@@ -26,11 +27,29 @@
#include "mozilla/layers/LayerManagerComposite.h"
#include "TreeTraversal.h" // for ForEachNode
#include "mozilla/gfx/JihadGpuLog.h" // Jihad (T-512): JIHAD_GPU_LOG
using namespace mozilla::gfx;
namespace mozilla {
namespace layers {
// Jihad T-502 round 115 (see LayerTreeInvalidation.h)
static struct { bool on; float scale; bool have; float dx, dy; } sJihadScrollDiff = { false, 1.0f, false, 0.0f, 0.0f };
void JihadDiffScrollBegin(bool aOn, float aScale)
{
sJihadScrollDiff.on = aOn; sJihadScrollDiff.scale = aScale > 0.0f ? aScale : 1.0f;
// turning it off keeps what the diff just measured for the caller to take (round 119: the
// round-115 shift was cleared here before the bridge could read it)
if (aOn) { sJihadScrollDiff.have = false; sJihadScrollDiff.dx = sJihadScrollDiff.dy = 0.0f; }
}
bool JihadDiffScrollShift(float* aDx, float* aDy)
{
if (!sJihadScrollDiff.have) return false;
*aDx = sJihadScrollDiff.dx; *aDy = sJihadScrollDiff.dy;
return true;
}
struct LayerPropertiesBase;
UniquePtr<LayerPropertiesBase> CloneLayerTreePropertiesInternal(Layer* aRoot, bool aIsMask = false);
@@ -181,6 +200,50 @@ public:
bool transformChanged = !mTransform.FuzzyEqual(GetTransformForInvalidation(mLayer)) ||
mLayer->GetPostXScale() != mPostXScale ||
mLayer->GetPostYScale() != mPostYScale;
if (sJihadScrollDiff.on && transformChanged && !mLayer->GetIsFixedPosition() && !mLayer->GetIsStickyPosition() &&
mLayer->GetPostXScale() == mPostXScale && mLayer->GetPostYScale() == mPostYScale) {
// Jihad T-502 round 115: a scroll moves the root-content layer by a pure translation; the
// rows it carries are shifted by the daemon, so only what else changed is reported
const Matrix4x4 now = GetTransformForInvalidation(mLayer);
const Matrix4x4& was = mTransform;
const bool pure = FuzzyEqual(now._11, was._11) && FuzzyEqual(now._12, was._12) && FuzzyEqual(now._13, was._13) &&
FuzzyEqual(now._14, was._14) && FuzzyEqual(now._21, was._21) && FuzzyEqual(now._22, was._22) &&
FuzzyEqual(now._23, was._23) && FuzzyEqual(now._24, was._24) && FuzzyEqual(now._31, was._31) &&
FuzzyEqual(now._32, was._32) && FuzzyEqual(now._33, was._33) && FuzzyEqual(now._34, was._34) &&
FuzzyEqual(now._43, was._43) && FuzzyEqual(now._44, was._44);
const float tx = now._41 - was._41, ty = now._42 - was._42;
if (pure && FuzzyEqual(tx, 0.0f)) {
const bool rootMetrics = mLayer->GetScrollMetadataCount() > 0 &&
mLayer->GetScrollMetadata(0).GetMetrics().IsRootContent();
const float rows = -ty * sJihadScrollDiff.scale;
const bool integral = fabsf(rows - roundf(rows)) < 0.01f;
if (rootMetrics && !sJihadScrollDiff.have && integral) {
sJihadScrollDiff.have = true; sJihadScrollDiff.dx = tx; sJihadScrollDiff.dy = ty;
}
if (sJihadScrollDiff.have && FuzzyEqual(ty, sJihadScrollDiff.dy)) {
mTransform = now;
transformChanged = false;
}
}
}
{
// Jihad T-502 diagnostic (JIHAD_GPU_DIFFLOG): a transform that changed, and by what
static const bool sDiffLog = getenv("JIHAD_GPU_DIFFLOG") != nullptr;
static uint32_t sN = 0;
if (sDiffLog && transformChanged && sN++ < 400) {
const Matrix4x4 now = GetTransformForInvalidation(mLayer);
const bool sameLinear = FuzzyEqual(now._11, mTransform._11) && FuzzyEqual(now._12, mTransform._12) &&
FuzzyEqual(now._21, mTransform._21) && FuzzyEqual(now._22, mTransform._22);
const IntRect vb = mLayer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds();
Layer* par = mLayer->GetParent();
JIHAD_GPU_LOG("[jihad-gpu] diff: layer %p (parent %p type %d metadata %u, type %d, fixed %d sticky %d, metadata %u, flags 0x%x, visible %d,%d %dx%d, clip %d) transform moved by %.1f,%.1f%s; old ty %.1f new ty %.1f\n",
mLayer, par, par ? (int)par->GetType() : -1, par ? (unsigned)par->GetScrollMetadataCount() : 0u,
(int)mLayer->GetType(), (int)mLayer->GetIsFixedPosition(), (int)mLayer->GetIsStickyPosition(),
(unsigned)mLayer->GetScrollMetadataCount(), (unsigned)mLayer->GetContentFlags(), vb.x, vb.y, vb.width, vb.height,
(int)!!mLayer->GetLocalClipRect(), now._41 - mTransform._41, now._42 - mTransform._42,
sameLinear ? "" : " (and scaled)", mTransform._42, now._42);
}
}
const Maybe<ParentLayerIntRect>& otherClip = mLayer->GetLocalClipRect();
nsIntRegion result;
@@ -234,6 +297,22 @@ public:
}
}
{
// Jihad T-502 diagnostic (JIHAD_GPU_DIFFLOG): a layer contributing a large change, and why
static const bool sDiffLog = getenv("JIHAD_GPU_DIFFLOG") != nullptr;
static uint32_t sBig = 0;
const IntRect rb = result.GetBounds();
if (sDiffLog && rb.height > 300 && sBig++ < 3000) {
const IntRect inv = mLayer->GetInvalidRegion().GetRegion().GetBounds();
const IntRect vOld = mVisibleRegion.GetBounds();
const IntRect vNew = mLayer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds();
const Matrix4x4 now = GetTransformForInvalidation(mLayer);
JIHAD_GPU_LOG("[jihad-gpu] diff big: layer %p type %d metadata %u: result y %d..%d; transform changed %d (ty %.1f -> %.1f), invalid (layer) y %d..%d, visible old y %d..%d new y %d..%d, clip changed %d\n",
mLayer, (int)mLayer->GetType(), (unsigned)mLayer->GetScrollMetadataCount(), rb.y, rb.YMost(), (int)transformChanged,
mTransform._42, now._42, inv.y, inv.YMost(), vOld.y, vOld.YMost(), vNew.y, vNew.YMost(),
(int)(mUseClipRect && otherClip && !mClipRect.IsEqualInterior(*otherClip)));
}
}
mLayer->ClearInvalidRect();
return result;
}
+7
View File
@@ -30,6 +30,13 @@ typedef void (*NotifySubDocInvalidationFunc)(ContainerLayer* aLayer,
* A set of cached layer properties (including those of child layers),
* used for comparing differences in layer trees.
*/
// Jihad T-502 round 115: the next ComputeDifferences treats a pure vertical translation of the
// root-content scroll layer (and of any non-fixed layer moved by the same amount) as a scroll, not
// a change, when it moves the frame by whole rows at aScale (the world scale). The shift it saw,
// in layer pixels, is reported by JihadDiffScrollShift; false when none.
void JihadDiffScrollBegin(bool aOn, float aScale);
bool JihadDiffScrollShift(float* aDx, float* aDy);
struct LayerProperties
{
protected:
+12 -1
View File
@@ -1397,7 +1397,18 @@ ContainerLayer::DefaultComputeEffectiveTransforms(const Matrix4x4& aTransformToS
checkClipRect = true;
checkMaskLayers = true;
} else {
if (gfx::ThebesMatrix(contTransform).HasNonIntegerTranslation()) {
// Jihad T-502: HasNonIntegerTranslation() is also true for any SCALE, so under the
// offscreen card's world zoom every container with a clipped child (the root, with the
// scroll frame's clip) rendered through an intermediate surface the size of its visible
// region: one more full-frame pass a composite, nothing of the displayport beyond the
// viewport, and fixed-layer compensation measured in the surface's space. On the
// compositor's tree an axis-aligned scale+translate clips fine by scissor
// (CalculateScissorRect transforms the clip by the parent's effective transform; the
// edge may be a pixel off), so no surface for that case. JIHAD_GPU_SURFACES=1 restores it.
static const bool sJihadNoSurface = getenv("JIHAD_GPU_COMPOSITOR") && !getenv("JIHAD_GPU_SURFACES");
const bool jihadScissorable = sJihadNoSurface && Manager() && Manager()->AsLayerManagerComposite() &&
contTransform.PreservesAxisAlignedRectangles();
if (gfx::ThebesMatrix(contTransform).HasNonIntegerTranslation() && !jihadScissorable) {
checkClipRect = true;
}
/* In 2D case, only translation and/or positive scaling can be done w/o using IntermediateSurface.
+10 -3
View File
@@ -87,12 +87,19 @@ public:
bool
BasicPlanarYCbCrImage::CopyData(const Data& aData)
{
RecyclingPlanarYCbCrImage::CopyData(aData);
if (mDelayedConversion) {
if (!RecyclingPlanarYCbCrImage::CopyData(aData)) {
return false;
}
// The YCbCr copy above succeeded; delaying the RGB conversion is not a
// failure. GetAsSourceSurface() converts on demand when mDecodedBuffer is
// null. Returning false here made VideoData::CreateAndCopyData report OOM
// (MEDIA_ERR_DECODE) for any frame decoded while BasicImageLayer::Paint had
// swapped this factory into the video's ImageContainer.
if (mDelayedConversion) {
return true;
}
// Do some sanity checks to prevent integer overflow
if (aData.mYSize.width > PlanarYCbCrImage::MAX_DIMENSION ||
aData.mYSize.height > PlanarYCbCrImage::MAX_DIMENSION) {
+18
View File
@@ -22,6 +22,8 @@
#include "gfxUtils.h"
#include "TextureClientSharedSurface.h"
#include "mozilla/gfx/JihadGpuLog.h" // Jihad (T-512): JIHAD_GPU_LOG
using namespace mozilla::gfx;
using namespace mozilla::gl;
@@ -69,6 +71,22 @@ ClientCanvasLayer::Initialize(const Data& aData)
}
UniquePtr<SurfaceFactory> factory = GLScreenBuffer::CreateFactory(mGLContext, caps, forwarder, mFlags);
// Jihad (T-511): a WebGL canvas whose context shares the compositor's textures (the share root,
// GLContextProviderEGL.cpp) hands the compositor its texture: no readback, no upload
if (!factory && !mGLFrontbuffer && !aData.mIsMirror && getenv("JIHAD_GPU_COMPOSITOR") &&
!getenv("JIHAD_GPU_NO_SHARE") && mGLContext->GetContextType() == gl::GLContextType::EGL &&
mGLContext->GetSharedContext()) {
RefPtr<LayersIPCChannel> channel = forwarder->GetTextureForwarder();
factory = MakeUnique<gl::SurfaceFactory_GLTexture>(mGLContext, caps, channel, mFlags);
}
// Jihad (T-511): which way a WebGL canvas reaches the compositor on the GPU path (the basic surface:
// read back, through the context's pbuffer, ScopedReadbackFB, and uploaded each frame)
if (getenv("JIHAD_GPU_COMPOSITOR")) {
static int sLogged = 0;
if (sLogged++ < 4)
JIHAD_GPU_LOG("[jihad-gpu] canvas layer: %s\n",
factory ? "a shared surface (zero copy)" : "the basic surface (read back through the pbuffer and uploaded each frame)");
}
if (mGLFrontbuffer || aData.mIsMirror) {
// We're using a source other than the one in the default screen.
+6 -1
View File
@@ -441,7 +441,12 @@ ClientLayerManager::DidComposite(uint64_t aTransactionId,
const TimeStamp& aCompositeStart,
const TimeStamp& aCompositeEnd)
{
MOZ_ASSERT(mWidget);
// Jihad (T-515): the embedder's offscreen compose jobs can be acknowledged after the widget is
// gone (a card closed while a job it had asked for was waited out): nothing is left to tell. The
// widget's teardown nulls mWidget; it was dereferenced here (SIGSEGV at 0, 2026-10-19).
if (!mWidget) {
return;
}
// |aTransactionId| will be > 0 if the compositor is acknowledging a shadow
// layers transaction.
+8
View File
@@ -24,6 +24,8 @@
#include "gfx2DGlue.h"
#include "ReadbackProcessor.h"
#include "mozilla/gfx/JihadGpuLog.h" // Jihad (T-512): JIHAD_GPU_LOG
namespace mozilla {
namespace layers {
@@ -146,6 +148,12 @@ already_AddRefed<PaintedLayer>
ClientLayerManager::CreatePaintedLayerWithHint(PaintedLayerCreationHint aHint)
{
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
{
// Jihad T-502 device rounds: whether painted layers are tiled (layers.enable-tiles is a
// once-only gfx pref: goanna.js, not prefs.js)
static bool sLogged = false;
if (!sLogged) { sLogged = true; JIHAD_GPU_LOG("[jihad-gpu] painted layers: %s\n", gfxPrefs::LayersTilesEnabled() ? "tiled" : "single-buffer (not tiled)"); }
}
if (gfxPrefs::LayersTilesEnabled()) {
RefPtr<ClientTiledPaintedLayer> layer = new ClientTiledPaintedLayer(this, aHint);
CREATE_SHADOW(Painted);
@@ -43,6 +43,8 @@
#include "TreeTraversal.h" // for ForEachNode, BreadthFirstSearch
#include "VsyncSource.h"
#include "mozilla/gfx/JihadGpuLog.h" // Jihad (T-512): JIHAD_GPU_LOG
struct nsCSSValueSharedList;
namespace mozilla {
@@ -512,6 +514,15 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aTransformedSubtreeRoo
// We want to translate the layer by the difference between
// |transformedAnchor| and |anchor|.
LayerPoint translation = transformedAnchor - anchor;
{
// Jihad T-502 diagnostic (every 50th fixed/sticky layer aligned)
static uint32_t sN = 0;
if ((sN++ % 50) == 0) {
JIHAD_GPU_LOG("[jihad-gpu] align fixed: layer %p (parent %p, fixed %d sticky %d) under subtree root %p (root's parent %p), scroll id %llu: anchor %.1f,%.1f, translation %.1f,%.1f\n",
layer, layer->GetParent(), (int)layer->GetIsFixedPosition(), (int)layer->GetIsStickyPosition(), aTransformedSubtreeRoot,
aTransformedSubtreeRoot->GetParent(), (unsigned long long)aTransformScrollId, anchor.x, anchor.y, translation.x, translation.y);
}
}
// A fixed layer will "consume" (be unadjusted by) the entire translation
// calculated above. A sticky layer may consume all, part, or none of it,
@@ -537,6 +548,24 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aTransformedSubtreeRoo
unconsumedTranslation = translation - originalTranslation;
}
// Jihad T-502 round 127: a sticky layer held in place this composite counts as fixed for the
// readback. T-503: also one the engine has already laid out stuck (an anchor move just put the
// async offset at zero, so it is not adjusted now): the next pan steps will hold it. Probed
// with a step's translation both ways against its sticky ranges.
if (layer->GetIsStickyPosition()) {
bool held = fabsf(translation.x) > 0.5f || fabsf(translation.y) > 0.5f;
if (!held) {
const LayerRect& outer = layer->GetStickyScrollRangeOuter();
const LayerRect& inner = layer->GetStickyScrollRangeInner();
const LayerPoint base = translation - unconsumedTranslation; // the translation before the sticky clamp
for (const float probe : { mJihadProbe, -mJihadProbe }) {
const float ty = base.y + probe;
const float hy = IntervalOverlap(ty, outer.y, outer.YMost()) - IntervalOverlap(ty, inner.y, inner.YMost());
if (fabsf(hy) > 0.5f) held = true;
}
}
if (held) mJihadStuck.push_back(layer);
}
// Finally, apply the translation to the layer transform. Note that in cases
// where the async transform on |aTransformedSubtreeRoot| affects this layer's
// clip rect, we need to apply the same translation to said clip rect, so
@@ -833,6 +862,19 @@ bool
AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
bool* aOutFoundRoot)
{
mJihadStuck.clear(); // Jihad T-502 round 127: this composite's stuck sticky layers
{
// T-513 (review): a sticky layer is probed as far as twice this composite's scroll step (64 px at
// least): a fast flick crossed the threshold by more than a fixed 64 px in one frame, its stuck
// position was not read and its old pixels slid with the content as a ghost strip
// (a frame may compose more than once at one scroll: only a move sets it)
const float step = mJihadScrollValid ? fabsf(mJihadScrollY - mJihadPrevScrollY) : 0.0f;
if (step > 0.5f) {
mJihadProbe = std::max(64.0f, std::min(2.0f * step, 1024.0f));
mJihadPrevScrollY = mJihadScrollY;
}
if (mJihadProbeOverride > 0.0f) mJihadProbe = mJihadProbeOverride; // T-504: an overview composite
}
bool appliedTransform = false;
std::stack<Maybe<ParentLayerIntRect>> stackDeferredClips;
@@ -909,23 +951,56 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
}
}
// Jihad T-502 diagnostic: what the tree offers the card's scroll (every 50th layer with
// metadata, and every 500th composite's root when nothing has any)
{
static uint32_t sSeen = 0, sRootSeen = 0;
if (layer->GetScrollMetadataCount() > 0 && (sSeen++ % 50) == 0) {
const FrameMetrics& m0 = layer->GetScrollMetadata(0).GetMetrics();
JIHAD_GPU_LOG("[jihad-gpu] async scroll: layer %p has %u metadata (first: root content %d, id %llu, offset %.1f,%.1f), card scroll valid %d want %.1f,%.1f, controller %d\n",
layer, (unsigned)layer->GetScrollMetadataCount(), (int)m0.IsRootContent(), (unsigned long long)m0.GetScrollId(),
m0.GetScrollOffset().x, m0.GetScrollOffset().y, (int)mJihadScrollValid, mJihadScrollX, mJihadScrollY, (int)(layer->GetAsyncPanZoomController(0) != nullptr));
} else if (layer->GetScrollMetadataCount() == 0 && !layer->GetParent() && (sRootSeen++ % 500) == 0) {
JIHAD_GPU_LOG("[jihad-gpu] async scroll: the root layer %p has no metadata (card scroll valid %d want %.1f,%.1f)\n", layer, (int)mJihadScrollValid, mJihadScrollX, mJihadScrollY);
}
}
for (uint32_t i = 0; i < layer->GetScrollMetadataCount(); i++) {
AsyncPanZoomController* controller = layer->GetAsyncPanZoomController(i);
// Jihad T-502: without APZ, the card's scroll on the root scroll frame's content
AsyncTransform jihadAsync;
bool jihadScroll = false;
if (!controller) {
continue;
const FrameMetrics& jm = layer->GetScrollMetadata(i).GetMetrics();
if (mJihadScrollValid && jm.IsRootContent()) {
const CSSPoint want(mJihadScrollX, mJihadScrollY);
const ParentLayerPoint translation = (want - jm.GetScrollOffset()) * jm.GetZoom();
jihadAsync = AsyncTransform(LayerToParentLayerScale(1.0f), -translation);
jihadScroll = true;
static uint32_t sN = 0;
if (sN++ < 10 || (sN % 25) == 0) {
JIHAD_GPU_LOG("[jihad-gpu] async scroll: want %.1f,%.1f, painted at %.1f,%.1f, zoom %.4f x %.4f -> translation %.1f,%.1f on layer %p (parent %p, id %llu)\n",
want.x, want.y, jm.GetScrollOffset().x, jm.GetScrollOffset().y, jm.GetZoom().xScale, jm.GetZoom().yScale, -translation.x, -translation.y,
layer, layer->GetParent(), (unsigned long long)jm.GetScrollId());
}
}
if (!jihadScroll) {
continue;
}
}
hasAsyncTransform = true;
AsyncTransform asyncTransformWithoutOverscroll =
controller->GetCurrentAsyncTransform(AsyncPanZoomController::RESPECT_FORCE_DISABLE);
AsyncTransformComponentMatrix overscrollTransform =
controller->GetOverscrollTransform(AsyncPanZoomController::RESPECT_FORCE_DISABLE);
AsyncTransform asyncTransformWithoutOverscroll = controller
? controller->GetCurrentAsyncTransform(AsyncPanZoomController::RESPECT_FORCE_DISABLE)
: jihadAsync;
AsyncTransformComponentMatrix overscrollTransform = controller
? controller->GetOverscrollTransform(AsyncPanZoomController::RESPECT_FORCE_DISABLE)
: AsyncTransformComponentMatrix();
AsyncTransformComponentMatrix asyncTransform =
AsyncTransformComponentMatrix(asyncTransformWithoutOverscroll)
* overscrollTransform;
if (!layer->IsScrollInfoLayer()) {
if (controller && !layer->IsScrollInfoLayer()) {
controller->MarkAsyncTransformAppliedToContent();
}
@@ -6,6 +6,7 @@
#ifndef GFX_ASYNCCOMPOSITIONMANAGER_H
#define GFX_ASYNCCOMPOSITIONMANAGER_H
#include <vector> // Jihad T-502
#include "Units.h" // for ScreenPoint, etc
#include "mozilla/layers/LayerManagerComposite.h" // for LayerManagerComposite
#include "mozilla/Attributes.h" // for final, etc
@@ -115,6 +116,23 @@ public:
// Returns true if the next composition will be the first for a
// particular document.
bool IsFirstPaint() { return mIsFirstPaint; }
// Jihad T-502: the card's scroll position (CSS px, absolute), applied to the root scroll
// frame's content as an async transform while the engine's own scroll (the metrics' offset)
// stays where the last paint put it; fixed and sticky layers are aligned as under APZ.
void JihadSetScroll(float aX, float aY, bool aValid) { mJihadScrollX = aX; mJihadScrollY = aY; mJihadScrollValid = aValid; }
// round 127: the sticky layers the last composite held in place (a nonzero alignment, or no
// async offset to tell by); a sticky layer scrolling with the content is not fixed rows
bool JihadIsStuck(Layer* aLayer) const {
for (Layer* l : mJihadStuck) if (l == aLayer) return true;
return false;
}
void JihadClearStuck() { mJihadStuck.clear(); }
// T-504: the sticky probe's state, kept across a verify composite (the daemon's overview windows sit a frame of
// rows from the card's scroll, and their step would leave a probe of up to 1024 px for the next real frame), and
// a fixed probe for the overview's composites (every window lists the same sticky layers)
void JihadProbeState(float* aPrevY, float* aProbe) const { *aPrevY = mJihadPrevScrollY; *aProbe = mJihadProbe; }
void JihadSetProbeState(float aPrevY, float aProbe) { mJihadPrevScrollY = aPrevY; mJihadProbe = aProbe; }
void JihadSetProbeOverride(float aProbe) { mJihadProbeOverride = aProbe; }
// GetFrameUniformity will return the frame uniformity for each layer attached to an APZ
// from the recorded data in RecordShadowTransform
@@ -225,6 +243,12 @@ private:
// front-end (e.g. Java on Android) about this so that it take the new page
// size and zoom into account when providing us with the next view transform.
bool mIsFirstPaint;
float mJihadScrollX = 0.0f, mJihadScrollY = 0.0f; // Jihad T-502
bool mJihadScrollValid = false;
float mJihadPrevScrollY = 0.0f; // T-513: the card's scroll at the composite before
float mJihadProbe = 64.0f; // T-513: how far a sticky layer is probed for sticking (layer px)
float mJihadProbeOverride = 0.0f; // T-504: this composite's probe (0: from the scroll step)
std::vector<Layer*> mJihadStuck; // round 127 (raw: valid until the next composite)
// This flag is set during a layers update, so that the first composition
// after a layers update has it set. It is cleared after that first composition.
+160 -8
View File
@@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "LayerManagerComposite.h"
#include "LayerTreeInvalidation.h" // Jihad T-502: JihadDiffScrollBegin
#include <stddef.h> // for size_t
#include <stdint.h> // for uint16_t, uint32_t
#include "CanvasLayerComposite.h" // for CanvasLayerComposite
@@ -416,6 +417,64 @@ LayerManagerComposite::EndTransaction(const TimeStamp& aTimeStamp,
#endif
}
void
LayerManagerComposite::JihadPrepareOnly()
{
if (!mRoot) {
return;
}
nsIntRegion opaque;
LayerIntRegion visible;
PostProcessLayers(mRoot, opaque, visible, Nothing());
mRoot->ComputeEffectiveTransforms(getenv("JIHAD_GPU_NO_WORLD_ENGINE") ? gfx::Matrix4x4() : mJihadWorld);
}
nsIntRegion
LayerManagerComposite::JihadDiffOnly()
{
nsIntRegion changed;
if (!mRoot) {
return changed;
}
nsIntRegion opaque;
LayerIntRegion visible;
PostProcessLayers(mRoot, opaque, visible, Nothing());
mRoot->ComputeEffectiveTransforms(getenv("JIHAD_GPU_NO_WORLD_ENGINE") ? gfx::Matrix4x4() : mJihadWorld);
if (mClonedLayerTreeProperties) {
JihadDiffScrollBegin(mJihadCompensateScroll, mJihadWorld._22);
bool geometryChanged = false;
changed = mClonedLayerTreeProperties->ComputeDifferences(mRoot, nullptr, &geometryChanged);
JihadDiffScrollBegin(false, 1.0f);
if (geometryChanged) mGeometryChanged = true;
if (!mJihadWorld.IsIdentity() && !changed.IsEmpty()) {
nsIntRegion scaled;
for (auto iter = changed.RectIter(); !iter.Done(); iter.Next()) {
const gfx::IntRect& r = iter.Get();
gfx::Rect fr = mJihadWorld.TransformBounds(gfx::Rect(r.x, r.y, r.width, r.height));
fr.RoundOut();
scaled.OrWith(gfx::IntRect(int32_t(fr.x), int32_t(fr.y), int32_t(fr.width), int32_t(fr.height)));
}
changed = Move(scaled);
}
} else {
changed = mRenderBounds;
}
mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot());
return changed;
}
// Jihad T-502 round 139 (JIHAD_GPU_PHASES=1): where a composite's CPU time goes, in ms:
// 0 post-process, 1 transforms + diff, 2 begin frame, 3 prepare, 4 render layers, 5 end frame,
// 6 shadow properties, 7 async transforms (CompositorBridgeParent), 8 draw calls' time, 9 draw
// calls, 10 draws culled (CompositorOGL), 11 texture uploads' time (TextureHostOGL)
double gJihadPhase[12];
static bool
JihadPhases()
{
static const bool sOn = getenv("JIHAD_GPU_PHASES") != nullptr;
return sOn;
}
void
LayerManagerComposite::UpdateAndRender()
{
@@ -424,18 +483,38 @@ LayerManagerComposite::UpdateAndRender()
nsIntRegion opaque;
LayerIntRegion visible;
const TimeStamp jihadP0 = JihadPhases() ? TimeStamp::Now() : TimeStamp();
PostProcessLayers(mRoot, opaque, visible, Nothing());
if (JihadPhases()) gJihadPhase[0] += (TimeStamp::Now() - jihadP0).ToMilliseconds();
const TimeStamp jihadP1 = JihadPhases() ? TimeStamp::Now() : TimeStamp();
if (mClonedLayerTreeProperties) {
if (mClonedLayerTreeProperties && mJihadHoldBaseline) {
mRoot->ComputeEffectiveTransforms(getenv("JIHAD_GPU_NO_WORLD_ENGINE") ? gfx::Matrix4x4() : mJihadWorld); // T-503: no diff
didEffectiveTransforms = true;
} else if (mClonedLayerTreeProperties) {
// Effective transforms are needed by ComputeDifferences().
mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
mRoot->ComputeEffectiveTransforms(getenv("JIHAD_GPU_NO_WORLD_ENGINE") ? gfx::Matrix4x4() : mJihadWorld); // Jihad T-502: the identity unless set
didEffectiveTransforms = true;
// We need to compute layer tree differences even if we're not going to
// immediately use the resulting damage area, since ComputeDifferences
// is also responsible for invalidates intermediate surfaces in
// ContainerLayers.
JihadDiffScrollBegin(mJihadCompensateScroll && !mTarget, mJihadWorld._22); // Jihad T-502 round 115
nsIntRegion changed = mClonedLayerTreeProperties->ComputeDifferences(mRoot, nullptr, &mGeometryChanged);
JihadDiffScrollBegin(false, 1.0f);
// Jihad T-502 round 115: the diff is in the root layer's space; the frame is the world
// transform of it (the card's zoom), and the scissor and the rows read are frame pixels
if (!mTarget && !mJihadWorld.IsIdentity() && !changed.IsEmpty()) {
nsIntRegion scaled;
for (auto iter = changed.RectIter(); !iter.Done(); iter.Next()) {
const gfx::IntRect& r = iter.Get();
gfx::Rect fr = mJihadWorld.TransformBounds(gfx::Rect(r.x, r.y, r.width, r.height));
fr.RoundOut();
scaled.OrWith(gfx::IntRect(int32_t(fr.x), int32_t(fr.y), int32_t(fr.width), int32_t(fr.height)));
}
changed = Move(scaled);
}
if (mTarget) {
// Since we're composing to an external target, we're not going to use
@@ -459,13 +538,49 @@ LayerManagerComposite::UpdateAndRender()
// Add any additional invalid rects from the window manager or previous
// damage computed during ComposeToTarget().
invalid.Or(invalid, mInvalidRegion);
mInvalidRegion.SetEmpty();
if (!mJihadHoldBaseline) { // T-503: a verify composite leaves it for the next frame
invalid.Or(invalid, mInvalidRegion);
mInvalidRegion.SetEmpty();
}
}
// Jihad T-502: what the tree changed is reported as such; the rows the daemon will read are
// composed as well (a partial, scissored composite covers exactly the rows read back).
if (mJihadIgnoreDiff && !mTarget) {
invalid.SetEmpty();
mJihadLastChanged = gfx::IntRect();
} else {
// round 124: clipped to the frame before the bounds (two strips off the frame are not a change)
nsIntRegion onFrame;
onFrame.And(invalid, mRenderBounds);
mJihadLastChanged = onFrame.GetBounds();
}
mJihadPartialOn = false;
if ((!mJihadBand.IsEmpty() || !mJihadBand2.IsEmpty() || !mJihadBand3.IsEmpty() || mJihadRegionN > 0) && !mTarget) {
if (!mJihadBand.IsEmpty()) invalid.Or(invalid, mJihadBand);
if (!mJihadBand2.IsEmpty()) invalid.Or(invalid, mJihadBand2);
if (!mJihadBand3.IsEmpty()) invalid.Or(invalid, mJihadBand3);
for (int k = 0; k < mJihadRegionN; k++) invalid.Or(invalid, mJihadRegionRect[k]); // T-517
mJihadPartialOn = true;
} else if (!mTarget && !mJihadLastChanged.IsEmpty() && mClonedLayerTreeProperties &&
!invalid.Contains(mRenderBounds)) {
if (mJihadWholeRows) {
// T-505: a frame without its parts reads the changed rows whole (no column read, review D4): the
// composite covers them whole too, or the columns beside the change keep what the target held
// from its last composite (a frame with its parts: their pixels then pass for the page beneath
// them, and a later shift shows them; found 2026-11-02 on the long page's first shifted frame)
const gfx::IntRect b = invalid.GetBounds();
const gfx::IntRect rows = gfx::IntRect(mRenderBounds.x, b.y, mRenderBounds.width, b.height).Intersect(mRenderBounds);
invalid = nsIntRegion(rows);
mJihadLastChanged = rows;
}
mJihadPartialOn = true; // only what changed, when that is less than the frame
}
if (invalid.IsEmpty() && !mWindowOverlayChanged) {
// Composition requested, but nothing has changed. Don't do any work.
mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot());
if (!mJihadHoldBaseline) mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot());
mJihadLastInvalid = mJihadLastChanged = gfx::IntRect(); // Jihad T-502: nothing to read back
mJihadPartialOn = false;
return;
}
@@ -476,15 +591,17 @@ LayerManagerComposite::UpdateAndRender()
if (!didEffectiveTransforms) {
// The results of our drawing always go directly into a pixel buffer,
// so we don't need to pass any global transform here.
mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
mRoot->ComputeEffectiveTransforms(getenv("JIHAD_GPU_NO_WORLD_ENGINE") ? gfx::Matrix4x4() : mJihadWorld); // Jihad T-502: the identity unless set
}
mJihadLastInvalid = invalid.GetBounds(); // Jihad T-502
if (JihadPhases()) gJihadPhase[1] += (TimeStamp::Now() - jihadP1).ToMilliseconds();
Render(invalid, opaque);
mGeometryChanged = false;
mWindowOverlayChanged = false;
// Update cached layer tree information.
mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot());
if (!mJihadHoldBaseline) mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot()); // T-503
}
already_AddRefed<DrawTarget>
@@ -901,7 +1018,17 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegi
CompositorBench(mCompositor, bounds);
MOZ_ASSERT(mRoot->GetOpacity() == 1);
if (mRoot->GetClipRect()) {
const TimeStamp jihadB0 = JihadPhases() ? TimeStamp::Now() : TimeStamp();
if (mJihadPartialOn) {
// Jihad T-502: a partial composite, clipped (and cleared) to what is being read back
IntRect rect = aInvalidRegion.GetBounds().Intersect(bounds);
if (mRoot->GetClipRect()) {
const ParentLayerIntRect& rc = *mRoot->GetClipRect();
rect = rect.Intersect(IntRect(rc.x, rc.y, rc.width, rc.height));
}
clipRect = ParentLayerIntRect(rect.x, rect.y, rect.width, rect.height);
mCompositor->BeginFrame(aInvalidRegion, &rect, bounds, aOpaqueRegion, nullptr, &actualBounds);
} else if (mRoot->GetClipRect()) {
clipRect = *mRoot->GetClipRect();
IntRect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
mCompositor->BeginFrame(aInvalidRegion, &rect, bounds, aOpaqueRegion, nullptr, &actualBounds);
@@ -928,8 +1055,31 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegi
}
// Render our layers.
const TimeStamp jihadR0 = JihadPhases() ? TimeStamp::Now() : TimeStamp();
if (JihadPhases()) gJihadPhase[2] += (jihadR0 - jihadB0).ToMilliseconds();
if (mJihadRegionN > 0 && mJihadPartialOn) {
// T-517: the band frame's regions, each at its own world and inside its own rect, in this one
// frame: the transaction, the diff and BeginFrame/EndFrame once (a pass cost ~5 ms of CPU
// whatever it drew; a Wikipedia pan frame took four or five of them)
for (int k = 0; k < mJihadRegionN; k++) {
IntRect r = mJihadRegionRect[k].Intersect(IntRect(clipRect.x, clipRect.y, clipRect.width, clipRect.height));
if (r.IsEmpty()) continue;
mRoot->ComputeEffectiveTransforms(mJihadRegionWorld[k]);
const ParentLayerIntRect rc(r.x, r.y, r.width, r.height);
RootLayer()->Prepare(ViewAs<RenderTargetPixel>(rc, PixelCastJustification::RenderTargetIsParentLayerForRoot));
RootLayer()->RenderLayer(r);
}
mRoot->ComputeEffectiveTransforms(mJihadWorld); // the state the frame's other users expect
if (JihadPhases()) gJihadPhase[4] += (TimeStamp::Now() - jihadR0).ToMilliseconds();
} else {
RootLayer()->Prepare(ViewAs<RenderTargetPixel>(clipRect, PixelCastJustification::RenderTargetIsParentLayerForRoot));
const TimeStamp jihadR1 = JihadPhases() ? TimeStamp::Now() : TimeStamp();
RootLayer()->RenderLayer(clipRect.ToUnknownRect());
if (JihadPhases()) {
gJihadPhase[3] += (jihadR1 - jihadR0).ToMilliseconds();
gJihadPhase[4] += (TimeStamp::Now() - jihadR1).ToMilliseconds();
}
}
if (!mRegionToClear.IsEmpty()) {
for (auto iter = mRegionToClear.RectIter(); !iter.Done(); iter.Next()) {
@@ -955,7 +1105,9 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegi
PROFILER_LABEL("LayerManagerComposite", "EndFrame",
js::ProfileEntry::Category::GRAPHICS);
const TimeStamp jihadE0 = JihadPhases() ? TimeStamp::Now() : TimeStamp();
mCompositor->EndFrame();
if (JihadPhases()) gJihadPhase[5] += (TimeStamp::Now() - jihadE0).ToMilliseconds();
// Call after EndFrame()
mCompositor->SetDispAcquireFence(mRoot);
@@ -115,6 +115,46 @@ public:
MOZ_CRASH("GFX: Use EndTransaction(aTimeStamp)");
return false;
}
// Jihad T-502: a transform applied to the whole tree at the root (the card's zoom and the
// visual viewport's residual offset), through ComputeEffectiveTransforms so every clip and
// scissor follows it.
void JihadSetWorldTransform(const gfx::Matrix4x4& aMatrix) { mJihadWorld = aMatrix; }
// Jihad T-502: the bounds of what the last UpdateAndRender found changed (empty when it drew
// nothing), so the daemon reads back only the rows that moved.
const gfx::IntRect& JihadLastInvalid() const { return mJihadLastInvalid; } // what was composed
const gfx::IntRect& JihadLastChanged() const { return mJihadLastChanged; } // what the tree changed
void JihadResetLastInvalid() { mJihadLastInvalid = mJihadLastChanged = gfx::IntRect(); }
// The rows the daemon is about to read: composed (cleared and drawn, scissored) together
// with what the tree changed, and nothing else. Empty: only what changed.
// T-503: a verify composite keeps the diff baseline and the pending invalid region (the next
// real frame must see the changes the verify composite also drew)
void JihadHoldBaseline(bool aHold) { mJihadHoldBaseline = aHold; }
void JihadSetBand(const gfx::IntRect& aBand, const gfx::IntRect& aBand2 = gfx::IntRect(), const gfx::IntRect& aBand3 = gfx::IntRect()) { mJihadBand = aBand; mJihadBand2 = aBand2; mJihadBand3 = aBand3; }
// T-517: a band frame's regions composed in one frame (one transaction, one BeginFrame and
// EndFrame): region k is the layer tree at world aWorlds[k], drawn only inside aRects[k] (target
// pixels). aN 0 ends it. At most 12.
void JihadSetRegions(const gfx::Matrix4x4* aWorlds, const gfx::IntRect* aRects, int aN) {
mJihadRegionN = 0;
for (int k = 0; k < aN && k < 12; k++) { mJihadRegionWorld[k] = aWorlds[k]; mJihadRegionRect[k] = aRects[k]; mJihadRegionN++; }
}
// the card's scroll alone moved (an async transform on the root scroll frame's content, which
// the layer diff reports as the content's whole bounds): the diff is dropped, the bands asked
// for are composed and read
void JihadIgnoreDiff(bool aOn) { mJihadIgnoreDiff = aOn; }
// T-505: a frame without its parts is read back in whole rows (no column read): a partial composite
// of what the tree changed covers those rows across the frame's width, not the change's columns
void JihadWholeRows(bool aOn) { mJihadWholeRows = aOn; }
// round 115: the next diff treats the root-content layer's scroll as a shift (LayerTreeInvalidation.h)
void JihadCompensateScroll(bool aOn) { mJihadCompensateScroll = aOn; }
// round 119: the tree diff now, without a render (the stored tree refreshed as a composite
// would), in frame pixels; the caller has begun a transaction and applied the async transforms
nsIntRegion JihadDiffOnly();
// T-505: the visible regions and effective transforms as a composite would make them, without the diff (the
// stored tree untouched); the caller has begun a transaction and applied the async transforms
void JihadPrepareOnly();
void JihadEndTransactionNoComposite() { mInTransaction = false; }
bool JihadPartial() const { return mJihadPartialOn; }
virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
void* aCallbackData,
EndTransactionFlags aFlags = END_DEFAULT) override
@@ -353,6 +393,17 @@ private:
bool mUnusedApzTransformWarning;
bool mDisabledApzWarning;
RefPtr<Compositor> mCompositor;
gfx::Matrix4x4 mJihadWorld; // Jihad T-502
gfx::IntRect mJihadLastInvalid; // Jihad T-502
bool mJihadHoldBaseline = false;
gfx::IntRect mJihadLastChanged, mJihadBand, mJihadBand2, mJihadBand3; // Jihad T-502 (band 3: round 138's columns)
gfx::Matrix4x4 mJihadRegionWorld[12]; // T-517: JihadSetRegions
gfx::IntRect mJihadRegionRect[12];
int mJihadRegionN = 0;
bool mJihadIgnoreDiff = false;
bool mJihadWholeRows = false; // T-505: the rows read back are whole rows
bool mJihadCompensateScroll = false;
bool mJihadPartialOn = false; // this Render is a partial composite
UniquePtr<LayerProperties> mClonedLayerTreeProperties;
nsTArray<ImageCompositeNotification> mImageCompositeNotifications;
+19
View File
@@ -593,6 +593,25 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
}
tileDrawRegion.ScaleRoundOut(resolution, resolution);
{
// Jihad (T-517): a tile wholly outside the clip is not locked, bound or given an effect only
// for the compositor to drop its quad: a band frame's regions each met every tile of the page
// (a Wikipedia pan frame: five regions, ~30 tiles). JIHAD_GPU_NO_TILE_CULL=1 for A/B
static const bool sNoTileCull = getenv("JIHAD_GPU_NO_TILE_CULL") != nullptr;
// The clip is the current render target's own coordinates, the transform's result is not:
// the target's origin added, as the compositor's DrawQuad does (an intermediate surface, a
// layer with opacity, starts away from 0,0)
CompositingRenderTarget* target = mCompositor->GetCurrentRenderTarget();
if (!sNoTileCull && target && aTransform.Is2D()) {
const IntPoint origin = target->GetOrigin();
const IntRect tb = tileDrawRegion.GetBounds();
gfx::Rect onTarget = aTransform.TransformBounds(gfx::Rect(tb.x, tb.y, tb.width, tb.height));
onTarget.Inflate(1.0f);
if (!onTarget.Intersects(gfx::Rect(aClipRect.x + origin.x, aClipRect.y + origin.y, aClipRect.width, aClipRect.height))) {
continue;
}
}
}
RenderTile(tile, aEffectChain, aOpacity,
aTransform, aSamplingFilter, aClipRect, tileDrawRegion,
tileOffset * resolution, aLayerBuffer.GetTileSize(),
@@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CompositableTransactionParent.h"
#include <atomic> // Jihad T-505
#include "CompositableHost.h" // for CompositableParent, etc
#include "CompositorBridgeParent.h" // for CompositorBridgeParent
#include "GLContext.h" // for GLContext
@@ -29,6 +30,9 @@
namespace mozilla {
namespace layers {
extern std::atomic<uint32_t> gJihadPartsGen; // Jihad T-505, CompositorBridgeParent.cpp
void JihadReqNote(const char* aSrc); // Jihad T-505 diagnostic, CompositorBridgeParent.cpp
class ClientTiledLayerBuffer;
class Compositor;
@@ -54,6 +58,7 @@ ScheduleComposition(CompositableHost* aCompositable)
if (!cp) {
return false;
}
JihadReqNote("a compositable's update");
cp->ScheduleComposition();
return true;
}
@@ -68,6 +73,11 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
if (compositable->GetCompositor() && !compositable->GetCompositor()->IsValid()) {
return true;
}
// Jihad T-505: an update to a layer under a fixed or sticky one moves the parts' generation (the daemon composes
// the page's fixed and sticky parts alone again when it moves: they changed)
for (Layer* l = compositable->GetLayer(); l; l = l->GetParent()) {
if (l->GetIsFixedPosition() || l->GetIsStickyPosition()) { ++gJihadPartsGen; break; }
}
switch (aEdit.detail().type()) {
case CompositableOperationDetail::TOpPaintTextureRegion: {
File diff suppressed because it is too large. Load diff
+39
View File
@@ -20,6 +20,7 @@
#include "mozilla/Attributes.h" // for override
#include "mozilla/Maybe.h"
#include "mozilla/Monitor.h" // for Monitor
#include "mozilla/Atomics.h" // Jihad T-502
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/TimeStamp.h" // for TimeStamp
#include "mozilla/dom/ipc/IdType.h"
@@ -61,6 +62,7 @@ class APZCTreeManager;
class APZCTreeManagerParent;
class AsyncCompositionManager;
class Compositor;
struct JihadFrameRequest; // Jihad T-502, CompositorOGL.h
class CompositorBridgeParent;
class LayerManagerComposite;
class LayerTransactionParent;
@@ -108,6 +110,8 @@ public:
bool NeedsComposite();
void Composite(TimeStamp aVsyncTimestamp);
void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect);
// Jihad T-502 (pull mode): composites asked for and not run; the daemon pulls a frame when it moves.
uint32_t JihadRequests() const { return mJihadRequests; }
const TimeStamp& GetLastComposeTime()
{
@@ -122,6 +126,7 @@ public:
#endif
private:
mozilla::Atomic<uint32_t> mJihadRequests{0}; // Jihad T-502
virtual ~CompositorVsyncScheduler();
void NotifyCompositeTaskExecuted();
@@ -516,6 +521,40 @@ public:
void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr);
// Jihad T-502: the scheduler's request count (any thread), and the frame pulled on the
// compositor thread: compose to the window (the pbuffer / renderbuffer) and read it into
// aDest (B8G8R8A8, aStride bytes a row, the top-left aWidth x aHeight of the frame).
uint32_t JihadRequests() const;
// Reads back rows [aRowLo, aRowHi) (0,0 = none asked for) joined with the rows the composite
// changed, which it reports in aInvLo/aInvHi (0,0 = nothing changed).
// Composes into the free window target and hands the read of rows [aReq->lo, aReq->hi)
// (0,0 = none asked for), joined with the rows the composite changed (left in lo/hi, the
// change alone in invLo/invHi), to the read thread; aReq->done runs when the frame is in
// aReq->dest. False: nothing was started.
bool JihadComposeAndRead(JihadFrameRequest* aReq, float aScale, float aOffsetX, float aOffsetY);
nsIntRegion JihadDiffNow(); // round 119: the tree diff without a render (frame pixels)
gfx::Matrix4x4 mJihadLastWorld; // Jihad T-502: the view the last composite was made with
float mJihadLastScrollX = 0.0f, mJihadLastScrollY = 0.0f;
bool mJihadLastScrollValid = false;
uint32_t mJihadSeqAtLast = 0; // the scheduler's request count when the last composite began
int mJihadLastFixedLo = 0, mJihadLastFixedHi = 0; // the fixed rows as last computed on a whole composite
// round 138: the fixed and stuck layers' rects on the frame, as last computed (at most four)
gfx::IntRect mJihadLastFixedRects[4];
int mJihadLastFixedN = 0;
// round 141: per rect, the pixels an opaque layer covers (empty when not opaque), and the keeps
// of the composite before the last (a keep must have held still)
gfx::IntRect mJihadLastKeep[4], mJihadPrevKeep[4];
int mJihadPrevKeepN = 0;
void JihadHideForJob(); // Jihad T-504/T-505: the overview's and a content-only frame's layers hidden
// Jihad T-505 (E2): the parts' signature (their layers, content, attributes and sizes); *aCovered when a content
// layer is drawn above a part (the daemon cannot draw that part over the frame)
uint32_t JihadPartsSig(const gfx::IntRect* aRects, int aN, bool* aCovered, int aWidth, int aHeight);
int JihadFixedRectsNow(int aWidth, int aHeight, gfx::IntRect* aOut, gfx::IntRect* aKeep);
void JihadUpdateLastFixed(int aWidth, int aHeight);
bool mJihadSeqKnown = false;
gfx::IntSize mJihadLastSize;
bool mJihadWorldKnown = false;
PAPZCTreeManagerParent* AllocPAPZCTreeManagerParent(const uint64_t& aLayersId) override;
bool DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor) override;
+33
View File
@@ -3,6 +3,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <sys/time.h> // Jihad T-517: the timeline's clock
#include <stdint.h>
#include <atomic>
namespace mozilla { namespace gl { extern std::atomic<uint32_t> gJihadUploads; extern std::atomic<uint64_t> gJihadUploadUs; } } // GLUploadHelpers.cpp
#include "LayerTransactionParent.h"
#include <vector> // for vector
#include "apz/src/AsyncPanZoomController.h"
@@ -265,6 +269,29 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
PROFILER_LABEL("LayerTransactionParent", "RecvUpdate",
js::ProfileEntry::Category::GRAPHICS);
// Jihad (T-517): with JIHAD_GPU_TIMELINE a transaction that holds the compositor thread 3 ms or
// more is on the daemon's timeline (the express lane's frames queue behind it)
struct JihadTxnTimer {
mozilla::TimeStamp t0 = mozilla::TimeStamp::Now();
size_t edits = 0;
double compMs = 0, updatedMs = 0, endMs = 0; // the compositable ops, ShadowLayersUpdated, EndTransaction
uint32_t up0 = gl::gJihadUploads;
uint64_t upUs0 = gl::gJihadUploadUs;
~JihadTxnTimer() {
static const bool sOn = getenv("JIHAD_GPU_TIMELINE") != nullptr;
if (!sOn) return;
const double ms = (mozilla::TimeStamp::Now() - t0).ToMilliseconds();
if (ms < 3.0) return;
struct timeval tv;
gettimeofday(&tv, nullptr);
fprintf(stderr, "[jihad-tl] t=%lld layer transaction on the compositor thread: %.1f ms, %zu edits "
"(compositable ops %.1f, %u uploads %.1f; layers updated %.1f; end %.1f; the rest %.1f)\n",
(long long)tv.tv_sec * 1000 + tv.tv_usec / 1000, ms, edits, compMs, gl::gJihadUploads - up0,
(gl::gJihadUploadUs - upUs0) / 1000.0, updatedMs, endMs, ms - compMs - updatedMs - endMs);
}
} jihadTxnTimer;
jihadTxnTimer.edits = cset.Length();
#ifdef COMPOSITOR_PERFORMANCE_WARNING
TimeStamp updateStart = TimeStamp::Now();
#endif
@@ -625,10 +652,12 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
break;
}
case Edit::TCompositableOperation: {
const TimeStamp jihadC0 = TimeStamp::Now();
if (!ReceiveCompositableUpdate(edit.get_CompositableOperation(),
replyv)) {
return false;
}
jihadTxnTimer.compMs += (TimeStamp::Now() - jihadC0).ToMilliseconds();
break;
}
case Edit::TOpAttachCompositable: {
@@ -669,15 +698,19 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
}
}
const TimeStamp jihadU0 = TimeStamp::Now();
mCompositorBridge->ShadowLayersUpdated(this, aTransactionId, targetConfig,
aPlugins, isFirstPaint, scheduleComposite,
paintSequenceNumber, isRepeatTransaction,
aPaintSyncId, updateHitTestingTree);
const TimeStamp jihadU1 = TimeStamp::Now();
jihadTxnTimer.updatedMs = (jihadU1 - jihadU0).ToMilliseconds();
{
AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this));
layer_manager()->EndTransaction(TimeStamp(), LayerManager::END_NO_IMMEDIATE_REDRAW);
}
jihadTxnTimer.endMs = (TimeStamp::Now() - jihadU1).ToMilliseconds();
if (reply) {
reply->SetCapacity(replyv.size());
@@ -19,7 +19,12 @@ CompositingRenderTargetOGL::~CompositingRenderTargetOGL()
{
if (mGL && mGL->MakeCurrent()) {
mGL->fDeleteTextures(1, &mTextureHandle);
mGL->fDeleteFramebuffers(1, &mFBO);
// Jihad T-502: the window target made for each frame borrows the compositor's renderbuffer
// FBO; deleting it here (harmless for FBO 0) killed the target after the first frame and
// every later composite drew into nothing (black frames, rounds 6-16).
if (!mJihadBorrowedFBO) {
mGL->fDeleteFramebuffers(1, &mFBO);
}
}
}
@@ -97,10 +97,12 @@ public:
*/
static already_AddRefed<CompositingRenderTargetOGL>
RenderTargetForWindow(CompositorOGL* aCompositor,
const gfx::IntSize& aSize)
const gfx::IntSize& aSize,
GLuint aFBO = 0) // Jihad T-502: the renderbuffer FBO that stands for the window
{
RefPtr<CompositingRenderTargetOGL> result
= new CompositingRenderTargetOGL(aCompositor, gfx::IntPoint(), 0, 0);
= new CompositingRenderTargetOGL(aCompositor, gfx::IntPoint(), 0, aFBO);
result->mJihadBorrowedFBO = (aFBO != 0); // the compositor's, not this target's to delete
result->mInitParams = InitParams(aSize, aSize, 0, INIT_MODE_NONE);
result->mInitParams.mStatus = InitParams::INITIALIZED;
return result.forget();
@@ -129,7 +131,9 @@ public:
*/
void BindRenderTarget();
bool IsWindow() { return GetFBO() == 0; }
// Jihad T-502: the compositor's renderbuffer FBO stands for the window, with the window's
// conventions (render offset, no y-flip of intermediate surfaces drawn back into it).
bool IsWindow() { return GetFBO() == 0 || mJihadBorrowedFBO; }
GLuint GetFBO() const
{
@@ -187,6 +191,7 @@ private:
RefPtr<GLContext> mGL;
GLuint mTextureHandle;
GLuint mFBO;
bool mJihadBorrowedFBO = false; // Jihad T-502: a window FBO the compositor owns
};
} // namespace layers
File diff suppressed because it is too large. Load diff
Loaded 100 of 263 files, more files were not shown because too many files have changed in this diff. Show more