fix(web): re-point the widget diagnostic at the REAL document — the transparency premise gets verified
The one-shot dump + alpha log was bound to the FIRST capture ever = the initial
about:blank placeholder (alpha=0, rgb=0, 5/5 sessions) — a blind instrument. The
pre-parse transparency injection (1a39b09) is intact but was NEVER verified
(MyMistakes '? VERIFY'), and the 2026-09-10 take still shows a black, opaque
block. Stop guessing: NavigationCompleted for a non-about:blank document now
arms WidgetDumpRemaining=5; the next 5 post-paint captures dump
%TEMP%\ytLive-web-<id>-w1..5.png + shared AlphaStats(min/max/mean/zero%) +
FindContentBounds to startup.log.
The stats line alone names the branch: zero%≈opaque ⇒ the injection did not hold
for this widget's CSS (fix: !important stylesheet / chroma-key); large zero% +
tight bounds ⇒ capture IS transparent and the black lives in the compositor
blend. No new test: WebView2 runtime is not instantiable in the suite and the
re-point is log-only; 8/8 WebView2 tests still pass.
This commit is contained in:
+55
-17
@@ -46,6 +46,7 @@ public sealed class WebView2Manager : IDisposable
|
||||
public long Epoch;
|
||||
public WriteableBitmap? PreviewBitmap;
|
||||
public bool DebugPngWritten;
|
||||
public int WidgetDumpRemaining;
|
||||
public int TelemetryCaptureCount;
|
||||
|
||||
public byte[] RentOutBuffer(int size)
|
||||
@@ -179,9 +180,19 @@ public sealed class WebView2Manager : IDisposable
|
||||
_ = cws.ExecuteScriptAsync(TransparentBackgroundScript);
|
||||
};
|
||||
|
||||
cws.NavigationCompleted += (_, _) =>
|
||||
cws.NavigationCompleted += (_, e) =>
|
||||
{
|
||||
_ = cws.ExecuteScriptAsync(TransparentBackgroundScript);
|
||||
if (e.IsSuccess && session.Control.CoreWebView2?.Source is { } src && src != "about:blank")
|
||||
{
|
||||
// Arm a one-shot diagnostic dump of the REAL widget document
|
||||
// (a few post-paint captures so styles/backgrounds settle) —
|
||||
// the old first-capture dump only ever saw the about:blank
|
||||
// document, so whether this widget's capture actually HAS the
|
||||
// transparent margins the injection promises has never been
|
||||
// verified (MyMistakes: "? VERIFY").
|
||||
session.WidgetDumpRemaining = 5;
|
||||
}
|
||||
_ = CaptureFrame(source.Id);
|
||||
};
|
||||
|
||||
@@ -257,6 +268,29 @@ public sealed class WebView2Manager : IDisposable
|
||||
return (minX, minY, maxX - minX + 1, maxY - minY + 1);
|
||||
}
|
||||
|
||||
// alpha[min/max/mean/zero%] — the one number that decides whether a widget's
|
||||
// capture really has transparent margins (0% = opaque, ~100% if the page
|
||||
// painted transparent-only). Sampled every 16th pixel like the original log.
|
||||
private static string AlphaStats(byte[] pixels, int pixW, int pixH, int stride)
|
||||
{
|
||||
int minA = 255, maxA = 0;
|
||||
long sumA = 0, nA = 0, zeroA = 0;
|
||||
for (var y = 0; y < pixH; y += 16)
|
||||
{
|
||||
var row = y * stride;
|
||||
for (var x = 0; x < pixW; x += 16)
|
||||
{
|
||||
var a = pixels[row + x * 4 + 3];
|
||||
if (a < minA) minA = a;
|
||||
if (a > maxA) maxA = a;
|
||||
sumA += a;
|
||||
if (a == 0) zeroA++;
|
||||
nA++;
|
||||
}
|
||||
}
|
||||
return $"alpha[min={minA},max={maxA},mean={sumA / (double)nA:F1},zero={100.0 * zeroA / nA:F1}%]";
|
||||
}
|
||||
|
||||
private async Task CaptureFrame(string sourceId)
|
||||
{
|
||||
if (!_sessions.TryGetValue(sourceId, out var session) || session.Disposed) return;
|
||||
@@ -313,27 +347,31 @@ public sealed class WebView2Manager : IDisposable
|
||||
|
||||
if (session.Epoch == 0)
|
||||
{
|
||||
int minA = 255, maxA = 0;
|
||||
long sumA = 0, nA = 0, zeroA = 0;
|
||||
for (var y = 0; y < pixH; y += 16)
|
||||
{
|
||||
var row = y * stride;
|
||||
for (var x = 0; x < pixW; x += 16)
|
||||
{
|
||||
var a = pixels[row + x * 4 + 3];
|
||||
if (a < minA) minA = a;
|
||||
if (a > maxA) maxA = a;
|
||||
sumA += a;
|
||||
if (a == 0) zeroA++;
|
||||
nA++;
|
||||
}
|
||||
}
|
||||
AppLog.Write(
|
||||
$"WebView2Manager: first capture for '{sourceId}' {pixW}x{pixH} " +
|
||||
$"alpha[min={minA},max={maxA},mean={sumA / (double)nA:F1},zero={100.0 * zeroA / nA:F1}%] " +
|
||||
$"{AlphaStats(pixels, pixW, pixH, stride)} " +
|
||||
$"contentBounds=({cropX},{cropY},{cropW},{cropH})");
|
||||
}
|
||||
|
||||
if (session.WidgetDumpRemaining > 0)
|
||||
{
|
||||
var dumpNo = 5 - session.WidgetDumpRemaining + 1;
|
||||
session.WidgetDumpRemaining--;
|
||||
try
|
||||
{
|
||||
var dbg = Path.Combine(Path.GetTempPath(), $"ytLive-web-{sourceId}-w{dumpNo}.png");
|
||||
File.WriteAllBytes(dbg, ms.ToArray());
|
||||
AppLog.Write(
|
||||
$"WebView2Manager: widget capture [{dumpNo}/5] for '{sourceId}' {pixW}x{pixH} " +
|
||||
$"{AlphaStats(pixels, pixW, pixH, stride)} " +
|
||||
$"contentBounds=({cropX},{cropY},{cropW},{cropH}) -> {dbg}");
|
||||
}
|
||||
catch (Exception dex)
|
||||
{
|
||||
AppLog.Write($"WebView2Manager: widget dump failed: {dex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
var outPixels = session.RentOutBuffer(cropW * cropH * 4);
|
||||
if (cropW == pixW && cropH == pixH && cropX == 0 && cropY == 0)
|
||||
Buffer.BlockCopy(pixels, 0, outPixels, 0, outPixels.Length);
|
||||
|
||||
Reference in New Issue
Block a user