Implement text attachment handling.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@15825 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
alexm 2003-01-31 21:08:24 +00:00
parent 36aea1c23d
commit 132c6dc661
9 changed files with 503 additions and 85 deletions

View file

@ -1,3 +1,26 @@
2003-01-31 21:59 Alexander Malmberg <alexander@malmberg.org>
* Headers/gnustep/gui/GSLayoutManager.h,
Headers/gnustep/gui/GSLayoutManager_internal.h,
Source/GSLayoutManager.m: Implement [GSLayoutManager
-setAttachmentSize:forGlyphRange:].
* Source/NSLayoutManager.m (-drawGlyphsForGlyphRange:atPoint:):
Implement drawing of attachments.
* Headers/gnustep/gui/NSFont.h: Add GSAttachmentGlyph to mark
attachments in a glyph context.
* Source/GSHorizontalLayoutManager.m: Cleanups and comments.
(-layoutLineNewParagraph:): Rewrite line height and baseline
handling. Implement typesetting of attachments.
* Headers/gnustep/gui/NSTextAttachment.h: Add documentation.
* Source/NSTextAttachment.m (-cellFrameForTextContainer:
proposedLineFragment:glyphPosition:characterIndex:): Return the
correct position.
Thu Jan 30 16:31:16 2003 Nicola Pero <n.pero@mi.flashnet.it> Thu Jan 30 16:31:16 2003 Nicola Pero <n.pero@mi.flashnet.it>
* Source/GNUmakefile (NSMenuItem.m_FILE_FLAGS): Use -Wno-protocol * Source/GNUmakefile (NSMenuItem.m_FILE_FLAGS): Use -Wno-protocol

View file

@ -203,10 +203,6 @@ subclassing). */
forGlyphAtIndex: (unsigned int)glyphIndex; forGlyphAtIndex: (unsigned int)glyphIndex;
- (void) setAttachmentSize: (NSSize)attachmentSize
forGlyphRange: (NSRange)glyphRange; /* not OPENSTEP */
/* Returns the font actually used for a range of glyphs. This isn't /* Returns the font actually used for a range of glyphs. This isn't
necessarily the font specified by NSFontAttributeName; both the typesetter necessarily the font specified by NSFontAttributeName; both the typesetter
and the layout manager can substitute a different font (the typesetter might and the layout manager can substitute a different font (the typesetter might
@ -258,6 +254,9 @@ manager might be substituting screen fonts. */
- (void) setLocation: (NSPoint)location - (void) setLocation: (NSPoint)location
forStartOfGlyphRange: (NSRange)glyphRange; forStartOfGlyphRange: (NSRange)glyphRange;
- (void) setAttachmentSize: (NSSize)attachmentSize
forGlyphRange: (NSRange)glyphRange; /* not OPENSTEP */
- (NSTextContainer *) textContainerForGlyphAtIndex: (unsigned int)glyphIndex - (NSTextContainer *) textContainerForGlyphAtIndex: (unsigned int)glyphIndex
effectiveRange: (NSRange *)effectiveRange; effectiveRange: (NSRange *)effectiveRange;

View file

@ -139,6 +139,12 @@ typedef struct
NSPoint p; NSPoint p;
} linefrag_point_t; } linefrag_point_t;
typedef struct
{
unsigned int pos, length;
NSSize size;
} linefrag_attachment_t;
typedef struct typedef struct
{ {
NSRect rect, used_rect; NSRect rect, used_rect;
@ -146,6 +152,9 @@ typedef struct
linefrag_point_t *points; linefrag_point_t *points;
int num_points; int num_points;
linefrag_attachment_t *attachments;
int num_attachments;
} linefrag_t; } linefrag_t;
typedef struct GSLayoutManager_textcontainer_s typedef struct GSLayoutManager_textcontainer_s

View file

@ -41,6 +41,7 @@ typedef unsigned int NSGlyph;
enum { enum {
NSControlGlyph = 0x00ffffff, NSControlGlyph = 0x00ffffff,
GSAttachmentGlyph = 0x00fffffe,
NSNullGlyph = 0x0 NSNullGlyph = 0x0
}; };

View file

@ -72,12 +72,47 @@ enum {
- (void)highlight:(BOOL)flag - (void)highlight:(BOOL)flag
withFrame:(NSRect)cellFrame withFrame:(NSRect)cellFrame
inView:(NSView *)controlView; inView:(NSView *)controlView;
/** The old way of placing the cell. The text system will never call
these directly (TODO: make sure it doesn't), but other things might. The
class implements the new method by calling these, so subclasses can
easily change behavior by overriding these. **/
- (NSSize)cellSize; - (NSSize)cellSize;
/* Returns the offset from the current point when typesetting to the lower
left corner of the cell. The class returns (0,0). Positive y is probably
up. (TODO) */
- (NSPoint)cellBaselineOffset; - (NSPoint)cellBaselineOffset;
/** The new way of placing the cell. **/
/* Returns the rectangle in which the cell should be drawn. The rectangle
is relative to the current point when typesetting. Positive y is probably
up. (TODO)
lineFrag is the line frag rect that this cell might be placed in, and
position is the current position in that line frag rect (positive y is
probably down (TODO)). Note that the line frag rect and glyph position
may not be where the cell is actually placed.
Note that this might be called many times for the same attachment. Eg. if
you return a rectangle that won't fit in the proposed line frag rect, the
typesetter might try to adjust things so it will fit. It will then send
this message with a new proposed line frag rect and glyph position. Thus,
great care must be taken when using the line frag rect to calculate the
returned rectangle to prevent the typesetting process from getting stuck.
The class uses -cellSize and -cellBaselineOffset to return a rect.
*/
-(NSRect) cellFrameForTextContainer: (NSTextContainer *)textContainer -(NSRect) cellFrameForTextContainer: (NSTextContainer *)textContainer
proposedLineFragment: (NSRect)lineFrag proposedLineFragment: (NSRect)lineFrag
glyphPosition: (NSPoint)position glyphPosition: (NSPoint)position
characterIndex:(unsigned)charIndex; characterIndex: (unsigned int)charIndex;
- (BOOL)wantsToTrackMouse; - (BOOL)wantsToTrackMouse;
- (BOOL)wantsToTrackMouseForEvent:(NSEvent *)theEvent - (BOOL)wantsToTrackMouseForEvent:(NSEvent *)theEvent
inRect:(NSRect)cellFrame inRect:(NSRect)cellFrame

View file

@ -36,8 +36,15 @@
#include "AppKit/NSTextStorage.h" #include "AppKit/NSTextStorage.h"
#include "AppKit/NSParagraphStyle.h" #include "AppKit/NSParagraphStyle.h"
#include "AppKit/NSTextContainer.h" #include "AppKit/NSTextContainer.h"
#include "AppKit/NSTextAttachment.h"
/*
Note that unless the user creates extra instances, there will only be one
instance of GSHorizontalTypesetter for all text typesetting, so we can
cache fairly aggressively without having to worry about memory consumption.
*/
@implementation GSHorizontalTypesetter @implementation GSHorizontalTypesetter
@ -69,6 +76,7 @@ static GSHorizontalTypesetter *shared;
typedef struct GSHorizontalTypesetter_glyph_cache_s typedef struct GSHorizontalTypesetter_glyph_cache_s
{ {
/* These fields are filled in by the caching: */
NSGlyph g; NSGlyph g;
int char_index; int char_index;
@ -81,9 +89,10 @@ typedef struct GSHorizontalTypesetter_glyph_cache_s
int superscript; int superscript;
} attributes; } attributes;
/* These fields are filled in during layout: */
BOOL nominal; BOOL nominal;
NSPoint pos; /* relative to the baseline */ NSPoint pos; /* relative to the line's baseline */
float width; NSSize size; /* height is used only for attachments */
BOOL dont_show, outside_line_frag; BOOL dont_show, outside_line_frag;
} glyph_cache_t; } glyph_cache_t;
@ -242,11 +251,11 @@ been cached.
if (gi > 0) if (gi > 0)
{ {
g->pos = g[-1].pos; g->pos = g[-1].pos;
g->pos.x += g[-1].width; g->pos.x += g[-1].size.width;
} }
else else
g->pos = NSMakePoint(0,0); g->pos = NSMakePoint(0,0);
g->width = 0; g->size.width = 0;
return gi + 1 + cache_base; return gi + 1 + cache_base;
} }
gi--; gi--;
@ -340,7 +349,27 @@ typedef struct
-(int) layoutLineNewParagraph: (BOOL)newParagraph -(int) layoutLineNewParagraph: (BOOL)newParagraph
{ {
NSRect rect, remain; NSRect rect, remain;
float line_height,max_line_height,baseline;
/* Baseline and line height handling. */
float line_height; /* Current line height. */
float max_line_height; /* Maximum line height (usually from the paragraph style). */
float baseline; /* Baseline position (0 is top of line-height, positive is down). */
float ascender; /* Amount of space we want above the baseline (always>=0). */
float descender; /* Amount of space we want below the baseline (always>=0). */
/*
These are values for the line as a whole. We start out by initializing
for the first glyph on the line and then update these as we add more
glyphs.
If we need to increase the line height, we jump back to 'restart:' and
rebuild our array of line frag rects.
(TODO (optimization): if we're dealing with a "simple rectangular
text container", we should try to extend the existing line frag in place
before jumping back to do all the expensive checking).
Normally, baseline==ascender.
*/
line_frag_t *line_frags = NULL; line_frag_t *line_frags = NULL;
int num_line_frags = 0; int num_line_frags = 0;
@ -352,6 +381,7 @@ typedef struct
if (!cache_length && at_end) if (!cache_length && at_end)
return 2; return 2;
/* Set up our initial baseline info. */
{ {
float min = [curParagraphStyle minimumLineHeight]; float min = [curParagraphStyle minimumLineHeight];
max_line_height = [curParagraphStyle maximumLineHeight]; max_line_height = [curParagraphStyle maximumLineHeight];
@ -361,7 +391,13 @@ typedef struct
max_line_height = min; max_line_height = min;
line_height = [cache->font defaultLineHeightForFont]; line_height = [cache->font defaultLineHeightForFont];
baseline = ([cache->font ascender] + [cache->font descender] + line_height) / 2.0; ascender = [cache->font ascender];
descender = [cache->font descender];
#define COMPUTE_BASELINE baseline = ascender
COMPUTE_BASELINE;
if (line_height < min) if (line_height < min)
line_height = min; line_height = min;
@ -371,7 +407,22 @@ typedef struct
/* If we find out that we need to increase the line height, we have to /* If we find out that we need to increase the line height, we have to
start over. The increased line height might give _completely_ different start over. The increased line height might give _completely_ different
line frag rects, so we can't reuse much of the layout information. */ line frag rects, so we can't reuse the layout information. */
#define WANT_LINE_HEIGHT(h) \
do { \
float __new_height = (h); \
if (max_line_height > 0 && __new_height > max_line_height) \
__new_height = max_line_height; \
if (__new_height > line_height) \
{ \
line_height = __new_height; \
COMPUTE_BASELINE; \
goto restart; \
} \
} while (0)
restart: restart:
// printf("start: at (%g %g) line_height = %g, baseline = %g\n",curPoint.x,curPoint.y,line_height,baseline); // printf("start: at (%g %g) line_height = %g, baseline = %g\n",curPoint.x,curPoint.y,line_height,baseline);
{ {
@ -391,6 +442,14 @@ restart:
line_height + [curParagraphStyle lineSpacing]); line_height + [curParagraphStyle lineSpacing]);
} }
/*
Build a list of all line frag rects for this line.
TODO: it's very convenient to do this in advance, but it might be
inefficient, and in theory, we might end up with an insane number of line
rects (eg. a text container with "hole"-columns every 100 points and
width 1e8)
*/
num_line_frags = 0; num_line_frags = 0;
if (line_frags) if (line_frags)
{ {
@ -424,25 +483,42 @@ restart:
return 1; return 1;
} }
{ {
unsigned int i = 0; unsigned int i = 0;
NSFont *f = cache->font;
glyph_cache_t *g; glyph_cache_t *g;
NSPoint p;
NSFont *f = cache->font;
float f_ascender = [f ascender], f_descender = [f descender];
NSGlyph last_glyph = NSNullGlyph; NSGlyph last_glyph = NSNullGlyph;
NSPoint last_p,p; NSPoint last_p;
unsigned int first_glyph; unsigned int first_glyph;
line_frag_t *lf = line_frags; line_frag_t *lf = line_frags;
int lfi = 0; int lfi = 0;
BOOL prev_was_attachment;
last_p = p = NSMakePoint(0,0); last_p = p = NSMakePoint(0,0);
g = cache; g = cache;
first_glyph = 0; first_glyph = 0;
prev_was_attachment = NO;
/*
Main glyph layout loop.
*/
while (1) while (1)
{ {
relayout: /*printf("at %3i+%2i, glyph %08x, char %04x (%i)\n",
cache_base,i,
g->g,
[[curTextStorage string] characterAtIndex: g->char_index],g->char_index);*/
/* Update the cache. */
if (i >= cache_length) if (i >= cache_length)
{ {
if (at_end) if (at_end)
@ -452,45 +528,184 @@ restart:
break; break;
g = cache + i; g = cache + i;
} }
/*
At this point:
p is the current point (sortof); the point where a nominally
spaced glyph would be placed.
g is the current glyph. i is the current glyph index, relative to
the start of the cache.
last_p and last_glyph are used for kerning and hold the previous
glyph and its position. If there's no previous glyph (for kerning
purposes), last_glyph is NSNullGlyph and last_p is undefined.
lf and lfi track the current line frag rect. first_glyph is the
first glyph in the current line frag rect.
Note that the variables tracking the previous glyph shouldn't be
updated until we know that the current glyph will fit in the line
frag rect.
*/
/* If there's a font change, check if the baseline or line height
needs adjusting. We update the ascender and descender too, even
though there might not actually be any glyphs for this font.
(TODO?) */
if (g->font != f) if (g->font != f)
{ {
float new_height; float new_height, new_ascender, new_descender;
f = g->font; f = g->font;
f_ascender = [f ascender];
f_descender = [f descender];
last_glyph = NSNullGlyph; last_glyph = NSNullGlyph;
new_height = [f defaultLineHeightForFont]; new_height = [f defaultLineHeightForFont];
if (max_line_height > 0 && new_height > max_line_height) new_ascender = [f ascender];
new_height = max_line_height; new_descender = [f descender];
if (new_height > line_height)
{ if (new_ascender > ascender)
line_height = new_height; ascender = new_ascender;
baseline = ([cache->font ascender] + [cache->font descender] + line_height) / 2.0; if (new_descender > descender)
goto restart; descender = new_descender;
}
COMPUTE_BASELINE;
WANT_LINE_HEIGHT(new_height);
} }
if (g->g == NSControlGlyph) if (g->g == NSControlGlyph)
{ {
unichar ch = [[curTextStorage string] characterAtIndex: g->char_index]; unichar ch = [[curTextStorage string] characterAtIndex: g->char_index];
/* TODO: need to handle other control characters */
g->pos = p; g->pos = p;
g->width = 0; g->size.width = 0;
g->dont_show = YES; g->dont_show = YES;
g->nominal = YES; g->nominal = !prev_was_attachment;
i++; i++;
g++; g++;
last_glyph = NSNullGlyph; last_glyph = NSNullGlyph;
prev_was_attachment = NO;
if (ch == 0xa) if (ch == 0xa)
break; break;
continue; continue;
} }
g->nominal = YES;
if (g->attributes.explicit_kern) /* Set up glyph information. */
/*
TODO:
Currently, the attributes of the attachment character (eg. font)
affect the layout. Think hard about this.
*/
g->nominal = !prev_was_attachment;
if (g->attributes.explicit_kern &&
g->attributes.kern != 0)
{
p.x += g->attributes.kern; p.x += g->attributes.kern;
g->nominal = NO;
}
/* Baseline adjustments. */
{
float y = 0;
/* Attributes are up-side-down in our coordinate system. */
if (g->attributes.superscript)
{
y -= g->attributes.superscript * [f xHeight];
}
if (g->attributes.baseline_offset)
{
y -= g->attributes.baseline_offset;
}
if (y != p.y)
{
p.y = y;
g->nominal = NO;
}
/* The y==0 case is taken care of when the font is changed. */
if (y < 0 && f_ascender - y > ascender)
ascender = f_ascender - y;
if (y > 0 && f_descender + y > descender)
descender = f_descender + y;
COMPUTE_BASELINE;
WANT_LINE_HEIGHT(ascender + descender);
}
if (g->g == GSAttachmentGlyph)
{
NSTextAttachment *attach = [curTextStorage attribute: NSAttachmentAttributeName
atIndex: g->char_index
effectiveRange: NULL];
NSTextAttachmentCell *cell = [attach attachmentCell];
NSRect r;
if (!cell)
{
g->pos = p;
g->size = NSMakeSize(0,0);
g->dont_show = YES;
g->nominal = YES;
i++;
g++;
last_glyph = NSNullGlyph;
continue;
}
r = [cell cellFrameForTextContainer: curTextContainer
proposedLineFragment: lf->rect
glyphPosition: p
characterIndex: g->char_index];
printf("cell at %i, (%g %g) in (%g %g)+(%g %g), got rect (%g %g)+(%g %g)\n",
g->char_index,p.x,p.y,
lf->rect.origin.x,lf->rect.origin.y,
lf->rect.size.width,lf->rect.size.height,
r.origin.x,r.origin.y,
r.size.width,r.size.height);
/* For some obscure reason, the rectangle we get is up-side-down
compared to everything else here, and has it's origin in p.
(Makes sense from the cell's pov, though.) */
if (-NSMinY(r) > descender)
descender = -NSMinY(r);
if (NSMaxY(r) > ascender)
ascender = NSMaxY(r);
/* Update ascender and descender. Adjust line height and
baseline if necessary. */
COMPUTE_BASELINE;
WANT_LINE_HEIGHT(ascender + descender);
g->size = r.size;
g->pos.x = p.x + r.origin.x;
g->pos.y = p.y + r.origin.y;
p.x = g->pos.x + g->size.width;
/* An attachment is always in a point range of its own. */
g->nominal = NO;
}
else
{
/* TODO: this is a major bottleneck */ /* TODO: this is a major bottleneck */
/* else if (last_glyph) /* if (last_glyph)
{ {
p = [f positionOfGlyph: g->g p = [f positionOfGlyph: g->g
precededByGlyph: last_glyph precededByGlyph: last_glyph
@ -499,14 +714,17 @@ restart:
p.y += last_p.y; p.y += last_p.y;
}*/ }*/
last_p = g->pos = p; last_p = g->pos = p;
g->width = [f advancementForGlyph: g->g].width; g->size = [f advancementForGlyph: g->g]; /* only width is used */
p.x += g->width; p.x += g->size.width;
}
/* Did the glyph fit in the line frag rect? */
if (p.x > lf->rect.size.width) if (p.x > lf->rect.size.width)
{ {
/* It didn't. Try to break the line. */
switch ([curParagraphStyle lineBreakMode]) switch ([curParagraphStyle lineBreakMode])
{ { /* TODO: implement all modes */
default: default:
case NSLineBreakByCharWrapping: case NSLineBreakByCharWrapping:
char_wrapping: char_wrapping:
@ -531,22 +749,36 @@ restart:
g = cache + i; g = cache + i;
/* The -1 is always valid since there's at least one glyph in the /* The -1 is always valid since there's at least one glyph in the
line frag rect (see above). */ line frag rect (see above). */
lf->last_used = g[-1].pos.x + g[-1].width; lf->last_used = g[-1].pos.x + g[-1].size.width;
last_glyph = NSNullGlyph; last_glyph = NSNullGlyph;
prev_was_attachment = NO;
lf++; lf++;
lfi++; lfi++;
if (lfi == num_line_frags) if (lfi == num_line_frags)
break; break;
first_glyph = i; first_glyph = i;
goto relayout;
} }
else
{
/* Move to next glyph. */
last_glyph = g->g; last_glyph = g->g;
if (last_glyph == GSAttachmentGlyph)
{
last_glyph = NSNullGlyph;
prev_was_attachment = YES;
}
else
{
prev_was_attachment = NO;
}
i++; i++;
g++; g++;
} }
}
/* Basic layout is done. */
/* Take care of the alignments. */
if (lfi != num_line_frags) if (lfi != num_line_frags)
{ {
lf->last_glyph = i; lf->last_glyph = i;
@ -574,6 +806,7 @@ restart:
newParagraph = NO; newParagraph = NO;
} }
/* Layout is complete. Package it and give it to the layout manager. */
[curLayoutManager setTextContainer: curTextContainer [curLayoutManager setTextContainer: curTextContainer
forGlyphRange: NSMakeRange(cache_base, i)]; forGlyphRange: NSMakeRange(cache_base, i)];
curGlyph = i + cache_base; curGlyph = i + cache_base;
@ -596,6 +829,7 @@ restart:
forGlyphRange: NSMakeRange(cache_base + i,lf->last_glyph - i) forGlyphRange: NSMakeRange(cache_base + i,lf->last_glyph - i)
usedRect: used_rect]; usedRect: used_rect];
p = g->pos; p = g->pos;
/* TODO: probably don't need to call unless the flags are YES */
[curLayoutManager setDrawsOutsideLineFragment: g->outside_line_frag [curLayoutManager setDrawsOutsideLineFragment: g->outside_line_frag
forGlyphAtIndex: cache_base + i]; forGlyphAtIndex: cache_base + i];
[curLayoutManager setNotShownAttribute: g->dont_show [curLayoutManager setNotShownAttribute: g->dont_show
@ -608,6 +842,11 @@ restart:
{ {
[curLayoutManager setLocation: p [curLayoutManager setLocation: p
forStartOfGlyphRange: NSMakeRange(cache_base + j, i - j)]; forStartOfGlyphRange: NSMakeRange(cache_base + j, i - j)];
if (g[-1].g == GSAttachmentGlyph)
{
[curLayoutManager setAttachmentSize: g[-1].size
forGlyphRange: NSMakeRange(cache_base + j, i - j)];
}
p = g->pos; p = g->pos;
p.y += baseline; p.y += baseline;
j = i; j = i;
@ -619,6 +858,11 @@ restart:
{ {
[curLayoutManager setLocation: p [curLayoutManager setLocation: p
forStartOfGlyphRange: NSMakeRange(cache_base + j,i - j)]; forStartOfGlyphRange: NSMakeRange(cache_base + j,i - j)];
if (g[-1].g == GSAttachmentGlyph)
{
[curLayoutManager setAttachmentSize: g[-1].size
forGlyphRange: NSMakeRange(cache_base + j, i - j)];
}
} }
} }
} }
@ -632,8 +876,8 @@ restart:
line_frags = NULL; line_frags = NULL;
} }
/* if we're really at the end, we should probably set the extra line frag /* TODO: if we're really at the end, we should probably set the extra
stuff here */ line frag stuff here */
if (newParagraph) if (newParagraph)
return 3; return 3;
else else

View file

@ -1257,13 +1257,6 @@ it should still be safe. might lose opportunities to merge runs, though.
return 0; return 0;
} }
-(void) setAttachmentSize: (NSSize)size
forGlyphRange: (NSRange)range
{
NSLog(@"%s not implemented yet", __PRETTY_FUNCTION__);
/* TODO!! */
}
@end @end
@ -1287,8 +1280,13 @@ it should still be safe. might lose opportunities to merge runs, though.
if (tc->linefrags) if (tc->linefrags)
{ {
for (j = 0, lf = tc->linefrags; j < tc->num_linefrags; j++, lf++) for (j = 0, lf = tc->linefrags; j < tc->num_linefrags; j++, lf++)
{
if (lf->points) if (lf->points)
free(lf->points); free(lf->points);
if (lf->attachments)
free(lf->attachments);
}
free(tc->linefrags); free(tc->linefrags);
} }
tc->linefrags = NULL; tc->linefrags = NULL;
@ -1653,6 +1651,53 @@ forStartOfGlyphRange: (NSRange)glyphRange
layout_char = [self characterIndexForGlyphAtIndex: layout_glyph]; layout_char = [self characterIndexForGlyphAtIndex: layout_glyph];
} }
-(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)
{
NSLog(@"%s: text container not set for range", __PRETTY_FUNCTION__);
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)
{
NSLog(@"%s: line fragment rect not set for range", __PRETTY_FUNCTION__);
return;
}
/* TODO: we do no sanity checking of attachment size ranges. might want
to consider doing it */
lf->attachments = realloc(lf->attachments,
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;
}
#undef SETUP_STUFF #undef SETUP_STUFF

View file

@ -697,6 +697,9 @@ container */
linefrag_t *lf; linefrag_t *lf;
linefrag_point_t *lp; linefrag_point_t *lp;
linefrag_attachment_t *la;
int la_i;
NSPoint p; NSPoint p;
unsigned int g; unsigned int g;
@ -715,6 +718,8 @@ container */
int gbuf_len; int gbuf_len;
NSPoint gbuf_point; NSPoint gbuf_point;
NSView *controlView = nil;
if (!range.length) if (!range.length)
return; return;
@ -741,6 +746,9 @@ container */
return; return;
} }
la = lf->attachments;
la_i = 0;
j = 0; j = 0;
lp = lf->points; lp = lf->points;
while (lp->pos + lp->length < range.location) while (lp->pos + lp->length < range.location)
@ -784,6 +792,8 @@ container */
lf++; lf++;
j = 0; j = 0;
lp = lf->points; lp = lf->points;
la = lf->attachments;
la_i = 0;
} }
p = lp->p; p = lp->p;
p.x += lf->rect.origin.x + containerOrigin.x; p.x += lf->rect.origin.x + containerOrigin.x;
@ -827,6 +837,58 @@ container */
} }
if (!glyph->isNotShown && glyph->g && glyph->g != NSControlGlyph) if (!glyph->isNotShown && glyph->g && glyph->g != NSControlGlyph)
{ {
if (glyph->g == GSAttachmentGlyph)
{
/* Silently ignore if we don't have any size information for
it. */
if (g >= range.location && la)
{
unsigned int char_index =
[self characterRangeForGlyphRange: NSMakeRange(g,1)
actualGlyphRange: NULL].location;
NSObject<NSTextAttachmentCell> *cell = [[_textStorage attribute: NSAttachmentAttributeName
atIndex: char_index
effectiveRange: NULL] attachmentCell];
NSRect cellFrame;
if (!controlView)
controlView = [tc->textContainer textView];
while (la->pos != g && la_i < lf->num_attachments)
{
la++;
la_i++;
}
if (la_i >= lf->num_attachments)
continue;
cellFrame.origin = p;
cellFrame.size = la->size;
cellFrame.origin.y -= cellFrame.size.height;
/* Drawing the cell might mess up our state. */
/* TODO:
optimize this. probably cheaper to not save and
explicitly reset just the stuff we actually use, or to
collect attachments and draw them in bunches of eg. 4
should they really be drawn in our coordinate system?
*/
[cell drawWithFrame: cellFrame
inView: controlView
characterIndex: char_index
layoutManager: self];
[f set];
if (color)
[color set];
else
{
DPSsetgray(ctxt, 0.0);
DPSsetalpha(ctxt, 1.0);
}
}
continue;
}
if (g >= range.location) if (g >= range.location)
{ {
if (!gbuf_len) if (!gbuf_len)
@ -860,6 +922,7 @@ for (i = 0; i < gbuf_len; i++) printf(" %3i : %04x\n", i, gbuf[i]); */
GSShowGlyphs(ctxt, gbuf, gbuf_len); GSShowGlyphs(ctxt, gbuf, gbuf_len);
DPSnewpath(ctxt); DPSnewpath(ctxt);
} }
#undef GBUF_SIZE #undef GBUF_SIZE
} }

View file

@ -75,8 +75,7 @@
{ {
NSRect aRect; NSRect aRect;
// FIXME: We ignore the proposedLineFragment aRect.origin = [self cellBaselineOffset];
aRect.origin = position;
aRect.size = [self cellSize]; aRect.size = [self cellSize];
return aRect; return aRect;
} }