NSFont is full of lies

Dear Lazyweb, I need to find the bounding box of a character, using Cocoa or Quartz or whatever.

Yes, I have seen Getting Font Metrics. However, on my planet, "bounding rectangle" means "the rectangle that completely encloses all ink that will be drawn by the character." It does not mean "a rectangle that is 'advancement' wide".

Here is some code. The image to the right is what it draws. Note that none of these rectangles could even remotely be considered a bounding box. How do I find the bounding box?

- (void)drawRect:(NSRect)rect
{
  NSString *str = @"j";
  NSFont *font = [NSFont fontWithName:@"Helvetica-BoldOblique" size:180];

  NSDictionary *attr = [NSDictionary dictionaryWithObject:font
                                    forKey:NSFontAttributeName];
  NSSize bbox = [str sizeWithAttributes:attr];
  NSRect frame = [self bounds];
  NSPoint pos;
  pos.x = (frame.origin.x + ((frame.size.width  - bbox.width)  / 2));
  pos.y = (frame.origin.y + ((frame.size.height - bbox.height) / 2));

  /* I can't believe we have to go through this bullshit just to
    convert a 'char' to an NSGlyph!!
  */
  NSGlyph g;
  {
    NSTextStorage *ts = [[NSTextStorage alloc] initWithString:str];
    [ts setFont:font];
    NSLayoutManager *lm = [[NSLayoutManager alloc] init];
    NSTextContainer *tc = [[NSTextContainer alloc] init];
    [lm addTextContainer:tc];
    [tc release]; // lm retains tc
    [ts addLayoutManager:lm];
    [lm release]; // ts retains lm
    g = [lm glyphAtIndex:0];
    [ts release];
  }


  /* Clear window and draw the character.
  */
  [[NSColor whiteColor] set];
  NSRectFill([self bounds]);
  [str drawAtPoint:pos withAttributes:attr];


  /* Draw blue square marking origin.
  */
  frame.origin = pos;
  frame.origin.y -= [font descender];
  frame.size.width = frame.size.height = 10;
  [[NSColor blueColor] set];
  NSRectFill (frame);


  /* Draw blue baseline according to [NSFont descender].
  */
  frame.origin.x = 0;
  frame.origin.y = pos.y - [font descender];
  frame.size.width = [self bounds].size.width;
  frame.size.height = 1;
  [[NSColor blueColor] set];
  NSFrameRect (frame);


  /* Draw blue line according to [NSFont advancementForGlyph].
  */
  frame.origin.x = pos.x + [font advancementForGlyph:g].width;
  frame.origin.y = 0;
  frame.size.width = 1;
  frame.size.height = [self bounds].size.height;
  [[NSColor blueColor] set];
  NSFrameRect (frame);


  /* Draw red bounding box according to [NSString sizeWithAttributes].
  */
  frame.origin = pos;
  frame.size = bbox;
  [[NSColor redColor] set];
  NSFrameRect (frame);


  /* Draw green bounding box according to [NSFont boundingRectForGlyph].
  */
  NSRect bbox2 = [font boundingRectForGlyph: g];
  frame.origin.x = pos.x + bbox2.origin.x;
  frame.origin.y = pos.y - bbox2.origin.y;
  frame.size = bbox2.size;
  [[NSColor greenColor] set];
  NSFrameRect (frame);
}

(Previously.)


Update: I did solve this eventually; if you want to see the working code, see the query_font() function in xscreensaver/OSX/jwxyz.m.

Tags: , , ,

Elvis is in your pants

Elvis has left the building. Now 30,000 impersonators may have to go as well:

A New York businessman has bought the rights to Elvis's name and likeness and has threatened to ban "unauthorised" Elvis clones.

Robert Sillerman, a billionaire media entrepreneur who owns American Idol, paid $114 million last year for an 85 per cent stake in Elvis Presley Enterprises, which is run by the Presley family. He got control of Graceland, the King's home in Memphis, Tennessee, and control of his name and likeness, but not his music.

Of Elvis impersonators, he said ominously: "If we were going to do a show that was based on Elvis impersonators, then obviously it wouldn't make sense to have unauthorised Elvis impersonators."

Impersonators in America believe that it is inevitable that their industry -- which includes dwarf Elvises, Chinese Elvises and African-American Elvises -- is in for a cull.

Matt Lewis, another Elvis impersonator, said that his agents had been studying the legal ramifications of his status since Mr Sillerman acquired the rights. Some impersonators make $300,000 a year, and Mr Lewis acknowledged that he made "six figures" per annum.

"If they tried to stop me I'd figure out a way to keep going," he said. "We would band together. I have this image of old ladies going to underground shows and giving passwords at the door. There would be underground Elvis speakeasies. Honestly."

Tags: , ,