1package cef
2
3import (
4 "math"
5 "strings"
6)
7
8const scaleProbeRoundFactor = 1_000_000
9
10type cefScaleProbeMetrics struct {
11 SurfaceWidth int32
12 SurfaceHeight int32
13 SurfaceScale float64
14 OSRBackingScale float64
15 UserZoom float64
16 InternalCEFFactor float64
17}
18
19func shouldRunCEFScaleProbe(frameURL string, httpStatusCode int32) bool {
20 url := strings.ToLower(strings.TrimSpace(frameURL))
21 if url == "" || url == "about:blank" {
22 return false
23 }
24 if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") {
25 return httpStatusCode >= 200 && httpStatusCode < 400
26 }
27 return httpStatusCode >= 0
28}
29
30func cefScaleProbeSnapshot(wv *WebView) cefScaleProbeMetrics {
31 m := cefScaleProbeMetrics{
32 SurfaceWidth: 1,
33 SurfaceHeight: 1,
34 SurfaceScale: 1,
35 OSRBackingScale: 1,
36 UserZoom: 1,
37 InternalCEFFactor: 1,
38 }
39 if wv == nil {
40 return m
41 }
42 m.UserZoom = normalizeScale(wv.GetZoomLevel())
43 m.OSRBackingScale = normalizeScale(wv.osrBackingScaleFactor())
44 m.SurfaceScale = normalizeScale(wv.viewBridgeScale())
45 m.InternalCEFFactor = m.UserZoom * zoomScaleRatio(m.SurfaceScale, m.OSRBackingScale)
46 if wv.viewBridge != nil {
47 m.SurfaceWidth, m.SurfaceHeight = wv.viewBridge.Size()
48 }
49 return m
50}
51
52func (m cefScaleProbeMetrics) logFields() map[string]interface{} {
53 return map[string]interface{}{
54 "surface_width": m.SurfaceWidth,
55 "surface_height": m.SurfaceHeight,
56 "surface_scale": roundedScale(m.SurfaceScale),
57 "osr_backing_scale": roundedScale(m.OSRBackingScale),
58 "user_zoom": roundedScale(m.UserZoom),
59 "internal_cef_factor": roundedScale(m.InternalCEFFactor),
60 }
61}
62
63func roundedScale(v float64) float64 {
64 if math.IsNaN(v) || math.IsInf(v, 0) {
65 return 1
66 }
67 return math.Round(v*scaleProbeRoundFactor) / scaleProbeRoundFactor
68}
69
70const cefScaleProbeScript = `(function(){
71 try {
72 var vv = window.visualViewport;
73 var probe = document.createElement('div');
74 probe.style.cssText = 'position:fixed;left:0;top:0;width:100px;height:100px;visibility:hidden;pointer-events:none;z-index:-1';
75 document.documentElement.appendChild(probe);
76 var rect = probe.getBoundingClientRect();
77 probe.remove();
78 var data = {
79 dpr: window.devicePixelRatio,
80 inner: [window.innerWidth, window.innerHeight],
81 outer: [window.outerWidth, window.outerHeight],
82 client: [document.documentElement.clientWidth, document.documentElement.clientHeight],
83 screen: [window.screen.width, window.screen.height],
84 avail: [window.screen.availWidth, window.screen.availHeight],
85 visualViewport: vv ? {
86 width: vv.width,
87 height: vv.height,
88 scale: vv.scale,
89 offsetLeft: vv.offsetLeft,
90 offsetTop: vv.offsetTop,
91 pageLeft: vv.pageLeft,
92 pageTop: vv.pageTop
93 } : null,
94 css100Rect: {width: rect.width, height: rect.height, left: rect.left, top: rect.top},
95 scroll: [window.scrollX, window.scrollY]
96 };
97 console.info('[SCALE-PROBE] ' + JSON.stringify(data));
98 } catch (e) {
99 console.warn('[SCALE-PROBE] error ' + (e && e.message ? e.message : String(e)));
100 }
101})();`