@@ -15,14 +15,6 @@ extension TextLayoutManager {
1515 let maxWidth: CGFloat
1616 }
1717
18- /// Asserts that the caller is not in an active layout pass.
19- /// See docs on ``isInLayout`` for more details.
20- private func assertNotInLayout() {
21- #if DEBUG // This is redundant, but it keeps the flag debug-only too which helps prevent misuse.
22- assert(!isInLayout, "layoutLines called while already in a layout pass. This is a programmer error.")
23- #endif
24- }
25-
2618 // MARK: - Layout Lines
2719
2820 /// Lays out all visible lines
@@ -63,14 +55,14 @@ extension TextLayoutManager {
6355 /// pass is already ongoing, internal data structures will be broken. In debug builds, this is checked with a simple
6456 /// boolean and assertion.
6557 ///
66- /// To help ensure this property, all view modifications are performed within a `CATransaction`. This guarantees that macOS calls
67- /// `layout` on any related views only after we’ve finished inserting and removing line fragment views. Otherwise,
68- /// inserting a line fragment view could trigger a layout pass prematurely and cause this method to re-enter.
69- ///
58+ /// To help ensure this property, all view modifications are performed within a `CATransaction`. This guarantees
59+ /// that macOS calls `layout` on any related views only after we’ve finished inserting and removing line fragment
60+ /// views. Otherwise, inserting a line fragment view could trigger a layout pass prematurely and cause this method
61+ /// to re-enter.
7062 /// - Warning: This is probably not what you're looking for. If you need to invalidate layout, or update lines, this
7163 /// is not the way to do so. This should only be called when macOS performs layout.
7264 public func layoutLines(in rect: NSRect? = nil) { // swiftlint:disable:this function_body_length
73- assertNotInLayout ()
65+ layoutLock.lock ()
7466 guard let visibleRect = rect ?? delegate?.visibleRect,
7567 !isInTransaction,
7668 let textStorage else {
@@ -81,9 +73,6 @@ extension TextLayoutManager {
8173 // tree modifications caused by this method are atomic, so macOS won't call `layout` while we're already doing
8274 // that
8375 CATransaction.begin()
84- #if DEBUG
85- isInLayout = true
86- #endif
8776
8877 let minY = max(visibleRect.minY - verticalLayoutPadding, 0)
8978 let maxY = max(visibleRect.maxY + verticalLayoutPadding, 0)
@@ -133,9 +122,6 @@ extension TextLayoutManager {
133122 newVisibleLines.insert(linePosition.data.id)
134123 }
135124
136- #if DEBUG
137- isInLayout = false
138- #endif
139125 // Enqueue any lines not used in this layout pass.
140126 viewReuseQueue.enqueueViews(notInSet: usedFragmentIDs)
141127
@@ -149,9 +135,6 @@ extension TextLayoutManager {
149135 // Commit the view tree changes we just made.
150136 CATransaction.commit()
151137
152- // These are fine to update outside of `isInLayout` as our internal data structures are finalized at this point
153- // so laying out again won't break our line storage or visible line.
154-
155138 if maxFoundLineWidth > maxLineWidth {
156139 maxLineWidth = maxFoundLineWidth
157140 }
@@ -163,6 +146,7 @@ extension TextLayoutManager {
163146 if originalHeight != lineStorage.height || layoutView?.frame.size.height != lineStorage.height {
164147 delegate?.layoutManagerHeightDidUpdate(newHeight: lineStorage.height)
165148 }
149+ layoutLock.unlock()
166150 }
167151
168152 // MARK: - Layout Single Line
@@ -215,10 +199,11 @@ extension TextLayoutManager {
215199 let relativeMinY = max(layoutData.minY - position.yPos, 0)
216200 let relativeMaxY = max(layoutData.maxY - position.yPos, relativeMinY)
217201
218- for lineFragmentPosition in line.lineFragments.linesStartingAt(
219- relativeMinY,
220- until: relativeMaxY
221- ) {
202+ // for lineFragmentPosition in line.lineFragments.linesStartingAt(
203+ // relativeMinY,
204+ // until: relativeMaxY
205+ // ) {
206+ for lineFragmentPosition in line.lineFragments {
222207 let lineFragment = lineFragmentPosition.data
223208
224209 layoutFragmentView(for: lineFragmentPosition, at: position.yPos + lineFragmentPosition.yPos)
0 commit comments