├── .github └── workflows │ ├── linux.yml │ └── macos.yml ├── .gitignore ├── .travis.yml ├── META6.json ├── README.md ├── doc ├── examples │ ├── README.md │ ├── arc-negative.raku │ ├── arc.raku │ ├── blend.raku │ ├── camelia.png │ ├── clip-image.raku │ ├── clip.raku │ ├── curve-rectangle.raku │ ├── curve_to.raku │ ├── dash.raku │ ├── fill-and-stroke.raku │ ├── fill-style.raku │ ├── fonts │ │ └── DejaVuSans.ttf │ ├── freetype.raku │ ├── gradient.raku │ ├── image-pattern.raku │ ├── image.raku │ ├── multi-page-pdf.raku │ ├── multi-segment-caps.raku │ ├── rounded-rectangle.raku │ ├── set-line-cap.raku │ ├── set-line-join.raku │ ├── svg-surface.raku │ ├── text-align-center.raku │ ├── text-extents.raku │ └── text.raku └── screenshot │ ├── arc-negative.png │ ├── arc.png │ ├── clip-image.png │ ├── clip.png │ ├── curve-rectangle.png │ ├── curve_to.png │ ├── dash.png │ ├── fill-and-stroke.png │ ├── fill-style.png │ ├── gradient.png │ ├── image-pattern.png │ ├── image.png │ ├── multi-page-pdf.pdf │ ├── multi-segment-caps.png │ ├── rounded-rectangle.png │ ├── set-line-cap.png │ ├── set-line-join.png │ ├── svg-surface.svg │ ├── text-align-center.png │ ├── text-extents.png │ └── text.png ├── lib └── Cairo.pm6 ├── sparrow.yaml └── t ├── matrix.t ├── pattern.t ├── readme.t ├── surface-image.t ├── surface-pdf.t ├── surface-svg.t └── text.t /.github/workflows/linux.yml: -------------------------------------------------------------------------------- 1 | name: test linux 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | tags-ignore: 8 | - '*' 9 | pull_request: 10 | 11 | jobs: 12 | raku: 13 | strategy: 14 | matrix: 15 | os: 16 | - ubuntu-latest 17 | raku-version: 18 | - 'latest' 19 | - '2021.12' 20 | runs-on: ${{ matrix.os }} 21 | steps: 22 | - uses: actions/checkout@v2 23 | - uses: Raku/setup-raku@v1 24 | with: 25 | raku-version: ${{ matrix.raku-version }} 26 | - name: Install Dependencies 27 | run: | 28 | # install and test if need be (includes [test-depends]) 29 | zef install --deps-only . 30 | zef install --/test App::Prove6 31 | - name: Run Tests 32 | run: prove6 -I. t 33 | - name: Install Module 34 | run: zef install --verbose . 35 | -------------------------------------------------------------------------------- /.github/workflows/macos.yml: -------------------------------------------------------------------------------- 1 | name: test macos 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | tags-ignore: 8 | - '*' 9 | pull_request: 10 | 11 | jobs: 12 | raku: 13 | strategy: 14 | matrix: 15 | os: 16 | - macOS-latest 17 | raku-version: 18 | - 'latest' 19 | - '2021.12' 20 | runs-on: ${{ matrix.os }} 21 | steps: 22 | - uses: actions/checkout@v2 23 | - uses: Raku/setup-raku@v1 24 | with: 25 | raku-version: ${{ matrix.raku-version }} 26 | - name: Install Dependencies 27 | run: | 28 | # install and test if need be (includes [test-depends]) 29 | brew update 30 | brew install cairo 31 | zef install --deps-only . 32 | zef install --/test App::Prove6 33 | - name: Run Tests 34 | run: prove6 -I. t 35 | - name: Install Module 36 | run: zef install --verbose . 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .* 3 | *#* 4 | #.png 5 | #*.svg 6 | #*.pdf 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: perl6 2 | perl6: 3 | - latest 4 | - '2018.12' 5 | addons: 6 | apt: 7 | packages: 8 | - libcairo2 9 | install: 10 | - rakudobrew build-zef 11 | - zef install --depsonly . 12 | script: 13 | - zef test . 14 | sudo: false 15 | -------------------------------------------------------------------------------- /META6.json: -------------------------------------------------------------------------------- 1 | { 2 | "perl" : "v6", 3 | "name" : "Cairo", 4 | "description" : "Cairo 2D graphics library", 5 | "version" : "0.3.7", 6 | "depends" : [ "MacOS::NativeLib" ], 7 | "source-url" : "https://github.com/timo/cairo-p6.git", 8 | "tags" : [ "png", "pdf", "svg", "cairo" ], 9 | "provides" : { 10 | "Cairo" : "lib/Cairo.pm6" 11 | }, 12 | "support" : { 13 | "source" : "https://github.com/timo/cairo-p6.git" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Cairo 2D Graphics library binding for Raku 2 | ========================================== 3 | 4 | Synopsis 5 | -------- 6 | 7 | ```raku 8 | use Cairo; 9 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 128, 128) { 10 | given Cairo::Context.new($_) { 11 | .rgb(0, 0.7, 0.9); 12 | .rectangle(10, 10, 50, 50); 13 | .fill :preserve; .rgb(1, 1, 1); 14 | .stroke 15 | }; 16 | .write_png("foobar.png") 17 | } 18 | ``` 19 | 20 | 21 | Native Cairo library 22 | -------------- 23 | 24 | In order to use this module, native `Cairo` library is needed. See instructions at https://cairographics.org/download/. 25 | 26 | ### Examples 27 | 28 | doc/screenshot/arc-negative.png 29 | ![arc-negative.png](doc/screenshot/arc-negative.png) 30 | 31 | doc/screenshot/arc.png 32 | ![arc.png](doc/screenshot/arc.png) 33 | 34 | doc/screenshot/clip-image.png 35 | ![clip-image.png](doc/screenshot/clip-image.png) 36 | 37 | doc/screenshot/clip.png 38 | ![clip.png](doc/screenshot/clip.png) 39 | 40 | doc/screenshot/curve-rectangle.png 41 | ![curve-rectangle.png](doc/screenshot/curve-rectangle.png) 42 | 43 | 44 | 45 | doc/screenshot/curve_to.png 46 | ![curve_to.png](doc/screenshot/curve_to.png) 47 | 48 | doc/screenshot/dash.png 49 | ![dash.png](doc/screenshot/dash.png) 50 | 51 | doc/screenshot/fill-and-stroke.png 52 | ![fill-and-stroke.png](doc/screenshot/fill-and-stroke.png) 53 | 54 | doc/screenshot/fill-style.png 55 | ![fill-style.png](doc/screenshot/fill-style.png) 56 | 57 | doc/screenshot/gradient.png 58 | ![gradient.png](doc/screenshot/gradient.png) 59 | 60 | doc/screenshot/image-pattern.png 61 | ![image-pattern.png](doc/screenshot/image-pattern.png) 62 | 63 | doc/screenshot/image.png 64 | ![image.png](doc/screenshot/image.png) 65 | 66 | doc/screenshot/multi-page-pdf.pdf 67 | ![multi-page-pdf.pdf](doc/screenshot/multi-page-pdf.pdf) 68 | 69 | doc/screenshot/multi-segment-caps.png 70 | ![multi-segment-caps.png](doc/screenshot/multi-segment-caps.png) 71 | 72 | doc/screenshot/rounded-rectangle.png 73 | ![rounded-rectangle.png](doc/screenshot/rounded-rectangle.png) 74 | 75 | doc/screenshot/set-line-cap.png 76 | ![set-line-cap.png](doc/screenshot/set-line-cap.png) 77 | 78 | doc/screenshot/set-line-join.png 79 | ![set-line-join.png](doc/screenshot/set-line-join.png) 80 | 81 | doc/screenshot/svg-surface.svg 82 | ![svg-surface.svg](doc/screenshot/svg-surface.svg) 83 | 84 | doc/screenshot/text-align-center.png 85 | ![text-align-center.png](doc/screenshot/text-align-center.png) 86 | 87 | doc/screenshot/text-extents.png 88 | ![text-extents.png](doc/screenshot/text-extents.png) 89 | 90 | doc/screenshot/text.png 91 | ![text.png](doc/screenshot/text.png) 92 | -------------------------------------------------------------------------------- /doc/examples/README.md: -------------------------------------------------------------------------------- 1 | - `multi-page-pdf.p6` demonstrates the creation of a two page PDF. 2 | - `svg-surface.p6` demonstrates creation of a SVG graphic. 3 | - all other examples produce PNG images. 4 | 5 | Please see https://cairographics.org/samples for expected output and equivalent C programs. 6 | -------------------------------------------------------------------------------- /doc/examples/arc-negative.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | constant xc = 128.0; 5 | constant yc = 128.0; 6 | constant radius = 100.0; 7 | constant angle1 = 45.0 * (pi/180.0); # angles are specified 8 | constant angle2 = 180.0 * (pi/180.0); # in radians 9 | 10 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 11 | given Cairo::Context.new($_) { 12 | .line_width = 10.0; 13 | .arc(xc, yc, radius, angle1, angle2, :negative); 14 | .stroke; 15 | 16 | # draw helping lines 17 | .rgba(1, 0.2, 0.2, 0.6); 18 | .line_width = 6.0; 19 | 20 | .arc(xc, yc, 10.0, 0, 2*pi); 21 | .fill; 22 | 23 | .arc(xc, yc, radius, angle1, angle1); 24 | .line_to(xc, yc); 25 | .arc(xc, yc, radius, angle2, angle2); 26 | .line_to(xc, yc); 27 | .stroke; 28 | }; 29 | .write_png("arc-negative.png"); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /doc/examples/arc.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | constant xc = 128.0; 5 | constant yc = 128.0; 6 | constant radius = 100.0; 7 | constant angle1 = 45.0 * (pi/180.0); # angles are specified 8 | constant angle2 = 180.0 * (pi/180.0); # in radians 9 | 10 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 11 | given Cairo::Context.new($_) { 12 | .line_width = 10.0; 13 | .arc(xc, yc, radius, angle1, angle2); 14 | .stroke; 15 | 16 | # draw helping lines 17 | .rgba(1, 0.2, 0.2, 0.6); 18 | .line_width = 6.0; 19 | 20 | .arc(xc, yc, 10.0, 0, 2*pi); 21 | .fill; 22 | 23 | .arc(xc, yc, radius, angle1, angle1); 24 | .line_to(xc, yc); 25 | .arc(xc, yc, radius, angle2, angle2); 26 | .line_to(xc, yc); 27 | .stroke; 28 | }; 29 | .write_png("arc.png"); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /doc/examples/blend.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | # adapted from https://zetcode.com/gfx/cairo/compositing/ 5 | 6 | sub do-drawing(Cairo::Context $ctx, Int $x, Int $w, Int $h, Int $op) { 7 | 8 | my Cairo::Image $blended-image .= create(Cairo::FORMAT_ARGB32, $w, $h); 9 | given Cairo::Context.new($blended-image) { 10 | .rgb(.5, .5, 0); 11 | .rectangle($x+10, 40, 50, 50); 12 | .fill; 13 | } 14 | my Cairo::Image $image .= create(Cairo::FORMAT_ARGB32, $w, $h); 15 | given Cairo::Context.new($image) { 16 | .rgb(0, 0, 0.4); 17 | .rectangle($x, 20, 50, 50); 18 | .fill; 19 | .operator = $op; 20 | .set_source_surface($blended-image, 0, 0); 21 | .paint; 22 | } 23 | $ctx.set_source_surface($image, 0, 0); 24 | $ctx.paint; 25 | 26 | } 27 | 28 | constant Width = 510; 29 | constant Height = 120; 30 | 31 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, Width, Height) { 32 | given Cairo::Context.new($_) { 33 | my @ops = (CAIRO_OPERATOR_DEST_OVER, 34 | CAIRO_OPERATOR_DEST_IN, 35 | CAIRO_OPERATOR_OUT, 36 | CAIRO_OPERATOR_ADD, 37 | CAIRO_OPERATOR_ATOP, 38 | CAIRO_OPERATOR_DEST_ATOP, 39 | ); 40 | 41 | my $x = 20; 42 | for @ops -> $op { 43 | do-drawing($_, $x, Width, Height, $op ); 44 | $x += 80; 45 | } 46 | } 47 | .write_png("blend.png"); 48 | } 49 | -------------------------------------------------------------------------------- /doc/examples/camelia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/examples/camelia.png -------------------------------------------------------------------------------- /doc/examples/clip-image.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 5 | given Cairo::Context.new($_) { 6 | .arc(128.0, 128.0, 76.8, 0, 2*pi); 7 | .clip; 8 | .new_path; # path not consumed by .clip 9 | 10 | my \image = Cairo::Image.open("examples/camelia.png" ); 11 | my \w = image.width; 12 | my \h = image.height; 13 | 14 | .scale(256.0/w, 256.0/h); 15 | 16 | .set_source_surface(image, 0, 0); 17 | .paint; 18 | 19 | image.destroy; 20 | }; 21 | .write_png("clip-image.png"); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /doc/examples/clip.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | constant xc = 128.0; 5 | constant yc = 128.0; 6 | constant radius = 100.0; 7 | constant angle1 = 45.0 * (pi/180.0); # angles are specified 8 | constant angle2 = 180.0 * (pi/180.0); # in radians 9 | 10 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 11 | given Cairo::Context.new($_) { 12 | .arc(128.0, 128.0, 76.8, 0, 2 * pi); 13 | .clip(); 14 | 15 | .new_path(); # current path is not 16 | # consumed by .clip 17 | .rectangle(0, 0, 256, 256); 18 | .fill(); 19 | .rgb(0, 1, 0); 20 | .move_to(0, 0); 21 | .line_to(256, 256); 22 | .move_to(256, 0); 23 | .line_to(0, 256); 24 | .line_width = 10.0; 25 | .stroke(); 26 | }; 27 | .write_png("clip.png"); 28 | } 29 | 30 | -------------------------------------------------------------------------------- /doc/examples/curve-rectangle.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 5 | given Cairo::Context.new($_) { 6 | # a custom shape that could be wrapped in a function 7 | constant x0 = 25.6; # parameters like cairo_rectangle 8 | constant y0 = 25.6; 9 | constant rect_width = 204.8; 10 | constant rect_height = 204.8; 11 | constant radius = 102.4 * 2; # and an approximate curvature radius 12 | 13 | constant x1 = x0 + rect_width; 14 | constant y1 = y0 + rect_height; 15 | 16 | if (!rect_width || !rect_height) { 17 | return; 18 | } 19 | if (rect_width/2 < radius) { 20 | if (rect_height/2 < radius) { 21 | .move_to(x0, (y0 + y1)/2); 22 | .curve_to(x0 ,y0, x0, y0, (x0 + x1)/2, y0); 23 | .curve_to(x1, y0, x1, y0, x1, (y0 + y1)/2); 24 | .curve_to(x1, y1, x1, y1, (x1 + x0)/2, y1); 25 | .curve_to(x0, y1, x0, y1, x0, (y0 + y1)/2); 26 | } else { 27 | .move_to(x0, y0 + radius); 28 | .curve_to(x0 ,y0, x0, y0, (x0 + x1)/2, y0); 29 | .curve_to(x1, y0, x1, y0, x1, y0 + radius); 30 | .line_to(x1 , y1 - radius); 31 | .curve_to(x1, y1, x1, y1, (x1 + x0)/2, y1); 32 | .curve_to(x0, y1, x0, y1, x0, y1- radius); 33 | } 34 | } else { 35 | if (rect_height/2 < radius) { 36 | .move_to(x0, (y0 + y1)/2); 37 | .curve_to(x0 , y0, x0 , y0, x0 + radius, y0); 38 | .line_to(x1 - radius, y0); 39 | .curve_to(x1, y0, x1, y0, x1, (y0 + y1)/2); 40 | .curve_to(x1, y1, x1, y1, x1 - radius, y1); 41 | .line_to(x0 + radius, y1); 42 | .curve_to(x0, y1, x0, y1, x0, (y0 + y1)/2); 43 | } else { 44 | .move_to(x0, y0 + radius); 45 | .curve_to(x0 , y0, x0 , y0, x0 + radius, y0); 46 | .line_to(x1 - radius, y0); 47 | .curve_to(x1, y0, x1, y0, x1, y0 + radius); 48 | .line_to(x1 , y1 - radius); 49 | .curve_to(x1, y1, x1, y1, x1 - radius, y1); 50 | .line_to(x0 + radius, y1); 51 | .curve_to(x0, y1, x0, y1, x0, y1- radius); 52 | } 53 | } 54 | 55 | .rgb(0.5, 0.5, 1); 56 | .fill(:preserve); 57 | .rgba(0.5, 0, 0, 0.5); 58 | .line_width = 10.0; 59 | .stroke; 60 | }; 61 | .write_png("curve-rectangle.png"); 62 | } 63 | 64 | -------------------------------------------------------------------------------- /doc/examples/curve_to.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 5 | given Cairo::Context.new($_) { 6 | 7 | constant x=25.6; 8 | constant y=128.0; 9 | constant x1=102.4; 10 | constant y1=230.4; 11 | constant x2=153.6; 12 | constant y2=25.6; 13 | constant x3=230.4; 14 | constant y3=128.0; 15 | 16 | .move_to(x, y); 17 | .curve_to(x1, y1, x2, y2, x3, y3); 18 | 19 | .line_width = 10.0; 20 | .stroke; 21 | 22 | .rgba(1, 0.2, 0.2, 0.6); 23 | .line_width = 6.0; 24 | .move_to(x,y); .line_to(x1,y1); 25 | .move_to(x2,y2); .line_to(x3,y3); 26 | .stroke; 27 | 28 | }; 29 | .write_png("curve_to.png"); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /doc/examples/dash.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 5 | given Cairo::Context.new($_) { 6 | 7 | my \dashes = (50.0, # ink 8 | 10.0, # skip 9 | 10.0, # ink 10 | 10.0 # skip 11 | ); 12 | my \ndash = +dashes; 13 | my \offset = -50.0; 14 | 15 | .set_dash(dashes, ndash, offset); 16 | .line_width = 10.0; 17 | 18 | .move_to(128.0, 25.6); 19 | .line_to(230.4, 230.4); 20 | .line_to(-102.4, 0.0, :relative); 21 | .curve_to(51.2, 230.4, 51.2, 128.0, 128.0, 128.0); 22 | 23 | .stroke; 24 | }; 25 | .write_png("dash.png"); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /doc/examples/fill-and-stroke.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 5 | given Cairo::Context.new($_) { 6 | .move_to(128.0, 25.6); 7 | .line_to(230.4, 230.4); 8 | .line_to(-102.4, 0.0, :relative); 9 | .curve_to(51.2, 230.4, 51.2, 128.0, 128.0, 128.0); 10 | .close_path; 11 | 12 | .move_to(64.0, 25.6); 13 | .line_to(51.2, 51.2, :relative); 14 | .line_to(-51.2, 51.2, :relative); 15 | .line_to(-51.2, -51.2, :relative); 16 | .close_path; 17 | 18 | .line_width = 10.0; 19 | .rgb(0, 0, 1); 20 | .fill(:preserve); 21 | .rgb(0, 0, 0); 22 | .stroke; 23 | }; 24 | .write_png("fill-and-stroke.png"); 25 | } 26 | 27 | -------------------------------------------------------------------------------- /doc/examples/fill-style.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 5 | given Cairo::Context.new($_) { 6 | 7 | .line_width = 6; 8 | 9 | .rectangle(12, 12, 232, 70); 10 | .sub_path; .arc(64, 64, 40, 0, 2*pi); 11 | .sub_path; .arc(192, 64, 40, 0, -2*pi, :negative); 12 | 13 | .fill_rule = Cairo::FILL_RULE_EVEN_ODD; 14 | .rgb(0, 0.7, 0); .fill(:preserve); 15 | .rgb(0, 0, 0); .stroke; 16 | 17 | .translate(0, 128); 18 | .rectangle(12, 12, 232, 70); 19 | .sub_path; .arc(64, 64, 40, 0, 2*pi); 20 | .sub_path; .arc(192, 64, 40, 0, -2*pi, :negative); 21 | 22 | .fill_rule = Cairo::FILL_RULE_WINDING; 23 | .rgb(0, 0, 0.9); .fill(:preserve); 24 | .rgb(0, 0, 0); .stroke; 25 | }; 26 | .write_png("fill-style.png"); 27 | } 28 | 29 | -------------------------------------------------------------------------------- /doc/examples/fonts/DejaVuSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/examples/fonts/DejaVuSans.ttf -------------------------------------------------------------------------------- /doc/examples/freetype.raku: -------------------------------------------------------------------------------- 1 | # This example requires the Font::FreeType module 2 | use Cairo; 3 | use Font::FreeType:ver<0.3.0+>; 4 | use Font::FreeType::Face; 5 | use Font::FreeType::Raw; 6 | 7 | my Font::FreeType $freetype .= new; 8 | 9 | sub MAIN( 10 | :$font-file = '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 11 | :$png = 'freetype.png', 12 | ) { 13 | my Font::FreeType::Face $face = $freetype.face($font-file); 14 | # get the underlying FreeType Face native C-struct 15 | my FT_Face $ft-face = $face.raw; 16 | my Cairo::Font $font .= create( 17 | $ft-face, :free-type, 18 | ); 19 | 20 | freetype-demo($font, $png); 21 | 22 | $font.destroy; 23 | } 24 | 25 | sub freetype-demo(Cairo::Font:D $font, Str:D $png-file) { 26 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 27 | 28 | given Cairo::Context.new($_) { 29 | 30 | .set_font_size(90.0); 31 | .set_font_face($font); 32 | .move_to(10.0, 135.0); 33 | .show_text("Hello"); 34 | 35 | .move_to(70.0, 165.0); 36 | .text_path("font"); 37 | .rgb(0.5, 0.5, 1); 38 | .fill(:preserve); 39 | .rgb(0, 0, 0); 40 | .line_width = 2.56; 41 | .stroke; 42 | 43 | # draw helping lines 44 | .rgba(1, 0.2, 0.2, 0.6); 45 | .arc(10.0, 135.0, 5.12, 0, 2*pi); 46 | .close_path; 47 | .arc(70.0, 165.0, 5.12, 0, 2*pi); 48 | .fill; 49 | } 50 | .write_png($png-file); 51 | 52 | .destroy; 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /doc/examples/gradient.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 5 | given Cairo::Context.new($_) { 6 | 7 | my Cairo::Pattern::Gradient::Linear $lpat .= create(0.0, 0.0, 0.0, 256.0); 8 | $lpat.add_color_stop_rgba(1, 0, 0, 0, 1); 9 | $lpat.add_color_stop_rgba(0, 1, 1, 1, 1); 10 | .rectangle(0, 0, 256, 256); 11 | .pattern($lpat); 12 | .fill; 13 | $lpat.destroy; 14 | 15 | my Cairo::Pattern::Gradient::Radial $rpat .= create(115.2, 102.4, 25.6, 16 | 102.4, 102.4, 128.0); 17 | $rpat.add_color_stop_rgba(0, 1, 1, 1, 1); 18 | $rpat.add_color_stop_rgba(1, 0, 0, 0, 1); 19 | .pattern($rpat); 20 | .arc(128.0, 128.0, 76.8, 0, 2 * pi); 21 | .fill; 22 | $rpat.destroy; 23 | 24 | }; 25 | .write_png("gradient.png"); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /doc/examples/image-pattern.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 5 | given Cairo::Context.new($_) { 6 | 7 | my $image = Cairo::Image.open("examples/camelia.png" ); 8 | my \w = $image.width; 9 | my \h = $image.height; 10 | 11 | my Cairo::Pattern::Surface $pattern .= create($image.surface); 12 | $pattern.extend = Cairo::EXTEND_REPEAT; 13 | 14 | .translate(128.0, 128.0); 15 | .rotate(pi / 4); 16 | .scale(1 / sqrt(2), 1 / sqrt(2)); 17 | .translate(-128.0, -128.0); 18 | 19 | my Cairo::Matrix $matrix .= new.scale(w/256.0 * 5.0, h/256.0 * 5.0); 20 | $pattern.matrix = $matrix; 21 | .pattern($pattern); 22 | 23 | .rectangle(0, 0, 256.0, 256.0); 24 | .fill; 25 | 26 | $pattern.destroy; 27 | $image.destroy; 28 | 29 | }; 30 | .write_png("image-pattern.png"); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /doc/examples/image.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 5 | given Cairo::Context.new($_) { 6 | 7 | my \image = Cairo::Image.open("camelia.png" ); 8 | my \w = image.width; 9 | my \h = image.height; 10 | 11 | .translate(128.0, 128.0); 12 | .rotate(30 * pi/180); 13 | .scale(256/w, 256/h); 14 | .translate(-0.5*w, -0.5*h); 15 | 16 | .set_source_surface(image, 0, 0); 17 | .paint; 18 | image.destroy; 19 | 20 | }; 21 | .write_png("image.png"); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /doc/examples/multi-page-pdf.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Surface::PDF.create("multi-page-pdf.pdf", 256, 256) -> $s { 5 | given Cairo::Context.new($s) { 6 | # Tag for accessibility 7 | .tag: "Document", { 8 | for 1..2 -> $page { 9 | .set_font_size(10); 10 | .tag: "Figure", { 11 | .save; 12 | .rgb(0, 0.7, 0.9); 13 | .rectangle(10, 10, 50, 50); 14 | .fill :preserve; 15 | .rgb(1, 1, 1); 16 | .stroke; 17 | .restore; 18 | }; 19 | .tag: "P", { 20 | .select_font_face("courier", Cairo::FONT_SLANT_ITALIC, Cairo::FONT_WEIGHT_BOLD); 21 | .move_to(10, 10); 22 | .show_text("Page $page/2"); 23 | } 24 | $s.show_page; 25 | } 26 | $s.finish; 27 | } 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /doc/examples/multi-segment-caps.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 5 | given Cairo::Context.new($_) { 6 | 7 | .move_to(50.0, 75.0); 8 | .line_to(200.0, 75.0); 9 | 10 | .move_to(50.0, 125.0); 11 | .line_to(200.0, 125.0); 12 | 13 | .move_to(50.0, 175.0); 14 | .line_to(200.0, 175.0); 15 | 16 | .line_width = 30.0; 17 | .line_cap = Cairo::LINE_CAP_ROUND; 18 | .stroke; 19 | 20 | }; 21 | .write_png("multi-segment-caps.png"); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /doc/examples/rounded-rectangle.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 5 | given Cairo::Context.new($_) { 6 | 7 | constant x = 25.6; # parameters like cairo_rectangle 8 | constant y = 25.6; 9 | constant width = 204.8; 10 | constant height = 204.8; 11 | constant aspect = 1.0; # aspect ratio 12 | constant corner_radius = height / 10.0; # and corner curvature radius 13 | constant radius = corner_radius / aspect; 14 | constant degrees = pi / 180.0; 15 | 16 | .sub_path; 17 | .arc(x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees); 18 | .arc(x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees); 19 | .arc(x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees); 20 | .arc(x + radius, y + radius, radius, 180 * degrees, 270 * degrees); 21 | .close_path; 22 | 23 | .rgb(0.5, 0.5, 1); 24 | .fill(:preserve); 25 | .rgba(0.5, 0, 0, 0.5); 26 | .line_width = 10; 27 | .stroke; 28 | 29 | }; 30 | .write_png("rounded-rectangle.png"); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /doc/examples/set-line-cap.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 5 | given Cairo::Context.new($_) { 6 | 7 | .line_width = 30.0; 8 | .line_cap = Cairo::LINE_CAP_BUTT; # default 9 | .move_to(64.0, 50.0); .line_to(64.0, 200.0); 10 | .stroke; 11 | .line_cap = Cairo::LINE_CAP_ROUND; 12 | .move_to(128.0, 50.0); .line_to(128.0, 200.0); 13 | .stroke; 14 | .line_cap = Cairo::LINE_CAP_SQUARE; 15 | .move_to(192.0, 50.0); .line_to(192.0, 200.0); 16 | .stroke; 17 | 18 | # draw helping lines */ 19 | .rgb(1, 0.2, 0.2); 20 | .line_width = 2.56; 21 | .move_to(64.0, 50.0); .line_to(64.0, 200.0); 22 | .move_to(128.0, 50.0); .line_to(128.0, 200.0); 23 | .move_to(192.0, 50.0); .line_to(192.0, 200.0); 24 | .stroke; 25 | 26 | }; 27 | .write_png("set-line-cap.png"); 28 | } 29 | 30 | -------------------------------------------------------------------------------- /doc/examples/set-line-join.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 5 | given Cairo::Context.new($_) { 6 | 7 | .line_width = 40.96; 8 | .move_to(76.8, 84.48); 9 | .line_to(51.2, -51.2, :relative); 10 | .line_to(51.2, 51.2, :relative); 11 | .line_join = Cairo::LINE_JOIN_MITER; # default 12 | .stroke; 13 | 14 | .move_to(76.8, 161.28); 15 | .line_to(51.2, -51.2, :relative); 16 | .line_to(51.2, 51.2, :relative); 17 | .line_join = Cairo::LINE_JOIN_BEVEL; 18 | .stroke; 19 | 20 | .move_to(76.8, 238.08); 21 | .line_to(51.2, -51.2, :relative); 22 | .line_to(51.2, 51.2, :relative); 23 | .line_join = Cairo::LINE_JOIN_ROUND; 24 | .stroke; 25 | 26 | }; 27 | .write_png("set-line-join.png"); 28 | } 29 | 30 | -------------------------------------------------------------------------------- /doc/examples/svg-surface.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Surface::SVG.create("svg-surface.svg", 256, 256) { 5 | given Cairo::Context.new($_) { 6 | 7 | .select_font_face("courier", Cairo::FONT_SLANT_ITALIC, Cairo::FONT_WEIGHT_BOLD); 8 | .set_font_size(10); 9 | .save; 10 | do { 11 | .rgb(0, 0.7, 0.9); 12 | .rectangle(10, 10, 50, 50); 13 | .fill :preserve; 14 | .rgb(1, 1, 1); 15 | .stroke; 16 | }; 17 | .restore; 18 | .move_to(10, 10); 19 | .show_text("SVG Example"); 20 | } 21 | .finish; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /doc/examples/text-align-center.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 5 | given Cairo::Context.new($_) { 6 | 7 | .select_font_face("Sans", 8 | Cairo::FONT_SLANT_NORMAL, 9 | Cairo::FONT_WEIGHT_BOLD); 10 | .set_font_size(52.0); 11 | 12 | my \text = "cairo"; 13 | my Cairo::cairo_text_extents_t \extents = .text_extents(text); 14 | my \x = 128.0-(extents.width/2 + extents.x_bearing); 15 | my \y = 128.0-(extents.height/2 + extents.y_bearing); 16 | 17 | .move_to(x, y); 18 | .show_text(text); 19 | 20 | # draw helping lines 21 | .rgba(1, 0.2, 0.2, 0.6); 22 | .line_width = 6.0; 23 | .arc(x, y, 10.0, 0, 2*pi); 24 | .fill; 25 | .move_to(128.0, 0); 26 | .line_to(0, 256, :relative); 27 | .move_to(0, 128.0); 28 | .line_to(256, 0, :relative); 29 | .stroke; 30 | }; 31 | .write_png("text-align-center.png"); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /doc/examples/text-extents.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 5 | given Cairo::Context.new($_) { 6 | 7 | .select_font_face("Sans", 8 | Cairo::FONT_SLANT_NORMAL, 9 | Cairo::FONT_WEIGHT_NORMAL); 10 | .set_font_size(100.0); 11 | 12 | my \text = "cairo"; 13 | my Cairo::cairo_text_extents_t \extents = .text_extents(text); 14 | constant x=25.0; 15 | constant y=150.0; 16 | 17 | .move_to(x,y); 18 | .show_text(text); 19 | 20 | # draw helping lines 21 | .rgba(1, 0.2, 0.2, 0.6); 22 | .line_width = 6.0; 23 | .arc(x, y, 10.0, 0, 2*pi); 24 | .fill; 25 | .move_to(x,y); 26 | .line_to(0, -extents.height, :relative); 27 | .line_to(extents.width, 0, :relative); 28 | .line_to(extents.x_bearing, -extents.y_bearing, :relative); 29 | .stroke; 30 | }; 31 | .write_png("text-extents.png"); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /doc/examples/text.raku: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | 4 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 256, 256) { 5 | given Cairo::Context.new($_) { 6 | 7 | .select_font_face("Sans", 8 | Cairo::FONT_SLANT_NORMAL, 9 | Cairo::FONT_WEIGHT_BOLD); 10 | .set_font_size(90.0); 11 | 12 | .move_to(10.0, 135.0); 13 | .show_text("Hello"); 14 | 15 | .move_to(70.0, 165.0); 16 | .text_path("void"); 17 | .rgb(0.5, 0.5, 1); 18 | .fill(:preserve); 19 | .rgb(0, 0, 0); 20 | .line_width = 2.56; 21 | .stroke; 22 | 23 | # draw helping lines 24 | .rgba(1, 0.2, 0.2, 0.6); 25 | .arc(10.0, 135.0, 5.12, 0, 2*pi); 26 | .close_path; 27 | .arc(70.0, 165.0, 5.12, 0, 2*pi); 28 | .fill; 29 | 30 | }; 31 | .write_png("text.png"); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /doc/screenshot/arc-negative.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/arc-negative.png -------------------------------------------------------------------------------- /doc/screenshot/arc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/arc.png -------------------------------------------------------------------------------- /doc/screenshot/clip-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/clip-image.png -------------------------------------------------------------------------------- /doc/screenshot/clip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/clip.png -------------------------------------------------------------------------------- /doc/screenshot/curve-rectangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/curve-rectangle.png -------------------------------------------------------------------------------- /doc/screenshot/curve_to.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/curve_to.png -------------------------------------------------------------------------------- /doc/screenshot/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/dash.png -------------------------------------------------------------------------------- /doc/screenshot/fill-and-stroke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/fill-and-stroke.png -------------------------------------------------------------------------------- /doc/screenshot/fill-style.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/fill-style.png -------------------------------------------------------------------------------- /doc/screenshot/gradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/gradient.png -------------------------------------------------------------------------------- /doc/screenshot/image-pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/image-pattern.png -------------------------------------------------------------------------------- /doc/screenshot/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/image.png -------------------------------------------------------------------------------- /doc/screenshot/multi-page-pdf.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/multi-page-pdf.pdf -------------------------------------------------------------------------------- /doc/screenshot/multi-segment-caps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/multi-segment-caps.png -------------------------------------------------------------------------------- /doc/screenshot/rounded-rectangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/rounded-rectangle.png -------------------------------------------------------------------------------- /doc/screenshot/set-line-cap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/set-line-cap.png -------------------------------------------------------------------------------- /doc/screenshot/set-line-join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/set-line-join.png -------------------------------------------------------------------------------- /doc/screenshot/svg-surface.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /doc/screenshot/text-align-center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/text-align-center.png -------------------------------------------------------------------------------- /doc/screenshot/text-extents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/text-extents.png -------------------------------------------------------------------------------- /doc/screenshot/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timo/cairo-p6/b946950165f75b0db4ade60dd9f81e16cc399ca6/doc/screenshot/text.png -------------------------------------------------------------------------------- /lib/Cairo.pm6: -------------------------------------------------------------------------------- 1 | unit module Cairo:ver<0.3.7>; 2 | 3 | use MacOS::NativeLib 'cairo'; 4 | 5 | our $cairolib; 6 | BEGIN { 7 | if $*VM.config ~~ /dll/ { 8 | $cairolib = 'libcairo-2'; 9 | } else { 10 | $cairolib = ('cairo', v2); 11 | } 12 | } 13 | 14 | use NativeCall; 15 | 16 | our enum cairo_status_t is export < 17 | CAIRO_STATUS_SUCCESS 18 | 19 | CAIRO_STATUS_NO_MEMORY 20 | CAIRO_STATUS_INVALID_RESTORE 21 | CAIRO_STATUS_INVALID_POP_GROUP 22 | CAIRO_STATUS_NO_CURRENT_POINT 23 | CAIRO_STATUS_INVALID_MATRIX 24 | CAIRO_STATUS_INVALID_STATUS 25 | CAIRO_STATUS_NULL_POINTER 26 | CAIRO_STATUS_INVALID_STRING 27 | CAIRO_STATUS_INVALID_PATH_DATA 28 | CAIRO_STATUS_READ_ERROR 29 | CAIRO_STATUS_WRITE_ERROR 30 | CAIRO_STATUS_SURFACE_FINISHED 31 | CAIRO_STATUS_SURFACE_TYPE_MISMATCH 32 | CAIRO_STATUS_PATTERN_TYPE_MISMATCH 33 | CAIRO_STATUS_INVALID_CONTENT 34 | CAIRO_STATUS_INVALID_FORMAT 35 | CAIRO_STATUS_INVALID_VISUAL 36 | CAIRO_STATUS_FILE_NOT_FOUND 37 | CAIRO_STATUS_INVALID_DASH 38 | CAIRO_STATUS_INVALID_DSC_COMMENT 39 | CAIRO_STATUS_INVALID_INDEX 40 | CAIRO_STATUS_CLIP_NOT_REPRESENTABLE 41 | CAIRO_STATUS_TEMP_FILE_ERROR 42 | CAIRO_STATUS_INVALID_STRIDE 43 | CAIRO_STATUS_FONT_TYPE_MISMATCH 44 | CAIRO_STATUS_USER_FONT_IMMUTABLE 45 | CAIRO_STATUS_USER_FONT_ERROR 46 | CAIRO_STATUS_NEGATIVE_COUNT 47 | CAIRO_STATUS_INVALID_CLUSTERS 48 | CAIRO_STATUS_INVALID_SLANT 49 | CAIRO_STATUS_INVALID_WEIGHT 50 | CAIRO_STATUS_INVALID_SIZE 51 | CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED 52 | CAIRO_STATUS_DEVICE_TYPE_MISMATCH 53 | CAIRO_STATUS_DEVICE_ERROR 54 | CAIRO_STATUS_INVALID_MESH_CONSTRUCTION 55 | CAIRO_STATUS_DEVICE_FINISHED 56 | 57 | CAIRO_STATUS_LAST_STATUS 58 | >; 59 | 60 | our enum CairoStatus is export < 61 | STATUS_SUCCESS 62 | 63 | STATUS_NO_MEMORY 64 | STATUS_INVALID_RESTORE 65 | STATUS_INVALID_POP_GROUP 66 | STATUS_NO_CURRENT_POINT 67 | STATUS_INVALID_MATRIX 68 | STATUS_INVALID_STATUS 69 | STATUS_NULL_POINTER 70 | STATUS_INVALID_STRING 71 | STATUS_INVALID_PATH_DATA 72 | STATUS_READ_ERROR 73 | STATUS_WRITE_ERROR 74 | STATUS_SURFACE_FINISHED 75 | STATUS_SURFACE_TYPE_MISMATCH 76 | STATUS_PATTERN_TYPE_MISMATCH 77 | STATUS_INVALID_CONTENT 78 | STATUS_INVALID_FORMAT 79 | STATUS_INVALID_VISUAL 80 | STATUS_FILE_NOT_FOUND 81 | STATUS_INVALID_DASH 82 | STATUS_INVALID_DSC_COMMENT 83 | STATUS_INVALID_INDEX 84 | STATUS_CLIP_NOT_REPRESENTABLE 85 | STATUS_TEMP_FILE_ERROR 86 | STATUS_INVALID_STRIDE 87 | STATUS_FONT_TYPE_MISMATCH 88 | STATUS_USER_FONT_IMMUTABLE 89 | STATUS_USER_FONT_ERROR 90 | STATUS_NEGATIVE_COUNT 91 | STATUS_INVALID_CLUSTERS 92 | STATUS_INVALID_SLANT 93 | STATUS_INVALID_WEIGHT 94 | STATUS_INVALID_SIZE 95 | STATUS_USER_FONT_NOT_IMPLEMENTED 96 | STATUS_DEVICE_TYPE_MISMATCH 97 | STATUS_DEVICE_ERROR 98 | STATUS_INVALID_MESH_CONSTRUCTION 99 | STATUS_DEVICE_FINISHED 100 | 101 | STATUS_LAST_STATUS 102 | >; 103 | 104 | our enum cairo_path_data_type_t is export < 105 | CAIRO_PATH_MOVE_TO 106 | CAIRO_PATH_LINE_TO 107 | CAIRO_PATH_CURVE_TO 108 | CAIRO_PATH_CLOSE_PATH 109 | >; 110 | 111 | our enum PathDataTypes is export < 112 | PATH_MOVE_TO 113 | PATH_LINE_TO 114 | PATH_CURVE_TO 115 | PATH_CLOSE_PATH 116 | >; 117 | 118 | our enum cairo_tag_t is export ( 119 | :CAIRO_TAG_DEST, 120 | :CAIRO_TAG_LINK, 121 | ); 122 | 123 | our enum cairo_pdf_outline_flags_t is export ( 124 | :CAIRO_PDF_OUTLINE_FLAG_OPEN(0x1), 125 | :CAIRO_PDF_OUTLINE_FLAG_BOLD(0x2), 126 | :CAIRO_PDF_OUTLINE_FLAG_ITALIC(0x4), 127 | ); 128 | 129 | our enum cairo_pdf_metadata_t is export < 130 | CAIRO_PDF_METADATA_TITLE 131 | CAIRO_PDF_METADATA_AUTHOR 132 | CAIRO_PDF_METADATA_SUBJECT 133 | CAIRO_PDF_METADATA_KEYWORDS 134 | CAIRO_PDF_METADATA_CREATOR 135 | CAIRO_PDF_METADATA_CREATE_DATE 136 | CAIRO_PDF_METADATA_MOD_DATE 137 | >; 138 | 139 | sub cairo_version_string 140 | returns Str 141 | is native($cairolib) 142 | {*} 143 | 144 | our sub version { 145 | Version.new: cairo_version_string() 146 | } 147 | 148 | my class StreamClosure is repr('CStruct') is rw { 149 | 150 | sub memcpy(Pointer[uint8] $dest, Pointer[uint8] $src, size_t $n) 151 | is native 152 | {*} 153 | 154 | has CArray[uint8] $!buf; 155 | has size_t $.buf-len; 156 | has size_t $.n-read; 157 | has size_t $.size; 158 | submethod TWEAK(CArray :$buf!) { $!buf := $buf } 159 | method buf-pointer( --> Pointer[uint8]) { 160 | nativecast(Pointer[uint8], $!buf); 161 | } 162 | method read-pointer(--> Pointer) { 163 | Pointer[uint8].new: +$.buf-pointer + $!n-read; 164 | } 165 | method write-pointer(--> Pointer) { 166 | Pointer[uint8].new: +$.buf-pointer + $!buf-len; 167 | } 168 | our method read(Pointer $out, uint32 $len --> int32) { 169 | return STATUS_READ_ERROR 170 | if $len > self.buf-len - self.n-read; 171 | 172 | memcpy($out, self.read-pointer, $len); 173 | self.n-read += $len; 174 | return STATUS_SUCCESS; 175 | } 176 | our method write(Pointer $in, uint32 $len --> int32) { 177 | return STATUS_WRITE_ERROR 178 | if $len > self.size - self.buf-len; 179 | memcpy(self.write-pointer, $in, $len); 180 | self.buf-len += $len; 181 | return STATUS_SUCCESS; 182 | } 183 | } 184 | 185 | module Attrs { 186 | sub attr-value($_) { 187 | when List { '[' ~ .map(&attr-value).join(' ') ~ ']' } 188 | when Bool { $_ ?? 'true' !! 'false'} 189 | when Int { .Str } 190 | when Numeric { 191 | my Str $num = .fmt('%.5f'); 192 | $num ~~ s/(\.\d*?)0+$/$0/; 193 | $num .= chop if $num.ends-with('.'); 194 | $num 195 | } 196 | when Str { 197 | q{'} ~ .trans("\\" => "\\\\", "'" => "\\'") ~ q{'}; 198 | } 199 | default { 200 | warn "unsupported attribute value: {.raku}"; 201 | '' 202 | } 203 | } 204 | 205 | our sub serialize(%attrs) { 206 | join ' ', %attrs.sort.map: { 207 | .value.defined 208 | ?? .key ~ '=' ~ attr-value(.value) 209 | !! Empty 210 | } 211 | } 212 | } 213 | 214 | our class cairo_surface_t is repr('CPointer') { 215 | 216 | method status 217 | returns uint32 218 | is native($cairolib) 219 | is symbol('cairo_surface_status') 220 | {*} 221 | 222 | method write_to_png(Str $filename) 223 | returns int32 224 | is native($cairolib) 225 | is symbol('cairo_surface_write_to_png') 226 | {*} 227 | 228 | method write_to_png_stream( 229 | &write-func (StreamClosure, Pointer[uint8], uint32 --> int32), 230 | StreamClosure) 231 | returns int32 232 | is native($cairolib) 233 | is symbol('cairo_surface_write_to_png_stream') 234 | {*} 235 | 236 | method reference 237 | returns cairo_surface_t 238 | is native($cairolib) 239 | is symbol('cairo_surface_reference') 240 | {*} 241 | 242 | method show_page 243 | is native($cairolib) 244 | is symbol('cairo_surface_show_page') 245 | {*} 246 | 247 | method flush 248 | is native($cairolib) 249 | is symbol('cairo_surface_flush') 250 | {*} 251 | 252 | method finish 253 | is native($cairolib) 254 | is symbol('cairo_surface_finish') 255 | {*} 256 | 257 | method destroy 258 | is native($cairolib) 259 | is symbol('cairo_surface_destroy') 260 | {*} 261 | 262 | method get_image_data 263 | returns OpaquePointer 264 | is native($cairolib) 265 | is symbol('cairo_image_surface_get_data') 266 | {*} 267 | method get_image_stride 268 | returns int32 269 | is native($cairolib) 270 | is symbol('cairo_image_surface_get_stride') 271 | {*} 272 | method get_image_width 273 | returns int32 274 | is native($cairolib) 275 | is symbol('cairo_image_surface_get_width') 276 | {*} 277 | method get_image_height 278 | returns int32 279 | is native($cairolib) 280 | is symbol('cairo_image_surface_get_height') 281 | {*} 282 | 283 | } 284 | 285 | class cairo_pdf_surface_t is cairo_surface_t is repr('CPointer') { 286 | 287 | our sub create(str $filename, num64 $width, num64 $height) 288 | returns cairo_pdf_surface_t 289 | is native($cairolib) 290 | is symbol('cairo_pdf_surface_create') 291 | {*} 292 | 293 | 294 | method add_outline(int32 $parent-id, Str $name, Str $link-attrs, int32 $flags --> int32) 295 | is native($cairolib) 296 | is symbol('cairo_pdf_surface_add_outline') 297 | {*} 298 | 299 | method set_metadata(int32 $type, Str $value) 300 | is native($cairolib) 301 | is symbol('cairo_pdf_surface_set_metadata') 302 | {*} 303 | 304 | method new(Str:D :$filename!, Num:D() :$width!, Num:D() :$height! --> cairo_pdf_surface_t:D) { 305 | create($filename, $width, $height); 306 | } 307 | } 308 | 309 | class cairo_svg_surface_t is cairo_surface_t is repr('CPointer') { 310 | our sub create(str $filename, num64 $width, num64 $height) 311 | returns cairo_svg_surface_t 312 | is native($cairolib) 313 | is symbol('cairo_svg_surface_create') 314 | {*} 315 | 316 | method new(Str:D :$filename!, Num:D() :$width!, Num:D() :$height! --> cairo_svg_surface_t) { 317 | create($filename, $width, $height); 318 | } 319 | } 320 | 321 | our class cairo_rectangle_t is repr('CPointer') { } 322 | 323 | our class cairo_path_data_header_t is repr('CStruct') { 324 | has uint32 $.type; 325 | has int32 $.length; 326 | } 327 | our class cairo_path_data_point_t is repr('CStruct') { 328 | has num64 $.x is rw; 329 | has num64 $.y is rw; 330 | } 331 | our class cairo_path_data_t is repr('CUnion') is export { 332 | HAS cairo_path_data_header_t $.header; 333 | HAS cairo_path_data_point_t $.point; 334 | 335 | method data-type { PathDataTypes( self.header.type ) } 336 | method length { self.header.length } 337 | method x is rw { self.point.x } 338 | method y is rw { self.point.y } 339 | } 340 | 341 | our class cairo_path_t is repr('CStruct') is export { 342 | has uint32 $.status; # cairo_path_data_type_t 343 | has Pointer[cairo_path_data_t] $.data; 344 | has int32 $.num_data; 345 | 346 | sub path_destroy(cairo_path_t) 347 | is symbol('cairo_path_destroy') 348 | is native($cairolib) 349 | {*} 350 | 351 | method destroy { 352 | path_destroy(self); 353 | } 354 | } 355 | 356 | our class cairo_text_extents_t is repr('CStruct') { 357 | has num64 $.x_bearing is rw; 358 | has num64 $.y_bearing is rw; 359 | has num64 $.width is rw; 360 | has num64 $.height is rw; 361 | has num64 $.x_advance is rw; 362 | has num64 $.y_advance is rw; 363 | } 364 | 365 | our class cairo_font_extents_t is repr('CStruct') { 366 | has num64 $.ascent is rw; 367 | has num64 $.descent is rw; 368 | has num64 $.height is rw; 369 | has num64 $.max_x_advance is rw; 370 | has num64 $.max_y_advance is rw; 371 | } 372 | 373 | our class cairo_rectangle_int_t is repr('CStruct') { 374 | has int32 $.x is rw; 375 | has int32 $.y is rw; 376 | has int32 $.width is rw; 377 | has int32 $.height is rw; 378 | } 379 | 380 | our class cairo_font_face_t is repr('CPointer') { 381 | 382 | method reference 383 | is native($cairolib) 384 | is symbol('cairo_font_face_reference') 385 | {*} 386 | method destroy 387 | is native($cairolib) 388 | is symbol('cairo_font_face_destroy') 389 | {*} 390 | } 391 | 392 | our class cairo_scaled_font_t is repr('CPointer') { 393 | 394 | method reference 395 | is native($cairolib) 396 | is symbol('cairo_scaled_font_reference') 397 | {*} 398 | method destroy 399 | is native($cairolib) 400 | is symbol('cairo_scaled_font_destroy') 401 | {*} 402 | } 403 | 404 | our class cairo_glyph_t is repr('CStruct') { 405 | has ulong $.index is rw; 406 | has num64 $.x is rw ; 407 | has num64 $.y is rw; 408 | 409 | sub cairo_glyph_allocate(int32 $num_glyphs) 410 | returns cairo_glyph_t 411 | is native($cairolib) 412 | {*} 413 | 414 | method allocate(UInt $num_glyphs) { 415 | cairo_glyph_allocate($num_glyphs); 416 | } 417 | 418 | method free 419 | is native($cairolib) 420 | is symbol('cairo_glyph_free') 421 | {*} 422 | } 423 | 424 | our class cairo_matrix_t is repr('CStruct') { 425 | has num64 $.xx; has num64 $.yx; 426 | has num64 $.xy; has num64 $.yy; 427 | has num64 $.x0; has num64 $.y0; 428 | 429 | method init(num64 $xx, num64 $yx, num64 $xy, num64 $yy, num64 $x0, num64 $y0) 430 | is native($cairolib) 431 | is symbol('cairo_matrix_init') 432 | {*} 433 | 434 | method scale(num64 $sx, num64 $sy) 435 | is native($cairolib) 436 | is symbol('cairo_matrix_scale') 437 | {*} 438 | 439 | method translate(num64 $tx, num64 $ty) 440 | is native($cairolib) 441 | is symbol('cairo_matrix_translate') 442 | {*} 443 | 444 | method rotate(cairo_matrix_t $b) 445 | is native($cairolib) 446 | is symbol('cairo_matrix_rotate') 447 | {*} 448 | 449 | method invert 450 | is native($cairolib) 451 | is symbol('cairo_matrix_invert') 452 | {*} 453 | 454 | method multiply(cairo_matrix_t $a, cairo_matrix_t $b) 455 | is native($cairolib) 456 | is symbol('cairo_matrix_multiply') 457 | {*} 458 | 459 | } 460 | 461 | our class cairo_pattern_t is repr('CPointer') { 462 | 463 | method destroy 464 | is native($cairolib) 465 | is symbol('cairo_pattern_destroy') 466 | {*} 467 | 468 | method get_extend 469 | returns int32 470 | is native($cairolib) 471 | is symbol('cairo_pattern_get_extend') 472 | {*} 473 | 474 | method set_extend(uint32 $extend) 475 | is native($cairolib) 476 | is symbol('cairo_pattern_set_extend') 477 | {*} 478 | 479 | method set_matrix(cairo_matrix_t $matrix) 480 | is native($cairolib) 481 | is symbol('cairo_pattern_set_matrix') 482 | {*} 483 | 484 | method get_matrix(cairo_matrix_t $matrix) 485 | is native($cairolib) 486 | is symbol('cairo_pattern_get_matrix') 487 | {*} 488 | 489 | method get_color_stop_count(int32 $count is rw) 490 | returns int32 491 | is native($cairolib) 492 | is symbol('cairo_pattern_get_color_stop_count') 493 | {*} 494 | 495 | method get_color_stop_rgba( 496 | int32 $index, 497 | num64 $o is rw, 498 | num64 $r is rw, 499 | num64 $g is rw, 500 | num64 $b is rw 501 | ) 502 | returns int32 503 | is native($cairolib) 504 | is symbol('cairo_pattern_get_color_stop_rgba') 505 | {*} 506 | 507 | method add_color_stop_rgb(num64 $offset, num64 $r, num64 $g, num64 $b) 508 | returns int32 509 | is native($cairolib) 510 | is symbol('cairo_pattern_add_color_stop_rgb') 511 | {*} 512 | 513 | method add_color_stop_rgba(num64 $offset, num64 $r, num64 $g, num64 $b, num64 $a) 514 | returns int32 515 | is native($cairolib) 516 | is symbol('cairo_pattern_add_color_stop_rgba') 517 | {*} 518 | 519 | } 520 | 521 | class cairo_font_options_t is repr('CPointer') { 522 | 523 | method copy 524 | returns cairo_font_options_t 525 | is native($cairolib) 526 | is symbol('cairo_font_options_create') 527 | {*} 528 | 529 | method destroy 530 | is native($cairolib) 531 | is symbol('cairo_font_options_destroy') 532 | {*} 533 | 534 | method status 535 | returns uint32 536 | is native($cairolib) 537 | is symbol('cairo_font_options_status') 538 | {*} 539 | 540 | method merge(cairo_font_options_t $other) 541 | is native($cairolib) 542 | is symbol('cairo_font_options_merge') 543 | {*} 544 | 545 | method hash 546 | returns uint64 547 | is native($cairolib) 548 | is symbol('cairo_font_options_hash') 549 | {*} 550 | 551 | method equal(cairo_font_options_t $opts) 552 | returns uint32 553 | is native($cairolib) 554 | is symbol('cairo_font_options_equal') 555 | {*} 556 | 557 | method set_antialias(uint32 $aa) 558 | is native($cairolib) 559 | is symbol('cairo_font_options_set_antialias') 560 | {*} 561 | 562 | method get_antialias 563 | returns uint32 564 | is native($cairolib) 565 | is symbol('cairo_font_options_get_antialias') 566 | {*} 567 | 568 | method set_subpixel_order(uint32 $order) 569 | is native($cairolib) 570 | is symbol('cairo_font_options_create_subpixel_order') 571 | {*} 572 | 573 | method get_subpixel_order 574 | returns uint32 575 | is native($cairolib) 576 | is symbol('cairo_font_options_create_get_subpixel_order') 577 | {*} 578 | 579 | method set_hint_style(uint32 $style) 580 | is native($cairolib) 581 | is symbol('cairo_font_options_set_hint_style') 582 | {*} 583 | 584 | method get_hint_style 585 | returns uint32 586 | is native($cairolib) 587 | is symbol('cairo_font_options_get_hint_style') 588 | {*} 589 | 590 | method set_hint_metrics(uint32 $metrics) 591 | is native($cairolib) 592 | is symbol('cairo_font_options_set_hint_metrics') 593 | {*} 594 | 595 | method get_hint_metrics 596 | returns uint32 597 | is native($cairolib) 598 | is symbol('cairo_font_options_get_hint_metrics') 599 | {*} 600 | 601 | } 602 | 603 | our class cairo_t is repr('CPointer') { 604 | 605 | method destroy 606 | is native($cairolib) 607 | is symbol('cairo_destroy') 608 | {*} 609 | 610 | method sub_path 611 | returns cairo_path_t 612 | is native($cairolib) 613 | is symbol('cairo_new_sub_path') 614 | {*} 615 | 616 | method copy_path 617 | returns cairo_path_t 618 | is native($cairolib) 619 | is symbol('cairo_copy_path') 620 | {*} 621 | 622 | method copy_path_flat 623 | returns cairo_path_t 624 | is native($cairolib) 625 | is symbol('cairo_copy_path_flat') 626 | {*} 627 | 628 | method append_path(cairo_path_t $path) 629 | returns cairo_path_t 630 | is native($cairolib) 631 | is symbol('cairo_append_path') 632 | {*} 633 | 634 | 635 | method push_group 636 | is native($cairolib) 637 | is symbol('cairo_push_group') 638 | {*} 639 | 640 | method pop_group 641 | returns cairo_pattern_t 642 | is native($cairolib) 643 | is symbol('cairo_pop_group') 644 | {*} 645 | 646 | method pop_group_to_source 647 | is native($cairolib) 648 | is symbol('cairo_pop_group_to_source') 649 | {*} 650 | 651 | 652 | method get_current_point(num64 $x is rw, num64 $y is rw) 653 | is native($cairolib) 654 | is symbol('cairo_get_current_point') 655 | {*} 656 | method line_to(num64 $x, num64 $y) 657 | is native($cairolib) 658 | is symbol('cairo_line_to') 659 | {*} 660 | 661 | method move_to(num64 $x, num64 $y) 662 | is native($cairolib) 663 | is symbol('cairo_move_to') 664 | {*} 665 | 666 | method curve_to(num64 $x1, num64 $y1, num64 $x2, num64 $y2, num64 $x3, num64 $y3) 667 | is native($cairolib) 668 | is symbol('cairo_curve_to') 669 | {*} 670 | 671 | method rel_line_to(num64 $x, num64 $y) 672 | is native($cairolib) 673 | is symbol('cairo_rel_line_to') 674 | {*} 675 | 676 | method rel_move_to(num64 $x, num64 $y) 677 | is native($cairolib) 678 | is symbol('cairo_rel_move_to') 679 | {*} 680 | 681 | method rel_curve_to(num64 $x1, num64 $y1, num64 $x2, num64 $y2, num64 $x3, num64 $y3) 682 | is native($cairolib) 683 | is symbol('cairo_rel_curve_to') 684 | {*} 685 | 686 | method arc(num64 $xc, num64 $yc, num64 $radius, num64 $angle1, num64 $angle2) 687 | is native($cairolib) 688 | is symbol('cairo_arc') 689 | {*} 690 | method arc_negative(num64 $xc, num64 $yc, num64 $radius, num64 $angle1, num64 $angle2) 691 | is native($cairolib) 692 | is symbol('cairo_arc_negative') 693 | {*} 694 | 695 | method close_path 696 | is native($cairolib) 697 | is symbol('cairo_close_path') 698 | {*} 699 | 700 | method new_path 701 | is native($cairolib) 702 | is symbol('cairo_new_path') 703 | {*} 704 | 705 | method rectangle(num64 $x, num64 $y, num64 $w, num64 $h) 706 | is native($cairolib) 707 | is symbol('cairo_rectangle') 708 | {*} 709 | 710 | 711 | method set_source_rgb(num64 $r, num64 $g, num64 $b) 712 | is native($cairolib) 713 | is symbol('cairo_set_source_rgb') 714 | {*} 715 | 716 | method set_source_rgba(num64 $r, num64 $g, num64 $b, num64 $a) 717 | is native($cairolib) 718 | is symbol('cairo_set_source_rgba') 719 | {*} 720 | 721 | method set_source(cairo_pattern_t $pat) 722 | is native($cairolib) 723 | is symbol('cairo_set_source') 724 | {*} 725 | 726 | method set_line_cap(int32 $cap) 727 | is native($cairolib) 728 | is symbol('cairo_set_line_cap') 729 | {*} 730 | 731 | method get_line_cap 732 | returns int32 733 | is native($cairolib) 734 | is symbol('cairo_get_line_cap') 735 | {*} 736 | 737 | method set_line_join(int32 $join) 738 | is native($cairolib) 739 | is symbol('cairo_set_line_join') 740 | {*} 741 | 742 | method get_line_join 743 | returns int32 744 | is native($cairolib) 745 | is symbol('cairo_get_line_join') 746 | {*} 747 | 748 | method set_fill_rule(int32 $cap) 749 | is native($cairolib) 750 | is symbol('cairo_set_fill_rule') 751 | {*} 752 | 753 | method get_fill_rule 754 | returns int32 755 | is native($cairolib) 756 | is symbol('cairo_get_fill_rule') 757 | {*} 758 | 759 | method set_line_width(num64 $width) 760 | is native($cairolib) 761 | is symbol('cairo_set_line_width') 762 | {*} 763 | method get_line_width 764 | returns num64 765 | is native($cairolib) 766 | is symbol('cairo_get_line_width') 767 | {*} 768 | 769 | method set_miter_limit(num64 $width) 770 | is native($cairolib) 771 | is symbol('cairo_set_miter_limit') 772 | {*} 773 | method get_miter_limit 774 | returns num64 775 | is native($cairolib) 776 | is symbol('cairo_get_miter_limit') 777 | {*} 778 | 779 | method set_dash(CArray[num64] $dashes, int32 $len, num64 $offset) 780 | is native($cairolib) 781 | is symbol('cairo_set_dash') 782 | {*} 783 | 784 | method get_operator 785 | returns int32 786 | is native($cairolib) 787 | is symbol('cairo_get_operator') 788 | {*} 789 | method set_operator(int32 $op) 790 | is native($cairolib) 791 | is symbol('cairo_set_operator') 792 | {*} 793 | 794 | method get_antialias 795 | returns int32 796 | is native($cairolib) 797 | is symbol('cairo_get_antialias') 798 | {*} 799 | method set_antialias(int32 $op) 800 | is native($cairolib) 801 | is symbol('cairo_set_antialias') 802 | {*} 803 | 804 | method set_source_surface(cairo_surface_t $surface, num64 $x, num64 $y) 805 | is native($cairolib) 806 | is symbol('cairo_set_source_surface') 807 | {*} 808 | 809 | method mask(cairo_pattern_t $pattern) 810 | is native($cairolib) 811 | is symbol('cairo_mask') 812 | {*} 813 | method mask_surface(cairo_surface_t $surface, num64 $sx, num64 $sy) 814 | is native($cairolib) 815 | is symbol('cairo_mask_surface') 816 | {*} 817 | 818 | method clip 819 | is native($cairolib) 820 | is symbol('cairo_clip') 821 | {*} 822 | method clip_preserve 823 | is native($cairolib) 824 | is symbol('cairo_clip_preserve') 825 | {*} 826 | 827 | method fill 828 | is native($cairolib) 829 | is symbol('cairo_fill') 830 | {*} 831 | 832 | method stroke 833 | is native($cairolib) 834 | is symbol('cairo_stroke') 835 | {*} 836 | 837 | method fill_preserve 838 | is native($cairolib) 839 | is symbol('cairo_fill_preserve') 840 | {*} 841 | 842 | method stroke_preserve 843 | is native($cairolib) 844 | is symbol('cairo_stroke_preserve') 845 | {*} 846 | 847 | method paint 848 | is native($cairolib) 849 | is symbol('cairo_paint') 850 | {*} 851 | method paint_with_alpha(num64 $alpha) 852 | is native($cairolib) 853 | is symbol('cairo_paint_with_alpha') 854 | {*} 855 | 856 | method translate(num64 $tx, num64 $ty) 857 | is native($cairolib) 858 | is symbol('cairo_translate') 859 | {*} 860 | method scale(num64 $sx, num64 $sy) 861 | is native($cairolib) 862 | is symbol('cairo_scale') 863 | {*} 864 | method rotate(num64 $angle) 865 | is native($cairolib) 866 | is symbol('cairo_rotate') 867 | {*} 868 | method transform(cairo_matrix_t $matrix) 869 | is native($cairolib) 870 | is symbol('cairo_transform') 871 | {*} 872 | method identity_matrix 873 | is native($cairolib) 874 | is symbol('cairo_identity_matrix') 875 | {*} 876 | method set_matrix(cairo_matrix_t $matrix) 877 | is native($cairolib) 878 | is symbol('cairo_set_matrix') 879 | {*} 880 | method get_matrix(cairo_matrix_t $matrix) 881 | is native($cairolib) 882 | is symbol('cairo_get_matrix') 883 | {*} 884 | 885 | method save 886 | is native($cairolib) 887 | is symbol('cairo_save') 888 | {*} 889 | method restore 890 | is native($cairolib) 891 | is symbol('cairo_restore') 892 | {*} 893 | 894 | method status 895 | returns int32 896 | is native($cairolib) 897 | is symbol('cairo_status') 898 | {*} 899 | 900 | 901 | method select_font_face(Str $family, int32 $slant, int32 $weight) 902 | is native($cairolib) 903 | is symbol('cairo_select_font_face') 904 | {*} 905 | 906 | method set_font_face(cairo_font_face_t $font) 907 | is native($cairolib) 908 | is symbol('cairo_set_font_face') 909 | {*} 910 | 911 | method get_font_face 912 | returns cairo_font_face_t 913 | is native($cairolib) 914 | is symbol('cairo_get_font_face') 915 | {*} 916 | 917 | method set_font_size(num64 $size) 918 | is native($cairolib) 919 | is symbol('cairo_set_font_size') 920 | {*} 921 | 922 | method set_scaled_font(cairo_scaled_font_t $font) 923 | is native($cairolib) 924 | is symbol('cairo_set_scaled_font') 925 | {*} 926 | 927 | method get_scaled_font 928 | returns cairo_scaled_font_t 929 | is native($cairolib) 930 | is symbol('cairo_get_scaled_font') 931 | {*} 932 | 933 | method show_text(Str $utf8) 934 | is native($cairolib) 935 | is symbol('cairo_show_text') 936 | {*} 937 | 938 | method text_path(Str $utf8) 939 | is native($cairolib) 940 | is symbol('cairo_text_path') 941 | {*} 942 | 943 | method show_glyphs(cairo_glyph_t $glyphs, int32 $len) 944 | is native($cairolib) 945 | is symbol('cairo_show_glyphs') 946 | {*} 947 | 948 | method glyph_path(cairo_glyph_t $glyphs, int32 $len) 949 | is native($cairolib) 950 | is symbol('cairo_glyph_path') 951 | {*} 952 | 953 | method text_extents(Str $utf8, cairo_text_extents_t $extents) 954 | is native($cairolib) 955 | is symbol('cairo_text_extents') 956 | {*} 957 | 958 | method font_extents(cairo_font_extents_t $extents) 959 | is native($cairolib) 960 | is symbol('cairo_font_extents') 961 | {*} 962 | 963 | method set_tolerance(num64 $tolerance) 964 | is native($cairolib) 965 | is symbol('cairo_set_tolerance') 966 | {*} 967 | 968 | method get_tolerance() 969 | returns num64 970 | is native($cairolib) 971 | is symbol('cairo_get_tolerance') 972 | {*} 973 | 974 | method set_font_options(cairo_font_options_t $options) 975 | is native($cairolib) 976 | is symbol('cairo_set_font_options') 977 | {*} 978 | method get_font_options() 979 | is native($cairolib) 980 | is symbol('cairo_get_font_options') 981 | {*} 982 | 983 | method tag_begin(Str $tag, Str $attrs) 984 | is native($cairolib) 985 | is symbol('cairo_tag_begin') 986 | {*} 987 | 988 | method tag_end(Str $tag) 989 | is native($cairolib) 990 | is symbol('cairo_tag_end') 991 | {*} 992 | 993 | } 994 | 995 | # Backwards compatibility 996 | our enum cairo_subpixel_order_t is export < 997 | CAIRO_SUBPIXEL_ORDER_DEFAULT, 998 | CAIRO_SUBPIXEL_ORDER_RGB, 999 | CAIRO_SUBPIXEL_ORDER_BGR, 1000 | CAIRO_SUBPIXEL_ORDER_VRGB, 1001 | CAIRO_SUBPIXEL_ORDER_VBGR 1002 | >; 1003 | 1004 | our enum SubpixelOrder is export < 1005 | SUBPIXEL_ORDER_DEFAULT 1006 | SUBPIXEL_ORDER_RGB 1007 | SUBPIXEL_ORDER_BGR 1008 | SUBPIXEL_ORDER_VRGB 1009 | SUBPIXEL_ORDER_VBGR 1010 | >; 1011 | 1012 | our enum cairo_hint_style_t is export < 1013 | CAIRO_HINT_STYLE_DEFAULT 1014 | CAIRO_HINT_STYLE_NONE 1015 | CAIRO_HINT_STYLE_SLIGHT 1016 | CAIRO_HINT_STYLE_MEDIUM 1017 | CAIRO_HINT_STYLE_FULL 1018 | >; 1019 | 1020 | our enum HintStyle is export < 1021 | HINT_STYLE_DEFAULT 1022 | HINT_STYLE_NONE 1023 | HINT_STYLE_SLIGHT 1024 | HINT_STYLE_MEDIUM 1025 | HINT_STYLE_FULL 1026 | >; 1027 | 1028 | our enum cairo_hint_metrics_t is export < 1029 | CAIRO_HINT_METRICS_DEFAULT 1030 | CAIRO_HINT_METRICS_OFF 1031 | CAIRO_HINT_METRICS_ON 1032 | >; 1033 | 1034 | our enum HintMetrics is export < 1035 | HINT_METRICS_DEFAULT 1036 | HINT_METRICS_OFF 1037 | HINT_METRICS_ON 1038 | >; 1039 | 1040 | our enum cairo_antialias_t is export < 1041 | CAIRO_ANTIALIAS_DEFAULT 1042 | CAIRO_ANTIALIAS_NONE 1043 | CAIRO_ANTIALIAS_GRAY 1044 | CAIRO_ANTIALIAS_SUBPIXEL 1045 | CAIRO_ANTIALIAS_FAST 1046 | CAIRO_ANTIALIAS_GOOD 1047 | CAIRO_ANTIALIAS_BEST 1048 | >; 1049 | 1050 | our class Matrix { ... } 1051 | our class Surface { ... } 1052 | our class Image { ... } 1053 | our class Pattern { ... } 1054 | our class Context { ... } 1055 | our class Font { ... } 1056 | our class FontOptions { ... } 1057 | our class ScaledFont { ... } 1058 | 1059 | # Backwards compatibility 1060 | our enum cairo_format_t is export ( 1061 | CAIRO_FORMAT_INVALID => -1, 1062 | CAIRO_FORMAT_ARGB32 => 0, 1063 | CAIRO_FORMAT_RGB24 => 1, 1064 | CAIRO_FORMAT_A8 => 2, 1065 | CAIRO_FORMAT_A1 => 3, 1066 | CAIRO_FORMAT_RGB16_565 => 4, 1067 | CAIRO_FORMAT_RGB30 => 5 1068 | ); 1069 | 1070 | our enum Format is export ( 1071 | FORMAT_INVALID => -1, 1072 | "FORMAT_ARGB32" , 1073 | "FORMAT_RGB24" , 1074 | "FORMAT_A8" , 1075 | "FORMAT_A1" , 1076 | "FORMAT_RGB16_565", 1077 | "FORMAT_RGB30" , 1078 | ); 1079 | 1080 | # Backwards compatibility 1081 | our enum cairo_operator_t is export < 1082 | CAIRO_OPERATOR_CLEAR 1083 | CAIRO_OPERATOR_SOURCE 1084 | CAIRO_OPERATOR_OVER 1085 | CAIRO_OPERATOR_IN 1086 | CAIRO_OPERATOR_OUT 1087 | CAIRO_OPERATOR_ATOP 1088 | CAIRO_OPERATOR_DEST 1089 | CAIRO_OPERATOR_DEST_OVER 1090 | CAIRO_OPERATOR_DEST_IN 1091 | CAIRO_OPERATOR_DEST_OUT 1092 | CAIRO_OPERATOR_DEST_ATOP 1093 | CAIRO_OPERATOR_XOR 1094 | CAIRO_OPERATOR_ADD 1095 | CAIRO_OPERATOR_SATURATE 1096 | CAIRO_OPERATOR_MULTIPLY 1097 | CAIRO_OPERATOR_SCREEN 1098 | CAIRO_OPERATOR_OVERLAY 1099 | CAIRO_OPERATOR_DARKEN 1100 | CAIRO_OPERATOR_LIGHTEN 1101 | CAIRO_OPERATOR_COLOR_DODGE 1102 | CAIRO_OPERATOR_COLOR_BURN 1103 | CAIRO_OPERATOR_HARD_LIGHT 1104 | CAIRO_OPERATOR_SOFT_LIGHT 1105 | CAIRO_OPERATOR_DIFFERENCE 1106 | CAIRO_OPERATOR_EXCLUSION 1107 | CAIRO_OPERATOR_HSL_HUE 1108 | CAIRO_OPERATOR_HSL_SATURATION 1109 | CAIRO_OPERATOR_HSL_COLOR 1110 | CAIRO_OPERATOR_HSL_LUMINOSITY 1111 | >; 1112 | 1113 | our enum CairoOperator is export < 1114 | OPERATOR_CLEAR 1115 | 1116 | OPERATOR_SOURCE 1117 | OPERATOR_OVER 1118 | OPERATOR_IN 1119 | OPERATOR_OUT 1120 | OPERATOR_ATOP 1121 | 1122 | OPERATOR_DEST 1123 | OPERATOR_DEST_OVER 1124 | OPERATOR_DEST_IN 1125 | OPERATOR_DEST_OUT 1126 | OPERATOR_DEST_ATOP 1127 | 1128 | OPERATOR_XOR 1129 | OPERATOR_ADD 1130 | OPERATOR_SATURATE 1131 | 1132 | OPERATOR_MULTIPLY 1133 | OPERATOR_SCREEN 1134 | OPERATOR_OVERLAY 1135 | OPERATOR_DARKEN 1136 | OPERATOR_LIGHTEN 1137 | OPERATOR_COLOR_DODGE 1138 | OPERATOR_COLOR_BURN 1139 | OPERATOR_HARD_LIGHT 1140 | OPERATOR_SOFT_LIGHT 1141 | OPERATOR_DIFFERENCE 1142 | OPERATOR_EXCLUSION 1143 | OPERATOR_HSL_HUE 1144 | OPERATOR_HSL_SATURATION 1145 | OPERATOR_HSL_COLOR 1146 | OPERATOR_HSL_LUMINOSITY 1147 | >; 1148 | 1149 | our enum cairo_line_cap is export < 1150 | CAIRO_LINE_CAP_BUTT 1151 | CAIRO_LINE_CAP_ROUND 1152 | CAIRO_LINE_CAP_SQUARE 1153 | >; 1154 | 1155 | our enum LineCap is export < 1156 | LINE_CAP_BUTT 1157 | LINE_CAP_ROUND 1158 | LINE_CAP_SQUARE 1159 | >; 1160 | 1161 | our enum cairo_line_join is export < 1162 | CAIRO_LINE_JOIN_MITER 1163 | CAIRO_LINE_JOIN_ROUND 1164 | CAIRO_LINE_JOIN_BEVEL 1165 | >; 1166 | 1167 | our enum LineJoin is export < 1168 | LINE_JOIN_MITER 1169 | LINE_JOIN_ROUND 1170 | LINE_JOIN_BEVEL 1171 | >; 1172 | 1173 | our enum Content is export ( 1174 | CONTENT_COLOR => 0x1000, 1175 | CONTENT_ALPHA => 0x2000, 1176 | CONTENT_COLOR_ALPHA => 0x3000, 1177 | ); 1178 | 1179 | our enum Antialias is export < 1180 | ANTIALIAS_DEFAULT 1181 | ANTIALIAS_NONE 1182 | ANTIALIAS_GRAY 1183 | ANTIALIAS_SUBPIXEL 1184 | ANTIALIAS_FAST 1185 | ANTIALIAS_GOOD 1186 | ANTIALIAS_BEST 1187 | >; 1188 | 1189 | our enum FontWeight is export < 1190 | FONT_WEIGHT_NORMAL 1191 | FONT_WEIGHT_BOLD 1192 | >; 1193 | 1194 | our enum FontSlant is export < 1195 | FONT_SLANT_NORMAL 1196 | FONT_SLANT_ITALIC 1197 | FONT_SLANT_OBLIQUE 1198 | >; 1199 | 1200 | our enum Extend is export < 1201 | EXTEND_NONE 1202 | EXTEND_REPEAT 1203 | EXTEND_REFLECT 1204 | CAIRO_EXTEND_PAD 1205 | >; 1206 | 1207 | our enum FillRule is export < 1208 | FILL_RULE_WINDING 1209 | FILL_RULE_EVEN_ODD 1210 | >; 1211 | 1212 | class Matrix { 1213 | has cairo_matrix_t $.matrix handles < 1214 | xx yx xy yy x0 y0 1215 | > .= new: :xx(1e0), :yy(1e0); 1216 | 1217 | multi method init(Num(Cool) :$xx = 1e0, Num(Cool) :$yx = 0e0, Num(Cool) :$xy = 0e0, Num(Cool) :$yy = 1e0, Num(Cool) :$x0 = 0e0, Num(Cool) :$y0 = 0e0) { 1218 | $!matrix.init( $xx, $yx, $xy, $yy, $x0, $y0 ); 1219 | self; 1220 | } 1221 | 1222 | multi method init(Num(Cool) $xx, Num(Cool) $yx = 0e0, 1223 | Num(Cool) $xy = 0e0, Num(Cool) $yy = 1e0, 1224 | Num(Cool) $x0 = 0e0, Num(Cool) $y0 = 0e0) { 1225 | $!matrix.init( $xx, $yx, $xy, $yy, $x0, $y0 ); 1226 | self; 1227 | } 1228 | 1229 | method scale(Num(Cool) $sx, Num(Cool) $sy) { 1230 | $!matrix.scale($sx, $sy); 1231 | self; 1232 | } 1233 | 1234 | method translate(Num(Cool) $tx, Num(Cool) $ty) { 1235 | $!matrix.translate($tx, $ty); 1236 | self; 1237 | } 1238 | 1239 | method rotate(Num(Cool) $rad) { 1240 | $!matrix.rotate($rad); 1241 | self; 1242 | } 1243 | 1244 | method invert { 1245 | $!matrix.invert; 1246 | self; 1247 | } 1248 | 1249 | method multiply(Matrix $b) { 1250 | my cairo_matrix_t $a-matrix = $!matrix; 1251 | $!matrix = cairo_matrix_t.new; 1252 | $!matrix.multiply($a-matrix, $b.matrix); 1253 | self; 1254 | } 1255 | 1256 | } 1257 | 1258 | class Surface { 1259 | has cairo_surface_t $.surface handles ; 1260 | method set-surface($!surface) {} 1261 | 1262 | method write_png(Str $filename) { 1263 | my $result = CairoStatus( $.surface.write_to_png($filename) ); 1264 | fail $result if $result != STATUS_SUCCESS; 1265 | $result; 1266 | } 1267 | 1268 | method Blob(UInt :$size = 64_000 --> Blob) { 1269 | my $buf = CArray[uint8].new; 1270 | $buf[$size] = 0; 1271 | my $closure = StreamClosure.new: :$buf, :buf-len(0), :n-read(0), :$size; 1272 | $.surface.write_to_png_stream(&StreamClosure::write, $closure); 1273 | return Blob[uint8].new: $buf[0 ..^ $closure.buf-len]; 1274 | } 1275 | 1276 | method record(&things) { 1277 | my $ctx = Context.new(self); 1278 | &things($ctx); 1279 | $ctx.destroy(); 1280 | return self; 1281 | } 1282 | 1283 | } 1284 | 1285 | class Surface::PDF is Surface { 1286 | has Num:D() $.width is required; 1287 | has Num:D() $.height is required; 1288 | 1289 | submethod BUILD(Str:D() :$filename!, :$!width!, :$!height!) is hidden-from-backtrace { 1290 | my $s = cairo_pdf_surface_t::create($filename, $!width, $!height); 1291 | self.set-surface: $s; 1292 | } 1293 | 1294 | method create(Str:D() $filename, Str:D() $width, Str:D() $height) { 1295 | return self.new( :$filename, :$width, :$height ); 1296 | } 1297 | 1298 | method add_outline(Int :$parent-id, Str:D :$name = '', :$flags = 0, *%attrs) { 1299 | $.surface.add_outline: $parent-id, $name, Attrs::serialize(%attrs), $flags; 1300 | } 1301 | 1302 | method surface returns cairo_pdf_surface_t handles { callsame() } 1303 | } 1304 | 1305 | class Surface::SVG is Surface { 1306 | has Num:D() $.width is required; 1307 | has Num:D() $.height is required; 1308 | 1309 | submethod BUILD(Str:D() :$filename!, :$!width!, :$!height!) is hidden-from-backtrace { 1310 | self.set-surface: cairo_svg_surface_t::create $filename, $!width, $!height; 1311 | } 1312 | 1313 | method create(Str:D() $filename, Int:D() $width, Int:D() $height) { 1314 | return self.new(:$filename, :$width, :$height); 1315 | } 1316 | 1317 | method surface returns cairo_svg_surface_t { callsame } 1318 | 1319 | } 1320 | 1321 | class RecordingSurface { 1322 | sub cairo_recording_surface_create(int32 $content, cairo_rectangle_t $extents) 1323 | returns cairo_surface_t 1324 | is native($cairolib) 1325 | {*} 1326 | 1327 | method new(Content $content = CONTENT_COLOR_ALPHA) { 1328 | my cairo_surface_t $surface = cairo_recording_surface_create($content.Int, OpaquePointer); 1329 | my RecordingSurface $rsurf = self.bless: :$surface; 1330 | $rsurf.reference; 1331 | $rsurf; 1332 | } 1333 | 1334 | method record(&things, Content :$content = CONTENT_COLOR_ALPHA) { 1335 | my Context $ctx .= new(my $surface = self.new($content)); 1336 | &things($ctx); 1337 | $ctx.destroy(); 1338 | return $surface; 1339 | } 1340 | } 1341 | 1342 | class Image is Surface { 1343 | sub cairo_image_surface_create(int32 $format, int32 $width, int32 $height) 1344 | returns cairo_surface_t 1345 | is native($cairolib) 1346 | {*} 1347 | 1348 | sub cairo_image_surface_create_for_data_ca(CArray[uint8] $data, int32 $format, int32 $width, int32 $height, int32 $stride) 1349 | returns cairo_surface_t 1350 | is native($cairolib) 1351 | {*} 1352 | sub cairo_image_surface_create_for_data_b(Blob[uint8] $data, int32 $format, int32 $width, int32 $height, int32 $stride) 1353 | returns cairo_surface_t 1354 | is native($cairolib) 1355 | {*} 1356 | sub cairo_image_surface_create_for_data(Pointer $data, int32 $format, int32 $width, int32 $height, int32 $stride) 1357 | returns cairo_surface_t 1358 | is native($cairolib) 1359 | {*} 1360 | 1361 | sub cairo_image_surface_create_from_png(Str $filename) 1362 | returns cairo_surface_t 1363 | is native($cairolib) 1364 | {*} 1365 | 1366 | sub cairo_image_surface_create_from_png_stream( 1367 | &read-func (StreamClosure, Pointer[uint8], uint32 --> int32), 1368 | StreamClosure) 1369 | returns cairo_surface_t 1370 | is native($cairolib) 1371 | {*} 1372 | 1373 | sub cairo_format_stride_for_width(int32 $format, int32 $width) 1374 | returns int32 1375 | is native($cairolib) 1376 | {*} 1377 | 1378 | multi submethod BUILD(cairo_surface_t:D :$surface) is hidden-from-backtrace { self.set-surface: $surface} 1379 | multi submethod BUILD(Str:D :$filename!) is hidden-from-backtrace { 1380 | self.set-surface: cairo_image_surface_create_from_png($filename) 1381 | } 1382 | multi submethod BUILD(Int:D() :$width!, Int:D() :$height!, Int:D() :$format = Cairo::FORMAT_ARGB32) is hidden-from-backtrace { 1383 | self.set-surface: cairo_image_surface_create($format, $width, $height); 1384 | } 1385 | 1386 | multi method create(Int() $format, Cool $width, Cool $height) { 1387 | return self.new(surface => cairo_image_surface_create($format.Int, $width.Int, $height.Int)); 1388 | } 1389 | 1390 | multi method create(Int() $format, Cool $width, Cool $height, $data, Cool $stride? is copy) { 1391 | if $stride eqv False { 1392 | $stride = $width.Int; 1393 | } elsif $stride eqv True { 1394 | $stride = cairo_format_stride_for_width($format.Int, $width.Int); 1395 | } 1396 | my $d = do given $data { 1397 | when Array[uint8] { my $tmp = CArray[uint8].new($_); 1398 | $_ = $tmp; 1399 | proceed; } 1400 | when Buf[uint8] { my $tmp = nativecast(Blob[uint8], $_); 1401 | $_ = $tmp; 1402 | proceed; } 1403 | when CArray[uint8] | 1404 | Blob[uint8] | 1405 | Pointer { $_ } 1406 | 1407 | default { 1408 | die qq:to/D/; 1409 | Invalid type: { .^name } 1410 | Cairo::Image.create only supports variables of type: { 1411 | '' }Array[uint8], CArray[uint8], Blob[uint8] and Pointer. 1412 | D 1413 | } 1414 | } 1415 | return self.new(surface => do given $d { 1416 | when CArray { cairo_image_surface_create_for_data_ca($d, $format.Int, $width.Int, $height.Int, $stride) } 1417 | when Blob { cairo_image_surface_create_for_data_b($d, $format.Int, $width.Int, $height.Int, $stride) } 1418 | when Pointer { cairo_image_surface_create_for_data($d, $format.Int, $width.Int, $height.Int, $stride) } 1419 | }); 1420 | } 1421 | 1422 | multi method create(Blob[uint8] $data, Int(Cool) $buf-len = $data.elems) { 1423 | my $buf = CArray[uint8].new: $data; 1424 | my $closure = StreamClosure.new: :$buf, :$buf-len, :n-read(0); 1425 | return self.new(surface => cairo_image_surface_create_from_png_stream(&StreamClosure::read, $closure)); 1426 | } 1427 | 1428 | multi method open(str $filename) { 1429 | return self.new(surface => cairo_image_surface_create_from_png($filename)); 1430 | } 1431 | multi method open(Str(Cool) $filename) { 1432 | return self.new(surface => cairo_image_surface_create_from_png($filename)); 1433 | } 1434 | 1435 | method record(&things, Cool $width?, Cool $height?, Format $format = FORMAT_ARGB32) { 1436 | if defined $width and defined $height { 1437 | my $surface = self.create($format, $width, $height); 1438 | my $ctx = Context.new($surface); 1439 | &things($ctx); 1440 | return $surface; 1441 | } else { 1442 | die "recording surfaces are currently NYI. please specify a width and height for your Cairo::Image."; 1443 | } 1444 | } 1445 | 1446 | method data() { $.surface.get_image_data } 1447 | method stride() { $.surface.get_image_stride } 1448 | method width() { $.surface.get_image_width } 1449 | method height() { $.surface.get_image_height } 1450 | } 1451 | 1452 | class Pattern::Solid { ... } 1453 | class Pattern::Surface { ... } 1454 | class Pattern::Gradient { ... } 1455 | class Pattern::Gradient::Linear { ... } 1456 | class Pattern::Gradient::Radial { ... } 1457 | class Glyphs {...} 1458 | 1459 | class Pattern { 1460 | 1461 | has cairo_pattern_t $.pattern handles ; 1462 | 1463 | method Cairo::cairo_pattern_t { $!pattern } 1464 | 1465 | multi method new(cairo_pattern_t $pattern) { 1466 | self.bless(:$pattern) 1467 | } 1468 | 1469 | method extend() is rw { 1470 | Proxy.new: 1471 | FETCH => { Extend($!pattern.get_extend) }, 1472 | STORE => -> \c, \value { $!pattern.set_extend(value.Int) } 1473 | } 1474 | 1475 | method matrix() is rw { 1476 | Proxy.new: 1477 | FETCH => { 1478 | my cairo_matrix_t $matrix .= new; 1479 | $!pattern.get_matrix($matrix); 1480 | Cairo::Matrix.new: :$matrix; 1481 | }, 1482 | STORE => -> \c, Cairo::Matrix \matrix { $!pattern.set_matrix(matrix.matrix) } 1483 | } 1484 | 1485 | } 1486 | 1487 | class Pattern::Solid is Pattern { 1488 | 1489 | sub cairo_pattern_create_rgb(num64 $r, num64 $g, num64 $b) 1490 | returns cairo_pattern_t 1491 | is native($cairolib) 1492 | {*} 1493 | 1494 | sub cairo_pattern_create_rgba(num64 $r, num64 $g, num64 $b, num64 $a) 1495 | returns cairo_pattern_t 1496 | is native($cairolib) 1497 | {*} 1498 | 1499 | multi method create(Num(Cool) $r, Num(Cool) $g, Num(Cool) $b) { 1500 | self.new: cairo_pattern_create_rgb($r, $g, $b); 1501 | } 1502 | 1503 | multi method create(Num(Cool) $r, Num(Cool) $g, Num(Cool) $b, Num(Cool) $a) { 1504 | self.new: cairo_pattern_create_rgba($r, $g, $b, $a); 1505 | } 1506 | 1507 | } 1508 | 1509 | class Pattern::Surface is Pattern { 1510 | sub cairo_pattern_create_for_surface(cairo_surface_t $surface) 1511 | returns cairo_pattern_t 1512 | is native($cairolib) 1513 | {*} 1514 | 1515 | method create(cairo_surface_t $surface) { 1516 | self.new: cairo_pattern_create_for_surface($surface); 1517 | } 1518 | 1519 | } 1520 | 1521 | class Pattern::Gradient is Pattern { 1522 | 1523 | method add_color_stop_rgb(Num(Cool) $offset, Num(Cool) $red, Num(Cool) $green, Num(Cool) $blue) { 1524 | my num64 ($o, $r, $g, $b) = ($offset, $red, $green, $blue); 1525 | say "o = $offset / r = $r / g = $g / b = $b"; 1526 | $.pattern.add_color_stop_rgb($o, $r, $g, $b); 1527 | } 1528 | 1529 | method add_color_stop_rgba(Num(Cool) $offset, Num(Cool) $r, Num(Cool) $g, Num(Cool) $b, Num(Cool) $a) { 1530 | say "o = $offset / r = $r / g = $g / b = $b / a = $a"; 1531 | $.pattern.add_color_stop_rgba($offset, $r, $g, $b, $a); 1532 | } 1533 | 1534 | multi method get_color_stop_count { 1535 | samewith($); 1536 | } 1537 | multi method get_color_stop_count ($count is rw) { 1538 | my int32 $c = 0; 1539 | $.pattern.get_color_stop_count($c); 1540 | $count = $c; 1541 | } 1542 | method elems { 1543 | self.get_color_stop_count; 1544 | } 1545 | 1546 | multi method get_color_stop_rgba (Int() $index) { 1547 | samewith($index, $, $, $, $); 1548 | } 1549 | multi method get_color_stop_rgba ( 1550 | Int() $index, 1551 | $offset is rw, 1552 | $red is rw, 1553 | $green is rw, 1554 | $blue is rw 1555 | ) { 1556 | my int32 $i = $index; 1557 | my num64 ($o, $r, $g, $b) = 0e0 xx 4; 1558 | 1559 | $.pattern.get_color_stop_rgba($i, $o, $r, $g, $b); 1560 | ($offset, $red, $green, $blue) = ($o, $r, $g, $b); 1561 | } 1562 | 1563 | method gist { 1564 | my @stops; 1565 | 1566 | for ^self.get_color_stop_count { 1567 | my @s = self.get_color_stop_rgba($_); 1568 | say "Stop #{ $_ } = { @s.join(', ') }"; 1569 | @stops.push: @s; 1570 | } 1571 | 1572 | say "Cario::Pattern::Gradient.new(stops => { @stops.join(', ') }) "; 1573 | } 1574 | 1575 | 1576 | } 1577 | 1578 | class Pattern::Gradient::Linear is Pattern::Gradient { 1579 | 1580 | sub cairo_pattern_create_linear(num64 $x0, num64 $y0, num64 $x1, num64 $y1) 1581 | returns cairo_pattern_t 1582 | is native($cairolib) 1583 | {*} 1584 | 1585 | method create(Num(Cool) $x0, Num(Cool) $y0, Num(Cool) $x1, Num(Cool) $y1) { 1586 | self.new: cairo_pattern_create_linear($x0, $y0, $x1, $y1); 1587 | } 1588 | 1589 | } 1590 | 1591 | class Pattern::Gradient::Radial is Pattern::Gradient { 1592 | sub cairo_pattern_create_radial(num64 $cx0, num64 $cy0, num64 $r0, num64 $cx1, num64 $cy1, num64 $r1) 1593 | returns cairo_pattern_t 1594 | is native($cairolib) 1595 | {*} 1596 | 1597 | method create(Num(Cool) $cx0, Num(Cool) $cy0, Num(Cool) $r0, 1598 | Num(Cool) $cx1, Num(Cool) $cy1, Num(Cool) $r1) { 1599 | self.new: cairo_pattern_create_radial($cx0, $cy0, $r0, $cx1, $cy1, $r1); 1600 | } 1601 | 1602 | } 1603 | 1604 | class Path { ... } 1605 | 1606 | class Context { 1607 | sub cairo_create(cairo_surface_t $surface) 1608 | returns cairo_t 1609 | is native($cairolib) 1610 | {*} 1611 | 1612 | has cairo_t $.context handles < 1613 | status destroy push_group pop_group_to_source sub_path 1614 | save restore paint close_path new_path identity_matrix 1615 | tag_end 1616 | >; 1617 | 1618 | method Cairo::cairo_t { 1619 | $.context 1620 | } 1621 | 1622 | multi method new(cairo_t $context) { 1623 | self.bless(:$context); 1624 | } 1625 | 1626 | multi method new(Surface $surface) { 1627 | my $context = cairo_create($surface.surface); 1628 | self.bless(:$context); 1629 | } 1630 | 1631 | submethod BUILD(:$!context) { } 1632 | 1633 | method pop_group() returns Pattern { 1634 | Pattern.new($!context.pop_group); 1635 | } 1636 | 1637 | method append_path(cairo_path_t() $path) { 1638 | $!context.append_path($path); 1639 | } 1640 | 1641 | multi method copy_path() { 1642 | Path.new($!context.copy_path); 1643 | } 1644 | multi method copy_path(:$flat! where .so) { 1645 | Path.new($!context.copy_path_flat) 1646 | } 1647 | 1648 | method memoize_path($storage is rw, &creator, :$flat?) { 1649 | if defined $storage { 1650 | self.append_path($storage); 1651 | } else { 1652 | &creator(); 1653 | $storage = self.copy_path(:$flat); 1654 | } 1655 | } 1656 | 1657 | multi method rgb(Num(Cool) $r, Num(Cool) $g, Num(Cool) $b) { 1658 | $!context.set_source_rgb($r, $g, $b); 1659 | } 1660 | multi method rgb(num $r, num $g, num $b) { 1661 | $!context.set_source_rgb($r, $g, $b); 1662 | } 1663 | 1664 | multi method rgba(Num(Cool) $r, Num(Cool) $g, Num(Cool) $b, Num(Cool) $a) { 1665 | $!context.set_source_rgba($r, $g, $b, $a); 1666 | } 1667 | multi method rgb(num $r, num $g, num $b, num $a) { 1668 | $!context.set_source_rgba($r, $g, $b, $a); 1669 | } 1670 | 1671 | method pattern(Pattern $pat) { 1672 | $!context.set_source($pat.pattern); 1673 | } 1674 | 1675 | method set_source_surface(Surface $surface, Num(Cool) $x = 0, Num(Cool) $y = 0) { 1676 | $!context.set_source_surface($surface.surface, $x, $y) 1677 | } 1678 | 1679 | multi method mask(Pattern $pat, Num(Cool) $sx = 0, Num(Cool) $sy = 0) { 1680 | $!context.mask($pat.pattern, $sx, $sy) 1681 | } 1682 | multi method mask(Pattern $pat, num $sx = 0e0, num $sy = 0e0) { 1683 | $!context.mask($pat.pattern, $sx, $sy) 1684 | } 1685 | multi method mask(Surface $surface, Num(Cool) $sx = 0, Num(Cool) $sy = 0) { 1686 | $!context.mask_surface($surface.surface, $sx, $sy) 1687 | } 1688 | multi method mask(Surface $surface, num $sx = 0e0, num $sy = 0e0) { 1689 | $!context.mask_surface($surface.surface, $sx, $sy) 1690 | } 1691 | 1692 | multi method fill { 1693 | $!context.fill 1694 | } 1695 | multi method stroke { 1696 | $!context.stroke 1697 | } 1698 | multi method fill(:$preserve! where .so) { 1699 | $!context.fill_preserve 1700 | } 1701 | multi method stroke(:$preserve! where .so) { 1702 | $!context.stroke_preserve 1703 | } 1704 | multi method clip { 1705 | $!context.clip 1706 | } 1707 | multi method clip(:$preserve! where .so) { 1708 | $!context.clip_preserve 1709 | } 1710 | 1711 | multi method paint_with_alpha( num64 $alpha) { 1712 | $!context.paint_with_alpha($alpha) 1713 | } 1714 | multi method paint_with_alpha( Num(Cool) $alpha) { 1715 | $!context.paint_with_alpha($alpha) 1716 | } 1717 | 1718 | multi method move_to(Num(Cool) $x, Num(Cool) $y) { 1719 | $!context.move_to($x, $y); 1720 | } 1721 | multi method line_to(Num(Cool) $x, Num(Cool) $y) { 1722 | $!context.line_to($x, $y); 1723 | } 1724 | 1725 | multi method move_to(Num(Cool) $x, Num(Cool) $y, :$relative! where .so) { 1726 | $!context.rel_move_to($x, $y); 1727 | } 1728 | multi method line_to(Num(Cool) $x, Num(Cool) $y, :$relative! where .so) { 1729 | $!context.rel_line_to($x, $y); 1730 | } 1731 | 1732 | multi method get_current_point { 1733 | my Num ($x, $y); 1734 | samewith($x, $y); 1735 | } 1736 | multi method get_current_point(Num $x is rw, Num $y is rw) { 1737 | my num64 ($xx, $yy) = (0.Num, 0.Num); 1738 | $!context.get_current_point($xx, $yy); 1739 | ($x, $y) = ($xx, $yy); 1740 | } 1741 | 1742 | multi method curve_to(Num(Cool) $x1, Num(Cool) $y1, Num(Cool) $x2, Num(Cool) $y2, Num(Cool) $x3, Num(Cool) $y3) { 1743 | $!context.curve_to($x1, $y1, $x2, $y2, $x3, $y3); 1744 | } 1745 | multi method curve_to(Num(Cool) $x1, Num(Cool) $y1, Num(Cool) $x2, Num(Cool) $y2, Num(Cool) $x3, Num(Cool) $y3, :$relative! where .so) { 1746 | $!context.rel_curve_to($x1, $y1, $x2, $y2, $x3, $y3); 1747 | } 1748 | 1749 | multi method arc(Num(Cool) $xc, Num(Cool) $yc, Num(Cool) $radius, Num(Cool) $angle1, Num(Cool) $angle2, :$negative! where .so) { 1750 | $!context.arc_negative($xc, $yc, $radius, $angle1, $angle2); 1751 | } 1752 | multi method arc(num $xc, num $yc, num $radius, num $angle1, num $angle2, :$negative! where .so) { 1753 | $!context.arc_negative($xc, $yc, $radius, $angle1, $angle2); 1754 | } 1755 | 1756 | multi method arc(Num(Cool) $xc, Num(Cool) $yc, Num(Cool) $radius, Num(Cool) $angle1, Num(Cool) $angle2) { 1757 | $!context.arc($xc, $yc, $radius, $angle1, $angle2); 1758 | } 1759 | multi method arc(num $xc, num $yc, num $radius, num $angle1, num $angle2) { 1760 | $!context.arc($xc, $yc, $radius, $angle1, $angle2); 1761 | } 1762 | 1763 | multi method rectangle(Num(Cool) $x, Num(Cool) $y, Num(Cool) $w, Num(Cool) $h) { 1764 | $!context.rectangle($x, $y, $w, $h); 1765 | } 1766 | multi method rectangle(num $x, num $y, num $w, num $h) { 1767 | $!context.rectangle($x, $y, $w, $h); 1768 | } 1769 | 1770 | multi method translate(num $tx, num $ty) { 1771 | $!context.translate($tx, $ty) 1772 | } 1773 | multi method translate(Num(Cool) $tx, Num(Cool) $ty) { 1774 | $!context.translate($tx, $ty) 1775 | } 1776 | 1777 | multi method scale(num $sx, num $sy) { 1778 | $!context.scale($sx, $sy) 1779 | } 1780 | multi method scale(Num(Cool) $sx, Num(Cool) $sy) { 1781 | $!context.scale($sx, $sy) 1782 | } 1783 | 1784 | multi method rotate(num $angle) { 1785 | $!context.rotate($angle) 1786 | } 1787 | multi method rotate(Num(Cool) $angle) { 1788 | $!context.rotate($angle) 1789 | } 1790 | 1791 | method transform(Matrix $matrix) { 1792 | $!context.transform($matrix.matrix) 1793 | } 1794 | 1795 | multi method select_font_face(str $family, int32 $slant, int32 $weight) { 1796 | $!context.select_font_face($family, $slant, $weight); 1797 | } 1798 | multi method select_font_face(Str(Cool) $family, Int(Cool) $slant, Int(Cool) $weight) { 1799 | $!context.select_font_face($family, $slant, $weight); 1800 | } 1801 | method set_font_face(Cairo::Font $font) { 1802 | $!context.set_font_face($font.face); 1803 | } 1804 | method get_font_face { 1805 | my $face = $!context.get_font_face; 1806 | $face.reference; 1807 | Cairo::Face.new: :$face; 1808 | } 1809 | 1810 | multi method set_font_size(num $size) { 1811 | $!context.set_font_size($size); 1812 | } 1813 | multi method set_font_size(Num(Cool) $size) { 1814 | $!context.set_font_size($size); 1815 | } 1816 | 1817 | method set_scaled_font(Cairo::ScaledFont $font) { 1818 | $!context.set_scaled_font($font.font); 1819 | } 1820 | method get_scaled_font { 1821 | my $font = $!context.get_scaled_font; 1822 | $font.reference; 1823 | Cairo::Face.new: :$font; 1824 | } 1825 | 1826 | multi method show_text(str $text) { 1827 | $!context.show_text($text); 1828 | } 1829 | multi method show_text(Str(Cool) $text) { 1830 | $!context.show_text($text); 1831 | } 1832 | 1833 | method show_glyphs(Glyphs $glyph_array, $n = $glyph_array.elems) { 1834 | $!context.show_glyphs($glyph_array.glyphs, $n); 1835 | } 1836 | 1837 | method glyph_path(Glyphs $glyph_array, $n = $glyph_array.elems) { 1838 | $!context.glyph_path($glyph_array.glyphs, $n); 1839 | } 1840 | 1841 | multi method text_path(str $text) { 1842 | $!context.text_path($text); 1843 | } 1844 | multi method text_path(Str(Cool) $text) { 1845 | $!context.text_path($text); 1846 | } 1847 | 1848 | multi method text_extents(str $text --> cairo_text_extents_t) { 1849 | my cairo_text_extents_t $extents .= new; 1850 | $!context.text_extents($text, $extents); 1851 | $extents; 1852 | } 1853 | multi method text_extents(Str(Cool) $text --> cairo_text_extents_t) { 1854 | my cairo_text_extents_t $extents .= new; 1855 | $!context.text_extents($text, $extents); 1856 | $extents; 1857 | } 1858 | 1859 | method font_extents { 1860 | my cairo_font_extents_t $extents .= new; 1861 | $!context.font_extents($extents); 1862 | $extents; 1863 | } 1864 | 1865 | multi method set_dash(CArray[num64] $dashes, int32 $len, num64 $offset) { 1866 | $!context.set_dash($dashes, $len, $offset); 1867 | } 1868 | multi method set_dash(@dashes, Num(Cool) $offset = 0) { 1869 | samewith(@dashes.List, @dashes.elems, $offset); 1870 | } 1871 | multi method set_dash(List $dashes, Int(Cool) $len, Num(Cool) $offset) { 1872 | my $d = CArray[num64].new; 1873 | $d[$_] = $dashes[$_].Num 1874 | for 0 ..^ $len; 1875 | $!context.set_dash($d, $len, $offset); 1876 | } 1877 | 1878 | method line_cap() is rw { 1879 | Proxy.new: 1880 | FETCH => { LineCap($!context.get_line_cap) }, 1881 | STORE => -> \c, \value { $!context.set_line_cap(value.Int) } 1882 | } 1883 | 1884 | method fill_rule() is rw { 1885 | Proxy.new: 1886 | FETCH => { LineCap($!context.get_fill_rule) }, 1887 | STORE => -> \c, \value { $!context.set_fill_rule(value.Int) } 1888 | } 1889 | 1890 | method line_join() is rw { 1891 | Proxy.new: 1892 | FETCH => { LineJoin($!context.get_line_join) }, 1893 | STORE => -> \c, \value { $!context.set_line_join(value.Int) } 1894 | } 1895 | 1896 | method operator() is rw { 1897 | Proxy.new: 1898 | FETCH => { CairoOperator($!context.get_operator) }, 1899 | STORE => -> \c, \value { $!context.set_operator(value.Int) } 1900 | } 1901 | 1902 | method antialias() is rw { 1903 | Proxy.new: 1904 | FETCH => { Antialias($!context.get_antialias) }, 1905 | STORE => -> \c, \value { $!context.set_antialias(value.Int) } 1906 | } 1907 | 1908 | method line_width() is rw { 1909 | Proxy.new: 1910 | FETCH => { $!context.get_line_width}, 1911 | STORE => -> \c, \value { $!context.set_line_width(value.Num) } 1912 | } 1913 | 1914 | method miter_limit() is rw { 1915 | Proxy.new: 1916 | FETCH => { $!context.get_miter_limit}, 1917 | STORE => -> \c, \value { $!context.set_miter_limit(value.Num) } 1918 | } 1919 | 1920 | method tolerance() is rw { 1921 | Proxy.new: 1922 | FETCH => { $!context.get_tolerance}, 1923 | STORE => -> \c, \value { $!context.set_tolerance(value.Num) } 1924 | } 1925 | method font_options() is rw { 1926 | Proxy.new: 1927 | FETCH => { $!context.get_font_options}, 1928 | STORE => -> \c, cairo_font_options_t() \value { $!context.set_font_options(value) } 1929 | } 1930 | method font_face() is rw { 1931 | Proxy.new: 1932 | FETCH => { self.get_font_face}, 1933 | STORE => -> \c, Cairo::Font() \value { self.set_font_face(value) } 1934 | } 1935 | 1936 | method tag_begin(Str:D $tag, *%attrs) { 1937 | $!context.tag_begin($tag, Attrs::serialize(%attrs)); 1938 | } 1939 | 1940 | # tags links, destinations; primarily for PDF backend 1941 | method tag(Str:D $tag, &block) { 1942 | $.tag_begin: $tag, |%_; 1943 | &block(self); 1944 | $.tag_end($tag); 1945 | } 1946 | 1947 | # URI link 1948 | multi method link_begin(Str:D :$uri!, List :$rect) { 1949 | $.tag_begin: CAIRO_TAG_LINK, :$uri, :$rect; 1950 | } 1951 | # link to a named destination, in this or another PDF file 1952 | multi method link_begin(Str:D :$dest!, Str :$file) { 1953 | $.tag_begin: CAIRO_TAG_LINK, :$dest, :$file; 1954 | } 1955 | # link to a page, in this or another PDF file 1956 | multi method link_begin(Int:D :$page!, List :$pos, Str :$file) { 1957 | $.tag_begin: CAIRO_TAG_LINK, :$page, :$pos, :$file; 1958 | } 1959 | method link_end { $.tag_end(CAIRO_TAG_LINK) } 1960 | method link(&block, |c) { 1961 | $.link_begin: |c; 1962 | &block(); 1963 | $.link_end; 1964 | } 1965 | 1966 | # creates a named destination 1967 | method destination(&block, Str:D :$name!, Numeric :$x, Numeric :$y, Bool :$internal) { 1968 | $.tag: CAIRO_TAG_DEST, &block, :$name, :$x, :$y, :$internal; 1969 | } 1970 | 1971 | method matrix() is rw { 1972 | Proxy.new: 1973 | FETCH => { 1974 | my cairo_matrix_t $matrix .= new; 1975 | $!context.get_matrix($matrix); 1976 | Matrix.new: :$matrix; 1977 | }, 1978 | STORE => -> \c, Matrix \matrix { $!context.set_matrix(matrix.matrix) } 1979 | } 1980 | 1981 | } 1982 | 1983 | class Path { 1984 | has cairo_path_t $.path handles ; 1985 | 1986 | submethod BUILD (:$!path) { } 1987 | 1988 | method Cairo::cairo_path_t { $.path } 1989 | 1990 | method AT-POS(|) { 1991 | die 'Sorry! Cairo::Path is an iterated list, not an array.' 1992 | } 1993 | 1994 | method get_data(Int $i) { 1995 | my $a = []; 1996 | $a[$_] := $!path.data[$i + $_] for ^$!path.data[$i].length; 1997 | $a; 1998 | } 1999 | 2000 | method iterator { 2001 | my $oc = self; 2002 | my $path = $!path; 2003 | 2004 | class :: does Iterator { 2005 | has $.index is rw = 0; 2006 | 2007 | method pull-one { 2008 | my $r; 2009 | if $path.num_data > $.index { 2010 | $r = $oc.get_data($.index); 2011 | $.index += $r.elems; 2012 | } else { 2013 | $r := IterationEnd; 2014 | } 2015 | $r; 2016 | } 2017 | }.new; 2018 | } 2019 | 2020 | method new (cairo_path_t $path) { 2021 | self.bless(:$path); 2022 | } 2023 | 2024 | method destroy { 2025 | $!path.destroy; 2026 | } 2027 | } 2028 | 2029 | 2030 | class Font { 2031 | sub cairo_ft_font_face_create_for_ft_face(Pointer $ft-face, int32 $flags) 2032 | returns cairo_font_face_t 2033 | is native($cairolib) 2034 | {*} 2035 | 2036 | sub cairo_ft_font_face_create_for_pattern(Pointer $fontconfig-patt) 2037 | returns cairo_font_face_t 2038 | is native($cairolib) 2039 | {*} 2040 | 2041 | has cairo_font_face_t $.face handles ; 2042 | multi method create($font-face, :free-type($)! where .so, Int :$flags = 0) { 2043 | return self.new( 2044 | face => cairo_ft_font_face_create_for_ft_face( 2045 | nativecast(Pointer, $font-face), 2046 | $flags ) 2047 | ) 2048 | } 2049 | multi method create($pattern, :fontconfig($)! where .so) { 2050 | return self.new( 2051 | face => cairo_ft_font_face_create_for_pattern( 2052 | nativecast(Pointer, $pattern), 2053 | ) 2054 | ) 2055 | } 2056 | } 2057 | 2058 | class ScaledFont { 2059 | sub cairo_scaled_font_create(cairo_font_face_t, cairo_matrix_t, cairo_matrix_t, cairo_font_options_t) 2060 | returns cairo_scaled_font_t 2061 | is native($cairolib) 2062 | {*} 2063 | 2064 | has cairo_scaled_font_t $.font handles ; 2065 | has Matrix:D $.ctm is required; 2066 | has Matrix:D $.scale is required; 2067 | multi method create(Font:D $font, Matrix:D $scale, Matrix:D $ctm, Cairo::FontOptions $opts = Cairo::FontOptions.new) { 2068 | return self.new( 2069 | :$ctm, 2070 | :$scale, 2071 | font => cairo_scaled_font_create( 2072 | $font.face, 2073 | $scale.matrix, 2074 | $ctm.matrix, 2075 | $opts.font_options, 2076 | ) 2077 | ) 2078 | } 2079 | } 2080 | 2081 | class FontOptions { 2082 | 2083 | sub font_options_create() 2084 | returns cairo_font_options_t 2085 | is native($cairolib) 2086 | is symbol('cairo_font_options_create') 2087 | {*} 2088 | 2089 | has cairo_font_options_t $.font_options handles ; 2090 | 2091 | submethod BUILD(:$!font_options) { } 2092 | 2093 | method Cairo::cairo_font_options_t { 2094 | $.font_options; 2095 | } 2096 | 2097 | multi method new { 2098 | my $font_options = font_options_create(); 2099 | self.bless(:$font_options); 2100 | } 2101 | multi method new (cairo_font_options_t $font_options) { 2102 | self.bless(:$font_options); 2103 | } 2104 | 2105 | method status { 2106 | CairoStatus( $.font_options.status ); 2107 | } 2108 | 2109 | method merge($other) { 2110 | $.font_options.merge($other); 2111 | } 2112 | 2113 | method equal(cairo_font_options_t $b) { 2114 | so $.font_options.equals($b); 2115 | } 2116 | 2117 | method antialias() is rw { 2118 | Proxy.new: 2119 | FETCH => { Antialias( $.font_options.get_antialias ) }, 2120 | STORE => -> \c, \value { $.font_options.set_antialias(value.Int) } 2121 | } 2122 | method subpixel_order() is rw { 2123 | Proxy.new: 2124 | FETCH => { SubpixelOrder( $.font_options.get_subpixel_order ) }, 2125 | STORE => -> \c, \value { $.font_options.set_subpixel_order(value.Int) } 2126 | } 2127 | method hint_style() is rw { 2128 | Proxy.new: 2129 | FETCH => { HintStyle( $.font_options.get_hint_style ) }, 2130 | STORE => -> \c, \value { $.font_options.set_hint_style(value.Int) } 2131 | } 2132 | method hint_metrics() is rw { 2133 | Proxy.new: 2134 | FETCH => { HintMetrics( $.font_options.get_hint_metrics ) }, 2135 | STORE => -> \c, \value { $.font_options.set_hint_metrics(value.Int) } 2136 | } 2137 | 2138 | } 2139 | 2140 | class Glyphs { 2141 | has UInt:D $.elems is required; 2142 | has cairo_glyph_t $!glyphs; # a contiguous array of $!elems glyphs 2143 | has Numeric ($.x-advance, $.y-advance) is rw; 2144 | constant RecSize = nativesizeof(cairo_glyph_t); 2145 | submethod TWEAK { 2146 | $!glyphs = cairo_glyph_t.allocate($!elems); 2147 | } 2148 | method glyphs { $!glyphs } 2149 | method AT-POS(Int:D $idx where 0 <= * < $!elems) { 2150 | my Pointer $base-addr := nativecast(Pointer, $!glyphs); 2151 | my Pointer $rec-addr := Pointer.new(+$base-addr + RecSize * $idx); 2152 | nativecast(cairo_glyph_t, $rec-addr); 2153 | } 2154 | submethod DESTROY { 2155 | $!glyphs.free; 2156 | } 2157 | } 2158 | -------------------------------------------------------------------------------- /sparrow.yaml: -------------------------------------------------------------------------------- 1 | image: 2 | - melezhik/sparrow:debian_arm 3 | tasks: 4 | - 5 | name: zef-build 6 | language: Bash 7 | default: true 8 | code: | 9 | set -e 10 | cd source/ 11 | zef install --deps-only --/test . 12 | zef test . 13 | depends: 14 | - 15 | name: deps 16 | - 17 | name: deps 18 | language: Bash 19 | code: | 20 | set -e 21 | sudo apt-get update 22 | sudo apt-get install -y libcairo2 libcairo2-dev 23 | -------------------------------------------------------------------------------- /t/matrix.t: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | use Test; 4 | 5 | plan 14; 6 | 7 | constant Matrix = Cairo::Matrix; 8 | constant matrix_t = Cairo::cairo_matrix_t; 9 | 10 | my $version = Cairo::version(); 11 | diag "Running cairo version: $version (module {Cairo.^ver}, Raku {$*RAKU.compiler.version})"; 12 | 13 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 128, 128) { 14 | given Cairo::Context.new($_) { 15 | 16 | my Matrix $identity-matrix .= new; 17 | is-deeply .matrix, Matrix.new.init(:xx(1e0), :yx(0e0), :xy(0e0), :yy(1e0), :x0(0e0), :y0(0e0)), 'identity'; 18 | 19 | .translate(10,20); 20 | is-deeply .matrix, Matrix.new.init( :xx(1e0), :yy(1e0), :x0(10e0), :y0(20e0) ), 'translate'; 21 | .save; { 22 | .scale(2, 3); 23 | is-deeply .matrix, Matrix.new.init( :xx(2e0), :yy(3e0), :x0(10e0), :y0(20e0) ), 'translate + scale'; 24 | 25 | # http://zetcode.com/gfx/cairo/transformations/ 26 | my Matrix $transform-matrix .= new.init( :xx(1), :yx(0.5), 27 | :xy(0), :yy(1), 28 | :x0(0), :y0(0) ); 29 | .transform( $transform-matrix); 30 | is-deeply .matrix, Matrix.new.init( :xx(2e0), :yx(1.5e0), :yy(3e0), :x0(10e0), :y0(20e0) ), 'transform'; 31 | }; 32 | .restore; 33 | 34 | is-deeply .matrix, Matrix.new.init( :xx(1e0), :yy(1e0), :x0(10e0), :y0(20e0) ), 'save/restore'; 35 | 36 | .identity_matrix; 37 | is-deeply .matrix, $identity-matrix, 'identity'; 38 | 39 | my $prev-matrix = .matrix; 40 | .rotate(pi/2); 41 | my $rot-matrix = .matrix; 42 | is-deeply $prev-matrix, $identity-matrix, 'previous'; 43 | is-approx $rot-matrix.yx, 1, 'rotated yx'; 44 | is-approx $rot-matrix.xy, -1, 'rotated xy'; 45 | 46 | my $matrix = Matrix.new.translate(10,20); 47 | is-deeply $matrix, Matrix.new.init( :xx(1e0), :yy(1e0), :x0(10e0), :y0(20e0) ), 'translate'; 48 | 49 | $matrix.multiply: Matrix.new.scale(2,3); 50 | is-deeply $matrix, Matrix.new.init( :xx(2e0), :yy(3e0), :x0(20e0), :y0(60e0) ), 'multiply'; 51 | 52 | $matrix.invert; 53 | is-approx $matrix.xx, 0.5, 'invert xx'; 54 | is-approx $matrix.yy, 1/3, 'invert yy'; 55 | is-approx $matrix.x0, -10, 'invert x0'; 56 | }; 57 | }; 58 | 59 | done-testing; 60 | -------------------------------------------------------------------------------- /t/pattern.t: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | use Test; 4 | 5 | plan 7; 6 | 7 | { 8 | my $pattern-rgb = Cairo::Pattern::Solid.create(.7, .5, .3); 9 | isa-ok $pattern-rgb, Cairo::Pattern::Solid; 10 | } 11 | 12 | { 13 | my $pattern-rgba = Cairo::Pattern::Solid.create(.7, .5, .3, .5); 14 | isa-ok $pattern-rgba, Cairo::Pattern::Solid; 15 | } 16 | 17 | { 18 | my $image = Cairo::Image.create(Cairo::FORMAT_ARGB32, 128, 128); 19 | my $pattern = Cairo::Pattern::Surface.create($image.surface); 20 | isa-ok $pattern, Cairo::Pattern::Surface; 21 | } 22 | 23 | { 24 | my $pattern = Cairo::Pattern::Gradient::Linear.create(0,0,170,120); 25 | isa-ok $pattern, Cairo::Pattern::Gradient::Linear; 26 | lives-ok {$pattern.add_color_stop_rgb(0.5, .8, .1, .1);}, 'linear color stop'; 27 | } 28 | 29 | { 30 | my $pattern = Cairo::Pattern::Gradient::Radial.create(75,50,5,90,60,100); 31 | isa-ok $pattern, Cairo::Pattern::Gradient::Radial; 32 | lives-ok {$pattern.add_color_stop_rgb(0.5, .8, .1, .1);}, 'radial color stop'; 33 | } 34 | 35 | done-testing; 36 | -------------------------------------------------------------------------------- /t/readme.t: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | use Test; 4 | 5 | plan 1; 6 | 7 | lives-ok { 8 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 128, 128) { 9 | given Cairo::Context.new($_) { 10 | .rgb(0, 0.7, 0.9); 11 | .rectangle(10, 10, 50, 50); 12 | .fill :preserve; .rgb(1, 1, 1); 13 | .stroke 14 | }; 15 | .write_png("foobar.png") 16 | } 17 | }; 18 | 19 | unlink "foobar.png"; # don't care if failed 20 | 21 | done-testing; 22 | -------------------------------------------------------------------------------- /t/surface-image.t: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | use Test; 4 | plan 2; 5 | 6 | lives-ok { 7 | given Cairo::Image.new(:width(256), :height(256)) { 8 | given Cairo::Context.new($_) { 9 | .arc(128.0, 128.0, 76.8, 0, 2*pi); 10 | .clip; 11 | .new_path; # path not consumed by .clip 12 | 13 | my \image = Cairo::Image.new(:filename ); 14 | my \w = image.width; 15 | my \h = image.height; 16 | 17 | .scale(256.0/w, 256.0/h); 18 | 19 | .set_source_surface(image, 0, 0); 20 | .paint; 21 | 22 | image.destroy; 23 | }; 24 | .write_png("clip-image.png"); 25 | } 26 | }; 27 | 28 | ok "clip-image.png".IO.e, "png created from new"; 29 | 30 | unlink "clip-image.png"; # don't care if failed 31 | 32 | done-testing; 33 | -------------------------------------------------------------------------------- /t/surface-pdf.t: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | use Test; 4 | 5 | plan 6; 6 | 7 | lives-ok { 8 | given Cairo::Surface::PDF.create("foobar.pdf", 128, 128) { 9 | is .width, 128, 'width'; 10 | is .height, 128, 'height'; 11 | given Cairo::Context.new($_) { 12 | .rgb(0, 0.7, 0.9); 13 | .rectangle(10, 10, 50, 50); 14 | .fill :preserve; .rgb(1, 1, 1); 15 | .stroke 16 | }; 17 | .show_page; 18 | .finish; 19 | ok "foobar.pdf".IO.e, "pdf created"; 20 | } 21 | }; 22 | 23 | lives-ok { 24 | my Cairo::Surface::PDF $pdf .= new: :filename, :width(128), :height(64); 25 | $pdf.finish; 26 | } 27 | ok "foo2.pdf".IO.e, "pdf created from new"; 28 | 29 | unlink "foobar.pdf"; # don't care if failed 30 | unlink "foo2.pdf"; # don't care if failed 31 | 32 | done-testing; 33 | -------------------------------------------------------------------------------- /t/surface-svg.t: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | use Test; 4 | 5 | plan 6; 6 | 7 | lives-ok { 8 | given Cairo::Surface::SVG.create("foobar.svg", 128, 128) { 9 | is .width, 128, 'width'; 10 | is .height, 128, 'height'; 11 | given Cairo::Context.new($_) { 12 | .rgb(0, 0.7, 0.9); 13 | .rectangle(10, 10, 50, 50); 14 | .fill :preserve; .rgb(1, 1, 1); 15 | .stroke 16 | }; 17 | .finish; 18 | ok "foobar.svg".IO.e, "svg created"; 19 | } 20 | }; 21 | 22 | lives-ok { 23 | my Cairo::Surface::SVG $svg .= new: :filename, :width(128), :height(64); 24 | $svg.finish; 25 | } 26 | ok "foo2.svg".IO.e, "svg created from new"; 27 | 28 | unlink "foobar.svg"; # don't care if failed 29 | unlink "foo2.svg"; # don't care if failed 30 | 31 | done-testing; 32 | -------------------------------------------------------------------------------- /t/text.t: -------------------------------------------------------------------------------- 1 | use v6; 2 | use Cairo; 3 | use Test; 4 | 5 | plan 10; 6 | 7 | given Cairo::Image.create(Cairo::FORMAT_ARGB32, 128, 128) { 8 | given Cairo::Context.new($_) { 9 | lives-ok { 10 | .move_to(10, 10); 11 | .select_font_face("courier", Cairo::FontSlant::FONT_SLANT_ITALIC, Cairo::FontWeight::FONT_WEIGHT_BOLD); 12 | .set_font_size(10); 13 | .show_text("Hello World"); 14 | } 15 | # issue #11 actual chosen font is system dependant 16 | my $font-extents = .font_extents; 17 | isa-ok $font-extents, Cairo::cairo_font_extents_t; 18 | ok 7 < $font-extents.ascent < 12, 'font extents ascent' 19 | or diag "got ascent: {$font-extents.ascent}"; 20 | 21 | my $text-extents = .text_extents("Hello World"); 22 | isa-ok $text-extents, Cairo::cairo_text_extents_t; 23 | ok 30 < $text-extents.width < 75, 'text extents width' 24 | or diag "got width: {$text-extents.width}"; 25 | ok 5 < $text-extents.height < 9, 'text extents height' 26 | or diag "got height: {$text-extents.height}"; 27 | }; 28 | my Blob $data; 29 | my Cairo::Image $image; 30 | lives-ok {$data = .Blob}, '.Blob'; 31 | ok $data.elems, 'data has length'; 32 | lives-ok {$image = Cairo::Image.create($data, $data.elems)}, 'create image from data'; 33 | is $image.width, 128, 'created image width'; 34 | }; 35 | 36 | done-testing; 37 | --------------------------------------------------------------------------------