Rewild Your Web
18
fork

Configure Feed

Select the types of activity you want to include in your feed.

Initial pairing support

Signed-off-by: webbeef <me@webbeef.org>

webbeef 3d7ba305 b31ee232

+1433 -339
+178 -201
Cargo.lock
··· 765 765 "headers 0.4.1", 766 766 "image", 767 767 "keyboard-types 0.8.3", 768 - "libservo", 769 768 "log", 770 769 "mime_guess", 771 770 "parking_lot", 772 771 "rustls", 773 772 "serde", 774 773 "serde_json", 774 + "servo", 775 775 "servo-config", 776 776 "servo-config-macro", 777 777 "servo-embedder-traits", ··· 902 902 source = "registry+https://github.com/rust-lang/crates.io-index" 903 903 checksum = "96eb4cdd6cf1b31d671e9efe75c5d1ec614776856cefbe109ca373554a6d514f" 904 904 dependencies = [ 905 - "hybrid-array 0.4.7", 905 + "hybrid-array 0.4.8", 906 906 ] 907 907 908 908 [[package]] ··· 911 911 source = "registry+https://github.com/rust-lang/crates.io-index" 912 912 checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" 913 913 dependencies = [ 914 - "hybrid-array 0.4.7", 914 + "hybrid-array 0.4.8", 915 915 "zeroize", 916 916 ] 917 917 ··· 1787 1787 source = "registry+https://github.com/rust-lang/crates.io-index" 1788 1788 checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" 1789 1789 dependencies = [ 1790 - "hybrid-array 0.4.7", 1790 + "hybrid-array 0.4.8", 1791 1791 ] 1792 1792 1793 1793 [[package]] ··· 4265 4265 4266 4266 [[package]] 4267 4267 name = "hybrid-array" 4268 - version = "0.4.7" 4268 + version = "0.4.8" 4269 4269 source = "registry+https://github.com/rust-lang/crates.io-index" 4270 - checksum = "e1b229d73f5803b562cc26e4da0396c8610a4ee209f4fac8fa4f8d709166dc45" 4270 + checksum = "8655f91cd07f2b9d0c24137bd650fe69617773435ee5ec83022377777ce65ef1" 4271 4271 dependencies = [ 4272 4272 "typenum", 4273 4273 "zeroize", ··· 4431 4431 "icu_properties 1.5.1", 4432 4432 "icu_provider 1.5.0", 4433 4433 "icu_provider_adapters", 4434 - "icu_segmenter 1.5.0", 4434 + "icu_segmenter", 4435 4435 "icu_timezone", 4436 4436 "tinystr 0.7.6", 4437 4437 "unicode-bidi", ··· 4616 4616 checksum = "52b1a7fbdbf3958f1be8354cb59ac73f165b7b7082d447ff2090355c9a069120" 4617 4617 4618 4618 [[package]] 4619 - name = "icu_locale" 4620 - version = "2.1.1" 4621 - source = "registry+https://github.com/rust-lang/crates.io-index" 4622 - checksum = "532b11722e350ab6bf916ba6eb0efe3ee54b932666afec989465f9243fe6dd60" 4623 - dependencies = [ 4624 - "icu_collections 2.1.1", 4625 - "icu_locale_core", 4626 - "icu_locale_data", 4627 - "icu_provider 2.1.1", 4628 - "potential_utf", 4629 - "tinystr 0.8.2", 4630 - "zerovec 0.11.5", 4631 - ] 4632 - 4633 - [[package]] 4634 4619 name = "icu_locale_core" 4635 4620 version = "2.1.1" 4636 4621 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4638 4623 dependencies = [ 4639 4624 "displaydoc", 4640 4625 "litemap 0.8.1", 4641 - "serde", 4642 4626 "tinystr 0.8.2", 4643 4627 "writeable 0.6.2", 4644 4628 "zerovec 0.11.5", 4645 4629 ] 4646 4630 4647 4631 [[package]] 4648 - name = "icu_locale_data" 4649 - version = "2.1.2" 4650 - source = "registry+https://github.com/rust-lang/crates.io-index" 4651 - checksum = "1c5f1d16b4c3a2642d3a719f18f6b06070ab0aef246a6418130c955ae08aa831" 4652 - 4653 - [[package]] 4654 4632 name = "icu_locid" 4655 4633 version = "1.5.0" 4656 4634 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4827 4805 dependencies = [ 4828 4806 "displaydoc", 4829 4807 "icu_locale_core", 4830 - "serde", 4831 - "stable_deref_trait", 4832 4808 "writeable 0.6.2", 4833 4809 "yoke 0.8.1", 4834 4810 "zerofrom", ··· 4871 4847 "icu_collections 1.5.0", 4872 4848 "icu_locid", 4873 4849 "icu_provider 1.5.0", 4874 - "icu_segmenter_data 1.5.1", 4850 + "icu_segmenter_data", 4875 4851 "utf8_iter", 4876 4852 "zerovec 0.10.4", 4877 4853 ] 4878 4854 4879 4855 [[package]] 4880 - name = "icu_segmenter" 4881 - version = "2.1.2" 4882 - source = "registry+https://github.com/rust-lang/crates.io-index" 4883 - checksum = "a807a7488f3f758629ae86d99d9d30dce24da2fb2945d74c80a4f4a62c71db73" 4884 - dependencies = [ 4885 - "core_maths", 4886 - "icu_collections 2.1.1", 4887 - "icu_locale", 4888 - "icu_provider 2.1.1", 4889 - "icu_segmenter_data 2.1.1", 4890 - "potential_utf", 4891 - "utf8_iter", 4892 - "zerovec 0.11.5", 4893 - ] 4894 - 4895 - [[package]] 4896 4856 name = "icu_segmenter_data" 4897 4857 version = "1.5.1" 4898 4858 source = "registry+https://github.com/rust-lang/crates.io-index" 4899 4859 checksum = "a1e52775179941363cc594e49ce99284d13d6948928d8e72c755f55e98caa1eb" 4900 - 4901 - [[package]] 4902 - name = "icu_segmenter_data" 4903 - version = "2.1.1" 4904 - source = "registry+https://github.com/rust-lang/crates.io-index" 4905 - checksum = "6ebbb7321d9e21d25f5660366cb6c08201d0175898a3a6f7a41ee9685af21c80" 4906 4860 4907 4861 [[package]] 4908 4862 name = "icu_timezone" ··· 4987 4941 4988 4942 [[package]] 4989 4943 name = "image" 4990 - version = "0.25.9" 4944 + version = "0.25.10" 4991 4945 source = "registry+https://github.com/rust-lang/crates.io-index" 4992 - checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" 4946 + checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" 4993 4947 dependencies = [ 4994 4948 "bytemuck", 4995 4949 "byteorder-lite", ··· 5075 5029 source = "registry+https://github.com/rust-lang/crates.io-index" 5076 5030 checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" 5077 5031 dependencies = [ 5078 - "hybrid-array 0.4.7", 5032 + "hybrid-array 0.4.8", 5079 5033 ] 5080 5034 5081 5035 [[package]] ··· 5177 5131 "rustls-webpki", 5178 5132 "serde", 5179 5133 "smallvec", 5180 - "strum", 5134 + "strum 0.27.2", 5181 5135 "swarm-discovery", 5182 5136 "sync_wrapper", 5183 5137 "time", ··· 5212 5166 5213 5167 [[package]] 5214 5168 name = "iroh-metrics" 5215 - version = "0.38.2" 5169 + version = "0.38.3" 5216 5170 source = "registry+https://github.com/rust-lang/crates.io-index" 5217 - checksum = "c946095f060e6e59b9ff30cc26c75cdb758e7fb0cde8312c89e2144654989fcb" 5171 + checksum = "761b45ba046134b11eb3e432fa501616b45c4bf3a30c21717578bc07aa6461dd" 5218 5172 dependencies = [ 5219 5173 "iroh-metrics-derive", 5220 5174 "itoa", 5221 5175 "n0-error", 5176 + "portable-atomic", 5222 5177 "postcard", 5223 5178 "ryu", 5224 5179 "serde", ··· 5346 5301 "rustls-pki-types", 5347 5302 "serde", 5348 5303 "serde_bytes", 5349 - "strum", 5304 + "strum 0.27.2", 5350 5305 "tokio", 5351 5306 "tokio-rustls", 5352 5307 "tokio-util", ··· 5621 5576 5622 5577 [[package]] 5623 5578 name = "libc" 5624 - version = "0.2.182" 5579 + version = "0.2.183" 5625 5580 source = "registry+https://github.com/rust-lang/crates.io-index" 5626 - checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" 5581 + checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" 5627 5582 5628 5583 [[package]] 5629 5584 name = "libdbus-sys" ··· 5683 5638 ] 5684 5639 5685 5640 [[package]] 5686 - name = "libservo" 5687 - version = "0.1.0" 5688 - dependencies = [ 5689 - "accesskit", 5690 - "arboard", 5691 - "bitflags 2.11.0", 5692 - "crossbeam-channel", 5693 - "dpi", 5694 - "env_logger", 5695 - "euclid", 5696 - "gaol", 5697 - "gstreamer", 5698 - "http 1.4.0", 5699 - "http-body-util", 5700 - "hyper 1.8.1", 5701 - "image", 5702 - "ipc-channel", 5703 - "keyboard-types 0.8.3", 5704 - "libservo", 5705 - "log", 5706 - "mozangle", 5707 - "parking_lot", 5708 - "rustc-hash 2.1.1", 5709 - "rustls", 5710 - "serde", 5711 - "servo-allocator", 5712 - "servo-background-hang-monitor", 5713 - "servo-base", 5714 - "servo-bluetooth", 5715 - "servo-bluetooth-traits", 5716 - "servo-canvas-traits", 5717 - "servo-config", 5718 - "servo-constellation", 5719 - "servo-constellation-traits", 5720 - "servo-devtools", 5721 - "servo-devtools-traits", 5722 - "servo-embedder-traits", 5723 - "servo-fonts", 5724 - "servo-geometry", 5725 - "servo-layout", 5726 - "servo-layout-api", 5727 - "servo-media", 5728 - "servo-media-dummy", 5729 - "servo-media-gstreamer", 5730 - "servo-media-thread", 5731 - "servo-net", 5732 - "servo-net-traits", 5733 - "servo-paint", 5734 - "servo-paint-api", 5735 - "servo-profile", 5736 - "servo-profile-traits", 5737 - "servo-script", 5738 - "servo-script-traits", 5739 - "servo-storage", 5740 - "servo-storage-traits", 5741 - "servo-tracing", 5742 - "servo-url", 5743 - "servo-webgl", 5744 - "servo-webgpu", 5745 - "servo-webxr", 5746 - "servo-webxr-api", 5747 - "stylo", 5748 - "stylo_traits", 5749 - "surfman", 5750 - "tokio", 5751 - "tracing", 5752 - "url", 5753 - "webrender", 5754 - "webrender_api", 5755 - "winit", 5756 - ] 5757 - 5758 - [[package]] 5759 5641 name = "libsqlite3-sys" 5760 5642 version = "0.35.0" 5761 5643 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 5787 5669 5788 5670 [[package]] 5789 5671 name = "libz-sys" 5790 - version = "1.1.24" 5672 + version = "1.1.25" 5791 5673 source = "registry+https://github.com/rust-lang/crates.io-index" 5792 - checksum = "4735e9cbde5aac84a5ce588f6b23a90b9b0b528f6c5a8db8a4aff300463a0839" 5674 + checksum = "d52f4c29e2a68ac30c9087e1b772dc9f44a2b66ed44edf2266cf2be9b03dafc1" 5793 5675 dependencies = [ 5794 5676 "cc", 5795 5677 "libc", ··· 6097 5979 6098 5980 [[package]] 6099 5981 name = "moxcms" 6100 - version = "0.7.11" 5982 + version = "0.8.1" 6101 5983 source = "registry+https://github.com/rust-lang/crates.io-index" 6102 - checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" 5984 + checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" 6103 5985 dependencies = [ 6104 5986 "num-traits", 6105 5987 "pxfm", ··· 6107 5989 6108 5990 [[package]] 6109 5991 name = "mozangle" 6110 - version = "0.5.4" 5992 + version = "0.5.5" 6111 5993 source = "registry+https://github.com/rust-lang/crates.io-index" 6112 - checksum = "97f4fcc47005b28e642cc098f2048a236fd8c531fc7a11b8b8bf14fb1230f122" 5994 + checksum = "298bc7f83d5cca3789e47779e92cda492b75f11e03995bf558475bd9df2f639b" 6113 5995 dependencies = [ 6114 5996 "bindgen", 6115 5997 "cc", ··· 6120 6002 6121 6003 [[package]] 6122 6004 name = "mozjs" 6123 - version = "0.15.1" 6005 + version = "0.15.5" 6124 6006 source = "registry+https://github.com/rust-lang/crates.io-index" 6125 - checksum = "074cf37bcac620b5c7e56ed0830a4a5288e08a266cbe7e9737d29035e3ab4e64" 6007 + checksum = "6efb4331060c22cc64e136c11c810eec22c063dd7cdeffdee394cb4e7f4d2880" 6126 6008 dependencies = [ 6127 6009 "bindgen", 6128 6010 "cc", ··· 6135 6017 6136 6018 [[package]] 6137 6019 name = "mozjs_sys" 6138 - version = "0.140.5-11" 6020 + version = "0.140.8-0" 6139 6021 source = "registry+https://github.com/rust-lang/crates.io-index" 6140 - checksum = "e57169b7c9e59053c26d76ecb499f5227fbcadbd1eadbb60009f3f745d21fce1" 6022 + checksum = "2d84f9f721dd87b500958f5815c118adb8adcd8e310e30b0188647c179ea7bcb" 6141 6023 dependencies = [ 6142 6024 "bindgen", 6143 6025 "cc", ··· 7662 7544 version = "1.13.1" 7663 7545 source = "registry+https://github.com/rust-lang/crates.io-index" 7664 7546 checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" 7547 + dependencies = [ 7548 + "serde", 7549 + ] 7665 7550 7666 7551 [[package]] 7667 7552 name = "portable-atomic-util" ··· 7733 7618 source = "registry+https://github.com/rust-lang/crates.io-index" 7734 7619 checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" 7735 7620 dependencies = [ 7736 - "serde_core", 7737 - "writeable 0.6.2", 7738 7621 "zerovec 0.11.5", 7739 7622 ] 7740 7623 ··· 7962 7845 7963 7846 [[package]] 7964 7847 name = "quinn-proto" 7965 - version = "0.11.13" 7848 + version = "0.11.14" 7966 7849 source = "registry+https://github.com/rust-lang/crates.io-index" 7967 - checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" 7850 + checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" 7968 7851 dependencies = [ 7969 7852 "aws-lc-rs", 7970 7853 "bytes", ··· 8176 8059 8177 8060 [[package]] 8178 8061 name = "ravif" 8179 - version = "0.12.0" 8062 + version = "0.13.0" 8180 8063 source = "registry+https://github.com/rust-lang/crates.io-index" 8181 - checksum = "ef69c1990ceef18a116855938e74793a5f7496ee907562bd0857b6ac734ab285" 8064 + checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45" 8182 8065 dependencies = [ 8183 8066 "avif-serialize", 8184 8067 "imgref", ··· 8665 8548 8666 8549 [[package]] 8667 8550 name = "schannel" 8668 - version = "0.1.28" 8551 + version = "0.1.29" 8669 8552 source = "registry+https://github.com/rust-lang/crates.io-index" 8670 - checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" 8553 + checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" 8671 8554 dependencies = [ 8672 8555 "windows-sys 0.61.2", 8673 8556 ] ··· 8699 8582 8700 8583 [[package]] 8701 8584 name = "sea-query" 8702 - version = "1.0.0-rc.31" 8585 + version = "1.0.0-rc.32" 8703 8586 source = "registry+https://github.com/rust-lang/crates.io-index" 8704 - checksum = "58decdaaaf2a698170af2fa1b2e8f7b43a970e7768bf18aebaab113bada46354" 8587 + checksum = "e504013549f817509224b39f2381da6b6e18e48cb7144a24ea13b6f22089e76c" 8705 8588 dependencies = [ 8706 8589 "inherent", 8707 8590 "sea-query-derive", ··· 8747 8630 8748 8631 [[package]] 8749 8632 name = "sec1" 8750 - version = "0.8.0-rc.13" 8633 + version = "0.8.0" 8751 8634 source = "registry+https://github.com/rust-lang/crates.io-index" 8752 - checksum = "7a2400ed44a13193820aa528a19f376c3843141a8ce96ff34b11104cc79763f2" 8635 + checksum = "f46b9a5ab87780a3189a1d704766579517a04ad59de653b7aad7d38e8a15f7dc" 8753 8636 dependencies = [ 8754 8637 "base16ct 1.0.0", 8755 - "hybrid-array 0.4.7", 8638 + "hybrid-array 0.4.8", 8756 8639 ] 8757 8640 8758 8641 [[package]] ··· 8790 8673 8791 8674 [[package]] 8792 8675 name = "selectors" 8793 - version = "0.35.0" 8794 - source = "git+https://github.com/servo/stylo?rev=9b635629e627a611419745198de1b1ba6c8667c2#9b635629e627a611419745198de1b1ba6c8667c2" 8676 + version = "0.36.0" 8677 + source = "git+https://github.com/servo/stylo?rev=f00c109074832b7fa7be52bbbf8f4987d24e323b#f00c109074832b7fa7be52bbbf8f4987d24e323b" 8795 8678 dependencies = [ 8796 8679 "bitflags 2.11.0", 8797 8680 "cssparser", ··· 8931 8814 ] 8932 8815 8933 8816 [[package]] 8817 + name = "servo" 8818 + version = "0.1.0" 8819 + dependencies = [ 8820 + "accesskit", 8821 + "arboard", 8822 + "bitflags 2.11.0", 8823 + "crossbeam-channel", 8824 + "dpi", 8825 + "env_logger", 8826 + "euclid", 8827 + "gaol", 8828 + "gstreamer", 8829 + "http 1.4.0", 8830 + "http-body-util", 8831 + "hyper 1.8.1", 8832 + "image", 8833 + "ipc-channel", 8834 + "keyboard-types 0.8.3", 8835 + "log", 8836 + "mozangle", 8837 + "parking_lot", 8838 + "rustc-hash 2.1.1", 8839 + "rustls", 8840 + "serde", 8841 + "servo", 8842 + "servo-allocator", 8843 + "servo-background-hang-monitor", 8844 + "servo-base", 8845 + "servo-bluetooth", 8846 + "servo-bluetooth-traits", 8847 + "servo-canvas-traits", 8848 + "servo-config", 8849 + "servo-constellation", 8850 + "servo-constellation-traits", 8851 + "servo-devtools", 8852 + "servo-devtools-traits", 8853 + "servo-embedder-traits", 8854 + "servo-fonts", 8855 + "servo-geometry", 8856 + "servo-layout", 8857 + "servo-layout-api", 8858 + "servo-media", 8859 + "servo-media-dummy", 8860 + "servo-media-gstreamer", 8861 + "servo-media-thread", 8862 + "servo-net", 8863 + "servo-net-traits", 8864 + "servo-paint", 8865 + "servo-paint-api", 8866 + "servo-profile", 8867 + "servo-profile-traits", 8868 + "servo-script", 8869 + "servo-script-traits", 8870 + "servo-storage", 8871 + "servo-storage-traits", 8872 + "servo-tracing", 8873 + "servo-url", 8874 + "servo-webgl", 8875 + "servo-webgpu", 8876 + "servo-webxr", 8877 + "servo-webxr-api", 8878 + "stylo", 8879 + "stylo_traits", 8880 + "surfman", 8881 + "tokio", 8882 + "tracing", 8883 + "url", 8884 + "webrender", 8885 + "webrender_api", 8886 + "winit", 8887 + ] 8888 + 8889 + [[package]] 8934 8890 name = "servo-allocator" 8935 8891 version = "0.1.0" 8936 8892 dependencies = [ ··· 9064 9020 "servo-malloc-size-of", 9065 9021 "servo-pixels", 9066 9022 "servo-webxr-api", 9067 - "strum", 9023 + "strum 0.27.2", 9068 9024 "stylo", 9069 9025 "webrender_api", 9070 9026 ] ··· 9095 9051 version = "0.1.0" 9096 9052 dependencies = [ 9097 9053 "backtrace", 9054 + "beaver-p2p", 9098 9055 "content-security-policy", 9099 9056 "crossbeam-channel", 9100 9057 "euclid", 9101 9058 "gaol", 9102 9059 "ipc-channel", 9060 + "iroh", 9061 + "iroh-persist", 9103 9062 "keyboard-types 0.8.3", 9104 9063 "log", 9105 9064 "parking_lot", 9065 + "petname", 9106 9066 "rand 0.9.2", 9107 9067 "rustc-hash 2.1.1", 9108 9068 "serde", ··· 9133 9093 "servo-webxr-api", 9134 9094 "stylo", 9135 9095 "stylo_traits", 9096 + "tokio", 9136 9097 "tracing", 9137 9098 "webrender", 9138 9099 "webrender_api", ··· 9166 9127 "servo-storage-traits", 9167 9128 "servo-url", 9168 9129 "servo-webgpu-traits", 9169 - "strum", 9130 + "strum 0.27.2", 9170 9131 "stylo_traits", 9171 9132 "uuid", 9172 9133 "webrender_api", ··· 9259 9220 "servo-malloc-size-of", 9260 9221 "servo-pixels", 9261 9222 "servo-url", 9262 - "strum", 9223 + "strum 0.27.2", 9263 9224 "stylo", 9264 9225 "stylo_traits", 9265 9226 "tokio", ··· 9393 9354 "euclid", 9394 9355 "html5ever", 9395 9356 "icu_locid", 9396 - "icu_segmenter 1.5.0", 9357 + "icu_segmenter", 9397 9358 "itertools 0.14.0", 9398 9359 "kurbo 0.12.0", 9399 9360 "log", ··· 9422 9383 "servo-url", 9423 9384 "servo_arc", 9424 9385 "smallvec", 9425 - "strum", 9386 + "strum 0.27.2", 9426 9387 "stylo", 9427 9388 "stylo_atoms", 9428 9389 "stylo_traits", ··· 9880 9841 "servo-tracing", 9881 9842 "servo-url", 9882 9843 "smallvec", 9883 - "strum", 9844 + "strum 0.27.2", 9884 9845 "stylo", 9885 9846 "stylo_traits", 9886 9847 "surfman", ··· 10054 10015 "sha2 0.10.9", 10055 10016 "sha3", 10056 10017 "smallvec", 10057 - "strum", 10018 + "strum 0.27.2", 10058 10019 "stylo", 10059 10020 "stylo_atoms", 10060 10021 "stylo_dom", ··· 10151 10112 "servo-url", 10152 10113 "servo-webgpu-traits", 10153 10114 "servo-webxr-api", 10154 - "strum", 10115 + "strum 0.27.2", 10155 10116 "stylo_atoms", 10156 10117 "stylo_traits", 10157 10118 "webrender_api", ··· 10337 10298 [[package]] 10338 10299 name = "servo_arc" 10339 10300 version = "0.4.3" 10340 - source = "git+https://github.com/servo/stylo?rev=9b635629e627a611419745198de1b1ba6c8667c2#9b635629e627a611419745198de1b1ba6c8667c2" 10301 + source = "git+https://github.com/servo/stylo?rev=f00c109074832b7fa7be52bbbf8f4987d24e323b#f00c109074832b7fa7be52bbbf8f4987d24e323b" 10341 10302 dependencies = [ 10342 10303 "serde", 10343 10304 "stable_deref_trait", ··· 10683 10644 "ed25519-dalek", 10684 10645 "home", 10685 10646 "rand_core 0.9.5", 10686 - "sec1 0.8.0-rc.13", 10647 + "sec1 0.8.0", 10687 10648 "sha2 0.11.0-rc.2", 10688 10649 "signature 3.0.0-rc.10", 10689 10650 "ssh-cipher", ··· 10766 10727 source = "registry+https://github.com/rust-lang/crates.io-index" 10767 10728 checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" 10768 10729 dependencies = [ 10769 - "strum_macros", 10730 + "strum_macros 0.27.2", 10770 10731 ] 10771 10732 10772 10733 [[package]] 10734 + name = "strum" 10735 + version = "0.28.0" 10736 + source = "registry+https://github.com/rust-lang/crates.io-index" 10737 + checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" 10738 + 10739 + [[package]] 10773 10740 name = "strum_macros" 10774 10741 version = "0.27.2" 10775 10742 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 10782 10749 ] 10783 10750 10784 10751 [[package]] 10752 + name = "strum_macros" 10753 + version = "0.28.0" 10754 + source = "registry+https://github.com/rust-lang/crates.io-index" 10755 + checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" 10756 + dependencies = [ 10757 + "heck 0.5.0", 10758 + "proc-macro2", 10759 + "quote", 10760 + "syn 2.0.117", 10761 + ] 10762 + 10763 + [[package]] 10785 10764 name = "stylo" 10786 - version = "0.12.0" 10787 - source = "git+https://github.com/servo/stylo?rev=9b635629e627a611419745198de1b1ba6c8667c2#9b635629e627a611419745198de1b1ba6c8667c2" 10765 + version = "0.13.0" 10766 + source = "git+https://github.com/servo/stylo?rev=f00c109074832b7fa7be52bbbf8f4987d24e323b#f00c109074832b7fa7be52bbbf8f4987d24e323b" 10788 10767 dependencies = [ 10789 10768 "app_units", 10790 10769 "arrayvec", ··· 10795 10774 "derive_more", 10796 10775 "encoding_rs", 10797 10776 "euclid", 10798 - "icu_segmenter 2.1.2", 10777 + "icu_segmenter", 10799 10778 "indexmap", 10800 10779 "itertools 0.14.0", 10801 10780 "itoa", ··· 10819 10798 "smallvec", 10820 10799 "static_assertions", 10821 10800 "string_cache", 10822 - "strum", 10823 - "strum_macros", 10801 + "strum 0.28.0", 10802 + "strum_macros 0.28.0", 10824 10803 "stylo_atoms", 10825 10804 "stylo_derive", 10826 10805 "stylo_dom", ··· 10839 10818 10840 10819 [[package]] 10841 10820 name = "stylo_atoms" 10842 - version = "0.12.0" 10843 - source = "git+https://github.com/servo/stylo?rev=9b635629e627a611419745198de1b1ba6c8667c2#9b635629e627a611419745198de1b1ba6c8667c2" 10821 + version = "0.13.0" 10822 + source = "git+https://github.com/servo/stylo?rev=f00c109074832b7fa7be52bbbf8f4987d24e323b#f00c109074832b7fa7be52bbbf8f4987d24e323b" 10844 10823 dependencies = [ 10845 10824 "string_cache", 10846 10825 "string_cache_codegen", ··· 10848 10827 10849 10828 [[package]] 10850 10829 name = "stylo_derive" 10851 - version = "0.12.0" 10852 - source = "git+https://github.com/servo/stylo?rev=9b635629e627a611419745198de1b1ba6c8667c2#9b635629e627a611419745198de1b1ba6c8667c2" 10830 + version = "0.13.0" 10831 + source = "git+https://github.com/servo/stylo?rev=f00c109074832b7fa7be52bbbf8f4987d24e323b#f00c109074832b7fa7be52bbbf8f4987d24e323b" 10853 10832 dependencies = [ 10854 10833 "darling", 10855 10834 "proc-macro2", ··· 10860 10839 10861 10840 [[package]] 10862 10841 name = "stylo_dom" 10863 - version = "0.12.0" 10864 - source = "git+https://github.com/servo/stylo?rev=9b635629e627a611419745198de1b1ba6c8667c2#9b635629e627a611419745198de1b1ba6c8667c2" 10842 + version = "0.13.0" 10843 + source = "git+https://github.com/servo/stylo?rev=f00c109074832b7fa7be52bbbf8f4987d24e323b#f00c109074832b7fa7be52bbbf8f4987d24e323b" 10865 10844 dependencies = [ 10866 10845 "bitflags 2.11.0", 10867 10846 "stylo_malloc_size_of", ··· 10869 10848 10870 10849 [[package]] 10871 10850 name = "stylo_malloc_size_of" 10872 - version = "0.12.0" 10873 - source = "git+https://github.com/servo/stylo?rev=9b635629e627a611419745198de1b1ba6c8667c2#9b635629e627a611419745198de1b1ba6c8667c2" 10851 + version = "0.13.0" 10852 + source = "git+https://github.com/servo/stylo?rev=f00c109074832b7fa7be52bbbf8f4987d24e323b#f00c109074832b7fa7be52bbbf8f4987d24e323b" 10874 10853 dependencies = [ 10875 10854 "app_units", 10876 10855 "cssparser", ··· 10886 10865 10887 10866 [[package]] 10888 10867 name = "stylo_static_prefs" 10889 - version = "0.12.0" 10890 - source = "git+https://github.com/servo/stylo?rev=9b635629e627a611419745198de1b1ba6c8667c2#9b635629e627a611419745198de1b1ba6c8667c2" 10868 + version = "0.13.0" 10869 + source = "git+https://github.com/servo/stylo?rev=f00c109074832b7fa7be52bbbf8f4987d24e323b#f00c109074832b7fa7be52bbbf8f4987d24e323b" 10891 10870 10892 10871 [[package]] 10893 10872 name = "stylo_traits" 10894 - version = "0.12.0" 10895 - source = "git+https://github.com/servo/stylo?rev=9b635629e627a611419745198de1b1ba6c8667c2#9b635629e627a611419745198de1b1ba6c8667c2" 10873 + version = "0.13.0" 10874 + source = "git+https://github.com/servo/stylo?rev=f00c109074832b7fa7be52bbbf8f4987d24e323b#f00c109074832b7fa7be52bbbf8f4987d24e323b" 10896 10875 dependencies = [ 10897 10876 "app_units", 10898 10877 "bitflags 2.11.0", ··· 11232 11211 11233 11212 [[package]] 11234 11213 name = "tiff" 11235 - version = "0.10.3" 11214 + version = "0.11.3" 11236 11215 source = "registry+https://github.com/rust-lang/crates.io-index" 11237 - checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" 11216 + checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" 11238 11217 dependencies = [ 11239 11218 "fax", 11240 11219 "flate2", 11241 11220 "half", 11242 11221 "quick-error", 11243 11222 "weezl", 11244 - "zune-jpeg 0.4.21", 11223 + "zune-jpeg 0.5.12", 11245 11224 ] 11246 11225 11247 11226 [[package]] ··· 11341 11320 checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" 11342 11321 dependencies = [ 11343 11322 "displaydoc", 11344 - "serde_core", 11345 11323 "zerovec 0.11.5", 11346 11324 ] 11347 11325 ··· 11373 11351 [[package]] 11374 11352 name = "to_shmem" 11375 11353 version = "0.3.0" 11376 - source = "git+https://github.com/servo/stylo?rev=9b635629e627a611419745198de1b1ba6c8667c2#9b635629e627a611419745198de1b1ba6c8667c2" 11354 + source = "git+https://github.com/servo/stylo?rev=f00c109074832b7fa7be52bbbf8f4987d24e323b#f00c109074832b7fa7be52bbbf8f4987d24e323b" 11377 11355 dependencies = [ 11378 11356 "cssparser", 11379 11357 "servo_arc", ··· 11386 11364 [[package]] 11387 11365 name = "to_shmem_derive" 11388 11366 version = "0.1.0" 11389 - source = "git+https://github.com/servo/stylo?rev=9b635629e627a611419745198de1b1ba6c8667c2#9b635629e627a611419745198de1b1ba6c8667c2" 11367 + source = "git+https://github.com/servo/stylo?rev=f00c109074832b7fa7be52bbbf8f4987d24e323b#f00c109074832b7fa7be52bbbf8f4987d24e323b" 11390 11368 dependencies = [ 11391 11369 "darling", 11392 11370 "proc-macro2", ··· 12517 12495 "bytes", 12518 12496 "cookie 0.16.2", 12519 12497 "http 0.2.12", 12520 - "icu_segmenter 1.5.0", 12498 + "icu_segmenter", 12521 12499 "log", 12522 12500 "serde", 12523 12501 "serde_derive", ··· 13853 13831 13854 13832 [[package]] 13855 13833 name = "zerocopy" 13856 - version = "0.8.40" 13834 + version = "0.8.42" 13857 13835 source = "registry+https://github.com/rust-lang/crates.io-index" 13858 - checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" 13836 + checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" 13859 13837 dependencies = [ 13860 13838 "zerocopy-derive", 13861 13839 ] 13862 13840 13863 13841 [[package]] 13864 13842 name = "zerocopy-derive" 13865 - version = "0.8.40" 13843 + version = "0.8.42" 13866 13844 source = "registry+https://github.com/rust-lang/crates.io-index" 13867 - checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" 13845 + checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" 13868 13846 dependencies = [ 13869 13847 "proc-macro2", 13870 13848 "quote", ··· 13951 13929 source = "registry+https://github.com/rust-lang/crates.io-index" 13952 13930 checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" 13953 13931 dependencies = [ 13954 - "serde", 13955 13932 "yoke 0.8.1", 13956 13933 "zerofrom", 13957 13934 "zerovec-derive 0.11.2",
+10 -10
Cargo.toml
··· 109 109 indexmap = { version = "2.11.4", features = ["std"] } 110 110 ipc-channel = "0.21" 111 111 itertools = "0.14" 112 - js = { package = "mozjs", version = "=0.15.1", default-features = false, features = ["libz-sys", "intl"] } 112 + js = { package = "mozjs", version = "=0.15.5", default-features = false, features = ["libz-sys", "intl"] } 113 113 keyboard-types = { version = "0.8.3", features = ["serde", "webdriver"] } 114 114 kurbo = { version = "0.12", features = ["euclid"] } 115 115 layout_api = { package = "servo-layout-api", path = "source/components/shared/layout" } ··· 167 167 sea-query = { version = "1.0.0-rc.30", default-features = false, features = ["backend-sqlite", "derive"] } 168 168 sea-query-rusqlite = { version = "0.8.0-rc.15" } 169 169 sec1 = "0.7" 170 - selectors = { git = "https://github.com/servo/stylo", rev = "9b635629e627a611419745198de1b1ba6c8667c2" } 170 + selectors = { git = "https://github.com/servo/stylo", rev = "f00c109074832b7fa7be52bbbf8f4987d24e323b" } 171 171 serde = "1.0.228" 172 172 serde_bytes = "0.11" 173 173 serde_core = "1.0.226" ··· 176 176 servo-media-dummy = { path = "source/components/media/backends/dummy" } 177 177 servo-media-gstreamer = { path = "source/components/media/backends/gstreamer" } 178 178 servo-tracing = { path = "source/components/servo_tracing" } 179 - servo_arc = { git = "https://github.com/servo/stylo", rev = "9b635629e627a611419745198de1b1ba6c8667c2" } 179 + servo_arc = { git = "https://github.com/servo/stylo", rev = "f00c109074832b7fa7be52bbbf8f4987d24e323b" } 180 180 sha1 = "0.10" 181 181 sha2 = "0.10" 182 182 sha3 = "0.10" ··· 185 185 storage_traits = { package = "servo-storage-traits", path = "source/components/shared/storage" } 186 186 string_cache = "0.9" 187 187 strum = { version = "0.27", features = ["derive"] } 188 - stylo = { git = "https://github.com/servo/stylo", rev = "9b635629e627a611419745198de1b1ba6c8667c2" } 189 - stylo_atoms = { git = "https://github.com/servo/stylo", rev = "9b635629e627a611419745198de1b1ba6c8667c2" } 190 - stylo_config = { git = "https://github.com/servo/stylo", rev = "9b635629e627a611419745198de1b1ba6c8667c2" } 191 - stylo_dom = { git = "https://github.com/servo/stylo", rev = "9b635629e627a611419745198de1b1ba6c8667c2" } 192 - stylo_malloc_size_of = { git = "https://github.com/servo/stylo", rev = "9b635629e627a611419745198de1b1ba6c8667c2" } 193 - stylo_static_prefs = { git = "https://github.com/servo/stylo", rev = "9b635629e627a611419745198de1b1ba6c8667c2" } 194 - stylo_traits = { git = "https://github.com/servo/stylo", rev = "9b635629e627a611419745198de1b1ba6c8667c2" } 188 + stylo = { git = "https://github.com/servo/stylo", rev = "f00c109074832b7fa7be52bbbf8f4987d24e323b" } 189 + stylo_atoms = { git = "https://github.com/servo/stylo", rev = "f00c109074832b7fa7be52bbbf8f4987d24e323b" } 190 + stylo_config = { git = "https://github.com/servo/stylo", rev = "f00c109074832b7fa7be52bbbf8f4987d24e323b" } 191 + stylo_dom = { git = "https://github.com/servo/stylo", rev = "f00c109074832b7fa7be52bbbf8f4987d24e323b" } 192 + stylo_malloc_size_of = { git = "https://github.com/servo/stylo", rev = "f00c109074832b7fa7be52bbbf8f4987d24e323b" } 193 + stylo_static_prefs = { git = "https://github.com/servo/stylo", rev = "f00c109074832b7fa7be52bbbf8f4987d24e323b" } 194 + stylo_traits = { git = "https://github.com/servo/stylo", rev = "f00c109074832b7fa7be52bbbf8f4987d24e323b" } 195 195 surfman = { version = "0.11.0", features = ["chains"] } 196 196 syn = { version = "2", default-features = false, features = ["clone-impls", "derive", "parsing"] } 197 197 synstructure = "0.13"
+1 -1
crates/beaver_p2p/src/main.rs
··· 1 1 use iroh::address_lookup::DiscoveryEvent; 2 2 use log::info; 3 - use p2p_beaver::{PairingManager, PeerEvent}; 3 + use beaver_p2p::{PairingManager, PeerEvent}; 4 4 use std::sync::mpsc::channel; 5 5 6 6 #[tokio::main]
+17 -17
crates/beaver_shell/Cargo.toml
··· 6 6 edition.workspace = true 7 7 8 8 [features] 9 - default = ["libservo/clipboard", "js_jit", "max_log_level", "native-bluetooth", "webgpu"] 10 - gamepad = ["libservo/gamepad"] 9 + default = ["servo/clipboard", "js_jit", "max_log_level", "native-bluetooth", "webgpu"] 10 + gamepad = ["servo/gamepad"] 11 11 global-hotkeys = ["dep:global-hotkey"] 12 - crown = ["libservo/crown"] 13 - debugmozjs = ["libservo/debugmozjs"] 14 - jitspew = ["libservo/jitspew"] 15 - js_backtrace = ["libservo/js_backtrace"] 16 - js_jit = ["libservo/js_jit"] 12 + crown = ["servo/crown"] 13 + debugmozjs = ["servo/debugmozjs"] 14 + jitspew = ["servo/jitspew"] 15 + js_backtrace = ["servo/js_backtrace"] 16 + js_jit = ["servo/js_jit"] 17 17 max_log_level = ["log/release_max_level_info"] 18 - media-gstreamer = ["libservo/media-gstreamer"] 19 - native-bluetooth = ["libservo/native-bluetooth"] 20 - profilemozjs = ["libservo/profilemozjs"] 21 - refcell_backtrace = ["libservo/refcell_backtrace"] 18 + media-gstreamer = ["servo/media-gstreamer"] 19 + native-bluetooth = ["servo/native-bluetooth"] 20 + profilemozjs = ["servo/profilemozjs"] 21 + refcell_backtrace = ["servo/refcell_backtrace"] 22 22 status-tray = ["dep:tray-icon", "dep:gtk"] 23 - tracing = ["dep:tracing", "dep:tracing-subscriber", "libservo/tracing"] 23 + tracing = ["dep:tracing", "dep:tracing-subscriber", "servo/tracing"] 24 24 tracing-perfetto = ["tracing", "dep:tracing-perfetto"] 25 - vello = ["libservo/vello"] 26 - webgl_backtrace = ["libservo/webgl_backtrace"] 27 - webgpu = ["libservo/webgpu"] 28 - webxr = ["libservo/webxr"] 25 + vello = ["servo/vello"] 26 + webgl_backtrace = ["servo/webgl_backtrace"] 27 + webgpu = ["servo/webgpu"] 28 + webxr = ["servo/webxr"] 29 29 30 30 [dependencies] 31 31 axum = { version = "0.8", features = ["http2"] } ··· 36 36 headers = { workspace = true } 37 37 image = { workspace = true } 38 38 keyboard-types = { workspace = true } 39 - libservo = { path = "../../source/components/servo", features = ["background_hang_monitor", "bluetooth"], default-features = false } 39 + servo = { path = "../../source/components/servo", features = ["background_hang_monitor", "bluetooth"], default-features = false } 40 40 log = { workspace = true } 41 41 mime_guess = { workspace = true } 42 42 parking_lot = { workspace = true }
+1 -1
forkme.lock
··· 1 - 401d327b96f6eda8c856aefcb54844c8209e0b48 1 + 517262fb34643d624d73eafa1ab7d6aa653f3b64
+35
patches/components/constellation/Cargo.toml.patch
··· 1 + --- original 2 + +++ modified 3 + @@ -28,6 +28,7 @@ 4 + background_hang_monitor_api = { workspace = true } 5 + backtrace = { workspace = true } 6 + base = { workspace = true } 7 + +beaver-p2p = { path = "../../../crates/beaver_p2p" } 8 + bluetooth_traits = { workspace = true, optional = true } 9 + canvas = { package = "servo-canvas", path = "../canvas" } 10 + canvas_traits = { workspace = true } 11 + @@ -39,6 +40,8 @@ 12 + euclid = { workspace = true } 13 + fonts = { package = "servo-fonts", path = "../fonts" } 14 + ipc-channel = { workspace = true } 15 + +iroh = "0.96" 16 + +iroh-persist = { git = "https://github.com/webbeef/iroh-persist.git", branch = "iroh-0.96" } 17 + keyboard-types = { workspace = true } 18 + layout_api = { workspace = true } 19 + log = { workspace = true } 20 + @@ -47,6 +50,7 @@ 21 + net_traits = { workspace = true } 22 + paint_api = { workspace = true } 23 + parking_lot = { workspace = true } 24 + +petname = "2.0" 25 + profile = { package = "servo-profile", path = "../profile" } 26 + profile_traits = { workspace = true } 27 + rand = { workspace = true } 28 + @@ -59,6 +63,7 @@ 29 + storage_traits = { workspace = true } 30 + stylo = { workspace = true } 31 + stylo_traits = { workspace = true } 32 + +tokio = { workspace = true } 33 + tracing = { workspace = true, optional = true } 34 + webgpu = { package = "servo-webgpu", path = "../webgpu" } 35 + webgpu_traits = { workspace = true }
+95 -16
patches/components/constellation/constellation.rs.patch
··· 27 27 }; 28 28 use euclid::Size2D; 29 29 use euclid::default::Size2D as UntypedSize2D; 30 - @@ -510,6 +511,19 @@ 30 + @@ -510,6 +511,22 @@ 31 31 32 32 /// Whether accessibility trees are being built and sent to the underlying platform. 33 33 pub(crate) accessibility_active: bool, ··· 44 44 + /// Set of script event loop IDs that have registered embedder error listeners. 45 45 + /// Only these event loops will receive DispatchServoError messages. 46 46 + embedder_error_listeners: FxHashSet<ScriptEventLoopId>, 47 + + 48 + + /// The P2P pairing service. 49 + + pairing: crate::pairing::PairingService, 47 50 } 48 51 49 52 /// State needed to construct a constellation. 50 - @@ -729,6 +743,9 @@ 53 + @@ -729,6 +746,10 @@ 51 54 screenshot_readiness_requests: Vec::new(), 52 55 user_contents_for_manager_id: Default::default(), 53 56 accessibility_active: false, 54 57 + embedded_webview_to_iframe: FxHashMap::default(), 55 58 + active_ime_webview: None, 56 59 + embedder_error_listeners: Default::default(), 60 + + pairing: crate::pairing::PairingService::new(), 57 61 }; 58 62 59 63 constellation.run(); 60 - @@ -754,6 +771,18 @@ 64 + @@ -754,6 +775,18 @@ 61 65 fn clean_up_finished_script_event_loops(&mut self) { 62 66 self.event_loop_join_handles 63 67 .retain(|join_handle| !join_handle.is_finished()); ··· 76 80 self.event_loops 77 81 .retain(|event_loop| event_loop.upgrade().is_some()); 78 82 } 79 - @@ -1045,6 +1074,11 @@ 83 + @@ -1045,6 +1078,11 @@ 80 84 .get(&webview_id) 81 85 .and_then(|webview| webview.user_content_manager_id); 82 86 ··· 88 92 let new_pipeline_info = NewPipelineInfo { 89 93 parent_info: parent_pipeline_id, 90 94 new_pipeline_id, 91 - @@ -1055,6 +1089,13 @@ 95 + @@ -1055,6 +1093,13 @@ 92 96 viewport_details: initial_viewport_details, 93 97 user_content_manager_id, 94 98 theme, ··· 102 106 }; 103 107 let pipeline = match Pipeline::spawn(new_pipeline_info, event_loop, self, throttled) { 104 108 Ok(pipeline) => pipeline, 105 - @@ -1534,11 +1575,7 @@ 109 + @@ -1229,6 +1274,7 @@ 110 + BackgroundHangMonitor(HangMonitorAlert), 111 + Embedder(EmbedderToConstellationMessage), 112 + FromSWManager(SWManagerMsg), 113 + + PairingEvent(constellation_traits::PairingEvent), 114 + RemoveProcess(usize), 115 + } 116 + // Get one incoming request. 117 + @@ -1249,6 +1295,15 @@ 118 + sel.recv(&self.embedder_to_constellation_receiver); 119 + sel.recv(&self.swmanager_receiver); 120 + 121 + + // Conditionally register the pairing event receiver (index 5 if present). 122 + + let has_pairing_receiver = if let Some(receiver) = self.pairing.event_receiver() { 123 + + sel.recv(receiver); 124 + + true 125 + + } else { 126 + + false 127 + + }; 128 + + let process_base_index = if has_pairing_receiver { 6 } else { 5 }; 129 + + 130 + self.process_manager.register(&mut sel); 131 + 132 + let request = { 133 + @@ -1277,9 +1332,13 @@ 134 + .recv(&self.swmanager_receiver) 135 + .expect("Unexpected SW channel panic in constellation") 136 + .map(Request::FromSWManager), 137 + + 5 if has_pairing_receiver => Ok(Request::PairingEvent( 138 + + oper.recv(self.pairing.event_receiver().expect("checked above")) 139 + + .expect("Unexpected pairing event channel panic in constellation"), 140 + + )), 141 + _ => { 142 + // This can only be a error reading on a closed lifeline receiver. 143 + - let process_index = index - 5; 144 + + let process_index = index - process_base_index; 145 + let _ = oper.recv(self.process_manager.receiver_at(process_index)); 146 + Ok(Request::RemoveProcess(process_index)) 147 + }, 148 + @@ -1305,6 +1364,9 @@ 149 + Request::FromSWManager(message) => { 150 + self.handle_request_from_swmanager(message); 151 + }, 152 + + Request::PairingEvent(event) => { 153 + + self.handle_pairing_event(event); 154 + + }, 155 + Request::RemoveProcess(index) => self.process_manager.remove(index), 156 + } 157 + } 158 + @@ -1534,11 +1596,7 @@ 106 159 } 107 160 }, 108 161 EmbedderToConstellationMessage::PreferencesUpdated(updates) => { ··· 115 168 let _ = event_loop.send(ScriptThreadMessage::PreferencesUpdated( 116 169 updates 117 170 .iter() 118 - @@ -1565,6 +1602,18 @@ 171 + @@ -1565,6 +1623,18 @@ 119 172 EmbedderToConstellationMessage::SetAccessibilityActive(active) => { 120 173 self.set_accessibility_active(active); 121 174 }, ··· 134 187 } 135 188 } 136 189 137 - @@ -1788,6 +1837,12 @@ 190 + @@ -1788,6 +1858,12 @@ 138 191 self.broadcast_channels 139 192 .remove_broadcast_channel_router(router_id); 140 193 }, ··· 147 200 ScriptToConstellationMessage::ScheduleBroadcast(router_id, message) => { 148 201 if self 149 202 .check_origin_against_pipeline(&source_pipeline_id, &message.origin) 150 - @@ -1818,6 +1873,12 @@ 203 + @@ -1818,6 +1894,12 @@ 151 204 ScriptToConstellationMessage::CreateAuxiliaryWebView(load_info) => { 152 205 self.handle_script_new_auxiliary(load_info); 153 206 }, ··· 160 213 ScriptToConstellationMessage::ChangeRunningAnimationsState(animation_state) => { 161 214 self.handle_change_running_animations_state(source_pipeline_id, animation_state) 162 215 }, 163 - @@ -1984,6 +2045,23 @@ 216 + @@ -1984,6 +2066,23 @@ 164 217 new_value, 165 218 ); 166 219 }, ··· 184 237 ScriptToConstellationMessage::MediaSessionEvent(pipeline_id, event) => { 185 238 // Unlikely at this point, but we may receive events coming from 186 239 // different media sessions, so we set the active media session based 187 - @@ -2057,6 +2135,129 @@ 240 + @@ -2057,9 +2156,155 @@ 188 241 let _ = event_loop.send(ScriptThreadMessage::TriggerGarbageCollection); 189 242 } 190 243 }, ··· 311 364 + self.active_ime_webview = None; 312 365 + } 313 366 + }, 367 + + ScriptToConstellationMessage::PairingStart(callback) => { 368 + + self.pairing.start(callback); 369 + + }, 370 + + ScriptToConstellationMessage::PairingStop(callback) => { 371 + + self.pairing.stop(callback); 372 + + }, 373 + + ScriptToConstellationMessage::PairingGetLocal(callback) => { 374 + + self.pairing.get_local(callback); 375 + + }, 376 + + ScriptToConstellationMessage::PairingGetPeers(callback) => { 377 + + self.pairing.get_peers(callback); 378 + + }, 379 + + ScriptToConstellationMessage::PairingSetName(name, callback) => { 380 + + self.pairing.set_name(name, callback); 381 + + }, 314 382 } 315 383 } 316 384 317 - @@ -3174,6 +3375,13 @@ 385 + + fn handle_pairing_event(&self, event: constellation_traits::PairingEvent) { 386 + + for event_loop in self.event_loops() { 387 + + if self.embedder_error_listeners.contains(&event_loop.id()) { 388 + + let _ = event_loop.send(ScriptThreadMessage::DispatchPairingEvent(event.clone())); 389 + + } 390 + + } 391 + + } 392 + + 393 + /// Check the origin of a message against that of the pipeline it came from. 394 + /// Note: this is still limited as a security check, 395 + /// see <https://github.com/servo/servo/issues/11722> 396 + @@ -3174,6 +3419,13 @@ 318 397 /// <https://html.spec.whatwg.org/multipage/#destroy-a-top-level-traversable> 319 398 fn handle_close_top_level_browsing_context(&mut self, webview_id: WebViewId) { 320 399 debug!("{webview_id}: Closing"); ··· 328 407 let browsing_context_id = BrowsingContextId::from(webview_id); 329 408 // Step 5. Remove traversable from the user agent's top-level traversable set. 330 409 let browsing_context = 331 - @@ -3450,8 +3658,27 @@ 410 + @@ -3450,8 +3702,27 @@ 332 411 opener_webview_id, 333 412 opener_pipeline_id, 334 413 response_sender, ··· 356 435 let Some((webview_id_sender, webview_id_receiver)) = generic_channel::channel() else { 357 436 warn!("Failed to create channel"); 358 437 let _ = response_sender.send(None); 359 - @@ -3550,6 +3777,361 @@ 438 + @@ -3550,6 +3821,361 @@ 360 439 }); 361 440 } 362 441 ··· 718 797 #[servo_tracing::instrument(skip_all)] 719 798 fn handle_refresh_cursor(&self, pipeline_id: PipelineId) { 720 799 let Some(pipeline) = self.pipelines.get(&pipeline_id) else { 721 - @@ -4676,7 +5258,7 @@ 800 + @@ -4676,7 +5302,7 @@ 722 801 } 723 802 724 803 #[servo_tracing::instrument(skip_all)] ··· 727 806 // Send a flat projection of the history to embedder. 728 807 // The final vector is a concatenation of the URLs of the past 729 808 // entries, the current entry and the future entries. 730 - @@ -4779,9 +5361,23 @@ 809 + @@ -4779,9 +5405,23 @@ 731 810 ); 732 811 self.embedder_proxy.send(EmbedderMsg::HistoryChanged( 733 812 webview_id,
+10
patches/components/constellation/lib.rs.patch
··· 1 + --- original 2 + +++ modified 3 + @@ -13,6 +13,7 @@ 4 + mod constellation_webview; 5 + mod event_loop; 6 + mod logging; 7 + +mod pairing; 8 + mod pipeline; 9 + mod process_manager; 10 + mod sandboxing;
+259
patches/components/constellation/pairing.rs.patch
··· 1 + --- original 2 + +++ modified 3 + @@ -0,0 +1,256 @@ 4 + +// SPDX-License-Identifier: AGPL-3.0-or-later 5 + + 6 + +//! P2P pairing service integration with the constellation. 7 + +//! 8 + +//! This module encapsulates the lifecycle of the `PairingManager` from `beaver_p2p` 9 + +//! and bridges its async events into the constellation's crossbeam-based event loop. 10 + +//! The endpoint's secret key and display name are persisted to the config directory. 11 + + 12 + +use std::path::PathBuf; 13 + +use std::sync::Arc; 14 + + 15 + +use base::generic_channel::GenericCallback; 16 + +use beaver_p2p::{EndpointStatus, PairingManager, PeerEvent}; 17 + +use constellation_traits::{LocalPeerInfo, PairingEvent, PeerInfo, PeerStatus}; 18 + +use crossbeam_channel; 19 + +use iroh::address_lookup::DiscoveryEvent; 20 + +use log::{info, warn}; 21 + +use tokio::sync::Mutex; 22 + + 23 + +pub(crate) struct PairingService { 24 + + manager: Arc<Mutex<Option<PairingManager>>>, 25 + + local_info: Arc<Mutex<Option<LocalPeerInfo>>>, 26 + + event_receiver: Option<crossbeam_channel::Receiver<PairingEvent>>, 27 + +} 28 + + 29 + +impl PairingService { 30 + + pub(crate) fn new() -> Self { 31 + + Self { 32 + + manager: Default::default(), 33 + + local_info: Default::default(), 34 + + event_receiver: None, 35 + + } 36 + + } 37 + + 38 + + /// Returns the event receiver for use in the constellation's Select loop. 39 + + pub(crate) fn event_receiver(&self) -> Option<&crossbeam_channel::Receiver<PairingEvent>> { 40 + + self.event_receiver.as_ref() 41 + + } 42 + + 43 + + /// Start the pairing service. Creates the PairingManager on the tokio runtime 44 + + /// and sets up a bridge task to forward PeerEvents to a crossbeam channel. 45 + + /// The secret key and display name are persisted to the config directory. 46 + + pub(crate) fn start(&mut self, callback: GenericCallback<Result<(), String>>) { 47 + + let manager = self.manager.clone(); 48 + + let local_info = self.local_info.clone(); 49 + + let (cb_sender, cb_receiver) = crossbeam_channel::unbounded(); 50 + + self.event_receiver = Some(cb_receiver); 51 + + 52 + + net::async_runtime::spawn_task(async move { 53 + + let mut guard = manager.lock().await; 54 + + if guard.is_some() { 55 + + let _ = callback.send(Ok(())); 56 + + return; 57 + + } 58 + + 59 + + let config_dir = servo_config::opts::get().config_dir.clone(); 60 + + 61 + + // Load or generate the persistent secret key. 62 + + let key = load_or_create_key(config_dir.as_ref()).await; 63 + + 64 + + // Load or generate the persistent display name. 65 + + let name = load_or_create_name(config_dir.as_ref()).await; 66 + + info!("Pairing service starting as \"{name}\""); 67 + + 68 + + // Store local endpoint info (id is derived from the secret key). 69 + + *local_info.lock().await = Some(LocalPeerInfo { 70 + + id: key.public().to_string(), 71 + + name: name.clone(), 72 + + }); 73 + + 74 + + let (event_sender, event_receiver) = std::sync::mpsc::channel(); 75 + + let new_manager = PairingManager::create(event_sender, &name, key).await; 76 + + *guard = Some(new_manager); 77 + + 78 + + // Bridge: forward PeerEvents to the crossbeam channel as PairingEvents. 79 + + // This loop exits naturally when PairingManager::stop() drops the sender, 80 + + // causing recv() to return Err. 81 + + tokio::task::spawn_blocking(move || { 82 + + while let Ok(event) = event_receiver.recv() { 83 + + if let Some(pairing_event) = to_pairing_event(&event) { 84 + + if cb_sender.send(pairing_event).is_err() { 85 + + break; 86 + + } 87 + + } 88 + + } 89 + + }); 90 + + 91 + + let _ = callback.send(Ok(())); 92 + + }); 93 + + } 94 + + 95 + + /// Stop the pairing service. Clears the event receiver first (so the constellation 96 + + /// stops selecting on it), then stops the PairingManager (which drops the mpsc sender, 97 + + /// causing the bridge task to exit naturally). 98 + + pub(crate) fn stop(&mut self, callback: GenericCallback<Result<(), String>>) { 99 + + // Remove the receiver first so the constellation's Select loop no longer polls it. 100 + + self.event_receiver = None; 101 + + 102 + + let manager = self.manager.clone(); 103 + + let local_info = self.local_info.clone(); 104 + + net::async_runtime::spawn_task(async move { 105 + + *local_info.lock().await = None; 106 + + let mut guard = manager.lock().await; 107 + + if let Some(mut mgr) = guard.take() { 108 + + mgr.stop().await; 109 + + } 110 + + let _ = callback.send(Ok(())); 111 + + }); 112 + + } 113 + + 114 + + /// Get the local endpoint info. Responds via callback since the info 115 + + /// may still be loading asynchronously on the tokio runtime. 116 + + pub(crate) fn get_local(&self, callback: GenericCallback<Result<LocalPeerInfo, String>>) { 117 + + let local_info = self.local_info.clone(); 118 + + net::async_runtime::spawn_task(async move { 119 + + let guard = local_info.lock().await; 120 + + let result = match guard.as_ref() { 121 + + Some(info) => Ok(info.clone()), 122 + + None => Err("Pairing service not started".to_owned()), 123 + + }; 124 + + let _ = callback.send(result); 125 + + }); 126 + + } 127 + + 128 + + /// Get the list of known peers from the PairingManager. 129 + + pub(crate) fn get_peers(&self, callback: GenericCallback<Result<Vec<PeerInfo>, String>>) { 130 + + let manager = self.manager.clone(); 131 + + net::async_runtime::spawn_task(async move { 132 + + let guard = manager.lock().await; 133 + + let result = match guard.as_ref() { 134 + + Some(mgr) => { 135 + + let peers = mgr 136 + + .peers() 137 + + .await 138 + + .into_iter() 139 + + .map(|ep| PeerInfo { 140 + + id: ep.id.to_string(), 141 + + name: ep.name, 142 + + status: match ep.status { 143 + + EndpointStatus::Discovered => PeerStatus::Discovered, 144 + + EndpointStatus::PairedConnected => PeerStatus::PairedConnected, 145 + + EndpointStatus::PairedDisconnected => { 146 + + PeerStatus::PairedDisconnected 147 + + }, 148 + + }, 149 + + }) 150 + + .collect(); 151 + + Ok(peers) 152 + + }, 153 + + None => Err("Pairing service not started".to_owned()), 154 + + }; 155 + + let _ = callback.send(result); 156 + + }); 157 + + } 158 + + 159 + + /// Update the persisted display name. The caller should stop and restart 160 + + /// the service for the new name to take effect on mDNS. 161 + + pub(crate) fn set_name(&self, name: String, callback: GenericCallback<Result<(), String>>) { 162 + + let local_info = self.local_info.clone(); 163 + + net::async_runtime::spawn_task(async move { 164 + + let config_dir = servo_config::opts::get().config_dir.clone(); 165 + + if let Some(dir) = config_dir.as_ref() { 166 + + let name_path = dir.join("pairing-name.txt"); 167 + + if let Err(e) = tokio::fs::create_dir_all(dir).await { 168 + + let _ = callback.send(Err(format!("Failed to create config dir: {e}"))); 169 + + return; 170 + + } 171 + + if let Err(e) = tokio::fs::write(&name_path, &name).await { 172 + + let _ = callback.send(Err(format!("Failed to write name: {e}"))); 173 + + return; 174 + + } 175 + + } 176 + + // Update the cached local info if the service is running. 177 + + if let Some(info) = local_info.lock().await.as_mut() { 178 + + info.name = name; 179 + + } 180 + + let _ = callback.send(Ok(())); 181 + + }); 182 + + } 183 + +} 184 + + 185 + +/// Load the secret key from the config directory, or generate and persist a new one. 186 + +/// Uses `iroh-persist` which stores keys in OpenSSH PEM format. 187 + +async fn load_or_create_key(config_dir: Option<&PathBuf>) -> iroh::SecretKey { 188 + + let mut retriever = iroh_persist::KeyRetriever::new("beaver"); 189 + + if let Some(dir) = config_dir { 190 + + retriever = retriever.persist_at_some(dir.join("iroh-secret-key.pem")); 191 + + } else { 192 + + retriever = retriever.persist(true); 193 + + } 194 + + retriever.lenient().get().await 195 + +} 196 + + 197 + +/// Load the display name from the config directory, or generate and persist a new one. 198 + +/// The name is stored as a plain text file `pairing-name.txt`. 199 + +async fn load_or_create_name(config_dir: Option<&PathBuf>) -> String { 200 + + if let Some(dir) = config_dir { 201 + + let name_path = dir.join("pairing-name.txt"); 202 + + if let Ok(name) = tokio::fs::read_to_string(&name_path).await { 203 + + let name = name.trim().to_owned(); 204 + + if !name.is_empty() { 205 + + return name; 206 + + } 207 + + } 208 + + 209 + + let name = generate_name(); 210 + + 211 + + // Ensure directory exists and write the name. 212 + + if let Err(e) = tokio::fs::create_dir_all(dir).await { 213 + + warn!("Failed to create config dir for pairing name: {e}"); 214 + + } else if let Err(e) = tokio::fs::write(&name_path, &name).await { 215 + + warn!("Failed to persist pairing name: {e}"); 216 + + } 217 + + 218 + + name 219 + + } else { 220 + + generate_name() 221 + + } 222 + +} 223 + + 224 + +/// Generate a memorable display name using petname. 225 + +fn generate_name() -> String { 226 + + petname::petname(3, "-").unwrap_or_else(|| format!("beaver-{}", rand::random::<u32>())) 227 + +} 228 + + 229 + +/// Convert a beaver_p2p PeerEvent to a serializable PairingEvent. 230 + +/// Returns None for events that don't map (e.g. Message). 231 + +fn to_pairing_event(event: &PeerEvent) -> Option<PairingEvent> { 232 + + match event { 233 + + PeerEvent::Discovery(DiscoveryEvent::Discovered { endpoint_info, .. }) => { 234 + + let name = endpoint_info 235 + + .data 236 + + .user_data() 237 + + .map(|d| d.as_ref().to_owned()) 238 + + .unwrap_or_else(|| "<unknown>".to_owned()); 239 + + Some(PairingEvent::PeerDiscovered { 240 + + id: endpoint_info.endpoint_id.to_string(), 241 + + name, 242 + + }) 243 + + }, 244 + + PeerEvent::Discovery(DiscoveryEvent::Expired { endpoint_id }) => { 245 + + Some(PairingEvent::PeerExpired { 246 + + id: endpoint_id.to_string(), 247 + + }) 248 + + }, 249 + + PeerEvent::PairingRequest(id) => Some(PairingEvent::PairingRequest { id: id.to_string() }), 250 + + PeerEvent::PairingAccepted(id) => { 251 + + Some(PairingEvent::PairingAccepted { id: id.to_string() }) 252 + + }, 253 + + PeerEvent::PairingRejected(id) => { 254 + + Some(PairingEvent::PairingRejected { id: id.to_string() }) 255 + + }, 256 + + PeerEvent::PairingFailed(id) => Some(PairingEvent::PairingFailed { id: id.to_string() }), 257 + + PeerEvent::Message(..) => None, 258 + + } 259 + +}
+6 -1
patches/components/constellation/tracing.rs.patch
··· 36 36 Self::ActivateDocument => target!("ActivateDocument"), 37 37 Self::SetDocumentState(..) => target!("SetDocumentState"), 38 38 Self::SetFinalUrl(..) => target!("SetFinalUrl"), 39 - @@ -186,6 +194,35 @@ 39 + @@ -186,6 +194,40 @@ 40 40 target!("RespondToScreenshotReadinessRequest") 41 41 }, 42 42 Self::TriggerGarbageCollection => target!("TriggerGarbageCollection"), ··· 69 69 + Self::ClearActiveImeWebView(..) => { 70 70 + target!("ClearActiveImeWebView") 71 71 + }, 72 + + Self::PairingStart(..) => target!("PairingStart"), 73 + + Self::PairingStop(..) => target!("PairingStop"), 74 + + Self::PairingGetLocal(..) => target!("PairingGetLocal"), 75 + + Self::PairingGetPeers(..) => target!("PairingGetPeers"), 76 + + Self::PairingSetName(..) => target!("PairingSetName"), 72 77 } 73 78 } 74 79 }
+3 -3
patches/components/layout/layout_impl.rs.patch
··· 1 1 --- original 2 2 +++ modified 3 - @@ -213,6 +213,10 @@ 3 + @@ -205,6 +205,10 @@ 4 4 /// Whether accessibility is active in this layout. 5 5 /// (Note: this is a temporary field which will be replaced with an optional accessibility tree member.) 6 6 accessibility_active: Cell<bool>, ··· 11 11 } 12 12 13 13 pub struct LayoutFactoryImpl(); 14 - @@ -253,12 +257,25 @@ 14 + @@ -245,12 +249,25 @@ 15 15 fn set_viewport_details(&mut self, viewport_details: ViewportDetails) -> bool { 16 16 let device = self.stylist.device_mut(); 17 17 let device_pixel_ratio = Scale::new(viewport_details.hidpi_scale_factor.get()); ··· 41 41 device.set_viewport_size(viewport_details.size); 42 42 device.set_device_pixel_ratio(device_pixel_ratio); 43 43 self.device_has_changed = true; 44 - @@ -818,6 +835,7 @@ 44 + @@ -729,6 +746,7 @@ 45 45 paint_timing_handler: Default::default(), 46 46 user_stylesheets: config.user_stylesheets, 47 47 accessibility_active: Cell::new(config.accessibility_active),
+1 -1
patches/components/script/dom/debuggerglobalscope.rs.patch
··· 1 1 --- original 2 2 +++ modified 3 - @@ -106,9 +106,11 @@ 3 + @@ -105,9 +105,11 @@ 4 4 None, 5 5 #[cfg(feature = "webgpu")] 6 6 gpu_id_hub,
+11 -11
patches/components/script/dom/document.rs.patch
··· 25 25 use fonts::WebFontDocumentContext; 26 26 use html5ever::{LocalName, Namespace, QualName, local_name, ns}; 27 27 use hyper_serde::Serde; 28 - @@ -615,6 +618,9 @@ 28 + @@ -617,6 +620,9 @@ 29 29 #[no_trace] 30 30 favicon: RefCell<Option<Image>>, 31 31 ··· 35 35 /// All websockets created that are associated with this document. 36 36 websockets: DOMTracker<WebSocket>, 37 37 38 - @@ -860,6 +866,12 @@ 38 + @@ -862,6 +868,12 @@ 39 39 40 40 // Set the document's activity level, reflow if necessary, and suspend or resume timers. 41 41 self.activity.set(activity); ··· 48 48 let media = ServoMedia::get(); 49 49 let pipeline_id = self.window().pipeline_id(); 50 50 let client_context_id = 51 - @@ -873,6 +885,7 @@ 51 + @@ -875,6 +887,7 @@ 52 52 53 53 self.title_changed(); 54 54 self.notify_embedder_favicon(); ··· 56 56 self.dirty_all_nodes(); 57 57 self.window().resume(CanGc::from_cx(cx)); 58 58 media.resume(&client_context_id); 59 - @@ -1277,6 +1290,9 @@ 59 + @@ -1279,6 +1292,9 @@ 60 60 LoadStatus::Started, 61 61 )); 62 62 self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None)); ··· 66 66 } 67 67 }, 68 68 DocumentReadyState::Complete => { 69 - @@ -1285,6 +1301,9 @@ 69 + @@ -1287,6 +1303,9 @@ 70 70 self.webview_id(), 71 71 LoadStatus::Complete, 72 72 )); ··· 76 76 } 77 77 update_with_current_instant(&self.dom_complete); 78 78 }, 79 - @@ -1691,7 +1710,13 @@ 79 + @@ -1693,7 +1712,13 @@ 80 80 let window = self.window(); 81 81 if window.is_top_level() { 82 82 let title = self.title().map(String::from); ··· 91 91 } 92 92 } 93 93 94 - @@ -1700,6 +1725,18 @@ 94 + @@ -1702,6 +1727,18 @@ 95 95 window.send_to_embedder(msg); 96 96 } 97 97 ··· 110 110 pub(crate) fn dirty_all_nodes(&self) { 111 111 let root = match self.GetDocumentElement() { 112 112 Some(root) => root, 113 - @@ -3198,9 +3235,59 @@ 113 + @@ -3216,9 +3253,59 @@ 114 114 current_rendering_epoch, 115 115 ); 116 116 ··· 170 170 pub(crate) fn handle_no_longer_waiting_on_asynchronous_image_updates(&self) { 171 171 self.waiting_on_canvas_image_updates.set(false); 172 172 } 173 - @@ -3943,6 +4030,7 @@ 173 + @@ -3961,6 +4048,7 @@ 174 174 active_sandboxing_flag_set: Cell::new(SandboxingFlagSet::empty()), 175 175 creation_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set), 176 176 favicon: RefCell::new(None), ··· 178 178 websockets: DOMTracker::new(), 179 179 details_name_groups: Default::default(), 180 180 protocol_handler_automation_mode: Default::default(), 181 - @@ -5047,6 +5135,36 @@ 181 + @@ -5065,6 +5153,36 @@ 182 182 183 183 pub(crate) fn notify_embedder_favicon(&self) { 184 184 if let Some(ref image) = *self.favicon.borrow() { ··· 215 215 self.send_to_embedder(EmbedderMsg::NewFavicon(self.webview_id(), image.clone())); 216 216 } 217 217 } 218 - @@ -5092,6 +5210,20 @@ 218 + @@ -5110,6 +5228,20 @@ 219 219 pub(crate) fn set_css_styling_flag(&self, value: bool) { 220 220 self.css_styling_flag.set(value) 221 221 }
+17 -17
patches/components/script/dom/document_event_handler.rs.patch
··· 108 108 /// The [`DocumentEventHandler`] is a structure responsible for handling input events for 109 109 /// the [`crate::Document`] and storing data related to event handling. It exists to 110 110 /// decrease the size of the [`crate::Document`] structure. 111 - @@ -178,6 +235,20 @@ 111 + @@ -180,6 +237,20 @@ 112 112 next_touch_pointer_id: Cell<i32>, 113 113 /// A map holding information about currently registered access key handlers. 114 114 access_key_handlers: DomRefCell<FxHashMap<char, Dom<HTMLElement>>>, ··· 129 129 } 130 130 131 131 impl DocumentEventHandler { 132 - @@ -198,6 +269,9 @@ 132 + @@ -201,6 +272,9 @@ 133 133 active_pointer_ids: Default::default(), 134 134 next_touch_pointer_id: Cell::new(1), 135 135 access_key_handlers: Default::default(), ··· 139 139 } 140 140 } 141 141 142 - @@ -463,6 +537,198 @@ 142 + @@ -491,6 +565,198 @@ 143 143 } 144 144 } 145 145 ··· 338 338 /// <https://w3c.github.io/uievents/#handle-native-mouse-move> 339 339 fn handle_native_mouse_move_event(&self, input_event: &ConstellationInputEvent, can_gc: CanGc) { 340 340 // Ignore all incoming events without a hit test. 341 - @@ -477,6 +743,57 @@ 341 + @@ -505,6 +771,57 @@ 342 342 return; 343 343 } 344 344 ··· 396 396 // Update the cursor when the mouse moves, if it has changed. 397 397 self.set_cursor(Some(hit_test_result.cursor)); 398 398 399 - @@ -702,6 +1019,12 @@ 399 + @@ -730,6 +1047,12 @@ 400 400 return; 401 401 }; 402 402 ··· 409 409 debug!( 410 410 "{:?}: at {:?}", 411 411 event.action, hit_test_result.point_in_frame 412 - @@ -794,18 +1117,25 @@ 412 + @@ -822,18 +1145,25 @@ 413 413 let target_el = element.find_click_focusable_shadow_host_if_necessary(); 414 414 415 415 let document = self.window.Document(); ··· 440 440 document.commit_focus_transaction(FocusInitiator::Click, can_gc); 441 441 } 442 442 443 - @@ -815,7 +1145,7 @@ 443 + @@ -843,7 +1173,7 @@ 444 444 self.maybe_show_context_menu( 445 445 node.upcast(), 446 446 &hit_test_result, ··· 449 449 can_gc, 450 450 ); 451 451 } 452 - @@ -939,9 +1269,30 @@ 452 + @@ -967,9 +1297,30 @@ 453 453 &self, 454 454 target: &EventTarget, 455 455 hit_test_result: &HitTestResult, ··· 481 481 // <https://w3c.github.io/uievents/#contextmenu> 482 482 let menu_event = PointerEvent::new( 483 483 &self.window, // window 484 - @@ -955,25 +1306,25 @@ 484 + @@ -983,25 +1334,25 @@ 485 485 hit_test_result 486 486 .point_relative_to_initial_containing_block 487 487 .to_i32(), ··· 526 526 can_gc, 527 527 ); 528 528 529 - @@ -989,6 +1340,89 @@ 529 + @@ -1017,6 +1368,89 @@ 530 530 }; 531 531 } 532 532 ··· 616 616 fn handle_touch_event( 617 617 &self, 618 618 event: EmbedderTouchEvent, 619 - @@ -995,6 +1429,29 @@ 619 + @@ -1023,6 +1457,29 @@ 620 620 input_event: &ConstellationInputEvent, 621 621 can_gc: CanGc, 622 622 ) -> InputEventResult { ··· 646 646 // Ignore all incoming events without a hit test. 647 647 let Some(hit_test_result) = self.window.hit_test_from_input_event(input_event) else { 648 648 self.update_active_touch_points_when_early_return(event); 649 - @@ -1001,6 +1458,16 @@ 649 + @@ -1029,6 +1486,16 @@ 650 650 return Default::default(); 651 651 }; 652 652 ··· 663 663 let TouchId(identifier) = event.touch_id; 664 664 665 665 let Some(element) = hit_test_result 666 - @@ -1132,6 +1599,10 @@ 666 + @@ -1160,6 +1627,10 @@ 667 667 // <https://html.spec.whatwg.org/multipage/#selector-active> 668 668 // If the element is being actively pointed at the element is being activated. 669 669 self.element_for_activation(element).set_active_state(true); ··· 674 674 (current_target, pointer_touch) 675 675 }, 676 676 _ => { 677 - @@ -1164,10 +1635,31 @@ 677 + @@ -1192,10 +1663,31 @@ 678 678 can_gc, 679 679 ); 680 680 ··· 707 707 }, 708 708 TouchEventType::Up | TouchEventType::Cancel => { 709 709 active_touch_points.swap_remove(index); 710 - @@ -1175,6 +1667,17 @@ 710 + @@ -1203,6 +1695,17 @@ 711 711 // <https://html.spec.whatwg.org/multipage/#selector-active> 712 712 // If the element is being actively pointed at the element is being activated. 713 713 self.element_for_activation(element).set_active_state(false); ··· 725 725 }, 726 726 TouchEventType::Down => unreachable!("Should have been handled above"), 727 727 } 728 - @@ -1218,6 +1721,19 @@ 728 + @@ -1246,6 +1749,19 @@ 729 729 ); 730 730 let event = touch_event.upcast::<Event>(); 731 731 event.fire(&touch_dispatch_target, can_gc); ··· 745 745 event.flags().into() 746 746 } 747 747 748 - @@ -1404,6 +1920,16 @@ 748 + @@ -1432,6 +1948,16 @@ 749 749 return Default::default(); 750 750 }; 751 751
+13 -4
patches/components/script/dom/embedder.rs.patch
··· 1 1 --- original 2 2 +++ modified 3 - @@ -0,0 +1,271 @@ 3 + @@ -0,0 +1,280 @@ 4 4 +/* SPDX Id: AGPL-3.0-or-later */ 5 5 + 6 6 +//! The `Embedder` interface provides communication between web content and the embedder. ··· 27 27 +use crate::dom::bindings::codegen::Bindings::EmbedderBinding::EmbedderMethods; 28 28 +use crate::dom::bindings::inheritance::Castable; 29 29 +use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object}; 30 - +use crate::dom::bindings::root::{Dom, DomRoot, Root}; 30 + +use crate::dom::bindings::root::{DomRoot, MutNullableDom}; 31 31 +use crate::dom::bindings::str::DOMString; 32 32 +use crate::dom::customevent::CustomEvent; 33 33 +use crate::dom::event::Event; 34 34 +use crate::dom::eventtarget::EventTarget; 35 35 +use crate::dom::globalscope::GlobalScope; 36 + +use crate::dom::pairing::Pairing; 36 37 +use crate::realms::{AlreadyInRealm, InRealm}; 37 38 +use crate::script_runtime::CanGc; 38 39 + 39 40 +#[dom_struct] 40 41 +pub(crate) struct Embedder { 41 42 + eventtarget: EventTarget, 43 + + pairing: MutNullableDom<Pairing>, 42 44 +} 43 45 + 44 46 +impl Embedder { 45 47 + fn new_inherited() -> Embedder { 46 48 + Embedder { 47 49 + eventtarget: EventTarget::new_inherited(), 50 + + pairing: Default::default(), 48 51 + } 49 52 + } 50 53 + ··· 59 62 + } 60 63 + 61 64 + reflect_dom_object(Box::new(Embedder::new_inherited()), global, can_gc) 65 + + } 66 + + 67 + + /// Get the Pairing instance if it has already been created (without lazy-initializing). 68 + + pub(crate) fn get_pairing(&self) -> Option<DomRoot<Pairing>> { 69 + + self.pairing.get() 62 70 + } 63 71 + 64 72 + /// Dispatch a servoerror event with the given error type and message. ··· 258 266 + .send(EmbedderMsg::StartWindowResize(webview_id)); 259 267 + } 260 268 + 261 - + fn Pairing(&self) -> Root<Dom<<crate::DomTypeHolder as crate::DomTypes>::Pairing>> { 262 - + todo!() 269 + + fn Pairing(&self, can_gc: CanGc) -> DomRoot<Pairing> { 270 + + self.pairing 271 + + .or_init(|| Pairing::new(&self.global(), can_gc)) 263 272 + } 264 273 + 265 274 + // Event handler for servo error events
+1 -1
patches/components/script/dom/globalscope.rs.patch
··· 35 35 unminified_js_dir: unminify_js.then(|| unminified_path("unminified-js")), 36 36 byte_length_queuing_strategy_size_function: OnceCell::new(), 37 37 count_queuing_strategy_size_function: OnceCell::new(), 38 - @@ -3107,6 +3121,16 @@ 38 + @@ -3112,6 +3126,16 @@ 39 39 self.inherited_secure_context 40 40 } 41 41
+2 -1
patches/components/script/dom/mod.rs.patch
··· 16 16 pub(crate) mod keyboardevent; 17 17 pub(crate) mod location; 18 18 pub(crate) mod media; 19 - @@ -349,6 +351,8 @@ 19 + @@ -349,6 +351,9 @@ 20 20 pub(crate) mod pagetransitionevent; 21 21 pub(crate) mod paintsize; 22 22 pub(crate) mod paintworkletglobalscope; 23 23 +pub(crate) mod pairing; 24 + +pub(crate) mod pairingpeerevent; 24 25 +pub(crate) mod peer; 25 26 pub(crate) mod performance; 26 27 pub(crate) use self::performance::*;
+186 -6
patches/components/script/dom/pairing.rs.patch
··· 1 1 --- original 2 2 +++ modified 3 - @@ -0,0 +1,45 @@ 3 + @@ -0,0 +1,225 @@ 4 4 +/* SPDX Id: AGPL-3.0-or-later */ 5 5 + 6 6 +use std::rc::Rc; 7 7 + 8 + +use constellation_traits::{ 9 + + LocalPeerInfo, PairingEvent, PeerInfo, PeerStatus, ScriptToConstellationMessage, 10 + +}; 8 11 +use dom_struct::dom_struct; 12 + +use script_bindings::error::Error; 13 + +use stylo_atoms::Atom; 9 14 + 10 15 +use crate::dom::bindings::codegen::Bindings::PairingBinding::PairingMethods; 16 + +use crate::dom::bindings::inheritance::Castable; 17 + +use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object}; 18 + +use crate::dom::bindings::root::DomRoot; 19 + +use crate::dom::event::Event; 11 20 +use crate::dom::eventtarget::EventTarget; 21 + +use crate::dom::globalscope::GlobalScope; 22 + +use crate::dom::pairingpeerevent::PairingPeerEvent; 12 23 +use crate::dom::peer::Peer; 13 24 +use crate::dom::promise::Promise; 25 + +use crate::realms::InRealm; 26 + +use crate::routed_promise::{RoutedPromiseListener, callback_promise}; 27 + +use crate::script_runtime::CanGc; 14 28 + 15 29 +#[dom_struct] 16 30 +pub(crate) struct Pairing { ··· 23 37 + eventtarget: EventTarget::new_inherited(), 24 38 + } 25 39 + } 40 + + 41 + + pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<Pairing> { 42 + + reflect_dom_object(Box::new(Pairing::new_inherited()), global, can_gc) 43 + + } 44 + + 45 + + /// Dispatch a pairing event as a PairingPeerEvent on this EventTarget. 46 + + pub(crate) fn dispatch_pairing_event(&self, event: &PairingEvent, can_gc: CanGc) { 47 + + let (event_name, id, name) = match event { 48 + + PairingEvent::PeerDiscovered { id, name } => { 49 + + ("peerdiscovered", id.as_str(), name.as_str()) 50 + + }, 51 + + PairingEvent::PeerExpired { id } => ("peerleft", id.as_str(), ""), 52 + + PairingEvent::PairingRequest { id } => ("pairingrequest", id.as_str(), ""), 53 + + PairingEvent::PairingAccepted { id } => ("peerjoined", id.as_str(), ""), 54 + + PairingEvent::PairingRejected { id } => ("peerleft", id.as_str(), ""), 55 + + PairingEvent::PairingFailed { id } => ("peerleft", id.as_str(), ""), 56 + + }; 57 + + 58 + + let global = self.global(); 59 + + let peer = Peer::new(&global, id.to_owned(), name.to_owned(), can_gc); 60 + + let ev = 61 + + PairingPeerEvent::new(&global, Atom::from(event_name), false, false, &peer, can_gc); 62 + + ev.upcast::<Event>() 63 + + .fire(self.upcast::<EventTarget>(), can_gc); 64 + + } 26 65 +} 27 66 + 28 67 +impl PairingMethods<crate::DomTypeHolder> for Pairing { 29 - + fn Local(&self) -> Rc<Promise> { 30 - + todo!() 68 + + fn Local(&self, comp: InRealm, can_gc: CanGc) -> Rc<Promise> { 69 + + let global = &self.global(); 70 + + let promise = Promise::new_in_current_realm(comp, can_gc); 71 + + let task_source = global.task_manager().dom_manipulation_task_source(); 72 + + let callback = callback_promise(&promise, self, task_source); 73 + + 74 + + let chan = global.script_to_constellation_chan(); 75 + + if chan 76 + + .send(ScriptToConstellationMessage::PairingGetLocal(callback)) 77 + + .is_err() 78 + + { 79 + + promise.reject_error(Error::Operation(None), can_gc); 80 + + } 81 + + promise 31 82 + } 32 83 + 33 - + fn Peers(&self) -> Rc<Promise> { 34 - + todo!() 84 + + fn Peers(&self, comp: InRealm, can_gc: CanGc) -> Rc<Promise> { 85 + + let global = &self.global(); 86 + + let promise = Promise::new_in_current_realm(comp, can_gc); 87 + + let task_source = global.task_manager().dom_manipulation_task_source(); 88 + + let callback = callback_promise(&promise, self, task_source); 89 + + 90 + + let chan = global.script_to_constellation_chan(); 91 + + if chan 92 + + .send(ScriptToConstellationMessage::PairingGetPeers(callback)) 93 + + .is_err() 94 + + { 95 + + promise.reject_error(Error::Operation(None), can_gc); 96 + + } 97 + + promise 35 98 + } 36 99 + 37 - + fn RequestPairing(&self, _peer: &Peer) -> Rc<Promise> { 100 + + fn RequestPairing(&self, _peer: &Peer, _comp: InRealm, _can_gc: CanGc) -> Rc<Promise> { 38 101 + todo!() 39 102 + } 40 103 + 104 + + fn SetName( 105 + + &self, 106 + + name: crate::dom::bindings::str::DOMString, 107 + + comp: InRealm, 108 + + can_gc: CanGc, 109 + + ) -> Rc<Promise> { 110 + + let global = &self.global(); 111 + + let promise = Promise::new_in_current_realm(comp, can_gc); 112 + + let task_source = global.task_manager().dom_manipulation_task_source(); 113 + + let callback = callback_promise(&promise, self, task_source); 114 + + 115 + + let chan = global.script_to_constellation_chan(); 116 + + if chan 117 + + .send(ScriptToConstellationMessage::PairingSetName( 118 + + name.to_string(), 119 + + callback, 120 + + )) 121 + + .is_err() 122 + + { 123 + + promise.reject_error(Error::Operation(None), can_gc); 124 + + } 125 + + promise 126 + + } 127 + + 128 + + fn Start(&self, comp: InRealm, can_gc: CanGc) -> Rc<Promise> { 129 + + let global = &self.global(); 130 + + let promise = Promise::new_in_current_realm(comp, can_gc); 131 + + let task_source = global.task_manager().dom_manipulation_task_source(); 132 + + let callback = callback_promise(&promise, self, task_source); 133 + + 134 + + let chan = global.script_to_constellation_chan(); 135 + + if chan 136 + + .send(ScriptToConstellationMessage::PairingStart(callback)) 137 + + .is_err() 138 + + { 139 + + promise.reject_error(Error::Operation(None), can_gc); 140 + + } 141 + + promise 142 + + } 143 + + 144 + + fn Stop(&self, comp: InRealm, can_gc: CanGc) -> Rc<Promise> { 145 + + let global = &self.global(); 146 + + let promise = Promise::new_in_current_realm(comp, can_gc); 147 + + let task_source = global.task_manager().dom_manipulation_task_source(); 148 + + let callback = callback_promise(&promise, self, task_source); 149 + + 150 + + let chan = global.script_to_constellation_chan(); 151 + + if chan 152 + + .send(ScriptToConstellationMessage::PairingStop(callback)) 153 + + .is_err() 154 + + { 155 + + promise.reject_error(Error::Operation(None), can_gc); 156 + + } 157 + + promise 158 + + } 159 + + 41 160 + event_handler!(peerdiscovered, GetOnpeerdiscovered, SetOnpeerdiscovered); 42 161 + 43 162 + event_handler!(peerjoined, GetOnpeerjoined, SetOnpeerjoined); ··· 46 165 + 47 166 + event_handler!(pairingrequest, GetOnpairingrequest, SetOnpairingrequest); 48 167 +} 168 + + 169 + +impl RoutedPromiseListener<Result<(), String>> for Pairing { 170 + + fn handle_response(&self, response: Result<(), String>, promise: &Rc<Promise>, can_gc: CanGc) { 171 + + match response { 172 + + Ok(()) => promise.resolve_native(&(), can_gc), 173 + + Err(msg) => promise.reject_error(Error::Operation(Some(msg)), can_gc), 174 + + } 175 + + } 176 + +} 177 + + 178 + +impl RoutedPromiseListener<Result<LocalPeerInfo, String>> for Pairing { 179 + + fn handle_response( 180 + + &self, 181 + + response: Result<LocalPeerInfo, String>, 182 + + promise: &Rc<Promise>, 183 + + can_gc: CanGc, 184 + + ) { 185 + + match response { 186 + + Ok(info) => { 187 + + let global = self.global(); 188 + + let peer = Peer::new(&global, info.id, info.name, can_gc); 189 + + promise.resolve_native(&peer, can_gc); 190 + + }, 191 + + Err(msg) => promise.reject_error(Error::Operation(Some(msg)), can_gc), 192 + + } 193 + + } 194 + +} 195 + + 196 + +impl RoutedPromiseListener<Result<Vec<PeerInfo>, String>> for Pairing { 197 + + fn handle_response( 198 + + &self, 199 + + response: Result<Vec<PeerInfo>, String>, 200 + + promise: &Rc<Promise>, 201 + + can_gc: CanGc, 202 + + ) { 203 + + match response { 204 + + Ok(peers) => { 205 + + let global = self.global(); 206 + + let peer_objects: Vec<DomRoot<Peer>> = peers 207 + + .into_iter() 208 + + .map(|info| { 209 + + let status = match info.status { 210 + + PeerStatus::Discovered => "discovered", 211 + + PeerStatus::PairedConnected => "paired-connected", 212 + + PeerStatus::PairedDisconnected => "paired-disconnected", 213 + + }; 214 + + Peer::new_with_status( 215 + + &global, 216 + + info.id, 217 + + info.name, 218 + + status.to_owned(), 219 + + can_gc, 220 + + ) 221 + + }) 222 + + .collect(); 223 + + promise.resolve_native(&peer_objects, can_gc); 224 + + }, 225 + + Err(msg) => promise.reject_error(Error::Operation(Some(msg)), can_gc), 226 + + } 227 + + } 228 + +}
+99
patches/components/script/dom/pairingpeerevent.rs.patch
··· 1 + --- original 2 + +++ modified 3 + @@ -0,0 +1,96 @@ 4 + +/* SPDX Id: AGPL-3.0-or-later */ 5 + + 6 + +use dom_struct::dom_struct; 7 + +use js::rust::HandleObject; 8 + +use script_bindings::error::Fallible; 9 + +use script_bindings::str::DOMString; 10 + +use stylo_atoms::Atom; 11 + + 12 + +use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods; 13 + +use crate::dom::bindings::codegen::Bindings::PairingBinding::{ 14 + + PairingPeerEventInit, PairingPeerEventMethods, 15 + +}; 16 + +use crate::dom::bindings::inheritance::Castable; 17 + +use crate::dom::bindings::reflector::reflect_dom_object_with_proto; 18 + +use crate::dom::bindings::root::{Dom, DomRoot}; 19 + +use crate::dom::event::Event; 20 + +use crate::dom::globalscope::GlobalScope; 21 + +use crate::dom::peer::Peer; 22 + +use crate::dom::window::Window; 23 + +use crate::script_runtime::CanGc; 24 + + 25 + +#[dom_struct] 26 + +pub(crate) struct PairingPeerEvent { 27 + + event: Event, 28 + + peer: Dom<Peer>, 29 + +} 30 + + 31 + +impl PairingPeerEvent { 32 + + fn new_inherited(peer: &Peer) -> PairingPeerEvent { 33 + + PairingPeerEvent { 34 + + event: Event::new_inherited(), 35 + + peer: Dom::from_ref(peer), 36 + + } 37 + + } 38 + + 39 + + pub(crate) fn new( 40 + + global: &GlobalScope, 41 + + type_: Atom, 42 + + bubbles: bool, 43 + + cancelable: bool, 44 + + peer: &Peer, 45 + + can_gc: CanGc, 46 + + ) -> DomRoot<PairingPeerEvent> { 47 + + Self::new_with_proto(global, None, type_, bubbles, cancelable, peer, can_gc) 48 + + } 49 + + 50 + + fn new_with_proto( 51 + + global: &GlobalScope, 52 + + proto: Option<HandleObject>, 53 + + type_: Atom, 54 + + bubbles: bool, 55 + + cancelable: bool, 56 + + peer: &Peer, 57 + + can_gc: CanGc, 58 + + ) -> DomRoot<PairingPeerEvent> { 59 + + let ev = reflect_dom_object_with_proto( 60 + + Box::new(PairingPeerEvent::new_inherited(peer)), 61 + + global, 62 + + proto, 63 + + can_gc, 64 + + ); 65 + + { 66 + + let event = ev.upcast::<Event>(); 67 + + event.init_event(type_, bubbles, cancelable); 68 + + } 69 + + ev 70 + + } 71 + +} 72 + + 73 + +impl PairingPeerEventMethods<crate::DomTypeHolder> for PairingPeerEvent { 74 + + fn Constructor( 75 + + window: &Window, 76 + + proto: Option<HandleObject>, 77 + + can_gc: CanGc, 78 + + type_: DOMString, 79 + + init: &PairingPeerEventInit, 80 + + ) -> Fallible<DomRoot<PairingPeerEvent>> { 81 + + Ok(PairingPeerEvent::new_with_proto( 82 + + &window.upcast::<GlobalScope>(), 83 + + proto, 84 + + Atom::from(type_), 85 + + init.parent.bubbles, 86 + + init.parent.cancelable, 87 + + &init.peer, 88 + + can_gc, 89 + + )) 90 + + } 91 + + 92 + + fn Peer(&self) -> DomRoot<Peer> { 93 + + DomRoot::from_ref(&*self.peer) 94 + + } 95 + + 96 + + fn IsTrusted(&self) -> bool { 97 + + self.upcast::<Event>().IsTrusted() 98 + + } 99 + +}
+45 -6
patches/components/script/dom/peer.rs.patch
··· 1 1 --- original 2 2 +++ modified 3 - @@ -0,0 +1,36 @@ 3 + @@ -0,0 +1,75 @@ 4 4 +/* SPDX Id: AGPL-3.0-or-later */ 5 + + 6 + +use std::cell::RefCell; 5 7 + 6 8 +use dom_struct::dom_struct; 7 9 +use script_bindings::domstring::DOMString; 8 10 + 9 11 +use crate::dom::bindings::codegen::Bindings::PairingBinding::PeerMethods; 12 + +use crate::dom::bindings::reflector::reflect_dom_object; 13 + +use crate::dom::bindings::root::DomRoot; 10 14 +use crate::dom::eventtarget::EventTarget; 15 + +use crate::dom::globalscope::GlobalScope; 16 + +use crate::script_runtime::CanGc; 11 17 + 12 18 +#[dom_struct] 13 19 +pub(crate) struct Peer { 14 20 + eventtarget: EventTarget, 21 + + id: String, 22 + + display_name: RefCell<String>, 23 + + status: String, 15 24 +} 16 25 + 17 26 +impl Peer { 18 - + fn new_inherited() -> Peer { 27 + + fn new_inherited(id: String, display_name: String, status: String) -> Peer { 19 28 + Peer { 20 29 + eventtarget: EventTarget::new_inherited(), 30 + + id, 31 + + display_name: RefCell::new(display_name), 32 + + status, 21 33 + } 22 34 + } 35 + + 36 + + pub(crate) fn new( 37 + + global: &GlobalScope, 38 + + id: String, 39 + + display_name: String, 40 + + can_gc: CanGc, 41 + + ) -> DomRoot<Peer> { 42 + + Self::new_with_status(global, id, display_name, String::new(), can_gc) 43 + + } 44 + + 45 + + pub(crate) fn new_with_status( 46 + + global: &GlobalScope, 47 + + id: String, 48 + + display_name: String, 49 + + status: String, 50 + + can_gc: CanGc, 51 + + ) -> DomRoot<Peer> { 52 + + reflect_dom_object( 53 + + Box::new(Peer::new_inherited(id, display_name, status)), 54 + + global, 55 + + can_gc, 56 + + ) 57 + + } 23 58 +} 24 59 + 25 60 +impl PeerMethods<crate::DomTypeHolder> for Peer { 26 61 + fn DisplayName(&self) -> DOMString { 27 - + todo!() 62 + + DOMString::from(self.display_name.borrow().clone()) 28 63 + } 29 64 + 30 - + fn SetDisplayName(&self, _name: DOMString) { 31 - + todo!() 65 + + fn SetDisplayName(&self, name: DOMString) { 66 + + *self.display_name.borrow_mut() = name.to_string(); 32 67 + } 33 68 + 34 69 + fn Id(&self) -> DOMString { 35 - + todo!() 70 + + DOMString::from(self.id.clone()) 71 + + } 72 + + 73 + + fn Status(&self) -> DOMString { 74 + + DOMString::from(self.status.clone()) 36 75 + } 37 76 + 38 77 + event_handler!(peerleft, GetOnpeerleft, SetOnpeerleft);
+4 -4
patches/components/script/dom/window.rs.patch
··· 83 83 // Step 6: Let userPromptHandler be WebDriver BiDi user prompt opened with this, 84 84 // "prompt", and message. 85 85 // TODO: Add support for WebDriver BiDi. 86 - @@ -3042,9 +3070,33 @@ 86 + @@ -3046,9 +3074,33 @@ 87 87 &self, 88 88 input_event: &ConstellationInputEvent, 89 89 ) -> Option<HitTestResult> { ··· 120 120 } 121 121 122 122 #[expect(unsafe_code)] 123 - @@ -3063,8 +3115,25 @@ 123 + @@ -3067,8 +3119,25 @@ 124 124 // SAFETY: This is safe because `Window::query_elements_from_point` has ensured that 125 125 // layout has run and any OpaqueNodes that no longer refer to real nodes are gone. 126 126 let address = UntrustedNodeAddress(result.node.0 as *const c_void); ··· 147 147 cursor: result.cursor, 148 148 point_in_node: result.point_in_target, 149 149 point_in_frame, 150 - @@ -3745,6 +3814,8 @@ 150 + @@ -3749,6 +3818,8 @@ 151 151 player_context: WindowGLContext, 152 152 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>, 153 153 inherited_secure_context: Option<bool>, ··· 156 156 theme: Theme, 157 157 weak_script_thread: Weak<ScriptThread>, 158 158 ) -> DomRoot<Self> { 159 - @@ -3771,6 +3842,8 @@ 159 + @@ -3775,6 +3846,8 @@ 160 160 gpu_id_hub, 161 161 inherited_secure_context, 162 162 unminify_js,
+1 -1
patches/components/script/dom/workletglobalscope.rs.patch
··· 1 1 --- original 2 2 +++ modified 3 - @@ -122,8 +122,10 @@ 3 + @@ -121,8 +121,10 @@ 4 4 #[cfg(feature = "webgpu")] 5 5 init.gpu_id_hub.clone(), 6 6 inherited_secure_context,
+2 -1
patches/components/script/messaging.rs.patch
··· 1 1 --- original 2 2 +++ modified 3 - @@ -108,6 +108,8 @@ 3 + @@ -108,6 +108,9 @@ 4 4 ScriptThreadMessage::UpdatePinchZoomInfos(id, _) => Some(*id), 5 5 ScriptThreadMessage::SetAccessibilityActive(..) => None, 6 6 ScriptThreadMessage::TriggerGarbageCollection => None, 7 7 + ScriptThreadMessage::DispatchEmbeddedWebViewEvent { parent, .. } => Some(*parent), 8 8 + ScriptThreadMessage::DispatchServoError(..) => None, 9 + + ScriptThreadMessage::DispatchPairingEvent(..) => None, 9 10 }, 10 11 MixedMessage::FromScript(inner_msg) => match inner_msg { 11 12 MainThreadScriptMsg::Common(CommonScriptMsg::Task(_, _, pipeline_id, _)) => {
+27 -8
patches/components/script/script_thread.rs.patch
··· 59 59 }, 60 60 ScriptThreadMessage::ForwardKeyboardScroll(pipeline_id, scroll) => { 61 61 if let Some(document) = self.documents.borrow().find_document(pipeline_id) { 62 - @@ -1976,6 +1988,16 @@ 62 + @@ -1976,6 +1988,19 @@ 63 63 ScriptThreadMessage::TriggerGarbageCollection => unsafe { 64 64 JS_GC(*GlobalScope::get_cx(), GCReason::API); 65 65 }, ··· 72 72 + }, 73 73 + ScriptThreadMessage::DispatchServoError(error_type, message) => { 74 74 + self.handle_dispatch_servo_error(error_type, message, CanGc::from_cx(cx)); 75 + + }, 76 + + ScriptThreadMessage::DispatchPairingEvent(event) => { 77 + + self.handle_dispatch_pairing_event(event, CanGc::from_cx(cx)); 75 78 + }, 76 79 } 77 80 } 78 81 79 - @@ -3047,6 +3069,9 @@ 82 + @@ -3047,6 +3072,9 @@ 80 83 .documents 81 84 .borrow() 82 85 .find_iframe(parent_pipeline_id, browsing_context_id); ··· 86 89 if let Some(frame_element) = frame_element { 87 90 frame_element.update_pipeline_id(new_pipeline_id, reason, cx); 88 91 } 89 - @@ -3066,6 +3091,7 @@ 92 + @@ -3066,6 +3094,7 @@ 90 93 // is no need to pass along existing opener information that 91 94 // will be discarded. 92 95 None, ··· 94 97 ); 95 98 } 96 99 } 97 - @@ -3342,6 +3368,44 @@ 100 + @@ -3342,6 +3371,60 @@ 98 101 } 99 102 } 100 103 ··· 136 139 + } 137 140 + } 138 141 + 142 + + /// Handle a pairing event by dispatching to all navigator.embedder.pairing instances. 143 + + fn handle_dispatch_pairing_event( 144 + + &self, 145 + + event: constellation_traits::PairingEvent, 146 + + can_gc: CanGc, 147 + + ) { 148 + + for (_, document) in self.documents.borrow().iter() { 149 + + if let Some(embedder) = document.window().Navigator().get_embedder() { 150 + + if let Some(pairing) = embedder.get_pairing() { 151 + + let _ac = enter_realm(&*pairing); 152 + + pairing.dispatch_pairing_event(&event, can_gc); 153 + + } 154 + + } 155 + + } 156 + + } 157 + + 139 158 fn ask_constellation_for_top_level_info( 140 159 &self, 141 160 sender_webview_id: WebViewId, 142 - @@ -3456,7 +3520,13 @@ 161 + @@ -3456,7 +3539,13 @@ 143 162 self.senders.pipeline_to_embedder_sender.clone(), 144 163 self.senders.constellation_sender.clone(), 145 164 incomplete.pipeline_id, ··· 154 173 incomplete.viewport_details, 155 174 origin.clone(), 156 175 final_url.clone(), 157 - @@ -3478,6 +3548,8 @@ 176 + @@ -3478,6 +3567,8 @@ 158 177 #[cfg(feature = "webgpu")] 159 178 self.gpu_id_hub.clone(), 160 179 incomplete.load_data.inherited_secure_context, ··· 163 182 incomplete.theme, 164 183 self.this.clone(), 165 184 ); 166 - @@ -3501,6 +3573,7 @@ 185 + @@ -3501,6 +3592,7 @@ 167 186 incomplete.webview_id, 168 187 incomplete.parent_info, 169 188 incomplete.opener, ··· 171 190 ); 172 191 if window_proxy.parent().is_some() { 173 192 // https://html.spec.whatwg.org/multipage/#navigating-across-documents:delaying-load-events-mode-2 174 - @@ -4271,6 +4344,24 @@ 193 + @@ -4271,6 +4363,24 @@ 175 194 document.event_handler().handle_refresh_cursor(); 176 195 } 177 196
+14 -1
patches/components/script_bindings/codegen/Bindings.conf.patch
··· 1 1 --- original 2 2 +++ modified 3 - @@ -264,6 +264,10 @@ 3 + @@ -278,6 +278,11 @@ 4 4 'cx': ['CheckValidity', 'ReportValidity'], 5 5 }, 6 6 7 7 +'Embedder': { 8 8 + 'additionalTraits': ['crate::interfaces::EmbedderHelpers'], 9 + + 'canGc': ['Pairing'], 9 10 +}, 10 11 + 11 12 'EventSource': { 12 13 'weakReferenceable': True, 13 14 }, 15 + @@ -688,6 +693,11 @@ 16 + 'cx': ['CreateLinearGradient', 'CreatePattern', 'CreateRadialGradient', 'GetTransform'], 17 + }, 18 + 19 + +'Pairing': { 20 + + 'inRealms': ['Start', 'Stop', 'Local', 'Peers', 'RequestPairing', 'SetName'], 21 + + 'canGc': ['Start', 'Stop', 'Local', 'Peers', 'RequestPairing', 'SetName'], 22 + +}, 23 + + 24 + 'PerformanceObserver': { 25 + 'canGc': ['SupportedEntryTypes'], 26 + },
+22 -1
patches/components/script_bindings/webidls/Pairing.webidl.patch
··· 1 1 --- original 2 2 +++ modified 3 - @@ -0,0 +1,41 @@ 3 + @@ -0,0 +1,62 @@ 4 4 +/* SPDX Id: AGPL-3.0-or-later */ 5 5 + 6 6 +[Exposed=Window, ··· 8 8 +interface Peer : EventTarget { 9 9 + attribute DOMString displayName; 10 10 + readonly attribute DOMString id; 11 + + readonly attribute DOMString status; 11 12 + 12 13 + // This peer left. 13 14 + attribute EventHandler onpeerleft; ··· 15 16 + 16 17 +[Exposed=Window, 17 18 +Func="Embedder::is_allowed_to_embed"] 19 + +interface PairingPeerEvent : Event { 20 + + [Throws] constructor(DOMString type, PairingPeerEventInit eventInitDict); 21 + + readonly attribute Peer peer; 22 + +}; 23 + + 24 + +dictionary PairingPeerEventInit : EventInit { 25 + + required Peer peer; 26 + +}; 27 + + 28 + +[Exposed=Window, 29 + +Func="Embedder::is_allowed_to_embed"] 18 30 +interface Pairing : EventTarget { 31 + + // Starts the pairing service. 32 + + Promise<undefined> start(); 33 + + 34 + + // Stops the pairing service. 35 + + Promise<undefined> stop(); 36 + + 19 37 + // Our own endpoint. 20 38 + Promise<Peer> local(); 39 + + 40 + + // Update the display name and restart the service. 41 + + Promise<undefined> setName(DOMString name); 21 42 + 22 43 + // The list of paired peers. 23 44 + Promise<sequence<Peer>> peers();
+11 -1
patches/components/shared/constellation/from_script_message.rs.patch
··· 119 119 /// Mark a new document as active 120 120 ActivateDocument, 121 121 /// Set the document state for a pipeline (used by screenshot / reftests) 122 - @@ -726,6 +775,44 @@ 122 + @@ -726,6 +775,54 @@ 123 123 RespondToScreenshotReadinessRequest(ScreenshotReadinessResponse), 124 124 /// Request the constellation to force garbage collection in all `ScriptThread`'s. 125 125 TriggerGarbageCollection, ··· 161 161 + EmbeddedWebViewControlResponse(EmbedderControlId, EmbedderControlResponse), 162 162 + /// Set page zoom for an embedded webview. 163 163 + EmbeddedWebViewSetPageZoom(WebViewId, f32), 164 + + /// Request the constellation to start the P2P pairing service. 165 + + PairingStart(GenericCallback<Result<(), String>>), 166 + + /// Request the constellation to stop the P2P pairing service. 167 + + PairingStop(GenericCallback<Result<(), String>>), 168 + + /// Request the local endpoint info from the P2P pairing service. 169 + + PairingGetLocal(GenericCallback<Result<super::LocalPeerInfo, String>>), 170 + + /// Request the list of known peers from the P2P pairing service. 171 + + PairingGetPeers(GenericCallback<Result<Vec<super::PeerInfo>, String>>), 172 + + /// Update the display name of the local P2P endpoint and restart the service. 173 + + PairingSetName(String, GenericCallback<Result<(), String>>), 164 174 } 165 175 166 176 impl fmt::Debug for ScriptToConstellationMessage {
+70 -2
patches/components/shared/constellation/lib.rs.patch
··· 21 21 }; 22 22 pub use from_script_message::*; 23 23 use malloc_size_of_derive::MallocSizeOf; 24 - @@ -36,9 +37,70 @@ 24 + @@ -36,9 +37,138 @@ 25 25 use servo_url::{ImmutableOrigin, ServoUrl}; 26 26 pub use structured_data::*; 27 27 use strum::IntoStaticStr; ··· 79 79 + NotificationShow(Notification), 80 80 +} 81 81 + 82 + +/// Information about the local P2P endpoint. 83 + +#[derive(Clone, Debug, Deserialize, Serialize)] 84 + +pub struct LocalPeerInfo { 85 + + /// The endpoint ID as a string. 86 + + pub id: String, 87 + + /// The display name. 88 + + pub name: String, 89 + +} 90 + + 91 + +/// Information about a remote P2P peer. 92 + +#[derive(Clone, Debug, Deserialize, Serialize)] 93 + +pub struct PeerInfo { 94 + + /// The endpoint ID as a string. 95 + + pub id: String, 96 + + /// The display name. 97 + + pub name: String, 98 + + /// The peer's connection/pairing status. 99 + + pub status: PeerStatus, 100 + +} 101 + + 102 + +/// The status of a remote peer. 103 + +#[derive(Clone, Debug, Deserialize, Serialize)] 104 + +pub enum PeerStatus { 105 + + /// Discovered but not paired. 106 + + Discovered, 107 + + /// Paired and currently connected. 108 + + PairedConnected, 109 + + /// Paired but currently disconnected. 110 + + PairedDisconnected, 111 + +} 112 + + 113 + +/// Events from the P2P pairing service, using simple serializable types. 114 + +#[derive(Clone, Debug, Deserialize, Serialize)] 115 + +pub enum PairingEvent { 116 + + /// A new unpaired peer was discovered on the local network. 117 + + PeerDiscovered { 118 + + /// The endpoint ID as a string. 119 + + id: String, 120 + + /// The display name of the peer. 121 + + name: String, 122 + + }, 123 + + /// A previously discovered peer is no longer visible. 124 + + PeerExpired { 125 + + /// The endpoint ID as a string. 126 + + id: String, 127 + + }, 128 + + /// A remote peer is requesting to pair with us. 129 + + PairingRequest { 130 + + /// The endpoint ID as a string. 131 + + id: String, 132 + + }, 133 + + /// A pairing request we sent was accepted. 134 + + PairingAccepted { 135 + + /// The endpoint ID as a string. 136 + + id: String, 137 + + }, 138 + + /// A pairing request we sent was rejected. 139 + + PairingRejected { 140 + + /// The endpoint ID as a string. 141 + + id: String, 142 + + }, 143 + + /// A pairing handshake failed. 144 + + PairingFailed { 145 + + /// The endpoint ID as a string. 146 + + id: String, 147 + + }, 148 + +} 149 + + 82 150 +/// The type of simple dialog to show. 83 151 +#[derive(Clone, Debug, Deserialize, Serialize)] 84 152 +pub enum SimpleDialogType { ··· 93 161 /// Messages to the Constellation from the embedding layer, whether from `ServoRenderer` or 94 162 /// from `libservo` itself. 95 163 #[derive(IntoStaticStr)] 96 - @@ -118,6 +180,9 @@ 164 + @@ -118,6 +248,9 @@ 97 165 UpdatePinchZoomInfos(PipelineId, PinchZoomInfos), 98 166 /// Activate or deactivate accessibility features. 99 167 SetAccessibilityActive(bool),
+3 -1
patches/components/shared/script/lib.rs.patch
··· 35 35 } 36 36 37 37 /// When a pipeline is closed, should its browsing context be discarded too? 38 - @@ -312,6 +320,19 @@ 38 + @@ -312,6 +320,21 @@ 39 39 SetAccessibilityActive(bool), 40 40 /// Force a garbage collection in this script thread. 41 41 TriggerGarbageCollection, ··· 52 52 + }, 53 53 + /// Dispatch a `servoerror` event to all `navigator.embedder` instances in this script thread. 54 54 + DispatchServoError(ServoErrorType, String), 55 + + /// Dispatch a pairing event to all `navigator.embedder.pairing` instances in this script thread. 56 + + DispatchPairingEvent(constellation_traits::PairingEvent), 55 57 } 56 58 57 59 impl fmt::Debug for ScriptThreadMessage {
+95
ui/settings/index.css
··· 475 475 flex: 1; 476 476 } 477 477 } 478 + 479 + /* P2P settings */ 480 + .p2p-section { 481 + margin-top: var(--spacing-md); 482 + padding-top: var(--spacing-md); 483 + border-top: 1px solid var(--color-border); 484 + } 485 + 486 + .p2p-name-row { 487 + display: flex; 488 + gap: var(--spacing-sm); 489 + margin-top: var(--spacing-sm); 490 + justify-items: center; 491 + align-items: center; 492 + } 493 + 494 + .p2p-name-row input { 495 + flex: 1; 496 + } 497 + 498 + .p2p-name-row button, 499 + #p2p-refresh-peers { 500 + padding: var(--spacing-sm) var(--spacing-md); 501 + border: 1px solid var(--color-border); 502 + border-radius: var(--radius-sm); 503 + background: var(--bg-webview); 504 + color: inherit; 505 + cursor: pointer; 506 + font-size: var(--font-size-menu); 507 + white-space: nowrap; 508 + } 509 + 510 + /* TODO: move to shared button styling */ 511 + .p2p-name-row button:hover, 512 + #p2p-refresh-peers:hover { 513 + background: var(--color-menu-item-hover); 514 + } 515 + 516 + .p2p-id { 517 + margin-top: var(--spacing-sm); 518 + } 519 + 520 + .p2p-id code { 521 + font-size: var(--font-size-sm); 522 + word-break: break-all; 523 + } 524 + 525 + .p2p-peer-list { 526 + margin-top: var(--spacing-sm); 527 + } 528 + 529 + .p2p-peer-item { 530 + display: flex; 531 + align-items: center; 532 + justify-content: space-between; 533 + padding: var(--spacing-sm) 0; 534 + border-bottom: 1px solid var(--color-border); 535 + } 536 + 537 + .p2p-peer-item:last-child { 538 + border-bottom: none; 539 + } 540 + 541 + .p2p-peer-name { 542 + font-weight: var(--font-weight-bold); 543 + font-size: var(--font-size-menu); 544 + } 545 + 546 + .p2p-peer-id { 547 + font-size: var(--font-size-sm); 548 + opacity: var(--opacity-muted); 549 + word-break: break-all; 550 + } 551 + 552 + .p2p-peer-status { 553 + font-size: var(--font-size-sm); 554 + padding: 2px var(--spacing-sm); 555 + border-radius: var(--radius-sm); 556 + white-space: nowrap; 557 + } 558 + 559 + .p2p-peer-status.discovered { 560 + background: var(--color-border); 561 + } 562 + 563 + /* TODO: don't hardcode colors */ 564 + .p2p-peer-status.paired-connected { 565 + background: #2d5a2d; 566 + color: #8fdf8f; 567 + } 568 + 569 + .p2p-peer-status.paired-disconnected { 570 + background: #5a3a2d; 571 + color: #df9f8f; 572 + }
+62 -4
ui/settings/index.html
··· 38 38 <lucide-icon name="code"></lucide-icon> 39 39 <span>Developer</span> 40 40 </a> 41 + <a href="#p2p" class="nav-item" data-category="p2p"> 42 + <lucide-icon name="waypoints"></lucide-icon> 43 + <span>P2P</span> 44 + </a> 41 45 </nav> 42 46 </aside> 43 47 <main class="settings-content"> ··· 160 164 </div> 161 165 <div class="setting-row"> 162 166 <div class="setting-info"> 163 - <label for="devtools-port" class="setting-label"> 164 - DevTools Port 167 + <label for="devtools-listen-address" class="setting-label"> 168 + DevTools Listening Address 169 + </label> 170 + <span class="setting-description"> 171 + Listening address for the remote debugging server 172 + </span> 173 + </div> 174 + <input type="text" id="devtools-listen-address" /> 175 + </div> 176 + </div> 177 + </details> 178 + </section> 179 + <section id="p2p" class="settings-category"> 180 + <details> 181 + <summary> 182 + <lucide-icon name="waypoints"></lucide-icon> 183 + <span>P2P</span> 184 + </summary> 185 + <div class="category-content"> 186 + <div class="setting-row"> 187 + <div class="setting-info"> 188 + <label for="p2p-toggle" class="setting-label"> 189 + Pairing Service 165 190 </label> 166 191 <span class="setting-description"> 167 - Port number for the remote debugging server 192 + Enable peer discovery on the local network 168 193 </span> 169 194 </div> 170 - <input type="number" id="devtools-port" min="1" max="65535" class="number-input" /> 195 + <label class="toggle-switch"> 196 + <input type="checkbox" id="p2p-toggle" /> 197 + <span class="toggle-slider"></span> 198 + </label> 199 + </div> 200 + 201 + <div id="p2p-local-info" class="p2p-section" style="display:none"> 202 + <div class="setting-row"> 203 + <div class="setting-info"> 204 + <label for="p2p-name" class="setting-label">Display Name</label> 205 + <span class="setting-description"> 206 + How this device appears to other peers 207 + </span> 208 + </div> 209 + </div> 210 + <div class="p2p-name-row"> 211 + <input type="text" id="p2p-name" placeholder="Device name" /> 212 + <button id="p2p-rename">Rename</button> 213 + </div> 214 + <div class="p2p-id"> 215 + <span class="setting-description">ID: <code id="p2p-id-value"></code></span> 216 + </div> 217 + </div> 218 + 219 + <div id="p2p-peers" class="p2p-section" style="display:none"> 220 + <div class="setting-row"> 221 + <div class="setting-info"> 222 + <label class="setting-label">Known Peers</label> 223 + </div> 224 + <button id="p2p-refresh-peers">Refresh</button> 225 + </div> 226 + <div id="p2p-peer-list" class="p2p-peer-list"> 227 + <span class="setting-description">No peers discovered yet.</span> 228 + </div> 171 229 </div> 172 230 </div> 173 231 </details>
+132 -18
ui/settings/index.js
··· 22 22 add(prefName, element) { 23 23 this.bindings[prefName] = element; 24 24 element.addEventListener("input", (event) => { 25 - console.log(`[PreferenceBinding] ${event.type} for ${prefName}, value is ${element.value}`); 25 + console.log( 26 + `[PreferenceBinding] ${event.type} for ${prefName}, value is ${element.value}`, 27 + ); 26 28 navigator.servo.setStringPreference(prefName, element.value); 27 29 }); 28 - console.log(`[PreferenceBinding] ${prefName} is ${navigator.servo.getStringPreference(prefName)}`) 30 + console.log( 31 + `[PreferenceBinding] ${prefName} is ${navigator.servo.getStringPreference(prefName)}`, 32 + ); 29 33 element.value = navigator.servo.getStringPreference(prefName); 30 34 } 31 35 32 36 addBool(prefName, element) { 33 37 this.bindings[prefName] = element; 34 38 element.addEventListener("change", (event) => { 35 - console.log(`[PreferenceBinding] ${event.type} for ${prefName}, checked is ${element.checked}`); 39 + console.log( 40 + `[PreferenceBinding] ${event.type} for ${prefName}, checked is ${element.checked}`, 41 + ); 36 42 navigator.servo.setBoolPreference(prefName, element.checked); 37 43 }); 38 - console.log(`[PreferenceBinding] ${prefName} is ${navigator.servo.getBoolPreference(prefName)}`) 44 + console.log( 45 + `[PreferenceBinding] ${prefName} is ${navigator.servo.getBoolPreference(prefName)}`, 46 + ); 39 47 element.checked = navigator.servo.getBoolPreference(prefName); 40 48 } 41 49 ··· 44 52 element.addEventListener("input", (event) => { 45 53 const value = parseInt(element.value, 10); 46 54 if (!isNaN(value)) { 47 - console.log(`[PreferenceBinding] ${event.type} for ${prefName}, value is ${value}`); 55 + console.log( 56 + `[PreferenceBinding] ${event.type} for ${prefName}, value is ${value}`, 57 + ); 48 58 navigator.servo.setIntPreference(prefName, value); 49 59 } 50 60 }); 51 - console.log(`[PreferenceBinding] ${prefName} is ${navigator.servo.getIntPreference(prefName)}`) 61 + console.log( 62 + `[PreferenceBinding] ${prefName} is ${navigator.servo.getIntPreference(prefName)}`, 63 + ); 52 64 element.value = navigator.servo.getIntPreference(prefName); 53 65 } 54 66 ··· 107 119 if (!isMobile()) { 108 120 return; 109 121 } 110 - 122 + 111 123 document.body.classList.add("show-detail"); 112 124 113 125 // Mark the active category ··· 220 232 }); 221 233 } 222 234 223 - // Initialize 224 - setupNavigation(); 225 - setupMobileNavigation(); 226 - renderThemeCards(); 227 - setupSearchEngines(); 228 - 229 235 const bindings = new PreferenceBindings(); 230 236 231 237 // Register bindings: [<element id>, <preference name>] ··· 248 254 }); 249 255 250 256 // Register integer bindings: [<element id>, <preference name>] 251 - [ 252 - ["devtools-port", "devtools_server_port"], 253 - ].forEach((item) => { 254 - bindings.addInt(item[1], document.getElementById(item[0])); 255 - }); 257 + [["devtools-listen-address", "devtools_server_listen_address"]].forEach( 258 + (item) => { 259 + bindings.add(item[1], document.getElementById(item[0])); 260 + }, 261 + ); 262 + 263 + // P2P Pairing settings 264 + function setupP2P() { 265 + const toggle = document.getElementById("p2p-toggle"); 266 + const localInfo = document.getElementById("p2p-local-info"); 267 + const peersSection = document.getElementById("p2p-peers"); 268 + const nameInput = document.getElementById("p2p-name"); 269 + const renameBtn = document.getElementById("p2p-rename"); 270 + const idValue = document.getElementById("p2p-id-value"); 271 + const peerList = document.getElementById("p2p-peer-list"); 272 + const refreshBtn = document.getElementById("p2p-refresh-peers"); 273 + 274 + const pairing = navigator.embedder.pairing; 275 + 276 + async function updateLocalInfo() { 277 + try { 278 + const local = await pairing.local(); 279 + nameInput.value = local.displayName; 280 + idValue.textContent = local.id; 281 + } catch (e) { 282 + console.error("Failed to get local info:", e); 283 + } 284 + } 285 + 286 + async function refreshPeers() { 287 + try { 288 + const peers = await pairing.peers(); 289 + if (peers.length === 0) { 290 + peerList.innerHTML = `<span class="setting-description">No peers discovered yet.</span>`; 291 + } else { 292 + peerList.innerHTML = peers 293 + .map( 294 + (p) => ` 295 + <div class="p2p-peer-item"> 296 + <div> 297 + <div class="p2p-peer-name">${p.displayName || p.id}</div> 298 + <div class="p2p-peer-id">${p.id}</div> 299 + </div> 300 + <span class="p2p-peer-status ${p.status}">${p.status}</span> 301 + </div>`, 302 + ) 303 + .join(""); 304 + } 305 + } catch (e) { 306 + console.error("Failed to get peers:", e); 307 + } 308 + } 309 + 310 + function setRunning(running) { 311 + localInfo.style.display = running ? "" : "none"; 312 + peersSection.style.display = running ? "" : "none"; 313 + } 314 + 315 + toggle.addEventListener("change", async () => { 316 + console.log(`[P2P] Toggle changed: ${toggle.checked}`); 317 + if (toggle.checked) { 318 + try { 319 + await pairing.start(); 320 + setRunning(true); 321 + await updateLocalInfo(); 322 + await refreshPeers(); 323 + } catch (e) { 324 + console.error("Failed to start pairing:", e); 325 + toggle.checked = false; 326 + } 327 + } else { 328 + try { 329 + await pairing.stop(); 330 + setRunning(false); 331 + } catch (e) { 332 + console.error("Failed to stop pairing:", e); 333 + toggle.checked = true; 334 + } 335 + } 336 + }); 337 + 338 + renameBtn.addEventListener("click", async () => { 339 + const newName = nameInput.value.trim(); 340 + if (!newName) return; 341 + 342 + renameBtn.disabled = true; 343 + try { 344 + // Update name, then restart service to broadcast via mDNS. 345 + await pairing.setName(newName); 346 + await pairing.stop(); 347 + await pairing.start(); 348 + await updateLocalInfo(); 349 + } catch (e) { 350 + console.error("Failed to rename:", e); 351 + } finally { 352 + renameBtn.disabled = false; 353 + } 354 + }); 355 + 356 + refreshBtn.addEventListener("click", refreshPeers); 357 + 358 + // Listen for peer events to auto-refresh 359 + pairing.addEventListener("peerdiscovered", refreshPeers); 360 + pairing.addEventListener("peerjoined", refreshPeers); 361 + pairing.addEventListener("peerleft", refreshPeers); 362 + } 363 + 364 + // Initialize 365 + setupNavigation(); 366 + setupMobileNavigation(); 367 + renderThemeCards(); 368 + setupSearchEngines(); 369 + setupP2P();