|
|
|
|
@@ -0,0 +1,118 @@
|
|
|
|
|
# NewEditor Frame Resize Synchronous Presentation Root Fix Plan
|
|
|
|
|
|
|
|
|
|
Date: 2026-04-22
|
|
|
|
|
Status: Completed Archive
|
|
|
|
|
|
|
|
|
|
## 1. Objective
|
|
|
|
|
|
|
|
|
|
Restore the original `new_editor` resize-time anti-deformation contract without adding fallback branches, duplicated resize paths, or new ownership confusion.
|
|
|
|
|
|
|
|
|
|
The fix must re-establish one clean rule:
|
|
|
|
|
|
|
|
|
|
1. when a host-side transition needs a new window size before the native window visibly adopts it, the window content must be rendered synchronously for that target size
|
|
|
|
|
2. when Win32 enters paint / size / DPI lifecycle messages, the host must be able to drive a synchronous frame before returning control
|
|
|
|
|
3. normal steady-state rendering must remain on the centralized frame driver path
|
|
|
|
|
|
|
|
|
|
## 2. Confirmed Root Cause
|
|
|
|
|
|
|
|
|
|
The regression was introduced by commit `b44f5ca9` (`refactor(new_editor): centralize win32 frame execution`).
|
|
|
|
|
|
|
|
|
|
That refactor removed the synchronous render step from the critical resize path:
|
|
|
|
|
|
|
|
|
|
1. `EditorWindowChromeController::HandleResizePointerMove(...)`
|
|
|
|
|
2. `EditorWindowChromeController::ApplyPredictedWindowRectTransition(...)`
|
|
|
|
|
3. `EditorWindowMessageDispatcher` handling of `WM_SIZE`, `WM_DPICHANGED`, `WM_EXITSIZEMOVE`, and `WM_PAINT`
|
|
|
|
|
|
|
|
|
|
and replaced it with deferred `RequestFrame(...)` bookkeeping.
|
|
|
|
|
|
|
|
|
|
That bookkeeping does not preserve the old contract because:
|
|
|
|
|
|
|
|
|
|
1. `RequestFrame(...)` only records a bitmask
|
|
|
|
|
2. rendering now happens later from the app main loop
|
|
|
|
|
3. the window can already be resized before the new frame is presented
|
|
|
|
|
4. the old presented surface is therefore stretched by the platform / swap chain path
|
|
|
|
|
|
|
|
|
|
This means the actual regression is not the custom title bar itself. The regression is the loss of synchronous presentation ownership in the Win32 host lifecycle.
|
|
|
|
|
|
|
|
|
|
## 3. Red Lines
|
|
|
|
|
|
|
|
|
|
The implementation must not:
|
|
|
|
|
|
|
|
|
|
1. add a second resize algorithm beside the current borderless resize path
|
|
|
|
|
2. add ad hoc `if (interactiveResize)` branches throughout unrelated rendering code
|
|
|
|
|
3. keep a dead frame-request state machine that no longer owns rendering policy
|
|
|
|
|
4. duplicate `RenderFrame(...)` orchestration in multiple modules
|
|
|
|
|
5. touch workspace transfer / docking semantics unrelated to resize-time presentation
|
|
|
|
|
|
|
|
|
|
## 4. Target End State
|
|
|
|
|
|
|
|
|
|
After the fix:
|
|
|
|
|
|
|
|
|
|
1. `EditorWindowFrameDriver` remains the single general-purpose frame execution entry point
|
|
|
|
|
2. synchronous Win32 lifecycle rendering uses that same driver wherever possible
|
|
|
|
|
3. `WM_PAINT` remains a special case only because it requires `BeginPaint` / `EndPaint`
|
|
|
|
|
4. borderless predicted transitions render the target-size frame synchronously before `SetWindowPos(...)`
|
|
|
|
|
5. dead `RequestFrame(...)` / `EditorWindowFrameRequestReason` plumbing is removed if it no longer owns any real policy
|
|
|
|
|
|
|
|
|
|
## 5. Implementation Plan
|
|
|
|
|
|
|
|
|
|
### Phase A. Remove the dead deferred frame-request layer
|
|
|
|
|
|
|
|
|
|
Completed on 2026-04-22.
|
|
|
|
|
|
|
|
|
|
1. removed `EditorWindowFrameRequestReason`
|
|
|
|
|
2. removed `EditorWindow::RequestFrame(...)`
|
|
|
|
|
3. removed `EditorWindow::ConsumePendingFrameRequestReasons()`
|
|
|
|
|
4. removed all call sites that only existed to defer rendering into the main loop
|
|
|
|
|
|
|
|
|
|
### Phase B. Rebuild one synchronous frame-execution helper path
|
|
|
|
|
|
|
|
|
|
Completed on 2026-04-22.
|
|
|
|
|
|
|
|
|
|
1. kept `EditorWindowFrameDriver::DriveFrame(...)` as the shared frame executor
|
|
|
|
|
2. added a dispatcher-local helper that drives a frame immediately and forwards transfer requests to `EditorWindowWorkspaceCoordinator`
|
|
|
|
|
3. restored that helper to `WM_SIZE`, `WM_DPICHANGED`, and `WM_EXITSIZEMOVE`
|
|
|
|
|
|
|
|
|
|
### Phase C. Restore paint-time synchronous rendering
|
|
|
|
|
|
|
|
|
|
Completed on 2026-04-22.
|
|
|
|
|
|
|
|
|
|
1. restored `WM_PAINT` to render synchronously inside the paint handling path
|
|
|
|
|
2. kept the paint special case local to `BeginPaint` / `EndPaint`
|
|
|
|
|
|
|
|
|
|
### Phase D. Restore predicted-transition pre-presentation
|
|
|
|
|
|
|
|
|
|
Completed on 2026-04-22.
|
|
|
|
|
|
|
|
|
|
1. `HandleResizePointerMove(...)` once again renders the target-size frame synchronously before `SetWindowPos(...)`
|
|
|
|
|
2. `ApplyPredictedWindowRectTransition(...)` does the same for maximize / restore style transitions
|
|
|
|
|
3. this was restored on the original transition path without adding a second resize subsystem
|
|
|
|
|
|
|
|
|
|
### Phase E. Verify no unrelated ownership was widened
|
|
|
|
|
|
|
|
|
|
Completed on 2026-04-22.
|
|
|
|
|
|
|
|
|
|
1. workspace transfer / docking semantics were left untouched
|
|
|
|
|
2. `EditorWindowHostRuntime::RenderAllWindows(...)` still owns steady-state frame pumping
|
|
|
|
|
3. only Win32 host lifecycle and predicted transition code were changed
|
|
|
|
|
|
|
|
|
|
## 6. Validation Requirements
|
|
|
|
|
|
|
|
|
|
Validation completed on 2026-04-22:
|
|
|
|
|
|
|
|
|
|
1. `XCUIEditorApp` Debug build passed after the fix
|
|
|
|
|
2. user verified the resize deformation regression was gone in actual runtime
|
|
|
|
|
|
|
|
|
|
Pending after this archive:
|
|
|
|
|
|
|
|
|
|
1. follow-up investigation for remaining resize jitter
|
|
|
|
|
2. any later refinement should stay on the same host lifecycle boundary and must not reintroduce a deferred fake scheduling layer
|
|
|
|
|
|
|
|
|
|
## 7. Completion Criteria
|
|
|
|
|
|
|
|
|
|
This work was completed with the following outcomes:
|
|
|
|
|
|
|
|
|
|
1. the regression source introduced by `b44f5ca9` was structurally removed
|
|
|
|
|
2. one clear synchronous presentation path was restored for resize-time lifecycle transitions
|
|
|
|
|
3. the dead deferred request layer was removed
|
|
|
|
|
4. the resulting code path remained a mainline host-lifecycle design instead of a post hoc fallback patch
|