2003-01-26 19:21:40 +00:00
|
|
|
/*
|
|
|
|
GSLayoutManager.m
|
|
|
|
|
2011-02-28 14:04:43 +00:00
|
|
|
Copyright (C) 2002-2011 Free Software Foundation, Inc.
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
Author: Alexander Malmberg <alexander@malmberg.org>
|
2003-02-18 23:34:51 +00:00
|
|
|
Date: November 2002 - February 2003
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
This file is part of the GNUstep GUI Library.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-10-29 21:16:17 +00:00
|
|
|
modify it under the terms of the GNU Lesser General Public
|
2003-01-26 19:21:40 +00:00
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-10 04:01:49 +00:00
|
|
|
version 2 of the License, or (at your option) any later version.
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2007-10-29 21:16:17 +00:00
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2007-10-29 21:16:17 +00:00
|
|
|
You should have received a copy of the GNU Lesser General Public
|
2003-01-26 19:21:40 +00:00
|
|
|
License along with this library; see the file COPYING.LIB.
|
2007-10-29 21:16:17 +00:00
|
|
|
If not, see <http://www.gnu.org/licenses/> or write to the
|
|
|
|
Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
2003-01-26 19:21:40 +00:00
|
|
|
*/
|
|
|
|
|
2010-05-24 10:48:14 +00:00
|
|
|
#import <Foundation/NSCharacterSet.h>
|
|
|
|
#import <Foundation/NSDebug.h>
|
|
|
|
#import <Foundation/NSEnumerator.h>
|
|
|
|
#import <Foundation/NSException.h>
|
|
|
|
#import <Foundation/NSValue.h>
|
2008-04-04 22:01:44 +00:00
|
|
|
|
2010-05-24 10:48:14 +00:00
|
|
|
#import "AppKit/NSAttributedString.h"
|
|
|
|
#import "AppKit/NSTextStorage.h"
|
|
|
|
#import "AppKit/NSTextContainer.h"
|
2019-12-10 17:23:04 +00:00
|
|
|
#import "AppKit/NSTextView.h"
|
2003-01-31 22:25:12 +00:00
|
|
|
|
|
|
|
/* just for NSAttachmentCharacter */
|
2010-05-24 10:48:14 +00:00
|
|
|
#import "AppKit/NSTextAttachment.h"
|
2003-06-13 15:01:12 +00:00
|
|
|
|
2010-05-24 10:48:14 +00:00
|
|
|
#import "GNUstepGUI/GSFontInfo.h"
|
|
|
|
#import "GNUstepGUI/GSTypesetter.h"
|
|
|
|
#import "GNUstepGUI/GSLayoutManager_internal.h"
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2003-02-05 15:44:07 +00:00
|
|
|
/* TODO: is using rand() here ok? */
|
2012-12-26 19:19:50 +00:00
|
|
|
static inline int random_level(void)
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < SKIP_LIST_DEPTH - 2; i++)
|
2003-02-05 15:44:07 +00:00
|
|
|
if ((rand() % SKIP_LIST_LEVEL_PROBABILITY) != 0)
|
2003-01-26 19:21:40 +00:00
|
|
|
break;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
/*
|
|
|
|
* Insert a new run with level into the context of the skip list.
|
|
|
|
* Return the new run.
|
|
|
|
*/
|
|
|
|
static glyph_run_t *run_insert(glyph_run_head_t **context, int level)
|
|
|
|
{
|
|
|
|
glyph_run_head_t *h;
|
|
|
|
glyph_run_t *r;
|
|
|
|
int i, size;
|
|
|
|
|
|
|
|
size = sizeof(glyph_run_head_t) * level + sizeof(glyph_run_t);
|
2011-02-28 14:04:43 +00:00
|
|
|
h = malloc(size);
|
2008-05-13 19:40:20 +00:00
|
|
|
memset(h, 0, size);
|
|
|
|
|
|
|
|
for (i = level; i >= 0; i--, h++)
|
|
|
|
{
|
|
|
|
h->next = context[i]->next;
|
|
|
|
context[i]->next = h;
|
|
|
|
}
|
|
|
|
h--;
|
|
|
|
|
|
|
|
r = (glyph_run_t *)h;
|
|
|
|
r->level = level;
|
|
|
|
r->prev = context[0];
|
|
|
|
if (h->next)
|
|
|
|
((glyph_run_t *)h->next)->prev = h;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2012-12-26 19:19:50 +00:00
|
|
|
/*
|
|
|
|
* Free the glphys of a run.
|
|
|
|
*/
|
|
|
|
static inline void run_free_glyphs(glyph_run_t *r)
|
|
|
|
{
|
|
|
|
if (r->glyphs)
|
|
|
|
{
|
|
|
|
r->head.complete = 0;
|
|
|
|
r->head.glyph_length = 0;
|
|
|
|
free(r->glyphs);
|
|
|
|
r->glyphs = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
/*
|
|
|
|
* Remove the run r from the context of the skip list and free it.
|
|
|
|
* The context does not point at r, but to the run immediately before r.
|
|
|
|
* context[0]->next == r
|
|
|
|
*/
|
2012-12-26 19:19:50 +00:00
|
|
|
static inline void run_remove(glyph_run_head_t **context, glyph_run_t *r)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
|
|
|
glyph_run_head_t *h;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// Free the glyphs
|
2012-12-26 19:19:50 +00:00
|
|
|
run_free_glyphs(r);
|
2008-05-13 19:40:20 +00:00
|
|
|
|
|
|
|
h = &r->head;
|
|
|
|
if (h->next)
|
|
|
|
((glyph_run_t *)h->next)->prev = r->prev;
|
|
|
|
|
|
|
|
for (i = 0; i <= r->level; i++)
|
|
|
|
context[i]->next = context[i]->next->next;
|
|
|
|
|
|
|
|
h -= r->level;
|
2011-02-28 14:24:57 +00:00
|
|
|
free(h);
|
2008-05-13 19:40:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Recalculates char_length, glyph_length, and complete for a
|
|
|
|
glyph_run_head_t. All "children" of this head must have valid values. */
|
|
|
|
static void run_fix_head(glyph_run_head_t *h)
|
|
|
|
{
|
|
|
|
glyph_run_head_t *h2, *next;
|
|
|
|
|
|
|
|
next = h->next;
|
|
|
|
if (next)
|
|
|
|
next++;
|
|
|
|
h2 = h + 1;
|
|
|
|
|
|
|
|
h->complete = 1;
|
|
|
|
h->glyph_length = 0;
|
|
|
|
h->char_length = 0;
|
|
|
|
|
|
|
|
// Loop over all heads below this one
|
|
|
|
while (h2 != next)
|
|
|
|
{
|
|
|
|
h->char_length += h2->char_length;
|
|
|
|
if (!h2->complete)
|
|
|
|
h->complete = 0;
|
|
|
|
else if (h->complete)
|
|
|
|
h->glyph_length += h2->glyph_length;
|
|
|
|
h2 = h2->next;
|
|
|
|
}
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2003-04-06 13:12:34 +00:00
|
|
|
/*
|
|
|
|
Private method used internally by GSLayoutManager for sanity checking.
|
|
|
|
*/
|
2006-11-06 10:19:20 +00:00
|
|
|
@interface NSTextStorage (GSLayoutManagerSanityChecking)
|
2003-04-06 13:12:34 +00:00
|
|
|
-(unsigned int) _editCount;
|
|
|
|
@end
|
2006-11-06 10:19:20 +00:00
|
|
|
@implementation NSTextStorage (GSLayoutManagerSanityChecking)
|
2003-04-06 13:12:34 +00:00
|
|
|
-(unsigned int) _editCount;
|
|
|
|
{
|
|
|
|
return _editCount;
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
@interface GSLayoutManager (backend)
|
|
|
|
-(unsigned int) _findSafeBreakMovingBackwardFrom: (unsigned int)ch;
|
|
|
|
-(unsigned int) _findSafeBreakMovingForwardFrom: (unsigned int)ch;
|
|
|
|
-(void) _generateGlyphsForRun: (glyph_run_t *)run at: (unsigned int)cpos;
|
|
|
|
@end
|
2003-04-06 13:12:34 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
/***** Glyph handling *****/
|
|
|
|
|
2006-11-06 10:19:20 +00:00
|
|
|
@implementation GSLayoutManager (GlyphsHelpers)
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
-(void) _run_cache_attributes: (glyph_run_t *)r : (NSDictionary *)attributes
|
|
|
|
{
|
|
|
|
/* set up attributes for this run */
|
|
|
|
NSNumber *n;
|
2012-12-26 19:19:50 +00:00
|
|
|
NSFont *font;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
r->explicit_kern = !![attributes objectForKey: NSKernAttributeName];
|
|
|
|
|
|
|
|
n = [attributes objectForKey: NSLigatureAttributeName];
|
|
|
|
if (n)
|
|
|
|
r->ligature = [n intValue];
|
|
|
|
else
|
|
|
|
r->ligature = 1;
|
|
|
|
|
2012-12-26 19:19:50 +00:00
|
|
|
font = [typesetter fontForCharactersWithAttributes: attributes];
|
2003-01-26 19:21:40 +00:00
|
|
|
/* TODO: it might be useful to change this slightly:
|
|
|
|
Returning a nil font from -fontForCharactersWithAttributes: causes those
|
|
|
|
characters to not be displayed (ie. no glyphs are generated).
|
|
|
|
|
|
|
|
How would glyph<->char mapping be handled? Map the entire run to one
|
|
|
|
NSNullGlyph?
|
|
|
|
*/
|
2012-12-26 19:19:50 +00:00
|
|
|
if (font == nil)
|
|
|
|
font = [NSFont userFontOfSize: 0];
|
|
|
|
font = [self substituteFontForFont: font];
|
|
|
|
ASSIGN(r->font, font);
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
2005-11-16 11:34:25 +00:00
|
|
|
-(void) _run_free_attributes: (glyph_run_t *)r
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
[r->font release];
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void) _run_copy_attributes: (glyph_run_t *)dst : (const glyph_run_t *)src
|
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
dst->font = [src->font copy];
|
2003-01-26 19:21:40 +00:00
|
|
|
dst->ligature = src->ligature;
|
|
|
|
dst->explicit_kern = src->explicit_kern;
|
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
/*
|
|
|
|
* Free up the skip list and all the glyph arrays
|
|
|
|
*/
|
|
|
|
- (void) _freeGlyphs
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
glyph_run_t *cur, *next;
|
|
|
|
glyph_run_head_t *h;
|
|
|
|
|
|
|
|
if (!glyphs)
|
|
|
|
return;
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
cached_run = NULL;
|
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
h = glyphs;
|
|
|
|
h += SKIP_LIST_DEPTH - 1;
|
|
|
|
|
|
|
|
for (cur = (glyph_run_t *)h->next; cur; cur = next)
|
|
|
|
{
|
|
|
|
next = (glyph_run_t *)cur->head.next;
|
|
|
|
if (cur->glyphs)
|
2011-02-28 14:24:57 +00:00
|
|
|
free(cur->glyphs);
|
2003-01-26 19:21:40 +00:00
|
|
|
[self _run_free_attributes: cur];
|
2008-05-13 19:40:20 +00:00
|
|
|
// Find the start of the allocated memory
|
2003-01-26 19:21:40 +00:00
|
|
|
h = &cur->head;
|
|
|
|
h -= cur->level;
|
2011-02-28 14:24:57 +00:00
|
|
|
free(h);
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
// Free the head element
|
2011-02-28 14:24:57 +00:00
|
|
|
free(glyphs);
|
2003-01-26 19:21:40 +00:00
|
|
|
glyphs = NULL;
|
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
/*
|
|
|
|
* Initialize the glyph skip list
|
|
|
|
*/
|
|
|
|
- (void) _initGlyphs
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
int i, size;
|
2008-05-13 19:40:20 +00:00
|
|
|
glyph_run_t *r;
|
2003-01-26 19:21:40 +00:00
|
|
|
glyph_run_head_t *h;
|
|
|
|
|
|
|
|
size = sizeof(glyph_run_head_t) * (SKIP_LIST_DEPTH - 1) + sizeof(glyph_run_t);
|
2011-02-28 14:04:43 +00:00
|
|
|
glyphs = malloc(size);
|
2003-01-26 19:21:40 +00:00
|
|
|
memset(glyphs, 0, size);
|
2008-05-13 19:40:20 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
for (h = glyphs, i = SKIP_LIST_DEPTH; i; i--, h++)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
|
|
|
h->complete = 1;
|
|
|
|
}
|
|
|
|
h--;
|
|
|
|
|
|
|
|
r = (glyph_run_t *)h;
|
|
|
|
r->level = SKIP_LIST_DEPTH - 1;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
- (void) _glyphDumpRuns
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
printf("--- dumping runs\n");
|
|
|
|
{
|
|
|
|
glyph_run_t *h;
|
2003-04-10 00:08:26 +00:00
|
|
|
unsigned int cpos = 0;
|
2008-05-13 19:40:20 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
h = (glyph_run_t *)(glyphs + SKIP_LIST_DEPTH - 1)->next;
|
|
|
|
for (; h; h = (glyph_run_t *)h->head.next)
|
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
printf("%8p %i chars, %i glyphs, %i complete, prev %8p next %8p\n",
|
|
|
|
h, h->head.char_length, h->head.glyph_length, h->head.complete,
|
|
|
|
h->prev, h->head.next);
|
|
|
|
printf(" level %i, continued %i\n", h->level, h->continued);
|
|
|
|
if (h->head.complete)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
printf("glyphs:\n");
|
|
|
|
for (i = 0;i < h->head.glyph_length;i++)
|
|
|
|
printf("%5i %04x u%04x ",
|
|
|
|
h->glyphs[i].char_offset,h->glyphs[i].g,
|
|
|
|
[[_textStorage string] characterAtIndex: cpos+h->glyphs[i].char_offset]);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
cpos += h->head.char_length;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
printf("- structure\n");
|
|
|
|
{
|
|
|
|
glyph_run_head_t *h, *g;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
printf(" head: ");
|
|
|
|
for (i = 0, h = glyphs + SKIP_LIST_DEPTH - 1; i < SKIP_LIST_DEPTH; i++, h--)
|
2006-07-04 21:31:49 +00:00
|
|
|
printf("%8p %i %3i %3i|", h->next, h->complete, h->char_length, h->glyph_length);
|
2003-01-26 19:21:40 +00:00
|
|
|
printf("\n");
|
|
|
|
h = (glyphs + SKIP_LIST_DEPTH - 1)->next;
|
|
|
|
for (; h; h = h->next)
|
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
printf("%8p: ", h);
|
|
|
|
for (g = h, i = ((glyph_run_t *)h)->level; i >= 0; i--, g--)
|
|
|
|
printf("%8p %i %3i %3i|", g->next, g->complete, g->char_length, g->glyph_length);
|
|
|
|
printf("\n");
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
printf("--- done\n");
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
- (void) _sanityChecks
|
2003-02-17 20:30:26 +00:00
|
|
|
{
|
|
|
|
glyph_run_t *g;
|
|
|
|
|
|
|
|
g = (glyph_run_t *)&glyphs[SKIP_LIST_DEPTH - 1];
|
|
|
|
while (g->head.next)
|
|
|
|
{
|
|
|
|
NSAssert((glyph_run_t *)((glyph_run_t *)g->head.next)->prev == g,
|
2008-05-13 19:40:20 +00:00
|
|
|
@"glyph structure corrupted: g->next->prev!=g");
|
2003-02-17 20:30:26 +00:00
|
|
|
g = (glyph_run_t *)g->head.next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
/*
|
|
|
|
* Returns the glyph run that contains glyphIndex, if there is any.
|
|
|
|
* glyph_pos and char_pos, when supplied, will contain the starting
|
|
|
|
* glyph/character index for this run.
|
|
|
|
*/
|
|
|
|
- (glyph_run_t *)run_for_glyph_index: (unsigned int)glyphIndex
|
|
|
|
: (unsigned int *)glyph_pos
|
|
|
|
: (unsigned int *)char_pos
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
int level;
|
|
|
|
glyph_run_head_t *h;
|
|
|
|
int pos, cpos;
|
|
|
|
|
|
|
|
if (glyphs->glyph_length <= glyphIndex)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
|
|
|
NSLog(@"run_for_glyph_index failed for %d", glyphIndex);
|
|
|
|
return NULL;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2003-02-17 01:19:34 +00:00
|
|
|
if (cached_run)
|
|
|
|
{
|
|
|
|
if (glyphIndex >= cached_pos &&
|
2008-05-13 19:40:20 +00:00
|
|
|
glyphIndex < cached_pos + cached_run->head.glyph_length)
|
|
|
|
{
|
|
|
|
if (glyph_pos)
|
|
|
|
*glyph_pos = cached_pos;
|
2012-12-26 19:19:50 +00:00
|
|
|
if (char_pos)
|
2008-05-13 19:40:20 +00:00
|
|
|
*char_pos = cached_cpos;
|
2012-12-26 19:19:50 +00:00
|
|
|
return cached_run;
|
2008-05-13 19:40:20 +00:00
|
|
|
}
|
2003-02-17 01:19:34 +00:00
|
|
|
}
|
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
pos = cpos = 0;
|
|
|
|
level = SKIP_LIST_DEPTH;
|
|
|
|
h = glyphs;
|
|
|
|
while (1)
|
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
// Find a head, where the glyphs are already created.
|
2003-01-26 19:21:40 +00:00
|
|
|
if (!h->complete)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
|
|
|
h++;
|
|
|
|
level--;
|
|
|
|
if (!level)
|
|
|
|
{
|
|
|
|
NSLog(@"run_for_glyph_index failed for %d", glyphIndex);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Find the head containing the index.
|
|
|
|
if (glyphIndex >= pos + h->glyph_length)
|
|
|
|
{
|
|
|
|
pos += h->glyph_length;
|
|
|
|
cpos += h->char_length;
|
|
|
|
h = h->next;
|
|
|
|
if (!h)
|
|
|
|
{
|
|
|
|
NSLog(@"run_for_glyph_index failed for %d", glyphIndex);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Go down one level
|
|
|
|
if (level > 1)
|
|
|
|
{
|
|
|
|
h++;
|
|
|
|
level--;
|
|
|
|
continue;
|
|
|
|
}
|
2003-02-17 01:19:34 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
// Level 1
|
|
|
|
if (glyph_pos)
|
|
|
|
*glyph_pos = pos;
|
|
|
|
if (char_pos)
|
|
|
|
*char_pos = cpos;
|
2003-02-17 01:19:34 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
cached_run = (glyph_run_t *)h;
|
|
|
|
cached_pos = pos;
|
|
|
|
cached_cpos = cpos;
|
|
|
|
|
|
|
|
return (glyph_run_t *)h;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
/*
|
|
|
|
* Returns the glyph run that contains charIndex, if there is any.
|
|
|
|
* glyph_pos and char_pos, when supplied, will contain the starting
|
|
|
|
* glyph/character index for this run.
|
|
|
|
*/
|
|
|
|
- (glyph_run_t *)run_for_character_index: (unsigned int)charIndex
|
|
|
|
: (unsigned int *)glyph_pos
|
|
|
|
: (unsigned int *)char_pos
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
int level;
|
|
|
|
glyph_run_head_t *h;
|
|
|
|
int pos, cpos;
|
2008-05-13 19:40:20 +00:00
|
|
|
BOOL cache = YES;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
if (glyphs->char_length <= charIndex)
|
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
NSLog(@"run_for_character_index failed for %d", charIndex);
|
|
|
|
return NULL;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
if (cached_run)
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
if (charIndex >= cached_cpos &&
|
|
|
|
charIndex < cached_cpos + cached_run->head.char_length)
|
|
|
|
{
|
|
|
|
if (glyph_pos)
|
|
|
|
*glyph_pos = cached_pos;
|
|
|
|
if (char_pos)
|
|
|
|
*char_pos = cached_cpos;
|
|
|
|
return cached_run;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
pos = cpos = 0;
|
|
|
|
h = glyphs;
|
|
|
|
for (level = SKIP_LIST_DEPTH - 1; level >= 0; level--)
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
// Find the head containing the index.
|
|
|
|
while (charIndex >= cpos + h->char_length)
|
|
|
|
{
|
|
|
|
// Ignore pos at the end
|
|
|
|
if (!h->complete)
|
|
|
|
cache = NO;
|
|
|
|
pos += h->glyph_length;
|
|
|
|
cpos += h->char_length;
|
|
|
|
h = h->next;
|
|
|
|
if (!h)
|
|
|
|
{
|
|
|
|
NSLog(@"run_for_character_index failed for %d", charIndex);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Go down one level
|
2003-01-26 19:21:40 +00:00
|
|
|
h++;
|
|
|
|
}
|
|
|
|
h--;
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
if (glyph_pos)
|
|
|
|
*glyph_pos = pos;
|
|
|
|
if (char_pos)
|
|
|
|
*char_pos = cpos;
|
|
|
|
|
|
|
|
if (cache)
|
|
|
|
{
|
|
|
|
cached_run = (glyph_run_t *)h;
|
|
|
|
cached_pos = pos;
|
|
|
|
cached_cpos = cpos;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
return (glyph_run_t *)h;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
/*
|
|
|
|
* Generate the glyph runs, but not the actual glyphs, up to the
|
|
|
|
* character index last.
|
|
|
|
* Build up empty skip list entries to later hold the glyphs.
|
|
|
|
* Only appends to the end of the skip list.
|
|
|
|
* Only called after setting up a complete new layout.
|
|
|
|
*/
|
2003-01-26 19:21:40 +00:00
|
|
|
-(void) _generateRunsToCharacter: (unsigned int)last
|
|
|
|
{
|
|
|
|
glyph_run_head_t *context[SKIP_LIST_DEPTH];
|
|
|
|
glyph_run_head_t *h;
|
2003-06-26 23:25:34 +00:00
|
|
|
unsigned int pos;
|
|
|
|
unsigned int length;
|
2003-01-26 19:21:40 +00:00
|
|
|
int level;
|
|
|
|
|
|
|
|
length = [_textStorage length];
|
|
|
|
if (last >= length)
|
|
|
|
last = length - 1;
|
|
|
|
|
|
|
|
h = glyphs;
|
|
|
|
pos = 0;
|
|
|
|
if (h->char_length > last)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* We haven't created any run for that character. Find the last run. */
|
|
|
|
for (level = SKIP_LIST_DEPTH; level; level--)
|
|
|
|
{
|
|
|
|
while (h->next) pos += h->char_length, h = h->next;
|
|
|
|
context[level - 1] = h;
|
|
|
|
h++;
|
|
|
|
}
|
|
|
|
h--;
|
|
|
|
pos += h->char_length;
|
|
|
|
|
|
|
|
/* Create runs and add them to the skip list until we're past our
|
|
|
|
target. */
|
|
|
|
while (pos <= last)
|
|
|
|
{
|
2003-02-25 23:55:03 +00:00
|
|
|
NSRange maxRange;
|
2003-01-26 19:21:40 +00:00
|
|
|
NSRange curRange;
|
|
|
|
NSDictionary *attributes;
|
|
|
|
glyph_run_t *new;
|
|
|
|
int new_level;
|
|
|
|
int i;
|
|
|
|
|
2003-02-25 23:55:03 +00:00
|
|
|
maxRange = NSMakeRange(pos, length - pos);
|
|
|
|
if (pos > 0)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
|
|
|
maxRange.location--;
|
|
|
|
maxRange.length++;
|
|
|
|
}
|
2003-02-25 23:55:03 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
attributes = [_textStorage attributesAtIndex: pos
|
2008-05-13 19:40:20 +00:00
|
|
|
longestEffectiveRange: &curRange
|
|
|
|
inRange: maxRange];
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2003-02-25 23:55:03 +00:00
|
|
|
/*
|
|
|
|
Optimize run structure by merging with the previous run under
|
|
|
|
some circumstances. See the comments in
|
|
|
|
-invalidateGlyphsForCharacterRange:changeInLength:actualCharacterRange:
|
|
|
|
for more information.
|
|
|
|
*/
|
|
|
|
if (curRange.location < pos && context[0]->char_length &&
|
2008-05-13 19:40:20 +00:00
|
|
|
// FIXME: Why 16 and not MAX_RUN_LENGTH
|
|
|
|
context[0]->char_length < 16)
|
|
|
|
{
|
|
|
|
curRange.length -= pos - curRange.location;
|
|
|
|
curRange.location = pos;
|
|
|
|
new = (glyph_run_t *)context[0];
|
|
|
|
// FIXME: We could try to reuse the glyphs
|
|
|
|
run_free_glyphs(new);
|
|
|
|
new->head.char_length += curRange.length;
|
|
|
|
for (i = 1; i < SKIP_LIST_DEPTH; i++)
|
|
|
|
{
|
|
|
|
run_fix_head(context[i]);
|
|
|
|
}
|
|
|
|
pos = NSMaxRange(curRange);
|
|
|
|
continue;
|
|
|
|
}
|
2003-02-25 23:55:03 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
if (curRange.location < pos)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
|
|
|
curRange.length -= pos - curRange.location;
|
|
|
|
curRange.location = pos;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2003-02-18 00:35:13 +00:00
|
|
|
/*
|
|
|
|
TODO: this shouldn't really be necessary if all searches inside runs
|
|
|
|
were binary. but for now, it helps performance, and it keeps things
|
|
|
|
more balanced when there are long runs of text.
|
|
|
|
*/
|
|
|
|
if (curRange.length > MAX_RUN_LENGTH)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
|
|
|
unsigned int safe_break = curRange.location + MAX_RUN_LENGTH;
|
|
|
|
safe_break = [self _findSafeBreakMovingForwardFrom: safe_break];
|
|
|
|
if (safe_break < NSMaxRange(curRange))
|
|
|
|
curRange.length = safe_break - curRange.location;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
/* Since we'll be creating these in order, we can be smart about
|
2008-05-13 19:40:20 +00:00
|
|
|
picking new levels. */
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
FIXME: Not sure whether using an ivar here as the counter is a great idea.
|
|
|
|
When the same range is edited over and over again this could lead to a strange structure.
|
|
|
|
It works fine when adding a great chunk of text at the end.
|
|
|
|
*/
|
|
|
|
glyph_num_end_runs++;
|
|
|
|
for (i=0; i < SKIP_LIST_DEPTH - 2; i++)
|
|
|
|
if (glyph_num_end_runs & (1 << i))
|
|
|
|
break;
|
|
|
|
new_level = i;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
new = run_insert(context, new_level);
|
2003-01-26 19:21:40 +00:00
|
|
|
[self _run_cache_attributes: new : attributes];
|
|
|
|
|
|
|
|
h = &new->head;
|
|
|
|
for (i = 0; i <= new_level; i++, h--)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
|
|
|
h->char_length = curRange.length;
|
|
|
|
context[i] = h;
|
|
|
|
}
|
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
for (; i < SKIP_LIST_DEPTH; i++)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
|
|
|
context[i]->char_length += curRange.length;
|
|
|
|
context[i]->complete = 0;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
pos += curRange.length;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
2003-04-03 18:31:25 +00:00
|
|
|
[self _sanityChecks];
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
2003-04-10 00:08:26 +00:00
|
|
|
/*
|
2008-05-13 19:40:20 +00:00
|
|
|
Recursive glyph generation helper method method.
|
2003-04-10 00:08:26 +00:00
|
|
|
Returns number of valid glyphs under h after generating up to last (sortof,
|
|
|
|
not completely accurate).
|
2008-05-13 19:40:20 +00:00
|
|
|
Fills in all glyph holes up to last. only looking at levels below level
|
2003-04-10 00:08:26 +00:00
|
|
|
*/
|
2008-05-13 19:40:20 +00:00
|
|
|
-(unsigned int) _generateGlyphs_char_r: (unsigned int)last : (unsigned int)cpos
|
|
|
|
: (unsigned int)gpos : (int)level
|
|
|
|
: (glyph_run_head_t *)h : (glyph_run_head_t *)stop
|
|
|
|
: (BOOL *)all_complete
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2003-04-10 00:08:26 +00:00
|
|
|
int total = 0, sub_total;
|
|
|
|
BOOL c;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
*all_complete = YES;
|
2008-05-13 19:40:20 +00:00
|
|
|
while (h != stop && (cpos <= last || *all_complete))
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
if (!h->complete)
|
|
|
|
{
|
|
|
|
if (cpos > last)
|
|
|
|
{
|
|
|
|
*all_complete = NO;
|
|
|
|
break;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
if (level)
|
|
|
|
{
|
|
|
|
glyph_run_head_t *stopn;
|
|
|
|
|
|
|
|
if (h->next)
|
|
|
|
stopn = h->next + 1;
|
|
|
|
else
|
|
|
|
stopn = NULL;
|
|
|
|
|
|
|
|
sub_total = [self _generateGlyphs_char_r: last : cpos : gpos + total
|
|
|
|
: level - 1 : h + 1: stopn: &c];
|
|
|
|
if (!c)
|
|
|
|
*all_complete = NO;
|
|
|
|
else
|
|
|
|
h->complete = 1;
|
|
|
|
h->glyph_length = sub_total;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-05-15 01:56:58 +00:00
|
|
|
NSUInteger cindex = cpos;
|
|
|
|
NSUInteger gindex = gpos + total;
|
2008-05-13 19:40:20 +00:00
|
|
|
|
|
|
|
// Cache the current run
|
|
|
|
cached_run = (glyph_run_t *)h;
|
|
|
|
cached_pos = gindex;
|
|
|
|
cached_cpos = cindex;
|
|
|
|
|
|
|
|
// Generate the glyphs for the run
|
|
|
|
[_glyphGenerator generateGlyphsForGlyphStorage: self
|
|
|
|
desiredNumberOfCharacters: h->char_length
|
|
|
|
glyphIndex: &gindex
|
|
|
|
characterIndex: &cindex];
|
|
|
|
h->complete = 1;
|
|
|
|
}
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
total += h->glyph_length;
|
|
|
|
cpos += h->char_length;
|
2003-01-26 19:21:40 +00:00
|
|
|
h = h->next;
|
|
|
|
}
|
2008-05-13 19:40:20 +00:00
|
|
|
|
2003-04-10 00:08:26 +00:00
|
|
|
return total;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
/*
|
|
|
|
* Generate all glyphs up to the character index last.
|
|
|
|
*/
|
2003-01-26 19:21:40 +00:00
|
|
|
-(void) _generateGlyphsUpToCharacter: (unsigned int)last
|
|
|
|
{
|
2003-06-26 23:25:34 +00:00
|
|
|
unsigned int length;
|
2003-01-26 19:21:40 +00:00
|
|
|
BOOL dummy;
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
if (!_textStorage)
|
|
|
|
return;
|
|
|
|
|
2003-04-06 13:12:34 +00:00
|
|
|
/*
|
|
|
|
Trying to do anything here while the text storage has unprocessed edits
|
|
|
|
(ie. an edit count>0) breaks things badly, and in strange ways. Thus, we
|
|
|
|
detect this and raise an exception.
|
|
|
|
*/
|
|
|
|
if ([_textStorage _editCount])
|
|
|
|
{
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
format: @"Glyph generation was triggered for a layout manager "
|
|
|
|
@"while the text storage it was attached to had "
|
|
|
|
@"unprocessed editing. This is not allowed. Glyph "
|
|
|
|
@"generation may be triggered only at points where "
|
|
|
|
@"calls to -beginEditing and -endEditing are "
|
|
|
|
@"balanced."];
|
|
|
|
}
|
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
length = [_textStorage length];
|
|
|
|
if (!length)
|
|
|
|
return;
|
|
|
|
if (last >= length)
|
|
|
|
last = length - 1;
|
|
|
|
|
|
|
|
if (glyphs->char_length <= last)
|
|
|
|
[self _generateRunsToCharacter: last];
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
// [self _glyphDumpRuns];
|
|
|
|
[self _generateGlyphs_char_r: last : 0 : 0 : SKIP_LIST_DEPTH - 1: glyphs : NULL : &dummy];
|
|
|
|
// [self _glyphDumpRuns];
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
-(void) _generateGlyphsUpToGlyph: (unsigned int)last
|
|
|
|
{
|
2003-06-26 23:25:34 +00:00
|
|
|
unsigned int length;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
if (!_textStorage)
|
|
|
|
return;
|
|
|
|
length = [_textStorage length];
|
|
|
|
|
|
|
|
while (glyphs->glyph_length <= last && (glyphs->char_length < length || !glyphs->complete))
|
|
|
|
{
|
2010-09-12 16:34:22 +00:00
|
|
|
// Make an estimate for the character position
|
|
|
|
unsigned int char_last;
|
|
|
|
|
|
|
|
if (glyphs->glyph_length == 0)
|
|
|
|
char_last = last;
|
|
|
|
else
|
|
|
|
char_last = glyphs->char_length + 1 +
|
|
|
|
(last - glyphs->glyph_length) * (glyphs->char_length / (glyphs->glyph_length + 1));
|
|
|
|
|
|
|
|
[self _generateGlyphsUpToCharacter: char_last];
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
/*
|
|
|
|
* Find the glyph run that contains target and the glyph that matches to that char index.
|
|
|
|
*/
|
|
|
|
- (glyph_run_t *) _glyphForCharacter: (unsigned int)target
|
|
|
|
index: (unsigned int *)rindex
|
|
|
|
positions: (unsigned int *)rpos
|
|
|
|
: (unsigned int *)rcpos
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
glyph_run_t *r;
|
2003-06-26 23:25:34 +00:00
|
|
|
unsigned int pos, cpos;
|
2003-02-19 02:18:41 +00:00
|
|
|
int lo, hi, mid, i;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2012-12-26 19:19:50 +00:00
|
|
|
r = [self run_for_character_index: target : &pos : &cpos];
|
2008-07-12 23:00:37 +00:00
|
|
|
if (!r)
|
2008-07-12 21:10:08 +00:00
|
|
|
{
|
|
|
|
[NSException raise: NSRangeException
|
2008-07-12 23:00:37 +00:00
|
|
|
format: @"%s character index %d out of range", __PRETTY_FUNCTION__, target];
|
2008-07-12 21:10:08 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-07-12 23:00:37 +00:00
|
|
|
if (!r->glyphs)
|
|
|
|
{
|
|
|
|
// range, but no glyphs, may be an empty glyph run
|
2008-11-30 14:06:15 +00:00
|
|
|
*rindex = 0; // FIXME ... is this right?
|
2008-07-12 23:00:37 +00:00
|
|
|
*rpos = pos;
|
|
|
|
*rcpos = cpos;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2003-02-19 02:18:41 +00:00
|
|
|
target -= cpos;
|
|
|
|
|
|
|
|
lo = 0;
|
|
|
|
hi = r->head.glyph_length - 1;
|
|
|
|
while (lo < hi)
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2003-02-19 02:18:41 +00:00
|
|
|
mid = (lo + hi) / 2;
|
|
|
|
if (r->glyphs[mid].char_offset > target)
|
2008-05-13 19:40:20 +00:00
|
|
|
hi = mid - 1;
|
2003-02-19 02:18:41 +00:00
|
|
|
else if (r->glyphs[mid].char_offset < target)
|
2008-05-13 19:40:20 +00:00
|
|
|
lo = mid + 1;
|
2003-01-26 19:21:40 +00:00
|
|
|
else
|
2008-05-13 19:40:20 +00:00
|
|
|
hi = lo = mid;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
2008-05-13 19:40:20 +00:00
|
|
|
|
|
|
|
// This final correction is needed as multiple glyph may have
|
|
|
|
// the same character offset and vise versa.
|
2003-02-19 02:18:41 +00:00
|
|
|
i = lo;
|
|
|
|
while (r->glyphs[i].char_offset > target)
|
|
|
|
i--;
|
|
|
|
while (i > 0 && r->glyphs[i - 1].char_offset == r->glyphs[i].char_offset)
|
|
|
|
i--;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
*rindex = i;
|
|
|
|
*rpos = pos;
|
|
|
|
*rcpos = cpos;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
@implementation GSLayoutManager (glyphs)
|
|
|
|
|
|
|
|
- (unsigned int) numberOfGlyphs
|
|
|
|
{
|
|
|
|
[self _generateGlyphsUpToCharacter: -1];
|
|
|
|
return glyphs->glyph_length;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSGlyph) glyphAtIndex: (unsigned int)glyphIndex
|
|
|
|
{
|
|
|
|
BOOL valid;
|
|
|
|
NSGlyph g;
|
2008-05-13 19:40:20 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
g = [self glyphAtIndex: glyphIndex isValidIndex: &valid];
|
2008-05-13 19:40:20 +00:00
|
|
|
if (!valid)
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
return g;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
- (NSGlyph) glyphAtIndex: (unsigned int)glyphIndex
|
2008-05-13 19:40:20 +00:00
|
|
|
isValidIndex: (BOOL *)isValidIndex
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
glyph_run_t *r;
|
2005-01-21 21:43 Alexander Malmberg <alexander@malmberg.org>
Various whitespace cleanups, comment type fixes, and changes
to avoid warnings from recent versions of gcc.
* Headers/Additions/GNUstepGUI/GSToolbar.h (-_toolbars): Declare.
* Source/NSWindow+Toolbar.m: Remove conflicting declaration of
[NSToolbar -_toolbars].
* Headers/Additions/GNUstepGUI/GSServicesManager.h,
Source/GSServicesMananger.m (-item2title:, -validateMenuItem:):
Adjust argument types.
* Headers/AppKit/NSMenu.h (-validateMenuItem:): Adjust argument
type.
* Source/NSTextView.m (-sizeToFit): Don't use size uninitialized
if neither resizable flags is set.
(-insertText:): Adjust argument type.
* Headers/AppKit/NSResponder.h, Source/NSResponder.m (-insertText:):
Adjust argument type. Document.
* Headers/AppKit/NSView.h: Change type of ivar _window to NSWindow *.
* Source/GSTitleView.m (-mouseDown:): Always initialize
startWindowOrigin.
* Source/NSApplication.m (-setApplicationIconImage:): Add casts
to avoid warnings.
* Source/NSCell.m (-cellSize): Add default: case.
* Source/NSPasteboard.m
([GSFiltered -pasteboard:provideDataForType:]): Detect and warn if we
can't find a filter that will get us the desired type.
* Source/NSProgressIndicator.m: Comment out unused variable 'images'.
* Source/NSBezierPath.m: Declare GSBezierPath fully before using it.
(-bezierPathByFlatteningPath, -bezierPathByReversingPath): Make sure
variables are always initialized.
* Source/NSMenuView.m,
* Source/NSPrintOperation.m,
* Source/NSSplitView.m,
* Source/NSTableHeaderView.m: Make sure variables are always
initialized.
* Source/NSBox.m,
* Source/NSImageview.m,
* Source/NSText.m,
* Source/NSTextStorage.m: Add missing includes.
* Source/GSKeyBindingTable.m,
* Source/GSLayoutManager.m,
* Source/NSBitmapImageRep+PNM.m,
* Source/NSBundleAdditions.m,
* Source/NSLayoutManager.m,
* Source/nsimage-tiff.h,
* Source/tiff.m,
* Headers/Additions/GNUstepGUI/GSDisplayServer.h,
* Source/GSDisplayServer.m: Change signedness of various variables.
* Source/NSPanel.m (-sendEvent:): Remove.
* Source/NSWindow.m (-becomesKeyOnlyIfNeeded): New method.
(-_sendEvent:becomesKeyOnlyIfNeeded:): Remove. Move code ...
(-sendEvent:): ... here. Use -becomesKeyOnlyIfNeeded instead
of the argument.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@20590 72102866-910b-0410-8b05-ffd578937521
2005-01-21 20:39:18 +00:00
|
|
|
unsigned int pos;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2010-09-12 16:34:22 +00:00
|
|
|
if (isValidIndex != NULL)
|
|
|
|
*isValidIndex = NO;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
/* glyph '-1' is returned in other places as an "invalid" marker; this
|
|
|
|
way, we can say that it isn't valid without building all glyphs */
|
|
|
|
/* TODO: check if this is really safe or smart. if it isn't, some other
|
|
|
|
methods will need to be changed so they can return "no glyph index" in
|
|
|
|
some other way. */
|
|
|
|
if (glyphIndex == (unsigned int)-1)
|
2008-05-13 19:40:20 +00:00
|
|
|
return NSNullGlyph;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
if (glyphs->glyph_length <= glyphIndex)
|
|
|
|
{
|
|
|
|
[self _generateGlyphsUpToGlyph: glyphIndex];
|
|
|
|
if (glyphs->glyph_length <= glyphIndex)
|
2008-05-13 19:40:20 +00:00
|
|
|
return NSNullGlyph;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
r = run_for_glyph_index(glyphIndex, glyphs, &pos, NULL);
|
2008-07-12 23:00:37 +00:00
|
|
|
if (!r || !r->glyphs) /* shouldn't happen */
|
2008-05-13 19:40:20 +00:00
|
|
|
return NSNullGlyph;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2010-09-12 16:34:22 +00:00
|
|
|
if (isValidIndex != NULL)
|
|
|
|
*isValidIndex = YES;
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
return r->glyphs[glyphIndex - pos].g;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
2003-09-29 21:25:46 +00:00
|
|
|
- (BOOL) isValidGlyphIndex: (unsigned int)glyphIndex
|
|
|
|
{
|
|
|
|
if (glyphIndex == (unsigned int)-1)
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
if (glyphs->glyph_length <= glyphIndex)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
- (unsigned int) getGlyphs: (NSGlyph *)glyphArray
|
2008-05-13 19:40:20 +00:00
|
|
|
range: (NSRange)glyphRange
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
glyph_run_t *r;
|
|
|
|
NSGlyph *g;
|
2003-06-26 23:25:34 +00:00
|
|
|
unsigned int pos;
|
|
|
|
unsigned int num;
|
|
|
|
unsigned int i, j, k;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2003-06-26 23:25:34 +00:00
|
|
|
if (glyphRange.length == 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = NSMaxRange(glyphRange) - 1;
|
2003-01-26 19:21:40 +00:00
|
|
|
if (glyphs->glyph_length <= pos)
|
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
[self _generateGlyphsUpToGlyph: pos];
|
|
|
|
if (glyphs->glyph_length <= pos)
|
|
|
|
{
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph range out of range", __PRETTY_FUNCTION__];
|
|
|
|
return 0;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
r = run_for_glyph_index(glyphRange.location, glyphs, &pos, NULL);
|
|
|
|
if (!r)
|
|
|
|
{ /* shouldn't happen */
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph range out of range", __PRETTY_FUNCTION__];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
g = glyphArray;
|
|
|
|
num = 0;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
if (pos < glyphRange.location)
|
2008-05-13 19:40:20 +00:00
|
|
|
j = glyphRange.location - pos;
|
2003-01-26 19:21:40 +00:00
|
|
|
else
|
2008-05-13 19:40:20 +00:00
|
|
|
j = 0;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2003-06-26 23:25:34 +00:00
|
|
|
k = NSMaxRange(glyphRange) - pos;
|
2003-01-26 19:21:40 +00:00
|
|
|
if (k > r->head.glyph_length)
|
2008-05-13 19:40:20 +00:00
|
|
|
k = r->head.glyph_length;
|
2003-01-26 19:21:40 +00:00
|
|
|
if (k <= j)
|
2008-05-13 19:40:20 +00:00
|
|
|
break;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
/* TODO? only "displayed" glyphs */
|
|
|
|
for (i = j; i < k; i++)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
|
|
|
*g++ = r->glyphs[i].g;
|
|
|
|
num++;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
pos += r->head.glyph_length;
|
|
|
|
r = (glyph_run_t *)r->head.next;
|
|
|
|
if (!r)
|
2008-05-13 19:40:20 +00:00
|
|
|
break;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (unsigned int) characterIndexForGlyphAtIndex: (unsigned int)glyphIndex
|
|
|
|
{
|
|
|
|
glyph_run_t *r;
|
2005-01-21 21:43 Alexander Malmberg <alexander@malmberg.org>
Various whitespace cleanups, comment type fixes, and changes
to avoid warnings from recent versions of gcc.
* Headers/Additions/GNUstepGUI/GSToolbar.h (-_toolbars): Declare.
* Source/NSWindow+Toolbar.m: Remove conflicting declaration of
[NSToolbar -_toolbars].
* Headers/Additions/GNUstepGUI/GSServicesManager.h,
Source/GSServicesMananger.m (-item2title:, -validateMenuItem:):
Adjust argument types.
* Headers/AppKit/NSMenu.h (-validateMenuItem:): Adjust argument
type.
* Source/NSTextView.m (-sizeToFit): Don't use size uninitialized
if neither resizable flags is set.
(-insertText:): Adjust argument type.
* Headers/AppKit/NSResponder.h, Source/NSResponder.m (-insertText:):
Adjust argument type. Document.
* Headers/AppKit/NSView.h: Change type of ivar _window to NSWindow *.
* Source/GSTitleView.m (-mouseDown:): Always initialize
startWindowOrigin.
* Source/NSApplication.m (-setApplicationIconImage:): Add casts
to avoid warnings.
* Source/NSCell.m (-cellSize): Add default: case.
* Source/NSPasteboard.m
([GSFiltered -pasteboard:provideDataForType:]): Detect and warn if we
can't find a filter that will get us the desired type.
* Source/NSProgressIndicator.m: Comment out unused variable 'images'.
* Source/NSBezierPath.m: Declare GSBezierPath fully before using it.
(-bezierPathByFlatteningPath, -bezierPathByReversingPath): Make sure
variables are always initialized.
* Source/NSMenuView.m,
* Source/NSPrintOperation.m,
* Source/NSSplitView.m,
* Source/NSTableHeaderView.m: Make sure variables are always
initialized.
* Source/NSBox.m,
* Source/NSImageview.m,
* Source/NSText.m,
* Source/NSTextStorage.m: Add missing includes.
* Source/GSKeyBindingTable.m,
* Source/GSLayoutManager.m,
* Source/NSBitmapImageRep+PNM.m,
* Source/NSBundleAdditions.m,
* Source/NSLayoutManager.m,
* Source/nsimage-tiff.h,
* Source/tiff.m,
* Headers/Additions/GNUstepGUI/GSDisplayServer.h,
* Source/GSDisplayServer.m: Change signedness of various variables.
* Source/NSPanel.m (-sendEvent:): Remove.
* Source/NSWindow.m (-becomesKeyOnlyIfNeeded): New method.
(-_sendEvent:becomesKeyOnlyIfNeeded:): Remove. Move code ...
(-sendEvent:): ... here. Use -becomesKeyOnlyIfNeeded instead
of the argument.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@20590 72102866-910b-0410-8b05-ffd578937521
2005-01-21 20:39:18 +00:00
|
|
|
unsigned int pos, cpos;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
if (glyphs->glyph_length <= glyphIndex)
|
|
|
|
{
|
|
|
|
[self _generateGlyphsUpToGlyph: glyphIndex];
|
|
|
|
if (glyphs->glyph_length <= glyphIndex)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
|
|
|
|
return 0;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
r = run_for_glyph_index(glyphIndex, glyphs, &pos, &cpos);
|
|
|
|
if (!r)
|
|
|
|
{
|
|
|
|
[NSException raise: NSRangeException
|
2008-05-13 19:40:20 +00:00
|
|
|
format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
|
2003-01-26 19:21:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-07-12 23:00:37 +00:00
|
|
|
if (r->head.glyph_length <= glyphIndex - pos)
|
|
|
|
{
|
|
|
|
return cpos;
|
|
|
|
}
|
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
return cpos + r->glyphs[glyphIndex - pos].char_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSRange) characterRangeForGlyphRange: (NSRange)glyphRange
|
2008-05-13 19:40:20 +00:00
|
|
|
actualGlyphRange: (NSRange *)actualGlyphRange
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
glyph_run_t *r;
|
|
|
|
NSRange real_range, char_range;
|
2003-06-26 23:25:34 +00:00
|
|
|
unsigned int cpos, pos;
|
|
|
|
unsigned j;
|
|
|
|
|
|
|
|
if (NSMaxRange(glyphRange) == 0)
|
|
|
|
{
|
|
|
|
if (actualGlyphRange)
|
2008-05-13 19:40:20 +00:00
|
|
|
*actualGlyphRange = glyphRange;
|
2003-06-26 23:25:34 +00:00
|
|
|
return NSMakeRange(0, 0);
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2003-06-26 23:25:34 +00:00
|
|
|
pos = NSMaxRange(glyphRange) - 1;
|
2003-01-26 19:21:40 +00:00
|
|
|
if (glyphs->glyph_length <= pos)
|
|
|
|
{
|
|
|
|
[self _generateGlyphsUpToGlyph: pos];
|
|
|
|
if (glyphs->glyph_length <= pos)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph range out of range", __PRETTY_FUNCTION__];
|
|
|
|
return NSMakeRange(0, 0);
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
r = run_for_glyph_index(glyphRange.location, glyphs, &pos, &cpos);
|
|
|
|
if (!r)
|
|
|
|
{
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph range out of range", __PRETTY_FUNCTION__];
|
|
|
|
return NSMakeRange(0, 0);
|
|
|
|
}
|
|
|
|
|
2008-07-12 23:00:37 +00:00
|
|
|
if (r->head.glyph_length <= glyphRange.location - pos)
|
|
|
|
{
|
|
|
|
j = cpos;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
j = cpos + r->glyphs[glyphRange.location - pos].char_offset;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
char_range.location = j;
|
|
|
|
|
|
|
|
/* scan backwards to find the real first glyph */
|
|
|
|
{
|
|
|
|
glyph_run_t *r2;
|
|
|
|
unsigned int adj, cadj;
|
2003-06-26 23:25:34 +00:00
|
|
|
int i;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
i = glyphRange.location - pos;
|
|
|
|
r2 = r;
|
|
|
|
adj = pos;
|
|
|
|
cadj = cpos;
|
2008-07-12 23:00:37 +00:00
|
|
|
while ((r2->head.glyph_length > i) &&
|
|
|
|
(r2->glyphs[i].char_offset + cadj == j))
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
i--;
|
|
|
|
while (i < 0)
|
|
|
|
{
|
|
|
|
if (!r2->prev)
|
|
|
|
break;
|
|
|
|
r2 = (glyph_run_t *)r2->prev;
|
|
|
|
i = r2->head.glyph_length - 1;
|
|
|
|
adj -= r2->head.glyph_length;
|
|
|
|
cadj -= r2->head.char_length;
|
|
|
|
}
|
|
|
|
if (i < 0)
|
|
|
|
break;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
real_range.location = i + 1 + adj;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* the range is likely short, so we can do better then a completely new
|
|
|
|
search */
|
|
|
|
r = run_for_glyph_index(glyphRange.location + glyphRange.length - 1,
|
2008-05-13 19:40:20 +00:00
|
|
|
glyphs, &pos, &cpos);
|
2003-01-26 19:21:40 +00:00
|
|
|
if (!r)
|
|
|
|
{
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph range out of range", __PRETTY_FUNCTION__];
|
|
|
|
return NSMakeRange(0, 0);
|
|
|
|
}
|
|
|
|
|
2008-07-12 23:00:37 +00:00
|
|
|
if (r->head.glyph_length <= glyphRange.location + glyphRange.length - 1 - pos)
|
|
|
|
{
|
|
|
|
j = cpos;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
j = cpos + r->glyphs[glyphRange.location + glyphRange.length - 1 - pos].char_offset;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
/* scan forwards to find the real last glyph */
|
|
|
|
{
|
|
|
|
glyph_run_t *r2;
|
|
|
|
unsigned int adj, cadj;
|
|
|
|
unsigned int last = 0;
|
2003-06-26 23:25:34 +00:00
|
|
|
unsigned int i;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
i = glyphRange.location + glyphRange.length - 1 - pos;
|
|
|
|
r2 = r;
|
|
|
|
adj = pos;
|
|
|
|
cadj = cpos;
|
2008-07-12 23:00:37 +00:00
|
|
|
while ((r2->head.glyph_length > i) &&
|
|
|
|
(r2->glyphs[i].char_offset + cadj == j))
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
GLYPH_STEP_FORWARD(r2,i,adj,cadj)
|
|
|
|
if (i==r2->head.glyph_length)
|
|
|
|
{
|
|
|
|
last = cadj + r2->head.char_length;
|
|
|
|
goto found;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
2008-07-12 23:00:37 +00:00
|
|
|
if (r2->head.glyph_length > i)
|
|
|
|
{
|
|
|
|
last = r2->glyphs[i].char_offset + cadj;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
last = j;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
found:
|
|
|
|
real_range.length = i + adj - real_range.location;
|
|
|
|
char_range.length = last - char_range.location;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (actualGlyphRange)
|
|
|
|
*actualGlyphRange = real_range;
|
|
|
|
return char_range;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSRange) glyphRangeForCharacterRange: (NSRange)charRange
|
2008-05-13 19:40:20 +00:00
|
|
|
actualCharacterRange: (NSRange *)actualCharRange
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
NSRange char_range, glyph_range;
|
|
|
|
glyph_run_t *r;
|
2003-06-26 23:25:34 +00:00
|
|
|
unsigned int cpos, pos;
|
|
|
|
unsigned int i, target;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2009-08-23 16:37:28 +00:00
|
|
|
if (charRange.length == 0 && charRange.location == 0)
|
|
|
|
{
|
|
|
|
if (actualCharRange)
|
|
|
|
*actualCharRange = charRange;
|
|
|
|
return NSMakeRange(0, 0);
|
|
|
|
}
|
2020-09-11 20:11:31 +00:00
|
|
|
target = charRange.location;
|
2003-06-26 23:25:34 +00:00
|
|
|
pos = NSMaxRange(charRange) - 1;
|
2003-01-26 19:21:40 +00:00
|
|
|
[self _generateGlyphsUpToCharacter: pos];
|
2020-09-11 20:11:31 +00:00
|
|
|
if (glyphs->char_length <= pos || glyphs->char_length <= target)
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2018-01-14 17:17:05 +00:00
|
|
|
if (actualCharRange)
|
|
|
|
*actualCharRange = NSMakeRange([[_textStorage string] length], 0);
|
|
|
|
return NSMakeRange([self numberOfGlyphs], 0);
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
r = [self _glyphForCharacter: target
|
2008-05-13 19:40:20 +00:00
|
|
|
index: &i
|
|
|
|
positions: &pos : &cpos];
|
2003-01-26 19:21:40 +00:00
|
|
|
glyph_range.location = i + pos;
|
2008-07-12 23:00:37 +00:00
|
|
|
if (r->head.glyph_length > i)
|
|
|
|
{
|
|
|
|
char_range.location = r->glyphs[i].char_offset + cpos;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char_range.location = cpos;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2003-06-26 23:25:34 +00:00
|
|
|
target = NSMaxRange(charRange) - 1;
|
2003-01-26 19:21:40 +00:00
|
|
|
r = [self _glyphForCharacter: target
|
2008-05-13 19:40:20 +00:00
|
|
|
index: &i
|
|
|
|
positions: &pos : &cpos];
|
2008-07-12 23:00:37 +00:00
|
|
|
if (r->head.glyph_length > i)
|
|
|
|
{
|
|
|
|
GLYPH_SCAN_FORWARD(r, i, pos, cpos, r->glyphs[i].char_offset + cpos <= target)
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2003-02-24 02:53:20 +00:00
|
|
|
glyph_range.length = i + pos - glyph_range.location;
|
2008-07-12 23:00:37 +00:00
|
|
|
if (i >= r->head.glyph_length)
|
2003-01-26 19:21:40 +00:00
|
|
|
char_range.length = glyphs->char_length - char_range.location;
|
|
|
|
else
|
|
|
|
char_range.length = r->glyphs[i].char_offset + cpos - char_range.location;
|
|
|
|
|
|
|
|
if (actualCharRange)
|
|
|
|
*actualCharRange = char_range;
|
|
|
|
return glyph_range;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
TODO? this might currently lead to continued runs not being marked as
|
|
|
|
continued runs. this will only happen at safe break spots, though, so
|
|
|
|
it should still be safe. might lose opportunities to merge runs, though.
|
|
|
|
*/
|
|
|
|
|
2003-02-18 00:35:13 +00:00
|
|
|
/*
|
|
|
|
This is hairy.
|
|
|
|
|
|
|
|
The ranges passed in and out of this method are ranges _after_ the change.
|
|
|
|
Internally, we switch between before- and after-indices. Comments mark the
|
|
|
|
places where we switch.
|
|
|
|
*/
|
2003-01-26 19:21:40 +00:00
|
|
|
- (void) invalidateGlyphsForCharacterRange: (NSRange)range
|
2008-05-13 19:40:20 +00:00
|
|
|
changeInLength: (int)lengthChange
|
|
|
|
actualCharacterRange: (NSRange *)actualRange
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
glyph_run_head_t *context[SKIP_LIST_DEPTH];
|
|
|
|
glyph_run_head_t *h;
|
|
|
|
glyph_run_t *r;
|
|
|
|
NSRange rng;
|
2003-06-26 23:25:34 +00:00
|
|
|
int position[SKIP_LIST_DEPTH];
|
|
|
|
unsigned int cpos;
|
|
|
|
int level;
|
|
|
|
unsigned int ch;
|
2008-05-13 19:40:20 +00:00
|
|
|
unsigned int max;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2003-02-17 01:19:34 +00:00
|
|
|
/*
|
2008-05-13 19:40:20 +00:00
|
|
|
We always clear out the cached run information to be safe. This is only needed
|
|
|
|
if the cached run is affected by the invalidation, that is if
|
|
|
|
NSMinRange(range) < cpos + cached_run->head.char_lenght
|
2003-02-17 01:19:34 +00:00
|
|
|
*/
|
|
|
|
cached_run = NULL;
|
|
|
|
|
2003-02-17 20:30:26 +00:00
|
|
|
/* Set it now for early returns. */
|
|
|
|
if (actualRange)
|
|
|
|
*actualRange = range;
|
|
|
|
|
2003-04-03 18:31:25 +00:00
|
|
|
// printf("\n +++ range=(%i+%i) lengthChange=%i\n", range.location, range.length, lengthChange);
|
2003-02-17 20:30:26 +00:00
|
|
|
[self _sanityChecks];
|
2003-02-18 00:35:13 +00:00
|
|
|
// [self _glyphDumpRuns];
|
|
|
|
|
2012-12-30 15:48:21 +00:00
|
|
|
if ((range.location == 0) && (range.length >= [_textStorage length]))
|
|
|
|
{
|
|
|
|
// Full invalidation
|
|
|
|
[self _invalidateEverything];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-02-18 00:35:13 +00:00
|
|
|
/*
|
|
|
|
Find out what range we actually need to invalidate. This depends on how
|
|
|
|
context affects glyph generation.
|
|
|
|
*/
|
2003-01-26 19:21:40 +00:00
|
|
|
ch = range.location;
|
|
|
|
if (ch > 0)
|
|
|
|
{
|
|
|
|
ch = [self _findSafeBreakMovingBackwardFrom: ch];
|
|
|
|
range.length += range.location - ch;
|
|
|
|
range.location = ch;
|
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
max = ch + range.length;
|
|
|
|
if (max < [_textStorage length])
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
max = [self _findSafeBreakMovingForwardFrom: max];
|
|
|
|
range.length = max - range.location;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
2008-05-13 19:40:20 +00:00
|
|
|
// printf("adjusted to %i+%i\n", range.location, range.length);
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
// Last affected character (indix before the change).
|
|
|
|
max -= lengthChange;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2003-02-18 00:35:13 +00:00
|
|
|
/*
|
|
|
|
Find the first run (and context) for the range.
|
|
|
|
*/
|
2003-01-26 19:21:40 +00:00
|
|
|
h = glyphs;
|
|
|
|
cpos = 0;
|
|
|
|
for (level = SKIP_LIST_DEPTH - 1; level >= 0; level--)
|
|
|
|
{
|
|
|
|
while (cpos + h->char_length <= ch)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
|
|
|
cpos += h->char_length;
|
|
|
|
h = h->next;
|
|
|
|
if (!h)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
No runs have been created for the range, so there's nothing
|
|
|
|
to invalidate.
|
|
|
|
*/
|
2003-02-18 00:35:13 +00:00
|
|
|
// printf("no runs created yet\n");
|
2008-05-13 19:40:20 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
context[level] = h;
|
|
|
|
position[level] = cpos;
|
|
|
|
h++;
|
|
|
|
}
|
|
|
|
h--;
|
|
|
|
r = (glyph_run_t *)h;
|
|
|
|
|
2003-02-18 00:35:13 +00:00
|
|
|
/*
|
|
|
|
Now we have the first run that intersects the range we're invalidating
|
|
|
|
in 'r' (and context in 'context' and 'position').
|
2003-01-26 19:21:40 +00:00
|
|
|
*/
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
//printf("split if %i+%i > %i+%i\n", cpos, r->head.char_length, ch, range.length);
|
2003-02-18 00:35:13 +00:00
|
|
|
/*
|
|
|
|
If 'r' extends beyond the invalidated range, split off the trailing, valid
|
2003-02-18 23:16:29 +00:00
|
|
|
part to a new run. The reason we need to do this is that we must have runs
|
|
|
|
for the first glyph not invalidated or the deletion loop below will fail.
|
2003-02-18 00:35:13 +00:00
|
|
|
*/
|
2008-05-13 19:40:20 +00:00
|
|
|
if (cpos + r->head.char_length > max && ch != cpos)
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
glyph_run_t *new;
|
|
|
|
glyph_run_head_t *hn;
|
|
|
|
int i;
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
new = run_insert(context, random_level());
|
|
|
|
new->head.char_length = cpos + r->head.char_length - max;
|
2003-01-26 19:21:40 +00:00
|
|
|
[self _run_copy_attributes: new : r];
|
2008-05-13 19:40:20 +00:00
|
|
|
|
2003-02-18 00:35:13 +00:00
|
|
|
/* OPT: keep valid glyphs
|
|
|
|
this seems to be a fairly rare case
|
|
|
|
*/
|
2003-01-26 19:21:40 +00:00
|
|
|
hn = &new->head;
|
|
|
|
hn--;
|
|
|
|
for (i = 1; i <= new->level; i++, hn--)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
|
|
|
// FIXME: Use simpler adjustment
|
|
|
|
run_fix_head(hn);
|
|
|
|
}
|
2003-02-17 20:30:26 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
r->head.char_length -= new->head.char_length;
|
2008-05-13 19:40:20 +00:00
|
|
|
// Glyphs get freed later
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
2003-02-18 00:35:13 +00:00
|
|
|
/*
|
|
|
|
Set things up. We want 'r' to be the last run we want to keep.
|
|
|
|
*/
|
2003-01-26 19:21:40 +00:00
|
|
|
if (ch == cpos)
|
|
|
|
{
|
2003-02-18 00:35:13 +00:00
|
|
|
/*
|
|
|
|
This run begins exactly at the beginning of the invalidated range.
|
|
|
|
Since we want 'r' to be the last run to keep, we actually want it
|
|
|
|
to be the previous run. Thus, we step backwards in the skip list
|
|
|
|
to get the previous run.
|
|
|
|
*/
|
2003-01-26 19:21:40 +00:00
|
|
|
glyph_run_head_t *h2;
|
|
|
|
|
|
|
|
h2 = h - r->level;
|
|
|
|
h = context[r->level + 1];
|
|
|
|
cpos = position[r->level + 1];
|
|
|
|
h++;
|
|
|
|
for (level = r->level; level >= 0; level--)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
|
|
|
while (h->next != h2)
|
|
|
|
{
|
|
|
|
cpos += h->char_length;
|
|
|
|
h = h->next;
|
|
|
|
}
|
|
|
|
// Fix up old context before switching
|
|
|
|
if (level)
|
|
|
|
run_fix_head(context[level]);
|
|
|
|
|
|
|
|
position[level] = cpos;
|
|
|
|
context[level] = h;
|
|
|
|
h++;
|
|
|
|
h2++;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
h--;
|
|
|
|
r = (glyph_run_t *)h;
|
2008-05-13 19:40:20 +00:00
|
|
|
cpos += r->head.char_length;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-02-18 00:35:13 +00:00
|
|
|
/*
|
|
|
|
This run begins before the invalidated range. Resize it so it ends
|
|
|
|
just before it.
|
|
|
|
*/
|
2008-05-13 19:40:20 +00:00
|
|
|
int len = r->head.char_length;
|
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
r->head.char_length = ch - cpos;
|
2008-05-13 19:40:20 +00:00
|
|
|
cpos += len;
|
2003-01-26 19:21:40 +00:00
|
|
|
/* OPT!!! keep valid glyphs */
|
2008-05-13 19:40:20 +00:00
|
|
|
run_free_glyphs(r);
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
2003-02-18 00:35:13 +00:00
|
|
|
/*
|
|
|
|
'r' is the last run we should keep, 'context' and 'position' are set up
|
2008-05-13 19:40:20 +00:00
|
|
|
for it. cpos
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2003-02-18 00:35:13 +00:00
|
|
|
Now we delete all runs completely invalidated.
|
|
|
|
*/
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
glyph_run_t *next;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
next = (glyph_run_t *)r->head.next;
|
2003-02-18 23:16:29 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
/* We reached the end of all created runs. */
|
|
|
|
if (!next)
|
|
|
|
break;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
NSAssert(max >= cpos,
|
|
|
|
@"no run for first glyph beyond invalidated range");
|
|
|
|
|
|
|
|
/* Clean cut, just stop. */
|
|
|
|
if (max == cpos)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Part of this run extends beyond the invalidated range. Resize it
|
|
|
|
so it's completely beyond the invalidated range and stop.
|
|
|
|
*/
|
|
|
|
if (max < cpos + next->head.char_length)
|
|
|
|
{
|
|
|
|
glyph_run_head_t *hn;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* adjust final run */
|
|
|
|
/* OPT!!! keep valid glyphs */
|
|
|
|
run_free_glyphs(next);
|
|
|
|
|
|
|
|
next->head.char_length -= max - cpos;
|
|
|
|
|
|
|
|
hn = &next->head;
|
|
|
|
hn--;
|
|
|
|
for (i = 1; i <= next->level; i++, hn--)
|
|
|
|
run_fix_head(hn);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
cpos += next->head.char_length;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
/*
|
|
|
|
This run is completely inside the invalidated range. Remove it.
|
|
|
|
The context run heads will be adjusted later.
|
|
|
|
*/
|
|
|
|
[self _run_free_attributes: next];
|
|
|
|
run_remove(context, next);
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-02-18 00:35:13 +00:00
|
|
|
/* printf("deleted\n");
|
|
|
|
[self _glyphDumpRuns];*/
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2003-02-18 00:35:13 +00:00
|
|
|
/*
|
2008-05-13 19:40:20 +00:00
|
|
|
From now one we are use indexes after after the length change.
|
2003-02-18 00:35:13 +00:00
|
|
|
'r' is the last run we want to keep, and the next run is the next
|
|
|
|
uninvalidated run. We need to insert new runs for invalidated range
|
|
|
|
after 'r'.
|
|
|
|
|
|
|
|
As we create new runs, we move the context forward. When we do this, we
|
|
|
|
adjust their heads with updated information. When we're done, we update
|
|
|
|
all the remaining heads.
|
2008-05-13 19:40:20 +00:00
|
|
|
|
|
|
|
FIXME: Much of this code could be shared with the implementation in _generateRunsToCharacter:
|
2003-02-18 00:35:13 +00:00
|
|
|
*/
|
2008-05-13 19:40:20 +00:00
|
|
|
//printf("create runs for %i+%i\n", range.location, range.length);
|
2003-02-18 00:35:13 +00:00
|
|
|
{ /* OPT: this is creating more runs than it needs to */
|
2003-01-26 19:21:40 +00:00
|
|
|
NSDictionary *attributes;
|
|
|
|
glyph_run_t *new;
|
|
|
|
unsigned int max = range.location + range.length;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ch = range.location;
|
|
|
|
while (ch < max)
|
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
attributes = [_textStorage attributesAtIndex: ch
|
|
|
|
longestEffectiveRange: &rng
|
|
|
|
inRange: NSMakeRange(0, [_textStorage length])];
|
|
|
|
|
|
|
|
/* printf("at %i, max=%i, effective range (%i+%i)\n",
|
|
|
|
ch, max, rng.location, rng.length);*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
Catch a common case. If the new run would be a continuation of the
|
|
|
|
previous run, and the previous run is short, we resize the previous
|
|
|
|
run instead of creating a new run.
|
|
|
|
|
|
|
|
(Note that we must make sure that we don't merge with the dummy runs
|
|
|
|
at the very front.)
|
|
|
|
|
|
|
|
This happens a lot with repeated single-character insertions, aka.
|
|
|
|
typing in a text view.
|
|
|
|
*/
|
|
|
|
if (rng.location < ch && context[0]->char_length &&
|
|
|
|
// FIXME: Why 16 and not MAX_RUN_LENGTH
|
|
|
|
context[0]->char_length < 16)
|
|
|
|
{
|
|
|
|
rng.length -= ch - rng.location;
|
|
|
|
rng.location = ch;
|
|
|
|
if (ch + rng.length > max)
|
|
|
|
{
|
|
|
|
rng.length = max - ch;
|
|
|
|
}
|
|
|
|
new = (glyph_run_t *)context[0];
|
|
|
|
// FIXME: We could try to reuse the glyphs
|
|
|
|
run_free_glyphs(new);
|
|
|
|
new->head.char_length += rng.length;
|
|
|
|
ch = NSMaxRange(rng);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
new = run_insert(context, random_level());
|
|
|
|
[self _run_cache_attributes: new : attributes];
|
|
|
|
|
|
|
|
/*
|
|
|
|
We have the longest range the attributes allow us to create a run
|
|
|
|
for. Since this might overlap the previous and next runs, we might
|
|
|
|
need to adjust the location and length of the range we create a
|
|
|
|
run for.
|
|
|
|
|
|
|
|
OPT: If the overlapped run is short, we might want to clear out
|
|
|
|
its glyphs and extend it to cover our range. This should result
|
|
|
|
in fewer runs being created for large sequences of single character
|
|
|
|
adds.
|
|
|
|
*/
|
|
|
|
if (rng.location < ch)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
The new run has the same attributes as the previous run, so we
|
|
|
|
mark it is as a continued run.
|
|
|
|
*/
|
|
|
|
new->continued = 1;
|
|
|
|
rng.length -= ch - rng.location;
|
|
|
|
rng.location = ch;
|
|
|
|
}
|
|
|
|
if (ch + rng.length > max)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
The new run has the same attributes as the next run, so we mark
|
|
|
|
the next run as a continued run.
|
|
|
|
*/
|
|
|
|
if (new->head.next)
|
|
|
|
((glyph_run_t *)new->head.next)->continued = 1;
|
|
|
|
rng.length = max - ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See comment in -_generateRunsToCharacter:. */
|
|
|
|
if (rng.length > MAX_RUN_LENGTH)
|
|
|
|
{
|
|
|
|
unsigned int safe_break = rng.location + MAX_RUN_LENGTH;
|
|
|
|
safe_break = [self _findSafeBreakMovingForwardFrom: safe_break];
|
|
|
|
if (safe_break < NSMaxRange(rng))
|
|
|
|
rng.length = safe_break - rng.location;
|
|
|
|
}
|
|
|
|
|
|
|
|
// printf("adjusted length: %i\n", rng.length);
|
|
|
|
|
|
|
|
h = &new->head;
|
|
|
|
h->char_length = rng.length;
|
|
|
|
for (i = 0; i <= new->level; i++, h--)
|
|
|
|
{
|
|
|
|
if (i)
|
|
|
|
{
|
|
|
|
// FIXME: Simpler adjustment
|
|
|
|
run_fix_head(context[i]);
|
|
|
|
run_fix_head(h);
|
|
|
|
}
|
|
|
|
//h->char_length = rng.length;
|
|
|
|
context[i] = h;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; i < SKIP_LIST_DEPTH; i++)
|
|
|
|
{
|
|
|
|
context[i]->char_length += rng.length;
|
|
|
|
context[i]->complete = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ch += rng.length;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
}
|
2008-05-13 19:40:20 +00:00
|
|
|
|
|
|
|
// Final fix up of context
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
int i;
|
2008-05-13 19:40:20 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
for (i = 1; i < SKIP_LIST_DEPTH; i++)
|
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
run_fix_head(context[i]);
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (actualRange)
|
|
|
|
*actualRange = range;
|
|
|
|
|
2003-02-17 20:30:26 +00:00
|
|
|
[self _sanityChecks];
|
2008-05-13 19:40:20 +00:00
|
|
|
//[self _glyphDumpRuns];
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-01-27 02:55:18 +00:00
|
|
|
#define GET_GLYPH \
|
2003-01-26 19:21:40 +00:00
|
|
|
glyph_run_t *r; \
|
2005-01-21 21:43 Alexander Malmberg <alexander@malmberg.org>
Various whitespace cleanups, comment type fixes, and changes
to avoid warnings from recent versions of gcc.
* Headers/Additions/GNUstepGUI/GSToolbar.h (-_toolbars): Declare.
* Source/NSWindow+Toolbar.m: Remove conflicting declaration of
[NSToolbar -_toolbars].
* Headers/Additions/GNUstepGUI/GSServicesManager.h,
Source/GSServicesMananger.m (-item2title:, -validateMenuItem:):
Adjust argument types.
* Headers/AppKit/NSMenu.h (-validateMenuItem:): Adjust argument
type.
* Source/NSTextView.m (-sizeToFit): Don't use size uninitialized
if neither resizable flags is set.
(-insertText:): Adjust argument type.
* Headers/AppKit/NSResponder.h, Source/NSResponder.m (-insertText:):
Adjust argument type. Document.
* Headers/AppKit/NSView.h: Change type of ivar _window to NSWindow *.
* Source/GSTitleView.m (-mouseDown:): Always initialize
startWindowOrigin.
* Source/NSApplication.m (-setApplicationIconImage:): Add casts
to avoid warnings.
* Source/NSCell.m (-cellSize): Add default: case.
* Source/NSPasteboard.m
([GSFiltered -pasteboard:provideDataForType:]): Detect and warn if we
can't find a filter that will get us the desired type.
* Source/NSProgressIndicator.m: Comment out unused variable 'images'.
* Source/NSBezierPath.m: Declare GSBezierPath fully before using it.
(-bezierPathByFlatteningPath, -bezierPathByReversingPath): Make sure
variables are always initialized.
* Source/NSMenuView.m,
* Source/NSPrintOperation.m,
* Source/NSSplitView.m,
* Source/NSTableHeaderView.m: Make sure variables are always
initialized.
* Source/NSBox.m,
* Source/NSImageview.m,
* Source/NSText.m,
* Source/NSTextStorage.m: Add missing includes.
* Source/GSKeyBindingTable.m,
* Source/GSLayoutManager.m,
* Source/NSBitmapImageRep+PNM.m,
* Source/NSBundleAdditions.m,
* Source/NSLayoutManager.m,
* Source/nsimage-tiff.h,
* Source/tiff.m,
* Headers/Additions/GNUstepGUI/GSDisplayServer.h,
* Source/GSDisplayServer.m: Change signedness of various variables.
* Source/NSPanel.m (-sendEvent:): Remove.
* Source/NSWindow.m (-becomesKeyOnlyIfNeeded): New method.
(-_sendEvent:becomesKeyOnlyIfNeeded:): Remove. Move code ...
(-sendEvent:): ... here. Use -becomesKeyOnlyIfNeeded instead
of the argument.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@20590 72102866-910b-0410-8b05-ffd578937521
2005-01-21 20:39:18 +00:00
|
|
|
unsigned int pos, cpos; \
|
2003-01-26 19:21:40 +00:00
|
|
|
\
|
|
|
|
if (glyphs->glyph_length <= idx) \
|
|
|
|
{ \
|
|
|
|
[self _generateGlyphsUpToGlyph: idx]; \
|
|
|
|
if (glyphs->glyph_length <= idx) \
|
|
|
|
{ \
|
|
|
|
[NSException raise: NSRangeException \
|
|
|
|
format: @"%s glyph range out of range", __PRETTY_FUNCTION__]; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
r = run_for_glyph_index(idx, glyphs, &pos, &cpos); \
|
|
|
|
if (!r) \
|
|
|
|
{ \
|
|
|
|
[NSException raise: NSRangeException \
|
|
|
|
format: @"%s glyph range out of range", __PRETTY_FUNCTION__]; \
|
|
|
|
} \
|
|
|
|
idx -= pos;
|
|
|
|
|
|
|
|
- (void) setDrawsOutsideLineFragment: (BOOL)flag
|
2008-05-13 19:40:20 +00:00
|
|
|
forGlyphAtIndex: (unsigned int)idx
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2003-01-27 02:55:18 +00:00
|
|
|
GET_GLYPH
|
2003-01-26 19:21:40 +00:00
|
|
|
r->glyphs[idx].drawsOutsideLineFragment = !!flag;
|
|
|
|
}
|
|
|
|
- (BOOL) drawsOutsideLineFragmentForGlyphAtIndex: (unsigned int)idx
|
|
|
|
{
|
2003-01-27 02:55:18 +00:00
|
|
|
GET_GLYPH
|
2003-01-26 19:21:40 +00:00
|
|
|
return r->glyphs[idx].drawsOutsideLineFragment;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setNotShownAttribute: (BOOL)flag
|
2008-05-13 19:40:20 +00:00
|
|
|
forGlyphAtIndex: (unsigned int)idx
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2003-01-27 02:55:18 +00:00
|
|
|
GET_GLYPH
|
2003-01-26 19:21:40 +00:00
|
|
|
r->glyphs[idx].isNotShown = !!flag;
|
|
|
|
}
|
|
|
|
- (BOOL) notShownAttributeForGlyphAtIndex: (unsigned int)idx
|
|
|
|
{
|
2003-01-27 02:55:18 +00:00
|
|
|
GET_GLYPH
|
2003-01-26 19:21:40 +00:00
|
|
|
return r->glyphs[idx].isNotShown;
|
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
// GNUstep extension
|
2003-01-26 19:21:40 +00:00
|
|
|
- (NSFont *) effectiveFontForGlyphAtIndex: (unsigned int)idx
|
2008-05-13 19:40:20 +00:00
|
|
|
range: (NSRange *)range
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2003-01-27 02:55:18 +00:00
|
|
|
GET_GLYPH
|
2003-01-26 19:21:40 +00:00
|
|
|
if (range)
|
|
|
|
*range = NSMakeRange(pos, r->head.glyph_length);
|
|
|
|
return r->font;
|
|
|
|
}
|
|
|
|
|
2016-10-23 20:13:37 +00:00
|
|
|
/**
|
|
|
|
* GNUstep extension
|
|
|
|
*/
|
|
|
|
- (NSSize) advancementForGlyphAtIndex: (unsigned int)idx
|
|
|
|
{
|
|
|
|
GET_GLYPH
|
|
|
|
return r->glyphs[idx].advancement;
|
|
|
|
}
|
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
- (void) insertGlyph: (NSGlyph)aGlyph
|
2008-05-13 19:40:20 +00:00
|
|
|
atGlyphIndex: (unsigned int)glyphIndex
|
2003-01-26 19:21:40 +00:00
|
|
|
characterIndex: (unsigned int)charIndex
|
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
[self insertGlyphs: &aGlyph
|
|
|
|
length: 1
|
|
|
|
forStartingGlyphAtIndex: glyphIndex
|
|
|
|
characterIndex: charIndex];
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
2008-05-13 19:40:20 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
- (void) replaceGlyphAtIndex: (unsigned int)glyphIndex
|
2008-05-13 19:40:20 +00:00
|
|
|
withGlyph: (NSGlyph)newGlyph
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
glyph_run_t *r;
|
|
|
|
unsigned int pos, cpos;
|
|
|
|
|
|
|
|
if (glyphs->glyph_length <= glyphIndex)
|
|
|
|
{
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = run_for_glyph_index(glyphIndex, glyphs, &pos, &cpos);
|
|
|
|
if (!r)
|
|
|
|
{
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!r->glyphs || r->head.glyph_length < glyphIndex - pos)
|
|
|
|
{
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
r->glyphs[glyphIndex - pos].g = newGlyph;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
2008-05-13 19:40:20 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
- (void) deleteGlyphsInRange: (NSRange)aRange
|
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
/* See invalidateGlyphsForCharacterRange:changeInLength:actualCharacterRange:
|
2012-12-26 19:19:50 +00:00
|
|
|
glyph_run_t *run;
|
2008-05-13 19:40:20 +00:00
|
|
|
unsigned int pos, cpos;
|
|
|
|
unsigned int glyphIndex;
|
2012-12-26 19:19:50 +00:00
|
|
|
unsigned int lastGlyphIndex;
|
2008-05-13 19:40:20 +00:00
|
|
|
glyph_run_head_t *context[SKIP_LIST_DEPTH];
|
|
|
|
|
|
|
|
glyphIndex = NSMinRange(aRange);
|
2012-12-26 19:19:50 +00:00
|
|
|
lastGlyphIndex = NSMaxRange(aRange) - 1;
|
|
|
|
while (glyphIndex <= lastGlyphIndex)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
2012-12-26 19:19:50 +00:00
|
|
|
run = run_for_glyph_index(glyphIndex, glyphs, &pos, &cpos);
|
|
|
|
if (!run)
|
2008-05-13 19:40:20 +00:00
|
|
|
{
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-12-26 19:19:50 +00:00
|
|
|
// FIXME: remove all invalid glyphs from run
|
|
|
|
if ((pos == 0) && (lastGlyphIndex >= glyphIndex - pos + run->head.glyph_length))
|
|
|
|
{
|
|
|
|
run_free_glyphs(run);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (lastGlyphIndex >= glyphIndex - pos + run->head.glyph_length)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
r->head.glyph_length = len;
|
|
|
|
}
|
|
|
|
// FIXME: Need to invalidate the entries above this one.
|
|
|
|
|
|
|
|
// FIXME Cache this value
|
|
|
|
glyphIndex += r->head.glyph_length - pos;
|
2008-05-13 19:40:20 +00:00
|
|
|
}
|
|
|
|
*/
|
2003-01-26 19:21:40 +00:00
|
|
|
NSLog(@"Internal method %s called", __PRETTY_FUNCTION__);
|
|
|
|
}
|
2008-05-13 19:40:20 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
- (void) setCharacterIndex: (unsigned int)charIndex
|
2008-05-13 19:40:20 +00:00
|
|
|
forGlyphAtIndex: (unsigned int)glyphIndex
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
glyph_run_t *r;
|
|
|
|
unsigned int pos, cpos;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
if (glyphs->glyph_length <= glyphIndex)
|
|
|
|
{
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
|
|
|
|
return;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
r = run_for_glyph_index(glyphIndex, glyphs, &pos, &cpos);
|
|
|
|
if (!r)
|
|
|
|
{
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!r->glyphs || r->head.glyph_length < glyphIndex - pos)
|
|
|
|
{
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
r->glyphs[glyphIndex - pos].char_offset = charIndex - cpos;
|
|
|
|
// What should happen to the following glyphs?
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
2008-05-13 19:40:20 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
- (int) intAttribute: (int)attributeTag
|
|
|
|
forGlyphAtIndex: (unsigned int)glyphIndex
|
|
|
|
{
|
2010-12-13 21:26:15 +00:00
|
|
|
glyph_run_t *run;
|
|
|
|
glyph_t *g;
|
|
|
|
unsigned int pos;
|
|
|
|
|
|
|
|
run = run_for_glyph_index(glyphIndex, glyphs, &pos, NULL);
|
|
|
|
if (run && run->glyphs && (run->head.glyph_length < glyphIndex - pos))
|
|
|
|
{
|
|
|
|
g = &run->glyphs[glyphIndex - pos];
|
|
|
|
|
|
|
|
if (attributeTag == NSGlyphAttributeInscribe)
|
|
|
|
return g->inscription;
|
|
|
|
else if (attributeTag == NSGlyphAttributeSoft)
|
|
|
|
return g->soft;
|
|
|
|
else if (attributeTag == NSGlyphAttributeElastic)
|
|
|
|
return g->elasitc;
|
|
|
|
else if (attributeTag == NSGlyphAttributeBidiLevel)
|
|
|
|
return g->bidilevel;
|
|
|
|
}
|
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***** Layout handling *****/
|
|
|
|
|
2006-11-06 10:19:20 +00:00
|
|
|
@implementation GSLayoutManager (LayoutHelpers)
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
-(void) _invalidateLayoutFromContainer: (int)idx
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
textcontainer_t *tc;
|
|
|
|
linefrag_t *lf;
|
|
|
|
|
|
|
|
extra_textcontainer = nil;
|
|
|
|
|
|
|
|
for (i = idx, tc = textcontainers + idx; i < num_textcontainers; i++, tc++)
|
|
|
|
{
|
2003-02-23 01:01:13 +00:00
|
|
|
tc->complete = NO;
|
2003-01-26 19:21:40 +00:00
|
|
|
if (tc->linefrags)
|
|
|
|
{
|
2003-02-18 17:15:25 +00:00
|
|
|
for (j = 0, lf = tc->linefrags; j < tc->num_linefrags + tc->num_soft; j++, lf++)
|
2003-01-31 21:08:24 +00:00
|
|
|
{
|
|
|
|
if (lf->points)
|
2011-02-28 14:24:57 +00:00
|
|
|
free(lf->points);
|
2003-01-31 21:08:24 +00:00
|
|
|
if (lf->attachments)
|
2011-02-28 14:24:57 +00:00
|
|
|
free(lf->attachments);
|
2003-01-31 21:08:24 +00:00
|
|
|
}
|
|
|
|
|
2011-02-28 14:24:57 +00:00
|
|
|
free(tc->linefrags);
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
tc->linefrags = NULL;
|
2003-02-18 17:15:25 +00:00
|
|
|
tc->num_linefrags = tc->num_soft = 0;
|
2003-02-19 14:12:16 +00:00
|
|
|
tc->size_linefrags = 0;
|
2003-01-26 19:21:40 +00:00
|
|
|
tc->pos = tc->length = 0;
|
2003-02-09 17:05:18 +00:00
|
|
|
tc->was_invalidated = YES;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
for (i = idx - 1, tc = textcontainers + idx - 1; i >= 0; i--, tc--)
|
|
|
|
{
|
2003-02-23 01:01:13 +00:00
|
|
|
if (tc->num_linefrags)
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
layout_glyph = tc->pos + tc->length;
|
|
|
|
if (layout_glyph == glyphs->glyph_length)
|
|
|
|
layout_char = glyphs->char_length;
|
|
|
|
else
|
|
|
|
layout_char = [self characterIndexForGlyphAtIndex: layout_glyph]; /* TODO? */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
layout_glyph = layout_char = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void) _freeLayout
|
|
|
|
{
|
|
|
|
[self _invalidateLayoutFromContainer: 0];
|
|
|
|
}
|
|
|
|
|
2012-12-30 15:48:21 +00:00
|
|
|
-(void) _invalidateEverything
|
|
|
|
{
|
|
|
|
[self _freeLayout];
|
|
|
|
[self _freeGlyphs];
|
|
|
|
[self _initGlyphs];
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
-(void) _doLayout
|
2008-01-04 21:02:29 +00:00
|
|
|
{
|
|
|
|
[self _doLayoutToContainer: num_textcontainers - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void) _doLayoutToGlyph: (unsigned int)glyphIndex
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
textcontainer_t *tc;
|
|
|
|
unsigned int next;
|
|
|
|
NSRect prev;
|
2003-02-10 14:14:34 +00:00
|
|
|
BOOL delegate_responds;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2003-02-10 14:14:34 +00:00
|
|
|
delegate_responds = [_delegate respondsToSelector:
|
|
|
|
@selector(layoutManager:didCompleteLayoutForTextContainer:atEnd:)];
|
|
|
|
|
|
|
|
next = layout_glyph;
|
2003-01-26 19:21:40 +00:00
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
{
|
|
|
|
if (tc->complete)
|
2008-01-04 21:02:29 +00:00
|
|
|
continue;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
while (1)
|
2008-01-04 21:02:29 +00:00
|
|
|
{
|
|
|
|
if (tc->num_linefrags)
|
|
|
|
prev = tc->linefrags[tc->num_linefrags - 1].rect;
|
|
|
|
else
|
|
|
|
prev = NSZeroRect;
|
|
|
|
j = [typesetter layoutGlyphsInLayoutManager: self
|
|
|
|
inTextContainer: tc->textContainer
|
|
|
|
startingAtGlyphIndex: next
|
|
|
|
previousLineFragmentRect: prev
|
|
|
|
nextGlyphIndex: &next
|
|
|
|
numberOfLineFragments: 0];
|
|
|
|
if (j)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (next > glyphIndex)
|
|
|
|
{
|
|
|
|
// If all the requested work is done just leave
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
tc->complete = YES;
|
2004-08-09 19:49:24 +00:00
|
|
|
tc->usedRectValid = NO;
|
2003-02-18 17:15:25 +00:00
|
|
|
if (tc->num_soft)
|
2008-01-04 21:02:29 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
If there is any soft invalidated layout information left, remove
|
|
|
|
it.
|
|
|
|
*/
|
|
|
|
int k;
|
|
|
|
linefrag_t *lf;
|
|
|
|
for (k = tc->num_linefrags, lf = tc->linefrags + k;
|
|
|
|
k < tc->num_linefrags + tc->num_soft; k++, lf++)
|
|
|
|
{
|
|
|
|
if (lf->points)
|
|
|
|
{
|
2011-02-28 14:24:57 +00:00
|
|
|
free(lf->points);
|
2008-01-04 21:02:29 +00:00
|
|
|
lf->points = NULL;
|
|
|
|
}
|
|
|
|
if (lf->attachments)
|
|
|
|
{
|
2011-02-28 14:24:57 +00:00
|
|
|
free(lf->attachments);
|
2008-01-04 21:02:29 +00:00
|
|
|
lf->attachments = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tc->num_soft = 0;
|
|
|
|
}
|
2003-02-10 14:14:34 +00:00
|
|
|
if (delegate_responds)
|
2008-01-04 21:02:29 +00:00
|
|
|
{
|
|
|
|
[_delegate layoutManager: self
|
|
|
|
didCompleteLayoutForTextContainer: tc->textContainer
|
|
|
|
atEnd: j == 2];
|
|
|
|
/* The call might have resulted in more text containers being
|
|
|
|
added, so 'textcontainers' might have moved. */
|
|
|
|
tc = textcontainers + i;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
if (j == 2)
|
2008-01-04 21:02:29 +00:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2003-02-10 14:14:34 +00:00
|
|
|
if (i == num_textcontainers && delegate_responds)
|
2008-01-04 21:02:29 +00:00
|
|
|
{
|
|
|
|
[_delegate layoutManager: self
|
|
|
|
didCompleteLayoutForTextContainer: nil
|
|
|
|
atEnd: NO];
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void) _doLayoutToContainer: (int)cindex
|
|
|
|
{
|
2008-01-04 21:02:29 +00:00
|
|
|
int i, j;
|
|
|
|
textcontainer_t *tc;
|
|
|
|
unsigned int next;
|
|
|
|
NSRect prev;
|
|
|
|
BOOL delegate_responds;
|
|
|
|
|
|
|
|
delegate_responds = [_delegate respondsToSelector:
|
|
|
|
@selector(layoutManager:didCompleteLayoutForTextContainer:atEnd:)];
|
|
|
|
|
|
|
|
next = layout_glyph;
|
|
|
|
for (i = 0, tc = textcontainers; i <= cindex; i++, tc++)
|
|
|
|
{
|
|
|
|
if (tc->complete)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
if (tc->num_linefrags)
|
|
|
|
prev = tc->linefrags[tc->num_linefrags - 1].rect;
|
|
|
|
else
|
|
|
|
prev = NSZeroRect;
|
|
|
|
j = [typesetter layoutGlyphsInLayoutManager: self
|
|
|
|
inTextContainer: tc->textContainer
|
|
|
|
startingAtGlyphIndex: next
|
|
|
|
previousLineFragmentRect: prev
|
|
|
|
nextGlyphIndex: &next
|
|
|
|
numberOfLineFragments: 0];
|
|
|
|
if (j)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
tc->complete = YES;
|
|
|
|
tc->usedRectValid = NO;
|
|
|
|
if (tc->num_soft)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
If there is any soft invalidated layout information left, remove
|
|
|
|
it.
|
|
|
|
*/
|
|
|
|
int k;
|
|
|
|
linefrag_t *lf;
|
|
|
|
for (k = tc->num_linefrags, lf = tc->linefrags + k;
|
|
|
|
k < tc->num_linefrags + tc->num_soft; k++, lf++)
|
|
|
|
{
|
|
|
|
if (lf->points)
|
|
|
|
{
|
2011-02-28 14:24:57 +00:00
|
|
|
free(lf->points);
|
2008-01-04 21:02:29 +00:00
|
|
|
lf->points = NULL;
|
|
|
|
}
|
|
|
|
if (lf->attachments)
|
|
|
|
{
|
2011-02-28 14:24:57 +00:00
|
|
|
free(lf->attachments);
|
2008-01-04 21:02:29 +00:00
|
|
|
lf->attachments = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tc->num_soft = 0;
|
|
|
|
}
|
|
|
|
if (delegate_responds)
|
|
|
|
{
|
|
|
|
[_delegate layoutManager: self
|
|
|
|
didCompleteLayoutForTextContainer: tc->textContainer
|
|
|
|
atEnd: j == 2];
|
|
|
|
/* The call might have resulted in more text containers being
|
|
|
|
added, so 'textcontainers' might have moved. */
|
|
|
|
tc = textcontainers + i;
|
|
|
|
}
|
|
|
|
if (j == 2)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == num_textcontainers && delegate_responds)
|
|
|
|
{
|
|
|
|
[_delegate layoutManager: self
|
|
|
|
didCompleteLayoutForTextContainer: nil
|
|
|
|
atEnd: NO];
|
|
|
|
}
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
2003-02-09 17:05:18 +00:00
|
|
|
-(void) _didInvalidateLayout
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
textcontainer_t *tc;
|
|
|
|
|
|
|
|
for (tc = textcontainers, i = 0; i < num_textcontainers; i++, tc++)
|
|
|
|
{
|
2012-12-30 15:48:21 +00:00
|
|
|
// FIXME: This value never gets used
|
|
|
|
tc->was_invalidated = YES;
|
2003-02-09 17:05:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
@implementation GSLayoutManager (layout)
|
|
|
|
|
|
|
|
|
2003-02-17 20:30:26 +00:00
|
|
|
/*
|
|
|
|
In the general case, we can't make any assumptions about how layout might
|
|
|
|
interact between line frag rects. To be safe in all cases, we must
|
|
|
|
invalidate all layout information.
|
|
|
|
|
|
|
|
TODO:
|
|
|
|
We could handle this by assuming that whoever calls this knows exactly what
|
|
|
|
needs to be invalidated. We won't be using it internally, anyway, so it
|
|
|
|
doesn't matter much to us, and it would make more advanced things possible
|
|
|
|
for external callers. On the other hand, it would be easy to break things
|
|
|
|
by calling this incorrectly.
|
|
|
|
*/
|
2003-01-26 19:21:40 +00:00
|
|
|
- (void) invalidateLayoutForCharacterRange: (NSRange)aRange
|
|
|
|
isSoft: (BOOL)flag
|
|
|
|
actualCharacterRange: (NSRange *)actualRange
|
|
|
|
{
|
|
|
|
[self _invalidateLayoutFromContainer: 0];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define SETUP_STUFF \
|
2003-02-09 20:13:16 +00:00
|
|
|
unsigned int max = glyphRange.location + glyphRange.length; \
|
|
|
|
\
|
|
|
|
[self _generateGlyphsUpToGlyph: max - 1]; \
|
|
|
|
if (glyphs->glyph_length < max) \
|
|
|
|
{ \
|
|
|
|
[NSException raise: NSRangeException \
|
|
|
|
format: @"%s: glyph range out of range", __PRETTY_FUNCTION__]; \
|
|
|
|
return; \
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
- (void) setTextContainer: (NSTextContainer *)aTextContainer
|
|
|
|
forGlyphRange: (NSRange)glyphRange
|
|
|
|
{
|
|
|
|
textcontainer_t *tc;
|
|
|
|
int i;
|
|
|
|
SETUP_STUFF
|
|
|
|
|
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
if (tc->textContainer == aTextContainer)
|
|
|
|
break;
|
|
|
|
if (i == num_textcontainers)
|
|
|
|
{
|
|
|
|
NSLog(@"%s: doesn't own text container", __PRETTY_FUNCTION__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-02-23 01:01:13 +00:00
|
|
|
/* Assume that no line frags means that layout hasn't started yet. */
|
|
|
|
if (tc->num_linefrags)
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
if (glyphRange.location != tc->pos + tc->length)
|
|
|
|
{
|
2003-02-09 20:13:16 +00:00
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s: glyph range not consistent with existing layout",
|
|
|
|
__PRETTY_FUNCTION__];
|
2003-01-26 19:21:40 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
tc->length += glyphRange.length;
|
|
|
|
}
|
|
|
|
else if (!i)
|
|
|
|
{
|
|
|
|
if (glyphRange.location)
|
|
|
|
{
|
2003-02-09 20:13:16 +00:00
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s: glyph range not consistent with existing layout",
|
|
|
|
__PRETTY_FUNCTION__];
|
2003-01-26 19:21:40 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
tc->pos = 0;
|
|
|
|
tc->length = glyphRange.length;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (tc[-1].pos + tc[-1].length != glyphRange.location)
|
|
|
|
{
|
2003-02-09 20:13:16 +00:00
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s: glyph range not consistent with existing layout",
|
|
|
|
__PRETTY_FUNCTION__];
|
2003-01-26 19:21:40 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
tc->pos = glyphRange.location;
|
|
|
|
tc->length = glyphRange.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
unsigned int gpos;
|
|
|
|
unsigned int g;
|
|
|
|
glyph_t *glyph;
|
|
|
|
glyph_run_t *run = run_for_glyph_index(glyphRange.location, glyphs, &gpos, NULL);
|
|
|
|
|
|
|
|
g = glyphRange.location;
|
|
|
|
glyph = &run->glyphs[g - gpos];
|
|
|
|
while (g < glyphRange.location + glyphRange.length)
|
|
|
|
{
|
|
|
|
if (g == gpos + run->head.glyph_length)
|
|
|
|
{
|
|
|
|
gpos += run->head.glyph_length;
|
|
|
|
run = (glyph_run_t *)run->head.next;
|
|
|
|
glyph = run->glyphs;
|
|
|
|
}
|
|
|
|
|
|
|
|
glyph->isNotShown = NO;
|
|
|
|
glyph->drawsOutsideLineFragment = NO;
|
|
|
|
g++;
|
|
|
|
glyph++;
|
|
|
|
}
|
|
|
|
}
|
2003-02-19 14:12:16 +00:00
|
|
|
|
|
|
|
layout_glyph = tc->pos + tc->length;
|
|
|
|
if (layout_glyph == glyphs->glyph_length)
|
|
|
|
layout_char = glyphs->char_length;
|
|
|
|
else
|
|
|
|
layout_char = [self characterIndexForGlyphAtIndex: layout_glyph];
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setLineFragmentRect: (NSRect)fragmentRect
|
|
|
|
forGlyphRange: (NSRange)glyphRange
|
|
|
|
usedRect: (NSRect)usedRect
|
|
|
|
{
|
|
|
|
textcontainer_t *tc;
|
|
|
|
int i;
|
|
|
|
linefrag_t *lf;
|
|
|
|
|
|
|
|
SETUP_STUFF
|
|
|
|
|
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
{
|
|
|
|
if (tc->pos <= glyphRange.location &&
|
|
|
|
tc->pos + tc->length >= glyphRange.location + glyphRange.length)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == num_textcontainers)
|
|
|
|
{
|
2003-02-09 20:13:16 +00:00
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s: glyph range not consistent with existing layout",
|
|
|
|
__PRETTY_FUNCTION__];
|
2003-01-26 19:21:40 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-02-18 17:15:25 +00:00
|
|
|
/* Make sure the given glyph range matches earlier layout. */
|
2003-01-26 19:21:40 +00:00
|
|
|
if (!tc->num_linefrags)
|
|
|
|
{
|
|
|
|
if (glyphRange.location != tc->pos)
|
|
|
|
{
|
2003-02-09 20:13:16 +00:00
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s: glyph range not consistent with existing layout",
|
|
|
|
__PRETTY_FUNCTION__];
|
2003-01-26 19:21:40 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lf = &tc->linefrags[tc->num_linefrags - 1];
|
|
|
|
if (lf->pos + lf->length != glyphRange.location)
|
|
|
|
{
|
2003-02-09 20:13:16 +00:00
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s: glyph range not consistent with existing layout",
|
|
|
|
__PRETTY_FUNCTION__];
|
2003-01-26 19:21:40 +00:00
|
|
|
return;
|
|
|
|
}
|
2003-02-18 17:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(tc->num_linefrags + tc->num_soft))
|
|
|
|
{
|
2003-02-19 14:12:16 +00:00
|
|
|
if (!tc->size_linefrags)
|
|
|
|
{
|
|
|
|
tc->size_linefrags = 16;
|
2011-02-28 14:04:43 +00:00
|
|
|
tc->linefrags = malloc(sizeof(linefrag_t) * tc->size_linefrags);
|
2003-02-19 14:12:16 +00:00
|
|
|
}
|
2003-02-18 17:15:25 +00:00
|
|
|
tc->num_linefrags = 1;
|
|
|
|
lf = tc->linefrags;
|
|
|
|
}
|
|
|
|
else if (!tc->num_soft)
|
|
|
|
{
|
2003-02-19 14:12:16 +00:00
|
|
|
if (tc->size_linefrags <= tc->num_linefrags)
|
|
|
|
{
|
|
|
|
tc->size_linefrags += tc->size_linefrags / 2;
|
2011-02-28 14:24:57 +00:00
|
|
|
tc->linefrags = realloc(tc->linefrags, sizeof(linefrag_t) * tc->size_linefrags);
|
2003-02-19 14:12:16 +00:00
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
tc->num_linefrags++;
|
|
|
|
lf = &tc->linefrags[tc->num_linefrags - 1];
|
|
|
|
}
|
2003-02-18 17:15:25 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = tc->num_linefrags, lf = tc->linefrags + i; i < tc->num_linefrags + tc->num_soft; i++, lf++)
|
|
|
|
{
|
|
|
|
if (lf->pos >= NSMaxRange(glyphRange))
|
|
|
|
break;
|
|
|
|
if (lf->points)
|
|
|
|
{
|
2011-02-28 14:24:57 +00:00
|
|
|
free(lf->points);
|
2003-02-18 17:15:25 +00:00
|
|
|
lf->points = NULL;
|
|
|
|
}
|
|
|
|
if (lf->attachments)
|
|
|
|
{
|
2011-02-28 14:24:57 +00:00
|
|
|
free(lf->attachments);
|
2003-02-18 17:15:25 +00:00
|
|
|
lf->attachments = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == tc->num_linefrags)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
If we should keep all soft frags, we need to enlarge the array
|
|
|
|
to fit the new line frag.
|
|
|
|
*/
|
2003-02-19 14:12:16 +00:00
|
|
|
if (tc->size_linefrags <= tc->num_linefrags + tc->num_soft)
|
|
|
|
{
|
|
|
|
tc->size_linefrags += tc->size_linefrags / 2;
|
2011-02-28 14:24:57 +00:00
|
|
|
tc->linefrags = realloc(tc->linefrags, sizeof(linefrag_t) * tc->size_linefrags);
|
2003-02-19 14:12:16 +00:00
|
|
|
}
|
2003-02-18 17:15:25 +00:00
|
|
|
memmove(&tc->linefrags[tc->num_linefrags + 1], &tc->linefrags[tc->num_linefrags], tc->num_soft * sizeof(linefrag_t));
|
|
|
|
}
|
|
|
|
else if (i > tc->num_linefrags + 1)
|
|
|
|
{
|
|
|
|
tc->num_soft -= i - tc->num_linefrags;
|
|
|
|
memmove(&tc->linefrags[tc->num_linefrags + 1], &tc->linefrags[i], tc->num_soft * sizeof(linefrag_t));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
If i == tc->num_linefrags + 1, we're lucky and everything already
|
|
|
|
lines up, so no moving is necessary.
|
|
|
|
*/
|
|
|
|
tc->num_soft--;
|
|
|
|
}
|
|
|
|
|
|
|
|
tc->num_linefrags++;
|
|
|
|
lf = &tc->linefrags[tc->num_linefrags - 1];
|
|
|
|
}
|
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
memset(lf, 0, sizeof(linefrag_t));
|
|
|
|
lf->rect = fragmentRect;
|
|
|
|
lf->used_rect = usedRect;
|
|
|
|
lf->pos = glyphRange.location;
|
|
|
|
lf->length = glyphRange.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setLocation: (NSPoint)location
|
|
|
|
forStartOfGlyphRange: (NSRange)glyphRange
|
|
|
|
{
|
|
|
|
textcontainer_t *tc;
|
|
|
|
int i;
|
|
|
|
linefrag_t *lf;
|
|
|
|
linefrag_point_t *lp;
|
|
|
|
|
|
|
|
SETUP_STUFF
|
|
|
|
|
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
{
|
|
|
|
if (tc->pos <= glyphRange.location &&
|
|
|
|
tc->pos + tc->length >= glyphRange.location + glyphRange.length)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == num_textcontainers)
|
|
|
|
{
|
2003-02-09 20:13:16 +00:00
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s: glyph range not consistent with existing layout",
|
|
|
|
__PRETTY_FUNCTION__];
|
2003-01-26 19:21:40 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-02-19 02:18:41 +00:00
|
|
|
for (i = tc->num_linefrags - 1, lf = tc->linefrags + i; i >= 0; i--, lf--)
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
if (lf->pos <= glyphRange.location &&
|
|
|
|
lf->pos + lf->length >= glyphRange.location + glyphRange.length)
|
|
|
|
break;
|
|
|
|
}
|
2003-02-19 14:12:16 +00:00
|
|
|
if (i < 0)
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2003-02-09 20:13:16 +00:00
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s: glyph range not consistent with existing layout",
|
|
|
|
__PRETTY_FUNCTION__];
|
2003-01-26 19:21:40 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!lf->num_points)
|
|
|
|
{
|
|
|
|
if (glyphRange.location != lf->pos)
|
|
|
|
{
|
2003-02-09 20:13:16 +00:00
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s: glyph range not consistent with existing layout",
|
|
|
|
__PRETTY_FUNCTION__];
|
2003-01-26 19:21:40 +00:00
|
|
|
return;
|
|
|
|
}
|
2011-02-28 14:04:43 +00:00
|
|
|
lp = lf->points = malloc(sizeof(linefrag_point_t));
|
2003-01-26 19:21:40 +00:00
|
|
|
lf->num_points++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lp = &lf->points[lf->num_points - 1];
|
|
|
|
if (lp->pos + lp->length != glyphRange.location)
|
|
|
|
{
|
2003-02-09 20:13:16 +00:00
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s: glyph range not consistent with existing layout",
|
|
|
|
__PRETTY_FUNCTION__];
|
2003-01-26 19:21:40 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
lf->num_points++;
|
2011-02-28 14:24:57 +00:00
|
|
|
lf->points = realloc(lf->points, sizeof(linefrag_point_t) * lf->num_points);
|
2003-01-26 19:21:40 +00:00
|
|
|
lp = &lf->points[lf->num_points - 1];
|
|
|
|
}
|
|
|
|
lp->pos = glyphRange.location;
|
|
|
|
lp->length = glyphRange.length;
|
|
|
|
lp->p = location;
|
|
|
|
}
|
|
|
|
|
2003-01-31 21:08:24 +00:00
|
|
|
|
|
|
|
-(void) setAttachmentSize: (NSSize)size
|
|
|
|
forGlyphRange: (NSRange)glyphRange
|
|
|
|
{
|
|
|
|
textcontainer_t *tc;
|
|
|
|
int i;
|
|
|
|
linefrag_t *lf;
|
|
|
|
linefrag_attachment_t *la;
|
|
|
|
|
|
|
|
SETUP_STUFF
|
|
|
|
|
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
{
|
|
|
|
if (tc->pos <= glyphRange.location &&
|
|
|
|
tc->pos + tc->length >= glyphRange.location + glyphRange.length)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == num_textcontainers)
|
|
|
|
{
|
2003-02-09 20:13:16 +00:00
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s: glyph range not consistent with existing layout",
|
|
|
|
__PRETTY_FUNCTION__];
|
2003-01-31 21:08:24 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0, lf = tc->linefrags; i < tc->num_linefrags; i++, lf++)
|
|
|
|
{
|
|
|
|
if (lf->pos <= glyphRange.location &&
|
|
|
|
lf->pos + lf->length >= glyphRange.location + glyphRange.length)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == tc->num_linefrags)
|
|
|
|
{
|
2003-02-09 20:13:16 +00:00
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s: glyph range not consistent with existing layout",
|
|
|
|
__PRETTY_FUNCTION__];
|
2003-01-31 21:08:24 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: we do no sanity checking of attachment size ranges. might want
|
|
|
|
to consider doing it */
|
2011-02-28 14:24:57 +00:00
|
|
|
lf->attachments = realloc(lf->attachments,
|
2003-01-31 21:08:24 +00:00
|
|
|
sizeof(linefrag_attachment_t) * (lf->num_attachments + 1));
|
|
|
|
la = &lf->attachments[lf->num_attachments++];
|
|
|
|
|
|
|
|
memset(la, 0, sizeof(linefrag_attachment_t));
|
|
|
|
la->pos = glyphRange.location;
|
|
|
|
la->length = glyphRange.length;
|
|
|
|
la->size = size;
|
|
|
|
}
|
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
#undef SETUP_STUFF
|
|
|
|
|
2008-12-31 16:29:44 +00:00
|
|
|
- (NSTextContainer *) textContainerForGlyphAtIndex: (NSUInteger)glyphIndex
|
|
|
|
effectiveRange: (NSRange *)effectiveRange
|
|
|
|
{
|
|
|
|
return [self textContainerForGlyphAtIndex: glyphIndex
|
|
|
|
effectiveRange: effectiveRange
|
|
|
|
withoutAdditionalLayout: NO];
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-12-31 16:29:44 +00:00
|
|
|
- (NSTextContainer *) textContainerForGlyphAtIndex: (NSUInteger)glyphIndex
|
|
|
|
effectiveRange: (NSRange *)effectiveRange
|
|
|
|
withoutAdditionalLayout: (BOOL)flag
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
textcontainer_t *tc;
|
|
|
|
int i;
|
|
|
|
|
2008-12-31 16:29:44 +00:00
|
|
|
if (!flag)
|
|
|
|
[self _doLayoutToGlyph: glyphIndex];
|
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
if (tc->pos + tc->length > glyphIndex)
|
|
|
|
break;
|
|
|
|
if (i == num_textcontainers)
|
|
|
|
{
|
|
|
|
NSLog(@"%s: can't find text container for glyph (internal error)", __PRETTY_FUNCTION__);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (effectiveRange)
|
|
|
|
{
|
|
|
|
[self _doLayoutToContainer: i];
|
2003-02-10 14:14:34 +00:00
|
|
|
tc = textcontainers + i;
|
2003-01-26 19:21:40 +00:00
|
|
|
*effectiveRange = NSMakeRange(tc->pos, tc->length);
|
|
|
|
}
|
|
|
|
return tc->textContainer;
|
|
|
|
}
|
|
|
|
|
2008-12-31 16:29:44 +00:00
|
|
|
- (NSRect) lineFragmentRectForGlyphAtIndex: (NSUInteger)glyphIndex
|
2003-01-26 19:21:40 +00:00
|
|
|
effectiveRange: (NSRange *)effectiveGlyphRange
|
2008-12-31 16:29:44 +00:00
|
|
|
{
|
|
|
|
return [self lineFragmentRectForGlyphAtIndex: glyphIndex
|
|
|
|
effectiveRange: effectiveGlyphRange
|
|
|
|
withoutAdditionalLayout: NO];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSRect) lineFragmentRectForGlyphAtIndex: (NSUInteger)glyphIndex
|
|
|
|
effectiveRange: (NSRange *)effectiveGlyphRange
|
|
|
|
withoutAdditionalLayout: (BOOL)flag
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
textcontainer_t *tc;
|
|
|
|
linefrag_t *lf;
|
|
|
|
|
2008-12-31 16:29:44 +00:00
|
|
|
if (!flag)
|
|
|
|
[self _doLayoutToGlyph: glyphIndex];
|
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
if (tc->pos + tc->length > glyphIndex)
|
|
|
|
break;
|
|
|
|
if (i == num_textcontainers)
|
|
|
|
{
|
|
|
|
NSLog(@"%s: can't find text container for glyph (internal error)", __PRETTY_FUNCTION__);
|
|
|
|
return NSZeroRect;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0, lf = tc->linefrags; i < tc->num_linefrags; i++, lf++)
|
|
|
|
if (lf->pos + lf->length > glyphIndex)
|
|
|
|
break;
|
|
|
|
if (i == tc->num_linefrags)
|
|
|
|
{
|
|
|
|
NSLog(@"%s: can't find line frag rect for glyph (internal error)", __PRETTY_FUNCTION__);
|
|
|
|
return NSZeroRect;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (effectiveGlyphRange)
|
|
|
|
{
|
|
|
|
*effectiveGlyphRange = NSMakeRange(lf->pos, lf->length);
|
|
|
|
}
|
|
|
|
return lf->rect;
|
|
|
|
}
|
|
|
|
|
2008-12-31 16:29:44 +00:00
|
|
|
- (NSRect) lineFragmentUsedRectForGlyphAtIndex: (NSUInteger)glyphIndex
|
2003-01-26 19:21:40 +00:00
|
|
|
effectiveRange: (NSRange *)effectiveGlyphRange
|
2008-12-31 16:29:44 +00:00
|
|
|
{
|
|
|
|
return [self lineFragmentUsedRectForGlyphAtIndex: glyphIndex
|
|
|
|
effectiveRange: effectiveGlyphRange
|
|
|
|
withoutAdditionalLayout: NO];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSRect) lineFragmentUsedRectForGlyphAtIndex: (NSUInteger)glyphIndex
|
|
|
|
effectiveRange: (NSRange *)effectiveGlyphRange
|
|
|
|
withoutAdditionalLayout: (BOOL)flag
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
textcontainer_t *tc;
|
|
|
|
linefrag_t *lf;
|
|
|
|
|
2008-12-31 16:29:44 +00:00
|
|
|
if (!flag)
|
|
|
|
[self _doLayoutToGlyph: glyphIndex];
|
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
if (tc->pos + tc->length > glyphIndex)
|
|
|
|
break;
|
|
|
|
if (i == num_textcontainers)
|
|
|
|
{
|
|
|
|
NSLog(@"%s: can't find text container for glyph (internal error)", __PRETTY_FUNCTION__);
|
|
|
|
return NSMakeRect(0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0, lf = tc->linefrags; i < tc->num_linefrags; i++, lf++)
|
|
|
|
if (lf->pos + lf->length > glyphIndex)
|
|
|
|
break;
|
|
|
|
if (i == tc->num_linefrags)
|
|
|
|
{
|
|
|
|
NSLog(@"%s: can't find line frag rect for glyph (internal error)", __PRETTY_FUNCTION__);
|
|
|
|
return NSMakeRect(0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (effectiveGlyphRange)
|
|
|
|
{
|
|
|
|
*effectiveGlyphRange = NSMakeRange(lf->pos, lf->length);
|
|
|
|
}
|
|
|
|
return lf->used_rect;
|
|
|
|
}
|
|
|
|
|
2003-02-17 20:30:26 +00:00
|
|
|
- (NSRange) rangeOfNominallySpacedGlyphsContainingIndex: (unsigned int)glyphIndex
|
2003-01-26 19:21:40 +00:00
|
|
|
startLocation: (NSPoint *)p
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
textcontainer_t *tc;
|
|
|
|
linefrag_t *lf;
|
|
|
|
linefrag_point_t *lp;
|
|
|
|
|
|
|
|
[self _doLayoutToGlyph: glyphIndex];
|
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
if (tc->pos + tc->length > glyphIndex)
|
|
|
|
break;
|
|
|
|
if (i == num_textcontainers)
|
|
|
|
{
|
|
|
|
NSLog(@"%s: can't find text container for glyph (internal error)", __PRETTY_FUNCTION__);
|
|
|
|
return NSMakeRange(NSNotFound, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0, lf = tc->linefrags; i < tc->num_linefrags; i++, lf++)
|
|
|
|
if (lf->pos + lf->length > glyphIndex)
|
|
|
|
break;
|
|
|
|
if (i == tc->num_linefrags)
|
|
|
|
{
|
|
|
|
NSLog(@"%s: can't find line frag rect for glyph (internal error)", __PRETTY_FUNCTION__);
|
|
|
|
return NSMakeRange(NSNotFound, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0, lp = lf->points; i < lf->num_points; i++, lp++)
|
|
|
|
if (lp->pos + lp->length > glyphIndex)
|
|
|
|
break;
|
|
|
|
if (i == lf->num_points)
|
|
|
|
{
|
|
|
|
NSLog(@"%s: can't find location for glyph (internal error)", __PRETTY_FUNCTION__);
|
|
|
|
return NSMakeRange(NSNotFound, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p)
|
|
|
|
*p = lp->p;
|
|
|
|
return NSMakeRange(lp->pos, lp->length);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (NSRange) rangeOfNominallySpacedGlyphsContainingIndex:(unsigned int)glyphIndex
|
|
|
|
{
|
|
|
|
return [self rangeOfNominallySpacedGlyphsContainingIndex: glyphIndex
|
|
|
|
startLocation: NULL];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* The union of all line frag rects' used rects. */
|
|
|
|
- (NSRect) usedRectForTextContainer: (NSTextContainer *)container
|
|
|
|
{
|
|
|
|
textcontainer_t *tc;
|
|
|
|
linefrag_t *lf;
|
|
|
|
int i;
|
|
|
|
NSRect used;
|
|
|
|
|
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
if (tc->textContainer == container)
|
|
|
|
break;
|
|
|
|
if (i == num_textcontainers)
|
|
|
|
{
|
|
|
|
NSLog(@"%s: doesn't own text container", __PRETTY_FUNCTION__);
|
|
|
|
return NSMakeRect(0, 0, 0, 0);
|
|
|
|
}
|
2012-12-30 15:48:21 +00:00
|
|
|
if (!tc->complete)
|
|
|
|
{
|
|
|
|
[self _doLayoutToContainer: i];
|
|
|
|
tc = textcontainers + i;
|
|
|
|
}
|
2003-02-16 03:18:35 +00:00
|
|
|
|
2004-08-09 19:49:24 +00:00
|
|
|
if (tc->usedRectValid)
|
2017-02-17 19:44:25 +00:00
|
|
|
{
|
|
|
|
used = tc->usedRect;
|
|
|
|
if (tc->textContainer == extra_textcontainer)
|
|
|
|
{
|
|
|
|
used = NSUnionRect(used, extra_used_rect);
|
|
|
|
}
|
|
|
|
return used;
|
|
|
|
}
|
2004-08-09 19:49:24 +00:00
|
|
|
|
|
|
|
if (tc->num_linefrags)
|
|
|
|
{
|
|
|
|
double x0, y0, x1, y1;
|
|
|
|
i = 0;
|
|
|
|
lf = tc->linefrags;
|
|
|
|
x0 = NSMinX(lf->used_rect);
|
|
|
|
y0 = NSMinY(lf->used_rect);
|
|
|
|
x1 = NSMaxX(lf->used_rect);
|
|
|
|
y1 = NSMaxY(lf->used_rect);
|
2004-08-09 19:50:01 +00:00
|
|
|
for (i++, lf++; i < tc->num_linefrags; i++, lf++)
|
2004-08-09 19:49:24 +00:00
|
|
|
{
|
|
|
|
if (NSMinX(lf->used_rect) < x0)
|
|
|
|
x0 = NSMinX(lf->used_rect);
|
|
|
|
if (NSMinY(lf->used_rect) < y0)
|
|
|
|
y0 = NSMinY(lf->used_rect);
|
|
|
|
if (NSMaxX(lf->used_rect) > x1)
|
2004-08-10 00:08:42 +00:00
|
|
|
x1 = NSMaxX(lf->used_rect);
|
2004-08-09 19:49:24 +00:00
|
|
|
if (NSMaxY(lf->used_rect) > y1)
|
2004-08-10 00:08:42 +00:00
|
|
|
y1 = NSMaxY(lf->used_rect);
|
2004-08-09 19:49:24 +00:00
|
|
|
}
|
|
|
|
used = NSMakeRect(x0, y0, x1 - x0, y1 - y0);
|
|
|
|
}
|
|
|
|
else
|
2017-02-17 19:44:25 +00:00
|
|
|
{
|
|
|
|
used = NSZeroRect;
|
|
|
|
}
|
2004-08-09 19:49:24 +00:00
|
|
|
tc->usedRect = used;
|
|
|
|
tc->usedRectValid = YES;
|
2017-02-17 19:44:25 +00:00
|
|
|
if (tc->textContainer == extra_textcontainer)
|
|
|
|
{
|
|
|
|
used = NSUnionRect(used, extra_used_rect);
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
return used;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSRange) glyphRangeForTextContainer: (NSTextContainer *)container
|
|
|
|
{
|
|
|
|
textcontainer_t *tc;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
if (tc->textContainer == container)
|
|
|
|
break;
|
|
|
|
if (i == num_textcontainers)
|
|
|
|
{
|
|
|
|
NSLog(@"%s: doesn't own text container", __PRETTY_FUNCTION__);
|
|
|
|
return NSMakeRange(NSNotFound, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
[self _doLayoutToContainer: i];
|
2003-02-10 14:14:34 +00:00
|
|
|
tc = textcontainers + i;
|
2003-01-26 19:21:40 +00:00
|
|
|
return NSMakeRange(tc->pos, tc->length);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-01 02:32:03 +00:00
|
|
|
/* TODO: make more efficient */
|
2003-01-26 19:21:40 +00:00
|
|
|
- (NSArray *) textContainers
|
|
|
|
{
|
|
|
|
NSMutableArray *ma;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ma = [[NSMutableArray alloc] initWithCapacity: num_textcontainers];
|
|
|
|
for (i = 0; i < num_textcontainers; i++)
|
|
|
|
[ma addObject: textcontainers[i].textContainer];
|
|
|
|
return [ma autorelease];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) addTextContainer: (NSTextContainer *)container
|
|
|
|
{
|
|
|
|
[self insertTextContainer: container
|
|
|
|
atIndex: num_textcontainers];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) insertTextContainer: (NSTextContainer *)aTextContainer
|
|
|
|
atIndex: (unsigned int)index
|
|
|
|
{
|
2003-06-26 23:25:34 +00:00
|
|
|
unsigned int i;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
if (index < num_textcontainers)
|
|
|
|
[self _invalidateLayoutFromContainer: index];
|
|
|
|
|
|
|
|
num_textcontainers++;
|
2011-02-28 14:24:57 +00:00
|
|
|
textcontainers = realloc(textcontainers,
|
2003-01-26 19:21:40 +00:00
|
|
|
sizeof(textcontainer_t) * num_textcontainers);
|
|
|
|
|
|
|
|
for (i = num_textcontainers - 1; i > index; i--)
|
|
|
|
textcontainers[i] = textcontainers[i - 1];
|
|
|
|
|
|
|
|
memset(&textcontainers[i], 0, sizeof(textcontainer_t));
|
|
|
|
textcontainers[i].textContainer = [aTextContainer retain];
|
|
|
|
|
|
|
|
[aTextContainer setLayoutManager: self];
|
2003-02-09 17:05:18 +00:00
|
|
|
|
|
|
|
[self _didInvalidateLayout];
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) removeTextContainerAtIndex: (unsigned int)index
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
textcontainer_t *tc = &textcontainers[index];
|
|
|
|
|
|
|
|
[self _invalidateLayoutFromContainer: index];
|
|
|
|
[tc->textContainer setLayoutManager: nil];
|
|
|
|
[tc->textContainer release];
|
2003-01-28 16:44:34 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
num_textcontainers--;
|
|
|
|
for (i = index; i < num_textcontainers; i++)
|
|
|
|
textcontainers[i] = textcontainers[i + 1];
|
|
|
|
|
|
|
|
if (num_textcontainers)
|
2011-02-28 14:24:57 +00:00
|
|
|
textcontainers = realloc(textcontainers,
|
2003-01-26 19:21:40 +00:00
|
|
|
sizeof(textcontainer_t) * num_textcontainers);
|
|
|
|
else
|
2003-02-01 02:32:03 +00:00
|
|
|
{
|
2011-02-28 14:24:57 +00:00
|
|
|
free(textcontainers);
|
2003-02-01 02:32:03 +00:00
|
|
|
textcontainers = NULL;
|
|
|
|
}
|
2003-02-09 17:05:18 +00:00
|
|
|
|
|
|
|
[self _didInvalidateLayout];
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) textContainerChangedGeometry: (NSTextContainer *)aContainer
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < num_textcontainers; i++)
|
|
|
|
if (textcontainers[i].textContainer == aContainer)
|
|
|
|
break;
|
|
|
|
if (i == num_textcontainers)
|
|
|
|
{
|
|
|
|
NSLog(@"%s: does not own text container", __PRETTY_FUNCTION__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
[self _invalidateLayoutFromContainer: i];
|
2003-02-09 17:05:18 +00:00
|
|
|
[self _didInvalidateLayout];
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (unsigned int) firstUnlaidCharacterIndex
|
|
|
|
{
|
|
|
|
return layout_char;
|
|
|
|
}
|
2012-12-30 15:48:21 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
- (unsigned int) firstUnlaidGlyphIndex
|
|
|
|
{
|
|
|
|
return layout_glyph;
|
|
|
|
}
|
2012-12-30 15:48:21 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
-(void) getFirstUnlaidCharacterIndex: (unsigned int *)cindex
|
|
|
|
glyphIndex: (unsigned int *)gindex
|
|
|
|
{
|
|
|
|
if (cindex)
|
|
|
|
*cindex = [self firstUnlaidCharacterIndex];
|
|
|
|
if (gindex)
|
|
|
|
*gindex = [self firstUnlaidGlyphIndex];
|
|
|
|
}
|
|
|
|
|
2003-02-16 03:18:35 +00:00
|
|
|
-(void) setExtraLineFragmentRect: (NSRect)linefrag
|
|
|
|
usedRect: (NSRect)used
|
|
|
|
textContainer: (NSTextContainer *)tc
|
|
|
|
{
|
|
|
|
extra_rect = linefrag;
|
|
|
|
extra_used_rect = used;
|
|
|
|
extra_textcontainer = tc;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(NSRect) extraLineFragmentRect
|
|
|
|
{
|
|
|
|
return extra_rect;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(NSRect) extraLineFragmentUsedRect
|
|
|
|
{
|
|
|
|
return extra_used_rect;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(NSTextContainer *) extraLineFragmentTextContainer
|
|
|
|
{
|
|
|
|
return extra_textcontainer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-18 20:26:49 +00:00
|
|
|
-(void) _softInvalidateUseLineFrags: (int)num
|
|
|
|
withShift: (NSSize)shift
|
|
|
|
inTextContainer: (NSTextContainer *)textContainer
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
textcontainer_t *tc;
|
|
|
|
linefrag_t *lf;
|
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
if (tc->textContainer == textContainer)
|
|
|
|
break;
|
|
|
|
if (i == num_textcontainers)
|
|
|
|
{
|
|
|
|
NSLog(@"(%s): does not own text container", __PRETTY_FUNCTION__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-02-18 23:34:51 +00:00
|
|
|
if (shift.width || shift.height)
|
2003-02-18 20:26:49 +00:00
|
|
|
{
|
2003-02-18 23:34:51 +00:00
|
|
|
for (i = 0, lf = &tc->linefrags[tc->num_linefrags]; i < num; i++, lf++)
|
|
|
|
{
|
|
|
|
lf->rect.origin.x += shift.width;
|
|
|
|
lf->rect.origin.y += shift.height;
|
|
|
|
lf->used_rect.origin.x += shift.width;
|
|
|
|
lf->used_rect.origin.y += shift.height;
|
|
|
|
}
|
2003-02-18 20:26:49 +00:00
|
|
|
}
|
|
|
|
tc->num_soft -= num;
|
|
|
|
tc->num_linefrags += num;
|
2003-02-18 23:34:51 +00:00
|
|
|
lf = &tc->linefrags[tc->num_linefrags - 1];
|
|
|
|
tc->length = lf->pos + lf->length - tc->pos;
|
2003-02-18 20:26:49 +00:00
|
|
|
|
|
|
|
layout_glyph = tc->pos + tc->length;
|
|
|
|
/*
|
2003-05-05 20:52:24 +00:00
|
|
|
We must have glyphs beyond all the soft-invalidated line frags,
|
2003-02-18 20:26:49 +00:00
|
|
|
so comparing with glyphs->glyph_length is ok.
|
|
|
|
*/
|
|
|
|
if (layout_glyph == glyphs->glyph_length)
|
|
|
|
layout_char = glyphs->char_length;
|
|
|
|
else
|
|
|
|
layout_char = [self characterIndexForGlyphAtIndex: layout_glyph]; /* TODO? */
|
|
|
|
}
|
|
|
|
|
|
|
|
-(NSRect) _softInvalidateLineFragRect: (int)index
|
2003-05-05 20:52:24 +00:00
|
|
|
firstGlyph: (unsigned int *)first_glyph
|
2003-02-18 20:26:49 +00:00
|
|
|
nextGlyph: (unsigned int *)next_glyph
|
|
|
|
inTextContainer: (NSTextContainer *)textContainer
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
textcontainer_t *tc;
|
|
|
|
linefrag_t *lf;
|
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
if (tc->textContainer == textContainer)
|
|
|
|
break;
|
|
|
|
if (i == num_textcontainers)
|
|
|
|
{
|
|
|
|
NSLog(@"(%s): does not own text container", __PRETTY_FUNCTION__);
|
|
|
|
return NSZeroRect;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index >= tc->num_soft)
|
|
|
|
return NSZeroRect;
|
|
|
|
|
|
|
|
lf = &tc->linefrags[tc->num_linefrags + index];
|
2003-05-05 20:52:24 +00:00
|
|
|
*first_glyph = lf->pos;
|
2003-02-18 20:26:49 +00:00
|
|
|
*next_glyph = lf->pos + lf->length;
|
|
|
|
return lf->rect;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(unsigned int) _softInvalidateFirstGlyphInTextContainer: (NSTextContainer *)textContainer
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
textcontainer_t *tc;
|
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
if (tc->textContainer == textContainer)
|
|
|
|
break;
|
|
|
|
if (i == num_textcontainers)
|
|
|
|
{
|
|
|
|
NSLog(@"(%s): does not own text container", __PRETTY_FUNCTION__);
|
|
|
|
return (unsigned int)-1;
|
|
|
|
}
|
|
|
|
if (tc->num_soft)
|
|
|
|
return tc->linefrags[tc->num_linefrags].pos;
|
|
|
|
else
|
|
|
|
return (unsigned int)-1;
|
|
|
|
}
|
|
|
|
|
2003-02-18 23:34:51 +00:00
|
|
|
-(unsigned int) _softInvalidateNumberOfLineFragsInTextContainer: (NSTextContainer *)textContainer
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
textcontainer_t *tc;
|
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
if (tc->textContainer == textContainer)
|
|
|
|
break;
|
|
|
|
if (i == num_textcontainers)
|
|
|
|
{
|
|
|
|
NSLog(@"(%s): does not own text container", __PRETTY_FUNCTION__);
|
|
|
|
return (unsigned int)-1;
|
|
|
|
}
|
|
|
|
return tc->num_soft;
|
|
|
|
}
|
2003-02-18 20:26:49 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
/***** The rest *****/
|
|
|
|
|
|
|
|
@implementation GSLayoutManager
|
|
|
|
|
|
|
|
- init
|
|
|
|
{
|
|
|
|
if (!(self = [super init]))
|
|
|
|
return nil;
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
[self setTypesetter: [GSTypesetter sharedSystemTypesetter]];
|
|
|
|
[self setGlyphGenerator: [NSGlyphGenerator sharedGlyphGenerator]];
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
usesScreenFonts = YES;
|
2008-05-13 19:40:20 +00:00
|
|
|
[self _initGlyphs];
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void) dealloc
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
textcontainer_t *tc;
|
|
|
|
|
2011-02-28 14:24:57 +00:00
|
|
|
free(rect_array);
|
2003-01-26 19:21:40 +00:00
|
|
|
rect_array_size = 0;
|
|
|
|
rect_array = NULL;
|
|
|
|
|
|
|
|
[self _freeLayout];
|
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
{
|
2012-06-05 11:34:02 +00:00
|
|
|
[tc->textContainer setLayoutManager: nil];
|
2003-01-26 19:21:40 +00:00
|
|
|
[tc->textContainer release];
|
|
|
|
}
|
2011-02-28 14:24:57 +00:00
|
|
|
free(textcontainers);
|
2003-02-01 02:32:03 +00:00
|
|
|
textcontainers = NULL;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
[self _freeGlyphs];
|
|
|
|
|
|
|
|
DESTROY(typesetter);
|
2008-05-13 19:40:20 +00:00
|
|
|
DESTROY(_glyphGenerator);
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the text storage for the layout manager.
|
|
|
|
* Use -replaceTextStorage: instead as a rule. - this method is really
|
|
|
|
* more for internal use by the text system.
|
|
|
|
* Invalidates the entire layout (should it??)
|
|
|
|
*/
|
2003-01-29 20:19:01 +00:00
|
|
|
/*
|
|
|
|
See [NSTextView -setTextContainer:] for more information about these calls.
|
|
|
|
*/
|
2003-01-26 19:21:40 +00:00
|
|
|
- (void) setTextStorage: (NSTextStorage *)aTextStorage
|
|
|
|
{
|
2003-01-29 20:19:01 +00:00
|
|
|
int i;
|
|
|
|
textcontainer_t *tc;
|
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
[self _invalidateEverything];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make a note of the new text storage object, but don't retain it.
|
|
|
|
* The text storage is owning us - it retains us.
|
|
|
|
*/
|
|
|
|
_textStorage = aTextStorage;
|
2003-01-28 16:44:34 +00:00
|
|
|
|
2003-01-29 20:19:01 +00:00
|
|
|
/*
|
|
|
|
We send this message to all text containers so they can respond to the
|
|
|
|
change (most importantly to let them tell their text views).
|
|
|
|
*/
|
|
|
|
for (i = 0, tc = textcontainers; i < num_textcontainers; i++, tc++)
|
|
|
|
{
|
|
|
|
[tc->textContainer setLayoutManager: self];
|
|
|
|
}
|
2003-02-09 17:05:18 +00:00
|
|
|
[self _didInvalidateLayout];
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the text storage for this layout manager.
|
|
|
|
*/
|
|
|
|
- (NSTextStorage *) textStorage
|
|
|
|
{
|
|
|
|
return _textStorage;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Replaces the text storage with a new one.<br />
|
|
|
|
* Takes care (since layout managers are owned by text storages)
|
|
|
|
* not to get self deallocated.
|
|
|
|
*/
|
|
|
|
- (void) replaceTextStorage: (NSTextStorage *)newTextStorage
|
|
|
|
{
|
|
|
|
NSArray *layoutManagers = [_textStorage layoutManagers];
|
|
|
|
NSEnumerator *enumerator = [layoutManagers objectEnumerator];
|
|
|
|
GSLayoutManager *object;
|
|
|
|
|
|
|
|
/* Remove layout managers from old NSTextStorage object and add them to the
|
|
|
|
new one. NSTextStorage's addLayoutManager invokes GSLayoutManager's
|
|
|
|
setTextStorage method automatically, and that includes self. */
|
|
|
|
|
|
|
|
while ((object = (GSLayoutManager*)[enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
RETAIN(object);
|
|
|
|
[_textStorage removeLayoutManager: object];
|
|
|
|
[newTextStorage addLayoutManager: object];
|
|
|
|
RELEASE(object);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
- (NSGlyphGenerator *) glyphGenerator
|
|
|
|
{
|
|
|
|
return _glyphGenerator;
|
|
|
|
}
|
|
|
|
- (void) setGlyphGenerator: (NSGlyphGenerator *)glyphGenerator
|
|
|
|
{
|
|
|
|
ASSIGN(_glyphGenerator, glyphGenerator);
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
|
|
|
- (id) delegate
|
|
|
|
{
|
|
|
|
return _delegate;
|
|
|
|
}
|
|
|
|
- (void) setDelegate: (id)aDelegate
|
|
|
|
{
|
|
|
|
_delegate = aDelegate;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-03-03 13:57:53 +00:00
|
|
|
-(GSTypesetter *) typesetter
|
|
|
|
{
|
|
|
|
return typesetter;
|
|
|
|
}
|
|
|
|
-(void) setTypesetter: (GSTypesetter *)a_typesetter
|
|
|
|
{
|
|
|
|
ASSIGN(typesetter, a_typesetter);
|
|
|
|
}
|
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
- (BOOL) usesScreenFonts
|
|
|
|
{
|
|
|
|
return usesScreenFonts;
|
|
|
|
}
|
2012-12-30 15:48:21 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
- (void) setUsesScreenFonts: (BOOL)flag
|
|
|
|
{
|
|
|
|
flag = !!flag;
|
|
|
|
if (flag == usesScreenFonts)
|
|
|
|
return;
|
|
|
|
usesScreenFonts = flag;
|
|
|
|
[self _invalidateEverything];
|
2003-02-09 17:05:18 +00:00
|
|
|
[self _didInvalidateLayout];
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSFont *) substituteFontForFont: (NSFont *)originalFont
|
|
|
|
{
|
|
|
|
NSFont *f;
|
|
|
|
if (usesScreenFonts)
|
|
|
|
{
|
|
|
|
f = [originalFont screenFont];
|
|
|
|
if (f)
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
return originalFont;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void) setBackgroundLayoutEnabled: (BOOL)flag
|
|
|
|
{
|
|
|
|
flag = !!flag;
|
|
|
|
if (flag == backgroundLayoutEnabled)
|
|
|
|
return;
|
|
|
|
backgroundLayoutEnabled = flag;
|
|
|
|
/* TODO */
|
|
|
|
}
|
|
|
|
- (BOOL) backgroundLayoutEnabled
|
|
|
|
{
|
|
|
|
return backgroundLayoutEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setShowsInvisibleCharacters: (BOOL)flag
|
|
|
|
{
|
|
|
|
flag = !!flag;
|
|
|
|
if (flag == showsInvisibleCharacters)
|
|
|
|
return;
|
|
|
|
|
|
|
|
showsInvisibleCharacters = flag;
|
|
|
|
[self _invalidateEverything];
|
2003-02-09 17:05:18 +00:00
|
|
|
[self _didInvalidateLayout];
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
2012-12-30 15:48:21 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
- (BOOL) showsInvisibleCharacters
|
|
|
|
{
|
|
|
|
return showsInvisibleCharacters;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setShowsControlCharacters: (BOOL)flag
|
|
|
|
{
|
|
|
|
flag = !!flag;
|
|
|
|
if (flag == showsControlCharacters)
|
|
|
|
return;
|
|
|
|
showsControlCharacters = flag;
|
|
|
|
[self _invalidateEverything];
|
2003-02-09 17:05:18 +00:00
|
|
|
[self _didInvalidateLayout];
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
2012-12-30 15:48:21 +00:00
|
|
|
|
2003-01-26 19:21:40 +00:00
|
|
|
- (BOOL) showsControlCharacters
|
|
|
|
{
|
|
|
|
return showsControlCharacters;
|
|
|
|
}
|
|
|
|
|
2022-11-05 20:01:53 +00:00
|
|
|
- (CGFloat) defaultLineHeightForFont: (NSFont*)theFont
|
|
|
|
{
|
|
|
|
return [theFont defaultLineHeightForFont];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (CGFloat) defaultBaselineOffsetForFont: (NSFont*)theFont
|
|
|
|
{
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
2003-02-17 20:30:26 +00:00
|
|
|
/*
|
|
|
|
Note that NSLayoutManager completely overrides this (to perform more
|
|
|
|
intelligent invalidation of layout using the constraints on layout it
|
|
|
|
has).
|
|
|
|
*/
|
2003-01-26 19:21:40 +00:00
|
|
|
- (void) textStorage: (NSTextStorage *)aTextStorage
|
2008-05-13 19:40:20 +00:00
|
|
|
edited: (unsigned int)mask
|
|
|
|
range: (NSRange)range
|
2003-01-26 19:21:40 +00:00
|
|
|
changeInLength: (int)lengthChange
|
|
|
|
invalidatedRange: (NSRange)invalidatedRange
|
|
|
|
{
|
|
|
|
NSRange r;
|
|
|
|
|
|
|
|
if (!(mask & NSTextStorageEditedCharacters))
|
|
|
|
lengthChange = 0;
|
|
|
|
|
|
|
|
[self invalidateGlyphsForCharacterRange: invalidatedRange
|
2008-05-13 19:40:20 +00:00
|
|
|
changeInLength: lengthChange
|
|
|
|
actualCharacterRange: &r];
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2003-02-17 20:30:26 +00:00
|
|
|
/*
|
|
|
|
See the comments above -invalidateLayoutForCharacterRange:isSoft:
|
|
|
|
actualCharacterRange: for information on why we invalidate everything
|
|
|
|
here.
|
|
|
|
*/
|
|
|
|
[self _invalidateLayoutFromContainer: 0];
|
2003-02-09 17:05:18 +00:00
|
|
|
[self _didInvalidateLayout];
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
-(unsigned int) _findSafeBreakMovingBackwardFrom: (unsigned int)ch
|
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
NSString *str = [_textStorage string];
|
2008-04-04 22:01:44 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
// FIXME: Better check for ligature
|
|
|
|
while (ch > 0 && [str characterAtIndex: ch-1] == 'f')
|
|
|
|
ch--;
|
|
|
|
return ch;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
-(unsigned int) _findSafeBreakMovingForwardFrom: (unsigned int)ch
|
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
unsigned int len = [_textStorage length];
|
|
|
|
NSString *str = [_textStorage string];
|
2008-04-04 22:01:44 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
// FIXME: Better check for ligature
|
|
|
|
while (ch < len && [str characterAtIndex: ch] == 'f')
|
|
|
|
ch++;
|
|
|
|
if (ch < len && ch > 0 && [str characterAtIndex: ch-1] == 'f')
|
|
|
|
ch++;
|
2008-04-04 22:01:44 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
return ch;
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
2008-04-04 22:01:44 +00:00
|
|
|
/*
|
2008-05-13 19:40:20 +00:00
|
|
|
* NSGlyphStorage protocol
|
|
|
|
*/
|
|
|
|
- (NSAttributedString*) attributedString
|
|
|
|
{
|
|
|
|
return _textStorage;
|
|
|
|
}
|
|
|
|
|
2011-08-02 23:34:06 +00:00
|
|
|
/**
|
|
|
|
* GNUstep extension
|
|
|
|
*/
|
2008-05-13 19:40:20 +00:00
|
|
|
- (void) insertGlyphs: (const NSGlyph*)glyph_list
|
2011-08-02 23:34:06 +00:00
|
|
|
withAdvancements: (const NSSize*)advancements
|
2008-05-13 19:40:20 +00:00
|
|
|
length: (NSUInteger)length
|
|
|
|
forStartingGlyphAtIndex: (NSUInteger)glyph
|
|
|
|
characterIndex: (NSUInteger)index
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
glyph_run_t *run;
|
|
|
|
int i;
|
2003-01-26 19:21:40 +00:00
|
|
|
glyph_t *g;
|
2008-05-13 19:40:20 +00:00
|
|
|
int len;
|
|
|
|
unsigned int gpos = 0;
|
|
|
|
unsigned int cpos = 0;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
//NSLog(@"Insert %d glyphs at %d for index %d", length, glyph, index);
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2012-12-26 19:19:50 +00:00
|
|
|
run = [self run_for_character_index: index : &gpos : &cpos];
|
2008-05-13 19:40:20 +00:00
|
|
|
if (!run)
|
|
|
|
{
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
|
|
|
|
return;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
len = glyph - gpos + length;
|
2012-12-26 19:19:50 +00:00
|
|
|
if (len < 0)
|
|
|
|
{
|
2013-01-30 09:48:54 +00:00
|
|
|
NSLog(@"Insert %d glyphs at %d for index %d", (int)length, (int)glyph, (int)index);
|
2012-12-26 19:19:50 +00:00
|
|
|
NSLog(@"Found gpos %d cpos %d len %d", gpos, cpos, len);
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
if (!run->glyphs)
|
|
|
|
{
|
2011-02-28 14:04:43 +00:00
|
|
|
run->glyphs = malloc(sizeof(glyph_t) * len);
|
2008-05-13 19:40:20 +00:00
|
|
|
memset(run->glyphs, 0, sizeof(glyph_t) * len);
|
|
|
|
}
|
|
|
|
else if (run->head.glyph_length < len)
|
|
|
|
{
|
2011-02-28 14:24:57 +00:00
|
|
|
run->glyphs = realloc(run->glyphs, sizeof(glyph_t) * len);
|
2008-05-13 19:40:20 +00:00
|
|
|
memset(&run->glyphs[glyph - gpos], 0, sizeof(glyph_t) * length);
|
|
|
|
}
|
|
|
|
run->head.glyph_length = len;
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
// Add the glyphs to the run
|
|
|
|
g = run->glyphs + (glyph - gpos);
|
|
|
|
for (i = 0; i < length; i++)
|
2003-01-26 19:21:40 +00:00
|
|
|
{
|
2008-05-13 19:40:20 +00:00
|
|
|
// We expect to get a nominal glyph run
|
|
|
|
g->char_offset = i + index - cpos;
|
|
|
|
g->g = glyph_list[i];
|
2011-08-02 23:34:06 +00:00
|
|
|
g->advancement = advancements[i];
|
2008-05-13 19:40:20 +00:00
|
|
|
g++;
|
|
|
|
}
|
|
|
|
}
|
2008-04-04 22:01:44 +00:00
|
|
|
|
2011-08-02 23:34:06 +00:00
|
|
|
- (void) insertGlyphs: (const NSGlyph*)glyph_list
|
|
|
|
length: (NSUInteger)length
|
|
|
|
forStartingGlyphAtIndex: (NSUInteger)glyph
|
|
|
|
characterIndex: (NSUInteger)index
|
|
|
|
{
|
|
|
|
glyph_run_t *run;
|
|
|
|
int i;
|
|
|
|
unsigned int gpos, cpos;
|
|
|
|
NSSize advances[length];
|
|
|
|
|
2012-12-26 19:19:50 +00:00
|
|
|
run = [self run_for_character_index: index : &gpos : &cpos];
|
2011-08-02 23:34:06 +00:00
|
|
|
if (!run)
|
|
|
|
{
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"%s glyph index out of range", __PRETTY_FUNCTION__];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<length; i++)
|
|
|
|
{
|
2016-12-18 11:58:31 +00:00
|
|
|
if ((glyph_list[i] != NSControlGlyph) && (glyph_list[i] != GSAttachmentGlyph))
|
2016-10-21 22:42:38 +00:00
|
|
|
{
|
|
|
|
advances[i] = [run->font advancementForGlyph: glyph_list[i]];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
advances[i] = NSZeroSize;
|
|
|
|
}
|
2011-08-02 23:34:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
[self insertGlyphs: glyph_list
|
|
|
|
withAdvancements: advances
|
|
|
|
length: length
|
|
|
|
forStartingGlyphAtIndex: glyph
|
|
|
|
characterIndex: index];
|
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
- (NSUInteger) layoutOptions
|
|
|
|
{
|
|
|
|
NSUInteger options = 0;
|
2008-04-04 22:01:44 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
if (showsInvisibleCharacters)
|
|
|
|
options |= NSShowInvisibleGlyphs;
|
|
|
|
if (showsInvisibleCharacters)
|
|
|
|
options |= NSShowControlGlyphs;
|
2008-04-04 22:01:44 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
return options;
|
|
|
|
}
|
2008-04-04 22:01:44 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
- (void) setIntAttribute: (NSInteger)attributeTag
|
|
|
|
value: (NSInteger)anInt
|
|
|
|
forGlyphAtIndex: (NSUInteger)glyphIndex
|
|
|
|
{
|
2010-12-13 21:26:15 +00:00
|
|
|
glyph_run_t *run;
|
|
|
|
glyph_t *g;
|
|
|
|
unsigned int pos;
|
|
|
|
|
|
|
|
run = run_for_glyph_index(glyphIndex, glyphs, &pos, NULL);
|
|
|
|
if (run && run->glyphs && (run->head.glyph_length < glyphIndex - pos))
|
|
|
|
{
|
|
|
|
g = &run->glyphs[glyphIndex - pos];
|
|
|
|
|
|
|
|
if (attributeTag == NSGlyphAttributeInscribe)
|
|
|
|
g->inscription = anInt;
|
|
|
|
else if (attributeTag == NSGlyphAttributeSoft)
|
|
|
|
g->soft = anInt;
|
|
|
|
else if (attributeTag == NSGlyphAttributeElastic)
|
|
|
|
g->elasitc = anInt;
|
|
|
|
else if (attributeTag == NSGlyphAttributeBidiLevel)
|
|
|
|
g->bidilevel = anInt;
|
|
|
|
}
|
2019-12-10 17:23:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSDictionary *) typingAttributes
|
|
|
|
{
|
|
|
|
return [NSTextView defaultTypingAttributes];
|
|
|
|
}
|
|
|
|
|
2008-04-04 22:01:44 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
/*
|
|
|
|
* NSCoding protocol
|
|
|
|
*/
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
|
|
|
{
|
|
|
|
// FIXME
|
2003-01-26 19:21:40 +00:00
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
- (id) initWithCoder: (NSCoder*)aDecoder
|
|
|
|
{
|
|
|
|
// FIXME
|
|
|
|
return self;
|
|
|
|
}
|
2003-01-26 19:21:40 +00:00
|
|
|
|
2008-05-13 19:40:20 +00:00
|
|
|
@end
|