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:
parent
6ba2d3606d
commit
acbe7c3149
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue