Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

kCTSuperscriptAttributeName is not working for using subscript and superscript

enter image description here

I am using this code for displaying subscript and superscript in label but it not working.

I create a category for NSAttributedString.

-(void)setSuperscript:(BOOL)isSuperscript range:(NSRange)range {
    [self removeAttribute:(NSString * )kCTSuperscriptAttributeName range:range]; // Work around for Apple leak
    [self addAttribute:(NSString*)kCTSuperscriptAttributeName value:[NSNumber numberWithInt:(isSuperscript?1:0)] range:range];
}
-(void)setSubscript:(BOOL)isSubscript range:(NSRange)range {
    [self removeAttribute:(NSString * )kCTSuperscriptAttributeName range:range]; // Work around for Apple leak
    [self addAttribute:(NSString*)kCTSuperscriptAttributeName value:[NSNumber numberWithInt:(isSubscript?-1:0)] range:range];
}
like image 237
alok chauve Avatar asked Feb 23 '12 11:02

alok chauve


1 Answers

The problem is that many fonts either do not define super- and subscript variants, or have some rather funky (speak wrong) metrics for it.

A possible workaround is to fake it, like with the method below (in a category on NSMutableAttributedString). It has some shortcomings though:

  • The stroke width isn't perfect, especially for larger font sizes
  • It is somewhat harder to undo
  • The calculated size and offset may not be perfect for some fonts

On the plus side this should work for all fonts, and if needed can be tweaked for specific purposes.

- (void)fakeSuperOrSubScript:(BOOL)superscript
    range:(NSRange)range
    defaultFont:(NSFont *)defaultFont
{

    NSFontManager   *fm=[NSFontManager sharedFontManager];
    NSFont          *font=[self
        attribute:NSFontAttributeName
        atIndex:range.location
        effectiveRange:NULL
    ];

    if(!font) font=defaultFont;
    if(!font)
    {
        NSLog(@"ERROR: fakeSuperOrSubScript has no font to use!");

        return;
    }

    // Bolden font to adjust stroke width
    NSFont          *siFont=[fm convertWeight:YES ofFont:font];
    float           originalSize=[siFont pointSize];
    float           newSize=originalSize*3.0/4.0;
    float           blOffset=(superscript)?originalSize/2.0:-originalSize/4.0;

    siFont=[fm convertFont:siFont toSize:newSize];

    NSDictionary *attrs=@{
        NSFontAttributeName:            siFont,
        NSBaselineOffsetAttributeName:  @(blOffset),
    };

    [self addAttributes:attrs range:range];
}
like image 153
Gerd K Avatar answered Oct 27 '22 01:10

Gerd K