Commit Graph

24 Commits

Author SHA1 Message Date
Thomas Cummings
ffb91ac4b1 script: Evict stale SVGs from image cache (#41675)
Parsed and vectorized representations of SVGs in the image cache are
never evicted when SVGs are updated, leading to stale SVGs staying in
the image cache alongside updated ones. This PR:
- adds a stringified uuid field to SVGSVGElement
- adds a map of `SVGSVGElement` uuid to `PendingImageId` in
`ImageCacheImpl`
- adds an optional argument for the uuid to
`ImageCacheImpl::rasterize_vector_image`, which, if provided, removes
any existing parsed svgs associated with the uuid and stores a new entry
of uuid -> `PendingImageId`
- implements `unbind_from_tree` on SVGSVGElement, which clears the
associated images/representations from the image_cache (from
`vector_images`, `rasterized_vector_images`, and `completed_loads`) as
well as from the layout image resolver image cache.

Testing: Each of the following documents should display their (very
flashy) content correctly and memory usage should stay constant
<details>
<summary>Changing SVGSVGElement</summary>

```

<svg height="100" width="100" xmlns="http://www.w3.org/2000/svg">
  <circle id="c" r="1" cx="50" cy="50" fill="red" />
</svg>
<script>
let c = document.querySelector("#c");
let r = 1;
setInterval(() => {
  r += 1;
  c.setAttribute("r", r.toString());
  let tmp = document.createTextNode("ignored");
  c.parentNode.appendChild(tmp);
  tmp.remove();
}, 100);
</script>

```

</details>
<details>
<summary>Unbinding SVGSVGElements</summary>

```

<div id="parent_div">
  <svg id="test" height="100" width="100" xmlns="http://www.w3.org/2000/svg">
    <circle id="c" r="10" cx="50" cy="50" fill="red" />
  </svg>
</div>
<script>
  let div = document.querySelector("#parent_div");
  let svg_html_string = div.innerHTML;
  let svg = document.querySelector("#test");
  let r = 10;
  setInterval(() => {
    svg.remove();
    div.innerHTML = svg_html_string;
    svg = document.querySelector("#test");
    let circle = document.querySelector("#c");
    r += 1;
    circle.setAttribute("r", r.toString());
  }, 100);
</script>

```

</details>
<details>
<summary>Unbinding SVGSVGElements (and rebinding the same SVG)</summary>

This didn't work until I also evicted the associated image from the
layout image resolver image cache and the image cache's
`completed_loads` on SVGSVGElement unbind, so it seems like a useful, if
a bit redundant, test.

```

<div id="parent_div">
  <svg id="test" height="100" width="100" xmlns="http://www.w3.org/2000/svg">
    <circle id="c" r="10" cx="50" cy="50" fill="red" />
  </svg>
</div>
<script>
  let div = document.querySelector("#parent_div");
  let svg_html_string = div.innerHTML;
  let svg = document.querySelector("#test");
  let r = 10;
  setInterval(() => {
    svg.remove();
    div.innerHTML = svg_html_string;
    svg = document.querySelector("#test");
  }, 100);
</script>

```

</details>

Fixes: #41070

---------

Signed-off-by: Tom Cummings <cummings.t287@gmail.com>
2026-01-26 06:02:50 +00:00
Martin Robinson
9c9d9c863f Rename compositing and compositing_traits to paint and paint_api (#42066)
This change finishes the big rename associated with the old
`compositing` crates. Long ago, these crates managed a compositor, like
you might find in a traditional web engine. These days, compositing is
done in WebRender so the name has stopped making much sense. Various
structs inside the crates have already been renamed and this is the
final big change necessary for the rename

Testing: This is just a rename so existing tests should cover it.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2026-01-24 09:17:35 +00:00
WaterWhisperer
85c33a9dcc net: Track fontdb allocations from SVG images by about:memory (#41254)
- make `ImageCache::memory_report` return `Vec<Report>` and rename
`memory_report` to `memory_reports`
- update `ImageCacheImpl::memory_report` to return a new Report for the
fontdb member
- add an implementation of `MallocSizeOf` for `fontdb::FaceInfo` which
sums the result of calling malloc_size_of on each of the string/vector
members
- add an implementation of `MallocSizeOf` for `fontdb::Database` which
sums the result of malloc_size_of on each of the faces

Testing: `./mach check` `./mach clippy`
`grep fontdb::Database::load_fonts_from_file untracked | wc -l` results:
2390 -> 545
- before:
<img width="1536" height="108" alt="截图 2025-12-14 13-53-32"
src="https://github.com/user-attachments/assets/422ce9d4-e962-45af-a072-7d1c0c9e80aa"
/>

- now:
<img width="1536" height="108" alt="截图 2025-12-14 13-58-26"
src="https://github.com/user-attachments/assets/363f933d-8ab0-4354-b8ae-89f6de46ca7b"
/>

Fixes: #38730

Signed-off-by: WaterWhisperer <waterwhisperer24@qq.com>
2025-12-14 06:46:37 +00:00
Martin Robinson
824f551f03 Rename IOCompositor to Paint (#41176)
For a long time, the "Compositor" hasn't done any compositing. This is
handled by WebRender. In addition the "Compositor" does many other
tasks. This change renames `IOCompositor` to `Paint`.

`Paint` is Servo's paint subsystem and contains multiple `Painter`s.
This change does not rename the crate; that will be done in a
followup change.

Testing: This just renames types and updates comments, so no new tests
are necessary.

---------

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2025-12-10 15:09:49 +00:00
Narfinger
3bfd107686 net: Do not implement Serialize/Deserialize for RasterImage and introduce`SharedRasterImage (#40459)
RasterImage is now not seralizeable and backed by Vec<u8> storage. Add a
new struct `SharedRasterImage` that allows serializeing. This can be
constructed from RasterImage. This introduces some more copying but I
think the tradeoff is ok. Newly introduced copies are for favicon
response to the embedder and EmbedderNotifications.

Testing: Should not change functionality, so covered by existing tests.
Fixes: https://github.com/servo/servo/issues/39626 and related issues.

---------

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
2025-11-07 16:49:32 +00:00
Martin Robinson
bdcae320fd net: Use callbacks instead of IPC channels in the ImageCache API (#40453)
Previously, the `ImageCache` would inform consumers of changes to image
availability by messaging an IPC channel. This isn't great, because it
requires serialization and deserialization. Nowadays, `ImageCache`s are
always owned by the same `Global` that uses them. This change replaces
the IPC channel with callback that implements `Send`.

For the case of normal HTML document images, the results are still sent
over the pre-existing Crossbeam channel that was connected via an IPC
route. A followup change might eliminate that channel entirely.

Testing: This should not change observable behavior so is covered by
existing tests.
Fixes: #24338.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Mukilan Thiyagarajan <mukilan@igalia.com>
2025-11-06 12:52:40 +00:00
Martin Robinson
f08460cded script: Handle broken image icon in HTMLImageElement (#40429)
Instead of having the `ImageCache` return the broken image icon for
failed loads, have `HTMLImageElement` explicitly request it. This means
that the image is loaded on demand (reducing the usage of resources) and
also simplifying the interface of the `ImageCache` greatly.

In addition, the display of the broken image icon is improved, more
closely matching other browsers. A test for this display (which was
falsely passing before) is updated to reflect the new display of the
broken image icon.

Testing: There is a Servo-specific test for this change. Some WPT tests
start to fail as well. Before these were not properly loading the broken
image icon so they were failing before, just in a hidden way.

---------

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Mukilan Thiyagarajan <mukilan@igalia.com>
2025-11-06 09:36:21 +00:00
Martin Robinson
9fa6303d26 script: Let HTMLCanvasElement manage the ImageKey for canvases (#40375)
This change makes it so that the `HTMLCanvasElement` is responsible for
managing the `ImageKey` for associated `RenderingContext`s. Only
canvases display their contents into WebRender directly, so this makes
it so that keys are not generated for `OffscreenCanvas`.

The main goal here is that `ImageKey`s are always associated with a
particular `WebView`, which isn't possible in the various canvas
backends yet. This is important because each `WebView` may soon have a
different WebRender instance entirely with its own set of `ImageKey`s.

This also allows for clearing `ImageKey`s when canvases are disconnected
from the DOM in a future change. One tricky thing here is placeholder
canvases, which are meant to be driven from workers.

It seems that the implementation isn't correct for these at the moment
as they need to be updated to the specification. Instead, what is
happening is that any existing context / image is completely lost when
converting to an `OffscreenCanvas`.

Testing: This shouldn't change observable behavior, so is covered by
existing tests.
Fixes: This is part of #40261.

---------

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
Co-authored-by: Mukilan Thiyagarajan <mukilan@igalia.com>
2025-11-04 12:18:30 +00:00
Martin Robinson
eed97f458b net: Associate every ImageCache with a WebView (#40376)
Every `ImageCache` should be assigned a `Pipeline` and a `WebView`, so
that it knows what WebRender instance to create image keys in. This
change accomplishes that by splitting the `ImageCache` trait into
`ImageCache` and `ImageCacheFactory`. There should only be one
`ImageCacheFactory` per process.

Testing: This should not change observable behavior and is thus covered
by
existing tests.

Fixes: This is part of #40261.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2025-11-04 08:26:05 +00:00
Narfinger
ca47cc2fa3 Add a basic caching mechanism for ImageKeys. (#37369)
This creates a new method in shared/compositing/lib to generate image
keys that are send over the webview. This does not immediately return
the keys but goes over the constellation to receive the keys from the
IOCompositor. To make this more efficient, we now cache the keys in
image_cache in a simple FIFO order. The old blocking method stays intact
for now but got renamed to make the blocking clear.
The blocking calls that are left are in:
- `components/canvas/canvas_data.rs`
- `components/script/dom/htmlmediaelement.rs`

Testing: WPT tests should cover this as this doesn't change any
functionality.
Fixes: Was mentioned in
https://github.com/servo/servo/issues/37161#issuecomment-2915750051 and
part of https://github.com/servo/servo/issues/37086

---------

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>
Co-authored-by: gterzian <2792687+gterzian@users.noreply.github.com>
2025-07-03 13:16:43 +00:00
Mukilan Thiyagarajan
8a20e42de4 Add support for static SVG images using resvg crate (#36721)
This change adds support for rendering static SVG images using the
`resvg` crate, allowing svg sources in the `img` tag and in CSS
`background` and `content` properties. There are some limitations in
using resvg:

1. There is no support for animations or interactivity as these would
require implementing the full DOM layer of SVG specification.
2. Only system fonts can be used for text rendering. There is some
mechanism to provide a custom font resolver to usvg, but that is not
explored in this change.
3. resvg's handling of certain edge cases involving lack of explicit
`width` and `height` on the root svg element deviates from what the
specification expects from browsers. For example, resvg uses the values
in `viewBox` to derive the missing width or height dimension, but
without scaling that dimension to preserve the aspect ratio. It also
doesn't allow overriding this behavior.

Demo screenshot:
![servo - resvg
img](https://github.com/user-attachments/assets/8ecb2de2-ab7c-48e2-9f08-2d09d2cb8791)

<details>
<summary>Source</summary>

```
<style>
 #svg1 {
   border: 1px solid red;
 }

 #svg2 {
   border: 1px solid red;
   width: 300px;
 }
 #svg3 {
   border: 1px solid red;
   width: 300px;
   height: 200px;
   object-fit: contain;
 }
 #svg4 {
   border: 1px solid red;
   width: 300px;
   height: 200px;
   object-fit: cover;
 }
 #svg5 {
   border: 1px solid red;
   width: 300px;
   height: 200px;
   object-fit: fill;
 }
 #svg6 {
   border: 1px solid red;
   width: 300px;
   height: 200px;
   object-fit: none;
 }
</style>
</head>
<body>
        <div>
          <img id="svg1" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo">
        </div>
        <div>
          <img id="svg2" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo">
          <img id="svg3" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo">
          <img id="svg4" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo">
        </div>
        <div>
          <img id="svg5" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo">
          <img id="svg6" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo">
        </div>
</body>
```

</details>

---------

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
2025-05-27 11:02:40 +00:00
Tim van der Lippe
8a837778d9 Create new image cache per document (#36832)
Rather than sharing the full image cache in a script_thread, the image
cache is now unique per document. This ensures that CSP factors no
longer affect whether the image is retrieved from the cache incorrectly.

To do so, the thread_pool is shared across all caches, but the store is
fresh. Except for the place_holder{image,url}, which are cloned. That's
because the `rippy_data` is only available in the constellation and no
longer accessible at the point that we need to create the document in
the script_thread.

Contrary to the description in #36505, the script_thread still has an
image_cache for this reason: so it has access to the store and
thread_pool to clone it.

With these changes, the two CSP tests no longer flake. Confirmed with
running the following commmand:

```
./mach test-wpt tests/wpt/tests/content-security-policy/generic/ --rerun=10
```

Fixes #36505

Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
2025-05-04 20:20:56 +00:00
Josh Matthews
5e2d42e944 Refactor common infrastructure for creating memory reports. (#36579)
This removes a bunch of duplicated code needed to support
ConditionalMallocSizeOf correctly, and fixes multiple places where that
code was subtly wrong (the seen pointers hashset was never cleared).

Testing: Measuring https://www.nist.gov/image-gallery lots of times.

Signed-off-by: Josh Matthews <josh@joshmatthews.net>
2025-04-18 02:14:49 +00:00
Josh Matthews
afe98e9e1e net: Report memory usage for image cache. (#36556)
These changes add a new report for image cache memory usage for each
script thread.

Testing: Looked at the numbers after browsing various stock photo sites
that show galleries of images.

Signed-off-by: Josh Matthews <josh@joshmatthews.net>
2025-04-16 13:11:51 +00:00
Martin Robinson
0caa271176 compositing: Combine webrender_traits and compositing_traits (#36372)
These two traits both exposed different parts of the compositing API,
but now that the compositor doesn't depend directly on `script` any
longer and the `script_traits` crate has been split into the
`constellation_traits` crate, this can be finally be cleaned up without
causing circular dependencies. In addition, some unit tests for the
`IOPCompositor`'s scroll node tree are also moved into
`compositing_traits` as well.

Testing: This just combines two crates, so no new tests are necessary.
Fixes: #35984.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2025-04-06 17:34:18 +00:00
Simon Wülker
3d320fa96a Update rustfmt to the 2024 style edition (#35764)
* Use 2024 style edition

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>

* Reformat all code

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>

---------

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
2025-03-03 11:26:53 +00:00
Martin Robinson
37695c8c8c script: Do not set up an IPC route for every image load (#35041)
Instead of setting up a route for every image load in the DOM / Layout,
route all incoming image cache responses through the `ScriptThread`.
This avoids creating a set of file descriptor for every image that is
loaded.

This change requires having the `ImageCache` track the `PipelineId` of
the original the listener so that the `ScriptThread` can route it
properly to the correct `Window`.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2025-01-25 09:39:04 +00:00
Josh Matthews
2115b6a6db net: Raed RippyPNG resource once at startup. (#34954)
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
2025-01-12 01:42:24 +00:00
Martin Robinson
9195344b75 compositor: Create a single cross-process compositor API (#33619) (#33660)
Instead of exposing many different kinds of messages to the compositor
that are routed through the constellation, expose a single message type
which can be sent across IPC channels. In addition, this IPC channel and
the route to the crossbeam channel with the compositor is created along
with the `CompositorProxy`, simplifying what needs to be passed around
during pipeline initialization.

Previously, some image updates (from video) were sent over IPC with a
special serialization routine and some were sent via crossbeam channels
(canvas). Now all updates go over the IPC channel `IpcSharedMemory` is
used to avoid serialization penalties. This should improve performance
and reduce copies for video, but add a memory copy overhead for canvas.
This will improve in the future when canvas renders directly into a
texture.

All-in-all this is a simplification which opens the path toward having a
standard compositor API and reduces the number of duplicate messages and
proxying that had to happen in libservo.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2024-10-09 17:30:24 +00:00
Martin Robinson
48f8ff6236 Revert "compositor: Create a single cross-process compositor API (#33619)" (#33645)
This reverts commit f2f5614ad6.

This is causing intermittent crashes: https://github.com/servo/servo/actions/runs/11167043809/job/31044255019

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2024-10-04 09:08:19 +00:00
Martin Robinson
f2f5614ad6 compositor: Create a single cross-process compositor API (#33619)
Instead of exposing many different kinds of messages to the compositor
that are routed through the constellation, expose a single message type
which can be sent across IPC channels. In addition, this IPC channel and
the route to the crossbeam channel with the compositor is created along
with the `CompositorProxy`, simplifying what needs to be passed around
during pipeline initialization.

Previously, some image updates (from video) were sent over IPC with a
special serialization routine and some were sent via crossbeam channels
(canvas). Now all updates go over the IPC channel `IpcSharedMemory` is
used to avoid serialization penalties. This should improve performance
and reduce copies for video, but add a memory copy overhead for canvas.
This will improve in the future when canvas renders directly into a
texture.

All-in-all this is a simplification which opens the path toward having a
standard compositor API and reduces the number of duplicate messages and
proxying that had to happen in libservo.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2024-10-03 14:42:04 +00:00
Mukilan Thiyagarajan
2af6fe0b30 compositor: Move WebRender-ish messages and types to webrender_traits (#32315)
* Move WebRender related types to `webrender_traits`

This refactor moves several WebRender related types
from `compositing_traits`, `script_traits` and `net_traits`
crates to the `webrender_traits` crate.

This change also moves the `Image` type and associated
function out of `net_traits` and into the `pixels` crate.

Co-authored-by: Martin Robinson <mrobinson@igalia.com>
Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>

* Move `script_traits::WebrenderIpcSender` to `webrender_traits::WebRenderScriptApi`

---------

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
2024-05-20 10:35:18 +00:00
eri
43f44965cd clippy: fix warnings in components/shared (#31565)
* clippy: fix some warnings in components/shared

* fix: unit tests

* fix: review comments
2024-03-08 15:28:19 +00:00
Martin Robinson
f4d3af296c Move *_traits and other shared types to shared
This is the start of the organization of types that are in their own
crates in order to break dependency cycles between other crates. The
idea here is that putting these packages into their own directory is the
first step toward cleaning them up. They have grown organically and it
is difficult to explain to new folks where to put new shared types. Many
of these crates contain more than traits or don't contain traits at all.

Notably, `script_traits` isn't touched because it is vendored from
Gecko. Eventually this will move to `third_party`.
2023-11-03 15:38:18 +00:00