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 // attrstr.m
extern void uiprivInitUnderlineColors(void); extern void uiprivInitUnderlineColors(void);
extern void uiprivUninitUnderlineColors(void); extern void uiprivUninitUnderlineColors(void);
typedef void (^backgroundBlock)(uiDrawContext *c, uiDrawTextLayout *layout, double x, double y); extern CFAttributedStringRef uiprivAttributedStringToCFAttributedString(uiDrawTextLayoutParams *p, NSArray **backgroundParams);
extern CFAttributedStringRef uiprivAttributedStringToCFAttributedString(uiDrawTextLayoutParams *p, NSArray **backgroundBlocks);
// 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... // TODO in fact I should just write something to explain everything in this file...
struct foreachParams { struct foreachParams {
CFMutableAttributedStringRef mas; 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 // 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) static CGColorRef mkcolor(double r, double g, double b, double a)
{ {
CGColorSpaceRef colorspace; CGColorSpaceRef colorspace;
@ -305,20 +291,38 @@ static CGColorRef mkcolor(double r, double g, double b, double a)
return color; 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) static uiForEach processAttribute(const uiAttributedString *s, const uiAttribute *attr, size_t start, size_t end, void *data)
{ {
struct foreachParams *p = (struct foreachParams *) data; struct foreachParams *p = (struct foreachParams *) data;
CFRange range; CFRange range;
CGColorRef color; CGColorRef color;
size_t ostart, oend;
backgroundBlock block;
int32_t us; int32_t us;
CFNumberRef num; CFNumberRef num;
double r, g, b, a; double r, g, b, a;
uiUnderlineColor colorType; uiUnderlineColor colorType;
ostart = start;
oend = end;
start = uiprivAttributedStringUTF8ToUTF16(s, start); start = uiprivAttributedStringUTF8ToUTF16(s, start);
end = uiprivAttributedStringUTF8ToUTF16(s, end); end = uiprivAttributedStringUTF8ToUTF16(s, end);
range.location = start; range.location = start;
@ -340,9 +344,7 @@ static uiForEach processAttribute(const uiAttributedString *s, const uiAttribute
break; break;
case uiAttributeTypeBackground: case uiAttributeTypeBackground:
uiAttributeColor(attr, &r, &g, &b, &a); uiAttributeColor(attr, &r, &g, &b, &a);
block = mkBackgroundBlock(ostart, oend, r, g, b, a); addBackgroundAttribute(p, start, end, r, g, b, a);
[p->backgroundBlocks addObject:block];
Block_release(block);
break; break;
// TODO turn into a class, like we did with the font attributes, or even integrate *into* the font attributes // TODO turn into a class, like we did with the font attributes, or even integrate *into* the font attributes
case uiAttributeTypeUnderline: 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... // 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; CFStringRef cfstr;
CFMutableDictionaryRef defaultAttrs; CFMutableDictionaryRef defaultAttrs;
@ -493,11 +495,11 @@ CFAttributedStringRef uiprivAttributedStringToCFAttributedString(uiDrawTextLayou
CFAttributedStringBeginEditing(mas); CFAttributedStringBeginEditing(mas);
fep.mas = mas; fep.mas = mas;
fep.backgroundBlocks = [NSMutableArray new]; fep.backgroundParams = [NSMutableArray new];
uiAttributedStringForEachAttribute(p->String, processAttribute, &fep); uiAttributedStringForEachAttribute(p->String, processAttribute, &fep);
applyFontAttributes(mas, p->DefaultFont); applyFontAttributes(mas, p->DefaultFont);
CFAttributedStringEndEditing(mas); CFAttributedStringEndEditing(mas);
*backgroundBlocks = fep.backgroundBlocks; *backgroundParams = fep.backgroundParams;
return mas; 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 // in the usual case, the separate copy will just be identical to the regular one, with extra references to everything within
@interface uiprivTextFrame : NSObject { @interface uiprivTextFrame : NSObject {
CFAttributedStringRef attrstr; CFAttributedStringRef attrstr;
NSArray *backgroundBlocks; NSArray *backgroundParams;
CTFramesetterRef framesetter; CTFramesetterRef framesetter;
CGSize size; CGSize size;
CGPathRef path; CGPathRef path;
@ -20,6 +20,29 @@
- (CFArrayRef)lines; - (CFArrayRef)lines;
@end @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 @implementation uiprivTextFrame
- (id)initWithLayoutParams:(uiDrawTextLayoutParams *)p - (id)initWithLayoutParams:(uiDrawTextLayoutParams *)p
@ -31,7 +54,7 @@
self = [super init]; self = [super init];
if (self) { if (self) {
self->attrstr = uiprivAttributedStringToCFAttributedString(p, &(self->backgroundBlocks)); self->attrstr = uiprivAttributedStringToCFAttributedString(p, &(self->backgroundParams));
// TODO kCTParagraphStyleSpecifierMaximumLineSpacing, kCTParagraphStyleSpecifierMinimumLineSpacing, kCTParagraphStyleSpecifierLineSpacingAdjustment for line spacing // TODO kCTParagraphStyleSpecifierMaximumLineSpacing, kCTParagraphStyleSpecifierMinimumLineSpacing, kCTParagraphStyleSpecifierLineSpacingAdjustment for line spacing
self->framesetter = CTFramesetterCreateWithAttributedString(self->attrstr); self->framesetter = CTFramesetterCreateWithAttributedString(self->attrstr);
if (self->framesetter == NULL) { if (self->framesetter == NULL) {
@ -71,22 +94,22 @@
CFRelease(self->frame); CFRelease(self->frame);
CFRelease(self->path); CFRelease(self->path);
CFRelease(self->framesetter); CFRelease(self->framesetter);
[self->backgroundBlocks release]; [self->backgroundParams release];
CFRelease(self->attrstr); CFRelease(self->attrstr);
[super dealloc]; [super dealloc];
} }
- (void)draw:(uiDrawContext *)c textLayout:(uiDrawTextLayout *)tl at:(double)x y:(double)y - (void)draw:(uiDrawContext *)c textLayout:(uiDrawTextLayout *)tl at:(double)x y:(double)y
{ {
backgroundBlock b; uiprivDrawTextBackgroundParams *dtb;
CGAffineTransform textMatrix; CGAffineTransform textMatrix;
CGContextSaveGState(c->c); CGContextSaveGState(c->c);
// save the text matrix because it's not part of the graphics state // save the text matrix because it's not part of the graphics state
textMatrix = CGContextGetTextMatrix(c->c); textMatrix = CGContextGetTextMatrix(c->c);
for (b in self->backgroundBlocks) for (dtb in self->backgroundParams)
b(c, tl, x, y); /* TODO */;
// Core Text doesn't draw onto a flipped view correctly; we have to pretend it was unflipped // 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) // 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_kCTFontOpenTypeFeatureTag = NULL;
CFStringRef *FUTURE_kCTFontOpenTypeFeatureValue = 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) // note that we treat any error as "the symbols aren't there" (and don't care if dlclose() failed)
void loadFutures(void) void loadFutures(void)
{ {
@ -20,6 +23,7 @@ void loadFutures(void)
#define GET(var, fn) *((void **) (&var)) = dlsym(handle, #fn) #define GET(var, fn) *((void **) (&var)) = dlsym(handle, #fn)
GET(FUTURE_kCTFontOpenTypeFeatureTag, kCTFontOpenTypeFeatureTag); GET(FUTURE_kCTFontOpenTypeFeatureTag, kCTFontOpenTypeFeatureTag);
GET(FUTURE_kCTFontOpenTypeFeatureValue, kCTFontOpenTypeFeatureValue); GET(FUTURE_kCTFontOpenTypeFeatureValue, kCTFontOpenTypeFeatureValue);
GET(FUTURE_kCTBackgroundColorAttributeName, kCTBackgroundColorAttributeName);
dlclose(handle); dlclose(handle);
} }

View File

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