libui/_wip/attrstr_metrics/textDarwinEmptyLayout.diff

172 lines
6.5 KiB
Diff

diff --git a/darwin/attrstr.m b/darwin/attrstr.m
index fd45ec25..86039fad 100644
--- a/darwin/attrstr.m
+++ b/darwin/attrstr.m
@@ -403,8 +403,13 @@ static CTParagraphStyleRef mkParagraphStyle(uiDrawTextLayoutParams *p)
return ps;
}
-CFAttributedStringRef attrstrToCoreFoundation(uiDrawTextLayoutParams *p, NSArray **backgroundBlocks)
+static const UniChar emptyChars[] = { 0x20, 0x0 };
+static const CFIndex emptyCharCount = 1;
+
+CFAttributedStringRef attrstrToCoreFoundation(uiDrawTextLayoutParams *p, BOOL *isEmpty, NSArray **backgroundBlocks)
{
+ const UniChar *chars;
+ CFIndex charCount;
CFStringRef cfstr;
CFMutableDictionaryRef defaultAttrs;
CTFontRef defaultCTFont;
@@ -413,7 +418,15 @@ CFAttributedStringRef attrstrToCoreFoundation(uiDrawTextLayoutParams *p, NSArray
CFMutableAttributedStringRef mas;
struct foreachParams fep;
- cfstr = CFStringCreateWithCharacters(NULL, attrstrUTF16(p->String), attrstrUTF16Len(p->String));
+ *isEmpty = NO;
+ chars = attrstrUTF16(p->String);
+ charCount = attrstrUTF16Len(p->String);
+ if (charCount == 0) {
+ *isEmpty = YES;
+ chars = emptyChars;
+ charCount = emptyCharCount;
+ }
+ cfstr = CFStringCreateWithCharacters(NULL, chars, charCount);
if (cfstr == NULL) {
// TODO
}
diff --git a/darwin/drawtext.m b/darwin/drawtext.m
index 1fa5920e..65912383 100644
--- a/darwin/drawtext.m
+++ b/darwin/drawtext.m
@@ -2,13 +2,16 @@
#import "uipriv_darwin.h"
#import "draw.h"
-// TODO on an empty string nLines == 0
-// we must prevent this somehow
-// TODO in general, every function could be more robust, but we cannot have a situation where there are zero lines
+// TODO in general, every function could be more robust
// TODO what happens to extents if only whitespace?
+// TODO for empty layouts:
+// - check if alignment correct compared to other OSs, or expected behavior at all
+// - double-check if uiAttributedString allows zero-length attributes; I forget if I did
struct uiDrawTextLayout {
CFAttributedStringRef attrstr;
+ // this is needed because Core Text will give us an empty line array on a frame made with an empty string
+ BOOL isEmpty;
// the width as passed into uiDrawTextLayout constructors
double width;
@@ -41,7 +44,7 @@
};
// TODO document that lines may or may not overlap because ours do in the case of multiple combining characters
-static uiDrawTextLayoutLineMetrics *computeLineMetrics(CTFrameRef frame, CGSize size)
+static uiDrawTextLayoutLineMetrics *computeLineMetrics(CTFrameRef frame, CGSize size, BOOL isEmpty)
{
uiDrawTextLayoutLineMetrics *metrics;
CFArrayRef lines;
@@ -79,6 +82,8 @@
metrics[i].X = origins[i].x;
metrics[i].Y = origins[i].y - descent - leading;
metrics[i].Width = bounds.size.width;
+ if (isEmpty)
+ metrics[i].Width = 0;
metrics[i].Height = ascent + descent + leading;
metrics[i].BaselineY = origins[i].y;
@@ -117,7 +122,7 @@
CGRect rect;
tl = uiNew(uiDrawTextLayout);
- tl->attrstr = attrstrToCoreFoundation(p, &(tl->backgroundBlocks));
+ tl->attrstr = attrstrToCoreFoundation(p, &(tl->isEmpty), &(tl->backgroundBlocks));
range.location = 0;
range.length = CFAttributedStringGetLength(tl->attrstr);
tl->width = p->Width;
@@ -152,7 +157,7 @@
tl->lines = CTFrameGetLines(tl->frame);
tl->nLines = CFArrayGetCount(tl->lines);
- tl->lineMetrics = computeLineMetrics(tl->frame, tl->size);
+ tl->lineMetrics = computeLineMetrics(tl->frame, tl->size, tl->isEmpty);
// and finally copy the UTF-8/UTF-16 conversion tables
tl->u8tou16 = attrstrCopyUTF8ToUTF16(p->String, &(tl->nUTF8));
@@ -180,6 +185,9 @@ void uiDrawText(uiDrawContext *c, uiDrawTextLayout *tl, double x, double y)
backgroundBlock b;
CGAffineTransform textMatrix;
+ if (tl->isEmpty)
+ return;
+
CGContextSaveGState(c->c);
// save the text matrix because it's not part of the graphics state
textMatrix = CGContextGetTextMatrix(c->c);
@@ -216,6 +224,8 @@ void uiDrawText(uiDrawContext *c, uiDrawTextLayout *tl, double x, double y)
void uiDrawTextLayoutExtents(uiDrawTextLayout *tl, double *width, double *height)
{
*width = tl->size.width;
+ if (tl->isEmpty)
+ *width = 0;
*height = tl->size.height;
}
@@ -233,6 +243,8 @@ void uiDrawTextLayoutLineByteRange(uiDrawTextLayout *tl, int line, size_t *start
range = CTLineGetStringRange(lr);
*start = tl->u16tou8[range.location];
*end = tl->u16tou8[range.location + range.length];
+ if (tl->isEmpty)
+ *start = *end;
}
void uiDrawTextLayoutLineGetMetrics(uiDrawTextLayout *tl, int line, uiDrawTextLayoutLineMetrics *m)
@@ -262,14 +274,17 @@ void uiDrawTextLayoutHitTest(uiDrawTextLayout *tl, double x, double y, size_t *p
*line = i;
ln = (CTLineRef) CFArrayGetValueAtIndex(tl->lines, i);
- // note: according to the docs, we pass a y of 0 for this since the is the baseline of that line (the point is relative to the line)
- // note: x is relative to the line origin
x -= tl->lineMetrics[*line].X;
- p = CTLineGetStringIndexForPosition(ln, CGPointMake(x, 0));
- if (p == kCFNotFound) {
- // TODO
+ *pos = 0;
+ if (!tl->isEmpty) {
+ // note: according to the docs, we pass a y of 0 for this since the is the baseline of that line (the point is relative to the line)
+ // note: x is relative to the line origin
+ p = CTLineGetStringIndexForPosition(ln, CGPointMake(x, 0));
+ if (p == kCFNotFound) {
+ // TODO
+ }
+ *pos = tl->u16tou8[p];
}
- *pos = tl->u16tou8[p];
}
double uiDrawTextLayoutByteLocationInLine(uiDrawTextLayout *tl, size_t pos, int line)
@@ -282,6 +297,9 @@ void uiDrawTextLayoutHitTest(uiDrawTextLayout *tl, double x, double y, size_t *p
return -1;
lr = (CTLineRef) CFArrayGetValueAtIndex(tl->lines, line);
range = CTLineGetStringRange(lr);
+ // TODO is the behavior of this part correct?
+ if (tl->isEmpty)
+ range.length = 0;
// note: >, not >=, because the position at end is valid!
if (pos < range.location || pos > (range.location + range.length))
return -1;
diff --git a/darwin/uipriv_darwin.h b/darwin/uipriv_darwin.h
index 0303c32c..d44ee410 100644
--- a/darwin/uipriv_darwin.h
+++ b/darwin/uipriv_darwin.h
@@ -151,7 +151,7 @@ extern void fontdescFromCTFontDescriptor(CTFontDescriptorRef ctdesc, uiDrawFontD
extern void initUnderlineColors(void);
extern void uninitUnderlineColors(void);
typedef void (^backgroundBlock)(uiDrawContext *c, uiDrawTextLayout *layout, double x, double y);
-extern CFAttributedStringRef attrstrToCoreFoundation(uiDrawTextLayoutParams *p, NSArray **backgroundBlocks);
+extern CFAttributedStringRef attrstrToCoreFoundation(uiDrawTextLayoutParams *p, BOOL *isEmpty, NSArray **backgroundBlocks);
// aat.m
typedef void (^aatBlock)(uint16_t type, uint16_t selector);