1/*
2   GSLayoutManager.m
3
4   Copyright (C) 2002-2011 Free Software Foundation, Inc.
5
6   Author: Alexander Malmberg <alexander@malmberg.org>
7   Date: November 2002 - February 2003
8
9   This file is part of the GNUstep GUI Library.
10
11   This library is free software; you can redistribute it and/or
12   modify it under the terms of the GNU Lesser General Public
13   License as published by the Free Software Foundation; either
14   version 2 of the License, or (at your option) any later version.
15
16   This library is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
19   Lesser General Public License for more details.
20
21   You should have received a copy of the GNU Lesser General Public
22   License along with this library; see the file COPYING.LIB.
23   If not, see <http://www.gnu.org/licenses/> or write to the
24   Free Software Foundation, 51 Franklin Street, Fifth Floor,
25   Boston, MA 02110-1301, USA.
26*/
27
28#import <Foundation/NSCharacterSet.h>
29#import <Foundation/NSDebug.h>
30#import <Foundation/NSEnumerator.h>
31#import <Foundation/NSException.h>
32#import <Foundation/NSValue.h>
33
34#import "AppKit/NSAttributedString.h"
35#import "AppKit/NSTextStorage.h"
36#import "AppKit/NSTextContainer.h"
37#import "AppKit/NSTextView.h"
38
39/* just for NSAttachmentCharacter */
40#import "AppKit/NSTextAttachment.h"
41
42#import "GNUstepGUI/GSFontInfo.h"
43#import "GNUstepGUI/GSTypesetter.h"
44#import "GNUstepGUI/GSLayoutManager_internal.h"
45
46/* TODO: is using rand() here ok? */
47static inline int random_level(void)
48{
49  int i;
50  for (i = 0; i < SKIP_LIST_DEPTH - 2; i++)
51    if ((rand() % SKIP_LIST_LEVEL_PROBABILITY) != 0)
52      break;
53  return i;
54}
55
56/*
57 * Insert a new run with level into the context of the skip list.
58 * Return the new run.
59 */
60static glyph_run_t *run_insert(glyph_run_head_t **context, int level)
61{
62  glyph_run_head_t *h;
63  glyph_run_t *r;
64  int i, size;
65
66  size = sizeof(glyph_run_head_t) * level + sizeof(glyph_run_t);
67  h = malloc(size);
68  memset(h, 0, size);
69
70  for (i = level; i >= 0; i--, h++)
71    {
72      h->next = context[i]->next;
73      context[i]->next = h;
74    }
75  h--;
76
77  r = (glyph_run_t *)h;
78  r->level = level;
79  r->prev = context[0];
80  if (h->next)
81    ((glyph_run_t *)h->next)->prev = h;
82
83  return r;
84}
85
86/*
87 * Free the glphys of a run.
88 */
89static inline void run_free_glyphs(glyph_run_t *r)
90{
91  if (r->glyphs)
92    {
93      r->head.complete = 0;
94      r->head.glyph_length = 0;
95      free(r->glyphs);
96      r->glyphs = NULL;
97    }
98 }
99
100/*
101 * Remove the run r from the context of the skip list and free it.
102 * The context does not point at r, but to the run immediately before r.
103 * context[0]->next == r
104 */
105static inline void run_remove(glyph_run_head_t **context, glyph_run_t *r)
106{
107  glyph_run_head_t *h;
108  int i;
109
110  // Free the glyphs
111  run_free_glyphs(r);
112
113  h = &r->head;
114  if (h->next)
115    ((glyph_run_t *)h->next)->prev = r->prev;
116
117  for (i = 0; i <= r->level; i++)
118    context[i]->next = context[i]->next->next;
119
120  h -= r->level;
121  free(h);
122}
123
124/* Recalculates char_length, glyph_length, and complete for a
125glyph_run_head_t. All "children" of this head must have valid values. */
126static void run_fix_head(glyph_run_head_t *h)
127{
128  glyph_run_head_t *h2, *next;
129
130  next = h->next;
131  if (next)
132    next++;
133  h2 = h + 1;
134
135  h->complete = 1;
136  h->glyph_length = 0;
137  h->char_length = 0;
138
139  // Loop over all heads below this one
140  while (h2 != next)
141    {
142      h->char_length += h2->char_length;
143      if (!h2->complete)
144        h->complete = 0;
145      else if (h->complete)
146        h->glyph_length += h2->glyph_length;
147      h2 = h2->next;
148    }
149}
150
151/*
152Private method used internally by GSLayoutManager for sanity checking.
153*/
154@interface NSTextStorage (GSLayoutManagerSanityChecking)
155-(unsigned int) _editCount;
156@end
157@implementation NSTextStorage (GSLayoutManagerSanityChecking)
158-(unsigned int) _editCount;
159{
160  return _editCount;
161}
162@end
163
164@interface GSLayoutManager (backend)
165-(unsigned int) _findSafeBreakMovingBackwardFrom: (unsigned int)ch;
166-(unsigned int) _findSafeBreakMovingForwardFrom: (unsigned int)ch;
167-(void) _generateGlyphsForRun: (glyph_run_t *)run  at: (unsigned int)cpos;
168@end
169
170/***** Glyph handling *****/
171
172@implementation GSLayoutManager (GlyphsHelpers)
173
174-(void) _run_cache_attributes: (glyph_run_t *)r : (NSDictionary *)attributes
175{
176  /* set up attributes for this run */
177  NSNumber *n;
178  NSFont *font;
179
180  r->explicit_kern = !![attributes objectForKey: NSKernAttributeName];
181
182  n = [attributes objectForKey: NSLigatureAttributeName];
183  if (n)
184    r->ligature = [n intValue];
185  else
186    r->ligature = 1;
187
188  font = [typesetter fontForCharactersWithAttributes: attributes];
189  /* TODO: it might be useful to change this slightly:
190  Returning a nil font from -fontForCharactersWithAttributes: causes those
191  characters to not be displayed (ie. no glyphs are generated).
192
193  How would glyph<->char mapping be handled? Map the entire run to one
194  NSNullGlyph?
195  */
196  if (font == nil)
197    font = [NSFont userFontOfSize: 0];
198  font = [self substituteFontForFont: font];
199  ASSIGN(r->font, font);
200}
201
202-(void) _run_free_attributes: (glyph_run_t *)r
203{
204  [r->font release];
205}
206
207-(void) _run_copy_attributes: (glyph_run_t *)dst : (const glyph_run_t *)src
208{
209  dst->font = [src->font copy];
210  dst->ligature = src->ligature;
211  dst->explicit_kern = src->explicit_kern;
212}
213
214/*
215 * Free up the skip list and all the glyph arrays
216 */
217- (void) _freeGlyphs
218{
219  glyph_run_t *cur, *next;
220  glyph_run_head_t *h;
221
222  if (!glyphs)
223    return;
224
225  cached_run = NULL;
226
227  h = glyphs;
228  h += SKIP_LIST_DEPTH - 1;
229
230  for (cur = (glyph_run_t *)h->next; cur; cur = next)
231    {
232      next = (glyph_run_t *)cur->head.next;
233      if (cur->glyphs)
234        free(cur->glyphs);
235      [self _run_free_attributes: cur];
236      // Find the start of the allocated memory
237      h = &cur->head;
238      h -= cur->level;
239      free(h);
240    }
241
242  // Free the head element
243  free(glyphs);
244  glyphs = NULL;
245}
246
247/*
248 * Initialize the glyph skip list
249 */
250- (void) _initGlyphs
251{
252  int i, size;
253  glyph_run_t *r;
254  glyph_run_head_t *h;
255
256  size = sizeof(glyph_run_head_t) * (SKIP_LIST_DEPTH - 1) + sizeof(glyph_run_t);
257  glyphs = malloc(size);
258  memset(glyphs, 0, size);
259
260  for (h = glyphs, i = SKIP_LIST_DEPTH; i; i--, h++)
261    {
262      h->complete = 1;
263    }
264  h--;
265
266  r = (glyph_run_t *)h;
267  r->level = SKIP_LIST_DEPTH - 1;
268}
269
270- (void) _glyphDumpRuns
271{
272  printf("--- dumping runs\n");
273  {
274    glyph_run_t *h;
275    unsigned int cpos = 0;
276
277    h = (glyph_run_t *)(glyphs + SKIP_LIST_DEPTH - 1)->next;
278    for (; h; h = (glyph_run_t *)h->head.next)
279      {
280        printf("%8p %i chars, %i glyphs, %i complete, prev %8p next %8p\n",
281               h, h->head.char_length, h->head.glyph_length, h->head.complete,
282               h->prev, h->head.next);
283        printf("         level %i, continued %i\n", h->level, h->continued);
284        if (h->head.complete)
285          {
286            unsigned int i;
287            printf("glyphs:\n");
288            for (i = 0;i < h->head.glyph_length;i++)
289              printf("%5i %04x u%04x  ",
290                     h->glyphs[i].char_offset,h->glyphs[i].g,
291                     [[_textStorage string] characterAtIndex: cpos+h->glyphs[i].char_offset]);
292            printf("\n");
293          }
294        cpos += h->head.char_length;
295      }
296  }
297  printf("- structure\n");
298  {
299    glyph_run_head_t *h, *g;
300    int i;
301
302    printf("    head: ");
303    for (i = 0, h = glyphs + SKIP_LIST_DEPTH - 1; i < SKIP_LIST_DEPTH; i++, h--)
304      printf("%8p %i %3i %3i|", h->next, h->complete, h->char_length, h->glyph_length);
305    printf("\n");
306    h = (glyphs + SKIP_LIST_DEPTH - 1)->next;
307    for (; h; h = h->next)
308      {
309        printf("%8p: ", h);
310        for (g = h, i = ((glyph_run_t *)h)->level; i >= 0; i--, g--)
311          printf("%8p %i %3i %3i|", g->next, g->complete, g->char_length, g->glyph_length);
312        printf("\n");
313      }
314  }
315  printf("--- done\n");
316  fflush(stdout);
317}
318
319- (void) _sanityChecks
320{
321  glyph_run_t *g;
322
323  g = (glyph_run_t *)&glyphs[SKIP_LIST_DEPTH - 1];
324  while (g->head.next)
325    {
326      NSAssert((glyph_run_t *)((glyph_run_t *)g->head.next)->prev == g,
327               @"glyph structure corrupted: g->next->prev!=g");
328      g = (glyph_run_t *)g->head.next;
329    }
330}
331
332
333/*
334 * Returns the glyph run that contains glyphIndex, if there is any.
335 * glyph_pos and char_pos, when supplied, will contain the starting
336 * glyph/character index for this run.
337 */
338- (glyph_run_t *)run_for_glyph_index: (unsigned int)glyphIndex
339				    : (unsigned int *)glyph_pos
340				    : (unsigned int *)char_pos
341{
342  int level;
343  glyph_run_head_t *h;
344  int pos, cpos;
345
346  if (glyphs->glyph_length <= glyphIndex)
347    {
348      NSLog(@"run_for_glyph_index failed for %d", glyphIndex);
349      return NULL;
350    }
351
352  if (cached_run)
353    {
354      if (glyphIndex >= cached_pos &&
355          glyphIndex < cached_pos + cached_run->head.glyph_length)
356        {
357          if (glyph_pos)
358            *glyph_pos = cached_pos;
359          if (char_pos)
360            *char_pos = cached_cpos;
361          return cached_run;
362        }
363    }
364
365  pos = cpos = 0;
366  level = SKIP_LIST_DEPTH;
367  h = glyphs;
368  while (1)
369    {
370      // Find a head, where the glyphs are already created.
371      if (!h->complete)
372        {
373          h++;
374          level--;
375          if (!level)
376            {
377              NSLog(@"run_for_glyph_index failed for %d", glyphIndex);
378              return NULL;
379            }
380          continue;
381        }
382      // Find the head containing the index.
383      if (glyphIndex >= pos + h->glyph_length)
384        {
385          pos += h->glyph_length;
386          cpos += h->char_length;
387          h = h->next;
388          if (!h)
389            {
390              NSLog(@"run_for_glyph_index failed for %d", glyphIndex);
391              return NULL;
392            }
393          continue;
394        }
395      // Go down one level
396      if (level > 1)
397        {
398          h++;
399          level--;
400          continue;
401        }
402
403      // Level 1
404      if (glyph_pos)
405        *glyph_pos = pos;
406      if (char_pos)
407        *char_pos = cpos;
408
409      cached_run = (glyph_run_t *)h;
410      cached_pos = pos;
411      cached_cpos = cpos;
412
413      return (glyph_run_t *)h;
414    }
415}
416
417/*
418 * Returns the glyph run that contains charIndex, if there is any.
419 * glyph_pos and char_pos, when supplied, will contain the starting
420 * glyph/character index for this run.
421 */
422- (glyph_run_t *)run_for_character_index: (unsigned int)charIndex
423					: (unsigned int *)glyph_pos
424					: (unsigned int *)char_pos
425{
426  int level;
427  glyph_run_head_t *h;
428  int pos, cpos;
429  BOOL cache = YES;
430
431  if (glyphs->char_length <= charIndex)
432    {
433      NSLog(@"run_for_character_index failed for %d", charIndex);
434      return NULL;
435    }
436
437  if (cached_run)
438    {
439      if (charIndex >= cached_cpos &&
440          charIndex < cached_cpos + cached_run->head.char_length)
441        {
442          if (glyph_pos)
443            *glyph_pos = cached_pos;
444          if (char_pos)
445            *char_pos = cached_cpos;
446          return cached_run;
447        }
448    }
449
450  pos = cpos = 0;
451  h = glyphs;
452  for (level = SKIP_LIST_DEPTH - 1; level >= 0; level--)
453    {
454      // Find the head containing the index.
455      while (charIndex >= cpos + h->char_length)
456        {
457          // Ignore pos at the end
458          if (!h->complete)
459            cache = NO;
460          pos += h->glyph_length;
461          cpos += h->char_length;
462          h = h->next;
463          if (!h)
464            {
465              NSLog(@"run_for_character_index failed for %d", charIndex);
466              return NULL;
467            }
468        }
469
470      // Go down one level
471      h++;
472    }
473  h--;
474
475  if (glyph_pos)
476    *glyph_pos = pos;
477  if (char_pos)
478    *char_pos = cpos;
479
480  if (cache)
481    {
482      cached_run = (glyph_run_t *)h;
483      cached_pos = pos;
484      cached_cpos = cpos;
485    }
486
487   return (glyph_run_t *)h;
488}
489
490/*
491 * Generate the glyph runs, but not the actual glyphs, up to the
492 * character index last.
493 * Build up empty skip list entries to later hold the glyphs.
494 * Only appends to the end of the skip list.
495 * Only called after setting up a complete new layout.
496 */
497-(void) _generateRunsToCharacter: (unsigned int)last
498{
499  glyph_run_head_t *context[SKIP_LIST_DEPTH];
500  glyph_run_head_t *h;
501  unsigned int pos;
502  unsigned int length;
503  int level;
504
505  length = [_textStorage length];
506  if (last >= length)
507    last = length - 1;
508
509  h = glyphs;
510  pos = 0;
511  if (h->char_length > last)
512    return;
513
514  /* We haven't created any run for that character. Find the last run. */
515  for (level = SKIP_LIST_DEPTH; level; level--)
516    {
517      while (h->next) pos += h->char_length, h = h->next;
518      context[level - 1] = h;
519      h++;
520    }
521  h--;
522  pos += h->char_length;
523
524  /* Create runs and add them to the skip list until we're past our
525     target. */
526  while (pos <= last)
527    {
528      NSRange maxRange;
529      NSRange curRange;
530      NSDictionary *attributes;
531      glyph_run_t *new;
532      int new_level;
533      int i;
534
535      maxRange = NSMakeRange(pos, length - pos);
536      if (pos > 0)
537        {
538          maxRange.location--;
539          maxRange.length++;
540        }
541
542      attributes = [_textStorage attributesAtIndex: pos
543                                 longestEffectiveRange: &curRange
544                                 inRange: maxRange];
545
546      /*
547      Optimize run structure by merging with the previous run under
548      some circumstances. See the comments in
549      -invalidateGlyphsForCharacterRange:changeInLength:actualCharacterRange:
550      for more information.
551      */
552      if (curRange.location < pos && context[0]->char_length &&
553          // FIXME: Why 16 and not MAX_RUN_LENGTH
554          context[0]->char_length < 16)
555        {
556          curRange.length -= pos - curRange.location;
557          curRange.location = pos;
558          new = (glyph_run_t *)context[0];
559          // FIXME: We could try to reuse the glyphs
560          run_free_glyphs(new);
561          new->head.char_length += curRange.length;
562          for (i = 1; i < SKIP_LIST_DEPTH; i++)
563            {
564              run_fix_head(context[i]);
565            }
566          pos = NSMaxRange(curRange);
567          continue;
568        }
569
570      if (curRange.location < pos)
571        {
572          curRange.length -= pos - curRange.location;
573          curRange.location = pos;
574        }
575
576      /*
577      TODO: this shouldn't really be necessary if all searches inside runs
578      were binary. but for now, it helps performance, and it keeps things
579      more balanced when there are long runs of text.
580      */
581      if (curRange.length > MAX_RUN_LENGTH)
582        {
583          unsigned int safe_break = curRange.location + MAX_RUN_LENGTH;
584          safe_break = [self _findSafeBreakMovingForwardFrom: safe_break];
585          if (safe_break < NSMaxRange(curRange))
586            curRange.length = safe_break - curRange.location;
587        }
588
589      /* Since we'll be creating these in order, we can be smart about
590         picking new levels. */
591      {
592        int i;
593
594        /*
595          FIXME: Not sure whether using an ivar here as the counter is a great idea.
596          When the same range is edited over and over again this could lead to a strange structure.
597          It works fine when adding a great chunk of text at the end.
598        */
599        glyph_num_end_runs++;
600        for (i=0; i < SKIP_LIST_DEPTH - 2; i++)
601          if (glyph_num_end_runs & (1 << i))
602            break;
603        new_level = i;
604      }
605
606      new = run_insert(context, new_level);
607      [self _run_cache_attributes: new : attributes];
608
609      h = &new->head;
610      for (i = 0; i <= new_level; i++, h--)
611        {
612          h->char_length = curRange.length;
613          context[i] = h;
614        }
615
616      for (; i < SKIP_LIST_DEPTH; i++)
617        {
618          context[i]->char_length += curRange.length;
619          context[i]->complete = 0;
620        }
621
622      pos += curRange.length;
623    }
624
625  [self _sanityChecks];
626}
627
628/*
629Recursive glyph generation helper method method.
630Returns number of valid glyphs under h after generating up to last (sortof,
631not completely accurate).
632Fills in all glyph holes up to last. only looking at levels below level
633*/
634-(unsigned int) _generateGlyphs_char_r: (unsigned int)last : (unsigned int)cpos
635                                      : (unsigned int)gpos : (int)level
636                                      : (glyph_run_head_t *)h : (glyph_run_head_t *)stop
637                                      : (BOOL *)all_complete
638{
639  int total = 0, sub_total;
640  BOOL c;
641
642  *all_complete = YES;
643  while (h != stop && (cpos <= last || *all_complete))
644    {
645      if (!h->complete)
646        {
647          if (cpos > last)
648            {
649              *all_complete = NO;
650              break;
651            }
652
653          if (level)
654            {
655              glyph_run_head_t *stopn;
656
657              if (h->next)
658                stopn = h->next + 1;
659              else
660                stopn = NULL;
661
662              sub_total = [self _generateGlyphs_char_r: last : cpos : gpos + total
663                                : level - 1 : h + 1: stopn: &c];
664              if (!c)
665                *all_complete = NO;
666              else
667                h->complete = 1;
668              h->glyph_length = sub_total;
669            }
670          else
671            {
672              NSUInteger cindex = cpos;
673              NSUInteger gindex = gpos + total;
674
675              // Cache the current run
676              cached_run = (glyph_run_t *)h;
677              cached_pos = gindex;
678              cached_cpos = cindex;
679
680              // Generate the glyphs for the run
681              [_glyphGenerator generateGlyphsForGlyphStorage: self
682                               desiredNumberOfCharacters: h->char_length
683                               glyphIndex: &gindex
684                               characterIndex: &cindex];
685              h->complete = 1;
686            }
687        }
688
689      total += h->glyph_length;
690      cpos += h->char_length;
691      h = h->next;
692    }
693
694  return total;
695}
696
697/*
698 * Generate all glyphs up to the character index last.
699 */
700-(void) _generateGlyphsUpToCharacter: (unsigned int)last
701{
702  unsigned int length;
703  BOOL dummy;
704
705  if (!_textStorage)
706    return;
707
708  /*
709  Trying to do anything here while the text storage has unprocessed edits
710  (ie. an edit count>0) breaks things badly, and in strange ways. Thus, we
711  detect this and raise an exception.
712  */
713  if ([_textStorage _editCount])
714    {
715      [NSException raise: NSGenericException
716	      format: @"Glyph generation was triggered for a layout manager "
717		      @"while the text storage it was attached to had "
718		      @"unprocessed editing. This is not allowed. Glyph "
719		      @"generation may be triggered only at points where "
720		      @"calls to -beginEditing and -endEditing are "
721		      @"balanced."];
722    }
723
724  length = [_textStorage length];
725  if (!length)
726    return;
727  if (last >= length)
728    last = length - 1;
729
730  if (glyphs->char_length <= last)
731    [self _generateRunsToCharacter: last];
732
733  // [self _glyphDumpRuns];
734  [self _generateGlyphs_char_r: last : 0 : 0 : SKIP_LIST_DEPTH - 1: glyphs : NULL : &dummy];
735  // [self _glyphDumpRuns];
736}
737
738-(void) _generateGlyphsUpToGlyph: (unsigned int)last
739{
740  unsigned int length;
741
742  if (!_textStorage)
743    return;
744  length = [_textStorage length];
745
746  while (glyphs->glyph_length <= last && (glyphs->char_length < length || !glyphs->complete))
747    {
748      // Make an estimate for the character position
749      unsigned int char_last;
750
751      if (glyphs->glyph_length == 0)
752        char_last = last;
753      else
754        char_last = glyphs->char_length + 1 +
755          (last - glyphs->glyph_length) * (glyphs->char_length / (glyphs->glyph_length + 1));
756
757      [self _generateGlyphsUpToCharacter: char_last];
758    }
759}
760
761/*
762 * Find the glyph run that contains target and the glyph that matches to that char index.
763 */
764- (glyph_run_t *) _glyphForCharacter: (unsigned int)target
765                               index: (unsigned int *)rindex
766                           positions: (unsigned int *)rpos
767                                    : (unsigned int *)rcpos
768{
769  glyph_run_t *r;
770  unsigned int pos, cpos;
771  int lo, hi, mid, i;
772
773  r = [self run_for_character_index: target : &pos : &cpos];
774  if (!r)
775    {
776      [NSException raise: NSRangeException
777                   format: @"%s character index %d out of range", __PRETTY_FUNCTION__, target];
778      return NULL;
779    }
780
781  if (!r->glyphs)
782    {
783      // range, but no glyphs, may be an empty glyph run
784      *rindex = 0;	// FIXME ... is this right?
785      *rpos = pos;
786      *rcpos = cpos;
787      return r;
788    }
789
790  target -= cpos;
791
792  lo = 0;
793  hi = r->head.glyph_length - 1;
794  while (lo < hi)
795    {
796      mid = (lo + hi) / 2;
797      if (r->glyphs[mid].char_offset > target)
798        hi = mid - 1;
799      else if (r->glyphs[mid].char_offset < target)
800        lo = mid + 1;
801      else
802        hi = lo = mid;
803    }
804
805  // This final correction is needed as multiple glyph may have
806  // the same character offset and vise versa.
807  i = lo;
808  while (r->glyphs[i].char_offset > target)
809    i--;
810  while (i > 0 && r->glyphs[i - 1].char_offset == r->glyphs[i].char_offset)
811    i--;
812
813  *rindex = i;
814  *rpos = pos;
815  *rcpos = cpos;
816  return r;
817}
818
819@end
820
821
822@implementation GSLayoutManager (glyphs)
823
824- (unsigned int) numberOfGlyphs
825{
826  [self _generateGlyphsUpToCharacter: -1];
827  return glyphs->glyph_length;
828}
829
830- (NSGlyph) glyphAtIndex: (unsigned int)glyphIndex
831{
832  BOOL valid;
833  NSGlyph g;
834
835  g = [self glyphAtIndex: glyphIndex isValidIndex: &valid];
836  if (!valid)
837    [NSException raise: NSRangeException
838                 format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
839
840  return g;
841}
842
843- (NSGlyph) glyphAtIndex: (unsigned int)glyphIndex
844            isValidIndex: (BOOL *)isValidIndex
845{
846  glyph_run_t *r;
847  unsigned int pos;
848
849  if (isValidIndex != NULL)
850    *isValidIndex = NO;
851
852  /* glyph '-1' is returned in other places as an "invalid" marker; this
853  way, we can say that it isn't valid without building all glyphs */
854  /* TODO: check if this is really safe or smart. if it isn't, some other
855  methods will need to be changed so they can return "no glyph index" in
856  some other way. */
857  if (glyphIndex == (unsigned int)-1)
858    return NSNullGlyph;
859
860  if (glyphs->glyph_length <= glyphIndex)
861    {
862      [self _generateGlyphsUpToGlyph: glyphIndex];
863      if (glyphs->glyph_length <= glyphIndex)
864        return NSNullGlyph;
865    }
866
867  r = run_for_glyph_index(glyphIndex, glyphs, &pos, NULL);
868  if (!r || !r->glyphs) /* shouldn't happen */
869    return NSNullGlyph;
870
871  if (isValidIndex != NULL)
872    *isValidIndex = YES;
873
874  return r->glyphs[glyphIndex - pos].g;
875}
876
877- (BOOL) isValidGlyphIndex: (unsigned int)glyphIndex
878{
879 if (glyphIndex == (unsigned int)-1)
880    return NO;
881
882  if (glyphs->glyph_length <= glyphIndex)
883    {
884      return NO;
885    }
886  else
887    {
888      return YES;
889    }
890}
891
892- (unsigned int) getGlyphs: (NSGlyph *)glyphArray
893                     range: (NSRange)glyphRange
894{
895  glyph_run_t *r;
896  NSGlyph *g;
897  unsigned int pos;
898  unsigned int num;
899  unsigned int i, j, k;
900
901  if (glyphRange.length == 0)
902    {
903      return 0;
904    }
905
906  pos = NSMaxRange(glyphRange) - 1;
907  if (glyphs->glyph_length <= pos)
908    {
909      [self _generateGlyphsUpToGlyph: pos];
910      if (glyphs->glyph_length <= pos)
911        {
912          [NSException raise: NSRangeException
913                       format: @"%s glyph range out of range", __PRETTY_FUNCTION__];
914          return 0;
915        }
916    }
917
918  r = run_for_glyph_index(glyphRange.location, glyphs, &pos, NULL);
919  if (!r)
920    { /* shouldn't happen */
921      [NSException raise: NSRangeException
922		   format: @"%s glyph range out of range", __PRETTY_FUNCTION__];
923      return 0;
924    }
925
926  g = glyphArray;
927  num = 0;
928
929  while (1)
930    {
931      if (pos < glyphRange.location)
932        j = glyphRange.location - pos;
933      else
934        j = 0;
935
936      k = NSMaxRange(glyphRange) - pos;
937      if (k > r->head.glyph_length)
938        k = r->head.glyph_length;
939      if (k <= j)
940        break;
941
942      /* TODO? only "displayed" glyphs */
943      for (i = j; i < k; i++)
944        {
945          *g++ = r->glyphs[i].g;
946          num++;
947        }
948
949      pos += r->head.glyph_length;
950      r = (glyph_run_t *)r->head.next;
951      if (!r)
952        break;
953    }
954
955  return num;
956}
957
958- (unsigned int) characterIndexForGlyphAtIndex: (unsigned int)glyphIndex
959{
960  glyph_run_t *r;
961  unsigned int pos, cpos;
962
963  if (glyphs->glyph_length <= glyphIndex)
964    {
965      [self _generateGlyphsUpToGlyph: glyphIndex];
966      if (glyphs->glyph_length <= glyphIndex)
967        {
968          [NSException raise: NSRangeException
969                       format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
970          return 0;
971        }
972    }
973
974  r = run_for_glyph_index(glyphIndex, glyphs, &pos, &cpos);
975  if (!r)
976    {
977      [NSException raise: NSRangeException
978                   format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
979      return 0;
980    }
981
982  if (r->head.glyph_length <= glyphIndex - pos)
983    {
984      return cpos;
985    }
986
987  return cpos + r->glyphs[glyphIndex - pos].char_offset;
988}
989
990- (NSRange) characterRangeForGlyphRange: (NSRange)glyphRange
991                       actualGlyphRange: (NSRange *)actualGlyphRange
992{
993  glyph_run_t *r;
994  NSRange real_range, char_range;
995  unsigned int cpos, pos;
996  unsigned j;
997
998  if (NSMaxRange(glyphRange) == 0)
999    {
1000      if (actualGlyphRange)
1001        *actualGlyphRange = glyphRange;
1002      return NSMakeRange(0, 0);
1003    }
1004
1005  pos = NSMaxRange(glyphRange) - 1;
1006  if (glyphs->glyph_length <= pos)
1007    {
1008      [self _generateGlyphsUpToGlyph: pos];
1009      if (glyphs->glyph_length <= pos)
1010        {
1011          [NSException raise: NSRangeException
1012                       format: @"%s glyph range out of range", __PRETTY_FUNCTION__];
1013          return NSMakeRange(0, 0);
1014        }
1015    }
1016
1017  r = run_for_glyph_index(glyphRange.location, glyphs, &pos, &cpos);
1018  if (!r)
1019    {
1020      [NSException raise: NSRangeException
1021		   format: @"%s glyph range out of range", __PRETTY_FUNCTION__];
1022      return NSMakeRange(0, 0);
1023    }
1024
1025  if (r->head.glyph_length <= glyphRange.location - pos)
1026    {
1027      j = cpos;
1028    }
1029  else
1030    {
1031      j = cpos + r->glyphs[glyphRange.location - pos].char_offset;
1032    }
1033  char_range.location = j;
1034
1035  /* scan backwards to find the real first glyph */
1036  {
1037    glyph_run_t *r2;
1038    unsigned int adj, cadj;
1039    int i;
1040
1041    i = glyphRange.location - pos;
1042    r2 = r;
1043    adj = pos;
1044    cadj = cpos;
1045    while ((r2->head.glyph_length > i) &&
1046           (r2->glyphs[i].char_offset + cadj == j))
1047      {
1048        i--;
1049        while (i < 0)
1050          {
1051            if (!r2->prev)
1052              break;
1053            r2 = (glyph_run_t *)r2->prev;
1054            i = r2->head.glyph_length - 1;
1055            adj -= r2->head.glyph_length;
1056            cadj -= r2->head.char_length;
1057          }
1058        if (i < 0)
1059          break;
1060      }
1061    real_range.location = i + 1 + adj;
1062  }
1063
1064  /* the range is likely short, so we can do better then a completely new
1065     search */
1066  r = run_for_glyph_index(glyphRange.location + glyphRange.length - 1,
1067                          glyphs, &pos, &cpos);
1068  if (!r)
1069    {
1070      [NSException raise: NSRangeException
1071		   format: @"%s glyph range out of range", __PRETTY_FUNCTION__];
1072      return NSMakeRange(0, 0);
1073    }
1074
1075  if (r->head.glyph_length <= glyphRange.location + glyphRange.length - 1 - pos)
1076    {
1077      j = cpos;
1078    }
1079  else
1080    {
1081      j = cpos + r->glyphs[glyphRange.location + glyphRange.length - 1 - pos].char_offset;
1082    }
1083
1084  /* scan forwards to find the real last glyph */
1085  {
1086    glyph_run_t *r2;
1087    unsigned int adj, cadj;
1088    unsigned int last = 0;
1089    unsigned int i;
1090
1091    i = glyphRange.location + glyphRange.length - 1 - pos;
1092    r2 = r;
1093    adj = pos;
1094    cadj = cpos;
1095    while ((r2->head.glyph_length > i) &&
1096           (r2->glyphs[i].char_offset + cadj == j))
1097      {
1098        GLYPH_STEP_FORWARD(r2,i,adj,cadj)
1099        if (i==r2->head.glyph_length)
1100          {
1101            last = cadj + r2->head.char_length;
1102            goto found;
1103          }
1104      }
1105    if (r2->head.glyph_length > i)
1106      {
1107        last = r2->glyphs[i].char_offset + cadj;
1108      }
1109    else
1110      {
1111        last = j;
1112      }
1113  found:
1114    real_range.length = i + adj - real_range.location;
1115    char_range.length = last - char_range.location;
1116  }
1117
1118  if (actualGlyphRange)
1119    *actualGlyphRange = real_range;
1120  return char_range;
1121}
1122
1123- (NSRange) glyphRangeForCharacterRange: (NSRange)charRange
1124                   actualCharacterRange: (NSRange *)actualCharRange
1125{
1126  NSRange char_range, glyph_range;
1127  glyph_run_t *r;
1128  unsigned int cpos, pos;
1129  unsigned int i, target;
1130
1131  if (charRange.length == 0 && charRange.location == 0)
1132    {
1133      if (actualCharRange)
1134        *actualCharRange = charRange;
1135      return NSMakeRange(0, 0);
1136    }
1137  pos = NSMaxRange(charRange) - 1;
1138  [self _generateGlyphsUpToCharacter: pos];
1139  if (glyphs->char_length <= pos)
1140    {
1141      if (actualCharRange)
1142        *actualCharRange = NSMakeRange([[_textStorage string] length], 0);
1143      return NSMakeRange([self numberOfGlyphs], 0);
1144    }
1145
1146  target = charRange.location;
1147  r = [self _glyphForCharacter: target
1148            index: &i
1149            positions: &pos : &cpos];
1150  glyph_range.location = i + pos;
1151  if (r->head.glyph_length > i)
1152    {
1153      char_range.location = r->glyphs[i].char_offset + cpos;
1154    }
1155  else
1156    {
1157      char_range.location = cpos;
1158    }
1159
1160  target = NSMaxRange(charRange) - 1;
1161  r = [self _glyphForCharacter: target
1162            index: &i
1163            positions: &pos : &cpos];
1164  if (r->head.glyph_length > i)
1165    {
1166      GLYPH_SCAN_FORWARD(r, i, pos, cpos, r->glyphs[i].char_offset + cpos <= target)
1167    }
1168
1169  glyph_range.length = i + pos - glyph_range.location;
1170  if (i >= r->head.glyph_length)
1171    char_range.length = glyphs->char_length - char_range.location;
1172  else
1173    char_range.length = r->glyphs[i].char_offset + cpos - char_range.location;
1174
1175  if (actualCharRange)
1176    *actualCharRange = char_range;
1177  return glyph_range;
1178}
1179
1180
1181/*
1182TODO? this might currently lead to continued runs not being marked as
1183continued runs. this will only happen at safe break spots, though, so
1184it should still be safe. might lose opportunities to merge runs, though.
1185*/
1186
1187/*
1188This is hairy.
1189
1190The ranges passed in and out of this method are ranges _after_ the change.
1191Internally, we switch between before- and after-indices. Comments mark the
1192places where we switch.
1193*/
1194- (void) invalidateGlyphsForCharacterRange: (NSRange)range
1195                            changeInLength: (int)lengthChange
1196                      actualCharacterRange: (NSRange *)actualRange
1197{
1198  glyph_run_head_t *context[SKIP_LIST_DEPTH];
1199  glyph_run_head_t *h;
1200  glyph_run_t *r;
1201  NSRange rng;
1202  int position[SKIP_LIST_DEPTH];
1203  unsigned int cpos;
1204  int level;
1205  unsigned int ch;
1206  unsigned int max;
1207
1208  /*
1209  We always clear out the cached run information to be safe. This is only needed
1210  if the cached run is affected by the invalidation, that is if
1211  NSMinRange(range) < cpos + cached_run->head.char_lenght
1212  */
1213  cached_run = NULL;
1214
1215  /* Set it now for early returns. */
1216  if (actualRange)
1217    *actualRange = range;
1218
1219//  printf("\n +++ range=(%i+%i) lengthChange=%i\n", range.location, range.length, lengthChange);
1220  [self _sanityChecks];
1221//  [self _glyphDumpRuns];
1222
1223  if ((range.location == 0) && (range.length >= [_textStorage length]))
1224    {
1225      // Full invalidation
1226      [self _invalidateEverything];
1227      return;
1228    }
1229
1230  /*
1231  Find out what range we actually need to invalidate. This depends on how
1232  context affects glyph generation.
1233  */
1234  ch = range.location;
1235  if (ch > 0)
1236    {
1237      ch = [self _findSafeBreakMovingBackwardFrom: ch];
1238      range.length += range.location - ch;
1239      range.location = ch;
1240    }
1241
1242  max = ch + range.length;
1243  if (max < [_textStorage length])
1244    {
1245      max = [self _findSafeBreakMovingForwardFrom: max];
1246      range.length = max - range.location;
1247    }
1248  //  printf("adjusted to %i+%i\n", range.location, range.length);
1249
1250  // Last affected character (indix before the change).
1251  max -= lengthChange;
1252
1253  /*
1254  Find the first run (and context) for the range.
1255  */
1256  h = glyphs;
1257  cpos = 0;
1258  for (level = SKIP_LIST_DEPTH - 1; level >= 0; level--)
1259    {
1260      while (cpos + h->char_length <= ch)
1261        {
1262          cpos += h->char_length;
1263          h = h->next;
1264          if (!h)
1265            {
1266              /*
1267                No runs have been created for the range, so there's nothing
1268                to invalidate.
1269              */
1270//	      printf("no runs created yet\n");
1271              return;
1272            }
1273        }
1274      context[level] = h;
1275      position[level] = cpos;
1276      h++;
1277    }
1278  h--;
1279  r = (glyph_run_t *)h;
1280
1281  /*
1282  Now we have the first run that intersects the range we're invalidating
1283  in 'r' (and context in 'context' and 'position').
1284  */
1285
1286  //printf("split if %i+%i > %i+%i\n", cpos, r->head.char_length, ch, range.length);
1287  /*
1288  If 'r' extends beyond the invalidated range, split off the trailing, valid
1289  part to a new run. The reason we need to do this is that we must have runs
1290  for the first glyph not invalidated or the deletion loop below will fail.
1291  */
1292  if (cpos + r->head.char_length > max && ch != cpos)
1293    {
1294      glyph_run_t *new;
1295      glyph_run_head_t *hn;
1296      int i;
1297
1298      new = run_insert(context,  random_level());
1299      new->head.char_length = cpos + r->head.char_length - max;
1300      [self _run_copy_attributes: new : r];
1301
1302      /* OPT: keep valid glyphs
1303      this seems to be a fairly rare case
1304      */
1305      hn = &new->head;
1306      hn--;
1307      for (i = 1; i <= new->level; i++, hn--)
1308        {
1309          // FIXME: Use simpler adjustment
1310          run_fix_head(hn);
1311        }
1312
1313      r->head.char_length -= new->head.char_length;
1314      // Glyphs get freed later
1315    }
1316
1317  /*
1318  Set things up. We want 'r' to be the last run we want to keep.
1319  */
1320  if (ch == cpos)
1321    {
1322      /*
1323      This run begins exactly at the beginning of the invalidated range.
1324      Since we want 'r' to be the last run to keep, we actually want it
1325      to be the previous run. Thus, we step backwards in the skip list
1326      to get the previous run.
1327      */
1328      glyph_run_head_t *h2;
1329
1330      h2 = h - r->level;
1331      h = context[r->level + 1];
1332      cpos = position[r->level + 1];
1333      h++;
1334      for (level = r->level; level >= 0; level--)
1335        {
1336          while (h->next != h2)
1337            {
1338              cpos += h->char_length;
1339              h = h->next;
1340            }
1341          // Fix up old context before switching
1342          if (level)
1343            run_fix_head(context[level]);
1344
1345          position[level] = cpos;
1346          context[level] = h;
1347          h++;
1348          h2++;
1349        }
1350      h--;
1351      r = (glyph_run_t *)h;
1352      cpos += r->head.char_length;
1353    }
1354  else
1355    {
1356      /*
1357      This run begins before the invalidated range. Resize it so it ends
1358      just before it.
1359      */
1360      int len = r->head.char_length;
1361
1362      r->head.char_length = ch - cpos;
1363      cpos += len;
1364      /* OPT!!! keep valid glyphs */
1365      run_free_glyphs(r);
1366    }
1367
1368  /*
1369  'r' is the last run we should keep, 'context' and 'position' are set up
1370  for it. cpos
1371
1372  Now we delete all runs completely invalidated.
1373  */
1374  {
1375    glyph_run_t *next;
1376
1377    while (1)
1378      {
1379        next = (glyph_run_t *)r->head.next;
1380
1381        /* We reached the end of all created runs. */
1382        if (!next)
1383          break;
1384
1385        NSAssert(max >= cpos,
1386                 @"no run for first glyph beyond invalidated range");
1387
1388        /* Clean cut, just stop. */
1389        if (max == cpos)
1390          break;
1391
1392        /*
1393          Part of this run extends beyond the invalidated range. Resize it
1394          so it's completely beyond the invalidated range and stop.
1395        */
1396        if (max < cpos + next->head.char_length)
1397          {
1398            glyph_run_head_t *hn;
1399            int i;
1400
1401            /* adjust final run */
1402            /* OPT!!! keep valid glyphs */
1403            run_free_glyphs(next);
1404
1405            next->head.char_length -= max - cpos;
1406
1407            hn = &next->head;
1408            hn--;
1409            for (i = 1; i <= next->level; i++, hn--)
1410              run_fix_head(hn);
1411
1412            break;
1413          }
1414
1415        cpos += next->head.char_length;
1416
1417        /*
1418          This run is completely inside the invalidated range. Remove it.
1419          The context run heads will be adjusted later.
1420        */
1421        [self _run_free_attributes: next];
1422        run_remove(context, next);
1423      }
1424  }
1425
1426/*  printf("deleted\n");
1427  [self _glyphDumpRuns];*/
1428
1429  /*
1430  From now one we are use indexes after after the length change.
1431  'r' is the last run we want to keep, and the next run is the next
1432  uninvalidated run. We need to insert new runs for invalidated range
1433  after 'r'.
1434
1435  As we create new runs, we move the context forward. When we do this, we
1436  adjust their heads with updated information. When we're done, we update
1437  all the remaining heads.
1438
1439  FIXME: Much of this code could be shared with the implementation in _generateRunsToCharacter:
1440  */
1441  //printf("create runs for %i+%i\n", range.location, range.length);
1442  { /* OPT: this is creating more runs than it needs to */
1443    NSDictionary *attributes;
1444    glyph_run_t *new;
1445    unsigned int max = range.location + range.length;
1446    int i;
1447
1448    ch = range.location;
1449    while (ch < max)
1450      {
1451        attributes = [_textStorage attributesAtIndex: ch
1452                                   longestEffectiveRange: &rng
1453                                   inRange: NSMakeRange(0, [_textStorage length])];
1454
1455        /* printf("at %i, max=%i, effective range (%i+%i)\n",
1456           ch, max, rng.location, rng.length);*/
1457
1458        /*
1459          Catch a common case. If the new run would be a continuation of the
1460          previous run, and the previous run is short, we resize the previous
1461          run instead of creating a new run.
1462
1463          (Note that we must make sure that we don't merge with the dummy runs
1464          at the very front.)
1465
1466          This happens a lot with repeated single-character insertions, aka.
1467          typing in a text view.
1468        */
1469        if (rng.location < ch && context[0]->char_length &&
1470            // FIXME: Why 16 and not MAX_RUN_LENGTH
1471            context[0]->char_length < 16)
1472          {
1473            rng.length -= ch - rng.location;
1474            rng.location = ch;
1475            if (ch + rng.length > max)
1476              {
1477                rng.length = max - ch;
1478              }
1479            new = (glyph_run_t *)context[0];
1480            // FIXME: We could try to reuse the glyphs
1481            run_free_glyphs(new);
1482            new->head.char_length += rng.length;
1483            ch = NSMaxRange(rng);
1484            continue;
1485          }
1486
1487        new = run_insert(context, random_level());
1488        [self _run_cache_attributes: new : attributes];
1489
1490        /*
1491          We have the longest range the attributes allow us to create a run
1492          for. Since this might overlap the previous and next runs, we might
1493          need to adjust the location and length of the range we create a
1494          run for.
1495
1496          OPT: If the overlapped run is short, we might want to clear out
1497          its glyphs and extend it to cover our range. This should result
1498          in fewer runs being created for large sequences of single character
1499          adds.
1500        */
1501        if (rng.location < ch)
1502          {
1503            /*
1504              The new run has the same attributes as the previous run, so we
1505              mark it is as a continued run.
1506            */
1507            new->continued = 1;
1508            rng.length -= ch - rng.location;
1509            rng.location = ch;
1510          }
1511        if (ch + rng.length > max)
1512          {
1513            /*
1514              The new run has the same attributes as the next run, so we mark
1515              the next run as a continued run.
1516            */
1517            if (new->head.next)
1518              ((glyph_run_t *)new->head.next)->continued = 1;
1519            rng.length = max - ch;
1520          }
1521
1522        /* See comment in -_generateRunsToCharacter:. */
1523        if (rng.length > MAX_RUN_LENGTH)
1524          {
1525            unsigned int safe_break = rng.location + MAX_RUN_LENGTH;
1526            safe_break = [self _findSafeBreakMovingForwardFrom: safe_break];
1527            if (safe_break < NSMaxRange(rng))
1528              rng.length = safe_break - rng.location;
1529          }
1530
1531        // printf("adjusted length: %i\n", rng.length);
1532
1533        h = &new->head;
1534        h->char_length = rng.length;
1535        for (i = 0; i <= new->level; i++, h--)
1536          {
1537            if (i)
1538              {
1539                // FIXME: Simpler adjustment
1540                run_fix_head(context[i]);
1541                run_fix_head(h);
1542              }
1543            //h->char_length = rng.length;
1544            context[i] = h;
1545          }
1546
1547        for (; i < SKIP_LIST_DEPTH; i++)
1548          {
1549            context[i]->char_length += rng.length;
1550            context[i]->complete = 0;
1551          }
1552
1553        ch += rng.length;
1554      }
1555  }
1556
1557  // Final fix up of context
1558  {
1559    int i;
1560
1561    for (i = 1; i < SKIP_LIST_DEPTH; i++)
1562      {
1563        run_fix_head(context[i]);
1564      }
1565  }
1566
1567  if (actualRange)
1568    *actualRange = range;
1569
1570  [self _sanityChecks];
1571  //[self _glyphDumpRuns];
1572}
1573
1574
1575#define GET_GLYPH \
1576	glyph_run_t *r; \
1577	unsigned int pos, cpos; \
1578\
1579	if (glyphs->glyph_length <= idx) \
1580	{ \
1581		[self _generateGlyphsUpToGlyph: idx]; \
1582		if (glyphs->glyph_length <= idx) \
1583		{ \
1584			[NSException raise: NSRangeException \
1585				format: @"%s glyph range out of range", __PRETTY_FUNCTION__]; \
1586		} \
1587	} \
1588 \
1589	r = run_for_glyph_index(idx, glyphs, &pos, &cpos); \
1590	if (!r) \
1591	{ \
1592		[NSException raise: NSRangeException \
1593			format: @"%s glyph range out of range", __PRETTY_FUNCTION__]; \
1594	} \
1595	idx -= pos;
1596
1597- (void) setDrawsOutsideLineFragment: (BOOL)flag
1598                     forGlyphAtIndex: (unsigned int)idx
1599{
1600  GET_GLYPH
1601  r->glyphs[idx].drawsOutsideLineFragment = !!flag;
1602}
1603- (BOOL) drawsOutsideLineFragmentForGlyphAtIndex: (unsigned int)idx
1604{
1605  GET_GLYPH
1606  return r->glyphs[idx].drawsOutsideLineFragment;
1607}
1608
1609- (void) setNotShownAttribute: (BOOL)flag
1610              forGlyphAtIndex: (unsigned int)idx
1611{
1612  GET_GLYPH
1613  r->glyphs[idx].isNotShown = !!flag;
1614}
1615- (BOOL) notShownAttributeForGlyphAtIndex: (unsigned int)idx
1616{
1617  GET_GLYPH
1618  return r->glyphs[idx].isNotShown;
1619}
1620
1621// GNUstep extension
1622- (NSFont *) effectiveFontForGlyphAtIndex: (unsigned int)idx
1623                                    range: (NSRange *)range
1624{
1625  GET_GLYPH
1626  if (range)
1627    *range = NSMakeRange(pos, r->head.glyph_length);
1628  return r->font;
1629}
1630
1631/**
1632 * GNUstep extension
1633 */
1634- (NSSize) advancementForGlyphAtIndex: (unsigned int)idx
1635{
1636  GET_GLYPH
1637  return r->glyphs[idx].advancement;
1638}
1639
1640- (void) insertGlyph: (NSGlyph)aGlyph
1641        atGlyphIndex: (unsigned int)glyphIndex
1642      characterIndex: (unsigned int)charIndex
1643{
1644  [self insertGlyphs: &aGlyph
1645        length: 1
1646        forStartingGlyphAtIndex: glyphIndex
1647        characterIndex: charIndex];
1648}
1649
1650- (void) replaceGlyphAtIndex: (unsigned int)glyphIndex
1651                   withGlyph: (NSGlyph)newGlyph
1652{
1653  glyph_run_t *r;
1654  unsigned int pos, cpos;
1655
1656  if (glyphs->glyph_length <= glyphIndex)
1657    {
1658      [NSException raise: NSRangeException
1659		  format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
1660      return;
1661    }
1662
1663  r = run_for_glyph_index(glyphIndex, glyphs, &pos, &cpos);
1664  if (!r)
1665    {
1666      [NSException raise: NSRangeException
1667		   format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
1668      return;
1669    }
1670
1671  if (!r->glyphs || r->head.glyph_length < glyphIndex - pos)
1672    {
1673      [NSException raise: NSRangeException
1674		   format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
1675      return;
1676    }
1677
1678  r->glyphs[glyphIndex - pos].g = newGlyph;
1679}
1680
1681- (void) deleteGlyphsInRange: (NSRange)aRange
1682{
1683  /* See invalidateGlyphsForCharacterRange:changeInLength:actualCharacterRange:
1684  glyph_run_t *run;
1685  unsigned int pos, cpos;
1686  unsigned int glyphIndex;
1687  unsigned int lastGlyphIndex;
1688  glyph_run_head_t *context[SKIP_LIST_DEPTH];
1689
1690  glyphIndex = NSMinRange(aRange);
1691  lastGlyphIndex = NSMaxRange(aRange) - 1;
1692  while (glyphIndex <= lastGlyphIndex)
1693    {
1694      run = run_for_glyph_index(glyphIndex, glyphs, &pos, &cpos);
1695      if (!run)
1696	{
1697	  [NSException raise: NSRangeException
1698		      format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
1699	  return;
1700	}
1701
1702        // FIXME: remove all invalid glyphs from run
1703        if ((pos == 0) && (lastGlyphIndex >= glyphIndex - pos + run->head.glyph_length))
1704          {
1705            run_free_glyphs(run);
1706          }
1707        else
1708          {
1709            if (lastGlyphIndex >= glyphIndex - pos + run->head.glyph_length)
1710              {
1711              }
1712            r->head.glyph_length = len;
1713          }
1714        // FIXME: Need to invalidate the entries above this one.
1715
1716        // FIXME Cache this value
1717        glyphIndex += r->head.glyph_length - pos;
1718    }
1719  */
1720  NSLog(@"Internal method %s called", __PRETTY_FUNCTION__);
1721}
1722
1723- (void) setCharacterIndex: (unsigned int)charIndex
1724           forGlyphAtIndex: (unsigned int)glyphIndex
1725{
1726  glyph_run_t *r;
1727  unsigned int pos, cpos;
1728
1729  if (glyphs->glyph_length <= glyphIndex)
1730    {
1731      [NSException raise: NSRangeException
1732		  format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
1733      return;
1734    }
1735
1736  r = run_for_glyph_index(glyphIndex, glyphs, &pos, &cpos);
1737  if (!r)
1738    {
1739      [NSException raise: NSRangeException
1740		   format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
1741      return;
1742    }
1743
1744  if (!r->glyphs || r->head.glyph_length < glyphIndex - pos)
1745    {
1746      [NSException raise: NSRangeException
1747		   format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
1748      return;
1749    }
1750
1751  r->glyphs[glyphIndex - pos].char_offset = charIndex - cpos;
1752  // What should happen to the following glyphs?
1753}
1754
1755- (int) intAttribute: (int)attributeTag
1756     forGlyphAtIndex: (unsigned int)glyphIndex
1757{
1758  glyph_run_t *run;
1759  glyph_t *g;
1760  unsigned int pos;
1761
1762  run = run_for_glyph_index(glyphIndex, glyphs, &pos, NULL);
1763  if (run && run->glyphs && (run->head.glyph_length < glyphIndex - pos))
1764    {
1765      g = &run->glyphs[glyphIndex - pos];
1766
1767      if (attributeTag == NSGlyphAttributeInscribe)
1768        return g->inscription;
1769      else if (attributeTag == NSGlyphAttributeSoft)
1770        return g->soft;
1771      else if (attributeTag == NSGlyphAttributeElastic)
1772        return g->elasitc;
1773      else if (attributeTag == NSGlyphAttributeBidiLevel)
1774        return g->bidilevel;
1775    }
1776
1777  return 0;
1778}
1779
1780@end
1781
1782
1783
1784/***** Layout handling *****/
1785
1786@implementation GSLayoutManager (LayoutHelpers)
1787
1788-(void) _invalidateLayoutFromContainer: (int)idx
1789{
1790  int i, j;
1791  textcontainer_t *tc;
1792  linefrag_t *lf;
1793
1794  extra_textcontainer = nil;
1795
1796  for (i = idx, tc = textcontainers + idx; i < num_textcontainers; i++, tc++)
1797    {
1798      tc->complete = NO;
1799      if (tc->linefrags)
1800	{
1801	  for (j = 0, lf = tc->linefrags; j < tc->num_linefrags + tc->num_soft; j++, lf++)
1802	    {
1803	      if (lf->points)
1804		free(lf->points);
1805	      if (lf->attachments)
1806		free(lf->attachments);
1807	    }
1808
1809	  free(tc->linefrags);
1810	}
1811      tc->linefrags = NULL;
1812      tc->num_linefrags = tc->num_soft = 0;
1813      tc->size_linefrags = 0;
1814      tc->pos = tc->length = 0;
1815      tc->was_invalidated = YES;
1816    }
1817  for (i = idx - 1, tc = textcontainers + idx - 1; i >= 0; i--, tc--)
1818    {
1819      if (tc->num_linefrags)
1820	{
1821	  layout_glyph = tc->pos + tc->length;
1822	  if (layout_glyph == glyphs->glyph_length)
1823	    layout_char = glyphs->char_length;
1824	  else
1825	    layout_char = [self characterIndexForGlyphAtIndex: layout_glyph]; /* TODO? */
1826	  return;
1827	}
1828    }
1829  layout_glyph = layout_char = 0;
1830}
1831
1832-(void) _freeLayout
1833{
1834  [self _invalidateLayoutFromContainer: 0];
1835}
1836
1837-(void) _invalidateEverything
1838{
1839  [self _freeLayout];
1840  [self _freeGlyphs];
1841  [self _initGlyphs];
1842}
1843
1844-(void) _doLayout
1845{
1846  [self _doLayoutToContainer: num_textcontainers - 1];
1847}
1848
1849-(void) _doLayoutToGlyph: (unsigned int)glyphIndex
1850{
1851  int i, j;
1852  textcontainer_t *tc;
1853  unsigned int next;
1854  NSRect prev;
1855  BOOL delegate_responds;
1856
1857  delegate_responds = [_delegate respondsToSelector:
1858    @selector(layoutManager:didCompleteLayoutForTextContainer:atEnd:)];
1859
1860  next = layout_glyph;
1861  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
1862    {
1863      if (tc->complete)
1864          continue;
1865
1866      while (1)
1867        {
1868          if (tc->num_linefrags)
1869            prev = tc->linefrags[tc->num_linefrags - 1].rect;
1870          else
1871            prev = NSZeroRect;
1872          j = [typesetter layoutGlyphsInLayoutManager: self
1873                          inTextContainer: tc->textContainer
1874                          startingAtGlyphIndex: next
1875                          previousLineFragmentRect: prev
1876                          nextGlyphIndex: &next
1877                          numberOfLineFragments: 0];
1878          if (j)
1879            break;
1880
1881          if (next > glyphIndex)
1882            {
1883              // If all the requested work is done just leave
1884              return;
1885            }
1886        }
1887      tc->complete = YES;
1888      tc->usedRectValid = NO;
1889      if (tc->num_soft)
1890        {
1891          /*
1892            If there is any soft invalidated layout information left, remove
1893            it.
1894          */
1895          int k;
1896          linefrag_t *lf;
1897          for (k = tc->num_linefrags, lf = tc->linefrags + k;
1898               k < tc->num_linefrags + tc->num_soft; k++, lf++)
1899            {
1900              if (lf->points)
1901                {
1902                  free(lf->points);
1903                  lf->points = NULL;
1904                }
1905              if (lf->attachments)
1906                {
1907                  free(lf->attachments);
1908                  lf->attachments = NULL;
1909                }
1910            }
1911          tc->num_soft = 0;
1912        }
1913      if (delegate_responds)
1914        {
1915          [_delegate layoutManager: self
1916                     didCompleteLayoutForTextContainer: tc->textContainer
1917                     atEnd: j == 2];
1918          /* The call might have resulted in more text containers being
1919             added, so 'textcontainers' might have moved. */
1920          tc = textcontainers + i;
1921        }
1922      if (j == 2)
1923        {
1924          break;
1925        }
1926      if (i == num_textcontainers && delegate_responds)
1927        {
1928          [_delegate layoutManager: self
1929                     didCompleteLayoutForTextContainer: nil
1930                     atEnd: NO];
1931        }
1932    }
1933}
1934
1935-(void) _doLayoutToContainer: (int)cindex
1936{
1937  int i, j;
1938  textcontainer_t *tc;
1939  unsigned int next;
1940  NSRect prev;
1941  BOOL delegate_responds;
1942
1943  delegate_responds = [_delegate respondsToSelector:
1944    @selector(layoutManager:didCompleteLayoutForTextContainer:atEnd:)];
1945
1946  next = layout_glyph;
1947  for (i = 0, tc = textcontainers; i <= cindex; i++, tc++)
1948    {
1949      if (tc->complete)
1950          continue;
1951
1952      while (1)
1953        {
1954          if (tc->num_linefrags)
1955            prev = tc->linefrags[tc->num_linefrags - 1].rect;
1956          else
1957            prev = NSZeroRect;
1958          j = [typesetter layoutGlyphsInLayoutManager: self
1959                          inTextContainer: tc->textContainer
1960                          startingAtGlyphIndex: next
1961                          previousLineFragmentRect: prev
1962                          nextGlyphIndex: &next
1963                          numberOfLineFragments: 0];
1964          if (j)
1965            break;
1966        }
1967      tc->complete = YES;
1968      tc->usedRectValid = NO;
1969      if (tc->num_soft)
1970        {
1971          /*
1972            If there is any soft invalidated layout information left, remove
1973            it.
1974          */
1975          int k;
1976          linefrag_t *lf;
1977          for (k = tc->num_linefrags, lf = tc->linefrags + k;
1978               k < tc->num_linefrags + tc->num_soft; k++, lf++)
1979            {
1980              if (lf->points)
1981                {
1982                  free(lf->points);
1983                  lf->points = NULL;
1984                }
1985              if (lf->attachments)
1986                {
1987                  free(lf->attachments);
1988                  lf->attachments = NULL;
1989                }
1990            }
1991          tc->num_soft = 0;
1992        }
1993      if (delegate_responds)
1994        {
1995          [_delegate layoutManager: self
1996                     didCompleteLayoutForTextContainer: tc->textContainer
1997                     atEnd: j == 2];
1998          /* The call might have resulted in more text containers being
1999             added, so 'textcontainers' might have moved. */
2000          tc = textcontainers + i;
2001        }
2002      if (j == 2)
2003        {
2004          break;
2005        }
2006      if (i == num_textcontainers && delegate_responds)
2007        {
2008          [_delegate layoutManager: self
2009                     didCompleteLayoutForTextContainer: nil
2010                     atEnd: NO];
2011        }
2012    }
2013}
2014
2015-(void) _didInvalidateLayout
2016{
2017  int i;
2018  textcontainer_t *tc;
2019
2020  for (tc = textcontainers, i = 0; i < num_textcontainers; i++, tc++)
2021    {
2022      // FIXME: This value never gets used
2023      tc->was_invalidated = YES;
2024    }
2025}
2026
2027@end
2028
2029
2030@implementation GSLayoutManager (layout)
2031
2032
2033/*
2034In the general case, we can't make any assumptions about how layout might
2035interact between line frag rects. To be safe in all cases, we must
2036invalidate all layout information.
2037
2038TODO:
2039We could handle this by assuming that whoever calls this knows exactly what
2040needs to be invalidated. We won't be using it internally, anyway, so it
2041doesn't matter much to us, and it would make more advanced things possible
2042for external callers. On the other hand, it would be easy to break things
2043by calling this incorrectly.
2044*/
2045- (void) invalidateLayoutForCharacterRange: (NSRange)aRange
2046				    isSoft: (BOOL)flag
2047		      actualCharacterRange: (NSRange *)actualRange
2048{
2049  [self _invalidateLayoutFromContainer: 0];
2050}
2051
2052
2053#define SETUP_STUFF \
2054  unsigned int max = glyphRange.location + glyphRange.length; \
2055  \
2056  [self _generateGlyphsUpToGlyph: max - 1]; \
2057  if (glyphs->glyph_length < max) \
2058    { \
2059      [NSException raise: NSRangeException \
2060		  format: @"%s: glyph range out of range", __PRETTY_FUNCTION__]; \
2061      return; \
2062    }
2063
2064- (void) setTextContainer: (NSTextContainer *)aTextContainer
2065	forGlyphRange: (NSRange)glyphRange
2066{
2067  textcontainer_t *tc;
2068  int i;
2069  SETUP_STUFF
2070
2071  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
2072    if (tc->textContainer == aTextContainer)
2073      break;
2074  if (i == num_textcontainers)
2075    {
2076      NSLog(@"%s: doesn't own text container", __PRETTY_FUNCTION__);
2077      return;
2078    }
2079
2080  /* Assume that no line frags means that layout hasn't started yet. */
2081  if (tc->num_linefrags)
2082    {
2083      if (glyphRange.location != tc->pos + tc->length)
2084	{
2085	  [NSException raise: NSRangeException
2086		      format: @"%s: glyph range not consistent with existing layout",
2087			      __PRETTY_FUNCTION__];
2088	  return;
2089	}
2090      tc->length += glyphRange.length;
2091    }
2092  else if (!i)
2093    {
2094      if (glyphRange.location)
2095	{
2096	  [NSException raise: NSRangeException
2097		      format: @"%s: glyph range not consistent with existing layout",
2098			      __PRETTY_FUNCTION__];
2099	  return;
2100	}
2101      tc->pos = 0;
2102      tc->length = glyphRange.length;
2103    }
2104  else
2105    {
2106      if (tc[-1].pos + tc[-1].length != glyphRange.location)
2107	{
2108	  [NSException raise: NSRangeException
2109		      format: @"%s: glyph range not consistent with existing layout",
2110			      __PRETTY_FUNCTION__];
2111	  return;
2112	}
2113      tc->pos = glyphRange.location;
2114      tc->length = glyphRange.length;
2115    }
2116
2117  {
2118    unsigned int gpos;
2119    unsigned int g;
2120    glyph_t *glyph;
2121    glyph_run_t *run = run_for_glyph_index(glyphRange.location, glyphs, &gpos, NULL);
2122
2123    g = glyphRange.location;
2124    glyph = &run->glyphs[g - gpos];
2125    while (g < glyphRange.location + glyphRange.length)
2126      {
2127	if (g == gpos + run->head.glyph_length)
2128	  {
2129	    gpos += run->head.glyph_length;
2130	    run = (glyph_run_t *)run->head.next;
2131	    glyph = run->glyphs;
2132	  }
2133
2134	glyph->isNotShown = NO;
2135	glyph->drawsOutsideLineFragment = NO;
2136	g++;
2137	glyph++;
2138      }
2139  }
2140
2141  layout_glyph = tc->pos + tc->length;
2142  if (layout_glyph == glyphs->glyph_length)
2143    layout_char = glyphs->char_length;
2144  else
2145    layout_char = [self characterIndexForGlyphAtIndex: layout_glyph];
2146}
2147
2148- (void) setLineFragmentRect: (NSRect)fragmentRect
2149	       forGlyphRange: (NSRange)glyphRange
2150		    usedRect: (NSRect)usedRect
2151{
2152  textcontainer_t *tc;
2153  int i;
2154  linefrag_t *lf;
2155
2156  SETUP_STUFF
2157
2158  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
2159    {
2160      if (tc->pos <= glyphRange.location &&
2161	  tc->pos + tc->length >= glyphRange.location + glyphRange.length)
2162	break;
2163    }
2164  if (i == num_textcontainers)
2165    {
2166      [NSException raise: NSRangeException
2167		  format: @"%s: glyph range not consistent with existing layout",
2168			  __PRETTY_FUNCTION__];
2169      return;
2170    }
2171
2172  /* Make sure the given glyph range matches earlier layout. */
2173  if (!tc->num_linefrags)
2174    {
2175      if (glyphRange.location != tc->pos)
2176	{
2177	  [NSException raise: NSRangeException
2178		      format: @"%s: glyph range not consistent with existing layout",
2179			      __PRETTY_FUNCTION__];
2180	  return;
2181	}
2182    }
2183  else
2184    {
2185      lf = &tc->linefrags[tc->num_linefrags - 1];
2186      if (lf->pos + lf->length != glyphRange.location)
2187	{
2188	  [NSException raise: NSRangeException
2189		      format: @"%s: glyph range not consistent with existing layout",
2190			      __PRETTY_FUNCTION__];
2191	  return;
2192	}
2193    }
2194
2195  if (!(tc->num_linefrags + tc->num_soft))
2196    {
2197      if (!tc->size_linefrags)
2198	{
2199	  tc->size_linefrags = 16;
2200	  tc->linefrags = malloc(sizeof(linefrag_t) * tc->size_linefrags);
2201	}
2202      tc->num_linefrags = 1;
2203      lf = tc->linefrags;
2204    }
2205  else if (!tc->num_soft)
2206    {
2207      if (tc->size_linefrags <= tc->num_linefrags)
2208	{
2209	  tc->size_linefrags += tc->size_linefrags / 2;
2210	  tc->linefrags = realloc(tc->linefrags, sizeof(linefrag_t) * tc->size_linefrags);
2211	}
2212      tc->num_linefrags++;
2213      lf = &tc->linefrags[tc->num_linefrags - 1];
2214    }
2215  else
2216    {
2217      int i;
2218      for (i = tc->num_linefrags, lf = tc->linefrags + i; i < tc->num_linefrags + tc->num_soft; i++, lf++)
2219	{
2220	  if (lf->pos >= NSMaxRange(glyphRange))
2221	    break;
2222	  if (lf->points)
2223	    {
2224	      free(lf->points);
2225	      lf->points = NULL;
2226	    }
2227	  if (lf->attachments)
2228	    {
2229	      free(lf->attachments);
2230	      lf->attachments = NULL;
2231	    }
2232	}
2233
2234      if (i == tc->num_linefrags)
2235	{
2236	  /*
2237	  If we should keep all soft frags, we need to enlarge the array
2238	  to fit the new line frag.
2239	  */
2240	  if (tc->size_linefrags <= tc->num_linefrags + tc->num_soft)
2241	    {
2242	      tc->size_linefrags += tc->size_linefrags / 2;
2243	      tc->linefrags = realloc(tc->linefrags, sizeof(linefrag_t) * tc->size_linefrags);
2244	    }
2245	  memmove(&tc->linefrags[tc->num_linefrags + 1], &tc->linefrags[tc->num_linefrags], tc->num_soft * sizeof(linefrag_t));
2246	}
2247      else if (i > tc->num_linefrags + 1)
2248	{
2249	  tc->num_soft -= i - tc->num_linefrags;
2250	  memmove(&tc->linefrags[tc->num_linefrags + 1], &tc->linefrags[i], tc->num_soft * sizeof(linefrag_t));
2251	}
2252      else
2253	{
2254	  /*
2255	  If i == tc->num_linefrags + 1, we're lucky and everything already
2256	  lines up, so no moving is necessary.
2257	  */
2258	  tc->num_soft--;
2259	}
2260
2261      tc->num_linefrags++;
2262      lf = &tc->linefrags[tc->num_linefrags - 1];
2263    }
2264
2265  memset(lf, 0, sizeof(linefrag_t));
2266  lf->rect = fragmentRect;
2267  lf->used_rect = usedRect;
2268  lf->pos = glyphRange.location;
2269  lf->length = glyphRange.length;
2270}
2271
2272- (void) setLocation: (NSPoint)location
2273forStartOfGlyphRange: (NSRange)glyphRange
2274{
2275  textcontainer_t *tc;
2276  int i;
2277  linefrag_t *lf;
2278  linefrag_point_t *lp;
2279
2280  SETUP_STUFF
2281
2282  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
2283    {
2284      if (tc->pos <= glyphRange.location &&
2285	  tc->pos + tc->length >= glyphRange.location + glyphRange.length)
2286	break;
2287    }
2288  if (i == num_textcontainers)
2289    {
2290      [NSException raise: NSRangeException
2291		  format: @"%s: glyph range not consistent with existing layout",
2292			  __PRETTY_FUNCTION__];
2293      return;
2294    }
2295
2296  for (i = tc->num_linefrags - 1, lf = tc->linefrags + i; i >= 0; i--, lf--)
2297    {
2298      if (lf->pos <= glyphRange.location &&
2299	  lf->pos + lf->length >= glyphRange.location + glyphRange.length)
2300	break;
2301    }
2302  if (i < 0)
2303    {
2304      [NSException raise: NSRangeException
2305		  format: @"%s: glyph range not consistent with existing layout",
2306			  __PRETTY_FUNCTION__];
2307      return;
2308    }
2309
2310  if (!lf->num_points)
2311    {
2312      if (glyphRange.location != lf->pos)
2313	{
2314	  [NSException raise: NSRangeException
2315		      format: @"%s: glyph range not consistent with existing layout",
2316			      __PRETTY_FUNCTION__];
2317	  return;
2318	}
2319      lp = lf->points = malloc(sizeof(linefrag_point_t));
2320      lf->num_points++;
2321    }
2322  else
2323    {
2324      lp = &lf->points[lf->num_points - 1];
2325      if (lp->pos + lp->length != glyphRange.location)
2326	{
2327	  [NSException raise: NSRangeException
2328		      format: @"%s: glyph range not consistent with existing layout",
2329			      __PRETTY_FUNCTION__];
2330	  return;
2331	}
2332      lf->num_points++;
2333      lf->points = realloc(lf->points, sizeof(linefrag_point_t) * lf->num_points);
2334      lp = &lf->points[lf->num_points - 1];
2335    }
2336  lp->pos = glyphRange.location;
2337  lp->length = glyphRange.length;
2338  lp->p = location;
2339}
2340
2341
2342-(void) setAttachmentSize: (NSSize)size
2343	    forGlyphRange: (NSRange)glyphRange
2344{
2345  textcontainer_t *tc;
2346  int i;
2347  linefrag_t *lf;
2348  linefrag_attachment_t *la;
2349
2350  SETUP_STUFF
2351
2352  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
2353    {
2354      if (tc->pos <= glyphRange.location &&
2355	  tc->pos + tc->length >= glyphRange.location + glyphRange.length)
2356	break;
2357    }
2358  if (i == num_textcontainers)
2359    {
2360      [NSException raise: NSRangeException
2361		  format: @"%s: glyph range not consistent with existing layout",
2362			  __PRETTY_FUNCTION__];
2363      return;
2364    }
2365
2366  for (i = 0, lf = tc->linefrags; i < tc->num_linefrags; i++, lf++)
2367    {
2368      if (lf->pos <= glyphRange.location &&
2369	  lf->pos + lf->length >= glyphRange.location + glyphRange.length)
2370	break;
2371    }
2372  if (i == tc->num_linefrags)
2373    {
2374      [NSException raise: NSRangeException
2375		  format: @"%s: glyph range not consistent with existing layout",
2376			  __PRETTY_FUNCTION__];
2377      return;
2378    }
2379
2380  /* TODO: we do no sanity checking of attachment size ranges. might want
2381  to consider doing it */
2382  lf->attachments = realloc(lf->attachments,
2383		      sizeof(linefrag_attachment_t) * (lf->num_attachments + 1));
2384  la = &lf->attachments[lf->num_attachments++];
2385
2386  memset(la, 0, sizeof(linefrag_attachment_t));
2387  la->pos = glyphRange.location;
2388  la->length = glyphRange.length;
2389  la->size = size;
2390}
2391
2392#undef SETUP_STUFF
2393
2394- (NSTextContainer *) textContainerForGlyphAtIndex: (NSUInteger)glyphIndex
2395                                    effectiveRange: (NSRange *)effectiveRange
2396{
2397  return [self textContainerForGlyphAtIndex: glyphIndex
2398               effectiveRange: effectiveRange
2399               withoutAdditionalLayout: NO];
2400}
2401
2402- (NSTextContainer *) textContainerForGlyphAtIndex: (NSUInteger)glyphIndex
2403                                    effectiveRange: (NSRange *)effectiveRange
2404                           withoutAdditionalLayout: (BOOL)flag
2405{
2406  textcontainer_t *tc;
2407  int i;
2408
2409  if (!flag)
2410    [self _doLayoutToGlyph: glyphIndex];
2411
2412  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
2413    if (tc->pos + tc->length > glyphIndex)
2414      break;
2415  if (i == num_textcontainers)
2416    {
2417      NSLog(@"%s: can't find text container for glyph (internal error)", __PRETTY_FUNCTION__);
2418      return nil;
2419    }
2420
2421  if (effectiveRange)
2422    {
2423      [self _doLayoutToContainer: i];
2424      tc = textcontainers + i;
2425      *effectiveRange = NSMakeRange(tc->pos, tc->length);
2426    }
2427  return tc->textContainer;
2428}
2429
2430- (NSRect) lineFragmentRectForGlyphAtIndex: (NSUInteger)glyphIndex
2431			    effectiveRange: (NSRange *)effectiveGlyphRange
2432{
2433  return [self lineFragmentRectForGlyphAtIndex: glyphIndex
2434               effectiveRange: effectiveGlyphRange
2435               withoutAdditionalLayout: NO];
2436}
2437
2438- (NSRect) lineFragmentRectForGlyphAtIndex: (NSUInteger)glyphIndex
2439                            effectiveRange: (NSRange *)effectiveGlyphRange
2440                   withoutAdditionalLayout: (BOOL)flag
2441{
2442  int i;
2443  textcontainer_t *tc;
2444  linefrag_t *lf;
2445
2446  if (!flag)
2447    [self _doLayoutToGlyph: glyphIndex];
2448
2449  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
2450    if (tc->pos + tc->length > glyphIndex)
2451      break;
2452  if (i == num_textcontainers)
2453    {
2454      NSLog(@"%s: can't find text container for glyph (internal error)", __PRETTY_FUNCTION__);
2455      return NSZeroRect;
2456    }
2457
2458  for (i = 0, lf = tc->linefrags; i < tc->num_linefrags; i++, lf++)
2459    if (lf->pos + lf->length > glyphIndex)
2460      break;
2461  if (i == tc->num_linefrags)
2462    {
2463      NSLog(@"%s: can't find line frag rect for glyph (internal error)", __PRETTY_FUNCTION__);
2464      return NSZeroRect;
2465    }
2466
2467  if (effectiveGlyphRange)
2468    {
2469      *effectiveGlyphRange = NSMakeRange(lf->pos, lf->length);
2470    }
2471  return lf->rect;
2472}
2473
2474- (NSRect) lineFragmentUsedRectForGlyphAtIndex: (NSUInteger)glyphIndex
2475				effectiveRange: (NSRange *)effectiveGlyphRange
2476{
2477  return [self lineFragmentUsedRectForGlyphAtIndex: glyphIndex
2478               effectiveRange: effectiveGlyphRange
2479               withoutAdditionalLayout: NO];
2480}
2481
2482- (NSRect) lineFragmentUsedRectForGlyphAtIndex: (NSUInteger)glyphIndex
2483                                effectiveRange: (NSRange *)effectiveGlyphRange
2484                       withoutAdditionalLayout: (BOOL)flag
2485{
2486  int i;
2487  textcontainer_t *tc;
2488  linefrag_t *lf;
2489
2490  if (!flag)
2491    [self _doLayoutToGlyph: glyphIndex];
2492
2493  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
2494    if (tc->pos + tc->length > glyphIndex)
2495      break;
2496  if (i == num_textcontainers)
2497    {
2498      NSLog(@"%s: can't find text container for glyph (internal error)", __PRETTY_FUNCTION__);
2499      return NSMakeRect(0, 0, 0, 0);
2500    }
2501
2502  for (i = 0, lf = tc->linefrags; i < tc->num_linefrags; i++, lf++)
2503    if (lf->pos + lf->length > glyphIndex)
2504      break;
2505  if (i == tc->num_linefrags)
2506    {
2507      NSLog(@"%s: can't find line frag rect for glyph (internal error)", __PRETTY_FUNCTION__);
2508      return NSMakeRect(0, 0, 0, 0);
2509    }
2510
2511  if (effectiveGlyphRange)
2512    {
2513      *effectiveGlyphRange = NSMakeRange(lf->pos, lf->length);
2514    }
2515  return lf->used_rect;
2516}
2517
2518- (NSRange) rangeOfNominallySpacedGlyphsContainingIndex: (unsigned int)glyphIndex
2519					  startLocation: (NSPoint *)p
2520{
2521  int i;
2522  textcontainer_t *tc;
2523  linefrag_t *lf;
2524  linefrag_point_t *lp;
2525
2526  [self _doLayoutToGlyph: glyphIndex];
2527  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
2528    if (tc->pos + tc->length > glyphIndex)
2529      break;
2530  if (i == num_textcontainers)
2531    {
2532      NSLog(@"%s: can't find text container for glyph (internal error)", __PRETTY_FUNCTION__);
2533      return NSMakeRange(NSNotFound, 0);
2534    }
2535
2536  for (i = 0, lf = tc->linefrags; i < tc->num_linefrags; i++, lf++)
2537    if (lf->pos + lf->length > glyphIndex)
2538      break;
2539  if (i == tc->num_linefrags)
2540    {
2541      NSLog(@"%s: can't find line frag rect for glyph (internal error)", __PRETTY_FUNCTION__);
2542      return NSMakeRange(NSNotFound, 0);
2543    }
2544
2545  for (i = 0, lp = lf->points; i < lf->num_points; i++, lp++)
2546    if (lp->pos + lp->length > glyphIndex)
2547      break;
2548  if (i == lf->num_points)
2549    {
2550      NSLog(@"%s: can't find location for glyph (internal error)", __PRETTY_FUNCTION__);
2551      return NSMakeRange(NSNotFound, 0);
2552    }
2553
2554  if (p)
2555    *p = lp->p;
2556  return NSMakeRange(lp->pos, lp->length);
2557}
2558
2559
2560- (NSRange) rangeOfNominallySpacedGlyphsContainingIndex:(unsigned int)glyphIndex
2561{
2562  return [self rangeOfNominallySpacedGlyphsContainingIndex: glyphIndex
2563	       startLocation: NULL];
2564}
2565
2566
2567/* The union of all line frag rects' used rects. */
2568- (NSRect) usedRectForTextContainer: (NSTextContainer *)container
2569{
2570  textcontainer_t *tc;
2571  linefrag_t *lf;
2572  int i;
2573  NSRect used;
2574
2575  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
2576    if (tc->textContainer == container)
2577      break;
2578  if (i == num_textcontainers)
2579    {
2580      NSLog(@"%s: doesn't own text container", __PRETTY_FUNCTION__);
2581      return NSMakeRect(0, 0, 0, 0);
2582    }
2583  if (!tc->complete)
2584    {
2585      [self _doLayoutToContainer: i];
2586      tc = textcontainers + i;
2587    }
2588
2589  if (tc->usedRectValid)
2590    {
2591      used = tc->usedRect;
2592      if (tc->textContainer == extra_textcontainer)
2593        {
2594          used = NSUnionRect(used, extra_used_rect);
2595        }
2596      return used;
2597    }
2598
2599  if (tc->num_linefrags)
2600    {
2601      double x0, y0, x1, y1;
2602      i = 0;
2603      lf = tc->linefrags;
2604      x0 = NSMinX(lf->used_rect);
2605      y0 = NSMinY(lf->used_rect);
2606      x1 = NSMaxX(lf->used_rect);
2607      y1 = NSMaxY(lf->used_rect);
2608      for (i++, lf++; i < tc->num_linefrags; i++, lf++)
2609	{
2610	  if (NSMinX(lf->used_rect) < x0)
2611	    x0 = NSMinX(lf->used_rect);
2612	  if (NSMinY(lf->used_rect) < y0)
2613	    y0 = NSMinY(lf->used_rect);
2614	  if (NSMaxX(lf->used_rect) > x1)
2615	    x1 = NSMaxX(lf->used_rect);
2616	  if (NSMaxY(lf->used_rect) > y1)
2617	    y1 = NSMaxY(lf->used_rect);
2618	}
2619      used = NSMakeRect(x0, y0, x1 - x0, y1 - y0);
2620    }
2621  else
2622    {
2623      used = NSZeroRect;
2624    }
2625  tc->usedRect = used;
2626  tc->usedRectValid = YES;
2627  if (tc->textContainer == extra_textcontainer)
2628    {
2629      used = NSUnionRect(used, extra_used_rect);
2630    }
2631  return used;
2632}
2633
2634- (NSRange) glyphRangeForTextContainer: (NSTextContainer *)container
2635{
2636  textcontainer_t *tc;
2637  int i;
2638
2639  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
2640    if (tc->textContainer == container)
2641      break;
2642  if (i == num_textcontainers)
2643    {
2644      NSLog(@"%s: doesn't own text container", __PRETTY_FUNCTION__);
2645      return NSMakeRange(NSNotFound, 0);
2646    }
2647
2648  [self _doLayoutToContainer: i];
2649  tc = textcontainers + i;
2650  return NSMakeRange(tc->pos, tc->length);
2651}
2652
2653
2654/* TODO: make more efficient */
2655- (NSArray *) textContainers
2656{
2657  NSMutableArray *ma;
2658  int i;
2659
2660  ma = [[NSMutableArray alloc] initWithCapacity: num_textcontainers];
2661  for (i = 0; i < num_textcontainers; i++)
2662    [ma addObject: textcontainers[i].textContainer];
2663  return [ma autorelease];
2664}
2665
2666- (void) addTextContainer: (NSTextContainer *)container
2667{
2668  [self insertTextContainer: container
2669	atIndex: num_textcontainers];
2670}
2671
2672- (void) insertTextContainer: (NSTextContainer *)aTextContainer
2673		     atIndex: (unsigned int)index
2674{
2675  unsigned int i;
2676
2677  if (index < num_textcontainers)
2678    [self _invalidateLayoutFromContainer: index];
2679
2680  num_textcontainers++;
2681  textcontainers = realloc(textcontainers,
2682			 sizeof(textcontainer_t) * num_textcontainers);
2683
2684  for (i = num_textcontainers - 1; i > index; i--)
2685    textcontainers[i] = textcontainers[i - 1];
2686
2687  memset(&textcontainers[i], 0, sizeof(textcontainer_t));
2688  textcontainers[i].textContainer = [aTextContainer retain];
2689
2690  [aTextContainer setLayoutManager: self];
2691
2692  [self _didInvalidateLayout];
2693}
2694
2695- (void) removeTextContainerAtIndex: (unsigned int)index
2696{
2697  int i;
2698  textcontainer_t *tc = &textcontainers[index];
2699
2700  [self _invalidateLayoutFromContainer: index];
2701  [tc->textContainer setLayoutManager: nil];
2702  [tc->textContainer release];
2703
2704  num_textcontainers--;
2705  for (i = index; i < num_textcontainers; i++)
2706    textcontainers[i] = textcontainers[i + 1];
2707
2708  if (num_textcontainers)
2709    textcontainers = realloc(textcontainers,
2710			   sizeof(textcontainer_t) * num_textcontainers);
2711  else
2712    {
2713      free(textcontainers);
2714      textcontainers = NULL;
2715    }
2716
2717  [self _didInvalidateLayout];
2718}
2719
2720- (void) textContainerChangedGeometry: (NSTextContainer *)aContainer
2721{
2722  int i;
2723  for (i = 0; i < num_textcontainers; i++)
2724    if (textcontainers[i].textContainer == aContainer)
2725      break;
2726  if (i == num_textcontainers)
2727    {
2728      NSLog(@"%s: does not own text container", __PRETTY_FUNCTION__);
2729      return;
2730    }
2731  [self _invalidateLayoutFromContainer: i];
2732  [self _didInvalidateLayout];
2733}
2734
2735- (unsigned int) firstUnlaidCharacterIndex
2736{
2737  return layout_char;
2738}
2739
2740- (unsigned int) firstUnlaidGlyphIndex
2741{
2742  return layout_glyph;
2743}
2744
2745-(void) getFirstUnlaidCharacterIndex: (unsigned int *)cindex
2746			  glyphIndex: (unsigned int *)gindex
2747{
2748  if (cindex)
2749    *cindex = [self firstUnlaidCharacterIndex];
2750  if (gindex)
2751    *gindex = [self firstUnlaidGlyphIndex];
2752}
2753
2754-(void) setExtraLineFragmentRect: (NSRect)linefrag
2755			usedRect: (NSRect)used
2756		   textContainer: (NSTextContainer *)tc
2757{
2758  extra_rect = linefrag;
2759  extra_used_rect = used;
2760  extra_textcontainer = tc;
2761}
2762
2763-(NSRect) extraLineFragmentRect
2764{
2765  return extra_rect;
2766}
2767
2768-(NSRect) extraLineFragmentUsedRect
2769{
2770  return extra_used_rect;
2771}
2772
2773-(NSTextContainer *) extraLineFragmentTextContainer
2774{
2775  return extra_textcontainer;
2776}
2777
2778
2779-(void) _softInvalidateUseLineFrags: (int)num
2780			  withShift: (NSSize)shift
2781		    inTextContainer: (NSTextContainer *)textContainer
2782{
2783  int i;
2784  textcontainer_t *tc;
2785  linefrag_t *lf;
2786  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
2787    if (tc->textContainer == textContainer)
2788      break;
2789  if (i == num_textcontainers)
2790    {
2791      NSLog(@"(%s): does not own text container", __PRETTY_FUNCTION__);
2792      return;
2793    }
2794
2795  if (shift.width || shift.height)
2796    {
2797      for (i = 0, lf = &tc->linefrags[tc->num_linefrags]; i < num; i++, lf++)
2798	{
2799	  lf->rect.origin.x += shift.width;
2800	  lf->rect.origin.y += shift.height;
2801	  lf->used_rect.origin.x += shift.width;
2802	  lf->used_rect.origin.y += shift.height;
2803	}
2804    }
2805  tc->num_soft -= num;
2806  tc->num_linefrags += num;
2807  lf = &tc->linefrags[tc->num_linefrags - 1];
2808  tc->length = lf->pos + lf->length - tc->pos;
2809
2810  layout_glyph = tc->pos + tc->length;
2811  /*
2812  We must have glyphs beyond all the soft-invalidated line frags,
2813  so comparing with glyphs->glyph_length is ok.
2814  */
2815  if (layout_glyph == glyphs->glyph_length)
2816    layout_char = glyphs->char_length;
2817  else
2818    layout_char = [self characterIndexForGlyphAtIndex: layout_glyph]; /* TODO? */
2819}
2820
2821-(NSRect) _softInvalidateLineFragRect: (int)index
2822			   firstGlyph: (unsigned int *)first_glyph
2823			    nextGlyph: (unsigned int *)next_glyph
2824		      inTextContainer: (NSTextContainer *)textContainer
2825{
2826  int i;
2827  textcontainer_t *tc;
2828  linefrag_t *lf;
2829  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
2830    if (tc->textContainer == textContainer)
2831      break;
2832  if (i == num_textcontainers)
2833    {
2834      NSLog(@"(%s): does not own text container", __PRETTY_FUNCTION__);
2835      return NSZeroRect;
2836    }
2837
2838  if (index >= tc->num_soft)
2839    return NSZeroRect;
2840
2841  lf = &tc->linefrags[tc->num_linefrags + index];
2842  *first_glyph = lf->pos;
2843  *next_glyph = lf->pos + lf->length;
2844  return lf->rect;
2845}
2846
2847-(unsigned int) _softInvalidateFirstGlyphInTextContainer: (NSTextContainer *)textContainer
2848{
2849  int i;
2850  textcontainer_t *tc;
2851  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
2852    if (tc->textContainer == textContainer)
2853      break;
2854  if (i == num_textcontainers)
2855    {
2856      NSLog(@"(%s): does not own text container", __PRETTY_FUNCTION__);
2857      return (unsigned int)-1;
2858    }
2859  if (tc->num_soft)
2860    return tc->linefrags[tc->num_linefrags].pos;
2861  else
2862    return (unsigned int)-1;
2863}
2864
2865-(unsigned int) _softInvalidateNumberOfLineFragsInTextContainer: (NSTextContainer *)textContainer
2866{
2867  int i;
2868  textcontainer_t *tc;
2869  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
2870    if (tc->textContainer == textContainer)
2871      break;
2872  if (i == num_textcontainers)
2873    {
2874      NSLog(@"(%s): does not own text container", __PRETTY_FUNCTION__);
2875      return (unsigned int)-1;
2876    }
2877  return tc->num_soft;
2878}
2879
2880@end
2881
2882
2883/***** The rest *****/
2884
2885@implementation GSLayoutManager
2886
2887- init
2888{
2889  if (!(self = [super init]))
2890    return nil;
2891
2892  [self setTypesetter: [GSTypesetter sharedSystemTypesetter]];
2893  [self setGlyphGenerator: [NSGlyphGenerator sharedGlyphGenerator]];
2894
2895  usesScreenFonts = YES;
2896  [self _initGlyphs];
2897
2898  return self;
2899}
2900
2901-(void) dealloc
2902{
2903  int i;
2904  textcontainer_t *tc;
2905
2906  free(rect_array);
2907  rect_array_size = 0;
2908  rect_array = NULL;
2909
2910  [self _freeLayout];
2911  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
2912    {
2913      [tc->textContainer setLayoutManager: nil];
2914      [tc->textContainer release];
2915    }
2916  free(textcontainers);
2917  textcontainers = NULL;
2918
2919  [self _freeGlyphs];
2920
2921  DESTROY(typesetter);
2922  DESTROY(_glyphGenerator);
2923
2924  [super dealloc];
2925}
2926
2927/**
2928 * Sets the text storage for the layout manager.
2929 * Use -replaceTextStorage: instead as a rule. - this method is really
2930 * more for internal use by the text system.
2931 * Invalidates the entire layout (should it??)
2932 */
2933/*
2934See [NSTextView -setTextContainer:] for more information about these calls.
2935*/
2936- (void) setTextStorage: (NSTextStorage *)aTextStorage
2937{
2938  int i;
2939  textcontainer_t *tc;
2940
2941  [self _invalidateEverything];
2942
2943  /*
2944   * Make a note of the new text storage object, but don't retain it.
2945   * The text storage is owning us - it retains us.
2946   */
2947  _textStorage = aTextStorage;
2948
2949  /*
2950  We send this message to all text containers so they can respond to the
2951  change (most importantly to let them tell their text views).
2952  */
2953  for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
2954    {
2955      [tc->textContainer setLayoutManager: self];
2956    }
2957  [self _didInvalidateLayout];
2958}
2959
2960/**
2961 * Returns the text storage for this layout manager.
2962 */
2963- (NSTextStorage *) textStorage
2964{
2965  return _textStorage;
2966}
2967
2968/**
2969 * Replaces the text storage with a new one.<br />
2970 * Takes care (since layout managers are owned by text storages)
2971 * not to get self deallocated.
2972 */
2973- (void) replaceTextStorage: (NSTextStorage *)newTextStorage
2974{
2975  NSArray		*layoutManagers = [_textStorage layoutManagers];
2976  NSEnumerator		*enumerator = [layoutManagers objectEnumerator];
2977  GSLayoutManager	*object;
2978
2979  /* Remove layout managers from old NSTextStorage object and add them to the
2980     new one.  NSTextStorage's addLayoutManager invokes GSLayoutManager's
2981     setTextStorage method automatically, and that includes self.  */
2982
2983  while ((object = (GSLayoutManager*)[enumerator nextObject]) != nil)
2984    {
2985      RETAIN(object);
2986      [_textStorage removeLayoutManager: object];
2987      [newTextStorage addLayoutManager: object];
2988      RELEASE(object);
2989    }
2990}
2991
2992- (NSGlyphGenerator *) glyphGenerator
2993{
2994  return _glyphGenerator;
2995}
2996- (void) setGlyphGenerator: (NSGlyphGenerator *)glyphGenerator
2997{
2998  ASSIGN(_glyphGenerator, glyphGenerator);
2999}
3000
3001- (id) delegate
3002{
3003  return _delegate;
3004}
3005- (void) setDelegate: (id)aDelegate
3006{
3007  _delegate = aDelegate;
3008}
3009
3010
3011-(GSTypesetter *) typesetter
3012{
3013  return typesetter;
3014}
3015-(void) setTypesetter: (GSTypesetter *)a_typesetter
3016{
3017  ASSIGN(typesetter, a_typesetter);
3018}
3019
3020- (BOOL) usesScreenFonts
3021{
3022  return usesScreenFonts;
3023}
3024
3025- (void) setUsesScreenFonts: (BOOL)flag
3026{
3027  flag = !!flag;
3028  if (flag == usesScreenFonts)
3029    return;
3030  usesScreenFonts = flag;
3031  [self _invalidateEverything];
3032  [self _didInvalidateLayout];
3033}
3034
3035- (NSFont *) substituteFontForFont: (NSFont *)originalFont
3036{
3037  NSFont *f;
3038  if (usesScreenFonts)
3039    {
3040      f = [originalFont screenFont];
3041      if (f)
3042	return f;
3043    }
3044  return originalFont;
3045}
3046
3047
3048- (void) setBackgroundLayoutEnabled: (BOOL)flag
3049{
3050  flag = !!flag;
3051  if (flag == backgroundLayoutEnabled)
3052    return;
3053  backgroundLayoutEnabled = flag;
3054  /* TODO */
3055}
3056- (BOOL) backgroundLayoutEnabled
3057{
3058  return backgroundLayoutEnabled;
3059}
3060
3061- (void) setShowsInvisibleCharacters: (BOOL)flag
3062{
3063  flag = !!flag;
3064  if (flag == showsInvisibleCharacters)
3065    return;
3066
3067  showsInvisibleCharacters = flag;
3068  [self _invalidateEverything];
3069  [self _didInvalidateLayout];
3070}
3071
3072- (BOOL) showsInvisibleCharacters
3073{
3074  return showsInvisibleCharacters;
3075}
3076
3077- (void) setShowsControlCharacters: (BOOL)flag
3078{
3079  flag = !!flag;
3080  if (flag == showsControlCharacters)
3081    return;
3082  showsControlCharacters = flag;
3083  [self _invalidateEverything];
3084  [self _didInvalidateLayout];
3085}
3086
3087- (BOOL) showsControlCharacters
3088{
3089  return showsControlCharacters;
3090}
3091
3092/*
3093Note that NSLayoutManager completely overrides this (to perform more
3094intelligent invalidation of layout using the constraints on layout it
3095has).
3096*/
3097- (void) textStorage: (NSTextStorage *)aTextStorage
3098              edited: (unsigned int)mask
3099               range: (NSRange)range
3100      changeInLength: (int)lengthChange
3101    invalidatedRange: (NSRange)invalidatedRange
3102{
3103  NSRange r;
3104
3105  if (!(mask & NSTextStorageEditedCharacters))
3106    lengthChange = 0;
3107
3108  [self invalidateGlyphsForCharacterRange: invalidatedRange
3109        changeInLength: lengthChange
3110        actualCharacterRange: &r];
3111
3112  /*
3113  See the comments above -invalidateLayoutForCharacterRange:isSoft:
3114  actualCharacterRange: for information on why we invalidate everything
3115  here.
3116  */
3117  [self _invalidateLayoutFromContainer: 0];
3118  [self _didInvalidateLayout];
3119}
3120
3121-(unsigned int) _findSafeBreakMovingBackwardFrom: (unsigned int)ch
3122{
3123  NSString *str = [_textStorage string];
3124
3125  // FIXME: Better check for ligature
3126  while (ch > 0 && [str characterAtIndex: ch-1] == 'f')
3127    ch--;
3128  return ch;
3129}
3130
3131-(unsigned int) _findSafeBreakMovingForwardFrom: (unsigned int)ch
3132{
3133  unsigned int len = [_textStorage length];
3134  NSString *str = [_textStorage string];
3135
3136  // FIXME: Better check for ligature
3137  while (ch < len && [str characterAtIndex: ch] == 'f')
3138    ch++;
3139  if (ch < len && ch > 0 && [str characterAtIndex: ch-1] == 'f')
3140    ch++;
3141
3142  return ch;
3143}
3144
3145/*
3146 * NSGlyphStorage protocol
3147 */
3148- (NSAttributedString*) attributedString
3149{
3150  return _textStorage;
3151}
3152
3153/**
3154 * GNUstep extension
3155 */
3156- (void) insertGlyphs: (const NSGlyph*)glyph_list
3157     withAdvancements: (const NSSize*)advancements
3158               length: (NSUInteger)length
3159forStartingGlyphAtIndex: (NSUInteger)glyph
3160       characterIndex: (NSUInteger)index
3161{
3162  glyph_run_t *run;
3163  int i;
3164  glyph_t *g;
3165  int len;
3166  unsigned int gpos = 0;
3167  unsigned int cpos = 0;
3168
3169  //NSLog(@"Insert %d glyphs at %d for index %d", length, glyph, index);
3170
3171  run = [self run_for_character_index: index : &gpos : &cpos];
3172  if (!run)
3173    {
3174      [NSException raise: NSRangeException
3175                   format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
3176      return;
3177    }
3178
3179  len = glyph - gpos + length;
3180  if (len < 0)
3181    {
3182      NSLog(@"Insert %d glyphs at %d for index %d", (int)length, (int)glyph, (int)index);
3183      NSLog(@"Found gpos %d cpos %d len %d", gpos, cpos, len);
3184      [NSException raise: NSRangeException
3185                   format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
3186      return;
3187    }
3188
3189  if (!run->glyphs)
3190    {
3191      run->glyphs = malloc(sizeof(glyph_t) * len);
3192      memset(run->glyphs, 0, sizeof(glyph_t) * len);
3193    }
3194  else if (run->head.glyph_length < len)
3195    {
3196      run->glyphs = realloc(run->glyphs, sizeof(glyph_t) * len);
3197      memset(&run->glyphs[glyph - gpos], 0, sizeof(glyph_t) * length);
3198    }
3199  run->head.glyph_length = len;
3200
3201  // Add the glyphs to the run
3202  g = run->glyphs + (glyph - gpos);
3203  for (i = 0; i < length; i++)
3204    {
3205      // We expect to get a nominal glyph run
3206      g->char_offset = i + index - cpos;
3207      g->g = glyph_list[i];
3208      g->advancement = advancements[i];
3209      g++;
3210    }
3211}
3212
3213- (void) insertGlyphs: (const NSGlyph*)glyph_list
3214               length: (NSUInteger)length
3215forStartingGlyphAtIndex: (NSUInteger)glyph
3216       characterIndex: (NSUInteger)index
3217{
3218  glyph_run_t *run;
3219  int i;
3220  unsigned int gpos, cpos;
3221  NSSize advances[length];
3222
3223  run = [self run_for_character_index: index : &gpos : &cpos];
3224  if (!run)
3225    {
3226      [NSException raise: NSRangeException
3227                   format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
3228      return;
3229    }
3230
3231  for (i=0; i<length; i++)
3232    {
3233      if ((glyph_list[i] != NSControlGlyph) && (glyph_list[i] != GSAttachmentGlyph))
3234        {
3235          advances[i] = [run->font advancementForGlyph: glyph_list[i]];
3236        }
3237      else
3238        {
3239          advances[i] = NSZeroSize;
3240        }
3241    }
3242
3243  [self insertGlyphs: glyph_list
3244    withAdvancements: advances
3245	      length: length
3246	forStartingGlyphAtIndex: glyph
3247      characterIndex: index];
3248}
3249
3250- (NSUInteger) layoutOptions
3251{
3252  NSUInteger options = 0;
3253
3254  if (showsInvisibleCharacters)
3255    options |= NSShowInvisibleGlyphs;
3256  if (showsInvisibleCharacters)
3257    options |= NSShowControlGlyphs;
3258
3259  return options;
3260}
3261
3262- (void) setIntAttribute: (NSInteger)attributeTag
3263                   value: (NSInteger)anInt
3264         forGlyphAtIndex: (NSUInteger)glyphIndex
3265{
3266  glyph_run_t *run;
3267  glyph_t *g;
3268  unsigned int pos;
3269
3270  run = run_for_glyph_index(glyphIndex, glyphs, &pos, NULL);
3271  if (run && run->glyphs && (run->head.glyph_length < glyphIndex - pos))
3272    {
3273      g = &run->glyphs[glyphIndex - pos];
3274
3275      if (attributeTag == NSGlyphAttributeInscribe)
3276        g->inscription = anInt;
3277      else if (attributeTag == NSGlyphAttributeSoft)
3278        g->soft = anInt;
3279      else if (attributeTag == NSGlyphAttributeElastic)
3280        g->elasitc = anInt;
3281      else if (attributeTag == NSGlyphAttributeBidiLevel)
3282        g->bidilevel = anInt;
3283    }
3284}
3285
3286- (NSDictionary *) typingAttributes
3287{
3288  return [NSTextView defaultTypingAttributes];
3289}
3290
3291
3292/*
3293 * NSCoding protocol
3294 */
3295- (void) encodeWithCoder: (NSCoder*)aCoder
3296{
3297  // FIXME
3298}
3299
3300- (id) initWithCoder: (NSCoder*)aDecoder
3301{
3302  // FIXME
3303  return self;
3304}
3305
3306@end
3307