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

Reply via email to