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
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue