fix(cef): ignore zero-size initial resize
Prevent render pipeline startup from treating a 0x0 allocation as the first resize event. This keeps browser creation waiting for a real non-zero size and preserves the intended OSR initialization flow.
- commit
- b6fcae6418cc03b9f5a297524a2f3fff6570700b
- author
- brice · · 2026-04-13 07:42 UTC
- parent
- 69a9665
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +32 -0
M internal/infrastructure/cef/render_pipeline.go +4 -0
| @@ -841,6 +841,10 @@ func compileShader(gl *glLoader, shaderType uint32, source string) uint32 { | |||
| 841 | 841 | // onResize is the GTK "resize" signal handler. Dimensions are in CSS pixels; | |
| 842 | 842 | // we multiply by scale to get device pixels. | |
| 843 | 843 | func (rp *renderPipeline) onResize(width, height int32) { | |
| 844 | + | if width <= 0 || height <= 0 { | |
| 845 | + | return | |
| 846 | + | } | |
| 847 | + | ||
| 844 | 848 | rp.mu.Lock() | |
| 845 | 849 | ||
| 846 | 850 | prevWidth := rp.widthAtomic.Load() | |
| @@ -841,6 +841,10 @@ func compileShader(gl *glLoader, shaderType uint32, source string) uint32 { | |||||
| 841 | // onResize is the GTK "resize" signal handler. Dimensions are in CSS pixels; | 841 | // onResize is the GTK "resize" signal handler. Dimensions are in CSS pixels; | ||
| 842 | // we multiply by scale to get device pixels. | 842 | // we multiply by scale to get device pixels. | ||
| 843 | func (rp *renderPipeline) onResize(width, height int32) { | 843 | func (rp *renderPipeline) onResize(width, height int32) { | ||
| 844 | + | if width <= 0 || height <= 0 { | |||
| 845 | + | return | |||
| 846 | + | } | |||
| 847 | + | ||||
| 844 | rp.mu.Lock() | 848 | rp.mu.Lock() | ||
| 845 | 849 | ||||
| 846 | prevWidth := rp.widthAtomic.Load() | 850 | prevWidth := rp.widthAtomic.Load() | ||
M internal/infrastructure/cef/render_pipeline_test.go +28 -0
| @@ -80,6 +80,34 @@ func TestHandlePaintCopiesDirtyRectsIntoPersistentStaging(t *testing.T) { | |||
| 80 | 80 | require.False(t, rp.forceFullUpload) | |
| 81 | 81 | } | |
| 82 | 82 | ||
| 83 | + | func TestOnResizeIgnoresZeroFirstResize(t *testing.T) { | |
| 84 | + | called := false | |
| 85 | + | rp := &renderPipeline{ | |
| 86 | + | scale: 1, | |
| 87 | + | onFirstResize: func(_, _ int32) { | |
| 88 | + | called = true | |
| 89 | + | }, | |
| 90 | + | } | |
| 91 | + | rp.widthAtomic.Store(123) | |
| 92 | + | rp.heightAtomic.Store(456) | |
| 93 | + | ||
| 94 | + | rp.onResize(0, 0) | |
| 95 | + | ||
| 96 | + | require.False(t, called) | |
| 97 | + | require.Equal(t, int32(123), rp.widthAtomic.Load()) | |
| 98 | + | require.Equal(t, int32(456), rp.heightAtomic.Load()) | |
| 99 | + | require.False(t, rp.sizeChanged) | |
| 100 | + | require.NotNil(t, rp.onFirstResize) | |
| 101 | + | ||
| 102 | + | rp.onResize(10, 20) | |
| 103 | + | ||
| 104 | + | require.True(t, called) | |
| 105 | + | require.Equal(t, int32(10), rp.widthAtomic.Load()) | |
| 106 | + | require.Equal(t, int32(20), rp.heightAtomic.Load()) | |
| 107 | + | require.True(t, rp.sizeChanged) | |
| 108 | + | require.Nil(t, rp.onFirstResize) | |
| 109 | + | } | |
| 110 | + | ||
| 83 | 111 | // sortRects sorts rects by (X, Y) so tests can compare without caring about order. | |
| 84 | 112 | func sortRects(rects []rect) { | |
| 85 | 113 | sort.Slice(rects, func(i, j int) bool { | |
| @@ -80,6 +80,34 @@ func TestHandlePaintCopiesDirtyRectsIntoPersistentStaging(t *testing.T) { | |||||
| 80 | require.False(t, rp.forceFullUpload) | 80 | require.False(t, rp.forceFullUpload) | ||
| 81 | } | 81 | } | ||
| 82 | 82 | ||||
| 83 | + | func TestOnResizeIgnoresZeroFirstResize(t *testing.T) { | |||
| 84 | + | called := false | |||
| 85 | + | rp := &renderPipeline{ | |||
| 86 | + | scale: 1, | |||
| 87 | + | onFirstResize: func(_, _ int32) { | |||
| 88 | + | called = true | |||
| 89 | + | }, | |||
| 90 | + | } | |||
| 91 | + | rp.widthAtomic.Store(123) | |||
| 92 | + | rp.heightAtomic.Store(456) | |||
| 93 | + | ||||
| 94 | + | rp.onResize(0, 0) | |||
| 95 | + | ||||
| 96 | + | require.False(t, called) | |||
| 97 | + | require.Equal(t, int32(123), rp.widthAtomic.Load()) | |||
| 98 | + | require.Equal(t, int32(456), rp.heightAtomic.Load()) | |||
| 99 | + | require.False(t, rp.sizeChanged) | |||
| 100 | + | require.NotNil(t, rp.onFirstResize) | |||
| 101 | + | ||||
| 102 | + | rp.onResize(10, 20) | |||
| 103 | + | ||||
| 104 | + | require.True(t, called) | |||
| 105 | + | require.Equal(t, int32(10), rp.widthAtomic.Load()) | |||
| 106 | + | require.Equal(t, int32(20), rp.heightAtomic.Load()) | |||
| 107 | + | require.True(t, rp.sizeChanged) | |||
| 108 | + | require.Nil(t, rp.onFirstResize) | |||
| 109 | + | } | |||
| 110 | + | ||||
| 83 | // sortRects sorts rects by (X, Y) so tests can compare without caring about order. | 111 | // sortRects sorts rects by (X, Y) so tests can compare without caring about order. | ||
| 84 | func sortRects(rects []rect) { | 112 | func sortRects(rects []rect) { | ||
| 85 | sort.Slice(rects, func(i, j int) bool { | 113 | sort.Slice(rects, func(i, j int) bool { | ||