Implemented uiAttributeTypeBackground for OS X 10.12 and newer using the attribute included with Core Text. Also laid out a non-block-based API for drawing backgrounds on older versions of OS X (not implemented here yet, however; that will require bringing back the old metrics code).

This commit is contained in:
Pietro Gagliardi 2018-03-11 03:26:32 -04:00
parent 6ba2d3606d
commit acbe7c3149
5 changed files with 75 additions and 33 deletions

View File

@ -74,5 +74,17 @@ extern void uiprivProcessFontVariation(uiprivFontStyleData *d, NSDictionary *axi
// attrstr.m
extern void uiprivInitUnderlineColors(void);
extern void uiprivUninitUnderlineColors(void);
typedef void (^backgroundBlock)(uiDrawContext *c, uiDrawTextLayout *layout, double x, double y);
extern CFAttributedStringRef uiprivAttributedStringToCFAttributedString(uiDrawTextLayoutParams *p, NSArray **backgroundBlocks);
extern CFAttributedStringRef uiprivAttributedStringToCFAttributedString(uiDrawTextLayoutParams *p, NSArray **backgroundParams);
// drawtext.m
@interface uiprivDrawTextBackgroundParams : NSObject {
size_t start;
size_t end;
double r;
double g;
double b;
double a;
}
- (id)initWithStart:(size_t)s end:(size_t)e r:(double)red g:(double)green b:(double)blue a:(double)alpha;
- (void)draw:(CGContextRef)c layout:(uiDrawTextLayout *)layout at:(double)x y:(double)y utf8Mapping:(const size_t *)u16tou8;
@end

View File

@ -65,7 +65,7 @@ void uiprivUninitUnderlineColors(void)
// TODO in fact I should just write something to explain everything in this file...
struct foreachParams {
CFMutableAttributedStringRef mas;
NSMutableArray *backgroundBlocks;
NSMutableArray *backgroundParams;
};
// unlike the other systems, Core Text rolls family, size, weight, italic, width, AND opentype features into the "font" attribute
@ -271,20 +271,6 @@ static void addFontAttributeToRange(struct foreachParams *p, size_t start, size_
}
}
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;
//TODO drawTextBackground(c, x, y, layout, start, end, &brush, 0);
});
}
static CGColorRef mkcolor(double r, double g, double b, double a)
{
CGColorSpaceRef colorspace;
@ -305,20 +291,38 @@ static CGColorRef mkcolor(double r, double g, double b, double a)
return color;
}
static void addBackgroundAttribute(struct foreachParams *p, size_t start, size_t end, double r, double g, double b, double a)
{
uiprivDrawTextBackgroundParams *dtb;
// TODO make sure this works properly with line paragraph spacings (after figuring out what that means, of course)
if (FUTURE_kCTBackgroundColorAttributeName != NULL) {
CGColorRef color;
CFRange range;
color = mkcolor(r, g, b, a);
range.location = start;
range.length = end - start;
CFAttributedStringSetAttribute(p->mas, range, *FUTURE_kCTBackgroundColorAttributeName, color);
CFRelease(color);
return;
}
dtb = [[uiprivDrawTextBackgroundParams alloc] initWithStart:start end:end r:r g:g b:b a:a];
[p->backgroundParams addObject:dtb];
[dtb release];
}
static uiForEach processAttribute(const uiAttributedString *s, const uiAttribute *attr, size_t start, size_t end, void *data)
{
struct foreachParams *p = (struct foreachParams *) data;
CFRange range;
CGColorRef color;
size_t ostart, oend;
backgroundBlock block;
int32_t us;
CFNumberRef num;
double r, g, b, a;
uiUnderlineColor colorType;
ostart = start;
oend = end;
start = uiprivAttributedStringUTF8ToUTF16(s, start);
end = uiprivAttributedStringUTF8ToUTF16(s, end);
range.location = start;
@ -340,9 +344,7 @@ static uiForEach processAttribute(const uiAttributedString *s, const uiAttribute
break;
case uiAttributeTypeBackground:
uiAttributeColor(attr, &r, &g, &b, &a);
block = mkBackgroundBlock(ostart, oend, r, g, b, a);
[p->backgroundBlocks addObject:block];
Block_release(block);
addBackgroundAttribute(p, start, end, r, g, b, a);
break;
// TODO turn into a class, like we did with the font attributes, or even integrate *into* the font attributes
case uiAttributeTypeUnderline:
@ -453,7 +455,7 @@ static CTParagraphStyleRef mkParagraphStyle(uiDrawTextLayoutParams *p)
}
// TODO either rename this to uiprivDrawTextLayoutParams... or rename this file or both or split the struct or something else...
CFAttributedStringRef uiprivAttributedStringToCFAttributedString(uiDrawTextLayoutParams *p, NSArray **backgroundBlocks)
CFAttributedStringRef uiprivAttributedStringToCFAttributedString(uiDrawTextLayoutParams *p, NSArray **backgroundParams)
{
CFStringRef cfstr;
CFMutableDictionaryRef defaultAttrs;
@ -493,11 +495,11 @@ CFAttributedStringRef uiprivAttributedStringToCFAttributedString(uiDrawTextLayou
CFAttributedStringBeginEditing(mas);
fep.mas = mas;
fep.backgroundBlocks = [NSMutableArray new];
fep.backgroundParams = [NSMutableArray new];
uiAttributedStringForEachAttribute(p->String, processAttribute, &fep);
applyFontAttributes(mas, p->DefaultFont);
CFAttributedStringEndEditing(mas);
*backgroundBlocks = fep.backgroundBlocks;
*backgroundParams = fep.backgroundParams;
return mas;
}

View File

@ -8,7 +8,7 @@
// in the usual case, the separate copy will just be identical to the regular one, with extra references to everything within
@interface uiprivTextFrame : NSObject {
CFAttributedStringRef attrstr;
NSArray *backgroundBlocks;
NSArray *backgroundParams;
CTFramesetterRef framesetter;
CGSize size;
CGPathRef path;
@ -20,6 +20,29 @@
- (CFArrayRef)lines;
@end
@implementation uiprivDrawTextBackgroundParams
- (id)initWithStart:(size_t)s end:(size_t)e r:(double)red g:(double)green b:(double)blue a:(double)alpha
{
self = [super init];
if (self) {
self->start = s;
self->end = e;
self->r = red;
self->g = green;
self->b = blue;
self->a = alpha;
}
return self;
}
- (void)draw:(CGContextRef)c layout:(uiDrawTextLayout *)layout at:(double)x y:(double)y utf8Mapping:(const size_t *)u16tou8
{
// TODO
}
@end
@implementation uiprivTextFrame
- (id)initWithLayoutParams:(uiDrawTextLayoutParams *)p
@ -31,7 +54,7 @@
self = [super init];
if (self) {
self->attrstr = uiprivAttributedStringToCFAttributedString(p, &(self->backgroundBlocks));
self->attrstr = uiprivAttributedStringToCFAttributedString(p, &(self->backgroundParams));
// TODO kCTParagraphStyleSpecifierMaximumLineSpacing, kCTParagraphStyleSpecifierMinimumLineSpacing, kCTParagraphStyleSpecifierLineSpacingAdjustment for line spacing
self->framesetter = CTFramesetterCreateWithAttributedString(self->attrstr);
if (self->framesetter == NULL) {
@ -71,22 +94,22 @@
CFRelease(self->frame);
CFRelease(self->path);
CFRelease(self->framesetter);
[self->backgroundBlocks release];
[self->backgroundParams release];
CFRelease(self->attrstr);
[super dealloc];
}
- (void)draw:(uiDrawContext *)c textLayout:(uiDrawTextLayout *)tl at:(double)x y:(double)y
{
backgroundBlock b;
uiprivDrawTextBackgroundParams *dtb;
CGAffineTransform textMatrix;
CGContextSaveGState(c->c);
// save the text matrix because it's not part of the graphics state
textMatrix = CGContextGetTextMatrix(c->c);
for (b in self->backgroundBlocks)
b(c, tl, x, y);
for (dtb in self->backgroundParams)
/* TODO */;
// 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)

View File

@ -8,6 +8,9 @@
CFStringRef *FUTURE_kCTFontOpenTypeFeatureTag = NULL;
CFStringRef *FUTURE_kCTFontOpenTypeFeatureValue = NULL;
// added in OS X 10.12; we need 10.8
CFStringRef *FUTURE_kCTBackgroundColorAttributeName = NULL;
// note that we treat any error as "the symbols aren't there" (and don't care if dlclose() failed)
void loadFutures(void)
{
@ -20,6 +23,7 @@ void loadFutures(void)
#define GET(var, fn) *((void **) (&var)) = dlsym(handle, #fn)
GET(FUTURE_kCTFontOpenTypeFeatureTag, kCTFontOpenTypeFeatureTag);
GET(FUTURE_kCTFontOpenTypeFeatureValue, kCTFontOpenTypeFeatureValue);
GET(FUTURE_kCTBackgroundColorAttributeName, kCTBackgroundColorAttributeName);
dlclose(handle);
}

View File

@ -145,6 +145,7 @@ extern void doManualResize(NSWindow *w, NSEvent *initialEvent, uiWindowResizeEdg
// future.m
extern CFStringRef *FUTURE_kCTFontOpenTypeFeatureTag;
extern CFStringRef *FUTURE_kCTFontOpenTypeFeatureValue;
extern CFStringRef *FUTURE_kCTBackgroundColorAttributeName;
extern void loadFutures(void);
extern void FUTURE_NSLayoutConstraint_setIdentifier(NSLayoutConstraint *constraint, NSString *identifier);
extern BOOL FUTURE_NSWindow_performWindowDragWithEvent(NSWindow *w, NSEvent *initialEvent);