GithubHelp home page GithubHelp logo

gtk-rs / cairo Goto Github PK

View Code? Open in Web Editor NEW
150.0 150.0 59.0 3.61 MB

DEPRECATED, use https://github.com/gtk-rs/gtk-rs-core repository instead!

Home Page: http://gtk-rs.org/

License: MIT License

Rust 100.00%

cairo's Introduction

gtk3-rs CI

This project is UNMAINTAINED. Please take a look at gtk4-rs instead!

The gtk-rs organization aims to provide safe Rust binding over GObject-based libraries. You can find more about it on https://gtk-rs.org.

This repository contains all the "core" crates of the gtk-rs organization. For more information about each crate, please refer to their README.md file in their directory.

Minimum supported Rust version

Currently, the minimum supported Rust version is 1.70.0.

Documentation

Ecosystem

The gtk3-rs repository contains Rust crates for GTK 3. However there is a large ecosystem of GObject libraries and many of these libraries have Rust bindings based on the tooling included in gtk-rs. Of particular note:

  • gtk-rs-core - bindings for some of the core libraries such as glib, gio, pango, graphene
  • gstreamer-rs - bindings for the GStreamer media framework

Additionally, Rust bindings for various libraries are hosted on GNOME's GitLab instance and can be found at https://gitlab.gnome.org/World/Rust.

When using crates that are not part of the gtk-rs repository, you will need to be careful and ensure that they do not pull in incompatible versions of core crates like glib-rs.

Regenerating

To regenerate crates using gir, please use the generator.py file as follows:

$ python3 generator.py

If you didn't do so yet, please check out all the submodules before via

$ git submodule update --checkout

Development

This repository is mostly split into two branches: master and crate. master contains the not yet released code and is where new developments are happening. crate contains the last release source code and isn't supposed to be updated.

This repository is structured as follows:

- crate/
   |
   |-- README.md
   |-- Gir.toml
   |-- Cargo.toml
   |-- src/
   |-- sys/

The crate is a "top" directory (so "atk" or "gdk" in here for example). Each crate contains:

  • README.md: explanations about the crate itself and eventually some details.
  • Cargo.toml: descriptor of the crate, used by cargo and Rust.
  • Gir.toml: configuration used by gir to generate most of the crates' code.
  • src: the source code of the crate.
  • sys: the 1:1 bindings of the C API.

The gir and gir-files top folders are not crates, but are git submodules which respectively contain the gir tool and the gir files used by the generator.

When running generator.py the tool will automatically update these git submodules and run the gir tool on the gir files to regenerate the code.

During development, it is useful to execute the generator with a different version of the gir tool or of the gir files, for instance to test if the code generation is successful before submitting a pull request to update one of the submodules. This can be done by specifying arguments to the generator script, for instance, to run the generator on a local copy of the gir files:

$ python3 generator.py --gir-files-directory ../gir-files/

See python3 generator.py --help for more details.

cairo's People

Contributors

andwur avatar bilelmoussaoui avatar blei avatar bpbp-boop avatar brooooooklyn avatar buster avatar derekdreery avatar dndanik avatar epashkin avatar evmar avatar federicomenaquintero avatar fengalin avatar gkoz avatar gsingh93 avatar guillaumegomez avatar jeremyletang avatar jgillich avatar jneem avatar johncf avatar jsparber avatar mathijshenquet avatar oakes avatar osa1 avatar ptersilie avatar razrfalcon avatar sdroege avatar simonsapin avatar tonalidadehidrica avatar vojtechkral avatar znapi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

cairo's Issues

ImageSurface::create_from_png not defined

From looking through the git repo, it looks like this function is defined here. However, it does not appear in the docs and when I try to use it with the latest on crates.io it cannot find the symbol. I tried to take the latest from the git repository, using the linked Cargo.toml, but the compiler could still not find this function. What am I doing wrong?

Cargo.txt

Could not compile cairo

I get the following error message when trying to compile caire :

   Compiling cairo v0.0.3
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/lib.rs:193:49: 193:53 error: type name `uint` is undefined or not in scope [E0412]
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/lib.rs:193       let dashes_len = self.get_dash_count() as uint;
                                                                                                                                                                            ^~~~
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/lib.rs:193:49: 193:53 help: run `rustc --explain E0412` to see a detailed explanation
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/lib.rs:193:49: 193:53 help: no candidates by the name of `uint` found in your project; maybe you misspelled the name or forgot to import an external crate?
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/font/mod.rs:154:55: 154:74 error: no associated item named `from_slice` found for type `std::ffi::c_str::CString` in the current scope
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/font/mod.rs:154       let foreign_result = cairo_toy_font_face_create(CString::from_slice(family.as_bytes()).as_ptr() as *mut i8, slant, weight);
                                                                                                                                                                                       ^~~~~~~~~~~~~~~~~~~
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/font/mod.rs:269:51: 269:70 error: no associated item named `from_slice` found for type `std::ffi::c_str::CString` in the current scope
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/font/mod.rs:269       cairo_scaled_font_text_extents(self.opaque, CString::from_slice(utf8.as_bytes()).as_ptr() as *mut i8, &mut extents);
                                                                                                                                                                                   ^~~~~~~~~~~~~~~~~~~
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/surface/mod.rs:180:64: 180:83 error: no associated item named `from_slice` found for type `std::ffi::c_str::CString` in the current scope
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/surface/mod.rs:180       let foreign_result = cairo_image_surface_create_from_png(CString::from_slice(filename.as_bytes()).as_ptr() as *mut i8);
                                                                                                                                                                                                   ^~~~~~~~~~~~~~~~~~~
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/surface/mod.rs:188:68: 188:87 error: no associated item named `from_slice` found for type `std::ffi::c_str::CString` in the current scope
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/surface/mod.rs:188       let foreign_result = cairo_surface_write_to_png(self.opaque, CString::from_slice(filename.as_bytes()).as_ptr() as *mut i8);
                                                                                                                                                                                                       ^~~~~~~~~~~~~~~~~~~
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/surface/mod.rs:196:45: 196:64 error: no associated item named `from_slice` found for type `std::ffi::c_str::CString` in the current scope
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/surface/mod.rs:196       cairo_svg_surface_create(self.opaque, CString::from_slice(filename.as_bytes()).as_ptr() as *mut i8, width, height);
                                                                                                                                                                                ^~~~~~~~~~~~~~~~~~~
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/lib.rs:534:36: 534:55 error: no associated item named `from_slice` found for type `std::ffi::c_str::CString` in the current scope
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/lib.rs:534       cairo_text_path(self.opaque, CString::from_slice(text_path.as_bytes()).as_ptr() as *mut i8);
                                                                                                                                                               ^~~~~~~~~~~~~~~~~~~
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/lib.rs:652:43: 652:62 error: no associated item named `from_slice` found for type `std::ffi::c_str::CString` in the current scope
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/lib.rs:652       cairo_select_font_face(self.opaque, CString::from_slice(family.as_bytes()).as_ptr() as *mut i8, slant, weight);
                                                                                                                                                                      ^~~~~~~~~~~~~~~~~~~
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/lib.rs:718:36: 718:55 error: no associated item named `from_slice` found for type `std::ffi::c_str::CString` in the current scope
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/lib.rs:718       cairo_show_text(self.opaque, CString::from_slice(utf8.as_bytes()).as_ptr() as *mut i8);
                                                                                                                                                               ^~~~~~~~~~~~~~~~~~~
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/lib.rs:731:43: 731:62 error: no associated item named `from_slice` found for type `std::ffi::c_str::CString` in the current scope
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/lib.rs:731       cairo_show_text_glyphs(self.opaque, CString::from_slice(utf8.as_bytes()).as_ptr() as *mut i8, -1, glyphs.as_mut_ptr(), glyphs.len() as libc::c_int, clusters.as_mut_ptr(), clusters.len() as libc::c_int, cluster_flags);
                                                                                                                                                                      ^~~~~~~~~~~~~~~~~~~
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/lib.rs:749:39: 749:58 error: no associated item named `from_slice` found for type `std::ffi::c_str::CString` in the current scope
/nfs/2013/g/gbersac/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/cairo-0.0.3/src/lib.rs:749       cairo_text_extents(self.opaque, CString::from_slice(utf8.as_bytes()).as_ptr() as *mut i8, &mut extents);
                                                                                                                                                                  ^~~~~~~~~~~~~~~~~~~
error: aborting due to 10 previous errors
Could not compile `cairo`.

I am on mac osx. I installed cairo with :

brew install cairo

Need a wrapper for cairo_format_stride_for_width()

ImageSurface.create_for_data() calls cairo_image_surface_create_for_data(), and its stride parameter:

  1. Needs to be aligned to 32 bits

  2. Must have an absolute value greater than or equal to cairo_format_stride_for_width() for the corresponding image (negative strides are allowed for bottom-to-top images).

The only place I could find that actually figures out a stride is in examples/src/cairo-threads.rs, but that gets it from an existing image_surface.get_stride() - it doesn't create a buffer on its own.

So, for people who actually want to allocate their own buffers to pass to ImageSurface.create_for_data(), I think we need a wrapper for cairo_format_stride_for_width().

Add online documentation

I was able to build documentation locally with cargo doc just fine, but it would be nice if the documentation was available online.

Build error on macOS (pkg-config)

cargo build in a fresh clone of this repo (bc8d33d) currently fails with a pkg-config warning:

error: failed to run custom build command for `gobject-sys v0.8.0 (https://github.com/gtk-rs/sys#c45adc74)`
process didn't exit successfully: `/Users/rofls/dev/hacking/ruststuff/cairo/target/debug/build/gobject-sys-b79f4cc46c4e2f34/build-script-build` (exit code: 1)
--- stderr
`"pkg-config" "--libs" "--cflags" "gobject-2.0 >= 2.42"` did not exit successfully: exit code: 1
--- stderr
Package libffi was not found in the pkg-config search path.
Perhaps you should add the directory containing `libffi.pc'
to the PKG_CONFIG_PATH environment variable
Package 'libffi', required by 'gobject-2.0', not found


warning: build failed, waiting for other jobs to finish...
error: failed to run custom build command for `cairo-sys-rs v0.8.0 (/Users/rofls/dev/hacking/ruststuff/cairo/cairo-sys-rs)`
process didn't exit successfully: `/Users/rofls/dev/hacking/ruststuff/cairo/target/debug/build/cairo-sys-rs-81b545a704bf5e01/build-script-build` (exit code: 1)
--- stderr
`"pkg-config" "--libs" "--cflags" "cairo-gobject >= 1.12"` did not exit successfully: exit code: 1
--- stderr
Package libffi was not found in the pkg-config search path.
Perhaps you should add the directory containing `libffi.pc'
to the PKG_CONFIG_PATH environment variable
Package 'libffi', required by 'gobject-2.0', not found


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

This can be solved by manually setting the PKG_CONFIG_PATH (if you're using homebrew this might look like),

>$ PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig" cargo build

but this should probably be working by default?

Missing emuns

The main lib.rs file are missing some enums from '-sys'. Like Content or Extend. Is this done on purpose?

Linker error if Cairo is configured with --disable-script

When building these Rust bindings, it currently fails during linking when Cairo is configured without the script backend (--disable-script).

For example compiling librsvg 2.45.6 produces these linker errors:

./.libs/librsvg-2.so: undefined reference to `cairo_script_set_mode'
./.libs/librsvg-2.so: undefined reference to `cairo_script_surface_create'
./.libs/librsvg-2.so: undefined reference to `cairo_script_from_recording_surface'
./.libs/librsvg-2.so: undefined reference to `cairo_script_surface_create_for_target'
./.libs/librsvg-2.so: undefined reference to `cairo_script_get_mode'
./.libs/librsvg-2.so: undefined reference to `cairo_script_write_comment'
collect2: error: ld returned 1 exit status
make[3]: *** [rsvg-convert] Error 1
make[3]: Leaving directory `/deps/svg'
make[2]: *** [install-recursive] Error 1
make[2]: Leaving directory `/deps/svg'
make[1]: *** [install] Error 2
make[1]: Leaving directory `/deps/svg'
make: *** [install-strip] Error 2

This can be fixed with this patch, but instead of removing the code that causes these linker errors, it would be better if it discovers that Cairo has been built without a script backend.

Minimal example

Could you put the code that you've used to generate the image linked on the README.md as an example?

The rest of the documentation seems fine, but I still have no clue how to generate a OpenGL window using this. I'm planning to use cairo to develop a 2D game written in Rust. Non-OpenGL support is important too.

pkg-config error under msys2

$ PKG_CONFIG_PATH="/mingw32/lib/pkgconfig" cargo.exe build --release --features "cairo-backend"
   Compiling cairo-sys-rs v0.6.0
   Compiling pango-sys v0.6.0
   Compiling libflate v0.1.16
   Compiling gio v0.4.1
error: failed to run custom build command for `cairo-sys-rs v0.6.0`
process didn't exit successfully: `C:\Users\razr\Desktop\Projects\resvg\target\release\build\cairo-sys-rs-ba2cd5cbbe604f8a\build-script-build` (exit code: 1)
--- stderr
`"pkg-config" "--libs" "--cflags" "cairo >= 1.10"` did not exit successfully: exit code: 1
--- stderr
Package cairo was not found in the pkg-config search path.
Perhaps you should add the directory containing `cairo.pc'
to the PKG_CONFIG_PATH environment variable
No package 'cairo' found

But:

$ PKG_CONFIG_PATH="/mingw32/lib/pkgconfig" pkg-config.exe --modversion cairo
1.15.12

But^2:

$ pkg-config.exe --modversion cairo
Package cairo was not found in the pkg-config search path.
Perhaps you should add the directory containing `cairo.pc'
to the PKG_CONFIG_PATH environment variable
No package 'cairo' found

I have the same error with pango too, so maybe it's a pkg-config bug.

  • Windows 10 x86
  • msys2 i686 with all updates
  • Rust 1.28.0 stable-i686-pc-windows-gnu
  • Crate in question
$ echo $PATH
/c/Users/razr/.cargo/bin:/usr/local/bin:/usr/bin:/bin:/opt/bin:/c/Windows/System32:/c/Windows:/c/Windows/System32/Wbem:/c/Windows/System32/WindowsPowerShell/v1.0/:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl

RFC: MatrixTrait::try_invert()

I appreciate how MatrixTrait::invert() actually ensures that the matrix is invertible, and panics otherwise; it has caught a lot of bugs in librsvg.

Now, I need to know if a matrix is actually invertible, to validate user-supplied data (actually, transformations that come from an SVG file).

The quick-and-dirty way is to call ffi::cairo_matrix_invert() by hand and test the result.

A more idiomatic way could be to have this in MatrixTrait:

pub trait MatrixTrait {
    ...
     fn try_invert(&self) -> Result <Matrix, Status>;
    ...
}

What do you think? I can submit a pull request for this if you like the API.

How to send Surface?

This may be a bit of noob question.

// wv - webview
wv.connect_load_changed(move |wv, ev| {
    if ev == LoadEvent::Finished {
        wv.get_snapshot(
            SnapshotRegion::FullDocument,
            SnapshotOptions::NONE,
            None,
            move |res| {
                if let Ok(surface) = res {
                    sender.send(surface).unwrap();
                }
            },
        );
    }
});
// somewhere else
img.set_from_surface(Some(surface));

Results in same error almost the same as in: https://pastebin.com/RzYNmW1v (I found this paste by googling, yet no references to it. Maybe similar question was answered on IRC?)

error[E0277]: `*mut cairo_sys::cairo_surface_t` cannot be sent between threads safely
   --> src/main.rs:122:16
    |
122 |             wv.get_snapshot(
    |                ^^^^^^^^^^^^ `*mut cairo_sys::cairo_surface_t` cannot be sent between threads safely
    |
    = help: within `cairo::surface::Surface`, the trait `std::marker::Send` is not implemented for `*mut cairo_sys::cairo_surface_t`
    = note: required because it appears within the type `cairo::surface::Surface`
    = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::mpsc::Sender<cairo::surface::Surface>`
    = note: required because it appears within the type `[closure@src/main.rs:126:17: 133:18 pstx:std::sync::mpsc::Sender<cairo::surface::Surface>]`

I tried using AtomicPtr:

let ptr = AtomicPtr::new(&mut surface);
sender.send(ptr).unwrap();
// somewhere else
let surface = ptr.load(Ordering::Relaxed);
let surface = unsafe { &*surface };
img.set_from_surface(Some(surface));

While this compiles, the problem seems to be that by the time I load the pointer, original closure erases Surface:

cairo-surface.c:930: cairo_surface_reference: Assertion `CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count)' failed.

The problem may come from the fact that get_snapshot callback closure gets called in the same thread as the main thread, blocking it (it can be tested by thread::sleeping in callback function and seeing the UI freeze), yet it requires callback closure to be Sendable. In that case it is issue for webkit2gtk-rs. Trying to just use Surface inside callback closure:

wv.get_snapshot(
    SnapshotRegion::FullDocument,
    SnapshotOptions::NONE,
    None,
    move |res| {
        if let Ok(surface) = res {
            img.set_from_surface(Some(&surface));
        }
    },
);
error[E0277]: `*mut gtk_sys::GtkImagePrivate` cannot be sent between threads safely
   --> src/main.rs:122:16
    |
122 |             wv.get_snapshot(
    |                ^^^^^^^^^^^^ `*mut gtk_sys::GtkImagePrivate` cannot be sent between threads safely
    |
    = help: within `[closure@src/main.rs:126:17: 134:18 pstx:std::sync::mpsc::Sender<cairo::surface::Surface>, img:gtk::auto::image::Image]`, the trait `std::marker::Send` is not implemented for `*mut gtk_sys::GtkImagePrivate`
    = note: required because it appears within the type `gtk_sys::GtkImage`
    = note: required because it appears within the type `std::marker::PhantomData<gtk_sys::GtkImage>`
    = note: required because it appears within the type `gtk::auto::image::Image`
    = note: required because it appears within the type `[closure@src/main.rs:126:17: 134:18 pstx:std::sync::mpsc::Sender<cairo::surface::Surface>, img:gtk::auto::image::Image]`

Maybe related to #175.

Can we consider implementation of `Send` for `Context`, `Surface`?

It seems that it should be possible to make Context and/or Surface sendable across the threads. Otherwise it's very limited as it does not allow the user to send the Context in case if it was just created in one thread and then being moved into another thread.

rust-xcb had the similar issue once, which was solved by introducing thread feature, which implements Send for certain types in order to allow passing xcb::Connection between threads.

I think it would be nice to have the similar thing here in cairo-rs.

#[cfg(macos)] should be #[cfg(target_os = "macos")]

Unless there is a reason for this that I don't see, in the very few places that there are #[cfg(macos)]s, it should be #[cfg(target_os = "macos")]. I'm on macOS, and the compiler just throws out anything under a #[cfg(macos)], making the quartz backend functions unusable.

I tried just replacing them, but it just revealed a few other errors within the functions themselves.

It's possible to observe a data race in safe Rust with the current Context API

In particular, it's possible to draw onto an ImageSurface using Context concurrently with using it as a source surface from a different thread, and observe the contents of the surface changing in the middle of being read from, which means it's a data race. Data races are undefined behavior in safe Rust, so I believe this makes the current API unsound.

Example program demonstrating the issue:

extern crate cairo;
use cairo::{Context, Format, ImageSurface};

use std::{fs::File, thread};

fn main() -> Result<(), cairo::Status> {
    // The main idea is to create a big surface and fill it with small surfaces
    // in a tiled pattern. On a separate thread, the small surface is
    // continuously filled with alternating colors, red and green. If any of
    // the small surface copies on the big surface are filled partially with
    // one color and partially with another color, it means that a data race
    // was observed, which constitutes as undefined behavior in safe Rust.

    // Create the small 32×32 surface.
    let small_surface = ImageSurface::create(Format::ARgb32, 32, 32)?;

    // Fill it with red, the initial color.
    {
        let cr = Context::new(&small_surface);
        cr.set_source_rgb(1.0, 0.0, 0.0);
        cr.paint();
    }

    // Create a second reference and spawn a second thread that fills it with
    // green and then red in a loop.
    let small_surface_clone = small_surface.clone();
    thread::spawn(move || loop {
        {
            let cr = Context::new(&small_surface_clone);
            cr.set_source_rgb(0.0, 1.0, 0.0);
            cr.paint();
        }

        {
            let cr = Context::new(&small_surface_clone);
            cr.set_source_rgb(1.0, 0.0, 0.0);
            cr.paint();
        }
    });

    // Create the big surface.
    let big_surface = ImageSurface::create(Format::ARgb32, 1024, 1024)?;

    // Leave a gap of 4 pixels between small surface copies on the big suface
    // to be able to see each individual copy of the small surface.
    const GAP: usize = 4;
    const FITS_IN_ROW: usize = (1024 - 32) / (32 + GAP) + 1;

    // In a loop, copy the small surface to the big surface in a tiled pattern.
    for j in 0..FITS_IN_ROW {
        for i in 0..FITS_IN_ROW {
            let x = i * (32 + GAP);
            let y = j * (32 + GAP);

            let cr = Context::new(&big_surface);
            cr.set_source_surface(&small_surface, x as f64, y as f64);
            cr.paint();
        }
    }

    // Save the resulting surface to a PNG file.
    big_surface
        .write_to_png(&mut File::create("output.png").unwrap())
        .unwrap();

    Ok(())
}

Example output that I got:
image
Note that most of the squares are partially green and partially red which means that a data race was observed.

I'm not sure what the best way of fixing this would be. Taking the surface by a mutable reference in Context::create() and ensuring its uniqueness, like in ImageSurface::get_data(), might be sufficient, however rather limiting, just like ImageSurface::get_data() currently is.

I believe the underlying issue is that Cairo objects are like Arc<T>, except they always offer mutable access and don't provide any way of checking whether someone is currently using them mutably. A more general solution could be to wrap Cairo objects in an Arc<RwLock<T>> and use that instead of the built-in Cairo refcounting, which would allow doing borrowing and reference counting on the Rust side, and make it possible to safely do shared read-only access (like ImageSurface::get_data(), but without the unique reference check) as well as safe write access even with multiple references laying around (thanks to RwLock). Wrapping the surface in an Arc<RwLock<T>> in the example program does fix the data race.

xcb features: method `from_glib_none` is not a member of trait `FromGlibPtrFull`

According to the doc, we have now multiples traits for each method. Here is the error after putting this in my Cargo.toml:

[dependencies.cairo-rs]
version = "0.1.3"
default-features = false
features = ["xcb"]
error[E0407]: method `from_glib_none` is not a member of trait `FromGlibPtrFull`
  --> /home/charles/.cargo/registry/src/github.com-1ecc6299db9ec823/cairo-rs-0.1.3/src/xcb.rs:42:5
   |
42 |       unsafe fn from_glib_none(ptr: *mut ffi::xcb_connection_t) -> XCBConnection {
   |  _____^ starting here...
43 | |         assert!(!ptr.is_null());
44 | |         XCBConnection(ptr)
45 | |     }
   | |_____^ ...ending here: not a member of trait `FromGlibPtrFull`

error[E0407]: method `from_glib_none` is not a member of trait `FromGlibPtrFull`
  --> /home/charles/.cargo/registry/src/github.com-1ecc6299db9ec823/cairo-rs-0.1.3/src/xcb.rs:80:5
   |
80 |       unsafe fn from_glib_none(ptr: *mut ffi::xcb_render_pictforminfo_t) -> XCBRenderPictFormInfo {
   |  _____^ starting here...
81 | |         assert!(!ptr.is_null());
82 | |         XCBRenderPictFormInfo(ptr)
83 | |     }
   | |_____^ ...ending here: not a member of trait `FromGlibPtrFull`

error[E0277]: the trait bound `xcb::XCBConnection: glib::translate::FromGlibPtrNone<*mut ffi::xcb_connection_t>` is not satisfied
  --> /home/charles/.cargo/registry/src/github.com-1ecc6299db9ec823/cairo-rs-0.1.3/src/xcb.rs:62:18
   |
62 |         unsafe { from_glib_none(self.to_glib_none().0) }
   |                  ^^^^^^^^^^^^^^ the trait `glib::translate::FromGlibPtrNone<*mut ffi::xcb_connection_t>` is not implemented for `xcb::XCBConnection`
   |
   = note: required by `glib::translate::from_glib_none`

error[E0277]: the trait bound `xcb::XCBRenderPictFormInfo: glib::translate::FromGlibPtrNone<*mut ffi::xcb_render_pictforminfo_t>` is not satisfied
   --> /home/charles/.cargo/registry/src/github.com-1ecc6299db9ec823/cairo-rs-0.1.3/src/xcb.rs:100:18
    |
100 |         unsafe { from_glib_none(self.to_glib_none().0) }
    |                  ^^^^^^^^^^^^^^ the trait `glib::translate::FromGlibPtrNone<*mut ffi::xcb_render_pictforminfo_t>` is not implemented for `xcb::XCBRenderPictFormInfo`
    |
    = note: required by `glib::translate::from_glib_none`

error: aborting due to 2 previous errors

error: Could not compile `cairo-rs`.
Build failed, waiting for other jobs to finish...
error: build failed

cairo_surface_create*() can return errors

Cairo's surface creation functions can return errors in the form of a valid cairo_surface_t* but whose cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS.

For example, cairo_image_surface_create() can return CAIRO_STATUS_INVALID_SIZE if the passed size is greater than what Pixman supports, or it can return CAIRO_STATUS_NO_MEMORY if allocation fails.

Cairo-rs similarly returns a valid Surface (or ImageSurface) whose status must be checked before proceeding.

Should we return a Result<Surface, Status> (or the corresponding Result<ImageSurface, Status>) instead?

Don't drop Pattern muti times

There is a bug while call get_source in context, there is a minimal example to show how to reproduce the bug:

fn main() {
  let surface = ImageSurface::create(Format::ARgb32,  100.0f64, 100.0f64).unwrap();
  let context = Context::new(&surface);
  context.get_source();
}

would caused panic:

Assertion failed: (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count)), function cairo_pattern_destroy, file cairo-pattern.c, line 1125.

And it may be caused by https://github.com/gtk-rs/cairo/blob/master/src/patterns.rs#L137

It should not Drop pattern which created by Context.

SurfaceExt is not exported

This seems like just an oversight, since lib.rs has

pub use surface::{
    MappedImageSurface,
    Surface,
};

Will submit a PR shortly.

Need to be able to Path::wrap() publically

I'm porting parts of librsvg to Rust; it uses Cairo internally.

At some point I get a cairo_path_t from the C code. However, gtk-rs/cairo doesn't make ffi::cairo_path_t public.

I added a simple

pub use ffi::cairo_path_t as cairo_path_t;

to cairo/lib.rs, so I can then

extern crate cairo;

extern "C" {
fn rsvg_path_builder_copy_path (builder: *mut RsvgPathBuilder) -> *mut cairo::cairo_path_t;
}

fn my_stuff (builder: *mut RsvgPathBuilder) {
let cairopath: *mut cairo::cairo_path_t;

unsafe { cairopath = rsvg_path_builder_copy_path (builder); }
let path = cairo::Path::wrap (cairopath);
... do stuff with path ...

}

at which point I have a proper cairo::Path out of its ::wrap().

I'm not sure if adding that "pub use ... as cairo_path_t" is the best solution, though it seemed easy enough :) Ideas are appreciated.

Surface::set_mime_data() shouldn't require a static lifetime on the data

The prototype right now is

    pub fn set_mime_data<T: AsRef<[u8]> + Send + 'static>(
        &self,
        mime_type: &str,
        slice: T) -> Result<(), Status> {
        let b = Box::new(slice);
        // note the immediate boxing here, to pass to cairo_surface_set_mime_data()

I think it's enough to pass a regular reference?

Shouldn't ImageSurface has an AsMut<Surface> impl?

Currently I can get a &Surface from a &ImageSurface, but I can't get a &mut Surface from &mut ImageSurface because there isn't an impl AsMut<Surface> for ImageSurface. This makes some operations impossible, e.g. I can't call set_device_offset() (added with #230) on an ImageSurface.

cairo_pattern_reference: Assertion `CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count)' failed.

I'm getting following error when using cairo::Pattern with the latest git version: cairo_pattern_reference: Assertion CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count)' failed., which results in a crash. This error is not occurring with version 0.3.

Here is related code snipped:

    let s = cr.get_target();
    // Create pattern which we can then "safely" draw to the surface. On X11, the pattern part was
    // not needed but on wayland it is - I suppose it has something to do with the underlaying
    // backbuffer.
    cr.push_group();
    let (_, y) = get_coords(ci.height, ci.width, dst_top - src_top, 0.0);
    cr.set_source_surface(&s, 0.0, y);
    cr.set_operator(cairo::Operator::Source);
    let (x1, y1, x2, y2) = get_rect(ci.height, ci.width, dst_top, dst_bot, left as f64, right as f64);
    let w = x2 - x1;
    let h = y2 - y1;
    cr.rectangle(x1, y1, w, h);
    cr.fill();

    // Get the pattern.
    let mut p = cr.pop_group();

    // Draw the parttern.
    cr.set_source(&mut p);
    cr.set_operator(cairo::Operator::Source);
    cr.rectangle(x1, y1, w, h);
    cr.fill();
    da.queue_draw_area(x1 as i32, y1 as i32, w as i32, h as i32);

Note that the "bug" related to the difference between X11 and wayland is not happening anymore with the git version, but still happens on version 0.3. Scratch that, its still happening.

Idea of the above code is to draw part of the current surface to it self as part of a scrolling procedure.

Duplicate types of enums in cairo-sys

The following enum types:

enums::{
    Antialias,
    Content,
    Extend,
    FillRule,
    LineCap,
    LineJoin,
    Filter,
}

have duplicate struct types:

#[repr(C)]
pub struct cairo_antialias_t(c_void);
#[repr(C)]
pub struct cairo_content_t(c_void);
#[repr(C)]
pub struct cairo_extend_t(c_void);
#[repr(C)]
pub struct cairo_fill_rule_t(c_void);
#[repr(C)]
pub struct cairo_line_cap_t(c_void);
#[repr(C)]
pub struct cairo_line_join_t(c_void);
#[repr(C)]
pub struct cairo_filter_t(c_void);

which are unused inside cairo_sys repository, but for some reason, seems to be used in other repositories. (Here is a example usage which does not work.)

Add unsafe from_raw method for FontOptions (and others)

I would like to suggest adding the following method to FontOptions:

    unsafe fn from_raw(ptr: *mut cairo_font_options_t) -> FontOptions {
        FontOptions(ptr)
    }

Side note: The inner pointer in FontFace is public. This is a bug, right? Since I can do unsafe things with this without using unsafe tag. Adding from_raw would be the correct alternative.

Cannot build cairo under MSYS2.

I can't build cairo on MSYS2 (Windows) because the build script for cairo-sys-rs fails.

Cargo output:

   Compiling cairo-sys-rs v0.2.0 (https://github.com/gtk-rs/cairo#e5e7d934)
Build failed, waiting for other jobs to finish...
failed to run custom build command for `cairo-sys-rs v0.2.0 (https://github.com/gtk-rs/cairo#e5e7d934)`
Process didn't exit successfully: `C:\msys32\home\jeanpierre\ghex-rs\target\debug\build\cairo-sys-rs-e1ce15088da7e508\build-script-build` (exit code: 1)
--- stderr
`"pkg-config" "--libs" "--cflags" "cairo"` did not exit successfully: exit code: 1
--- stderr
Package cairo was not found in the pkg-config search path.
Perhaps you should add the directory containing `cairo.pc'
to the PKG_CONFIG_PATH environment variable
No package 'cairo' found

However if run pkg-config with the same arguments it gives the correct output.

$ "pkg-config" "--libs" "--cflags" "cairo"
-mms-bitfields -I/mingw32/include/cairo -I/mingw32/include/pixman-1 -I/mingw32/include -I/mingw32/include/freetype2 -I/mingw32/include/libpng16 -I/mingw32/include/harfbuzz -I/mingw32/include/glib-2.0 -I/mingw32/lib/glib-2.0/include -I/mingw32/include -I/mingw32/include/freetype2 -I/mingw32/include -I/mingw32/include/harfbuzz -I/mingw32/include/glib-2.0 -I/mingw32/lib/glib-2.0/include -I/mingw32/include/libpng16 -L/mingw32/lib -LC:/building/msys64/mingw32/lib/../lib -L/mingw32/lib -lcairo -lz -lgobject-2.0 -lffi -lpixman-1 -lfontconfig -lexpat -lfreetype -liconv -lexpat -lfreetype -lz -lbz2 -lharfbuzz -lglib-2.0 -lintl -pthread -lws2_32 -lole32 -lwinmm -lshlwapi -lintl -lpng16 -lz

Rework type hierarchies?

Since breaking changes are on the table already (#255 (comment)) I’m considering some more, but I’d like some opinions before writing code.

Patterns

cairo-rs 0.6.0 has a Pattern enum where each variant contains a pointer-wrapping struct for the corresponding kind of pattern. Both the enums and each struct implement a PatternTrait trait that has methods in common to all patterns. Two of the structs implement a Gradient trait.

For bindings in object-oriented languages, https://www.cairographics.org/manual/bindings-patterns.html reccomends classes for each pattern kind and inheritance. The closest in today’s Rust is having structs whose only (or first, with #[repr(C)]) field is the parent type, that implement Deref<Target=ParentType> (and maybe AsRef<AncestorType> for all recursive ancestors, I’m not sure it’s needed given auto-deref). cairo-rs 0.6.0 already does this with surfaces.

This way, the Pattern and Gradient structs could have inherent methods that are usable on “sub-types” through auto-deref, without the need for traits.

Additionally, there could be methods similar to the standard library’s downcast to go from less specific to more specific types.

PDF, PS, and SVG surfaces

#250 has some complaints about the API for these surface types. While I disagree with some of the points there (there’s a reason for differences with ImageSurface, they are already closer to idiomatic Rust than bare C FFI, …) I do agree that the current API is a bit weird:

There are public modules named pdf, ps, and svg (whereas all other modules except prelude are private with contents reexported from the crate root) and contain identical types named File, Writer, and RefWriter.

I think we can have one Rust type for each of these surface kinds, and no public module for them. For example PdfSurface with create and create_for_stream constructors.

(BTW I’m not sure we can safely keep RefWriter’s functionality, for the same reason as #228. (Surface ref-counting make it insufficient to have a wrapper type with a lifetime parameter.) It may still be worth having an unsafe fn constructor for it.)

Remaining public traits

  • XCBSurface is a trait implemented for Surface, but #102 does not explain why. Should it be a type similar to ImageSurface instead?

  • SurfaceExt could be inherent methods of Surface, accessible on “sub-types” through auto-deref.

  • MatrixTrait adds methods to the Matrix type which is reexported from cairo-sys-rs. There could be a local Matrix type that duplicates the definition and has compatible layout, so that it can have inherent methods. (A wrapper type would lose the benefit of public fields.)

With all this the prelude module could become unnecessary.

Thoughts?

Add tests for Path::iter()

I'm starting to rust-ify parts of librsvg. In there, sometimes I need to take apart a cairo_path_t and look at the segments by hand. I noticed that gtk-rs/cairo has a very convenient Path::iter() which gives me exactly what I need!

I'd like to have a couple of tests for the path iterator and PathSegments in general. Would you be interested in a pull request that adds tests like these inside the cairo module? (I think the gtk-rs/tests module is for runnable-by-hand tests, not unit tests for little pieces; is this correct?)

Context::set_source_surface not properly working

I load an svg file into a Surface and want to draw this onto a drawingArea. This is working only if I draw nothing else on this drawingArea. If I draw another shape, the svg is not shown anymore.
Am I doing something wrong?

use std::env::args;

use std::f64::consts::PI;

use gio::prelude::*;
use gtk::prelude::*;
use gtk::DrawingArea;

fn main() {
    let application = gtk::Application::new(
        Some("example.svg"),
        gio::ApplicationFlags::from_bits_truncate(4),
    )
    .expect("Initialization failed...");

    application.connect_open(move |app, _files, _| {
        build_ui(app);
    });

    application.run(&args().collect::<Vec<_>>());
}

fn build_ui(application: &gtk::Application) {
    let window = gtk::ApplicationWindow::new(application);
    window.set_default_size(500, 500);

    let drawing_area = Box::new(DrawingArea::new)();

    drawing_area.connect_draw(move |w, cr| {
        // cr.scale(
        //     w.get_allocated_width() as f64,
        //     w.get_allocated_height() as f64,
        // );
        // cr.arc(0.5, 0.5, 0.3, 0.0 * PI, 2.0 * PI);

        // cr.set_source_rgba(1.0, 0.0, 0.0, 0.8);
        // cr.fill_preserve();

        let opt = resvg::Options::default();
        let path = "/home/rust/test_svg/example.svg";
        let tree = resvg::usvg::Tree::from_file(path, &opt.usvg).unwrap();
        let img = resvg::backend_cairo::render_to_image(&tree, &opt).unwrap();

        cr.set_source_surface(&img, 0.1, 0.1);
        cr.paint();

        Inhibit(false)
    });

    window.add(&drawing_area);
    window.show_all();
}

Uncommenting the arc drawing part will make the loaded svg disappear and only show the drawn circle. Why is that?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.