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/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to