Merge 9cbc7180e6
into fea45b2d5b
This commit is contained in:
commit
b4a4af44f9
|
@ -89,3 +89,5 @@ extern CFAttributedStringRef uiprivAttributedStringToCFAttributedString(uiDrawTe
|
||||||
- (id)initWithStart:(size_t)s end:(size_t)e r:(double)red g:(double)green b:(double)blue a:(double)alpha;
|
- (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;
|
- (void)draw:(CGContextRef)c layout:(uiDrawTextLayout *)layout at:(double)x y:(double)y utf8Mapping:(const size_t *)u16tou8;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
CGColorRef mkcolor(double r, double g, double b, double a);
|
||||||
|
|
|
@ -271,26 +271,6 @@ static void addFontAttributeToRange(struct foreachParams *p, size_t start, size_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static CGColorRef mkcolor(double r, double g, double b, double a)
|
|
||||||
{
|
|
||||||
CGColorSpaceRef colorspace;
|
|
||||||
CGColorRef color;
|
|
||||||
CGFloat components[4];
|
|
||||||
|
|
||||||
// TODO we should probably just create this once and recycle it throughout program execution...
|
|
||||||
colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
|
|
||||||
if (colorspace == NULL) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
components[0] = r;
|
|
||||||
components[1] = g;
|
|
||||||
components[2] = b;
|
|
||||||
components[3] = a;
|
|
||||||
color = CGColorCreate(colorspace, components);
|
|
||||||
CFRelease(colorspace);
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void addBackgroundAttribute(struct foreachParams *p, size_t start, size_t end, double r, double g, double b, double a)
|
static void addBackgroundAttribute(struct foreachParams *p, size_t start, size_t end, double r, double g, double b, double a)
|
||||||
{
|
{
|
||||||
uiprivDrawTextBackgroundParams *dtb;
|
uiprivDrawTextBackgroundParams *dtb;
|
||||||
|
@ -308,6 +288,7 @@ static void addBackgroundAttribute(struct foreachParams *p, size_t start, size_t
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CFAttributedStringSetAttribute(p->mas, CFRangeMake(start, end - start), (CFStringRef)@"FORCE_RUN", [NSString stringWithFormat:@"%lu %lu", start, end]);
|
||||||
dtb = [[uiprivDrawTextBackgroundParams alloc] initWithStart:start end:end r:r g:g b:b a:a];
|
dtb = [[uiprivDrawTextBackgroundParams alloc] initWithStart:start end:end r:r g:g b:b a:a];
|
||||||
[p->backgroundParams addObject:dtb];
|
[p->backgroundParams addObject:dtb];
|
||||||
[dtb release];
|
[dtb release];
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#import "draw.h"
|
#import "draw.h"
|
||||||
#import "attrstr.h"
|
#import "attrstr.h"
|
||||||
|
|
||||||
|
#define inRange(min, x, max) ((min) <= (x) && (x) <= (max))
|
||||||
|
|
||||||
// problem: for a CTFrame made from an empty string, the CTLine array will be empty, and we will crash when doing anything requiring a CTLine
|
// problem: for a CTFrame made from an empty string, the CTLine array will be empty, and we will crash when doing anything requiring a CTLine
|
||||||
// solution: for those cases, maintain a separate framesetter just for computing those things
|
// solution: for those cases, maintain a separate framesetter just for computing those things
|
||||||
// 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
|
||||||
|
@ -18,8 +20,41 @@
|
||||||
- (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;
|
||||||
- (void)returnWidth:(double *)width height:(double *)height;
|
- (void)returnWidth:(double *)width height:(double *)height;
|
||||||
- (CFArrayRef)lines;
|
- (CFArrayRef)lines;
|
||||||
|
- (void)lineOrigins:(CFRange)range origins:(CGPoint*)origins;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
struct uiDrawTextLayout {
|
||||||
|
uiprivTextFrame *frame;
|
||||||
|
uiprivTextFrame *forLines;
|
||||||
|
BOOL empty;
|
||||||
|
|
||||||
|
// for converting CFAttributedString indices from/to byte offsets
|
||||||
|
size_t *u8tou16;
|
||||||
|
size_t nUTF8;
|
||||||
|
size_t *u16tou8;
|
||||||
|
size_t nUTF16;
|
||||||
|
};
|
||||||
|
|
||||||
|
CGColorRef mkcolor(double r, double g, double b, double a)
|
||||||
|
{
|
||||||
|
CGColorSpaceRef colorspace;
|
||||||
|
CGColorRef color;
|
||||||
|
CGFloat components[4];
|
||||||
|
|
||||||
|
// TODO we should probably just create this once and recycle it throughout program execution...
|
||||||
|
colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
|
||||||
|
if (colorspace == NULL) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
components[0] = r;
|
||||||
|
components[1] = g;
|
||||||
|
components[2] = b;
|
||||||
|
components[3] = a;
|
||||||
|
color = CGColorCreate(colorspace, components);
|
||||||
|
CFRelease(colorspace);
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
@implementation uiprivDrawTextBackgroundParams
|
@implementation uiprivDrawTextBackgroundParams
|
||||||
|
|
||||||
- (id)initWithStart:(size_t)s end:(size_t)e r:(double)red g:(double)green b:(double)blue a:(double)alpha
|
- (id)initWithStart:(size_t)s end:(size_t)e r:(double)red g:(double)green b:(double)blue a:(double)alpha
|
||||||
|
@ -38,7 +73,58 @@
|
||||||
|
|
||||||
- (void)draw:(CGContextRef)c layout:(uiDrawTextLayout *)layout at:(double)x y:(double)y utf8Mapping:(const size_t *)u16tou8
|
- (void)draw:(CGContextRef)c layout:(uiDrawTextLayout *)layout at:(double)x y:(double)y utf8Mapping:(const size_t *)u16tou8
|
||||||
{
|
{
|
||||||
// TODO
|
long startI = u16tou8[self->start];
|
||||||
|
long endI = u16tou8[self->end];
|
||||||
|
|
||||||
|
CGColorRef color = mkcolor(self->r, self->g, self->b, self->a);
|
||||||
|
|
||||||
|
double frameHeight;
|
||||||
|
[layout->frame returnWidth:NULL height:&frameHeight];
|
||||||
|
|
||||||
|
CFArrayRef lines = [layout->frame lines];
|
||||||
|
size_t numOfLines = CFArrayGetCount(lines);
|
||||||
|
CGPoint lineOrigins[numOfLines];
|
||||||
|
|
||||||
|
[layout->frame lineOrigins:CFRangeMake(0, numOfLines) origins:lineOrigins];
|
||||||
|
for (size_t i = 0; i < numOfLines; i++) {
|
||||||
|
CTLineRef line = CFArrayGetValueAtIndex(lines, i);
|
||||||
|
CFRange lr = CTLineGetStringRange(line);
|
||||||
|
CFIndex lineStart = lr.location;
|
||||||
|
CFIndex lineEnd = lineStart + lr.length;
|
||||||
|
if (inRange(startI, lineStart, endI) ||
|
||||||
|
inRange(startI, lineEnd, endI) ||
|
||||||
|
inRange(lineStart, startI, lineEnd) ||
|
||||||
|
inRange(lineStart, endI, lineEnd)) {
|
||||||
|
|
||||||
|
CFArrayRef glyphruns = CTLineGetGlyphRuns(line);
|
||||||
|
size_t numOfRuns = CFArrayGetCount(glyphruns);
|
||||||
|
for (size_t j = 0; j < numOfRuns; j++) {
|
||||||
|
// from https://stackoverflow.com/a/5341819/2352201
|
||||||
|
CTRunRef run = CFArrayGetValueAtIndex(glyphruns, j);
|
||||||
|
CFRange runRange = CTRunGetStringRange(run);
|
||||||
|
CFIndex runStart = runRange.location;
|
||||||
|
CFIndex runEnd = runStart + runRange.length;
|
||||||
|
if (startI <= runStart && runEnd <= endI) {
|
||||||
|
CGRect rect;
|
||||||
|
|
||||||
|
CGFloat ascent; //height above the baseline
|
||||||
|
CGFloat descent; //height below the baseline
|
||||||
|
rect.size.width = CTRunGetTypographicBounds(run, CFRangeMake(0, 0), &ascent, &descent, NULL);
|
||||||
|
rect.size.height = ascent + descent;
|
||||||
|
|
||||||
|
rect.origin.x = lineOrigins[i].x + x + CTLineGetOffsetForStringIndex(line, runRange.location, NULL);
|
||||||
|
rect.origin.y = (frameHeight - lineOrigins[i].y) + y - ascent + descent;
|
||||||
|
rect.origin.y -= descent;
|
||||||
|
|
||||||
|
CGContextAddRect(c, rect);
|
||||||
|
CGContextSetFillColorWithColor(c, color);
|
||||||
|
CGContextDrawPath(c, kCGPathFill);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -109,7 +195,7 @@
|
||||||
textMatrix = CGContextGetTextMatrix(c->c);
|
textMatrix = CGContextGetTextMatrix(c->c);
|
||||||
|
|
||||||
for (dtb in self->backgroundParams)
|
for (dtb in self->backgroundParams)
|
||||||
/* TODO */;
|
[dtb draw:c->c layout:tl at:x y:y utf8Mapping:tl->u16tou8];
|
||||||
|
|
||||||
// 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)
|
||||||
|
@ -147,20 +233,13 @@
|
||||||
return CTFrameGetLines(self->frame);
|
return CTFrameGetLines(self->frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)lineOrigins:(CFRange)range origins:(CGPoint*)origins
|
||||||
|
{
|
||||||
|
CTFrameGetLineOrigins(self->frame, range, origins);
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
struct uiDrawTextLayout {
|
|
||||||
uiprivTextFrame *frame;
|
|
||||||
uiprivTextFrame *forLines;
|
|
||||||
BOOL empty;
|
|
||||||
|
|
||||||
// for converting CFAttributedString indices from/to byte offsets
|
|
||||||
size_t *u8tou16;
|
|
||||||
size_t nUTF8;
|
|
||||||
size_t *u16tou8;
|
|
||||||
size_t nUTF16;
|
|
||||||
};
|
|
||||||
|
|
||||||
uiDrawTextLayout *uiDrawNewTextLayout(uiDrawTextLayoutParams *p)
|
uiDrawTextLayout *uiDrawNewTextLayout(uiDrawTextLayoutParams *p)
|
||||||
{
|
{
|
||||||
uiDrawTextLayout *tl;
|
uiDrawTextLayout *tl;
|
||||||
|
|
|
@ -11,6 +11,8 @@ CFStringRef *uiprivFUTURE_kCTFontOpenTypeFeatureValue = NULL;
|
||||||
// added in OS X 10.12; we need 10.8
|
// added in OS X 10.12; we need 10.8
|
||||||
CFStringRef *uiprivFUTURE_kCTBackgroundColorAttributeName = NULL;
|
CFStringRef *uiprivFUTURE_kCTBackgroundColorAttributeName = NULL;
|
||||||
|
|
||||||
|
NSOperatingSystemVersion HIGH_SIERRA_VERSION = { .majorVersion = 10, .minorVersion = 13, .patchVersion = 0 };
|
||||||
|
|
||||||
// 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 uiprivLoadFutures(void)
|
void uiprivLoadFutures(void)
|
||||||
{
|
{
|
||||||
|
@ -23,7 +25,9 @@ void uiprivLoadFutures(void)
|
||||||
#define GET(var, fn) *((void **) (&var)) = dlsym(handle, #fn)
|
#define GET(var, fn) *((void **) (&var)) = dlsym(handle, #fn)
|
||||||
GET(uiprivFUTURE_kCTFontOpenTypeFeatureTag, kCTFontOpenTypeFeatureTag);
|
GET(uiprivFUTURE_kCTFontOpenTypeFeatureTag, kCTFontOpenTypeFeatureTag);
|
||||||
GET(uiprivFUTURE_kCTFontOpenTypeFeatureValue, kCTFontOpenTypeFeatureValue);
|
GET(uiprivFUTURE_kCTFontOpenTypeFeatureValue, kCTFontOpenTypeFeatureValue);
|
||||||
GET(uiprivFUTURE_kCTBackgroundColorAttributeName, kCTBackgroundColorAttributeName);
|
if (![NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:HIGH_SIERRA_VERSION])
|
||||||
|
GET(uiprivFUTURE_kCTBackgroundColorAttributeName, kCTBackgroundColorAttributeName);
|
||||||
|
|
||||||
dlclose(handle);
|
dlclose(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue