@@ -124,12 +124,11 @@ extension STTextView {
124
124
textLayoutManager. enumerateTextLayoutFragments ( in: viewportRange, options: . ensuresLayout) { layoutFragment in
125
125
let contentRangeInElement = ( layoutFragment. textElement as? NSTextParagraph ) ? . paragraphContentRange ?? layoutFragment. rangeInElement
126
126
127
- for lineFragment in layoutFragment. textLineFragments where ( lineFragment. isExtraLineFragment || layoutFragment. textLineFragments. first == lineFragment) {
128
-
127
+ for textLineFragment in layoutFragment. textLineFragments where ( textLineFragment. isExtraLineFragment || layoutFragment. textLineFragments. first == textLineFragment) {
129
128
func isLineSelected( ) -> Bool {
130
129
textLayoutManager. textSelections. flatMap ( \. textRanges) . reduce ( true ) { partialResult, selectionTextRange in
131
130
var result = true
132
- if lineFragment . isExtraLineFragment {
131
+ if textLineFragment . isExtraLineFragment {
133
132
let c1 = layoutFragment. rangeInElement. endLocation == selectionTextRange. location
134
133
result = result && c1
135
134
} else {
@@ -145,22 +144,73 @@ extension STTextView {
145
144
}
146
145
147
146
let isLineSelected = isLineSelected ( )
147
+ let lineNumber = startLineIndex + linesCount + 1
148
148
149
+ // calculated values depends on the "isExtraLineFragment" condition
149
150
var baselineYOffset : CGFloat = 0
150
- if let paragraphStyle = lineFragment. attributedString. attribute ( . paragraphStyle, at: 0 , effectiveRange: nil ) as? NSParagraphStyle , !paragraphStyle. lineHeightMultiple. isAlmostZero ( ) {
151
- baselineYOffset = - ( lineFragment. typographicBounds. height * ( paragraphStyle. lineHeightMultiple - 1.0 ) / 2 )
152
- }
151
+ let locationForFirstCharacter : CGPoint
152
+ let lineFragmentFrame : CGRect
153
+
154
+ // The logic for extra line handling would use some cleanup
155
+ // It apply workaround for FB15131180 invalid frame being reported
156
+ // for the extra line fragment. The workaround is to calculate (adjust)
157
+ // extra line fragment frame based on previous text line (from the same layout fragment)
158
+ if layoutFragment. isExtraLineFragment {
159
+ if !textLineFragment. isExtraLineFragment {
160
+ locationForFirstCharacter = textLineFragment. locationForCharacter ( at: 0 )
161
+
162
+ if let paragraphStyle = textLineFragment. attributedString. attribute ( . paragraphStyle, at: 0 , effectiveRange: nil ) as? NSParagraphStyle , !paragraphStyle. lineHeightMultiple. isAlmostZero ( ) {
163
+ baselineYOffset = - ( textLineFragment. typographicBounds. height * ( paragraphStyle. lineHeightMultiple - 1.0 ) / 2 )
164
+ }
153
165
154
- let lineNumber = startLineIndex + linesCount + 1
155
- let locationForFirstCharacter = lineFragment. locationForCharacter ( at: 0 )
166
+ lineFragmentFrame = CGRect (
167
+ origin: CGPoint (
168
+ x: layoutFragment. layoutFragmentFrame. origin. x + textLineFragment. typographicBounds. origin. x,
169
+ y: layoutFragment. layoutFragmentFrame. origin. y + textLineFragment. typographicBounds. origin. y - scrollView. contentView. bounds. minY/*contentOffset.y*/
170
+ ) ,
171
+ size: CGSize (
172
+ width: textLineFragment. typographicBounds. width,
173
+ height: textLineFragment. typographicBounds. height
174
+ )
175
+ )
176
+ } else {
177
+ // Use values from the same layoutFragment but previous line, that is not extra line fragment.
178
+ // Since this is extra line fragment, it is guaranteed that there is at least 2 line fragments in the layout fragment
179
+ let prevTextLineFragment = layoutFragment. textLineFragments [ layoutFragment. textLineFragments. count - 2 ]
180
+ locationForFirstCharacter = prevTextLineFragment. locationForCharacter ( at: 0 )
181
+
182
+ if let paragraphStyle = prevTextLineFragment. attributedString. attribute ( . paragraphStyle, at: 0 , effectiveRange: nil ) as? NSParagraphStyle , !paragraphStyle. lineHeightMultiple. isAlmostZero ( ) {
183
+ baselineYOffset = - ( prevTextLineFragment. typographicBounds. height * ( paragraphStyle. lineHeightMultiple - 1.0 ) / 2 )
184
+ }
156
185
157
- var lineFragmentFrame = CGRect ( origin: CGPoint ( x: 0 , y: layoutFragment. layoutFragmentFrame. origin. y - scrollView. contentView. bounds. minY/*contentOffset.y*/) , size: layoutFragment. layoutFragmentFrame. size)
186
+ lineFragmentFrame = CGRect (
187
+ origin: CGPoint (
188
+ x: layoutFragment. layoutFragmentFrame. origin. x + prevTextLineFragment. typographicBounds. origin. x,
189
+ y: layoutFragment. layoutFragmentFrame. origin. y + prevTextLineFragment. typographicBounds. maxY - scrollView. contentView. bounds. minY/*contentOffset.y*/
190
+ ) ,
191
+ size: CGSize (
192
+ width: textLineFragment. typographicBounds. width,
193
+ height: prevTextLineFragment. typographicBounds. height
194
+ )
195
+ )
196
+ }
197
+ } else {
198
+ locationForFirstCharacter = textLineFragment. locationForCharacter ( at: 0 )
158
199
159
- lineFragmentFrame. origin. y += lineFragment. typographicBounds. origin. y
160
- if lineFragment. isExtraLineFragment {
161
- lineFragmentFrame. size. height = lineFragment. typographicBounds. height
162
- } else if !lineFragment. isExtraLineFragment, let extraLineFragment = layoutFragment. textLineFragments. first ( where: { $0. isExtraLineFragment } ) {
163
- lineFragmentFrame. size. height -= extraLineFragment. typographicBounds. height
200
+ if let paragraphStyle = textLineFragment. attributedString. attribute ( . paragraphStyle, at: 0 , effectiveRange: nil ) as? NSParagraphStyle , !paragraphStyle. lineHeightMultiple. isAlmostZero ( ) {
201
+ baselineYOffset = - ( textLineFragment. typographicBounds. height * ( paragraphStyle. lineHeightMultiple - 1.0 ) / 2 )
202
+ }
203
+
204
+ lineFragmentFrame = CGRect (
205
+ origin: CGPoint (
206
+ x: layoutFragment. layoutFragmentFrame. origin. x + textLineFragment. typographicBounds. origin. x,
207
+ y: layoutFragment. layoutFragmentFrame. origin. y + textLineFragment. typographicBounds. origin. y - scrollView. contentView. bounds. minY/*contentOffset.y*/
208
+ ) ,
209
+ size: CGSize (
210
+ width: layoutFragment. layoutFragmentFrame. width, // extend width to he fragment layout for the convenience of gutter
211
+ height: layoutFragment. layoutFragmentFrame. height
212
+ )
213
+ )
164
214
}
165
215
166
216
var effectiveLineTextAttributes = lineTextAttributes
0 commit comments