buninu-browser 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -1
- package/frontends/wayland/README.md +50 -21
- package/frontends/wayland/index.js +14 -0
- package/frontends/wayland/input.js +24 -5
- package/frontends/wayland/urlbar.js +9 -5
- package/lib/audio/shared-connection.js +31 -0
- package/lib/cdp-server.js +15 -2
- package/lib/happy-dom/inert-link.js +26 -0
- package/lib/happy-dom/node-iterator-removal.js +36 -0
- package/lib/happy-dom/node-replacement.js +60 -0
- package/lib/happy-dom/parser.js +4 -1
- package/lib/headless-shell.js +7 -4
- package/lib/layout/text-layout.js +4 -2
- package/lib/paint/display-list.js +2 -1
- package/lib/qml/README.md +456 -0
- package/lib/qml/builtins.js +76 -5
- package/lib/qml/canvas.js +76 -0
- package/lib/qml/document.js +47 -24
- package/lib/qml/fonts.js +69 -0
- package/lib/qml/host.js +28 -0
- package/lib/qml/loader.js +7 -3
- package/lib/qml/models.js +1 -1
- package/lib/qml/reactive.js +26 -3
- package/lib/qml/runtime.js +263 -41
- package/lib/qml/shader/fragment.js +83 -0
- package/lib/qml/shader/qsb.js +27 -0
- package/lib/qml/shader/renderer.js +39 -0
- package/lib/qml/shader/runtime.js +61 -0
- package/lib/qml/shapes.js +9 -1
- package/lib/qml/shortcuts.js +65 -0
- package/lib/qml/textures.js +4 -1
- package/lib/qml/window-constraints.js +16 -0
- package/lib/renderer/bindings.js +110 -4
- package/lib/renderer/canvas-2d.js +16 -0
- package/lib/renderer/document-selection.js +19 -0
- package/lib/renderer/host.js +14 -11
- package/lib/renderer/main.js +2 -0
- package/lib/renderer/page-realm.js +4 -9
- package/lib/renderer/page-renderer.js +283 -39
- package/lib/renderer/pointer-move.js +5 -3
- package/lib/renderer/render-interval.js +9 -0
- package/lib/style/computed-style.js +8 -2
- package/package.json +1 -1
- package/test/audio-connection-lifetime.test.js +46 -0
- package/test/canvas-paint.test.js +8 -0
- package/test/compare-node-iterator.js +42 -0
- package/test/computed-style.test.js +12 -0
- package/test/document-selection.test.js +27 -0
- package/test/double-click.test.js +85 -0
- package/test/fixtures/canvas-damage.js +40 -0
- package/test/fixtures/fake-renderer.js +1 -0
- package/test/fixtures/fractional-text-scale.js +38 -0
- package/test/fixtures/node-iterator-cases.js +59 -0
- package/test/fixtures/node-iterator-chromium.json +315 -0
- package/test/fixtures/omastorm-helpers/Dockerfile +35 -0
- package/test/fixtures/omastorm-helpers/check.mjs +56 -0
- package/test/fixtures/omastorm-helpers/launch.mjs +24 -0
- package/test/fixtures/omastorm-helpers/prepare.mjs +17 -0
- package/test/fixtures/omastorm-helpers/runtime.mjs +32 -0
- package/test/fixtures/pointer-paint-batching.js +23 -0
- package/test/fixtures/qml-fonts/main.qml +10 -0
- package/test/fixtures/qml-locale/check.mjs +6 -0
- package/test/fixtures/qml-locale/main.qml +8 -0
- package/test/fixtures/qml-shader/grab.qml +14 -0
- package/test/fixtures/qml-shader/gradient.frag +5 -0
- package/test/fixtures/qml-shader/main.qml +14 -0
- package/test/fixtures/qml-shader/texture-grab.qml +25 -0
- package/test/fixtures/qml-shader/texture-size.frag +5 -0
- package/test/fixtures/qml-shader-check.mjs +24 -0
- package/test/fixtures/title-no-paint.js +20 -0
- package/test/fractional-text-scale.test.js +6 -0
- package/test/inert-link.test.js +37 -0
- package/test/manual-double-click.html +21 -0
- package/test/manual-mouse-buttons.html +18 -0
- package/test/manual-omastorm-engine.mjs +19 -0
- package/test/manual-omastorm-shaders.mjs +28 -0
- package/test/manual-omastorm-software.mjs +25 -0
- package/test/manual-pointer-scroll.html +43 -0
- package/test/node-iterator.test.js +81 -0
- package/test/page-scripts.test.js +116 -1
- package/test/pointer-drag.test.js +104 -0
- package/test/qml-canvas.test.js +21 -0
- package/test/qml-connections-timing.test.js +22 -0
- package/test/qml-controls-window.test.js +182 -0
- package/test/qml-fonts.test.js +31 -0
- package/test/qml-grid-multiline.test.js +48 -0
- package/test/qml-locale.test.js +45 -0
- package/test/qml-nonvisual-visible.test.js +19 -0
- package/test/qml-shader-runtime.test.js +6 -0
- package/test/qml-shortcuts.test.js +39 -0
- package/test/qml-socket.test.js +60 -0
- package/test/qml-software-shader.test.js +55 -0
- package/test/qml-window-update.test.js +36 -0
- package/test/render-interval.test.js +33 -0
- package/test/text-layout.test.js +15 -0
- package/test/title-no-paint.test.js +6 -0
- package/test/wayland-scroll.test.js +40 -0
- package/test/wayland-urlbar.test.js +23 -0
- package/test/window-resize.test.js +29 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {test,expect} from 'bun:test';
|
|
2
|
+
import {mkdtempSync,rmSync} from 'node:fs';
|
|
3
|
+
|
|
4
|
+
// Opt-in sibling integration, with its own socket; never touches the user's Land.
|
|
5
|
+
test.skipIf(process.env.BUNINU_TEST_WAYLAND!=='1')('Casty SGR wheel -> Land -> browser scrolls both DOM axes',async()=>{
|
|
6
|
+
const {start}=await import('../../buninu-land/compositor.js');
|
|
7
|
+
const {mouseWheelEvent}=await import('../../casty/lib/input.js');
|
|
8
|
+
const {launch}=await import('../frontends/wayland/index.js');
|
|
9
|
+
const dir=mkdtempSync('/tmp/browser-wheel-'),old=process.env.XDG_RUNTIME_DIR;
|
|
10
|
+
process.env.XDG_RUNTIME_DIR=dir;let land,app;
|
|
11
|
+
const wait=async(fn)=>{for(let n=0;n<300;n++){if(await fn())return;await Bun.sleep(20)}throw Error('Scroll timed out')};
|
|
12
|
+
try{
|
|
13
|
+
land=await start(['--remote-debugging-port=0','--window-size=640,480']);
|
|
14
|
+
app=await launch({socket:dir+'/wayland-buninu',url:'data:text/html,'+encodeURIComponent('<style>body{margin:0}#box{width:400px;height:250px;overflow:auto}#content{width:1600px;height:1600px;background:linear-gradient(red,blue)}</style><div id="box"><div id="content"></div></div>')});
|
|
15
|
+
const state=async()=>JSON.parse(await app.browser.context.evaluate('JSON.stringify([document.getElementById("box").scrollLeft,document.getElementById("box").scrollTop])'));
|
|
16
|
+
await wait(()=>land.compositor.wm.renderSurfaces().some(s=>s.pixels));
|
|
17
|
+
const surface=land.compositor.wm.renderSurfaces().find(s=>s.pixels),origin=land.compositor.wm.origin(surface);
|
|
18
|
+
const wheel=code=>land.context.dispatchMouseEvent(mouseWheelEvent(code,origin.x+100,origin.y+130));
|
|
19
|
+
wheel(67);await wait(async()=>(await state())[0]>0);
|
|
20
|
+
const right=await state();expect(right).toEqual([100,0]);
|
|
21
|
+
wheel(65);await wait(async()=>(await state())[1]>0);
|
|
22
|
+
const down=await state();expect(down).toEqual([100,100]);
|
|
23
|
+
wheel(66);await wait(async()=>(await state())[0]<right[0]);
|
|
24
|
+
wheel(64);await wait(async()=>(await state())[1]<down[1]);
|
|
25
|
+
expect(await state()).toEqual([0,0]);
|
|
26
|
+
// Touchpad-like fractional deltas must not be rounded into wheel ticks.
|
|
27
|
+
land.context.dispatchMouseEvent({type:'mouseWheel',x:origin.x+100,y:origin.y+130,deltaX:12.5,deltaY:7.5});
|
|
28
|
+
await wait(async()=>(await state())[1]>0);
|
|
29
|
+
const fractional=await state();
|
|
30
|
+
expect(fractional[0]).toBeGreaterThan(0);expect(fractional[1]).toBeGreaterThan(0);
|
|
31
|
+
// Compare the same wheel input with the direct Browser/CDP scroll path.
|
|
32
|
+
await app.browser.context.scroll(-100,-100,{x:100,y:100});
|
|
33
|
+
expect(await state()).toEqual([0,0]);
|
|
34
|
+
await app.browser.context.scroll(12.5,7.5,{x:100,y:100});
|
|
35
|
+
expect(await state()).toEqual(fractional);
|
|
36
|
+
await app.browser.context.scroll(-100,-100,{x:100,y:100});
|
|
37
|
+
await app.browser.context.scroll(100,100,{x:100,y:100});
|
|
38
|
+
expect(await state()).toEqual(down);
|
|
39
|
+
}finally{app?.close();land?.close();if(old===undefined)delete process.env.XDG_RUNTIME_DIR;else process.env.XDG_RUNTIME_DIR=old;rmSync(dir,{recursive:true,force:true})}
|
|
40
|
+
},30000);
|
|
@@ -36,3 +36,26 @@ test('Toolbar raster cache and horizontal scrolling preserve page-independent re
|
|
|
36
36
|
expect(bar.editor.selectedText.length).toBeGreaterThan(0);
|
|
37
37
|
}finally{bar.dispose();}
|
|
38
38
|
});
|
|
39
|
+
|
|
40
|
+
test('Wayland chrome forwards page click counts through zoom and bar offset',async()=>{
|
|
41
|
+
const clicks=[];
|
|
42
|
+
const bar=new WaylandUrlBar({url:'about:blank',click:(...args)=>clicks.push(args)},{history,close(){},clipboard:{read:async()=>'',write:async()=>{}}});
|
|
43
|
+
try{
|
|
44
|
+
bar.zoom=2;
|
|
45
|
+
await bar.pointerButton(40,bar.height+60,272,1,{clickCount:2});
|
|
46
|
+
await bar.pointerButton(40,bar.height+60,272,0,{clickCount:2});
|
|
47
|
+
expect(clicks).toEqual([[20,30,{clickCount:2}]]);
|
|
48
|
+
}finally{bar.dispose()}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('Wayland toolbar forwards right/middle page clicks but ignores them on chrome',async()=>{
|
|
52
|
+
const clicks=[];const bar=new WaylandUrlBar({click:(...a)=>clicks.push(a)},{history});
|
|
53
|
+
try{
|
|
54
|
+
for(const code of [273,274]){
|
|
55
|
+
await bar.pointerButton(40,bar.height+60,code,1);
|
|
56
|
+
await bar.pointerButton(40,bar.height+60,code,0);
|
|
57
|
+
await bar.pointerButton(40,5,code,0);
|
|
58
|
+
}
|
|
59
|
+
expect(clicks.map(c=>c[2].button)).toEqual(['right','middle']);
|
|
60
|
+
}finally{bar.dispose()}
|
|
61
|
+
});
|
|
@@ -34,3 +34,32 @@ test('viewport resize notifies window listeners with fresh geometry and repaints
|
|
|
34
34
|
expect(await host.call('evaluate','propertyEvents')).toBe(2);
|
|
35
35
|
}finally{host.close();}
|
|
36
36
|
},30000);
|
|
37
|
+
|
|
38
|
+
test('same-pixel-size DPR changes relayout a quiet page and update viewport CSS',async()=>{
|
|
39
|
+
const host=new RendererHost({timeout:20000});
|
|
40
|
+
try {
|
|
41
|
+
await host.call('resize',1920,1035,1);
|
|
42
|
+
await host.call('loadDocument',{url:'https://resize.test/',contentType:'text/html',source:`
|
|
43
|
+
<style>body{margin:0}#center{width:1000px;margin:0 auto;height:20px}
|
|
44
|
+
#units{width:50vw;height:10vh}#media{width:10px}
|
|
45
|
+
@media(max-width:1400px){#media{width:30px}}</style>
|
|
46
|
+
<div id="center">Contact — Buninu Linux</div><div id="units"></div><div id="media"></div>`});
|
|
47
|
+
await host.call('whenLoaded');
|
|
48
|
+
const geometry=()=>host.call('evaluate',`JSON.stringify(['center','units','media'].map(id=>{
|
|
49
|
+
const r=document.getElementById(id).getBoundingClientRect();return [r.x,r.width,r.height];
|
|
50
|
+
}))`);
|
|
51
|
+
expect(await geometry()).toBe('[[460,1000,20],[0,960,103.5],[0,10,0]]');
|
|
52
|
+
for(const [width,height,dpr,expected] of [
|
|
53
|
+
[1280,690,1.5,'[[140,1000,20],[0,640,69],[0,30,0]]'],
|
|
54
|
+
[1920,1035,1,'[[460,1000,20],[0,960,103.5],[0,10,0]]'],
|
|
55
|
+
[1280,690,1.5,'[[140,1000,20],[0,640,69],[0,30,0]]'],
|
|
56
|
+
// DPR-only changes repaint without changing CSS geometry.
|
|
57
|
+
[1280,690,2,'[[140,1000,20],[0,640,69],[0,30,0]]'],
|
|
58
|
+
]) {
|
|
59
|
+
await host.call('resize',width,height,dpr);
|
|
60
|
+
expect(await geometry()).toBe(expected);
|
|
61
|
+
const png=Buffer.from(await host.composite('screenshot',{format:'png'}),'base64');
|
|
62
|
+
expect([png.readUInt32BE(16),png.readUInt32BE(20)]).toEqual([width*dpr,height*dpr]);
|
|
63
|
+
}
|
|
64
|
+
}finally{host.close()}
|
|
65
|
+
},30000);
|