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