diff --git a/AppKit/CPTextView/CPLayoutManager.j b/AppKit/CPTextView/CPLayoutManager.j index f64d8d6a4..926e2b993 100644 --- a/AppKit/CPTextView/CPLayoutManager.j +++ b/AppKit/CPTextView/CPLayoutManager.j @@ -286,6 +286,8 @@ _oncontextmenuhandler = function () { return false; }; if (removeRange.length) _removeInvalidLineFragmentsRange = CPMakeRangeCopy(removeRange); + else + _removeInvalidLineFragmentsRange = nil; // We erased all lines if (!startIndex) diff --git a/AppKit/CPTextView/CPTypesetter.j b/AppKit/CPTextView/CPTypesetter.j index 49169206f..ef793cb86 100644 --- a/AppKit/CPTextView/CPTypesetter.j +++ b/AppKit/CPTextView/CPTypesetter.j @@ -365,6 +365,17 @@ var CPSystemTypesetterFactory, wrapWidth = rangeWidth; wrapRange._height = _lineHeight; wrapRange._base = _lineBase; + + // Optimization: Start measuring from the next character to avoid O(n^2) + // string width calculation within a line since spaces do not carry ligatures or kerning. + // Only reset the measuring range if the next character is NOT another space. + // This prevents compounded subpixel rounding errors with contiguous spaces. + if (theString.charCodeAt(glyphIndex + 1) !== 32) + { + currentAnchor = rangeWidth; + measuringRange = CPMakeRange(glyphIndex + 1, 0); + } + break; case 10: