# Try to contribute to opensource #1 librsvg

I have noticed that someone wants newbie help for some open source from a local community member.

I follow the link to Mustodon's [post](https://mstdn.mx/@mrkz/110579468250285868).

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1688048693711/5948c58e-28af-44d2-aff3-98c142db2cbc.png align="center")

found out that it was a librsvg issue on the gnome GitLab repository that has hashtag for `rust newbies`. It will be good for me since I was new to the project.

## Read the docs

I was surprised by the [document pages](https://gnome.pages.gitlab.gnome.org/librsvg/devel-docs/index.html) that were so informative.

## Use on mac

### Local machine

I start out by using `git clone` to a Mac m1 since the architecture was different from the [GETTING STARTED AS A CONTRIBUTOR - Setting up your development environment](https://gnome.pages.gitlab.gnome.org/librsvg/devel-docs/devel_environment.html#build) that using x86\_64 and openSUSE Tumbleweed, I was curious that could it be buildable on the local machine.

I couldn't build on the local machine due to the version of dependency for the setup development environment. As I'm writing this the development environment requires `cairo` as a system library with version 1.17 or above but the machine has `cairo` with version 1.16.0 via brew installed via brew.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1688049634682/64306e15-bf1b-41f4-af34-20471c111e14.png align="center")

```plaintext
$ cargo test
  --- stderr
  `PKG_CONFIG_ALLOW_SYSTEM_CFLAGS="1" "pkg-config" "--libs" "--cflags" "cairo" "cairo >= 1.17"` did not exit successfully: exit status: 1
  error: could not find system library 'cairo' required by the 'librsvg' crate

  --- stderr
  Requested 'cairo >= 1.17' but version of cairo is 1.16.0

warning: build failed, waiting for other jobs to finish...

librsvg > brew install cairo@1.17.2
Warning: No available formula with the name "cairo@1.17.2". Did you mean cairomm@1.14?
==> Searching for similarly named formulae and casks...
```

I don't want to mess with the local machine packages so I try to use `podman` as development.

### Podman

Start with installing `podman` with brew.

```bash
$ brew install podman
==> Fetching podman
...
==> Pouring podman--4.5.1.arm64_monterey.bottle.tar.gz
```

Setup initial machine on `podman`.

```bash
$ podman machine init
Downloading VM image: fedora-coreos-38.20230609.2.1-qemu.aarch64.qcow2.xz: done
Extracting compressed file
Image resized.
Machine init complete
```

```bash
$ podman machine start
```

Pull machine for `librsvg` development.

```bash
$ sh ci/pull-container-image.sh
full_tag="x86_64-1.68.2-2023-05-03.0-main"
pulling image registry.gitlab.gnome.org/gnome/librsvg/opensuse/tumbleweed:x86_64-1.68.2-2023-05-03.0-main
...
WARNING: image platform (linux/amd64) does not match the expected platform (linux/arm64)
...
You can now run this:
  podman run --rm -ti --cap-add=SYS_PTRACE -v $(pwd):/srv/project -w /srv/project registry.gitlab.gnome.org/gnome/librsvg/opensuse/tumbleweed:x86_64-1.68.2-2023-05-03.0-main

Don't forget to run this once inside the container:
  source ci/env.sh
```

After I run as the command output, I got an error when using the test. It seems to be a container failed to connect a network error message.

```bash
$ podman run --rm -ti --cap-add=SYS_PTRACE -v $(pwd):/srv/project -w /srv/project registry.gitlab.gnome.org/gnome/librsvg/opensuse/tumbleweed:x86_64-1.68.2-2023-05-03.0-main
:/srv/project # source ci/env.sh
:/srv/project # cargo test
    Updating crates.io index
warning: spurious network error (2 tries remaining): failed to mmap. Could not write data: Invalid argument; class=Os (2)
warning: spurious network error (1 tries remaining): failed to mmap. Could not write data: Invalid argument; class=Os (2)
error: Unable to update registry `crates-io`
```

I find this [issue](https://github.com/containers/podman/issues/10012) that could fix it with specifying `slirp4netns:port_handler=slirp4netns` as the network option value.

```bash
$ podman run --rm -ti --network=slirp4netns:port_handler=slirp4netns --cap-add=SYS_PTRACE -v $(pwd):/srv/project -w /srv/project registry.gitlab.gnome.org/gnome/librsvg/opensuse/tumbleweed:x86_64-1.68.2-2023-05-03.0-main
```

A build-in git seems a bit off so I use executable instead.

```bash
:/srv/project # source ci/env.sh
:/srv/project # cargo test
    Updating crates.io index
warning: spurious network error (1 tries remaining): failed to resolve address for github.com: Name or service not known; class=Net (12)
```

After setup for a while, I could run a test but I got the error message after that.

```bash
:/srv/project # source ci/env.sh
:/srv/project # CARGO_NET_GIT_FETCH_WITH_CLI=true cargo test
error[E0786]: found invalid metadata files for crate `itertools`
 --> rsvg/src/space.rs:3:5
  |
3 | use itertools::Itertools;
  |     ^^^^^^^^^
  |
  = note: failed to mmap rmeta metadata: '/srv/project/target/debug/deps/libitertools-72978d5f52e1ee56.rmeta'

error: could not compile `librsvg` due to previous error
```

## Setup VM

I was concerned that it might be an architecture or package on architecture problem so I switched to using VMware on the x86\_64 machine.

* Download the latest [Opensesu Tumbleweed](https://get.opensuse.org/tumbleweed/) with x86\_64 architecture.
    
* Open a new machine with ram 8 gb as recommended.
    
* I used 50 GB disk space since it will expand to this cap when I use up more space.
    
* I use Gnome as a display manager.
    

After the machine was up I install dependency as a guide but I want to use rustup to install formatter so I install `rustup` instead of `rust rust-std cargo`. I couldn't install `python38-docutils` so I removed it.

```bash
sudo zypper install -y gcc rustup make \
automake autoconf libtool python3-gi-docgen git \
gdk-pixbuf-devel gobject-introspection-devel \
libxml2-devel cairo-devel pango-devel
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1688049714276/d7ddf81e-6efa-44e8-b153-42741f3c04fc.png align="center")

Use rustup to set the default toolchain.

```bash
rustup default stable
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1688049744004/58ed8ea4-b2cc-421b-90f0-80df0e66600f.png align="center")

## Clone to VMware

After installing packages, I clone the repository and then test. It worked!

```bash
git clone https://gitlab.gnome.org/GNOME/librsvg
cargo test
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1688049780931/13d9011a-ae8a-414a-8826-3994b75895ea.png align="center")

## Read the issue

The issue seems to involve rendering new property for SVG image tag with cairo's library.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1688049802000/5b851ae8-b114-4537-9a41-66b255d26a49.png align="center")

## Follow contribute guide

I set up neovim and tmux a bit in the machine and make changes following the [contribution guide](https://gnome.pages.gitlab.gnome.org/librsvg/devel-docs/adding_a_property.html)

### Follow contribute guide

There was comment line for a new property.

```rust
// "image-rendering" => (PresentationAttr::Yes, unimplemented),
```

After reading CSS `imgage-rendering` [property](https://drafts.csswg.org/css-images/#the-image-rendering).

I used the macro to create a following with an effort to follow with other property patterns.

`rsvg/src/property_defs.rs`

```rust
make_property!(
    /// `image-rendering` property.
    ///
    /// CSS Images Module Level 3: <https://www.w3.org/TR/css-images-3/#the-image-rendering>
    ///
    /// Note that this property previously accepted the values optimizeSpeed and optimizeQuality.
    /// These are now deprecated; a user agent must accept them as valid values but must treat
    /// them as having the same behavior as crisp-edges and smooth respectively.
    ImageRendering,
    default: Auto,
    inherits_automatically: true,

    identifiers:
    "auto" => Auto,
    "smooth" => Smooth,
    "optimizeQuality" => OptimizeQuality,
    "high-quality" => HighQuality,
    "crisp-edges" => CrispEdges,
    "optimizeSpeed" => OptimizeSpeed,
    "pixelated" => Pixelated,
);
```

Uncomment line and use compute following the repository [architecture](https://gnome.pages.gitlab.gnome.org/librsvg/devel-docs/architecture.html).

`rsvg/src/properties.rs`

```diff
- // "image-rendering"          => (PresentationAttr::Yes, unimplemented),
+ "image-rendering"             => (PresentationAttr::Yes, image_rendering             : ImageRendering),
...
+ compute!(ImageRendering, image_rendering);
```

## Tackling issue

Up to this point was straightforward. Well, After reading I was imagining that an image will be converted as follows.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1688049836576/798f2c18-0039-4da2-b3fd-a6485bb9dfb6.png align="center")

### Tackling issue logic with cairo as suggested

I never use `cairo` library or librsvg before. After I spent time reading the codebase, I noticed that in drawing function have not passed the values that were computed.

I try using `Context.set_antialias()` in draw function as mentioned in the issue discussed. I have to make the draw function notice the `image-rendering` value so I modify the image layout and pass it to the image in `draw` when Implement `ElementTrait for Image` since the `draw_ctx.draw_layer` didn't get a computed value.

Now I got `image-rendering` add the following code before the actual draw to `set_antialias`.

```rust
match image.image_rendering {
	ImageRendering::Pixelated
	| ImageRendering::CrispEdges
	| ImageRendering::OptimizeSpeed => {
		dc.cr.set_antialias(cairo::Antialias::None)
	}
	ImageRendering::Smooth
	| ImageRendering::OptimizeQuality
	| ImageRendering::HighQuality => {
		dc.cr.set_antialias(cairo::Antialias::Best)
	}
	ImageRendering::Auto => {
		dc.cr.set_antialias(cairo::Antialias::Default)
	}
}
```

I compile and test converting an image then the image was as same as before. After I searched I find that there are issues on [Git Hub using a cairo filter](https://github.com/Kozea/CairoSVG/issues/204). I use it and it worked. I still set antialias as a way to pass ImageRendering to `paint_surface`.

```rust
if cr.antialias() == cairo::Antialias::None {
	ptn.set_filter(cairo::Filter::Nearest);
}
```

After that, I also add support to `feImage` filter primitive, I use the same approach by trying to pass value and `set_filter` then manually this with a file that has filter property.

After some try and error, I stage and make a commit.

## Testing

I could manually test, but I couldn't figure how to compare the exact png image format. I use png in svg to test. After I render image the image, I try to use the output image in svg input test file and then render it again but the result was not the same.

## Feature.md

A `feature.md` file was mentioned but I didn't find the file.

## Push

After I register to Gitlab gnome and set up my ssh key and wait some time, I could fork and change the remote origin then push and open draft PR.

As I push, I could see that I mentioned issue in my commit was noticed in the main repository issue.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1688049900435/17e5973e-500c-4d6a-bcb5-6c5875304b30.png align="center")

I wait for my fork to finish CI before I change my draft PR to actual PR.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1688049920516/33735dff-ffa9-430a-93f7-a353672e5be7.png align="center")

I make some mistakes in my commit. I forgot to test after pasting cairo filter from `image-rendering` to `feImage`. I forgot to remove my test line. The CI was not passed.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1688049944476/4dcfbd82-bff4-4de4-87a4-c36cdbb5ac72.png align="center")

I got back to the editor and make changes then test in my local machine with `cargo test` then using `git commit --amend` to change the commit code while I leave the message as same as the previous one with the option `--no-edit`.

After the CI passed I change PR draft state to ready.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1688049965367/d445a921-f182-4b91-844f-5184d65116b0.png align="center")

Well, This was my contribution journey so far.
