More work.
This commit is contained in:
parent
1bd2ca22c2
commit
e32341b24b
|
@ -312,3 +312,20 @@ size_t attrstrUTF16LEn(uiAttributedString *s)
|
|||
{
|
||||
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 struct graphemes *graphemes(void *s, size_t len);
|
||||
|
||||
// TODO split these into a separate header file?
|
||||
|
||||
// attrstr.c
|
||||
extern const uint16_t *attrstrUTF16(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
|
||||
struct attrlist;
|
||||
|
|
|
@ -15,6 +15,8 @@ struct uiDrawTextLayout {
|
|||
CGPathRef path;
|
||||
CTFrameRef frame;
|
||||
CFArrayRef lines;
|
||||
size_t *u16tou8;
|
||||
size_t nu16tou8; // TODO I don't like the casing of this name
|
||||
};
|
||||
|
||||
static CTFontRef fontdescToCTFont(uiDrawFontDescriptor *fd)
|
||||
|
@ -112,11 +114,15 @@ uiDrawTextLayout *uiDrawNewTextLayout(uiAttributedString *s, uiDrawFontDescripto
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
void uiDrawFreeTextLayout(uiDrawTextLayout *tl)
|
||||
{
|
||||
uiFree(tl->u16tou8);
|
||||
// TODO release tl->lines?
|
||||
CFRelease(tl->frame);
|
||||
CFRelease(tl->path);
|
||||
|
@ -174,7 +180,8 @@ void uiDrawTextLayoutLineByteRange(uiDrawTextLayout *tl, int line, size_t *start
|
|||
|
||||
lr = getline(tl, line);
|
||||
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)
|
||||
|
@ -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)
|
||||
|
|
24
ui_attrstr.h
24
ui_attrstr.h
|
@ -87,6 +87,7 @@ struct uiDrawFontDescriptor {
|
|||
|
||||
typedef struct uiDrawTextLayout uiDrawTextLayout;
|
||||
typedef struct uiDrawTextLayoutLineMetrics uiDrawTextLayoutLineMetrics;
|
||||
typedef struct uiDrawTextLayoutHitTestResult uiDrawTextLayoutHitTestResult;
|
||||
typedef struct uiDrawTextLayoutByteRangeRectangle uiDrawTextLayoutByteRangeRectangle;
|
||||
|
||||
struct uiDrawTextLayoutLineMetrics {
|
||||
|
@ -102,10 +103,19 @@ struct uiDrawTextLayoutLineMetrics {
|
|||
// TODO trailing whitespace?
|
||||
};
|
||||
|
||||
_UI_ENUM(uiDrawTextLayoutHitTestResult) {
|
||||
uiDrawTextLayoutHitTestResultNowhere,
|
||||
uiDrawTextLayoutHitTestResultOnLineTrailingWhitespace,
|
||||
uiDrawTextLayoutHitTestResultOnCharacter,
|
||||
_UI_ENUM(uiDrawTextLayoutHitTestPosition) {
|
||||
uiDrawTextLayoutHitTestPositionBefore,
|
||||
uiDrawTextLayoutHitTestPositionInside,
|
||||
uiDrawTextLayoutHitTestPositionAfter,
|
||||
};
|
||||
|
||||
struct uiDrawTextLayoutHitTestResult {
|
||||
size_t Pos;
|
||||
int Line;
|
||||
uiDrawTextLayoutHitTestPosition XPosition;
|
||||
uiDrawTextLayoutHitTestPosition YPosition;
|
||||
int InTrailingWhitespace;
|
||||
double XFraction;
|
||||
};
|
||||
|
||||
struct uiDrawTextLayoutByteRangeRectangle {
|
||||
|
@ -122,6 +132,10 @@ struct uiDrawTextLayoutByteRangeRectangle {
|
|||
// - allow creating a layout out of a substring
|
||||
// - allow marking compositon strings
|
||||
// - 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 void uiDrawFreeTextLayout(uiDrawTextLayout *tl);
|
||||
_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?
|
||||
_UI_EXTERN void uiDrawTextLayoutByteIndexToGraphemeRect(uiDrawTextLayout *tl, size_t pos, int *line, double *x, double *y, double *width, double *height);
|
||||
// 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);
|
||||
// TODO draw only a line?
|
||||
// TODO other layout-specific attributes (alignment, wrapping, etc.)?
|
||||
|
|
Loading…
Reference in New Issue