├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── settings.gradle ├── src ├── test │ └── java │ │ └── org │ │ └── freedesktop │ │ └── cairo │ │ └── test │ │ ├── CairoTest.java │ │ ├── FontFaceTest.java │ │ ├── LinearGradientTest.java │ │ ├── SolidPatternTest.java │ │ ├── RadialGradientTest.java │ │ ├── ToyFontFaceTest.java │ │ ├── GradientTest.java │ │ ├── PathTest.java │ │ ├── UserScaledFontTest.java │ │ ├── SVGSurfaceTest.java │ │ ├── RecordingSurfaceTest.java │ │ ├── DeviceTest.java │ │ ├── PatternTest.java │ │ ├── FTFontFaceTest.java │ │ ├── RasterSourceTest.java │ │ ├── FontOptionsTest.java │ │ ├── ScriptTest.java │ │ ├── PSSurfaceTest.java │ │ ├── TeeSurfaceTest.java │ │ ├── FTScaledFontTest.java │ │ ├── PDFSurfaceTest.java │ │ ├── MeshTest.java │ │ ├── MatrixTest.java │ │ └── UserFontFaceTest.java └── main │ └── java │ ├── io │ └── github │ │ └── jwharm │ │ └── cairobindings │ │ ├── package-info.java │ │ ├── Flag.java │ │ ├── ArenaCloseAction.java │ │ ├── Platform.java │ │ ├── Proxy.java │ │ ├── LibLoad.java │ │ └── Interop.java │ ├── org │ └── freedesktop │ │ ├── cairo │ │ ├── Point.java │ │ ├── Circle.java │ │ ├── RGBA.java │ │ ├── Rect.java │ │ ├── ScriptMode.java │ │ ├── SurfaceObserverMode.java │ │ ├── ScriptSurface.java │ │ ├── UserDataKey.java │ │ ├── PDFOutlineFlags.java │ │ ├── ColorMode.java │ │ ├── PDFMetadata.java │ │ ├── FTSynthesize.java │ │ ├── Dither.java │ │ ├── DestroyFunc.java │ │ ├── FontWeight.java │ │ ├── SurfaceObserverCallback.java │ │ ├── FontSlant.java │ │ ├── RasterSourceFinishFunc.java │ │ ├── TextClusterFlags.java │ │ ├── RegionOverlap.java │ │ ├── LineCap.java │ │ ├── PathDataType.java │ │ ├── LineJoin.java │ │ ├── PathElement.java │ │ ├── HintMetrics.java │ │ ├── RasterSourceReleaseFunc.java │ │ ├── TextCluster.java │ │ ├── SubpixelOrder.java │ │ ├── SVGUnit.java │ │ ├── Content.java │ │ ├── Extend.java │ │ ├── Filter.java │ │ ├── RasterSourceCopyFunc.java │ │ ├── HintStyle.java │ │ ├── SurfacePattern.java │ │ ├── RasterSourceSnapshotFunc.java │ │ ├── FillRule.java │ │ ├── WriteFunc.java │ │ ├── FontType.java │ │ ├── PatternType.java │ │ ├── ReadFunc.java │ │ ├── Glyph.java │ │ ├── MimeType.java │ │ └── PSLevel.java │ │ └── freetype │ │ ├── FreeType2.java │ │ ├── package-info.java │ │ └── Face.java │ └── module-info.java ├── .github └── workflows │ └── publish-pages.yml ├── .gitignore └── gradlew.bat /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jwharm/cairo-java-bindings/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' 3 | } 4 | 5 | rootProject.name = 'cairo' 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/CairoTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import static org.junit.jupiter.api.Assertions.*; 4 | 5 | import org.freedesktop.cairo.Cairo; 6 | import org.junit.jupiter.api.Test; 7 | 8 | class CairoTest { 9 | 10 | @Test 11 | void testVersionEncode() { 12 | assertEquals(10203, Cairo.versionEncode(1, 2, 3)); 13 | } 14 | 15 | @Test 16 | void testVersionStringize() { 17 | assertEquals("1.2.3", Cairo.versionStringize(1, 2, 3)); 18 | } 19 | 20 | @Test 21 | void testVersion() { 22 | assertTrue(Cairo.version() > 10000); 23 | } 24 | 25 | @Test 26 | void testVersionString() { 27 | assertNotNull(Cairo.versionString()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/FontFaceTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import org.freedesktop.cairo.FontSlant; 6 | import org.freedesktop.cairo.FontType; 7 | import org.freedesktop.cairo.FontWeight; 8 | import org.freedesktop.cairo.Status; 9 | import org.freedesktop.cairo.ToyFontFace; 10 | import org.junit.jupiter.api.Test; 11 | 12 | class FontFaceTest { 13 | 14 | @Test 15 | void testStatus() { 16 | assertEquals(Status.SUCCESS, ToyFontFace.create("Arial", FontSlant.NORMAL, FontWeight.NORMAL).status()); 17 | } 18 | 19 | @Test 20 | void testGetFontType() { 21 | assertEquals(FontType.TOY, ToyFontFace.create("Arial", FontSlant.NORMAL, FontWeight.NORMAL).getFontType()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/LinearGradientTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import org.freedesktop.cairo.LinearGradient; 6 | import org.freedesktop.cairo.Status; 7 | import org.junit.jupiter.api.Test; 8 | 9 | class LinearGradientTest { 10 | 11 | @Test 12 | void testCreate() { 13 | LinearGradient gradient = LinearGradient.create(0, 0, 10, 10); 14 | assertEquals(Status.SUCCESS, gradient.status()); 15 | } 16 | 17 | @Test 18 | void testGetLinearPoints() { 19 | LinearGradient gradient = LinearGradient.create(0, 1, 10, 11); 20 | var points = gradient.getLinearPoints(); 21 | assertEquals(2, points.length); 22 | assertEquals(0, points[0].x()); 23 | assertEquals(1, points[0].y()); 24 | assertEquals(10, points[1].x()); 25 | assertEquals(11, points[1].y()); 26 | assertEquals(Status.SUCCESS, gradient.status()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/io/github/jwharm/cairobindings/package-info.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2024 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | /** 21 | * This package contains functionality that the cairo java bindings 22 | * need to load native libraries and call native functions. 23 | */ 24 | package io.github.jwharm.cairobindings; 25 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/SolidPatternTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import static org.junit.jupiter.api.Assertions.*; 4 | 5 | import org.freedesktop.cairo.SolidPattern; 6 | import org.freedesktop.cairo.Status; 7 | import org.junit.jupiter.api.Test; 8 | 9 | class SolidPatternTest { 10 | 11 | @Test 12 | void testCreateRGB() { 13 | SolidPattern pattern = SolidPattern.createRGB(0.1, 0.2, 0.3); 14 | assertEquals(Status.SUCCESS, pattern.status()); 15 | } 16 | 17 | @Test 18 | void testCreateRGBA() { 19 | SolidPattern pattern = SolidPattern.createRGBA(0.1, 0.2, 0.3, 0.4); 20 | assertEquals(Status.SUCCESS, pattern.status()); 21 | } 22 | 23 | @Test 24 | void testGetRGBA() { 25 | SolidPattern pattern = SolidPattern.createRGBA(0.1, 0.2, 0.3, 0.4); 26 | double[] rgba = pattern.getRGBA(); 27 | assertEquals(4, rgba.length); 28 | assertEquals(0.1, rgba[0]); 29 | assertEquals(0.2, rgba[1]); 30 | assertEquals(0.3, rgba[2]); 31 | assertEquals(0.4, rgba[3]); 32 | assertEquals(Status.SUCCESS, pattern.status()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/RadialGradientTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import org.freedesktop.cairo.Circle; 6 | import org.freedesktop.cairo.RadialGradient; 7 | import org.freedesktop.cairo.Status; 8 | import org.junit.jupiter.api.Test; 9 | 10 | class RadialGradientTest { 11 | 12 | @Test 13 | void testCreate() { 14 | RadialGradient gradient = RadialGradient.create(100, 100, 50, 200, 100, 60); 15 | assertEquals(Status.SUCCESS, gradient.status()); 16 | } 17 | 18 | @Test 19 | void testGetRadialCircles() { 20 | RadialGradient gradient = RadialGradient.create(100, 100, 50, 200, 100, 60); 21 | Circle[] circles = gradient.getRadialCircles(); 22 | assertEquals(circles.length, 2); 23 | assertEquals(circles[0].x(), 100); 24 | assertEquals(circles[0].y(), 100); 25 | assertEquals(circles[0].radius(), 50); 26 | assertEquals(circles[1].x(), 200); 27 | assertEquals(circles[1].y(), 100); 28 | assertEquals(circles[1].radius(), 60); 29 | assertEquals(Status.SUCCESS, gradient.status()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/Point.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | /** 23 | * A Point defined by its x and y coordinates. 24 | * 25 | * @param x the X coordinate of the point 26 | * @param y the Y coordinate of the point 27 | * @since 1.16 28 | */ 29 | public record Point(double x, double y) { 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/io/github/jwharm/cairobindings/Flag.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package io.github.jwharm.cairobindings; 21 | 22 | /** 23 | * Base class for flag types (enumerations that can be combined into bitfields) 24 | */ 25 | public interface Flag { 26 | 27 | /** 28 | * Get the integer value for an enum member 29 | * @return the integer value 30 | */ 31 | int getValue(); 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/publish-pages.yml: -------------------------------------------------------------------------------- 1 | name: Publish Pages 2 | 3 | on: 4 | release: 5 | types: [created] 6 | push: 7 | branches: 8 | - main 9 | 10 | jobs: 11 | publish: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Setup Java 15 | uses: actions/setup-java@v4 16 | with: 17 | distribution: 'temurin' 18 | java-version: 22 19 | - name: Checkout 20 | uses: actions/checkout@v4 21 | - name: Setup Gradle 22 | uses: gradle/actions/setup-gradle@v3 23 | - name: Create javadoc with Gradle Wrapper 24 | run: ./gradlew javadoc 25 | - name: Create Site Artifact 26 | run: | 27 | mkdir site 28 | mv build/docs/javadoc site/ 29 | - name: Upload Site Artifact 30 | uses: actions/upload-pages-artifact@v3 31 | with: 32 | path: 'site' 33 | pages: 34 | runs-on: ubuntu-latest 35 | needs: publish 36 | if: github.event_name == 'push' 37 | permissions: 38 | pages: write 39 | id-token: write 40 | environment: 41 | name: github-pages 42 | url: ${{ steps.deployment.outputs.page_url }} 43 | steps: 44 | - name: Deploy to GitHub Pages 45 | id: deployment 46 | uses: actions/deploy-pages@v4 47 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/Circle.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | /** 23 | * A circle defined by the x and y coordinates of the center and the radius. 24 | * 25 | * @param x x coordinate of the center 26 | * @param y y coordinate of the center 27 | * @param radius radius of the circle 28 | * @since 1.16 29 | */ 30 | public record Circle(double x, double y, double radius) { 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/RGBA.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | /** 23 | * A color with red, green, blue and alpha components 24 | * 25 | * @param red red component of color 26 | * @param green green component of color 27 | * @param blue blue component of color 28 | * @param alpha alpha component of color 29 | * @since 1.18 30 | */ 31 | public record RGBA(double red, double green, double blue, double alpha) { 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2024 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | /** 21 | * This module contains Java language bindings for the cairo 22 | * graphics library using the JEP-454 Panama FFI. The bindings are based on cairo 1.18 23 | * and work with JDK 22 or later. 24 | */ 25 | module org.freedesktop.cairo { 26 | requires static org.gnome.glib; // Optional dependency on java-gi when cairo-gobject is used 27 | exports org.freedesktop.cairo; 28 | exports org.freedesktop.freetype; 29 | exports io.github.jwharm.cairobindings; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/io/github/jwharm/cairobindings/ArenaCloseAction.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | package io.github.jwharm.cairobindings; 20 | 21 | import java.lang.foreign.Arena; 22 | import java.lang.ref.Cleaner; 23 | 24 | /** 25 | * Helper class to separate the cleanup logic from the object being cleaned 26 | * 27 | * @param arena the Arena that will be closed 28 | * @since 1.18.1 29 | */ 30 | public record ArenaCloseAction(Arena arena) implements Runnable { 31 | 32 | // Cleaner used to close the arena 33 | public static final Cleaner CLEANER = Cleaner.create(); 34 | 35 | @Override 36 | public void run() { 37 | arena.close(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/ToyFontFaceTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import org.freedesktop.cairo.FontSlant; 6 | import org.freedesktop.cairo.FontWeight; 7 | import org.freedesktop.cairo.Status; 8 | import org.freedesktop.cairo.ToyFontFace; 9 | import org.junit.jupiter.api.Test; 10 | 11 | class ToyFontFaceTest { 12 | 13 | @Test 14 | void testCreate() { 15 | ToyFontFace f = ToyFontFace.create(); 16 | assertEquals(Status.SUCCESS, f.status()); 17 | } 18 | 19 | @Test 20 | void testCreateStringFontSlantFontWeight() { 21 | ToyFontFace f = ToyFontFace.create("Arial", FontSlant.NORMAL, FontWeight.NORMAL); 22 | assertEquals(Status.SUCCESS, f.status()); 23 | } 24 | 25 | @Test 26 | void testGetFamily() { 27 | ToyFontFace f = ToyFontFace.create("Arial", FontSlant.NORMAL, FontWeight.NORMAL); 28 | assertEquals("Arial", f.getFamily()); 29 | assertEquals(Status.SUCCESS, f.status()); 30 | } 31 | 32 | @Test 33 | void testGetSlant() { 34 | ToyFontFace f = ToyFontFace.create("Arial", FontSlant.ITALIC, FontWeight.BOLD); 35 | assertEquals(FontSlant.ITALIC, f.getSlant()); 36 | assertEquals(Status.SUCCESS, f.status()); 37 | } 38 | 39 | @Test 40 | void testGetWeight() { 41 | ToyFontFace f = ToyFontFace.create("Arial", FontSlant.ITALIC, FontWeight.BOLD); 42 | assertEquals(FontWeight.BOLD, f.getWeight()); 43 | assertEquals(Status.SUCCESS, f.status()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ############################## 2 | ## Java 3 | ############################## 4 | .mtj.tmp/ 5 | *.class 6 | *.jar 7 | *.war 8 | *.ear 9 | *.nar 10 | hs_err_pid* 11 | replay_pid* 12 | 13 | ############################## 14 | ## Maven 15 | ############################## 16 | target/ 17 | pom.xml.tag 18 | pom.xml.releaseBackup 19 | pom.xml.versionsBackup 20 | pom.xml.next 21 | pom.xml.bak 22 | release.properties 23 | dependency-reduced-pom.xml 24 | buildNumber.properties 25 | .mvn/timing.properties 26 | .mvn/wrapper/maven-wrapper.jar 27 | 28 | ############################## 29 | ## Gradle 30 | ############################## 31 | bin/ 32 | build/ 33 | .gradle 34 | .gradletasknamecache 35 | gradle-app.setting 36 | !gradle-wrapper.jar 37 | 38 | ############################## 39 | ## IntelliJ 40 | ############################## 41 | out/ 42 | .idea/ 43 | .idea_modules/ 44 | *.iml 45 | *.ipr 46 | *.iws 47 | 48 | ############################## 49 | ## Eclipse 50 | ############################## 51 | .settings/ 52 | bin/ 53 | tmp/ 54 | .metadata 55 | .classpath 56 | .project 57 | *.tmp 58 | *.bak 59 | *.swp 60 | *~.nib 61 | local.properties 62 | .loadpath 63 | .factorypath 64 | 65 | ############################## 66 | ## NetBeans 67 | ############################## 68 | nbproject/private/ 69 | build/ 70 | nbbuild/ 71 | dist/ 72 | nbdist/ 73 | nbactions.xml 74 | nb-configuration.xml 75 | 76 | ############################## 77 | ## Visual Studio Code 78 | ############################## 79 | .vscode/ 80 | .code-workspace 81 | 82 | ############################## 83 | ## OS X 84 | ############################## 85 | .DS_Store 86 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/GradientTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import org.freedesktop.cairo.Gradient; 6 | import org.freedesktop.cairo.LinearGradient; 7 | import org.freedesktop.cairo.Status; 8 | import org.junit.jupiter.api.Test; 9 | 10 | class GradientTest { 11 | 12 | @Test 13 | void testAddColorStopRGB() { 14 | Gradient gradient = LinearGradient.create(0, 0, 10, 10); 15 | gradient.addColorStopRGB(0, 1, 1, 1); 16 | assertEquals(Status.SUCCESS, gradient.status()); 17 | } 18 | 19 | @Test 20 | void testAddColorStopRGBA() { 21 | Gradient gradient = LinearGradient.create(0, 0, 10, 10); 22 | gradient.addColorStopRGBA(0, 1, 1, 1, 1); 23 | assertEquals(Status.SUCCESS, gradient.status()); 24 | } 25 | 26 | @Test 27 | void testGetColorStopCount() { 28 | Gradient gradient = LinearGradient.create(0, 0, 10, 10); 29 | gradient.addColorStopRGB(0, 1, 1, 1); 30 | assertEquals(1, gradient.getColorStopCount()); 31 | assertEquals(Status.SUCCESS, gradient.status()); 32 | } 33 | 34 | @Test 35 | void testGetColorStopRGBA() { 36 | Gradient gradient = LinearGradient.create(0, 0, 10, 10); 37 | gradient.addColorStopRGBA(0, 0.5, 0.6, 0.7, 0.8); 38 | var color = gradient.getColorStopRGBA(0); 39 | assertEquals(0, color[0]); 40 | assertEquals(0.5, color[1]); 41 | assertEquals(0.6, color[2]); 42 | assertEquals(0.7, color[3]); 43 | assertEquals(0.8, color[4]); 44 | assertEquals(Status.SUCCESS, gradient.status()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/Rect.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | /** 23 | * A rectangle. 24 | *

25 | * This is one of several helper classes in Java (see also {@link RGBA} and 26 | * {@link Point}), that do not exist in the native cairo API. The difference between 27 | * {@code Rect} and {@link Rectangle} is that the latter class is part of the native 28 | * cairo API and stores its values in native memory, while {@code Rect} instances 29 | * only exist in the JVM. 30 | * 31 | * @param x X coordinate of the left side of the rectangle 32 | * @param y Y coordinate of the top side of the rectangle 33 | * @param width width of the rectangle 34 | * @param height height of the rectangle 35 | * @since 1.18.1 36 | */ 37 | public record Rect(double x, double y, double width, double height) { 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/PathTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import org.freedesktop.cairo.Context; 6 | import org.freedesktop.cairo.Format; 7 | import org.freedesktop.cairo.ImageSurface; 8 | import org.freedesktop.cairo.Path; 9 | import org.freedesktop.cairo.PathElement; 10 | import org.junit.jupiter.api.Test; 11 | 12 | public class PathTest { 13 | 14 | @Test 15 | public void testPath() throws Exception { 16 | Context cr = Context.create(ImageSurface.create(Format.ARGB32, 120, 120)); 17 | 18 | cr.moveTo(10, 20); 19 | cr.lineTo(30, 40); 20 | cr.curveTo(50, 60, 70, 80, 90, 100); 21 | cr.closePath(); // also adds an explicit move_to to the path 22 | 23 | var result = new StringBuilder(); 24 | 25 | Path path = cr.copyPath(); 26 | for (PathElement element : path) { 27 | switch (element) { 28 | case PathElement.MoveTo(double x, double y) -> result.append(String.format("move %.0f %.0f", x, y)); 29 | case PathElement.LineTo(double x, double y) -> result.append(String.format("line %.0f %.0f", x, y)); 30 | case PathElement.CurveTo(double x1, double y1, double x2, double y2, double x3, double y3) -> 31 | result.append(String.format("curve %.0f %.0f %.0f %.0f %.0f %.0f", x1, y1, x2, y2, x3, y3)); 32 | case PathElement.ClosePath() -> result.append(String.format("close")); 33 | } 34 | } 35 | 36 | assertEquals("move 10 20" + "line 30 40" + "curve 50 60 70 80 90 100" + "close" + "move 10 20", 37 | result.toString()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/freetype/FreeType2.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.freetype; 21 | 22 | import io.github.jwharm.cairobindings.LibLoad; 23 | import io.github.jwharm.cairobindings.Platform; 24 | 25 | /** 26 | * This class contains global declarations that do not belong in a specific 27 | * FreeType class definition. 28 | */ 29 | public class FreeType2 { 30 | 31 | static { 32 | switch (Platform.getRuntimePlatform()) { 33 | case "linux" -> LibLoad.loadLibrary("libfreetype.so.6"); 34 | case "windows" -> LibLoad.loadLibrary("libfreetype-6.dll"); 35 | case "macos" -> LibLoad.loadLibrary("libfreetype.6.dylib"); 36 | } 37 | } 38 | 39 | /** 40 | * Ensures the class initializer has loaded the freetype library. 41 | */ 42 | public static void ensureInitialized() { 43 | } 44 | 45 | // Prohibit instantiation 46 | private FreeType2() { 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/UserScaledFontTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import org.freedesktop.cairo.*; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.io.IOException; 7 | import java.util.concurrent.atomic.AtomicBoolean; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertEquals; 10 | import static org.junit.jupiter.api.Assertions.assertTrue; 11 | 12 | public class UserScaledFontTest { 13 | 14 | @Test 15 | void testForegroundMarker() throws IOException { 16 | UserFontFace uf = UserFontFace.create(); 17 | AtomicBoolean flag = new AtomicBoolean(false); 18 | uf.setRenderColorGlyphFunc((font, glyph, cr, extents) -> { 19 | Pattern p = font.getForegroundMarker(); 20 | flag.set(Status.SUCCESS.equals(p.status())); 21 | }); 22 | try (SVGSurface s = SVGSurface.create((String) null, 120, 120)) { 23 | Context cr = Context.create(s); 24 | cr.setFontFace(uf); 25 | cr.showText("test"); 26 | assertTrue(flag.get()); 27 | assertEquals(Status.SUCCESS, uf.status()); 28 | } 29 | } 30 | 31 | @Test 32 | void testForegroundSource() throws IOException { 33 | UserFontFace uf = UserFontFace.create(); 34 | AtomicBoolean flag = new AtomicBoolean(false); 35 | uf.setRenderColorGlyphFunc((font, glyph, cr, extents) -> { 36 | Pattern p = font.getForegroundSource(); 37 | flag.set(Status.SUCCESS.equals(p.status())); 38 | }); 39 | try (SVGSurface s = SVGSurface.create((String) null, 120, 120)) { 40 | Context cr = Context.create(s); 41 | cr.setFontFace(uf); 42 | cr.showText("test"); 43 | assertTrue(flag.get()); 44 | assertEquals(Status.SUCCESS, uf.status()); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/freetype/package-info.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2024 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | /** 21 | * Minimal wrapper for FreeType, for use with cairo FTFontFace and FTScaledFont. 22 | *

23 | * To use this wrapper, make sure that FreeType is installed and in the Java library path. 24 | * 25 | *

    26 | *
  • {@code libfreetype.6.so} on Linux 27 | *
  • {@code freetype-6.dll} on Windows 28 | *
  • {@code libfreetype.6.dylib} on MacOS 29 | *
30 | * 31 | * Example usage of the wrapper, using a Windows-style path to load {@code arial.ttf}: 32 | * 33 | *
{@code
34 |  * Library ftLib = Library.initFreeType();
35 |  * Face ftFace = new Face(ftLib, "C:\\Windows\\Fonts\\arial.ttf", 0);
36 |  * 
37 |  * // Create a font face for FreeType
38 |  * FTFontFace face = FTFontFace.create(ftFace, 0);
39 |  * 
40 |  * // Create a scaled font from the FreeType font backend
41 |  * FTScaledFont scaledFont = FTScaledFont.create(face, matrix, ctm, options);
42 |  * }
43 | */ 44 | package org.freedesktop.freetype; 45 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/ScriptMode.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | /** 23 | * A set of script output variants. 24 | * 25 | * @since 1.12 26 | */ 27 | public enum ScriptMode { 28 | 29 | /** 30 | * the output will be in readable text (default). 31 | * 32 | * @since 1.12 33 | */ 34 | ASCII, 35 | 36 | /** 37 | * the output will use byte codes. 38 | * 39 | * @since 1.12 40 | */ 41 | BINARY; 42 | 43 | /** 44 | * Return the value of this enum 45 | * @return the value 46 | */ 47 | public int getValue() { 48 | return ordinal(); 49 | } 50 | 51 | /** 52 | * Returns the enum constant for the given ordinal (its position in the enum 53 | * declaration). 54 | * 55 | * @param ordinal the position in the enum declaration, starting from zero 56 | * @return the enum constant for the given ordinal 57 | */ 58 | public static ScriptMode of(int ordinal) { 59 | return values()[ordinal]; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/SurfaceObserverMode.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | /** 23 | * Whether operations should be recorded. 24 | * 25 | * @see SurfaceObserver 26 | * @see Surface 27 | */ 28 | public enum SurfaceObserverMode { 29 | 30 | /** 31 | * no recording is done 32 | * 33 | * @since 1.12 34 | */ 35 | NORMAL, 36 | 37 | /** 38 | * operations are recorded 39 | * 40 | * @since 1.12 41 | */ 42 | RECORD_OPERATIONS; 43 | 44 | /** 45 | * Return the value of this enum 46 | * @return the value 47 | */ 48 | public int getValue() { 49 | return ordinal(); 50 | } 51 | 52 | /** 53 | * Returns the enum constant for the given ordinal (its position in the enum 54 | * declaration). 55 | * 56 | * @param ordinal the position in the enum declaration, starting from zero 57 | * @return the enum constant for the given ordinal 58 | */ 59 | public static SurfaceObserverMode of(int ordinal) { 60 | return values()[ordinal]; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/io/github/jwharm/cairobindings/Platform.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package io.github.jwharm.cairobindings; 21 | 22 | /** 23 | * The Platform class provides utility functions to retrieve the runtime platform 24 | * and check if a function is supported on the runtime platform. 25 | */ 26 | public final class Platform { 27 | 28 | private static String runtimePlatform = null; 29 | 30 | // Prevent instantiation 31 | private Platform() {} 32 | 33 | /** 34 | * Determine the runtime platform 35 | * @return the runtime platform: "windows", "linux" or "macos" 36 | */ 37 | public static String getRuntimePlatform() { 38 | if (runtimePlatform == null) { 39 | String osName = System.getProperty("os.name").toLowerCase(); 40 | if (osName.contains("windows")) { 41 | runtimePlatform = "windows"; 42 | } else if (osName.contains("linux")) { 43 | runtimePlatform = "linux"; 44 | } else { 45 | runtimePlatform = "macos"; 46 | } 47 | } 48 | return runtimePlatform; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/SVGSurfaceTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import org.freedesktop.cairo.*; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.io.IOException; 7 | import java.io.OutputStream; 8 | import java.util.concurrent.atomic.AtomicBoolean; 9 | 10 | import static org.junit.jupiter.api.Assertions.*; 11 | 12 | class SVGSurfaceTest { 13 | 14 | @Test 15 | void testCreateStringIntInt() { 16 | try (SVGSurface s = SVGSurface.create((String) null, 120, 120)) { 17 | assertEquals(Status.SUCCESS, s.status()); 18 | } 19 | } 20 | 21 | @Test 22 | void testCreateOutputStreamIntInt() throws IOException { 23 | AtomicBoolean success = new AtomicBoolean(); 24 | OutputStream stream = new OutputStream() { 25 | @Override 26 | public void write(int b) { 27 | success.set(true); 28 | } 29 | }; 30 | try (SVGSurface s = SVGSurface.create(stream, 120, 120)) { 31 | Context cr = Context.create(s); 32 | cr.rectangle(10, 10, 20, 20); 33 | cr.fill(); 34 | assertEquals(Status.SUCCESS, s.status()); 35 | } 36 | assertTrue(success.get()); 37 | } 38 | 39 | @Test 40 | void testGetDocumentUnit() { 41 | try (SVGSurface s = SVGSurface.create((String) null, 120, 120)) { 42 | s.getDocumentUnit(); 43 | assertEquals(Status.SUCCESS, s.status()); 44 | } 45 | } 46 | 47 | @Test 48 | void testSetDocumentUnit() { 49 | try (SVGSurface s = SVGSurface.create((String) null, 120, 120)) { 50 | s.setDocumentUnit(SVGUnit.CM); 51 | assertEquals(Status.SUCCESS, s.status()); 52 | } 53 | } 54 | 55 | @Test 56 | void testRestrictToVersion() { 57 | try (SVGSurface s = SVGSurface.create((String) null, 120, 120)) { 58 | s.restrictToVersion(SVGVersion.VERSION_1_2); 59 | assertEquals(Status.SUCCESS, s.status()); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/ScriptSurface.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import java.lang.foreign.MemorySegment; 23 | 24 | /** 25 | * The script surface provides the ability to render to a native script that 26 | * matches the cairo drawing model. The scripts can be replayed using tools 27 | * under the util/cairo-script directory, or with cairo-perf-trace. 28 | * 29 | * @see Surface 30 | * @see Script 31 | * @since 1.12 32 | */ 33 | public final class ScriptSurface extends Surface { 34 | 35 | static { 36 | Cairo.ensureInitialized(); 37 | } 38 | 39 | /* 40 | * Keep a reference to the Script and the wrapped Surface instances during the 41 | * lifetime of the ScriptSurface. 42 | */ 43 | Script script; 44 | Surface target; 45 | 46 | /** 47 | * Constructor used internally to instantiate a java ScriptSurface object for a 48 | * native {@code cairo_surface_t} instance 49 | * 50 | * @param address the memory address of the native {@code cairo_surface_t} 51 | * instance 52 | */ 53 | public ScriptSurface(MemorySegment address) { 54 | super(address); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/UserDataKey.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Proxy; 23 | 24 | import java.lang.foreign.*; 25 | 26 | /** 27 | * UserDataKey is used for attaching user data to cairo data structures. 28 | * 29 | * @since 1.0 30 | */ 31 | public final class UserDataKey extends Proxy { 32 | 33 | static MemoryLayout getMemoryLayout() { 34 | return MemoryLayout.structLayout( 35 | ValueLayout.JAVA_INT.withName("unused") 36 | ).withName("cairo_user_data_key_t"); 37 | } 38 | 39 | /** 40 | * Constructor used internally to instantiate a java UserDataKey object for a 41 | * native {@code UserDataKey} instance 42 | * 43 | * @param address the memory address of the native {@code UserDataKey} instance 44 | */ 45 | public UserDataKey(MemorySegment address) { 46 | super(address); 47 | } 48 | 49 | /** 50 | * Create a new UserDataKey 51 | * 52 | * @param arena the arena in which the returned UserDataKey will be allocated 53 | * @return the newly created UserDataKey 54 | */ 55 | public static UserDataKey create(Arena arena) { 56 | return new UserDataKey(arena.allocate(getMemoryLayout())); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/RecordingSurfaceTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import org.freedesktop.cairo.*; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.io.IOException; 7 | import java.lang.foreign.Arena; 8 | 9 | import static org.junit.jupiter.api.Assertions.*; 10 | 11 | class RecordingSurfaceTest { 12 | 13 | @Test 14 | void testCreate() throws IOException { 15 | try (Arena arena = Arena.ofConfined(); 16 | Surface s = ImageSurface.create(Format.ARGB32, 120, 120); 17 | RecordingSurface r = RecordingSurface.create(Content.COLOR_ALPHA, Rectangle.create(arena, 20, 20, 50, 50))) { 18 | assertEquals(Status.SUCCESS, s.status()); 19 | assertEquals(Status.SUCCESS, r.status()); 20 | } 21 | } 22 | 23 | @Test 24 | void testInkExtents() throws IOException { 25 | try (Surface s = ImageSurface.create(Format.ARGB32, 120, 120); 26 | RecordingSurface r = RecordingSurface.create(Content.COLOR_ALPHA, null)) { 27 | Context.create(r) 28 | .rectangle(12, 14, 16, 18) 29 | .fill(); 30 | Rect rect = r.inkExtents(); 31 | assertEquals(12, rect.x()); 32 | assertEquals(14, rect.y()); 33 | assertEquals(16, rect.width()); 34 | assertEquals(18, rect.height()); 35 | assertEquals(Status.SUCCESS, s.status()); 36 | assertEquals(Status.SUCCESS, r.status()); 37 | } 38 | } 39 | 40 | @Test 41 | void testGetExtents() { 42 | try (Arena arena = Arena.ofConfined(); 43 | Surface s = ImageSurface.create(Format.ARGB32, 120, 120); 44 | RecordingSurface r = RecordingSurface.create(Content.COLOR_ALPHA, Rectangle.create(arena, 20, 30, 50, 60))) { 45 | Rectangle rect = Rectangle.create(arena, 0, 0, 0, 0); 46 | r.getExtents(rect); 47 | assertEquals(20, rect.x()); 48 | assertEquals(30, rect.y()); 49 | assertEquals(50, rect.width()); 50 | assertEquals(60, rect.height()); 51 | assertEquals(Status.SUCCESS, s.status()); 52 | assertEquals(Status.SUCCESS, r.status()); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/DeviceTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import org.freedesktop.cairo.*; 4 | import org.junit.jupiter.api.Test; 5 | import org.junit.jupiter.api.io.TempDir; 6 | 7 | import java.lang.foreign.Arena; 8 | import java.nio.file.Path; 9 | 10 | import static org.junit.jupiter.api.Assertions.*; 11 | 12 | class DeviceTest { 13 | 14 | @TempDir 15 | Path tempDir; 16 | 17 | @Test 18 | void status() { 19 | try (Device d = Script.create(tempDir.resolve("test.script").toString())) { 20 | assertEquals(Status.SUCCESS, d.status()); 21 | } 22 | } 23 | 24 | @Test 25 | void finish() { 26 | try (Device d = Script.create(tempDir.resolve("test.script").toString())) { 27 | d.finish(); 28 | assertEquals(Status.SUCCESS, d.status()); 29 | } 30 | } 31 | 32 | @Test 33 | void flush() { 34 | try (Device d = Script.create(tempDir.resolve("test.script").toString())) { 35 | d.flush(); 36 | assertEquals(Status.SUCCESS, d.status()); 37 | } 38 | } 39 | 40 | @Test 41 | void getDeviceType() { 42 | try (Device d = Script.create(tempDir.resolve("test.script").toString())) { 43 | DeviceType type = d.getDeviceType(); 44 | assertEquals(DeviceType.SCRIPT, type); 45 | assertEquals(Status.SUCCESS, d.status()); 46 | } 47 | } 48 | 49 | @Test 50 | void acquireAndRelease() { 51 | try (Device d = Script.create(tempDir.resolve("test.script").toString())) { 52 | d.acquire(); 53 | d.release(); 54 | assertEquals(d.status(), Status.SUCCESS); 55 | } 56 | } 57 | 58 | @Test 59 | void testUserData() { 60 | try (Arena arena = Arena.ofConfined(); 61 | Device device = Script.create(tempDir.resolve("test.script").toString())) { 62 | Rectangle input = Rectangle.create(arena, 0, 0, 10, 10); 63 | UserDataKey key = UserDataKey.create(arena); 64 | device.setUserData(key, input.handle()); 65 | Rectangle output = new Rectangle(device.getUserData(key)); 66 | assertEquals(input, output); 67 | assertEquals(device.status(), Status.SUCCESS); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/PatternTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import static org.junit.jupiter.api.Assertions.*; 4 | 5 | import org.freedesktop.cairo.*; 6 | import org.junit.jupiter.api.Disabled; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import java.lang.foreign.Arena; 10 | 11 | class PatternTest { 12 | 13 | @Test 14 | void testStatus() { 15 | Gradient pattern = LinearGradient.create(0, 0, 10, 10); 16 | assertEquals(Status.SUCCESS, pattern.status()); 17 | } 18 | 19 | @Test 20 | void testExtend() { 21 | Gradient pattern = LinearGradient.create(0, 0, 10, 10); 22 | pattern.setExtend(Extend.PAD); 23 | Extend e = pattern.getExtend(); 24 | assertEquals(Extend.PAD, e); 25 | assertEquals(Status.SUCCESS, pattern.status()); 26 | } 27 | 28 | @Test 29 | void testFilter() { 30 | Gradient pattern = LinearGradient.create(0, 0, 10, 10); 31 | pattern.setFilter(Filter.NEAREST); 32 | Filter f = pattern.getFilter(); 33 | assertEquals(Filter.NEAREST, f); 34 | assertEquals(Status.SUCCESS, pattern.status()); 35 | } 36 | 37 | @Test 38 | void testMatrix() { 39 | try (Arena arena = Arena.ofConfined()) { 40 | Gradient pattern = LinearGradient.create(0, 0, 10, 10); 41 | Matrix scale = Matrix.create(arena).initIdentity(); 42 | scale.scale(2, 2); 43 | pattern.setMatrix(scale); 44 | Matrix m = Matrix.create(arena).init(0, 0, 0, 0, 0, 0); 45 | pattern.getMatrix(m); 46 | assertEquals(Status.SUCCESS, pattern.status()); 47 | } 48 | } 49 | 50 | @Test 51 | void testGetPatternType() { 52 | Gradient pattern = LinearGradient.create(0, 0, 10, 10); 53 | assertEquals(PatternType.LINEAR, pattern.getPatternType()); 54 | assertEquals(Status.SUCCESS, pattern.status()); 55 | } 56 | 57 | @Disabled("Does not work with cairo 1.17.8 (Fedora 38, Gnome 45 Flatpak SDK)") 58 | @Test 59 | void testDither() { 60 | Pattern pattern = LinearGradient.create(0, 0, 10, 10); 61 | pattern.setDither(Dither.FAST); 62 | assertEquals(Dither.FAST, pattern.getDither()); 63 | assertEquals(Status.SUCCESS, pattern.status()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/PDFOutlineFlags.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Flag; 23 | 24 | /** 25 | * {@code PDFOutlineFlags} is used by the cairo_pdf_surface_add_outline() 26 | * function specify the attributes of an outline item. These flags may be 27 | * bitwise-or'd to produce any combination of flags. 28 | * 29 | * @since 1.16 30 | */ 31 | public enum PDFOutlineFlags implements Flag { 32 | 33 | /** 34 | * The outline item defaults to open in the PDF viewer 35 | * 36 | * @since 1.16 37 | */ 38 | OPEN, 39 | 40 | /** 41 | * The outline item is displayed by the viewer in bold text 42 | * 43 | * @since 1.16 44 | */ 45 | BOLD, 46 | 47 | /** 48 | * The outline item is displayed by the viewer in italic text 49 | * 50 | * @since 1.16 51 | */ 52 | ITALIC; 53 | 54 | /** 55 | * Return the value of this enum 56 | * @return the value 57 | */ 58 | public int getValue() { 59 | return ordinal(); 60 | } 61 | 62 | /** 63 | * Returns the enum constant for the given ordinal (its position in the enum 64 | * declaration). 65 | * 66 | * @param ordinal the position in the enum declaration, starting from zero 67 | * @return the enum constant for the given ordinal 68 | */ 69 | public static PDFOutlineFlags of(int ordinal) { 70 | return values()[ordinal]; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/ColorMode.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | /** 23 | * Specifies if color fonts are to be rendered using the color glyphs or 24 | * outline glyphs. Glyphs that do not have a color presentation, and 25 | * non-color fonts are not affected by this font option. 26 | * 27 | * @since 1.18 28 | */ 29 | public enum ColorMode { 30 | 31 | /** 32 | * Use the default color mode for font backend and target device 33 | * 34 | * @since 1.18 35 | */ 36 | DEFAULT, 37 | 38 | /** 39 | * Disable rendering color glyphs. Glyphs are always rendered as outline 40 | * glyphs 41 | * 42 | * @since 1.18 43 | */ 44 | NO_COLOR, 45 | 46 | /** 47 | * Enable rendering color glyphs. If the font contains a color presentation 48 | * for a glyph, and when supported by the font backend, the glyph will be 49 | * rendered in color 50 | * 51 | * @since 1.18 52 | */ 53 | COLOR; 54 | 55 | /** 56 | * Return the value of this enum 57 | * 58 | * @return the value 59 | */ 60 | public int getValue() { 61 | return ordinal(); 62 | } 63 | 64 | /** 65 | * Returns the enum constant for the given ordinal (its position in the enum 66 | * declaration). 67 | * 68 | * @param ordinal the position in the enum declaration, starting from zero 69 | * @return the enum constant for the given ordinal 70 | */ 71 | public static ColorMode of(int ordinal) { 72 | return values()[ordinal]; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/io/github/jwharm/cairobindings/Proxy.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package io.github.jwharm.cairobindings; 21 | 22 | import java.lang.foreign.MemorySegment; 23 | 24 | /** 25 | * Base type for a Java proxy object to an instance in native memory. 26 | */ 27 | public class Proxy { 28 | 29 | private final MemorySegment address; 30 | 31 | /** 32 | * Create a new {@code Proxy} object for an instance in native memory. 33 | * @param address the memory address of the instance 34 | */ 35 | public Proxy(MemorySegment address) { 36 | this.address = address; 37 | MemoryCleaner.register(this); 38 | } 39 | 40 | /** 41 | * Get the memory address of the instance 42 | * @return the memory address of the instance 43 | */ 44 | public MemorySegment handle() { 45 | return address; 46 | } 47 | 48 | /** 49 | * Returns the hashcode of the memory address 50 | * @return the hashcode of the memory address 51 | * @see MemorySegment#hashCode() 52 | */ 53 | public int hashCode() { 54 | return address.hashCode(); 55 | } 56 | 57 | /** 58 | * Checks whether the other object is a Proxy instance and the memory 59 | * addresses are equal. 60 | * @param obj another object 61 | * @return true when the other object is a Proxy instance and the memory 62 | * addresses are equal, otherwise false. 63 | * @see MemorySegment#equals(Object) 64 | */ 65 | @Override 66 | public boolean equals(Object obj) { 67 | return obj instanceof Proxy other 68 | && address.equals(other.address); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/FTFontFaceTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import org.freedesktop.cairo.FTFontFace; 6 | import org.freedesktop.cairo.FTSynthesize; 7 | import org.freedesktop.cairo.Status; 8 | import org.freedesktop.freetype.Face; 9 | import org.freedesktop.freetype.Library; 10 | import org.junit.jupiter.api.BeforeAll; 11 | import org.junit.jupiter.api.Test; 12 | 13 | import io.github.jwharm.cairobindings.Platform; 14 | 15 | import java.io.File; 16 | import java.util.Set; 17 | 18 | class FTFontFaceTest { 19 | 20 | private static String TTF_FILE; 21 | 22 | @BeforeAll 23 | static void setup() { 24 | // These files are going to be in different locations depending on your system. 25 | switch (Platform.getRuntimePlatform()) { 26 | case "linux" -> { 27 | // Fedora 28 | TTF_FILE = "/usr/share/fonts/liberation-serif/LiberationSerif-Regular.ttf"; 29 | if (! new File(TTF_FILE).exists()) { 30 | // Ubuntu 31 | TTF_FILE = "/usr/share/fonts/truetype/liberation/LiberationSerif-Regular.ttf"; 32 | } 33 | if (! new File(TTF_FILE).exists()) { 34 | // OpenSUSE 35 | TTF_FILE = "/usr/share/fonts/truetype/LiberationSerif-Regular.ttf"; 36 | } 37 | } 38 | case "windows" -> TTF_FILE = "C:\\Windows\\Fonts\\arial.ttf"; 39 | case "macos" -> TTF_FILE = "/Library/Fonts/Arial Unicode.ttf"; 40 | } 41 | } 42 | 43 | @Test 44 | void testCreate() { 45 | Library ftLib = Library.initFreeType(); 46 | Face ftFace = Face.newFace(ftLib, TTF_FILE, 0); 47 | FTFontFace face = FTFontFace.create(ftFace, 0); 48 | assertEquals(Status.SUCCESS, face.status()); 49 | ftFace.doneFace(); 50 | ftLib.doneFreeType(); 51 | } 52 | 53 | @Test 54 | void testSynthesize() { 55 | Library ftLib = Library.initFreeType(); 56 | Face ftFace = Face.newFace(ftLib, TTF_FILE, 0); 57 | FTFontFace face = FTFontFace.create(ftFace, 0); 58 | face.setSynthesize(Set.of(FTSynthesize.BOLD, FTSynthesize.OBLIQUE)); 59 | face.unsetSynthesize(Set.of(FTSynthesize.BOLD)); 60 | assertEquals(Set.of(FTSynthesize.OBLIQUE), face.getSynthesize()); 61 | assertEquals(Status.SUCCESS, face.status()); 62 | ftFace.doneFace(); 63 | ftLib.doneFreeType(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/PDFMetadata.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | /** 23 | * {@code PDFMetadata} is used by the cairo_pdf_surface_set_metadata() function 24 | * specify the metadata to set. 25 | * 26 | * @since 1.16 27 | */ 28 | public enum PDFMetadata { 29 | 30 | /** 31 | * The document title 32 | * 33 | * @since 1.16 34 | */ 35 | TITLE, 36 | 37 | /** 38 | * The document author 39 | * 40 | * @since 1.16 41 | */ 42 | AUTHOR, 43 | 44 | /** 45 | * The document subject 46 | * 47 | * @since 1.16 48 | */ 49 | SUBJECT, 50 | 51 | /** 52 | * The document keywords 53 | * 54 | * @since 1.16 55 | */ 56 | KEYWORDS, 57 | 58 | /** 59 | * The document creator 60 | * 61 | * @since 1.16 62 | */ 63 | CREATOR, 64 | 65 | /** 66 | * The document creation date 67 | * 68 | * @since 1.16 69 | */ 70 | CREATE_DATE, 71 | 72 | /** 73 | * The document modification date 74 | * 75 | * @since 1.16 76 | */ 77 | MOD_DATE; 78 | 79 | /** 80 | * Return the value of this enum 81 | * @return the value 82 | */ 83 | public int getValue() { 84 | return ordinal(); 85 | } 86 | 87 | /** 88 | * Returns the enum constant for the given ordinal (its position in the enum 89 | * declaration). 90 | * 91 | * @param ordinal the position in the enum declaration, starting from zero 92 | * @return the enum constant for the given ordinal 93 | */ 94 | public static PDFMetadata of(int ordinal) { 95 | return values()[ordinal]; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/RasterSourceTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import org.freedesktop.cairo.Content; 6 | import org.freedesktop.cairo.RasterSource; 7 | import org.freedesktop.cairo.RasterSourceAcquireFunc; 8 | import org.freedesktop.cairo.RasterSourceCopyFunc; 9 | import org.freedesktop.cairo.RasterSourceFinishFunc; 10 | import org.freedesktop.cairo.RasterSourceReleaseFunc; 11 | import org.freedesktop.cairo.RasterSourceSnapshotFunc; 12 | import org.freedesktop.cairo.Status; 13 | import org.junit.jupiter.api.Test; 14 | 15 | class RasterSourceTest { 16 | 17 | @Test 18 | void testCreate() { 19 | RasterSource source = RasterSource.create(Content.COLOR_ALPHA, 100, 100); 20 | assertEquals(Status.SUCCESS, source.status()); 21 | } 22 | 23 | @Test 24 | void testAcquireAndRelease() { 25 | RasterSource source = RasterSource.create(Content.COLOR_ALPHA, 100, 100); 26 | RasterSourceAcquireFunc acquireFunc = (pattern, target, extents) -> null; 27 | RasterSourceReleaseFunc releaseFunc = (pattern, target) -> {}; 28 | source.setAcquire(acquireFunc, releaseFunc); 29 | assertEquals(acquireFunc, source.getAcquire()); 30 | assertEquals(releaseFunc, source.getRelease()); 31 | assertEquals(Status.SUCCESS, source.status()); 32 | } 33 | 34 | @Test 35 | void testSnapshot() { 36 | RasterSource source = RasterSource.create(Content.COLOR_ALPHA, 100, 100); 37 | RasterSourceSnapshotFunc s1 = (pattern) -> null; 38 | source.setSnapshot(s1); 39 | RasterSourceSnapshotFunc s2 = source.getSnapshot(); 40 | assertEquals(s1, s2); 41 | assertEquals(Status.SUCCESS, source.status()); 42 | } 43 | 44 | @Test 45 | void testCopy() { 46 | RasterSource source = RasterSource.create(Content.COLOR_ALPHA, 100, 100); 47 | RasterSourceCopyFunc c1 = (pattern, other) -> null; 48 | source.setCopy(c1); 49 | RasterSourceCopyFunc c2 = source.getCopy(); 50 | assertEquals(c1, c2); 51 | assertEquals(Status.SUCCESS, source.status()); 52 | } 53 | 54 | @Test 55 | void testFinish() { 56 | RasterSource source = RasterSource.create(Content.COLOR_ALPHA, 100, 100); 57 | RasterSourceFinishFunc f1 = (pattern) -> {}; 58 | source.setFinish(f1); 59 | RasterSourceFinishFunc f2 = source.getFinish(); 60 | assertEquals(f1, f2); 61 | assertEquals(Status.SUCCESS, source.status()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/FontOptionsTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import org.freedesktop.cairo.*; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | 8 | class FontOptionsTest { 9 | 10 | @Test 11 | void testAntialias() { 12 | FontOptions fo = FontOptions.create(); 13 | fo.setAntialias(Antialias.FAST); 14 | assertEquals(Antialias.FAST, fo.getAntialias()); 15 | assertEquals(Status.SUCCESS, fo.status()); 16 | } 17 | 18 | @Test 19 | void testSubpixelOrder() { 20 | FontOptions fo = FontOptions.create(); 21 | fo.setSubpixelOrder(SubpixelOrder.BGR); 22 | assertEquals(SubpixelOrder.BGR, fo.getSubpixelOrder()); 23 | assertEquals(Status.SUCCESS, fo.status()); 24 | } 25 | 26 | @Test 27 | void testHintStyle() { 28 | FontOptions fo = FontOptions.create(); 29 | fo.setHintStyle(HintStyle.SLIGHT); 30 | assertEquals(HintStyle.SLIGHT, fo.getHintStyle()); 31 | assertEquals(Status.SUCCESS, fo.status()); 32 | } 33 | 34 | @Test 35 | void testHintMetrics() { 36 | FontOptions fo = FontOptions.create(); 37 | fo.setHintMetrics(HintMetrics.OFF); 38 | assertEquals(HintMetrics.OFF, fo.getHintMetrics()); 39 | assertEquals(Status.SUCCESS, fo.status()); 40 | } 41 | 42 | @Test 43 | void testVariations() { 44 | FontOptions fo = FontOptions.create(); 45 | fo.setVariations("wght=200,wdth=140.5"); 46 | assertEquals("wght=200,wdth=140.5", fo.getVariations()); 47 | assertEquals(Status.SUCCESS, fo.status()); 48 | } 49 | 50 | @Test 51 | void testColorMode() { 52 | FontOptions fo = FontOptions.create(); 53 | fo.setColorMode(ColorMode.NO_COLOR); 54 | assertEquals(ColorMode.NO_COLOR, fo.getColorMode()); 55 | assertEquals(Status.SUCCESS, fo.status()); 56 | } 57 | 58 | @Test 59 | void testColorPalette() { 60 | FontOptions fo = FontOptions.create(); 61 | fo.setColorPalette(FontOptions.COLOR_PALETTE_DEFAULT); 62 | assertEquals(FontOptions.COLOR_PALETTE_DEFAULT, fo.getColorPalette()); 63 | assertEquals(Status.SUCCESS, fo.status()); 64 | } 65 | 66 | @Test 67 | void testCustomColorPalette() { 68 | FontOptions fo = FontOptions.create(); 69 | fo.setCustomPaletteColor(0, 10.0, 20.0, 30.0, 40.5); 70 | assertEquals(new RGBA(10.0, 20.0, 30.0, 40.5), fo.getCustomPaletteColor(0)); 71 | assertEquals(Status.SUCCESS, fo.status()); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/FTSynthesize.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Flag; 23 | 24 | /** 25 | * A set of synthesis options to control how FreeType renders the glyphs for a particular font face. 26 | *

27 | * Individual synthesis features of a {@link FTFontFace} can be set using 28 | * {@link FTFontFace#setSynthesize}, or disabled using {@link FTFontFace#unsetSynthesize}. 29 | * The currently enabled set of synthesis options can be queried with {@link FTFontFace#getSynthesize}. 30 | *

31 | * Note that when synthesizing glyphs, the font metrics returned will only be estimates. 32 | * 33 | * @since 1.12 34 | */ 35 | public enum FTSynthesize implements Flag { 36 | /** 37 | * Embolden the glyphs (redraw with a pixel offset) 38 | */ 39 | BOLD(1), 40 | 41 | /** 42 | * Slant the glyph outline by 12 degrees to the right. 43 | */ 44 | OBLIQUE(1 << 1); 45 | 46 | private final int value; 47 | 48 | /** 49 | * Create a new FTSynthesize enum value 50 | * 51 | * @param value {@link #BOLD}, {@link #OBLIQUE} or a combination of both 52 | */ 53 | FTSynthesize(int value) { 54 | this.value = value; 55 | } 56 | 57 | /** 58 | * Get the value of this FTSynthesize enum 59 | * 60 | * @return {@link #BOLD}, {@link #OBLIQUE} or a combination of both 61 | */ 62 | public int getValue() { 63 | return value; 64 | } 65 | 66 | /** 67 | * Create an FTSynthesize enum for this value 68 | * 69 | * @param value the value of the enum 70 | * @return a new FTSynthesize enum member 71 | */ 72 | public static FTSynthesize of(int value) { 73 | return value == 1 ? BOLD : OBLIQUE; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/ScriptTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import org.freedesktop.cairo.*; 4 | import org.junit.jupiter.api.Test; 5 | import org.junit.jupiter.api.io.TempDir; 6 | 7 | import java.io.OutputStream; 8 | import java.nio.file.Path; 9 | import java.util.concurrent.atomic.AtomicBoolean; 10 | 11 | import static org.junit.jupiter.api.Assertions.*; 12 | 13 | class ScriptTest { 14 | 15 | @TempDir 16 | Path tempDir; 17 | 18 | @Test 19 | void testCreateString() { 20 | try (Script s = Script.create(tempDir.resolve("test.script").toString())) { 21 | assertEquals(Status.SUCCESS, s.status()); 22 | } 23 | } 24 | 25 | @Test 26 | void testCreateOutputStream() { 27 | AtomicBoolean success = new AtomicBoolean(); 28 | OutputStream stream = new OutputStream() { 29 | @Override 30 | public void write(int b) { 31 | success.set(true); 32 | } 33 | }; 34 | try (Script s = Script.create(stream)) { 35 | assertEquals(Status.SUCCESS, s.status()); 36 | } 37 | assertTrue(success.get()); 38 | } 39 | 40 | @Test 41 | void testFrom() { 42 | try (Script s = Script.create(tempDir.resolve("test.script").toString())) { 43 | s.from(RecordingSurface.create(Content.COLOR_ALPHA, null)); 44 | assertEquals(Status.SUCCESS, s.status()); 45 | } 46 | } 47 | 48 | @Test 49 | void testMode() { 50 | try (Script s = Script.create(tempDir.resolve("test.script").toString())) { 51 | s.setMode(ScriptMode.ASCII); 52 | assertEquals(ScriptMode.ASCII, s.getMode()); 53 | assertEquals(Status.SUCCESS, s.status()); 54 | } 55 | } 56 | 57 | @Test 58 | void testCreateScriptSurface() { 59 | try (Script s = Script.create(tempDir.resolve("test.script").toString())) { 60 | s.createScriptSurface(Content.COLOR, 30, 30); 61 | assertEquals(Status.SUCCESS, s.status()); 62 | } 63 | } 64 | 65 | @Test 66 | void testCreateScriptSurfaceForTarget() { 67 | try (Script s = Script.create(tempDir.resolve("test.script").toString())) { 68 | s.createScriptSurfaceForTarget(ImageSurface.create(Format.ARGB32, 120, 120)); 69 | assertEquals(Status.SUCCESS, s.status()); 70 | } 71 | } 72 | 73 | @Test 74 | void testWriteComment() { 75 | try (Script s = Script.create(tempDir.resolve("test.script").toString())) { 76 | s.writeComment("test"); 77 | assertEquals(Status.SUCCESS, s.status()); 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/PSSurfaceTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import org.freedesktop.cairo.PSLevel; 4 | import org.freedesktop.cairo.PSSurface; 5 | import org.freedesktop.cairo.Status; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.io.OutputStream; 9 | import java.util.concurrent.atomic.AtomicBoolean; 10 | 11 | import static org.junit.jupiter.api.Assertions.*; 12 | 13 | class PSSurfaceTest { 14 | 15 | @Test 16 | void testCreateStringIntInt() { 17 | try (PSSurface s = PSSurface.create((String) null, 120, 120)) { 18 | assertEquals(Status.SUCCESS, s.status()); 19 | } 20 | } 21 | 22 | @Test 23 | void testCreateOutputStreamIntInt() { 24 | AtomicBoolean success = new AtomicBoolean(); 25 | OutputStream stream = new OutputStream() { 26 | @Override 27 | public void write(int b) { 28 | success.set(true); 29 | } 30 | }; 31 | try (PSSurface s = PSSurface.create(stream, 120, 120)) { 32 | s.showPage(); 33 | assertEquals(Status.SUCCESS, s.status()); 34 | } 35 | assertTrue(success.get()); 36 | } 37 | 38 | @Test 39 | void testRestrictToLevel() { 40 | try (PSSurface s = PSSurface.create((String) null, 120, 120)) { 41 | s.restrictToLevel(PSLevel.LEVEL_3); 42 | assertEquals(Status.SUCCESS, s.status()); 43 | } 44 | } 45 | 46 | @Test 47 | void testEPS() { 48 | try (PSSurface s = PSSurface.create((String) null, 120, 120)) { 49 | s.setEPS(true); 50 | assertTrue(s.getEPS()); 51 | assertEquals(Status.SUCCESS, s.status()); 52 | } 53 | } 54 | 55 | @Test 56 | void testSetSize() { 57 | try (PSSurface s = PSSurface.create((String) null, 120, 120)) { 58 | s.setSize(140, 140); 59 | assertEquals(Status.SUCCESS, s.status()); 60 | } 61 | } 62 | 63 | @Test 64 | void testDscBeginSetup() { 65 | try (PSSurface s = PSSurface.create((String) null, 120, 120)) { 66 | s.dscBeginSetup(); 67 | assertEquals(Status.SUCCESS, s.status()); 68 | } 69 | } 70 | 71 | @Test 72 | void testDscBeginPageSetup() { 73 | try (PSSurface s = PSSurface.create((String) null, 120, 120)) { 74 | s.dscBeginPageSetup(); 75 | assertEquals(Status.SUCCESS, s.status()); 76 | } 77 | } 78 | 79 | @Test 80 | void testDscComment() { 81 | try (PSSurface s = PSSurface.create((String) null, 120, 120)) { 82 | s.dscComment("%%Title: Test"); 83 | assertEquals(Status.SUCCESS, s.status()); 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/Dither.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | /** 23 | * Dither is an intentionally applied form of noise used to randomize 24 | * quantization error, preventing large-scale patterns such as color banding in 25 | * images (e.g. for gradients). Ordered dithering applies a precomputed 26 | * threshold matrix to spread the errors smoothly. 27 | *

28 | * {@link Dither} is modeled on pixman dithering algorithm choice. As of 29 | * Pixman 0.40, FAST corresponds to a 8x8 ordered bayer noise and GOOD and BEST 30 | * use an ordered 64x64 precomputed blue noise. 31 | * 32 | * @since 1.18 33 | */ 34 | public enum Dither { 35 | 36 | /** 37 | * No dithering. 38 | * 39 | * @since 1.18 40 | */ 41 | NONE, 42 | 43 | /** 44 | * Default choice at cairo compile time. Currently NONE. 45 | * 46 | * @since 1.18 47 | */ 48 | DEFAULT, 49 | 50 | /** 51 | * Fastest dithering algorithm supported by the backend 52 | * 53 | * @since 1.18 54 | */ 55 | FAST, 56 | 57 | /** 58 | * An algorithm with smoother dithering than FAST 59 | * 60 | * @since 1.18 61 | */ 62 | GOOD, 63 | 64 | /** 65 | * Best algorithm available in the backend 66 | * 67 | * @since 1.18 68 | */ 69 | BEST; 70 | 71 | /** 72 | * Return the value of this enum 73 | * 74 | * @return the value 75 | */ 76 | public int getValue() { 77 | return ordinal(); 78 | } 79 | 80 | /** 81 | * Returns the enum constant for the given ordinal (its position in the enum 82 | * declaration). 83 | * 84 | * @param ordinal the position in the enum declaration, starting from zero 85 | * @return the enum constant for the given ordinal 86 | */ 87 | public static Dither of(int ordinal) { 88 | return values()[ordinal]; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/DestroyFunc.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import java.lang.foreign.*; 23 | import java.lang.invoke.MethodHandle; 24 | import java.lang.invoke.MethodHandles; 25 | 26 | /** 27 | * DestroyFunc the type of function which is called when a data element is 28 | * destroyed. It is passed the pointer to the data element and should free any 29 | * memory and resources allocated for it. 30 | * 31 | * @since 1.0 32 | */ 33 | @FunctionalInterface 34 | public interface DestroyFunc { 35 | 36 | /** 37 | * The function to implement as callback in a destroy operation. 38 | * 39 | * @param data the data element being destroyed. 40 | * @since 1.0 41 | */ 42 | void destroy(MemorySegment data); 43 | 44 | /** 45 | * The callback that is executed by native code. This method marshals the 46 | * parameters and calls {@link #destroy}. 47 | * 48 | * @param data the data element being destroyed. 49 | * @since 1.0 50 | */ 51 | default void upcall(MemorySegment data) { 52 | destroy(data); 53 | } 54 | 55 | /** 56 | * Generates an upcall stub, a C function pointer that will call 57 | * {@link #upcall}. 58 | * 59 | * @param arena the arena in which the upcall stub will be allocated 60 | * @return the function pointer of the upcall stub 61 | * @since 1.0 62 | */ 63 | default MemorySegment toCallback(Arena arena) { 64 | try { 65 | FunctionDescriptor fdesc = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS); 66 | MethodHandle handle = MethodHandles.lookup().findVirtual(DestroyFunc.class, "upcall", fdesc.toMethodType()); 67 | return Linker.nativeLinker().upcallStub(handle.bindTo(this), fdesc, arena); 68 | } catch (NoSuchMethodException | IllegalAccessException e) { 69 | throw new RuntimeException(e); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/FontWeight.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.ValueLayout; 26 | import java.lang.invoke.MethodHandle; 27 | 28 | /** 29 | * Specifies variants of a font face based on their weight. 30 | * 31 | * @since 1.0 32 | */ 33 | public enum FontWeight { 34 | 35 | /** 36 | * Normal font weight 37 | * 38 | * @since 1.0 39 | */ 40 | NORMAL, 41 | 42 | /** 43 | * Bold font weight 44 | * 45 | * @since 1.0 46 | */ 47 | BOLD; 48 | 49 | static { 50 | Cairo.ensureInitialized(); 51 | } 52 | 53 | /** 54 | * Return the value of this enum 55 | * 56 | * @return the value 57 | */ 58 | public int getValue() { 59 | return ordinal(); 60 | } 61 | 62 | /** 63 | * Returns the enum constant for the given ordinal (its position in the enum 64 | * declaration). 65 | * 66 | * @param ordinal the position in the enum declaration, starting from zero 67 | * @return the enum constant for the given ordinal 68 | */ 69 | public static FontWeight of(int ordinal) { 70 | return values()[ordinal]; 71 | } 72 | 73 | /** 74 | * Get the CairoFontWeight GType 75 | * @return the GType 76 | */ 77 | public static org.gnome.glib.Type getType() { 78 | try { 79 | long result = (long) cairo_gobject_font_weight_get_type.invoke(); 80 | return new org.gnome.glib.Type(result); 81 | } catch (Throwable e) { 82 | throw new RuntimeException(e); 83 | } 84 | } 85 | 86 | private static final MethodHandle cairo_gobject_font_weight_get_type = Interop.downcallHandle( 87 | "cairo_gobject_font_weight_get_type", FunctionDescriptor.of(ValueLayout.JAVA_LONG)); 88 | } 89 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/TeeSurfaceTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import io.github.jwharm.cairobindings.Interop; 4 | import org.freedesktop.cairo.*; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import java.lang.foreign.FunctionDescriptor; 8 | import java.lang.foreign.MemorySegment; 9 | import java.lang.foreign.ValueLayout; 10 | import java.lang.invoke.MethodHandle; 11 | 12 | import static org.junit.jupiter.api.Assertions.assertEquals; 13 | 14 | public class TeeSurfaceTest { 15 | 16 | @Test 17 | void testCreate() { 18 | try (Surface primary = ImageSurface.create(Format.ARGB32, 120, 120)) { 19 | TeeSurface tee = TeeSurface.create(primary); 20 | assertEquals(Status.SUCCESS, tee.status()); 21 | } 22 | } 23 | 24 | @Test 25 | void testIndex() { 26 | try (Surface primary = ImageSurface.create(Format.ARGB32, 120, 120); 27 | Surface target1 = ImageSurface.create(Format.ARGB32, 120, 120); 28 | Surface target2 = ImageSurface.create(Format.ARGB32, 120, 120)) { 29 | TeeSurface tee = TeeSurface.create(primary); 30 | tee.add(target1); 31 | tee.add(target2); 32 | 33 | assertEquals(primary, tee.index(0)); 34 | assertEquals(target1, tee.index(1)); 35 | assertEquals(target2, tee.index(2)); 36 | 37 | /* We don't actually call `cairo_tee_surface_index` in the bindings, 38 | * but we call it in the method below, to assert that the results 39 | * are the same. 40 | */ 41 | assertEquals(tee.index(0).handle(), cairo_tee_surface_index(tee, 0)); 42 | assertEquals(tee.index(1).handle(), cairo_tee_surface_index(tee, 1)); 43 | assertEquals(tee.index(2).handle(), cairo_tee_surface_index(tee, 2)); 44 | 45 | assertEquals(Status.SUCCESS, tee.status()); 46 | } 47 | } 48 | 49 | private MemorySegment cairo_tee_surface_index(Surface tee, int index) { 50 | MethodHandle cairo_tee_surface_index = Interop.downcallHandle("cairo_tee_surface_index", 51 | FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_INT)); 52 | try { 53 | return (MemorySegment) cairo_tee_surface_index.invoke(tee.handle(), index); 54 | } catch (Throwable e) { 55 | throw new RuntimeException(e); 56 | } 57 | } 58 | 59 | @Test 60 | void testAddAndRemove() { 61 | try (Surface primary = ImageSurface.create(Format.ARGB32, 120, 120); 62 | Surface target = ImageSurface.create(Format.ARGB32, 120, 120)) { 63 | TeeSurface tee = TeeSurface.create(primary); 64 | tee.add(target); 65 | tee.remove(target); 66 | assertEquals(Status.SUCCESS, tee.status()); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/SurfaceObserverCallback.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import java.lang.foreign.*; 23 | import java.lang.invoke.MethodHandle; 24 | import java.lang.invoke.MethodHandles; 25 | 26 | /** 27 | * A generic callback function for surface operations. 28 | * 29 | * @since 1.12 30 | */ 31 | @FunctionalInterface 32 | public interface SurfaceObserverCallback { 33 | 34 | /** 35 | * A generic callback function for surface operations. 36 | * 37 | * @param target the observed surface 38 | * @since 1.12 39 | */ 40 | void run(Surface target); 41 | 42 | /** 43 | * The callback that is executed by native code. This method marshals the 44 | * parameters and calls {@link #run}. 45 | * 46 | * @param observer the {@link SurfaceObserver}, ignored 47 | * @param target the observed surface 48 | * @param data ignored 49 | * @since 1.12 50 | */ 51 | default void upcall(MemorySegment observer, MemorySegment target, MemorySegment data) { 52 | run(new Surface(target)); 53 | } 54 | 55 | /** 56 | * Generates an upcall stub, a C function pointer that will call 57 | * {@link #upcall}. 58 | * 59 | * @param arena the arena in which the upcall stub will be allocated 60 | * @return the function pointer of the upcall stub 61 | * @since 1.12 62 | */ 63 | default MemorySegment toCallback(Arena arena) { 64 | try { 65 | FunctionDescriptor fdesc = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, 66 | ValueLayout.ADDRESS, ValueLayout.ADDRESS); 67 | MethodHandle handle = MethodHandles.lookup().findVirtual( 68 | SurfaceObserverCallback.class, "upcall", fdesc.toMethodType()); 69 | return Linker.nativeLinker().upcallStub(handle.bindTo(this), fdesc, arena); 70 | } catch (NoSuchMethodException | IllegalAccessException e) { 71 | throw new RuntimeException(e); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/FontSlant.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.ValueLayout; 26 | import java.lang.invoke.MethodHandle; 27 | 28 | /** 29 | * Specifies variants of a font face based on their slant. 30 | * 31 | * @since 1.0 32 | */ 33 | public enum FontSlant { 34 | 35 | /** 36 | * Upright font style 37 | * 38 | * @since 1.0 39 | */ 40 | NORMAL, 41 | 42 | /** 43 | * Italic font style 44 | * 45 | * @since 1.0 46 | */ 47 | ITALIC, 48 | 49 | /** 50 | * Oblique font style 51 | * 52 | * @since 1.0 53 | */ 54 | OBLIQUE; 55 | 56 | static { 57 | Cairo.ensureInitialized(); 58 | } 59 | 60 | /** 61 | * Return the value of this enum 62 | * 63 | * @return the value 64 | */ 65 | public int getValue() { 66 | return ordinal(); 67 | } 68 | 69 | /** 70 | * Returns the enum constant for the given ordinal (its position in the enum 71 | * declaration). 72 | * 73 | * @param ordinal the position in the enum declaration, starting from zero 74 | * @return the enum constant for the given ordinal 75 | */ 76 | public static FontSlant of(int ordinal) { 77 | return values()[ordinal]; 78 | } 79 | 80 | /** 81 | * Get the CairoFontSlant GType 82 | * @return the GType 83 | */ 84 | public static org.gnome.glib.Type getType() { 85 | try { 86 | long result = (long) cairo_gobject_font_slant_get_type.invoke(); 87 | return new org.gnome.glib.Type(result); 88 | } catch (Throwable e) { 89 | throw new RuntimeException(e); 90 | } 91 | } 92 | 93 | private static final MethodHandle cairo_gobject_font_slant_get_type = Interop.downcallHandle( 94 | "cairo_gobject_font_slant_get_type", FunctionDescriptor.of(ValueLayout.JAVA_LONG)); 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/RasterSourceFinishFunc.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import java.lang.foreign.*; 23 | import java.lang.invoke.MethodHandle; 24 | import java.lang.invoke.MethodHandles; 25 | 26 | /** 27 | * RasterSourceFinishFunc is the type of function which is called when the 28 | * pattern (or a copy thereof) is no longer required. 29 | * 30 | * @since 1.12 31 | */ 32 | @FunctionalInterface 33 | public interface RasterSourceFinishFunc { 34 | 35 | /** 36 | * Called when the pattern (or a copy thereof) is no longer required. 37 | * 38 | * @param pattern the pattern being rendered from 39 | * @since 1.12 40 | */ 41 | void finish(RasterSource pattern); 42 | 43 | /** 44 | * The callback that is executed by native code. This method marshals the 45 | * parameters and calls {@link #finish(RasterSource)}. 46 | * 47 | * @param pattern the pattern being rendered from 48 | * @param callbackData ignored 49 | * @since 1.12 50 | */ 51 | default void upcall(MemorySegment pattern, MemorySegment callbackData) { 52 | finish(new RasterSource(pattern)); 53 | } 54 | 55 | /** 56 | * Generates an upcall stub, a C function pointer that will call 57 | * {@link #upcall}. 58 | * 59 | * @param arena the arena in which the upcall stub will be allocated 60 | * @return the function pointer of the upcall stub 61 | * @since 1.12 62 | */ 63 | default MemorySegment toCallback(Arena arena) { 64 | try { 65 | FunctionDescriptor fdesc = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS); 66 | MethodHandle handle = MethodHandles.lookup().findVirtual(RasterSourceFinishFunc.class, "upcall", 67 | fdesc.toMethodType()); 68 | return Linker.nativeLinker().upcallStub(handle.bindTo(this), fdesc, arena); 69 | } catch (NoSuchMethodException | IllegalAccessException e) { 70 | throw new RuntimeException(e); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/TextClusterFlags.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.ValueLayout; 26 | import java.lang.invoke.MethodHandle; 27 | 28 | /** 29 | * Specifies properties of a text cluster mapping. 30 | * 31 | * @since 1.8 32 | */ 33 | public enum TextClusterFlags { 34 | 35 | /** 36 | * The clusters in the cluster array map to glyphs in the glyph array from end 37 | * to start. 38 | * 39 | * @since 1.8 40 | */ 41 | BACKWARD(0x00000001); 42 | 43 | static { 44 | Cairo.ensureInitialized(); 45 | } 46 | 47 | private final int value; 48 | 49 | TextClusterFlags(int value) { 50 | this.value = value; 51 | } 52 | 53 | /** 54 | * Return the value of this enum 55 | * 56 | * @return the value 57 | */ 58 | public int getValue() { 59 | return value; 60 | } 61 | 62 | /** 63 | * Returns the enum member for the given value. 64 | * 65 | * @param value the value of the enum member 66 | * @return the enum member for the given value 67 | */ 68 | public static TextClusterFlags of(int value) { 69 | if (value == 0x00000001) { 70 | return BACKWARD; 71 | } else { 72 | throw new IllegalArgumentException("No TextClusterFlags enum with value " + value); 73 | } 74 | } 75 | 76 | /** 77 | * Get the CairoTextClusterFlags GType 78 | * @return the GType 79 | */ 80 | public static org.gnome.glib.Type getType() { 81 | try { 82 | long result = (long) cairo_gobject_text_cluster_flags_get_type.invoke(); 83 | return new org.gnome.glib.Type(result); 84 | } catch (Throwable e) { 85 | throw new RuntimeException(e); 86 | } 87 | } 88 | 89 | private static final MethodHandle cairo_gobject_text_cluster_flags_get_type = Interop.downcallHandle( 90 | "cairo_gobject_text_cluster_flags_get_type", FunctionDescriptor.of(ValueLayout.JAVA_LONG)); 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/RegionOverlap.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.ValueLayout; 26 | import java.lang.invoke.MethodHandle; 27 | 28 | /** 29 | * Used as the return value for cairo_region_contains_rectangle(). 30 | * 31 | * @since 1.10 32 | */ 33 | public enum RegionOverlap { 34 | 35 | /** 36 | * The contents are entirely inside the region. 37 | * 38 | * @since 1.10 39 | */ 40 | IN, 41 | 42 | /** 43 | * The contents are entirely outside the region. 44 | * 45 | * @since 1.10 46 | */ 47 | OUT, 48 | 49 | /** 50 | * The contents are partially inside and partially outside the region. 51 | * 52 | * @since 1.10 53 | */ 54 | PART; 55 | 56 | static { 57 | Cairo.ensureInitialized(); 58 | } 59 | 60 | /** 61 | * Return the value of this enum 62 | * @return the value 63 | */ 64 | public int getValue() { 65 | return ordinal(); 66 | } 67 | 68 | /** 69 | * Returns the enum constant for the given ordinal (its position in the enum 70 | * declaration). 71 | * 72 | * @param ordinal the position in the enum declaration, starting from zero 73 | * @return the enum constant for the given ordinal 74 | */ 75 | public static RegionOverlap of(int ordinal) { 76 | return values()[ordinal]; 77 | } 78 | 79 | /** 80 | * Get the CairoRegionOverlap GType 81 | * @return the GType 82 | */ 83 | public static org.gnome.glib.Type getType() { 84 | try { 85 | long result = (long) cairo_gobject_region_overlap_get_type.invoke(); 86 | return new org.gnome.glib.Type(result); 87 | } catch (Throwable e) { 88 | throw new RuntimeException(e); 89 | } 90 | } 91 | 92 | private static final MethodHandle cairo_gobject_region_overlap_get_type = Interop.downcallHandle( 93 | "cairo_gobject_region_overlap_get_type", FunctionDescriptor.of(ValueLayout.JAVA_LONG)); 94 | } 95 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/FTScaledFontTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import io.github.jwharm.cairobindings.Platform; 6 | import org.freedesktop.cairo.FTFontFace; 7 | import org.freedesktop.cairo.FTScaledFont; 8 | import org.freedesktop.cairo.FontOptions; 9 | import org.freedesktop.cairo.Matrix; 10 | import org.freedesktop.cairo.Status; 11 | import org.freedesktop.freetype.Face; 12 | import org.freedesktop.freetype.Library; 13 | import org.junit.jupiter.api.BeforeAll; 14 | import org.junit.jupiter.api.Test; 15 | 16 | import java.io.File; 17 | import java.lang.foreign.Arena; 18 | 19 | class FTScaledFontTest { 20 | 21 | private static String TTF_FILE; 22 | 23 | @BeforeAll 24 | static void setup() { 25 | // These files are going to be in different locations depending on your system. 26 | switch (Platform.getRuntimePlatform()) { 27 | case "linux" -> { 28 | // Fedora 29 | TTF_FILE = "/usr/share/fonts/liberation-serif/LiberationSerif-Regular.ttf"; 30 | if (! new File(TTF_FILE).exists()) { 31 | // Ubuntu 32 | TTF_FILE = "/usr/share/fonts/truetype/liberation/LiberationSerif-Regular.ttf"; 33 | } 34 | if (! new File(TTF_FILE).exists()) { 35 | // OpenSUSE 36 | TTF_FILE = "/usr/share/fonts/truetype/LiberationSerif-Regular.ttf"; 37 | } 38 | } 39 | case "windows" -> TTF_FILE = "C:\\Windows\\Fonts\\arial.ttf"; 40 | case "macos" -> TTF_FILE = "/Library/Fonts/Arial Unicode.ttf"; 41 | } 42 | } 43 | 44 | @Test 45 | void testCreate() { 46 | try (Arena arena = Arena.ofConfined()) { 47 | Library ftLib = Library.initFreeType(); 48 | Face ftFace = Face.newFace(ftLib, TTF_FILE, 0); 49 | FTFontFace face = FTFontFace.create(ftFace, 0); 50 | FTScaledFont scaledFont = FTScaledFont.create(face, Matrix.create(arena).initIdentity(), Matrix.create(arena).initIdentity(), FontOptions.create()); 51 | assertEquals(Status.SUCCESS, scaledFont.status()); 52 | ftFace.doneFace(); 53 | ftLib.doneFreeType(); 54 | } 55 | } 56 | 57 | @Test 58 | void testLockAndUnlockFace() { 59 | try (Arena arena = Arena.ofConfined()) { 60 | Library ftLib = Library.initFreeType(); 61 | Face ftFace = Face.newFace(ftLib, TTF_FILE, 0); 62 | FTFontFace face = FTFontFace.create(ftFace, 0); 63 | FTScaledFont scaledFont = FTScaledFont.create(face, Matrix.create(arena).initIdentity(), Matrix.create(arena).initIdentity(), FontOptions.create()); 64 | scaledFont.lockFace(); 65 | scaledFont.unlockFace(); 66 | assertEquals(Status.SUCCESS, scaledFont.status()); 67 | ftFace.doneFace(); 68 | ftLib.doneFreeType(); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/LineCap.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.ValueLayout; 26 | import java.lang.invoke.MethodHandle; 27 | 28 | /** 29 | * Specifies how to render the endpoints of the path when stroking. 30 | *

31 | * The default line cap style is CAIRO_LINE_CAP_BUTT. 32 | */ 33 | public enum LineCap { 34 | 35 | /** 36 | * start(stop) the line exactly at the start(end) point 37 | * 38 | * @since 1.0 39 | */ 40 | BUTT, 41 | 42 | /** 43 | * use a round ending, the center of the circle is the end point 44 | * 45 | * @since 1.0 46 | */ 47 | ROUND, 48 | 49 | /** 50 | * use a squared ending, the center of the square is the end point 51 | * 52 | * @since 1.0 53 | */ 54 | SQUARE; 55 | 56 | static { 57 | Cairo.ensureInitialized(); 58 | } 59 | 60 | /** 61 | * Return the value of this enum 62 | * @return the value 63 | */ 64 | public int getValue() { 65 | return ordinal(); 66 | } 67 | 68 | /** 69 | * Returns the enum constant for the given ordinal (its position in the enum 70 | * declaration). 71 | * 72 | * @param ordinal the position in the enum declaration, starting from zero 73 | * @return the enum constant for the given ordinal 74 | */ 75 | public static LineCap of(int ordinal) { 76 | return values()[ordinal]; 77 | } 78 | 79 | /** 80 | * Get the CairoLineCap GType 81 | * @return the GType 82 | */ 83 | public static org.gnome.glib.Type getType() { 84 | try { 85 | long result = (long) cairo_gobject_line_cap_get_type.invoke(); 86 | return new org.gnome.glib.Type(result); 87 | } catch (Throwable e) { 88 | throw new RuntimeException(e); 89 | } 90 | } 91 | 92 | private static final MethodHandle cairo_gobject_line_cap_get_type = Interop.downcallHandle( 93 | "cairo_gobject_line_cap_get_type", FunctionDescriptor.of(ValueLayout.JAVA_LONG)); 94 | } -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/PathDataType.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.ValueLayout; 26 | import java.lang.invoke.MethodHandle; 27 | 28 | /** 29 | * Describes the type of one portion of a path when represented as a 30 | * {@link Path}. See {@link PathData} for details. 31 | * 32 | * @since 1.0 33 | */ 34 | public enum PathDataType { 35 | 36 | /** 37 | * A move-to operation 38 | * @since 1.0 39 | */ 40 | MOVE_TO, 41 | 42 | /** 43 | * A line-to operation 44 | * @since 1.0 45 | */ 46 | LINE_TO, 47 | 48 | /** 49 | * A curve-to operation 50 | * @since 1.0 51 | */ 52 | CURVE_TO, 53 | 54 | /** 55 | * A close-path operation 56 | * @since 1.0 57 | */ 58 | CLOSE_PATH; 59 | 60 | static { 61 | Cairo.ensureInitialized(); 62 | } 63 | 64 | /** 65 | * Return the value of this enum 66 | * @return the value 67 | */ 68 | public int getValue() { 69 | return ordinal(); 70 | } 71 | 72 | /** 73 | * Returns the enum constant for the given ordinal (its position in the enum 74 | * declaration). 75 | * 76 | * @param ordinal the position in the enum declaration, starting from zero 77 | * @return the enum constant for the given ordinal 78 | */ 79 | public static PathDataType of(int ordinal) { 80 | return values()[ordinal]; 81 | } 82 | 83 | /** 84 | * Get the CairoPathDataType GType 85 | * @return the GType 86 | */ 87 | public static org.gnome.glib.Type getType() { 88 | try { 89 | long result = (long) cairo_gobject_path_data_type_get_type.invoke(); 90 | return new org.gnome.glib.Type(result); 91 | } catch (Throwable e) { 92 | throw new RuntimeException(e); 93 | } 94 | } 95 | 96 | private static final MethodHandle cairo_gobject_path_data_type_get_type = Interop.downcallHandle( 97 | "cairo_gobject_path_data_type_get_type", FunctionDescriptor.of(ValueLayout.JAVA_LONG)); 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/LineJoin.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.ValueLayout; 26 | import java.lang.invoke.MethodHandle; 27 | 28 | /** 29 | * Specifies how to render the junction of two lines when stroking. 30 | *

31 | * The default line join style is CAIRO_LINE_JOIN_MITER. 32 | */ 33 | public enum LineJoin { 34 | 35 | /** 36 | * use a sharp (angled) corner, see cairo_set_miter_limit() 37 | * 38 | * @since 1.0 39 | */ 40 | MITER, 41 | 42 | /** 43 | * use a rounded join, the center of the circle is the joint point 44 | * 45 | * @since 1.0 46 | */ 47 | ROUND, 48 | 49 | /** 50 | * use a cut-off join, the join is cut off at half the line width from the joint 51 | * point 52 | * 53 | * @since 1.0 54 | */ 55 | BEVEL; 56 | 57 | static { 58 | Cairo.ensureInitialized(); 59 | } 60 | 61 | /** 62 | * Return the value of this enum 63 | * @return the value 64 | */ 65 | public int getValue() { 66 | return ordinal(); 67 | } 68 | 69 | /** 70 | * Returns the enum constant for the given ordinal (its position in the enum 71 | * declaration). 72 | * 73 | * @param ordinal the position in the enum declaration, starting from zero 74 | * @return the enum constant for the given ordinal 75 | */ 76 | public static LineJoin of(int ordinal) { 77 | return values()[ordinal]; 78 | } 79 | 80 | /** 81 | * Get the CairoLineJoin GType 82 | * @return the GType 83 | */ 84 | public static org.gnome.glib.Type getType() { 85 | try { 86 | long result = (long) cairo_gobject_line_join_get_type.invoke(); 87 | return new org.gnome.glib.Type(result); 88 | } catch (Throwable e) { 89 | throw new RuntimeException(e); 90 | } 91 | } 92 | 93 | private static final MethodHandle cairo_gobject_line_join_get_type = Interop.downcallHandle( 94 | "cairo_gobject_line_join_get_type", FunctionDescriptor.of(ValueLayout.JAVA_LONG)); 95 | } -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/PathElement.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | /** 23 | * The PathElement interface is a sealed type that models Path elements. It permits four records: 24 | * 25 | *

    26 | *
  • {@link PathElement.MoveTo} that corresponds with {@link Context#moveTo(double, double)} 27 | *
  • {@link PathElement.LineTo} that corresponds with {@link Context#lineTo(double, double)} 28 | *
  • {@link PathElement.CurveTo} that corresponds with {@link Context#curveTo(double, double, double, double, double, double)} 29 | *
  • {@link PathElement.ClosePath} that corresponds with {@link Context#closePath()} 30 | *
31 | * 32 | * See {@link Path} for more information about working with paths. 33 | */ 34 | public sealed interface PathElement 35 | permits PathElement.MoveTo, PathElement.LineTo, PathElement.CurveTo, PathElement.ClosePath { 36 | 37 | /** 38 | * A {@link PathDataType#MOVE_TO} path element 39 | * 40 | * @param x the X coordinate of the new position 41 | * @param y the Y coordinate of the new position 42 | */ 43 | record MoveTo(double x, double y) implements PathElement { 44 | } 45 | 46 | /** 47 | * A {@link PathDataType#LINE_TO} path element 48 | * 49 | * @param x the X coordinate of the end of the new line 50 | * @param y the Y coordinate of the end of the new line 51 | */ 52 | record LineTo(double x, double y) implements PathElement { 53 | } 54 | 55 | /** 56 | * A {@link PathDataType#CURVE_TO} path element 57 | * 58 | * @param x1 the X coordinate of the first control point 59 | * @param y1 the Y coordinate of the first control point 60 | * @param x2 the X coordinate of the second control point 61 | * @param y2 the Y coordinate of the second control point 62 | * @param x3 the X coordinate of the end of the curve 63 | * @param y3 the Y coordinate of the end of the curve 64 | */ 65 | record CurveTo(double x1, double y1, double x2, double y2, double x3, double y3) implements PathElement { 66 | } 67 | 68 | /** 69 | * A {@link PathDataType#CLOSE_PATH} path element 70 | */ 71 | record ClosePath() implements PathElement { 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/PDFSurfaceTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertTrue; 5 | 6 | import java.io.OutputStream; 7 | import java.util.Set; 8 | import java.util.concurrent.atomic.AtomicBoolean; 9 | 10 | import org.freedesktop.cairo.*; 11 | import org.junit.jupiter.api.Test; 12 | 13 | class PDFSurfaceTest { 14 | 15 | @Test 16 | void testCreateStringIntInt() { 17 | try (PDFSurface s = PDFSurface.create((String) null, 120, 120)) { 18 | assertEquals(Status.SUCCESS, s.status()); 19 | } 20 | } 21 | 22 | @Test 23 | void testCreateOutputStreamIntInt() { 24 | AtomicBoolean success = new AtomicBoolean(); 25 | OutputStream stream = new OutputStream() { 26 | @Override 27 | public void write(int b) { 28 | success.set(true); 29 | } 30 | }; 31 | try (PDFSurface s = PDFSurface.create(stream, 120, 120)) { 32 | s.showPage(); 33 | assertEquals(Status.SUCCESS, s.status()); 34 | } 35 | assertTrue(success.get()); 36 | } 37 | 38 | @Test 39 | void testRestrictToVersion() { 40 | try (PDFSurface s = PDFSurface.create((String) null, 120, 120)) { 41 | s.restrictToVersion(PDFVersion.VERSION_1_4); 42 | assertEquals(Status.SUCCESS, s.status()); 43 | } 44 | } 45 | 46 | @Test 47 | void testSetSize() { 48 | try (PDFSurface s = PDFSurface.create((String) null, 120, 120)) { 49 | s.setSize(100, 100); 50 | assertEquals(Status.SUCCESS, s.status()); 51 | } 52 | } 53 | 54 | @Test 55 | void testAddOutline() { 56 | try (PDFSurface s = PDFSurface.create((String) null, 120, 120)) { 57 | // This verifies the method call runs, but the result will not be successful 58 | s.addOutline(PDFSurface.CAIRO_PDF_OUTLINE_ROOT, "test", "test", Set.of(PDFOutlineFlags.ITALIC)); 59 | } 60 | } 61 | 62 | @Test 63 | void testSetMetadata() { 64 | try (PDFSurface s = PDFSurface.create((String) null, 120, 120)) { 65 | s.setMetadata(PDFMetadata.TITLE, "test document"); 66 | assertEquals(Status.SUCCESS, s.status()); 67 | } 68 | } 69 | 70 | @Test 71 | void testSetCustomMetadata() { 72 | try (PDFSurface s = PDFSurface.create((String) null, 120, 120)) { 73 | s.setCustomMetadata("ISBN", "978-0123456789"); 74 | assertEquals(Status.SUCCESS, s.status()); 75 | } 76 | } 77 | 78 | @Test 79 | void testSetPageLabel() { 80 | try (PDFSurface s = PDFSurface.create((String) null, 120, 120)) { 81 | s.setPageLabel("label"); 82 | assertEquals(Status.SUCCESS, s.status()); 83 | } 84 | } 85 | 86 | @Test 87 | void testSetThumbnailSize() { 88 | try (PDFSurface s = PDFSurface.create((String) null, 120, 120)) { 89 | s.setThumbnailSize(30, 30); 90 | assertEquals(Status.SUCCESS, s.status()); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/HintMetrics.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.ValueLayout; 26 | import java.lang.invoke.MethodHandle; 27 | 28 | /** 29 | * Specifies whether to hint font metrics; hinting font metrics means quantizing 30 | * them so that they are integer values in device space. Doing this improves the 31 | * consistency of letter and line spacing, however it also means that text will 32 | * be laid out differently at different zoom factors. 33 | * 34 | * @since 1.0 35 | */ 36 | public enum HintMetrics { 37 | 38 | /** 39 | * Hint metrics in the default manner for the font backend and target device 40 | * 41 | * @since 1.0 42 | */ 43 | DEFAULT, 44 | 45 | /** 46 | * Do not hint font metrics 47 | * 48 | * @since 1.0 49 | */ 50 | OFF, 51 | 52 | /** 53 | * Hint font metrics 54 | * 55 | * @since 1.0 56 | */ 57 | ON; 58 | 59 | static { 60 | Cairo.ensureInitialized(); 61 | } 62 | 63 | /** 64 | * Return the value of this enum 65 | * 66 | * @return the value 67 | */ 68 | public int getValue() { 69 | return ordinal(); 70 | } 71 | 72 | /** 73 | * Returns the enum constant for the given ordinal (its position in the enum 74 | * declaration). 75 | * 76 | * @param ordinal the position in the enum declaration, starting from zero 77 | * @return the enum constant for the given ordinal 78 | */ 79 | public static HintMetrics of(int ordinal) { 80 | return values()[ordinal]; 81 | } 82 | 83 | /** 84 | * Get the CairoHintMetrics GType 85 | * @return the GType 86 | */ 87 | public static org.gnome.glib.Type getType() { 88 | try { 89 | long result = (long) cairo_gobject_hint_metrics_get_type.invoke(); 90 | return new org.gnome.glib.Type(result); 91 | } catch (Throwable e) { 92 | throw new RuntimeException(e); 93 | } 94 | } 95 | 96 | private static final MethodHandle cairo_gobject_hint_metrics_get_type = Interop.downcallHandle( 97 | "cairo_gobject_hint_metrics_get_type", FunctionDescriptor.of(ValueLayout.JAVA_LONG)); 98 | } 99 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /src/main/java/io/github/jwharm/cairobindings/LibLoad.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package io.github.jwharm.cairobindings; 21 | 22 | import java.io.File; 23 | import java.nio.file.Files; 24 | import java.nio.file.Path; 25 | import java.util.stream.Stream; 26 | 27 | /** 28 | * The LibLoad class is used internally to load native libraries by name 29 | */ 30 | public final class LibLoad { 31 | 32 | static { 33 | String javagiPath = System.getProperty("javagi.path"); 34 | String javaPath = System.getProperty("java.library.path"); 35 | if (javagiPath != null) { 36 | if (javaPath == null) { 37 | System.setProperty("java.library.path", javagiPath); 38 | } else { 39 | System.setProperty("java.library.path", javaPath + File.pathSeparator + javagiPath); 40 | } 41 | } 42 | } 43 | 44 | // Prevent instantiation 45 | private LibLoad() {} 46 | 47 | /** 48 | * Load the native library with the provided name 49 | * @param name the name of the library 50 | */ 51 | public static void loadLibrary(String name) { 52 | RuntimeException fail = new RuntimeException("Could not load library " + name); 53 | try { 54 | System.loadLibrary(name); 55 | return; 56 | } catch (Throwable t) { 57 | fail.addSuppressed(t); 58 | } 59 | for (String s : System.getProperty("java.library.path").split(File.pathSeparator)) { 60 | if (s.isBlank()) { 61 | continue; 62 | } 63 | 64 | Path pk = Path.of(s).toAbsolutePath().normalize(); 65 | if (!Files.isDirectory(pk)) { 66 | continue; 67 | } 68 | 69 | Path[] paths; 70 | try (Stream p = Files.list(pk)) { 71 | paths = p.toArray(Path[]::new); 72 | } catch (Throwable t) { 73 | fail.addSuppressed(t); 74 | continue; 75 | } 76 | 77 | for (Path path : paths) { 78 | try { 79 | String fn = path.getFileName().toString(); 80 | if (fn.equals(name)) { 81 | System.load(path.toString()); 82 | return; 83 | } 84 | } catch (Throwable t) { 85 | fail.addSuppressed(t); 86 | } 87 | } 88 | } 89 | throw fail; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/RasterSourceReleaseFunc.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import java.lang.foreign.*; 23 | import java.lang.invoke.MethodHandle; 24 | import java.lang.invoke.MethodHandles; 25 | 26 | /** 27 | * RasterSourceReleaseFunc is the type of function which is called when the 28 | * pixel data is no longer being access by the pattern for the rendering 29 | * operation. Typically this function will simply destroy the surface created 30 | * during acquire. 31 | * 32 | * @since 1.12 33 | */ 34 | @FunctionalInterface 35 | public interface RasterSourceReleaseFunc { 36 | 37 | /** 38 | * Called when the pixel data is no longer being access by the pattern for the 39 | * rendering operation. Typically this function will simply destroy the surface 40 | * created during acquire. 41 | * 42 | * @param pattern the pattern being rendered from 43 | * @param target the surface created during acquire 44 | * @since 1.12 45 | */ 46 | void release(RasterSource pattern, Surface target); 47 | 48 | /** 49 | * The callback that is executed by native code. This method marshals the 50 | * parameters and calls {@link #release(RasterSource, Surface)}. 51 | * 52 | * @param pattern the pattern being rendered from 53 | * @param callbackData ignored 54 | * @param target the surface created during acquire 55 | * @since 1.12 56 | */ 57 | default void upcall(MemorySegment pattern, MemorySegment callbackData, MemorySegment target) { 58 | release(new RasterSource(pattern), new Surface(target)); 59 | } 60 | 61 | /** 62 | * Generates an upcall stub, a C function pointer that will call 63 | * {@link #upcall}. 64 | * 65 | * @param arena the arena in which the upcall stub will be allocated 66 | * @return the function pointer of the upcall stub 67 | * @since 1.12 68 | */ 69 | default MemorySegment toCallback(Arena arena) { 70 | try { 71 | FunctionDescriptor fdesc = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS, 72 | ValueLayout.ADDRESS); 73 | MethodHandle handle = MethodHandles.lookup().findVirtual(RasterSourceReleaseFunc.class, "upcall", 74 | fdesc.toMethodType()); 75 | return Linker.nativeLinker().upcallStub(handle.bindTo(this), fdesc, arena); 76 | } catch (NoSuchMethodException | IllegalAccessException e) { 77 | throw new RuntimeException(e); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/TextCluster.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Proxy; 23 | 24 | import java.lang.foreign.MemoryLayout; 25 | import java.lang.foreign.MemorySegment; 26 | import java.lang.foreign.ValueLayout; 27 | import java.lang.invoke.VarHandle; 28 | 29 | /** 30 | * The TextCluster structure holds information about a single text 31 | * cluster. A text cluster is a minimal mapping of some glyphs corresponding 32 | * to some UTF-8 text. 33 | *

34 | * For a cluster to be valid, both {@code numBytes} and {@code numGlyphs} should 35 | * be non-negative, and at least one should be non-zero. Note that clusters with 36 | * zero glyphs are not as well supported as normal clusters. For example, PDF 37 | * rendering applications typically ignore those clusters when PDF text is being 38 | * selected. 39 | *

40 | * See cairo_show_text_glyphs() for how clusters are used in advanced text 41 | * operations. 42 | * 43 | * @since 1.8 44 | */ 45 | public class TextCluster extends Proxy { 46 | 47 | /** 48 | * The memory layout of the native C struct 49 | * 50 | * @return the memory layout of the native C struct 51 | */ 52 | static MemoryLayout getMemoryLayout() { 53 | return MemoryLayout.structLayout( 54 | ValueLayout.JAVA_INT.withName("num_bytes"), 55 | ValueLayout.JAVA_INT.withName("num_glyphs")) 56 | .withName("cairo_text_cluster_t"); 57 | } 58 | 59 | private static final VarHandle NUM_BYTES = getMemoryLayout().varHandle(MemoryLayout.PathElement.groupElement("num_bytes")); 60 | private static final VarHandle NUM_GLYPHS = getMemoryLayout().varHandle(MemoryLayout.PathElement.groupElement("num_glyphs")); 61 | 62 | /** 63 | * The number of bytes of UTF-8 text covered by the cluster 64 | * 65 | * @return the number of bytes of UTF-8 text 66 | */ 67 | public int numBytes() { 68 | return (int) NUM_BYTES.get(handle(), 0); 69 | } 70 | 71 | /** 72 | * The number of glyphs covered by cluster 73 | * 74 | * @return the number of glyphs covered by cluster 75 | */ 76 | public int numGlyphs() { 77 | return (int) NUM_GLYPHS.get(handle(), 0); 78 | } 79 | 80 | /** 81 | * Constructor used internally to instantiate a java TextCluster object for a 82 | * native {@code cairo_text_cluster_t} instance 83 | * 84 | * @param address the memory address of the native {@code cairo_text_cluster_t} 85 | * instance 86 | */ 87 | public TextCluster(MemorySegment address) { 88 | super(address); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/SubpixelOrder.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.ValueLayout; 26 | import java.lang.invoke.MethodHandle; 27 | 28 | /** 29 | * The subpixel order specifies the order of color elements within each pixel on 30 | * the display device when rendering with an antialiasing mode of 31 | * {@link Antialias#SUBPIXEL}. 32 | * 33 | * @since 1.0 34 | */ 35 | public enum SubpixelOrder { 36 | 37 | /** 38 | * Use the default subpixel order for for the target device 39 | * 40 | * @since 1.0 41 | */ 42 | DEFAULT, 43 | 44 | /** 45 | * Subpixel elements are arranged horizontally with red at the left 46 | * 47 | * @since 1.0 48 | */ 49 | RGB, 50 | 51 | /** 52 | * Subpixel elements are arranged horizontally with blue at the left 53 | * 54 | * @since 1.0 55 | */ 56 | BGR, 57 | 58 | /** 59 | * Subpixel elements are arranged vertically with red at the top 60 | * 61 | * @since 1.0 62 | */ 63 | VRGB, 64 | 65 | /** 66 | * Subpixel elements are arranged vertically with blue at the top 67 | * 68 | * @since 1.0 69 | */ 70 | VBGR; 71 | 72 | static { 73 | Cairo.ensureInitialized(); 74 | } 75 | 76 | /** 77 | * Return the value of this enum 78 | * @return the value 79 | */ 80 | public int getValue() { 81 | return ordinal(); 82 | } 83 | 84 | /** 85 | * Returns the enum constant for the given ordinal (its position in the enum 86 | * declaration). 87 | * 88 | * @param ordinal the position in the enum declaration, starting from zero 89 | * @return the enum constant for the given ordinal 90 | */ 91 | public static SubpixelOrder of(int ordinal) { 92 | return values()[ordinal]; 93 | } 94 | 95 | /** 96 | * Get the CairoSubpixelOrder GType 97 | * @return the GType 98 | */ 99 | public static org.gnome.glib.Type getType() { 100 | try { 101 | long result = (long) cairo_gobject_subpixel_order_get_type.invoke(); 102 | return new org.gnome.glib.Type(result); 103 | } catch (Throwable e) { 104 | throw new RuntimeException(e); 105 | } 106 | } 107 | 108 | private static final MethodHandle cairo_gobject_subpixel_order_get_type = Interop.downcallHandle( 109 | "cairo_gobject_subpixel_order_get_type", FunctionDescriptor.of(ValueLayout.JAVA_LONG)); 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/SVGUnit.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | /** 23 | * SVGUnit is used to describe the units valid for coordinates and lengths in 24 | * the SVG specification. 25 | *

26 | * See also: 27 | *

35 | * 36 | * @see Surface 37 | * @since 1.16 38 | */ 39 | public enum SVGUnit { 40 | 41 | /** 42 | * User unit, a value in the current coordinate system. If used in the root 43 | * element for the initial coordinate systems it corresponds to pixels. 44 | * 45 | * @since 1.16 46 | */ 47 | USER, 48 | 49 | /** 50 | * The size of the element's font. 51 | * 52 | * @since 1.16 53 | */ 54 | EM, 55 | 56 | /** 57 | * The x-height of the element’s font. 58 | * 59 | * @since 1.16 60 | */ 61 | EX, 62 | 63 | /** 64 | * Pixels (1px = 1/96th of 1in). 65 | * 66 | * @since 1.16 67 | */ 68 | PX, 69 | 70 | /** 71 | * Inches (1in = 2.54cm = 96px). 72 | * 73 | * @since 1.16 74 | */ 75 | IN, 76 | 77 | /** 78 | * Centimeters (1cm = 96px/2.54). 79 | * 80 | * @since 1.16 81 | */ 82 | CM, 83 | 84 | /** 85 | * Millimeters (1mm = 1/10th of 1cm). 86 | * 87 | * @since 1.16 88 | */ 89 | MM, 90 | 91 | /** 92 | * Points (1pt = 1/72th of 1in). 93 | * 94 | * @since 1.16 95 | */ 96 | PT, 97 | 98 | /** 99 | * Picas (1pc = 1/6th of 1in). 100 | * 101 | * @since 1.16 102 | */ 103 | PC, 104 | 105 | /** 106 | * Percent, a value that is some fraction of another reference value. 107 | * 108 | * @since 1.16 109 | */ 110 | PERCENT; 111 | 112 | /** 113 | * Return the value of this enum 114 | * @return the value 115 | */ 116 | public int getValue() { 117 | return ordinal(); 118 | } 119 | 120 | /** 121 | * Returns the enum constant for the given ordinal (its position in the enum 122 | * declaration). 123 | * 124 | * @param ordinal the position in the enum declaration, starting from zero 125 | * @return the enum constant for the given ordinal 126 | */ 127 | public static SVGUnit of(int ordinal) { 128 | return values()[ordinal]; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/Content.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2024 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.ValueLayout; 26 | import java.lang.invoke.MethodHandle; 27 | 28 | /** 29 | * Content is used to describe the content that a surface will contain, 30 | * whether color information, alpha information (translucence vs. opacity), or 31 | * both. 32 | *

33 | * Note: The large values here are designed to keep Content values 34 | * distinct from Format values so that the implementation can detect the 35 | * error if users confuse the two types. 36 | * 37 | * @since 1.0 38 | */ 39 | public enum Content { 40 | 41 | /** 42 | * The surface will hold color content only. 43 | * 44 | * @since 1.0 45 | */ 46 | COLOR(0x1000), 47 | 48 | /** 49 | * The surface will hold alpha content only. 50 | * 51 | * @since 1.0 52 | */ 53 | ALPHA(0x2000), 54 | 55 | /** 56 | * The surface will hold color and alpha content. 57 | * 58 | * @since 1.0 59 | */ 60 | COLOR_ALPHA(0x3000); 61 | 62 | static { 63 | Cairo.ensureInitialized(); 64 | } 65 | 66 | private final int value; 67 | 68 | Content(int value) { 69 | this.value = value; 70 | } 71 | 72 | /** 73 | * Return the value of this enum 74 | * @return the value 75 | */ 76 | public int getValue() { 77 | return value; 78 | } 79 | 80 | /** 81 | * Returns the enum member for the given value. 82 | * 83 | * @param value the value of the enum member 84 | * @return the enum member for the given value 85 | */ 86 | public static Content of(int value) { 87 | if (value == 0x1000) { 88 | return COLOR; 89 | } else if (value == 0x2000) { 90 | return ALPHA; 91 | } else if (value == 0x3000) { 92 | return COLOR_ALPHA; 93 | } else { 94 | throw new IllegalArgumentException("No Content enum with value " + value); 95 | } 96 | } 97 | 98 | /** 99 | * Get the CairoContent GType 100 | * @return the GType 101 | */ 102 | public static org.gnome.glib.Type getType() { 103 | try { 104 | long result = (long) cairo_gobject_content_get_type.invoke(); 105 | return new org.gnome.glib.Type(result); 106 | } catch (Throwable e) { 107 | throw new RuntimeException(e); 108 | } 109 | } 110 | 111 | private static final MethodHandle cairo_gobject_content_get_type = Interop.downcallHandle( 112 | "cairo_gobject_content_get_type", FunctionDescriptor.of(ValueLayout.JAVA_LONG)); 113 | } -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/Extend.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.ValueLayout; 26 | import java.lang.invoke.MethodHandle; 27 | 28 | /** 29 | * Extend is used to describe how pattern color/alpha will be determined for 30 | * areas "outside" the pattern's natural area, (for example, outside the surface 31 | * bounds or outside the gradient geometry). 32 | *

33 | * Mesh patterns are not affected by the extend mode. 34 | *

35 | * The default extend mode is {@link #NONE} for surface patterns and 36 | * {@link #PAD} for gradient patterns. 37 | *

38 | * New entries may be added in future versions. 39 | * 40 | * @since 1.0 41 | */ 42 | public enum Extend { 43 | 44 | /** 45 | * pixels outside of the source pattern are fully transparent 46 | * 47 | * @since 1.0 48 | */ 49 | NONE, 50 | 51 | /** 52 | * the pattern is tiled by repeating 53 | * 54 | * @since 1.0 55 | */ 56 | REPEAT, 57 | 58 | /** 59 | * the pattern is tiled by reflecting at the edges 60 | * 61 | * @since 1.0; but only implemented for surface patterns since 1.6 62 | */ 63 | REFLECT, 64 | 65 | /** 66 | * pixels outside of the pattern copy the closest pixel from the source 67 | * 68 | * @since 1.2; but only implemented for surface patterns since 1.6 69 | */ 70 | PAD; 71 | 72 | static { 73 | Cairo.ensureInitialized(); 74 | } 75 | 76 | /** 77 | * Return the value of this enum 78 | * @return the value 79 | */ 80 | public int getValue() { 81 | return ordinal(); 82 | } 83 | 84 | /** 85 | * Returns the enum constant for the given ordinal (its position in the enum 86 | * declaration). 87 | * 88 | * @param ordinal the position in the enum declaration, starting from zero 89 | * @return the enum constant for the given ordinal 90 | */ 91 | public static Extend of(int ordinal) { 92 | return values()[ordinal]; 93 | } 94 | 95 | /** 96 | * Get the CairoExtend GType 97 | * @return the GType 98 | */ 99 | public static org.gnome.glib.Type getType() { 100 | try { 101 | long result = (long) cairo_gobject_extend_get_type.invoke(); 102 | return new org.gnome.glib.Type(result); 103 | } catch (Throwable e) { 104 | throw new RuntimeException(e); 105 | } 106 | } 107 | 108 | private static final MethodHandle cairo_gobject_extend_get_type = Interop.downcallHandle( 109 | "cairo_gobject_extend_get_type", FunctionDescriptor.of(ValueLayout.JAVA_LONG)); 110 | } 111 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/MeshTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertNotNull; 5 | 6 | import org.freedesktop.cairo.Mesh; 7 | import org.freedesktop.cairo.Path; 8 | import org.freedesktop.cairo.Point; 9 | import org.freedesktop.cairo.Status; 10 | import org.junit.jupiter.api.Test; 11 | 12 | class MeshTest { 13 | 14 | @Test 15 | void testCreate() { 16 | Mesh mesh = Mesh.create(); 17 | assertEquals(Status.SUCCESS, mesh.status()); 18 | } 19 | 20 | @Test 21 | void testBeginAndEndPatch() { 22 | Mesh mesh = Mesh.create(); 23 | mesh.beginPatch(); 24 | mesh.moveTo(10, 10); 25 | mesh.endPatch(); 26 | assertEquals(Status.SUCCESS, mesh.status()); 27 | } 28 | 29 | @Test 30 | void testMoveTo() { 31 | Mesh mesh = Mesh.create(); 32 | mesh.beginPatch(); 33 | mesh.moveTo(10, 10); 34 | assertEquals(Status.SUCCESS, mesh.status()); 35 | } 36 | 37 | @Test 38 | void testLineTo() { 39 | Mesh mesh = Mesh.create(); 40 | mesh.beginPatch(); 41 | mesh.lineTo(10, 10); 42 | assertEquals(Status.SUCCESS, mesh.status()); 43 | } 44 | 45 | @Test 46 | void testCurveTo() { 47 | Mesh mesh = Mesh.create(); 48 | mesh.beginPatch(); 49 | mesh.curveTo(30, -30, 60, 30, 100, 0); 50 | assertEquals(Status.SUCCESS, mesh.status()); 51 | } 52 | 53 | @Test 54 | void testSetCornerColorRGB() { 55 | Mesh mesh = Mesh.create(); 56 | mesh.beginPatch() 57 | .moveTo(10, 10) 58 | .lineTo(20, 20) 59 | .lineTo(30, 30) 60 | .setCornerColorRGB(0, 0.5, 0.5, 0.5); 61 | assertEquals(Status.SUCCESS, mesh.status()); 62 | } 63 | 64 | @Test 65 | void testGetPatchCount() { 66 | Mesh mesh = Mesh.create(); 67 | assertEquals(0, mesh.getPatchCount()); 68 | mesh.beginPatch(); 69 | mesh.moveTo(10, 10); 70 | mesh.endPatch(); 71 | assertEquals(1, mesh.getPatchCount()); 72 | assertEquals(Status.SUCCESS, mesh.status()); 73 | } 74 | 75 | @Test 76 | void testGetPath() { 77 | Mesh mesh = Mesh.create(); 78 | mesh.beginPatch(); 79 | mesh.moveTo(10, 10); 80 | mesh.endPatch(); 81 | Path path = mesh.getPath(0); 82 | assertNotNull(path); 83 | assertEquals(Status.SUCCESS, mesh.status()); 84 | } 85 | 86 | @Test 87 | void testControlPoint() { 88 | Mesh mesh = Mesh.create(); 89 | mesh.beginPatch(); 90 | mesh.setControlPoint(0, 10, 15); 91 | mesh.moveTo(20, 30); 92 | mesh.endPatch(); 93 | Point point = mesh.getControlPoint(0, 0); 94 | assertEquals(10, point.x()); 95 | assertEquals(15, point.y()); 96 | assertEquals(Status.SUCCESS, mesh.status()); 97 | } 98 | 99 | @Test 100 | void testCornerColorRGBA() { 101 | Mesh mesh = Mesh.create(); 102 | mesh.beginPatch() 103 | .moveTo(10, 10) 104 | .lineTo(20, 20) 105 | .lineTo(30, 30) 106 | .setCornerColorRGBA(0, 0.5, 0.6, 0.7, 0.8) 107 | .endPatch(); 108 | double[] color = mesh.getCornerColorRGBA(0, 0); 109 | assertEquals(color.length, 4); 110 | assertEquals(0.5, color[0]); 111 | assertEquals(0.6, color[1]); 112 | assertEquals(0.7, color[2]); 113 | assertEquals(0.8, color[3]); 114 | assertEquals(Status.SUCCESS, mesh.status()); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/Filter.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.ValueLayout; 26 | import java.lang.invoke.MethodHandle; 27 | 28 | /** 29 | * Filter is used to indicate what filtering should be applied when reading 30 | * pixel values from patterns. See {@link Pattern#setFilter} for indicating the 31 | * desired filter to be used with a particular pattern. 32 | * 33 | * @since 1.0 34 | */ 35 | public enum Filter { 36 | 37 | /** 38 | * A high-performance filter, with quality similar to {@link #NEAREST} 39 | * 40 | * @since 1.0 41 | */ 42 | FAST, 43 | 44 | /** 45 | * A reasonable-performance filter, with quality similar to {@link #BILINEAR} 46 | * 47 | * @since 1.0 48 | */ 49 | GOOD, 50 | 51 | /** 52 | * The highest-quality available, performance may not be suitable for 53 | * interactive use. 54 | * 55 | * @since 1.0 56 | */ 57 | BEST, 58 | 59 | /** 60 | * Nearest-neighbor filtering 61 | * 62 | * @since 1.0 63 | */ 64 | NEAREST, 65 | 66 | /** 67 | * Linear interpolation in two dimensions 68 | * 69 | * @since 1.0 70 | */ 71 | BILINEAR, 72 | 73 | /** 74 | * This filter value is currently unimplemented, and should not be used in 75 | * current code. 76 | * 77 | * @since 1.0 78 | */ 79 | GAUSSIAN; 80 | 81 | static { 82 | Cairo.ensureInitialized(); 83 | } 84 | 85 | /** 86 | * Return the value of this enum 87 | * @return the value 88 | */ 89 | public int getValue() { 90 | return ordinal(); 91 | } 92 | 93 | /** 94 | * Returns the enum constant for the given ordinal (its position in the enum 95 | * declaration). 96 | * 97 | * @param ordinal the position in the enum declaration, starting from zero 98 | * @return the enum constant for the given ordinal 99 | */ 100 | public static Filter of(int ordinal) { 101 | return values()[ordinal]; 102 | } 103 | 104 | /** 105 | * Get the CairoFilter GType 106 | * @return the GType 107 | */ 108 | public static org.gnome.glib.Type getType() { 109 | try { 110 | long result = (long) cairo_gobject_filter_get_type.invoke(); 111 | return new org.gnome.glib.Type(result); 112 | } catch (Throwable e) { 113 | throw new RuntimeException(e); 114 | } 115 | } 116 | 117 | private static final MethodHandle cairo_gobject_filter_get_type = Interop.downcallHandle( 118 | "cairo_gobject_filter_get_type", FunctionDescriptor.of(ValueLayout.JAVA_LONG)); 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/RasterSourceCopyFunc.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import java.lang.foreign.*; 23 | import java.lang.invoke.MethodHandle; 24 | import java.lang.invoke.MethodHandles; 25 | 26 | /** 27 | * RasterSourceCopyFunc is the type of function which is called when the pattern 28 | * gets copied as a normal part of rendering. 29 | * 30 | * @since 1.12 31 | */ 32 | @FunctionalInterface 33 | public interface RasterSourceCopyFunc { 34 | 35 | /** 36 | * Called when the pattern gets copied as a normal part of rendering. 37 | * 38 | * @param pattern the pattern that was copied to 39 | * @param other the pattern being used as the source for the copy 40 | * @return {@link Status#SUCCESS} on success, or one of the {@link Status} error 41 | * codes for failure. 42 | * @since 1.12 43 | */ 44 | Status copy(RasterSource pattern, RasterSource other); 45 | 46 | /** 47 | * The callback that is executed by native code. This method marshals the 48 | * parameters and calls {@link #copy(RasterSource, RasterSource)}. 49 | * 50 | * @param pattern the pattern being rendered from 51 | * @param callbackData ignored 52 | * @param other the pattern being used as the source for the copy 53 | * @return {@link Status#SUCCESS} on success, or one of the {@link Status} error 54 | * codes for failure. 55 | * @since 1.12 56 | */ 57 | default int upcall(MemorySegment pattern, MemorySegment callbackData, MemorySegment other) { 58 | Status result = copy(new RasterSource(pattern), new RasterSource(other)); 59 | /* 60 | * Will throw a NPE if the callback function returns null. This is deliberate: 61 | * The snapshot function must always return a Status enum member; failing to do 62 | * so is a programming error that should fail fast and obvious. 63 | */ 64 | return result.getValue(); 65 | } 66 | 67 | /** 68 | * Generates an upcall stub, a C function pointer that will call 69 | * {@link #upcall}. 70 | * 71 | * @param arena the arena in which the upcall stub will be allocated 72 | * @return the function pointer of the upcall stub 73 | * @since 1.12 74 | */ 75 | default MemorySegment toCallback(Arena arena) { 76 | try { 77 | FunctionDescriptor fdesc = FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS, 78 | ValueLayout.ADDRESS, ValueLayout.ADDRESS); 79 | MethodHandle handle = MethodHandles.lookup().findVirtual(RasterSourceCopyFunc.class, "upcall", 80 | fdesc.toMethodType()); 81 | return Linker.nativeLinker().upcallStub(handle.bindTo(this), fdesc, arena); 82 | } catch (NoSuchMethodException | IllegalAccessException e) { 83 | throw new RuntimeException(e); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/HintStyle.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.ValueLayout; 26 | import java.lang.invoke.MethodHandle; 27 | 28 | /** 29 | * Specifies the type of hinting to do on font outlines. Hinting is the process 30 | * of fitting outlines to the pixel grid in order to improve the appearance of 31 | * the result. Since hinting outlines involves distorting them, it also reduces 32 | * the faithfulness to the original outline shapes. Not all of the outline 33 | * hinting styles are supported by all font backends. 34 | *

35 | * New entries may be added in future versions. 36 | * 37 | * @since 1.0 38 | */ 39 | public enum HintStyle { 40 | 41 | /** 42 | * Use the default hint style for font backend and target device 43 | * 44 | * @since 1.0 45 | */ 46 | DEFAULT, 47 | 48 | /** 49 | * Do not hint outlines 50 | * 51 | * @since 1.0 52 | */ 53 | NONE, 54 | 55 | /** 56 | * Hint outlines slightly to improve contrast while retaining good fidelity to 57 | * the original shapes 58 | * 59 | * @since 1.0 60 | */ 61 | SLIGHT, 62 | 63 | /** 64 | * Hint outlines with medium strength giving a compromise between fidelity to 65 | * the original shapes and contrast 66 | * 67 | * @since 1.0 68 | */ 69 | MEDIUM, 70 | 71 | /** 72 | * Hint outlines to maximize contrast 73 | * 74 | * @since 1.0 75 | */ 76 | FULL; 77 | 78 | static { 79 | Cairo.ensureInitialized(); 80 | } 81 | 82 | /** 83 | * Return the value of this enum 84 | * 85 | * @return the value 86 | */ 87 | public int getValue() { 88 | return ordinal(); 89 | } 90 | 91 | /** 92 | * Returns the enum constant for the given ordinal (its position in the enum 93 | * declaration). 94 | * 95 | * @param ordinal the position in the enum declaration, starting from zero 96 | * @return the enum constant for the given ordinal 97 | */ 98 | public static HintStyle of(int ordinal) { 99 | return values()[ordinal]; 100 | } 101 | 102 | /** 103 | * Get the CairoHintStyle GType 104 | * @return the GType 105 | */ 106 | public static org.gnome.glib.Type getType() { 107 | try { 108 | long result = (long) cairo_gobject_hint_style_get_type.invoke(); 109 | return new org.gnome.glib.Type(result); 110 | } catch (Throwable e) { 111 | throw new RuntimeException(e); 112 | } 113 | } 114 | 115 | private static final MethodHandle cairo_gobject_hint_style_get_type = Interop.downcallHandle( 116 | "cairo_gobject_hint_style_get_type", FunctionDescriptor.of(ValueLayout.JAVA_LONG)); 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/SurfacePattern.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | import io.github.jwharm.cairobindings.MemoryCleaner; 24 | 25 | import java.lang.foreign.Arena; 26 | import java.lang.foreign.FunctionDescriptor; 27 | import java.lang.foreign.MemorySegment; 28 | import java.lang.foreign.ValueLayout; 29 | import java.lang.invoke.MethodHandle; 30 | 31 | /** 32 | * A pattern based on a surface (an image). 33 | */ 34 | public class SurfacePattern extends Pattern { 35 | 36 | static { 37 | Cairo.ensureInitialized(); 38 | } 39 | 40 | // Keep a reference to the target surface during the lifetime of this pattern 41 | Surface surface; 42 | 43 | /** 44 | * Constructor used internally to instantiate a java SurfacePattern object for a 45 | * native {@code cairo_pattern_t} instance 46 | * 47 | * @param address the memory address of the native {@code cairo_pattern_t} 48 | * instance 49 | */ 50 | public SurfacePattern(MemorySegment address) { 51 | super(address); 52 | } 53 | 54 | /** 55 | * Create a new {@link Pattern} for the given surface. 56 | * 57 | * @param surface the surface 58 | * @return the newly created {@link SurfacePattern} 59 | * @since 1.0 60 | */ 61 | public static SurfacePattern create(Surface surface) { 62 | try { 63 | MemorySegment result = (MemorySegment) cairo_pattern_create_for_surface 64 | .invoke(surface == null ? MemorySegment.NULL : surface.handle()); 65 | SurfacePattern pattern = new SurfacePattern(result); 66 | MemoryCleaner.takeOwnership(pattern.handle()); 67 | pattern.surface = surface; 68 | return pattern; 69 | } catch (Throwable e) { 70 | throw new RuntimeException(e); 71 | } 72 | } 73 | 74 | private static final MethodHandle cairo_pattern_create_for_surface = Interop.downcallHandle( 75 | "cairo_pattern_create_for_surface", FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS)); 76 | 77 | /** 78 | * Gets the surface of a surface pattern. 79 | * 80 | * @return surface of pattern 81 | * @since 1.4 82 | */ 83 | public Surface getSurface() { 84 | try { 85 | try (Arena arena = Arena.ofConfined()) { 86 | MemorySegment surfacePtr = arena.allocate(ValueLayout.ADDRESS); 87 | cairo_pattern_get_surface.invoke(handle(), surfacePtr); 88 | return new Surface(surfacePtr.get(ValueLayout.ADDRESS, 0)); 89 | } 90 | } catch (Throwable e) { 91 | throw new RuntimeException(e); 92 | } 93 | } 94 | 95 | private static final MethodHandle cairo_pattern_get_surface = Interop.downcallHandle("cairo_pattern_get_surface", 96 | FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS, ValueLayout.ADDRESS)); 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/RasterSourceSnapshotFunc.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import java.lang.foreign.*; 23 | import java.lang.invoke.MethodHandle; 24 | import java.lang.invoke.MethodHandles; 25 | 26 | /** 27 | * RasterSourceSnapshotFunc is the type of function which is called when the 28 | * pixel data needs to be preserved for later use during printing. This pattern 29 | * will be accessed again later, and it is expected to provide the pixel data 30 | * that was current at the time of snapshotting. 31 | * 32 | * @since 1.12 33 | */ 34 | @FunctionalInterface 35 | public interface RasterSourceSnapshotFunc { 36 | 37 | /** 38 | * Called when the pixel data needs to be preserved for later use during 39 | * printing. This pattern will be accessed again later, and it is expected to 40 | * provide the pixel data that was current at the time of snapshotting. 41 | * 42 | * @param pattern the pattern being rendered from 43 | * @return {@link Status#SUCCESS} on success, or one of the {@link Status} error 44 | * codes for failure. 45 | * @since 1.12 46 | */ 47 | Status snapshot(RasterSource pattern); 48 | 49 | /** 50 | * The callback that is executed by native code. This method marshals the 51 | * parameters and calls {@link #snapshot(RasterSource)}. 52 | * 53 | * @param pattern the pattern being rendered from 54 | * @param callbackData ignored 55 | * @return {@link Status#SUCCESS} on success, or one of the {@link Status} error 56 | * codes for failure. 57 | * @since 1.12 58 | */ 59 | default int upcall(MemorySegment pattern, MemorySegment callbackData) { 60 | Status result = snapshot(new RasterSource(pattern)); 61 | /* 62 | * Will throw a NPE if the callback function returns null. This is deliberate: 63 | * The snapshot function must always return a Status enum member; failing to do 64 | * so is a programming error that should fail fast and obvious. 65 | */ 66 | return result.getValue(); 67 | } 68 | 69 | /** 70 | * Generates an upcall stub, a C function pointer that will call 71 | * {@link #upcall}. 72 | * 73 | * @param arena the arena in which the upcall stub will be allocated 74 | * @return the function pointer of the upcall stub 75 | * @since 1.12 76 | */ 77 | default MemorySegment toCallback(Arena arena) { 78 | try { 79 | FunctionDescriptor fdesc = FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS, 80 | ValueLayout.ADDRESS); 81 | MethodHandle handle = MethodHandles.lookup().findVirtual(RasterSourceSnapshotFunc.class, "upcall", 82 | fdesc.toMethodType()); 83 | return Linker.nativeLinker().upcallStub(handle.bindTo(this), fdesc, arena); 84 | } catch (NoSuchMethodException | IllegalAccessException e) { 85 | throw new RuntimeException(e); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/FillRule.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.ValueLayout; 26 | import java.lang.invoke.MethodHandle; 27 | 28 | /** 29 | * cairo_fill_rule_t is used to select how paths are filled. For both fill 30 | * rules, whether or not a point is included in the fill is determined by taking 31 | * a ray from that point to infinity and looking at intersections with the path. 32 | * The ray can be in any direction, as long as it doesn't pass through the end 33 | * point of a segment or have a tricky intersection such as intersecting tangent 34 | * to the path. (Note that filling is not actually implemented in this way. This 35 | * is just a description of the rule that is applied.) 36 | *

37 | * The default fill rule is CAIRO_FILL_RULE_WINDING. 38 | *

39 | * New entries may be added in future versions. 40 | * 41 | * @since 1.0 42 | */ 43 | public enum FillRule { 44 | 45 | /** 46 | * If the path crosses the ray from left-to-right, counts +1. If the path 47 | * crosses the ray from right to left, counts -1. (Left and right are determined 48 | * from the perspective of looking along the ray from the starting point.) If 49 | * the total count is non-zero, the point will be filled. 50 | * 51 | * @since 1.0 52 | */ 53 | WINDING, 54 | 55 | /** 56 | * Counts the total number of intersections, without regard to the orientation 57 | * of the contour. If the total number of intersections is odd, the point will 58 | * be filled. 59 | * 60 | * @since 1.0 61 | */ 62 | EVEN_ODD; 63 | 64 | static { 65 | Cairo.ensureInitialized(); 66 | } 67 | 68 | /** 69 | * Return the value of this enum 70 | * @return the value 71 | */ 72 | public int getValue() { 73 | return ordinal(); 74 | } 75 | 76 | /** 77 | * Returns the enum constant for the given ordinal (its position in the enum 78 | * declaration). 79 | * 80 | * @param ordinal the position in the enum declaration, starting from zero 81 | * @return the enum constant for the given ordinal 82 | */ 83 | public static FillRule of(int ordinal) { 84 | return values()[ordinal]; 85 | } 86 | 87 | /** 88 | * Get the CairoFillRule GType 89 | * @return the GType 90 | */ 91 | public static org.gnome.glib.Type getType() { 92 | try { 93 | long result = (long) cairo_gobject_fill_rule_get_type.invoke(); 94 | return new org.gnome.glib.Type(result); 95 | } catch (Throwable e) { 96 | throw new RuntimeException(e); 97 | } 98 | } 99 | 100 | private static final MethodHandle cairo_gobject_fill_rule_get_type = Interop.downcallHandle( 101 | "cairo_gobject_fill_rule_get_type", FunctionDescriptor.of(ValueLayout.JAVA_LONG)); 102 | } -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/MatrixTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertNotNull; 5 | 6 | import org.freedesktop.cairo.Matrix; 7 | import org.freedesktop.cairo.Point; 8 | import org.junit.jupiter.api.Test; 9 | 10 | import java.lang.foreign.Arena; 11 | 12 | class MatrixTest { 13 | 14 | @Test 15 | void testInit() { 16 | try (Arena arena = Arena.ofConfined()) { 17 | Matrix matrix = Matrix.create(arena).init(1, 0, 0, 1, 0, 0); 18 | matrix.init(2, 0, 0, 2, 0, 0); 19 | } 20 | } 21 | 22 | @Test 23 | void testCreateIdentity() { 24 | try (Arena arena = Arena.ofConfined()) { 25 | Matrix matrix = Matrix.create(arena).initIdentity(); 26 | assertNotNull(matrix); 27 | } 28 | } 29 | 30 | @Test 31 | void testCreateTranslate() { 32 | try (Arena arena = Arena.ofConfined()) { 33 | Matrix matrix = Matrix.create(arena).initTranslate(20, 20); 34 | assertNotNull(matrix); 35 | } 36 | } 37 | 38 | @Test 39 | void testCreateScale() { 40 | try (Arena arena = Arena.ofConfined()) { 41 | Matrix matrix = Matrix.create(arena).initIdentity(); 42 | matrix.scale(2, 2); 43 | assertNotNull(matrix); 44 | } 45 | } 46 | 47 | @Test 48 | void testCreateRotate() { 49 | try (Arena arena = Arena.ofConfined()) { 50 | Matrix matrix = Matrix.create(arena).initIdentity(); 51 | matrix.rotate(90); 52 | assertNotNull(matrix); 53 | } 54 | } 55 | 56 | @Test 57 | void testTranslate() { 58 | try (Arena arena = Arena.ofConfined()) { 59 | Matrix matrix = Matrix.create(arena).initIdentity(); 60 | matrix.translate(10, 10); 61 | } 62 | } 63 | 64 | @Test 65 | void testScale() { 66 | try (Arena arena = Arena.ofConfined()) { 67 | Matrix matrix = Matrix.create(arena).initTranslate(20, 20); 68 | matrix.scale(0.5, 0.5); 69 | } 70 | } 71 | 72 | @Test 73 | void testRotate() { 74 | try (Arena arena = Arena.ofConfined()) { 75 | Matrix matrix = Matrix.create(arena).initTranslate(20, 20); 76 | matrix.rotate(180); 77 | } 78 | } 79 | 80 | @Test 81 | void testInvert() { 82 | try (Arena arena = Arena.ofConfined()) { 83 | Matrix matrix = Matrix.create(arena).initTranslate(20, 20); 84 | matrix.invert(); 85 | } 86 | } 87 | 88 | @Test 89 | void testMultiply() { 90 | try (Arena arena = Arena.ofConfined()) { 91 | Matrix matrix1 = Matrix.create(arena).initIdentity(); 92 | matrix1.rotate(90); 93 | Matrix matrix2 = Matrix.create(arena).initTranslate(20, 20); 94 | Matrix matrix3 = Matrix.create(arena).initIdentity(); 95 | matrix3.multiply(matrix1, matrix2); 96 | } 97 | } 98 | 99 | @Test 100 | void testTransformDistance() { 101 | try (Arena arena = Arena.ofConfined()) { 102 | Matrix matrix = Matrix.create(arena).initIdentity(); 103 | matrix.scale(3, 2); 104 | Point point = matrix.transformDistance(new Point(10, 10)); 105 | assertEquals(30, point.x()); 106 | assertEquals(20, point.y()); 107 | } 108 | } 109 | 110 | @Test 111 | void testTransformPoint() { 112 | try (Arena arena = Arena.ofConfined()) { 113 | Matrix matrix = Matrix.create(arena).initTranslate(20, 30); 114 | Point point = matrix.transformPoint(new Point(30, 40)); 115 | assertEquals(50, point.x()); 116 | assertEquals(70, point.y()); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/WriteFunc.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import java.io.IOException; 23 | import java.lang.foreign.Arena; 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.Linker; 26 | import java.lang.foreign.MemorySegment; 27 | import java.lang.foreign.ValueLayout; 28 | import java.lang.invoke.MethodHandle; 29 | import java.lang.invoke.MethodHandles; 30 | 31 | /** 32 | * WriteFunc is the type of function which is called when a backend needs to 33 | * write data to an output stream. It is passed the closure which was specified 34 | * by the user at the time the write function was registered, the data to write 35 | * and the length of the data in bytes. The write function should throw 36 | * {@link IOException} if all the data was not successfully written. 37 | * 38 | * @since 1.0 39 | */ 40 | @FunctionalInterface 41 | public interface WriteFunc { 42 | 43 | /** 44 | * The function to implement as callback in a write operation to an output 45 | * stream. 46 | * 47 | * @param data the data to write to the output stream 48 | * @throws IOException to be thrown when an error occurs during the write 49 | * operation 50 | * @since 1.0 51 | */ 52 | void write(byte[] data) throws IOException; 53 | 54 | /** 55 | * The callback that is executed by native code. This method marshals the 56 | * parameters and calls {@link #write(byte[])}. 57 | * 58 | * @param closure ignored 59 | * @param data the buffer from which to read the data 60 | * @param length the amount of data to write 61 | * @return {@link Status#SUCCESS} on success, or {@link Status#WRITE_ERROR} if 62 | * an IOException occured. 63 | * @since 1.0 64 | */ 65 | default int upcall(MemorySegment closure, MemorySegment data, int length) { 66 | if (length <= 0) { 67 | return Status.SUCCESS.getValue(); 68 | } 69 | byte[] bytes = data.reinterpret(length).toArray(ValueLayout.JAVA_BYTE); 70 | try { 71 | write(bytes); 72 | return Status.SUCCESS.getValue(); 73 | } catch (IOException ioe) { 74 | return Status.WRITE_ERROR.getValue(); 75 | } 76 | } 77 | 78 | /** 79 | * Generates an upcall stub, a C function pointer that will call 80 | * {@link #upcall}. 81 | * 82 | * @param arena the arena in which the upcall stub will be allocated 83 | * @return the function pointer of the upcall stub 84 | * @since 1.0 85 | */ 86 | default MemorySegment toCallback(Arena arena) { 87 | try { 88 | FunctionDescriptor fdesc = FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS, 89 | ValueLayout.ADDRESS, ValueLayout.JAVA_INT); 90 | MethodHandle handle = MethodHandles.lookup().findVirtual(WriteFunc.class, "upcall", fdesc.toMethodType()); 91 | return Linker.nativeLinker().upcallStub(handle.bindTo(this), fdesc, arena); 92 | } catch (NoSuchMethodException | IllegalAccessException e) { 93 | throw new RuntimeException(e); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/FontType.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.ValueLayout; 26 | import java.lang.invoke.MethodHandle; 27 | 28 | /** 29 | * FontType is used to describe the type of a given font face or scaled font. 30 | * The font types are also known as "font backends" within cairo. 31 | *

32 | * The type of a font face is determined by the function used to create it, 33 | * which will generally be of the form {@code FontFaceClass.create()}. The font 34 | * face type can be queried with {@link FontFace#getType()}. 35 | *

36 | * The various {@link FontFace} functions can be used with a font face of any 37 | * type. 38 | *

39 | * The type of a scaled font is determined by the type of the font face passed 40 | * to {@link ScaledFont#create(FontFace, Matrix, Matrix, FontOptions)}. The 41 | * scaled font type can be queried with {@link ScaledFont#getType()}. 42 | *

43 | * New entries may be added in future versions. 44 | * 45 | * @since 1.2 46 | */ 47 | public enum FontType { 48 | 49 | /** 50 | * The font was created using cairo's toy font api 51 | * 52 | * @since 1.2 53 | */ 54 | TOY, 55 | 56 | /** 57 | * The font is of type FreeType 58 | * 59 | * @since 1.2 60 | */ 61 | FT, 62 | 63 | /** 64 | * The font is of type Win32 65 | * 66 | * @since 1.2 67 | */ 68 | WIN32, 69 | 70 | /** 71 | * The font is of type Quartz 72 | * 73 | * @since 1.6, in 1.2 and 1.4 it was named ATSUI 74 | */ 75 | QUARTZ, 76 | 77 | /** 78 | * The font was create using cairo's user font api 79 | * 80 | * @since 1.8 81 | */ 82 | USER, 83 | 84 | /** 85 | * The font is of type Win32 DWrite 86 | * 87 | * @since 1.18 88 | */ 89 | DWRITE; 90 | 91 | static { 92 | Cairo.ensureInitialized(); 93 | } 94 | 95 | /** 96 | * Return the value of this enum 97 | * 98 | * @return the value 99 | */ 100 | public int getValue() { 101 | return ordinal(); 102 | } 103 | 104 | /** 105 | * Returns the enum constant for the given ordinal (its position in the enum 106 | * declaration). 107 | * 108 | * @param ordinal the position in the enum declaration, starting from zero 109 | * @return the enum constant for the given ordinal 110 | */ 111 | public static FontType of(int ordinal) { 112 | return values()[ordinal]; 113 | } 114 | 115 | /** 116 | * Get the CairoFontType GType 117 | * @return the GType 118 | */ 119 | public static org.gnome.glib.Type getType() { 120 | try { 121 | long result = (long) cairo_gobject_font_type_get_type.invoke(); 122 | return new org.gnome.glib.Type(result); 123 | } catch (Throwable e) { 124 | throw new RuntimeException(e); 125 | } 126 | } 127 | 128 | private static final MethodHandle cairo_gobject_font_type_get_type = Interop.downcallHandle( 129 | "cairo_gobject_font_type_get_type", FunctionDescriptor.of(ValueLayout.JAVA_LONG)); 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/PatternType.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.ValueLayout; 26 | import java.lang.invoke.MethodHandle; 27 | 28 | /** 29 | * PatternType is used to describe the type of a given pattern. 30 | *

31 | * The type of a pattern is determined by the function used to create it. The 32 | * cairo_pattern_create_rgb() and cairo_pattern_create_rgba() functions create 33 | * SOLID patterns. The remaining cairo_pattern_create functions map to pattern 34 | * types in obvious ways. 35 | *

36 | * The pattern type can be queried with cairo_pattern_get_type() 37 | *

38 | * Most Pattern functions can be called with a pattern of any type, (though 39 | * trying to change the extend or filter for a solid pattern will have no 40 | * effect). A notable exception is cairo_pattern_add_color_stop_rgb() and 41 | * cairo_pattern_add_color_stop_rgba() which must only be called with gradient 42 | * patterns (either LINEAR or RADIAL). Otherwise the pattern will be shutdown 43 | * and put into an error state. 44 | *

45 | * New entries may be added in future versions. 46 | * 47 | * @since 1.2 48 | */ 49 | public enum PatternType { 50 | 51 | /** 52 | * The pattern is a solid (uniform) color. It may be opaque or translucent 53 | * @since 1.2 54 | */ 55 | SOLID, 56 | 57 | /** 58 | * The pattern is a based on a surface (an image) 59 | * @since 1.2 60 | */ 61 | SURFACE, 62 | 63 | /** 64 | * The pattern is a linear gradient 65 | * @since 1.2 66 | */ 67 | LINEAR, 68 | 69 | /** 70 | * The pattern is a radial gradient 71 | * @since 1.2 72 | */ 73 | RADIAL, 74 | 75 | /** 76 | * The pattern is a mesh 77 | * @since 1.2 78 | */ 79 | MESH, 80 | 81 | /** 82 | * The pattern is a user pattern providing raster data 83 | * @since 1.2 84 | */ 85 | RASTER_SOURCE; 86 | 87 | static { 88 | Cairo.ensureInitialized(); 89 | } 90 | 91 | /** 92 | * Return the value of this enum 93 | * @return the value 94 | */ 95 | public int getValue() { 96 | return ordinal(); 97 | } 98 | 99 | /** 100 | * Returns the enum constant for the given ordinal (its position in the enum 101 | * declaration). 102 | * 103 | * @param ordinal the position in the enum declaration, starting from zero 104 | * @return the enum constant for the given ordinal 105 | */ 106 | public static PatternType of(int ordinal) { 107 | return values()[ordinal]; 108 | } 109 | 110 | /** 111 | * Get the CairoPatternType GType 112 | * @return the GType 113 | */ 114 | public static org.gnome.glib.Type getType() { 115 | try { 116 | long result = (long) cairo_gobject_pattern_type_get_type.invoke(); 117 | return new org.gnome.glib.Type(result); 118 | } catch (Throwable e) { 119 | throw new RuntimeException(e); 120 | } 121 | } 122 | 123 | private static final MethodHandle cairo_gobject_pattern_type_get_type = Interop.downcallHandle( 124 | "cairo_gobject_pattern_type_get_type", FunctionDescriptor.of(ValueLayout.JAVA_LONG)); 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/ReadFunc.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import java.io.IOException; 23 | import java.lang.foreign.Arena; 24 | import java.lang.foreign.FunctionDescriptor; 25 | import java.lang.foreign.Linker; 26 | import java.lang.foreign.MemorySegment; 27 | import java.lang.foreign.ValueLayout; 28 | import java.lang.invoke.MethodHandle; 29 | import java.lang.invoke.MethodHandles; 30 | 31 | /** 32 | * ReadFunc is the type of function which is called when a backend needs to read 33 | * data from an input stream. It is passed the closure which was specified by 34 | * the user at the time the read function was registered, the buffer to read the 35 | * data into and the length of the data in bytes. The read function should throw 36 | * {@link IOException} if all the data was not successfully read. 37 | * 38 | * @since 1.0 39 | */ 40 | @FunctionalInterface 41 | public interface ReadFunc { 42 | 43 | /** 44 | * The function to implement as callback in a read operation from an input 45 | * stream. 46 | * 47 | * @param length the amount of data to read 48 | * @return data the data read from the input stream 49 | * @throws IOException to be thrown when an error occurs during the read 50 | * operation 51 | * @since 1.0 52 | */ 53 | byte[] read(int length) throws IOException; 54 | 55 | /** 56 | * The callback that is executed by native code. This method marshals the 57 | * parameters and calls {@link #read(int)}. 58 | * 59 | * @param closure ignored 60 | * @param data the buffer into which to read the data 61 | * @param length the amount of data to read 62 | * @return {@link Status#SUCCESS} on success, or {@link Status#READ_ERROR} if an 63 | * IOException occured or 0 bytes (or null) was returned from 64 | * {@code read()}. 65 | * @since 1.0 66 | */ 67 | default int upcall(MemorySegment closure, MemorySegment data, int length) { 68 | if (length <= 0) { 69 | return Status.SUCCESS.getValue(); 70 | } 71 | try { 72 | byte[] bytes = read(length); 73 | if (bytes == null || bytes.length == 0) { 74 | return Status.READ_ERROR.getValue(); 75 | } 76 | data.reinterpret(length).asByteBuffer().put(bytes); 77 | return Status.SUCCESS.getValue(); 78 | } catch (IOException ioe) { 79 | return Status.READ_ERROR.getValue(); 80 | } 81 | } 82 | 83 | /** 84 | * Generates an upcall stub, a C function pointer that will call 85 | * {@link #upcall}. 86 | * 87 | * @param arena the arena in which the upcall stub will be allocated 88 | * @return the function pointer of the upcall stub 89 | * @since 1.0 90 | */ 91 | default MemorySegment toCallback(Arena arena) { 92 | try { 93 | FunctionDescriptor fdesc = FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS, 94 | ValueLayout.ADDRESS, ValueLayout.JAVA_INT); 95 | MethodHandle handle = MethodHandles.lookup().findVirtual(ReadFunc.class, "upcall", fdesc.toMethodType()); 96 | return Linker.nativeLinker().upcallStub(handle.bindTo(this), fdesc, arena); 97 | } catch (NoSuchMethodException | IllegalAccessException e) { 98 | throw new RuntimeException(e); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/Glyph.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | import io.github.jwharm.cairobindings.Proxy; 24 | 25 | import java.lang.foreign.MemoryLayout; 26 | import java.lang.foreign.MemorySegment; 27 | import java.lang.foreign.ValueLayout; 28 | import java.lang.invoke.VarHandle; 29 | 30 | /** 31 | * The Glyph structure holds information about a single glyph when drawing or 32 | * measuring text. A font is (in simple terms) a collection of shapes used to 33 | * draw text. A glyph is one of these shapes. There can be multiple glyphs for a 34 | * single character (alternates to be used in different contexts, for example), 35 | * or a glyph can be a ligature of multiple characters. Cairo doesn't 36 | * expose any way of converting input text into glyphs, so in order to use the 37 | * Cairo interfaces that take arrays of glyphs, you must directly access the 38 | * appropriate underlying font system. 39 | *

40 | * Note that the offsets given by {@code x} and {@code y} are not cumulative. 41 | * When drawing or measuring text, each glyph is individually positioned with 42 | * respect to the overall origin. 43 | * 44 | * @since 1.0 45 | */ 46 | public class Glyph extends Proxy { 47 | 48 | /** 49 | * The memory layout of the native C struct 50 | * 51 | * @return the memory layout of the native C struct 52 | */ 53 | static MemoryLayout getMemoryLayout() { 54 | return MemoryLayout.structLayout( 55 | ValueLayout.JAVA_LONG.withName("index"), 56 | ValueLayout.JAVA_DOUBLE.withName("x"), 57 | ValueLayout.JAVA_DOUBLE.withName("y")) 58 | .withName("cairo_glyph_t"); 59 | } 60 | 61 | private static final VarHandle INDEX = getMemoryLayout().varHandle(MemoryLayout.PathElement.groupElement("index")); 62 | private static final VarHandle X = getMemoryLayout().varHandle(MemoryLayout.PathElement.groupElement("x")); 63 | private static final VarHandle Y = getMemoryLayout().varHandle(MemoryLayout.PathElement.groupElement("y")); 64 | 65 | /** 66 | * Glyph index in the font. The exact interpretation of the glyph index depends 67 | * on the font technology being used. 68 | * 69 | * @return glyph index in the font 70 | */ 71 | public long index() { 72 | return (long) INDEX.get(handle(), 0); 73 | } 74 | 75 | /** 76 | * The offset in the X direction between the origin used for drawing or 77 | * measuring the string and the origin of this glyph. 78 | * 79 | * @return the offset in the X direction 80 | */ 81 | public double x() { 82 | return (double) X.get(handle(), 0); 83 | } 84 | 85 | /** 86 | * The offset in the Y direction between the origin used for drawing or 87 | * measuring the string and the origin of this glyph. 88 | * 89 | * @return the offset in the Y direction 90 | */ 91 | public double y() { 92 | return (double) Y.get(handle(), 0); 93 | } 94 | 95 | /** 96 | * Constructor used internally to instantiate a java Glyph object for a native 97 | * {@code cairo_glyph_t} instance 98 | * 99 | * @param address the memory address of the native {@code cairo_glyph_t} 100 | * instance 101 | */ 102 | public Glyph(MemorySegment address) { 103 | super(address.reinterpret(getMemoryLayout().byteSize())); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/io/github/jwharm/cairobindings/Interop.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package io.github.jwharm.cairobindings; 21 | 22 | import java.lang.foreign.*; 23 | import java.lang.invoke.*; 24 | import java.util.EnumSet; 25 | import java.util.Set; 26 | import java.util.function.Function; 27 | 28 | /** 29 | * The Interop class contains functionality for interoperability with native code. 30 | */ 31 | public final class Interop { 32 | 33 | private final static SymbolLookup symbolLookup; 34 | private final static Linker linker = Linker.nativeLinker(); 35 | 36 | static { 37 | SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); 38 | symbolLookup = name -> loaderLookup.find(name).or(() -> linker.defaultLookup().find(name)); 39 | } 40 | 41 | // Prevent instantiation 42 | private Interop() {} 43 | 44 | /** 45 | * Creates a method handle that is used to call the native function with 46 | * the provided name and function descriptor. The method handle is cached 47 | * and reused in subsequent lookups. 48 | * @param name Name of the native function 49 | * @param fdesc Function descriptor of the native function 50 | * @return the MethodHandle 51 | */ 52 | public static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { 53 | return symbolLookup 54 | .find(name) 55 | .map(addr -> linker.downcallHandle(addr, fdesc)) 56 | .orElse(null); 57 | } 58 | 59 | /** 60 | * Allocate a native string using SegmentAllocator.allocateUtf8String(String). 61 | * @param string the string to allocate as a native string (utf8 char*) 62 | * @param allocator the segment allocator to use 63 | * @return the allocated MemorySegment 64 | */ 65 | public static MemorySegment allocateNativeString(String string, SegmentAllocator allocator) { 66 | return string == null ? MemorySegment.NULL : allocator.allocateFrom(string); 67 | } 68 | 69 | /** 70 | * Create an EnumSet of class `cls` from the provided bitfield 71 | * 72 | * @param an enum implementing the Java-GI Enumeration interface 73 | * @param cls the class of the enum 74 | * @param make function that will construct an enum from one flag value 75 | * @param bitfield the integer containing the bitfield 76 | * @return an EnumSet containing the enum values as set in the bitfield 77 | */ 78 | public static & Flag> 79 | EnumSet intToEnumSet(Class cls, 80 | Function make, 81 | int bitfield) { 82 | int n = bitfield; 83 | EnumSet enumSet = EnumSet.noneOf(cls); 84 | int position = 0; 85 | while (n != 0) { 86 | if ((n & 1) == 1) 87 | enumSet.add(make.apply(1 << position)); 88 | position++; 89 | n >>= 1; 90 | } 91 | return enumSet; 92 | } 93 | 94 | /** 95 | * Create a bitfield from the provided Set of enums 96 | * 97 | * @param an enum implementing the Java-GI Enumeration interface 98 | * @param set the set of enums 99 | * @return the resulting bitfield 100 | */ 101 | public static & Flag> 102 | int enumSetToInt(Set set) { 103 | int bitfield = 0; 104 | for (T element : set) 105 | bitfield |= element.getValue(); 106 | return bitfield; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/test/java/org/freedesktop/cairo/test/UserFontFaceTest.java: -------------------------------------------------------------------------------- 1 | package org.freedesktop.cairo.test; 2 | 3 | import org.freedesktop.cairo.*; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.io.IOException; 7 | import java.util.concurrent.atomic.AtomicBoolean; 8 | 9 | import static org.junit.jupiter.api.Assertions.*; 10 | 11 | public class UserFontFaceTest { 12 | 13 | private Context createContext() { 14 | try { 15 | return Context.create(ImageSurface.create(Format.ARGB32, 120, 120)); 16 | } catch (IOException ioe) { 17 | fail(ioe); 18 | throw new RuntimeException(ioe); 19 | } 20 | } 21 | 22 | @Test 23 | void testCreate() { 24 | UserFontFace uf = UserFontFace.create(); 25 | assertEquals(Status.SUCCESS, uf.status()); 26 | } 27 | 28 | @Test 29 | void testInit() { 30 | UserFontFace uf = UserFontFace.create(); 31 | AtomicBoolean flag = new AtomicBoolean(false); 32 | UserScaledFontInitFunc func = (font, cr, extents) -> flag.set(true); 33 | uf.setInitFunc(func); 34 | Context cr = createContext(); 35 | cr.setFontFace(uf); 36 | cr.showText("test"); 37 | assertTrue(flag.get()); 38 | assertEquals(func, uf.getInitFunc()); 39 | assertEquals(Status.SUCCESS, uf.status()); 40 | } 41 | 42 | @Test 43 | void testRenderGlyph() { 44 | UserFontFace uf = UserFontFace.create(); 45 | AtomicBoolean flag = new AtomicBoolean(false); 46 | UserScaledFontRenderGlyphFunc func = (font, glyph, cr, extents) -> flag.set(true); 47 | uf.setRenderGlyphFunc(func); 48 | Context cr = createContext(); 49 | cr.setFontFace(uf); 50 | cr.showText("test"); 51 | assertTrue(flag.get()); 52 | assertEquals(func, uf.getRenderGlyphFunc()); 53 | assertEquals(Status.SUCCESS, uf.status()); 54 | } 55 | 56 | @Test 57 | void testRenderColorGlyph() { 58 | UserFontFace uf = UserFontFace.create(); 59 | AtomicBoolean flag = new AtomicBoolean(false); 60 | UserScaledFontRenderGlyphFunc func = (font, glyph, cr, extents) -> flag.set(true); 61 | uf.setRenderColorGlyphFunc(func); 62 | Context cr = createContext(); 63 | cr.setFontFace(uf); 64 | cr.showText("test"); 65 | assertTrue(flag.get()); 66 | assertEquals(func, uf.getRenderColorGlyphFunc()); 67 | assertEquals(Status.SUCCESS, uf.status()); 68 | } 69 | 70 | @Test 71 | void testRenderColorGlyph_Fallback() { 72 | UserFontFace uf = UserFontFace.create(); 73 | AtomicBoolean flag = new AtomicBoolean(false); 74 | UserScaledFontRenderGlyphFunc renderColorFunc = (font, glyph, cr, extents) -> { 75 | throw new UnsupportedOperationException(); // should redirect to renderFunc 76 | }; 77 | UserScaledFontRenderGlyphFunc renderFunc = (font, glyph, cr, extents) -> flag.set(true); 78 | uf.setRenderColorGlyphFunc(renderColorFunc); 79 | uf.setRenderGlyphFunc(renderFunc); 80 | Context cr = createContext(); 81 | cr.setFontFace(uf); 82 | cr.showText("test"); 83 | assertTrue(flag.get()); 84 | assertEquals(Status.SUCCESS, uf.status()); 85 | } 86 | 87 | @Test 88 | void testUnicodeToGlyph() { 89 | UserFontFace uf = UserFontFace.create(); 90 | AtomicBoolean flag = new AtomicBoolean(false); 91 | UserScaledFontUnicodeToGlyphFunc func = (font, unicode) -> { 92 | flag.set(true); 93 | return 0; 94 | }; 95 | uf.setUnicodeToGlyphFunc(func); 96 | Context cr = createContext(); 97 | cr.setFontFace(uf); 98 | cr.showText("test"); 99 | assertTrue(flag.get()); 100 | assertEquals(func, uf.getUnicodeToGlyphFunc()); 101 | assertEquals(Status.SUCCESS, uf.status()); 102 | } 103 | 104 | @Test 105 | void testTextToGlyphs() { 106 | UserFontFace uf = UserFontFace.create(); 107 | AtomicBoolean flag = new AtomicBoolean(false); 108 | UserScaledFontTextToGlyphsFunc func = (font, string, glyphs) -> { 109 | flag.set(true); 110 | }; 111 | uf.setTextToGlyphsFunc(func); 112 | Context cr = createContext(); 113 | cr.setFontFace(uf); 114 | cr.showText("test"); 115 | assertTrue(flag.get()); 116 | assertEquals(func, uf.getTextToGlyphsFunc()); 117 | assertEquals(Status.SUCCESS, uf.status()); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/MimeType.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | /** 23 | * MIME types defined as constants in Cairo. 24 | */ 25 | public enum MimeType { 26 | 27 | /** 28 | * Group 3 or Group 4 CCITT facsimile encoding (International Telecommunication 29 | * Union, Recommendations T.4 and T.6.) 30 | * 31 | * @since 1.16 32 | */ 33 | CCITT_FAX("image/g3fax"), 34 | 35 | /** 36 | * Decode parameters for Group 3 or Group 4 CCITT facsimile encoding. See 37 | * CCITT 39 | * Fax Images. 40 | * 41 | * @since 1.16 42 | */ 43 | CCITT_FAX_PARAMS("application/x-cairo.ccitt.params"), 44 | 45 | /** 46 | * Encapsulated PostScript file. Encapsulated 48 | * PostScript File Format Specification 49 | * 50 | * @since 1.16 51 | */ 52 | TYPE_EPS("application/postscript"), 53 | 54 | /** 55 | * Embedding parameters Encapsulated PostScript data. See Embedding 57 | * EPS files. 58 | * 59 | * @since 1.16 60 | */ 61 | EPS_PARAMS("application/x-cairo.eps.params"), 62 | 63 | /** 64 | * Joint Bi-level Image Experts Group image coding standard (ISO/IEC 11544). 65 | * 66 | * @since 1.14 67 | */ 68 | JBIG2("application/x-cairo.jbig2"), 69 | 70 | /** 71 | * Joint Bi-level Image Experts Group image coding standard (ISO/IEC 11544) 72 | * global segment. 73 | * 74 | * @since 1.14 75 | */ 76 | JBIG2_GLOBAL("application/x-cairo.jbig2-global"), 77 | 78 | /** 79 | * An unique identifier shared by a JBIG2 global segment and all JBIG2 images 80 | * that depend on the global segment. 81 | * 82 | * @since 1.14 83 | */ 84 | JBIG2_GLOBAL_ID("application/x-cairo.jbig2-global-id"), 85 | 86 | /** 87 | * The Joint Photographic Experts Group (JPEG) 2000 image coding standard 88 | * (ISO/IEC 15444-1). 89 | * 90 | * @since 1.10 91 | */ 92 | JP2("image/jp2"), 93 | 94 | /** 95 | * The Joint Photographic Experts Group (JPEG) image coding standard (ISO/IEC 96 | * 10918-1). 97 | * 98 | * @since 1.10 99 | */ 100 | JPEG("image/jpeg"), 101 | 102 | /** 103 | * The Portable Network Graphics image file format (ISO/IEC 15948). 104 | * 105 | * @since 1.10 106 | */ 107 | PNG("image/png"), 108 | 109 | /** 110 | * URI for an image file (unofficial MIME type). 111 | * 112 | * @since 1.10 113 | */ 114 | URI("text/x-uri"), 115 | 116 | /** 117 | * Unique identifier for a surface (cairo specific MIME type). All surfaces with 118 | * the same unique identifier will only be embedded once. 119 | * 120 | * @since 1.12 121 | */ 122 | UNIQUE_ID("application/x-cairo.uuid"); 123 | 124 | private final String name; 125 | 126 | MimeType(String name) { 127 | this.name = name; 128 | } 129 | 130 | @Override 131 | public String toString() { 132 | return this.name; 133 | } 134 | 135 | /** 136 | * Returns the enum constant for the given ordinal (its position in the enum 137 | * declaration). 138 | * 139 | * @param ordinal the position in the enum declaration, starting from zero 140 | * @return the enum constant for the given ordinal 141 | */ 142 | public static MimeType of(int ordinal) { 143 | return values()[ordinal]; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/freetype/Face.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.freetype; 21 | 22 | import io.github.jwharm.cairobindings.Proxy; 23 | import io.github.jwharm.cairobindings.Interop; 24 | 25 | import java.lang.foreign.Arena; 26 | import java.lang.foreign.FunctionDescriptor; 27 | import java.lang.foreign.MemorySegment; 28 | import java.lang.foreign.ValueLayout; 29 | import java.lang.invoke.MethodHandle; 30 | 31 | /** 32 | * A handle to a typographic face object. A face object models a given typeface, 33 | * in a given style. 34 | */ 35 | public class Face extends Proxy { 36 | 37 | static { 38 | FreeType2.ensureInitialized(); 39 | } 40 | 41 | // The Arena in which the handle to the Face object was allocated. 42 | private Arena allocator = null; 43 | 44 | /** 45 | * Constructor used internally to instantiate a java Face object for a native 46 | * {@code FT_Face} instance 47 | * 48 | * @param address the memory address of the native {@code FT_Face} instance 49 | */ 50 | public Face(MemorySegment address) { 51 | super(address); 52 | } 53 | 54 | /** 55 | * Call {@code FT_Open_Face} to open a font by its pathname. 56 | *

57 | * The resulting Face instance must be cleaned up manually with a call to 58 | * {@link #doneFace()}. 59 | * 60 | * @param library the library resource 61 | * @param filepathname path to the font file 62 | * @param faceIndex See FT_Open_Face 64 | * for a detailed description of this parameter. 65 | * @return the newly created Face instance 66 | * @throws UnsupportedOperationException when {@code FT_Init_FreeType} returns a 67 | * non-zero error code 68 | */ 69 | public static Face newFace(Library library, String filepathname, long faceIndex) { 70 | Arena allocator = Arena.ofConfined(); 71 | try { 72 | MemorySegment pointer = allocator.allocate(ValueLayout.ADDRESS.withTargetLayout(ValueLayout.ADDRESS)); 73 | try (Arena arena = Arena.ofConfined()) { 74 | MemorySegment utf8 = Interop.allocateNativeString(filepathname, arena); 75 | int result = (int) FT_New_Face.invoke(library.handle(), utf8, faceIndex, pointer); 76 | if (result != 0) { 77 | throw new UnsupportedOperationException( 78 | "Error " + result + " occurred during FreeType FT_Face initialization"); 79 | } 80 | Face face = new Face(pointer.get(ValueLayout.ADDRESS, 0)); 81 | face.allocator = allocator; 82 | return face; 83 | } 84 | } catch (Throwable e) { 85 | throw new RuntimeException(e); 86 | } 87 | } 88 | 89 | private static final MethodHandle FT_New_Face = Interop.downcallHandle("FT_New_Face", 90 | FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_LONG, 91 | ValueLayout.ADDRESS)); 92 | 93 | /** 94 | * Discard a given face object, as well as all of its child slots and sizes. 95 | */ 96 | public void doneFace() { 97 | try { 98 | int ignored = (int) FT_Done_Face.invoke(handle()); 99 | } catch (Throwable e) { 100 | throw new RuntimeException(e); 101 | } 102 | if (allocator != null) { 103 | allocator.close(); 104 | allocator = null; 105 | } 106 | } 107 | 108 | private static final MethodHandle FT_Done_Face = Interop.downcallHandle("FT_Done_Face", 109 | FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS)); 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/org/freedesktop/cairo/PSLevel.java: -------------------------------------------------------------------------------- 1 | /* cairo-java-bindings - Java language bindings for cairo 2 | * Copyright (C) 2023 Jan-Willem Harmannij 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, see . 18 | */ 19 | 20 | package org.freedesktop.cairo; 21 | 22 | import io.github.jwharm.cairobindings.Interop; 23 | 24 | import java.lang.foreign.Arena; 25 | import java.lang.foreign.FunctionDescriptor; 26 | import java.lang.foreign.MemorySegment; 27 | import java.lang.foreign.ValueLayout; 28 | import java.lang.invoke.MethodHandle; 29 | 30 | /** 31 | * PSLevel is used to describe the language level of the PostScript 32 | * Language Reference that a generated PostScript file will conform to. 33 | * 34 | * @since 1.6 35 | */ 36 | public enum PSLevel { 37 | 38 | /** 39 | * The language level 2 of the PostScript specification. 40 | * 41 | * @since 1.6 42 | */ 43 | LEVEL_2, 44 | 45 | /** 46 | * The language level 3 of the PostScript specification. 47 | * 48 | * @since 1.6 49 | */ 50 | LEVEL_3; 51 | 52 | /** 53 | * Return the value of this enum 54 | * @return the value 55 | */ 56 | public int getValue() { 57 | return ordinal(); 58 | } 59 | 60 | /** 61 | * Returns the enum constant for the given ordinal (its position in the enum 62 | * declaration). 63 | * 64 | * @param ordinal the position in the enum declaration, starting from zero 65 | * @return the enum constant for the given ordinal 66 | */ 67 | public static PSLevel of(int ordinal) { 68 | return values()[ordinal]; 69 | } 70 | 71 | static { 72 | Cairo.ensureInitialized(); 73 | } 74 | 75 | /** 76 | * Used to retrieve the list of supported levels. See 77 | * {@link PSSurface#restrictToLevel(PSLevel)}. 78 | * 79 | * @return supported level list 80 | * @since 1.6 81 | */ 82 | public static PSLevel[] getLevels() { 83 | try { 84 | try (Arena arena = Arena.ofConfined()) { 85 | MemorySegment levelsPtr = arena.allocate(ValueLayout.ADDRESS); 86 | MemorySegment numLevelsPtr = arena.allocate(ValueLayout.JAVA_INT); 87 | cairo_ps_get_levels.invoke(levelsPtr, numLevelsPtr); 88 | int numLevels = numLevelsPtr.get(ValueLayout.JAVA_INT, 0); 89 | int[] levelInts = levelsPtr.reinterpret(ValueLayout.JAVA_INT.byteSize() * numLevels).toArray(ValueLayout.JAVA_INT); 90 | PSLevel[] levels = new PSLevel[numLevels]; 91 | for (int i = 0; i < levelInts.length; i++) { 92 | levels[i] = PSLevel.of(levelInts[i]); 93 | } 94 | return levels; 95 | } 96 | } catch (Throwable e) { 97 | throw new RuntimeException(e); 98 | } 99 | } 100 | 101 | private static final MethodHandle cairo_ps_get_levels = Interop.downcallHandle("cairo_ps_get_levels", 102 | FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS)); 103 | 104 | /** 105 | * Get the string representation of this level. This function will return 106 | * {@code null} if the level isn't valid. See {@link #getLevels()} for a way to 107 | * get the list of valid levels. 108 | * 109 | * @return the string associated to this level. 110 | * @since 1.6 111 | */ 112 | @Override 113 | public String toString() { 114 | try { 115 | MemorySegment result = (MemorySegment) cairo_ps_level_to_string.invoke(getValue()); 116 | if (MemorySegment.NULL.equals(result)) { 117 | return null; 118 | } 119 | return result.reinterpret(Integer.MAX_VALUE).getString(0); 120 | } catch (Throwable e) { 121 | throw new RuntimeException(e); 122 | } 123 | } 124 | 125 | private static final MethodHandle cairo_ps_level_to_string = Interop.downcallHandle("cairo_ps_level_to_string", 126 | FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.JAVA_INT)); 127 | } 128 | --------------------------------------------------------------------------------