More work.
This commit is contained in:
parent
1bd2ca22c2
commit
e32341b24b
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
24
ui_attrstr.h
24
ui_attrstr.h
|
@ -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.)?
|
||||||
|
|
Loading…
Reference in New Issue