Finished writing a NSLayoutManager-based text system. Not quite perfect yet, but we're getting somewhere!
This commit is contained in:
parent
4e2dc90f4f
commit
b19f4cf251
|
@ -2,16 +2,26 @@
|
||||||
#import "uipriv_darwin.h"
|
#import "uipriv_darwin.h"
|
||||||
#import "draw.h"
|
#import "draw.h"
|
||||||
|
|
||||||
// TODO what happens if nLines == 0 in any function?
|
@interface lineInfo : NSObject
|
||||||
|
@property NSRange glyphRange;
|
||||||
|
@property NSRange characterRange;
|
||||||
|
@property NSRect lineRect;
|
||||||
|
@property CGFloat baselineOffset;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation lineInfo
|
||||||
|
@end
|
||||||
|
|
||||||
struct uiDrawTextLayout {
|
struct uiDrawTextLayout {
|
||||||
CFAttributedStringRef attrstr;
|
// NSTextStorage is subclassed from NSMutableAttributedString
|
||||||
|
NSTextStorage *attrstr;
|
||||||
|
NSTextContainer *container;
|
||||||
|
NSLayoutManager *layoutManager;
|
||||||
|
|
||||||
// the width as passed into uiDrawTextLayout constructors
|
// the width as passed into uiDrawTextLayout constructors
|
||||||
double width;
|
double width;
|
||||||
|
|
||||||
CTFramesetterRef framesetter;
|
#if 0 /* TODO */
|
||||||
|
|
||||||
// the *actual* size of the frame
|
// the *actual* size of the frame
|
||||||
// note: technically, metrics returned from frame are relative to CGPathGetPathBoundingBox(tl->path)
|
// note: technically, metrics returned from frame are relative to CGPathGetPathBoundingBox(tl->path)
|
||||||
// however, from what I can gather, for a path created by CGPathCreateWithRect(), like we do (with a NULL transform), CGPathGetPathBoundingBox() seems to just return the standardized form of the rect used to create the path
|
// however, from what I can gather, for a path created by CGPathCreateWithRect(), like we do (with a NULL transform), CGPathGetPathBoundingBox() seems to just return the standardized form of the rect used to create the path
|
||||||
|
@ -19,188 +29,101 @@ struct uiDrawTextLayout {
|
||||||
// so we can just use tl->size for adjustments
|
// so we can just use tl->size for adjustments
|
||||||
// we don't need to adjust coordinates by any origin since our rect origin is (0, 0)
|
// we don't need to adjust coordinates by any origin since our rect origin is (0, 0)
|
||||||
CGSize size;
|
CGSize size;
|
||||||
|
#endif
|
||||||
|
|
||||||
CGPathRef path;
|
NSMutableArray<lineInfo *> *lineInfo;
|
||||||
CTFrameRef frame;
|
|
||||||
|
|
||||||
CFArrayRef lines;
|
|
||||||
CFIndex nLines;
|
|
||||||
// we compute this once when first creating the layout
|
|
||||||
uiDrawTextLayoutLineMetrics *lineMetrics;
|
|
||||||
|
|
||||||
// for converting CFAttributedString indices to byte offsets
|
// for converting CFAttributedString indices to byte offsets
|
||||||
size_t *u16tou8;
|
size_t *u16tou8;
|
||||||
size_t nu16tou8; // TODO I don't like the casing of this name
|
size_t nu16tou8; // TODO I don't like the casing of this name
|
||||||
};
|
};
|
||||||
|
|
||||||
static CTFontRef fontdescToCTFont(uiDrawFontDescriptor *fd)
|
static NSFont *fontdescToNSFont(uiDrawFontDescriptor *fd)
|
||||||
{
|
{
|
||||||
CTFontDescriptorRef desc;
|
NSFontDescriptor *desc;
|
||||||
CTFontRef font;
|
NSFont *font;
|
||||||
|
|
||||||
desc = fontdescToCTFontDescriptor(fd);
|
desc = fontdescToNSFontDescriptor(fd);
|
||||||
font = CTFontCreateWithFontDescriptor(desc, fd->Size, NULL);
|
font = [NSFont fontWithDescriptor:desc size:fd->Size];
|
||||||
CFRelease(desc); // TODO correct?
|
[desc release];
|
||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CFAttributedStringRef attrstrToCoreFoundation(uiAttributedString *s, uiDrawFontDescriptor *defaultFont)
|
static NSTextStorage *attrstrToTextStorage(uiAttributedString *s, uiDrawFontDescriptor *defaultFont)
|
||||||
{
|
{
|
||||||
CFStringRef cfstr;
|
NSString *nsstr;
|
||||||
CFMutableDictionaryRef defaultAttrs;
|
NSMutableDictionary *defaultAttrs;
|
||||||
CTFontRef defaultCTFont;
|
NSTextStorage *attrstr;
|
||||||
CFAttributedStringRef base;
|
|
||||||
CFMutableAttributedStringRef mas;
|
|
||||||
|
|
||||||
cfstr = CFStringCreateWithCharacters(NULL, attrstrUTF16(s), attrstrUTF16Len(s));
|
nsstr = [[NSString alloc] initWithCharacters:attrstrUTF16(s)
|
||||||
if (cfstr == NULL) {
|
length:attrstrUTF16Len(s)];
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
defaultAttrs = CFDictionaryCreateMutable(NULL, 1,
|
|
||||||
&kCFCopyStringDictionaryKeyCallBacks,
|
|
||||||
&kCFTypeDictionaryValueCallBacks);
|
|
||||||
if (defaultAttrs == NULL) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
defaultCTFont = fontdescToCTFont(defaultFont);
|
|
||||||
CFDictionaryAddValue(defaultAttrs, kCTFontAttributeName, defaultCTFont);
|
|
||||||
CFRelease(defaultCTFont);
|
|
||||||
|
|
||||||
base = CFAttributedStringCreate(NULL, cfstr, defaultAttrs);
|
defaultAttrs = [NSMutableDictionary new];
|
||||||
if (base == NULL) {
|
[defaultAttrs setObject:fontdescToNSFont(defaultFont)
|
||||||
// TODO
|
forKey:NSFontAttributeName];
|
||||||
}
|
|
||||||
CFRelease(cfstr);
|
|
||||||
CFRelease(defaultAttrs);
|
|
||||||
mas = CFAttributedStringCreateMutableCopy(NULL, 0, base);
|
|
||||||
CFRelease(base);
|
|
||||||
|
|
||||||
CFAttributedStringBeginEditing(mas);
|
attrstr = [[NSTextStorage alloc] initWithString:nsstr
|
||||||
|
attributes:defaultAttrs];
|
||||||
|
[defaultAttrs release];
|
||||||
|
[nsstr release];
|
||||||
|
|
||||||
|
[attrstr beginEditing];
|
||||||
// TODO copy in the attributes
|
// TODO copy in the attributes
|
||||||
CFAttributedStringEndEditing(mas);
|
[attrstr endEditing];
|
||||||
|
|
||||||
return mas;
|
return attrstr;
|
||||||
}
|
|
||||||
|
|
||||||
// TODO this is wrong for our hit-test example's multiple combining character example
|
|
||||||
static uiDrawTextLayoutLineMetrics *computeLineMetrics(CTFrameRef frame, CGSize size)
|
|
||||||
{
|
|
||||||
uiDrawTextLayoutLineMetrics *metrics;
|
|
||||||
CFArrayRef lines;
|
|
||||||
CTLineRef line;
|
|
||||||
CFIndex i, n;
|
|
||||||
CGFloat ypos;
|
|
||||||
CGRect bounds, boundsNoLeading;
|
|
||||||
CGFloat ascent, descent, leading;
|
|
||||||
CGPoint *origins;
|
|
||||||
|
|
||||||
lines = CTFrameGetLines(frame);
|
|
||||||
n = CFArrayGetCount(lines);
|
|
||||||
metrics = (uiDrawTextLayoutLineMetrics *) uiAlloc(n * sizeof (uiDrawTextLayoutLineMetrics), "uiDrawTextLayoutLineMetrics[] (text layout)");
|
|
||||||
|
|
||||||
origins = (CGPoint *) uiAlloc(n * sizeof (CGPoint), "CGPoint[] (text layout)");
|
|
||||||
CTFrameGetLineOrigins(frame, CFRangeMake(0, n), origins);
|
|
||||||
|
|
||||||
ypos = size.height;
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
line = (CTLineRef) CFArrayGetValueAtIndex(lines, i);
|
|
||||||
bounds = CTLineGetBoundsWithOptions(line, 0);
|
|
||||||
boundsNoLeading = CTLineGetBoundsWithOptions(line, kCTLineBoundsExcludeTypographicLeading);
|
|
||||||
|
|
||||||
// this is equivalent to boundsNoLeading.size.height + boundsNoLeading.origin.y (manually verified)
|
|
||||||
ascent = bounds.size.height + bounds.origin.y;
|
|
||||||
descent = -boundsNoLeading.origin.y;
|
|
||||||
// TODO does this preserve leading sign?
|
|
||||||
leading = -bounds.origin.y - descent;
|
|
||||||
|
|
||||||
// Core Text always rounds these up for paragraph style calculations; there is a flag to control it but it's inaccessible (and this behavior is turned off for old versions of iPhoto)
|
|
||||||
ascent = floor(ascent + 0.5);
|
|
||||||
descent = floor(descent + 0.5);
|
|
||||||
if (leading > 0)
|
|
||||||
leading = floor(leading + 0.5);
|
|
||||||
|
|
||||||
metrics[i].X = origins[i].x;
|
|
||||||
metrics[i].Y = origins[i].y - descent - leading;
|
|
||||||
metrics[i].Width = bounds.size.width;
|
|
||||||
metrics[i].Height = ascent + descent + leading;
|
|
||||||
|
|
||||||
metrics[i].BaselineY = origins[i].y;
|
|
||||||
metrics[i].Ascent = ascent;
|
|
||||||
metrics[i].Descent = descent;
|
|
||||||
metrics[i].Leading = leading;
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
metrics[i].ParagraphSpacingBefore = 0;
|
|
||||||
metrics[i].LineHeightSpace = 0;
|
|
||||||
metrics[i].LineSpacing = 0;
|
|
||||||
metrics[i].ParagraphSpacing = 0;
|
|
||||||
|
|
||||||
// and finally advance to the next line
|
|
||||||
ypos += metrics[i].Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
// okay, but now all these metrics are unflipped
|
|
||||||
// we need to flip them
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
metrics[i].Y = size.height - metrics[i].Y;
|
|
||||||
// go from bottom-left corner to top-left
|
|
||||||
metrics[i].Y -= metrics[i].Height;
|
|
||||||
metrics[i].BaselineY = size.height - metrics[i].BaselineY;
|
|
||||||
// TODO also adjust by metrics[i].Height?
|
|
||||||
}
|
|
||||||
|
|
||||||
uiFree(origins);
|
|
||||||
return metrics;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO fine-tune all the properties
|
||||||
uiDrawTextLayout *uiDrawNewTextLayout(uiAttributedString *s, uiDrawFontDescriptor *defaultFont, double width)
|
uiDrawTextLayout *uiDrawNewTextLayout(uiAttributedString *s, uiDrawFontDescriptor *defaultFont, double width)
|
||||||
{
|
{
|
||||||
uiDrawTextLayout *tl;
|
uiDrawTextLayout *tl;
|
||||||
CGFloat cgwidth;
|
CGFloat cgwidth;
|
||||||
CFRange range, unused;
|
// TODO correct type?
|
||||||
CGRect rect;
|
NSUInteger index;
|
||||||
|
|
||||||
tl = uiNew(uiDrawTextLayout);
|
tl = uiNew(uiDrawTextLayout);
|
||||||
tl->attrstr = attrstrToCoreFoundation(s, defaultFont);
|
tl->attrstr = attrstrToTextStorage(s, defaultFont);
|
||||||
range.location = 0;
|
|
||||||
range.length = CFAttributedStringGetLength(tl->attrstr);
|
|
||||||
tl->width = width;
|
tl->width = width;
|
||||||
|
|
||||||
// TODO CTFrameProgression for RTL/LTR
|
// TODO the documentation on the size property implies this might not be necessary?
|
||||||
// TODO kCTParagraphStyleSpecifierMaximumLineSpacing, kCTParagraphStyleSpecifierMinimumLineSpacing, kCTParagraphStyleSpecifierLineSpacingAdjustment for line spacing
|
|
||||||
tl->framesetter = CTFramesetterCreateWithAttributedString(tl->attrstr);
|
|
||||||
if (tl->framesetter == NULL) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
cgwidth = (CGFloat) width;
|
cgwidth = (CGFloat) width;
|
||||||
if (cgwidth < 0)
|
if (cgwidth < 0)
|
||||||
cgwidth = CGFLOAT_MAX;
|
cgwidth = CGFLOAT_MAX;
|
||||||
// TODO these seem to be floor()'d or truncated?
|
// TODO rename to tl->textContainer
|
||||||
// TODO double check to make sure this TODO was right
|
tl->container = [[NSTextContainer alloc] initWithSize:NSMakeSize(cgwidth, CGFLOAT_MAX)];
|
||||||
tl->size = CTFramesetterSuggestFrameSizeWithConstraints(tl->framesetter,
|
// TODO pull the reference for this
|
||||||
range,
|
[tl->container setLineFragmentPadding:0];
|
||||||
// TODO kCTFramePathWidthAttributeName?
|
|
||||||
NULL,
|
|
||||||
CGSizeMake(cgwidth, CGFLOAT_MAX),
|
|
||||||
&unused); // not documented as accepting NULL (TODO really?)
|
|
||||||
|
|
||||||
rect.origin = CGPointZero;
|
tl->layoutManager = [[NSLayoutManager alloc] init];
|
||||||
rect.size = tl->size;
|
|
||||||
tl->path = CGPathCreateWithRect(rect, NULL);
|
[tl->layoutManager addTextContainer:tl->container];
|
||||||
tl->frame = CTFramesetterCreateFrame(tl->framesetter,
|
[tl->attrstr addLayoutManager:tl->layoutManager];
|
||||||
range,
|
// and force a re-layout (TODO get source
|
||||||
tl->path,
|
[tl->layoutManager glyphRangeForTextContainer:tl->container];
|
||||||
// TODO kCTFramePathWidthAttributeName?
|
|
||||||
NULL);
|
// TODO equivalent of CTFrameProgression for RTL/LTR?
|
||||||
if (tl->frame == NULL) {
|
|
||||||
// TODO
|
// now collect line information; see https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/TextLayout/Tasks/CountLines.html
|
||||||
|
tl->lineInfo = [NSMutableArray<lineInfo *> new];
|
||||||
|
index = 0;
|
||||||
|
while (index < [tl->layoutManager numberOfGlyphs]) {
|
||||||
|
NSRange glyphRange;
|
||||||
|
NSRect lineRect;
|
||||||
|
lineInfo *li;
|
||||||
|
|
||||||
|
lineRect = [tl->layoutManager lineFragmentRectForGlyphAtIndex:index effectiveRange:&glyphRange];
|
||||||
|
li = [lineInfo new];
|
||||||
|
li.glyphRange = glyphRange;
|
||||||
|
li.characterRange = [tl->layoutManager characterRangeForGlyphRange:li.glyphRange actualGlyphRange:NULL];
|
||||||
|
li.lineRect = lineRect;
|
||||||
|
// and this is from http://www.cocoabuilder.com/archive/cocoa/308568-how-to-get-baseline-info.html and http://www.cocoabuilder.com/archive/cocoa/199283-height-and-location-of-text-within-line-in-nslayoutmanager-ignoring-spacing.html
|
||||||
|
li.baselineOffset = [[tl->layoutManager typesetter] baselineOffsetInLayoutManager:tl->layoutManager glyphIndex:index];
|
||||||
|
[tl->lineInfo addObject:li];
|
||||||
|
[li release];
|
||||||
|
index = glyphRange.location + glyphRange.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
tl->lines = CTFrameGetLines(tl->frame);
|
|
||||||
tl->nLines = CFArrayGetCount(tl->lines);
|
|
||||||
tl->lineMetrics = computeLineMetrics(tl->frame, tl->size);
|
|
||||||
|
|
||||||
// and finally copy the UTF-16 to UTF-8 index conversion table
|
// and finally copy the UTF-16 to UTF-8 index conversion table
|
||||||
tl->u16tou8 = attrstrCopyUTF16ToUTF8(s, &(tl->nu16tou8));
|
tl->u16tou8 = attrstrCopyUTF16ToUTF8(s, &(tl->nu16tou8));
|
||||||
|
|
||||||
|
@ -210,74 +133,91 @@ uiDrawTextLayout *uiDrawNewTextLayout(uiAttributedString *s, uiDrawFontDescripto
|
||||||
void uiDrawFreeTextLayout(uiDrawTextLayout *tl)
|
void uiDrawFreeTextLayout(uiDrawTextLayout *tl)
|
||||||
{
|
{
|
||||||
uiFree(tl->u16tou8);
|
uiFree(tl->u16tou8);
|
||||||
uiFree(tl->lineMetrics);
|
[tl->lineInfo release];
|
||||||
// TODO release tl->lines?
|
[tl->layoutManager release];
|
||||||
CFRelease(tl->frame);
|
[tl->container release];
|
||||||
CFRelease(tl->path);
|
[tl->attrstr release];
|
||||||
CFRelease(tl->framesetter);
|
|
||||||
CFRelease(tl->attrstr);
|
|
||||||
uiFree(tl);
|
uiFree(tl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO document that (x,y) is the top-left corner of the *entire frame*
|
// TODO document that (x,y) is the top-left corner of the *entire frame*
|
||||||
void uiDrawText(uiDrawContext *c, uiDrawTextLayout *tl, double x, double y)
|
void uiDrawText(uiDrawContext *c, uiDrawTextLayout *tl, double x, double y)
|
||||||
{
|
{
|
||||||
CGContextSaveGState(c->c);
|
NSGraphicsContext *gc;
|
||||||
|
|
||||||
// Core Text doesn't draw onto a flipped view correctly; we have to pretend it was unflipped
|
CGContextFlush(c->c); // just to be safe
|
||||||
// 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)
|
[NSGraphicsContext saveGraphicsState];
|
||||||
// TODO how is this affected by a non-identity CTM?
|
gc = [NSGraphicsContext graphicsContextWithGraphicsPort:c->c flipped:YES];
|
||||||
CGContextTranslateCTM(c->c, 0, c->height);
|
[NSGraphicsContext setCurrentContext:gc];
|
||||||
CGContextScaleCTM(c->c, 1.0, -1.0);
|
|
||||||
CGContextSetTextMatrix(c->c, CGAffineTransformIdentity);
|
|
||||||
|
|
||||||
// wait, that's not enough; we need to offset y values to account for our new flipping
|
// TODO is this the right point?
|
||||||
// TODO explain this calculation
|
// TODO does this draw with the proper default styles?
|
||||||
y = c->height - tl->size.height - y;
|
[tl->layoutManager drawGlyphsForGlyphRange:[tl->layoutManager glyphRangeForTextContainer:tl->container]
|
||||||
|
atPoint:NSMakePoint(x, y)];
|
||||||
|
|
||||||
// CTFrameDraw() draws in the path we specified when creating the frame
|
[gc flushGraphics]; // just to be safe
|
||||||
// this means that in our usage, CTFrameDraw() will draw at (0,0)
|
[NSGraphicsContext restoreGraphicsState];
|
||||||
// so move the origin to be at (x,y) instead
|
// TODO release gc?
|
||||||
// TODO are the signs correct?
|
|
||||||
CGContextTranslateCTM(c->c, x, y);
|
|
||||||
|
|
||||||
CTFrameDraw(tl->frame, c->c);
|
|
||||||
|
|
||||||
CGContextRestoreGState(c->c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO update all of these {
|
||||||
// TODO document that the width and height of a layout is not necessarily the sum of the widths and heights of its constituent lines; this is definitely untrue on OS X, where lines are placed in such a way that the distance between baselines is always integral
|
// TODO document that the width and height of a layout is not necessarily the sum of the widths and heights of its constituent lines; this is definitely untrue on OS X, where lines are placed in such a way that the distance between baselines is always integral
|
||||||
// TODO width doesn't include trailing whitespace...
|
// TODO width doesn't include trailing whitespace...
|
||||||
// TODO figure out how paragraph spacing should play into this
|
// TODO figure out how paragraph spacing should play into this
|
||||||
|
// }
|
||||||
void uiDrawTextLayoutExtents(uiDrawTextLayout *tl, double *width, double *height)
|
void uiDrawTextLayoutExtents(uiDrawTextLayout *tl, double *width, double *height)
|
||||||
{
|
{
|
||||||
*width = tl->size.width;
|
NSRect r;
|
||||||
*height = tl->size.height;
|
|
||||||
|
// see https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/TextLayout/Tasks/StringHeight.html
|
||||||
|
r = [tl->layoutManager usedRectForTextContainer:tl->container];
|
||||||
|
*width = r.size.width;
|
||||||
|
*height = r.size.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
int uiDrawTextLayoutNumLines(uiDrawTextLayout *tl)
|
int uiDrawTextLayoutNumLines(uiDrawTextLayout *tl)
|
||||||
{
|
{
|
||||||
return tl->nLines;
|
return [tl->lineInfo count];
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiDrawTextLayoutLineByteRange(uiDrawTextLayout *tl, int line, size_t *start, size_t *end)
|
void uiDrawTextLayoutLineByteRange(uiDrawTextLayout *tl, int line, size_t *start, size_t *end)
|
||||||
{
|
{
|
||||||
CTLineRef lr;
|
lineInfo *li;
|
||||||
CFRange range;
|
|
||||||
|
|
||||||
lr = (CTLineRef) CFArrayGetValueAtIndex(tl->lines, line);
|
li = (lineInfo *) [tl->lineInfo objectAtIndex:line];
|
||||||
range = CTLineGetStringRange(lr);
|
*start = tl->u16tou8[li.characterRange.location];
|
||||||
*start = tl->u16tou8[range.location];
|
*end = tl->u16tou8[li.characterRange.location + li.characterRange.length];
|
||||||
*end = tl->u16tou8[range.location + range.length];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiDrawTextLayoutLineGetMetrics(uiDrawTextLayout *tl, int line, uiDrawTextLayoutLineMetrics *m)
|
void uiDrawTextLayoutLineGetMetrics(uiDrawTextLayout *tl, int line, uiDrawTextLayoutLineMetrics *m)
|
||||||
{
|
{
|
||||||
*m = tl->lineMetrics[line];
|
lineInfo *li;
|
||||||
|
|
||||||
|
li = (lineInfo *) [tl->lineInfo objectAtIndex:line];
|
||||||
|
|
||||||
|
m->X = li.lineRect.origin.x;
|
||||||
|
m->Y = li.lineRect.origin.y;
|
||||||
|
m->Width = li.lineRect.size.width;
|
||||||
|
m->Height = li.lineRect.size.height;
|
||||||
|
|
||||||
|
// TODO is this correct?
|
||||||
|
m->BaselineY = (m->X + m->Height) - li.baselineOffset;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
m->Ascent = 10000;
|
||||||
|
m->Descent = 10000;
|
||||||
|
m->Leading = 10000;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
m->ParagraphSpacingBefore = 0;
|
||||||
|
m->LineHeightSpace = 0;
|
||||||
|
m->LineSpacing = 0;
|
||||||
|
m->ParagraphSpacing = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiDrawTextLayoutHitTest(uiDrawTextLayout *tl, double x, double y, uiDrawTextLayoutHitTestResult *result)
|
void uiDrawTextLayoutHitTest(uiDrawTextLayout *tl, double x, double y, uiDrawTextLayoutHitTestResult *result)
|
||||||
{
|
{
|
||||||
|
#if 0 /* TODO */
|
||||||
CFIndex i;
|
CFIndex i;
|
||||||
CTLineRef line;
|
CTLineRef line;
|
||||||
CFIndex pos;
|
CFIndex pos;
|
||||||
|
@ -320,6 +260,7 @@ void uiDrawTextLayoutHitTest(uiDrawTextLayout *tl, double x, double y, uiDrawTex
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
result->Pos = tl->u16tou8[pos];
|
result->Pos = tl->u16tou8[pos];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiDrawTextLayoutByteRangeToRectangle(uiDrawTextLayout *tl, size_t start, size_t end, uiDrawTextLayoutByteRangeRectangle *r)
|
void uiDrawTextLayoutByteRangeToRectangle(uiDrawTextLayout *tl, size_t start, size_t end, uiDrawTextLayoutByteRangeRectangle *r)
|
||||||
|
|
|
@ -21,7 +21,6 @@ struct closeness {
|
||||||
static double doubleAttr(NSDictionary *traits, NSString *attr)
|
static double doubleAttr(NSDictionary *traits, NSString *attr)
|
||||||
{
|
{
|
||||||
NSNumber *n;
|
NSNumber *n;
|
||||||
double val;
|
|
||||||
|
|
||||||
n = (NSNumber *) [traits objectForKey:attr];
|
n = (NSNumber *) [traits objectForKey:attr];
|
||||||
return [n doubleValue];
|
return [n doubleValue];
|
||||||
|
@ -90,7 +89,7 @@ static NSFontDescriptor *matchTraits(NSFontDescriptor *against, double targetWei
|
||||||
n = [matching count];
|
n = [matching count];
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
// likewise
|
// likewise
|
||||||
[matching release];
|
//TODO [matching release];
|
||||||
return against;
|
return against;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +99,7 @@ static NSFontDescriptor *matchTraits(NSFontDescriptor *against, double targetWei
|
||||||
|
|
||||||
closeness[i].index = i;
|
closeness[i].index = i;
|
||||||
current = (NSFontDescriptor *) [matching objectAtIndex:i];
|
current = (NSFontDescriptor *) [matching objectAtIndex:i];
|
||||||
traits = (NSDictionary *) [current objectAtIndex:NSFontTraitsAttribute];
|
traits = (NSDictionary *) [current objectForKey:NSFontTraitsAttribute];
|
||||||
if (traits == nil) {
|
if (traits == nil) {
|
||||||
// couldn't get traits; be safe by ranking it lowest
|
// couldn't get traits; be safe by ranking it lowest
|
||||||
// LONGTERM figure out what the longest possible distances are
|
// LONGTERM figure out what the longest possible distances are
|
||||||
|
@ -143,7 +142,7 @@ static NSFontDescriptor *matchTraits(NSFontDescriptor *against, double targetWei
|
||||||
|
|
||||||
// release everything
|
// release everything
|
||||||
uiFree(closeness);
|
uiFree(closeness);
|
||||||
[matching release];
|
//TODO [matching release];
|
||||||
// and release the original descriptor since we no longer need it
|
// and release the original descriptor since we no longer need it
|
||||||
[against release];
|
[against release];
|
||||||
|
|
||||||
|
@ -207,15 +206,13 @@ static const double stretchesToCTWidths[] = {
|
||||||
NSFontDescriptor *fontdescToNSFontDescriptor(uiDrawFontDescriptor *fd)
|
NSFontDescriptor *fontdescToNSFontDescriptor(uiDrawFontDescriptor *fd)
|
||||||
{
|
{
|
||||||
NSMutableDictionary *attrs;
|
NSMutableDictionary *attrs;
|
||||||
CFStringRef cffamily;
|
NSFontDescriptor *basedesc;
|
||||||
CFNumberRef cfsize;
|
|
||||||
CTFontDescriptorRef basedesc;
|
|
||||||
|
|
||||||
attrs = [NSMutableDictionary new];
|
attrs = [NSMutableDictionary new];
|
||||||
[attrs setObject:[NSString stringWithUTF8String:fd->Family]
|
[attrs setObject:[NSString stringWithUTF8String:fd->Family]
|
||||||
forKey:NSFontFamilyAttribute];
|
forKey:NSFontFamilyAttribute];
|
||||||
[attrs setObject:[NSNumber numberWithDouble:fd->Size]
|
[attrs setObject:[NSNumber numberWithDouble:fd->Size]
|
||||||
forKye:NSFontSizeAttribute];
|
forKey:NSFontSizeAttribute];
|
||||||
|
|
||||||
basedesc = [[NSFontDescriptor alloc] initWithFontAttributes:attrs];
|
basedesc = [[NSFontDescriptor alloc] initWithFontAttributes:attrs];
|
||||||
[attrs release];
|
[attrs release];
|
||||||
|
|
Loading…
Reference in New Issue