Web source: container == content — element grid + selection box sized to the cropped frame's canvas extent

- FindContentBounds already trimmed the bitmap; the grid/box still rendered at the uncropped user
  size, so Fill stretched the tight widget into a bigger frame = dead-between-content-and-border.
- ContentCanvasSize maps the crop rect to canvas units (1920/pixW per axis, DPI-correct) and the
  preview event now carries (bitmap, canvasW, canvasH).
- OnWebView2PreviewBitmapChanged sets the element Width/Height to that size; the grid and the
  SelectionOverlay (both bound to the element's Width/Height) now equal the widget exactly.
- IsPreviewDragging (set in MainWindow drag/resize) suppresses auto-fit mid-gesture.
- Tests 10/10 (alpha bounds, canvas-size mapping incl. DPI, control size); 0 warnings.
This commit is contained in:
2026-08-28 12:08:04 -07:00
parent bccdb4892c
commit ab29ec801d
7 changed files with 103 additions and 51 deletions
+11 -13
View File
@@ -31,17 +31,15 @@ Stream widget bounding box: hug the widget on all four sides, pinned to canvas (
extents regardless. Lesson: verify declared mechanics actually execute; assume nothing ran.
## Current iteration (web bounding box — UNCOMMITTED, verification pending)
ALPHA-BBOX CROP: `FindContentBounds` scans the captured Bgra32 frame and returns the bounding box
of non-transparent pixels (the background is injected transparent, so alpha = the widget's extent).
Capture is cropped to that rect and `Stretch="Fill"` maps it flush under the box. No DOM query, no
layout timing — the crop rect IS the rendered widget by construction, so it can NEVER truncate
visible content. Worst case (widget fills the canvas) = full frame = the confirmed-good render.
Canvas-size viewport + Fill untouched. `QueryContentBoundsAsync` + the JS script are DELETED.
CONTAINER == CONTENT. The element grid and the selection box now SIZE to the cropped frame:
`WebView2Manager.ContentCanvasSize` maps the alpha-crop pixel rect to MASTER CANVAS units
(1920/pixW per axis, DPI-correct) and the preview event carries it; `MainViewModel` sets the
Source.Width/Height (the grid + SelectionOverlay bindings) to that size. No Fill-stretching of a
cropped bitmap into a larger frame — the box IS the widget. Auto-fit is suppressed while the
drag/resize gesture is active (`IsPreviewDragging`, set by MainWindow code-behind).
## Iteration that just failed (`a5b9952` — wrapper-excluded DOM-union crop + image alignment)
Broke the image rendering — creator could not evaluate the box because the image was gone/ruined.
Why: the visible-element-union rect is measured ONCE on NavigationCompleted; widget layout isn't
settled then (async fonts/images, load animations, iframes), so the crop rect comes out tiny/wrong
and the Fill-stretched frame renders a broken/zoomed sliver. This was against the creator's explicit
"don't break the rendering" instruction. Lesson: measure actual RENDERED PIXELS (alpha), never
transient DOM state; and never ship a crop blind.
## Iteration that just failed (`bccdb48` — alpha crop, but container stayed at Source.Width/Height)
Crop trimmed the bitmap but the element grid/box still rendered at the UNcropped user-set size, so
Fill stretched the tight widget across a larger frame and dead space floated between content bounds
and the selection border. Lesson: fixing the BITMAP is not fixing the BOX — the layout container
must match the cropped dimensions or the gap persists by construction.