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:
Alexander Malmberg 2003-01-31 21:08:24 +00:00
parent 8ec1d6751e
commit 3ea5844deb
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>
* Source/GNUmakefile (NSMenuItem.m_FILE_FLAGS): Use -Wno-protocol

View file

@ -203,10 +203,6 @@ subclassing). */
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
necessarily the font specified by NSFontAttributeName; both the typesetter
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
forStartOfGlyphRange: (NSRange)glyphRange;
- (void) setAttachmentSize: (NSSize)attachmentSize
forGlyphRange: (NSRange)glyphRange; /* not OPENSTEP */
- (NSTextContainer *) textContainerForGlyphAtIndex: (unsigned int)glyphIndex
effectiveRange: (NSRange *)effectiveRange;

View file

@ -56,7 +56,7 @@ typedef struct GSLayoutManager_glyph_run_head_s
/* char_length must always be accurate. glyph_length is the number of
valid glyphs counting from the start. For a level 0 head, it's the number
of glyphs in that run. */
int glyph_length,char_length;
int glyph_length, char_length;
/* Glyph generation is complete for all created runs. */
unsigned int complete:1;
@ -135,25 +135,34 @@ typedef struct GSLayoutManager_glyph_run_s
/* All positions and lengths in glyphs */
typedef struct
{
unsigned int pos,length;
unsigned int pos, length;
NSPoint p;
} linefrag_point_t;
typedef struct
{
NSRect rect,used_rect;
unsigned int pos,length;
unsigned int pos, length;
NSSize size;
} linefrag_attachment_t;
typedef struct
{
NSRect rect, used_rect;
unsigned int pos, length;
linefrag_point_t *points;
int num_points;
linefrag_attachment_t *attachments;
int num_attachments;
} linefrag_t;
typedef struct GSLayoutManager_textcontainer_s
{
NSTextContainer *textContainer;
BOOL started,complete;
unsigned int pos,length;
BOOL started, complete;
unsigned int pos, length;
linefrag_t *linefrags;
int num_linefrags;
@ -199,7 +208,7 @@ run, i is the glyph index in the run. */
/* Steps forward to the next glyph. If there is no next glyph, r will be
the last run and i==r->head.glyph_length. */
#define GLYPH_STEP_FORWARD(r,i,pos,cpos) \
#define GLYPH_STEP_FORWARD(r, i, pos, cpos) \
{ \
i++; \
while (i==r->head.glyph_length) \
@ -219,7 +228,7 @@ the last run and i==r->head.glyph_length. */
/* Steps backward to the previous glyph. If there is no previous glyph, r
will be the first glyph and i==-1. */
#define GLYPH_STEP_BACKWARD(r,i,pos,cpos) \
#define GLYPH_STEP_BACKWARD(r, i, pos, cpos) \
{ \
i--; \
while (i<0 && r->prev) \
@ -238,11 +247,11 @@ condition holds. r, i, pos, and cpos must be simple variables. When done, r,
i, pos, and cpos will be set for the first glyph for which the condition
doesn't hold. If there is no such glyph, r is the last run and
i==r->head.glyph_length. */
#define GLYPH_SCAN_FORWARD(r,i,pos,cpos,condition) \
#define GLYPH_SCAN_FORWARD(r, i, pos, cpos, condition) \
{ \
while (condition) \
{ \
GLYPH_STEP_FORWARD(r,i,pos,cpos) \
GLYPH_STEP_FORWARD(r, i, pos, cpos) \
if (i==r->head.glyph_length) \
break; \
} \
@ -251,18 +260,18 @@ i==r->head.glyph_length. */
/* Scan backward. r, i, pos, and cpos will be set to the first glyph for
which condition doesn't hold. If there is no such glyph, r is the first run
and i==-1. */
#define GLYPH_SCAN_BACKWARD(r,i,pos,cpos,condition) \
#define GLYPH_SCAN_BACKWARD(r, i, pos, cpos, condition) \
{ \
while (condition) \
{ \
GLYPH_STEP_BACKWARD(r,i,pos,cpos) \
GLYPH_STEP_BACKWARD(r, i, pos, cpos) \
if (i==-1) \
break; \
} \
}
glyph_run_t *GSLayoutManager_run_for_glyph_index(unsigned int glyphIndex,
glyph_run_head_t *glyphs,unsigned int *glyph_pos,unsigned int *char_pos);
glyph_run_head_t *glyphs, unsigned int *glyph_pos, unsigned int *char_pos);
#define run_for_glyph_index GSLayoutManager_run_for_glyph_index
#endif

View file

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

View file

@ -72,12 +72,47 @@ enum {
- (void)highlight:(BOOL)flag
withFrame:(NSRect)cellFrame
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;
/* 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;
- (NSRect)cellFrameForTextContainer:(NSTextContainer *)textContainer
proposedLineFragment:(NSRect)lineFrag
glyphPosition:(NSPoint)position
characterIndex:(unsigned)charIndex;
/** 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
proposedLineFragment: (NSRect)lineFrag
glyphPosition: (NSPoint)position
characterIndex: (unsigned int)charIndex;
- (BOOL)wantsToTrackMouse;
- (BOOL)wantsToTrackMouseForEvent:(NSEvent *)theEvent
inRect:(NSRect)cellFrame

View file

@ -36,8 +36,15 @@
#include "AppKit/NSTextStorage.h"
#include "AppKit/NSParagraphStyle.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
@ -69,6 +76,7 @@ static GSHorizontalTypesetter *shared;
typedef struct GSHorizontalTypesetter_glyph_cache_s
{
/* These fields are filled in by the caching: */
NSGlyph g;
int char_index;
@ -81,9 +89,10 @@ typedef struct GSHorizontalTypesetter_glyph_cache_s
int superscript;
} attributes;
/* These fields are filled in during layout: */
BOOL nominal;
NSPoint pos; /* relative to the baseline */
float width;
NSPoint pos; /* relative to the line's baseline */
NSSize size; /* height is used only for attachments */
BOOL dont_show, outside_line_frag;
} glyph_cache_t;
@ -242,11 +251,11 @@ been cached.
if (gi > 0)
{
g->pos = g[-1].pos;
g->pos.x += g[-1].width;
g->pos.x += g[-1].size.width;
}
else
g->pos = NSMakePoint(0,0);
g->width = 0;
g->size.width = 0;
return gi + 1 + cache_base;
}
gi--;
@ -339,8 +348,28 @@ typedef struct
-(int) layoutLineNewParagraph: (BOOL)newParagraph
{
NSRect rect,remain;
float line_height,max_line_height,baseline;
NSRect rect, remain;
/* 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;
int num_line_frags = 0;
@ -352,6 +381,7 @@ typedef struct
if (!cache_length && at_end)
return 2;
/* Set up our initial baseline info. */
{
float min = [curParagraphStyle minimumLineHeight];
max_line_height = [curParagraphStyle maximumLineHeight];
@ -361,7 +391,13 @@ typedef struct
max_line_height = min;
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)
line_height = min;
@ -370,8 +406,23 @@ typedef struct
}
/* 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
line frag rects, so we can't reuse much of the layout information. */
start over. The increased line height might give _completely_ different
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:
// 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]);
}
/*
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;
if (line_frags)
{
@ -424,25 +483,42 @@ restart:
return 1;
}
{
unsigned int i = 0;
NSFont *f = cache->font;
glyph_cache_t *g;
NSPoint p;
NSFont *f = cache->font;
float f_ascender = [f ascender], f_descender = [f descender];
NSGlyph last_glyph = NSNullGlyph;
NSPoint last_p,p;
NSPoint last_p;
unsigned int first_glyph;
line_frag_t *lf = line_frags;
int lfi = 0;
BOOL prev_was_attachment;
last_p = p = NSMakePoint(0,0);
g = cache;
first_glyph = 0;
prev_was_attachment = NO;
/*
Main glyph layout loop.
*/
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 (at_end)
@ -452,61 +528,203 @@ restart:
break;
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)
{
float new_height;
float new_height, new_ascender, new_descender;
f = g->font;
f_ascender = [f ascender];
f_descender = [f descender];
last_glyph = NSNullGlyph;
new_height = [f defaultLineHeightForFont];
if (max_line_height > 0 && new_height > max_line_height)
new_height = max_line_height;
if (new_height > line_height)
{
line_height = new_height;
baseline = ([cache->font ascender] + [cache->font descender] + line_height) / 2.0;
goto restart;
}
new_ascender = [f ascender];
new_descender = [f descender];
if (new_ascender > ascender)
ascender = new_ascender;
if (new_descender > descender)
descender = new_descender;
COMPUTE_BASELINE;
WANT_LINE_HEIGHT(new_height);
}
if (g->g == NSControlGlyph)
{
unichar ch = [[curTextStorage string] characterAtIndex: g->char_index];
/* TODO: need to handle other control characters */
g->pos = p;
g->width = 0;
g->size.width = 0;
g->dont_show = YES;
g->nominal = YES;
g->nominal = !prev_was_attachment;
i++;
g++;
last_glyph = NSNullGlyph;
prev_was_attachment = NO;
if (ch == 0xa)
break;
continue;
}
g->nominal = YES;
if (g->attributes.explicit_kern)
p.x += g->attributes.kern;
/* TODO: this is a major bottleneck */
/* else if (last_glyph)
/* 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 = [f positionOfGlyph: g->g
precededByGlyph: last_glyph
isNominal: &g->nominal];
p.x += last_p.x;
p.y += last_p.y;
}*/
p.x += g->attributes.kern;
g->nominal = NO;
}
/* Baseline adjustments. */
{
float y = 0;
last_p = g->pos = p;
g->width = [f advancementForGlyph: g->g].width;
p.x += g->width;
/* 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 */
/* if (last_glyph)
{
p = [f positionOfGlyph: g->g
precededByGlyph: last_glyph
isNominal: &g->nominal];
p.x += last_p.x;
p.y += last_p.y;
}*/
last_p = g->pos = p;
g->size = [f advancementForGlyph: g->g]; /* only width is used */
p.x += g->size.width;
}
/* Did the glyph fit in the line frag rect? */
if (p.x > lf->rect.size.width)
{
/* It didn't. Try to break the line. */
switch ([curParagraphStyle lineBreakMode])
{
{ /* TODO: implement all modes */
default:
case NSLineBreakByCharWrapping:
char_wrapping:
@ -521,8 +739,8 @@ restart:
}
/* We force at least one glyph into each line frag rect. This
ensures that typesetting will never get stuck (ie. if the text
container is to narrow to fit even a single glyph). */
ensures that typesetting will never get stuck (ie. if the text
container is to narrow to fit even a single glyph). */
if (lf->last_glyph <= first_glyph)
lf->last_glyph = i + 1;
@ -530,23 +748,37 @@ restart:
i = lf->last_glyph;
g = cache + i;
/* The -1 is always valid since there's at least one glyph in the
line frag rect (see above). */
lf->last_used = g[-1].pos.x + g[-1].width;
line frag rect (see above). */
lf->last_used = g[-1].pos.x + g[-1].size.width;
last_glyph = NSNullGlyph;
prev_was_attachment = NO;
lf++;
lfi++;
if (lfi == num_line_frags)
break;
first_glyph = i;
goto relayout;
}
last_glyph = g->g;
i++;
g++;
else
{
/* Move to next glyph. */
last_glyph = g->g;
if (last_glyph == GSAttachmentGlyph)
{
last_glyph = NSNullGlyph;
prev_was_attachment = YES;
}
else
{
prev_was_attachment = NO;
}
i++;
g++;
}
}
/* Basic layout is done. */
/* Take care of the alignments. */
if (lfi != num_line_frags)
{
lf->last_glyph = i;
@ -574,17 +806,18 @@ restart:
newParagraph = NO;
}
/* Layout is complete. Package it and give it to the layout manager. */
[curLayoutManager setTextContainer: curTextContainer
forGlyphRange: NSMakeRange(cache_base,i)];
forGlyphRange: NSMakeRange(cache_base, i)];
curGlyph = i + cache_base;
{
line_frag_t *lf;
NSPoint p;
unsigned int i,j;
unsigned int i, j;
glyph_cache_t *g;
NSRect used_rect;
for (lf = line_frags,i = 0,g = cache;lfi >= 0;lfi--,lf++)
for (lf = line_frags, i = 0, g = cache; lfi >= 0; lfi--, lf++)
{
used_rect.origin.x = g->pos.x + lf->rect.origin.x;
used_rect.size.width = lf->last_used - g->pos.x;
@ -596,6 +829,7 @@ restart:
forGlyphRange: NSMakeRange(cache_base + i,lf->last_glyph - i)
usedRect: used_rect];
p = g->pos;
/* TODO: probably don't need to call unless the flags are YES */
[curLayoutManager setDrawsOutsideLineFragment: g->outside_line_frag
forGlyphAtIndex: cache_base + i];
[curLayoutManager setNotShownAttribute: g->dont_show
@ -607,7 +841,12 @@ restart:
if (!g->nominal && i != j)
{
[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.y += baseline;
j = i;
@ -619,6 +858,11 @@ restart:
{
[curLayoutManager setLocation: p
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;
}
/* if we're really at the end, we should probably set the extra line frag
stuff here */
/* TODO: if we're really at the end, we should probably set the extra
line frag stuff here */
if (newParagraph)
return 3;
else

View file

@ -1257,13 +1257,6 @@ it should still be safe. might lose opportunities to merge runs, though.
return 0;
}
-(void) setAttachmentSize: (NSSize)size
forGlyphRange: (NSRange)range
{
NSLog(@"%s not implemented yet", __PRETTY_FUNCTION__);
/* TODO!! */
}
@end
@ -1287,8 +1280,13 @@ it should still be safe. might lose opportunities to merge runs, though.
if (tc->linefrags)
{
for (j = 0, lf = tc->linefrags; j < tc->num_linefrags; j++, lf++)
if (lf->points)
free(lf->points);
{
if (lf->points)
free(lf->points);
if (lf->attachments)
free(lf->attachments);
}
free(tc->linefrags);
}
tc->linefrags = NULL;
@ -1653,6 +1651,53 @@ forStartOfGlyphRange: (NSRange)glyphRange
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

View file

@ -697,6 +697,9 @@ container */
linefrag_t *lf;
linefrag_point_t *lp;
linefrag_attachment_t *la;
int la_i;
NSPoint p;
unsigned int g;
@ -715,6 +718,8 @@ container */
int gbuf_len;
NSPoint gbuf_point;
NSView *controlView = nil;
if (!range.length)
return;
@ -741,6 +746,9 @@ container */
return;
}
la = lf->attachments;
la_i = 0;
j = 0;
lp = lf->points;
while (lp->pos + lp->length < range.location)
@ -784,6 +792,8 @@ container */
lf++;
j = 0;
lp = lf->points;
la = lf->attachments;
la_i = 0;
}
p = lp->p;
p.x += lf->rect.origin.x + containerOrigin.x;
@ -827,6 +837,58 @@ container */
}
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 (!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);
DPSnewpath(ctxt);
}
#undef GBUF_SIZE
}

View file

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