Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 244cdafe1b | |||
| a0d17418de | |||
| 093e6241e7 | |||
| 67b504f823 | |||
| 659bc813a4 | |||
| 293c0774b3 | |||
| 988062889b | |||
| 461922b495 | |||
| 7150a53ccb | |||
| 1e306b148e | |||
| 6af9dc8612 | |||
| 35b313f9b0 | |||
| fe84ce8686 | |||
| 02a4e5a457 | |||
| a548a91e6d | |||
| fc3c2e0942 | |||
| 60e07335a1 | |||
| cb6b968fb5 | |||
| 3aa3816125 | |||
| c37c29422a | |||
| db71c07f8f | |||
| bf1b97efd3 | |||
| 4d7277f72c | |||
| 3296f01edf | |||
| dbcbf0523b | |||
| 888abb6f24 | |||
| 9b916b329a | |||
| eb3ada6386 | |||
| 2a725b658b | |||
| 97f605f811 | |||
| 4e7d578881 | |||
| 438d936f57 | |||
| fc4a464b47 | |||
| 785b9541f6 | |||
| a4cbabb80f | |||
| 1b5dfcba7e | |||
| ba41edf531 | |||
| bf3892caed | |||
| 1e6a95aa1b | |||
| 70a9d08e21 | |||
| 7511d4e281 | |||
| 53ea97decb | |||
| 28190ded71 | |||
| 8083cb0e47 | |||
| d241ec4f3e | |||
| 544320a961 | |||
| ee5a95ba24 | |||
| 232260b86b | |||
| 857f50649c | |||
| a39d9d60a7 | |||
| 5f9bc97291 | |||
| 01b3b096fe | |||
| a483fb2d96 | |||
| d27e7e0180 | |||
| aa888c0b3f |
+11
-35
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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
|
||||
=========================================
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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));
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
^^^^^^^^^
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -86,5 +86,3 @@ libgdk_x11 = static_library('gdk-x11',
|
||||
] + common_cflags,
|
||||
dependencies: [ gdk_deps, gdk_x11_deps, ],
|
||||
)
|
||||
|
||||
x11_public_deps = [x11_dep]
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gsk/gsk.h>
|
||||
#include <gsk/gskrenderer.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
+87
-105
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+144
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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,
|
||||
]
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gsk/gsk.h>
|
||||
#include <gsk/gskrenderer.h>
|
||||
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user