Refactor: single writer for tool output geometry, extract surface classes - #324
Open
muukii wants to merge 2 commits into
Open
Refactor: single writer for tool output geometry, extract surface classes#324muukii wants to merge 2 commits into
muukii wants to merge 2 commits into
Conversation
`ToolSurface.outputGeometry` had two writers in two types: `ToolSurface.updateCanvas` and `CropView.updateToolScrollGeometry`, the latter deliberately writing before its zoom write. Both `makeToolCropDisplayViewport` and stroke mapping read that value, so whichever writer ran last silently defined the display domain, and the invariant that made them consistent — both derive from `toolDisplayCrop(from:)` — was stated nowhere. Route both writes through `ToolSurface.publishOutputGeometry(_:)` and make the property `private(set)`, so every publish site is greppable and the "publish before any zoom write" ordering rule lives in one doc comment. Also rename `ToolSurface.crop` to `lastAppliedDisplayCrop`: it is only a reset-detection memo, not primary state, but was named like the latter. Behavior-neutral: the same values are written at the same points. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`CropView.swift` was 3463 lines, ~670 of which were the surface classes:
`ViewportRenderingSurface`, `ViewportRenderingState`, `SurfaceHost`,
`CanvasSurface`, `CropSurface`, and `ToolSurface`. They are self-contained —
they never reach into `CropView` state except through the weak `owner`
back-pointer and the stored event closures — and they own the scroll,
canvas, and bounce-ride mechanics that evolve together.
Move them verbatim into `CropView.CanvasSurface.swift` as
`extension CropView { ... }`, mirroring the existing
`CropView._CropScrollView.swift` pattern, so every call site keeps its
`CropView`-nested spelling and compiles unchanged.
This is a pure move: the relocated lines are byte-identical to the removed
ones except for the access-control widenings listed below. No logic, no
renames, no reordering. The display-link state machine and the geometry
builders stay in CropView.swift.
Access-control changes forced by the move (a `private`/`fileprivate` member
is not visible from an extension in another file):
- the six moved type declarations: `private` -> internal
- `CropView.CanvasStrokeCommitHandler`: `private` -> internal
- `CropView.CanvasInputKey`: `private` -> internal
- `CropView.viewportRenderingDisplayLinkDidTick(_:surface:)`: `private` ->
internal
- `UIEdgeInsets.multiplied(_:)`: `fileprivate` -> internal
- `CGRect.isNearlyEqual(to:tolerance:)`: `fileprivate` -> internal
- `CropDisplayViewport.editingCanvasViewport`: `fileprivate` -> internal
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two behavior-neutral structural changes to
CropView, one per commit so each diff is reviewable on its own. No runtime behavior changes: the same values are written at the same points, and the extracted code is byte-identical to what was removed apart from the access-control widenings listed below.1. Single publish path for
ToolSurface.outputGeometrytoolSurface.outputGeometryhad two writers in two types —ToolSurface.updateCanvasandCropView.updateToolScrollGeometry, the latter deliberately writing before its zoom write. BothmakeToolCropDisplayViewportand stroke mapping read that value, so whichever writer ran last silently defined the display domain. The invariant that kept the two consistent (both derive fromtoolDisplayCrop(from:)) was stated nowhere in the code.ToolSurface.publishOutputGeometry(_:), and the property isprivate(set). Every publish site is greppable, and the "publish before any zoom write" ordering rule lives in one doc comment instead of a comment at one of the two call sites.ToolSurface.croprenamed tolastAppliedDisplayCrop. It is only a reset-detection memo — nothing renders from it — but it was named like primary state.2. Extract the surface classes
CropView.swiftwas 3463 lines, ~670 of which were the surface classes:ViewportRenderingSurface,ViewportRenderingState,SurfaceHost,CanvasSurface,CropSurface,ToolSurface. They are self-contained — they never reach intoCropViewstate except through the weakownerback-pointer and the stored event closures — and they own the scroll, canvas, and bounce-ride mechanics that evolve together.They move verbatim into
CropView.CanvasSurface.swiftasextension CropView { ... }, mirroring the existingCropView._CropScrollView.swiftpattern. Preserving the nesting via an extension means every call site keeps itsCropView-nested spelling and compiles unchanged.Explicitly not moved: the display-link state machine and the geometry builders stay in
CropView.swift.Access-control widenings forced by the move
A
private/fileprivatemember is not visible from an extension in a different file, so the move forces these — nothing else was touched:privateCropView.CanvasStrokeCommitHandlerprivateCropView.CanvasInputKeyprivateCropView.viewportRenderingDisplayLinkDidTick(_:surface:)privateUIEdgeInsets.multiplied(_:)fileprivateCGRect.isNearlyEqual(to:tolerance:)fileprivateCropDisplayViewport.editingCanvasViewportfileprivateAll are internal-only types in
BrightroomUI; no public API changes.Verification
xcodebuild -scheme SwiftUIDemo -destination 'generic/platform=iOS Simulator' build— BUILD SUCCEEDEDBrightroomEngineTestson a clean iPhone 17 Pro simulator with-parallel-testing-enabled NO— 153 tests in 36 suites passed, includingCropEditingZoomScaleTests,CropViewCanvasStrokeDomainTests,CropSurfaceBlurRenderPathTests, andCropGeometryTests.privateprefixes are accounted for. Diff stat:CropView.swift−677/+6, new file +700 (670 moved + license header and extension wrapper).🤖 Generated with Claude Code