mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-23 06:51:44 +00:00
* Headers/Additions/GNUstepGUI/GSLayoutManager_internal.h: Make
-_invalidateEverything visible. * Source/GSLayoutManager.m * (-invalidateGlyphsForCharacterRange:...): Call -_invalidateEverything when the whole character range is invalidated. * Source/NSStringDrawing.m: Remove workarounds for full layout * invalidation. Move initialisation check into cache_lock(). Extract size match code in function. Put #ifdef around all statistics code. Use same LARGE_SIZE value as Apple does. Make the methods taking options the main ones. * Source/GSHorizontalTypesetter.m (-fullJustifyLine::, -rightAlignLine::, -centerAlignLine::): Don't align when the line width is bigger than 1e7. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@35925 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
60fcb3622e
commit
89fed0244c
5 changed files with 161 additions and 212 deletions
16
ChangeLog
16
ChangeLog
|
@ -1,3 +1,19 @@
|
|||
2012-12-30 Fred Kiefer <FredKiefer@gmx.de>
|
||||
|
||||
* Headers/Additions/GNUstepGUI/GSLayoutManager_internal.h: Make
|
||||
-_invalidateEverything visible.
|
||||
* Source/GSLayoutManager.m (-invalidateGlyphsForCharacterRange:...): Call
|
||||
-_invalidateEverything when the whole character range is invalidated.
|
||||
* Source/NSStringDrawing.m: Remove workarounds for full layout invalidation.
|
||||
Move initialisation check into cache_lock().
|
||||
Extract size match code in function.
|
||||
Put #ifdef around all statistics code.
|
||||
Use same LARGE_SIZE value as Apple does.
|
||||
Make the methods taking options the main ones.
|
||||
* Source/GSHorizontalTypesetter.m (-fullJustifyLine::,
|
||||
-rightAlignLine::, -centerAlignLine::): Don't align when the line
|
||||
width is bigger than 1e7.
|
||||
|
||||
2012-12-26 Fred Kiefer <FredKiefer@gmx.de>
|
||||
|
||||
* Headers/AppKit/NSOpenGL.h,
|
||||
|
|
|
@ -237,6 +237,7 @@ typedef struct GSLayoutManager_textcontainer_s
|
|||
@interface GSLayoutManager (LayoutHelpers)
|
||||
-(void) _freeLayout;
|
||||
-(void) _invalidateLayoutFromContainer: (int)idx;
|
||||
-(void) _invalidateEverything;
|
||||
|
||||
-(void) _doLayout; /* TODO: this is just a hack until proper incremental layout is done */
|
||||
-(void) _doLayoutToGlyph: (unsigned int)glyphIndex;
|
||||
|
|
|
@ -320,6 +320,12 @@ struct GSHorizontalTypesetter_line_frag_s
|
|||
};
|
||||
typedef struct GSHorizontalTypesetter_line_frag_s line_frag_t;
|
||||
|
||||
/*
|
||||
Apple uses this as the maximum width of an NSTextContainer.
|
||||
For bigger values the width gets ignored.
|
||||
*/
|
||||
#define LARGE_SIZE 1e7
|
||||
|
||||
-(void) fullJustifyLine: (line_frag_t *)lf : (int)num_line_frags
|
||||
{
|
||||
unsigned int i, start;
|
||||
|
@ -329,6 +335,11 @@ typedef struct GSHorizontalTypesetter_line_frag_s line_frag_t;
|
|||
glyph_cache_t *g;
|
||||
unichar ch;
|
||||
|
||||
if (lf->rect.size.width >= LARGE_SIZE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (start = 0; num_line_frags; num_line_frags--, lf++)
|
||||
{
|
||||
num_spaces = 0;
|
||||
|
@ -361,13 +372,17 @@ typedef struct GSHorizontalTypesetter_line_frag_s line_frag_t;
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
-(void) rightAlignLine: (line_frag_t *)lf : (int)num_line_frags
|
||||
{
|
||||
unsigned int i;
|
||||
float delta;
|
||||
glyph_cache_t *g;
|
||||
|
||||
if (lf->rect.size.width >= LARGE_SIZE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0, g = cache; num_line_frags; num_line_frags--, lf++)
|
||||
{
|
||||
delta = lf->rect.size.width - lf->last_used;
|
||||
|
@ -383,6 +398,11 @@ typedef struct GSHorizontalTypesetter_line_frag_s line_frag_t;
|
|||
float delta;
|
||||
glyph_cache_t *g;
|
||||
|
||||
if (lf->rect.size.width >= LARGE_SIZE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0, g = cache; num_line_frags; num_line_frags--, lf++)
|
||||
{
|
||||
delta = (lf->rect.size.width - lf->last_used) / 2.0;
|
||||
|
|
|
@ -1271,6 +1271,13 @@ places where we switch.
|
|||
[self _sanityChecks];
|
||||
// [self _glyphDumpRuns];
|
||||
|
||||
if ((range.location == 0) && (range.length >= [_textStorage length]))
|
||||
{
|
||||
// Full invalidation
|
||||
[self _invalidateEverything];
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Find out what range we actually need to invalidate. This depends on how
|
||||
context affects glyph generation.
|
||||
|
@ -1869,6 +1876,12 @@ places where we switch.
|
|||
[self _invalidateLayoutFromContainer: 0];
|
||||
}
|
||||
|
||||
-(void) _invalidateEverything
|
||||
{
|
||||
[self _freeLayout];
|
||||
[self _freeGlyphs];
|
||||
[self _initGlyphs];
|
||||
}
|
||||
|
||||
-(void) _doLayout
|
||||
{
|
||||
|
@ -2041,7 +2054,6 @@ places where we switch.
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
-(void) _didInvalidateLayout
|
||||
{
|
||||
int i;
|
||||
|
@ -2049,7 +2061,8 @@ places where we switch.
|
|||
|
||||
for (tc = textcontainers, i = 0; i < num_textcontainers; i++, tc++)
|
||||
{
|
||||
tc->was_invalidated = NO;
|
||||
// FIXME: This value never gets used
|
||||
tc->was_invalidated = YES;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2609,9 +2622,11 @@ forStartOfGlyphRange: (NSRange)glyphRange
|
|||
NSLog(@"%s: doesn't own text container", __PRETTY_FUNCTION__);
|
||||
return NSMakeRect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
[self _doLayoutToContainer: i];
|
||||
tc = textcontainers + i;
|
||||
if (!tc->complete)
|
||||
{
|
||||
[self _doLayoutToContainer: i];
|
||||
tc = textcontainers + i;
|
||||
}
|
||||
|
||||
if (tc->usedRectValid)
|
||||
return tc->usedRect;
|
||||
|
@ -2746,15 +2761,16 @@ forStartOfGlyphRange: (NSRange)glyphRange
|
|||
[self _didInvalidateLayout];
|
||||
}
|
||||
|
||||
|
||||
- (unsigned int) firstUnlaidCharacterIndex
|
||||
{
|
||||
return layout_char;
|
||||
}
|
||||
|
||||
- (unsigned int) firstUnlaidGlyphIndex
|
||||
{
|
||||
return layout_glyph;
|
||||
}
|
||||
|
||||
-(void) getFirstUnlaidCharacterIndex: (unsigned int *)cindex
|
||||
glyphIndex: (unsigned int *)gindex
|
||||
{
|
||||
|
@ -2764,7 +2780,6 @@ forStartOfGlyphRange: (NSRange)glyphRange
|
|||
*gindex = [self firstUnlaidGlyphIndex];
|
||||
}
|
||||
|
||||
|
||||
-(void) setExtraLineFragmentRect: (NSRect)linefrag
|
||||
usedRect: (NSRect)used
|
||||
textContainer: (NSTextContainer *)tc
|
||||
|
@ -2938,16 +2953,6 @@ forStartOfGlyphRange: (NSRange)glyphRange
|
|||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
-(void) _invalidateEverything
|
||||
{
|
||||
[self _freeLayout];
|
||||
|
||||
[self _freeGlyphs];
|
||||
[self _initGlyphs];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the text storage for the layout manager.
|
||||
* Use -replaceTextStorage: instead as a rule. - this method is really
|
||||
|
@ -3045,6 +3050,7 @@ See [NSTextView -setTextContainer:] for more information about these calls.
|
|||
{
|
||||
return usesScreenFonts;
|
||||
}
|
||||
|
||||
- (void) setUsesScreenFonts: (BOOL)flag
|
||||
{
|
||||
flag = !!flag;
|
||||
|
@ -3091,6 +3097,7 @@ See [NSTextView -setTextContainer:] for more information about these calls.
|
|||
[self _invalidateEverything];
|
||||
[self _didInvalidateLayout];
|
||||
}
|
||||
|
||||
- (BOOL) showsInvisibleCharacters
|
||||
{
|
||||
return showsInvisibleCharacters;
|
||||
|
@ -3105,6 +3112,7 @@ See [NSTextView -setTextContainer:] for more information about these calls.
|
|||
[self _invalidateEverything];
|
||||
[self _didInvalidateLayout];
|
||||
}
|
||||
|
||||
- (BOOL) showsControlCharacters
|
||||
{
|
||||
return showsControlCharacters;
|
||||
|
@ -3136,7 +3144,6 @@ has).
|
|||
here.
|
||||
*/
|
||||
[self _invalidateLayoutFromContainer: 0];
|
||||
|
||||
[self _didInvalidateLayout];
|
||||
}
|
||||
|
||||
|
|
|
@ -43,28 +43,20 @@
|
|||
#import "AppKit/DPSOperators.h"
|
||||
|
||||
/*
|
||||
TODO:
|
||||
|
||||
these methods are _not_ reentrant. should they be?
|
||||
Apple uses this as the maximum width of an NSTextContainer.
|
||||
For bigger values the width gets ignored.
|
||||
*/
|
||||
#define LARGE_SIZE 1e7
|
||||
|
||||
|
||||
#define LARGE_SIZE 4e6
|
||||
/*
|
||||
4e6 is chosen because it's close to (half of, for extra margin) 1<<23-1, the
|
||||
largest number that can be stored in a 32-bit float with an ulp of 0.5, which
|
||||
means things should round to the correct whole point.
|
||||
*/
|
||||
|
||||
|
||||
#define NUM_CACHE_ENTRIES 16
|
||||
#define HIT_BOOST 2
|
||||
#define MISS_COST 1
|
||||
/*
|
||||
A size of 16 and these constants give a hit rate of 80%-90% for normal app
|
||||
use (based on real world statistics gathered with the help of some users
|
||||
from #GNUstep).
|
||||
*/
|
||||
#define NUM_CACHE_ENTRIES 16
|
||||
#define HIT_BOOST 2
|
||||
#define MISS_COST 1
|
||||
|
||||
|
||||
typedef struct
|
||||
|
@ -82,7 +74,7 @@ typedef struct
|
|||
} cache_t;
|
||||
|
||||
|
||||
static BOOL did_init;
|
||||
static BOOL did_init = NO;
|
||||
static cache_t cache[NUM_CACHE_ENTRIES];
|
||||
|
||||
static NSTextStorage *scratchTextStorage;
|
||||
|
@ -91,12 +83,12 @@ static NSTextContainer *scratchTextContainer;
|
|||
|
||||
static NSRecursiveLock *cacheLock = nil;
|
||||
|
||||
static int total, hits, misses, hash_hits;
|
||||
|
||||
/* For collecting statistics. */
|
||||
//#define STATS
|
||||
|
||||
#ifdef STATS
|
||||
static int total, hits, misses, hash_hits;
|
||||
|
||||
static void NSStringDrawing_dump_stats(void)
|
||||
{
|
||||
#define P(x) printf("%15i %s\n", x, #x);
|
||||
|
@ -109,7 +101,6 @@ static void NSStringDrawing_dump_stats(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void init_string_drawing(void)
|
||||
{
|
||||
int i;
|
||||
|
@ -152,20 +143,42 @@ static void init_string_drawing(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void cache_lock()
|
||||
static inline void cache_lock()
|
||||
{
|
||||
if(cacheLock == nil)
|
||||
// FIXME: Put all the init code into an +initialize method
|
||||
// to let the runtime take care of it.
|
||||
if (cacheLock == nil)
|
||||
{
|
||||
cacheLock = [[NSRecursiveLock alloc] init];
|
||||
}
|
||||
[cacheLock lock];
|
||||
if (!did_init)
|
||||
{
|
||||
init_string_drawing();
|
||||
}
|
||||
}
|
||||
|
||||
static void cache_unlock()
|
||||
static inline void cache_unlock()
|
||||
{
|
||||
[cacheLock unlock];
|
||||
}
|
||||
|
||||
static inline BOOL is_size_match(cache_t *c, int hasSize, NSSize size)
|
||||
{
|
||||
if ((!c->hasSize && !hasSize) ||
|
||||
(c->hasSize && hasSize && c->givenSize.width == size.width
|
||||
&& c->givenSize.height == size.height) ||
|
||||
(!c->hasSize && hasSize && size.width >= NSMaxX(c->usedRect)
|
||||
&& size.height >= NSMaxY(c->usedRect)))
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
static int cache_match(int hasSize, NSSize size, int useScreenFonts, int *matched)
|
||||
{
|
||||
int i, j;
|
||||
|
@ -173,10 +186,11 @@ static int cache_match(int hasSize, NSSize size, int useScreenFonts, int *matche
|
|||
int least_used;
|
||||
int replace;
|
||||
int orig_used;
|
||||
|
||||
unsigned int string_hash = [[scratchTextStorage string] hash];
|
||||
|
||||
#ifdef STATS
|
||||
total++;
|
||||
#endif
|
||||
|
||||
*matched = 1;
|
||||
replace = least_used = -1;
|
||||
|
@ -213,39 +227,29 @@ static int cache_match(int hasSize, NSSize size, int useScreenFonts, int *matche
|
|||
|| c->useScreenFonts != useScreenFonts)
|
||||
continue;
|
||||
|
||||
#ifdef STATS
|
||||
hash_hits++;
|
||||
#endif
|
||||
|
||||
if (![scratchTextStorage isEqualToAttributedString: c->textStorage])
|
||||
continue;
|
||||
|
||||
/* String and attributes match. */
|
||||
if (!c->hasSize && !hasSize)
|
||||
{
|
||||
c->used = orig_used + HIT_BOOST;
|
||||
hits++;
|
||||
return j;
|
||||
}
|
||||
|
||||
if (c->hasSize && hasSize && c->givenSize.width == size.width
|
||||
&& c->givenSize.height == size.height)
|
||||
{
|
||||
c->used = orig_used + HIT_BOOST;
|
||||
hits++;
|
||||
return j;
|
||||
}
|
||||
|
||||
if (!c->hasSize && hasSize && size.width >= NSMaxX(c->usedRect)
|
||||
&& size.height >= NSMaxY(c->usedRect))
|
||||
/* String and attributes match, check size. */
|
||||
if (is_size_match(c, hasSize, size))
|
||||
{
|
||||
c->used = orig_used + HIT_BOOST;
|
||||
#ifdef STATS
|
||||
hits++;
|
||||
#endif
|
||||
return j;
|
||||
}
|
||||
}
|
||||
|
||||
NSCAssert(replace != -1, @"Couldn't find a cache entry to replace.");
|
||||
|
||||
#ifdef STATS
|
||||
misses++;
|
||||
#endif
|
||||
*matched = 0;
|
||||
|
||||
c = cache + replace;
|
||||
|
@ -268,93 +272,44 @@ static int cache_match(int hasSize, NSSize size, int useScreenFonts, int *matche
|
|||
return replace;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int cache_lookup_string(NSString *string, NSDictionary *attributes,
|
||||
int hasSize, NSSize size, int useScreenFonts)
|
||||
static inline void prepare_string(NSString *string, NSDictionary *attributes)
|
||||
{
|
||||
cache_t *c;
|
||||
int ci, hit;
|
||||
NSLayoutManager *layoutManager;
|
||||
NSTextContainer *textContainer;
|
||||
|
||||
if (!did_init)
|
||||
init_string_drawing();
|
||||
|
||||
/*
|
||||
This is a hack, but it's an efficient way of getting the layout manager
|
||||
to just ditch all old information, and here, we don't want it to try to
|
||||
be clever and cache or soft-invalidate anything since the new string has
|
||||
nothing to do with the old one.
|
||||
|
||||
TODO: the layout manager should realize this by itself
|
||||
*/
|
||||
[scratchLayoutManager setTextStorage: scratchTextStorage];
|
||||
|
||||
[scratchTextStorage beginEditing];
|
||||
[scratchTextStorage replaceCharactersInRange: NSMakeRange(0, [scratchTextStorage length])
|
||||
withString: @""];
|
||||
withString: string];
|
||||
if ([string length])
|
||||
{
|
||||
[scratchTextStorage replaceCharactersInRange: NSMakeRange(0, 0)
|
||||
withString: string];
|
||||
[scratchTextStorage setAttributes: attributes
|
||||
range: NSMakeRange(0, [string length])];
|
||||
}
|
||||
[scratchTextStorage endEditing];
|
||||
|
||||
ci = cache_match(hasSize, size, useScreenFonts, &hit);
|
||||
|
||||
if (hit)
|
||||
{
|
||||
return ci;
|
||||
}
|
||||
c = &cache[ci];
|
||||
|
||||
layoutManager = c->layoutManager;
|
||||
textContainer = c->textContainer;
|
||||
|
||||
if (hasSize)
|
||||
[textContainer setContainerSize: NSMakeSize(size.width, LARGE_SIZE)];
|
||||
else
|
||||
[textContainer setContainerSize: NSMakeSize(LARGE_SIZE, LARGE_SIZE)];
|
||||
[layoutManager setUsesScreenFonts: useScreenFonts];
|
||||
|
||||
c->usedRect = [layoutManager usedRectForTextContainer: textContainer];
|
||||
|
||||
return ci;
|
||||
}
|
||||
|
||||
static int cache_lookup_attributed_string(NSAttributedString *string,
|
||||
int hasSize, NSSize size, int useScreenFonts)
|
||||
static inline void prepare_attributed_string(NSAttributedString *string)
|
||||
{
|
||||
[scratchTextStorage replaceCharactersInRange: NSMakeRange(0, [scratchTextStorage length])
|
||||
withAttributedString: string];
|
||||
}
|
||||
|
||||
static int cache_lookup(int hasSize, NSSize size, int useScreenFonts)
|
||||
{
|
||||
cache_t *c;
|
||||
int ci, hit;
|
||||
NSLayoutManager *layoutManager;
|
||||
NSTextContainer *textContainer;
|
||||
|
||||
if (!did_init)
|
||||
init_string_drawing();
|
||||
|
||||
[scratchTextStorage replaceCharactersInRange: NSMakeRange(0, [scratchTextStorage length])
|
||||
withString: @""];
|
||||
[scratchTextStorage replaceCharactersInRange: NSMakeRange(0, 0)
|
||||
withAttributedString: string];
|
||||
|
||||
ci = cache_match(hasSize, size, useScreenFonts, &hit);
|
||||
|
||||
if (hit)
|
||||
{
|
||||
return ci;
|
||||
}
|
||||
|
||||
// Cache miss, need to set up the text system
|
||||
c = &cache[ci];
|
||||
|
||||
layoutManager = c->layoutManager;
|
||||
textContainer = c->textContainer;
|
||||
|
||||
if (hasSize)
|
||||
[textContainer setContainerSize: NSMakeSize(size.width, LARGE_SIZE)];
|
||||
[textContainer setContainerSize: NSMakeSize(size.width, size.height)];
|
||||
else
|
||||
[textContainer setContainerSize: NSMakeSize(LARGE_SIZE, LARGE_SIZE)];
|
||||
[layoutManager setUsesScreenFonts: useScreenFonts];
|
||||
|
@ -364,7 +319,6 @@ static int cache_lookup_attributed_string(NSAttributedString *string,
|
|||
return ci;
|
||||
}
|
||||
|
||||
|
||||
static int use_screen_fonts(void)
|
||||
{
|
||||
NSGraphicsContext *ctxt = GSCurrentContext();
|
||||
|
@ -407,7 +361,8 @@ glyphs to be drawn upside-down, so we need to tell NSFont to flip the fonts.
|
|||
|
||||
NS_DURING
|
||||
{
|
||||
ci = cache_lookup_attributed_string(self, 0, NSZeroSize, use_screen_fonts());
|
||||
prepare_attributed_string(self);
|
||||
ci = cache_lookup(0, NSZeroSize, use_screen_fonts());
|
||||
c = &cache[ci];
|
||||
|
||||
r = NSMakeRange(0, [c->layoutManager numberOfGlyphs]);
|
||||
|
@ -449,6 +404,14 @@ glyphs to be drawn upside-down, so we need to tell NSFont to flip the fonts.
|
|||
|
||||
- (void) drawInRect: (NSRect)rect
|
||||
{
|
||||
[self drawWithRect: rect
|
||||
options: NSStringDrawingUsesLineFragmentOrigin];
|
||||
}
|
||||
|
||||
- (void) drawWithRect: (NSRect)rect
|
||||
options: (NSStringDrawingOptions)options
|
||||
{
|
||||
// FIXME: This ignores options
|
||||
int ci;
|
||||
cache_t *c;
|
||||
|
||||
|
@ -459,12 +422,12 @@ glyphs to be drawn upside-down, so we need to tell NSFont to flip the fonts.
|
|||
if (rect.size.width <= 0 || rect.size.height <= 0)
|
||||
return;
|
||||
|
||||
|
||||
cache_lock();
|
||||
|
||||
NS_DURING
|
||||
{
|
||||
ci = cache_lookup_attributed_string(self, 1, rect.size, use_screen_fonts());
|
||||
prepare_attributed_string(self);
|
||||
ci = cache_lookup(1, rect.size, use_screen_fonts());
|
||||
c = &cache[ci];
|
||||
|
||||
/*
|
||||
|
@ -502,7 +465,6 @@ glyphs to be drawn upside-down, so we need to tell NSFont to flip the fonts.
|
|||
|
||||
[c->layoutManager drawBackgroundForGlyphRange: r
|
||||
atPoint: rect.origin];
|
||||
|
||||
[c->layoutManager drawGlyphsForGlyphRange: r
|
||||
atPoint: rect.origin];
|
||||
}
|
||||
|
@ -527,58 +489,26 @@ glyphs to be drawn upside-down, so we need to tell NSFont to flip the fonts.
|
|||
}
|
||||
}
|
||||
|
||||
- (void) drawWithRect:(NSRect)rect
|
||||
options:(NSStringDrawingOptions)options
|
||||
{
|
||||
// FIXME: This ignores options
|
||||
[self drawInRect: rect];
|
||||
}
|
||||
|
||||
- (NSSize) size
|
||||
{
|
||||
int ci;
|
||||
NSSize result = NSZeroSize;
|
||||
|
||||
cache_lock();
|
||||
NS_DURING
|
||||
{
|
||||
ci = cache_lookup_attributed_string(self, 0, NSZeroSize, 1);
|
||||
/*
|
||||
An argument could be made for using NSMaxX/NSMaxY here, but that fails
|
||||
horribly on right-aligned strings. For now, we handle that case in a
|
||||
useful way and ignore indents.
|
||||
*/
|
||||
|
||||
result = cache[ci].usedRect.size;
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
cache_unlock();
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
cache_unlock();
|
||||
|
||||
return result;
|
||||
NSRect usedRect = [self boundingRectWithSize: NSZeroSize
|
||||
options: NSStringDrawingUsesLineFragmentOrigin];
|
||||
return usedRect.size;
|
||||
}
|
||||
|
||||
- (NSRect) boundingRectWithSize: (NSSize)size
|
||||
options: (NSStringDrawingOptions)options
|
||||
{
|
||||
// FIXME: This ignores options
|
||||
int ci;
|
||||
NSRect result = NSZeroRect;
|
||||
int hasSize = NSEqualSizes(NSZeroSize, size) ? 0 : 1;
|
||||
|
||||
cache_lock();
|
||||
NS_DURING
|
||||
{
|
||||
// FIXME: This ignores options
|
||||
ci = cache_lookup_attributed_string(self, 1, size, 1);
|
||||
/*
|
||||
An argument could be made for using NSMaxX/NSMaxY here, but that fails
|
||||
horribly on right-aligned strings. For now, we handle that case in a
|
||||
useful way and ignore indents.
|
||||
*/
|
||||
|
||||
prepare_attributed_string(self);
|
||||
ci = cache_lookup(hasSize, size, 1);
|
||||
result = cache[ci].usedRect;
|
||||
}
|
||||
NS_HANDLER
|
||||
|
@ -594,10 +524,7 @@ glyphs to be drawn upside-down, so we need to tell NSFont to flip the fonts.
|
|||
|
||||
@end
|
||||
|
||||
/*
|
||||
TODO: It's severely sub-optimal, but the NSString methods just use
|
||||
NSAttributedString to do the job.
|
||||
*/
|
||||
|
||||
@implementation NSString (NSStringDrawing)
|
||||
|
||||
- (void) drawAtPoint: (NSPoint)point withAttributes: (NSDictionary *)attrs
|
||||
|
@ -611,7 +538,8 @@ NSAttributedString to do the job.
|
|||
cache_lock();
|
||||
NS_DURING
|
||||
{
|
||||
ci = cache_lookup_string(self, attrs, 0, NSZeroSize, use_screen_fonts());
|
||||
prepare_string(self, attrs);
|
||||
ci = cache_lookup(0, NSZeroSize, use_screen_fonts());
|
||||
c = &cache[ci];
|
||||
|
||||
r = NSMakeRange(0, [c->layoutManager numberOfGlyphs]);
|
||||
|
@ -632,7 +560,6 @@ NSAttributedString to do the job.
|
|||
|
||||
[c->layoutManager drawBackgroundForGlyphRange: r
|
||||
atPoint: point];
|
||||
|
||||
[c->layoutManager drawGlyphsForGlyphRange: r
|
||||
atPoint: point];
|
||||
}
|
||||
|
@ -653,6 +580,16 @@ NSAttributedString to do the job.
|
|||
|
||||
- (void) drawInRect: (NSRect)rect withAttributes: (NSDictionary *)attrs
|
||||
{
|
||||
[self drawWithRect: rect
|
||||
options: NSStringDrawingUsesLineFragmentOrigin
|
||||
attributes: attrs];
|
||||
}
|
||||
|
||||
- (void) drawWithRect: (NSRect)rect
|
||||
options: (NSStringDrawingOptions)options
|
||||
attributes: (NSDictionary *)attrs
|
||||
{
|
||||
// FIXME: This ignores options
|
||||
int ci;
|
||||
cache_t *c;
|
||||
|
||||
|
@ -666,7 +603,8 @@ NSAttributedString to do the job.
|
|||
cache_lock();
|
||||
NS_DURING
|
||||
{
|
||||
ci = cache_lookup_string(self, attrs, 1, rect.size, use_screen_fonts());
|
||||
prepare_string(self, attrs);
|
||||
ci = cache_lookup(1, rect.size, use_screen_fonts());
|
||||
c = &cache[ci];
|
||||
|
||||
/*
|
||||
|
@ -704,7 +642,6 @@ NSAttributedString to do the job.
|
|||
|
||||
[c->layoutManager drawBackgroundForGlyphRange: r
|
||||
atPoint: rect.origin];
|
||||
|
||||
[c->layoutManager drawGlyphsForGlyphRange: r
|
||||
atPoint: rect.origin];
|
||||
}
|
||||
|
@ -729,60 +666,28 @@ NSAttributedString to do the job.
|
|||
}
|
||||
}
|
||||
|
||||
- (void) drawWithRect: (NSRect)rect
|
||||
options: (NSStringDrawingOptions)options
|
||||
attributes: (NSDictionary *)attributes
|
||||
{
|
||||
// FIXME: This ignores options
|
||||
[self drawInRect: rect withAttributes: attributes];
|
||||
}
|
||||
|
||||
- (NSSize) sizeWithAttributes: (NSDictionary *)attrs
|
||||
{
|
||||
int ci;
|
||||
NSSize result = NSZeroSize;
|
||||
|
||||
cache_lock();
|
||||
NS_DURING
|
||||
{
|
||||
ci = cache_lookup_string(self, attrs, 0, NSZeroSize, 1);
|
||||
/*
|
||||
An argument could be made for using NSMaxX/NSMaxY here, but that fails
|
||||
horribly on right-aligned strings (which may be the right thing). For now,
|
||||
we handle that case in a useful way and ignore indents.
|
||||
*/
|
||||
|
||||
result = cache[ci].usedRect.size;
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
cache_unlock();
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
cache_unlock();
|
||||
|
||||
return result;
|
||||
NSRect usedRect = [self boundingRectWithSize: NSZeroSize
|
||||
options: NSStringDrawingUsesLineFragmentOrigin
|
||||
attributes: attrs];
|
||||
return usedRect.size;
|
||||
}
|
||||
|
||||
- (NSRect) boundingRectWithSize: (NSSize)size
|
||||
options: (NSStringDrawingOptions)options
|
||||
attributes: (NSDictionary *)attributes
|
||||
attributes: (NSDictionary *)attrs
|
||||
{
|
||||
// FIXME: This ignores options
|
||||
int ci;
|
||||
NSRect result = NSZeroRect;
|
||||
int hasSize = NSEqualSizes(NSZeroSize, size) ? 0 : 1;
|
||||
|
||||
cache_lock();
|
||||
NS_DURING
|
||||
{
|
||||
// FIXME: This ignores options
|
||||
ci = cache_lookup_string(self, attributes, 1, size, 1);
|
||||
/*
|
||||
An argument could be made for using NSMaxX/NSMaxY here, but that fails
|
||||
horribly on right-aligned strings (which may be the right thing). For now,
|
||||
we handle that case in a useful way and ignore indents.
|
||||
*/
|
||||
|
||||
prepare_string(self, attrs);
|
||||
ci = cache_lookup(hasSize, size, 1);
|
||||
result = cache[ci].usedRect;
|
||||
}
|
||||
NS_HANDLER
|
||||
|
|
Loading…
Reference in a new issue