diff --git a/common/drawtext.c b/common/drawtext.c index 3e657a7d..938e1aeb 100644 --- a/common/drawtext.c +++ b/common/drawtext.c @@ -68,13 +68,14 @@ void drawTextBackground(uiDrawContext *c, double x, double y, uiDrawTextLayout * double startx, endx; uiDrawPath *path; + uiDrawTextLayoutLineByteRange(layout, line, &lstart, &lend); if (lend > end) // don't cross lines lend = end; - startx = uiDrawTextLayoutByteLocationInLine(layout, line, start); + startx = uiDrawTextLayoutByteLocationInLine(layout, start, line); // TODO explain this; note the use of start with lend endx = layoutwid; if (!isSelection || end <= lend) - endx = uiDrawTextLayoutByteLocationInLine(layout, line, lend); + endx = uiDrawTextLayoutByteLocationInLine(layout, lend, line); uiDrawTextLayoutLineGetMetrics(layout, line, &m); path = uiDrawNewPath(uiDrawFillModeWinding); uiDrawPathAddRectangle(path, diff --git a/darwin/attrstr.m b/darwin/attrstr.m index e5d3c84e..c383ab59 100644 --- a/darwin/attrstr.m +++ b/darwin/attrstr.m @@ -9,6 +9,7 @@ struct foreachParams { CFMutableAttributedStringRef mas; NSMutableDictionary *converted; uiDrawFontDescriptor *defaultFont; + NSMutableArray *backgroundBlocks; }; static void ensureFontInRange(struct foreachParams *p, size_t start, size_t end) @@ -40,6 +41,20 @@ static void adjustFontInRange(struct foreachParams *p, size_t start, size_t end, } } +static backgroundBlock mkBackgroundBlock(size_t start, size_t end, double r, double g, double b, double a) +{ + return Block_copy(^(uiDrawContext *c, uiDrawTextLayout *layout, double x, double y) { + uiDrawBrush brush; + + brush.Type = uiDrawBrushTypeSolid; + brush.R = r; + brush.G = g; + brush.B = b; + brush.A = a; + drawTextBackground(c, x, y, layout, start, end, &brush, 0); + }); +} + static int processAttribute(uiAttributedString *s, uiAttributeSpec *spec, size_t start, size_t end, void *data) { struct foreachParams *p = (struct foreachParams *) data; @@ -47,7 +62,11 @@ static int processAttribute(uiAttributedString *s, uiAttributeSpec *spec, size_t CGColorSpaceRef colorspace; CGColorRef color; CGFloat components[4]; + size_t ostart, oend; + backgroundBlock block; + ostart = start; + oend = end; start = attrstrUTF8ToUTF16(s, start); end = attrstrUTF8ToUTF16(s, end); range.location = start; @@ -97,6 +116,12 @@ static int processAttribute(uiAttributedString *s, uiAttributeSpec *spec, size_t CFAttributedStringSetAttribute(p->mas, range, kCTForegroundColorAttributeName, color); CFRelease(color); break; + case uiAttributeBackground: + block = mkBackgroundBlock(ostart, oend, + spec->R, spec->G, spec->B, spec->A); + [p->backgroundBlocks addObject:block]; + Block_release(block); + break; // TODO } return 0; @@ -154,7 +179,7 @@ static CTParagraphStyleRef mkParagraphStyle(uiDrawTextLayoutParams *p) return ps; } -CFAttributedStringRef attrstrToCoreFoundation(uiDrawTextLayoutParams *p) +CFAttributedStringRef attrstrToCoreFoundation(uiDrawTextLayoutParams *p, NSArray **backgroundBlocks) { CFStringRef cfstr; CFMutableDictionaryRef defaultAttrs; @@ -194,10 +219,12 @@ CFAttributedStringRef attrstrToCoreFoundation(uiDrawTextLayoutParams *p) fep.mas = mas; fep.converted = [NSMutableDictionary new]; fep.defaultFont = p->DefaultFont; + fep.backgroundBlocks = [NSMutableArray new]; uiAttributedStringForEachAttribute(p->String, processAttribute, &fep); applyAndFreeFontAttributes(&fep); [fep.converted release]; CFAttributedStringEndEditing(mas); + *backgroundBlocks = fep.backgroundBlocks; return mas; } diff --git a/darwin/drawtext.m b/darwin/drawtext.m index 9fbe5bed..c5736bf9 100644 --- a/darwin/drawtext.m +++ b/darwin/drawtext.m @@ -28,6 +28,8 @@ struct uiDrawTextLayout { // we compute this once when first creating the layout uiDrawTextLayoutLineMetrics *lineMetrics; + NSArray *backgroundBlocks; + // for converting CFAttributedString indices from/to byte offsets size_t *u8tou16; size_t nUTF8; @@ -114,7 +116,7 @@ uiDrawTextLayout *uiDrawNewTextLayout(uiDrawTextLayoutParams *p) CGRect rect; tl = uiNew(uiDrawTextLayout); - tl->attrstr = attrstrToCoreFoundation(p); + tl->attrstr = attrstrToCoreFoundation(p, &(tl->backgroundBlocks)); range.location = 0; range.length = CFAttributedStringGetLength(tl->attrstr); tl->width = p->Width; @@ -165,6 +167,7 @@ void uiDrawFreeTextLayout(uiDrawTextLayout *tl) { uiFree(tl->u16tou8); uiFree(tl->u8tou16); + [tl->backgroundBlocks release]; uiFree(tl->lineMetrics); // TODO release tl->lines? CFRelease(tl->frame); @@ -177,8 +180,13 @@ void uiDrawFreeTextLayout(uiDrawTextLayout *tl) // TODO document that (x,y) is the top-left corner of the *entire frame* void uiDrawText(uiDrawContext *c, uiDrawTextLayout *tl, double x, double y) { + backgroundBlock b; + CGContextSaveGState(c->c); + for (b in tl->backgroundBlocks) + b(c, tl, x, y); + // Core Text doesn't draw onto a flipped view correctly; we have to pretend it was unflipped // see the iOS bits of the first example at https://developer.apple.com/library/mac/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW1 (iOS is naturally flipped) // TODO how is this affected by a non-identity CTM? diff --git a/darwin/uipriv_darwin.h b/darwin/uipriv_darwin.h index c9ab1c34..bf009522 100644 --- a/darwin/uipriv_darwin.h +++ b/darwin/uipriv_darwin.h @@ -145,4 +145,5 @@ extern CTFontDescriptorRef fontdescToCTFontDescriptor(uiDrawFontDescriptor *fd); extern void fontdescFromCTFontDescriptor(CTFontDescriptorRef ctdesc, uiDrawFontDescriptor *uidesc); // attrstr.m -extern CFAttributedStringRef attrstrToCoreFoundation(uiDrawTextLayoutParams *p); +typedef void (^backgroundBlock)(uiDrawContext *c, uiDrawTextLayout *layout, double x, double y); +extern CFAttributedStringRef attrstrToCoreFoundation(uiDrawTextLayoutParams *p, NSArray **backgroundBlocks); diff --git a/examples/drawtext/attributes.c b/examples/drawtext/attributes.c index 63e2e762..543ba94c 100644 --- a/examples/drawtext/attributes.c +++ b/examples/drawtext/attributes.c @@ -82,6 +82,7 @@ static void setupAttributedString(void) uiAttributedStringAppendUnattributed(attrstr, next); spec.Type = uiAttributeBackground; // Direct2D "Peach Puff" (#FFDAB9) + // TODO choose a darker color spec.R = 1.0; spec.G = 0.85490196078431372; spec.B = 0.7254901960784313;