Compare commits

..

55 Commits

Author SHA1 Message Date
Matthias Clasen 244cdafe1b Add gsk_path_get_previous/next_point
These functions let you iterate over the 'significant'
points of a path.
2023-08-08 11:06:35 -04:00
Matthias Clasen a0d17418de fixup start/end point 2023-08-08 10:41:03 -04:00
Matthias Clasen 093e6241e7 path: Add gsk_path_get_start/end_point
These are useful to have, now that we are
relying more on GskPathPoint in our api.
2023-08-08 08:38:36 -04:00
Matthias Clasen 67b504f823 Add tests for gsk_path_builder_add_segment
Test at least some of the special cases:
- start and end point on the same contour
- start and end point on the same segment
- end before start
2023-08-08 08:37:51 -04:00
Matthias Clasen 659bc813a4 Redo gsk_path_builder_add_segment 2023-08-08 08:37:51 -04:00
Benjamin Otte 293c0774b3 demos: Add a text-on-path demo 2023-08-07 19:52:17 -04:00
Matthias Clasen 988062889b Add tests for GskPathMeasure 2023-08-07 19:52:17 -04:00
Matthias Clasen 461922b495 Avoid zero-length measure segments
if measure->start == measure->end, we are in trouble.
2023-08-07 19:52:17 -04:00
Matthias Clasen 7150a53ccb contour: measure fixes 2023-08-07 19:43:47 -04:00
Matthias Clasen 1e306b148e Add GskPathMeasure
GskPathMeasure is an auxiliary object for
measuring path lengths.
2023-08-07 19:43:47 -04:00
Matthias Clasen 6af9dc8612 Merge branch 'xry111/issue6003' into 'main'
print: Revert "Start sorting apart includes" change for gtkprinteroptionprivate.h

Closes #6003

See merge request GNOME/gtk!6250
2023-08-07 22:52:43 +00:00
Benjamin Otte 35b313f9b0 Merge branch 'path-for-merge-3' into 'main'
gskpath: Add stroking

See merge request GNOME/gtk!6248
2023-08-07 22:17:53 +00:00
Matthias Clasen fe84ce8686 gsk: Try to fix flipped fallback rendering
This patch is pretty much a blind guess, but
it seems to fix flipped rendering of fill
and stroke nodes.
2023-08-07 17:53:49 -04:00
Matthias Clasen 02a4e5a457 Add compare tests for fill and stroke nodes 2023-08-07 13:02:57 -04:00
Matthias Clasen a548a91e6d Add nodeparser tests for fill and stroke nodes 2023-08-07 13:02:57 -04:00
Matthias Clasen fc3c2e0942 gsk: Implement parsing fill and stroke nodes
Make serialization and deserialization work for stroke and
fill nodes.
2023-08-07 13:02:57 -04:00
Matthias Clasen 60e07335a1 demos: Add stroking to the path fill demo 2023-08-07 13:02:57 -04:00
Benjamin Otte cb6b968fb5 snapshot: Add gtk_snapshot_push_stroke()
This is the obvious GtkSnapshot API to go
along with the new stroke nodes.
2023-08-07 13:02:57 -04:00
Benjamin Otte 3aa3816125 gsk: Add GskStrokeNode
Take a rendernode as source and a GskPath and GskStroke,
and fill the area that is covered when stroking the path
with the given stroke parameters, like cairo_stroke() would.
2023-08-07 13:02:57 -04:00
Matthias Clasen c37c29422a Add gsk_path_get_stroke_bounds
This is a helper to compute the bounds for
stroke nodes. We keep it private for now.
2023-08-07 13:02:57 -04:00
Matthias Clasen db71c07f8f Add GskStroke
A GskStroke struct collects the parameters that are
needed for stroking a path.
2023-08-07 13:02:57 -04:00
Emmanuele Bassi bf1b97efd3 Merge branch 'gdk-macos-depth-fix' into 'main'
gdk: Fix compilation on macos

See merge request GNOME/gtk!6208
2023-08-07 14:46:47 +00:00
Xi Ruoyao 4d7277f72c print: Revert "Start sorting apart includes" change for gtkprinteroptionprivate.h
The print backends needs the functions in gtkprinteroptionprivate.h to
be exported.

Fixes #6003.
2023-08-07 22:29:10 +08:00
Matthias Clasen 3296f01edf Merge branch 'path-fixes' into 'main'
Fix path point preconditions

See merge request GNOME/gtk!6251
2023-08-07 13:00:18 +00:00
Matthias Clasen dbcbf0523b Add tests for GskPathPoint
As always, untested code doesn't work...
2023-08-07 08:33:05 -04:00
Matthias Clasen 888abb6f24 path: Make get_closest_point work
We weren't setting point->path. Oops.
Good to have tests.
2023-08-07 08:33:05 -04:00
Matthias Clasen 9b916b329a pathpoint: Implement get_tangent fully
We were not taking the direction into account
at all.
2023-08-07 08:33:05 -04:00
Matthias Clasen eb3ada6386 Fix path point preconditions
These were inverted and did not work. Oops.
2023-08-07 08:32:50 -04:00
Matthias Clasen 2a725b658b Merge branch 'path-for-merge-2' into 'main'
GskPath for merge, part 0

See merge request GNOME/gtk!6247
2023-08-07 01:31:37 +00:00
Benjamin Otte 97f605f811 demos: Add a simple demo filling a path 2023-08-06 21:01:11 -04:00
Benjamin Otte 4e7d578881 rendernode: Implement fast-path for solid fills
They happen so often that it's worth avoiding the clip + paint path
there.
2023-08-06 21:01:11 -04:00
Benjamin Otte 438d936f57 gtk: Add gtk_snapshot_push_fill()
This is the obvious GtkSnapshot API to go
along with the new fill nodes.
2023-08-06 21:01:11 -04:00
Benjamin Otte fc4a464b47 gsk: Add GskFillNode
Take a rendernode as source and a GskPath and fill
the region inside the path with the source, just like
cairo_fill() would.
2023-08-06 21:01:11 -04:00
Matthias Clasen 785b9541f6 gsk: Add tests for GskPath 2023-08-06 21:01:11 -04:00
Matthias Clasen a4cbabb80f gsk: Add tests for GskCurve 2023-08-06 20:48:09 -04:00
Matthias Clasen 1b5dfcba7e gsk: Add GskPath
This commit adds the basic infrastructure for paths.
The public APIs consists of GskPath, GskPathPoint and
GskPathBuilder.

GskPath is a data structure for paths that consists
of contours, which in turn might contain Bézier curves.
The Bezier data structure is inspired by Skia, with separate
arrays for points and operations. One advantage of this
arrangement is that start and end points are shared
between adjacent curves.

A GskPathPoint represents a point on a path, which can
be queried for various properties.

GskPathBuilder is an auxiliary builder object for paths.
2023-08-06 20:48:09 -04:00
Matthias Clasen ba41edf531 gsk: Add tests for GskBoundingBox 2023-08-06 17:16:46 -04:00
Matthias Clasen bf3892caed gsk: Add a bounding box type
graphene_rect_t is not well-suited for this purpose,
since you end up with floating-point precision problems
at the upper bound (x + width, y + height).
2023-08-06 17:16:30 -04:00
Benjamin Otte 1e6a95aa1b Merge branch 'grid-scroll-crash' into 'main'
gtkgridview: Fix crash on scroll to 0 sized tile

Closes #5945

See merge request GNOME/gtk!6228
2023-08-06 17:56:57 +00:00
tszymanski 70a9d08e21 gtkgridview: return empty area for empty tiles during scroll 2023-08-06 10:26:32 -07:00
Piotr Drąg 7511d4e281 Update Polish translation 2023-08-06 14:22:51 +02:00
Asier Sarasua Garmendia 53ea97decb Update Basque translation 2023-08-06 07:20:22 +00:00
Matthias Clasen 28190ded71 Merge branch 'matthiasc/for-main' into 'main'
Update tests

See merge request GNOME/gtk!6244
2023-08-05 19:32:56 +00:00
Matthias Clasen 8083cb0e47 Merge branch 'smaller-than' into 'main'
section-accessibility: Close tag

See merge request GNOME/gtk!6243
2023-08-05 19:21:44 +00:00
Matthias Clasen d241ec4f3e Update tests 2023-08-05 15:02:00 -04:00
Hari Rana 544320a961 section-accessibility: Close tag 2023-08-05 12:25:23 -04:00
Florentina Musat ee5a95ba24 Update Romanian translation 2023-08-05 15:54:45 +00:00
Jordi Mas 232260b86b Update Catalan translation 2023-08-05 17:30:28 +02:00
Matthias Clasen 857f50649c Merge branch 'microoptimize-label-wfh' into 'main'
Microoptimize GtkLabel width-for-height computation

See merge request GNOME/gtk!6219
2023-08-05 15:15:55 +00:00
Matthias Clasen a39d9d60a7 Merge branch 'bilelmoussaoui/tree-deprecated' into 'main'
gi: Mark more GtkTreeModel types as deprecated

See merge request GNOME/gtk!6241
2023-08-05 12:09:25 +00:00
Bilal Elmoussaoui 5f9bc97291 gi: Mark more GtkTreeModel types as deprecated
They show up in rust docs as not deprecated without this
2023-08-05 13:10:52 +02:00
Matthias Clasen 01b3b096fe Post-release version bump 2023-08-05 05:42:32 -04:00
tszymanski a483fb2d96 gtkgridview: Fix crash on scroll to 0 sized tile
No longer crashes with my listview_clocks demo or in real scrolling in
my application. "GtkGridView failed to scroll to given position. Ignoring..."
warnings are printed when it would have crashed.

Sometimes the scroll jumps incorrectly when it doesn't crash, but that's
a separate bug but is probably related to whatever is causing this
crash.

Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/5945, at least in
terms of the immediate crash.
2023-08-01 22:17:54 -07:00
Sergey Bugaev d27e7e0180 label: Microoptimize width-for-height computation
We told Pango to limit width to mid pixels, and it returned a layout
size of text_width by text_height; text_width can be considerably
smaller than mid. If the layout fits, we know that it fits at
text_width, so set max to that. This lets us skip many iterations in a
typical case.
2023-07-28 18:42:17 +03:00
Jayson Reis aa888c0b3f gdk: Remove a leftover reference to the renamed variable prefers_high_depth 2023-07-23 23:13:47 +02:00
239 changed files with 49167 additions and 42183 deletions
+11 -35
View File
@@ -30,16 +30,8 @@ variables:
workflow:
rules:
# run merge request pipelines
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
# do not run branch pipelines if corresponding merge requests exist...
# (this avoids duplicate pipelines)
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
# ...but otherwise run branch pipelines
- if: $CI_COMMIT_BRANCH
# run tag pipelines
- if: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH
default:
retry:
@@ -205,44 +197,28 @@ msys2-mingw64:
paths:
- "${CI_PROJECT_DIR}/_build/gtkdll.tar.gz"
macos-x86_64:
macos:
# Sadly, this fails regularly, and its failure is never enlightening
allow_failure: true
rules:
# Do not run in forks as the runner is not available there.
- if: $CI_PROJECT_NAMESPACE == "GNOME"
stage: build
tags:
- macosintel
- macos
needs: []
variables:
MESON_FORCE_BACKTRACKE: 1
TMPDIR: /Users/Shared/work/tmp
SDKROOT: /opt/sdks/MacOSX10.13.4.sdk
PIP_CACHE_DIR: /Users/Shared/build/cache
PIPENV_CACHE_DIR: $PIP_CACHE_DIR
PYTHONPYCACHEPREFIX: $PIP_CACHE_DIR
EXTRA_MESON_FLAGS: "-Dgobject-introspection:werror=false"
before_script:
# Not using ccache on purpose as it accelerates the build so much that it
# can trigger race conditions in the gobject-introspection subproject.
- bash .gitlab-ci/show-info-osx.sh
- /opt/macports/bin/python3.10 -m venv .venv
- ln -s /opt/cmake/CMake.app/Contents/bin/cmake .venv/bin
- ln -s /opt/pkg-config/bin/pkg-config .venv/bin
- ln -s /opt/bison/bin/bison .venv/bin
- source .venv/bin/activate
- pip3 install meson==1.2.0
- pip3 install ninja==1.11.1
- pip3 install /Users/Shared/build/pkgs/PyGObject-3.44.0-cp310-cp310-macosx_10_13_x86_64.whl
/Users/Shared/build/pkgs/pycairo-1.23.0-cp310-cp310-macosx_10_13_x86_64.whl
- pip3 install --user meson~=1.0
- pip3 install --user ninja
- export PATH=/Users/gitlabrunner/Library/Python/3.7/bin:$PATH
- export MESON_FORCE_BACKTRACE=1
script:
- meson setup
${COMMON_MESON_FLAGS}
${EXTRA_MESON_FLAGS}
- meson setup ${COMMON_MESON_FLAGS}
-Dx11-backend=false
-Dbroadway-backend=true
-Dmacos-backend=true
-Dmedia-gstreamer=disabled
-Dintrospection=enabled
-Dintrospection=disabled
-Dcpp_std=c++11
-Dpixman:tests=disabled
-Dlibjpeg-turbo:simd=disabled
+1 -1
View File
@@ -6,7 +6,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliar
:: FIXME: make warnings fatal
pip3 install --upgrade --user meson~=0.64 || goto :error
meson setup -Dbackend_max_links=1 -Ddebug=false -Dmedia-gstreamer=disabled _build || goto :error
meson -Ddebug=false -Dmedia-gstreamer=disabled _build || goto :error
ninja -C _build || goto :error
goto :EOF
+150
View File
@@ -0,0 +1,150 @@
TAP version 13
# random seed: R02S22611f6aefc1121b0ab2dc5286960449
# GLib-GIO-DEBUG: _g_io_module_get_default: Found default implementation dconf (DConfSettingsBackend) for gsettings-backend
# GLib-GIO-DEBUG: Using cross-namespace EXTERNAL authentication (this will deadlock if server is GDBus < 2.73.3)
# GLib-GIO-DEBUG: Using cross-namespace EXTERNAL authentication (this will deadlock if server is GDBus < 2.73.3)
1..1
# Start of ops tests
# testcase 0 op 0
collecting#
Cubic 0: # M 100.000000 100.000000 C 150.000000 100.000000 200.000000 100.000000 250.000000 100.000000
Cubic 1: # M 250.000000 100.000000 C 300.000000 100.000000 350.000000 100.000000 400.000000 100.000000
Line 2: # M 400 100 L 200 300
Line 3: # M 200 300 L 100 100
Cubic 4: # M 200.000000 100.000000 C 250.000000 100.000000 300.000000 100.000000 350.000000 100.000000
Cubic 5: # M 350.000000 100.000000 C 400.000000 100.000000 450.000000 100.000000 500.000000 100.000000
Line 6: # M 500 100 L 300 300
Line 7: # M 300 300 L 200 100
splitting#
1 intersections between Cubic 0 and Cubic 1#
1 intersections between Cubic 0 and Line 3#
9 intersections between Cubic 0 and Cubic 4#
# split Cubic 0.0 from Cubic 0 at 0.666666: M 100.000000 100.000000 C 133.333298 100.000000 166.666595 100.000000 199.999893 100.000000
split Cubic 0.1 from Cubic 0 at 0.666666: M 199.999893 100.000000 C 216.666595 100.000000 233.333298 100.000000 250.000000 100.000000split Cubic 0.4 from Cubic 0 at 0.00600814: M 200.300323 100.000000 C 216.866882 100.000000 233.433441 100.000000 250.000000 100.000000split Cubic 0.7 from Cubic 0 at 0.00604445: M 200.600708 100.000000 C 217.067139 100.000000 233.533569 100.000000 250.000000 100.000000# split Cubic 4.9 from Cubic 4 at 0.00533867: M 200.800812 100.000000 C 250.533875 100.000000 300.266937 100.000000 350.000000 100.000000
1 intersections between Cubic 0.1 and Line 7#
1 intersections between Cubic 1 and Line 2#
9 intersections between Cubic 1 and Cubic 4.9#
split Cubic 1.9 from Cubic 1 at 0.00534248: M 250.801361 100.000000 C 300.534241 100.000000 350.267120 100.000000 400.000000 100.000000# split Cubic 4.9.0 from Cubic 4.9 at 0.329756: M 200.800812 100.000000 C 217.200577 100.000000 233.600342 100.000000 250.000122 100.000000
# split Cubic 4.9.1 from Cubic 4.9 at 0.329756: M 250.000122 100.000000 C 283.333435 100.000000 316.666718 100.000000 350.000000 100.000000
# split Cubic 4.9.6 from Cubic 4.9 at 0.00500283: M 250.500412 100.000000 C 283.666931 100.000000 316.833466 100.000000 350.000000 100.000000
9 intersections between Cubic 1.9 and Cubic 5#
# split Cubic 1.9.0 from Cubic 1.9 at 0.664877: M 250.801361 100.000000 C 283.867615 100.000000 316.933868 100.000000 350.000122 100.000000
split Cubic 1.9.1 from Cubic 1.9 at 0.664877: M 350.000122 100.000000 C 366.666748 100.000000 383.333374 100.000000 400.000000 100.000000split Cubic 1.9.4 from Cubic 1.9 at 0.00601021: M 350.300598 100.000000 C 366.867065 100.000000 383.433533 100.000000 400.000000 100.000000split Cubic 1.9.7 from Cubic 1.9 at 0.00604655: M 350.601074 100.000000 C 367.067383 100.000000 383.533691 100.000000 400.000000 100.000000# split Cubic 5.9 from Cubic 5 at 0.00534248: M 350.801361 100.000000 C 400.534241 100.000000 450.267120 100.000000 500.000000 100.000000
1 intersections between Line 2 and Line 3#
1 intersections between Line 2 and Line 7#
# split Line 2.0 from Line 2 at 0.666667: M 400 100 L 266.667 233.333
split Line 2.1 from Line 2 at 0.666667: M 266.667 233.333 L 200 300# split Line 7.0 from Line 7 at 0.333333: M 300 300 L 266.667 233.333
# split Line 7.1 from Line 7 at 0.333333: M 266.667 233.333 L 200 100
1 intersections between Cubic 4 and Cubic 4.9.0#
1 intersections between Cubic 4 and Line 7.1#
1 intersections between Cubic 4.9.0 and Cubic 4.9.1#
1 intersections between Cubic 4.9.1 and Cubic 4.9.6#
1 intersections between Cubic 4.9.6 and Cubic 5#
1 intersections between Cubic 5 and Cubic 5.9#
1 intersections between Cubic 5.9 and Line 6#
1 intersections between Line 6 and Line 7.0#
Cubic 0.0: # M 100.000000 100.000000 C 133.333298 100.000000 166.666595 100.000000 199.999893 100.000000
Cubic 0.1: # M 199.999893 100.000000 C 200.100037 100.000000 200.200180 100.000000 200.300323 100.000000
Cubic 0.4: # M 200.300323 100.000000 C 200.400452 100.000000 200.500580 100.000000 200.600708 100.000000
Cubic 0.7: # M 200.600708 100.000000 C 217.067139 100.000000 233.533569 100.000000 250.000000 100.000000
Cubic 1: # M 250.000000 100.000000 C 250.267120 100.000000 250.534241 100.000000 250.801361 100.000000
Cubic 1.9.0: # M 250.801361 100.000000 C 283.867615 100.000000 316.933868 100.000000 350.000122 100.000000
Cubic 1.9.1: # M 350.000122 100.000000 C 350.100281 100.000000 350.200439 100.000000 350.300598 100.000000
Cubic 1.9.4: # M 350.300598 100.000000 C 350.400757 100.000000 350.500916 100.000000 350.601074 100.000000
Cubic 1.9.7: # M 350.601074 100.000000 C 367.067383 100.000000 383.533691 100.000000 400.000000 100.000000
Line 2.0: # M 400 100 L 266.667 233.333
Line 2.1: # M 266.667 233.333 L 200 300
Line 3: # M 200 300 L 100 100
Cubic 4: # M 200.000000 100.000000 C 200.266937 100.000000 200.533875 100.000000 200.800812 100.000000
Cubic 4.9.0: # M 200.800812 100.000000 C 217.200577 100.000000 233.600342 100.000000 250.000122 100.000000
Cubic 4.9.1: # M 250.000122 100.000000 C 250.166885 100.000000 250.333649 100.000000 250.500412 100.000000
Cubic 4.9.6: # M 250.500412 100.000000 C 283.666931 100.000000 316.833466 100.000000 350.000000 100.000000
Cubic 5: # M 350.000000 100.000000 C 350.267120 100.000000 350.534241 100.000000 350.801361 100.000000
Cubic 5.9: # M 350.801361 100.000000 C 400.534241 100.000000 450.267120 100.000000 500.000000 100.000000
Line 6: # M 500 100 L 300 300
Line 7.0: # M 300 300 L 266.667 233.333
Line 7.1: # M 266.667 233.333 L 200 100
classifying#
01 Cubic 0.0: # M 100.000000 100.000000 C 133.333298 100.000000 166.666595 100.000000 199.999893 100.000000
[11 Cubic 0.7: # M 200.600708 100.000000 C 217.067139 100.000000 233.533569 100.000000 250.000000 100.000000 ]
[11 Cubic 1.9.0: # M 250.801361 100.000000 C 283.867615 100.000000 316.933868 100.000000 350.000122 100.000000 ]
[11 Cubic 1.9.7: # M 350.601074 100.000000 C 367.067383 100.000000 383.533691 100.000000 400.000000 100.000000 ]
[11 Line 2.0: # M 400 100 L 266.667 233.333 ]
01 Line 2.1: # M 266.667 233.333 L 200 300
01 Line 3: # M 200 300 L 100 100
[11 Cubic 4: # M 200.000000 100.000000 C 200.266937 100.000000 200.533875 100.000000 200.800812 100.000000 ]
[11 Cubic 4.9.0: # M 200.800812 100.000000 C 217.200577 100.000000 233.600342 100.000000 250.000122 100.000000 ]
[11 Cubic 4.9.6: # M 250.500412 100.000000 C 283.666931 100.000000 316.833466 100.000000 350.000000 100.000000 ]
[11 Cubic 5: # M 350.000000 100.000000 C 350.267120 100.000000 350.534241 100.000000 350.801361 100.000000 ]
01 Cubic 5.9: # M 350.801361 100.000000 C 400.534241 100.000000 450.267120 100.000000 500.000000 100.000000
01 Line 6: # M 500 100 L 300 300
01 Line 7.0: # M 300 300 L 266.667 233.333
[11 Line 7.1: # M 266.667 233.333 L 200 100 ]
fixups#
# found 3 bad nodes
# split Cubic 0/Cubic 4 BAD 200.600723 100.000000
# [11 Line 7.1 ] 116.565
# [11 Cubic 0.7 ] 180
# [11 Cubic 4 ] 180
# [11 Cubic 4 ] 180
# [11 Cubic 4.9.0 ] 180
# >01 Cubic 0.0 360
# split Cubic 1/Cubic 4.9 BAD 250.801376 100.000000
# [11 Cubic 1.9.0 ] 180
# [11 Cubic 4.9.6 ] 180
# [11 Cubic 0.7 ] 360
# [11 Cubic 4.9.0 ] 360
# split Cubic 1.9/Cubic 5 BAD 350.601105 100.000000
# [11 Cubic 1.9.7 ] 180
# [11 Cubic 5 ] 180
# [11 Cubic 5 ] 180
# <01 Cubic 5.9 180
# [11 Cubic 1.9.0 ] 360
# [11 Cubic 4.9.6 ] 360
reassembling#
start new contour Cubic 0.0#
# Cubic 0.0 ends at:
# start 0 100.000000 100.000000
# >01 Line 3 116.565
# (10 Cubic 0.0 ) 180
picking cw#
append Line 3#
# Line 3 ends at:
# end 2 200.000000 300.000000
# >01 Line 2.1 225
# (10 Line 3 ) 296.565
picking cw#
append Line 2.1#
# Line 2.1 ends at:
# split Line 2/Line 7 266.666656 233.333344
# (10 Line 2.1 ) 45
# >01 Line 7.0 116.565
# [11 Line 2.0 ] 225
# [11 Line 7.1 ] 296.565
picking cw#
append Line 7.0#
# Line 7.0 ends at:
# end 6 300.000000 300.000000
# >01 Line 6 225
# (10 Line 7.0 ) 296.565
picking cw#
append Line 6#
# Line 6 ends at:
# end 5 500.000000 100.000000
# (10 Line 6 ) 45
# >01 Cubic 5.9 360
picking cw#
append Cubic 5.9#
# Cubic 5.9 ends at:
# split Cubic 1.9/Cubic 5 BAD 350.601105 100.000000
# [11 Cubic 1.9.7 ] 180
# [11 Cubic 5 ] 180
# [11 Cubic 5 ] 180
# (10 Cubic 5.9 ) 180
# [11 Cubic 1.9.0 ] 360
# [11 Cubic 4.9.6 ] 360
picking cw#
**
ERROR:../testsuite/gsk/path-ops.c:359:test_ops_simple: assertion failed (s == tests[i].out): ("M 354.60110473632812 100 A 4 4 0 0 0 346.60110473632812 100 A 4 4 0 0 0 354.60110473632812 100 z M 252.80137634277344 100 A 2 2 0 0 0 248.80137634277344 100 A 2 2 0 0 0 252.80137634277344 100 z M 204.60072326660156 100 A 4 4 0 0 0 196.60072326660156 100 A 4 4 0 0 0 204.60072326660156 100 z" == "M 100 100 z")
not ok /ops/simple - ERROR:../testsuite/gsk/path-ops.c:359:test_ops_simple: assertion failed (s == tests[i].out): ("M 354.60110473632812 100 A 4 4 0 0 0 346.60110473632812 100 A 4 4 0 0 0 354.60110473632812 100 z M 252.80137634277344 100 A 2 2 0 0 0 248.80137634277344 100 A 2 2 0 0 0 252.80137634277344 100 z M 204.60072326660156 100 A 4 4 0 0 0 196.60072326660156 100 A 4 4 0 0 0 204.60072326660156 100 z" == "M 100 100 z")
Bail out!
+1 -155
View File
@@ -1,160 +1,6 @@
Overview of Changes in 4.12.4, 17-11-2023
Overview of Changes in 4.13.0, xx-xx-xxxx
=========================================
* a11y:
- Tweak name computation for some corner cases
* gdk:
- gl: Improve our use of GLES a bit (use vertex arrays and
GL_BGRA if available)
- Fix some errors in our memory format tables
* gsk:
- gl: handle texture-scale nodes more faithfully
- gl: Fix icon padding in the atlas
* Windows:
- Stop relying on glib for build configuration
* Tools:
- Add a --undecorated option to gtk4-rendernode-tool
* Translation updates
Catalan
French
Romanian
Russian
Spanish
Turkish
Overview of Changes in 4.12.3, 28-09-2023
=========================================
* GtkWindow:
- Don't assume titlebars are GtkHeaderBar
* GtkTreeView:
- Fix a crash in gtk_tree_view_is_blank_at_pos
* printing:
- Fix some issues with the portal implementation
* GSK:
- Some optimizations in the GL renderer
- Fix memory leaks in the Broadway renderer
* demos:
- Fix a crash in gtk4-demo
* Translation updates
Basque
Brazilian Portuguese
Czech
Galician
Georgian
German
Hungarian
Kazakh
Lithuanian
Persian
Polish
Spanish
Swedish
Turkish
Overview of Changes in 4.12.2, 20-09-2023
=========================================
* GtkTooltip:
- Don't cross native boundaries when looking for tooltips
* GtkCenterLayout, GtkEntry, GtkSearchEntry:
- Fix some issues with baseline handling
* GtkSwitch:
- Respect text direction
* Theme:
- Use relative font sizes
* GSK:
- Make repeated gradients match between GL and cairo
- Make rounded rect shrinking match between Vulkan, GL and cairo
- Fix parsing of text nodes with color glyphs
- Restrict an optimization to the cases where it is correct
- Fix rendering of shadows with opacity
* macOS:
- Clamp damage regions to the surface size
* Windows:
- Fix missing minimize and maximize buttons
* Translation updates
Basque
Brazilian Portuguese
Catalan
Chinese (China)
Czech
Danish
Dutch
Finnish
Galician
German
Hungarian
Italian
Kazakh
Latvian
Lithuanian
Slovenian
Spanish
Turkish
Overview of Changes in 4.12.1, 25-08-2023
=========================================
* GtkGridView:
- Fix a crash when scrolling
* GtkColumnView:
- Fix a refcounting issue in the new scroll_to api
* GtkTreeView
- Fix style classes for sort arrows
* GtkEntry:
- Improve tracking of user changes (for undo)
* GtkNotebook:
- Fix a critical when switching pages
* GtkColor/FontDialogButton:
- Make these widgets activatable
* GtkMenuButton:
- Fix problems with focus handling
- Fix problems with DND
* Printing
- Fix the cpdb backend build
* MacOS:
- Make file filters work again
* GSK:
- Fix issues with color matrix nodes
* Wayland:
- Fix a crash with compositors other than gnome-shell
* Translation updates:
Polish
Swedish
Overview of Changes in 4.12.0, 05-08-2023
=========================================
-41
View File
@@ -1,41 +0,0 @@
#ifndef _MSC_VER
#pragma error "This header is for Microsoft VC or clang-cl only."
#endif /* _MSC_VER */
/* Make MSVC more pedantic, this is a recommended pragma list
* from _Win32_Programming_ by Rector and Newcomer.
*/
#ifndef __clang__
#pragma warning(error:4002) /* too many actual parameters for macro */
#pragma warning(error:4003) /* not enough actual parameters for macro */
#pragma warning(1:4010) /* single-line comment contains line-continuation character */
#pragma warning(error:4013) /* 'function' undefined; assuming extern returning int */
#pragma warning(1:4016) /* no function return type; using int as default */
#pragma warning(error:4020) /* too many actual parameters */
#pragma warning(error:4021) /* too few actual parameters */
#pragma warning(error:4027) /* function declared without formal parameter list */
#pragma warning(error:4029) /* declared formal parameter list different from definition */
#pragma warning(error:4033) /* 'function' must return a value */
#pragma warning(error:4035) /* 'function' : no return value */
#pragma warning(error:4045) /* array bounds overflow */
#pragma warning(error:4047) /* different levels of indirection */
#pragma warning(error:4049) /* terminating line number emission */
#pragma warning(error:4053) /* An expression of type void was used as an operand */
#pragma warning(error:4071) /* no function prototype given */
#pragma warning(disable:4101) /* unreferenced local variable */
#pragma warning(error:4150)
/* G_NORETURN */
#pragma warning(error:4646) /* function declared with __declspec(noreturn) has non-void return type */
#pragma warning(error:4715) /* 'function': not all control paths return a value */
#pragma warning(error:4098) /* 'void' function returning a value */
#pragma warning(disable:4244) /* No possible loss of data warnings */
#pragma warning(disable:4305) /* No truncation from int to char warnings */
#pragma warning(error:4819) /* The file contains a character that cannot be represented in the current code page */
#endif /* __clang__ */
/* work around Microsoft's premature attempt to deprecate the C-Library */
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_NONSTDC_NO_WARNINGS
+2 -2
View File
@@ -223,7 +223,7 @@ delete_messages (gpointer data)
static void
pop_message (GtkWidget *status)
{
GList *messages = (GList *) g_object_steal_data (G_OBJECT (status), "messages");
GList *messages = (GList *) g_object_get_data (G_OBJECT (status), "messages");
if (messages)
{
@@ -241,7 +241,7 @@ static void
push_message (GtkWidget *status,
const char *message)
{
GList *messages = (GList *) g_object_steal_data (G_OBJECT (status), "messages");
GList *messages = (GList *) g_object_get_data (G_OBJECT (status), "messages");
gtk_label_set_label (GTK_LABEL (status), message);
messages = g_list_prepend (messages, g_strdup (message));
+5
View File
@@ -335,6 +335,8 @@
<file>paintable_symbolic.c</file>
<file>panes.c</file>
<file>password_entry.c</file>
<file>path_fill.c</file>
<file>path_text.c</file>
<file>peg_solitaire.c</file>
<file>pickers.c</file>
<file>printing.c</file>
@@ -420,6 +422,9 @@
<gresource prefix="/fontrendering">
<file>fontrendering.ui</file>
</gresource>
<gresource prefix="/path_text">
<file>path_text.ui</file>
</gresource>
<gresource prefix="/org/gtk/Demo4">
<file>icons/16x16/actions/application-exit.png</file>
<file>icons/16x16/actions/document-new.png</file>
+8 -1
View File
@@ -71,7 +71,14 @@ create_blurred_button (void)
static GtkWidget *
create_font_button (void)
{
return gtk_font_dialog_button_new (gtk_font_dialog_new ());
GtkFontDialog *dialog;
GtkWidget *button;
dialog = gtk_font_dialog_new ();
button = gtk_font_dialog_button_new (dialog);
g_object_unref (dialog);
return button;
}
static GtkWidget *
+14 -14
View File
@@ -840,24 +840,24 @@ gtk_gears_unrealize (GtkWidget *widget)
GtkGearsPrivate *priv = gtk_gears_get_instance_private ((GtkGears *) widget);
gtk_gl_area_make_current (glarea);
if (gtk_gl_area_get_error (glarea) == NULL)
{
/* Release the resources associated with OpenGL */
if (priv->gear_vbo[0] != 0)
glDeleteBuffers (1, &(priv->gear_vbo[0]));
if (gtk_gl_area_get_error (glarea) != NULL)
return;
if (priv->gear_vbo[1] != 0)
glDeleteBuffers (1, &(priv->gear_vbo[1]));
/* Release the resources associated with OpenGL */
if (priv->gear_vbo[0] != 0)
glDeleteBuffers (1, &(priv->gear_vbo[0]));
if (priv->gear_vbo[2] != 0)
glDeleteBuffers (1, &(priv->gear_vbo[2]));
if (priv->gear_vbo[1] != 0)
glDeleteBuffers (1, &(priv->gear_vbo[1]));
if (priv->vao != 0)
glDeleteVertexArrays (1, &priv->vao);
if (priv->gear_vbo[2] != 0)
glDeleteBuffers (1, &(priv->gear_vbo[2]));
if (priv->program != 0)
glDeleteProgram (priv->program);
}
if (priv->vao != 0)
glDeleteVertexArrays (1, &priv->vao);
if (priv->program != 0)
glDeleteProgram (priv->program);
priv->ModelViewProjectionMatrix_location = 0;
priv->NormalMatrix_location = 0;
+2
View File
@@ -72,6 +72,8 @@ demos = files([
'paintable_symbolic.c',
'panes.c',
'password_entry.c',
'path_fill.c',
'path_text.c',
'peg_solitaire.c',
'pickers.c',
'printing.c',
+198
View File
@@ -0,0 +1,198 @@
/* Path/Fill and Stroke
*
* This demo shows how to use GskPath to draw shapes that are (a bit)
* more complex than a rounded rectangle.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "paintable.h"
#define GTK_TYPE_LOGO_PAINTABLE (gtk_logo_paintable_get_type ())
G_DECLARE_FINAL_TYPE (GtkLogoPaintable, gtk_logo_paintable, GTK, LOGO_PAINTABLE, GObject)
struct _GtkLogoPaintable
{
GObject parent_instance;
int width;
int height;
GskPath *path[3];
GdkRGBA color[3];
GskPath *stroke_path;
GskStroke *stroke1;
GskStroke *stroke2;
GdkRGBA stroke_color;
};
struct _GtkLogoPaintableClass
{
GObjectClass parent_class;
};
static int
gtk_logo_paintable_get_intrinsic_width (GdkPaintable *paintable)
{
GtkLogoPaintable *self = GTK_LOGO_PAINTABLE (paintable);
return self->width;
}
static int
gtk_logo_paintable_get_intrinsic_height (GdkPaintable *paintable)
{
GtkLogoPaintable *self = GTK_LOGO_PAINTABLE (paintable);
return self->height;
}
static void
gtk_logo_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
GtkLogoPaintable *self = GTK_LOGO_PAINTABLE (paintable);
for (unsigned int i = 0; i < 3; i++)
{
gtk_snapshot_push_fill (snapshot, self->path[i], GSK_FILL_RULE_WINDING);
gtk_snapshot_append_color (snapshot,
&self->color[i],
&GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
}
for (unsigned int i = 0; i < 3; i++)
{
gtk_snapshot_push_stroke (snapshot, self->stroke_path, self->stroke1);
gtk_snapshot_append_color (snapshot,
&self->stroke_color,
&GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
}
gtk_snapshot_push_stroke (snapshot, self->stroke_path, self->stroke2);
gtk_snapshot_append_color (snapshot,
&self->stroke_color,
&GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
}
static GdkPaintableFlags
gtk_logo_paintable_get_flags (GdkPaintable *paintable)
{
return GDK_PAINTABLE_STATIC_CONTENTS | GDK_PAINTABLE_STATIC_SIZE;
}
static void
gtk_logo_paintable_paintable_init (GdkPaintableInterface *iface)
{
iface->get_intrinsic_width = gtk_logo_paintable_get_intrinsic_width;
iface->get_intrinsic_height = gtk_logo_paintable_get_intrinsic_height;
iface->snapshot = gtk_logo_paintable_snapshot;
iface->get_flags = gtk_logo_paintable_get_flags;
}
/* When defining the GType, we need to implement the GdkPaintable interface */
G_DEFINE_TYPE_WITH_CODE (GtkLogoPaintable, gtk_logo_paintable, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gtk_logo_paintable_paintable_init))
static void
gtk_logo_paintable_dispose (GObject *object)
{
GtkLogoPaintable *self = GTK_LOGO_PAINTABLE (object);
for (unsigned int i = 0; i < 3; i++)
gsk_path_unref (self->path[i]);
gsk_path_unref (self->stroke_path);
gsk_stroke_free (self->stroke1);
gsk_stroke_free (self->stroke2);
G_OBJECT_CLASS (gtk_logo_paintable_parent_class)->dispose (object);
}
static void
gtk_logo_paintable_class_init (GtkLogoPaintableClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_logo_paintable_dispose;
}
static void
gtk_logo_paintable_init (GtkLogoPaintable *self)
{
}
static GdkPaintable *
gtk_logo_paintable_new (void)
{
GtkLogoPaintable *self;
graphene_rect_t bounds, bounds2;
self = g_object_new (GTK_TYPE_LOGO_PAINTABLE, NULL);
/* Paths and colors extracted from gtk-logo.svg */
self->path[0] = gsk_path_parse ("m3.12,66.17 -2.06,-51.46 32.93,24.7 v55.58 l-30.87,-28.82 z");
self->path[1] = gsk_path_parse ("m34,95 49.4,-20.58 4.12,-51.46 -53.52,16.47 v55.58 z");
self->path[2] = gsk_path_parse ("m1.06,14.71 32.93,24.7 53.52,-16.47 -36.75,-21.88 -49.7,13.65 z");
gdk_rgba_parse (&self->color[0], "#e40000");
gdk_rgba_parse (&self->color[1], "#7fe719");
gdk_rgba_parse (&self->color[2], "#729fcf");
self->stroke_path = gsk_path_parse ("m50.6,51.3 -47.3,14 z l33,23 z v-50");
self->stroke1 = gsk_stroke_new (2.12);
self->stroke2 = gsk_stroke_new (1.25);
gdk_rgba_parse (&self->stroke_color, "#ffffff");
gsk_path_get_stroke_bounds (self->path[0], self->stroke1, &bounds);
gsk_path_get_stroke_bounds (self->path[1], self->stroke1, &bounds2);
graphene_rect_union (&bounds, &bounds2, &bounds);
gsk_path_get_stroke_bounds (self->path[2], self->stroke1, &bounds2);
graphene_rect_union (&bounds, &bounds2, &bounds);
gsk_path_get_stroke_bounds (self->stroke_path, self->stroke2, &bounds2);
graphene_rect_union (&bounds, &bounds2, &bounds);
self->width = bounds.origin.x + bounds.size.width;
self->height = bounds.origin.y + bounds.size.height;
return GDK_PAINTABLE (self);
}
GtkWidget *
do_path_fill (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkWidget *picture;
GdkPaintable *paintable;
window = gtk_window_new ();
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
gtk_window_set_title (GTK_WINDOW (window), "Path Fill");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
paintable = gtk_logo_paintable_new ();
picture = gtk_picture_new_for_paintable (paintable);
gtk_picture_set_content_fit (GTK_PICTURE (picture), GTK_CONTENT_FIT_CONTAIN);
gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE);
g_object_unref (paintable);
gtk_window_set_child (GTK_WINDOW (window), picture);
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}
+604
View File
@@ -0,0 +1,604 @@
/* Path/Text
*
* This demo shows how to use GskPath to animate a path along another path.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#define GTK_TYPE_PATH_WIDGET (gtk_path_widget_get_type ())
G_DECLARE_FINAL_TYPE (GtkPathWidget, gtk_path_widget, GTK, PATH_WIDGET, GtkWidget)
#define POINT_SIZE 8
enum {
PROP_0,
PROP_TEXT,
PROP_EDITABLE,
N_PROPS
};
struct _GtkPathWidget
{
GtkWidget parent_instance;
char *text;
gboolean editable;
graphene_point_t points[4];
guint active_point;
float line_closest;
GskPath *line_path;
GskPathMeasure *line_measure;
GskPath *text_path;
GdkPaintable *background;
};
struct _GtkPathWidgetClass
{
GtkWidgetClass parent_class;
};
static GParamSpec *properties[N_PROPS] = { NULL, };
G_DEFINE_TYPE (GtkPathWidget, gtk_path_widget, GTK_TYPE_WIDGET)
static GskPath *
create_path_from_text (GtkWidget *widget,
const char *text,
graphene_point_t *out_offset)
{
PangoLayout *layout;
PangoFontDescription *desc;
GskPathBuilder *builder;
GskPath *result;
layout = gtk_widget_create_pango_layout (widget, text);
desc = pango_font_description_from_string ("sans bold 36");
pango_layout_set_font_description (layout, desc);
pango_font_description_free (desc);
builder = gsk_path_builder_new ();
gsk_path_builder_add_layout (builder, layout);
result = gsk_path_builder_free_to_path (builder);
if (out_offset)
graphene_point_init (out_offset, 0, - pango_layout_get_baseline (layout) / (double) PANGO_SCALE);
g_object_unref (layout);
return result;
}
typedef struct
{
GskPathMeasure *measure;
GskPathBuilder *builder;
graphene_point_t offset;
double scale;
} GtkPathTransform;
static void
gtk_path_transform_point (GskPathMeasure *measure,
const graphene_point_t *pt,
const graphene_point_t *offset,
float scale,
graphene_point_t *res)
{
graphene_vec2_t tangent;
GskPathPoint point;
if (gsk_path_measure_get_point (measure, (pt->x + offset->x) * scale, &point))
{
GskPath *path = gsk_path_measure_get_path (measure);
gsk_path_point_get_position (path, &point, res);
gsk_path_point_get_tangent (path, &point, GSK_PATH_END, &tangent);
res->x -= (pt->y + offset->y) * scale * graphene_vec2_get_y (&tangent);
res->y += (pt->y + offset->y) * scale * graphene_vec2_get_x (&tangent);
}
}
static gboolean
gtk_path_transform_op (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
gpointer data)
{
GtkPathTransform *transform = data;
switch (op)
{
case GSK_PATH_MOVE:
{
graphene_point_t res;
gtk_path_transform_point (transform->measure, &pts[0], &transform->offset, transform->scale, &res);
gsk_path_builder_move_to (transform->builder, res.x, res.y);
}
break;
case GSK_PATH_LINE:
{
graphene_point_t res;
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res);
gsk_path_builder_line_to (transform->builder, res.x, res.y);
}
break;
case GSK_PATH_QUAD:
{
graphene_point_t res[2];
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res[0]);
gtk_path_transform_point (transform->measure, &pts[2], &transform->offset, transform->scale, &res[1]);
gsk_path_builder_quad_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y);
}
break;
case GSK_PATH_CUBIC:
{
graphene_point_t res[3];
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res[0]);
gtk_path_transform_point (transform->measure, &pts[2], &transform->offset, transform->scale, &res[1]);
gtk_path_transform_point (transform->measure, &pts[3], &transform->offset, transform->scale, &res[2]);
gsk_path_builder_cubic_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y, res[2].x, res[2].y);
}
break;
case GSK_PATH_CLOSE:
gsk_path_builder_close (transform->builder);
break;
default:
g_assert_not_reached();
return FALSE;
}
return TRUE;
}
static GskPath *
gtk_path_transform (GskPathMeasure *measure,
GskPath *path,
const graphene_point_t *offset)
{
GtkPathTransform transform = { measure, gsk_path_builder_new (), *offset };
graphene_rect_t bounds;
gsk_path_get_bounds (path, &bounds);
if (bounds.origin.x + bounds.size.width > 0)
transform.scale = gsk_path_measure_get_length (measure) / (bounds.origin.x + bounds.size.width);
else
transform.scale = 1.0f;
gsk_path_foreach (path, -1, gtk_path_transform_op, &transform);
return gsk_path_builder_free_to_path (transform.builder);
}
static void
gtk_path_widget_clear_text_path (GtkPathWidget *self)
{
g_clear_pointer (&self->text_path, gsk_path_unref);
}
static void
gtk_path_widget_clear_paths (GtkPathWidget *self)
{
gtk_path_widget_clear_text_path (self);
g_clear_pointer (&self->line_path, gsk_path_unref);
g_clear_pointer (&self->line_measure, gsk_path_measure_unref);
}
static void
gtk_path_widget_create_text_path (GtkPathWidget *self)
{
GskPath *path;
graphene_point_t offset;
gtk_path_widget_clear_text_path (self);
if (self->line_measure == NULL)
return;
path = create_path_from_text (GTK_WIDGET (self), self->text, &offset);
self->text_path = gtk_path_transform (self->line_measure, path, &offset);
gsk_path_unref (path);
}
static void
gtk_path_widget_create_paths (GtkPathWidget *self)
{
double width = gtk_widget_get_width (GTK_WIDGET (self));
double height = gtk_widget_get_height (GTK_WIDGET (self));
GskPathBuilder *builder;
gtk_path_widget_clear_paths (self);
if (width <= 0 || height <= 0)
return;
builder = gsk_path_builder_new ();
gsk_path_builder_move_to (builder,
self->points[0].x * width, self->points[0].y * height);
gsk_path_builder_cubic_to (builder,
self->points[1].x * width, self->points[1].y * height,
self->points[2].x * width, self->points[2].y * height,
self->points[3].x * width, self->points[3].y * height);
self->line_path = gsk_path_builder_free_to_path (builder);
self->line_measure = gsk_path_measure_new (self->line_path);
gtk_path_widget_create_text_path (self);
}
static void
gtk_path_widget_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
GtkPathWidget *self = GTK_PATH_WIDGET (widget);
GTK_WIDGET_CLASS (gtk_path_widget_parent_class)->size_allocate (widget, width, height, baseline);
gtk_path_widget_create_paths (self);
}
static void
gtk_path_widget_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkPathWidget *self = GTK_PATH_WIDGET (widget);
double width = gtk_widget_get_width (widget);
double height = gtk_widget_get_height (widget);
GskPath *path;
GskStroke *stroke;
gsize i;
/* frosted glass the background */
gtk_snapshot_push_blur (snapshot, 100);
gdk_paintable_snapshot (self->background, snapshot, width, height);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 1, 1, 1, 0.6 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
/* draw the text */
if (self->text_path)
{
gtk_snapshot_push_fill (snapshot, self->text_path, GSK_FILL_RULE_WINDING);
gdk_paintable_snapshot (self->background, snapshot, width, height);
/* ... with an emboss effect */
stroke = gsk_stroke_new (2.0);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT(1, 1));
gtk_snapshot_push_stroke (snapshot, self->text_path, stroke);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 0.2 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gsk_stroke_free (stroke);
gtk_snapshot_pop (snapshot);
gtk_snapshot_pop (snapshot);
}
if (self->editable && self->line_path)
{
GskPathBuilder *builder;
/* draw the control line */
stroke = gsk_stroke_new (1.0);
gtk_snapshot_push_stroke (snapshot, self->line_path, stroke);
gsk_stroke_free (stroke);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
/* draw the points */
builder = gsk_path_builder_new ();
for (i = 0; i < 4; i++)
{
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (self->points[i].x * width, self->points[i].y * height), POINT_SIZE);
}
path = gsk_path_builder_free_to_path (builder);
gtk_snapshot_push_fill (snapshot, path, GSK_FILL_RULE_WINDING);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 1, 1, 1, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
stroke = gsk_stroke_new (1.0);
gtk_snapshot_push_stroke (snapshot, path, stroke);
gsk_stroke_free (stroke);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
gsk_path_unref (path);
}
if (self->line_closest >= 0)
{
GskPathBuilder *builder;
GskPathPoint point;
graphene_point_t closest;
builder = gsk_path_builder_new ();
if (gsk_path_measure_get_point (self->line_measure, self->line_closest, &point))
{
gsk_path_point_get_position (self->line_path, &point, &closest);
gsk_path_builder_add_circle (builder, &closest, POINT_SIZE);
path = gsk_path_builder_free_to_path (builder);
gtk_snapshot_push_fill (snapshot, path, GSK_FILL_RULE_WINDING);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 1, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
gsk_path_unref (path);
}
}
}
static void
gtk_path_widget_set_text (GtkPathWidget *self,
const char *text)
{
if (g_strcmp0 (self->text, text) == 0)
return;
g_free (self->text);
self->text = g_strdup (text);
gtk_path_widget_create_paths (self);
gtk_widget_queue_draw (GTK_WIDGET (self));
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TEXT]);
}
static void
gtk_path_widget_set_editable (GtkPathWidget *self,
gboolean editable)
{
if (self->editable == editable)
return;
self->editable = editable;
gtk_widget_queue_draw (GTK_WIDGET (self));
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EDITABLE]);
}
static void
gtk_path_widget_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkPathWidget *self = GTK_PATH_WIDGET (object);
switch (prop_id)
{
case PROP_TEXT:
gtk_path_widget_set_text (self, g_value_get_string (value));
break;
case PROP_EDITABLE:
gtk_path_widget_set_editable (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_path_widget_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkPathWidget *self = GTK_PATH_WIDGET (object);
switch (prop_id)
{
case PROP_TEXT:
g_value_set_string (value, self->text);
break;
case PROP_EDITABLE:
g_value_set_boolean (value, self->editable);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_path_widget_dispose (GObject *object)
{
GtkPathWidget *self = GTK_PATH_WIDGET (object);
gtk_path_widget_clear_paths (self);
G_OBJECT_CLASS (gtk_path_widget_parent_class)->dispose (object);
}
static void
gtk_path_widget_class_init (GtkPathWidgetClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_path_widget_dispose;
object_class->set_property = gtk_path_widget_set_property;
object_class->get_property = gtk_path_widget_get_property;
widget_class->size_allocate = gtk_path_widget_allocate;
widget_class->snapshot = gtk_path_widget_snapshot;
properties[PROP_TEXT] =
g_param_spec_string ("text",
"text",
"Text transformed along a path",
NULL,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_EDITABLE] =
g_param_spec_boolean ("editable",
"editable",
"If the path can be edited by the user",
FALSE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
drag_begin (GtkGestureDrag *gesture,
double x,
double y,
GtkPathWidget *self)
{
graphene_point_t mouse = GRAPHENE_POINT_INIT (x, y);
double width = gtk_widget_get_width (GTK_WIDGET (self));
double height = gtk_widget_get_height (GTK_WIDGET (self));
gsize i;
for (i = 0; i < 4; i++)
{
if (graphene_point_distance (&GRAPHENE_POINT_INIT (self->points[i].x * width, self->points[i].y * height), &mouse, NULL, NULL) <= POINT_SIZE)
{
self->active_point = i;
break;
}
}
if (i == 4)
{
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
return;
}
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
drag_update (GtkGestureDrag *drag,
double offset_x,
double offset_y,
GtkPathWidget *self)
{
double width = gtk_widget_get_width (GTK_WIDGET (self));
double height = gtk_widget_get_height (GTK_WIDGET (self));
double start_x, start_y;
gtk_gesture_drag_get_start_point (drag, &start_x, &start_y);
self->points[self->active_point] = GRAPHENE_POINT_INIT ((start_x + offset_x) / width,
(start_y + offset_y) / height);
self->points[self->active_point].x = CLAMP (self->points[self->active_point].x, 0, 1);
self->points[self->active_point].y = CLAMP (self->points[self->active_point].y, 0, 1);
gtk_path_widget_create_paths (self);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
pointer_motion (GtkEventControllerMotion *controller,
double x,
double y,
GtkPathWidget *self)
{
GskPathPoint point;
graphene_point_t pos;
if (gsk_path_get_closest_point (gsk_path_measure_get_path (self->line_measure),
&GRAPHENE_POINT_INIT (x, y),
INFINITY,
&point))
{
gsk_path_point_get_position (self->line_path, &point, &pos);
self->line_closest = graphene_point_distance (&pos, &GRAPHENE_POINT_INIT (x, y), NULL, NULL);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
}
static void
pointer_leave (GtkEventControllerMotion *controller,
GtkPathWidget *self)
{
self->line_closest = -1;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
gtk_path_widget_init (GtkPathWidget *self)
{
GtkEventController *controller;
controller = GTK_EVENT_CONTROLLER (gtk_gesture_drag_new ());
g_signal_connect (controller, "drag-begin", G_CALLBACK (drag_begin), self);
g_signal_connect (controller, "drag-update", G_CALLBACK (drag_update), self);
g_signal_connect (controller, "drag-end", G_CALLBACK (drag_update), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
controller = GTK_EVENT_CONTROLLER (gtk_event_controller_motion_new ());
g_signal_connect (controller, "enter", G_CALLBACK (pointer_motion), self);
g_signal_connect (controller, "motion", G_CALLBACK (pointer_motion), self);
g_signal_connect (controller, "leave", G_CALLBACK (pointer_leave), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
self->line_closest = -1;
self->points[0] = GRAPHENE_POINT_INIT (0.1, 0.9);
self->points[1] = GRAPHENE_POINT_INIT (0.3, 0.1);
self->points[2] = GRAPHENE_POINT_INIT (0.7, 0.1);
self->points[3] = GRAPHENE_POINT_INIT (0.9, 0.9);
self->background = GDK_PAINTABLE (gdk_texture_new_from_resource ("/sliding_puzzle/portland-rose.jpg"));
gtk_path_widget_set_text (self, "It's almost working");
}
GtkWidget *
gtk_path_widget_new (void)
{
GtkPathWidget *self;
self = g_object_new (GTK_TYPE_PATH_WIDGET, NULL);
return GTK_WIDGET (self);
}
GtkWidget *
do_path_text (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkBuilder *builder;
g_type_ensure (GTK_TYPE_PATH_WIDGET);
builder = gtk_builder_new_from_resource ("/path_text/path_text.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}
+38
View File
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window">
<property name="title" translatable="yes">Text along a Path</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<child type="end">
<object class="GtkToggleButton" id="edit-toggle">
<property name="icon-name">document-edit-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkRevealer">
<property name="reveal-child" bind-source="edit-toggle" bind-property="active" bind-flags="sync-create"></property>
<child>
<object class="GtkEntry" id="text">
<property name="text">Through the looking glass</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkPathWidget" id="view">
<property name="editable" bind-source="edit-toggle" bind-property="active" bind-flags="sync-create"></property>
<property name="text" bind-source="text" bind-property="text" bind-flags="sync-create"></property>
<property name="hexpand">true</property>
<property name="vexpand">true</property>
</object>
</child>
</object>
</child>
</object>
</interface>
Binary file not shown.

After

Width:  |  Height:  |  Size: 533 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M3.384 3h3.231c.213 0 .385.224.385.502v2.996C7 6.776 6.828 7 6.615 7h-3.23C3.17 7 3 6.776 3 6.498V3.502C3 3.224 3.17 3 3.384 3zm6 0h3.231c.213 0 .385.224.385.502v2.996c0 .278-.172.502-.385.502h-3.23C9.17 7 9 6.776 9 6.498V3.502C9 3.224 9.17 3 9.384 3zm-6 6h3.231c.213 0 .385.224.385.502v2.996c0 .278-.172.502-.385.502h-3.23C3.17 13 3 12.776 3 12.498V9.502C3 9.224 3.17 9 3.384 9zm6 0h3.231c.213 0 .385.224.385.502v2.996c0 .278-.172.502-.385.502h-3.23C9.17 13 9 12.776 9 12.498V9.502C9 9.224 9.17 9 9.384 9z" style="marker:none" overflow="visible" color="#000" fill="#474747"/></svg>

After

Width:  |  Height:  |  Size: 654 B

@@ -25,12 +25,14 @@
<file>icons/16x16/actions/format-justify-fill-symbolic.symbolic.png</file>
<file>icons/16x16/actions/format-justify-left-symbolic.symbolic.png</file>
<file>icons/16x16/actions/format-justify-right-symbolic.symbolic.png</file>
<file>icons/16x16/actions/insert-image.png</file>
<file>icons/16x16/actions/insert-link-symbolic.symbolic.png</file>
<file>icons/16x16/actions/send-to-symbolic.symbolic.png</file>
<file>icons/16x16/actions/star-new-symbolic.symbolic.png</file>
<file>icons/16x16/actions/view-continuous-symbolic.symbolic.png</file>
<file>icons/16x16/actions/view-dual-symbolic.symbolic.png</file>
<file>icons/16x16/actions/view-fullscreen-symbolic.symbolic.png</file>
<file>icons/16x16/actions/view-grid-symbolic.symbolic.png</file>
<file>icons/16x16/actions/view-paged-symbolic.symbolic.png</file>
<file>icons/16x16/actions/zoom-in-symbolic.symbolic.png</file>
<file>icons/16x16/actions/zoom-in.png</file>
@@ -86,6 +88,7 @@
<file>icons/scalable/actions/view-dual-symbolic.svg</file>
<file>icons/scalable/actions/view-paged-symbolic.svg</file>
<file>icons/scalable/actions/view-fullscreen-symbolic.svg</file>
<file>icons/scalable/actions/view-grid-symbolic.svg</file>
<file>icons/scalable/actions/zoom-in-symbolic.svg</file>
<file>icons/scalable/actions/zoom-original-symbolic.svg</file>
<file>icons/scalable/actions/zoom-out-symbolic.svg</file>
+6 -5
View File
@@ -41,7 +41,7 @@ activate (GtkApplication* app,
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
}
int
@@ -183,7 +183,7 @@ activate (GtkApplication *app,
gtk_box_append (GTK_BOX (box), button);
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
}
int
@@ -331,7 +331,8 @@ activate (GtkApplication *app,
*/
gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 2, 1);
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
}
int
@@ -553,7 +554,7 @@ activate (GtkApplication *app,
g_signal_connect (press, "pressed", G_CALLBACK (pressed), drawing_area);
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
}
int
@@ -630,7 +631,7 @@ activate (GtkApplication *app,
button = gtk_builder_get_object (builder, "quit");
g_signal_connect_swapped (button, "clicked", G_CALLBACK (quit_cb), window);
gtk_widget_set_visible (GTK_WIDGET (window), TRUE);
gtk_widget_show (GTK_WIDGET (window));
/* We do not need the builder any more */
g_object_unref (builder);
@@ -35,11 +35,6 @@ Showing
The ``show`` command displays the rendernode.
``--undecorated``
Removes window decorations. This is meant for rendering of exactly the rendernode
without any titlebar.
Rendering
^^^^^^^^^
+1 -1
View File
@@ -49,7 +49,7 @@ main (int argc, char **argv)
// ...
// Show the application window
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
// Enter the main event loop, and wait for user interaction
while (!done)
+1 -1
View File
@@ -263,7 +263,7 @@ gdk_parse_debug_var (const char *variable,
if (debug_enabled || keys[i].always_enabled)
fprintf (stderr, " %s%*s%s\n", keys[i].key, (int)(max_width - strlen (keys[i].key)), " ", keys[i].help);
}
fprintf (stderr, " %s%*s%s\n", "all", max_width - 3, " ", "Enable all values. Other given values are subtracted");
fprintf (stderr, " %s%*s%s\n", "all", max_width - 3, " ", "Enable all values");
fprintf (stderr, " %s%*s%s\n", "help", max_width - 4, " ", "Print this help");
fprintf (stderr, "\nMultiple values can be given, separated by : or space.\n");
}
+1 -3
View File
@@ -151,7 +151,7 @@ gdk_array(reserve) (GdkArray *self,
return;
size = gdk_array(get_size) (self);
new_size = ((gsize) 1) << g_bit_storage (MAX (GDK_ARRAY_REAL_SIZE (n), 16) - 1);
new_size = 1 << g_bit_storage (MAX (GDK_ARRAY_REAL_SIZE (n), 16) - 1);
#ifdef GDK_ARRAY_PREALLOC
if (self->start == self->preallocated)
@@ -286,5 +286,3 @@ gdk_array(get) (const GdkArray *self,
#undef GDK_ARRAY_TYPE_NAME
#undef GDK_ARRAY_NO_MEMSET
#endif
G_END_DECLS
+2 -1
View File
@@ -473,7 +473,8 @@ gdk_display_get_event (GdkDisplay *display)
* @display: a `GdkDisplay`
* @event: (transfer none): a `GdkEvent`
*
* Adds the given event to the event queue for @display.
* Appends the given event onto the front of the event
* queue for @display.
*
* Deprecated: 4.10: This function is only useful in very
* special situations and should not be used by applications.
+3 -39
View File
@@ -109,7 +109,6 @@ typedef struct {
guint has_sync : 1;
guint has_unpack_subimage : 1;
guint has_debug_output : 1;
guint has_bgra : 1;
guint extensions_checked : 1;
guint debug_enabled : 1;
guint forward_compatible : 1;
@@ -1529,16 +1528,13 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
if (gdk_gl_context_get_use_es (context))
{
priv->has_unpack_subimage = gdk_gl_version_greater_equal (&priv->gl_version, &GDK_GL_VERSION_INIT (3, 0)) ||
epoxy_has_gl_extension ("GL_EXT_unpack_subimage");
priv->has_unpack_subimage = epoxy_has_gl_extension ("GL_EXT_unpack_subimage");
priv->has_khr_debug = epoxy_has_gl_extension ("GL_KHR_debug");
priv->has_bgra = epoxy_has_gl_extension ("GL_EXT_texture_format_BGRA8888");
}
else
{
priv->has_unpack_subimage = TRUE;
priv->has_khr_debug = epoxy_has_gl_extension ("GL_KHR_debug");
priv->has_bgra = TRUE;
/* We asked for a core profile, but we didn't get one, so we're in legacy mode */
if (!gdk_gl_version_greater_equal (&priv->gl_version, &GDK_GL_VERSION_INIT (3, 2)))
@@ -1570,8 +1566,7 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
" - GL_KHR_debug: %s\n"
" - GL_EXT_unpack_subimage: %s\n"
" - half float: %s\n"
" - sync: %s\n"
" - bgra: %s",
" - sync: %s",
gdk_gl_context_get_use_es (context) ? "OpenGL ES" : "OpenGL",
gdk_gl_version_get_major (&priv->gl_version), gdk_gl_version_get_minor (&priv->gl_version),
priv->is_legacy ? "legacy" : "core",
@@ -1580,8 +1575,7 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
priv->has_khr_debug ? "yes" : "no",
priv->has_unpack_subimage ? "yes" : "no",
priv->has_half_float ? "yes" : "no",
priv->has_sync ? "yes" : "no",
priv->has_bgra ? "yes" : "no");
priv->has_sync ? "yes" : "no");
}
#endif
@@ -1817,36 +1811,6 @@ gdk_gl_context_has_sync (GdkGLContext *self)
return priv->has_sync;
}
/* Return if GL_BGRA works with glTexImage2D */
gboolean
gdk_gl_context_has_bgra (GdkGLContext *self)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
return priv->has_bgra;
}
/* Return if glGenVertexArrays, glBindVertexArray and glDeleteVertexArrays
* can be used
*/
gboolean
gdk_gl_context_has_vertex_arrays (GdkGLContext *self)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
switch (priv->api)
{
case GDK_GL_API_GL:
return TRUE;
case GDK_GL_API_GLES:
return gdk_gl_version_get_major (&priv->gl_version) >= 3;
default:
g_return_val_if_reached (FALSE);
}
}
/* This is currently private! */
/* When using GL/ES, don't flip the 'R' and 'B' bits on Windows/ANGLE for glReadPixels() */
gboolean
-4
View File
@@ -155,10 +155,6 @@ gboolean gdk_gl_context_has_vertex_half_float (GdkGLContext
gboolean gdk_gl_context_has_sync (GdkGLContext *self) G_GNUC_PURE;
gboolean gdk_gl_context_has_bgra (GdkGLContext *self) G_GNUC_PURE;
gboolean gdk_gl_context_has_vertex_arrays (GdkGLContext *self) G_GNUC_PURE;
double gdk_gl_context_get_scale (GdkGLContext *self);
G_END_DECLS
+2 -2
View File
@@ -153,7 +153,7 @@ gdk_gl_texture_find_format (gboolean use_es,
if (gdk_memory_format_alpha (format) != alpha)
continue;
if (!gdk_memory_format_gl_format (format, use_es, gl_major, gl_minor, &q_internal_format, &q_format, &q_type, q_swizzle))
if (!gdk_memory_format_gl_format (format, use_es, gl_major, gl_minor, &q_internal_format, &q_format, &q_type, &q_swizzle))
continue;
if (q_format != gl_format || q_type != gl_type)
@@ -188,7 +188,7 @@ gdk_gl_texture_do_download (GdkGLTexture *self,
FALSE,
major, minor,
&gl_internal_format,
&gl_format, &gl_type, gl_swizzle))
&gl_format, &gl_type, &gl_swizzle))
{
if (download->stride == expected_stride &&
download->format == format)
+8 -8
View File
@@ -423,7 +423,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
G_ALIGNOF (guchar),
GDK_MEMORY_U8,
{ 0, 0, 0, 0 },
{ GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
{ GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, { GL_RED, GL_GREEN, GL_BLUE, GL_ONE } },
r8g8b8_to_float,
r8g8b8_from_float,
},
@@ -433,7 +433,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
G_ALIGNOF (guchar),
GDK_MEMORY_U8,
{ 0, 0, G_MAXUINT, G_MAXUINT },
{ GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
{ GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE, { GL_RED, GL_GREEN, GL_BLUE, GL_ONE } },
b8g8r8_to_float,
b8g8r8_from_float,
},
@@ -443,7 +443,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
G_ALIGNOF (guint16),
GDK_MEMORY_U16,
{ 0, 0, 3, 0 },
{ GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
{ GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT, { GL_RED, GL_GREEN, GL_BLUE, GL_ONE } },
r16g16b16_to_float,
r16g16b16_from_float,
},
@@ -473,7 +473,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
G_ALIGNOF (guint16),
GDK_MEMORY_FLOAT16,
{ 0, 0, 3, 0 },
{ GL_RGB16F, GL_RGB, GL_HALF_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
{ GL_RGB16F, GL_RGB, GL_HALF_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ONE } },
r16g16b16_float_to_float,
r16g16b16_float_from_float,
},
@@ -503,7 +503,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
G_ALIGNOF (float),
GDK_MEMORY_FLOAT32,
{ 0, 0, 3, 0 },
{ GL_RGB32F, GL_RGB, GL_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
{ GL_RGB32F, GL_RGB, GL_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ONE } },
r32g32b32_float_to_float,
r32g32b32_float_from_float,
},
@@ -511,7 +511,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
GDK_MEMORY_ALPHA_PREMULTIPLIED,
16,
G_ALIGNOF (float),
GDK_MEMORY_FLOAT32,
TRUE,
{ 0, 0, 3, 0 },
{ GL_RGBA32F, GL_RGBA, GL_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
r32g32b32a32_float_to_float,
@@ -739,12 +739,12 @@ gdk_memory_format_gl_format (GdkMemoryFormat format,
guint *out_internal_format,
guint *out_format,
guint *out_type,
GLint out_swizzle[4])
GLint (*out_swizzle)[4])
{
*out_internal_format = memory_formats[format].gl.internal_format;
*out_format = memory_formats[format].gl.format;
*out_type = memory_formats[format].gl.type;
memcpy (out_swizzle, memory_formats[format].gl.swizzle, sizeof(GLint) * 4);
memcpy (out_swizzle, &memory_formats[format].gl.swizzle, sizeof(GLint) * 4);
if (gles)
{
+1 -1
View File
@@ -52,7 +52,7 @@ gboolean gdk_memory_format_gl_format (GdkMemoryFormat
guint *out_internal_format,
guint *out_format,
guint *out_type,
GLint out_gizzle[4]);
GLint (*out_gizzle)[4]);
void gdk_memory_convert (guchar *dest_data,
gsize dest_stride,
+2 -19
View File
@@ -24,16 +24,11 @@
#include "gdksnapshotprivate.h"
#include "gdkprivate.h"
#include <graphene.h>
/* HACK: So we don't need to include any (not-yet-created) GSK or GTK headers */
GdkSnapshot * gtk_snapshot_new (void);
void gtk_snapshot_push_debug (GdkSnapshot *snapshot,
const char *message,
...) G_GNUC_PRINTF (2, 3);
void gtk_snapshot_pop (GdkSnapshot *snapshot);
GdkPaintable * gtk_snapshot_free_to_paintable (GdkSnapshot *snapshot,
const graphene_size_t *size);
/**
* GdkPaintable:
@@ -107,21 +102,9 @@ gdk_paintable_default_snapshot (GdkPaintable *paintable,
static GdkPaintable *
gdk_paintable_default_get_current_image (GdkPaintable *paintable)
{
int width, height;
GdkSnapshot *snapshot;
g_warning ("FIXME: implement by snapshotting at default size and returning a GskRendererNodePaintable");
/* No need to check whether the paintable is static, as
* gdk_paintable_get_current_image () takes care of that already. */
width = gdk_paintable_get_intrinsic_width (paintable);
height = gdk_paintable_get_intrinsic_height (paintable);
if (width <= 0 || height <= 0)
return gdk_paintable_new_empty (width, height);
snapshot = gtk_snapshot_new ();
gdk_paintable_snapshot (paintable, snapshot, width, height);
return gtk_snapshot_free_to_paintable (snapshot, NULL);
return paintable;
}
static GdkPaintableFlags
+1 -1
View File
@@ -40,7 +40,7 @@ struct _GdkIOPipe
GCond cond;
guchar *buffer;
gsize size;
guint state : 2; /* GdkIOPipeState */
GdkIOPipeState state : 2;
guint input_closed : 1;
guint output_closed : 1;
};
+3 -5
View File
@@ -345,9 +345,7 @@ gdk_texture_init (GdkTexture *self)
*
* Creates a new texture object representing the surface.
*
* The @surface must be an image surface with format `CAIRO_FORMAT_ARGB32`.
*
* The newly created texture will acquire a reference on the @surface.
* @surface must be an image surface with format `CAIRO_FORMAT_ARGB32`.
*
* Returns: a new `GdkTexture`
*/
@@ -366,7 +364,7 @@ gdk_texture_new_for_surface (cairo_surface_t *surface)
* cairo_image_surface_get_stride (surface),
(GDestroyNotify) cairo_surface_destroy,
cairo_surface_reference (surface));
texture = gdk_memory_texture_new (cairo_image_surface_get_width (surface),
cairo_image_surface_get_height (surface),
GDK_MEMORY_DEFAULT,
@@ -821,7 +819,7 @@ gdk_texture_set_render_data (GdkTexture *self,
GDestroyNotify notify)
{
g_return_val_if_fail (data != NULL, FALSE);
if (self->render_key != NULL)
return FALSE;
-10
View File
@@ -188,14 +188,6 @@ copy_surface_data (GdkMacosBuffer *from,
}
}
static void
clamp_region_to_surface (cairo_region_t *region,
GdkSurface *surface)
{
cairo_rectangle_int_t rectangle = {0, 0, surface->width, surface->height};
cairo_region_intersect_rectangle (region, &rectangle);
}
static void
_gdk_macos_cairo_context_begin_frame (GdkDrawContext *draw_context,
GdkMemoryDepth depth,
@@ -213,8 +205,6 @@ _gdk_macos_cairo_context_begin_frame (GdkDrawContext *draw_context,
surface = GDK_MACOS_SURFACE (gdk_draw_context_get_surface (draw_context));
buffer = _gdk_macos_surface_get_buffer (surface);
clamp_region_to_surface (region, GDK_SURFACE (surface));
_gdk_macos_buffer_set_damage (buffer, region);
_gdk_macos_buffer_set_flipped (buffer, FALSE);
+1 -1
View File
@@ -90,7 +90,7 @@ struct _GdkMacosDisplay
/* Note if we have a key window that is not a GdkMacosWindow
* such as a NSPanel used for native dialogs.
*/
guint key_window_is_foreign : 1;
guint key_window_is_foregin : 1;
};
struct _GdkMacosDisplayClass
+3 -3
View File
@@ -424,7 +424,7 @@ select_key_in_idle_cb (gpointer data)
self->select_key_in_idle = 0;
/* Don't steal focus from NSPanel, etc */
if (self->key_window_is_foreign)
if (self->key_window_is_foregin)
return G_SOURCE_REMOVE;
if (self->keyboard_surface == NULL)
@@ -941,7 +941,7 @@ _gdk_macos_display_get_surfaces (GdkMacosDisplay *self)
NSArray *array = [NSApp orderedWindows];
GQueue sorted = G_QUEUE_INIT;
self->key_window_is_foreign = FALSE;
self->key_window_is_foregin = FALSE;
for (id obj in array)
{
@@ -949,7 +949,7 @@ _gdk_macos_display_get_surfaces (GdkMacosDisplay *self)
GdkMacosSurface *surface;
if ([nswindow isKeyWindow])
self->key_window_is_foreign = !GDK_IS_MACOS_WINDOW (nswindow);
self->key_window_is_foregin = !GDK_IS_MACOS_WINDOW (nswindow);
if (!GDK_IS_MACOS_WINDOW (nswindow))
continue;
+1 -1
View File
@@ -331,7 +331,7 @@ _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self)
gdk_monitor_set_physical_size (GDK_MONITOR (self), width_mm, height_mm);
gdk_monitor_set_scale_factor (GDK_MONITOR (self), scale_factor);
gdk_monitor_set_refresh_rate (GDK_MONITOR (self), refresh_rate);
gdk_monitor_set_subpixel_layout (GDK_MONITOR (self), subpixel_layout);
gdk_monitor_set_subpixel_layout (GDK_MONITOR (self), GDK_SUBPIXEL_LAYOUT_UNKNOWN);
self->workarea = [screen visibleFrame];
+5 -18
View File
@@ -46,21 +46,6 @@ static const struct xdg_activation_token_v1_listener token_listener = {
token_done,
};
static struct wl_surface *
peek_launcher_toplevel (GdkSeat *seat)
{
struct wl_surface *wl_surface = NULL;
GdkSurface *focus_surface;
focus_surface = gdk_wayland_device_get_focus (gdk_seat_get_keyboard (seat));
while (focus_surface && focus_surface->parent)
focus_surface = focus_surface->parent;
if (focus_surface)
wl_surface = gdk_wayland_surface_get_wl_surface (focus_surface);
return wl_surface;
}
static char *
gdk_wayland_app_launch_context_get_startup_notify_id (GAppLaunchContext *context,
GAppInfo *info,
@@ -77,6 +62,7 @@ gdk_wayland_app_launch_context_get_startup_notify_id (GAppLaunchContext *context
struct wl_event_queue *event_queue;
struct wl_surface *wl_surface = NULL;
GdkWaylandSeat *seat;
GdkSurface *focus_surface;
AppLaunchData app_launch_data = { 0 };
event_queue = wl_display_create_queue (display->wl_display);
@@ -92,7 +78,9 @@ gdk_wayland_app_launch_context_get_startup_notify_id (GAppLaunchContext *context
_gdk_wayland_seat_get_last_implicit_grab_serial (seat, NULL),
gdk_wayland_seat_get_wl_seat (GDK_SEAT (seat)));
wl_surface = peek_launcher_toplevel (GDK_SEAT (seat));
focus_surface = gdk_wayland_device_get_focus (gdk_seat_get_keyboard (GDK_SEAT (seat)));
if (focus_surface)
wl_surface = gdk_wayland_surface_get_wl_surface (focus_surface);
if (wl_surface)
xdg_activation_token_v1_set_surface (token, wl_surface);
@@ -105,8 +93,7 @@ gdk_wayland_app_launch_context_get_startup_notify_id (GAppLaunchContext *context
id = app_launch_data.token;
wl_event_queue_destroy (event_queue);
}
else if (display->gtk_shell &&
gtk_shell1_get_version (display->gtk_shell) >= GTK_SHELL1_NOTIFY_LAUNCH_SINCE_VERSION)
else if (gtk_shell1_get_version (display->gtk_shell) >= GTK_SHELL1_NOTIFY_LAUNCH_SINCE_VERSION)
{
id = g_uuid_string_random ();
gtk_shell1_notify_launch (display->gtk_shell, id);
+1 -8
View File
@@ -96,12 +96,6 @@
#define XDG_ACTIVATION_VERSION 1
#define OUTPUT_VERSION 3
#ifdef HAVE_TOPLEVEL_STATE_SUSPENDED
#define XDG_WM_BASE_VERSION 6
#else
#define XDG_WM_BASE_VERSION 5
#endif
static void _gdk_wayland_display_load_cursor_theme (GdkWaylandDisplay *display_wayland);
G_DEFINE_TYPE (GdkWaylandDisplay, gdk_wayland_display, GDK_TYPE_DISPLAY)
@@ -644,8 +638,7 @@ _gdk_wayland_display_open (const char *display_name)
wl_registry_bind (display_wayland->wl_registry,
display_wayland->xdg_wm_base_id,
&xdg_wm_base_interface,
MIN (display_wayland->xdg_wm_base_version,
XDG_WM_BASE_VERSION));
MIN (display_wayland->xdg_wm_base_version, 4));
xdg_wm_base_add_listener (display_wayland->xdg_wm_base,
&xdg_wm_base_listener,
display_wayland);
-8
View File
@@ -672,18 +672,10 @@ xdg_toplevel_configure_bounds (void *data,
toplevel->pending.has_bounds = TRUE;
}
static void
xdg_toplevel_wm_capabilities (void *data,
struct xdg_toplevel *xdg_toplevel,
struct wl_array *capabilities)
{
}
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
xdg_toplevel_configure,
xdg_toplevel_close,
xdg_toplevel_configure_bounds,
xdg_toplevel_wm_capabilities,
};
static void
-3
View File
@@ -127,6 +127,3 @@ libgdk_wayland = static_library('gdk-wayland',
link_with: [ libwayland_cursor, ],
dependencies: [ gdk_deps, gdk_wayland_deps ],
)
# Used to generate pkg-config Requires
wayland_public_deps = [wlclientdep]
+6 -7
View File
@@ -286,16 +286,15 @@ _gdk_win32_display_init_monitors (GdkWin32Display *win32_display)
GdkMonitor *ex_monitor;
w32_ex_monitor = GDK_WIN32_MONITOR (g_list_model_get_item (win32_display->monitors, i));
g_object_unref (w32_ex_monitor);
ex_monitor = GDK_MONITOR (w32_ex_monitor);
if (w32_ex_monitor->remove)
{
w32_ex_monitor->hmonitor = NULL;
g_list_store_remove (G_LIST_STORE (win32_display->monitors), i);
gdk_monitor_invalidate (ex_monitor);
}
if (!w32_ex_monitor->remove)
continue;
g_object_unref (w32_ex_monitor);
w32_ex_monitor->hmonitor = NULL;
g_list_store_remove (G_LIST_STORE (win32_display->monitors), i);
gdk_monitor_invalidate (ex_monitor);
}
for (i = 0; i < new_monitors->len; i++)
+1 -12
View File
@@ -2857,10 +2857,7 @@ gdk_event_translate (MSG *msg,
break;
case WM_SYSCOMMAND:
/* From: https://learn.microsoft.com/en-us/windows/win32/menurc/wm-syscommand?redirectedfrom=MSDN
* To obtain the correct result when testing the value of wParam,
* an application must combine the value 0xFFF0 with the wParam value by using the bitwise AND operator. */
switch (msg->wParam & 0xFFF0)
switch (msg->wParam)
{
case SC_MINIMIZE:
case SC_RESTORE:
@@ -2967,14 +2964,6 @@ gdk_event_translate (MSG *msg,
windowpos = (WINDOWPOS *) msg->lParam;
windowpos->cx = our_mmi.ptMaxSize.x;
windowpos->cy = our_mmi.ptMaxSize.y;
if (!_gdk_win32_surface_lacks_wm_decorations (window) &&
!(windowpos->flags & SWP_NOCLIENTSIZE) &&
window->width == impl->next_layout.configured_width &&
window->height == impl->next_layout.configured_height)
{
impl->inhibit_configure = TRUE;
}
}
impl->maximizing = FALSE;
+8 -5
View File
@@ -1230,11 +1230,18 @@ get_effective_window_decorations (GdkSurface *window,
*decoration |= GDK_DECOR_MINIMIZE;
return TRUE;
}
else if (impl->hint_flags & GDK_HINT_MAX_SIZE)
{
*decoration = GDK_DECOR_ALL | GDK_DECOR_MAXIMIZE;
*decoration |= GDK_DECOR_MINIMIZE;
return TRUE;
}
else
{
*decoration = GDK_DECOR_ALL;
*decoration = (GDK_DECOR_ALL | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
return TRUE;
}
@@ -4442,10 +4449,6 @@ _gdk_win32_surface_request_layout (GdkSurface *surface)
{
_gdk_win32_get_window_rect (surface, &rect);
/* Keep current position if rect is invalid (i.e. queried in bad context) */
if (rect.right == rect.left || rect.bottom == rect.top)
return;
impl->next_layout.configured_width = (rect.right - rect.left + scale - 1) / scale;
impl->next_layout.configured_height = (rect.bottom - rect.top + scale - 1) / scale;
+1 -3
View File
@@ -201,7 +201,7 @@ gdk_x11_clipboard_formats_to_targets (GdkContentFormats *formats)
continue;
if (g_str_equal (mime_types[i], special_targets[j].mime_type))
targets = g_slist_prepend (targets, (gpointer) g_intern_static_string (special_targets[j].x_target));
targets = g_slist_prepend (targets, (gpointer) g_intern_string (special_targets[j].x_target));
}
targets = g_slist_prepend (targets, (gpointer) mime_types[i]);
}
@@ -238,8 +238,6 @@ gdk_x11_clipboard_formats_to_atoms (GdkDisplay *display,
for (l = targets; l; l = l->next)
atoms[i++] = gdk_x11_get_xatom_by_name_for_display (display, l->data);
g_slist_free (targets);
return atoms;
}
-2
View File
@@ -86,5 +86,3 @@ libgdk_x11 = static_library('gdk-x11',
] + common_cflags,
dependencies: [ gdk_deps, gdk_x11_deps, ],
)
x11_public_deps = [x11_dep]
+6 -7
View File
@@ -271,6 +271,8 @@ collect_reused_child_nodes (GskRenderer *renderer,
case GSK_CROSS_FADE_NODE:
case GSK_BLUR_NODE:
case GSK_MASK_NODE:
case GSK_FILL_NODE:
case GSK_STROKE_NODE:
default:
@@ -451,7 +453,7 @@ get_colorized_texture (GdkTexture *texture,
const graphene_matrix_t *color_matrix,
const graphene_vec4_t *color_offset)
{
cairo_surface_t *surface;
cairo_surface_t *surface = gdk_texture_download_surface (texture);
cairo_surface_t *image_surface;
graphene_vec4_t pixel;
guint32* pixel_data;
@@ -473,7 +475,6 @@ get_colorized_texture (GdkTexture *texture,
return g_object_ref (colorized->texture);
}
surface = gdk_texture_download_surface (texture);
image_surface = cairo_surface_map_to_image (surface, NULL);
data = cairo_image_surface_get_data (image_surface);
width = cairo_image_surface_get_width (image_surface);
@@ -535,8 +536,6 @@ get_colorized_texture (GdkTexture *texture,
colorized_list, (GDestroyNotify)colorized_texture_free_list);
}
cairo_surface_destroy (surface);
return colorized_texture;
}
@@ -612,7 +611,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
}
texture = gdk_texture_new_for_surface (image_surface);
g_ptr_array_add (self->node_textures, texture); /* Transfers ownership to node_textures */
g_ptr_array_add (self->node_textures, g_object_ref (texture)); /* Transfers ownership to node_textures */
texture_id = gdk_broadway_display_ensure_texture (display, texture);
add_rect (nodes, &node->bounds, offset_x, offset_y);
@@ -862,6 +861,8 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
case GSK_CROSS_FADE_NODE:
case GSK_BLUR_NODE:
case GSK_GL_SHADER_NODE:
case GSK_FILL_NODE:
case GSK_STROKE_NODE:
default:
break; /* Fallback */
}
@@ -901,8 +902,6 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
add_float (nodes, width);
add_float (nodes, height);
add_uint32 (nodes, texture_id);
cairo_surface_destroy (surface);
}
}
+7 -6
View File
@@ -1070,7 +1070,7 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation (GL_FUNC_ADD);
if (gdk_gl_context_has_vertex_arrays (self->context))
if (!gdk_gl_context_get_use_es (self->context))
{
glGenVertexArrays (1, &vao_id);
glBindVertexArray (vao_id);
@@ -1257,7 +1257,7 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
}
glDeleteBuffers (1, &vbo_id);
if (gdk_gl_context_has_vertex_arrays (self->context))
if (!gdk_gl_context_get_use_es (self->context))
glDeleteVertexArrays (1, &vao_id);
gdk_profiler_set_int_counter (self->metrics.n_binds, n_binds);
@@ -1456,7 +1456,7 @@ memory_format_gl_format (GdkMemoryFormat data_format,
guint *gl_internalformat,
guint *gl_format,
guint *gl_type,
GLint gl_swizzle[4])
GLint (*gl_swizzle)[4])
{
GdkMemoryDepth depth;
@@ -1577,7 +1577,7 @@ gsk_gl_command_queue_do_upload_texture_chunk (GskGLCommandQueue *self,
&gl_internalformat,
&gl_format,
&gl_type,
gl_swizzle);
&gl_swizzle);
gdk_texture_downloader_init (&downloader, texture);
gdk_texture_downloader_set_format (&downloader, data_format);
@@ -1595,7 +1595,8 @@ gsk_gl_command_queue_do_upload_texture_chunk (GskGLCommandQueue *self,
{
glTexSubImage2D (GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, data);
}
else if (stride % bpp == 0 && gdk_gl_context_has_unpack_subimage (self->context))
else if (stride % bpp == 0 &&
(gdk_gl_context_check_version (self->context, NULL, "3.0") || gdk_gl_context_has_unpack_subimage (self->context)))
{
glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / bpp);
@@ -1683,7 +1684,7 @@ gsk_gl_command_queue_upload_texture_chunks (GskGLCommandQueue *self,
&gl_internalformat,
&gl_format,
&gl_type,
gl_swizzle);
&gl_swizzle);
glTexImage2D (GL_TEXTURE_2D, 0, gl_internalformat, width, height, 0, gl_format, gl_type, NULL);
+2 -4
View File
@@ -1601,9 +1601,8 @@ create_texture_from_texture_destroy (gpointer data)
}
GdkTexture *
gsk_gl_driver_create_gdk_texture (GskGLDriver *self,
guint texture_id,
GdkMemoryFormat format)
gsk_gl_driver_create_gdk_texture (GskGLDriver *self,
guint texture_id)
{
GskGLTextureState *state;
GdkGLTextureBuilder *builder;
@@ -1631,7 +1630,6 @@ gsk_gl_driver_create_gdk_texture (GskGLDriver *self,
builder = gdk_gl_texture_builder_new ();
gdk_gl_texture_builder_set_context (builder, self->command_queue->context);
gdk_gl_texture_builder_set_id (builder, texture_id);
gdk_gl_texture_builder_set_format (builder, format);
gdk_gl_texture_builder_set_width (builder, texture->width);
gdk_gl_texture_builder_set_height (builder, texture->height);
gdk_gl_texture_builder_set_sync (builder, state->sync);
+1 -2
View File
@@ -149,8 +149,7 @@ void gsk_gl_driver_begin_frame (GskGLDriver *s
void gsk_gl_driver_end_frame (GskGLDriver *self);
void gsk_gl_driver_after_frame (GskGLDriver *self);
GdkTexture * gsk_gl_driver_create_gdk_texture (GskGLDriver *self,
guint texture_id,
GdkMemoryFormat format);
guint texture_id);
void gsk_gl_driver_cache_texture (GskGLDriver *self,
const GskTextureKey *key,
guint texture_id);
+5 -8
View File
@@ -119,11 +119,7 @@ gsk_gl_glyph_library_init_atlas (GskGLTextureLibrary *self,
memset (pixel_data, 255, sizeof pixel_data);
if (!gdk_gl_context_has_bgra (gdk_gl_context_get_current ())
#if G_BYTE_ORDER == G_BIG_ENDIAN
|| gdk_gl_context_get_use_es (gdk_gl_context_get_current ())
#endif
)
if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
{
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
@@ -131,8 +127,9 @@ gsk_gl_glyph_library_init_atlas (GskGLTextureLibrary *self,
else
{
gl_format = GL_BGRA;
gl_type = GL_UNSIGNED_BYTE;
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
}
glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
glTexSubImage2D (GL_TEXTURE_2D, 0,
@@ -280,7 +277,7 @@ gsk_gl_glyph_library_upload_glyph (GskGLGlyphLibrary *self,
g_assert (texture_id > 0);
if (G_UNLIKELY (!gdk_gl_context_has_bgra (gdk_gl_context_get_current ())))
if G_UNLIKELY (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
{
pixel_data = free_data = g_malloc (width * height * 4);
gdk_memory_convert (pixel_data, width * 4,
@@ -297,7 +294,7 @@ gsk_gl_glyph_library_upload_glyph (GskGLGlyphLibrary *self,
{
pixel_data = cairo_image_surface_get_data (surface);
gl_format = GL_BGRA;
gl_type = GL_UNSIGNED_BYTE;
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
}
glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / 4);
+3 -7
View File
@@ -111,11 +111,7 @@ gsk_gl_icon_library_add (GskGLIconLibrary *self,
gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
"Uploading texture");
if (!gdk_gl_context_has_bgra (gdk_gl_context_get_current ())
#if G_BYTE_ORDER == G_BIG_ENDIAN
|| gdk_gl_context_get_use_es (gdk_gl_context_get_current ())
#endif
)
if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
{
pixel_data = free_data = g_malloc (width * height * 4);
gdk_memory_convert (pixel_data, width * 4,
@@ -129,7 +125,7 @@ gsk_gl_icon_library_add (GskGLIconLibrary *self,
{
pixel_data = surface_data;
gl_format = GL_BGRA;
gl_type = GL_UNSIGNED_BYTE;
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
}
texture_id = GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (icon_data);
@@ -148,7 +144,6 @@ gsk_gl_icon_library_add (GskGLIconLibrary *self,
gl_format, gl_type,
pixel_data);
/* Padding left */
glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x, packed_y + 1,
1, height,
@@ -162,6 +157,7 @@ gsk_gl_icon_library_add (GskGLIconLibrary *self,
pixel_data);
/* Padding right */
glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1);
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + width + 1, packed_y + 1,
+3 -10
View File
@@ -332,7 +332,6 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
GskGLRenderJob *job;
GdkTexture *texture;
guint texture_id;
GdkMemoryFormat gdk_format;
int width, height, max_size;
int format;
@@ -376,15 +375,9 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
if (gsk_render_node_get_preferred_depth (root) != GDK_MEMORY_U8 &&
gdk_gl_context_check_version (self->context, "3.0", "3.0"))
{
gdk_format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
format = GL_RGBA32F;
}
format = GL_RGBA32F;
else
{
format = GL_RGBA8;
gdk_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
}
format = GL_RGBA8;
gdk_gl_context_make_current (self->context);
@@ -401,7 +394,7 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
#endif
gsk_gl_render_job_render_flipped (job, root);
texture_id = gsk_gl_driver_release_render_target (self->driver, render_target, FALSE);
texture = gsk_gl_driver_create_gdk_texture (self->driver, texture_id, gdk_format);
texture = gsk_gl_driver_create_gdk_texture (self->driver, texture_id);
gsk_gl_driver_end_frame (self->driver);
gsk_gl_render_job_free (job);
+1 -1
View File
@@ -20,7 +20,7 @@
#pragma once
#include <gsk/gsk.h>
#include <gsk/gskrenderer.h>
G_BEGIN_DECLS
+87 -105
View File
@@ -65,14 +65,6 @@ typedef struct _GskGLRenderClip
guint is_fully_contained : 1;
} GskGLRenderClip;
#define GDK_ARRAY_NAME clips
#define GDK_ARRAY_TYPE_NAME Clips
#define GDK_ARRAY_ELEMENT_TYPE GskGLRenderClip
#define GDK_ARRAY_BY_VALUE 1
#define GDK_ARRAY_PREALLOC 16
#define GDK_ARRAY_NO_MEMSET
#include "gdk/gdkarrayimpl.c"
typedef struct _GskGLRenderModelview
{
GskTransform *transform;
@@ -85,14 +77,6 @@ typedef struct _GskGLRenderModelview
graphene_matrix_t matrix;
} GskGLRenderModelview;
#define GDK_ARRAY_NAME modelviews
#define GDK_ARRAY_TYPE_NAME Modelviews
#define GDK_ARRAY_ELEMENT_TYPE GskGLRenderModelview
#define GDK_ARRAY_BY_VALUE 1
#define GDK_ARRAY_PREALLOC 16
#define GDK_ARRAY_NO_MEMSET
#include "gdk/gdkarrayimpl.c"
struct _GskGLRenderJob
{
/* The context containing the framebuffer we are drawing to. Generally this
@@ -133,12 +117,12 @@ struct _GskGLRenderJob
/* An array of GskGLRenderModelview updated as nodes are processed. The
* current modelview is the last element.
*/
Modelviews modelview;
GArray *modelview;
/* An array of GskGLRenderClip updated as nodes are processed. The
* current clip is the last element.
*/
Clips clip;
GArray *clip;
/* Our current alpha state as we process nodes */
float alpha;
@@ -158,8 +142,6 @@ struct _GskGLRenderJob
const GskGLRenderModelview *current_modelview;
GskGLProgram *current_program;
guint source_is_glyph_atlas : 1;
/* If we should be rendering red zones over fallback nodes */
guint debug_fallback : 1;
@@ -209,22 +191,6 @@ static gboolean gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob
const GskRenderNode *node,
GskGLRenderOffscreen *offscreen);
static inline GskGLRenderClip *
clips_grow_one (Clips *clips)
{
guint len = clips_get_size (clips);
clips_set_size (clips, len + 1);
return clips_get (clips, len);
}
static inline GskGLRenderModelview *
modelviews_grow_one (Modelviews *modelviews)
{
guint len = modelviews_get_size (modelviews);
modelviews_set_size (modelviews, len + 1);
return modelviews_get (modelviews, len);
}
static inline int
get_target_format (GskGLRenderJob *job,
const GskRenderNode *node)
@@ -270,7 +236,7 @@ gsk_rounded_rect_shrink_to_minimum (GskRoundedRect *self)
static inline gboolean G_GNUC_PURE
node_supports_2d_transform (const GskRenderNode *node)
{
switch (GSK_RENDER_NODE_TYPE (node))
switch (gsk_render_node_get_node_type (node))
{
case GSK_COLOR_NODE:
case GSK_OPACITY_NODE:
@@ -289,6 +255,8 @@ node_supports_2d_transform (const GskRenderNode *node)
case GSK_BLEND_NODE:
case GSK_BLUR_NODE:
case GSK_MASK_NODE:
case GSK_FILL_NODE:
case GSK_STROKE_NODE:
return TRUE;
case GSK_SHADOW_NODE:
@@ -330,7 +298,7 @@ node_supports_transform (const GskRenderNode *node)
* opacity or color matrix.
*/
switch (GSK_RENDER_NODE_TYPE (node))
switch (gsk_render_node_get_node_type (node))
{
case GSK_COLOR_NODE:
case GSK_OPACITY_NODE:
@@ -343,6 +311,8 @@ node_supports_transform (const GskRenderNode *node)
case GSK_BLEND_NODE:
case GSK_BLUR_NODE:
case GSK_MASK_NODE:
case GSK_FILL_NODE:
case GSK_STROKE_NODE:
return TRUE;
case GSK_SHADOW_NODE:
@@ -494,10 +464,15 @@ gsk_gl_render_job_set_modelview (GskGLRenderJob *job,
GskGLRenderModelview *modelview;
g_assert (job != NULL);
g_assert (job->modelview != NULL);
job->driver->stamps[UNIFORM_SHARED_MODELVIEW]++;
modelview = modelviews_grow_one (&job->modelview);
g_array_set_size (job->modelview, job->modelview->len + 1);
modelview = &g_array_index (job->modelview,
GskGLRenderModelview,
job->modelview->len - 1);
modelview->transform = transform;
@@ -522,17 +497,26 @@ gsk_gl_render_job_push_modelview (GskGLRenderJob *job,
GskGLRenderModelview *modelview;
g_assert (job != NULL);
g_assert (job->modelview != NULL);
g_assert (transform != NULL);
job->driver->stamps[UNIFORM_SHARED_MODELVIEW]++;
modelview = modelviews_grow_one (&job->modelview);
g_array_set_size (job->modelview, job->modelview->len + 1);
if G_LIKELY (modelviews_get_size (&job->modelview) > 1)
modelview = &g_array_index (job->modelview,
GskGLRenderModelview,
job->modelview->len - 1);
if G_LIKELY (job->modelview->len > 1)
{
GskGLRenderModelview *last = job->modelview.end - 2;
GskGLRenderModelview *last;
GskTransform *t = NULL;
last = &g_array_index (job->modelview,
GskGLRenderModelview,
job->modelview->len - 2);
/* Multiply given matrix with our previous modelview */
t = gsk_transform_translate (gsk_transform_ref (last->transform),
&(graphene_point_t) {
@@ -566,7 +550,8 @@ gsk_gl_render_job_pop_modelview (GskGLRenderJob *job)
const GskGLRenderModelview *head;
g_assert (job != NULL);
g_assert (modelviews_get_size (&job->modelview) > 0);
g_assert (job->modelview);
g_assert (job->modelview->len > 0);
job->driver->stamps[UNIFORM_SHARED_MODELVIEW]++;
@@ -577,11 +562,11 @@ gsk_gl_render_job_pop_modelview (GskGLRenderJob *job)
gsk_transform_unref (head->transform);
job->modelview.end--;
job->modelview->len--;
if (modelviews_get_size (&job->modelview) >= 1)
if (job->modelview->len >= 1)
{
head = job->modelview.end - 1;
head = &g_array_index (job->modelview, GskGLRenderModelview, job->modelview->len - 1);
job->scale_x = head->scale_x;
job->scale_y = head->scale_y;
@@ -601,12 +586,14 @@ gsk_gl_render_job_push_clip (GskGLRenderJob *job,
GskGLRenderClip *clip;
g_assert (job != NULL);
g_assert (job->clip != NULL);
g_assert (rect != NULL);
job->driver->stamps[UNIFORM_SHARED_CLIP_RECT]++;
clip = clips_grow_one (&job->clip);
g_array_set_size (job->clip, job->clip->len + 1);
clip = &g_array_index (job->clip, GskGLRenderClip, job->clip->len - 1);
memcpy (&clip->rect, rect, sizeof *rect);
clip->is_rectilinear = gsk_rounded_rect_is_rectilinear (rect);
clip->is_fully_contained = FALSE;
@@ -621,13 +608,16 @@ gsk_gl_render_job_push_contained_clip (GskGLRenderJob *job)
GskGLRenderClip *old_clip;
g_assert (job != NULL);
g_assert (clips_get_size (&job->clip) > 0);
g_assert (job->clip != NULL);
g_assert (job->clip->len > 0);
job->driver->stamps[UNIFORM_SHARED_CLIP_RECT]++;
clip = clips_grow_one (&job->clip);
old_clip = clips_get (&job->clip, clips_get_size (&job->clip) - 2);
old_clip = &g_array_index (job->clip, GskGLRenderClip, job->clip->len - 1);
g_array_set_size (job->clip, job->clip->len + 1);
clip = &g_array_index (job->clip, GskGLRenderClip, job->clip->len - 1);
memcpy (&clip->rect.bounds, &old_clip->rect.bounds, sizeof (graphene_rect_t));
memset (clip->rect.corner, 0, sizeof clip->rect.corner);
clip->is_rectilinear = TRUE;
@@ -640,11 +630,12 @@ static void
gsk_gl_render_job_pop_clip (GskGLRenderJob *job)
{
g_assert (job != NULL);
g_assert (clips_get_size (&job->clip) > 0);
g_assert (job->clip != NULL);
g_assert (job->clip->len > 0);
job->driver->stamps[UNIFORM_SHARED_CLIP_RECT]++;
job->current_clip--;
job->clip.end--;
job->clip->len--;
}
static inline void
@@ -726,7 +717,7 @@ gsk_gl_render_job_transform_bounds (GskGLRenderJob *job,
GskTransformCategory category;
g_assert (job != NULL);
g_assert (modelviews_get_size (&job->modelview) > 0);
g_assert (job->modelview->len > 0);
g_assert (rect != NULL);
g_assert (out_rect != NULL);
@@ -1221,12 +1212,12 @@ gsk_gl_render_job_visit_as_fallback (GskGLRenderJob *job,
{
cairo_move_to (cr, 0, 0);
cairo_rectangle (cr, 0, 0, node->bounds.size.width, node->bounds.size.height);
if (GSK_RENDER_NODE_TYPE (node) == GSK_CAIRO_NODE)
if (gsk_render_node_get_node_type (node) == GSK_CAIRO_NODE)
cairo_set_source_rgba (cr, 0.3, 0, 1, 0.25);
else
cairo_set_source_rgba (cr, 1, 0, 0, 0.25);
cairo_fill_preserve (cr);
if (GSK_RENDER_NODE_TYPE (node) == GSK_CAIRO_NODE)
if (gsk_render_node_get_node_type (node) == GSK_CAIRO_NODE)
cairo_set_source_rgba (cr, 0.3, 0, 1, 1);
else
cairo_set_source_rgba (cr, 1, 0, 0, 1);
@@ -1254,9 +1245,9 @@ gsk_gl_render_job_visit_as_fallback (GskGLRenderJob *job,
done:
if (scale_x < 0 || scale_y < 0)
{
GskTransform *transform = gsk_transform_translate (NULL,
&GRAPHENE_POINT_INIT (scale_x < 0 ? - surface_width : 0,
scale_y < 0 ? - surface_height : 0));
GskTransform *transform = gsk_transform_translate (gsk_transform_scale (NULL, scale_x < 0 ? -1 : 1, scale_y < 0 ? -1 : 1),
&GRAPHENE_POINT_INIT (scale_x < 0 ? - (node->bounds.size.width + 2 * node->bounds.origin.x) : 0,
scale_y < 0 ? - (node->bounds.size.height + 2 * node->bounds.origin.y) : 0));
gsk_gl_render_job_push_modelview (job, transform);
gsk_transform_unref (transform);
}
@@ -1269,7 +1260,6 @@ done:
GL_TEXTURE_2D,
GL_TEXTURE0,
texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_render_job_draw_offscreen_rect (job, &node->bounds);
gsk_gl_render_job_end_draw (job);
@@ -1335,7 +1325,6 @@ blur_offscreen (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen->texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_program_set_uniform1f (job->current_program,
UNIFORM_BLUR_RADIUS, 0,
blur_radius_x);
@@ -1365,7 +1354,6 @@ blur_offscreen (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
pass1->texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_program_set_uniform1f (job->current_program,
UNIFORM_BLUR_RADIUS, 0,
blur_radius_y);
@@ -1473,8 +1461,7 @@ gsk_gl_render_job_visit_color_node (GskGLRenderJob *job,
batch = gsk_gl_command_queue_get_batch (job->command_queue);
/* Limit the size, or we end up with a coordinate overflow somewhere. */
if (job->source_is_glyph_atlas &&
node->bounds.size.width < 300 &&
if (node->bounds.size.width < 300 &&
node->bounds.size.height < 300 &&
batch->any.kind == GSK_GL_COMMAND_KIND_DRAW &&
batch->any.program == program->id)
@@ -1519,7 +1506,7 @@ gsk_gl_render_job_visit_linear_gradient_node (GskGLRenderJob *job,
const graphene_point_t *start = gsk_linear_gradient_node_get_start (node);
const graphene_point_t *end = gsk_linear_gradient_node_get_end (node);
int n_color_stops = gsk_linear_gradient_node_get_n_color_stops (node);
gboolean repeat = GSK_RENDER_NODE_TYPE (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE;
gboolean repeat = gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE;
float x1 = job->offset_x + start->x;
float x2 = job->offset_x + end->x;
float y1 = job->offset_y + start->y;
@@ -1592,7 +1579,7 @@ gsk_gl_render_job_visit_radial_gradient_node (GskGLRenderJob *job,
float end = gsk_radial_gradient_node_get_end (node);
float hradius = gsk_radial_gradient_node_get_hradius (node);
float vradius = gsk_radial_gradient_node_get_vradius (node);
gboolean repeat = GSK_RENDER_NODE_TYPE (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE;
gboolean repeat = gsk_render_node_get_node_type (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE;
float scale = 1.0f / (end - start);
float bias = -start * scale;
@@ -1681,7 +1668,6 @@ gsk_gl_render_job_visit_clipped_child (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_render_job_draw_offscreen_rect (job, clip);
gsk_gl_render_job_end_draw (job);
}
@@ -1737,7 +1723,7 @@ gsk_gl_render_job_visit_rounded_clip_node (GskGLRenderJob *job,
* which both have rounded corners.
*/
if (clips_get_size (&job->clip) <= 1)
if (job->clip->len <= 1)
need_offscreen = FALSE;
else if (gsk_rounded_rect_contains_rect (&job->current_clip->rect, &transformed_clip.bounds))
need_offscreen = FALSE;
@@ -1772,7 +1758,6 @@ gsk_gl_render_job_visit_rounded_clip_node (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_render_job_draw_offscreen (job, &node->bounds, &offscreen);
gsk_gl_render_job_end_draw (job);
}
@@ -2138,7 +2123,6 @@ gsk_gl_render_job_visit_transform_node (GskGLRenderJob *job,
offscreen.texture_id,
linear_filter ? GL_LINEAR : GL_NEAREST,
linear_filter ? GL_LINEAR : GL_NEAREST);
job->source_is_glyph_atlas = FALSE;
gsk_gl_render_job_draw_offscreen (job, &child->bounds, &offscreen);
gsk_gl_render_job_end_draw (job);
}
@@ -2348,7 +2332,6 @@ gsk_gl_render_job_visit_blurred_inset_shadow_node (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
blurred_texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_render_job_draw_offscreen (job, &node->bounds, &offscreen);
gsk_gl_render_job_end_draw (job);
}
@@ -2614,7 +2597,6 @@ gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
blurred_texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_program_set_uniform_rounded_rect (job->current_program,
UNIFORM_OUTSET_SHADOW_OUTLINE_RECT, 0,
&transformed_outline);
@@ -2640,7 +2622,6 @@ gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
blurred_texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_program_set_uniform_rounded_rect (job->current_program,
UNIFORM_OUTSET_SHADOW_OUTLINE_RECT, 0,
&transformed_outline);
@@ -2806,8 +2787,8 @@ static inline gboolean G_GNUC_PURE
equal_texture_nodes (const GskRenderNode *node1,
const GskRenderNode *node2)
{
if (GSK_RENDER_NODE_TYPE (node1) != GSK_TEXTURE_NODE ||
GSK_RENDER_NODE_TYPE (node2) != GSK_TEXTURE_NODE)
if (gsk_render_node_get_node_type (node1) != GSK_TEXTURE_NODE ||
gsk_render_node_get_node_type (node2) != GSK_TEXTURE_NODE)
return FALSE;
if (gsk_texture_node_get_texture (node1) !=
@@ -2878,7 +2859,6 @@ gsk_gl_render_job_visit_cross_fade_node (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE1,
offscreen_end.texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_program_set_uniform1f (job->current_program,
UNIFORM_CROSS_FADE_PROGRESS, 0,
progress);
@@ -2925,7 +2905,6 @@ gsk_gl_render_job_visit_opacity_node (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_render_job_draw_offscreen (job, &node->bounds, &offscreen);
gsk_gl_render_job_end_draw (job);
}
@@ -3067,7 +3046,6 @@ gsk_gl_render_job_visit_text_node (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
texture_id);
job->source_is_glyph_atlas = TRUE;
last_texture = texture_id;
}
@@ -3110,7 +3088,7 @@ gsk_gl_render_job_visit_shadow_node (GskGLRenderJob *job,
/* Shadow nodes recolor every pixel of the source texture, but leave the alpha in tact.
* If the child is a color matrix node that doesn't touch the alpha, we can throw that away. */
if (GSK_RENDER_NODE_TYPE (shadow_child) == GSK_COLOR_MATRIX_NODE &&
if (gsk_render_node_get_node_type (shadow_child) == GSK_COLOR_MATRIX_NODE &&
!color_matrix_modifies_alpha (shadow_child))
shadow_child = gsk_color_matrix_node_get_child (shadow_child);
@@ -3130,7 +3108,7 @@ gsk_gl_render_job_visit_shadow_node (GskGLRenderJob *job,
continue;
if (shadow->radius == 0 &&
GSK_RENDER_NODE_TYPE (shadow_child) == GSK_TEXT_NODE)
gsk_render_node_get_node_type (shadow_child) == GSK_TEXT_NODE)
{
if (dx != 0 || dy != 0)
{
@@ -3164,6 +3142,10 @@ gsk_gl_render_job_visit_shadow_node (GskGLRenderJob *job,
offscreen.was_offscreen = TRUE;
}
else if (dx == 0 && dy == 0)
{
continue; /* Invisible anyway */
}
else
{
offscreen.bounds = &shadow_child->bounds;
@@ -3184,7 +3166,6 @@ gsk_gl_render_job_visit_shadow_node (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id);
job->source_is_glyph_atlas = FALSE;
rgba_to_half (&shadow->color, color);
gsk_gl_render_job_draw_offscreen_with_color (job, &bounds, &offscreen, color);
gsk_gl_render_job_end_draw (job);
@@ -3241,7 +3222,6 @@ gsk_gl_render_job_visit_blur_node (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_render_job_draw_coords (job,
min_x, min_y, max_x, max_y,
0, 1, 1, 0,
@@ -3292,7 +3272,6 @@ gsk_gl_render_job_visit_blend_node (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
bottom_offscreen.texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_render_job_draw_offscreen (job, &node->bounds, &bottom_offscreen);
gsk_gl_render_job_end_draw (job);
}
@@ -3315,7 +3294,6 @@ gsk_gl_render_job_visit_blend_node (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE1,
top_offscreen.texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_program_set_uniform1i (job->current_program,
UNIFORM_BLEND_MODE, 0,
gsk_blend_node_get_blend_mode (node));
@@ -3378,7 +3356,6 @@ gsk_gl_render_job_visit_mask_node (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE1,
mask_offscreen.texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_program_set_uniform1i (job->current_program,
UNIFORM_MASK_MODE, 0,
gsk_mask_node_get_mask_mode (node));
@@ -3415,7 +3392,6 @@ gsk_gl_render_job_visit_color_matrix_node (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_program_set_uniform_matrix (job->current_program,
UNIFORM_COLOR_MATRIX_COLOR_MATRIX, 0,
gsk_color_matrix_node_get_color_matrix (node));
@@ -3498,7 +3474,6 @@ gsk_gl_render_job_visit_gl_shader_node (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0 + i,
offscreens[i].texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_program_set_uniform2f (program,
UNIFORM_CUSTOM_SIZE, 0,
node->bounds.size.width,
@@ -3633,7 +3608,6 @@ gsk_gl_render_job_visit_texture (GskGLRenderJob *job,
offscreen.has_mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR,
GL_LINEAR,
offscreen.sync);
job->source_is_glyph_atlas = FALSE;
gsk_gl_render_job_draw_offscreen (job, bounds, &offscreen);
gsk_gl_render_job_end_draw (job);
}
@@ -3671,7 +3645,6 @@ gsk_gl_render_job_visit_texture (GskGLRenderJob *job,
slice->texture_id,
use_mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR,
GL_LINEAR);
job->source_is_glyph_atlas = FALSE;
gsk_gl_render_job_draw_coords (job,
x1, y1, x2, y2,
@@ -3718,6 +3691,12 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
GskTextureKey key;
guint texture_id;
if (filter == GSK_SCALING_FILTER_LINEAR)
{
gsk_gl_render_job_visit_texture (job, texture, bounds);
return;
}
gsk_gl_render_job_untransform_bounds (job, &job->current_clip->rect.bounds, &clip_rect);
if (!graphene_rect_intersection (bounds, &clip_rect, &clip_rect))
@@ -3784,7 +3763,6 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
min_filter,
mag_filter,
sync);
job->source_is_glyph_atlas = FALSE;
gsk_gl_render_job_draw_coords (job,
0, 0, clip_rect.size.width, clip_rect.size.height,
u0, v0, u1, v1,
@@ -3826,7 +3804,6 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
slice->texture_id,
min_filter,
mag_filter);
job->source_is_glyph_atlas = FALSE;
gsk_gl_render_job_draw_coords (job,
slice_bounds.origin.x,
slice_bounds.origin.y,
@@ -3859,7 +3836,6 @@ render_texture:
GL_TEXTURE_2D,
GL_TEXTURE0,
texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_render_job_draw_coords (job,
job->offset_x + clip_rect.origin.x,
job->offset_y + clip_rect.origin.y,
@@ -3912,7 +3888,6 @@ gsk_gl_render_job_visit_repeat_node (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_program_set_uniform4f (job->current_program,
UNIFORM_REPEAT_CHILD_BOUNDS, 0,
(node->bounds.origin.x - child_bounds->origin.x) / child_bounds->size.width,
@@ -3947,7 +3922,7 @@ gsk_gl_render_job_visit_node (GskGLRenderJob *job,
if (!gsk_gl_render_job_update_clip (job, &node->bounds, &has_clip))
return;
switch (GSK_RENDER_NODE_TYPE (node))
switch (gsk_render_node_get_node_type (node))
{
case GSK_BLEND_NODE:
gsk_gl_render_job_visit_blend_node (job, node);
@@ -4000,12 +3975,12 @@ gsk_gl_render_job_visit_node (GskGLRenderJob *job,
if (i + 1 < n_children &&
job->current_clip->is_fully_contained &&
GSK_RENDER_NODE_TYPE (child) == GSK_ROUNDED_CLIP_NODE)
gsk_render_node_get_node_type (child) == GSK_ROUNDED_CLIP_NODE)
{
const GskRenderNode *grandchild = gsk_rounded_clip_node_get_child (child);
const GskRenderNode *child2 = children[i + 1];
if (GSK_RENDER_NODE_TYPE (grandchild) == GSK_COLOR_NODE &&
GSK_RENDER_NODE_TYPE (child2) == GSK_BORDER_NODE &&
if (gsk_render_node_get_node_type (grandchild) == GSK_COLOR_NODE &&
gsk_render_node_get_node_type (child2) == GSK_BORDER_NODE &&
gsk_border_node_get_uniform_color (child2) &&
rounded_rect_equal (gsk_rounded_clip_node_get_clip (child),
gsk_border_node_get_outline (child2)))
@@ -4118,6 +4093,14 @@ gsk_gl_render_job_visit_node (GskGLRenderJob *job,
gsk_gl_render_job_visit_as_fallback (job, node);
break;
case GSK_FILL_NODE:
gsk_gl_render_job_visit_as_fallback (job, node);
break;
case GSK_STROKE_NODE:
gsk_gl_render_job_visit_as_fallback (job, node);
break;
case GSK_NOT_A_RENDER_NODE:
default:
g_assert_not_reached ();
@@ -4151,7 +4134,7 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job,
return FALSE;
}
if (GSK_RENDER_NODE_TYPE (node) == GSK_TEXTURE_NODE &&
if (gsk_render_node_get_node_type (node) == GSK_TEXTURE_NODE &&
!offscreen->force_offscreen)
{
GdkTexture *texture = gsk_texture_node_get_texture (node);
@@ -4399,7 +4382,6 @@ gsk_gl_render_job_render_flipped (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_render_job_draw_rect (job, &job->viewport);
gsk_gl_render_job_end_draw (job);
}
@@ -4524,8 +4506,8 @@ gsk_gl_render_job_new (GskGLDriver *driver,
job = g_new0 (GskGLRenderJob, 1);
job->driver = g_object_ref (driver);
job->command_queue = job->driver->command_queue;
clips_init (&job->clip);
modelviews_init (&job->modelview);
job->clip = g_array_sized_new (FALSE, FALSE, sizeof (GskGLRenderClip), 16);
job->modelview = g_array_sized_new (FALSE, FALSE, sizeof (GskGLRenderModelview), 16);
job->framebuffer = framebuffer;
job->clear_framebuffer = !!clear_framebuffer;
job->default_framebuffer = default_framebuffer;
@@ -4575,16 +4557,16 @@ gsk_gl_render_job_free (GskGLRenderJob *job)
job->current_modelview = NULL;
job->current_clip = NULL;
while (job->modelview.end > job->modelview.start)
while (job->modelview->len > 0)
{
GskGLRenderModelview *modelview = job->modelview.end-1;
GskGLRenderModelview *modelview = &g_array_index (job->modelview, GskGLRenderModelview, job->modelview->len-1);
g_clear_pointer (&modelview->transform, gsk_transform_unref);
job->modelview.end--;
job->modelview->len--;
}
g_clear_object (&job->driver);
g_clear_pointer (&job->region, cairo_region_destroy);
modelviews_clear (&job->modelview);
clips_clear (&job->clip);
g_clear_pointer (&job->modelview, g_array_unref);
g_clear_pointer (&job->clip, g_array_unref);
g_free (job);
}
+3 -3
View File
@@ -75,10 +75,10 @@ void main() {
if (offset < next_offset) {
float f = (offset - curr_offset) / (next_offset - curr_offset);
vec4 curr_color = get_color(i);
vec4 next_color = get_color(i + 1);
vec4 curr_color = gsk_premultiply(get_color(i));
vec4 next_color = gsk_premultiply(get_color(i + 1));
vec4 color = mix(curr_color, next_color, f);
gskSetScaledOutputColor(gsk_premultiply(color), u_alpha);
gskSetScaledOutputColor(color, u_alpha);
return;
}
}
+3 -3
View File
@@ -97,10 +97,10 @@ void main() {
if (offset < next_offset) {
float f = (offset - curr_offset) / (next_offset - curr_offset);
vec4 curr_color = get_color(i);
vec4 next_color = get_color(i + 1);
vec4 curr_color = gsk_premultiply(get_color(i));
vec4 next_color = gsk_premultiply(get_color(i + 1));
vec4 color = mix(curr_color, next_color, f);
gskSetScaledOutputColor(gsk_premultiply (color), u_alpha);
gskSetScaledOutputColor(color, u_alpha);
return;
}
}
-2
View File
@@ -28,8 +28,6 @@ gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount)
if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy;
if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw;
if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw;
new_corner_points1 = clamp (new_corner_points1, new_bounds.xyxy, new_bounds.zwzw);
new_corner_points2 = clamp (new_corner_points2, new_bounds.xyxy, new_bounds.zwzw);
return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2);
}
+3 -3
View File
@@ -77,10 +77,10 @@ void main() {
if (offset < next_offset) {
float f = (offset - curr_offset) / (next_offset - curr_offset);
vec4 curr_color = get_color(i);
vec4 next_color = get_color(i + 1);
vec4 curr_color = gsk_premultiply(get_color(i));
vec4 next_color = gsk_premultiply(get_color(i + 1));
vec4 color = mix(curr_color, next_color, f);
gskSetScaledOutputColor(gsk_premultiply(color), u_alpha);
gskSetScaledOutputColor(color, u_alpha);
return;
}
}
+5
View File
@@ -20,9 +20,14 @@
#define __GSK_H_INSIDE__
#include <gsk/gskenums.h>
#include <gsk/gskpath.h>
#include <gsk/gskpathbuilder.h>
#include <gsk/gskpathmeasure.h>
#include <gsk/gskpathpoint.h>
#include <gsk/gskrenderer.h>
#include <gsk/gskrendernode.h>
#include <gsk/gskroundedrect.h>
#include <gsk/gskstroke.h>
#include <gsk/gsktransform.h>
#include <gsk/gskglshader.h>
+115
View File
@@ -0,0 +1,115 @@
#pragma once
#include <gsk/gsktypes.h>
G_BEGIN_DECLS
typedef struct _GskBoundingBox GskBoundingBox;
struct _GskBoundingBox {
graphene_point_t min;
graphene_point_t max;
};
static inline GskBoundingBox *
gsk_bounding_box_init (GskBoundingBox *self,
const graphene_point_t *a,
const graphene_point_t *b)
{
self->min.x = MIN (a->x, b->x);
self->min.y = MIN (a->y, b->y);
self->max.x = MAX (a->x, b->x);
self->max.y = MAX (a->y, b->y);
return self;
}
static inline GskBoundingBox *
gsk_bounding_box_init_copy (GskBoundingBox *self,
const GskBoundingBox *src)
{
self->min = src->min;
self->max = src->max;
return self;
}
static inline GskBoundingBox *
gsk_bounding_box_init_from_rect (GskBoundingBox *self,
const graphene_rect_t *bounds)
{
self->min = bounds->origin;
self->max.x = bounds->origin.x + bounds->size.width;
self->max.y = bounds->origin.y + bounds->size.height;
return self;
}
static inline void
gsk_bounding_box_expand (GskBoundingBox *self,
const graphene_point_t *p)
{
self->min.x = MIN (self->min.x, p->x);
self->min.y = MIN (self->min.y, p->y);
self->max.x = MAX (self->max.x, p->x);
self->max.y = MAX (self->max.y, p->y);
}
static inline graphene_rect_t *
gsk_bounding_box_to_rect (const GskBoundingBox *self,
graphene_rect_t *rect)
{
rect->origin = self->min;
rect->size.width = self->max.x - self->min.x;
rect->size.height = self->max.y - self->min.y;
return rect;
}
static inline gboolean
gsk_bounding_box_contains_point (const GskBoundingBox *self,
const graphene_point_t *p)
{
return self->min.x <= p->x && p->x <= self->max.x &&
self->min.y <= p->y && p->y <= self->max.y;
}
static inline gboolean
gsk_bounding_box_contains_point_with_epsilon (const GskBoundingBox *self,
const graphene_point_t *p,
float epsilon)
{
return self->min.x - epsilon <= p->x && p->x <= self->max.x + epsilon &&
self->min.y - epsilon <= p->y && p->y <= self->max.y + epsilon;
}
static inline gboolean
gsk_bounding_box_intersection (const GskBoundingBox *a,
const GskBoundingBox *b,
GskBoundingBox *res)
{
graphene_point_t min, max;
min.x = MAX (a->min.x, b->min.x);
min.y = MAX (a->min.y, b->min.y);
max.x = MIN (a->max.x, b->max.x);
max.y = MIN (a->max.y, b->max.y);
if (res)
gsk_bounding_box_init (res, &min, &max);
return min.x <= max.x && min.y <= max.y;
}
static inline void
gsk_bounding_box_union (const GskBoundingBox *a,
const GskBoundingBox *b,
GskBoundingBox *res)
{
graphene_point_t min, max;
min.x = MIN (a->min.x, b->min.x);
min.y = MIN (a->min.y, b->min.y);
max.x = MAX (a->max.x, b->max.x);
max.y = MAX (a->max.y, b->max.y);
gsk_bounding_box_init (res, &min, &max);
}
G_END_DECLS
+1188
View File
File diff suppressed because it is too large Load Diff
+111
View File
@@ -0,0 +1,111 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#pragma once
#include "gskpathprivate.h"
#include "gskpathpointprivate.h"
#include "gskpathopprivate.h"
#include "gskboundingboxprivate.h"
G_BEGIN_DECLS
GskContour * gsk_standard_contour_new (GskPathFlags flags,
const graphene_point_t *points,
gsize n_points,
const gskpathop *ops,
gsize n_ops,
gssize offset);
void gsk_contour_copy (GskContour * dest,
const GskContour *src);
GskContour * gsk_contour_dup (const GskContour *src);
GskContour * gsk_contour_reverse (const GskContour *src);
gsize gsk_contour_get_size (const GskContour *self);
GskPathFlags gsk_contour_get_flags (const GskContour *self);
void gsk_contour_print (const GskContour *self,
GString *string);
gboolean gsk_contour_get_bounds (const GskContour *self,
GskBoundingBox *bounds);
gboolean gsk_contour_get_stroke_bounds (const GskContour *self,
const GskStroke *stroke,
GskBoundingBox *bounds);
gboolean gsk_contour_foreach (const GskContour *self,
float tolerance,
GskPathForeachFunc func,
gpointer user_data);
void gsk_contour_get_start_end (const GskContour *self,
graphene_point_t *start,
graphene_point_t *end);
int gsk_contour_get_winding (const GskContour *self,
const graphene_point_t *point);
gboolean gsk_contour_get_closest_point (const GskContour *self,
const graphene_point_t *point,
float threshold,
GskRealPathPoint *result,
float *out_dist);
void gsk_contour_get_position (const GskContour *self,
GskRealPathPoint *point,
graphene_point_t *pos);
void gsk_contour_get_tangent (const GskContour *self,
GskRealPathPoint *point,
GskPathDirection direction,
graphene_vec2_t *tangent);
float gsk_contour_get_curvature (const GskContour *self,
GskRealPathPoint *point,
graphene_point_t *center);
gpointer gsk_contour_init_measure (const GskContour *self,
float tolerance,
float *out_length);
void gsk_contour_free_measure (const GskContour *self,
gpointer data);
int gsk_contour_point_compare (const GskContour *self,
GskRealPathPoint *p1,
GskRealPathPoint *p2);
void gsk_contour_add_segment (const GskContour *self,
GskPathBuilder *builder,
gboolean emit_move_to,
GskRealPathPoint *start,
GskRealPathPoint *end);
void gsk_contour_get_point (const GskContour *self,
gpointer measure_data,
float offset,
GskRealPathPoint *result);
void gsk_contour_get_start_point (const GskContour *self,
GskRealPathPoint *result);
void gsk_contour_get_end_point (const GskContour *self,
GskRealPathPoint *result);
gboolean gsk_contour_get_previous_point (const GskContour *self,
GskRealPathPoint *point,
GskRealPathPoint *result);
gboolean gsk_contour_get_next_point (const GskContour *self,
GskRealPathPoint *point,
GskRealPathPoint *result);
float gsk_contour_get_distance (const GskContour *self,
GskRealPathPoint *point,
gpointer measure_data);
G_END_DECLS
+1533
View File
File diff suppressed because it is too large Load Diff
+157
View File
@@ -0,0 +1,157 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#pragma once
#include "gskpathopprivate.h"
#include "gskpath.h"
#include "gskboundingboxprivate.h"
G_BEGIN_DECLS
typedef gpointer gskpathop;
typedef union _GskCurve GskCurve;
typedef struct _GskLineCurve GskLineCurve;
typedef struct _GskQuadCurve GskQuadCurve;
typedef struct _GskCubicCurve GskCubicCurve;
struct _GskLineCurve
{
GskPathOperation op;
gboolean padding;
graphene_point_t points[2];
};
struct _GskQuadCurve
{
GskPathOperation op;
gboolean has_coefficients;
graphene_point_t points[3];
graphene_point_t coeffs[3];
};
struct _GskCubicCurve
{
GskPathOperation op;
gboolean has_coefficients;
graphene_point_t points[4];
graphene_point_t coeffs[4];
};
union _GskCurve
{
GskPathOperation op;
GskLineCurve line;
GskQuadCurve quad;
GskCubicCurve cubic;
};
typedef enum {
GSK_CURVE_LINE_REASON_STRAIGHT,
GSK_CURVE_LINE_REASON_SHORT
} GskCurveLineReason;
typedef gboolean (* GskCurveAddLineFunc) (const graphene_point_t *from,
const graphene_point_t *to,
float from_progress,
float to_progress,
GskCurveLineReason reason,
gpointer user_data);
typedef gboolean (* GskCurveAddCurveFunc) (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
gpointer user_data);
void gsk_curve_init (GskCurve *curve,
gskpathop op);
void gsk_curve_init_foreach (GskCurve *curve,
GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts);
void gsk_curve_print (const GskCurve *curve,
GString *string);
char * gsk_curve_to_string (const GskCurve *curve);
gskpathop gsk_curve_pathop (const GskCurve *curve);
const graphene_point_t *gsk_curve_get_start_point (const GskCurve *curve);
const graphene_point_t *gsk_curve_get_end_point (const GskCurve *curve);
void gsk_curve_get_start_tangent (const GskCurve *curve,
graphene_vec2_t *tangent);
void gsk_curve_get_end_tangent (const GskCurve *curve,
graphene_vec2_t *tangent);
void gsk_curve_get_point (const GskCurve *curve,
float progress,
graphene_point_t *pos);
void gsk_curve_get_tangent (const GskCurve *curve,
float progress,
graphene_vec2_t *tangent);
void gsk_curve_reverse (const GskCurve *curve,
GskCurve *reverse);
void gsk_curve_split (const GskCurve *curve,
float progress,
GskCurve *start,
GskCurve *end);
void gsk_curve_segment (const GskCurve *curve,
float start,
float end,
GskCurve *segment);
gboolean gsk_curve_decompose (const GskCurve *curve,
float tolerance,
GskCurveAddLineFunc add_line_func,
gpointer user_data);
gboolean gsk_curve_decompose_curve (const GskCurve *curve,
GskPathForeachFlags flags,
float tolerance,
GskCurveAddCurveFunc add_curve_func,
gpointer user_data);
#define gsk_curve_builder_to(curve, builder) gsk_path_builder_pathop_to ((builder), gsk_curve_pathop (curve))
float gsk_curve_get_curvature (const GskCurve *curve,
float t,
graphene_point_t *center);
void gsk_curve_get_bounds (const GskCurve *curve,
GskBoundingBox *bounds);
void gsk_curve_get_tight_bounds (const GskCurve *curve,
GskBoundingBox *bounds);
int gsk_curve_get_crossing (const GskCurve *curve,
const graphene_point_t *point);
gboolean gsk_curve_get_closest_point (const GskCurve *curve,
const graphene_point_t *point,
float threshold,
float *out_dist,
float *out_t);
G_END_DECLS
+125 -1
View File
@@ -42,6 +42,8 @@
* @GSK_REPEAT_NODE: A node that repeats the child's contents
* @GSK_CLIP_NODE: A node that clips its child to a rectangular area
* @GSK_ROUNDED_CLIP_NODE: A node that clips its child to a rounded rectangle
* @GSK_FILL_NODE: A node that fills a path
* @GSK_STROKE_NODE: A node that strokes a path
* @GSK_SHADOW_NODE: A node that draws a shadow below its child
* @GSK_BLEND_NODE: A node that blends two children together
* @GSK_CROSS_FADE_NODE: A node that cross-fades between two children
@@ -74,6 +76,8 @@ typedef enum {
GSK_REPEAT_NODE,
GSK_CLIP_NODE,
GSK_ROUNDED_CLIP_NODE,
GSK_FILL_NODE,
GSK_STROKE_NODE,
GSK_SHADOW_NODE,
GSK_BLEND_NODE,
GSK_CROSS_FADE_NODE,
@@ -170,6 +174,127 @@ typedef enum {
GSK_CORNER_BOTTOM_LEFT
} GskCorner;
/**
* GskFillRule:
* @GSK_FILL_RULE_WINDING: If the path crosses the ray from
* left-to-right, counts +1. If the path crosses the ray
* from right to left, counts -1. (Left and right are determined
* from the perspective of looking along the ray from the starting
* point.) If the total count is non-zero, the point will be filled.
* @GSK_FILL_RULE_EVEN_ODD: Counts the total number of
* intersections, without regard to the orientation of the contour. If
* the total number of intersections is odd, the point will be
* filled.
*
* `GskFillRule` is used to select how paths are filled.
*
* Whether or not a point is included in the fill is determined by taking
* a ray from that point to infinity and looking at intersections with the
* path. The ray can be in any direction, as long as it doesn't pass through
* the end point of a segment or have a tricky intersection such as
* intersecting tangent to the path.
*
* (Note that filling is not actually implemented in this way. This
* is just a description of the rule that is applied.)
*
* New entries may be added in future versions.
*
* Since: 4.14
*/
typedef enum {
GSK_FILL_RULE_WINDING,
GSK_FILL_RULE_EVEN_ODD
} GskFillRule;
/**
* GskLineCap:
* @GSK_LINE_CAP_BUTT: Start and stop the line exactly at the start
* and end point
* @GSK_LINE_CAP_ROUND: Use a round ending, the center of the circle
* is the start or end point
* @GSK_LINE_CAP_SQUARE: use squared ending, the center of the square
* is the start or end point
*
* Specifies how to render the start and end points of contours or
* dashes when stroking.
*
* The default line cap style is `GSK_LINE_CAP_BUTT`.
*
* New entries may be added in future versions.
*
* Since: 4.14
*/
typedef enum {
GSK_LINE_CAP_BUTT,
GSK_LINE_CAP_ROUND,
GSK_LINE_CAP_SQUARE
} GskLineCap;
/**
* GskLineJoin:
* @GSK_LINE_JOIN_MITER: Use a sharp angled corner
* @GSK_LINE_JOIN_ROUND: Use a round join, the center of the circle is
* the join point
* @GSK_LINE_JOIN_BEVEL: use a cut-off join, the join is cut off at half
* the line width from the joint point
*
* Specifies how to render the junction of two lines when stroking.
*
* The default line join style is `GSK_LINE_JOIN_MITER`.
*
* New entries may be added in future versions.
*
* Since: 4.14
*/
typedef enum {
GSK_LINE_JOIN_MITER,
GSK_LINE_JOIN_ROUND,
GSK_LINE_JOIN_BEVEL,
} GskLineJoin;
/**
* GskPathOperation:
* @GSK_PATH_MOVE: A move-to operation, with 1 point describing the target point.
* @GSK_PATH_CLOSE: A close operation ending the current contour with a line back
* to the starting point. Two points describe the start and end of the line.
* @GSK_PATH_LINE: A line-to operation, with 2 points describing the start and
* end point of a straight line.
* @GSK_PATH_QUAD: A curve-to operation describing a quadratic Bézier curve
* with 3 points describing the start point, the control point and the end
* point of the curve.
* @GSK_PATH_CUBIC: A curve-to operation describing a cubic Bézier curve with 4
* points describing the start point, the two control points and the end point
* of the curve.
*
* Path operations are used to described segments of a `GskPath`.
*
* More values may be added in the future.
*
* Since: 4.14
*/
typedef enum {
GSK_PATH_MOVE,
GSK_PATH_CLOSE,
GSK_PATH_LINE,
GSK_PATH_QUAD,
GSK_PATH_CUBIC,
} GskPathOperation;
/**
* GskPathDirection:
* @GSK_PATH_START: The side that leads to the start of the path
* @GSK_PATH_END: The side that leads to the end of the path
*
* The values of the `GskPathDirection` enum are used to pick one
* of the two sides of the path that at a given point on the path.
*
* Since: 4.14
*/
typedef enum {
GSK_PATH_START,
GSK_PATH_END
} GskPathDirection;
/**
* GskSerializationError:
* @GSK_SERIALIZATION_UNSUPPORTED_FORMAT: The format can not be identified
@@ -274,4 +399,3 @@ typedef enum
GSK_MASK_MODE_LUMINANCE,
GSK_MASK_MODE_INVERTED_LUMINANCE
} GskMaskMode;
+1564
View File
File diff suppressed because it is too large Load Diff
+144
View File
@@ -0,0 +1,144 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#pragma once
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gsk/gsk.h> can be included directly."
#endif
#include <gsk/gsktypes.h>
G_BEGIN_DECLS
/**
* GskPathForeachFlags:
* @GSK_PATH_FOREACH_ALLOW_ONLY_LINES: The default behavior, only allow lines.
* @GSK_PATH_FOREACH_ALLOW_QUAD: Allow emission of `GSK_PATH_QUAD` operations
* @GSK_PATH_FOREACH_ALLOW_CUBIC: Allow emission of `GSK_PATH_CUBIC` operations.
* @GSK_PATH_FOREACH_ALLOW_ANY: Allow emission of any kind of operation.
*
* Flags that can be passed to gsk_path_foreach() to enable additional
* features.
*
* By default, [method@Gsk.Path.foreach] will only emit a path with all operations
* flattened to straight lines to allow for maximum compatibility. The only
* operations emitted will be `GSK_PATH_MOVE`, `GSK_PATH_LINE` and `GSK_PATH_CLOSE`.
*/
typedef enum
{
GSK_PATH_FOREACH_ALLOW_ONLY_LINES = 0,
GSK_PATH_FOREACH_ALLOW_QUAD = (1 << 0),
GSK_PATH_FOREACH_ALLOW_CUBIC = (1 << 1),
} GskPathForeachFlags;
/**
* GskPathForeachFunc:
* @op: The operation to perform
* @pts: The points of the operation
* @n_pts: The number of points
* @user_data: The user data provided with the function
*
* Prototype of the callback to iterate throught the operations of
* a path.
*
* Returns: %TRUE to continue evaluating the path, %FALSE to
* immediately abort and not call the function again.
*/
typedef gboolean (* GskPathForeachFunc) (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
gpointer user_data);
#define GSK_TYPE_PATH (gsk_path_get_type ())
GDK_AVAILABLE_IN_4_14
GType gsk_path_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_14
GskPath * gsk_path_ref (GskPath *self);
GDK_AVAILABLE_IN_4_14
void gsk_path_unref (GskPath *self);
GDK_AVAILABLE_IN_4_14
void gsk_path_print (GskPath *self,
GString *string);
GDK_AVAILABLE_IN_4_14
char * gsk_path_to_string (GskPath *self);
GDK_AVAILABLE_IN_4_14
GskPath * gsk_path_parse (const char *string);
GDK_AVAILABLE_IN_4_14
void gsk_path_to_cairo (GskPath *self,
cairo_t *cr);
GDK_AVAILABLE_IN_4_14
gboolean gsk_path_is_empty (GskPath *self);
GDK_AVAILABLE_IN_4_14
gboolean gsk_path_is_closed (GskPath *self);
GDK_AVAILABLE_IN_4_14
gboolean gsk_path_get_bounds (GskPath *self,
graphene_rect_t *bounds);
GDK_AVAILABLE_IN_4_14
gboolean gsk_path_get_stroke_bounds (GskPath *self,
const GskStroke *stroke,
graphene_rect_t *bounds);
GDK_AVAILABLE_IN_4_14
gboolean gsk_path_in_fill (GskPath *self,
const graphene_point_t *point,
GskFillRule fill_rule);
GDK_AVAILABLE_IN_4_14
gboolean gsk_path_get_closest_point (GskPath *self,
const graphene_point_t *point,
float threshold,
GskPathPoint *result);
GDK_AVAILABLE_IN_4_14
gboolean gsk_path_get_previous_point (GskPath *self,
const GskPathPoint *point,
GskPathPoint *result);
GDK_AVAILABLE_IN_4_14
gboolean gsk_path_get_next_point (GskPath *self,
const GskPathPoint *point,
GskPathPoint *result);
GDK_AVAILABLE_IN_4_14
gboolean gsk_path_get_start_point (GskPath *self,
GskPathPoint *result);
GDK_AVAILABLE_IN_4_14
gboolean gsk_path_get_end_point (GskPath *self,
GskPathPoint *result);
GDK_AVAILABLE_IN_4_14
gboolean gsk_path_foreach (GskPath *self,
GskPathForeachFlags flags,
GskPathForeachFunc func,
gpointer user_data);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskPath, gsk_path_unref)
G_END_DECLS
+985
View File
@@ -0,0 +1,985 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include <math.h>
#include "gskpathbuilder.h"
#include "gskpathprivate.h"
#include "gskcontourprivate.h"
#include "gsksplineprivate.h"
/**
* GskPathBuilder:
*
* `GskPathBuilder` is an auxiliary object for constructing
* `GskPath` objects.
*
* A path is constructed like this:
*
* |[<!-- language="C" -->
* GskPath *
* construct_path (void)
* {
* GskPathBuilder *builder;
*
* builder = gsk_path_builder_new ();
*
* // add contours to the path here
*
* return gsk_path_builder_free_to_path (builder);
* ]|
*
* Adding contours to the path can be done in two ways.
* The easiest option is to use the `gsk_path_builder_add_*` group
* of functions that add predefined contours to the current path,
* either common shapes like [method@Gsk.PathBuilder.add_circle]
* or by adding from other paths like [method@Gsk.PathBuilder.add_path].
*
* The other option is to define each line and curve manually with
* the `gsk_path_builder_*_to` group of functions. You start with
* a call to [method@Gsk.PathBuilder.move_to] to set the starting point
* and then use multiple calls to any of the drawing functions to
* move the pen along the plane. Once you are done, you can call
* [method@Gsk.PathBuilder.close] to close the path by connecting it
* back with a line to the starting point.
*
* This is similar for how paths are drawn in Cairo.
*/
struct _GskPathBuilder
{
int ref_count;
GSList *contours; /* (reverse) list of already recorded contours */
GskPathFlags flags; /* flags for the current path */
graphene_point_t current_point; /* the point all drawing ops start from */
GArray *ops; /* operations for current contour - size == 0 means no current contour */
GArray *points; /* points for the operations */
};
G_DEFINE_BOXED_TYPE (GskPathBuilder,
gsk_path_builder,
gsk_path_builder_ref,
gsk_path_builder_unref)
/**
* gsk_path_builder_new:
*
* Create a new `GskPathBuilder` object.
*
* The resulting builder would create an empty `GskPath`.
* Use addition functions to add types to it.
*
* Returns: a new `GskPathBuilder`
*
* Since: 4.14
*/
GskPathBuilder *
gsk_path_builder_new (void)
{
GskPathBuilder *self;
self = g_slice_new0 (GskPathBuilder);
self->ref_count = 1;
self->ops = g_array_new (FALSE, FALSE, sizeof (gskpathop));
self->points = g_array_new (FALSE, FALSE, sizeof (graphene_point_t));
/* Be explicit here */
self->current_point = GRAPHENE_POINT_INIT (0, 0);
return self;
}
/**
* gsk_path_builder_ref:
* @self: a `GskPathBuilder`
*
* Acquires a reference on the given builder.
*
* This function is intended primarily for language bindings.
* `GskPathBuilder` objects should not be kept around.
*
* Returns: (transfer none): the given `GskPathBuilder` with
* its reference count increased
*
* Since: 4.14
*/
GskPathBuilder *
gsk_path_builder_ref (GskPathBuilder *self)
{
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (self->ref_count > 0, NULL);
self->ref_count += 1;
return self;
}
/* We're cheating here. Out pathops are relative to the NULL pointer,
* so that we can not care about the points GArray reallocating itself
* until we create the contour.
* This does however mean that we need to not use gsk_pathop_get_points()
* without offsetting the returned pointer.
*/
static inline gskpathop
gsk_pathop_encode_index (GskPathOperation op,
gsize index)
{
return gsk_pathop_encode (op, ((graphene_point_t *) NULL) + index);
}
static void
gsk_path_builder_ensure_current (GskPathBuilder *self)
{
if (self->ops->len != 0)
return;
self->flags = GSK_PATH_FLAT;
g_array_append_vals (self->ops, (gskpathop[1]) { gsk_pathop_encode_index (GSK_PATH_MOVE, 0) }, 1);
g_array_append_val (self->points, self->current_point);
}
static void
gsk_path_builder_append_current (GskPathBuilder *self,
GskPathOperation op,
gsize n_points,
const graphene_point_t *points)
{
gsk_path_builder_ensure_current (self);
g_array_append_vals (self->ops, (gskpathop[1]) { gsk_pathop_encode_index (op, self->points->len - 1) }, 1);
g_array_append_vals (self->points, points, n_points);
self->current_point = points[n_points - 1];
}
static void
gsk_path_builder_end_current (GskPathBuilder *self)
{
GskContour *contour;
if (self->ops->len == 0)
return;
contour = gsk_standard_contour_new (self->flags,
(graphene_point_t *) self->points->data,
self->points->len,
(gskpathop *) self->ops->data,
self->ops->len,
(graphene_point_t *) self->points->data - (graphene_point_t *) NULL);
g_array_set_size (self->ops, 0);
g_array_set_size (self->points, 0);
/* do this at the end to avoid inflooping when add_contour calls back here */
gsk_path_builder_add_contour (self, contour);
}
static void
gsk_path_builder_clear (GskPathBuilder *self)
{
gsk_path_builder_end_current (self);
g_slist_free_full (self->contours, g_free);
self->contours = NULL;
}
/**
* gsk_path_builder_unref:
* @self: a `GskPathBuilder`
*
* Releases a reference on the given builder.
*
* Since: 4.14
*/
void
gsk_path_builder_unref (GskPathBuilder *self)
{
g_return_if_fail (self != NULL);
g_return_if_fail (self->ref_count > 0);
self->ref_count -= 1;
if (self->ref_count > 0)
return;
gsk_path_builder_clear (self);
g_array_unref (self->ops);
g_array_unref (self->points);
g_slice_free (GskPathBuilder, self);
}
/**
* gsk_path_builder_free_to_path: (skip)
* @self: a `GskPathBuilder`
*
* Creates a new `GskPath` from the current state of the
* given builder, and frees the @builder instance.
*
* Returns: (transfer full): the newly created `GskPath`
* with all the contours added to the builder
*
* Since: 4.14
*/
GskPath *
gsk_path_builder_free_to_path (GskPathBuilder *self)
{
GskPath *res;
g_return_val_if_fail (self != NULL, NULL);
res = gsk_path_builder_to_path (self);
gsk_path_builder_unref (self);
return res;
}
/**
* gsk_path_builder_to_path:
* @self: a `GskPathBuilder`
*
* Creates a new `GskPath` from the given builder.
*
* The given `GskPathBuilder` is reset once this function returns;
* you cannot call this function multiple times on the same builder
* instance.
*
* This function is intended primarily for language bindings.
* C code should use [method@Gsk.PathBuilder.free_to_path].
*
* Returns: (transfer full): the newly created `GskPath`
* with all the contours added to the builder
*
* Since: 4.14
*/
GskPath *
gsk_path_builder_to_path (GskPathBuilder *self)
{
GskPath *path;
g_return_val_if_fail (self != NULL, NULL);
gsk_path_builder_end_current (self);
self->contours = g_slist_reverse (self->contours);
path = gsk_path_new_from_contours (self->contours);
gsk_path_builder_clear (self);
return path;
}
void
gsk_path_builder_add_contour (GskPathBuilder *self,
GskContour *contour)
{
gsk_path_builder_end_current (self);
self->contours = g_slist_prepend (self->contours, contour);
}
/**
* gsk_path_builder_get_current_point:
* @self: a `GskPathBuilder`
*
* Gets the current point. The current point is used for relative
* drawing commands and updated after every operation.
*
* When the builder is created, the default current point is set to (0, 0).
* Note that this is different from cairo, which starts out without
* a current point.
*
* Returns: (transfer none): The current point
*
* Since: 4.14
*/
const graphene_point_t *
gsk_path_builder_get_current_point (GskPathBuilder *self)
{
g_return_val_if_fail (self != NULL, NULL);
return &self->current_point;
}
/**
* gsk_path_builder_add_path:
* @self: a `GskPathBuilder`
* @path: (transfer none): the path to append
*
* Appends all of @path to the builder.
*
* Since: 4.14
*/
void
gsk_path_builder_add_path (GskPathBuilder *self,
GskPath *path)
{
g_return_if_fail (self != NULL);
g_return_if_fail (path != NULL);
for (gsize i = 0; i < gsk_path_get_n_contours (path); i++)
{
const GskContour *contour = gsk_path_get_contour (path, i);
gsk_path_builder_add_contour (self, gsk_contour_dup (contour));
}
}
/**
* gsk_path_builder_add_reverse_path:
* @self: a `GskPathBuilder`
* @path: (transfer none): the path to append
*
* Appends all of @path to the builder, in reverse order.
*
* Since: 4.14
*/
void
gsk_path_builder_add_reverse_path (GskPathBuilder *self,
GskPath *path)
{
g_return_if_fail (self != NULL);
g_return_if_fail (path != NULL);
for (gsize i = gsk_path_get_n_contours (path); i > 0; i--)
{
const GskContour *contour = gsk_path_get_contour (path, i - 1);
gsk_path_builder_add_contour (self, gsk_contour_reverse (contour));
}
}
/**
* gsk_path_builder_add_cairo_path:
* @self: a `GskPathBuilder`
*
* Adds a Cairo path to the builder.
*
* You can use cairo_copy_path() to access the path
* from a Cairo context.
*
* Since: 4.14
*/
void
gsk_path_builder_add_cairo_path (GskPathBuilder *self,
const cairo_path_t *path)
{
g_return_if_fail (self != NULL);
g_return_if_fail (path != NULL);
for (gsize i = 0; i < path->num_data; i += path->data[i].header.length)
{
const cairo_path_data_t *data = &path->data[i];
switch (data->header.type)
{
case CAIRO_PATH_MOVE_TO:
gsk_path_builder_move_to (self, data[1].point.x, data[1].point.y);
break;
case CAIRO_PATH_LINE_TO:
gsk_path_builder_line_to (self, data[1].point.x, data[1].point.y);
break;
case CAIRO_PATH_CURVE_TO:
gsk_path_builder_cubic_to (self,
data[1].point.x, data[1].point.y,
data[2].point.x, data[2].point.y,
data[3].point.x, data[3].point.y);
break;
case CAIRO_PATH_CLOSE_PATH:
gsk_path_builder_close (self);
break;
default:
g_assert_not_reached ();
break;
}
}
}
/**
* gsk_path_builder_add_rect:
* @self: A `GskPathBuilder`
* @rect: The rectangle to create a path for
*
* Adds @rect as a new contour to the path built by the builder.
*
* If the width or height of the rectangle is negative, the start
* point will be on the right or bottom, respectively.
*
* If the the width or height are 0, the path will be a closed
* horizontal or vertical line. If both are 0, it'll be a closed dot.
*
* Since: 4.14
*/
void
gsk_path_builder_add_rect (GskPathBuilder *self,
const graphene_rect_t *rect)
{
g_return_if_fail (self != NULL);
gsk_path_builder_move_to (self, rect->origin.x, rect->origin.y);
gsk_path_builder_rel_line_to (self, rect->size.width, 0);
gsk_path_builder_rel_line_to (self, 0, rect->size.height);
gsk_path_builder_rel_line_to (self, - rect->size.width, 0);
gsk_path_builder_close (self);
}
static gboolean
circle_contour_curve (const graphene_point_t pts[4],
gpointer data)
{
GskPathBuilder *self = data;
gsk_path_builder_cubic_to (self,
pts[1].x, pts[1].y,
pts[2].x, pts[2].y,
pts[3].x, pts[3].y);
return TRUE;
}
/**
* gsk_path_builder_add_circle:
* @self: a `GskPathBuilder`
* @center: the center of the circle
* @radius: the radius of the circle
*
* Adds a circle with the @center and @radius.
*
* Since: 4.14
*/
void
gsk_path_builder_add_circle (GskPathBuilder *self,
const graphene_point_t *center,
float radius)
{
g_return_if_fail (self != NULL);
g_return_if_fail (center != NULL);
g_return_if_fail (radius > 0);
gsk_path_builder_move_to (self, center->x + radius, center->y);
gsk_spline_decompose_arc (center, radius,
GSK_PATH_TOLERANCE_DEFAULT,
0, 2 * M_PI,
circle_contour_curve, self);
gsk_path_builder_close (self);
}
/**
* gsk_path_builder_move_to:
* @self: a `GskPathBuilder`
* @x: x coordinate
* @y: y coordinate
*
* Starts a new contour by placing the pen at @x, @y.
*
* If this function is called twice in succession, the first
* call will result in a contour made up of a single point.
* The second call will start a new contour.
*
* Since: 4.14
*/
void
gsk_path_builder_move_to (GskPathBuilder *self,
float x,
float y)
{
g_return_if_fail (self != NULL);
gsk_path_builder_end_current (self);
self->current_point = GRAPHENE_POINT_INIT(x, y);
gsk_path_builder_ensure_current (self);
}
/**
* gsk_path_builder_rel_move_to:
* @self: a `GskPathBuilder`
* @x: x offset
* @y: y offset
*
* Starts a new contour by placing the pen at @x, @y relative to the current
* point.
*
* This is the relative version of [method@Gsk.PathBuilder.move_to].
*
* Since: 4.14
*/
void
gsk_path_builder_rel_move_to (GskPathBuilder *self,
float x,
float y)
{
g_return_if_fail (self != NULL);
gsk_path_builder_move_to (self,
self->current_point.x + x,
self->current_point.y + y);
}
/**
* gsk_path_builder_line_to:
* @self: a `GskPathBuilder`
* @x: x coordinate
* @y: y coordinate
*
* Draws a line from the current point to @x, @y and makes it
* the new current point.
*
* Since: 4.14
*/
void
gsk_path_builder_line_to (GskPathBuilder *self,
float x,
float y)
{
g_return_if_fail (self != NULL);
/* skip the line if it goes to the same point */
if (graphene_point_equal (&self->current_point,
&GRAPHENE_POINT_INIT (x, y)))
return;
gsk_path_builder_append_current (self,
GSK_PATH_LINE,
1, (graphene_point_t[1]) {
GRAPHENE_POINT_INIT (x, y)
});
}
/**
* gsk_path_builder_rel_line_to:
* @self: a `GskPathBuilder`
* @x: x offset
* @y: y offset
*
* Draws a line from the current point to a point offset to it by @x, @y
* and makes it the new current point.
*
* This is the relative version of [method@Gsk.PathBuilder.line_to].
*
* Since: 4.14
*/
void
gsk_path_builder_rel_line_to (GskPathBuilder *self,
float x,
float y)
{
g_return_if_fail (self != NULL);
gsk_path_builder_line_to (self,
self->current_point.x + x,
self->current_point.y + y);
}
/**
* gsk_path_builder_quad_to:
* @self: a #GskPathBuilder
* @x1: x coordinate of control point
* @y1: y coordinate of control point
* @x2: x coordinate of the end of the curve
* @y2: y coordinate of the end of the curve
*
* Adds a [quadratic Bézier curve](https://en.wikipedia.org/wiki/B%C3%A9zier_curve)
* from the current point to @x2, @y2 with @x1, @y1 as the control point.
*
* After this, @x2, @y2 will be the new current point.
*
* Since: 4.14
*/
void
gsk_path_builder_quad_to (GskPathBuilder *self,
float x1,
float y1,
float x2,
float y2)
{
g_return_if_fail (self != NULL);
self->flags &= ~GSK_PATH_FLAT;
gsk_path_builder_append_current (self,
GSK_PATH_QUAD,
2, (graphene_point_t[2]) {
GRAPHENE_POINT_INIT (x1, y1),
GRAPHENE_POINT_INIT (x2, y2)
});
}
/**
* gsk_path_builder_rel_quad_to:
* @self: a `GskPathBuilder`
* @x1: x offset of control point
* @y1: y offset of control point
* @x2: x offset of the end of the curve
* @y2: y offset of the end of the curve
*
* Adds a [quadratic Bézier curve](https://en.wikipedia.org/wiki/B%C3%A9zier_curve)
* from the current point to @x2, @y2 with @x1, @y1 the control point.
*
* All coordinates are given relative to the current point.
*
* This is the relative version of [method@Gsk.PathBuilder.quad_to].
*
* Since: 4.14
*/
void
gsk_path_builder_rel_quad_to (GskPathBuilder *self,
float x1,
float y1,
float x2,
float y2)
{
g_return_if_fail (self != NULL);
gsk_path_builder_quad_to (self,
self->current_point.x + x1,
self->current_point.y + y1,
self->current_point.x + x2,
self->current_point.y + y2);
}
/**
* gsk_path_builder_cubic_to:
* @self: a `GskPathBuilder`
* @x1: x coordinate of first control point
* @y1: y coordinate of first control point
* @x2: x coordinate of second control point
* @y2: y coordinate of second control point
* @x3: x coordinate of the end of the curve
* @y3: y coordinate of the end of the curve
*
* Adds a [cubic Bézier curve](https://en.wikipedia.org/wiki/B%C3%A9zier_curve)
* from the current point to @x3, @y3 with @x1, @y1 and @x2, @y2 as the control
* points.
*
* After this, @x3, @y3 will be the new current point.
*
* Since: 4.14
*/
void
gsk_path_builder_cubic_to (GskPathBuilder *self,
float x1,
float y1,
float x2,
float y2,
float x3,
float y3)
{
g_return_if_fail (self != NULL);
self->flags &= ~GSK_PATH_FLAT;
gsk_path_builder_append_current (self,
GSK_PATH_CUBIC,
3, (graphene_point_t[3]) {
GRAPHENE_POINT_INIT (x1, y1),
GRAPHENE_POINT_INIT (x2, y2),
GRAPHENE_POINT_INIT (x3, y3)
});
}
/**
* gsk_path_builder_rel_cubic_to:
* @self: a `GskPathBuilder`
* @x1: x offset of first control point
* @y1: y offset of first control point
* @x2: x offset of second control point
* @y2: y offset of second control point
* @x3: x offset of the end of the curve
* @y3: y offset of the end of the curve
*
* Adds a [cubic Bézier curve](https://en.wikipedia.org/wiki/B%C3%A9zier_curve)
* from the current point to @x3, @y3 with @x1, @y1 and @x2, @y2 as the control
* points. All coordinates are given relative to the current point.
*
* This is the relative version of [method@Gsk.PathBuilder.cubic_to].
*
* Since: 4.14
*/
void
gsk_path_builder_rel_cubic_to (GskPathBuilder *self,
float x1,
float y1,
float x2,
float y2,
float x3,
float y3)
{
g_return_if_fail (self != NULL);
gsk_path_builder_cubic_to (self,
self->current_point.x + x1,
self->current_point.y + y1,
self->current_point.x + x2,
self->current_point.y + y2,
self->current_point.x + x3,
self->current_point.y + y3);
}
/**
* gsk_path_builder_close:
* @self: a `GskPathBuilder`
*
* Ends the current contour with a line back to the start point.
*
* Note that this is different from calling [method@Gsk.PathBuilder.line_to]
* with the start point in that the contour will be closed. A closed
* contour behaves different from an open one when stroking its start
* and end point are considered connected, so they will be joined
* via the line join, and not ended with line caps.
*
* Since: 4.14
*/
void
gsk_path_builder_close (GskPathBuilder *self)
{
g_return_if_fail (self != NULL);
if (self->ops->len == 0)
return;
self->flags |= GSK_PATH_CLOSED;
gsk_path_builder_append_current (self,
GSK_PATH_CLOSE,
1, (graphene_point_t[1]) {
g_array_index (self->points, graphene_point_t, 0)
});
gsk_path_builder_end_current (self);
}
static void
arc_segment (GskPathBuilder *self,
double cx,
double cy,
double rx,
double ry,
double sin_phi,
double cos_phi,
double sin_th0,
double cos_th0,
double sin_th1,
double cos_th1,
double t)
{
double x1, y1, x2, y2, x3, y3;
x1 = rx * (cos_th0 - t * sin_th0);
y1 = ry * (sin_th0 + t * cos_th0);
x3 = rx * cos_th1;
y3 = ry * sin_th1;
x2 = x3 + rx * (t * sin_th1);
y2 = y3 + ry * (-t * cos_th1);
gsk_path_builder_cubic_to (self,
cx + cos_phi * x1 - sin_phi * y1,
cy + sin_phi * x1 + cos_phi * y1,
cx + cos_phi * x2 - sin_phi * y2,
cy + sin_phi * x2 + cos_phi * y2,
cx + cos_phi * x3 - sin_phi * y3,
cy + sin_phi * x3 + cos_phi * y3);
}
static inline void
_sincos (double angle,
double *y,
double *x)
{
#ifdef HAVE_SINCOS
sincos (angle, y, x);
#else
*x = cos (angle);
*y = sin (angle);
#endif
}
void
gsk_path_builder_svg_arc_to (GskPathBuilder *self,
float rx,
float ry,
float x_axis_rotation,
gboolean large_arc,
gboolean positive_sweep,
float x,
float y)
{
graphene_point_t *current;
double x1, y1, x2, y2;
double phi, sin_phi, cos_phi;
double mid_x, mid_y;
double lambda;
double d;
double k;
double x1_, y1_;
double cx_, cy_;
double cx, cy;
double ux, uy, u_len;
double cos_theta1, theta1;
double vx, vy, v_len;
double dp_uv;
double cos_delta_theta, delta_theta;
int i, n_segs;
double d_theta, theta;
double sin_th0, cos_th0;
double sin_th1, cos_th1;
double th_half;
double t;
if (self->points->len > 0)
{
current = &g_array_index (self->points, graphene_point_t, self->points->len - 1);
x1 = current->x;
y1 = current->y;
}
else
{
x1 = 0;
y1 = 0;
}
x2 = x;
y2 = y;
phi = x_axis_rotation * M_PI / 180.0;
_sincos (phi, &sin_phi, &cos_phi);
rx = fabs (rx);
ry = fabs (ry);
mid_x = (x1 - x2) / 2;
mid_y = (y1 - y2) / 2;
x1_ = cos_phi * mid_x + sin_phi * mid_y;
y1_ = - sin_phi * mid_x + cos_phi * mid_y;
lambda = (x1_ / rx) * (x1_ / rx) + (y1_ / ry) * (y1_ / ry);
if (lambda > 1)
{
lambda = sqrt (lambda);
rx *= lambda;
ry *= lambda;
}
d = (rx * y1_) * (rx * y1_) + (ry * x1_) * (ry * x1_);
if (d == 0)
return;
k = sqrt (fabs ((rx * ry) * (rx * ry) / d - 1.0));
if (positive_sweep == large_arc)
k = -k;
cx_ = k * rx * y1_ / ry;
cy_ = -k * ry * x1_ / rx;
cx = cos_phi * cx_ - sin_phi * cy_ + (x1 + x2) / 2;
cy = sin_phi * cx_ + cos_phi * cy_ + (y1 + y2) / 2;
ux = (x1_ - cx_) / rx;
uy = (y1_ - cy_) / ry;
u_len = sqrt (ux * ux + uy * uy);
if (u_len == 0)
return;
cos_theta1 = CLAMP (ux / u_len, -1, 1);
theta1 = acos (cos_theta1);
if (uy < 0)
theta1 = - theta1;
vx = (- x1_ - cx_) / rx;
vy = (- y1_ - cy_) / ry;
v_len = sqrt (vx * vx + vy * vy);
if (v_len == 0)
return;
dp_uv = ux * vx + uy * vy;
cos_delta_theta = CLAMP (dp_uv / (u_len * v_len), -1, 1);
delta_theta = acos (cos_delta_theta);
if (ux * vy - uy * vx < 0)
delta_theta = - delta_theta;
if (positive_sweep && delta_theta < 0)
delta_theta += 2 * M_PI;
else if (!positive_sweep && delta_theta > 0)
delta_theta -= 2 * M_PI;
n_segs = ceil (fabs (delta_theta / (M_PI_2 + 0.001)));
d_theta = delta_theta / n_segs;
theta = theta1;
_sincos (theta1, &sin_th1, &cos_th1);
th_half = d_theta / 2;
t = (8.0 / 3.0) * sin (th_half / 2) * sin (th_half / 2) / sin (th_half);
for (i = 0; i < n_segs; i++)
{
theta = theta1;
theta1 = theta + d_theta;
sin_th0 = sin_th1;
cos_th0 = cos_th1;
_sincos (theta1, &sin_th1, &cos_th1);
arc_segment (self,
cx, cy, rx, ry,
sin_phi, cos_phi,
sin_th0, cos_th0,
sin_th1, cos_th1,
t);
}
}
/**
* gsk_path_builder_add_layout:
* @self: a #GskPathBuilder
* @layout: the pango layout to add
*
* Adds the outlines for the glyphs in @layout to
* the builder.
*
* Since: 4.14
*/
void
gsk_path_builder_add_layout (GskPathBuilder *self,
PangoLayout *layout)
{
cairo_surface_t *surface;
cairo_t *cr;
cairo_path_t *cairo_path;
surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
cr = cairo_create (surface);
pango_cairo_layout_path (cr, layout);
cairo_path = cairo_copy_path (cr);
gsk_path_builder_add_cairo_path (self, cairo_path);
cairo_path_destroy (cairo_path);
cairo_destroy (cr);
cairo_surface_destroy (surface);
}
+125
View File
@@ -0,0 +1,125 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#pragma once
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gsk/gsk.h> can be included directly."
#endif
#include <gsk/gskroundedrect.h>
#include <gsk/gsktypes.h>
G_BEGIN_DECLS
#define GSK_TYPE_PATH_BUILDER (gsk_path_builder_get_type ())
GDK_AVAILABLE_IN_4_14
GType gsk_path_builder_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_14
GskPathBuilder * gsk_path_builder_new (void);
GDK_AVAILABLE_IN_4_14
GskPathBuilder * gsk_path_builder_ref (GskPathBuilder *self);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_unref (GskPathBuilder *self);
GDK_AVAILABLE_IN_4_14
GskPath * gsk_path_builder_free_to_path (GskPathBuilder *self) G_GNUC_WARN_UNUSED_RESULT;
GDK_AVAILABLE_IN_4_14
GskPath * gsk_path_builder_to_path (GskPathBuilder *self) G_GNUC_WARN_UNUSED_RESULT;
GDK_AVAILABLE_IN_4_14
const graphene_point_t *gsk_path_builder_get_current_point (GskPathBuilder *self);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_add_path (GskPathBuilder *self,
GskPath *path);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_add_reverse_path (GskPathBuilder *self,
GskPath *path);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_add_cairo_path (GskPathBuilder *self,
const cairo_path_t *path);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_add_layout (GskPathBuilder *self,
PangoLayout *layout);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_add_rect (GskPathBuilder *self,
const graphene_rect_t *rect);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_add_circle (GskPathBuilder *self,
const graphene_point_t *center,
float radius);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_add_segment (GskPathBuilder *self,
GskPath *path,
const GskPathPoint *start,
const GskPathPoint *end);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_move_to (GskPathBuilder *self,
float x,
float y);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_rel_move_to (GskPathBuilder *self,
float x,
float y);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_line_to (GskPathBuilder *self,
float x,
float y);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_rel_line_to (GskPathBuilder *self,
float x,
float y);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_quad_to (GskPathBuilder *self,
float x1,
float y1,
float x2,
float y2);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_rel_quad_to (GskPathBuilder *self,
float x1,
float y1,
float x2,
float y2);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_cubic_to (GskPathBuilder *self,
float x1,
float y1,
float x2,
float y2,
float x3,
float y3);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_rel_cubic_to (GskPathBuilder *self,
float x1,
float y1,
float x2,
float y2,
float x3,
float y3);
GDK_AVAILABLE_IN_4_14
void gsk_path_builder_close (GskPathBuilder *self);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskPathBuilder, gsk_path_builder_unref)
G_END_DECLS
+328
View File
@@ -0,0 +1,328 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gskpathmeasure.h"
#include "gskpathbuilder.h"
#include "gskpathpointprivate.h"
#include "gskpathprivate.h"
/**
* GskPathMeasure:
*
* `GskPathMeasure` is an object that allows measurements
* on `GskPath`s such as determining the length of the path.
*
* Many measuring operations require approximating the path
* with simpler shapes. Therefore, a `GskPathMeasure` has
* a tolerance that determines what precision is required
* for such approximations.
*
* A `GskPathMeasure` struct is a reference counted struct
* and should be treated as opaque.
*/
typedef struct _GskContourMeasure GskContourMeasure;
struct _GskContourMeasure
{
float length;
gpointer contour_data;
};
struct _GskPathMeasure
{
/*< private >*/
guint ref_count;
GskPath *path;
float tolerance;
float length;
gsize n_contours;
GskContourMeasure measures[];
};
G_DEFINE_BOXED_TYPE (GskPathMeasure, gsk_path_measure,
gsk_path_measure_ref,
gsk_path_measure_unref)
/**
* gsk_path_measure_new:
* @path: the path to measure
*
* Creates a measure object for the given @path.
*
* Returns: a new `GskPathMeasure` representing @path
*
* Since: 4.14
*/
GskPathMeasure *
gsk_path_measure_new (GskPath *path)
{
return gsk_path_measure_new_with_tolerance (path, GSK_PATH_TOLERANCE_DEFAULT);
}
/**
* gsk_path_measure_new_with_tolerance:
* @path: the path to measure
* @tolerance: the tolerance for measuring operations
*
* Creates a measure object for the given @path and @tolerance.
*
* Returns: a new `GskPathMeasure` representing @path
*
* Since: 4.14
*/
GskPathMeasure *
gsk_path_measure_new_with_tolerance (GskPath *path,
float tolerance)
{
GskPathMeasure *self;
gsize i, n_contours;
g_return_val_if_fail (path != NULL, NULL);
g_return_val_if_fail (tolerance > 0, NULL);
n_contours = gsk_path_get_n_contours (path);
self = g_malloc0 (sizeof (GskPathMeasure) + n_contours * sizeof (GskContourMeasure));
self->ref_count = 1;
self->path = gsk_path_ref (path);
self->tolerance = tolerance;
self->n_contours = n_contours;
for (i = 0; i < n_contours; i++)
{
self->measures[i].contour_data = gsk_contour_init_measure (gsk_path_get_contour (path, i),
self->tolerance,
&self->measures[i].length);
self->length += self->measures[i].length;
}
return self;
}
/**
* gsk_path_measure_ref:
* @self: a `GskPathMeasure`
*
* Increases the reference count of a `GskPathMeasure` by one.
*
* Returns: the passed in `GskPathMeasure`.
*
* Since: 4.14
*/
GskPathMeasure *
gsk_path_measure_ref (GskPathMeasure *self)
{
g_return_val_if_fail (self != NULL, NULL);
self->ref_count++;
return self;
}
/**
* gsk_path_measure_unref:
* @self: a `GskPathMeasure`
*
* Decreases the reference count of a `GskPathMeasure` by one.
*
* If the resulting reference count is zero, frees the object.
*
* Since: 4.14
*/
void
gsk_path_measure_unref (GskPathMeasure *self)
{
gsize i;
g_return_if_fail (self != NULL);
g_return_if_fail (self->ref_count > 0);
self->ref_count--;
if (self->ref_count > 0)
return;
for (i = 0; i < self->n_contours; i++)
{
gsk_contour_free_measure (gsk_path_get_contour (self->path, i),
self->measures[i].contour_data);
}
gsk_path_unref (self->path);
g_free (self);
}
/**
* gsk_path_measure_get_path:
* @self: a `GskPathMeasure`
*
* Returns the path that the measure was created for.
*
* Returns: (transfer none): the path of @self
*
* Since: 4.14
*/
GskPath *
gsk_path_measure_get_path (GskPathMeasure *self)
{
return self->path;
}
/**
* gsk_path_measure_get_tolerance:
* @self: a `GskPathMeasure`
*
* Returns the tolerance that the measure was created with.
*
* Returns: the tolerance of @self
*
* Since: 4.14
*/
float
gsk_path_measure_get_tolerance (GskPathMeasure *self)
{
return self->tolerance;
}
/**
* gsk_path_measure_get_length:
* @self: a `GskPathMeasure`
*
* Gets the length of the path being measured.
*
* The length is cached, so this function does not do any work.
*
* Returns: The length of the path measured by @self
*
* Since: 4.14
*/
float
gsk_path_measure_get_length (GskPathMeasure *self)
{
g_return_val_if_fail (self != NULL, 0);
return self->length;
}
static float
gsk_path_measure_clamp_distance (GskPathMeasure *self,
float distance)
{
if (isnan (distance))
return 0;
return CLAMP (distance, 0, self->length);
}
/**
* gsk_path_measure_get_point:
* @self: a `GskPathMeasure`
* @distance: the distance
* @result: (out caller-allocates): return location for the result
*
* Sets @result to the point at the given distance into the path.
*
* An empty path has no points, so `FALSE` is returned in that case.
*
* Returns: `TRUE` if @result was set
*
* Since: 4.14
*/
gboolean
gsk_path_measure_get_point (GskPathMeasure *self,
float distance,
GskPathPoint *result)
{
GskRealPathPoint *res = (GskRealPathPoint *) result;
gsize i;
float offset;
const GskContour *contour;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (result != NULL, FALSE);
if (self->n_contours == 0)
return FALSE;
offset = gsk_path_measure_clamp_distance (self, distance);
for (i = 0; i < self->n_contours - 1; i++)
{
if (offset < self->measures[i].length)
break;
offset -= self->measures[i].length;
}
g_assert (0 <= i && i < self->n_contours);
offset = CLAMP (offset, 0, self->measures[i].length);
contour = gsk_path_get_contour (self->path, i);
gsk_contour_get_point (contour, self->measures[i].contour_data, offset, res);
res->path = self->path;
res->contour = i;
return TRUE;
}
/**
* gsk_path_point_get_distance:
* @measure: a `GskPathMeasure`
* @point: a `GskPathPoint on the path of @self
*
* Returns the distance from the beginning of the path
* to @point.
*
* Returns: the distance of @point
*
* Since: 4.14
*/
float
gsk_path_point_get_distance (GskPathMeasure *measure,
const GskPathPoint *point)
{
GskRealPathPoint *p = (GskRealPathPoint *)point;
const GskContour *contour = gsk_path_get_contour (measure->path, p->contour);
float contour_offset = 0;
g_return_val_if_fail (measure != NULL, 0);
g_return_val_if_fail (measure->path == p->path, 0);
g_return_val_if_fail (contour != NULL, 0);
for (gsize i = 0; i < measure->n_contours; i++)
{
if (contour == gsk_path_get_contour (measure->path, i))
return contour_offset + gsk_contour_get_distance (contour,
p,
measure->measures[i].contour_data);
contour_offset += measure->measures[i].length;
}
g_return_val_if_reached (0);
}
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#pragma once
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gsk/gsk.h> can be included directly."
#endif
#include <gsk/gskpath.h>
#include <gsk/gskpathpoint.h>
G_BEGIN_DECLS
#define GSK_TYPE_PATH_MEASURE (gsk_path_measure_get_type ())
GDK_AVAILABLE_IN_4_14
GType gsk_path_measure_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_14
GskPathMeasure * gsk_path_measure_new (GskPath *path);
GDK_AVAILABLE_IN_4_14
GskPathMeasure * gsk_path_measure_new_with_tolerance (GskPath *path,
float tolerance);
GDK_AVAILABLE_IN_4_14
GskPathMeasure * gsk_path_measure_ref (GskPathMeasure *self);
GDK_AVAILABLE_IN_4_14
void gsk_path_measure_unref (GskPathMeasure *self);
GDK_AVAILABLE_IN_4_14
GskPath * gsk_path_measure_get_path (GskPathMeasure *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
float gsk_path_measure_get_tolerance (GskPathMeasure *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
float gsk_path_measure_get_length (GskPathMeasure *self);
GDK_AVAILABLE_IN_4_14
gboolean gsk_path_measure_get_point (GskPathMeasure *self,
float distance,
GskPathPoint *result);
GDK_AVAILABLE_IN_4_14
float gsk_path_measure_get_distance (GskPathMeasure *self,
const GskPathPoint *point);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskPathMeasure, gsk_path_measure_unref)
G_END_DECLS
+172
View File
@@ -0,0 +1,172 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#pragma once
#include "gskpath.h"
#include "gskpathbuilder.h"
G_BEGIN_DECLS
typedef gpointer gskpathop;
static inline
gskpathop gsk_pathop_encode (GskPathOperation op,
const graphene_point_t *pts);
static inline
const graphene_point_t *gsk_pathop_points (gskpathop pop);
static inline
GskPathOperation gsk_pathop_op (gskpathop pop);
static inline
gboolean gsk_pathop_foreach (gskpathop pop,
GskPathForeachFunc func,
gpointer user_data);
/* included inline so tests can use them */
static inline
void gsk_path_builder_pathop_to (GskPathBuilder *builder,
gskpathop op);
static inline
void gsk_path_builder_pathop_reverse_to (GskPathBuilder *builder,
gskpathop op);
/* IMPLEMENTATION */
#define GSK_PATHOP_OPERATION_MASK (0x7)
static inline gskpathop
gsk_pathop_encode (GskPathOperation op,
const graphene_point_t *pts)
{
/* g_assert (op & GSK_PATHOP_OPERATION_MASK == op); */
g_assert ((GPOINTER_TO_SIZE (pts) & GSK_PATHOP_OPERATION_MASK) == 0);
return GSIZE_TO_POINTER (GPOINTER_TO_SIZE (pts) | op);
}
static inline const graphene_point_t *
gsk_pathop_points (gskpathop pop)
{
return GSIZE_TO_POINTER (GPOINTER_TO_SIZE (pop) & ~GSK_PATHOP_OPERATION_MASK);
}
static inline
GskPathOperation gsk_pathop_op (gskpathop pop)
{
return GPOINTER_TO_SIZE (pop) & GSK_PATHOP_OPERATION_MASK;
}
static inline gboolean
gsk_pathop_foreach (gskpathop pop,
GskPathForeachFunc func,
gpointer user_data)
{
switch (gsk_pathop_op (pop))
{
case GSK_PATH_MOVE:
return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 1, user_data);
case GSK_PATH_CLOSE:
case GSK_PATH_LINE:
return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 2, user_data);
case GSK_PATH_QUAD:
return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 3, user_data);
case GSK_PATH_CUBIC:
return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 4, user_data);
default:
g_assert_not_reached ();
return TRUE;
}
}
static inline void
gsk_path_builder_pathop_to (GskPathBuilder *builder,
gskpathop op)
{
const graphene_point_t *pts = gsk_pathop_points (op);
switch (gsk_pathop_op (op))
{
case GSK_PATH_MOVE:
gsk_path_builder_move_to (builder, pts[0].x, pts[0].y);
break;
case GSK_PATH_CLOSE:
gsk_path_builder_close (builder);
break;
case GSK_PATH_LINE:
gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
break;
case GSK_PATH_QUAD:
gsk_path_builder_quad_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].y);
break;
case GSK_PATH_CUBIC:
gsk_path_builder_cubic_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].y, pts[3].x, pts[3].y);
break;
default:
g_assert_not_reached ();
break;
}
}
static inline void
gsk_path_builder_pathop_reverse_to (GskPathBuilder *builder,
gskpathop op)
{
const graphene_point_t *pts = gsk_pathop_points (op);
switch (gsk_pathop_op (op))
{
case GSK_PATH_MOVE:
gsk_path_builder_move_to (builder, pts[0].x, pts[0].y);
break;
case GSK_PATH_CLOSE:
gsk_path_builder_line_to (builder, pts[0].x, pts[0].y);
break;
case GSK_PATH_LINE:
gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
break;
case GSK_PATH_QUAD:
gsk_path_builder_quad_to (builder, pts[1].x, pts[1].y, pts[0].x, pts[0].y);
break;
case GSK_PATH_CUBIC:
gsk_path_builder_cubic_to (builder, pts[2].x, pts[2].y, pts[1].x, pts[1].y, pts[0].x, pts[0].y);
break;
default:
g_assert_not_reached ();
break;
}
}
G_END_DECLS
+157
View File
@@ -0,0 +1,157 @@
/*
* Copyright © 2023 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen <mclasen@redhat.com>
*/
#include "config.h"
#include "gskpathpointprivate.h"
#include "gskcontourprivate.h"
#include "gskpathmeasure.h"
#include "gdk/gdkprivate.h"
/**
* GskPathPoint:
*
* `GskPathPoint` is an opaque type representing a point on a path.
*
* It can be queried for properties of the path at that point, such as its
* tangent or its curvature.
*
* To obtain a `GskPathPoint`, use [method@Gsk.Path.get_closest_point]
* or [method@Gsk.PathMeasure.get_point].
*
* Note that `GskPathPoint` structs are meant to be stack-allocated, and
* don't a reference to the path object they are obtained from. It is the
* callers responsibility to keep a reference to the path as long as the
* `GskPathPoint` is used.
*/
G_DEFINE_BOXED_TYPE (GskPathPoint, gsk_path_point,
gsk_path_point_copy,
gsk_path_point_free)
GskPathPoint *
gsk_path_point_copy (GskPathPoint *point)
{
GskPathPoint *copy;
copy = g_new0 (GskPathPoint, 1);
memcpy (copy, point, sizeof (GskRealPathPoint));
return copy;
}
void
gsk_path_point_free (GskPathPoint *point)
{
g_free (point);
}
/**
* gsk_path_point_get_position:
* @path: a `GskPath`
* @point: a `GskPathPoint` on @path
* @position: (out caller-allocates): Return location for
* the coordinates of the point
*
* Gets the position of the point.
*
* Since: 4.14
*/
void
gsk_path_point_get_position (GskPath *path,
const GskPathPoint *point,
graphene_point_t *position)
{
GskRealPathPoint *self = (GskRealPathPoint *) point;
const GskContour *contour = gsk_path_get_contour (path, self->contour);
g_return_if_fail (path == self->path);
g_return_if_fail (contour != NULL);
gsk_contour_get_position (contour, self, position);
}
/**
* gsk_path_point_get_tangent:
* @path: a `GskPath`
* @point: a `GskPathPoint` on @path
* @direction: the direction for which to return the tangent
* @tangent: (out caller-allocates): Return location for
* the tangent at the point
*
* Gets the tangent of the path at the point.
*
* Note that certain points on a path may not have a single
* tangent, such as sharp turns. At such points, there are
* two tangents -- the direction of the path going into the
* point, and the direction coming out of it. The @direction
* argument lets you choose which one to get.
*
* Since: 4.14
*/
void
gsk_path_point_get_tangent (GskPath *path,
const GskPathPoint *point,
GskPathDirection direction,
graphene_vec2_t *tangent)
{
GskRealPathPoint *self = (GskRealPathPoint *) point;
const GskContour *contour = gsk_path_get_contour (path, self->contour);
g_return_if_fail (path == self->path);
g_return_if_fail (contour != NULL);
gsk_contour_get_tangent (contour, self, direction, tangent);
}
/**
* gsk_path_point_get_curvature:
* @path: a `GskPath`
* @point: a `GskPathPoint` on @path
* @center: (out caller-allocates): Return location for
* the center of the osculating circle
*
* Calculates the curvature of the path at the point.
*
* Optionally, returns the center of the osculating circle as well.
*
* If the curvature is infinite (at line segments), zero is returned,
* and @center is not modified.
*
* Returns: The curvature of the path at the given point
*
* Since: 4.14
*/
float
gsk_path_point_get_curvature (GskPath *path,
const GskPathPoint *point,
graphene_point_t *center)
{
GskRealPathPoint *self = (GskRealPathPoint *) point;
const GskContour *contour = gsk_path_get_contour (path, self->contour);
g_return_val_if_fail (path == self->path, 0);
g_return_val_if_fail (contour != NULL, 0);
return gsk_contour_get_curvature (contour, self, center);
}
+71
View File
@@ -0,0 +1,71 @@
/*
* Copyright © 2023 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen <mclasen@redhat.com>
*/
#pragma once
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gsk/gsk.h> can be included directly."
#endif
#include <gsk/gsktypes.h>
G_BEGIN_DECLS
#define GSK_TYPE_PATH_POINT (gsk_path_point_get_type ())
typedef struct _GskPathPoint GskPathPoint;
struct _GskPathPoint {
/*< private >*/
union {
float f[8];
gpointer p[8];
} data;
};
GDK_AVAILABLE_IN_4_14
GType gsk_path_point_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_14
GskPathPoint * gsk_path_point_copy (GskPathPoint *point);
GDK_AVAILABLE_IN_4_14
void gsk_path_point_free (GskPathPoint *point);
GDK_AVAILABLE_IN_4_14
void gsk_path_point_get_position (GskPath *path,
const GskPathPoint *point,
graphene_point_t *position);
GDK_AVAILABLE_IN_4_14
void gsk_path_point_get_tangent (GskPath *path,
const GskPathPoint *point,
GskPathDirection direction,
graphene_vec2_t *tangent);
GDK_AVAILABLE_IN_4_14
float gsk_path_point_get_curvature (GskPath *path,
const GskPathPoint *point,
graphene_point_t *center);
GDK_AVAILABLE_IN_4_14
float gsk_path_point_get_distance (GskPathMeasure *measure,
const GskPathPoint *point);
G_END_DECLS
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#include "gskpathpoint.h"
#include "gskcontourprivate.h"
G_BEGIN_DECLS
struct _GskRealPathPoint
{
GskPath *path;
gsize contour;
union {
struct {
unsigned int idx;
float t;
} std;
} data;
};
G_STATIC_ASSERT (sizeof (GskRealPathPoint) <= sizeof (GskPathPoint));
G_END_DECLS
+70
View File
@@ -0,0 +1,70 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#pragma once
#include "gskpath.h"
#include "gskpathopprivate.h"
G_BEGIN_DECLS
typedef enum
{
GSK_PATH_FLAT,
GSK_PATH_CLOSED
} GskPathFlags;
typedef struct _GskContour GskContour;
typedef struct _GskRealPathPoint GskRealPathPoint;
/* Same as Skia, so looks like a good value. ¯\_(ツ)_/¯ */
#define GSK_PATH_TOLERANCE_DEFAULT (0.5)
GskPath * gsk_path_new_from_contours (const GSList *contours);
gsize gsk_path_get_n_contours (const GskPath *self);
const GskContour * gsk_path_get_contour (const GskPath *self,
gsize i);
GskPathFlags gsk_path_get_flags (const GskPath *self);
gboolean gsk_path_foreach_with_tolerance (GskPath *self,
GskPathForeachFlags flags,
double tolerance,
GskPathForeachFunc func,
gpointer user_data);
void gsk_path_builder_add_contour (GskPathBuilder *builder,
GskContour *contour);
void gsk_path_builder_svg_arc_to (GskPathBuilder *builder,
float rx,
float ry,
float x_axis_rotation,
gboolean large_arc,
gboolean positive_sweep,
float x,
float y);
G_END_DECLS
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <graphene.h>
static inline void G_GNUC_PURE
gsk_point_interpolate (const graphene_point_t *p1,
const graphene_point_t *p2,
float t,
graphene_point_t *p)
{
p->x = p1->x * (1 - t) + p2->x * t;
p->Y = p1->y * (1 - t) + p2->y * t;
}
static inline float G_GNUC_PURE
gsk_point_distance (const graphene_point_t *p1,
const graphene_point_t *p2)
{
return sqrtf ((p1->x - p2->x)*(p1->x - p2->x) + (p1->y - p2->y)*(p1->y - p2->y));
}
+6 -11
View File
@@ -287,21 +287,15 @@ gsk_render_node_alloc (GskRenderNodeType node_type)
* Returns: (transfer full): the `GskRenderNode` with an additional reference
*/
GskRenderNode *
(gsk_render_node_ref) (GskRenderNode *node)
gsk_render_node_ref (GskRenderNode *node)
{
g_return_val_if_fail (GSK_IS_RENDER_NODE (node), NULL);
return _gsk_render_node_ref (node);
}
g_atomic_ref_count_inc (&node->ref_count);
void
_gsk_render_node_unref (GskRenderNode *node)
{
if G_UNLIKELY (g_atomic_ref_count_dec (&node->ref_count))
GSK_RENDER_NODE_GET_CLASS (node)->finalize (node);
return node;
}
/**
* gsk_render_node_unref:
* @node: (transfer full): a `GskRenderNode`
@@ -312,11 +306,12 @@ _gsk_render_node_unref (GskRenderNode *node)
* freed.
*/
void
(gsk_render_node_unref) (GskRenderNode *node)
gsk_render_node_unref (GskRenderNode *node)
{
g_return_if_fail (GSK_IS_RENDER_NODE (node));
_gsk_render_node_unref (node);
if (g_atomic_ref_count_dec (&node->ref_count))
GSK_RENDER_NODE_GET_CLASS (node)->finalize (node);
}
+30
View File
@@ -158,6 +158,8 @@ GskRenderNode * gsk_render_node_deserialize (GBytes
#define GSK_TYPE_REPEAT_NODE (gsk_repeat_node_get_type())
#define GSK_TYPE_CLIP_NODE (gsk_clip_node_get_type())
#define GSK_TYPE_ROUNDED_CLIP_NODE (gsk_rounded_clip_node_get_type())
#define GSK_TYPE_FILL_NODE (gsk_fill_node_get_type())
#define GSK_TYPE_STROKE_NODE (gsk_stroke_node_get_type())
#define GSK_TYPE_SHADOW_NODE (gsk_shadow_node_get_type())
#define GSK_TYPE_BLEND_NODE (gsk_blend_node_get_type())
#define GSK_TYPE_CROSS_FADE_NODE (gsk_cross_fade_node_get_type())
@@ -186,6 +188,8 @@ typedef struct _GskColorMatrixNode GskColorMatrixNode;
typedef struct _GskRepeatNode GskRepeatNode;
typedef struct _GskClipNode GskClipNode;
typedef struct _GskRoundedClipNode GskRoundedClipNode;
typedef struct _GskFillNode GskFillNode;
typedef struct _GskStrokeNode GskStrokeNode;
typedef struct _GskShadowNode GskShadowNode;
typedef struct _GskBlendNode GskBlendNode;
typedef struct _GskCrossFadeNode GskCrossFadeNode;
@@ -459,6 +463,32 @@ GskRenderNode * gsk_rounded_clip_node_get_child (const GskRender
GDK_AVAILABLE_IN_ALL
const GskRoundedRect * gsk_rounded_clip_node_get_clip (const GskRenderNode *node) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
GType gsk_fill_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_14
GskRenderNode * gsk_fill_node_new (GskRenderNode *child,
GskPath *path,
GskFillRule fill_rule);
GDK_AVAILABLE_IN_4_14
GskRenderNode * gsk_fill_node_get_child (const GskRenderNode *node);
GDK_AVAILABLE_IN_4_14
GskPath * gsk_fill_node_get_path (const GskRenderNode *node);
GDK_AVAILABLE_IN_4_14
GskFillRule gsk_fill_node_get_fill_rule (const GskRenderNode *node);
GDK_AVAILABLE_IN_4_14
GType gsk_stroke_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_14
GskRenderNode * gsk_stroke_node_new (GskRenderNode *child,
GskPath *path,
const GskStroke *stroke);
GDK_AVAILABLE_IN_4_14
GskRenderNode * gsk_stroke_node_get_child (const GskRenderNode *node);
GDK_AVAILABLE_IN_4_14
GskPath * gsk_stroke_node_get_path (const GskRenderNode *node);
GDK_AVAILABLE_IN_4_14
const GskStroke * gsk_stroke_node_get_stroke (const GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
GType gsk_shadow_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
+447 -53
View File
@@ -25,8 +25,11 @@
#include "gskdebugprivate.h"
#include "gskdiffprivate.h"
#include "gl/gskglrenderer.h"
#include "gskpathprivate.h"
#include "gskrectprivate.h"
#include "gskrendererprivate.h"
#include "gskroundedrectprivate.h"
#include "gskstrokeprivate.h"
#include "gsktransformprivate.h"
#include "gdk/gdktextureprivate.h"
@@ -245,13 +248,6 @@ gsk_linear_gradient_node_draw (GskRenderNode *node,
if (gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE)
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
if (self->stops[0].offset > 0.0)
cairo_pattern_add_color_stop_rgba (pattern,
0.0,
self->stops[0].color.red,
self->stops[0].color.green,
self->stops[0].color.blue,
self->stops[0].color.alpha);
for (i = 0; i < self->n_stops; i++)
{
cairo_pattern_add_color_stop_rgba (pattern,
@@ -261,13 +257,6 @@ gsk_linear_gradient_node_draw (GskRenderNode *node,
self->stops[i].color.blue,
self->stops[i].color.alpha);
}
if (self->stops[self->n_stops-1].offset < 1.0)
cairo_pattern_add_color_stop_rgba (pattern,
1.0,
self->stops[self->n_stops-1].color.red,
self->stops[self->n_stops-1].color.green,
self->stops[self->n_stops-1].color.blue,
self->stops[self->n_stops-1].color.alpha);
cairo_set_source (cr, pattern);
cairo_pattern_destroy (pattern);
@@ -573,29 +562,13 @@ gsk_radial_gradient_node_draw (GskRenderNode *node,
else
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
if (self->stops[0].offset > 0.0)
cairo_pattern_add_color_stop_rgba (pattern,
0.0,
self->stops[0].color.red,
self->stops[0].color.green,
self->stops[0].color.blue,
self->stops[0].color.alpha);
for (i = 0; i < self->n_stops; i++)
{
cairo_pattern_add_color_stop_rgba (pattern,
self->stops[i].offset,
self->stops[i].color.red,
self->stops[i].color.green,
self->stops[i].color.blue,
self->stops[i].color.alpha);
}
if (self->stops[self->n_stops-1].offset < 1.0)
cairo_pattern_add_color_stop_rgba (pattern,
1.0,
self->stops[self->n_stops-1].color.red,
self->stops[self->n_stops-1].color.green,
self->stops[self->n_stops-1].color.blue,
self->stops[self->n_stops-1].color.alpha);
self->stops[i].offset,
self->stops[i].color.red,
self->stops[i].color.green,
self->stops[i].color.blue,
self->stops[i].color.alpha);
gsk_cairo_rectangle (cr, &node->bounds);
cairo_translate (cr, self->center.x, self->center.y);
@@ -1835,7 +1808,6 @@ gsk_texture_scale_node_draw (GskRenderNode *node,
cairo_matrix_init_scale (&matrix,
gdk_texture_get_width (self->texture) / node->bounds.size.width,
gdk_texture_get_height (self->texture) / node->bounds.size.height);
cairo_matrix_translate (&matrix, -node->bounds.origin.x, -node->bounds.origin.y);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_pattern_set_filter (pattern, filters[self->filter]);
@@ -1843,15 +1815,23 @@ gsk_texture_scale_node_draw (GskRenderNode *node,
cairo_pattern_destroy (pattern);
cairo_surface_destroy (surface);
gsk_cairo_rectangle (cr2, &node->bounds);
cairo_rectangle (cr2, 0, 0, node->bounds.size.width, node->bounds.size.height);
cairo_fill (cr2);
cairo_destroy (cr2);
cairo_save (cr);
cairo_set_source_surface (cr, surface2, 0, 0);
cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD);
pattern = cairo_pattern_create_for_surface (surface2);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
cairo_matrix_init_identity (&matrix);
cairo_matrix_translate (&matrix,
-node->bounds.origin.x,
-node->bounds.origin.y);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_set_source (cr, pattern);
cairo_pattern_destroy (pattern);
cairo_surface_destroy (surface2);
gsk_cairo_rectangle (cr, &node->bounds);
@@ -3861,12 +3841,11 @@ gsk_color_matrix_node_class_init (gpointer g_class,
* Creates a `GskRenderNode` that will drawn the @child with
* @color_matrix.
*
* In particular, the node will transform colors by applying
* In particular, the node will transform the operation
*
* pixel = transpose(color_matrix) * pixel + color_offset
* pixel = color_matrix * pixel + color_offset
*
* for every pixel. The transformation operates on unpremultiplied
* colors, with color components ordered R, G, B, A.
* for every pixel.
*
* Returns: (transfer full) (type GskColorMatrixNode): A new `GskRenderNode`
*/
@@ -4390,6 +4369,403 @@ gsk_rounded_clip_node_get_clip (const GskRenderNode *node)
return &self->clip;
}
/* }}} */
/* {{{ GSK_FILL_NODE */
struct _GskFillNode
{
GskRenderNode render_node;
GskRenderNode *child;
GskPath *path;
GskFillRule fill_rule;
};
static void
gsk_fill_node_finalize (GskRenderNode *node)
{
GskFillNode *self = (GskFillNode *) node;
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_FILL_NODE));
gsk_render_node_unref (self->child);
gsk_path_unref (self->path);
parent_class->finalize (node);
}
static void
gsk_fill_node_draw (GskRenderNode *node,
cairo_t *cr)
{
GskFillNode *self = (GskFillNode *) node;
cairo_save (cr);
switch (self->fill_rule)
{
case GSK_FILL_RULE_WINDING:
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING);
break;
case GSK_FILL_RULE_EVEN_ODD:
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
break;
default:
g_assert_not_reached ();
break;
}
gsk_path_to_cairo (self->path, cr);
if (gsk_render_node_get_node_type (self->child) == GSK_COLOR_NODE &&
gsk_rect_contains_rect (&self->child->bounds, &node->bounds))
{
gdk_cairo_set_source_rgba (cr, gsk_color_node_get_color (self->child));
cairo_fill (cr);
}
else
{
cairo_clip (cr);
gsk_render_node_draw (self->child, cr);
}
cairo_restore (cr);
}
static void
gsk_fill_node_diff (GskRenderNode *node1,
GskRenderNode *node2,
cairo_region_t *region)
{
GskFillNode *self1 = (GskFillNode *) node1;
GskFillNode *self2 = (GskFillNode *) node2;
if (self1->path == self2->path)
{
cairo_region_t *sub;
cairo_rectangle_int_t clip_rect;
sub = cairo_region_create();
gsk_render_node_diff (self1->child, self2->child, sub);
rectangle_init_from_graphene (&clip_rect, &node1->bounds);
cairo_region_intersect_rectangle (sub, &clip_rect);
cairo_region_union (region, sub);
cairo_region_destroy (sub);
}
else
{
gsk_render_node_diff_impossible (node1, node2, region);
}
}
static void
gsk_fill_node_class_init (gpointer g_class,
gpointer class_data)
{
GskRenderNodeClass *node_class = g_class;
node_class->node_type = GSK_FILL_NODE;
node_class->finalize = gsk_fill_node_finalize;
node_class->draw = gsk_fill_node_draw;
node_class->diff = gsk_fill_node_diff;
}
/**
* gsk_fill_node_new:
* @child: The node to fill the area with
* @path: The path describing the area to fill
* @fill_rule: The fill rule to use
*
* Creates a `GskRenderNode` that will fill the @child in the area
* given by @path and @fill_rule.
*
* Returns: (transfer none) (type GskFillNode): A new `GskRenderNode`
*
* Since: 4.14
*/
GskRenderNode *
gsk_fill_node_new (GskRenderNode *child,
GskPath *path,
GskFillRule fill_rule)
{
GskFillNode *self;
GskRenderNode *node;
graphene_rect_t path_bounds;
g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
g_return_val_if_fail (path != NULL, NULL);
self = gsk_render_node_alloc (GSK_FILL_NODE);
node = (GskRenderNode *) self;
self->child = gsk_render_node_ref (child);
self->path = gsk_path_ref (path);
self->fill_rule = fill_rule;
if (gsk_path_get_bounds (path, &path_bounds))
graphene_rect_intersection (&path_bounds, &child->bounds, &node->bounds);
else
graphene_rect_init_from_rect (&node->bounds, graphene_rect_zero ());
return node;
}
/**
* gsk_fill_node_get_child:
* @node: (type GskFillNode): a fill `GskRenderNode`
*
* Gets the child node that is getting drawn by the given @node.
*
* Returns: (transfer none): The child that is getting drawn
*
* Since: 4.14
*/
GskRenderNode *
gsk_fill_node_get_child (const GskRenderNode *node)
{
const GskFillNode *self = (const GskFillNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_FILL_NODE), NULL);
return self->child;
}
/**
* gsk_fill_node_get_path:
* @node: (type GskFillNode): a fill `GskRenderNode`
*
* Retrieves the path used to describe the area filled with the contents of
* the @node.
*
* Returns: (transfer none): a `GskPath`
*
* Since: 4.14
*/
GskPath *
gsk_fill_node_get_path (const GskRenderNode *node)
{
const GskFillNode *self = (const GskFillNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_FILL_NODE), NULL);
return self->path;
}
/**
* gsk_fill_node_get_fill_rule:
* @node: (type GskFillNode): a fill `GskRenderNode`
*
* Retrieves the fill rule used to determine how the path is filled.
*
* Returns: a `GskFillRule`
*
* Since: 4.14
*/
GskFillRule
gsk_fill_node_get_fill_rule (const GskRenderNode *node)
{
const GskFillNode *self = (const GskFillNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_FILL_NODE), GSK_FILL_RULE_WINDING);
return self->fill_rule;
}
/* }}} */
/* {{{ GSK_STROKE_NODE */
struct _GskStrokeNode
{
GskRenderNode render_node;
GskRenderNode *child;
GskPath *path;
GskStroke stroke;
};
static void
gsk_stroke_node_finalize (GskRenderNode *node)
{
GskStrokeNode *self = (GskStrokeNode *) node;
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_STROKE_NODE));
gsk_render_node_unref (self->child);
gsk_path_unref (self->path);
gsk_stroke_clear (&self->stroke);
parent_class->finalize (node);
}
static void
gsk_stroke_node_draw (GskRenderNode *node,
cairo_t *cr)
{
GskStrokeNode *self = (GskStrokeNode *) node;
cairo_save (cr);
if (gsk_render_node_get_node_type (self->child) == GSK_COLOR_NODE &&
gsk_rect_contains_rect (&self->child->bounds, &node->bounds))
{
gdk_cairo_set_source_rgba (cr, gsk_color_node_get_color (self->child));
}
else
{
gsk_cairo_rectangle (cr, &self->child->bounds);
cairo_clip (cr);
cairo_push_group (cr);
gsk_render_node_draw (self->child, cr);
cairo_pop_group_to_source (cr);
}
gsk_stroke_to_cairo (&self->stroke, cr);
gsk_path_to_cairo (self->path, cr);
cairo_stroke (cr);
cairo_restore (cr);
}
static void
gsk_stroke_node_diff (GskRenderNode *node1,
GskRenderNode *node2,
cairo_region_t *region)
{
GskStrokeNode *self1 = (GskStrokeNode *) node1;
GskStrokeNode *self2 = (GskStrokeNode *) node2;
if (self1->path == self2->path &&
gsk_stroke_equal (&self1->stroke, &self2->stroke))
{
cairo_region_t *sub;
cairo_rectangle_int_t clip_rect;
sub = cairo_region_create();
gsk_render_node_diff (self1->child, self2->child, sub);
rectangle_init_from_graphene (&clip_rect, &node1->bounds);
cairo_region_intersect_rectangle (sub, &clip_rect);
cairo_region_union (region, sub);
cairo_region_destroy (sub);
}
else
{
gsk_render_node_diff_impossible (node1, node2, region);
}
}
static void
gsk_stroke_node_class_init (gpointer g_class,
gpointer class_data)
{
GskRenderNodeClass *node_class = g_class;
node_class->node_type = GSK_STROKE_NODE;
node_class->finalize = gsk_stroke_node_finalize;
node_class->draw = gsk_stroke_node_draw;
node_class->diff = gsk_stroke_node_diff;
}
/**
* gsk_stroke_node_new:
* @child: The node to stroke the area with
* @path: (transfer none): The path describing the area to stroke
* @stroke: (transfer none): The stroke attributes to use
*
* Creates a #GskRenderNode that will stroke the @child along the given
* @path using the attributes defined in @stroke.
*
* Returns: (transfer none) (type GskStrokeNode): A new #GskRenderNode
*
* Since: 4.14
*/
GskRenderNode *
gsk_stroke_node_new (GskRenderNode *child,
GskPath *path,
const GskStroke *stroke)
{
GskStrokeNode *self;
GskRenderNode *node;
graphene_rect_t stroke_bounds;
g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
g_return_val_if_fail (path != NULL, NULL);
g_return_val_if_fail (stroke != NULL, NULL);
self = gsk_render_node_alloc (GSK_STROKE_NODE);
node = (GskRenderNode *) self;
self->child = gsk_render_node_ref (child);
self->path = gsk_path_ref (path);
gsk_stroke_init_copy (&self->stroke, stroke);
if (gsk_path_get_stroke_bounds (self->path, &self->stroke, &stroke_bounds))
graphene_rect_intersection (&stroke_bounds, &child->bounds, &node->bounds);
else
graphene_rect_init_from_rect (&node->bounds, graphene_rect_zero ());
return node;
}
/**
* gsk_stroke_node_get_child:
* @node: (type GskStrokeNode): a stroke #GskRenderNode
*
* Gets the child node that is getting drawn by the given @node.
*
* Returns: (transfer none): The child that is getting drawn
*
* Since: 4.14
*/
GskRenderNode *
gsk_stroke_node_get_child (const GskRenderNode *node)
{
const GskStrokeNode *self = (const GskStrokeNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_STROKE_NODE), NULL);
return self->child;
}
/**
* gsk_stroke_node_get_path:
* @node: (type GskStrokeNode): a stroke #GskRenderNode
*
* Retrieves the path that will be stroked with the contents of
* the @node.
*
* Returns: (transfer none): a #GskPath
*
* Since: 4.14
*/
GskPath *
gsk_stroke_node_get_path (const GskRenderNode *node)
{
const GskStrokeNode *self = (const GskStrokeNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_STROKE_NODE), NULL);
return self->path;
}
/**
* gsk_stroke_node_get_stroke:
* @node: (type GskStrokeNode): a stroke #GskRenderNode
*
* Retrieves the stroke attributes used in this @node.
*
* Returns: a #GskStroke
*
* Since: 4.14
*/
const GskStroke *
gsk_stroke_node_get_stroke (const GskRenderNode *node)
{
const GskStrokeNode *self = (const GskStrokeNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_STROKE_NODE), NULL);
return &self->stroke;
}
/* }}} */
/* {{{ GSK_SHADOW_NODE */
@@ -4425,8 +4801,18 @@ gsk_shadow_node_draw (GskRenderNode *node,
cairo_t *cr)
{
GskShadowNode *self = (GskShadowNode *) node;
cairo_pattern_t *pattern;
gsize i;
cairo_save (cr);
/* clip so the push_group() creates a small surface */
gsk_cairo_rectangle (cr, &self->child->bounds);
cairo_clip (cr);
cairo_push_group (cr);
gsk_render_node_draw (self->child, cr);
pattern = cairo_pop_group (cr);
cairo_restore (cr);
cairo_save (cr);
/* clip so the blur area stays small */
gsk_cairo_rectangle (cr, &node->bounds);
@@ -4435,31 +4821,27 @@ gsk_shadow_node_draw (GskRenderNode *node,
for (i = 0; i < self->n_shadows; i++)
{
GskShadow *shadow = &self->shadows[i];
cairo_pattern_t *pattern;
/* We don't need to draw invisible shadows */
if (gdk_rgba_is_clear (&shadow->color))
continue;
cairo_save (cr);
gdk_cairo_set_source_rgba (cr, &shadow->color);
cr = gsk_cairo_blur_start_drawing (cr, shadow->radius, GSK_BLUR_X | GSK_BLUR_Y);
cairo_save (cr);
cairo_translate (cr, shadow->dx, shadow->dy);
cairo_push_group (cr);
gsk_render_node_draw (self->child, cr);
pattern = cairo_pop_group (cr);
gdk_cairo_set_source_rgba (cr, &shadow->color);
cairo_mask (cr, pattern);
cairo_restore (cr);
cr = gsk_cairo_blur_finish_drawing (cr, shadow->radius, &shadow->color, GSK_BLUR_X | GSK_BLUR_Y);
cairo_restore (cr);
}
gsk_render_node_draw (self->child, cr);
cairo_set_source (cr, pattern);
cairo_paint (cr);
cairo_restore (cr);
cairo_pattern_destroy (pattern);
}
static void
@@ -4580,7 +4962,7 @@ gsk_shadow_node_new (GskRenderNode *child,
self = gsk_render_node_alloc (GSK_SHADOW_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = TRUE;
node->offscreen_for_opacity = child->offscreen_for_opacity;
self->child = gsk_render_node_ref (child);
self->n_shadows = n_shadows;
@@ -6277,6 +6659,8 @@ GSK_DEFINE_RENDER_NODE_TYPE (gsk_color_matrix_node, GSK_COLOR_MATRIX_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_repeat_node, GSK_REPEAT_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_clip_node, GSK_CLIP_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_rounded_clip_node, GSK_ROUNDED_CLIP_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_fill_node, GSK_FILL_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_stroke_node, GSK_STROKE_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_shadow_node, GSK_SHADOW_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_blend_node, GSK_BLEND_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_cross_fade_node, GSK_CROSS_FADE_NODE)
@@ -6425,6 +6809,16 @@ gsk_render_node_init_types_once (void)
sizeof (GskDebugNode),
gsk_debug_node_class_init);
gsk_render_node_types[GSK_DEBUG_NODE] = node_type;
node_type = gsk_render_node_type_register_static (I_("GskFillNode"),
sizeof (GskFillNode),
gsk_fill_node_class_init);
gsk_render_node_types[GSK_FILL_NODE] = node_type;
node_type = gsk_render_node_type_register_static (I_("GskStrokeNode"),
sizeof (GskStrokeNode),
gsk_stroke_node_class_init);
gsk_render_node_types[GSK_STROKE_NODE] = node_type;
}
static void
+279 -4
View File
@@ -23,9 +23,13 @@
#include "gskrendernodeparserprivate.h"
#include "gskpath.h"
#include "gskpathbuilder.h"
#include "gskroundedrectprivate.h"
#include "gskrendernodeprivate.h"
#include "gskstroke.h"
#include "gsktransformprivate.h"
#include "gskenumtypes.h"
#include "gdk/gdkrgbaprivate.h"
#include "gdk/gdktextureprivate.h"
@@ -1174,6 +1178,26 @@ create_default_render_node (void)
return gsk_color_node_new (&GDK_RGBA("FF00CC"), &GRAPHENE_RECT_INIT (0, 0, 50, 50));
}
static GskPath *
create_default_path (void)
{
GskPathBuilder *builder;
guint i;
builder = gsk_path_builder_new ();
gsk_path_builder_move_to (builder, 25, 0);
for (i = 1; i < 5; i++)
{
gsk_path_builder_line_to (builder,
sin (i * G_PI * 0.8) * 25 + 25,
-cos (i * G_PI * 0.8) * 25 + 25);
}
gsk_path_builder_close (builder);
return gsk_path_builder_free_to_path (builder);
}
static GskRenderNode *
parse_color_node (GtkCssParser *parser,
Context *context)
@@ -2097,6 +2121,165 @@ parse_rounded_clip_node (GtkCssParser *parser,
return result;
}
static gboolean
parse_path (GtkCssParser *parser,
Context *context,
gpointer out_path)
{
GskPath *path;
char *str = NULL;
if (!parse_string (parser, context, &str))
return FALSE;
path = gsk_path_parse (str);
g_free (str);
if (path == NULL)
{
gtk_css_parser_error_value (parser, "Invalid path");
return FALSE;
}
*((GskPath **) out_path) = path;
return TRUE;
}
static void
clear_path (gpointer inout_path)
{
g_clear_pointer ((GskPath **) inout_path, gsk_path_unref);
}
static gboolean
parse_enum (GtkCssParser *parser,
GType type,
gpointer out_value)
{
GEnumClass *class;
GEnumValue *v;
char *enum_name;
enum_name = gtk_css_parser_consume_ident (parser);
if (enum_name == NULL)
return FALSE;
class = g_type_class_ref (type);
v = g_enum_get_value_by_nick (class, enum_name);
if (v == NULL)
{
gtk_css_parser_error_value (parser, "Unknown value \"%s\" for enum \"%s\"",
enum_name, g_type_name (type));
g_free (enum_name);
g_type_class_unref (class);
return FALSE;
}
*(int*)out_value = v->value;
g_free (enum_name);
g_type_class_unref (class);
return TRUE;
}
static gboolean
parse_fill_rule (GtkCssParser *parser,
Context *context,
gpointer out_rule)
{
return parse_enum (parser, GSK_TYPE_FILL_RULE, out_rule);
}
static GskRenderNode *
parse_fill_node (GtkCssParser *parser,
Context *context)
{
GskRenderNode *child = NULL;
GskPath *path = NULL;
int rule = GSK_FILL_RULE_WINDING;
const Declaration declarations[] = {
{ "child", parse_node, clear_node, &child },
{ "path", parse_path, clear_path, &path },
{ "fill-rule", parse_fill_rule, NULL, &rule },
};
GskRenderNode *result;
parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations));
if (child == NULL)
child = create_default_render_node ();
if (path == NULL)
path = create_default_path ();
result = gsk_fill_node_new (child, path, rule);
gsk_path_unref (path);
gsk_render_node_unref (child);
return result;
}
static gboolean
parse_line_cap (GtkCssParser *parser,
Context *context,
gpointer out)
{
return parse_enum (parser, GSK_TYPE_LINE_CAP, out);
}
static gboolean
parse_line_join (GtkCssParser *parser,
Context *context,
gpointer out)
{
return parse_enum (parser, GSK_TYPE_LINE_JOIN, out);
}
static GskRenderNode *
parse_stroke_node (GtkCssParser *parser,
Context *context)
{
GskRenderNode *child = NULL;
GskPath *path = NULL;
double line_width = 1.0;
int line_cap = GSK_LINE_CAP_BUTT;
int line_join = GSK_LINE_JOIN_MITER;
double miter_limit = 4.0;
GskStroke *stroke;
const Declaration declarations[] = {
{ "child", parse_node, clear_node, &child },
{ "path", parse_path, clear_path, &path },
{ "line-width", parse_positive_double, NULL, &line_width },
{ "line-cap", parse_line_cap, NULL, &line_cap },
{ "line-join", parse_line_join, NULL, &line_join },
{ "miter-limit", parse_positive_double, NULL, &miter_limit }
};
GskRenderNode *result;
parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations));
if (child == NULL)
child = create_default_render_node ();
if (path == NULL)
path = create_default_path ();
stroke = gsk_stroke_new (line_width);
gsk_stroke_set_line_cap (stroke, line_cap);
gsk_stroke_set_line_join (stroke, line_join);
gsk_stroke_set_miter_limit (stroke, miter_limit);
result = gsk_stroke_node_new (child, path, stroke);
gsk_path_unref (path);
gsk_stroke_free (stroke);
gsk_render_node_unref (child);
return result;
}
static GskRenderNode *
parse_shadow_node (GtkCssParser *parser,
Context *context)
@@ -2179,6 +2362,8 @@ parse_node (GtkCssParser *parser,
{ "repeating-linear-gradient", parse_repeating_linear_gradient_node },
{ "repeating-radial-gradient", parse_repeating_radial_gradient_node },
{ "rounded-clip", parse_rounded_clip_node },
{ "fill", parse_fill_node },
{ "stroke", parse_stroke_node },
{ "shadow", parse_shadow_node },
{ "text", parse_text_node },
{ "texture", parse_texture_node },
@@ -2433,6 +2618,14 @@ printer_init_duplicates_for_node (Printer *printer,
printer_init_duplicates_for_node (printer, gsk_debug_node_get_child (node));
break;
case GSK_FILL_NODE:
printer_init_duplicates_for_node (printer, gsk_fill_node_get_child (node));
break;
case GSK_STROKE_NODE:
printer_init_duplicates_for_node (printer, gsk_stroke_node_get_child (node));
break;
case GSK_BLEND_NODE:
printer_init_duplicates_for_node (printer, gsk_blend_node_get_bottom_child (node));
printer_init_duplicates_for_node (printer, gsk_blend_node_get_top_child (node));
@@ -2658,7 +2851,7 @@ append_float_param (Printer *p,
float value,
float default_value)
{
/* Don't approximate-compare here, better be topo verbose */
/* Don't approximate-compare here, better be too verbose */
if (value == default_value)
return;
@@ -2833,8 +3026,11 @@ append_escaping_newlines (GString *str,
len = strcspn (string, "\n");
g_string_append_len (str, string, len);
string += len;
g_string_append (str, "\\\n");
string++;
if (*string)
{
g_string_append (str, "\\\n");
string++;
}
} while (*string);
}
@@ -3019,7 +3215,7 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node,
string_append_double (p, (double) glyphs[i].geometry.y_offset / PANGO_SCALE);
if (!glyphs[i].attr.is_cluster_start)
g_string_append (p, " same-cluster");
if (glyphs[i].attr.is_color)
if (!glyphs[i].attr.is_color)
g_string_append (p, " color");
}
@@ -3035,6 +3231,55 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node,
pango_glyph_string_free (ascii);
}
static const char *
enum_to_nick (GType type,
int value)
{
GEnumClass *class;
GEnumValue *v;
class = g_type_class_ref (type);
v = g_enum_get_value (class, value);
g_type_class_unref (class);
return v->value_nick;
}
static void
append_enum_param (Printer *p,
const char *param_name,
GType type,
int value)
{
_indent (p);
g_string_append_printf (p->str, "%s: ", param_name);
g_string_append (p->str, enum_to_nick (type, value));
g_string_append_c (p->str, ';');
g_string_append_c (p->str, '\n');
}
static void
append_path_param (Printer *p,
const char *param_name,
GskPath *path)
{
char *str, *s;
_indent (p);
g_string_append (p->str, "path: \"\\\n");
str = gsk_path_to_string (path);
/* Put each command on a new line */
for (s = str; *s; s++)
{
if (*s == ' ' &&
(s[1] == 'M' || s[1] == 'C' || s[1] == 'Z' || s[1] == 'L'))
*s = '\n';
}
append_escaping_newlines (p->str, str);
g_string_append (p->str, "\";\n");
g_free (str);
}
static void
render_node_print (Printer *p,
GskRenderNode *node)
@@ -3204,6 +3449,36 @@ render_node_print (Printer *p,
append_rounded_rect_param (p, "clip", gsk_rounded_clip_node_get_clip (node));
append_node_param (p, "child", gsk_rounded_clip_node_get_child (node));
end_node (p);
}
break;
case GSK_FILL_NODE:
{
start_node (p, "fill", node_name);
append_node_param (p, "child", gsk_fill_node_get_child (node));
append_path_param (p, "path", gsk_fill_node_get_path (node));
append_enum_param (p, "fill-rule", GSK_TYPE_FILL_RULE, gsk_fill_node_get_fill_rule (node));
end_node (p);
}
break;
case GSK_STROKE_NODE:
{
const GskStroke *stroke;
start_node (p, "stroke", node_name);
append_node_param (p, "child", gsk_stroke_node_get_child (node));
append_path_param (p, "path", gsk_stroke_node_get_path (node));
stroke = gsk_stroke_node_get_stroke (node);
append_float_param (p, "line-width", gsk_stroke_get_line_width (stroke), 0.0f);
append_enum_param (p, "line-cap", GSK_TYPE_LINE_CAP, gsk_stroke_get_line_cap (stroke));
append_enum_param (p, "line-join", GSK_TYPE_LINE_JOIN, gsk_stroke_get_line_join (stroke));
append_float_param (p, "miter-limit", gsk_stroke_get_miter_limit (stroke), 4.0f);
end_node (p);
}
-14
View File
@@ -21,9 +21,6 @@ extern GType gsk_render_node_types[];
#define GSK_IS_RENDER_NODE_TYPE(node,type) \
(G_TYPE_INSTANCE_GET_CLASS ((node), GSK_TYPE_RENDER_NODE, GskRenderNodeClass)->node_type == (type))
#define GSK_RENDER_NODE_TYPE(node) \
(G_TYPE_INSTANCE_GET_CLASS ((node), GSK_TYPE_RENDER_NODE, GskRenderNodeClass)->node_type)
struct _GskRenderNode
{
GTypeInstance parent_instance;
@@ -60,8 +57,6 @@ GType gsk_render_node_type_register_static (const char
gpointer gsk_render_node_alloc (GskRenderNodeType node_type);
void _gsk_render_node_unref (GskRenderNode *node);
gboolean gsk_render_node_can_diff (const GskRenderNode *node1,
const GskRenderNode *node2) G_GNUC_PURE;
void gsk_render_node_diff (GskRenderNode *node1,
@@ -92,15 +87,6 @@ gboolean gsk_container_node_is_disjoint (const GskRenderNode
gboolean gsk_render_node_use_offscreen_for_opacity (const GskRenderNode *node);
#define gsk_render_node_ref(node) _gsk_render_node_ref(node)
#define gsk_render_node_unref(node) _gsk_render_node_unref(node)
static inline GskRenderNode *
_gsk_render_node_ref (GskRenderNode *node)
{
g_atomic_ref_count_inc (&node->ref_count);
return node;
}
G_END_DECLS
+208
View File
@@ -0,0 +1,208 @@
/*
* Copyright © 2002 University of Southern California
* 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
* Carl D. Worth <cworth@cworth.org>
*/
#include "config.h"
#include "gsksplineprivate.h"
#include <math.h>
/* Spline deviation from the circle in radius would be given by:
error = sqrt (x**2 + y**2) - 1
A simpler error function to work with is:
e = x**2 + y**2 - 1
From "Good approximation of circles by curvature-continuous Bezier
curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
Design 8 (1990) 22-41, we learn:
abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4)
and
abs (error) =~ 1/2 * e
Of course, this error value applies only for the particular spline
approximation that is used in _cairo_gstate_arc_segment.
*/
static float
arc_error_normalized (float angle)
{
return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
}
static float
arc_max_angle_for_tolerance_normalized (float tolerance)
{
float angle, error;
guint i;
/* Use table lookup to reduce search time in most cases. */
struct {
float angle;
float error;
} table[] = {
{ G_PI / 1.0, 0.0185185185185185036127 },
{ G_PI / 2.0, 0.000272567143730179811158 },
{ G_PI / 3.0, 2.38647043651461047433e-05 },
{ G_PI / 4.0, 4.2455377443222443279e-06 },
{ G_PI / 5.0, 1.11281001494389081528e-06 },
{ G_PI / 6.0, 3.72662000942734705475e-07 },
{ G_PI / 7.0, 1.47783685574284411325e-07 },
{ G_PI / 8.0, 6.63240432022601149057e-08 },
{ G_PI / 9.0, 3.2715520137536980553e-08 },
{ G_PI / 10.0, 1.73863223499021216974e-08 },
{ G_PI / 11.0, 9.81410988043554039085e-09 },
};
for (i = 0; i < G_N_ELEMENTS (table); i++)
{
if (table[i].error < tolerance)
return table[i].angle;
}
i++;
do {
angle = G_PI / i++;
error = arc_error_normalized (angle);
} while (error > tolerance);
return angle;
}
static guint
arc_segments_needed (float angle,
float radius,
float tolerance)
{
float max_angle;
/* the error is amplified by at most the length of the
* major axis of the circle; see cairo-pen.c for a more detailed analysis
* of this. */
max_angle = arc_max_angle_for_tolerance_normalized (tolerance / radius);
return ceil (fabs (angle) / max_angle);
}
/* We want to draw a single spline approximating a circular arc radius
R from angle A to angle B. Since we want a symmetric spline that
matches the endpoints of the arc in position and slope, we know
that the spline control points must be:
(R * cos(A), R * sin(A))
(R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
(R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
(R * cos(B), R * sin(B))
for some value of h.
"Approximation of circular arcs by cubic polynomials", Michael
Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides
various values of h along with error analysis for each.
From that paper, a very practical value of h is:
h = 4/3 * R * tan(angle/4)
This value does not give the spline with minimal error, but it does
provide a very good approximation, (6th-order convergence), and the
error expression is quite simple, (see the comment for
_arc_error_normalized).
*/
static gboolean
gsk_spline_decompose_arc_segment (const graphene_point_t *center,
float radius,
float angle_A,
float angle_B,
GskSplineAddCurveFunc curve_func,
gpointer user_data)
{
float r_sin_A, r_cos_A;
float r_sin_B, r_cos_B;
float h;
r_sin_A = radius * sin (angle_A);
r_cos_A = radius * cos (angle_A);
r_sin_B = radius * sin (angle_B);
r_cos_B = radius * cos (angle_B);
h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
return curve_func ((graphene_point_t[4]) {
GRAPHENE_POINT_INIT (
center->x + r_cos_A,
center->y + r_sin_A
),
GRAPHENE_POINT_INIT (
center->x + r_cos_A - h * r_sin_A,
center->y + r_sin_A + h * r_cos_A
),
GRAPHENE_POINT_INIT (
center->x + r_cos_B + h * r_sin_B,
center->y + r_sin_B - h * r_cos_B
),
GRAPHENE_POINT_INIT (
center->x + r_cos_B,
center->y + r_sin_B
)
},
user_data);
}
gboolean
gsk_spline_decompose_arc (const graphene_point_t *center,
float radius,
float tolerance,
float start_angle,
float end_angle,
GskSplineAddCurveFunc curve_func,
gpointer user_data)
{
float step = start_angle - end_angle;
guint i, n_segments;
/* Recurse if drawing arc larger than pi */
if (ABS (step) > G_PI)
{
float mid_angle = (start_angle + end_angle) / 2.0;
return gsk_spline_decompose_arc (center, radius, tolerance, start_angle, mid_angle, curve_func, user_data)
&& gsk_spline_decompose_arc (center, radius, tolerance, mid_angle, end_angle, curve_func, user_data);
}
else if (ABS (step) < tolerance)
{
return gsk_spline_decompose_arc_segment (center, radius, start_angle, end_angle, curve_func, user_data);
}
n_segments = arc_segments_needed (ABS (step), radius, tolerance);
step = (end_angle - start_angle) / n_segments;
for (i = 0; i < n_segments - 1; i++, start_angle += step)
{
if (!gsk_spline_decompose_arc_segment (center, radius, start_angle, start_angle + step, curve_func, user_data))
return FALSE;
}
return gsk_spline_decompose_arc_segment (center, radius, start_angle, end_angle, curve_func, user_data);
}
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GSK_SPLINE_PRIVATE_H__
#define __GSK_SPLINE_PRIVATE_H__
#include "gskpath.h"
G_BEGIN_DECLS
typedef gboolean (* GskSplineAddCurveFunc) (const graphene_point_t curve[4],
gpointer user_data);
gboolean gsk_spline_decompose_arc (const graphene_point_t *center,
float radius,
float tolerance,
float start_angle,
float end_angle,
GskSplineAddCurveFunc curve_func,
gpointer user_data);
G_END_DECLS
#endif /* __GSK_SPLINE_PRIVATE_H__ */
+535
View File
@@ -0,0 +1,535 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gskstrokeprivate.h"
/**
* GskStroke:
*
* A `GskStroke` struct collects the parameters that influence
* the operation of stroking a path.
*/
G_DEFINE_BOXED_TYPE (GskStroke, gsk_stroke, gsk_stroke_copy, gsk_stroke_free)
/**
* gsk_stroke_new:
* @line_width: line width of the stroke. Must be > 0
*
* Creates a new `GskStroke` with the given @line_width.
*
* Returns: a new `GskStroke`
*
* Since: 4.14
*/
GskStroke *
gsk_stroke_new (float line_width)
{
GskStroke *self;
g_return_val_if_fail (line_width > 0, NULL);
self = g_new0 (GskStroke, 1);
self->line_width = line_width;
self->line_cap = GSK_LINE_CAP_BUTT;
self->line_join = GSK_LINE_JOIN_MITER;
self->miter_limit = 4.f; /* following svg */
return self;
}
/**
* gsk_stroke_copy:
* @other: `GskStroke` to copy
*
* Creates a copy of the given @other stroke.
*
* Returns: a new `GskStroke`. Use [method@Gsk.Stroke.free] to free it
*
* Since: 4.14
*/
GskStroke *
gsk_stroke_copy (const GskStroke *other)
{
GskStroke *self;
g_return_val_if_fail (other != NULL, NULL);
self = g_new (GskStroke, 1);
gsk_stroke_init_copy (self, other);
return self;
}
/**
* gsk_stroke_free:
* @self: a `GskStroke`
*
* Frees a `GskStroke`.
*
* Since: 4.14
*/
void
gsk_stroke_free (GskStroke *self)
{
if (self == NULL)
return;
gsk_stroke_clear (self);
g_free (self);
}
/**
* gsk_stroke_to_cairo:
* @self: a `GskStroke`
* @cr: the cairo context to configure
*
* A helper function that sets the stroke parameters
* of @cr from the values found in @self.
*
* Since: 4.14
*/
void
gsk_stroke_to_cairo (const GskStroke *self,
cairo_t *cr)
{
cairo_set_line_width (cr, self->line_width);
/* gcc can optimize that to a direct case. This catches later additions to the enum */
switch (self->line_cap)
{
case GSK_LINE_CAP_BUTT:
cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
break;
case GSK_LINE_CAP_ROUND:
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
break;
case GSK_LINE_CAP_SQUARE:
cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
break;
default:
g_assert_not_reached ();
break;
}
/* gcc can optimize that to a direct case. This catches later additions to the enum */
switch (self->line_join)
{
case GSK_LINE_JOIN_MITER:
cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
break;
case GSK_LINE_JOIN_ROUND:
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
break;
case GSK_LINE_JOIN_BEVEL:
cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL);
break;
default:
g_assert_not_reached ();
break;
}
cairo_set_miter_limit (cr, self->miter_limit);
if (self->dash_length)
{
gsize i;
double *dash = g_newa (double, self->n_dash);
for (i = 0; i < self->n_dash; i++)
{
dash[i] = self->dash[i];
}
cairo_set_dash (cr, dash, self->n_dash, self->dash_offset);
}
else
cairo_set_dash (cr, NULL, 0, 0.0);
}
/**
* gsk_stroke_equal:
* @stroke1: the first `GskStroke`
* @stroke2: the second `GskStroke`
*
* Checks if 2 strokes are identical.
*
* Returns: `TRUE` if the 2 strokes are equal, `FALSE` otherwise
*
* Since: 4.14
*/
gboolean
gsk_stroke_equal (gconstpointer stroke1,
gconstpointer stroke2)
{
const GskStroke *self1 = stroke1;
const GskStroke *self2 = stroke2;
if (self1->line_width != self2->line_width ||
self1->line_cap != self2->line_cap ||
self1->line_join != self2->line_join ||
self1->miter_limit != self2->miter_limit ||
self1->n_dash != self2->n_dash ||
self1->dash_offset != self2->dash_offset)
return FALSE;
for (gsize i = 0; i < self1->n_dash; i++)
if (self1->dash[i] != self2->dash[i])
return FALSE;
return TRUE;
}
/**
* gsk_stroke_set_line_width:
* @self: a `GskStroke`
* @line_width: width of the line in pixels
*
* Sets the line width to be used when stroking.
*
* The line width must be > 0.
*
* Since: 4.14
*/
void
gsk_stroke_set_line_width (GskStroke *self,
float line_width)
{
g_return_if_fail (self != NULL);
g_return_if_fail (line_width > 0);
self->line_width = line_width;
}
/**
* gsk_stroke_get_line_width:
* @self: a `GskStroke`
*
* Gets the line width used.
*
* Returns: The line width
*
* Since: 4.14
*/
float
gsk_stroke_get_line_width (const GskStroke *self)
{
g_return_val_if_fail (self != NULL, 0.0);
return self->line_width;
}
/**
* gsk_stroke_set_line_cap:
* @self: a`GskStroke`
* @line_cap: the `GskLineCap`
*
* Sets the line cap to be used when stroking.
*
* See [enum@Gsk.LineCap] for details.
*
* Since: 4.14
*/
void
gsk_stroke_set_line_cap (GskStroke *self,
GskLineCap line_cap)
{
g_return_if_fail (self != NULL);
self->line_cap = line_cap;
}
/**
* gsk_stroke_get_line_cap:
* @self: a `GskStroke`
*
* Gets the line cap used.
*
* See [enum@Gsk.LineCap] for details.
*
* Returns: The line cap
*
* Since: 4.14
*/
GskLineCap
gsk_stroke_get_line_cap (const GskStroke *self)
{
g_return_val_if_fail (self != NULL, 0.0);
return self->line_cap;
}
/**
* gsk_stroke_set_line_join:
* @self: a `GskStroke`
* @line_join: The line join to use
*
* Sets the line join to be used when stroking.
*
* See [enum@Gsk.LineJoin] for details.
*
* Since: 4.14
*/
void
gsk_stroke_set_line_join (GskStroke *self,
GskLineJoin line_join)
{
g_return_if_fail (self != NULL);
self->line_join = line_join;
}
/**
* gsk_stroke_get_line_join:
* @self: a `GskStroke`
*
* Gets the line join used.
*
* See [enum@Gsk.LineJoin] for details.
*
* Returns: The line join
*
* Since: 4.14
*/
GskLineJoin
gsk_stroke_get_line_join (const GskStroke *self)
{
g_return_val_if_fail (self != NULL, 0.0);
return self->line_join;
}
/**
* gsk_stroke_set_miter_limit:
* @self: a `GskStroke`
* @limit: the miter limit
*
* Sets the limit for the distance from the corner where sharp
* turns of joins get cut off.
*
* The miter limit is in units of line width and must be non-negative.
*
* For joins of type `GSK_LINE_JOIN_MITER` that exceed the miter
* limit, the join gets rendered as if it was of type
* `GSK_LINE_JOIN_BEVEL`.
*
* Since: 4.14
*/
void
gsk_stroke_set_miter_limit (GskStroke *self,
float limit)
{
g_return_if_fail (self != NULL);
g_return_if_fail (limit >= 0);
self->miter_limit = limit;
}
/**
* gsk_stroke_get_miter_limit:
* @self: a `GskStroke`
*
* Returns the miter limit of a `GskStroke`.
*
* Since: 4.14
*/
float
gsk_stroke_get_miter_limit (const GskStroke *self)
{
g_return_val_if_fail (self != NULL, 4.f);
return self->miter_limit;
}
/**
* gsk_stroke_set_dash:
* @self: a `GskStroke`
* @dash: (array length=n_dash) (transfer none) (nullable):
* the array of dashes
* @n_dash: number of elements in @dash
*
* Sets the dash pattern to use by this stroke.
*
* A dash pattern is specified by an array of alternating non-negative
* values. Each value provides the length of alternate "on" and "off"
* portions of the stroke.
*
* Each "on" segment will have caps applied as if the segment were a
* separate contour. In particular, it is valid to use an "on" length
* of 0 with `GSK_LINE_CAP_ROUND` or `GSK_LINE_CAP_SQUARE` to draw dots
* or squares along a path.
*
* If @n_dash is 0, if all elements in @dash are 0, or if there are
* negative values in @dash, then dashing is disabled.
*
* If @n_dash is 1, an alternating "on" and "off" pattern with the
* single dash length provided is assumed.
*
* If @n_dash is uneven, the dash array will be used with the first
* element in @dash defining an "on" or "off" in alternating passes
* through the array.
*
* You can specify a starting offset into the dash with
* [method@Gsk.Stroke.set_dash_offset].
*
* Since: 4.14
*/
void
gsk_stroke_set_dash (GskStroke *self,
const float *dash,
gsize n_dash)
{
float dash_length;
gsize i;
g_return_if_fail (self != NULL);
g_return_if_fail (dash != NULL || n_dash == 0);
dash_length = 0;
for (i = 0; i < n_dash; i++)
{
if (!(dash[i] >= 0)) /* should catch NaN */
{
g_critical ("invalid value in dash array at position %zu", i);
return;
}
dash_length += dash[i];
}
self->dash_length = dash_length;
g_free (self->dash);
self->dash = g_memdup (dash, sizeof (gfloat) * n_dash);
self->n_dash = n_dash;
}
/**
* gsk_stroke_get_dash:
* @self: a `GskStroke`
* @n_dash: (out caller-allocates): number of elements
* in the array returned
*
* Gets the dash array in use or `NULL` if dashing is disabled.
*
* Returns: (array length=n_dash) (transfer none) (nullable):
* The dash array or `NULL` if the dash array is empty.
*
* Since: 4.14
*/
const float *
gsk_stroke_get_dash (const GskStroke *self,
gsize *n_dash)
{
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (n_dash != NULL, NULL);
*n_dash = self->n_dash;
return self->dash;
}
/**
* gsk_stroke_set_dash_offset:
* @self: a `GskStroke`
* @offset: offset into the dash pattern
*
* Sets the offset into the dash pattern where dashing should begin.
*
* This is an offset into the length of the path, not an index into
* the array values of the dash array.
*
* See [method@Gsk.Stroke.set_dash] for more details on dashing.
*
* Since: 4.14
*/
void
gsk_stroke_set_dash_offset (GskStroke *self,
float offset)
{
g_return_if_fail (self != NULL);
self->dash_offset = offset;
}
/**
* gsk_stroke_get_dash_offset:
* @self: a `GskStroke`
*
* Returns the dash_offset of a `GskStroke`.
*
* Since: 4.14
*/
float
gsk_stroke_get_dash_offset (const GskStroke *self)
{
g_return_val_if_fail (self != NULL, 4.f);
return self->dash_offset;
}
/*< private >
* gsk_stroke_get_join_width:
* @stroke: a `GskStroke`
*
* Return a width that is sufficient to use
* when calculating stroke bounds around joins
* and caps.
*
* Returns: the join width
*/
float
gsk_stroke_get_join_width (const GskStroke *stroke)
{
float width;
switch (stroke->line_cap)
{
case GSK_LINE_CAP_BUTT:
width = 0;
break;
case GSK_LINE_CAP_ROUND:
width = stroke->line_width;
break;
case GSK_LINE_CAP_SQUARE:
width = G_SQRT2 * stroke->line_width;
break;
default:
g_assert_not_reached ();
}
switch (stroke->line_join)
{
case GSK_LINE_JOIN_MITER:
width = MAX (width, MAX (stroke->miter_limit, 1.f) * stroke->line_width);
break;
case GSK_LINE_JOIN_ROUND:
case GSK_LINE_JOIN_BEVEL:
width = MAX (width, stroke->line_width);
break;
default:
g_assert_not_reached ();
}
return width;
}
+87
View File
@@ -0,0 +1,87 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#pragma once
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gsk/gsk.h> can be included directly."
#endif
#include <gsk/gsktypes.h>
G_BEGIN_DECLS
#define GSK_TYPE_STROKE (gsk_stroke_get_type ())
GDK_AVAILABLE_IN_4_14
GType gsk_stroke_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_14
GskStroke * gsk_stroke_new (float line_width);
GDK_AVAILABLE_IN_4_14
GskStroke * gsk_stroke_copy (const GskStroke *other);
GDK_AVAILABLE_IN_4_14
void gsk_stroke_free (GskStroke *self);
GDK_AVAILABLE_IN_4_14
gboolean gsk_stroke_equal (gconstpointer stroke1,
gconstpointer stroke2);
GDK_AVAILABLE_IN_4_14
void gsk_stroke_set_line_width (GskStroke *self,
float line_width);
GDK_AVAILABLE_IN_4_14
float gsk_stroke_get_line_width (const GskStroke *self);
GDK_AVAILABLE_IN_4_14
void gsk_stroke_set_line_cap (GskStroke *self,
GskLineCap line_cap);
GDK_AVAILABLE_IN_4_14
GskLineCap gsk_stroke_get_line_cap (const GskStroke *self);
GDK_AVAILABLE_IN_4_14
void gsk_stroke_set_line_join (GskStroke *self,
GskLineJoin line_join);
GDK_AVAILABLE_IN_4_14
GskLineJoin gsk_stroke_get_line_join (const GskStroke *self);
GDK_AVAILABLE_IN_4_14
void gsk_stroke_set_miter_limit (GskStroke *self,
float limit);
GDK_AVAILABLE_IN_4_14
float gsk_stroke_get_miter_limit (const GskStroke *self);
GDK_AVAILABLE_IN_4_14
void gsk_stroke_set_dash (GskStroke *self,
const float *dash,
gsize n_dash);
GDK_AVAILABLE_IN_4_14
const float * gsk_stroke_get_dash (const GskStroke *self,
gsize *n_dash);
GDK_AVAILABLE_IN_4_14
void gsk_stroke_set_dash_offset (GskStroke *self,
float offset);
GDK_AVAILABLE_IN_4_14
float gsk_stroke_get_dash_offset (const GskStroke *self);
GDK_AVAILABLE_IN_4_14
void gsk_stroke_to_cairo (const GskStroke *self,
cairo_t *cr);
G_END_DECLS
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#pragma once
#include "gskstroke.h"
G_BEGIN_DECLS
struct _GskStroke
{
float line_width;
GskLineCap line_cap;
GskLineJoin line_join;
float miter_limit;
float *dash;
gsize n_dash;
float dash_length; /* sum of all dashes in the array */
float dash_offset;
};
static inline void
gsk_stroke_init_copy (GskStroke *stroke,
const GskStroke *other)
{
*stroke = *other;
stroke->dash = g_memdup (other->dash, stroke->n_dash * sizeof (float));
}
static inline void
gsk_stroke_clear (GskStroke *stroke)
{
g_clear_pointer (&stroke->dash, g_free);
stroke->n_dash = 0; /* better safe than sorry */
}
float gsk_stroke_get_join_width (const GskStroke *stroke);
G_END_DECLS
+1 -2
View File
@@ -857,8 +857,7 @@ normalize_angle (float angle)
* @next: (nullable) (transfer full): the next transform
* @angle: the rotation angle, in degrees (clockwise)
*
* Rotates @next @angle degrees in 2D - or in 3D-speak, around the Z axis.
* The rotation happens around the origin point of (0, 0).
* Rotates @next @angle degrees in 2D - or in 3D-speak, around the z axis.
*
* Returns: (nullable): The new transform
*/
+5
View File
@@ -25,6 +25,11 @@
#include <gdk/gdk.h>
#include <gsk/gskenums.h>
typedef struct _GskPath GskPath;
typedef struct _GskPathBuilder GskPathBuilder;
typedef struct _GskPathMeasure GskPathMeasure;
typedef struct _GskPathPoint GskPathPoint;
typedef struct _GskRenderer GskRenderer;
typedef struct _GskStroke GskStroke;
typedef struct _GskTransform GskTransform;
+20 -2
View File
@@ -23,23 +23,31 @@ gsk_private_gl_shaders = [
]
gsk_public_sources = files([
'gskdiff.c',
'gskcairorenderer.c',
'gskdiff.c',
'gskglshader.c',
'gskpath.c',
'gskpathbuilder.c',
'gskpathmeasure.c',
'gskpathpoint.c',
'gskrenderer.c',
'gskrendernode.c',
'gskrendernodeimpl.c',
'gskrendernodeparser.c',
'gskroundedrect.c',
'gskstroke.c',
'gsktransform.c',
'gl/gskglrenderer.c',
])
gsk_private_sources = files([
'gskcairoblur.c',
'gskcontour.c',
'gskcurve.c',
'gskdebug.c',
'gskprivate.c',
'gskprofiler.c',
'gskspline.c',
'gl/gskglattachmentstate.c',
'gl/gskglbuffer.c',
'gl/gskglcommandqueue.c',
@@ -66,9 +74,14 @@ gsk_public_headers = files([
'gskcairorenderer.h',
'gskenums.h',
'gskglshader.h',
'gskpath.h',
'gskpathbuilder.h',
'gskpathmeasure.h',
'gskpathpoint.h',
'gskrenderer.h',
'gskrendernode.h',
'gskroundedrect.h',
'gskstroke.h',
'gsktransform.h',
'gsktypes.h',
])
@@ -97,6 +110,10 @@ if have_vulkan
endif
gsk_private_vulkan_shaders = []
# This is an odd split because we use configure_file() below to workaround
# a limitation in meson preventing using custom_target() with gnome.compile_resources()
# and that requires file paths, but we also need to have dependencies during development
# on constantly regenerated files.
gsk_private_vulkan_compiled_shaders = []
gsk_private_vulkan_compiled_shaders_deps = []
gsk_private_vulkan_shader_headers = []
@@ -144,7 +161,7 @@ if get_variable('broadway_enabled')
])
endif
gsk_resources_xml = custom_target(output: 'gsk.resources.xml',
gsk_resources_xml = configure_file(output: 'gsk.resources.xml',
input: 'gen-gsk-gresources-xml.py',
command: [
find_program('gen-gsk-gresources-xml.py'),
@@ -180,6 +197,7 @@ gsk_deps = [
pango_dep,
cairo_dep,
cairo_csi_dep,
pixbuf_dep,
libgdk_dep,
]
+1 -1
View File
@@ -18,7 +18,7 @@
#pragma once
#include <gdk/gdk.h>
#include <gsk/gsk.h>
#include <gsk/gskrenderer.h>
#ifdef GDK_RENDERING_VULKAN
+2
View File
@@ -1260,6 +1260,8 @@ static const GskVulkanRenderPassNodeFunc nodes_vtable[] = {
[GSK_GL_SHADER_NODE] = NULL,
[GSK_TEXTURE_SCALE_NODE] = gsk_vulkan_render_pass_add_texture_scale_node,
[GSK_MASK_NODE] = gsk_vulkan_render_pass_add_mask_node,
[GSK_FILL_NODE] = NULL,
[GSK_STROKE_NODE] = NULL,
};
static void
+7 -7
View File
@@ -93,12 +93,12 @@ foreach shader: gsk_private_vulkan_shaders
endforeach
foreach shader: gsk_private_vulkan_vertex_shaders
shader_header = custom_target(output: '@0@.h'.format(shader),
input: shader,
command: [
find_program('generate-header.py'),
'@INPUT@',
],
capture: true)
shader_header = configure_file(output: '@0@.h'.format(shader),
input: shader,
command: [
find_program('generate-header.py'),
'@INPUT@',
],
capture: true)
gsk_private_vulkan_shader_headers += shader_header
endforeach
-3
View File
@@ -290,9 +290,6 @@ gtk_color_button_init (GtkColorButton *button)
button->button = gtk_button_new ();
g_signal_connect (button->button, "clicked", G_CALLBACK (gtk_color_button_clicked), button);
g_object_bind_property (button, "focus-on-click",
button->button, "focus-on-click",
0);
gtk_widget_set_parent (button->button, GTK_WIDGET (button));
button->swatch = g_object_new (GTK_TYPE_COLOR_SWATCH,
+2 -4
View File
@@ -454,8 +454,7 @@ gtk_dialog_constructed (GObject *object)
}
g_list_free (children);
if (GTK_IS_HEADER_BAR (priv->headerbar))
_gtk_header_bar_track_default_decoration (GTK_HEADER_BAR (priv->headerbar));
_gtk_header_bar_track_default_decoration (GTK_HEADER_BAR (priv->headerbar));
}
else
{
@@ -1398,8 +1397,7 @@ gtk_dialog_buildable_add_child (GtkBuildable *buildable,
else if (g_str_equal (type, "titlebar"))
{
priv->headerbar = GTK_WIDGET (child);
if (GTK_IS_HEADER_BAR (priv->headerbar))
_gtk_header_bar_track_default_decoration (GTK_HEADER_BAR (priv->headerbar));
_gtk_header_bar_track_default_decoration (GTK_HEADER_BAR (priv->headerbar));
gtk_window_set_titlebar (GTK_WINDOW (buildable), priv->headerbar);
}
else if (g_str_equal (type, "action"))
-3
View File
@@ -594,9 +594,6 @@ gtk_font_button_init (GtkFontButton *font_button)
font_button->button = gtk_button_new ();
g_signal_connect (font_button->button, "clicked", G_CALLBACK (gtk_font_button_clicked), font_button);
g_object_bind_property (font_button, "focus-on-click",
font_button->button, "focus-on-click",
0);
font_button->font_label = gtk_label_new (_("Font"));
gtk_widget_set_hexpand (font_button->font_label, TRUE);
font_button->size_label = gtk_label_new ("14");
+2
View File
@@ -257,6 +257,8 @@ static guint tree_model_signals[LAST_SIGNAL] = { 0 };
* GtkTreePath:
*
* An opaque structure representing a path to a row in a model.
*
* Deprecated: 4.10
*/
struct _GtkTreePath
{
+6
View File
@@ -69,6 +69,8 @@ typedef gboolean (* GtkTreeModelForeachFunc) (GtkTreeModel *model, GtkTreePath *
* static for the lifetime of the object. A more complete description
* of %GTK_TREE_MODEL_ITERS_PERSIST can be found in the overview of
* this section.
*
* Deprecated: 4.10
*/
typedef enum
{
@@ -88,6 +90,8 @@ typedef enum
* integer in the @stamp member, and put
* model-specific data in the three @user_data
* members.
*
* Deprecated: 4.10
*/
struct _GtkTreeIter
{
@@ -251,6 +255,8 @@ gboolean gtk_tree_path_is_descendant (GtkTreePath *path,
* A GtkTreeRowReference tracks model changes so that it always refers to the
* same row (a `GtkTreePath` refers to a position, not a fixed row). Create a
* new GtkTreeRowReference with gtk_tree_row_reference_new().
*
* Deprecated: 4.10: Use [iface@Gio.ListModel] instead
*/
GDK_AVAILABLE_IN_ALL
-2
View File
@@ -734,12 +734,10 @@ gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
g_assert (filter->priv->child_model != NULL);
/* Avoid building a level that already exists */
#ifndef G_DISABLE_ASSERT
if (parent_level)
g_assert (parent_elt->children == NULL);
else
g_assert (filter->priv->root == NULL);
#endif
if (filter->priv->in_row_deleted)
return;
-6
View File
@@ -12834,12 +12834,6 @@ gtk_tree_view_is_blank_at_pos (GtkTreeView *tree_view,
gtk_tree_model_get_iter (priv->model, &iter, real_path);
_gtk_tree_view_find_node (tree_view, real_path, &tree, &node);
if (node == NULL)
{
if (!path)
gtk_tree_path_free (real_path);
return TRUE;
}
/* Check if there's an expander arrow at (x, y) */
if (real_column == priv->expander_column
+4 -4
View File
@@ -937,13 +937,13 @@ gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column)
if ((!alternative && priv->sort_order == GTK_SORT_ASCENDING) ||
(alternative && priv->sort_order == GTK_SORT_DESCENDING))
{
gtk_widget_remove_css_class (arrow, "ascending");
gtk_widget_add_css_class (arrow, "descending");
gtk_widget_remove_css_class (arrow, "descending");
gtk_widget_add_css_class (arrow, "ascending");
}
else
{
gtk_widget_remove_css_class (arrow, "descending");
gtk_widget_add_css_class (arrow, "ascending");
gtk_widget_remove_css_class (arrow, "ascending");
gtk_widget_add_css_class (arrow, "descending");
}
}

Some files were not shown because too many files have changed in this diff Show More