mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-05-31 19:50:48 +00:00
* Source/GSHorizontalTypesetter.m: Use thread dictionary to hold
the instance of the typesetter for that thread. * Source/NSStringDrawing.m: Add locks to methods to prevent modification of static variables by separate threads from causing the application to get glyph generation errors. NOTE: These changes based on suggestions/ideas from Doug Simons <doug@riverrock.org>. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@28219 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
1162ab09f8
commit
a14429a2df
3 changed files with 328 additions and 183 deletions
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
||||||
|
2009-04-14 21:24-EDT Gregory John Casamento <greg.casamento@gmail.com>
|
||||||
|
|
||||||
|
* Source/GSHorizontalTypesetter.m: Use thread dictionary to hold
|
||||||
|
the instance of the typesetter for that thread.
|
||||||
|
* Source/NSStringDrawing.m: Add locks to methods to prevent modification
|
||||||
|
of static variables by separate threads from causing the application
|
||||||
|
to get glyph generation errors.
|
||||||
|
NOTE: These changes based on suggestions/ideas from Doug
|
||||||
|
Simons <doug@riverrock.org>.
|
||||||
|
|
||||||
2009-04-12 15:16-EDT Gregory John Casamento <greg_casamento@yahoo.com>
|
2009-04-12 15:16-EDT Gregory John Casamento <greg_casamento@yahoo.com>
|
||||||
|
|
||||||
* Source/GSWindowDecorationView.m: initialize offsets to prevent
|
* Source/GSWindowDecorationView.m: initialize offsets to prevent
|
||||||
|
|
|
@ -78,13 +78,22 @@ cache fairly aggressively without having to worry about memory consumption.
|
||||||
|
|
||||||
+(GSHorizontalTypesetter *) sharedInstance
|
+(GSHorizontalTypesetter *) sharedInstance
|
||||||
{
|
{
|
||||||
static GSHorizontalTypesetter *shared;
|
NSMutableDictionary *threadDict =
|
||||||
|
[[NSThread currentThread] threadDictionary];
|
||||||
|
GSHorizontalTypesetter *shared =
|
||||||
|
[threadDict objectForKey: @"sharedHorizontalTypesetter"];
|
||||||
|
|
||||||
if (!shared)
|
if (!shared)
|
||||||
shared = [[self alloc] init];
|
{
|
||||||
|
shared = [[self alloc] init];
|
||||||
|
[threadDict setObject: shared
|
||||||
|
forKey: @"sharedHorizontalTypesetter"];
|
||||||
|
RELEASE(shared);
|
||||||
|
}
|
||||||
|
|
||||||
return shared;
|
return shared;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define CACHE_INITIAL 192
|
#define CACHE_INITIAL 192
|
||||||
#define CACHE_STEP 192
|
#define CACHE_STEP 192
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include <Foundation/NSException.h>
|
#include <Foundation/NSException.h>
|
||||||
|
#include <Foundation/NSLock.h>
|
||||||
|
|
||||||
#include "AppKit/NSAffineTransform.h"
|
#include "AppKit/NSAffineTransform.h"
|
||||||
#include "AppKit/NSLayoutManager.h"
|
#include "AppKit/NSLayoutManager.h"
|
||||||
|
@ -84,10 +85,11 @@ typedef struct
|
||||||
static BOOL did_init;
|
static BOOL did_init;
|
||||||
static cache_t cache[NUM_CACHE_ENTRIES];
|
static cache_t cache[NUM_CACHE_ENTRIES];
|
||||||
|
|
||||||
static NSTextStorage *scratchTextStorage;
|
static NSTextStorage *scratchTextStorage;
|
||||||
static NSLayoutManager *scratchLayoutManager;
|
static NSLayoutManager *scratchLayoutManager;
|
||||||
static NSTextContainer *scratchTextContainer;
|
static NSTextContainer *scratchTextContainer;
|
||||||
|
|
||||||
|
static NSRecursiveLock *cacheLock = nil;
|
||||||
|
|
||||||
static int total, hits, misses, hash_hits;
|
static int total, hits, misses, hash_hits;
|
||||||
|
|
||||||
|
@ -122,7 +124,7 @@ static void init_string_drawing(void)
|
||||||
#ifdef STATS
|
#ifdef STATS
|
||||||
atexit(NSStringDrawing_dump_stats);
|
atexit(NSStringDrawing_dump_stats);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (i = 0; i < NUM_CACHE_ENTRIES + 1; i++)
|
for (i = 0; i < NUM_CACHE_ENTRIES + 1; i++)
|
||||||
{
|
{
|
||||||
textStorage = [[NSTextStorage alloc] init];
|
textStorage = [[NSTextStorage alloc] init];
|
||||||
|
@ -133,7 +135,7 @@ static void init_string_drawing(void)
|
||||||
initWithContainerSize: NSMakeSize(10, 10)];
|
initWithContainerSize: NSMakeSize(10, 10)];
|
||||||
[layoutManager addTextContainer: textContainer];
|
[layoutManager addTextContainer: textContainer];
|
||||||
[textContainer release];
|
[textContainer release];
|
||||||
|
|
||||||
if (i < NUM_CACHE_ENTRIES)
|
if (i < NUM_CACHE_ENTRIES)
|
||||||
{
|
{
|
||||||
cache[i].textStorage = textStorage;
|
cache[i].textStorage = textStorage;
|
||||||
|
@ -149,6 +151,19 @@ static void init_string_drawing(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cache_lock()
|
||||||
|
{
|
||||||
|
if(cacheLock == nil)
|
||||||
|
{
|
||||||
|
cacheLock = [[NSRecursiveLock alloc] init];
|
||||||
|
}
|
||||||
|
[cacheLock lock];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cache_unlock()
|
||||||
|
{
|
||||||
|
[cacheLock unlock];
|
||||||
|
}
|
||||||
|
|
||||||
static int cache_match(int hasSize, NSSize size, int useScreenFonts, int *matched)
|
static int cache_match(int hasSize, NSSize size, int useScreenFonts, int *matched)
|
||||||
{
|
{
|
||||||
|
@ -266,45 +281,46 @@ static int cache_lookup_string(NSString *string, NSDictionary *attributes,
|
||||||
if (!did_init)
|
if (!did_init)
|
||||||
init_string_drawing();
|
init_string_drawing();
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This is a hack, but it's an efficient way of getting the layout manager
|
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
|
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
|
be clever and cache or soft-invalidate anything since the new string has
|
||||||
nothing to do with the old one.
|
nothing to do with the old one.
|
||||||
|
|
||||||
TODO: the layout manager should realize this by itself
|
TODO: the layout manager should realize this by itself
|
||||||
*/
|
*/
|
||||||
[scratchLayoutManager setTextStorage: scratchTextStorage];
|
[scratchLayoutManager setTextStorage: scratchTextStorage];
|
||||||
|
|
||||||
[scratchTextStorage beginEditing];
|
[scratchTextStorage beginEditing];
|
||||||
[scratchTextStorage replaceCharactersInRange: NSMakeRange(0, [scratchTextStorage length])
|
[scratchTextStorage replaceCharactersInRange: NSMakeRange(0, [scratchTextStorage length])
|
||||||
withString: @""];
|
withString: @""];
|
||||||
if ([string length])
|
if ([string length])
|
||||||
{
|
{
|
||||||
[scratchTextStorage replaceCharactersInRange: NSMakeRange(0, 0)
|
[scratchTextStorage replaceCharactersInRange: NSMakeRange(0, 0)
|
||||||
withString: string];
|
withString: string];
|
||||||
[scratchTextStorage setAttributes: attributes
|
[scratchTextStorage setAttributes: attributes
|
||||||
range: NSMakeRange(0, [string length])];
|
range: NSMakeRange(0, [string length])];
|
||||||
}
|
}
|
||||||
[scratchTextStorage endEditing];
|
[scratchTextStorage endEditing];
|
||||||
|
|
||||||
ci = cache_match(hasSize, size, useScreenFonts, &hit);
|
ci = cache_match(hasSize, size, useScreenFonts, &hit);
|
||||||
|
|
||||||
if (hit)
|
if (hit)
|
||||||
return ci;
|
{
|
||||||
|
return ci;
|
||||||
|
}
|
||||||
c = &cache[ci];
|
c = &cache[ci];
|
||||||
|
|
||||||
textStorage = c->textStorage;
|
textStorage = c->textStorage;
|
||||||
layoutManager = c->layoutManager;
|
layoutManager = c->layoutManager;
|
||||||
textContainer = c->textContainer;
|
textContainer = c->textContainer;
|
||||||
|
|
||||||
if (hasSize)
|
if (hasSize)
|
||||||
[textContainer setContainerSize: NSMakeSize(size.width, LARGE_SIZE)];
|
[textContainer setContainerSize: NSMakeSize(size.width, LARGE_SIZE)];
|
||||||
else
|
else
|
||||||
[textContainer setContainerSize: NSMakeSize(LARGE_SIZE, LARGE_SIZE)];
|
[textContainer setContainerSize: NSMakeSize(LARGE_SIZE, LARGE_SIZE)];
|
||||||
[layoutManager setUsesScreenFonts: useScreenFonts];
|
[layoutManager setUsesScreenFonts: useScreenFonts];
|
||||||
|
|
||||||
c->usedRect = [layoutManager usedRectForTextContainer: textContainer];
|
c->usedRect = [layoutManager usedRectForTextContainer: textContainer];
|
||||||
|
|
||||||
return ci;
|
return ci;
|
||||||
|
@ -321,28 +337,31 @@ static int cache_lookup_attributed_string(NSAttributedString *string,
|
||||||
|
|
||||||
if (!did_init)
|
if (!did_init)
|
||||||
init_string_drawing();
|
init_string_drawing();
|
||||||
|
|
||||||
[scratchTextStorage replaceCharactersInRange: NSMakeRange(0, [scratchTextStorage length])
|
[scratchTextStorage replaceCharactersInRange: NSMakeRange(0, [scratchTextStorage length])
|
||||||
withString: @""];
|
withString: @""];
|
||||||
[scratchTextStorage replaceCharactersInRange: NSMakeRange(0, 0)
|
[scratchTextStorage replaceCharactersInRange: NSMakeRange(0, 0)
|
||||||
withAttributedString: string];
|
withAttributedString: string];
|
||||||
|
|
||||||
ci = cache_match(hasSize, size, useScreenFonts, &hit);
|
ci = cache_match(hasSize, size, useScreenFonts, &hit);
|
||||||
|
|
||||||
if (hit)
|
if (hit)
|
||||||
return ci;
|
{
|
||||||
|
return ci;
|
||||||
|
}
|
||||||
|
|
||||||
c = &cache[ci];
|
c = &cache[ci];
|
||||||
|
|
||||||
textStorage = c->textStorage;
|
textStorage = c->textStorage;
|
||||||
layoutManager = c->layoutManager;
|
layoutManager = c->layoutManager;
|
||||||
textContainer = c->textContainer;
|
textContainer = c->textContainer;
|
||||||
|
|
||||||
if (hasSize)
|
if (hasSize)
|
||||||
[textContainer setContainerSize: NSMakeSize(size.width, LARGE_SIZE)];
|
[textContainer setContainerSize: NSMakeSize(size.width, LARGE_SIZE)];
|
||||||
else
|
else
|
||||||
[textContainer setContainerSize: NSMakeSize(LARGE_SIZE, LARGE_SIZE)];
|
[textContainer setContainerSize: NSMakeSize(LARGE_SIZE, LARGE_SIZE)];
|
||||||
[layoutManager setUsesScreenFonts: useScreenFonts];
|
[layoutManager setUsesScreenFonts: useScreenFonts];
|
||||||
|
|
||||||
c->usedRect = [layoutManager usedRectForTextContainer: textContainer];
|
c->usedRect = [layoutManager usedRectForTextContainer: textContainer];
|
||||||
|
|
||||||
return ci;
|
return ci;
|
||||||
|
@ -365,8 +384,6 @@ static int use_screen_fonts(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This is an ugly hack to get text to display correctly in non-flipped views.
|
This is an ugly hack to get text to display correctly in non-flipped views.
|
||||||
|
|
||||||
|
@ -389,30 +406,42 @@ glyphs to be drawn upside-down, so we need to tell NSFont to flip the fonts.
|
||||||
NSRange r;
|
NSRange r;
|
||||||
NSGraphicsContext *ctxt = GSCurrentContext();
|
NSGraphicsContext *ctxt = GSCurrentContext();
|
||||||
|
|
||||||
ci = cache_lookup_attributed_string(self, 0, NSZeroSize, use_screen_fonts());
|
cache_lock();
|
||||||
c = &cache[ci];
|
|
||||||
|
|
||||||
r = NSMakeRange(0, [c->layoutManager numberOfGlyphs]);
|
NS_DURING
|
||||||
|
|
||||||
if (![[NSView focusView] isFlipped])
|
|
||||||
{
|
{
|
||||||
DPSscale(ctxt, 1, -1);
|
ci = cache_lookup_attributed_string(self, 0, NSZeroSize, use_screen_fonts());
|
||||||
point.y = -point.y;
|
c = &cache[ci];
|
||||||
|
|
||||||
/*
|
r = NSMakeRange(0, [c->layoutManager numberOfGlyphs]);
|
||||||
Adjust point.y so the lower left corner of the used rect is at the
|
|
||||||
point that was passed to us.
|
if (![[NSView focusView] isFlipped])
|
||||||
*/
|
{
|
||||||
point.y -= NSMaxY(c->usedRect);
|
DPSscale(ctxt, 1, -1);
|
||||||
|
point.y = -point.y;
|
||||||
[NSFont _setFontFlipHack: YES];
|
|
||||||
|
/*
|
||||||
|
Adjust point.y so the lower left corner of the used rect is at the
|
||||||
|
point that was passed to us.
|
||||||
|
*/
|
||||||
|
point.y -= NSMaxY(c->usedRect);
|
||||||
|
|
||||||
|
[NSFont _setFontFlipHack: YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
[c->layoutManager drawBackgroundForGlyphRange: r
|
||||||
|
atPoint: point];
|
||||||
|
|
||||||
|
[c->layoutManager drawGlyphsForGlyphRange: r
|
||||||
|
atPoint: point];
|
||||||
}
|
}
|
||||||
|
NS_HANDLER
|
||||||
[c->layoutManager drawBackgroundForGlyphRange: r
|
{
|
||||||
atPoint: point];
|
cache_unlock();
|
||||||
|
[localException raise];
|
||||||
[c->layoutManager drawGlyphsForGlyphRange: r
|
}
|
||||||
atPoint: point];
|
NS_ENDHANDLER;
|
||||||
|
cache_unlock();
|
||||||
|
|
||||||
if (![[NSView focusView] isFlipped])
|
if (![[NSView focusView] isFlipped])
|
||||||
{
|
{
|
||||||
|
@ -432,48 +461,61 @@ 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)
|
if (rect.size.width <= 0 || rect.size.height <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
ci = cache_lookup_attributed_string(self, 1, rect.size, use_screen_fonts());
|
cache_lock();
|
||||||
c = &cache[ci];
|
|
||||||
|
|
||||||
/*
|
NS_DURING
|
||||||
If the used rect fits completely in the rect we draw in, we save time
|
|
||||||
by avoiding the DPSrectclip (and the state save and restore).
|
|
||||||
|
|
||||||
This isn't completely safe; the used rect isn't guaranteed to contain
|
|
||||||
all parts of all glyphs.
|
|
||||||
*/
|
|
||||||
if (c->usedRect.origin.x >= 0 && c->usedRect.origin.y <= 0
|
|
||||||
&& NSMaxX(c->usedRect) <= rect.size.width
|
|
||||||
&& NSMaxY(c->usedRect) <= rect.size.height)
|
|
||||||
{
|
{
|
||||||
need_clip = NO;
|
ci = cache_lookup_attributed_string(self, 1, rect.size, use_screen_fonts());
|
||||||
|
c = &cache[ci];
|
||||||
|
|
||||||
|
/*
|
||||||
|
If the used rect fits completely in the rect we draw in, we save time
|
||||||
|
by avoiding the DPSrectclip (and the state save and restore).
|
||||||
|
|
||||||
|
This isn't completely safe; the used rect isn't guaranteed to contain
|
||||||
|
all parts of all glyphs.
|
||||||
|
*/
|
||||||
|
if (c->usedRect.origin.x >= 0 && c->usedRect.origin.y <= 0
|
||||||
|
&& NSMaxX(c->usedRect) <= rect.size.width
|
||||||
|
&& NSMaxY(c->usedRect) <= rect.size.height)
|
||||||
|
{
|
||||||
|
need_clip = NO;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
need_clip = YES;
|
||||||
|
DPSgsave(ctxt);
|
||||||
|
DPSrectclip(ctxt, rect.origin.x, rect.origin.y,
|
||||||
|
rect.size.width, rect.size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = [c->layoutManager
|
||||||
|
glyphRangeForBoundingRect: NSMakeRect(0, 0, rect.size.width,
|
||||||
|
rect.size.height)
|
||||||
|
inTextContainer: c->textContainer];
|
||||||
|
|
||||||
|
if (![[NSView focusView] isFlipped])
|
||||||
|
{
|
||||||
|
DPSscale(ctxt, 1, -1);
|
||||||
|
rect.origin.y = -NSMaxY(rect);
|
||||||
|
[NSFont _setFontFlipHack: YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
[c->layoutManager drawBackgroundForGlyphRange: r
|
||||||
|
atPoint: rect.origin];
|
||||||
|
|
||||||
|
[c->layoutManager drawGlyphsForGlyphRange: r
|
||||||
|
atPoint: rect.origin];
|
||||||
}
|
}
|
||||||
else
|
NS_HANDLER
|
||||||
{
|
{
|
||||||
need_clip = YES;
|
cache_unlock();
|
||||||
DPSgsave(ctxt);
|
[localException raise];
|
||||||
DPSrectclip(ctxt, rect.origin.x, rect.origin.y,
|
|
||||||
rect.size.width, rect.size.height);
|
|
||||||
}
|
}
|
||||||
|
NS_ENDHANDLER;
|
||||||
r = [c->layoutManager
|
cache_unlock();
|
||||||
glyphRangeForBoundingRect: NSMakeRect(0, 0, rect.size.width,
|
|
||||||
rect.size.height)
|
|
||||||
inTextContainer: c->textContainer];
|
|
||||||
|
|
||||||
if (![[NSView focusView] isFlipped])
|
|
||||||
{
|
|
||||||
DPSscale(ctxt, 1, -1);
|
|
||||||
rect.origin.y = -NSMaxY(rect);
|
|
||||||
[NSFont _setFontFlipHack: YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
[c->layoutManager drawBackgroundForGlyphRange: r
|
|
||||||
atPoint: rect.origin];
|
|
||||||
|
|
||||||
[c->layoutManager drawGlyphsForGlyphRange: r
|
|
||||||
atPoint: rect.origin];
|
|
||||||
|
|
||||||
[NSFont _setFontFlipHack: NO];
|
[NSFont _setFontFlipHack: NO];
|
||||||
if (![[NSView focusView] isFlipped])
|
if (![[NSView focusView] isFlipped])
|
||||||
|
@ -498,28 +540,59 @@ glyphs to be drawn upside-down, so we need to tell NSFont to flip the fonts.
|
||||||
- (NSSize) size
|
- (NSSize) size
|
||||||
{
|
{
|
||||||
int ci;
|
int ci;
|
||||||
ci = cache_lookup_attributed_string(self, 0, NSZeroSize, 1);
|
NSSize result;
|
||||||
/*
|
|
||||||
An argument could be made for using NSMaxX/NSMaxY here, but that fails
|
cache_lock();
|
||||||
horribly on right-aligned strings. For now, we handle that case in a
|
NS_DURING
|
||||||
useful way and ignore indents.
|
{
|
||||||
*/
|
ci = cache_lookup_attributed_string(self, 0, NSZeroSize, 1);
|
||||||
return cache[ci].usedRect.size;
|
/*
|
||||||
|
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) boundingRectWithSize: (NSSize)size
|
- (NSRect) boundingRectWithSize: (NSSize)size
|
||||||
options: (NSStringDrawingOptions)options
|
options: (NSStringDrawingOptions)options
|
||||||
{
|
{
|
||||||
int ci;
|
int ci;
|
||||||
|
NSRect result;
|
||||||
|
|
||||||
// FIXME: This ignores options
|
cache_lock();
|
||||||
ci = cache_lookup_attributed_string(self, 1, size, 1);
|
NS_DURING
|
||||||
/*
|
{
|
||||||
An argument could be made for using NSMaxX/NSMaxY here, but that fails
|
// FIXME: This ignores options
|
||||||
horribly on right-aligned strings. For now, we handle that case in a
|
ci = cache_lookup_attributed_string(self, 1, size, 1);
|
||||||
useful way and ignore indents.
|
/*
|
||||||
*/
|
An argument could be made for using NSMaxX/NSMaxY here, but that fails
|
||||||
return cache[ci].usedRect;
|
horribly on right-aligned strings. For now, we handle that case in a
|
||||||
|
useful way and ignore indents.
|
||||||
|
*/
|
||||||
|
|
||||||
|
result = cache[ci].usedRect;
|
||||||
|
}
|
||||||
|
NS_HANDLER
|
||||||
|
{
|
||||||
|
cache_unlock();
|
||||||
|
[localException raise];
|
||||||
|
}
|
||||||
|
NS_ENDHANDLER;
|
||||||
|
cache_unlock();
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -538,30 +611,41 @@ NSAttributedString to do the job.
|
||||||
NSRange r;
|
NSRange r;
|
||||||
NSGraphicsContext *ctxt = GSCurrentContext();
|
NSGraphicsContext *ctxt = GSCurrentContext();
|
||||||
|
|
||||||
ci = cache_lookup_string(self, attrs, 0, NSZeroSize, use_screen_fonts());
|
cache_lock();
|
||||||
c = &cache[ci];
|
NS_DURING
|
||||||
|
|
||||||
r = NSMakeRange(0, [c->layoutManager numberOfGlyphs]);
|
|
||||||
|
|
||||||
if (![[NSView focusView] isFlipped])
|
|
||||||
{
|
{
|
||||||
DPSscale(ctxt, 1, -1);
|
ci = cache_lookup_string(self, attrs, 0, NSZeroSize, use_screen_fonts());
|
||||||
point.y = -point.y;
|
c = &cache[ci];
|
||||||
|
|
||||||
/*
|
r = NSMakeRange(0, [c->layoutManager numberOfGlyphs]);
|
||||||
Adjust point.y so the lower left corner of the used rect is at the
|
|
||||||
point that was passed to us.
|
if (![[NSView focusView] isFlipped])
|
||||||
*/
|
{
|
||||||
point.y -= NSMaxY(c->usedRect);
|
DPSscale(ctxt, 1, -1);
|
||||||
|
point.y = -point.y;
|
||||||
[NSFont _setFontFlipHack: YES];
|
|
||||||
|
/*
|
||||||
|
Adjust point.y so the lower left corner of the used rect is at the
|
||||||
|
point that was passed to us.
|
||||||
|
*/
|
||||||
|
point.y -= NSMaxY(c->usedRect);
|
||||||
|
|
||||||
|
[NSFont _setFontFlipHack: YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
[c->layoutManager drawBackgroundForGlyphRange: r
|
||||||
|
atPoint: point];
|
||||||
|
|
||||||
|
[c->layoutManager drawGlyphsForGlyphRange: r
|
||||||
|
atPoint: point];
|
||||||
}
|
}
|
||||||
|
NS_HANDLER
|
||||||
[c->layoutManager drawBackgroundForGlyphRange: r
|
{
|
||||||
atPoint: point];
|
cache_unlock();
|
||||||
|
[localException raise];
|
||||||
[c->layoutManager drawGlyphsForGlyphRange: r
|
}
|
||||||
atPoint: point];
|
NS_ENDHANDLER;
|
||||||
|
cache_unlock();
|
||||||
|
|
||||||
if (![[NSView focusView] isFlipped])
|
if (![[NSView focusView] isFlipped])
|
||||||
{
|
{
|
||||||
|
@ -581,49 +665,60 @@ NSAttributedString to do the job.
|
||||||
|
|
||||||
if (rect.size.width <= 0 || rect.size.height <= 0)
|
if (rect.size.width <= 0 || rect.size.height <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ci = cache_lookup_string(self, attrs, 1, rect.size, use_screen_fonts());
|
cache_lock();
|
||||||
c = &cache[ci];
|
NS_DURING
|
||||||
|
{
|
||||||
/*
|
ci = cache_lookup_string(self, attrs, 1, rect.size, use_screen_fonts());
|
||||||
If the used rect fits completely in the rect we draw in, we save time
|
c = &cache[ci];
|
||||||
by avoiding the DPSrectclip (and the state save and restore).
|
|
||||||
|
/*
|
||||||
This isn't completely safe; the used rect isn't guaranteed to contain
|
If the used rect fits completely in the rect we draw in, we save time
|
||||||
all parts of all glyphs.
|
by avoiding the DPSrectclip (and the state save and restore).
|
||||||
*/
|
|
||||||
if (c->usedRect.origin.x >= 0 && c->usedRect.origin.y <= 0
|
This isn't completely safe; the used rect isn't guaranteed to contain
|
||||||
&& NSMaxX(c->usedRect) <= rect.size.width
|
all parts of all glyphs.
|
||||||
&& NSMaxY(c->usedRect) <= rect.size.height)
|
*/
|
||||||
{
|
if (c->usedRect.origin.x >= 0 && c->usedRect.origin.y <= 0
|
||||||
need_clip = NO;
|
&& NSMaxX(c->usedRect) <= rect.size.width
|
||||||
|
&& NSMaxY(c->usedRect) <= rect.size.height)
|
||||||
|
{
|
||||||
|
need_clip = NO;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
need_clip = YES;
|
||||||
|
DPSgsave(ctxt);
|
||||||
|
DPSrectclip(ctxt, rect.origin.x, rect.origin.y,
|
||||||
|
rect.size.width, rect.size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = [c->layoutManager
|
||||||
|
glyphRangeForBoundingRect: NSMakeRect(0, 0, rect.size.width,
|
||||||
|
rect.size.height)
|
||||||
|
inTextContainer: c->textContainer];
|
||||||
|
|
||||||
|
if (![[NSView focusView] isFlipped])
|
||||||
|
{
|
||||||
|
DPSscale(ctxt, 1, -1);
|
||||||
|
rect.origin.y = -NSMaxY(rect);
|
||||||
|
[NSFont _setFontFlipHack: YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
[c->layoutManager drawBackgroundForGlyphRange: r
|
||||||
|
atPoint: rect.origin];
|
||||||
|
|
||||||
|
[c->layoutManager drawGlyphsForGlyphRange: r
|
||||||
|
atPoint: rect.origin];
|
||||||
}
|
}
|
||||||
else
|
NS_HANDLER
|
||||||
{
|
{
|
||||||
need_clip = YES;
|
cache_unlock();
|
||||||
DPSgsave(ctxt);
|
[localException raise];
|
||||||
DPSrectclip(ctxt, rect.origin.x, rect.origin.y,
|
|
||||||
rect.size.width, rect.size.height);
|
|
||||||
}
|
}
|
||||||
|
NS_ENDHANDLER;
|
||||||
r = [c->layoutManager
|
cache_unlock();
|
||||||
glyphRangeForBoundingRect: NSMakeRect(0, 0, rect.size.width,
|
|
||||||
rect.size.height)
|
|
||||||
inTextContainer: c->textContainer];
|
|
||||||
|
|
||||||
if (![[NSView focusView] isFlipped])
|
|
||||||
{
|
|
||||||
DPSscale(ctxt, 1, -1);
|
|
||||||
rect.origin.y = -NSMaxY(rect);
|
|
||||||
[NSFont _setFontFlipHack: YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
[c->layoutManager drawBackgroundForGlyphRange: r
|
|
||||||
atPoint: rect.origin];
|
|
||||||
|
|
||||||
[c->layoutManager drawGlyphsForGlyphRange: r
|
|
||||||
atPoint: rect.origin];
|
|
||||||
|
|
||||||
[NSFont _setFontFlipHack: NO];
|
[NSFont _setFontFlipHack: NO];
|
||||||
if (![[NSView focusView] isFlipped])
|
if (![[NSView focusView] isFlipped])
|
||||||
{
|
{
|
||||||
|
@ -648,13 +743,29 @@ NSAttributedString to do the job.
|
||||||
- (NSSize) sizeWithAttributes: (NSDictionary *)attrs
|
- (NSSize) sizeWithAttributes: (NSDictionary *)attrs
|
||||||
{
|
{
|
||||||
int ci;
|
int ci;
|
||||||
ci = cache_lookup_string(self, attrs, 0, NSZeroSize, 1);
|
NSSize result;
|
||||||
/*
|
|
||||||
An argument could be made for using NSMaxX/NSMaxY here, but that fails
|
cache_lock();
|
||||||
horribly on right-aligned strings (which may be the right thing). For now,
|
NS_DURING
|
||||||
we handle that case in a useful way and ignore indents.
|
{
|
||||||
*/
|
ci = cache_lookup_string(self, attrs, 0, NSZeroSize, 1);
|
||||||
return cache[ci].usedRect.size;
|
/*
|
||||||
|
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) boundingRectWithSize: (NSSize)size
|
- (NSRect) boundingRectWithSize: (NSSize)size
|
||||||
|
@ -662,15 +773,30 @@ NSAttributedString to do the job.
|
||||||
attributes: (NSDictionary *)attributes
|
attributes: (NSDictionary *)attributes
|
||||||
{
|
{
|
||||||
int ci;
|
int ci;
|
||||||
|
NSRect result;
|
||||||
|
|
||||||
// FIXME: This ignores options
|
cache_lock();
|
||||||
ci = cache_lookup_string(self, attributes, 1, size, 1);
|
NS_DURING
|
||||||
/*
|
{
|
||||||
An argument could be made for using NSMaxX/NSMaxY here, but that fails
|
// FIXME: This ignores options
|
||||||
horribly on right-aligned strings (which may be the right thing). For now,
|
ci = cache_lookup_string(self, attributes, 1, size, 1);
|
||||||
we handle that case in a useful way and ignore indents.
|
/*
|
||||||
*/
|
An argument could be made for using NSMaxX/NSMaxY here, but that fails
|
||||||
return cache[ci].usedRect;
|
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;
|
||||||
|
}
|
||||||
|
NS_HANDLER
|
||||||
|
{
|
||||||
|
cache_unlock();
|
||||||
|
[localException raise];
|
||||||
|
}
|
||||||
|
NS_ENDHANDLER;
|
||||||
|
cache_unlock();
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue