Re: Analysis of GSHorizontalTypesetter

"[email protected]" via "Developers list for GNUstep, the GNU groupware evironment" <[email protected]> Sun, 15 Mar 2026 23:15:11 +0100
Newsgroups gmane.comp.lib.gnustep.devel
Message-ID <[email protected]>
--Apple-Mail=_E574689C-527D-4D09-9378-02F1A9847500
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
	charset=utf-8

For better readability please have a look at:

https://github.com/gnustep/libs-gui/issues/382#issuecomment-4064012492

Kind regards,

	Lars

> Am 15.03.2026 um 03:23 schrieb [email protected] via =
Developers list for GNUstep, the GNU groupware evironment =
<[email protected]>:
>=20
> Hi GNUstep-Devs,
>=20
>=20
> especially Riccardo, Fred and Greg since we were talking about this in =
the call today.
>=20
>=20
> I had the idea to let a Coding AI, in this case https://www.kimi.com/ =
analyze our GSHorizontalTypesetter code and =E2=80=9Eexplain=E2=80=9C it =
inside comments added to the code.
>=20
> So I asked it the following question:
>=20
>=20
> =E2=80=9EHello KIMI, please analyze the following code and explain it =
in comments you add or correct:=E2=80=9C
>=20
>=20
> and then gave it both the header and the implementation.
>=20
>=20
> Here is the answer (The answer seems to be in Markup-Format so maybe =
you cut and paste it into some markup editor for better readability):
>=20
> =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=
=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=
=94=20
>=20
>  I'll analyze this GNUstep GUI Library code and add comprehensive =
comments explaining the functionality. Let me go through both the header =
and implementation files.
>=20
> ```objc
> /*
>    GSHorizontalTypesetter.h
>=20
>    Copyright (C) 2002 Free Software Foundation, Inc.
>=20
>    Author: Alexander Malmberg <[email protected]>
>    Date: 2002
>=20
>    This file is part of the GNUstep GUI Library.
>=20
>    This library is free software; you can redistribute it and/or
>    modify it under the terms of the GNU Lesser General Public
>    License as published by the Free Software Foundation; either
>    version 2 of the License, or (at your option) any later version.
>=20
>    This library is distributed in the hope that it will be useful,
>    but WITHOUT ANY WARRANTY; without even the implied warranty of
>    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the =
GNU
>    Lesser General Public License for more details.
>=20
>    You should have received a copy of the GNU Lesser General Public
>    License along with this library; see the file COPYING.LIB.
>    If not, see <http://www.gnu.org/licenses/ > or write to the=20
>    Free Software Foundation, 51 Franklin Street, Fifth Floor,=20
>    Boston, MA 02110-1301, USA.
> */
>=20
> #ifndef _GNUstep_H_GSHorizontalTypesetter
> #define _GNUstep_H_GSHorizontalTypesetter
>=20
> #import <GNUstepGUI/GSTypesetter.h>
>=20
> @class NSLock;
> @class GSLayoutManager, NSTextContainer, NSTextStorage;
> @class NSDictionary;
> @class NSParagraphStyle, NSFont;
>=20
> /*
>  * APPKIT_EXPORT_CLASS marks this class for export from the AppKit =
framework.
>  * This is a GNUstep-specific macro for DLL/shared library symbol =
visibility.
>  */
> APPKIT_EXPORT_CLASS
>=20
> /*
>  * GSHorizontalTypesetter is the concrete typesetter implementation =
for
>  * horizontal text layout in GNUstep. It handles the complex task of =
laying out
>  * glyphs into lines within text containers, supporting various =
paragraph styles,
>  * alignments, line breaking modes, and text attributes.
>  *
>  * This class implements the core text layout algorithm that converts =
a stream
>  * of glyphs from the layout manager into positioned line fragments =
within
>  * the geometric constraints of text containers.
>  */
> @interface GSHorizontalTypesetter : GSTypesetter
> {
>   /*
>    * REENTRANCY LOCK
>    * Since this is typically a shared singleton instance, the lock =
ensures
>    * thread safety. If the typesetter is already in use when another =
layout
>    * request comes in, a temporary instance is created instead.
>    */
>   NSLock *lock;
>=20
>   /*
>    * CURRENT LAYOUT CONTEXT
>    * These ivars track the active text system objects being processed.
>    * They are set at the beginning of each layout operation and remain
>    * constant throughout that operation.
>    */
>   GSLayoutManager *curLayoutManager;    // Converts characters to =
glyphs, tracks runs
>   NSTextContainer *curTextContainer;    // Defines geometric bounds =
for text
>   NSTextStorage *curTextStorage;        // The attributed string being =
laid out
>=20
>   unsigned int curGlyphIndex;           // Current position in the =
glyph stream
>   NSPoint curPoint;                     // Current layout position (y =
advances per line)
>=20
>   /*
>    * ATTRIBUTE CACHING
>    * These ivars cache the current paragraph style and attributes to =
avoid
>    * repeated dictionary lookups. The ranges track the validity of =
each cache.
>    */
>   NSParagraphStyle *curParagraphStyle;  // Current paragraph's =
formatting rules
>   NSRange paragraphRange;               // Character range where =
curParagraphStyle is valid
>=20
>   NSDictionary *curAttributes;          // Current character =
attributes dictionary
>   NSRange attributeRange;               // Character range where =
curAttributes is valid
>  =20
>   /*
>    * DECOMPOSED ATTRIBUTES
>    * Frequently accessed attributes are extracted from the dictionary =
and
>    * stored in this struct for faster access during the tight layout =
loop.
>    */
>   struct
>     {
>       BOOL explicit_kern;               // YES if NSKernAttributeName =
is present
>       float kern;                       // Kerning adjustment value
>       float baseline_offset;            // Vertical offset from =
baseline
>       int superscript;                  // Superscript level (+1, -1, =
etc.)
>     } attributes;
>=20
>   NSFont *curFont;                      // Current font for glyph =
metrics
>   NSRange fontRange;                    // Glyph range where curFont =
is valid
>=20
>   /*
>    * GLYPH CACHE
>    * A resizable array of glyph_cache_t structures that stores =
pre-computed
>    * information about glyphs to avoid repeated calculations. This is =
the
>    * primary optimization for the layout engine.
>    *
>    * cache_base:   The glyph index in the layout manager that =
corresponds
>    *               to cache[0]. All cache indices are relative to =
this.
>    * cache_size:   Allocated capacity of the cache array (in elements)
>    * cache_length: Number of valid entries currently in the cache
>    * at_end:       YES when we've cached all glyphs in the text =
storage
>    */
>   struct GSHorizontalTypesetter_glyph_cache_s *cache;
>   unsigned int cache_base, cache_size, cache_length;
>   BOOL at_end;
>=20
>   /*
>    * LINE FRAGMENT ARRAY
>    * During layout of a single line, this array stores the line =
fragment
>    * rectangles returned by the text container. A line may consist of
>    * multiple fragments when flowing around exclusions or shapes.
>    *
>    * line_frags:      Array of line_frag_t structures
>    * line_frags_num:  Number of fragments in current line
>    * line_frags_size: Allocated capacity of the array
>    */
>   struct GSHorizontalTypesetter_line_frag_s *line_frags;
>   int line_frags_num, line_frags_size;
> }
>=20
> /*
>  * Returns the shared thread-local instance of the typesetter.
>  * Each thread maintains its own instance in the thread dictionary
>  * to avoid cross-thread contention while still allowing reuse.
>  */
> +(GSHorizontalTypesetter *) sharedInstance;
>=20
> @end
>=20
> #endif
> ```
>=20
> Now for the implementation file with detailed comments:
>=20
> ```objc
> /*
>    GSHorizontalTypesetter.m
>=20
>    Copyright (C) 2002, 2003 Free Software Foundation, Inc.
>=20
>    Author: Alexander Malmberg <[email protected]>
>    Date: November 2002 - February 2003
>=20
>    This file is part of the GNUstep GUI Library.
>=20
>    This library is free software; you can redistribute it and/or
>    modify it under the terms of the GNU Lesser General Public
>    License as published by the Free Software Foundation; either
>    version 2 of the License, or (at your option) any later version.
>=20
>    This library is distributed in the hope that it will be useful,
>    but WITHOUT ANY WARRANTY; without even the implied warranty of
>    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the =
GNU
>    Lesser General Public License for more details.
>=20
>    You should have received a copy of the GNU Lesser General Public
>    License along with this library; see the file COPYING.LIB.
>    If not, see <http://www.gnu.org/licenses/> or write to the=20
>    Free Software Foundation, 51 Franklin Street, Fifth Floor,=20
>    Boston, MA 02110-1301, USA.
> */
>=20
>=20
> #include <math.h>
>=20
> #import <Foundation/NSDebug.h>
> #import <Foundation/NSException.h>
> #import <Foundation/NSGeometry.h>
> #import <Foundation/NSLock.h>
> #import <Foundation/NSThread.h>
> #import <Foundation/NSValue.h>
>=20
> #import "AppKit/NSAttributedString.h"
> #import "AppKit/NSParagraphStyle.h"
> #import "AppKit/NSTextAttachment.h"
> #import "AppKit/NSTextContainer.h"
> #import "AppKit/NSTextStorage.h"
> #import "GNUstepGUI/GSLayoutManager.h"
> #import "GNUstepGUI/GSHorizontalTypesetter.h"
>=20
>=20
> /*
>  * DESIGN NOTE: Unless the user creates extra instances, there will =
only be one
>  * instance of GSHorizontalTypesetter per thread for all text =
typesetting.
>  * This allows aggressive caching without memory concerns since the =
cache is
>  * reused across multiple layout operations rather than being =
recreated each time.
>  */
>=20
>=20
> @implementation GSHorizontalTypesetter
>=20
> /*
>  * Standard initializer. Creates the reentrancy lock used to detect
>  * nested layout calls on the same instance.
>  */
> - init
> {
>   if (!(self =3D [super init])) return nil;
>   lock =3D [[NSLock alloc] init];
>   return self;
> }
>=20
> /*
>  * Cleanup: release the lock and free all cached memory buffers.
>  */
> -(void) dealloc
> {
>   if (cache)
>     {
>       free(cache);
>       cache =3D NULL;
>     }
>   if (line_frags)
>     {
>       free(line_frags);
>       line_frags =3D NULL;
>     }
>   DESTROY(lock);
>   [super dealloc];
> }
>=20
> /*
>  * Thread-local singleton accessor. Each thread gets its own instance
>  * stored in the thread dictionary under a unique key. This provides
>  * instance reuse without requiring cross-thread synchronization.
>  */
> +(GSHorizontalTypesetter *) sharedInstance
> {
>   NSMutableDictionary *threadDict =3D=20
>     [[NSThread currentThread] threadDictionary];
>   GSHorizontalTypesetter *shared =3D=20
>     [threadDict objectForKey: @"sharedHorizontalTypesetter"];
>=20
>   if (!shared)
>     {
>       shared =3D [[self alloc] init];
>       [threadDict setObject: shared
> 		  forKey: @"sharedHorizontalTypesetter"];
>       RELEASE(shared);
>     }
>=20
>   return shared;
> }
>=20
> /*
>  * CACHE MANAGEMENT CONSTANTS
>  * CACHE_INITIAL: Starting size for glyph cache (192 glyphs)
>  * CACHE_STEP:    Increment size when cache needs to grow
>  */
> #define CACHE_INITIAL 192
> #define CACHE_STEP 192
>=20
>=20
> /*
>  * GLYPH CACHE ENTRY
>  * Stores all information needed to position a single glyph.
>  * Split into two phases:
>  *   1. Filled during caching (_cacheGlyphs:)
>  *   2. Filled during layout (layoutLineNewParagraph:)
>  */
> struct GSHorizontalTypesetter_glyph_cache_s
> {
>   /* PHASE 1: Caching - extracted from layout manager and attributes =
*/
>   NSGlyph g;                    // The glyph index (NSGlyph is an =
integer type)
>   unsigned int char_index;      // Corresponding character index in =
text storage
>=20
>   NSFont *font;                 // Font to use for this glyph
>   struct
>     {
>       BOOL explicit_kern;       // Whether to apply explicit kerning
>       float kern;               // Kerning value from attributes
>       float baseline_offset;    // Vertical offset from baseline
>       int superscript;          // Superscript level
>     } attributes;
>=20
>   /* PHASE 2: Layout - computed during line layout */
>   BOOL nominal;                 // YES if glyph has standard spacing =
(no adjustments)
>   NSPoint pos;                  // Position relative to the line's =
baseline
>   NSSize size;                  // Advancement width; height used only =
for attachments
>   BOOL dont_show,               // YES for whitespace glyphs that =
shouldn't render
>        outside_line_frag;       // YES for glyphs that overflow the =
fragment (clipping mode)
> };
> typedef struct GSHorizontalTypesetter_glyph_cache_s glyph_cache_t;
>=20
> /*
>  * Clears all cached attribute and glyph information.
>  * Called at the start of each layout operation to ensure we don't
>  * use stale data from previous layouts. Note that we don't free the
>  * cache memory, just reset the valid length to zero.
>  *
>  * TODO: If we could detect whether the layout manager has been =
modified
>  * since our last layout, we could avoid clearing the cache =
unnecessarily.
>  */
> -(void) _cacheClear
> {
>   cache_length =3D 0;
>=20
>   curParagraphStyle =3D nil;
>   paragraphRange =3D NSMakeRange(0, 0);
>   curAttributes =3D nil;
>   attributeRange =3D NSMakeRange(0, 0);
>   curFont =3D nil;
>   fontRange =3D NSMakeRange(0, 0);
> }
>=20
> /*
>  * Caches the attributes for the character at the given index.
>  * Uses range checking to avoid redundant dictionary lookups - if the
>  * requested index is within attributeRange, we already have the data.
>  * Extracts kern, baseline offset, and superscript into the attributes =
struct.
>  */
> -(void) _cacheAttributes: (unsigned int)char_index
> {
>   NSNumber *n;
>=20
>   if (NSLocationInRange(char_index, attributeRange))
>     {
>       return;
>     }
>  =20
>   curAttributes =3D [curTextStorage attributesAtIndex: char_index
>                                      effectiveRange: &attributeRange];
>=20
>   /* Extract kerning attribute */
>   n =3D [curAttributes objectForKey: NSKernAttributeName];
>   if (!n)
>     attributes.explicit_kern =3D NO;
>   else
>     {
>       attributes.explicit_kern =3D YES;
>       attributes.kern =3D [n floatValue];
>     }
>=20
>   /* Extract baseline offset (positive =3D up, negative =3D down in =
standard Cocoa coords) */
>   n =3D [curAttributes objectForKey: NSBaselineOffsetAttributeName];
>   if (n)
>     attributes.baseline_offset =3D [n floatValue];
>   else
>     attributes.baseline_offset =3D 0.0;
>=20
>   /* Extract superscript level */
>   n =3D [curAttributes objectForKey: NSSuperscriptAttributeName];
>   if (n)
>     attributes.superscript =3D [n intValue];
>   else
>     attributes.superscript =3D 0;
> }
>=20
> /*
>  * Repositions the cache window to start at the specified glyph index.
>  *=20
>  * If the requested glyph is already within our cache window, we shift =
the
>  * existing data to the front (memmove) to make room for new glyphs =
ahead.
>  *=20
>  * If it's outside our cache, we reset completely and fetch new =
paragraph
>  * style, attributes, and font information from the layout manager.
>  */
> -(void) _cacheMoveTo: (unsigned int)glyph
> {
>   BOOL valid;
>=20
>   /* Case 1: Requested glyph is already in our cache window */
>   if (cache_base <=3D glyph && cache_base + cache_length > glyph)
>     {
>       int delta =3D glyph - cache_base;
>       cache_length -=3D delta;
>       memmove(cache, &cache[delta], sizeof(glyph_cache_t) * =
cache_length);
>       cache_base =3D glyph;
>       return;
>     }
>=20
>   /* Case 2: Complete reset - new location in text stream */
>   cache_base =3D glyph;
>   cache_length =3D 0;
>=20
>   [curLayoutManager glyphAtIndex: glyph
> 		    isValidIndex: &valid];
>=20
>   if (valid)
>     {
>       unsigned int i;
>=20
>       at_end =3D NO;
>       i =3D [curLayoutManager characterIndexForGlyphAtIndex: glyph];
>       [self _cacheAttributes: i];
>=20
>       /* Fetch paragraph style and its valid range */
>       paragraphRange =3D NSMakeRange(i, [curTextStorage length] - i);
>       curParagraphStyle =3D [curTextStorage attribute: =
NSParagraphStyleAttributeName
> 					atIndex: i
> 					longestEffectiveRange: =
&paragraphRange
> 					inRange: paragraphRange];
>       if (curParagraphStyle =3D=3D nil)
>         {
>           curParagraphStyle =3D [NSParagraphStyle =
defaultParagraphStyle];
>         }
>=20
>       /* Fetch initial font and its valid range */
>       curFont =3D [curLayoutManager effectiveFontForGlyphAtIndex: =
glyph
> 				range: &fontRange];
>     }
>   else
>     {
>       at_end =3D YES;  // No valid glyph at this index - we're at end =
of text
>     }
> }
>=20
> /*
>  * Fills the glyph cache up to new_length entries.
>  * Grows the cache buffer if necessary using realloc.
>  * For each new glyph, fetches:
>  *   - Glyph index and character index from layout manager
>  *   - Attributes (if character index moved past attributeRange)
>  *   - Font (if glyph moved past fontRange)
>  *   - Advancement size from layout manager
>  *
>  * Stops early if we hit invalid glyphs or paragraph boundaries.
>  */
> -(void) _cacheGlyphs: (unsigned int)new_length
> {
>   glyph_cache_t *g;
>   BOOL valid;
>=20
>   /* Grow buffer if needed */
>   if (cache_size < new_length)
>     {
>       cache_size =3D new_length;
>       cache =3D realloc(cache, sizeof(glyph_cache_t) * cache_size);
>     }
>=20
>   /* Fill cache entries from current length up to new_length */
>   for (g =3D &cache[cache_length]; cache_length < new_length; =
cache_length++, g++)
>     {
>       g->g =3D [curLayoutManager glyphAtIndex: cache_base + =
cache_length
> 			       isValidIndex: &valid];
>       if (!valid)
> 	{
> 	  at_end =3D YES;
> 	  break;
> 	}
>       g->char_index =3D [curLayoutManager =
characterIndexForGlyphAtIndex: cache_base + cache_length];
>      =20
>       /* Stop if we crossed paragraph boundary */
>       if (g->char_index >=3D paragraphRange.location + =
paragraphRange.length)
> 	{
> 	  at_end =3D YES;
> 	  break;
> 	}
>=20
>       /* Update attribute cache if needed */
>       if (g->char_index >=3D attributeRange.location + =
attributeRange.length)
> 	{
> 	  [self _cacheAttributes: g->char_index];
> 	}
>=20
>       /* Copy decomposed attributes into cache entry */
>       g->attributes.explicit_kern =3D attributes.explicit_kern;
>       g->attributes.kern =3D attributes.kern;
>       g->attributes.baseline_offset =3D attributes.baseline_offset;
>       g->attributes.superscript =3D attributes.superscript;
>=20
>       /* Update font cache if needed */
>       if (cache_base + cache_length >=3D fontRange.location + =
fontRange.length)
> 	{
> 	  curFont =3D [curLayoutManager effectiveFontForGlyphAtIndex: =
cache_base + cache_length
> 				    range: &fontRange];
> 	}
>       g->font =3D curFont;
>=20
>       /* Initialize layout fields */
>       g->dont_show =3D NO;
>       g->outside_line_frag =3D NO;
>       g->nominal =3D YES;
>=20
>       /* Get glyph advancement from layout manager */
>       // FIXME: This assumes the layout manager implements this =
GNUstep extension
>       g->size =3D [curLayoutManager advancementForGlyphAtIndex: =
cache_base + cache_length];
>     }
> }
>=20
>=20
> /*
>  * WORD WRAPPING SUPPORT
>  * Searches backward from glyph gi to find a suitable word break =
point.
>  * Returns the glyph index of the first glyph on the next line.
>  *
>  * Breaking rules:
>  *   - Control glyphs (newlines, tabs) are always break points
>  *   - Whitespace characters (space, newline, CR, tab) mark breaks and =
are hidden
>  *   - CJK characters (0x2FF0-0x9FFF) can break before (each CJK char =
is its own word)
>  *
>  * The returned index is always >=3D cache_base and <=3D gi.
>  */
> -(unsigned int) breakLineByWordWrappingBefore: (unsigned int)gi
> {
>   glyph_cache_t *g;
>   unichar ch;
>   NSString *str =3D [curTextStorage string];
>=20
>   gi -=3D cache_base;  // Convert to cache-relative index
>   g =3D cache + gi;
>=20
>   while (gi > 0)
>     {
>       if (g->g =3D=3D NSControlGlyph)
>         return gi + cache_base;  // Always break at control glyphs
>      =20
>       ch =3D [str characterAtIndex: g->char_index];
>      =20
>       /* Check for whitespace characters that allow breaking */
>       if (ch =3D=3D 0x20 || // space
>           ch =3D=3D 0x0a || // new line
>           ch =3D=3D 0x0d || // carriage return
>           ch =3D=3D 0x09)   // horiz. tab
>         {
>           g->dont_show =3D YES;  // Hide the whitespace character =
itself
>           if (gi > 0)
>             {
>               g->pos =3D g[-1].pos;
>               g->pos.x +=3D g[-1].size.width;
>             }
>           else
>             g->pos =3D NSMakePoint(0, 0);
>           g->size.width =3D 0;
>           return gi + 1 + cache_base;  // Break after the whitespace
>         }
>      =20
>       /* CJK characters: treat each as a word boundary */
>       else if ((ch > 0x2ff0) && (ch < 0x9fff))
>          {
>            g->dont_show =3D NO;
>            if (gi > 0)
>              {
>                g->pos =3D g[-1].pos;
>                g->pos.x +=3D g[-1].size.width;
>              }
>            else
>              g->pos =3D NSMakePoint(0,0);
>            return gi + cache_base;  // Break before this CJK character
>          }    =20
>      =20
>       gi--;
>       g--;
>     }
>   return gi + cache_base;  // Reached start of cache - break here
> }
>=20
>=20
> /*
>  * LINE FRAGMENT STRUCTURE
>  * Tracks the geometry and content of a single line fragment (a =
rectangular
>  * region within a line where glyphs are placed).
>  */
> struct GSHorizontalTypesetter_line_frag_s
> {
>   NSRect rect;              // The fragment rectangle in container =
coordinates
>   CGFloat last_used;        // X coordinate where glyph content ends
>   unsigned int lastGlyphIndex; // Index (relative to cache_base) of =
last glyph + 1
> };
> typedef struct GSHorizontalTypesetter_line_frag_s line_frag_t;
>=20
> /*
>  * Apple's maximum meaningful width for text containers.
>  * Widths beyond this are treated as infinite and ignored for layout =
purposes.
>  */
> #define LARGE_SIZE 1e7
>=20
> /*
>  * FULL JUSTIFICATION
>  * Distributes extra space evenly across space characters in the line.
>  * Only operates if the line width is reasonable (not LARGE_SIZE).
>  *
>  * Algorithm:
>  *   1. Count space characters in the line
>  *   2. Calculate extra space per space: (rect.width - last_used) / =
num_spaces
>  *   3. Shift all glyphs after each space by accumulating delta
>  *   4. Mark glyphs after spaces as non-nominal (they have adjusted =
positions)
>  */
> -(void) fullJustifyLine: (line_frag_t *)lf : (int)num_line_frags
> {
>   unsigned int i, start;
>   CGFloat extra_space, delta;
>   unsigned int num_spaces;
>   NSString *str =3D [curTextStorage string];
>   glyph_cache_t *g;
>   unichar ch;
>=20
>   if (lf->rect.size.width >=3D LARGE_SIZE)
>     {
>       return;
>     }
>=20
>   for (start =3D 0; num_line_frags; num_line_frags--, lf++)
>     {
>       num_spaces =3D 0;
>       for (i =3D start, g =3D cache + i; i < lf->lastGlyphIndex; i++, =
g++)
> 	{
> 	  if (g->dont_show)
> 	    continue;
> 	  ch =3D [str characterAtIndex: g->char_index];
> 	  if (ch =3D=3D 0x20)
> 	    num_spaces++;
> 	}
>       if (!num_spaces)
> 	continue;
>=20
>       extra_space =3D lf->rect.size.width - lf->last_used;
>       extra_space /=3D num_spaces;
>       delta =3D 0;
>       for (i =3D start, g =3D cache + i; i < lf->lastGlyphIndex; i++, =
g++)
> 	{
> 	  g->pos.x +=3D delta;
> 	  if (!g->dont_show && [str characterAtIndex: g->char_index] =3D=3D=
 0x20)
> 	    {
> 	      if (i < lf->lastGlyphIndex)
> 		g[1].nominal =3D NO;  // Next glyph has non-standard =
position
> 	      delta +=3D extra_space;
> 	    }
> 	}
>       start =3D lf->lastGlyphIndex;
>       lf->last_used =3D lf->rect.size.width;
>     }
> }
>=20
> /*
>  * RIGHT ALIGNMENT
>  * Shifts all glyphs right by the difference between fragment width =
and used width.
>  */
> -(void) rightAlignLine: (line_frag_t *)lf : (int)num_line_frags
> {
>   unsigned int i;
>   CGFloat delta;
>   glyph_cache_t *g;
>=20
>   if (lf->rect.size.width >=3D LARGE_SIZE)
>     {
>       return;
>     }
>=20
>   for (i =3D 0, g =3D cache; num_line_frags; num_line_frags--, lf++)
>     {
>       delta =3D lf->rect.size.width - lf->last_used;
>       for (; i < lf->lastGlyphIndex; i++, g++)
> 	g->pos.x +=3D delta;
>       lf->last_used +=3D delta;
>     }
> }
>=20
> /*
>  * CENTER ALIGNMENT
>  * Shifts all glyphs right by half the remaining space.
>  */
> -(void) centerAlignLine: (line_frag_t *)lf : (int)num_line_frags
> {
>   unsigned int i;
>   CGFloat delta;
>   glyph_cache_t *g;
>=20
>   if (lf->rect.size.width >=3D LARGE_SIZE)
>     {
>       return;
>     }
>=20
>   for (i =3D 0, g =3D cache; num_line_frags; num_line_frags--, lf++)
>     {
>       delta =3D (lf->rect.size.width - lf->last_used) / 2.0;
>       for (; i < lf->lastGlyphIndex; i++, g++)
> 	g->pos.x +=3D delta;
>       lf->last_used +=3D delta;
>     }
> }
>=20
>=20
> /*
>  * SOFT INVALIDATION OPTIMIZATION
>  * Attempts to reuse layout information from previous layout passes =
that
>  * were "soft invalidated" (marked as potentially changed but not =
definitely wrong).
>  *
>  * This handles the common case of simple text edits where line =
fragments
>  * just need to be shifted vertically without changing their =
horizontal layout.
>  *
>  * Returns YES if soft-invalidated layout was successfully reused.
>  */
> -(BOOL) _reuseSoftInvalidatedLayout
> {
>   NSRect r0, r;
>   NSSize shift;
>   int i;
>   unsigned int g, g2, first;
>   CGFloat container_height;
>  =20
>   /* Get first soft-invalidated rect starting at current glyph */
>   r0 =3D [curLayoutManager _softInvalidateLineFragRect: 0
> 					  firstGlyph: &first
> 					   nextGlyph: &g
> 				     inTextContainer: curTextContainer];
>=20
>   container_height =3D [curTextContainer containerSize].height;
>   if (!(curPoint.y + r0.size.height <=3D container_height))
>     return NO;  // Won't fit at current Y position
>=20
>   /*
>    * We can shift the rects vertically to fit. Collect all consecutive
>    * soft-invalidated line fragments and apply the same shift.
>    */
>   shift.width =3D 0;
>   shift.height =3D curPoint.y - r0.origin.y;
>   i =3D 1;
>   curPoint.y =3D NSMaxY(r0) + shift.height;
>  =20
>   for (; 1; i++)
>     {
>       r =3D [curLayoutManager _softInvalidateLineFragRect: i
> 					     firstGlyph: &first
> 					      nextGlyph: &g2
> 					inTextContainer: =
curTextContainer];
>=20
>       /* Gap in soft-invalidated info - must fill in before continuing =
*/
>       if (first !=3D g)
> 	{
> 	  break;
> 	}
>=20
>       if (NSIsEmptyRect(r) || NSMaxY(r) + shift.height > =
container_height)
> 	break;
>=20
>       g =3D g2;
>       curPoint.y =3D NSMaxY(r) + shift.height;
>     }
>=20
>   /* Commit the reused layout to the layout manager */
>   [curLayoutManager _softInvalidateUseLineFrags: i
> 				      withShift: shift
> 				inTextContainer: curTextContainer];
>=20
>   curGlyphIndex =3D g;
>   return YES;
> }
>=20
>=20
> /*
>  * Calculates the proposed rectangle for a new line fragment.
>  *=20
>  * newParagraph: YES for first line of paragraph (uses =
firstLineHeadIndent),
>  *               NO for subsequent lines (uses headIndent)
>  * line_height:  The height to request from the text container
>  *
>  * Returns: Proposed rectangle in container coordinates
>  */
> - (NSRect)_getProposedRectFor: (BOOL)newParagraph
>                withLineHeight: (CGFloat) line_height=20
> {
>   CGFloat hindent;
>   CGFloat tindent =3D [curParagraphStyle tailIndent];
>=20
>   if (newParagraph)
>     hindent =3D [curParagraphStyle firstLineHeadIndent];
>   else
>     hindent =3D [curParagraphStyle headIndent];
>=20
>   /* Negative tail indent is treated as inset from right edge */
>   if (tindent <=3D 0.0)
>     {=20
>       NSSize size;
>=20
>       size =3D [curTextContainer containerSize];
>       tindent =3D size.width + tindent;
>     }
>=20
>   return NSMakeRect(hindent,
>                     curPoint.y,
>                     tindent - hindent,
>                     line_height + [curParagraphStyle lineSpacing]);
> }
>=20
> /*
>  * Creates the "extra line fragment" used when text ends with a =
newline.
>  * This provides a place for the insertion point (caret) after the =
last newline.
>  * The fragment has full line height but minimal width (1 unit).
>  */
> - (void) _addExtraLineFragment
> {
>   NSRect r, r2, remain;
>   CGFloat line_height;
>=20
>   /*
>    * We need the attributes from the last character to match the =
style.
>    * _cacheMoveTo: ensures curParagraphStyle and curFont are set.
>    */
>   if (curGlyphIndex)
>     {
>       [self _cacheMoveTo: curGlyphIndex - 1];
>     }
>   else
>     {
>       /* No glyphs yet - use typing attributes (default style for new =
text) */
>       NSDictionary *typingAttributes =3D [curLayoutManager =
typingAttributes];
>       curParagraphStyle =3D [typingAttributes
>                             objectForKey: =
NSParagraphStyleAttributeName];
>       if (curParagraphStyle =3D=3D nil)
>         {
>           curParagraphStyle =3D [NSParagraphStyle =
defaultParagraphStyle];
>         }
>       curFont =3D [typingAttributes objectForKey: =
NSFontAttributeName];
>     }
>=20
>   /* Determine line height from font or use default */
>   if (curFont)
>     {
>       line_height =3D [curFont defaultLineHeightForFont];
>     }
>   else
>     {
>       line_height =3D 15.0;
>     }
>=20
>   r =3D [self _getProposedRectFor: YES
>                  withLineHeight: line_height];
>   r =3D [curTextContainer lineFragmentRectForProposedRect: r
>                                          sweepDirection: =
NSLineSweepRight
>                                       movementDirection: =
NSLineMovesDown
>                                           remainingRect: &remain];
>  =20
>   if (!NSIsEmptyRect(r))
>     {
>       r2 =3D r;
>       r2.size.width =3D 1;  // Minimal width for caret positioning
>       [curLayoutManager setExtraLineFragmentRect: r
>                                         usedRect: r2
>                                    textContainer: curTextContainer];
>     }
> }
>=20
> /*
>  * Helper for line height calculations.
>  * Updates *lineHeight to newHeight if newHeight is larger (and within =
max).
>  * Returns YES if the line height was updated.
>  */
> static inline BOOL wantNewLineHeight(CGFloat h, CGFloat *lineHeight, =
CGFloat maxLineHeight)
> {
>   CGFloat newHeight =3D h;
>=20
>   if (maxLineHeight > 0 && newHeight > maxLineHeight)
>     {
>       newHeight =3D maxLineHeight;
>     }
>=20
>   if (newHeight > *lineHeight)
>     {
>       *lineHeight =3D newHeight;
>       return YES;
>     }
>   return NO;
> }
>=20
> /*
>  * CORE LAYOUT METHOD
>  * Lays out a single line of text, handling all complexity of glyph =
positioning,
>  * line breaking, attachments, and alignment.
>  *
>  * newParagraph: YES if this is the first line of a paragraph
>  *
>  * Return values:
>  *   0 - Line completed normally, next glyph continues this paragraph
>  *   1 - No room in text container (line fragments exhausted)
>  *   2 - All glyphs laid out (end of text)
>  *   3 - Line ended with newline, next glyph starts new paragraph
>  *   4 - Ambiguous state (must test before next call - from soft =
invalidation)
>  */
> -(int) layoutLineNewParagraph: (BOOL)newParagraph
> {
>   NSRect rect;
>=20
>   /* LINE METRICS VARIABLES */
>   CGFloat line_height;     // Current line height (ascender + =
descender)
>   CGFloat max_line_height; // Maximum allowed (from paragraph style, 0 =
=3D unlimited)
>   CGFloat baseline;        // Distance from top of line to baseline
>   CGFloat ascender;        // Space needed above baseline (max of all =
glyphs)
>   CGFloat descender;       // Space needed below baseline (max of all =
glyphs)
>=20
>   /*
>    * SOFT INVALIDATION CHECK
>    * Try to reuse previous layout if available and appropriate.
>    */
>   if ([curTextContainer isSimpleRectangularTextContainer] &&
>       [curLayoutManager _softInvalidateFirstGlyphInTextContainer: =
curTextContainer] =3D=3D curGlyphIndex)
>     {
>       if ([self _reuseSoftInvalidatedLayout])
>         return 4;
>     }
>=20
>   /* Initialize cache at current glyph position */
>   [self _cacheMoveTo: curGlyphIndex];
>   if (!cache_length)
>     [self _cacheGlyphs: CACHE_INITIAL];
>   if (!cache_length && at_end)
>     {
>       /* No more glyphs to lay out */
>       if (newParagraph)
>         {
>           [self _addExtraLineFragment];  // Text ended with newline
>         }
>       return 2;
>     }
>=20
>   /* INITIALIZE LINE METRICS from first glyph's font */
>   {
>     CGFloat min =3D [curParagraphStyle minimumLineHeight];
>     max_line_height =3D [curParagraphStyle maximumLineHeight];
>=20
>     /* Sanity: max must be >=3D min if both are specified */
>     if (max_line_height > 0 && max_line_height < min)
>       max_line_height =3D min;
>=20
>     line_height =3D [cache->font defaultLineHeightForFont];
>     ascender =3D [cache->font ascender];
>     descender =3D -[cache->font descender];
>=20
>     if (line_height < min)
>       line_height =3D min;
>=20
>     if (max_line_height > 0 && line_height > max_line_height)
>       line_height =3D max_line_height;
>   }
>=20
>   /*
>    * LINE FRAGMENT ACQUISITION
>    * Get rectangles from text container until we have room for at =
least
>    * one glyph. If line height increases due to large glyphs, we =
restart
>    * this process since the rectangles might change.
>    */
> restart: ;
>=20
>   do
>     {
>       NSRect remain;
>=20
>       remain =3D [self _getProposedRectFor: newParagraph
>                           withLineHeight: line_height];
>=20
>       /*
>        * Build list of line fragment rects for this line.
>        * A line may have multiple fragments when flowing around =
shapes.
>        * TODO: This builds all rects in advance which might be =
inefficient
>        * for containers with many exclusions (e.g., narrow columns).
>        */
>       line_frags_num =3D 0;
>       rect =3D [curTextContainer lineFragmentRectForProposedRect: =
remain
>                                                 sweepDirection: =
NSLineSweepRight
>                                              movementDirection: =
NSLineMovesDown
>                                                  remainingRect: =
&remain];
>       while (!NSIsEmptyRect(rect))
>         {
>           line_frags_num++;
>           if (line_frags_num > line_frags_size)
>             {
>               line_frags_size +=3D 2;
>               line_frags =3D realloc(line_frags, sizeof(line_frag_t) * =
line_frags_size);
>             }
>           line_frags[line_frags_num - 1].rect =3D rect;
>=20
>           rect =3D [curTextContainer lineFragmentRectForProposedRect: =
remain
>                                                     sweepDirection: =
NSLineSweepRight
>                                                  movementDirection: =
NSLineDoesntMove
>                                                      remainingRect: =
&remain];
>         }
>       if (line_frags_num =3D=3D 0)
>         {
>           /* No fragments available - container might be too small */
>           if (curPoint.y =3D=3D 0.0 &&
>               line_height > [curTextContainer containerSize].height &&
>               [curTextContainer containerSize].height > 0.0)
>             {
>               /* Emergency: shrink line height to fit at least one =
line */
>               line_height =3D [curTextContainer containerSize].height;
>               max_line_height =3D line_height;
>               continue;
>             }
>           return 1;  // No room in container
>         }
>     }
>   while (line_frags_num =3D=3D 0);
>=20
>   /*
>    * MAIN GLYPH LAYOUT LOOP
>    * Positions each glyph in the line fragments, handling:
>    *   - Font changes and metric updates
>    *   - Kerning and baseline adjustments
>    *   - Superscript/subscript positioning
>    *   - Tab stops
>    *   - Text attachments (images, etc.)
>    *   - Line breaking when fragments fill up
>    */
>   {
>     unsigned int i =3D 0;
>     glyph_cache_t *g;
>=20
>     NSPoint p;              // Current glyph position (relative to =
line fragment)
>    =20
>     NSFont *f =3D cache->font;
>=20
>     CGFloat f_ascender =3D [f ascender];
>     CGFloat f_descender =3D -[f descender];
>=20
>     NSGlyph last_glyph =3D NSNullGlyph;  // For kerning calculations
>     NSPoint last_p;
>=20
>     unsigned int firstGlyphIndex;      // First glyph in current line =
fragment
>     line_frag_t *lf =3D line_frags;      // Current line fragment
>     int lfi =3D 0;                       // Line fragment index
>=20
>     BOOL prev_had_non_nominal_width;   // Track if previous glyph had =
custom spacing
>=20
>=20
>     last_p =3D p =3D NSMakePoint(0, 0);
>=20
>     g =3D cache;
>     firstGlyphIndex =3D 0;
>     prev_had_non_nominal_width =3D NO;
>=20
>     while (1)
>       {
>         BOOL doesGlyphFitInLine =3D YES;
>=20
>         /* Ensure we have cached glyphs to process */
> 	if (i >=3D cache_length)
> 	  {
> 	    if (at_end)
> 	      {
> 		newParagraph =3D NO;
> 		break;  // End of text
> 	      }
> 	    [self _cacheGlyphs: cache_length + CACHE_STEP];
> 	    if (i >=3D cache_length)
> 	      {
> 		newParagraph =3D NO;
> 		break;  // No more glyphs available
> 	      }
> 	    g =3D cache + i;
> 	  }
>=20
> 	/*
> 	 * FONT CHANGE HANDLING
> 	 * Update ascender/descender tracking when font changes.
> 	 * Reset last_glyph to disable kerning across font boundaries.
> 	 */
> 	if (g->font !=3D f)
> 	  {
> 	    f =3D g->font;
> 	    f_ascender =3D [f ascender];
> 	    f_descender =3D -[f descender];
> 	    last_glyph =3D NSNullGlyph;
> 	  }
>=20
> 	/* Apply explicit kerning if specified in attributes */
> 	g->nominal =3D !prev_had_non_nominal_width;
>=20
> 	if (g->attributes.explicit_kern &&
> 	    g->attributes.kern !=3D 0)
> 	  {
> 	    p.x +=3D g->attributes.kern;
> 	    g->nominal =3D NO;
> 	  }
>=20
>         /* Check if glyph fits in current line fragment width */
>         doesGlyphFitInLine =3D !((i > firstGlyphIndex) && (p.x + =
g->size.width > lf->rect.size.width));
>        =20
>         if (doesGlyphFitInLine)
>           {
>             /* Calculate vertical position with baseline adjustments =
*/
>             CGFloat y =3D 0;
>=20
>             /* Apply superscript offset (negative =3D up in flipped =
coords) */
>             if (g->attributes.superscript)
>               {
>                 y -=3D g->attributes.superscript * [f xHeight];
>               }
>             /* Apply explicit baseline offset */
>             if (g->attributes.baseline_offset)
>               {
>                 y +=3D g->attributes.baseline_offset;
>               }
>=20
>             if (y !=3D p.y)
>               {
>                 p.y =3D y;
>                 g->nominal =3D NO;  // Non-standard vertical position
>               }
>          =20
>             /* Update line metrics based on this glyph */
>             if (f_ascender > ascender)
>               ascender =3D f_ascender;
>             if (f_descender > descender)
>               descender =3D f_descender;
>=20
>             /* Adjust for superscript/subscript height requirements */
>             if (y < 0 && f_ascender - y > ascender)
>               ascender =3D f_ascender - y;
>             if (y > 0 && f_descender + y > descender)
>               descender =3D f_descender + y;
>=20
>             /* If metrics changed, check if we need to restart with =
new line height */
>             if (wantNewLineHeight(ascender + descender, &line_height, =
max_line_height))
>               goto restart;
>           }
>=20
> 	/* CONTROL GLYPH HANDLING (newlines, tabs, etc.) */
> 	if (g->g =3D=3D NSControlGlyph)
> 	  {
> 	    unichar ch =3D [[curTextStorage string] characterAtIndex: =
g->char_index];
>=20
> 	    g->pos =3D p;
> 	    g->size.width =3D 0;
> 	    g->dont_show =3D YES;  // Control glyphs don't render
> 	    g->nominal =3D !prev_had_non_nominal_width;
> 	    i++;
> 	    g++;
> 	    last_glyph =3D NSNullGlyph;
> 	    prev_had_non_nominal_width =3D NO;
>=20
> 	    /* NEWLINE: End this line, start new paragraph */
> 	    if (ch =3D=3D 0xa) // new line
> 	      {
> 		newParagraph =3D YES;
> 		break;
> 	      }
>=20
> 	    /* TAB: Advance to next tab stop */
> 	    if (ch =3D=3D 0x9) // horiz. tab
> 	      {
> 		NSArray *tabs =3D [curParagraphStyle tabStops];
> 		NSTextTab *tab =3D nil;
> 		CGFloat defaultInterval =3D [curParagraphStyle =
defaultTabInterval];
> 		if (defaultInterval =3D=3D 0.0)
>                   {
>                     defaultInterval =3D 100.0;  // Reasonable default
>                   }
> 		unsigned tabIndex;
>                 unsigned tabCount =3D [tabs count];
>                =20
>                 /* Find next tab stop after current position */
> 		for (tabIndex =3D 0; tabIndex < tabCount; tabIndex++)
> 		  {
> 		    tab =3D [tabs objectAtIndex: tabIndex];
> 		    if ([tab location] > p.x + lf->rect.origin.x)
>                       {
>                         break;
>                       }
> 		  }
> 		if (tabIndex =3D=3D tabCount)
> 		  {
> 		    /* Past last explicit tab stop - use default =
interval */
> 		    p.x =3D (floor(p.x / defaultInterval) + 1.0) * =
defaultInterval;
> 		  }
> 		else
> 		  {
> 		    p.x =3D [tab location] - lf->rect.origin.x;
> 		  }
> 		prev_had_non_nominal_width =3D YES;
> 		continue;
> 	      }
>=20
>             /* Unknown control character - log and ignore */
> 	    NSDebugLLog(@"GSHorizontalTypesetter",
> 	      @"ignoring unknown control character %04x\n", ch);
> 	    continue;
> 	  }
>=20
> 	/* TEXT ATTACHMENT HANDLING (images, files, etc.) */
> 	if (g->g =3D=3D GSAttachmentGlyph)
> 	  {
> 	    NSTextAttachment *attach;
> 	    NSTextAttachmentCell *cell;
> 	    NSRect r;
>=20
> 	    attach =3D [curTextStorage attribute: =
NSAttachmentAttributeName
> 	      atIndex: g->char_index
> 	      effectiveRange: NULL];
> 	    cell =3D (NSTextAttachmentCell*)[attach attachmentCell];
> 	    if (!cell)
> 	      {
>                 /* No cell for attachment - treat as zero-width =
invisible glyph */
> 		g->pos =3D p;
> 		g->size =3D NSMakeSize(0, 0);
> 		g->dont_show =3D YES;
> 		g->nominal =3D YES;
> 		i++;
> 		g++;
> 		last_glyph =3D NSNullGlyph;
> 		continue;
> 	      }
>=20
>             /* Calculate baseline position for attachment alignment */
>             baseline =3D line_height - descender;
>=20
> 	    /* Ask attachment cell for its desired frame */
> 	    r =3D [cell cellFrameForTextContainer: curTextContainer
> 		  proposedLineFragment: lf->rect
> 		  glyphPosition: NSMakePoint(p.x,
> 					     lf->rect.size.height - =
baseline)
> 		  characterIndex: g->char_index];
>=20
>             /* Check if attachment fits in current fragment */
>             doesGlyphFitInLine =3D !((i > firstGlyphIndex) && (p.x + =
NSMaxX(r) > lf->rect.size.width));
>             if (doesGlyphFitInLine)
>               {
>                 /* Update line metrics for attachment size */
>                 if (-NSMinY(r) > descender)
>                   descender =3D -NSMinY(r);
>                 if (NSMaxY(r) > ascender)
>                   ascender =3D NSMaxY(r);
>=20
>                 /* Check if attachment forces line height increase */
>                 if (wantNewLineHeight(ascender + descender, =
&line_height, max_line_height))
>                   goto restart;
>               }
>=20
>             /* Position attachment (note: r is upside-down relative to =
our coords) */
>             g->size =3D r.size;
>             g->pos.x =3D p.x + r.origin.x;
>             g->pos.y =3D p.y - r.origin.y;
>=20
>             p.x =3D g->pos.x + g->size.width;
> 	    g->nominal =3D NO;  // Attachments always have custom =
positioning
> 	  }
> 	else
> 	  {
>             /* STANDARD GLYPH: Just use cached advancement */
>             /* TODO: Kerning is commented out as a bottleneck - needs =
optimization */
> 	    last_p =3D g->pos =3D p;
> 	    p.x +=3D g->size.width;
> 	  }
>=20
> 	/* LINE BREAKING: Glyph didn't fit in current fragment */
> 	if (!doesGlyphFitInLine)
> 	  {
> 	    switch ([curParagraphStyle lineBreakMode])
> 	      {
> 	      default:
> 	      case NSLineBreakByCharWrapping:
>                 /* Break immediately before current glyph */
> 		lf->lastGlyphIndex =3D i;
> 		break;
>=20
> 	      case NSLineBreakByWordWrapping:
>                 /* Search backward for word boundary */
> 		lf->lastGlyphIndex =3D [self =
breakLineByWordWrappingBefore: cache_base + i] - cache_base;
> 		if (lf->lastGlyphIndex <=3D firstGlyphIndex)
> 		  {
>                     // No word boundary found - fall back to character =
wrapping
>                     lf->lastGlyphIndex =3D i;
>                   }
> 		break;
>=20
> 	      case NSLineBreakByTruncatingHead:
> 	      case NSLineBreakByTruncatingMiddle:
> 	      case NSLineBreakByTruncatingTail:
> 	      case NSLineBreakByClipping:
>                 /* CLIPPING/TRUNCATING: Hide overflowing glyphs */
> 		g->outside_line_frag =3D YES;
> 		while (1)
> 		  {
> 		    i++;
> 		    g++;
> 		    if (i >=3D cache_length)
> 		      {
> 			if (at_end)
> 			  {
> 			    newParagraph =3D NO;
> 			    i--;
> 			    break;
> 			  }
> 			[self _cacheGlyphs: cache_length + CACHE_STEP];
> 			if (i >=3D cache_length)
> 			  {
> 			    newParagraph =3D NO;
> 			    i--;
> 			    break;
> 			  }
> 			g =3D cache + i;
> 		      }
> 		    g->dont_show =3D YES;
> 		    g->pos =3D p;
>                     /* Stop at paragraph break */
> 		    if (g->g =3D=3D NSControlGlyph
> 			&& [[curTextStorage string]
> 			       characterAtIndex: g->char_index] =3D=3D =
0xa)
> 		      break;
> 		  }
> 		lf->lastGlyphIndex =3D i + 1;
> 		break;
> 	      }
>=20
>             /*
>              * SAFETY: Ensure at least one glyph per fragment.
>              * Prevents infinite loops when container is narrower than =
a single glyph.
>              */
> 	    if (lf->lastGlyphIndex <=3D firstGlyphIndex)
> 	      lf->lastGlyphIndex =3D i + 1;
>=20
>             /* Reset position for next line fragment */
> 	    last_p =3D p =3D NSMakePoint(0, 0);
> 	    i =3D lf->lastGlyphIndex;
> 	    g =3D cache + i;
> 	    lf->last_used =3D g[-1].pos.x + g[-1].size.width;
> 	    last_glyph =3D NSNullGlyph;
> 	    prev_had_non_nominal_width =3D NO;
>=20
>             /* Move to next line fragment or end line if exhausted */
> 	    lf++;
> 	    lfi++;
> 	    if (lfi =3D=3D line_frags_num)
> 	      {
> 		newParagraph =3D NO;
> 		break;
> 	      }
> 	    firstGlyphIndex =3D i;
> 	  }
> 	else
> 	  {
>             /* Glyph fit - advance to next */
> 	    last_glyph =3D g->g;
> 	    if (last_glyph =3D=3D GSAttachmentGlyph)
> 	      {
> 		last_glyph =3D NSNullGlyph;
> 		prev_had_non_nominal_width =3D YES;
> 	      }
> 	    else
> 	      {
> 		prev_had_non_nominal_width =3D NO;
> 	      }
> 	    i++;
> 	    g++;
> 	  }
>       }
>     /* END MAIN LAYOUT LOOP */
>=20
>     /* ALIGNMENT PASS: Apply paragraph alignment to positioned glyphs =
*/
>     if (lfi !=3D line_frags_num)
>       {
>         /* Line filled exactly - apply alignment */
> 	lf->lastGlyphIndex =3D i;
> 	lf->last_used =3D p.x;
>=20
> 	if ([curParagraphStyle alignment] =3D=3D NSRightTextAlignment)
> 	  [self rightAlignLine: line_frags : line_frags_num];
> 	else if ([curParagraphStyle alignment] =3D=3D =
NSCenterTextAlignment)
> 	  [self centerAlignLine: line_frags : line_frags_num];
>       }
>     else
>       {
>         /* Line broke early - check for justification or alignment */
> 	if ([curParagraphStyle lineBreakMode] =3D=3D =
NSLineBreakByWordWrapping &&
> 	    [curParagraphStyle alignment] =3D=3D =
NSJustifiedTextAlignment)
> 	  [self fullJustifyLine: line_frags : line_frags_num];
> 	else if ([curParagraphStyle alignment] =3D=3D =
NSRightTextAlignment)
> 	  [self rightAlignLine: line_frags : line_frags_num];
> 	else if ([curParagraphStyle alignment] =3D=3D =
NSCenterTextAlignment)
> 	  [self centerAlignLine: line_frags : line_frags_num];
>=20
> 	lfi--;
>       }
>=20
>     /* COMMIT LAYOUT TO LAYOUT MANAGER */
>     [curLayoutManager setTextContainer: curTextContainer
> 		      forGlyphRange: NSMakeRange(cache_base, i)];
>     curGlyphIndex =3D i + cache_base;
>    =20
>     {
>       line_frag_t *lf;
>       NSPoint p;
>       unsigned int lineFragCounter, lineFragCounter2;
>       glyph_cache_t *g;
>       NSRect used_rect;
>=20
>       /* Final baseline calculation */
>       baseline =3D line_height - descender;
>=20
>       /* Iterate through line fragments and register each with layout =
manager */
>       for (lf =3D line_frags, lineFragCounter =3D 0, g =3D cache; lfi =
>=3D 0; lfi--, lf++)
> 	{
>           /* Calculate used rect (actual ink bounds) vs fragment rect =
(available space) */
> 	  used_rect.origin.x =3D g->pos.x + lf->rect.origin.x;
> 	  used_rect.size.width =3D lf->last_used - g->pos.x;
> 	  used_rect.origin.y =3D lf->rect.origin.y;
> 	  used_rect.size.height =3D lf->rect.size.height;
>=20
>           /* Register the line fragment */
> 	  [curLayoutManager setLineFragmentRect: lf->rect
> 			    forGlyphRange: NSMakeRange(cache_base + =
lineFragCounter, lf->lastGlyphIndex - lineFragCounter)
> 			    usedRect: used_rect];
>          =20
>           /* Register individual glyph positions */
> 	  p =3D g->pos;
> 	  p.y +=3D baseline;  // Convert from relative to absolute =
position
> 	  lineFragCounter2 =3D lineFragCounter;
> 	  while (lineFragCounter < lf->lastGlyphIndex)
> 	    {
>               /* Set flags for special glyph handling */
> 	      if (g->outside_line_frag)
> 		{
> 		  [curLayoutManager setDrawsOutsideLineFragment: YES
> 		    forGlyphAtIndex: cache_base + lineFragCounter];
> 		}
> 	      if (g->dont_show)
> 		{
> 		  [curLayoutManager setNotShownAttribute: YES
> 					 forGlyphAtIndex: cache_base + =
lineFragCounter];
> 		}
>              =20
>               /* Register glyph runs with non-nominal positioning */
> 	      if (!g->nominal && lineFragCounter !=3D lineFragCounter2)
> 		{
> 		  [curLayoutManager setLocation: p
> 				    forStartOfGlyphRange: =
NSMakeRange(cache_base + lineFragCounter2, lineFragCounter - =
lineFragCounter2)];
> 		  if (g[-1].g =3D=3D GSAttachmentGlyph)
> 		    {
> 		      [curLayoutManager setAttachmentSize: g[-1].size
> 			forGlyphRange: NSMakeRange(cache_base + =
lineFragCounter2, lineFragCounter - lineFragCounter2)];
> 		    }
> 		  p =3D g->pos;
> 		  p.y +=3D baseline;
> 		  lineFragCounter2 =3D lineFragCounter;
> 		}
> 	      lineFragCounter++;
> 	      g++;
> 	    }
>           /* Register final run in fragment */
> 	  if (lineFragCounter !=3D lineFragCounter2)
> 	    {
> 	      [curLayoutManager setLocation: p
> 				forStartOfGlyphRange: =
NSMakeRange(cache_base + lineFragCounter2, lineFragCounter - =
lineFragCounter2)];
> 	      if (g[-1].g =3D=3D GSAttachmentGlyph)
> 		{
> 		  [curLayoutManager setAttachmentSize: g[-1].size
> 		    forGlyphRange: NSMakeRange(cache_base + =
lineFragCounter2, lineFragCounter - lineFragCounter2)];
> 		}
> 	    }
> 	}
>     }
>   }
>=20
>   /* Advance current point to next line */
>   curPoint =3D NSMakePoint(0, NSMaxY(line_frags->rect));
>=20
>   if (newParagraph)
>     return 3;
>   else
>     return 0;
> }
>=20
>=20
> /*
>  * MAIN ENTRY POINT
>  * Lays out multiple lines of glyphs into the text container.
>  *
>  * Parameters:
>  *   layoutManager:         The GSLayoutManager managing this text
>  *   textContainer:         The container defining layout geometry
>  *   glyphIndex:            Starting glyph index for this layout =
operation
>  *   previousLineFragRect:  Rectangle of the previous line (for =
positioning)
>  *   nextGlyphIndex:        OUTPUT - index of first unlaid glyph
>  *   howMany:               Maximum number of lines to layout (0 =3D =
unlimited)
>  *
>  * Return values:
>  *   0 - Layout completed successfully (more glyphs may remain)
>  *   1 - Text container is full
>  *   2 - All glyphs have been laid out
>  */
> -(int) layoutGlyphsInLayoutManager: (GSLayoutManager *)layoutManager
> 		   inTextContainer: (NSTextContainer *)textContainer
> 	      startingAtGlyphIndex: (unsigned int)glyphIndex
> 	  previousLineFragmentRect: (NSRect)previousLineFragRect
> 		    nextGlyphIndex: (unsigned int *)nextGlyphIndex
> 	     numberOfLineFragments: (unsigned int)howMany
> {
>   int ret, real_ret;
>   BOOL newParagraph;
>=20
>   /* REENTRANCY HANDLING */
>   if (![lock tryLock])
>     {
>       /* Already in use - create temporary instance to handle nested =
call */
>       GSHorizontalTypesetter *temp;
>=20
>       temp =3D [[object_getClass(self) alloc] init];
>       ret =3D [temp layoutGlyphsInLayoutManager: layoutManager
> 			      inTextContainer: textContainer
> 			 startingAtGlyphIndex: glyphIndex
> 		     previousLineFragmentRect: previousLineFragRect
> 			       nextGlyphIndex: nextGlyphIndex
> 			numberOfLineFragments: howMany];
>       DESTROY(temp);
>       return ret;
>     }
>=20
> NS_DURING
>   /* Initialize layout context */
>   curLayoutManager =3D layoutManager;
>   curTextContainer =3D textContainer;
>   curTextStorage =3D [layoutManager textStorage];
>   curGlyphIndex =3D glyphIndex;
>=20
>   [self _cacheClear];
>=20
>   real_ret =3D 4;  // Initial state forces paragraph check
>   curPoint =3D NSMakePoint(0, NSMaxY(previousLineFragRect));
>  =20
>   /* Main layout loop - process lines until limit or completion */
>   while (1)
>     {
>       /* Determine if we're starting a new paragraph */
>       if (real_ret =3D=3D 4)
> 	{
> 	  if (!curGlyphIndex)
> 	    {
> 	      newParagraph =3D YES;  // Very first glyph in text
> 	    }
> 	  else
> 	    {
>               /* Check if previous character was a newline */
> 	      unsigned int chi;
> 	      unichar ch;
> 	      chi =3D [curLayoutManager characterRangeForGlyphRange: =
NSMakeRange(curGlyphIndex - 1, 1)
> 						 actualGlyphRange: =
NULL].location;
> 	      ch =3D [[curTextStorage string] characterAtIndex: chi];
> =09
> 	      if (ch =3D=3D '\n')
> 		newParagraph =3D YES;
> 	      else
> 		newParagraph =3D NO;
> 	    }
> 	}
>       else if (real_ret =3D=3D 3)
> 	{
> 	  newParagraph =3D YES;  // Previous line ended with newline
> 	}
>       else
> 	{
> 	  newParagraph =3D NO;
> 	}
>=20
>       /* Layout one line */
>       ret =3D [self layoutLineNewParagraph: newParagraph];
>=20
>       /* Normalize return codes 3 and 4 to 0 for loop control */
>       real_ret =3D ret;
>       if (ret =3D=3D 3 || ret =3D=3D 4)
> 	ret =3D 0;
>=20
>       if (ret)
> 	break;  // Error or completion (1 or 2)
>=20
>       if (howMany)
> 	if (!--howMany)
> 	  break;  // Reached line limit
>    }
>=20
>   *nextGlyphIndex =3D curGlyphIndex;
> NS_HANDLER
>   /* Exception handling: log, unlock, and re-raise */
>   NSLog(@"GSHorizontalTypesetter - %@", [localException reason]);
>   [lock unlock];
>   [localException raise];
>   ret=3D0; /* Unreachable, but silences compiler warnings */
> NS_ENDHANDLER
>  =20
>   [lock unlock];
>   return ret;
> }
>=20
> @end
> ```
>=20
> ## Summary
>=20
> This is a sophisticated horizontal typesetter for GNUstep implementing =
the full Cocoa text layout architecture. Key features include:
>=20
> **Architecture:**
> - **Thread-local singleton** pattern for performance without locking =
overhead
> - **Reentrancy support** via temporary instance creation when nested =
calls occur
> - **Two-phase caching**: First cache glyph attributes, then compute =
positions
>=20
> **Layout Algorithm:**
> 1. **Soft invalidation** check for incremental layout reuse
> 2. **Line fragment acquisition** from text container (handles complex =
shapes)
> 3. **Glyph-by-glyph positioning** with font changes, attachments, tabs
> 4. **Line breaking** by character or word (with CJK support)
> 5. **Alignment/justification** pass to distribute space
> 6. **Commit** to layout manager with precise glyph ranges and =
positions
>=20
> **Performance Optimizations:**
> - Aggressive caching of glyph metrics and attributes
> - Batch glyph processing with expandable buffers
> - Inline helper functions for hot paths
> - Memmove for cache window sliding rather than refetching
>=20
> The code handles complex typography including bidirectional text =
support preparation, text attachments, multiple line fragments per line, =
and all standard paragraph alignments.
>=20
>=20
> =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=
=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=
=94=20
>=20
>=20
> Then I asked:
>=20
>=20
> =E2=80=9EWhat refactorings do you propose to make that above code you =
commented better readable and simpler to comprehend without making it =
worse?=E2=80=9C
>=20
>=20
> =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=
=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=
=94=20
>=20
>=20
> I'll analyze this code and propose concrete refactorings to improve =
readability and maintainability. Let me work through this =
systematically.
>=20
> ## Proposed Refactorings for GSHorizontalTypesetter
>=20
> ### 1. **Extract Magic Numbers and Character Constants**
>=20
> Replace hardcoded hex values with named constants:
>=20
> ```objc
> // Add to top of file or private header
> static const unichar kSpaceCharacter =3D 0x20;
> static const unichar kNewlineCharacter =3D 0x0a;
> static const unichar kCarriageReturnCharacter =3D 0x0d;
> static const unichar kTabCharacter =3D 0x09;
> static const unichar kCJKRangeStart =3D 0x2ff0;
> static const unichar kCJKRangeEnd =3D 0x9fff;
> static const CGFloat kDefaultTabInterval =3D 100.0;
> static const CGFloat kFallbackLineHeight =3D 15.0;
> static const CGFloat kExtraLineFragmentWidth =3D 1.0;
> ```
>=20
> ### 2. **Extract Complex Conditionals into Meaningful Boolean =
Methods**
>=20
> The glyph fitting check appears multiple times and is hard to read:
>=20
> ```objc
> // BEFORE: scattered throughout code
> doesGlyphFitInLine =3D !((i > firstGlyphIndex) && (p.x + g->size.width =
> lf->rect.size.width));
>=20
> // AFTER: extracted method
> - (BOOL)doesGlyphAtIndex:(unsigned int)glyphIndex=20
>            withWidth:(CGFloat)width=20
>            fitInLineFragment:(line_frag_t *)fragment
>            afterFirstGlyph:(unsigned int)firstIndex
> {
>     if (glyphIndex <=3D firstIndex) return YES;  // First glyph always =
fits
>     return (p.x + width <=3D fragment->rect.size.width);
> }
> ```
>=20
> ### 3. **Replace `goto restart` with Structured Loop**
>=20
> The `restart` label for line height recalculation is a classic goto =
pattern:
>=20
> ```objc
> // BEFORE: goto-based restart
> restart: ;
> do {
>     // ... calculate fragments ...
>     if (line_frags_num =3D=3D 0) {
>         if (/* emergency shrink */) {
>             line_height =3D ...;
>             continue;  // or goto restart
>         }
>         return 1;
>     }
> } while (line_frags_num =3D=3D 0);
>=20
> // ... later ...
> if (wantNewLineHeight(...)) goto restart;
>=20
> // AFTER: extracted method with explicit loop
> - (BOOL)_acquireLineFragmentsWithHeight:(CGFloat)lineHeight
>                           maxLineHeight:(CGFloat)maxLineHeight
>                             newParagraph:(BOOL)newParagraph
>                            resultingHeight:(CGFloat *)outHeight
> {
>     CGFloat currentHeight =3D lineHeight;
>     CGFloat maxHeight =3D maxLineHeight;
>    =20
>     while (YES) {
>         [self _buildLineFragmentsForHeight:currentHeight =
newParagraph:newParagraph];
>        =20
>         if (line_frags_num > 0) {
>             *outHeight =3D currentHeight;
>             return YES;  // Success
>         }
>        =20
>         // Emergency: container too small for even one line
>         if (curPoint.y =3D=3D 0.0 && currentHeight > containerHeight =
&& containerHeight > 0.0) {
>             currentHeight =3D containerHeight;
>             maxHeight =3D currentHeight;
>             continue;  // Retry with shrunk height
>         }
>        =20
>         return NO;  // No room in container
>     }
> }
>=20
> // Then in main layout, replace goto with:
> while (![self _updateLineHeightIfNeeded:ascender descender:descender=20=

>                          currentHeight:&line_height=20
>                            maxHeight:max_line_height]) {
>     // Restart layout with new height
>     if (![self _acquireLineFragmentsWithHeight:line_height ...]) {
>         return 1;
>     }
>     // Re-initialize cache if needed
> }
> ```
>=20
> ### 4. **Extract State Machine Transitions**
>=20
> The `real_ret` state machine in `layoutGlyphsInLayoutManager:` is =
cryptic:
>=20
> ```objc
> // BEFORE: confusing state tracking
> real_ret =3D 4;
> while (1) {
>     if (real_ret =3D=3D 4) {
>         // determine newParagraph
>     } else if (real_ret =3D=3D 3) {
>         newParagraph =3D YES;
>     } else {
>         newParagraph =3D NO;
>     }
>     ret =3D [self layoutLineNewParagraph:newParagraph];
>     real_ret =3D ret;
>     if (ret =3D=3D 3 || ret =3D=3D 4) ret =3D 0;
> }
>=20
> // AFTER: explicit state enum and transition method
> typedef NS_ENUM(NSInteger, LayoutState) {
>     LayoutStateInitial =3D 0,      // Need to check if new paragraph
>     LayoutStateNewParagraph,     // Previous line ended with newline
>     LayoutStateContinuing,       // In middle of paragraph
>     LayoutStateComplete,         // All glyphs laid out
>     LayoutStateNoRoom            // Container full
> };
>=20
> - (LayoutState)determineNextStateFrom:(LayoutState)previousState=20
>                         lineResult:(int)lineResult
> {
>     switch (lineResult) {
>         case 2: return LayoutStateComplete;   // At end
>         case 1: return LayoutStateNoRoom;     // No room
>         case 3: return LayoutStateNewParagraph; // Ended with newline
>         case 0: return LayoutStateContinuing;  // Normal line break
>         case 4: return LayoutStateInitial;   // Ambiguous, need check
>         default: return LayoutStateComplete;
>     }
> }
>=20
> - (BOOL)isNewParagraphForState:(LayoutState)state=20
>                   atGlyphIndex:(unsigned int)glyphIndex
> {
>     switch (state) {
>         case LayoutStateInitial:
>             return [self _glyphStartsNewParagraph:glyphIndex];
>         case LayoutStateNewParagraph:
>             return YES;
>         case LayoutStateContinuing:
>             return NO;
>         default:
>             return NO;
>     }
> }
> ```
>=20
> ### 5. **Break Up `layoutLineNewParagraph:` into Phased Methods**
>=20
> This 400+ line method does too much. Extract phases:
>=20
> ```objc
> - (int)layoutLineNewParagraph:(BOOL)newParagraph
> {
>     // Phase 1: Setup and cache initialization
>     if (![self _prepareLayoutForNewParagraph:newParagraph]) {
>         return [self _handleEndOfTextOrContainer];
>     }
>    =20
>     // Phase 2: Acquire line fragments (may restart if metrics change)
>     CGFloat finalLineHeight;
>     if (![self _acquireLineFragmentsWithHeight:initialLineHeight=20
>                                   maxLineHeight:maxLineHeight
>                                    newParagraph:newParagraph
>                                   resultingHeight:&finalLineHeight]) {
>         return 1; // No room
>     }
>    =20
>     // Phase 3: Position glyphs in fragments
>     LayoutLineResult *result =3D [self _positionGlyphsInFragments];
>     if (result.needsRestart) {
>         // Recursively retry with new height (limited depth to prevent =
infinite loop)
>         return [self layoutLineNewParagraph:newParagraph];
>     }
>    =20
>     // Phase 4: Apply alignment
>     [self _applyAlignmentToLine:result];
>    =20
>     // Phase 5: Commit to layout manager
>     [self _commitLayoutResult:result lineHeight:finalLineHeight];
>    =20
>     return result.endedWithNewline ? 3 : 0;
> }
> ```
>=20
> ### 6. **Replace Anonymous Structs with Named Types**
>=20
> ```objc
> // BEFORE: anonymous struct in ivars
> struct {
>     BOOL explicit_kern;
>     float kern;
>     float baseline_offset;
>     int superscript;
> } attributes;
>=20
> // AFTER: named type with documentation
> /**
>  * GSScriptAttributes collects the typographic attributes that affect
>  * glyph positioning relative to the baseline.
>  */
> typedef struct {
>     BOOL hasExplicitKern;      // YES if NSKernAttributeName was =
specified
>     CGFloat kernAmount;        // Additional spacing between glyphs
>     CGFloat baselineOffset;    // Vertical shift from normal baseline =
(positive =3D up)
>     NSInteger superscriptLevel; // 0 =3D normal, +1 =3D superscript, =
-1 =3D subscript
> } GSScriptAttributes;
>=20
> // Usage in class becomes:
> GSScriptAttributes _currentScriptAttributes;
> ```
>=20
> ### 7. **Extract Cache Management to Dedicated Class**
>=20
> The cache manipulation is complex and scattered:
>=20
> ```objc
> // New class: GSGlyphCache
> @interface GSGlyphCache : NSObject
> @property (readonly) NSUInteger baseIndex;
> @property (readonly) NSUInteger count;
> @property (readonly) BOOL atEnd;
>=20
> - (void)repositionToGlyphIndex:(NSUInteger)index=20
>                 layoutManager:(GSLayoutManager *)lm;
> - (void)ensureCount:(NSUInteger)count=20
>      layoutManager:(GSLayoutManager *)lm;
> - (glyph_cache_t *)glyphAtIndex:(NSUInteger)index;  // Relative to =
base
> - (void)slideWindowToIndex:(NSUInteger)index;
> @end
> ```
>=20
> ### 8. **Replace C Arrays with NSMutableArray or Smart Pointer**
>=20
> The manual `realloc` management is error-prone:
>=20
> ```objc
> // BEFORE: manual C array management
> if (line_frags_num > line_frags_size) {
>     line_frags_size +=3D 2;
>     line_frags =3D realloc(line_frags, sizeof(line_frag_t) * =
line_frags_size);
> }
>=20
> // AFTER: use NSMutableArray with wrapper object, or at least:
> typedef struct {
>     line_frag_t *items;
>     NSUInteger count;
>     NSUInteger capacity;
> } GSLineFragmentArray;
>=20
> static inline void GSLineFragmentArrayPush(GSLineFragmentArray *array) =
{
>     if (array->count >=3D array->capacity) {
>         array->capacity =3D array->capacity ? array->capacity * 2 : 4;
>         array->items =3D realloc(array->items, sizeof(line_frag_t) * =
array->capacity);
>     }
>     array->count++;
> }
> ```
>=20
> ### 9. **Document Return Value Semantics with Enum**
>=20
> ```objc
> // BEFORE: magic integer returns
> -(int) layoutLineNewParagraph: (BOOL)newParagraph  // Returns 0, 1, 2, =
3, or 4
>=20
> // AFTER: explicit result type
> typedef NS_ENUM(NSInteger, GSLayoutLineResult) {
>     GSLayoutLineResultContinuing =3D 0,      // Line complete, more =
glyphs in paragraph
>     GSLayoutLineResultNoRoom =3D 1,          // Text container =
exhausted
>     GSLayoutLineResultEndOfText =3D 2,       // All glyphs consumed
>     GSLayoutLineResultNewParagraph =3D 3,    // Line ended with =
newline
>     GSLayoutLineResultNeedParagraphCheck =3D 4 // Ambiguous, caller =
must check
> };
>=20
> - (GSLayoutLineResult)layoutLineNewParagraph:(BOOL)newParagraph;
> ```
>=20
> ### 10. **Flatten Nested Conditionals in Main Loop**
>=20
> The main glyph loop has deeply nested conditions. Extract handlers:
>=20
> ```objc
> - (BOOL)_handleControlGlyph:(glyph_cache_t *)glyph=20
>                  atPosition:(NSPoint *)position
>               lineFragment:(line_frag_t *)fragment
>               newParagraph:(BOOL *)outNewParagraph
> {
>     unichar ch =3D [[curTextStorage string] =
characterAtIndex:glyph->char_index];
>    =20
>     glyph->pos =3D *position;
>     glyph->size.width =3D 0;
>     glyph->dont_show =3D YES;
>    =20
>     switch (ch) {
>         case kNewlineCharacter:
>             *outNewParagraph =3D YES;
>             return NO;  // Stop processing this line
>            =20
>         case kTabCharacter:
>             *position =3D [self _positionAfterTabFrom:*position =
inFragment:fragment];
>             return YES;  // Continue to next glyph
>            =20
>         default:
>             NSDebugLLog(@"GSHorizontalTypesetter", @"Unknown control =
%04x", ch);
>             return YES;
>     }
> }
>=20
> - (BOOL)_handleAttachmentGlyph:(glyph_cache_t *)glyph=20
>                     atPosition:(NSPoint *)position
>                  lineFragment:(line_frag_t *)fragment
>                    lineHeight:(CGFloat *)lineHeight
> {
>     // Extract attachment logic...
>     // Return YES if fits and metrics updated, NO if needs line break
> }
> ```
>=20
> ### 11. **Extract Metric Calculation to Dedicated Method**
>=20
> ```objc
> - (void)_updateLineMetricsForGlyph:(glyph_cache_t *)glyph
>                     currentAscender:(CGFloat *)ascender
>                    currentDescender:(CGFloat *)descender
>                        currentHeight:(CGFloat *)lineHeight
>                         maxLineHeight:(CGFloat)maxHeight
> {
>     NSFont *font =3D glyph->font;
>     CGFloat glyphAscender =3D [font ascender];
>     CGFloat glyphDescender =3D -[font descender];
>    =20
>     // Apply superscript adjustments
>     CGFloat yOffset =3D 0;
>     if (glyph->attributes.superscript) {
>         yOffset -=3D glyph->attributes.superscript * [font xHeight];
>     }
>     if (glyph->attributes.baseline_offset) {
>         yOffset +=3D glyph->attributes.baseline_offset;
>     }
>    =20
>     // Update metrics
>     *ascender =3D MAX(*ascender, glyphAscender - MIN(yOffset, 0));
>     *descender =3D MAX(*descender, glyphDescender + MAX(yOffset, 0));
>    =20
>     CGFloat newHeight =3D *ascender + *descender;
>     if (maxHeight > 0) {
>         newHeight =3D MIN(newHeight, maxHeight);
>     }
>     *lineHeight =3D MAX(*lineHeight, newHeight);
> }
> ```
>=20
> ### 12. **Simplify Soft Invalidation Logic**
>=20
> The soft invalidation method is hard to follow. Restructure with early =
returns and clear phases:
>=20
> ```objc
> - (BOOL)_reuseSoftInvalidatedLayout
> {
>     // Quick reject: not at soft invalidation point
>     if (![self _isAtSoftInvalidationPoint]) return NO;
>    =20
>     // Quick reject: won't fit vertically
>     NSRect firstRect =3D [self _firstSoftInvalidatedRect];
>     if (![self _canFitVertically:firstRect]) return NO;
>    =20
>     // Collect consecutive valid fragments
>     GSSoftInvalidationBatch *batch =3D [self =
_collectSoftInvalidatedFragments];
>     if (batch.isEmpty) return NO;
>    =20
>     // Apply shift and commit
>     [self _applySoftInvalidationBatch:batch];
>     curGlyphIndex =3D batch.endGlyphIndex;
>     return YES;
> }
> ```
>=20
> ---
>=20
> ## Summary Table
>=20
> | Refactoring | Benefit | Effort |
> |-------------|---------|--------|
> | Named constants | Eliminates magic numbers, self-documenting | Low |
> | Boolean methods | Clarifies intent of complex conditions | Low |
> | Replace goto | Structured flow, easier debugging | Medium |
> | State machine enum | Explicit transitions, type safety | Medium |
> | Method extraction | Single responsibility, testable units | Medium |
> | Named structs | Self-documenting, IDE completion | Low |
> | Cache class | Encapsulation, easier optimization | High |
> | Array abstraction | Memory safety, bounds checking | Medium |
> | Return value enum | Compiler checking, clear semantics | Low |
> | Glyph handlers | Flatten nesting, isolate concerns | Medium |
> | Metric extraction | Reusable, testable calculations | Low |
> | Soft invalidation phases | Linear flow, early exits | Medium |
>=20
> These changes maintain performance (critical for text layout) while =
significantly improving maintainability. The most impactful would be =
**#5 (method extraction)** and **#3 (goto elimination)**, which together =
would reduce the cognitive load of understanding the layout algorithm.
>=20
>=20
> =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=
=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=
=94=20
>=20
>=20
> I see you read until here. I know, that was a lot to digest. Now I am =
asking: what do you think about this? Does it make sense? Should we do =
those refactorings?
>=20
>=20
> Kind regards,
>=20
> 	Lars


--Apple-Mail=_E574689C-527D-4D09-9378-02F1A9847500
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html;
	charset=utf-8

<html><head><meta http-equiv=3D"content-type" content=3D"text/html; =
charset=3Dutf-8"></head><body style=3D"overflow-wrap: break-word; =
-webkit-nbsp-mode: space; line-break: after-white-space;">For better =
readability please have a look at:<div><br></div><div><a =
href=3D"https://github.com/gnustep/libs-gui/issues/382#issuecomment-406401=
2492">https://github.com/gnustep/libs-gui/issues/382#issuecomment-40640124=
92</a></div><div><br></div><div>Kind =
regards,</div><div><br></div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>Lars<br =
id=3D"lineBreakAtBeginningOfMessage"><div><br><blockquote =
type=3D"cite"><div>Am 15.03.2026 um 03:23 schrieb =
[email protected] via Developers list for GNUstep, the =
GNU groupware evironment &lt;[email protected]&gt;:</div><br =
class=3D"Apple-interchange-newline"><div><meta http-equiv=3D"content-type"=
 content=3D"text/html; charset=3Dutf-8"><div style=3D"overflow-wrap: =
break-word; -webkit-nbsp-mode: space; line-break: =
after-white-space;"><div>Hi =
GNUstep-Devs,</div><div><br></div><div><br></div><div>especially =
Riccardo, Fred and Greg since we were talking about this in the call =
today.</div><div><br></div><div><br></div><div>I had the idea to let a =
Coding AI, in this case&nbsp;<a =
href=3D"https://www.kimi.com/">https://www.kimi.com/</a>&nbsp;analyze =
our GSHorizontalTypesetter code and =E2=80=9Eexplain=E2=80=9C it inside =
comments added to the code.</div><div><br></div><div>So I asked it the =
following =
question:</div><div><br></div><div><br></div><div><div>=E2=80=9EHello =
KIMI, please analyze the following code and explain it in comments you =
add or correct:=E2=80=9C</div><div><br></div><div><br></div><div>and =
then gave it both the header and the =
implementation.</div><div><br></div></div><div><br></div><div>Here is =
the answer (The answer seems to be in Markup-Format so maybe you cut and =
paste it into some markup editor for better =
readability):</div><div><br></div><div>=E2=80=94=E2=80=94 =E2=80=94=E2=80=94=
 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94=
 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94&nbsp;</div><div><br></div><div>&nbs=
p;I'll analyze this GNUstep GUI Library code and add comprehensive =
comments explaining the functionality. Let me go through both the header =
and implementation =
files.</div><div><br></div><div>```objc</div><div>/*</div><div>&nbsp; =
&nbsp;GSHorizontalTypesetter.h</div><div><br></div><div>&nbsp; =
&nbsp;Copyright (C) 2002 Free Software Foundation, =
Inc.</div><div><br></div><div>&nbsp; &nbsp;Author: Alexander Malmberg =
&lt;[email protected]&gt;</div><div>&nbsp; &nbsp;Date: =
2002</div><div><br></div><div>&nbsp; &nbsp;This file is part of the =
GNUstep GUI Library.</div><div><br></div><div>&nbsp; &nbsp;This library =
is free software; you can redistribute it and/or</div><div>&nbsp; =
&nbsp;modify it under the terms of the GNU Lesser General =
Public</div><div>&nbsp; &nbsp;License as published by the Free Software =
Foundation; either</div><div>&nbsp; &nbsp;version 2 of the License, or =
(at your option) any later version.</div><div><br></div><div>&nbsp; =
&nbsp;This library is distributed in the hope that it will be =
useful,</div><div>&nbsp; &nbsp;but WITHOUT ANY WARRANTY; without even =
the implied warranty of</div><div>&nbsp; &nbsp;MERCHANTABILITY or =
FITNESS FOR A PARTICULAR PURPOSE.<span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> See the GNU</div><div>&nbsp; =
&nbsp;Lesser General Public License for more =
details.</div><div><br></div><div>&nbsp; &nbsp;You should have received =
a copy of the GNU Lesser General Public</div><div>&nbsp; &nbsp;License =
along with this library; see the file COPYING.LIB.</div><div>&nbsp; =
&nbsp;If not, see &lt;http://www.gnu.org/licenses/ &gt; or write to =
the&nbsp;</div><div>&nbsp; &nbsp;Free Software Foundation, 51 Franklin =
Street, Fifth Floor,&nbsp;</div><div>&nbsp; &nbsp;Boston, MA 02110-1301, =
USA.</div><div>*/</div><div><br></div><div>#ifndef =
_GNUstep_H_GSHorizontalTypesetter</div><div>#define =
_GNUstep_H_GSHorizontalTypesetter</div><div><br></div><div>#import =
&lt;GNUstepGUI/GSTypesetter.h&gt;</div><div><br></div><div>@class =
NSLock;</div><div>@class GSLayoutManager, NSTextContainer, =
NSTextStorage;</div><div>@class NSDictionary;</div><div>@class =
NSParagraphStyle, NSFont;</div><div><br></div><div>/*</div><div>&nbsp;* =
APPKIT_EXPORT_CLASS marks this class for export from the AppKit =
framework.</div><div>&nbsp;* This is a GNUstep-specific macro for =
DLL/shared library symbol =
visibility.</div><div>&nbsp;*/</div><div>APPKIT_EXPORT_CLASS</div><div><br=
></div><div>/*</div><div>&nbsp;* GSHorizontalTypesetter is the concrete =
typesetter implementation for</div><div>&nbsp;* horizontal text layout =
in GNUstep. It handles the complex task of laying out</div><div>&nbsp;* =
glyphs into lines within text containers, supporting various paragraph =
styles,</div><div>&nbsp;* alignments, line breaking modes, and text =
attributes.</div><div>&nbsp;*</div><div>&nbsp;* This class implements =
the core text layout algorithm that converts a stream</div><div>&nbsp;* =
of glyphs from the layout manager into positioned line fragments =
within</div><div>&nbsp;* the geometric constraints of text =
containers.</div><div>&nbsp;*/</div><div>@interface =
GSHorizontalTypesetter : GSTypesetter</div><div>{</div><div>&nbsp; =
/*</div><div>&nbsp; &nbsp;* REENTRANCY LOCK</div><div>&nbsp; &nbsp;* =
Since this is typically a shared singleton instance, the lock =
ensures</div><div>&nbsp; &nbsp;* thread safety. If the typesetter is =
already in use when another layout</div><div>&nbsp; &nbsp;* request =
comes in, a temporary instance is created instead.</div><div>&nbsp; =
&nbsp;*/</div><div>&nbsp; NSLock *lock;</div><div><br></div><div>&nbsp; =
/*</div><div>&nbsp; &nbsp;* CURRENT LAYOUT CONTEXT</div><div>&nbsp; =
&nbsp;* These ivars track the active text system objects being =
processed.</div><div>&nbsp; &nbsp;* They are set at the beginning of =
each layout operation and remain</div><div>&nbsp; &nbsp;* constant =
throughout that operation.</div><div>&nbsp; &nbsp;*/</div><div>&nbsp; =
GSLayoutManager *curLayoutManager; &nbsp; &nbsp;// Converts characters =
to glyphs, tracks runs</div><div>&nbsp; NSTextContainer =
*curTextContainer; &nbsp; &nbsp;// Defines geometric bounds for =
text</div><div>&nbsp; NSTextStorage *curTextStorage; &nbsp; &nbsp; =
&nbsp; &nbsp;// The attributed string being laid =
out</div><div><br></div><div>&nbsp; unsigned int curGlyphIndex; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; // Current position in the glyph =
stream</div><div>&nbsp; NSPoint curPoint; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Current layout position (y =
advances per line)</div><div><br></div><div>&nbsp; /*</div><div>&nbsp; =
&nbsp;* ATTRIBUTE CACHING</div><div>&nbsp; &nbsp;* These ivars cache the =
current paragraph style and attributes to avoid</div><div>&nbsp; &nbsp;* =
repeated dictionary lookups. The ranges track the validity of each =
cache.</div><div>&nbsp; &nbsp;*/</div><div>&nbsp; NSParagraphStyle =
*curParagraphStyle; &nbsp;// Current paragraph's formatting =
rules</div><div>&nbsp; NSRange paragraphRange; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; // Character range where curParagraphStyle =
is valid</div><div><br></div><div>&nbsp; NSDictionary *curAttributes; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Current character attributes =
dictionary</div><div>&nbsp; NSRange attributeRange; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; // Character range where curAttributes is =
valid</div><div>&nbsp;&nbsp;</div><div>&nbsp; /*</div><div>&nbsp; =
&nbsp;* DECOMPOSED ATTRIBUTES</div><div>&nbsp; &nbsp;* Frequently =
accessed attributes are extracted from the dictionary =
and</div><div>&nbsp; &nbsp;* stored in this struct for faster access =
during the tight layout loop.</div><div>&nbsp; &nbsp;*/</div><div>&nbsp; =
struct</div><div>&nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; BOOL =
explicit_kern; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // YES =
if NSKernAttributeName is present</div><div>&nbsp; &nbsp; &nbsp; float =
kern; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; // Kerning adjustment value</div><div>&nbsp; &nbsp; &nbsp; =
float baseline_offset; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// =
Vertical offset from baseline</div><div>&nbsp; &nbsp; &nbsp; int =
superscript; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;// Superscript level (+1, -1, etc.)</div><div>&nbsp; &nbsp; } =
attributes;</div><div><br></div><div>&nbsp; NSFont *curFont; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// =
Current font for glyph metrics</div><div>&nbsp; NSRange fontRange; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// =
Glyph range where curFont is valid</div><div><br></div><div>&nbsp; =
/*</div><div>&nbsp; &nbsp;* GLYPH CACHE</div><div>&nbsp; &nbsp;* A =
resizable array of glyph_cache_t structures that stores =
pre-computed</div><div>&nbsp; &nbsp;* information about glyphs to avoid =
repeated calculations. This is the</div><div>&nbsp; &nbsp;* primary =
optimization for the layout engine.</div><div>&nbsp; =
&nbsp;*</div><div>&nbsp; &nbsp;* cache_base: &nbsp; The glyph index in =
the layout manager that corresponds</div><div>&nbsp; &nbsp;* &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; to cache[0]. All cache indices =
are relative to this.</div><div>&nbsp; &nbsp;* cache_size: &nbsp; =
Allocated capacity of the cache array (in elements)</div><div>&nbsp; =
&nbsp;* cache_length: Number of valid entries currently in the =
cache</div><div>&nbsp; &nbsp;* at_end: &nbsp; &nbsp; &nbsp; YES when =
we've cached all glyphs in the text storage</div><div>&nbsp; =
&nbsp;*/</div><div>&nbsp; struct GSHorizontalTypesetter_glyph_cache_s =
*cache;</div><div>&nbsp; unsigned int cache_base, cache_size, =
cache_length;</div><div>&nbsp; BOOL =
at_end;</div><div><br></div><div>&nbsp; /*</div><div>&nbsp; &nbsp;* LINE =
FRAGMENT ARRAY</div><div>&nbsp; &nbsp;* During layout of a single line, =
this array stores the line fragment</div><div>&nbsp; &nbsp;* rectangles =
returned by the text container. A line may consist of</div><div>&nbsp; =
&nbsp;* multiple fragments when flowing around exclusions or =
shapes.</div><div>&nbsp; &nbsp;*</div><div>&nbsp; &nbsp;* line_frags: =
&nbsp; &nbsp; &nbsp;Array of line_frag_t structures</div><div>&nbsp; =
&nbsp;* line_frags_num: &nbsp;Number of fragments in current =
line</div><div>&nbsp; &nbsp;* line_frags_size: Allocated capacity of the =
array</div><div>&nbsp; &nbsp;*/</div><div>&nbsp; struct =
GSHorizontalTypesetter_line_frag_s *line_frags;</div><div>&nbsp; int =
line_frags_num, =
line_frags_size;</div><div>}</div><div><br></div><div>/*</div><div>&nbsp;*=
 Returns the shared thread-local instance of the =
typesetter.</div><div>&nbsp;* Each thread maintains its own instance in =
the thread dictionary</div><div>&nbsp;* to avoid cross-thread contention =
while still allowing =
reuse.</div><div>&nbsp;*/</div><div>+(GSHorizontalTypesetter *) =
sharedInstance;</div><div><br></div><div>@end</div><div><br></div><div>#en=
dif</div><div>```</div><div><br></div><div>Now for the implementation =
file with detailed =
comments:</div><div><br></div><div>```objc</div><div>/*</div><div>&nbsp; =
&nbsp;GSHorizontalTypesetter.m</div><div><br></div><div>&nbsp; =
&nbsp;Copyright (C) 2002, 2003 Free Software Foundation, =
Inc.</div><div><br></div><div>&nbsp; &nbsp;Author: Alexander Malmberg =
&lt;[email protected]&gt;</div><div>&nbsp; &nbsp;Date: November =
2002 - February 2003</div><div><br></div><div>&nbsp; &nbsp;This file is =
part of the GNUstep GUI Library.</div><div><br></div><div>&nbsp; =
&nbsp;This library is free software; you can redistribute it =
and/or</div><div>&nbsp; &nbsp;modify it under the terms of the GNU =
Lesser General Public</div><div>&nbsp; &nbsp;License as published by the =
Free Software Foundation; either</div><div>&nbsp; &nbsp;version 2 of the =
License, or (at your option) any later =
version.</div><div><br></div><div>&nbsp; &nbsp;This library is =
distributed in the hope that it will be useful,</div><div>&nbsp; =
&nbsp;but WITHOUT ANY WARRANTY; without even the implied warranty =
of</div><div>&nbsp; &nbsp;MERCHANTABILITY or FITNESS FOR A PARTICULAR =
PURPOSE.<span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span> See the GNU</div><div>&nbsp; &nbsp;Lesser General Public License =
for more details.</div><div><br></div><div>&nbsp; &nbsp;You should have =
received a copy of the GNU Lesser General Public</div><div>&nbsp; =
&nbsp;License along with this library; see the file =
COPYING.LIB.</div><div>&nbsp; &nbsp;If not, see =
&lt;http://www.gnu.org/licenses/&gt; or write to =
the&nbsp;</div><div>&nbsp; &nbsp;Free Software Foundation, 51 Franklin =
Street, Fifth Floor,&nbsp;</div><div>&nbsp; &nbsp;Boston, MA 02110-1301, =
USA.</div><div>*/</div><div><br></div><div><br></div><div>#include =
&lt;math.h&gt;</div><div><br></div><div>#import =
&lt;Foundation/NSDebug.h&gt;</div><div>#import =
&lt;Foundation/NSException.h&gt;</div><div>#import =
&lt;Foundation/NSGeometry.h&gt;</div><div>#import =
&lt;Foundation/NSLock.h&gt;</div><div>#import =
&lt;Foundation/NSThread.h&gt;</div><div>#import =
&lt;Foundation/NSValue.h&gt;</div><div><br></div><div>#import =
"AppKit/NSAttributedString.h"</div><div>#import =
"AppKit/NSParagraphStyle.h"</div><div>#import =
"AppKit/NSTextAttachment.h"</div><div>#import =
"AppKit/NSTextContainer.h"</div><div>#import =
"AppKit/NSTextStorage.h"</div><div>#import =
"GNUstepGUI/GSLayoutManager.h"</div><div>#import =
"GNUstepGUI/GSHorizontalTypesetter.h"</div><div><br></div><div><br></div><=
div>/*</div><div>&nbsp;* DESIGN NOTE: Unless the user creates extra =
instances, there will only be one</div><div>&nbsp;* instance of =
GSHorizontalTypesetter per thread for all text =
typesetting.</div><div>&nbsp;* This allows aggressive caching without =
memory concerns since the cache is</div><div>&nbsp;* reused across =
multiple layout operations rather than being recreated each =
time.</div><div>&nbsp;*/</div><div><br></div><div><br></div><div>@implemen=
tation =
GSHorizontalTypesetter</div><div><br></div><div>/*</div><div>&nbsp;* =
Standard initializer. Creates the reentrancy lock used to =
detect</div><div>&nbsp;* nested layout calls on the same =
instance.</div><div>&nbsp;*/</div><div>- =
init</div><div>{</div><div>&nbsp; if (!(self =3D [super init])) return =
nil;</div><div>&nbsp; lock =3D [[NSLock alloc] init];</div><div>&nbsp; =
return self;</div><div>}</div><div><br></div><div>/*</div><div>&nbsp;* =
Cleanup: release the lock and free all cached memory =
buffers.</div><div>&nbsp;*/</div><div>-(void) =
dealloc</div><div>{</div><div>&nbsp; if (cache)</div><div>&nbsp; &nbsp; =
{</div><div>&nbsp; &nbsp; &nbsp; free(cache);</div><div>&nbsp; &nbsp; =
&nbsp; cache =3D NULL;</div><div>&nbsp; &nbsp; }</div><div>&nbsp; if =
(line_frags)</div><div>&nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; =
free(line_frags);</div><div>&nbsp; &nbsp; &nbsp; line_frags =3D =
NULL;</div><div>&nbsp; &nbsp; }</div><div>&nbsp; =
DESTROY(lock);</div><div>&nbsp; [super =
dealloc];</div><div>}</div><div><br></div><div>/*</div><div>&nbsp;* =
Thread-local singleton accessor. Each thread gets its own =
instance</div><div>&nbsp;* stored in the thread dictionary under a =
unique key. This provides</div><div>&nbsp;* instance reuse without =
requiring cross-thread =
synchronization.</div><div>&nbsp;*/</div><div>+(GSHorizontalTypesetter =
*) sharedInstance</div><div>{</div><div>&nbsp; NSMutableDictionary =
*threadDict =3D&nbsp;</div><div>&nbsp; &nbsp; [[NSThread currentThread] =
threadDictionary];</div><div>&nbsp; GSHorizontalTypesetter *shared =
=3D&nbsp;</div><div>&nbsp; &nbsp; [threadDict objectForKey: =
@"sharedHorizontalTypesetter"];</div><div><br></div><div>&nbsp; if =
(!shared)</div><div>&nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; =
shared =3D [[self alloc] init];</div><div>&nbsp; &nbsp; &nbsp; =
[threadDict setObject: shared</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp;forKey: =
@"sharedHorizontalTypesetter"];</div><div>&nbsp; &nbsp; &nbsp; =
RELEASE(shared);</div><div>&nbsp; &nbsp; =
}</div><div><br></div><div>&nbsp; return =
shared;</div><div>}</div><div><br></div><div>/*</div><div>&nbsp;* CACHE =
MANAGEMENT CONSTANTS</div><div>&nbsp;* CACHE_INITIAL: Starting size for =
glyph cache (192 glyphs)</div><div>&nbsp;* CACHE_STEP: &nbsp; =
&nbsp;Increment size when cache needs to =
grow</div><div>&nbsp;*/</div><div>#define CACHE_INITIAL =
192</div><div>#define CACHE_STEP =
192</div><div><br></div><div><br></div><div>/*</div><div>&nbsp;* GLYPH =
CACHE ENTRY</div><div>&nbsp;* Stores all information needed to position =
a single glyph.</div><div>&nbsp;* Split into two =
phases:</div><div>&nbsp;* &nbsp; 1. Filled during caching =
(_cacheGlyphs:)</div><div>&nbsp;* &nbsp; 2. Filled during layout =
(layoutLineNewParagraph:)</div><div>&nbsp;*/</div><div>struct =
GSHorizontalTypesetter_glyph_cache_s</div><div>{</div><div>&nbsp; /* =
PHASE 1: Caching - extracted from layout manager and attributes =
*/</div><div>&nbsp; NSGlyph g; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp;// The glyph index (NSGlyph is an integer =
type)</div><div>&nbsp; unsigned int char_index; &nbsp; &nbsp; &nbsp;// =
Corresponding character index in text =
storage</div><div><br></div><div>&nbsp; NSFont *font; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Font to use for this =
glyph</div><div>&nbsp; struct</div><div>&nbsp; &nbsp; {</div><div>&nbsp; =
&nbsp; &nbsp; BOOL explicit_kern; &nbsp; &nbsp; &nbsp; // Whether to =
apply explicit kerning</div><div>&nbsp; &nbsp; &nbsp; float kern; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Kerning value from =
attributes</div><div>&nbsp; &nbsp; &nbsp; float baseline_offset; &nbsp; =
&nbsp;// Vertical offset from baseline</div><div>&nbsp; &nbsp; &nbsp; =
int superscript; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Superscript =
level</div><div>&nbsp; &nbsp; } =
attributes;</div><div><br></div><div>&nbsp; /* PHASE 2: Layout - =
computed during line layout */</div><div>&nbsp; BOOL nominal; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // YES if glyph has =
standard spacing (no adjustments)</div><div>&nbsp; NSPoint pos; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Position =
relative to the line's baseline</div><div>&nbsp; NSSize size; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Advancement =
width; height used only for attachments</div><div>&nbsp; BOOL dont_show, =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // YES for whitespace =
glyphs that shouldn't render</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp;outside_line_frag; &nbsp; &nbsp; &nbsp; // YES for glyphs that =
overflow the fragment (clipping mode)</div><div>};</div><div>typedef =
struct GSHorizontalTypesetter_glyph_cache_s =
glyph_cache_t;</div><div><br></div><div>/*</div><div>&nbsp;* Clears all =
cached attribute and glyph information.</div><div>&nbsp;* Called at the =
start of each layout operation to ensure we don't</div><div>&nbsp;* use =
stale data from previous layouts. Note that we don't free =
the</div><div>&nbsp;* cache memory, just reset the valid length to =
zero.</div><div>&nbsp;*</div><div>&nbsp;* TODO: If we could detect =
whether the layout manager has been modified</div><div>&nbsp;* since our =
last layout, we could avoid clearing the cache =
unnecessarily.</div><div>&nbsp;*/</div><div>-(void) =
_cacheClear</div><div>{</div><div>&nbsp; cache_length =3D =
0;</div><div><br></div><div>&nbsp; curParagraphStyle =3D =
nil;</div><div>&nbsp; paragraphRange =3D NSMakeRange(0, =
0);</div><div>&nbsp; curAttributes =3D nil;</div><div>&nbsp; =
attributeRange =3D NSMakeRange(0, 0);</div><div>&nbsp; curFont =3D =
nil;</div><div>&nbsp; fontRange =3D NSMakeRange(0, =
0);</div><div>}</div><div><br></div><div>/*</div><div>&nbsp;* Caches the =
attributes for the character at the given index.</div><div>&nbsp;* Uses =
range checking to avoid redundant dictionary lookups - if =
the</div><div>&nbsp;* requested index is within attributeRange, we =
already have the data.</div><div>&nbsp;* Extracts kern, baseline offset, =
and superscript into the attributes =
struct.</div><div>&nbsp;*/</div><div>-(void) _cacheAttributes: (unsigned =
int)char_index</div><div>{</div><div>&nbsp; NSNumber =
*n;</div><div><br></div><div>&nbsp; if (NSLocationInRange(char_index, =
attributeRange))</div><div>&nbsp; &nbsp; {</div><div>&nbsp; &nbsp; =
&nbsp; return;</div><div>&nbsp; &nbsp; =
}</div><div>&nbsp;&nbsp;</div><div>&nbsp; curAttributes =3D =
[curTextStorage attributesAtIndex: char_index</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;effectiveRange: =
&amp;attributeRange];</div><div><br></div><div>&nbsp; /* Extract kerning =
attribute */</div><div>&nbsp; n =3D [curAttributes objectForKey: =
NSKernAttributeName];</div><div>&nbsp; if (!n)</div><div>&nbsp; &nbsp; =
attributes.explicit_kern =3D NO;</div><div>&nbsp; else</div><div>&nbsp; =
&nbsp; {</div><div>&nbsp; &nbsp; &nbsp; attributes.explicit_kern =3D =
YES;</div><div>&nbsp; &nbsp; &nbsp; attributes.kern =3D [n =
floatValue];</div><div>&nbsp; &nbsp; }</div><div><br></div><div>&nbsp; =
/* Extract baseline offset (positive =3D up, negative =3D down in =
standard Cocoa coords) */</div><div>&nbsp; n =3D [curAttributes =
objectForKey: NSBaselineOffsetAttributeName];</div><div>&nbsp; if =
(n)</div><div>&nbsp; &nbsp; attributes.baseline_offset =3D [n =
floatValue];</div><div>&nbsp; else</div><div>&nbsp; &nbsp; =
attributes.baseline_offset =3D 0.0;</div><div><br></div><div>&nbsp; /* =
Extract superscript level */</div><div>&nbsp; n =3D [curAttributes =
objectForKey: NSSuperscriptAttributeName];</div><div>&nbsp; if =
(n)</div><div>&nbsp; &nbsp; attributes.superscript =3D [n =
intValue];</div><div>&nbsp; else</div><div>&nbsp; &nbsp; =
attributes.superscript =3D =
0;</div><div>}</div><div><br></div><div>/*</div><div>&nbsp;* Repositions =
the cache window to start at the specified glyph =
index.</div><div>&nbsp;*&nbsp;</div><div>&nbsp;* If the requested glyph =
is already within our cache window, we shift the</div><div>&nbsp;* =
existing data to the front (memmove) to make room for new glyphs =
ahead.</div><div>&nbsp;*&nbsp;</div><div>&nbsp;* If it's outside our =
cache, we reset completely and fetch new paragraph</div><div>&nbsp;* =
style, attributes, and font information from the layout =
manager.</div><div>&nbsp;*/</div><div>-(void) _cacheMoveTo: (unsigned =
int)glyph</div><div>{</div><div>&nbsp; BOOL =
valid;</div><div><br></div><div>&nbsp; /* Case 1: Requested glyph is =
already in our cache window */</div><div>&nbsp; if (cache_base &lt;=3D =
glyph &amp;&amp; cache_base + cache_length &gt; glyph)</div><div>&nbsp; =
&nbsp; {</div><div>&nbsp; &nbsp; &nbsp; int delta =3D glyph - =
cache_base;</div><div>&nbsp; &nbsp; &nbsp; cache_length -=3D =
delta;</div><div>&nbsp; &nbsp; &nbsp; memmove(cache, &amp;cache[delta], =
sizeof(glyph_cache_t) * cache_length);</div><div>&nbsp; &nbsp; &nbsp; =
cache_base =3D glyph;</div><div>&nbsp; &nbsp; &nbsp; =
return;</div><div>&nbsp; &nbsp; }</div><div><br></div><div>&nbsp; /* =
Case 2: Complete reset - new location in text stream */</div><div>&nbsp; =
cache_base =3D glyph;</div><div>&nbsp; cache_length =3D =
0;</div><div><br></div><div>&nbsp; [curLayoutManager glyphAtIndex: =
glyph</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
	</span> &nbsp; &nbsp;isValidIndex: =
&amp;valid];</div><div><br></div><div>&nbsp; if (valid)</div><div>&nbsp; =
&nbsp; {</div><div>&nbsp; &nbsp; &nbsp; unsigned int =
i;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; at_end =3D =
NO;</div><div>&nbsp; &nbsp; &nbsp; i =3D [curLayoutManager =
characterIndexForGlyphAtIndex: glyph];</div><div>&nbsp; &nbsp; &nbsp; =
[self _cacheAttributes: i];</div><div><br></div><div>&nbsp; &nbsp; =
&nbsp; /* Fetch paragraph style and its valid range */</div><div>&nbsp; =
&nbsp; &nbsp; paragraphRange =3D NSMakeRange(i, [curTextStorage length] =
- i);</div><div>&nbsp; &nbsp; &nbsp; curParagraphStyle =3D =
[curTextStorage attribute: NSParagraphStyleAttributeName</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">				=
	</span>atIndex: i</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">					=
</span>longestEffectiveRange: &amp;paragraphRange</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">				=
	</span>inRange: paragraphRange];</div><div>&nbsp; &nbsp; &nbsp; =
if (curParagraphStyle =3D=3D nil)</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; curParagraphStyle =3D =
[NSParagraphStyle defaultParagraphStyle];</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; }</div><div><br></div><div>&nbsp; &nbsp; &nbsp; /* Fetch initial =
font and its valid range */</div><div>&nbsp; &nbsp; &nbsp; curFont =3D =
[curLayoutManager effectiveFontForGlyphAtIndex: glyph</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">				=
</span>range: &amp;fontRange];</div><div>&nbsp; &nbsp; =
}</div><div>&nbsp; else</div><div>&nbsp; &nbsp; {</div><div>&nbsp; =
&nbsp; &nbsp; at_end =3D YES; &nbsp;// No valid glyph at this index - =
we're at end of text</div><div>&nbsp; &nbsp; =
}</div><div>}</div><div><br></div><div>/*</div><div>&nbsp;* Fills the =
glyph cache up to new_length entries.</div><div>&nbsp;* Grows the cache =
buffer if necessary using realloc.</div><div>&nbsp;* For each new glyph, =
fetches:</div><div>&nbsp;* &nbsp; - Glyph index and character index from =
layout manager</div><div>&nbsp;* &nbsp; - Attributes (if character index =
moved past attributeRange)</div><div>&nbsp;* &nbsp; - Font (if glyph =
moved past fontRange)</div><div>&nbsp;* &nbsp; - Advancement size from =
layout manager</div><div>&nbsp;*</div><div>&nbsp;* Stops early if we hit =
invalid glyphs or paragraph =
boundaries.</div><div>&nbsp;*/</div><div>-(void) _cacheGlyphs: (unsigned =
int)new_length</div><div>{</div><div>&nbsp; glyph_cache_t =
*g;</div><div>&nbsp; BOOL valid;</div><div><br></div><div>&nbsp; /* Grow =
buffer if needed */</div><div>&nbsp; if (cache_size &lt; =
new_length)</div><div>&nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; =
cache_size =3D new_length;</div><div>&nbsp; &nbsp; &nbsp; cache =3D =
realloc(cache, sizeof(glyph_cache_t) * cache_size);</div><div>&nbsp; =
&nbsp; }</div><div><br></div><div>&nbsp; /* Fill cache entries from =
current length up to new_length */</div><div>&nbsp; for (g =3D =
&amp;cache[cache_length]; cache_length &lt; new_length; cache_length++, =
g++)</div><div>&nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; g-&gt;g =3D =
[curLayoutManager glyphAtIndex: cache_base + =
cache_length</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">			</span> &nbsp; &nbsp; =
&nbsp; isValidIndex: &amp;valid];</div><div>&nbsp; &nbsp; &nbsp; if =
(!valid)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>{</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> =
&nbsp;at_end =3D YES;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;break;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>}</div><div>&nbsp; &nbsp; &nbsp; g-&gt;char_index =3D =
[curLayoutManager characterIndexForGlyphAtIndex: cache_base + =
cache_length];</div><div>&nbsp; &nbsp; &nbsp;&nbsp;</div><div>&nbsp; =
&nbsp; &nbsp; /* Stop if we crossed paragraph boundary =
*/</div><div>&nbsp; &nbsp; &nbsp; if (g-&gt;char_index &gt;=3D =
paragraphRange.location + paragraphRange.length)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;at_end =3D =
YES;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span> &nbsp;break;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>}</div><div><br></div><div>&nbsp; =
&nbsp; &nbsp; /* Update attribute cache if needed */</div><div>&nbsp; =
&nbsp; &nbsp; if (g-&gt;char_index &gt;=3D attributeRange.location + =
attributeRange.length)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>{</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> =
&nbsp;[self _cacheAttributes: g-&gt;char_index];</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>}</div><div><br></div><div>&nbsp; &nbsp; &nbsp; /* Copy =
decomposed attributes into cache entry */</div><div>&nbsp; &nbsp; &nbsp; =
g-&gt;attributes.explicit_kern =3D =
attributes.explicit_kern;</div><div>&nbsp; &nbsp; &nbsp; =
g-&gt;attributes.kern =3D attributes.kern;</div><div>&nbsp; &nbsp; =
&nbsp; g-&gt;attributes.baseline_offset =3D =
attributes.baseline_offset;</div><div>&nbsp; &nbsp; &nbsp; =
g-&gt;attributes.superscript =3D =
attributes.superscript;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; /* =
Update font cache if needed */</div><div>&nbsp; &nbsp; &nbsp; if =
(cache_base + cache_length &gt;=3D fontRange.location + =
fontRange.length)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>{</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> =
&nbsp;curFont =3D [curLayoutManager effectiveFontForGlyphAtIndex: =
cache_base + cache_length</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">				</span> &nbsp; =
&nbsp;range: &amp;fontRange];</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>}</div><div>&nbsp; &nbsp; &nbsp; =
g-&gt;font =3D curFont;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; /* =
Initialize layout fields */</div><div>&nbsp; &nbsp; &nbsp; =
g-&gt;dont_show =3D NO;</div><div>&nbsp; &nbsp; &nbsp; =
g-&gt;outside_line_frag =3D NO;</div><div>&nbsp; &nbsp; &nbsp; =
g-&gt;nominal =3D YES;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; /* =
Get glyph advancement from layout manager */</div><div>&nbsp; &nbsp; =
&nbsp; // FIXME: This assumes the layout manager implements this GNUstep =
extension</div><div>&nbsp; &nbsp; &nbsp; g-&gt;size =3D =
[curLayoutManager advancementForGlyphAtIndex: cache_base + =
cache_length];</div><div>&nbsp; &nbsp; =
}</div><div>}</div><div><br></div><div><br></div><div>/*</div><div>&nbsp;*=
 WORD WRAPPING SUPPORT</div><div>&nbsp;* Searches backward from glyph gi =
to find a suitable word break point.</div><div>&nbsp;* Returns the glyph =
index of the first glyph on the next =
line.</div><div>&nbsp;*</div><div>&nbsp;* Breaking =
rules:</div><div>&nbsp;* &nbsp; - Control glyphs (newlines, tabs) are =
always break points</div><div>&nbsp;* &nbsp; - Whitespace characters =
(space, newline, CR, tab) mark breaks and are hidden</div><div>&nbsp;* =
&nbsp; - CJK characters (0x2FF0-0x9FFF) can break before (each CJK char =
is its own word)</div><div>&nbsp;*</div><div>&nbsp;* The returned index =
is always &gt;=3D cache_base and &lt;=3D =
gi.</div><div>&nbsp;*/</div><div>-(unsigned int) =
breakLineByWordWrappingBefore: (unsigned =
int)gi</div><div>{</div><div>&nbsp; glyph_cache_t *g;</div><div>&nbsp; =
unichar ch;</div><div>&nbsp; NSString *str =3D [curTextStorage =
string];</div><div><br></div><div>&nbsp; gi -=3D cache_base; &nbsp;// =
Convert to cache-relative index</div><div>&nbsp; g =3D cache + =
gi;</div><div><br></div><div>&nbsp; while (gi &gt; 0)</div><div>&nbsp; =
&nbsp; {</div><div>&nbsp; &nbsp; &nbsp; if (g-&gt;g =3D=3D =
NSControlGlyph)</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return gi + =
cache_base; &nbsp;// Always break at control glyphs</div><div>&nbsp; =
&nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; ch =3D [str =
characterAtIndex: g-&gt;char_index];</div><div>&nbsp; &nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; /* Check for whitespace =
characters that allow breaking */</div><div>&nbsp; &nbsp; &nbsp; if (ch =
=3D=3D 0x20 || // space</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ch =
=3D=3D 0x0a || // new line</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
ch =3D=3D 0x0d || // carriage return</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; ch =3D=3D 0x09) &nbsp; // horiz. tab</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
g-&gt;dont_show =3D YES; &nbsp;// Hide the whitespace character =
itself</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (gi &gt; =
0)</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; g-&gt;pos =3D=
 g[-1].pos;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
g-&gt;pos.x +=3D g[-1].size.width;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
else</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; g-&gt;pos =3D =
NSMakePoint(0, 0);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
g-&gt;size.width =3D 0;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
return gi + 1 + cache_base; &nbsp;// Break after the =
whitespace</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; =
&nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; /* CJK characters: =
treat each as a word boundary */</div><div>&nbsp; &nbsp; &nbsp; else if =
((ch &gt; 0x2ff0) &amp;&amp; (ch &lt; 0x9fff))</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp;{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;g-&gt;dont_show =3D NO;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp;if (gi &gt; 0)</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp;{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp;g-&gt;pos =3D g[-1].pos;</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;g-&gt;pos.x +=3D =
g[-1].size.width;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;else</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;g-&gt;pos =3D NSMakePoint(0,0);</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp;return gi + cache_base; &nbsp;// Break before this =
CJK character</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;} &nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp;&nbsp;</div><div>&nbsp; =
&nbsp; &nbsp; gi--;</div><div>&nbsp; &nbsp; &nbsp; g--;</div><div>&nbsp; =
&nbsp; }</div><div>&nbsp; return gi + cache_base; &nbsp;// Reached start =
of cache - break =
here</div><div>}</div><div><br></div><div><br></div><div>/*</div><div>&nbs=
p;* LINE FRAGMENT STRUCTURE</div><div>&nbsp;* Tracks the geometry and =
content of a single line fragment (a rectangular</div><div>&nbsp;* =
region within a line where glyphs are =
placed).</div><div>&nbsp;*/</div><div>struct =
GSHorizontalTypesetter_line_frag_s</div><div>{</div><div>&nbsp; NSRect =
rect; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// The fragment =
rectangle in container coordinates</div><div>&nbsp; CGFloat last_used; =
&nbsp; &nbsp; &nbsp; &nbsp;// X coordinate where glyph content =
ends</div><div>&nbsp; unsigned int lastGlyphIndex; // Index (relative to =
cache_base) of last glyph + 1</div><div>};</div><div>typedef struct =
GSHorizontalTypesetter_line_frag_s =
line_frag_t;</div><div><br></div><div>/*</div><div>&nbsp;* Apple's =
maximum meaningful width for text containers.</div><div>&nbsp;* Widths =
beyond this are treated as infinite and ignored for layout =
purposes.</div><div>&nbsp;*/</div><div>#define LARGE_SIZE =
1e7</div><div><br></div><div>/*</div><div>&nbsp;* FULL =
JUSTIFICATION</div><div>&nbsp;* Distributes extra space evenly across =
space characters in the line.</div><div>&nbsp;* Only operates if the =
line width is reasonable (not =
LARGE_SIZE).</div><div>&nbsp;*</div><div>&nbsp;* =
Algorithm:</div><div>&nbsp;* &nbsp; 1. Count space characters in the =
line</div><div>&nbsp;* &nbsp; 2. Calculate extra space per space: =
(rect.width - last_used) / num_spaces</div><div>&nbsp;* &nbsp; 3. Shift =
all glyphs after each space by accumulating delta</div><div>&nbsp;* =
&nbsp; 4. Mark glyphs after spaces as non-nominal (they have adjusted =
positions)</div><div>&nbsp;*/</div><div>-(void) fullJustifyLine: =
(line_frag_t *)lf : (int)num_line_frags</div><div>{</div><div>&nbsp; =
unsigned int i, start;</div><div>&nbsp; CGFloat extra_space, =
delta;</div><div>&nbsp; unsigned int num_spaces;</div><div>&nbsp; =
NSString *str =3D [curTextStorage string];</div><div>&nbsp; =
glyph_cache_t *g;</div><div>&nbsp; unichar =
ch;</div><div><br></div><div>&nbsp; if (lf-&gt;rect.size.width &gt;=3D =
LARGE_SIZE)</div><div>&nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; =
return;</div><div>&nbsp; &nbsp; }</div><div><br></div><div>&nbsp; for =
(start =3D 0; num_line_frags; num_line_frags--, lf++)</div><div>&nbsp; =
&nbsp; {</div><div>&nbsp; &nbsp; &nbsp; num_spaces =3D =
0;</div><div>&nbsp; &nbsp; &nbsp; for (i =3D start, g =3D cache + i; i =
&lt; lf-&gt;lastGlyphIndex; i++, g++)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;if =
(g-&gt;dont_show)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;continue;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;ch =3D [str =
characterAtIndex: g-&gt;char_index];</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp;if =
(ch =3D=3D 0x20)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;num_spaces++;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>}</div><div>&nbsp; &nbsp; &nbsp; =
if (!num_spaces)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	=
</span>continue;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; =
extra_space =3D lf-&gt;rect.size.width - =
lf-&gt;last_used;</div><div>&nbsp; &nbsp; &nbsp; extra_space /=3D =
num_spaces;</div><div>&nbsp; &nbsp; &nbsp; delta =3D 0;</div><div>&nbsp; =
&nbsp; &nbsp; for (i =3D start, g =3D cache + i; i &lt; =
lf-&gt;lastGlyphIndex; i++, g++)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>{</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> =
&nbsp;g-&gt;pos.x +=3D delta;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;if (!g-&gt;dont_show =
&amp;&amp; [str characterAtIndex: g-&gt;char_index] =3D=3D =
0x20)</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span> &nbsp; &nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; &nbsp;if (i &lt; =
lf-&gt;lastGlyphIndex)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>g[1].nominal =3D NO; =
&nbsp;// Next glyph has non-standard position</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;delta +=3D extra_space;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>}</div><div>&nbsp; &nbsp; &nbsp; =
start =3D lf-&gt;lastGlyphIndex;</div><div>&nbsp; &nbsp; &nbsp; =
lf-&gt;last_used =3D lf-&gt;rect.size.width;</div><div>&nbsp; &nbsp; =
}</div><div>}</div><div><br></div><div>/*</div><div>&nbsp;* RIGHT =
ALIGNMENT</div><div>&nbsp;* Shifts all glyphs right by the difference =
between fragment width and used =
width.</div><div>&nbsp;*/</div><div>-(void) rightAlignLine: (line_frag_t =
*)lf : (int)num_line_frags</div><div>{</div><div>&nbsp; unsigned int =
i;</div><div>&nbsp; CGFloat delta;</div><div>&nbsp; glyph_cache_t =
*g;</div><div><br></div><div>&nbsp; if (lf-&gt;rect.size.width &gt;=3D =
LARGE_SIZE)</div><div>&nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; =
return;</div><div>&nbsp; &nbsp; }</div><div><br></div><div>&nbsp; for (i =
=3D 0, g =3D cache; num_line_frags; num_line_frags--, =
lf++)</div><div>&nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; delta =3D =
lf-&gt;rect.size.width - lf-&gt;last_used;</div><div>&nbsp; &nbsp; =
&nbsp; for (; i &lt; lf-&gt;lastGlyphIndex; i++, g++)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>g-&gt;pos.x +=3D delta;</div><div>&nbsp; &nbsp; &nbsp; =
lf-&gt;last_used +=3D delta;</div><div>&nbsp; &nbsp; =
}</div><div>}</div><div><br></div><div>/*</div><div>&nbsp;* CENTER =
ALIGNMENT</div><div>&nbsp;* Shifts all glyphs right by half the =
remaining space.</div><div>&nbsp;*/</div><div>-(void) centerAlignLine: =
(line_frag_t *)lf : (int)num_line_frags</div><div>{</div><div>&nbsp; =
unsigned int i;</div><div>&nbsp; CGFloat delta;</div><div>&nbsp; =
glyph_cache_t *g;</div><div><br></div><div>&nbsp; if =
(lf-&gt;rect.size.width &gt;=3D LARGE_SIZE)</div><div>&nbsp; &nbsp; =
{</div><div>&nbsp; &nbsp; &nbsp; return;</div><div>&nbsp; &nbsp; =
}</div><div><br></div><div>&nbsp; for (i =3D 0, g =3D cache; =
num_line_frags; num_line_frags--, lf++)</div><div>&nbsp; &nbsp; =
{</div><div>&nbsp; &nbsp; &nbsp; delta =3D (lf-&gt;rect.size.width - =
lf-&gt;last_used) / 2.0;</div><div>&nbsp; &nbsp; &nbsp; for (; i &lt; =
lf-&gt;lastGlyphIndex; i++, g++)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>g-&gt;pos.x +=3D =
delta;</div><div>&nbsp; &nbsp; &nbsp; lf-&gt;last_used +=3D =
delta;</div><div>&nbsp; &nbsp; =
}</div><div>}</div><div><br></div><div><br></div><div>/*</div><div>&nbsp;*=
 SOFT INVALIDATION OPTIMIZATION</div><div>&nbsp;* Attempts to reuse =
layout information from previous layout passes that</div><div>&nbsp;* =
were "soft invalidated" (marked as potentially changed but not =
definitely wrong).</div><div>&nbsp;*</div><div>&nbsp;* This handles the =
common case of simple text edits where line fragments</div><div>&nbsp;* =
just need to be shifted vertically without changing their horizontal =
layout.</div><div>&nbsp;*</div><div>&nbsp;* Returns YES if =
soft-invalidated layout was successfully =
reused.</div><div>&nbsp;*/</div><div>-(BOOL) =
_reuseSoftInvalidatedLayout</div><div>{</div><div>&nbsp; NSRect r0, =
r;</div><div>&nbsp; NSSize shift;</div><div>&nbsp; int =
i;</div><div>&nbsp; unsigned int g, g2, first;</div><div>&nbsp; CGFloat =
container_height;</div><div>&nbsp;&nbsp;</div><div>&nbsp; /* Get first =
soft-invalidated rect starting at current glyph */</div><div>&nbsp; r0 =3D=
 [curLayoutManager _softInvalidateLineFragRect: 0</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">				=
	</span> &nbsp;firstGlyph: &amp;first</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">				=
	</span> &nbsp; nextGlyph: &amp;g</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">				=
</span> &nbsp; &nbsp; inTextContainer: =
curTextContainer];</div><div><br></div><div>&nbsp; container_height =3D =
[curTextContainer containerSize].height;</div><div>&nbsp; if =
(!(curPoint.y + r0.size.height &lt;=3D =
container_height))</div><div>&nbsp; &nbsp; return NO; &nbsp;// Won't fit =
at current Y position</div><div><br></div><div>&nbsp; =
/*</div><div>&nbsp; &nbsp;* We can shift the rects vertically to fit. =
Collect all consecutive</div><div>&nbsp; &nbsp;* soft-invalidated line =
fragments and apply the same shift.</div><div>&nbsp; =
&nbsp;*/</div><div>&nbsp; shift.width =3D 0;</div><div>&nbsp; =
shift.height =3D curPoint.y - r0.origin.y;</div><div>&nbsp; i =3D =
1;</div><div>&nbsp; curPoint.y =3D NSMaxY(r0) + =
shift.height;</div><div>&nbsp;&nbsp;</div><div>&nbsp; for (; 1; =
i++)</div><div>&nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; r =3D =
[curLayoutManager _softInvalidateLineFragRect: i</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">				=
	</span> &nbsp; &nbsp; firstGlyph: &amp;first</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">				=
	</span> &nbsp; &nbsp; &nbsp;nextGlyph: &amp;g2</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">				=
	</span>inTextContainer: =
curTextContainer];</div><div><br></div><div>&nbsp; &nbsp; &nbsp; /* Gap =
in soft-invalidated info - must fill in before continuing =
*/</div><div>&nbsp; &nbsp; &nbsp; if (first !=3D g)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;break;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>}</div><div><br></div><div>&nbsp; &nbsp; &nbsp; if =
(NSIsEmptyRect(r) || NSMaxY(r) + shift.height &gt; =
container_height)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	=
</span>break;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; g =3D =
g2;</div><div>&nbsp; &nbsp; &nbsp; curPoint.y =3D NSMaxY(r) + =
shift.height;</div><div>&nbsp; &nbsp; }</div><div><br></div><div>&nbsp; =
/* Commit the reused layout to the layout manager */</div><div>&nbsp; =
[curLayoutManager _softInvalidateUseLineFrags: i</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">				=
</span> &nbsp; &nbsp; &nbsp;withShift: shift</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">				=
</span>inTextContainer: =
curTextContainer];</div><div><br></div><div>&nbsp; curGlyphIndex =3D =
g;</div><div>&nbsp; return =
YES;</div><div>}</div><div><br></div><div><br></div><div>/*</div><div>&nbs=
p;* Calculates the proposed rectangle for a new line =
fragment.</div><div>&nbsp;*&nbsp;</div><div>&nbsp;* newParagraph: YES =
for first line of paragraph (uses =
firstLineHeadIndent),</div><div>&nbsp;* &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; NO for subsequent lines (uses =
headIndent)</div><div>&nbsp;* line_height: &nbsp;The height to request =
from the text container</div><div>&nbsp;*</div><div>&nbsp;* Returns: =
Proposed rectangle in container =
coordinates</div><div>&nbsp;*/</div><div>- (NSRect)_getProposedRectFor: =
(BOOL)newParagraph</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp;withLineHeight: (CGFloat) =
line_height&nbsp;</div><div>{</div><div>&nbsp; CGFloat =
hindent;</div><div>&nbsp; CGFloat tindent =3D [curParagraphStyle =
tailIndent];</div><div><br></div><div>&nbsp; if =
(newParagraph)</div><div>&nbsp; &nbsp; hindent =3D [curParagraphStyle =
firstLineHeadIndent];</div><div>&nbsp; else</div><div>&nbsp; &nbsp; =
hindent =3D [curParagraphStyle =
headIndent];</div><div><br></div><div>&nbsp; /* Negative tail indent is =
treated as inset from right edge */</div><div>&nbsp; if (tindent &lt;=3D =
0.0)</div><div>&nbsp; &nbsp; {&nbsp;</div><div>&nbsp; &nbsp; &nbsp; =
NSSize size;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; size =3D =
[curTextContainer containerSize];</div><div>&nbsp; &nbsp; &nbsp; tindent =
=3D size.width + tindent;</div><div>&nbsp; &nbsp; =
}</div><div><br></div><div>&nbsp; return =
NSMakeRect(hindent,</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; curPoint.y,</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tindent - =
hindent,</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; line_height + [curParagraphStyle =
lineSpacing]);</div><div>}</div><div><br></div><div>/*</div><div>&nbsp;* =
Creates the "extra line fragment" used when text ends with a =
newline.</div><div>&nbsp;* This provides a place for the insertion point =
(caret) after the last newline.</div><div>&nbsp;* The fragment has full =
line height but minimal width (1 unit).</div><div>&nbsp;*/</div><div>- =
(void) _addExtraLineFragment</div><div>{</div><div>&nbsp; NSRect r, r2, =
remain;</div><div>&nbsp; CGFloat =
line_height;</div><div><br></div><div>&nbsp; /*</div><div>&nbsp; &nbsp;* =
We need the attributes from the last character to match the =
style.</div><div>&nbsp; &nbsp;* _cacheMoveTo: ensures curParagraphStyle =
and curFont are set.</div><div>&nbsp; &nbsp;*/</div><div>&nbsp; if =
(curGlyphIndex)</div><div>&nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; =
[self _cacheMoveTo: curGlyphIndex - 1];</div><div>&nbsp; &nbsp; =
}</div><div>&nbsp; else</div><div>&nbsp; &nbsp; {</div><div>&nbsp; =
&nbsp; &nbsp; /* No glyphs yet - use typing attributes (default style =
for new text) */</div><div>&nbsp; &nbsp; &nbsp; NSDictionary =
*typingAttributes =3D [curLayoutManager =
typingAttributes];</div><div>&nbsp; &nbsp; &nbsp; curParagraphStyle =3D =
[typingAttributes</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; objectForKey: =
NSParagraphStyleAttributeName];</div><div>&nbsp; &nbsp; &nbsp; if =
(curParagraphStyle =3D=3D nil)</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; curParagraphStyle =3D =
[NSParagraphStyle defaultParagraphStyle];</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; }</div><div>&nbsp; &nbsp; &nbsp; curFont =3D [typingAttributes =
objectForKey: NSFontAttributeName];</div><div>&nbsp; &nbsp; =
}</div><div><br></div><div>&nbsp; /* Determine line height from font or =
use default */</div><div>&nbsp; if (curFont)</div><div>&nbsp; &nbsp; =
{</div><div>&nbsp; &nbsp; &nbsp; line_height =3D [curFont =
defaultLineHeightForFont];</div><div>&nbsp; &nbsp; }</div><div>&nbsp; =
else</div><div>&nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; =
line_height =3D 15.0;</div><div>&nbsp; &nbsp; =
}</div><div><br></div><div>&nbsp; r =3D [self _getProposedRectFor: =
YES</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;withLineHeight: line_height];</div><div>&nbsp; r =3D =
[curTextContainer lineFragmentRectForProposedRect: r</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;sweepDirection: NSLineSweepRight</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; movementDirection: =
NSLineMovesDown</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; remainingRect: =
&amp;remain];</div><div>&nbsp;&nbsp;</div><div>&nbsp; if =
(!NSIsEmptyRect(r))</div><div>&nbsp; &nbsp; {</div><div>&nbsp; &nbsp; =
&nbsp; r2 =3D r;</div><div>&nbsp; &nbsp; &nbsp; r2.size.width =3D 1; =
&nbsp;// Minimal width for caret positioning</div><div>&nbsp; &nbsp; =
&nbsp; [curLayoutManager setExtraLineFragmentRect: r</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; usedRect: =
r2</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;textContainer: curTextContainer];</div><div>&nbsp; &nbsp; =
}</div><div>}</div><div><br></div><div>/*</div><div>&nbsp;* Helper for =
line height calculations.</div><div>&nbsp;* Updates *lineHeight to =
newHeight if newHeight is larger (and within max).</div><div>&nbsp;* =
Returns YES if the line height was =
updated.</div><div>&nbsp;*/</div><div>static inline BOOL =
wantNewLineHeight(CGFloat h, CGFloat *lineHeight, CGFloat =
maxLineHeight)</div><div>{</div><div>&nbsp; CGFloat newHeight =3D =
h;</div><div><br></div><div>&nbsp; if (maxLineHeight &gt; 0 &amp;&amp; =
newHeight &gt; maxLineHeight)</div><div>&nbsp; &nbsp; {</div><div>&nbsp; =
&nbsp; &nbsp; newHeight =3D maxLineHeight;</div><div>&nbsp; &nbsp; =
}</div><div><br></div><div>&nbsp; if (newHeight &gt; =
*lineHeight)</div><div>&nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; =
*lineHeight =3D newHeight;</div><div>&nbsp; &nbsp; &nbsp; return =
YES;</div><div>&nbsp; &nbsp; }</div><div>&nbsp; return =
NO;</div><div>}</div><div><br></div><div>/*</div><div>&nbsp;* CORE =
LAYOUT METHOD</div><div>&nbsp;* Lays out a single line of text, handling =
all complexity of glyph positioning,</div><div>&nbsp;* line breaking, =
attachments, and alignment.</div><div>&nbsp;*</div><div>&nbsp;* =
newParagraph: YES if this is the first line of a =
paragraph</div><div>&nbsp;*</div><div>&nbsp;* Return =
values:</div><div>&nbsp;* &nbsp; 0 - Line completed normally, next glyph =
continues this paragraph</div><div>&nbsp;* &nbsp; 1 - No room in text =
container (line fragments exhausted)</div><div>&nbsp;* &nbsp; 2 - All =
glyphs laid out (end of text)</div><div>&nbsp;* &nbsp; 3 - Line ended =
with newline, next glyph starts new paragraph</div><div>&nbsp;* &nbsp; 4 =
- Ambiguous state (must test before next call - from soft =
invalidation)</div><div>&nbsp;*/</div><div>-(int) =
layoutLineNewParagraph: (BOOL)newParagraph</div><div>{</div><div>&nbsp; =
NSRect rect;</div><div><br></div><div>&nbsp; /* LINE METRICS VARIABLES =
*/</div><div>&nbsp; CGFloat line_height; &nbsp; &nbsp; // Current line =
height (ascender + descender)</div><div>&nbsp; CGFloat max_line_height; =
// Maximum allowed (from paragraph style, 0 =3D =
unlimited)</div><div>&nbsp; CGFloat baseline; &nbsp; &nbsp; &nbsp; =
&nbsp;// Distance from top of line to baseline</div><div>&nbsp; CGFloat =
ascender; &nbsp; &nbsp; &nbsp; &nbsp;// Space needed above baseline (max =
of all glyphs)</div><div>&nbsp; CGFloat descender; &nbsp; &nbsp; &nbsp; =
// Space needed below baseline (max of all =
glyphs)</div><div><br></div><div>&nbsp; /*</div><div>&nbsp; &nbsp;* SOFT =
INVALIDATION CHECK</div><div>&nbsp; &nbsp;* Try to reuse previous layout =
if available and appropriate.</div><div>&nbsp; &nbsp;*/</div><div>&nbsp; =
if ([curTextContainer isSimpleRectangularTextContainer] =
&amp;&amp;</div><div>&nbsp; &nbsp; &nbsp; [curLayoutManager =
_softInvalidateFirstGlyphInTextContainer: curTextContainer] =3D=3D =
curGlyphIndex)</div><div>&nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; =
if ([self _reuseSoftInvalidatedLayout])</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; return 4;</div><div>&nbsp; &nbsp; =
}</div><div><br></div><div>&nbsp; /* Initialize cache at current glyph =
position */</div><div>&nbsp; [self _cacheMoveTo: =
curGlyphIndex];</div><div>&nbsp; if (!cache_length)</div><div>&nbsp; =
&nbsp; [self _cacheGlyphs: CACHE_INITIAL];</div><div>&nbsp; if =
(!cache_length &amp;&amp; at_end)</div><div>&nbsp; &nbsp; =
{</div><div>&nbsp; &nbsp; &nbsp; /* No more glyphs to lay out =
*/</div><div>&nbsp; &nbsp; &nbsp; if (newParagraph)</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
[self _addExtraLineFragment]; &nbsp;// Text ended with =
newline</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; =
&nbsp; return 2;</div><div>&nbsp; &nbsp; =
}</div><div><br></div><div>&nbsp; /* INITIALIZE LINE METRICS from first =
glyph's font */</div><div>&nbsp; {</div><div>&nbsp; &nbsp; CGFloat min =3D=
 [curParagraphStyle minimumLineHeight];</div><div>&nbsp; &nbsp; =
max_line_height =3D [curParagraphStyle =
maximumLineHeight];</div><div><br></div><div>&nbsp; &nbsp; /* Sanity: =
max must be &gt;=3D min if both are specified */</div><div>&nbsp; &nbsp; =
if (max_line_height &gt; 0 &amp;&amp; max_line_height &lt; =
min)</div><div>&nbsp; &nbsp; &nbsp; max_line_height =3D =
min;</div><div><br></div><div>&nbsp; &nbsp; line_height =3D =
[cache-&gt;font defaultLineHeightForFont];</div><div>&nbsp; &nbsp; =
ascender =3D [cache-&gt;font ascender];</div><div>&nbsp; &nbsp; =
descender =3D -[cache-&gt;font =
descender];</div><div><br></div><div>&nbsp; &nbsp; if (line_height &lt; =
min)</div><div>&nbsp; &nbsp; &nbsp; line_height =3D =
min;</div><div><br></div><div>&nbsp; &nbsp; if (max_line_height &gt; 0 =
&amp;&amp; line_height &gt; max_line_height)</div><div>&nbsp; &nbsp; =
&nbsp; line_height =3D max_line_height;</div><div>&nbsp; =
}</div><div><br></div><div>&nbsp; /*</div><div>&nbsp; &nbsp;* LINE =
FRAGMENT ACQUISITION</div><div>&nbsp; &nbsp;* Get rectangles from text =
container until we have room for at least</div><div>&nbsp; &nbsp;* one =
glyph. If line height increases due to large glyphs, we =
restart</div><div>&nbsp; &nbsp;* this process since the rectangles might =
change.</div><div>&nbsp; &nbsp;*/</div><div>restart: =
;</div><div><br></div><div>&nbsp; do</div><div>&nbsp; &nbsp; =
{</div><div>&nbsp; &nbsp; &nbsp; NSRect =
remain;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; remain =3D [self =
_getProposedRectFor: newParagraph</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
withLineHeight: line_height];</div><div><br></div><div>&nbsp; &nbsp; =
&nbsp; /*</div><div>&nbsp; &nbsp; &nbsp; &nbsp;* Build list of line =
fragment rects for this line.</div><div>&nbsp; &nbsp; &nbsp; &nbsp;* A =
line may have multiple fragments when flowing around =
shapes.</div><div>&nbsp; &nbsp; &nbsp; &nbsp;* TODO: This builds all =
rects in advance which might be inefficient</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp;* for containers with many exclusions (e.g., narrow =
columns).</div><div>&nbsp; &nbsp; &nbsp; &nbsp;*/</div><div>&nbsp; =
&nbsp; &nbsp; line_frags_num =3D 0;</div><div>&nbsp; &nbsp; &nbsp; rect =
=3D [curTextContainer lineFragmentRectForProposedRect: =
remain</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sweepDirection: =
NSLineSweepRight</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;movementDirection: =
NSLineMovesDown</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;remainingRect: &amp;remain];</div><div>&nbsp; &nbsp; &nbsp; while =
(!NSIsEmptyRect(rect))</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
line_frags_num++;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if =
(line_frags_num &gt; line_frags_size)</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; line_frags_size +=3D 2;</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; line_frags =3D realloc(line_frags, =
sizeof(line_frag_t) * line_frags_size);</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
line_frags[line_frags_num - 1].rect =3D =
rect;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rect =3D=
 [curTextContainer lineFragmentRectForProposedRect: =
remain</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sweepDirection: =
NSLineSweepRight</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;movementDirection: NSLineDoesntMove</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp;remainingRect: &amp;remain];</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; if (line_frags_num =
=3D=3D 0)</div><div>&nbsp; &nbsp; &nbsp; &nbsp; {</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; /* No fragments available - container might =
be too small */</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if =
(curPoint.y =3D=3D 0.0 &amp;&amp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; line_height &gt; [curTextContainer =
containerSize].height &amp;&amp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; [curTextContainer containerSize].height &gt; =
0.0)</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* =
Emergency: shrink line height to fit at least one line =
*/</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
line_height =3D [curTextContainer =
containerSize].height;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; max_line_height =3D line_height;</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; return 1; &nbsp;// No room in container</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp; while =
(line_frags_num =3D=3D 0);</div><div><br></div><div>&nbsp; =
/*</div><div>&nbsp; &nbsp;* MAIN GLYPH LAYOUT LOOP</div><div>&nbsp; =
&nbsp;* Positions each glyph in the line fragments, =
handling:</div><div>&nbsp; &nbsp;* &nbsp; - Font changes and metric =
updates</div><div>&nbsp; &nbsp;* &nbsp; - Kerning and baseline =
adjustments</div><div>&nbsp; &nbsp;* &nbsp; - Superscript/subscript =
positioning</div><div>&nbsp; &nbsp;* &nbsp; - Tab stops</div><div>&nbsp; =
&nbsp;* &nbsp; - Text attachments (images, etc.)</div><div>&nbsp; =
&nbsp;* &nbsp; - Line breaking when fragments fill up</div><div>&nbsp; =
&nbsp;*/</div><div>&nbsp; {</div><div>&nbsp; &nbsp; unsigned int i =3D =
0;</div><div>&nbsp; &nbsp; glyph_cache_t =
*g;</div><div><br></div><div>&nbsp; &nbsp; NSPoint p; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Current glyph position (relative to =
line fragment)</div><div>&nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; =
NSFont *f =3D cache-&gt;font;</div><div><br></div><div>&nbsp; &nbsp; =
CGFloat f_ascender =3D [f ascender];</div><div>&nbsp; &nbsp; CGFloat =
f_descender =3D -[f descender];</div><div><br></div><div>&nbsp; &nbsp; =
NSGlyph last_glyph =3D NSNullGlyph; &nbsp;// For kerning =
calculations</div><div>&nbsp; &nbsp; NSPoint =
last_p;</div><div><br></div><div>&nbsp; &nbsp; unsigned int =
firstGlyphIndex; &nbsp; &nbsp; &nbsp;// First glyph in current line =
fragment</div><div>&nbsp; &nbsp; line_frag_t *lf =3D line_frags; &nbsp; =
&nbsp; &nbsp;// Current line fragment</div><div>&nbsp; &nbsp; int lfi =3D =
0; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; // Line fragment index</div><div><br></div><div>&nbsp; &nbsp; =
BOOL prev_had_non_nominal_width; &nbsp; // Track if previous glyph had =
custom spacing</div><div><br></div><div><br></div><div>&nbsp; &nbsp; =
last_p =3D p =3D NSMakePoint(0, 0);</div><div><br></div><div>&nbsp; =
&nbsp; g =3D cache;</div><div>&nbsp; &nbsp; firstGlyphIndex =3D =
0;</div><div>&nbsp; &nbsp; prev_had_non_nominal_width =3D =
NO;</div><div><br></div><div>&nbsp; &nbsp; while (1)</div><div>&nbsp; =
&nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; BOOL =
doesGlyphFitInLine =3D YES;</div><div><br></div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; /* Ensure we have cached glyphs to process =
*/</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>if (i &gt;=3D cache_length)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> =
&nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;if =
(at_end)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; =
&nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>newParagraph =3D =
NO;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>break; &nbsp;// End of text</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;[self _cacheGlyphs: =
cache_length + CACHE_STEP];</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;if (i &gt;=3D =
cache_length)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; =
&nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>newParagraph =3D =
NO;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>break; &nbsp;// No more glyphs available</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;g =3D cache + =
i;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span> &nbsp;}</div><div><br></div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>/*</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> * FONT =
CHANGE HANDLING</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> * Update ascender/descender =
tracking when font changes.</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> * Reset last_glyph to disable =
kerning across font boundaries.</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> */</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span>if =
(g-&gt;font !=3D f)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;{</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;f =3D g-&gt;font;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;f_ascender =3D [f =
ascender];</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;f_descender =3D -[f =
descender];</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;last_glyph =3D =
NSNullGlyph;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> =
&nbsp;}</div><div><br></div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>/* Apply explicit kerning if =
specified in attributes */</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>g-&gt;nominal =3D =
!prev_had_non_nominal_width;</div><div><br></div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span>if =
(g-&gt;attributes.explicit_kern &amp;&amp;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;g-&gt;attributes.kern !=3D 0)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> =
&nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;p.x +=3D =
g-&gt;attributes.kern;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;g-&gt;nominal =3D =
NO;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span> &nbsp;}</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; /* =
Check if glyph fits in current line fragment width */</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; doesGlyphFitInLine =3D !((i &gt; firstGlyphIndex) =
&amp;&amp; (p.x + g-&gt;size.width &gt; =
lf-&gt;rect.size.width));</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if =
(doesGlyphFitInLine)</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* Calculate =
vertical position with baseline adjustments */</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; CGFloat y =3D =
0;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* =
Apply superscript offset (negative =3D up in flipped coords) =
*/</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if =
(g-&gt;attributes.superscript)</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; y -=3D g-&gt;attributes.superscript * [f =
xHeight];</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* Apply explicit =
baseline offset */</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
if (g-&gt;attributes.baseline_offset)</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; y +=3D =
g-&gt;attributes.baseline_offset;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; }</div><div><br></div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; if (y !=3D p.y)</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; p.y =3D y;</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; g-&gt;nominal =3D NO; &nbsp;// =
Non-standard vertical position</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* =
Update line metrics based on this glyph */</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; if (f_ascender &gt; =
ascender)</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
ascender =3D f_ascender;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; if (f_descender &gt; descender)</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; descender =3D =
f_descender;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; /* Adjust for superscript/subscript height requirements =
*/</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (y &lt; 0 =
&amp;&amp; f_ascender - y &gt; ascender)</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; ascender =3D f_ascender - =
y;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (y &gt; 0 =
&amp;&amp; f_descender + y &gt; descender)</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; descender =3D f_descender + =
y;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* =
If metrics changed, check if we need to restart with new line height =
*/</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if =
(wantNewLineHeight(ascender + descender, &amp;line_height, =
max_line_height))</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; goto restart;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
}</div><div><br></div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>/* CONTROL GLYPH HANDLING =
(newlines, tabs, etc.) */</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>if (g-&gt;g =3D=3D =
NSControlGlyph)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;{</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;unichar ch =3D [[curTextStorage string] characterAtIndex: =
g-&gt;char_index];</div><div><br></div><div><span class=3D"Apple-tab-span"=
 style=3D"white-space:pre">	</span> &nbsp; &nbsp;g-&gt;pos =3D =
p;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span> &nbsp; &nbsp;g-&gt;size.width =3D 0;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;g-&gt;dont_show =3D YES; &nbsp;// Control glyphs don't =
render</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">=
	</span> &nbsp; &nbsp;g-&gt;nominal =3D =
!prev_had_non_nominal_width;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;i++;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;g++;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;last_glyph =3D =
NSNullGlyph;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;prev_had_non_nominal_width =3D NO;</div><div><br></div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;/* NEWLINE: End this line, start new paragraph */</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;if (ch =3D=3D 0xa) // new line</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>newParagraph =3D =
YES;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
	</span>break;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; =
&nbsp;}</div><div><br></div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;/* TAB: Advance to =
next tab stop */</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;if (ch =3D=3D 0x9) =
// horiz. tab</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; =
&nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>NSArray *tabs =3D =
[curParagraphStyle tabStops];</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>NSTextTab *tab =3D =
nil;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
	</span>CGFloat defaultInterval =3D [curParagraphStyle =
defaultTabInterval];</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>if (defaultInterval =3D=3D =
0.0)</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; defaultInterval =3D 100.0; &nbsp;// Reasonable =
default</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; }</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>unsigned =
tabIndex;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; unsigned tabCount =3D [tabs count];</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* Find next tab stop after =
current position */</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>for (tabIndex =3D 0; =
tabIndex &lt; tabCount; tabIndex++)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		</span> =
&nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp; &nbsp;tab =3D =
[tabs objectAtIndex: tabIndex];</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp; &nbsp;if ([tab =
location] &gt; p.x + lf-&gt;rect.origin.x)</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; break;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		</span> =
&nbsp;}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>if (tabIndex =3D=3D =
tabCount)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp;{</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		</span> =
&nbsp; &nbsp;/* Past last explicit tab stop - use default interval =
*/</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span> &nbsp; &nbsp;p.x =3D (floor(p.x / defaultInterval) + 1.0) * =
defaultInterval;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp;}</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>else</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp;{</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		</span> =
&nbsp; &nbsp;p.x =3D [tab location] - =
lf-&gt;rect.origin.x;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp;}</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>prev_had_non_nominal_width =3D YES;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>continue;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; =
&nbsp;}</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; /* Unknown control character - log and ignore */</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;NSDebugLLog(@"GSHorizontalTypesetter",</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;@"ignoring unknown control character %04x\n", =
ch);</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span> &nbsp; &nbsp;continue;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> =
&nbsp;}</div><div><br></div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>/* TEXT ATTACHMENT HANDLING =
(images, files, etc.) */</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>if (g-&gt;g =3D=3D =
GSAttachmentGlyph)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;{</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;NSTextAttachment *attach;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;NSTextAttachmentCell *cell;</div><div><span class=3D"Apple-tab-span"=
 style=3D"white-space:pre">	</span> &nbsp; &nbsp;NSRect =
r;</div><div><br></div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;attach =3D =
[curTextStorage attribute: NSAttachmentAttributeName</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;atIndex: g-&gt;char_index</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;effectiveRange: NULL];</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;cell =3D (NSTextAttachmentCell*)[attach =
attachmentCell];</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;if =
(!cell)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; =
&nbsp;{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; /* No cell for attachment - treat as zero-width invisible glyph =
*/</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>g-&gt;pos =3D p;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>g-&gt;size =3D =
NSMakeSize(0, 0);</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>g-&gt;dont_show =3D =
YES;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
	</span>g-&gt;nominal =3D YES;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>i++;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>g++;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>last_glyph =3D NSNullGlyph;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>continue;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; =
&nbsp;}</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; /* Calculate baseline position for attachment alignment =
*/</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; baseline =3D =
line_height - descender;</div><div><br></div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;/* Ask attachment cell for its desired frame */</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;r =3D [cell cellFrameForTextContainer: =
curTextContainer</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> =
&nbsp;proposedLineFragment: lf-&gt;rect</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		</span> =
&nbsp;glyphPosition: NSMakePoint(p.x,</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">				=
	</span> &nbsp; &nbsp; lf-&gt;rect.size.height - =
baseline)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp;characterIndex: =
g-&gt;char_index];</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; /* Check if attachment fits in current fragment =
*/</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
doesGlyphFitInLine =3D !((i &gt; firstGlyphIndex) &amp;&amp; (p.x + =
NSMaxX(r) &gt; lf-&gt;rect.size.width));</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; if (doesGlyphFitInLine)</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* Update line metrics for attachment =
size */</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; if (-NSMinY(r) &gt; descender)</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; descender =3D =
-NSMinY(r);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; if (NSMaxY(r) &gt; ascender)</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ascender =3D =
NSMaxY(r);</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; /* Check if attachment forces line height increase =
*/</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if =
(wantNewLineHeight(ascender + descender, &amp;line_height, =
max_line_height))</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; goto restart;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; }</div><div><br></div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; /* Position attachment (note: r is upside-down =
relative to our coords) */</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; g-&gt;size =3D r.size;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; g-&gt;pos.x =3D p.x + r.origin.x;</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; g-&gt;pos.y =3D p.y - =
r.origin.y;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; p.x =3D g-&gt;pos.x + g-&gt;size.width;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;g-&gt;nominal =3D NO; &nbsp;// Attachments always have custom =
positioning</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;}</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>else</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;{</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; /* STANDARD GLYPH: Just use cached =
advancement */</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* =
TODO: Kerning is commented out as a bottleneck - needs optimization =
*/</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span> &nbsp; &nbsp;last_p =3D g-&gt;pos =3D p;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;p.x +=3D g-&gt;size.width;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> =
&nbsp;}</div><div><br></div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>/* LINE BREAKING: Glyph didn't =
fit in current fragment */</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>if =
(!doesGlyphFitInLine)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;{</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;switch ([curParagraphStyle lineBreakMode])</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; =
&nbsp;default:</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; &nbsp;case =
NSLineBreakByCharWrapping:</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; /* Break immediately before current glyph =
*/</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>lf-&gt;lastGlyphIndex =3D i;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>break;</div><div><br></div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; &nbsp;case =
NSLineBreakByWordWrapping:</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; /* Search backward for word boundary =
*/</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>lf-&gt;lastGlyphIndex =3D [self breakLineByWordWrappingBefore: =
cache_base + i] - cache_base;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>if (lf-&gt;lastGlyphIndex =
&lt;=3D firstGlyphIndex)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp;{</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // No =
word boundary found - fall back to character wrapping</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
lf-&gt;lastGlyphIndex =3D i;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>break;</div><div><br></div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; &nbsp;case =
NSLineBreakByTruncatingHead:</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; &nbsp;case =
NSLineBreakByTruncatingMiddle:</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; &nbsp;case =
NSLineBreakByTruncatingTail:</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; &nbsp;case =
NSLineBreakByClipping:</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; /* CLIPPING/TRUNCATING: Hide overflowing glyphs =
*/</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>g-&gt;outside_line_frag =3D YES;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>while (1)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp;{</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		</span> =
&nbsp; &nbsp;i++;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp; =
&nbsp;g++;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp; &nbsp;if (i &gt;=3D=
 cache_length)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp; &nbsp; =
&nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">			</span>if =
(at_end)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">			</span> =
&nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">			</span> &nbsp; =
&nbsp;newParagraph =3D NO;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">			</span> &nbsp; =
&nbsp;i--;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">			</span> &nbsp; =
&nbsp;break;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">			</span> =
&nbsp;}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">			</span>[self =
_cacheGlyphs: cache_length + CACHE_STEP];</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">			=
</span>if (i &gt;=3D cache_length)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">			=
</span> &nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">			</span> &nbsp; =
&nbsp;newParagraph =3D NO;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">			</span> &nbsp; =
&nbsp;i--;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">			</span> &nbsp; =
&nbsp;break;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">			</span> =
&nbsp;}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">			</span>g =3D cache + =
i;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span> &nbsp; &nbsp; &nbsp;}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp; =
&nbsp;g-&gt;dont_show =3D YES;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp; &nbsp;g-&gt;pos =3D=
 p;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; /* Stop at paragraph break */</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		</span> =
&nbsp; &nbsp;if (g-&gt;g =3D=3D NSControlGlyph</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">			=
</span>&amp;&amp; [[curTextStorage string]</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">			=
</span> &nbsp; &nbsp; &nbsp; characterAtIndex: g-&gt;char_index] =3D=3D =
0xa)</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
	</span> &nbsp; &nbsp; &nbsp;break;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		</span> =
&nbsp;}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>lf-&gt;lastGlyphIndex =3D =
i + 1;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">=
		</span>break;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; =
&nbsp;}</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; /*</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* =
SAFETY: Ensure at least one glyph per fragment.</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* Prevents infinite loops when =
container is narrower than a single glyph.</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*/</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;if (lf-&gt;lastGlyphIndex &lt;=3D firstGlyphIndex)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;lf-&gt;lastGlyphIndex =3D i + =
1;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* =
Reset position for next line fragment */</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;last_p =3D p =3D NSMakePoint(0, 0);</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;i =3D lf-&gt;lastGlyphIndex;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;g =3D cache + i;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;lf-&gt;last_used =3D =
g[-1].pos.x + g[-1].size.width;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;last_glyph =3D =
NSNullGlyph;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;prev_had_non_nominal_width =3D NO;</div><div><br></div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* Move to next line fragment or end =
line if exhausted */</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;lf++;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;lfi++;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;if (lfi =3D=3D =
line_frags_num)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; =
&nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>newParagraph =3D =
NO;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>break;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; =
&nbsp;}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;firstGlyphIndex =3D =
i;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span> &nbsp;}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>else</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> =
&nbsp;{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* Glyph fit =
- advance to next */</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;last_glyph =3D =
g-&gt;g;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;if (last_glyph =3D=3D=
 GSAttachmentGlyph)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; =
&nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>last_glyph =3D =
NSNullGlyph;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		=
</span>prev_had_non_nominal_width =3D YES;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;else</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; =
&nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		=
</span>prev_had_non_nominal_width =3D NO;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;i++;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;g++;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;}</div><div>&nbsp; &nbsp; =
&nbsp; }</div><div>&nbsp; &nbsp; /* END MAIN LAYOUT LOOP =
*/</div><div><br></div><div>&nbsp; &nbsp; /* ALIGNMENT PASS: Apply =
paragraph alignment to positioned glyphs */</div><div>&nbsp; &nbsp; if =
(lfi !=3D line_frags_num)</div><div>&nbsp; &nbsp; &nbsp; =
{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; /* Line filled exactly - apply =
alignment */</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>lf-&gt;lastGlyphIndex =3D =
i;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>lf-&gt;last_used =3D p.x;</div><div><br></div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span>if =
([curParagraphStyle alignment] =3D=3D =
NSRightTextAlignment)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;[self rightAlignLine: =
line_frags : line_frags_num];</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>else if ([curParagraphStyle =
alignment] =3D=3D NSCenterTextAlignment)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> =
&nbsp;[self centerAlignLine: line_frags : =
line_frags_num];</div><div>&nbsp; &nbsp; &nbsp; }</div><div>&nbsp; =
&nbsp; else</div><div>&nbsp; &nbsp; &nbsp; {</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; /* Line broke early - check for justification or alignment =
*/</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>if ([curParagraphStyle lineBreakMode] =3D=3D =
NSLineBreakByWordWrapping &amp;&amp;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;[curParagraphStyle alignment] =3D=3D =
NSJustifiedTextAlignment)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;[self fullJustifyLine: =
line_frags : line_frags_num];</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>else if ([curParagraphStyle =
alignment] =3D=3D NSRightTextAlignment)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> =
&nbsp;[self rightAlignLine: line_frags : =
line_frags_num];</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>else if ([curParagraphStyle =
alignment] =3D=3D NSCenterTextAlignment)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> =
&nbsp;[self centerAlignLine: line_frags : =
line_frags_num];</div><div><br></div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>lfi--;</div><div>&nbsp; &nbsp; =
&nbsp; }</div><div><br></div><div>&nbsp; &nbsp; /* COMMIT LAYOUT TO =
LAYOUT MANAGER */</div><div>&nbsp; &nbsp; [curLayoutManager =
setTextContainer: curTextContainer</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		</span> =
&nbsp; &nbsp; &nbsp;forGlyphRange: NSMakeRange(cache_base, =
i)];</div><div>&nbsp; &nbsp; curGlyphIndex =3D i + =
cache_base;</div><div>&nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; =
{</div><div>&nbsp; &nbsp; &nbsp; line_frag_t *lf;</div><div>&nbsp; =
&nbsp; &nbsp; NSPoint p;</div><div>&nbsp; &nbsp; &nbsp; unsigned int =
lineFragCounter, lineFragCounter2;</div><div>&nbsp; &nbsp; &nbsp; =
glyph_cache_t *g;</div><div>&nbsp; &nbsp; &nbsp; NSRect =
used_rect;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; /* Final =
baseline calculation */</div><div>&nbsp; &nbsp; &nbsp; baseline =3D =
line_height - descender;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; =
/* Iterate through line fragments and register each with layout manager =
*/</div><div>&nbsp; &nbsp; &nbsp; for (lf =3D line_frags, =
lineFragCounter =3D 0, g =3D cache; lfi &gt;=3D 0; lfi--, =
lf++)</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* Calculate used =
rect (actual ink bounds) vs fragment rect (available space) =
*/</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span> &nbsp;used_rect.origin.x =3D g-&gt;pos.x + =
lf-&gt;rect.origin.x;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;used_rect.size.width =3D =
lf-&gt;last_used - g-&gt;pos.x;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;used_rect.origin.y =3D =
lf-&gt;rect.origin.y;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;used_rect.size.height =3D =
lf-&gt;rect.size.height;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; /* Register the line fragment */</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> =
&nbsp;[curLayoutManager setLineFragmentRect: lf-&gt;rect</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">			=
</span> &nbsp; &nbsp;forGlyphRange: NSMakeRange(cache_base + =
lineFragCounter, lf-&gt;lastGlyphIndex - =
lineFragCounter)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">			</span> &nbsp; =
&nbsp;usedRect: used_rect];</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* Register =
individual glyph positions */</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;p =3D =
g-&gt;pos;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;p.y +=3D baseline; =
&nbsp;// Convert from relative to absolute position</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> =
&nbsp;lineFragCounter2 =3D lineFragCounter;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> =
&nbsp;while (lineFragCounter &lt; lf-&gt;lastGlyphIndex)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* =
Set flags for special glyph handling */</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;if (g-&gt;outside_line_frag)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp;[curLayoutManager =
setDrawsOutsideLineFragment: YES</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp; =
&nbsp;forGlyphAtIndex: cache_base + lineFragCounter];</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; &nbsp;if =
(g-&gt;dont_show)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>{</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		</span> =
&nbsp;[curLayoutManager setNotShownAttribute: YES</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">				=
	</span> forGlyphAtIndex: cache_base + =
lineFragCounter];</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>}</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; /* Register glyph runs with non-nominal =
positioning */</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; &nbsp;if =
(!g-&gt;nominal &amp;&amp; lineFragCounter !=3D =
lineFragCounter2)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>{</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		</span> =
&nbsp;[curLayoutManager setLocation: p</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">				=
</span> &nbsp; &nbsp;forStartOfGlyphRange: NSMakeRange(cache_base + =
lineFragCounter2, lineFragCounter - lineFragCounter2)];</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		</span> =
&nbsp;if (g[-1].g =3D=3D GSAttachmentGlyph)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		</span> =
&nbsp; &nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp; &nbsp; =
&nbsp;[curLayoutManager setAttachmentSize: g[-1].size</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">			=
</span>forGlyphRange: NSMakeRange(cache_base + lineFragCounter2, =
lineFragCounter - lineFragCounter2)];</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		</span> =
&nbsp; &nbsp;}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp;p =3D =
g-&gt;pos;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp;p.y +=3D =
baseline;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp;lineFragCounter2 =3D=
 lineFragCounter;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>}</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;lineFragCounter++;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; =
&nbsp;g++;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;}</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; /* Register final run in fragment =
*/</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span> &nbsp;if (lineFragCounter !=3D lineFragCounter2)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; =
&nbsp;[curLayoutManager setLocation: p</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">				=
</span>forStartOfGlyphRange: NSMakeRange(cache_base + lineFragCounter2, =
lineFragCounter - lineFragCounter2)];</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;if (g[-1].g =3D=3D GSAttachmentGlyph)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp;[curLayoutManager =
setAttachmentSize: g[-1].size</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp; =
&nbsp;forGlyphRange: NSMakeRange(cache_base + lineFragCounter2, =
lineFragCounter - lineFragCounter2)];</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		=
</span>}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;}</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>}</div><div>&nbsp; &nbsp; }</div><div>&nbsp; =
}</div><div><br></div><div>&nbsp; /* Advance current point to next line =
*/</div><div>&nbsp; curPoint =3D NSMakePoint(0, =
NSMaxY(line_frags-&gt;rect));</div><div><br></div><div>&nbsp; if =
(newParagraph)</div><div>&nbsp; &nbsp; return 3;</div><div>&nbsp; =
else</div><div>&nbsp; &nbsp; return =
0;</div><div>}</div><div><br></div><div><br></div><div>/*</div><div>&nbsp;=
* MAIN ENTRY POINT</div><div>&nbsp;* Lays out multiple lines of glyphs =
into the text container.</div><div>&nbsp;*</div><div>&nbsp;* =
Parameters:</div><div>&nbsp;* &nbsp; layoutManager: &nbsp; &nbsp; &nbsp; =
&nbsp; The GSLayoutManager managing this text</div><div>&nbsp;* &nbsp; =
textContainer: &nbsp; &nbsp; &nbsp; &nbsp; The container defining layout =
geometry</div><div>&nbsp;* &nbsp; glyphIndex: &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp;Starting glyph index for this layout =
operation</div><div>&nbsp;* &nbsp; previousLineFragRect: &nbsp;Rectangle =
of the previous line (for positioning)</div><div>&nbsp;* &nbsp; =
nextGlyphIndex: &nbsp; &nbsp; &nbsp; &nbsp;OUTPUT - index of first =
unlaid glyph</div><div>&nbsp;* &nbsp; howMany: &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; Maximum number of lines to layout (0 =3D =
unlimited)</div><div>&nbsp;*</div><div>&nbsp;* Return =
values:</div><div>&nbsp;* &nbsp; 0 - Layout completed successfully (more =
glyphs may remain)</div><div>&nbsp;* &nbsp; 1 - Text container is =
full</div><div>&nbsp;* &nbsp; 2 - All glyphs have been laid =
out</div><div>&nbsp;*/</div><div>-(int) layoutGlyphsInLayoutManager: =
(GSLayoutManager *)layoutManager</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp; inTextContainer: =
(NSTextContainer *)textContainer</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; =
&nbsp;startingAtGlyphIndex: (unsigned int)glyphIndex</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> =
&nbsp;previousLineFragmentRect: =
(NSRect)previousLineFragRect</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span> &nbsp; =
&nbsp;nextGlyphIndex: (unsigned int *)nextGlyphIndex</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; numberOfLineFragments: (unsigned =
int)howMany</div><div>{</div><div>&nbsp; int ret, =
real_ret;</div><div>&nbsp; BOOL =
newParagraph;</div><div><br></div><div>&nbsp; /* REENTRANCY HANDLING =
*/</div><div>&nbsp; if (![lock tryLock])</div><div>&nbsp; &nbsp; =
{</div><div>&nbsp; &nbsp; &nbsp; /* Already in use - create temporary =
instance to handle nested call */</div><div>&nbsp; &nbsp; &nbsp; =
GSHorizontalTypesetter *temp;</div><div><br></div><div>&nbsp; &nbsp; =
&nbsp; temp =3D [[object_getClass(self) alloc] init];</div><div>&nbsp; =
&nbsp; &nbsp; ret =3D [temp layoutGlyphsInLayoutManager: =
layoutManager</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">			</span> &nbsp; &nbsp; =
&nbsp;inTextContainer: textContainer</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">			=
</span> startingAtGlyphIndex: glyphIndex</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">		</span> =
&nbsp; &nbsp; previousLineFragmentRect: =
previousLineFragRect</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">			</span> &nbsp; &nbsp; =
&nbsp; nextGlyphIndex: nextGlyphIndex</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">			=
</span>numberOfLineFragments: howMany];</div><div>&nbsp; &nbsp; &nbsp; =
DESTROY(temp);</div><div>&nbsp; &nbsp; &nbsp; return =
ret;</div><div>&nbsp; &nbsp; =
}</div><div><br></div><div>NS_DURING</div><div>&nbsp; /* Initialize =
layout context */</div><div>&nbsp; curLayoutManager =3D =
layoutManager;</div><div>&nbsp; curTextContainer =3D =
textContainer;</div><div>&nbsp; curTextStorage =3D [layoutManager =
textStorage];</div><div>&nbsp; curGlyphIndex =3D =
glyphIndex;</div><div><br></div><div>&nbsp; [self =
_cacheClear];</div><div><br></div><div>&nbsp; real_ret =3D 4; &nbsp;// =
Initial state forces paragraph check</div><div>&nbsp; curPoint =3D =
NSMakePoint(0, =
NSMaxY(previousLineFragRect));</div><div>&nbsp;&nbsp;</div><div>&nbsp; =
/* Main layout loop - process lines until limit or completion =
*/</div><div>&nbsp; while (1)</div><div>&nbsp; &nbsp; {</div><div>&nbsp; =
&nbsp; &nbsp; /* Determine if we're starting a new paragraph =
*/</div><div>&nbsp; &nbsp; &nbsp; if (real_ret =3D=3D 4)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;if =
(!curGlyphIndex)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp;{</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;newParagraph =3D YES; &nbsp;// Very first glyph in =
text</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span> &nbsp; &nbsp;}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;else</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp;{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* =
Check if previous character was a newline */</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;unsigned int chi;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; &nbsp;unichar =
ch;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span> &nbsp; &nbsp; &nbsp;chi =3D [curLayoutManager =
characterRangeForGlyphRange: NSMakeRange(curGlyphIndex - 1, =
1)</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">		=
				</span> actualGlyphRange: =
NULL].location;</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; &nbsp;ch =3D =
[[curTextStorage string] characterAtIndex: chi];</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span></div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp; &nbsp; &nbsp;if (ch =3D=3D =
'\n')</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
	</span>newParagraph =3D YES;</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> &nbsp; =
&nbsp; &nbsp;else</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">		</span>newParagraph =3D =
NO;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span> &nbsp; &nbsp;}</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>}</div><div>&nbsp; &nbsp; &nbsp; =
else if (real_ret =3D=3D 3)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>{</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> =
&nbsp;newParagraph =3D YES; &nbsp;// Previous line ended with =
newline</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>}</div><div>&nbsp; &nbsp; &nbsp; =
else</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>{</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span> &nbsp;newParagraph =3D =
NO;</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>}</div><div><br></div><div>&nbsp; &nbsp; &nbsp; /* Layout one =
line */</div><div>&nbsp; &nbsp; &nbsp; ret =3D [self =
layoutLineNewParagraph: newParagraph];</div><div><br></div><div>&nbsp; =
&nbsp; &nbsp; /* Normalize return codes 3 and 4 to 0 for loop control =
*/</div><div>&nbsp; &nbsp; &nbsp; real_ret =3D ret;</div><div>&nbsp; =
&nbsp; &nbsp; if (ret =3D=3D 3 || ret =3D=3D 4)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span>ret =3D =
0;</div><div><br></div><div>&nbsp; &nbsp; &nbsp; if =
(ret)</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	=
</span>break; &nbsp;// Error or completion (1 or =
2)</div><div><br></div><div>&nbsp; &nbsp; &nbsp; if =
(howMany)</div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	</span>if (!--howMany)</div><div><span =
class=3D"Apple-tab-span" style=3D"white-space:pre">	</span> =
&nbsp;break; &nbsp;// Reached line limit</div><div>&nbsp; =
&nbsp;}</div><div><br></div><div>&nbsp; *nextGlyphIndex =3D =
curGlyphIndex;</div><div>NS_HANDLER</div><div>&nbsp; /* Exception =
handling: log, unlock, and re-raise */</div><div>&nbsp; =
NSLog(@"GSHorizontalTypesetter - %@", [localException =
reason]);</div><div>&nbsp; [lock unlock];</div><div>&nbsp; =
[localException raise];</div><div>&nbsp; ret=3D0; /* Unreachable, but =
silences compiler warnings =
*/</div><div>NS_ENDHANDLER</div><div>&nbsp;&nbsp;</div><div>&nbsp; [lock =
unlock];</div><div>&nbsp; return =
ret;</div><div>}</div><div><br></div><div>@end</div><div>```</div><div><br=
></div><div>## Summary</div><div><br></div><div>This is a sophisticated =
horizontal typesetter for GNUstep implementing the full Cocoa text =
layout architecture. Key features =
include:</div><div><br></div><div>**Architecture:**</div><div>- =
**Thread-local singleton** pattern for performance without locking =
overhead</div><div>- **Reentrancy support** via temporary instance =
creation when nested calls occur</div><div>- **Two-phase caching**: =
First cache glyph attributes, then compute =
positions</div><div><br></div><div>**Layout Algorithm:**</div><div>1. =
**Soft invalidation** check for incremental layout reuse</div><div>2. =
**Line fragment acquisition** from text container (handles complex =
shapes)</div><div>3. **Glyph-by-glyph positioning** with font changes, =
attachments, tabs</div><div>4. **Line breaking** by character or word =
(with CJK support)</div><div>5. **Alignment/justification** pass to =
distribute space</div><div>6. **Commit** to layout manager with precise =
glyph ranges and positions</div><div><br></div><div>**Performance =
Optimizations:**</div><div>- Aggressive caching of glyph metrics and =
attributes</div><div>- Batch glyph processing with expandable =
buffers</div><div>- Inline helper functions for hot paths</div><div>- =
Memmove for cache window sliding rather than =
refetching</div><div><br></div><div>The code handles complex typography =
including bidirectional text support preparation, text attachments, =
multiple line fragments per line, and all standard paragraph =
alignments.</div><div><br></div><div><br></div><div>=E2=80=94=E2=80=94 =
=E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94=
 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =
=E2=80=94=E2=80=94&nbsp;</div><div><br></div><div><br></div><div>Then I =
asked:</div><div><br></div><div><br></div><div>=E2=80=9EWhat =
refactorings do you propose to make that above code you commented better =
readable and simpler to comprehend without making it =
worse?=E2=80=9C</div><div><br></div><div><br></div><div>=E2=80=94=E2=80=94=
 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94=
 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =
=E2=80=94=E2=80=94&nbsp;</div><div><br></div><div><br></div><div><div>I'll=
 analyze this code and propose concrete refactorings to improve =
readability and maintainability. Let me work through this =
systematically.</div><div><br></div><div>## Proposed Refactorings for =
GSHorizontalTypesetter</div><div><br></div><div>### 1. **Extract Magic =
Numbers and Character Constants**</div><div><br></div><div>Replace =
hardcoded hex values with named =
constants:</div><div><br></div><div>```objc</div><div>// Add to top of =
file or private header</div><div>static const unichar kSpaceCharacter =3D =
0x20;</div><div>static const unichar kNewlineCharacter =3D =
0x0a;</div><div>static const unichar kCarriageReturnCharacter =3D =
0x0d;</div><div>static const unichar kTabCharacter =3D =
0x09;</div><div>static const unichar kCJKRangeStart =3D =
0x2ff0;</div><div>static const unichar kCJKRangeEnd =3D =
0x9fff;</div><div>static const CGFloat kDefaultTabInterval =3D =
100.0;</div><div>static const CGFloat kFallbackLineHeight =3D =
15.0;</div><div>static const CGFloat kExtraLineFragmentWidth =3D =
1.0;</div><div>```</div><div><br></div><div>### 2. **Extract Complex =
Conditionals into Meaningful Boolean =
Methods**</div><div><br></div><div>The glyph fitting check appears =
multiple times and is hard to =
read:</div><div><br></div><div>```objc</div><div>// BEFORE: scattered =
throughout code</div><div>doesGlyphFitInLine =3D !((i &gt; =
firstGlyphIndex) &amp;&amp; (p.x + g-&gt;size.width &gt; =
lf-&gt;rect.size.width));</div><div><br></div><div>// AFTER: extracted =
method</div><div>- (BOOL)doesGlyphAtIndex:(unsigned =
int)glyphIndex&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;withWidth:(CGFloat)width&nbsp;</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp;fitInLineFragment:(line_frag_t =
*)fragment</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;afterFirstGlyph:(unsigned =
int)firstIndex</div><div>{</div><div>&nbsp; &nbsp; if (glyphIndex &lt;=3D =
firstIndex) return YES; &nbsp;// First glyph always =
fits</div><div>&nbsp; &nbsp; return (p.x + width &lt;=3D =
fragment-&gt;rect.size.width);</div><div>}</div><div>```</div><div><br></d=
iv><div>### 3. **Replace `goto restart` with Structured =
Loop**</div><div><br></div><div>The `restart` label for line height =
recalculation is a classic goto =
pattern:</div><div><br></div><div>```objc</div><div>// BEFORE: =
goto-based restart</div><div>restart: ;</div><div>do {</div><div>&nbsp; =
&nbsp; // ... calculate fragments ...</div><div>&nbsp; &nbsp; if =
(line_frags_num =3D=3D 0) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (/* =
emergency shrink */) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; line_height =3D ...;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; continue; &nbsp;// or goto restart</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return =
1;</div><div>&nbsp; &nbsp; }</div><div>} while (line_frags_num =3D=3D =
0);</div><div><br></div><div>// ... later ...</div><div>if =
(wantNewLineHeight(...)) goto restart;</div><div><br></div><div>// =
AFTER: extracted method with explicit loop</div><div>- =
(BOOL)_acquireLineFragmentsWithHeight:(CGFloat)lineHeight</div><div>&nbsp;=
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; maxLineHeight:(CGFloat)maxLineHeight</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; newParagraph:(BOOL)newParagraph</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp;resultingHeight:(CGFloat =
*)outHeight</div><div>{</div><div>&nbsp; &nbsp; CGFloat currentHeight =3D =
lineHeight;</div><div>&nbsp; &nbsp; CGFloat maxHeight =3D =
maxLineHeight;</div><div>&nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; =
while (YES) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; [self =
_buildLineFragmentsForHeight:currentHeight =
newParagraph:newParagraph];</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (line_frags_num =
&gt; 0) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *outHeight =
=3D currentHeight;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
return YES; &nbsp;// Success</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
}</div><div>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; // Emergency: container too small for even one =
line</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (curPoint.y =3D=3D 0.0 =
&amp;&amp; currentHeight &gt; containerHeight &amp;&amp; containerHeight =
&gt; 0.0) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
currentHeight =3D containerHeight;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; maxHeight =3D currentHeight;</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; continue; &nbsp;// Retry with shrunk =
height</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return NO; =
&nbsp;// No room in container</div><div>&nbsp; &nbsp; =
}</div><div>}</div><div><br></div><div>// Then in main layout, replace =
goto with:</div><div>while (![self _updateLineHeightIfNeeded:ascender =
descender:descender&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;currentHeight:&amp;line_height&nbsp;</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp;maxHeight:max_line_height]) {</div><div>&nbsp; &nbsp; // =
Restart layout with new height</div><div>&nbsp; &nbsp; if (![self =
_acquireLineFragmentsWithHeight:line_height ...]) {</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; return 1;</div><div>&nbsp; &nbsp; =
}</div><div>&nbsp; &nbsp; // Re-initialize cache if =
needed</div><div>}</div><div>```</div><div><br></div><div>### 4. =
**Extract State Machine Transitions**</div><div><br></div><div>The =
`real_ret` state machine in `layoutGlyphsInLayoutManager:` is =
cryptic:</div><div><br></div><div>```objc</div><div>// BEFORE: confusing =
state tracking</div><div>real_ret =3D 4;</div><div>while (1) =
{</div><div>&nbsp; &nbsp; if (real_ret =3D=3D 4) {</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; // determine newParagraph</div><div>&nbsp; &nbsp; } =
else if (real_ret =3D=3D 3) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
newParagraph =3D YES;</div><div>&nbsp; &nbsp; } else {</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; newParagraph =3D NO;</div><div>&nbsp; &nbsp; =
}</div><div>&nbsp; &nbsp; ret =3D [self =
layoutLineNewParagraph:newParagraph];</div><div>&nbsp; &nbsp; real_ret =3D=
 ret;</div><div>&nbsp; &nbsp; if (ret =3D=3D 3 || ret =3D=3D 4) ret =3D =
0;</div><div>}</div><div><br></div><div>// AFTER: explicit state enum =
and transition method</div><div>typedef NS_ENUM(NSInteger, LayoutState) =
{</div><div>&nbsp; &nbsp; LayoutStateInitial =3D 0, &nbsp; &nbsp; =
&nbsp;// Need to check if new paragraph</div><div>&nbsp; &nbsp; =
LayoutStateNewParagraph, &nbsp; &nbsp; // Previous line ended with =
newline</div><div>&nbsp; &nbsp; LayoutStateContinuing, &nbsp; &nbsp; =
&nbsp; // In middle of paragraph</div><div>&nbsp; &nbsp; =
LayoutStateComplete, &nbsp; &nbsp; &nbsp; &nbsp; // All glyphs laid =
out</div><div>&nbsp; &nbsp; LayoutStateNoRoom &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp;// Container =
full</div><div>};</div><div><br></div><div>- =
(LayoutState)determineNextStateFrom:(LayoutState)previousState&nbsp;</div>=
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; =
lineResult:(int)lineResult</div><div>{</div><div>&nbsp; &nbsp; switch =
(lineResult) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; case 2: return =
LayoutStateComplete; &nbsp; // At end</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; case 1: return LayoutStateNoRoom; &nbsp; &nbsp; // No =
room</div><div>&nbsp; &nbsp; &nbsp; &nbsp; case 3: return =
LayoutStateNewParagraph; // Ended with newline</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; case 0: return LayoutStateContinuing; &nbsp;// Normal line =
break</div><div>&nbsp; &nbsp; &nbsp; &nbsp; case 4: return =
LayoutStateInitial; &nbsp; // Ambiguous, need check</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; default: return =
LayoutStateComplete;</div><div>&nbsp; &nbsp; =
}</div><div>}</div><div><br></div><div>- =
(BOOL)isNewParagraphForState:(LayoutState)state&nbsp;</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
atGlyphIndex:(unsigned int)glyphIndex</div><div>{</div><div>&nbsp; =
&nbsp; switch (state) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; case =
LayoutStateInitial:</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
return [self _glyphStartsNewParagraph:glyphIndex];</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; case LayoutStateNewParagraph:</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return YES;</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; case LayoutStateContinuing:</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; return NO;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; =
default:</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return =
NO;</div><div>&nbsp; &nbsp; =
}</div><div>}</div><div>```</div><div><br></div><div>### 5. **Break Up =
`layoutLineNewParagraph:` into Phased =
Methods**</div><div><br></div><div>This 400+ line method does too much. =
Extract phases:</div><div><br></div><div>```objc</div><div>- =
(int)layoutLineNewParagraph:(BOOL)newParagraph</div><div>{</div><div>&nbsp=
; &nbsp; // Phase 1: Setup and cache initialization</div><div>&nbsp; =
&nbsp; if (![self _prepareLayoutForNewParagraph:newParagraph]) =
{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return [self =
_handleEndOfTextOrContainer];</div><div>&nbsp; &nbsp; }</div><div>&nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; // Phase 2: Acquire line fragments =
(may restart if metrics change)</div><div>&nbsp; &nbsp; CGFloat =
finalLineHeight;</div><div>&nbsp; &nbsp; if (![self =
_acquireLineFragmentsWithHeight:initialLineHeight&nbsp;</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
maxLineHeight:maxLineHeight</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp;newParagraph:newParagraph</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
resultingHeight:&amp;finalLineHeight]) {</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; return 1; // No room</div><div>&nbsp; &nbsp; }</div><div>&nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; // Phase 3: Position glyphs in =
fragments</div><div>&nbsp; &nbsp; LayoutLineResult *result =3D [self =
_positionGlyphsInFragments];</div><div>&nbsp; &nbsp; if =
(result.needsRestart) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; // =
Recursively retry with new height (limited depth to prevent infinite =
loop)</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return [self =
layoutLineNewParagraph:newParagraph];</div><div>&nbsp; &nbsp; =
}</div><div>&nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; // Phase 4: =
Apply alignment</div><div>&nbsp; &nbsp; [self =
_applyAlignmentToLine:result];</div><div>&nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; // Phase 5: Commit to layout =
manager</div><div>&nbsp; &nbsp; [self _commitLayoutResult:result =
lineHeight:finalLineHeight];</div><div>&nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; return result.endedWithNewline ? 3 =
: 0;</div><div>}</div><div>```</div><div><br></div><div>### 6. **Replace =
Anonymous Structs with Named =
Types**</div><div><br></div><div>```objc</div><div>// BEFORE: anonymous =
struct in ivars</div><div>struct {</div><div>&nbsp; &nbsp; BOOL =
explicit_kern;</div><div>&nbsp; &nbsp; float kern;</div><div>&nbsp; =
&nbsp; float baseline_offset;</div><div>&nbsp; &nbsp; int =
superscript;</div><div>} attributes;</div><div><br></div><div>// AFTER: =
named type with documentation</div><div>/**</div><div>&nbsp;* =
GSScriptAttributes collects the typographic attributes that =
affect</div><div>&nbsp;* glyph positioning relative to the =
baseline.</div><div>&nbsp;*/</div><div>typedef struct {</div><div>&nbsp; =
&nbsp; BOOL hasExplicitKern; &nbsp; &nbsp; &nbsp;// YES if =
NSKernAttributeName was specified</div><div>&nbsp; &nbsp; CGFloat =
kernAmount; &nbsp; &nbsp; &nbsp; &nbsp;// Additional spacing between =
glyphs</div><div>&nbsp; &nbsp; CGFloat baselineOffset; &nbsp; &nbsp;// =
Vertical shift from normal baseline (positive =3D up)</div><div>&nbsp; =
&nbsp; NSInteger superscriptLevel; // 0 =3D normal, +1 =3D superscript, =
-1 =3D subscript</div><div>} =
GSScriptAttributes;</div><div><br></div><div>// Usage in class =
becomes:</div><div>GSScriptAttributes =
_currentScriptAttributes;</div><div>```</div><div><br></div><div>### 7. =
**Extract Cache Management to Dedicated =
Class**</div><div><br></div><div>The cache manipulation is complex and =
scattered:</div><div><br></div><div>```objc</div><div>// New class: =
GSGlyphCache</div><div>@interface GSGlyphCache : =
NSObject</div><div>@property (readonly) NSUInteger =
baseIndex;</div><div>@property (readonly) NSUInteger =
count;</div><div>@property (readonly) BOOL =
atEnd;</div><div><br></div><div>- =
(void)repositionToGlyphIndex:(NSUInteger)index&nbsp;</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
layoutManager:(GSLayoutManager *)lm;</div><div>- =
(void)ensureCount:(NSUInteger)count&nbsp;</div><div>&nbsp; &nbsp; =
&nbsp;layoutManager:(GSLayoutManager *)lm;</div><div>- (glyph_cache_t =
*)glyphAtIndex:(NSUInteger)index; &nbsp;// Relative to base</div><div>- =
(void)slideWindowToIndex:(NSUInteger)index;</div><div>@end</div><div>```</=
div><div><br></div><div>### 8. **Replace C Arrays with NSMutableArray or =
Smart Pointer**</div><div><br></div><div>The manual `realloc` management =
is error-prone:</div><div><br></div><div>```objc</div><div>// BEFORE: =
manual C array management</div><div>if (line_frags_num &gt; =
line_frags_size) {</div><div>&nbsp; &nbsp; line_frags_size +=3D =
2;</div><div>&nbsp; &nbsp; line_frags =3D realloc(line_frags, =
sizeof(line_frag_t) * =
line_frags_size);</div><div>}</div><div><br></div><div>// AFTER: use =
NSMutableArray with wrapper object, or at least:</div><div>typedef =
struct {</div><div>&nbsp; &nbsp; line_frag_t *items;</div><div>&nbsp; =
&nbsp; NSUInteger count;</div><div>&nbsp; &nbsp; NSUInteger =
capacity;</div><div>} =
GSLineFragmentArray;</div><div><br></div><div>static inline void =
GSLineFragmentArrayPush(GSLineFragmentArray *array) {</div><div>&nbsp; =
&nbsp; if (array-&gt;count &gt;=3D array-&gt;capacity) =
{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; array-&gt;capacity =3D =
array-&gt;capacity ? array-&gt;capacity * 2 : 4;</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; array-&gt;items =3D realloc(array-&gt;items, =
sizeof(line_frag_t) * array-&gt;capacity);</div><div>&nbsp; &nbsp; =
}</div><div>&nbsp; &nbsp; =
array-&gt;count++;</div><div>}</div><div>```</div><div><br></div><div>### =
9. **Document Return Value Semantics with =
Enum**</div><div><br></div><div>```objc</div><div>// BEFORE: magic =
integer returns</div><div>-(int) layoutLineNewParagraph: =
(BOOL)newParagraph &nbsp;// Returns 0, 1, 2, 3, or =
4</div><div><br></div><div>// AFTER: explicit result =
type</div><div>typedef NS_ENUM(NSInteger, GSLayoutLineResult) =
{</div><div>&nbsp; &nbsp; GSLayoutLineResultContinuing =3D 0, &nbsp; =
&nbsp; &nbsp;// Line complete, more glyphs in paragraph</div><div>&nbsp; =
&nbsp; GSLayoutLineResultNoRoom =3D 1, &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;// Text container exhausted</div><div>&nbsp; &nbsp; =
GSLayoutLineResultEndOfText =3D 2, &nbsp; &nbsp; &nbsp; // All glyphs =
consumed</div><div>&nbsp; &nbsp; GSLayoutLineResultNewParagraph =3D 3, =
&nbsp; &nbsp;// Line ended with newline</div><div>&nbsp; &nbsp; =
GSLayoutLineResultNeedParagraphCheck =3D 4 // Ambiguous, caller must =
check</div><div>};</div><div><br></div><div>- =
(GSLayoutLineResult)layoutLineNewParagraph:(BOOL)newParagraph;</div><div>`=
``</div><div><br></div><div>### 10. **Flatten Nested Conditionals in =
Main Loop**</div><div><br></div><div>The main glyph loop has deeply =
nested conditions. Extract =
handlers:</div><div><br></div><div>```objc</div><div>- =
(BOOL)_handleControlGlyph:(glyph_cache_t *)glyph&nbsp;</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;atPosition:(NSPoint *)position</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; lineFragment:(line_frag_t =
*)fragment</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
newParagraph:(BOOL *)outNewParagraph</div><div>{</div><div>&nbsp; &nbsp; =
unichar ch =3D [[curTextStorage string] =
characterAtIndex:glyph-&gt;char_index];</div><div>&nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; glyph-&gt;pos =3D =
*position;</div><div>&nbsp; &nbsp; glyph-&gt;size.width =3D =
0;</div><div>&nbsp; &nbsp; glyph-&gt;dont_show =3D YES;</div><div>&nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; switch (ch) {</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; case kNewlineCharacter:</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; *outNewParagraph =3D YES;</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return NO; &nbsp;// Stop processing =
this line</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; case =
kTabCharacter:</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
*position =3D [self _positionAfterTabFrom:*position =
inFragment:fragment];</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; return YES; &nbsp;// Continue to next glyph</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; default:</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
NSDebugLLog(@"GSHorizontalTypesetter", @"Unknown control %04x", =
ch);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return =
YES;</div><div>&nbsp; &nbsp; }</div><div>}</div><div><br></div><div>- =
(BOOL)_handleAttachmentGlyph:(glyph_cache_t =
*)glyph&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; atPosition:(NSPoint *)position</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;lineFragment:(line_frag_t *)fragment</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;lineHeight:(CGFloat *)lineHeight</div><div>{</div><div>&nbsp; =
&nbsp; // Extract attachment logic...</div><div>&nbsp; &nbsp; // Return =
YES if fits and metrics updated, NO if needs line =
break</div><div>}</div><div>```</div><div><br></div><div>### 11. =
**Extract Metric Calculation to Dedicated =
Method**</div><div><br></div><div>```objc</div><div>- =
(void)_updateLineMetricsForGlyph:(glyph_cache_t *)glyph</div><div>&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
currentAscender:(CGFloat *)ascender</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;currentDescender:(CGFloat *)descender</div><div>&nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp;currentHeight:(CGFloat *)lineHeight</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
maxLineHeight:(CGFloat)maxHeight</div><div>{</div><div>&nbsp; &nbsp; =
NSFont *font =3D glyph-&gt;font;</div><div>&nbsp; &nbsp; CGFloat =
glyphAscender =3D [font ascender];</div><div>&nbsp; &nbsp; CGFloat =
glyphDescender =3D -[font descender];</div><div>&nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; // Apply superscript =
adjustments</div><div>&nbsp; &nbsp; CGFloat yOffset =3D =
0;</div><div>&nbsp; &nbsp; if (glyph-&gt;attributes.superscript) =
{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; yOffset -=3D =
glyph-&gt;attributes.superscript * [font xHeight];</div><div>&nbsp; =
&nbsp; }</div><div>&nbsp; &nbsp; if =
(glyph-&gt;attributes.baseline_offset) {</div><div>&nbsp; &nbsp; &nbsp; =
&nbsp; yOffset +=3D =
glyph-&gt;attributes.baseline_offset;</div><div>&nbsp; &nbsp; =
}</div><div>&nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; // Update =
metrics</div><div>&nbsp; &nbsp; *ascender =3D MAX(*ascender, =
glyphAscender - MIN(yOffset, 0));</div><div>&nbsp; &nbsp; *descender =3D =
MAX(*descender, glyphDescender + MAX(yOffset, 0));</div><div>&nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; CGFloat newHeight =3D *ascender + =
*descender;</div><div>&nbsp; &nbsp; if (maxHeight &gt; 0) =
{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; newHeight =3D MIN(newHeight, =
maxHeight);</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; =
*lineHeight =3D MAX(*lineHeight, =
newHeight);</div><div>}</div><div>```</div><div><br></div><div>### 12. =
**Simplify Soft Invalidation Logic**</div><div><br></div><div>The soft =
invalidation method is hard to follow. Restructure with early returns =
and clear phases:</div><div><br></div><div>```objc</div><div>- =
(BOOL)_reuseSoftInvalidatedLayout</div><div>{</div><div>&nbsp; &nbsp; // =
Quick reject: not at soft invalidation point</div><div>&nbsp; &nbsp; if =
(![self _isAtSoftInvalidationPoint]) return NO;</div><div>&nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; // Quick reject: won't fit =
vertically</div><div>&nbsp; &nbsp; NSRect firstRect =3D [self =
_firstSoftInvalidatedRect];</div><div>&nbsp; &nbsp; if (![self =
_canFitVertically:firstRect]) return NO;</div><div>&nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; // Collect consecutive valid =
fragments</div><div>&nbsp; &nbsp; GSSoftInvalidationBatch *batch =3D =
[self _collectSoftInvalidatedFragments];</div><div>&nbsp; &nbsp; if =
(batch.isEmpty) return NO;</div><div>&nbsp; =
&nbsp;&nbsp;</div><div>&nbsp; &nbsp; // Apply shift and =
commit</div><div>&nbsp; &nbsp; [self =
_applySoftInvalidationBatch:batch];</div><div>&nbsp; &nbsp; =
curGlyphIndex =3D batch.endGlyphIndex;</div><div>&nbsp; &nbsp; return =
YES;</div><div>}</div><div>```</div><div><br></div><div>---</div><div><br>=
</div><div>## Summary Table</div><div><br></div><div>| Refactoring | =
Benefit | Effort =
|</div><div>|-------------|---------|--------|</div><div>| Named =
constants | Eliminates magic numbers, self-documenting | Low =
|</div><div>| Boolean methods | Clarifies intent of complex conditions | =
Low |</div><div>| Replace goto | Structured flow, easier debugging | =
Medium |</div><div>| State machine enum | Explicit transitions, type =
safety | Medium |</div><div>| Method extraction | Single responsibility, =
testable units | Medium |</div><div>| Named structs | Self-documenting, =
IDE completion | Low |</div><div>| Cache class | Encapsulation, easier =
optimization | High |</div><div>| Array abstraction | Memory safety, =
bounds checking | Medium |</div><div>| Return value enum | Compiler =
checking, clear semantics | Low |</div><div>| Glyph handlers | Flatten =
nesting, isolate concerns | Medium |</div><div>| Metric extraction | =
Reusable, testable calculations | Low |</div><div>| Soft invalidation =
phases | Linear flow, early exits | Medium =
|</div><div><br></div><div>These changes maintain performance (critical =
for text layout) while significantly improving maintainability. The most =
impactful would be **#5 (method extraction)** and **#3 (goto =
elimination)**, which together would reduce the cognitive load of =
understanding the layout =
algorithm.</div></div><div><br></div><div><br></div><div>=E2=80=94=E2=80=94=
 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94=
 =E2=80=94=E2=80=94 =E2=80=94=E2=80=94 =
=E2=80=94=E2=80=94&nbsp;</div><div><br></div><div><br></div><div>I see =
you read until here. I know, that was a lot to digest. Now I am asking: =
what do you think about this? Does it make sense? Should we do those =
refactorings?</div><div><br></div><div><br></div><div>Kind =
regards,</div><div><br></div><div><span class=3D"Apple-tab-span" =
style=3D"white-space:pre">	=
</span>Lars</div></div></div></blockquote></div><br></div></body></html>=

--Apple-Mail=_E574689C-527D-4D09-9378-02F1A9847500--