To be compatible with NSLayoutManager, you should use -drawWithRect:options:attributes: here instead of using CT.
Your source of trouble is using -drawAtPoint: which uses NSStringDrawingUsesLineFragmentOrigin option (layout glyphs from the top instead of the glyph origin). Aki On 2012/09/24, at 7:02, jonat...@mugginsoft.com wrote: > > > > On 24 Sep 2012, at 12:49, jonat...@mugginsoft.com wrote: > >> >> On 23 Sep 2012, at 17:33, Kyle Sluder <k...@ksluder.com> wrote: >>> >>> Attributes are specified on a character, rather than glyph, basis. So if >>> you need to draw your characters with a separate color, you should >>> probably override >>> -showCGGlyphs:positions:count:font:matrix:attributes:inContext: to push >>> and pop the foreground color you want before calling super. Should be a >>> really simple override, because the context is already set up for you. >>> >>> >> It turns out that customising NSGlyphGenerator is not necessary as the >> subclass merely calls its delegate, which is the layout manager. >> So an override on NSLayoutManager of - >> insertGlyphs:length:forStartingGlyphAtIndex:characterIndex: is appropriate. >> I cache my substitute glyphs and swap them in as required (a secondary >> layout manager generates the substitute glyphs). >> >> However there are issues. >> >> Colourisation in - >> showCGGlyphs:positions:count:font:matrix:attributes:inContext: >> will necessitate colouring by glyph value. So if a period is used to >> highlight a space then all periods in the text get highlighted regardless. >> >> Secondly, swapping out the tab glyph for another seems to break the tab >> functionality in the NSTextView. >> >> Also, new line and carriage return glyph substitution doesn't seem to work. >> The substitute glyph is not drawn. >> Perhaps its omitted as part of the fragment processing. >> >> I imagine that the second issue is related to the type setter, though >> that's just a guess. >> > > I took another look at NSLayoutManager - drawGlyphsForGlyphRange:atPoint: > and decided to try dropping down to CoreText. > NSString -drawAtPoint:withAttributes: seemed to be the source of trouble and > was very inefficient. > > I created and cached a CTLineRef for each of my substitute characters thus: > > attrString = [[NSAttributedString alloc] initWithString:newLineCharacter > attributes:defAttributes]; > textLine = > CFMakeCollectable(CTLineCreateWithAttributedString((CFAttributedStringRef)attrString)); > [lineRefs addObject:(id)textLine]; > > I then used CTLineDraw to draw the required line on demand. > The vertical alignment of the extra glyphs seems fine with this approach. > > - (void)drawGlyphsForGlyphRange:(NSRange)glyphRange > atPoint:(NSPoint)containerOrigin > { > if (showInvisibleCharacters ) { > > NSPoint pointToDrawAt; > NSRect glyphFragment; > NSString *completeString = [[self textStorage] string]; > NSInteger lengthToRedraw = NSMaxRange(glyphRange); > > void *gcContext = [[NSGraphicsContext currentContext] graphicsPort]; > > // if our context is flipped then we need to flip our drawn text too > CGAffineTransform t = {1.0, 0.0, 0.0, -1.0, 0.0, 0.0}; > if (![[NSGraphicsContext currentContext] isFlipped]) { > t = CGAffineTransformIdentity; > } > CGContextSetTextMatrix (gcContext, t); > > // we may not have any glyphs generated at this stage > for (NSInteger idx = glyphRange.location; idx < lengthToRedraw; > idx++) { > unichar characterToCheck = [completeString > characterAtIndex:idx]; > NSUInteger lineRefIndex = 0; > > if (characterToCheck == '\t') { > lineRefIndex = 0; > } else if (characterToCheck == ' ') { > lineRefIndex = 1; > } else if (characterToCheck == '\n' || characterToCheck > == '\r') { > lineRefIndex = 2; > } else { > continue; > } > > pointToDrawAt = [self locationForGlyphAtIndex:idx]; > glyphFragment = [self lineFragmentRectForGlyphAtIndex:idx > effectiveRange:NULL]; > pointToDrawAt.x += glyphFragment.origin.x; > pointToDrawAt.y += glyphFragment.origin.y; > > // get our text line object > CTLineRef line = (CTLineRef)[lineRefs objectAtIndex:lineRefIndex]; > > CGContextSetTextPosition(gcContext, pointToDrawAt.x, > pointToDrawAt.y); > CTLineDraw(line, gcContext); > } > } > > // the following causes glyph generation to occur if required > [super drawGlyphsForGlyphRange:glyphRange atPoint:containerOrigin]; > } > > > Regards > > Jonathan Mitchell > Mugginsoft LLP > > > > > > > > > _______________________________________________ > > Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) > > Please do not post admin requests or moderator comments to the list. > Contact the moderators at cocoa-dev-admins(at)lists.apple.com > > Help/Unsubscribe/Update your Subscription: > https://lists.apple.com/mailman/options/cocoa-dev/aki%40apple.com > > This email sent to a...@apple.com _______________________________________________ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com