More work.

This commit is contained in:
Pietro Gagliardi 2017-01-07 20:09:44 -05:00
parent 1bd2ca22c2
commit e32341b24b
4 changed files with 137 additions and 7 deletions

View File

@ -312,3 +312,20 @@ size_t attrstrUTF16LEn(uiAttributedString *s)
{ {
return s->u16len; return s->u16len;
} }
size_t attrstrUTF8ToUTF16(uiAttributedString *s, size_t n)
{
return s->u8tou16[n];
}
size_t *attrstrCopyUTF16ToUTF8(uiAttributedString *s, size_t *n)
{
size_t *out;
size_t nbytes;
nbytes = (s->u16len + 1) * sizeof (size_t);
*n = s->u16len;
out = (size_t *) uiAlloc(nbytes, "size_t[] (uiAttributedString)");
memmove(out, s->u16tou8, nbytes);
return out;
}

View File

@ -64,9 +64,13 @@ struct graphemes {
extern int graphemesTakesUTF16(void); extern int graphemesTakesUTF16(void);
extern struct graphemes *graphemes(void *s, size_t len); extern struct graphemes *graphemes(void *s, size_t len);
// TODO split these into a separate header file?
// attrstr.c // attrstr.c
extern const uint16_t *attrstrUTF16(uiAttributedString *s); extern const uint16_t *attrstrUTF16(uiAttributedString *s);
extern size_t attrstrUTF16LEn(uiAttributedString *s); extern size_t attrstrUTF16LEn(uiAttributedString *s);
extern size_t attrstrUTF8ToUTF16(uiAttributedString *s, size_t n);
extern size_t *attrstrCopyUTF16ToUTF8(uiAttributedString *s, size_t *n);
// attrlist.c // attrlist.c
struct attrlist; struct attrlist;

View File

@ -15,6 +15,8 @@ struct uiDrawTextLayout {
CGPathRef path; CGPathRef path;
CTFrameRef frame; CTFrameRef frame;
CFArrayRef lines; CFArrayRef lines;
size_t *u16tou8;
size_t nu16tou8; // TODO I don't like the casing of this name
}; };
static CTFontRef fontdescToCTFont(uiDrawFontDescriptor *fd) static CTFontRef fontdescToCTFont(uiDrawFontDescriptor *fd)
@ -112,11 +114,15 @@ uiDrawTextLayout *uiDrawNewTextLayout(uiAttributedString *s, uiDrawFontDescripto
tl->lines = CTFrameGetLines(tl->frame); tl->lines = CTFrameGetLines(tl->frame);
// and finally copy the UTF-16 to UTF-8 index conversion table
tl->u16tou8 = attrstrCopyUTF16ToUTF8(s, &(tl->nu16tou8));
return tl; return tl;
} }
void uiDrawFreeTextLayout(uiDrawTextLayout *tl) void uiDrawFreeTextLayout(uiDrawTextLayout *tl)
{ {
uiFree(tl->u16tou8);
// TODO release tl->lines? // TODO release tl->lines?
CFRelease(tl->frame); CFRelease(tl->frame);
CFRelease(tl->path); CFRelease(tl->path);
@ -174,7 +180,8 @@ void uiDrawTextLayoutLineByteRange(uiDrawTextLayout *tl, int line, size_t *start
lr = getline(tl, line); lr = getline(tl, line);
range = CTLineGetStringRange(lr); range = CTLineGetStringRange(lr);
// TODO set start and end *start = tl->u16tou8[range.location];
*end = tl->u16tou8[range.location + range.length];
} }
void uiDrawTextLayoutLineGetMetrics(uiDrawTextLayout *tl, int line, uiDrawTextLayoutLineMetrics *m) void uiDrawTextLayoutLineGetMetrics(uiDrawTextLayout *tl, int line, uiDrawTextLayoutLineMetrics *m)
@ -203,8 +210,96 @@ void uiDrawTextLayoutByteIndexToGraphemeRect(uiDrawTextLayout *tl, size_t pos, i
{ {
} }
uiDrawTextLayoutHitTestResult uiDrawTextLayoutHitTest(uiDrawTextLayout *tl, double x, double y, size_t *byteIndex, int *line) static CGPoint *mkLineOrigins(uiDrawTextLayout *tl)
{ {
CGPoint *origins;
CFRange range;
CFIndex i, n;
CTLine line;
CGFloat ascent;
n = CFArrayGetCount(tl->lines);
range.location = 0;
range.length = n;
origins = (CGPoint *) uiAlloc(n * sizeof (CGPoint), "CGPoint[]");
CTFrameGetLineOrigins(tl->frame, range, origins);
for (i = 0; i < n; i++) {
line = getline(tl, i);
CTLineGetTypographicBounds(line, &ascent, NULL, NULL);
origins[i].y = tl->size.height - (origins[i].y + ascent);
}
return origins;
}
void uiDrawTextLayoutHitTest(uiDrawTextLayout *tl, double x, double y, uiDrawTextLayoutHitTestResult *result)
{
CGPoint *mkLineOrigins;
CFIndex i, n;
CTLineRef line;
double firstYForLine;
CGFloat width, NULL, descent, leading;
CFRange range;
n = CFArrayGetCount(tl->lines);
if (n == 0) {
// TODO fill result
return;
}
origins = mkLineOrigins(tl);
if (y < 0) {
line = getline(tl, 0);
width = CTLineGetTypographicBounds(line, NULL, NULL, NULL);
i = 0;
} else {
firstYForLine = 0;
for (i = 0; i < n; i++) {
line = getline(tl, i);
width = CTLineGetTypographicBounds(line, NULL, &descent, &leading);
if (y < maxYForLine)
break;
firstYForLine = origins[i].y + descent + leading;
}
}
if (i == n) {
i--;
result->Line = i;
result->YPosition = uiDrawTextLayoutHitTestPositionAfter;
} else {
result->Line = i;
result->YPosition = uiDrawTextLayoutHitTestPositionInside;
if (i == 0 && y < 0)
result->YPosition = uiDrawTextLayoutHitTestPositionBefore;
}
result->InTrailingWhitespace = 0;
range = CTLineGetStringRange(line);
if (x < 0) {
result->Start = tl->u16tou8[range.location];
result->End = result->Start;
result->XPosition = uiDrawTextLayoutHitTestPositionBefore;
} else if (x > tl->size.width) {
result->Start = tl->u16tou8[range.location + range.length];
result->End = result->Start;
result->XPosition = uiDrawTextLayoutHitTestPositionAfter;
} else {
CGPoint pos;
CFIndex index;
result->XPosition = uiDrawTextLa
youtHitTestPositionInside;
pos.x = x;
// TODO this isn't set properly in any of the fast-track cases
pos.y = y - firstYForLine;
index = CTLineGetStringIn
dexForPosition(line, pos);
if (index == kCFNotFound) {
// TODO
}
result->Pos = tl->u16tou8[index];
// TODO compute the fractional offset
result->InTrailingWhitespace = x < origins[i].x || x >= (origins[i].x + width);
}
uiFree(origins);
} }
void uiDrawTextLayoutByteRangeToRectangle(uiDrawTextLayout *tl, size_t start, size_t end, uiDrawTextLayoutByteRangeRectangle *r) void uiDrawTextLayoutByteRangeToRectangle(uiDrawTextLayout *tl, size_t start, size_t end, uiDrawTextLayoutByteRangeRectangle *r)

View File

@ -87,6 +87,7 @@ struct uiDrawFontDescriptor {
typedef struct uiDrawTextLayout uiDrawTextLayout; typedef struct uiDrawTextLayout uiDrawTextLayout;
typedef struct uiDrawTextLayoutLineMetrics uiDrawTextLayoutLineMetrics; typedef struct uiDrawTextLayoutLineMetrics uiDrawTextLayoutLineMetrics;
typedef struct uiDrawTextLayoutHitTestResult uiDrawTextLayoutHitTestResult;
typedef struct uiDrawTextLayoutByteRangeRectangle uiDrawTextLayoutByteRangeRectangle; typedef struct uiDrawTextLayoutByteRangeRectangle uiDrawTextLayoutByteRangeRectangle;
struct uiDrawTextLayoutLineMetrics { struct uiDrawTextLayoutLineMetrics {
@ -102,10 +103,19 @@ struct uiDrawTextLayoutLineMetrics {
// TODO trailing whitespace? // TODO trailing whitespace?
}; };
_UI_ENUM(uiDrawTextLayoutHitTestResult) { _UI_ENUM(uiDrawTextLayoutHitTestPosition) {
uiDrawTextLayoutHitTestResultNowhere, uiDrawTextLayoutHitTestPositionBefore,
uiDrawTextLayoutHitTestResultOnLineTrailingWhitespace, uiDrawTextLayoutHitTestPositionInside,
uiDrawTextLayoutHitTestResultOnCharacter, uiDrawTextLayoutHitTestPositionAfter,
};
struct uiDrawTextLayoutHitTestResult {
size_t Pos;
int Line;
uiDrawTextLayoutHitTestPosition XPosition;
uiDrawTextLayoutHitTestPosition YPosition;
int InTrailingWhitespace;
double XFraction;
}; };
struct uiDrawTextLayoutByteRangeRectangle { struct uiDrawTextLayoutByteRangeRectangle {
@ -122,6 +132,10 @@ struct uiDrawTextLayoutByteRangeRectangle {
// - allow creating a layout out of a substring // - allow creating a layout out of a substring
// - allow marking compositon strings // - allow marking compositon strings
// - allow marking selections, even after creation // - allow marking selections, even after creation
// - add the following functions:
// - uiDrawTextLayoutHeightForWidth() (returns the height that a layout would need to be to display the entire string at a given width)
// - uiDrawTextLayoutRangeForSize() (returns what substring would fit in a given size)
// - uiDrawTextLayoutNewWithHeight() (limits amount of string used by the height)
_UI_EXTERN uiDrawTextLayout *uiDrawNewTextLayout(uiAttributedString *s, uiDrawFontDescriptor *defaultFont, double width); _UI_EXTERN uiDrawTextLayout *uiDrawNewTextLayout(uiAttributedString *s, uiDrawFontDescriptor *defaultFont, double width);
_UI_EXTERN void uiDrawFreeTextLayout(uiDrawTextLayout *tl); _UI_EXTERN void uiDrawFreeTextLayout(uiDrawTextLayout *tl);
_UI_EXTERN void uiDrawText(uiDrawContext *c, uiDrawTextLayout *tl, double x, double y); _UI_EXTERN void uiDrawText(uiDrawContext *c, uiDrawTextLayout *tl, double x, double y);
@ -132,7 +146,7 @@ _UI_EXTERN void uiDrawTextLayoutLineGetMetrics(uiDrawTextLayout *tl, int line, u
// TODO redo this? remove it entirely? // TODO redo this? remove it entirely?
_UI_EXTERN void uiDrawTextLayoutByteIndexToGraphemeRect(uiDrawTextLayout *tl, size_t pos, int *line, double *x, double *y, double *width, double *height); _UI_EXTERN void uiDrawTextLayoutByteIndexToGraphemeRect(uiDrawTextLayout *tl, size_t pos, int *line, double *x, double *y, double *width, double *height);
// TODO partial offset? // TODO partial offset?
_UI_EXTERN uiDrawTextLayoutHitTestResult uiDrawTextLayoutHitTest(uiDrawTextLayout *tl, double x, double y, size_t *byteIndex, int *line); _UI_EXTERN void uiDrawTextLayoutHitTest(uiDrawTextLayout *tl, double x, double y, uiDrawTextLayoutHitTestResult *result);
_UI_EXTERN void uiDrawTextLayoutByteRangeToRectangle(uiDrawTextLayout *tl, size_t start, size_t end, uiDrawTextLayoutByteRangeRectangle *r); _UI_EXTERN void uiDrawTextLayoutByteRangeToRectangle(uiDrawTextLayout *tl, size_t start, size_t end, uiDrawTextLayoutByteRangeRectangle *r);
// TODO draw only a line? // TODO draw only a line?
// TODO other layout-specific attributes (alignment, wrapping, etc.)? // TODO other layout-specific attributes (alignment, wrapping, etc.)?