Re: NSString to *NSGlyph conversion...
Re: NSString to *NSGlyph conversion...
- Subject: Re: NSString to *NSGlyph conversion...
- From: Douglas Davidson <email@hidden>
- Date: Mon, 8 Oct 2001 10:08:52 -0700
On Monday, October 8, 2001, at 05:20 AM, Simon Stapleton wrote:
I need to lay some text out along an arbitrary path. This could be a
curve. Now, I can work out how to lay out a glyph, and all that good
stuff, but I can't for the life of me work out how to go from an
NSString to an array of NSGlyphs.
This is one of the jobs of NSLayoutManager--you can expect to become
quite familiar with this handy class if you do sophisticated work with
the Cocoa text system, since the layout manager is the central
controlling object for text display.
Before you start working with it, you should read the overview
documentation
(
http://developer.apple.com/techpubs/macosx/Cocoa/ProgrammingTopics/TextOverview.
pdf) which describes how the various classes are related to each other
and discusses some common configurations. Most of this is oriented
toward configurations containing an NSTextView, which is not what you
will be doing, but it will tell you what does what.
Next, you should look at the CircleView example included with 10.1,
since this is very close to what you want to do. You could probably
just cut and paste a lot of that code, but you will probably want to get
a deeper understanding of what it is doing.
Here is a brief summary. The three objects you minimally need to do
this sort of work with text without displaying it in an NSTextView (e.g.
for displaying it in some other kind of view, or just for measuring it)
are an NSTextStorage (the model object, to hold the text), an
NSLayoutManager (the controller), and an NSTextContainer (an auxiliary
object that describes the geometric region in which the text is to be
laid out).
The NSTextStorage, a subclass of NSAttributedString, holds the contents
of the text as an attributed string--that is, a string with additional
attributes for such things as fonts, colors, etc. The NSLayoutManager
takes this text and derives from it all of the additional information
needed to display the text, on a lazy as-needed basis. There are two
distinct steps to this: glyph generation and layout.
The way this works is that you ask the layout manager questions about
the text (e.g., what is the glyph range corresponding to a given
character range?) and the layout manager answers them, doing whatever
work is required to do so. If answering the question requires glyph
generation, then the layout manager will generate glyphs as needed to
answer it. If answering the question requires layout, then the layout
manager will perform layout (using an auxiliary class, NSTypesetter to
do so) as needed to answer it. The NSLayoutManager header file
describes in detail exactly which questions will cause glyph generation
or layout.
Note that glyph generation and layout are both complex and
time-consuming tasks, so the layout manager caches the results of both
processes, and in addition manages fine-grained invalidation of these
caches. If the text storage changes, then the relevant glyph and layout
information will automatically be invalidated. If you wish, you can
also manually invalidate either glyph or layout information.
The CircleView example uses NSLayoutManager for both glyph generation
and layout. It creates a layout manager, associates it to a text
storage for the text, and adds a simple rectangular NSTextContainer in
which the text is to be laid out. When it needs to display the text, it
goes on to ask a question that causes NSLayoutManager to make sure that
glyph generation and layout is up to date for the entire text. (This
does only as much work as necessary. The first time it is called, the
work will be done; thereafter, unless the text changes, this will be
very cheap.)
Then the example code takes the layout thus created, in a simple
rectangular text container, and transforms it glyph by glyph so that the
text lies along a circle. The spacing of the glyphs along a line in the
original layout is turned into angular spacing along the circle.
Vertical spacing of the glyphs (e.g. if the original text included hard
line breaks) becomes radial spacing. For each glyph an appropriately
rotated and translated coordinate system is set up, and the layout
manager is used to draw the glyph (this could also be done through CG
directly, but that would be considerably more inconvenient and probably
not much faster).
The performance ends up being fairly reasonable--try pressing the button
to turn on animation, and click and drag in the view to drag the circle
around while it rotates, and see how it performs for you. Click on the
border of the color well, and you will get a color panel; you can click
and drag the mouse around in the color wheel, and the color will change
on the fly.
Douglas Davidson