Merge pull request #358 from bnema/fix/cef-canvas-background
fix(cef): keep browser canvas white, move anti-flash to presentation layer
80 files · +1985 -2004
M go.mod +1 -1
| @@ -6,7 +6,7 @@ require ( | |||
| 6 | 6 | github.com/a-h/templ v0.3.1020 | |
| 7 | 7 | github.com/andybalholm/brotli v1.2.2 | |
| 8 | 8 | github.com/bnema/purego v0.11.0-bnema.4 | |
| 9 | - | github.com/bnema/purego-cef v0.13.4 | |
| 9 | + | github.com/bnema/purego-cef v0.14.1 | |
| 10 | 10 | github.com/bnema/purego-cef2gtk v0.8.5 | |
| 11 | 11 | github.com/bnema/purego-pipewire v0.1.5 | |
| 12 | 12 | github.com/bnema/purego-sqlite v0.1.4 | |
| @@ -6,7 +6,7 @@ require ( | |||||
| 6 | github.com/a-h/templ v0.3.1020 | 6 | github.com/a-h/templ v0.3.1020 | ||
| 7 | github.com/andybalholm/brotli v1.2.2 | 7 | github.com/andybalholm/brotli v1.2.2 | ||
| 8 | github.com/bnema/purego v0.11.0-bnema.4 | 8 | github.com/bnema/purego v0.11.0-bnema.4 | ||
| 9 | - | github.com/bnema/purego-cef v0.13.4 | 9 | + | github.com/bnema/purego-cef v0.14.1 |
| 10 | github.com/bnema/purego-cef2gtk v0.8.5 | 10 | github.com/bnema/purego-cef2gtk v0.8.5 | ||
| 11 | github.com/bnema/purego-pipewire v0.1.5 | 11 | github.com/bnema/purego-pipewire v0.1.5 | ||
| 12 | github.com/bnema/purego-sqlite v0.1.4 | 12 | github.com/bnema/purego-sqlite v0.1.4 | ||
M go.sum +2 -2 generated file: collapsed
A internal/infrastructure/cef/background_guard.go +106 -0
| @@ -0,0 +1,106 @@ | |||
| 1 | + | package cef | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "fmt" | |
| 5 | + | ||
| 6 | + | "github.com/bnema/puregotk/v4/gdk" | |
| 7 | + | "github.com/bnema/puregotk/v4/gtk" | |
| 8 | + | ) | |
| 9 | + | ||
| 10 | + | // opaqueWhiteBackground is Chromium's standard windowless canvas fallback. It is | |
| 11 | + | // baked into every BrowserSettings.BackgroundColor so pages that paint nothing | |
| 12 | + | // get an opaque white canvas (never a theme-dark one). A zero value must not be | |
| 13 | + | // used: in windowless/OSR mode a zero-alpha background enables transparent | |
| 14 | + | // painting, which this engine does not want. | |
| 15 | + | const opaqueWhiteBackground uint32 = 0xFFFFFFFF | |
| 16 | + | ||
| 17 | + | // flashGuardCSSClassPrefix scopes each WebView's transient background provider to | |
| 18 | + | // its own render widget so guards from different tabs never collide. | |
| 19 | + | const flashGuardCSSClassPrefix = "dumber-cef-flash-guard-" | |
| 20 | + | ||
| 21 | + | // colorByteMask isolates a single 8-bit channel from a packed ARGB value. | |
| 22 | + | const colorByteMask = 0xFF | |
| 23 | + | ||
| 24 | + | // applyBackgroundFlashGuard paints the theme background color behind the CEF | |
| 25 | + | // render widget until the first frame is presented. It is the presentation-layer | |
| 26 | + | // replacement for the former dark BrowserSettings.BackgroundColor: Chromium's | |
| 27 | + | // canvas is now always opaque white, so the anti-white-flash lives here instead. | |
| 28 | + | // The bridge widget (a GtkPicture/GtkGLArea) renders its CSS background until an | |
| 29 | + | // opaque frame texture covers it, at which point markFirstFramePainted tears the | |
| 30 | + | // guard down. Must run on the GTK main thread. | |
| 31 | + | func (wv *WebView) applyBackgroundFlashGuard(widget *gtk.Widget) { | |
| 32 | + | if wv == nil || widget == nil { | |
| 33 | + | return | |
| 34 | + | } | |
| 35 | + | argb := wv.backgroundColor | |
| 36 | + | if argb == 0 { | |
| 37 | + | return // No theme color configured; nothing to guard against. | |
| 38 | + | } | |
| 39 | + | display := gdk.DisplayGetDefault() | |
| 40 | + | if display == nil { | |
| 41 | + | return | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | a := float64((argb>>24)&colorByteMask) / colorScale | |
| 45 | + | r := (argb >> 16) & colorByteMask | |
| 46 | + | g := (argb >> 8) & colorByteMask | |
| 47 | + | b := argb & colorByteMask | |
| 48 | + | class := fmt.Sprintf("%s%d", flashGuardCSSClassPrefix, uint64(wv.id)) | |
| 49 | + | css := fmt.Sprintf(".%s { background-color: rgba(%d, %d, %d, %.4f); }", class, r, g, b, a) | |
| 50 | + | ||
| 51 | + | provider := gtk.NewCssProvider() | |
| 52 | + | if provider == nil { | |
| 53 | + | return | |
| 54 | + | } | |
| 55 | + | provider.LoadFromString(css) | |
| 56 | + | ||
| 57 | + | wv.bgGuardMu.Lock() | |
| 58 | + | defer wv.bgGuardMu.Unlock() | |
| 59 | + | if wv.firstFramePainted.Load() { | |
| 60 | + | return // First frame already arrived before the guard could be installed. | |
| 61 | + | } | |
| 62 | + | widget.AddCssClass(class) | |
| 63 | + | gtk.StyleContextAddProviderForDisplay(display, provider, uint(gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)) | |
| 64 | + | wv.bgGuardProvider = provider | |
| 65 | + | wv.bgGuardWidget = widget | |
| 66 | + | wv.bgGuardClass = class | |
| 67 | + | } | |
| 68 | + | ||
| 69 | + | // markFirstFramePainted records that the first CEF frame has been presented and | |
| 70 | + | // schedules teardown of the background flash guard so later frames render | |
| 71 | + | // normally. Safe to call from any thread and idempotent. | |
| 72 | + | func (wv *WebView) markFirstFramePainted() { | |
| 73 | + | if wv == nil || !wv.firstFramePainted.CompareAndSwap(false, true) { | |
| 74 | + | return | |
| 75 | + | } | |
| 76 | + | wv.runOnGTK(func() { | |
| 77 | + | wv.removeBackgroundFlashGuard() | |
| 78 | + | }) | |
| 79 | + | } | |
| 80 | + | ||
| 81 | + | // removeBackgroundFlashGuard detaches the transient theme-background provider and | |
| 82 | + | // clears the render widget's guard class. Must run on the GTK main thread. It is | |
| 83 | + | // safe to call when no guard is installed. | |
| 84 | + | func (wv *WebView) removeBackgroundFlashGuard() { | |
| 85 | + | if wv == nil { | |
| 86 | + | return | |
| 87 | + | } | |
| 88 | + | wv.bgGuardMu.Lock() | |
| 89 | + | provider := wv.bgGuardProvider | |
| 90 | + | widget := wv.bgGuardWidget | |
| 91 | + | class := wv.bgGuardClass | |
| 92 | + | wv.bgGuardProvider = nil | |
| 93 | + | wv.bgGuardWidget = nil | |
| 94 | + | wv.bgGuardClass = "" | |
| 95 | + | wv.bgGuardMu.Unlock() | |
| 96 | + | ||
| 97 | + | if provider == nil { | |
| 98 | + | return | |
| 99 | + | } | |
| 100 | + | if widget != nil && class != "" { | |
| 101 | + | widget.RemoveCssClass(class) | |
| 102 | + | } | |
| 103 | + | if display := gdk.DisplayGetDefault(); display != nil { | |
| 104 | + | gtk.StyleContextRemoveProviderForDisplay(display, provider) | |
| 105 | + | } | |
| 106 | + | } | |
| @@ -0,0 +1,106 @@ | |||||
| 1 | + | package cef | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "fmt" | |||
| 5 | + | ||||
| 6 | + | "github.com/bnema/puregotk/v4/gdk" | |||
| 7 | + | "github.com/bnema/puregotk/v4/gtk" | |||
| 8 | + | ) | |||
| 9 | + | ||||
| 10 | + | // opaqueWhiteBackground is Chromium's standard windowless canvas fallback. It is | |||
| 11 | + | // baked into every BrowserSettings.BackgroundColor so pages that paint nothing | |||
| 12 | + | // get an opaque white canvas (never a theme-dark one). A zero value must not be | |||
| 13 | + | // used: in windowless/OSR mode a zero-alpha background enables transparent | |||
| 14 | + | // painting, which this engine does not want. | |||
| 15 | + | const opaqueWhiteBackground uint32 = 0xFFFFFFFF | |||
| 16 | + | ||||
| 17 | + | // flashGuardCSSClassPrefix scopes each WebView's transient background provider to | |||
| 18 | + | // its own render widget so guards from different tabs never collide. | |||
| 19 | + | const flashGuardCSSClassPrefix = "dumber-cef-flash-guard-" | |||
| 20 | + | ||||
| 21 | + | // colorByteMask isolates a single 8-bit channel from a packed ARGB value. | |||
| 22 | + | const colorByteMask = 0xFF | |||
| 23 | + | ||||
| 24 | + | // applyBackgroundFlashGuard paints the theme background color behind the CEF | |||
| 25 | + | // render widget until the first frame is presented. It is the presentation-layer | |||
| 26 | + | // replacement for the former dark BrowserSettings.BackgroundColor: Chromium's | |||
| 27 | + | // canvas is now always opaque white, so the anti-white-flash lives here instead. | |||
| 28 | + | // The bridge widget (a GtkPicture/GtkGLArea) renders its CSS background until an | |||
| 29 | + | // opaque frame texture covers it, at which point markFirstFramePainted tears the | |||
| 30 | + | // guard down. Must run on the GTK main thread. | |||
| 31 | + | func (wv *WebView) applyBackgroundFlashGuard(widget *gtk.Widget) { | |||
| 32 | + | if wv == nil || widget == nil { | |||
| 33 | + | return | |||
| 34 | + | } | |||
| 35 | + | argb := wv.backgroundColor | |||
| 36 | + | if argb == 0 { | |||
| 37 | + | return // No theme color configured; nothing to guard against. | |||
| 38 | + | } | |||
| 39 | + | display := gdk.DisplayGetDefault() | |||
| 40 | + | if display == nil { | |||
| 41 | + | return | |||
| 42 | + | } | |||
| 43 | + | ||||
| 44 | + | a := float64((argb>>24)&colorByteMask) / colorScale | |||
| 45 | + | r := (argb >> 16) & colorByteMask | |||
| 46 | + | g := (argb >> 8) & colorByteMask | |||
| 47 | + | b := argb & colorByteMask | |||
| 48 | + | class := fmt.Sprintf("%s%d", flashGuardCSSClassPrefix, uint64(wv.id)) | |||
| 49 | + | css := fmt.Sprintf(".%s { background-color: rgba(%d, %d, %d, %.4f); }", class, r, g, b, a) | |||
| 50 | + | ||||
| 51 | + | provider := gtk.NewCssProvider() | |||
| 52 | + | if provider == nil { | |||
| 53 | + | return | |||
| 54 | + | } | |||
| 55 | + | provider.LoadFromString(css) | |||
| 56 | + | ||||
| 57 | + | wv.bgGuardMu.Lock() | |||
| 58 | + | defer wv.bgGuardMu.Unlock() | |||
| 59 | + | if wv.firstFramePainted.Load() { | |||
| 60 | + | return // First frame already arrived before the guard could be installed. | |||
| 61 | + | } | |||
| 62 | + | widget.AddCssClass(class) | |||
| 63 | + | gtk.StyleContextAddProviderForDisplay(display, provider, uint(gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)) | |||
| 64 | + | wv.bgGuardProvider = provider | |||
| 65 | + | wv.bgGuardWidget = widget | |||
| 66 | + | wv.bgGuardClass = class | |||
| 67 | + | } | |||
| 68 | + | ||||
| 69 | + | // markFirstFramePainted records that the first CEF frame has been presented and | |||
| 70 | + | // schedules teardown of the background flash guard so later frames render | |||
| 71 | + | // normally. Safe to call from any thread and idempotent. | |||
| 72 | + | func (wv *WebView) markFirstFramePainted() { | |||
| 73 | + | if wv == nil || !wv.firstFramePainted.CompareAndSwap(false, true) { | |||
| 74 | + | return | |||
| 75 | + | } | |||
| 76 | + | wv.runOnGTK(func() { | |||
| 77 | + | wv.removeBackgroundFlashGuard() | |||
| 78 | + | }) | |||
| 79 | + | } | |||
| 80 | + | ||||
| 81 | + | // removeBackgroundFlashGuard detaches the transient theme-background provider and | |||
| 82 | + | // clears the render widget's guard class. Must run on the GTK main thread. It is | |||
| 83 | + | // safe to call when no guard is installed. | |||
| 84 | + | func (wv *WebView) removeBackgroundFlashGuard() { | |||
| 85 | + | if wv == nil { | |||
| 86 | + | return | |||
| 87 | + | } | |||
| 88 | + | wv.bgGuardMu.Lock() | |||
| 89 | + | provider := wv.bgGuardProvider | |||
| 90 | + | widget := wv.bgGuardWidget | |||
| 91 | + | class := wv.bgGuardClass | |||
| 92 | + | wv.bgGuardProvider = nil | |||
| 93 | + | wv.bgGuardWidget = nil | |||
| 94 | + | wv.bgGuardClass = "" | |||
| 95 | + | wv.bgGuardMu.Unlock() | |||
| 96 | + | ||||
| 97 | + | if provider == nil { | |||
| 98 | + | return | |||
| 99 | + | } | |||
| 100 | + | if widget != nil && class != "" { | |||
| 101 | + | widget.RemoveCssClass(class) | |||
| 102 | + | } | |||
| 103 | + | if display := gdk.DisplayGetDefault(); display != nil { | |||
| 104 | + | gtk.StyleContextRemoveProviderForDisplay(display, provider) | |||
| 105 | + | } | |||
| 106 | + | } | |||
M internal/infrastructure/cef/factory.go +12 -8
| @@ -27,7 +27,7 @@ type WebViewFactory struct { | |||
| 27 | 27 | windowlessFrameRate int32 | |
| 28 | 28 | windowlessFrameRateMax int32 | |
| 29 | 29 | inputConfig RuntimeInputConfig | |
| 30 | - | bgColor atomic.Uint32 // packed ARGB for BrowserSettings.BackgroundColor | |
| 30 | + | bgColor atomic.Uint32 // packed ARGB theme color for the presentation-layer flash guard | |
| 31 | 31 | audioOutputFactory port.AudioOutputFactory | |
| 32 | 32 | } | |
| 33 | 33 | ||
| @@ -69,7 +69,9 @@ func newWebViewFactory(engine *Engine, opts webViewFactoryOptions) *WebViewFacto | |||
| 69 | 69 | } | |
| 70 | 70 | } | |
| 71 | 71 | ||
| 72 | - | // setDefaultBackgroundColor stores a packed ARGB color for new browser creation. | |
| 72 | + | // setDefaultBackgroundColor stores the packed ARGB theme color used by the | |
| 73 | + | // presentation-layer flash guard on newly-created WebViews. It no longer feeds | |
| 74 | + | // BrowserSettings.BackgroundColor, which is always opaque white. | |
| 73 | 75 | func (f *WebViewFactory) setDefaultBackgroundColor(r, g, b, a float64) { | |
| 74 | 76 | const s = colorScale | |
| 75 | 77 | argb := uint32(a*s)<<24 | uint32(r*s)<<16 | uint32(g*s)<<8 | uint32(b*s) | |
| @@ -96,9 +98,9 @@ func (f *WebViewFactory) Create(ctx context.Context) (port.WebView, error) { | |||
| 96 | 98 | settings := purecef.NewBrowserSettings() | |
| 97 | 99 | cef2gtk.ConfigureBrowserSettings(&settings, cef2gtk.BrowserSettingsOptions{WindowlessFrameRate: f.windowlessFrameRate}) | |
| 98 | 100 | settings.LocalStorage = 1 // CEF_STATE_ENABLED | |
| 99 | - | if bg := f.bgColor.Load(); bg != 0 { | |
| 100 | - | settings.BackgroundColor = bg | |
| 101 | - | } | |
| 101 | + | // Always opaque white: Chromium's standard canvas fallback. The theme | |
| 102 | + | // background is applied at the presentation layer as a flash guard instead. | |
| 103 | + | settings.BackgroundColor = opaqueWhiteBackground | |
| 102 | 104 | ||
| 103 | 105 | // Defer browser creation until the bridge view has a non-zero size. | |
| 104 | 106 | // CEF requires GetViewRect to return a non-empty rect, but the GL area | |
| @@ -142,6 +144,8 @@ func (f *WebViewFactory) newWebView(ctx context.Context) (*WebView, error) { | |||
| 142 | 144 | wv.nativeWidget = popupRoot | |
| 143 | 145 | } | |
| 144 | 146 | } | |
| 147 | + | // Guard the render widget with the theme background until the first frame. | |
| 148 | + | wv.applyBackgroundFlashGuard(nativeWidget) | |
| 145 | 149 | }) | |
| 146 | 150 | if !result.Completed() { | |
| 147 | 151 | wv.destroyViewBridgeOnGTKAsync() | |
| @@ -383,9 +387,9 @@ func (f *WebViewFactory) CreateRelated(ctx context.Context, parentID port.WebVie | |||
| 383 | 387 | settings := purecef.NewBrowserSettings() | |
| 384 | 388 | cef2gtk.ConfigureBrowserSettings(&settings, cef2gtk.BrowserSettingsOptions{WindowlessFrameRate: f.windowlessFrameRate}) | |
| 385 | 389 | settings.LocalStorage = 1 // CEF_STATE_ENABLED | |
| 386 | - | if bg := f.bgColor.Load(); bg != 0 { | |
| 387 | - | settings.BackgroundColor = bg | |
| 388 | - | } | |
| 390 | + | // Always opaque white: the theme background is applied as a presentation-layer | |
| 391 | + | // flash guard, not baked into Chromium's canvas. | |
| 392 | + | settings.BackgroundColor = opaqueWhiteBackground | |
| 389 | 393 | ||
| 390 | 394 | if err := f.configureInitialBrowserCreation(ctx, popupWV, popupWV.client, &windowInfo, &settings, func(w, h int32) { | |
| 391 | 395 | f.handlePopupShellInitialResize(ctx, popupWV, func(w, h int32) { | |
| @@ -27,7 +27,7 @@ type WebViewFactory struct { | |||||
| 27 | windowlessFrameRate int32 | 27 | windowlessFrameRate int32 | ||
| 28 | windowlessFrameRateMax int32 | 28 | windowlessFrameRateMax int32 | ||
| 29 | inputConfig RuntimeInputConfig | 29 | inputConfig RuntimeInputConfig | ||
| 30 | - | bgColor atomic.Uint32 // packed ARGB for BrowserSettings.BackgroundColor | 30 | + | bgColor atomic.Uint32 // packed ARGB theme color for the presentation-layer flash guard |
| 31 | audioOutputFactory port.AudioOutputFactory | 31 | audioOutputFactory port.AudioOutputFactory | ||
| 32 | } | 32 | } | ||
| 33 | 33 | ||||
| @@ -69,7 +69,9 @@ func newWebViewFactory(engine *Engine, opts webViewFactoryOptions) *WebViewFacto | |||||
| 69 | } | 69 | } | ||
| 70 | } | 70 | } | ||
| 71 | 71 | ||||
| 72 | - | // setDefaultBackgroundColor stores a packed ARGB color for new browser creation. | 72 | + | // setDefaultBackgroundColor stores the packed ARGB theme color used by the |
| 73 | + | // presentation-layer flash guard on newly-created WebViews. It no longer feeds | |||
| 74 | + | // BrowserSettings.BackgroundColor, which is always opaque white. | |||
| 73 | func (f *WebViewFactory) setDefaultBackgroundColor(r, g, b, a float64) { | 75 | func (f *WebViewFactory) setDefaultBackgroundColor(r, g, b, a float64) { | ||
| 74 | const s = colorScale | 76 | const s = colorScale | ||
| 75 | argb := uint32(a*s)<<24 | uint32(r*s)<<16 | uint32(g*s)<<8 | uint32(b*s) | 77 | argb := uint32(a*s)<<24 | uint32(r*s)<<16 | uint32(g*s)<<8 | uint32(b*s) | ||
| @@ -96,9 +98,9 @@ func (f *WebViewFactory) Create(ctx context.Context) (port.WebView, error) { | |||||
| 96 | settings := purecef.NewBrowserSettings() | 98 | settings := purecef.NewBrowserSettings() | ||
| 97 | cef2gtk.ConfigureBrowserSettings(&settings, cef2gtk.BrowserSettingsOptions{WindowlessFrameRate: f.windowlessFrameRate}) | 99 | cef2gtk.ConfigureBrowserSettings(&settings, cef2gtk.BrowserSettingsOptions{WindowlessFrameRate: f.windowlessFrameRate}) | ||
| 98 | settings.LocalStorage = 1 // CEF_STATE_ENABLED | 100 | settings.LocalStorage = 1 // CEF_STATE_ENABLED | ||
| 99 | - | if bg := f.bgColor.Load(); bg != 0 { | 101 | + | // Always opaque white: Chromium's standard canvas fallback. The theme |
| 100 | - | settings.BackgroundColor = bg | 102 | + | // background is applied at the presentation layer as a flash guard instead. |
| 101 | - | } | 103 | + | settings.BackgroundColor = opaqueWhiteBackground |
| 102 | 104 | ||||
| 103 | // Defer browser creation until the bridge view has a non-zero size. | 105 | // Defer browser creation until the bridge view has a non-zero size. | ||
| 104 | // CEF requires GetViewRect to return a non-empty rect, but the GL area | 106 | // CEF requires GetViewRect to return a non-empty rect, but the GL area | ||
| @@ -142,6 +144,8 @@ func (f *WebViewFactory) newWebView(ctx context.Context) (*WebView, error) { | |||||
| 142 | wv.nativeWidget = popupRoot | 144 | wv.nativeWidget = popupRoot | ||
| 143 | } | 145 | } | ||
| 144 | } | 146 | } | ||
| 147 | + | // Guard the render widget with the theme background until the first frame. | |||
| 148 | + | wv.applyBackgroundFlashGuard(nativeWidget) | |||
| 145 | }) | 149 | }) | ||
| 146 | if !result.Completed() { | 150 | if !result.Completed() { | ||
| 147 | wv.destroyViewBridgeOnGTKAsync() | 151 | wv.destroyViewBridgeOnGTKAsync() | ||
| @@ -383,9 +387,9 @@ func (f *WebViewFactory) CreateRelated(ctx context.Context, parentID port.WebVie | |||||
| 383 | settings := purecef.NewBrowserSettings() | 387 | settings := purecef.NewBrowserSettings() | ||
| 384 | cef2gtk.ConfigureBrowserSettings(&settings, cef2gtk.BrowserSettingsOptions{WindowlessFrameRate: f.windowlessFrameRate}) | 388 | cef2gtk.ConfigureBrowserSettings(&settings, cef2gtk.BrowserSettingsOptions{WindowlessFrameRate: f.windowlessFrameRate}) | ||
| 385 | settings.LocalStorage = 1 // CEF_STATE_ENABLED | 389 | settings.LocalStorage = 1 // CEF_STATE_ENABLED | ||
| 386 | - | if bg := f.bgColor.Load(); bg != 0 { | 390 | + | // Always opaque white: the theme background is applied as a presentation-layer |
| 387 | - | settings.BackgroundColor = bg | 391 | + | // flash guard, not baked into Chromium's canvas. |
| 388 | - | } | 392 | + | settings.BackgroundColor = opaqueWhiteBackground |
| 389 | 393 | ||||
| 390 | if err := f.configureInitialBrowserCreation(ctx, popupWV, popupWV.client, &windowInfo, &settings, func(w, h int32) { | 394 | if err := f.configureInitialBrowserCreation(ctx, popupWV, popupWV.client, &windowInfo, &settings, func(w, h int32) { | ||
| 391 | f.handlePopupShellInitialResize(ctx, popupWV, func(w, h int32) { | 395 | f.handlePopupShellInitialResize(ctx, popupWV, func(w, h int32) { | ||
M internal/infrastructure/cef/render_handler_adapter.go +9 -0
| @@ -51,6 +51,15 @@ func newDumberRenderHandler(wv *WebView) purecef.RenderHandler { | |||
| 51 | 51 | ||
| 52 | 52 | var unsupportedPaintOnce sync.Once | |
| 53 | 53 | hooks := startupPresentationHooks(activeStartupTrace()) | |
| 54 | + | // Tear down the theme background flash guard once the first frame is | |
| 55 | + | // presented, without dropping the startup trace mark the bridge already set. | |
| 56 | + | firstAcceleratedPaint := hooks.OnFirstAcceleratedPaint | |
| 57 | + | hooks.OnFirstAcceleratedPaint = func() { | |
| 58 | + | if firstAcceleratedPaint != nil { | |
| 59 | + | firstAcceleratedPaint() | |
| 60 | + | } | |
| 61 | + | wv.markFirstFramePainted() | |
| 62 | + | } | |
| 54 | 63 | hooks.OnUnsupportedPaint = func() { | |
| 55 | 64 | unsupportedPaintOnce.Do(func() { | |
| 56 | 65 | if wv.ctx != nil { | |
| @@ -51,6 +51,15 @@ func newDumberRenderHandler(wv *WebView) purecef.RenderHandler { | |||||
| 51 | 51 | ||||
| 52 | var unsupportedPaintOnce sync.Once | 52 | var unsupportedPaintOnce sync.Once | ||
| 53 | hooks := startupPresentationHooks(activeStartupTrace()) | 53 | hooks := startupPresentationHooks(activeStartupTrace()) | ||
| 54 | + | // Tear down the theme background flash guard once the first frame is | |||
| 55 | + | // presented, without dropping the startup trace mark the bridge already set. | |||
| 56 | + | firstAcceleratedPaint := hooks.OnFirstAcceleratedPaint | |||
| 57 | + | hooks.OnFirstAcceleratedPaint = func() { | |||
| 58 | + | if firstAcceleratedPaint != nil { | |||
| 59 | + | firstAcceleratedPaint() | |||
| 60 | + | } | |||
| 61 | + | wv.markFirstFramePainted() | |||
| 62 | + | } | |||
| 54 | hooks.OnUnsupportedPaint = func() { | 63 | hooks.OnUnsupportedPaint = func() { | ||
| 55 | unsupportedPaintOnce.Do(func() { | 64 | unsupportedPaintOnce.Do(func() { | ||
| 56 | if wv.ctx != nil { | 65 | if wv.ctx != nil { | ||
M internal/infrastructure/cef/webview.go +20 -11
| @@ -239,6 +239,18 @@ type WebView struct { | |||
| 239 | 239 | backgroundColor uint32 | |
| 240 | 240 | inputConfig RuntimeInputConfig | |
| 241 | 241 | ||
| 242 | + | // Background flash guard: a theme-colored CSS provider painted behind the | |
| 243 | + | // render widget until the first CEF frame is presented. It replaces the | |
| 244 | + | // former dark BrowserSettings.BackgroundColor anti-white-flash, whose canvas | |
| 245 | + | // is now always opaque white. State is guarded by bgGuardMu; firstFramePainted | |
| 246 | + | // gates the one-shot teardown and resets naturally when a fresh WebView is | |
| 247 | + | // created after a browser recreation. | |
| 248 | + | firstFramePainted atomic.Bool | |
| 249 | + | bgGuardMu sync.Mutex | |
| 250 | + | bgGuardProvider *gtk.CssProvider | |
| 251 | + | bgGuardWidget *gtk.Widget | |
| 252 | + | bgGuardClass string | |
| 253 | + | ||
| 242 | 254 | // Touchpad input diagnostics are debounced to avoid flooding logs while | |
| 243 | 255 | // debugging continuous scroll streams. | |
| 244 | 256 | touchpadNavigation *touchpadNavigationRecognizer | |
| @@ -992,7 +1004,7 @@ func (wv *WebView) prepareNativePopup( | |||
| 992 | 1004 | prep.parent.trackPendingNativePopup(popupID, wv) | |
| 993 | 1005 | } | |
| 994 | 1006 | ||
| 995 | - | configureNativePopupWindow(windowInfo, settings, prep.frameRate, prep.backgroundColor) | |
| 1007 | + | configureNativePopupWindow(windowInfo, settings, prep.frameRate) | |
| 996 | 1008 | clientSlot.Set(client) | |
| 997 | 1009 | return true | |
| 998 | 1010 | } | |
| @@ -1007,9 +1019,8 @@ func (wv *WebView) nativePopupPreparationSnapshot() (nativePopupPreparation, boo | |||
| 1007 | 1019 | return nativePopupPreparation{}, false | |
| 1008 | 1020 | } | |
| 1009 | 1021 | return nativePopupPreparation{ | |
| 1010 | - | parent: wv.nativePopupParent, | |
| 1011 | - | frameRate: wv.windowlessFrameRate, | |
| 1012 | - | backgroundColor: wv.backgroundColor, | |
| 1022 | + | parent: wv.nativePopupParent, | |
| 1023 | + | frameRate: wv.windowlessFrameRate, | |
| 1013 | 1024 | }, true | |
| 1014 | 1025 | } | |
| 1015 | 1026 | ||
| @@ -1045,7 +1056,6 @@ func configureNativePopupWindow( | |||
| 1045 | 1056 | windowInfo *purecef.WindowInfo, | |
| 1046 | 1057 | settings *purecef.BrowserSettings, | |
| 1047 | 1058 | frameRate int32, | |
| 1048 | - | backgroundColor uint32, | |
| 1049 | 1059 | ) { | |
| 1050 | 1060 | cef2gtk.ConfigureWindowInfo(windowInfo, cef2gtk.WindowInfoOptions{}) | |
| 1051 | 1061 | if externalBeginFrameEnabled() { | |
| @@ -1056,15 +1066,13 @@ func configureNativePopupWindow( | |||
| 1056 | 1066 | } | |
| 1057 | 1067 | cef2gtk.ConfigureBrowserSettings(settings, cef2gtk.BrowserSettingsOptions{WindowlessFrameRate: frameRate}) | |
| 1058 | 1068 | settings.LocalStorage = 1 | |
| 1059 | - | if backgroundColor != 0 { | |
| 1060 | - | settings.BackgroundColor = backgroundColor | |
| 1061 | - | } | |
| 1069 | + | // Always opaque white; the popup shell WebView carries the theme flash guard. | |
| 1070 | + | settings.BackgroundColor = opaqueWhiteBackground | |
| 1062 | 1071 | } | |
| 1063 | 1072 | ||
| 1064 | 1073 | type nativePopupPreparation struct { | |
| 1065 | - | parent *WebView | |
| 1066 | - | frameRate int32 | |
| 1067 | - | backgroundColor uint32 | |
| 1074 | + | parent *WebView | |
| 1075 | + | frameRate int32 | |
| 1068 | 1076 | } | |
| 1069 | 1077 | ||
| 1070 | 1078 | func (wv *WebView) handleNativePopupAborted() { | |
| @@ -1244,6 +1252,7 @@ func (wv *WebView) destroyViewBridgeOnGTKThread() { | |||
| 1244 | 1252 | if wv == nil || wv.viewBridge == nil { | |
| 1245 | 1253 | return | |
| 1246 | 1254 | } | |
| 1255 | + | wv.removeBackgroundFlashGuard() | |
| 1247 | 1256 | if wv.removeSizeObserver != nil { | |
| 1248 | 1257 | wv.removeSizeObserver() | |
| 1249 | 1258 | wv.removeSizeObserver = nil | |
| @@ -239,6 +239,18 @@ type WebView struct { | |||||
| 239 | backgroundColor uint32 | 239 | backgroundColor uint32 | ||
| 240 | inputConfig RuntimeInputConfig | 240 | inputConfig RuntimeInputConfig | ||
| 241 | 241 | ||||
| 242 | + | // Background flash guard: a theme-colored CSS provider painted behind the | |||
| 243 | + | // render widget until the first CEF frame is presented. It replaces the | |||
| 244 | + | // former dark BrowserSettings.BackgroundColor anti-white-flash, whose canvas | |||
| 245 | + | // is now always opaque white. State is guarded by bgGuardMu; firstFramePainted | |||
| 246 | + | // gates the one-shot teardown and resets naturally when a fresh WebView is | |||
| 247 | + | // created after a browser recreation. | |||
| 248 | + | firstFramePainted atomic.Bool | |||
| 249 | + | bgGuardMu sync.Mutex | |||
| 250 | + | bgGuardProvider *gtk.CssProvider | |||
| 251 | + | bgGuardWidget *gtk.Widget | |||
| 252 | + | bgGuardClass string | |||
| 253 | + | ||||
| 242 | // Touchpad input diagnostics are debounced to avoid flooding logs while | 254 | // Touchpad input diagnostics are debounced to avoid flooding logs while | ||
| 243 | // debugging continuous scroll streams. | 255 | // debugging continuous scroll streams. | ||
| 244 | touchpadNavigation *touchpadNavigationRecognizer | 256 | touchpadNavigation *touchpadNavigationRecognizer | ||
| @@ -992,7 +1004,7 @@ func (wv *WebView) prepareNativePopup( | |||||
| 992 | prep.parent.trackPendingNativePopup(popupID, wv) | 1004 | prep.parent.trackPendingNativePopup(popupID, wv) | ||
| 993 | } | 1005 | } | ||
| 994 | 1006 | ||||
| 995 | - | configureNativePopupWindow(windowInfo, settings, prep.frameRate, prep.backgroundColor) | 1007 | + | configureNativePopupWindow(windowInfo, settings, prep.frameRate) |
| 996 | clientSlot.Set(client) | 1008 | clientSlot.Set(client) | ||
| 997 | return true | 1009 | return true | ||
| 998 | } | 1010 | } | ||
| @@ -1007,9 +1019,8 @@ func (wv *WebView) nativePopupPreparationSnapshot() (nativePopupPreparation, boo | |||||
| 1007 | return nativePopupPreparation{}, false | 1019 | return nativePopupPreparation{}, false | ||
| 1008 | } | 1020 | } | ||
| 1009 | return nativePopupPreparation{ | 1021 | return nativePopupPreparation{ | ||
| 1010 | - | parent: wv.nativePopupParent, | 1022 | + | parent: wv.nativePopupParent, |
| 1011 | - | frameRate: wv.windowlessFrameRate, | 1023 | + | frameRate: wv.windowlessFrameRate, |
| 1012 | - | backgroundColor: wv.backgroundColor, | |||
| 1013 | }, true | 1024 | }, true | ||
| 1014 | } | 1025 | } | ||
| 1015 | 1026 | ||||
| @@ -1045,7 +1056,6 @@ func configureNativePopupWindow( | |||||
| 1045 | windowInfo *purecef.WindowInfo, | 1056 | windowInfo *purecef.WindowInfo, | ||
| 1046 | settings *purecef.BrowserSettings, | 1057 | settings *purecef.BrowserSettings, | ||
| 1047 | frameRate int32, | 1058 | frameRate int32, | ||
| 1048 | - | backgroundColor uint32, | |||
| 1049 | ) { | 1059 | ) { | ||
| 1050 | cef2gtk.ConfigureWindowInfo(windowInfo, cef2gtk.WindowInfoOptions{}) | 1060 | cef2gtk.ConfigureWindowInfo(windowInfo, cef2gtk.WindowInfoOptions{}) | ||
| 1051 | if externalBeginFrameEnabled() { | 1061 | if externalBeginFrameEnabled() { | ||
| @@ -1056,15 +1066,13 @@ func configureNativePopupWindow( | |||||
| 1056 | } | 1066 | } | ||
| 1057 | cef2gtk.ConfigureBrowserSettings(settings, cef2gtk.BrowserSettingsOptions{WindowlessFrameRate: frameRate}) | 1067 | cef2gtk.ConfigureBrowserSettings(settings, cef2gtk.BrowserSettingsOptions{WindowlessFrameRate: frameRate}) | ||
| 1058 | settings.LocalStorage = 1 | 1068 | settings.LocalStorage = 1 | ||
| 1059 | - | if backgroundColor != 0 { | 1069 | + | // Always opaque white; the popup shell WebView carries the theme flash guard. |
| 1060 | - | settings.BackgroundColor = backgroundColor | 1070 | + | settings.BackgroundColor = opaqueWhiteBackground |
| 1061 | - | } | |||
| 1062 | } | 1071 | } | ||
| 1063 | 1072 | ||||
| 1064 | type nativePopupPreparation struct { | 1073 | type nativePopupPreparation struct { | ||
| 1065 | - | parent *WebView | 1074 | + | parent *WebView |
| 1066 | - | frameRate int32 | 1075 | + | frameRate int32 |
| 1067 | - | backgroundColor uint32 | |||
| 1068 | } | 1076 | } | ||
| 1069 | 1077 | ||||
| 1070 | func (wv *WebView) handleNativePopupAborted() { | 1078 | func (wv *WebView) handleNativePopupAborted() { | ||
| @@ -1244,6 +1252,7 @@ func (wv *WebView) destroyViewBridgeOnGTKThread() { | |||||
| 1244 | if wv == nil || wv.viewBridge == nil { | 1252 | if wv == nil || wv.viewBridge == nil { | ||
| 1245 | return | 1253 | return | ||
| 1246 | } | 1254 | } | ||
| 1255 | + | wv.removeBackgroundFlashGuard() | |||
| 1247 | if wv.removeSizeObserver != nil { | 1256 | if wv.removeSizeObserver != nil { | ||
| 1248 | wv.removeSizeObserver() | 1257 | wv.removeSizeObserver() | ||
| 1249 | wv.removeSizeObserver = nil | 1258 | wv.removeSizeObserver = nil | ||
M internal/infrastructure/cef/webview_handlers_test.go +2 -2
| @@ -380,14 +380,14 @@ func TestConfigureNativePopupWindow_UsesSharedTextureWindowlessDefaults(t *testi | |||
| 380 | 380 | windowInfo := purecef.NewWindowInfo() | |
| 381 | 381 | settings := purecef.NewBrowserSettings() | |
| 382 | 382 | ||
| 383 | - | configureNativePopupWindow(&windowInfo, &settings, 72, 0xFF112233) | |
| 383 | + | configureNativePopupWindow(&windowInfo, &settings, 72) | |
| 384 | 384 | ||
| 385 | 385 | require.Equal(t, purecef.WindowHandle(0), windowInfo.ParentWindow) | |
| 386 | 386 | require.Equal(t, int32(1), windowInfo.WindowlessRenderingEnabled) | |
| 387 | 387 | require.Equal(t, int32(1), windowInfo.SharedTextureEnabled) | |
| 388 | 388 | require.Equal(t, int32(72), settings.WindowlessFrameRate) | |
| 389 | 389 | require.Equal(t, int32(1), settings.LocalStorage) | |
| 390 | - | require.Equal(t, uint32(0xFF112233), settings.BackgroundColor) | |
| 390 | + | require.Equal(t, opaqueWhiteBackground, settings.BackgroundColor) | |
| 391 | 391 | } | |
| 392 | 392 | ||
| 393 | 393 | func TestOnLoadStartFiresCommittedAndUpdatesURI(t *testing.T) { | |
| @@ -380,14 +380,14 @@ func TestConfigureNativePopupWindow_UsesSharedTextureWindowlessDefaults(t *testi | |||||
| 380 | windowInfo := purecef.NewWindowInfo() | 380 | windowInfo := purecef.NewWindowInfo() | ||
| 381 | settings := purecef.NewBrowserSettings() | 381 | settings := purecef.NewBrowserSettings() | ||
| 382 | 382 | ||||
| 383 | - | configureNativePopupWindow(&windowInfo, &settings, 72, 0xFF112233) | 383 | + | configureNativePopupWindow(&windowInfo, &settings, 72) |
| 384 | 384 | ||||
| 385 | require.Equal(t, purecef.WindowHandle(0), windowInfo.ParentWindow) | 385 | require.Equal(t, purecef.WindowHandle(0), windowInfo.ParentWindow) | ||
| 386 | require.Equal(t, int32(1), windowInfo.WindowlessRenderingEnabled) | 386 | require.Equal(t, int32(1), windowInfo.WindowlessRenderingEnabled) | ||
| 387 | require.Equal(t, int32(1), windowInfo.SharedTextureEnabled) | 387 | require.Equal(t, int32(1), windowInfo.SharedTextureEnabled) | ||
| 388 | require.Equal(t, int32(72), settings.WindowlessFrameRate) | 388 | require.Equal(t, int32(72), settings.WindowlessFrameRate) | ||
| 389 | require.Equal(t, int32(1), settings.LocalStorage) | 389 | require.Equal(t, int32(1), settings.LocalStorage) | ||
| 390 | - | require.Equal(t, uint32(0xFF112233), settings.BackgroundColor) | 390 | + | require.Equal(t, opaqueWhiteBackground, settings.BackgroundColor) |
| 391 | } | 391 | } | ||
| 392 | 392 | ||||
| 393 | func TestOnLoadStartFiresCommittedAndUpdatesURI(t *testing.T) { | 393 | func TestOnLoadStartFiresCommittedAndUpdatesURI(t *testing.T) { | ||
M vendor/github.com/bnema/purego-cef/cef/cef_browser_gen.go +15 -2 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_command_line_gen.go +15 -2 generated file: collapsed
A vendor/github.com/bnema/purego-cef/cef/cef_component_updater_gen.go +323 -0 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_cookie_gen.go +14 -1 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_drag_data_gen.go +14 -1 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_image_gen.go +14 -1 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_media_router_gen.go +24 -41 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_menu_model_gen.go +14 -1 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_parser_gen.go +10 -4 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_preference_gen.go +14 -1 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_print_settings_gen.go +14 -1 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_process_message_gen.go +14 -1 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_request_context_gen.go +16 -3 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_request_gen.go +42 -3 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_resource_bundle_gen.go +14 -1 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_response_gen.go +14 -1 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_shared_memory_region_gen.go +3 -3 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_shared_process_message_builder_gen.go +20 -4 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_stream_gen.go +34 -5 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_task_gen.go +15 -2 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_task_manager_gen.go +14 -1 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_thread_gen.go +14 -1 generated file: collapsed
A vendor/github.com/bnema/purego-cef/cef/cef_types_component_gen.go +45 -0 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_types_content_settings_gen.go +72 -79 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_types_gen.go +59 -52 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_urlrequest_gen.go +14 -1 generated file: collapsed
M vendor/github.com/bnema/purego-cef/cef/cef_v8_gen.go +166 -19
| @@ -156,6 +156,19 @@ func wrapV8Context(ptr unsafe.Pointer) V8Context { | |||
| 156 | 156 | return impl | |
| 157 | 157 | } | |
| 158 | 158 | ||
| 159 | + | // takeV8Context adopts a CEF V8Context pointer whose reference is already owned by | |
| 160 | + | // the caller (as returned by a global factory function). Unlike wrapV8Context it | |
| 161 | + | // does NOT call AddRef, because the C API already transferred one reference to us. | |
| 162 | + | func takeV8Context(ptr unsafe.Pointer) V8Context { | |
| 163 | + | if ptr == nil { | |
| 164 | + | return nil | |
| 165 | + | } | |
| 166 | + | r := (*capi.CEFV8ContextT)(ptr) | |
| 167 | + | impl := &v8ContextImpl{rawPtr: r} | |
| 168 | + | runtime.SetFinalizer(impl, (*v8ContextImpl).Release) | |
| 169 | + | return impl | |
| 170 | + | } | |
| 171 | + | ||
| 159 | 172 | // V8Handler Structure that should be implemented to handle V8 function calls. The functions of this structure will be called on the thread associated with the V8 function. | |
| 160 | 173 | type V8Handler = portin.V8Handler | |
| 161 | 174 | ||
| @@ -818,6 +831,93 @@ func wrapV8ArrayBufferReleaseCallback(ptr unsafe.Pointer) V8ArrayBufferReleaseCa | |||
| 818 | 831 | return impl | |
| 819 | 832 | } | |
| 820 | 833 | ||
| 834 | + | // V8BackingStore Structure representing a V8 ArrayBuffer backing store. The backing store holds the memory that backs an ArrayBuffer. It must be created on a thread with a valid V8 isolate (renderer main thread or WebWorker thread). Once created, the data() pointer can be safely read/written from any thread. This allows expensive operations like memcpy to be performed on a background thread before creating the ArrayBuffer on the V8 thread. The backing store is consumed when passed to cef_v8_value_t::cef_v8_value_create_array_buffer_from_backing_store(), after which is_valid() returns false (0). | |
| 835 | + | type V8BackingStore = portin.V8BackingStore | |
| 836 | + | ||
| 837 | + | // v8BackingStoreImpl is a reverse wrapper for a CEF-owned V8BackingStore pointer. | |
| 838 | + | // Release is idempotent, but callers must externally synchronize Release with | |
| 839 | + | // concurrent method calls and must not use the wrapper after Release returns. | |
| 840 | + | type v8BackingStoreImpl struct { | |
| 841 | + | rawPtr *capi.CEFV8BackingStoreT | |
| 842 | + | releaseOnce sync.Once | |
| 843 | + | } | |
| 844 | + | ||
| 845 | + | func (obj *v8BackingStoreImpl) Data() uintptr { | |
| 846 | + | if obj == nil || obj.rawPtr == nil { | |
| 847 | + | return 0 | |
| 848 | + | } | |
| 849 | + | rawPtr := obj.rawPtr | |
| 850 | + | ret := rawPtr.CallData() | |
| 851 | + | return uintptr(ret) | |
| 852 | + | } | |
| 853 | + | ||
| 854 | + | func (obj *v8BackingStoreImpl) ByteLength() int { | |
| 855 | + | if obj == nil || obj.rawPtr == nil { | |
| 856 | + | return 0 | |
| 857 | + | } | |
| 858 | + | rawPtr := obj.rawPtr | |
| 859 | + | ret := rawPtr.CallByteLength() | |
| 860 | + | return int(ret) | |
| 861 | + | } | |
| 862 | + | ||
| 863 | + | func (obj *v8BackingStoreImpl) IsValid() bool { | |
| 864 | + | if obj == nil || obj.rawPtr == nil { | |
| 865 | + | return false | |
| 866 | + | } | |
| 867 | + | rawPtr := obj.rawPtr | |
| 868 | + | ret := rawPtr.CallIsValid() | |
| 869 | + | return ret != 0 | |
| 870 | + | } | |
| 871 | + | ||
| 872 | + | func (obj *v8BackingStoreImpl) RawPointer() unsafe.Pointer { | |
| 873 | + | if obj == nil || obj.rawPtr == nil { | |
| 874 | + | return nil | |
| 875 | + | } | |
| 876 | + | return unsafe.Pointer(obj.rawPtr) | |
| 877 | + | } | |
| 878 | + | ||
| 879 | + | // Release releases the underlying CEF object. | |
| 880 | + | func (obj *v8BackingStoreImpl) Release() { | |
| 881 | + | if obj == nil { | |
| 882 | + | return | |
| 883 | + | } | |
| 884 | + | obj.releaseOnce.Do(func() { | |
| 885 | + | if obj.rawPtr == nil { | |
| 886 | + | return | |
| 887 | + | } | |
| 888 | + | rawPtr := obj.rawPtr | |
| 889 | + | obj.rawPtr = nil | |
| 890 | + | runtime.SetFinalizer(obj, nil) | |
| 891 | + | base := (*capi.CEFBaseRefCountedT)(unsafe.Pointer(rawPtr)) | |
| 892 | + | base.CallRelease() | |
| 893 | + | }) | |
| 894 | + | } | |
| 895 | + | ||
| 896 | + | func wrapV8BackingStore(ptr unsafe.Pointer) V8BackingStore { | |
| 897 | + | if ptr == nil { | |
| 898 | + | return nil | |
| 899 | + | } | |
| 900 | + | r := (*capi.CEFV8BackingStoreT)(ptr) | |
| 901 | + | base := (*capi.CEFBaseRefCountedT)(ptr) | |
| 902 | + | base.CallAddRef() | |
| 903 | + | impl := &v8BackingStoreImpl{rawPtr: r} | |
| 904 | + | runtime.SetFinalizer(impl, (*v8BackingStoreImpl).Release) | |
| 905 | + | return impl | |
| 906 | + | } | |
| 907 | + | ||
| 908 | + | // takeV8BackingStore adopts a CEF V8BackingStore pointer whose reference is already owned by | |
| 909 | + | // the caller (as returned by a global factory function). Unlike wrapV8BackingStore it | |
| 910 | + | // does NOT call AddRef, because the C API already transferred one reference to us. | |
| 911 | + | func takeV8BackingStore(ptr unsafe.Pointer) V8BackingStore { | |
| 912 | + | if ptr == nil { | |
| 913 | + | return nil | |
| 914 | + | } | |
| 915 | + | r := (*capi.CEFV8BackingStoreT)(ptr) | |
| 916 | + | impl := &v8BackingStoreImpl{rawPtr: r} | |
| 917 | + | runtime.SetFinalizer(impl, (*v8BackingStoreImpl).Release) | |
| 918 | + | return impl | |
| 919 | + | } | |
| 920 | + | ||
| 821 | 921 | // V8Value Structure representing a V8 value handle. V8 handles can only be accessed from the thread on which they are created. Valid threads for creating a V8 handle include the render process main thread (TID_RENDERER) and WebWorker threads. A task runner for posting tasks on the associated thread can be retrieved via the cef_v8_context_t::get_task_runner() function. | |
| 822 | 922 | type V8Value = portin.V8Value | |
| 823 | 923 | ||
| @@ -1249,13 +1349,13 @@ func (obj *v8ValueImpl) GetArrayBufferByteLength() int { | |||
| 1249 | 1349 | return int(ret) | |
| 1250 | 1350 | } | |
| 1251 | 1351 | ||
| 1252 | - | func (obj *v8ValueImpl) GetArrayBufferData() unsafe.Pointer { | |
| 1352 | + | func (obj *v8ValueImpl) GetArrayBufferData() uintptr { | |
| 1253 | 1353 | if obj == nil || obj.rawPtr == nil { | |
| 1254 | - | return nil | |
| 1354 | + | return 0 | |
| 1255 | 1355 | } | |
| 1256 | 1356 | rawPtr := obj.rawPtr | |
| 1257 | 1357 | ret := rawPtr.CallGetArrayBufferData() | |
| 1258 | - | return unsafe.Pointer(ret) | |
| 1358 | + | return uintptr(ret) | |
| 1259 | 1359 | } | |
| 1260 | 1360 | ||
| 1261 | 1361 | func (obj *v8ValueImpl) GetFunctionName() string { | |
| @@ -1368,6 +1468,19 @@ func wrapV8Value(ptr unsafe.Pointer) V8Value { | |||
| 1368 | 1468 | return impl | |
| 1369 | 1469 | } | |
| 1370 | 1470 | ||
| 1471 | + | // takeV8Value adopts a CEF V8Value pointer whose reference is already owned by | |
| 1472 | + | // the caller (as returned by a global factory function). Unlike wrapV8Value it | |
| 1473 | + | // does NOT call AddRef, because the C API already transferred one reference to us. | |
| 1474 | + | func takeV8Value(ptr unsafe.Pointer) V8Value { | |
| 1475 | + | if ptr == nil { | |
| 1476 | + | return nil | |
| 1477 | + | } | |
| 1478 | + | r := (*capi.CEFV8ValueT)(ptr) | |
| 1479 | + | impl := &v8ValueImpl{rawPtr: r} | |
| 1480 | + | runtime.SetFinalizer(impl, (*v8ValueImpl).Release) | |
| 1481 | + | return impl | |
| 1482 | + | } | |
| 1483 | + | ||
| 1371 | 1484 | // V8StackTrace Structure representing a V8 stack trace handle. V8 handles can only be accessed from the thread on which they are created. Valid threads for creating a V8 handle include the render process main thread (TID_RENDERER) and WebWorker threads. A task runner for posting tasks on the associated thread can be retrieved via the cef_v8_context_t::get_task_runner() function. | |
| 1372 | 1485 | type V8StackTrace = portin.V8StackTrace | |
| 1373 | 1486 | ||
| @@ -1442,6 +1555,19 @@ func wrapV8StackTrace(ptr unsafe.Pointer) V8StackTrace { | |||
| 1442 | 1555 | return impl | |
| 1443 | 1556 | } | |
| 1444 | 1557 | ||
| 1558 | + | // takeV8StackTrace adopts a CEF V8StackTrace pointer whose reference is already owned by | |
| 1559 | + | // the caller (as returned by a global factory function). Unlike wrapV8StackTrace it | |
| 1560 | + | // does NOT call AddRef, because the C API already transferred one reference to us. | |
| 1561 | + | func takeV8StackTrace(ptr unsafe.Pointer) V8StackTrace { | |
| 1562 | + | if ptr == nil { | |
| 1563 | + | return nil | |
| 1564 | + | } | |
| 1565 | + | r := (*capi.CEFV8StackTraceT)(ptr) | |
| 1566 | + | impl := &v8StackTraceImpl{rawPtr: r} | |
| 1567 | + | runtime.SetFinalizer(impl, (*v8StackTraceImpl).Release) | |
| 1568 | + | return impl | |
| 1569 | + | } | |
| 1570 | + | ||
| 1445 | 1571 | // V8StackFrame Structure representing a V8 stack frame handle. V8 handles can only be accessed from the thread on which they are created. Valid threads for creating a V8 handle include the render process main thread (TID_RENDERER) and WebWorker threads. A task runner for posting tasks on the associated thread can be retrieved via the cef_v8_context_t::get_task_runner() function. | |
| 1446 | 1572 | type V8StackFrame = portin.V8StackFrame | |
| 1447 | 1573 | ||
| @@ -1564,13 +1690,13 @@ func wrapV8StackFrame(ptr unsafe.Pointer) V8StackFrame { | |||
| 1564 | 1690 | // V8ContextGetCurrentContext Returns the current (top) context object in the V8 context stack. | |
| 1565 | 1691 | func V8ContextGetCurrentContext() V8Context { | |
| 1566 | 1692 | ret := capi.CEFV8ContextGetCurrentContext() | |
| 1567 | - | return wrapV8Context(ret) | |
| 1693 | + | return takeV8Context(ret) | |
| 1568 | 1694 | } | |
| 1569 | 1695 | ||
| 1570 | 1696 | // V8ContextGetEnteredContext Returns the entered (bottom) context object in the V8 context stack. | |
| 1571 | 1697 | func V8ContextGetEnteredContext() V8Context { | |
| 1572 | 1698 | ret := capi.CEFV8ContextGetEnteredContext() | |
| 1573 | - | return wrapV8Context(ret) | |
| 1699 | + | return takeV8Context(ret) | |
| 1574 | 1700 | } | |
| 1575 | 1701 | ||
| 1576 | 1702 | // V8ContextInContext Returns true (1) if V8 is currently inside a context. | |
| @@ -1579,40 +1705,49 @@ func V8ContextInContext() int32 { | |||
| 1579 | 1705 | return int32(ret) | |
| 1580 | 1706 | } | |
| 1581 | 1707 | ||
| 1708 | + | // V8BackingStoreCreate Create a new backing store with allocated memory of |byte_length| bytes. The memory is uninitialized. This function must be called on a thread with a valid V8 isolate. The returned object can safely be passed to other threads. Returns nullptr on failure. | |
| 1709 | + | func V8BackingStoreCreate(byteLength int) V8BackingStore { | |
| 1710 | + | if byteLength < 0 { | |
| 1711 | + | return nil | |
| 1712 | + | } | |
| 1713 | + | ret := capi.CEFV8BackingStoreCreate(uintptr(byteLength)) | |
| 1714 | + | return takeV8BackingStore(ret) | |
| 1715 | + | } | |
| 1716 | + | ||
| 1582 | 1717 | // V8ValueCreateUndefined Create a new cef_v8_value_t object of type undefined. | |
| 1583 | 1718 | func V8ValueCreateUndefined() V8Value { | |
| 1584 | 1719 | ret := capi.CEFV8ValueCreateUndefined() | |
| 1585 | - | return wrapV8Value(ret) | |
| 1720 | + | return takeV8Value(ret) | |
| 1586 | 1721 | } | |
| 1587 | 1722 | ||
| 1588 | 1723 | // V8ValueCreateNull Create a new cef_v8_value_t object of type null. | |
| 1589 | 1724 | func V8ValueCreateNull() V8Value { | |
| 1590 | 1725 | ret := capi.CEFV8ValueCreateNull() | |
| 1591 | - | return wrapV8Value(ret) | |
| 1726 | + | return takeV8Value(ret) | |
| 1592 | 1727 | } | |
| 1593 | 1728 | ||
| 1594 | 1729 | // V8ValueCreateBool Create a new cef_v8_value_t object of type bool. | |
| 1595 | 1730 | func V8ValueCreateBool(value int32) V8Value { | |
| 1596 | 1731 | ret := capi.CEFV8ValueCreateBool(value) | |
| 1597 | - | return wrapV8Value(ret) | |
| 1732 | + | return takeV8Value(ret) | |
| 1598 | 1733 | } | |
| 1599 | 1734 | ||
| 1600 | 1735 | // V8ValueCreateInt Create a new cef_v8_value_t object of type int. | |
| 1601 | 1736 | func V8ValueCreateInt(value int32) V8Value { | |
| 1602 | 1737 | ret := capi.CEFV8ValueCreateInt(value) | |
| 1603 | - | return wrapV8Value(ret) | |
| 1738 | + | return takeV8Value(ret) | |
| 1604 | 1739 | } | |
| 1605 | 1740 | ||
| 1606 | 1741 | // V8ValueCreateUint Create a new cef_v8_value_t object of type unsigned int. | |
| 1607 | 1742 | func V8ValueCreateUint(value uint32) V8Value { | |
| 1608 | 1743 | ret := capi.CEFV8ValueCreateUint(value) | |
| 1609 | - | return wrapV8Value(ret) | |
| 1744 | + | return takeV8Value(ret) | |
| 1610 | 1745 | } | |
| 1611 | 1746 | ||
| 1612 | 1747 | // V8ValueCreateDouble Create a new cef_v8_value_t object of type double. | |
| 1613 | 1748 | func V8ValueCreateDouble(value float64) V8Value { | |
| 1614 | 1749 | ret := capi.CEFV8ValueCreateDouble(value) | |
| 1615 | - | return wrapV8Value(ret) | |
| 1750 | + | return takeV8Value(ret) | |
| 1616 | 1751 | } | |
| 1617 | 1752 | ||
| 1618 | 1753 | // V8ValueCreateString Create a new cef_v8_value_t object of type string. | |
| @@ -1620,31 +1755,43 @@ func V8ValueCreateString(value string) V8Value { | |||
| 1620 | 1755 | valueStr := cefString(value) | |
| 1621 | 1756 | defer freeCefString(&valueStr) | |
| 1622 | 1757 | ret := capi.CEFV8ValueCreateString(unsafe.Pointer(&valueStr)) | |
| 1623 | - | return wrapV8Value(ret) | |
| 1758 | + | return takeV8Value(ret) | |
| 1624 | 1759 | } | |
| 1625 | 1760 | ||
| 1626 | 1761 | // V8ValueCreateObject wraps the CEF CEFV8ValueCreateObject function. | |
| 1627 | 1762 | func V8ValueCreateObject(accessor V8Accessor, interceptor V8Interceptor) V8Value { | |
| 1628 | 1763 | ret := capi.CEFV8ValueCreateObject(extractOrWrapRawPointer(accessor, func() any { return NewV8Accessor(accessor) }), extractOrWrapRawPointer(interceptor, func() any { return NewV8Interceptor(interceptor) })) | |
| 1629 | - | return wrapV8Value(ret) | |
| 1764 | + | return takeV8Value(ret) | |
| 1630 | 1765 | } | |
| 1631 | 1766 | ||
| 1632 | 1767 | // V8ValueCreateArray Create a new cef_v8_value_t object of type array with the specified |length|. If |length| is negative the returned array will have length 0. This function should only be called from within the scope of a cef_render_process_handler_t, cef_v8_handler_t or cef_v8_accessor_t callback, or in combination with calling enter() and exit() on a stored cef_v8_context_t reference. | |
| 1633 | 1768 | func V8ValueCreateArray(length int32) V8Value { | |
| 1634 | 1769 | ret := capi.CEFV8ValueCreateArray(length) | |
| 1635 | - | return wrapV8Value(ret) | |
| 1770 | + | return takeV8Value(ret) | |
| 1636 | 1771 | } | |
| 1637 | 1772 | ||
| 1638 | 1773 | // V8ValueCreateArrayBuffer Create a new cef_v8_value_t object of type ArrayBuffer which wraps the provided |buffer| of size |length| bytes. The ArrayBuffer is externalized, meaning that it does not own |buffer|. The caller is responsible for freeing |buffer| when requested via a call to cef_v8_array_buffer_release_callback_t::ReleaseBuffer. This function should only be called from within the scope of a cef_render_process_handler_t, cef_v8_handler_t or cef_v8_accessor_t callback, or in combination with calling enter() and exit() on a stored cef_v8_context_t reference. NOTE: Always returns nullptr when V8 sandbox is enabled. | |
| 1639 | 1774 | func V8ValueCreateArrayBuffer(buffer unsafe.Pointer, length int, releaseCallback V8ArrayBufferReleaseCallback) V8Value { | |
| 1775 | + | if length < 0 { | |
| 1776 | + | return nil | |
| 1777 | + | } | |
| 1640 | 1778 | ret := capi.CEFV8ValueCreateArrayBuffer(buffer, uintptr(length), extractOrWrapRawPointer(releaseCallback, func() any { return NewV8ArrayBufferReleaseCallback(releaseCallback) })) | |
| 1641 | - | return wrapV8Value(ret) | |
| 1779 | + | return takeV8Value(ret) | |
| 1642 | 1780 | } | |
| 1643 | 1781 | ||
| 1644 | 1782 | // V8ValueCreateArrayBufferWithCopy Create a new cef_v8_value_t object of type ArrayBuffer which copies the provided |buffer| of size |length| bytes. This function should only be called from within the scope of a cef_render_process_handler_t, cef_v8_handler_t or cef_v8_accessor_t callback, or in combination with calling enter() and exit() on a stored cef_v8_context_t reference. | |
| 1645 | 1783 | func V8ValueCreateArrayBufferWithCopy(buffer unsafe.Pointer, length int) V8Value { | |
| 1784 | + | if length < 0 { | |
| 1785 | + | return nil | |
| 1786 | + | } | |
| 1646 | 1787 | ret := capi.CEFV8ValueCreateArrayBufferWithCopy(buffer, uintptr(length)) | |
| 1647 | - | return wrapV8Value(ret) | |
| 1788 | + | return takeV8Value(ret) | |
| 1789 | + | } | |
| 1790 | + | ||
| 1791 | + | // V8ValueCreateArrayBufferFromBackingStore wraps the CEF CEFV8ValueCreateArrayBufferFromBackingStore function. | |
| 1792 | + | func V8ValueCreateArrayBufferFromBackingStore(backingStore V8BackingStore) V8Value { | |
| 1793 | + | ret := capi.CEFV8ValueCreateArrayBufferFromBackingStore(extractRawPointer(backingStore)) | |
| 1794 | + | return takeV8Value(ret) | |
| 1648 | 1795 | } | |
| 1649 | 1796 | ||
| 1650 | 1797 | // V8ValueCreateFunction Create a new cef_v8_value_t object of type function. This function should only be called from within the scope of a cef_render_process_handler_t, cef_v8_handler_t or cef_v8_accessor_t callback, or in combination with calling enter() and exit() on a stored cef_v8_context_t reference. | |
| @@ -1652,19 +1799,19 @@ func V8ValueCreateFunction(name string, handler V8Handler) V8Value { | |||
| 1652 | 1799 | nameStr := cefString(name) | |
| 1653 | 1800 | defer freeCefString(&nameStr) | |
| 1654 | 1801 | ret := capi.CEFV8ValueCreateFunction(unsafe.Pointer(&nameStr), extractOrWrapRawPointer(handler, func() any { return NewV8Handler(handler) })) | |
| 1655 | - | return wrapV8Value(ret) | |
| 1802 | + | return takeV8Value(ret) | |
| 1656 | 1803 | } | |
| 1657 | 1804 | ||
| 1658 | 1805 | // V8ValueCreatePromise Create a new cef_v8_value_t object of type Promise. This function should only be called from within the scope of a cef_render_process_handler_t, cef_v8_handler_t or cef_v8_accessor_t callback, or in combination with calling enter() and exit() on a stored cef_v8_context_t reference. | |
| 1659 | 1806 | func V8ValueCreatePromise() V8Value { | |
| 1660 | 1807 | ret := capi.CEFV8ValueCreatePromise() | |
| 1661 | - | return wrapV8Value(ret) | |
| 1808 | + | return takeV8Value(ret) | |
| 1662 | 1809 | } | |
| 1663 | 1810 | ||
| 1664 | 1811 | // V8StackTraceGetCurrent Returns the stack trace for the currently active context. |frame_limit| is the maximum number of frames that will be captured. | |
| 1665 | 1812 | func V8StackTraceGetCurrent(frameLimit int32) V8StackTrace { | |
| 1666 | 1813 | ret := capi.CEFV8StackTraceGetCurrent(frameLimit) | |
| 1667 | - | return wrapV8StackTrace(ret) | |
| 1814 | + | return takeV8StackTrace(ret) | |
| 1668 | 1815 | } | |
| 1669 | 1816 | ||
| 1670 | 1817 | // RegisterExtension Register a new V8 extension with the specified JavaScript extension code and handler. Functions implemented by the handler are prototyped using the keyword 'native'. The calling of a native function is restricted to the scope in which the prototype of the native function is defined. This function may only be called on the render process main thread. Example JavaScript extension code: <pre> // create the 'example' global object if it doesn't already exist. if (!example) example = {}; // create the 'example.test' global object if it doesn't already exist. if (!example.test) example.test = {}; (function() { // Define the function 'example.test.myfunction'. example.test.myfunction = function() { // Call CefV8Handler::Execute() with the function name 'MyFunction' // and no arguments. native function MyFunction(); return MyFunction(); }; // Define the getter function for parameter 'example.test.myparam'. example.test.__defineGetter__('myparam', function() { // Call CefV8Handler::Execute() with the function name 'GetMyParam' // and no arguments. native function GetMyParam(); return GetMyParam(); }); // Define the setter function for parameter 'example.test.myparam'. example.test.__defineSetter__('myparam', function(b) { // Call CefV8Handler::Execute() with the function name 'SetMyParam' // and a single argument. native function SetMyParam(); if(b) SetMyParam(b); }); // Extension definitions can also contain normal JavaScript variables // and functions. var myint = 0; example.test.increment = function() { myint += 1; return myint; }; })(); </pre> Example usage in the page: <pre> // Call the function. example.test.myfunction(); // Set the parameter. example.test.myparam = value; // Get the parameter. value = example.test.myparam; // Call another function. example.test.increment(); </pre> | |
| @@ -156,6 +156,19 @@ func wrapV8Context(ptr unsafe.Pointer) V8Context { | |||||
| 156 | return impl | 156 | return impl | ||
| 157 | } | 157 | } | ||
| 158 | 158 | ||||
| 159 | + | // takeV8Context adopts a CEF V8Context pointer whose reference is already owned by | |||
| 160 | + | // the caller (as returned by a global factory function). Unlike wrapV8Context it | |||
| 161 | + | // does NOT call AddRef, because the C API already transferred one reference to us. | |||
| 162 | + | func takeV8Context(ptr unsafe.Pointer) V8Context { | |||
| 163 | + | if ptr == nil { | |||
| 164 | + | return nil | |||
| 165 | + | } | |||
| 166 | + | r := (*capi.CEFV8ContextT)(ptr) | |||
| 167 | + | impl := &v8ContextImpl{rawPtr: r} | |||
| 168 | + | runtime.SetFinalizer(impl, (*v8ContextImpl).Release) | |||
| 169 | + | return impl | |||
| 170 | + | } | |||
| 171 | + | ||||
| 159 | // V8Handler Structure that should be implemented to handle V8 function calls. The functions of this structure will be called on the thread associated with the V8 function. | 172 | // V8Handler Structure that should be implemented to handle V8 function calls. The functions of this structure will be called on the thread associated with the V8 function. | ||
| 160 | type V8Handler = portin.V8Handler | 173 | type V8Handler = portin.V8Handler | ||
| 161 | 174 | ||||
| @@ -818,6 +831,93 @@ func wrapV8ArrayBufferReleaseCallback(ptr unsafe.Pointer) V8ArrayBufferReleaseCa | |||||
| 818 | return impl | 831 | return impl | ||
| 819 | } | 832 | } | ||
| 820 | 833 | ||||
| 834 | + | // V8BackingStore Structure representing a V8 ArrayBuffer backing store. The backing store holds the memory that backs an ArrayBuffer. It must be created on a thread with a valid V8 isolate (renderer main thread or WebWorker thread). Once created, the data() pointer can be safely read/written from any thread. This allows expensive operations like memcpy to be performed on a background thread before creating the ArrayBuffer on the V8 thread. The backing store is consumed when passed to cef_v8_value_t::cef_v8_value_create_array_buffer_from_backing_store(), after which is_valid() returns false (0). | |||
| 835 | + | type V8BackingStore = portin.V8BackingStore | |||
| 836 | + | ||||
| 837 | + | // v8BackingStoreImpl is a reverse wrapper for a CEF-owned V8BackingStore pointer. | |||
| 838 | + | // Release is idempotent, but callers must externally synchronize Release with | |||
| 839 | + | // concurrent method calls and must not use the wrapper after Release returns. | |||
| 840 | + | type v8BackingStoreImpl struct { | |||
| 841 | + | rawPtr *capi.CEFV8BackingStoreT | |||
| 842 | + | releaseOnce sync.Once | |||
| 843 | + | } | |||
| 844 | + | ||||
| 845 | + | func (obj *v8BackingStoreImpl) Data() uintptr { | |||
| 846 | + | if obj == nil || obj.rawPtr == nil { | |||
| 847 | + | return 0 | |||
| 848 | + | } | |||
| 849 | + | rawPtr := obj.rawPtr | |||
| 850 | + | ret := rawPtr.CallData() | |||
| 851 | + | return uintptr(ret) | |||
| 852 | + | } | |||
| 853 | + | ||||
| 854 | + | func (obj *v8BackingStoreImpl) ByteLength() int { | |||
| 855 | + | if obj == nil || obj.rawPtr == nil { | |||
| 856 | + | return 0 | |||
| 857 | + | } | |||
| 858 | + | rawPtr := obj.rawPtr | |||
| 859 | + | ret := rawPtr.CallByteLength() | |||
| 860 | + | return int(ret) | |||
| 861 | + | } | |||
| 862 | + | ||||
| 863 | + | func (obj *v8BackingStoreImpl) IsValid() bool { | |||
| 864 | + | if obj == nil || obj.rawPtr == nil { | |||
| 865 | + | return false | |||
| 866 | + | } | |||
| 867 | + | rawPtr := obj.rawPtr | |||
| 868 | + | ret := rawPtr.CallIsValid() | |||
| 869 | + | return ret != 0 | |||
| 870 | + | } | |||
| 871 | + | ||||
| 872 | + | func (obj *v8BackingStoreImpl) RawPointer() unsafe.Pointer { | |||
| 873 | + | if obj == nil || obj.rawPtr == nil { | |||
| 874 | + | return nil | |||
| 875 | + | } | |||
| 876 | + | return unsafe.Pointer(obj.rawPtr) | |||
| 877 | + | } | |||
| 878 | + | ||||
| 879 | + | // Release releases the underlying CEF object. | |||
| 880 | + | func (obj *v8BackingStoreImpl) Release() { | |||
| 881 | + | if obj == nil { | |||
| 882 | + | return | |||
| 883 | + | } | |||
| 884 | + | obj.releaseOnce.Do(func() { | |||
| 885 | + | if obj.rawPtr == nil { | |||
| 886 | + | return | |||
| 887 | + | } | |||
| 888 | + | rawPtr := obj.rawPtr | |||
| 889 | + | obj.rawPtr = nil | |||
| 890 | + | runtime.SetFinalizer(obj, nil) | |||
| 891 | + | base := (*capi.CEFBaseRefCountedT)(unsafe.Pointer(rawPtr)) | |||
| 892 | + | base.CallRelease() | |||
| 893 | + | }) | |||
| 894 | + | } | |||
| 895 | + | ||||
| 896 | + | func wrapV8BackingStore(ptr unsafe.Pointer) V8BackingStore { | |||
| 897 | + | if ptr == nil { | |||
| 898 | + | return nil | |||
| 899 | + | } | |||
| 900 | + | r := (*capi.CEFV8BackingStoreT)(ptr) | |||
| 901 | + | base := (*capi.CEFBaseRefCountedT)(ptr) | |||
| 902 | + | base.CallAddRef() | |||
| 903 | + | impl := &v8BackingStoreImpl{rawPtr: r} | |||
| 904 | + | runtime.SetFinalizer(impl, (*v8BackingStoreImpl).Release) | |||
| 905 | + | return impl | |||
| 906 | + | } | |||
| 907 | + | ||||
| 908 | + | // takeV8BackingStore adopts a CEF V8BackingStore pointer whose reference is already owned by | |||
| 909 | + | // the caller (as returned by a global factory function). Unlike wrapV8BackingStore it | |||
| 910 | + | // does NOT call AddRef, because the C API already transferred one reference to us. | |||
| 911 | + | func takeV8BackingStore(ptr unsafe.Pointer) V8BackingStore { | |||
| 912 | + | if ptr == nil { | |||
| 913 | + | return nil | |||
| 914 | + | } | |||
| 915 | + | r := (*capi.CEFV8BackingStoreT)(ptr) | |||
| 916 | + | impl := &v8BackingStoreImpl{rawPtr: r} | |||
| 917 | + | runtime.SetFinalizer(impl, (*v8BackingStoreImpl).Release) | |||
| 918 | + | return impl | |||
| 919 | + | } | |||
| 920 | + | ||||
| 821 | // V8Value Structure representing a V8 value handle. V8 handles can only be accessed from the thread on which they are created. Valid threads for creating a V8 handle include the render process main thread (TID_RENDERER) and WebWorker threads. A task runner for posting tasks on the associated thread can be retrieved via the cef_v8_context_t::get_task_runner() function. | 921 | // V8Value Structure representing a V8 value handle. V8 handles can only be accessed from the thread on which they are created. Valid threads for creating a V8 handle include the render process main thread (TID_RENDERER) and WebWorker threads. A task runner for posting tasks on the associated thread can be retrieved via the cef_v8_context_t::get_task_runner() function. | ||
| 822 | type V8Value = portin.V8Value | 922 | type V8Value = portin.V8Value | ||
| 823 | 923 | ||||
| @@ -1249,13 +1349,13 @@ func (obj *v8ValueImpl) GetArrayBufferByteLength() int { | |||||
| 1249 | return int(ret) | 1349 | return int(ret) | ||
| 1250 | } | 1350 | } | ||
| 1251 | 1351 | ||||
| 1252 | - | func (obj *v8ValueImpl) GetArrayBufferData() unsafe.Pointer { | 1352 | + | func (obj *v8ValueImpl) GetArrayBufferData() uintptr { |
| 1253 | if obj == nil || obj.rawPtr == nil { | 1353 | if obj == nil || obj.rawPtr == nil { | ||
| 1254 | - | return nil | 1354 | + | return 0 |
| 1255 | } | 1355 | } | ||
| 1256 | rawPtr := obj.rawPtr | 1356 | rawPtr := obj.rawPtr | ||
| 1257 | ret := rawPtr.CallGetArrayBufferData() | 1357 | ret := rawPtr.CallGetArrayBufferData() | ||
| 1258 | - | return unsafe.Pointer(ret) | 1358 | + | return uintptr(ret) |
| 1259 | } | 1359 | } | ||
| 1260 | 1360 | ||||
| 1261 | func (obj *v8ValueImpl) GetFunctionName() string { | 1361 | func (obj *v8ValueImpl) GetFunctionName() string { | ||
| @@ -1368,6 +1468,19 @@ func wrapV8Value(ptr unsafe.Pointer) V8Value { | |||||
| 1368 | return impl | 1468 | return impl | ||
| 1369 | } | 1469 | } | ||
| 1370 | 1470 | ||||
| 1471 | + | // takeV8Value adopts a CEF V8Value pointer whose reference is already owned by | |||
| 1472 | + | // the caller (as returned by a global factory function). Unlike wrapV8Value it | |||
| 1473 | + | // does NOT call AddRef, because the C API already transferred one reference to us. | |||
| 1474 | + | func takeV8Value(ptr unsafe.Pointer) V8Value { | |||
| 1475 | + | if ptr == nil { | |||
| 1476 | + | return nil | |||
| 1477 | + | } | |||
| 1478 | + | r := (*capi.CEFV8ValueT)(ptr) | |||
| 1479 | + | impl := &v8ValueImpl{rawPtr: r} | |||
| 1480 | + | runtime.SetFinalizer(impl, (*v8ValueImpl).Release) | |||
| 1481 | + | return impl | |||
| 1482 | + | } | |||
| 1483 | + | ||||
| 1371 | // V8StackTrace Structure representing a V8 stack trace handle. V8 handles can only be accessed from the thread on which they are created. Valid threads for creating a V8 handle include the render process main thread (TID_RENDERER) and WebWorker threads. A task runner for posting tasks on the associated thread can be retrieved via the cef_v8_context_t::get_task_runner() function. | 1484 | // V8StackTrace Structure representing a V8 stack trace handle. V8 handles can only be accessed from the thread on which they are created. Valid threads for creating a V8 handle include the render process main thread (TID_RENDERER) and WebWorker threads. A task runner for posting tasks on the associated thread can be retrieved via the cef_v8_context_t::get_task_runner() function. | ||
| 1372 | type V8StackTrace = portin.V8StackTrace | 1485 | type V8StackTrace = portin.V8StackTrace | ||
| 1373 | 1486 | ||||
| @@ -1442,6 +1555,19 @@ func wrapV8StackTrace(ptr unsafe.Pointer) V8StackTrace { | |||||
| 1442 | return impl | 1555 | return impl | ||
| 1443 | } | 1556 | } | ||
| 1444 | 1557 | ||||
| 1558 | + | // takeV8StackTrace adopts a CEF V8StackTrace pointer whose reference is already owned by | |||
| 1559 | + | // the caller (as returned by a global factory function). Unlike wrapV8StackTrace it | |||
| 1560 | + | // does NOT call AddRef, because the C API already transferred one reference to us. | |||
| 1561 | + | func takeV8StackTrace(ptr unsafe.Pointer) V8StackTrace { | |||
| 1562 | + | if ptr == nil { | |||
| 1563 | + | return nil | |||
| 1564 | + | } | |||
| 1565 | + | r := (*capi.CEFV8StackTraceT)(ptr) | |||
| 1566 | + | impl := &v8StackTraceImpl{rawPtr: r} | |||
| 1567 | + | runtime.SetFinalizer(impl, (*v8StackTraceImpl).Release) | |||
| 1568 | + | return impl | |||
| 1569 | + | } | |||
| 1570 | + | ||||
| 1445 | // V8StackFrame Structure representing a V8 stack frame handle. V8 handles can only be accessed from the thread on which they are created. Valid threads for creating a V8 handle include the render process main thread (TID_RENDERER) and WebWorker threads. A task runner for posting tasks on the associated thread can be retrieved via the cef_v8_context_t::get_task_runner() function. | 1571 | // V8StackFrame Structure representing a V8 stack frame handle. V8 handles can only be accessed from the thread on which they are created. Valid threads for creating a V8 handle include the render process main thread (TID_RENDERER) and WebWorker threads. A task runner for posting tasks on the associated thread can be retrieved via the cef_v8_context_t::get_task_runner() function. | ||
| 1446 | type V8StackFrame = portin.V8StackFrame | 1572 | type V8StackFrame = portin.V8StackFrame | ||
| 1447 | 1573 | ||||
| @@ -1564,13 +1690,13 @@ func wrapV8StackFrame(ptr unsafe.Pointer) V8StackFrame { | |||||
| 1564 | // V8ContextGetCurrentContext Returns the current (top) context object in the V8 context stack. | 1690 | // V8ContextGetCurrentContext Returns the current (top) context object in the V8 context stack. | ||
| 1565 | func V8ContextGetCurrentContext() V8Context { | 1691 | func V8ContextGetCurrentContext() V8Context { | ||
| 1566 | ret := capi.CEFV8ContextGetCurrentContext() | 1692 | ret := capi.CEFV8ContextGetCurrentContext() | ||
| 1567 | - | return wrapV8Context(ret) | 1693 | + | return takeV8Context(ret) |
| 1568 | } | 1694 | } | ||
| 1569 | 1695 | ||||
| 1570 | // V8ContextGetEnteredContext Returns the entered (bottom) context object in the V8 context stack. | 1696 | // V8ContextGetEnteredContext Returns the entered (bottom) context object in the V8 context stack. | ||
| 1571 | func V8ContextGetEnteredContext() V8Context { | 1697 | func V8ContextGetEnteredContext() V8Context { | ||
| 1572 | ret := capi.CEFV8ContextGetEnteredContext() | 1698 | ret := capi.CEFV8ContextGetEnteredContext() | ||
| 1573 | - | return wrapV8Context(ret) | 1699 | + | return takeV8Context(ret) |
| 1574 | } | 1700 | } | ||
| 1575 | 1701 | ||||
| 1576 | // V8ContextInContext Returns true (1) if V8 is currently inside a context. | 1702 | // V8ContextInContext Returns true (1) if V8 is currently inside a context. | ||
| @@ -1579,40 +1705,49 @@ func V8ContextInContext() int32 { | |||||
| 1579 | return int32(ret) | 1705 | return int32(ret) | ||
| 1580 | } | 1706 | } | ||
| 1581 | 1707 | ||||
| 1708 | + | // V8BackingStoreCreate Create a new backing store with allocated memory of |byte_length| bytes. The memory is uninitialized. This function must be called on a thread with a valid V8 isolate. The returned object can safely be passed to other threads. Returns nullptr on failure. | |||
| 1709 | + | func V8BackingStoreCreate(byteLength int) V8BackingStore { | |||
| 1710 | + | if byteLength < 0 { | |||
| 1711 | + | return nil | |||
| 1712 | + | } | |||
| 1713 | + | ret := capi.CEFV8BackingStoreCreate(uintptr(byteLength)) | |||
| 1714 | + | return takeV8BackingStore(ret) | |||
| 1715 | + | } | |||
| 1716 | + | ||||
| 1582 | // V8ValueCreateUndefined Create a new cef_v8_value_t object of type undefined. | 1717 | // V8ValueCreateUndefined Create a new cef_v8_value_t object of type undefined. | ||
| 1583 | func V8ValueCreateUndefined() V8Value { | 1718 | func V8ValueCreateUndefined() V8Value { | ||
| 1584 | ret := capi.CEFV8ValueCreateUndefined() | 1719 | ret := capi.CEFV8ValueCreateUndefined() | ||
| 1585 | - | return wrapV8Value(ret) | 1720 | + | return takeV8Value(ret) |
| 1586 | } | 1721 | } | ||
| 1587 | 1722 | ||||
| 1588 | // V8ValueCreateNull Create a new cef_v8_value_t object of type null. | 1723 | // V8ValueCreateNull Create a new cef_v8_value_t object of type null. | ||
| 1589 | func V8ValueCreateNull() V8Value { | 1724 | func V8ValueCreateNull() V8Value { | ||
| 1590 | ret := capi.CEFV8ValueCreateNull() | 1725 | ret := capi.CEFV8ValueCreateNull() | ||
| 1591 | - | return wrapV8Value(ret) | 1726 | + | return takeV8Value(ret) |
| 1592 | } | 1727 | } | ||
| 1593 | 1728 | ||||
| 1594 | // V8ValueCreateBool Create a new cef_v8_value_t object of type bool. | 1729 | // V8ValueCreateBool Create a new cef_v8_value_t object of type bool. | ||
| 1595 | func V8ValueCreateBool(value int32) V8Value { | 1730 | func V8ValueCreateBool(value int32) V8Value { | ||
| 1596 | ret := capi.CEFV8ValueCreateBool(value) | 1731 | ret := capi.CEFV8ValueCreateBool(value) | ||
| 1597 | - | return wrapV8Value(ret) | 1732 | + | return takeV8Value(ret) |
| 1598 | } | 1733 | } | ||
| 1599 | 1734 | ||||
| 1600 | // V8ValueCreateInt Create a new cef_v8_value_t object of type int. | 1735 | // V8ValueCreateInt Create a new cef_v8_value_t object of type int. | ||
| 1601 | func V8ValueCreateInt(value int32) V8Value { | 1736 | func V8ValueCreateInt(value int32) V8Value { | ||
| 1602 | ret := capi.CEFV8ValueCreateInt(value) | 1737 | ret := capi.CEFV8ValueCreateInt(value) | ||
| 1603 | - | return wrapV8Value(ret) | 1738 | + | return takeV8Value(ret) |
| 1604 | } | 1739 | } | ||
| 1605 | 1740 | ||||
| 1606 | // V8ValueCreateUint Create a new cef_v8_value_t object of type unsigned int. | 1741 | // V8ValueCreateUint Create a new cef_v8_value_t object of type unsigned int. | ||
| 1607 | func V8ValueCreateUint(value uint32) V8Value { | 1742 | func V8ValueCreateUint(value uint32) V8Value { | ||
| 1608 | ret := capi.CEFV8ValueCreateUint(value) | 1743 | ret := capi.CEFV8ValueCreateUint(value) | ||
| 1609 | - | return wrapV8Value(ret) | 1744 | + | return takeV8Value(ret) |
| 1610 | } | 1745 | } | ||
| 1611 | 1746 | ||||
| 1612 | // V8ValueCreateDouble Create a new cef_v8_value_t object of type double. | 1747 | // V8ValueCreateDouble Create a new cef_v8_value_t object of type double. | ||
| 1613 | func V8ValueCreateDouble(value float64) V8Value { | 1748 | func V8ValueCreateDouble(value float64) V8Value { | ||
| 1614 | ret := capi.CEFV8ValueCreateDouble(value) | 1749 | ret := capi.CEFV8ValueCreateDouble(value) | ||
| 1615 | - | return wrapV8Value(ret) | 1750 | + | return takeV8Value(ret) |
| 1616 | } | 1751 | } | ||
| 1617 | 1752 | ||||
| 1618 | // V8ValueCreateString Create a new cef_v8_value_t object of type string. | 1753 | // V8ValueCreateString Create a new cef_v8_value_t object of type string. | ||
| @@ -1620,31 +1755,43 @@ func V8ValueCreateString(value string) V8Value { | |||||
| 1620 | valueStr := cefString(value) | 1755 | valueStr := cefString(value) | ||
| 1621 | defer freeCefString(&valueStr) | 1756 | defer freeCefString(&valueStr) | ||
| 1622 | ret := capi.CEFV8ValueCreateString(unsafe.Pointer(&valueStr)) | 1757 | ret := capi.CEFV8ValueCreateString(unsafe.Pointer(&valueStr)) | ||
| 1623 | - | return wrapV8Value(ret) | 1758 | + | return takeV8Value(ret) |
| 1624 | } | 1759 | } | ||
| 1625 | 1760 | ||||
| 1626 | // V8ValueCreateObject wraps the CEF CEFV8ValueCreateObject function. | 1761 | // V8ValueCreateObject wraps the CEF CEFV8ValueCreateObject function. | ||
| 1627 | func V8ValueCreateObject(accessor V8Accessor, interceptor V8Interceptor) V8Value { | 1762 | func V8ValueCreateObject(accessor V8Accessor, interceptor V8Interceptor) V8Value { | ||
| 1628 | ret := capi.CEFV8ValueCreateObject(extractOrWrapRawPointer(accessor, func() any { return NewV8Accessor(accessor) }), extractOrWrapRawPointer(interceptor, func() any { return NewV8Interceptor(interceptor) })) | 1763 | ret := capi.CEFV8ValueCreateObject(extractOrWrapRawPointer(accessor, func() any { return NewV8Accessor(accessor) }), extractOrWrapRawPointer(interceptor, func() any { return NewV8Interceptor(interceptor) })) | ||
| 1629 | - | return wrapV8Value(ret) | 1764 | + | return takeV8Value(ret) |
| 1630 | } | 1765 | } | ||
| 1631 | 1766 | ||||
| 1632 | // V8ValueCreateArray Create a new cef_v8_value_t object of type array with the specified |length|. If |length| is negative the returned array will have length 0. This function should only be called from within the scope of a cef_render_process_handler_t, cef_v8_handler_t or cef_v8_accessor_t callback, or in combination with calling enter() and exit() on a stored cef_v8_context_t reference. | 1767 | // V8ValueCreateArray Create a new cef_v8_value_t object of type array with the specified |length|. If |length| is negative the returned array will have length 0. This function should only be called from within the scope of a cef_render_process_handler_t, cef_v8_handler_t or cef_v8_accessor_t callback, or in combination with calling enter() and exit() on a stored cef_v8_context_t reference. | ||
| 1633 | func V8ValueCreateArray(length int32) V8Value { | 1768 | func V8ValueCreateArray(length int32) V8Value { | ||
| 1634 | ret := capi.CEFV8ValueCreateArray(length) | 1769 | ret := capi.CEFV8ValueCreateArray(length) | ||
| 1635 | - | return wrapV8Value(ret) | 1770 | + | return takeV8Value(ret) |
| 1636 | } | 1771 | } | ||
| 1637 | 1772 | ||||
| 1638 | // V8ValueCreateArrayBuffer Create a new cef_v8_value_t object of type ArrayBuffer which wraps the provided |buffer| of size |length| bytes. The ArrayBuffer is externalized, meaning that it does not own |buffer|. The caller is responsible for freeing |buffer| when requested via a call to cef_v8_array_buffer_release_callback_t::ReleaseBuffer. This function should only be called from within the scope of a cef_render_process_handler_t, cef_v8_handler_t or cef_v8_accessor_t callback, or in combination with calling enter() and exit() on a stored cef_v8_context_t reference. NOTE: Always returns nullptr when V8 sandbox is enabled. | 1773 | // V8ValueCreateArrayBuffer Create a new cef_v8_value_t object of type ArrayBuffer which wraps the provided |buffer| of size |length| bytes. The ArrayBuffer is externalized, meaning that it does not own |buffer|. The caller is responsible for freeing |buffer| when requested via a call to cef_v8_array_buffer_release_callback_t::ReleaseBuffer. This function should only be called from within the scope of a cef_render_process_handler_t, cef_v8_handler_t or cef_v8_accessor_t callback, or in combination with calling enter() and exit() on a stored cef_v8_context_t reference. NOTE: Always returns nullptr when V8 sandbox is enabled. | ||
| 1639 | func V8ValueCreateArrayBuffer(buffer unsafe.Pointer, length int, releaseCallback V8ArrayBufferReleaseCallback) V8Value { | 1774 | func V8ValueCreateArrayBuffer(buffer unsafe.Pointer, length int, releaseCallback V8ArrayBufferReleaseCallback) V8Value { | ||
| 1775 | + | if length < 0 { | |||
| 1776 | + | return nil | |||
| 1777 | + | } | |||
| 1640 | ret := capi.CEFV8ValueCreateArrayBuffer(buffer, uintptr(length), extractOrWrapRawPointer(releaseCallback, func() any { return NewV8ArrayBufferReleaseCallback(releaseCallback) })) | 1778 | ret := capi.CEFV8ValueCreateArrayBuffer(buffer, uintptr(length), extractOrWrapRawPointer(releaseCallback, func() any { return NewV8ArrayBufferReleaseCallback(releaseCallback) })) | ||
| 1641 | - | return wrapV8Value(ret) | 1779 | + | return takeV8Value(ret) |
| 1642 | } | 1780 | } | ||
| 1643 | 1781 | ||||
| 1644 | // V8ValueCreateArrayBufferWithCopy Create a new cef_v8_value_t object of type ArrayBuffer which copies the provided |buffer| of size |length| bytes. This function should only be called from within the scope of a cef_render_process_handler_t, cef_v8_handler_t or cef_v8_accessor_t callback, or in combination with calling enter() and exit() on a stored cef_v8_context_t reference. | 1782 | // V8ValueCreateArrayBufferWithCopy Create a new cef_v8_value_t object of type ArrayBuffer which copies the provided |buffer| of size |length| bytes. This function should only be called from within the scope of a cef_render_process_handler_t, cef_v8_handler_t or cef_v8_accessor_t callback, or in combination with calling enter() and exit() on a stored cef_v8_context_t reference. | ||
| 1645 | func V8ValueCreateArrayBufferWithCopy(buffer unsafe.Pointer, length int) V8Value { | 1783 | func V8ValueCreateArrayBufferWithCopy(buffer unsafe.Pointer, length int) V8Value { | ||
| 1784 | + | if length < 0 { | |||
| 1785 | + | return nil | |||
| 1786 | + | } | |||
| 1646 | ret := capi.CEFV8ValueCreateArrayBufferWithCopy(buffer, uintptr(length)) | 1787 | ret := capi.CEFV8ValueCreateArrayBufferWithCopy(buffer, uintptr(length)) | ||
| 1647 | - | return wrapV8Value(ret) | 1788 | + | return takeV8Value(ret) |
| 1789 | + | } | |||
| 1790 | + | ||||
| 1791 | + | // V8ValueCreateArrayBufferFromBackingStore wraps the CEF CEFV8ValueCreateArrayBufferFromBackingStore function. | |||
| 1792 | + | func V8ValueCreateArrayBufferFromBackingStore(backingStore V8BackingStore) V8Value { | |||
| 1793 | + | ret := capi.CEFV8ValueCreateArrayBufferFromBackingStore(extractRawPointer(backingStore)) | |||
| 1794 | + | return takeV8Value(ret) | |||
| 1648 | } | 1795 | } | ||
| 1649 | 1796 | ||||
| 1650 | // V8ValueCreateFunction Create a new cef_v8_value_t object of type function. This function should only be called from within the scope of a cef_render_process_handler_t, cef_v8_handler_t or cef_v8_accessor_t callback, or in combination with calling enter() and exit() on a stored cef_v8_context_t reference. | 1797 | // V8ValueCreateFunction Create a new cef_v8_value_t object of type function. This function should only be called from within the scope of a cef_render_process_handler_t, cef_v8_handler_t or cef_v8_accessor_t callback, or in combination with calling enter() and exit() on a stored cef_v8_context_t reference. | ||
| @@ -1652,19 +1799,19 @@ func V8ValueCreateFunction(name string, handler V8Handler) V8Value { | |||||
| 1652 | nameStr := cefString(name) | 1799 | nameStr := cefString(name) | ||
| 1653 | defer freeCefString(&nameStr) | 1800 | defer freeCefString(&nameStr) | ||
| 1654 | ret := capi.CEFV8ValueCreateFunction(unsafe.Pointer(&nameStr), extractOrWrapRawPointer(handler, func() any { return NewV8Handler(handler) })) | 1801 | ret := capi.CEFV8ValueCreateFunction(unsafe.Pointer(&nameStr), extractOrWrapRawPointer(handler, func() any { return NewV8Handler(handler) })) | ||
| 1655 | - | return wrapV8Value(ret) | 1802 | + | return takeV8Value(ret) |
| 1656 | } | 1803 | } | ||
| 1657 | 1804 | ||||
| 1658 | // V8ValueCreatePromise Create a new cef_v8_value_t object of type Promise. This function should only be called from within the scope of a cef_render_process_handler_t, cef_v8_handler_t or cef_v8_accessor_t callback, or in combination with calling enter() and exit() on a stored cef_v8_context_t reference. | 1805 | // V8ValueCreatePromise Create a new cef_v8_value_t object of type Promise. This function should only be called from within the scope of a cef_render_process_handler_t, cef_v8_handler_t or cef_v8_accessor_t callback, or in combination with calling enter() and exit() on a stored cef_v8_context_t reference. | ||
| 1659 | func V8ValueCreatePromise() V8Value { | 1806 | func V8ValueCreatePromise() V8Value { | ||
| 1660 | ret := capi.CEFV8ValueCreatePromise() | 1807 | ret := capi.CEFV8ValueCreatePromise() | ||
| 1661 | - | return wrapV8Value(ret) | 1808 | + | return takeV8Value(ret) |
| 1662 | } | 1809 | } | ||
| 1663 | 1810 | ||||
| 1664 | // V8StackTraceGetCurrent Returns the stack trace for the currently active context. |frame_limit| is the maximum number of frames that will be captured. | 1811 | // V8StackTraceGetCurrent Returns the stack trace for the currently active context. |frame_limit| is the maximum number of frames that will be captured. | ||
| 1665 | func V8StackTraceGetCurrent(frameLimit int32) V8StackTrace { | 1812 | func V8StackTraceGetCurrent(frameLimit int32) V8StackTrace { | ||
| 1666 | ret := capi.CEFV8StackTraceGetCurrent(frameLimit) | 1813 | ret := capi.CEFV8StackTraceGetCurrent(frameLimit) | ||
| 1667 | - | return wrapV8StackTrace(ret) | 1814 | + | return takeV8StackTrace(ret) |
| 1668 | } | 1815 | } | ||
| 1669 | 1816 | ||||
| 1670 | // RegisterExtension Register a new V8 extension with the specified JavaScript extension code and handler. Functions implemented by the handler are prototyped using the keyword 'native'. The calling of a native function is restricted to the scope in which the prototype of the native function is defined. This function may only be called on the render process main thread. Example JavaScript extension code: <pre> // create the 'example' global object if it doesn't already exist. if (!example) example = {}; // create the 'example.test' global object if it doesn't already exist. if (!example.test) example.test = {}; (function() { // Define the function 'example.test.myfunction'. example.test.myfunction = function() { // Call CefV8Handler::Execute() with the function name 'MyFunction' // and no arguments. native function MyFunction(); return MyFunction(); }; // Define the getter function for parameter 'example.test.myparam'. example.test.__defineGetter__('myparam', function() { // Call CefV8Handler::Execute() with the function name 'GetMyParam' // and no arguments. native function GetMyParam(); return GetMyParam(); }); // Define the setter function for parameter 'example.test.myparam'. example.test.__defineSetter__('myparam', function(b) { // Call CefV8Handler::Execute() with the function name 'SetMyParam' // and a single argument. native function SetMyParam(); if(b) SetMyParam(b); }); // Extension definitions can also contain normal JavaScript variables // and functions. var myint = 0; example.test.increment = function() { myint += 1; return myint; }; })(); </pre> Example usage in the page: <pre> // Call the function. example.test.myfunction(); // Set the parameter. example.test.myparam = value; // Get the parameter. value = example.test.myparam; // Call another function. example.test.increment(); </pre> | 1817 | // RegisterExtension Register a new V8 extension with the specified JavaScript extension code and handler. Functions implemented by the handler are prototyped using the keyword 'native'. The calling of a native function is restricted to the scope in which the prototype of the native function is defined. This function may only be called on the render process main thread. Example JavaScript extension code: <pre> // create the 'example' global object if it doesn't already exist. if (!example) example = {}; // create the 'example.test' global object if it doesn't already exist. if (!example.test) example.test = {}; (function() { // Define the function 'example.test.myfunction'. example.test.myfunction = function() { // Call CefV8Handler::Execute() with the function name 'MyFunction' // and no arguments. native function MyFunction(); return MyFunction(); }; // Define the getter function for parameter 'example.test.myparam'. example.test.__defineGetter__('myparam', function() { // Call CefV8Handler::Execute() with the function name 'GetMyParam' // and no arguments. native function GetMyParam(); return GetMyParam(); }); // Define the setter function for parameter 'example.test.myparam'. example.test.__defineSetter__('myparam', function(b) { // Call CefV8Handler::Execute() with the function name 'SetMyParam' // and a single argument. native function SetMyParam(); if(b) SetMyParam(b); }); // Extension definitions can also contain normal JavaScript variables // and functions. var myint = 0; example.test.increment = function() { myint += 1; return myint; }; })(); </pre> Example usage in the page: <pre> // Call the function. example.test.myfunction(); // Set the parameter. example.test.myparam = value; // Get the parameter. value = example.test.myparam; // Call another function. example.test.increment(); </pre> | ||