172 lines
6.5 KiB
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);
|