From d44c20c4a122f44b1e51dc8fae91933013893d3c Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sat, 4 Nov 2017 16:48:02 -0400 Subject: [PATCH] Stashed diffs for fixing empty text layouts on OS X; the code is now utterly complicated AND my memory of what I did so far on this branch is starting to fail. --- textDarwinEmptyLayout.diff | 171 +++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 textDarwinEmptyLayout.diff diff --git a/textDarwinEmptyLayout.diff b/textDarwinEmptyLayout.diff new file mode 100644 index 00000000..bff4959f --- /dev/null +++ b/textDarwinEmptyLayout.diff @@ -0,0 +1,171 @@ +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);