WWDC2010 Session 114

Transcript

>> Aki Inoue: This is session 114,
Advanced Cocoa Text Tips and Tricks.
This year, this session is all about the Cocoa text system.
We're going to be diving deeper into
the core of the layer subsystem.
By the end of this session, you should be able
to get better understanding of the layer process
and get comfortable extending and customizing based
functionalities, the Cocoa text system provides.
Some prerequisite information, this session expects some
degrees of experience working with the Cocoa text system.
And for your code reading pleasure, we have
the simple project we're going to be using
in this session downloadable from the attendee site.
The technique du jour, we're going to be warming
up looking at multiple text view linking,
learn how to customize ruler view, how to
fold lines without touching a content of text,
and we're going to be embedding UIObjects inline,
and we're going to be covering text animation.
These functionalities are features
commonly found in advanced text editors,
but you should be able to use these
functionalities in any kind of applications.
OK, let's get started.
The Cocoa text system is an integral part of the framework.
It's easy to access.
The power can be accessed simply by drag dropping the text
UIObjects in Interface Builder and its design to scale.
The same layout engine is used by various projects
from a single line text field to subsequent application
with advanced text handling features like these.
And advanced typography features
such as ligatures, kerning,
contextual shaping are provided right out of the box.
Just like any other part of the Cocoa framework, the text
system is based on a model-view-controller design pattern
so that it gives you many customization points.
These are the primary text system classes.
The top, a view class, NSTextView provides
user interaction and area to display.
At the bottom, we have model objects
NSTextStorage and TextContainer representing data.
In the middle, NSLayoutManager acts as controller object.
The primary text classes alone
provides very rich customization points.
You can have flexible MVC configurations.
We can do multipage, multicolor,
multipane so on and so forth.
Each primary class provides a wealth
of delegation interface.
So you can customize validation behaviors or provide
custom pasteboard type, override selection points.
Well, even provide your own context menu.
In addition to this, these classes
are ready to be subclassed.
You can provide non-rectangular shape with text container
or you can define your text attributes
that can affect layout and rendering.
In addition to these primary classes, we're going
to be covering additional helpful classes this year.
NSGlyphGenerator and NSTypeSetter
are the controller classes.
Also, text attachment, it's a model class.
At this point, I'm handing over to
my colleague Dan Schimpf who's going
to be discussing cool functionalities
you can use with the primary classes.
[ Applause ]
>> Dan Schimpf: Good morning.
My name is Dan Schimpf, and I'm going to cover
some of the-- the core classes that Aki mentioned.
So NSTextStorage is your model.
The model of the text, Cocoa text system, and it
is actually a subclass of MutableAttributedString.
So it is the thing that actually stores
all of your characters and your data.
Does restores the attributes like
font and bold and things like that.
And it can be reused across many
views, like any good model should.
And as layout manager, actually lays out the--
[ Cut Audio ]
-- click on something.
It detects view as the
text container where you clicked.
So NSTextView, NSTextView is the subclass of NSView.
That's the thing that you drag out of Interface Builder.
That's what you actually have in your view hierarchy.
It has a layout manager that it
uses to draw a text in drawRect.
It edits the text in the TextStorage.
When you type something, that's the thing that
gets changed and it resizes the TextContainer
as the view resizes to keep those two in sync.
So here's the basic setup of how the
classes work when you just drag something
out of the Interface Builder palette
into your window, this is what you get.
You have a single text storage with a single layout manager
drawn into a single text container with the text view.
So, now we're going to cover how can I use multiple text
views to show the same content in one single text storage.
So, what we're going to do, we're going to have multiple
text views and they're all going to have layout managers
but we're all going to tell them
to use the same text storage,
and that's going to be using this call
replaceTextStorage on layoutManager.
And so this can be done using the views
you've configured in Interface Builder.
So, it minimizes the set up just down to that one call.
So this is what it's going to turn into.
A single text storage with two layout managers,
two text containers and two text views.
So, I'm going to show you how that's going to work.
So, here I've got a-- this is our demo app.
It's a basic NSDocument based application.
I can have several of them, and I can even open
documents, such as the release notes.
And you can see it has rich text,
different font sizes, different fonts.
And what I can do here is just create a split.
Now this is something that you've seen in a lot of text
editors including Xcode and it's showing the same text,
but if I go up here I can edit both views
at once and it shows up in both places now,
and they each have separate text selections and
scroll positions but they both have the same content.
So, how does this work?
Let's go into Xcode, and the first
thing I'm going to show you is the NIB.
So, I'm going to open up the document
NIB in Interface Builder.
And here's our window, it looks pretty much like
it did when we're running and you can even see
that there are two text views here in our split view.
And I can configure those right here, and then what I
do in the document, this is our document class here,
I create a single text storage that they all share.
And that's the text storage that I can alter
in when I'm reading in the data from the file
and that's what I used to write out the data.
So, here's when I load the NIB I get-- I have
my two-I have outlets to my two text views,
and what I do is I just call replaceTextStorage
on their layoutManager
with the text storage that I have already created.
And then at the bottom, I remove the
bottom scroll view from my split view.
So later on, I can just add it back
in and that's all I need to do.
And that's what I really need to do to get
multiple text views showing the same content.
Alright, the next thing I'm going
to cover, and you may have seen
in the demo there is how to add
line numbers to your text views.
That's another thing you see in a lot of advanced text
editors, and it's not too hard, and I'll show you how.
So text views, when you drag them out of an Interface
Builder palette, they're actually encased in an NSScrollView
and what NSScrollView does is show one part of
your view and then allow you to scroll things.
It also has a ruler.
If you've seen-- if you open up Text Edit, you've
seen the ruler that's built in NSScrollView.
But scroll view can also have custom rulers
using an instance of this class NSRulerView.
So, what we're going to do here is we're going
to make a custom ruler view to show line numbers.
And it's going to be entirely driven
by changes to the text storage.
You don't need to have any sort of
hooks in your application to do this.
It's already there in NSTextStorage
DidProcessEditingNotification.
All you need to do is register for this notification on
the right text storage and you'll be off to the races.
So, it's going to use the information from the
layoutManager to draw in the right spot using this call,
rectArrayForCharacterRange, with some extra arguments.
And I'm just going to show you how that's done.
OK, so you may have seen some extra
code here that I skipped over before,
and what this is going to do, it's
going to get the scroll view.
It's going to turn off the horizontal
ruler and turn on the vertical ruler.
And now-- then it's going to create
a subclass, a ruler view,
tell it what text view we have and then just set it in.
And that's really all it need-- all
the application code needs to do.
Now, we can go into the ruler view here,
and we just set up some things here.
We have to configure both font and
text color and background color.
Here in set client view, here is where we register
for this notification, and here is where we get it.
All we need to do is tell ourselves that
we need to refresh our line information
and then we just tell the window that we need the display.
And what happens is in Snow Leopard
there is a new call called viewWillDraw.
And what this is, this is an opportunity for your view to
do extra setup and setup time before you're about to draw,
but you can do extra things during
this time like change your frame
or set extra areas needing display
that you couldn't do during display.
So this is a good chance for us to update our
line information if that hasn't been done yet.
So here we are, and there's another new call in Snow
Leopard for enumerating all the words or lines in a string.
So this is what we're going to do, we're going to numerate
the substrings in a range passing-- just we want the lines.
So it's going to give us the ranges of
all the lines in this string for us,
and we're just going to save this off for later.
And this is a set in the thickness
so this is us resizing the view.
That's all we can only do it in viewWillDraw.
So, when we want to draw, this is
draw hash marks and labels interact.
This is NSRulerViews override point for drawing.
This is what you want to use.
So, we're going to draw the background
color and then here we're going to--
now we're going to get into drawing the actual line numbers.
And the interesting part is right here.
So this is where we get direct array for our character
range 'cause-- and previously, in update line information,
we got all of the indexes for the lines, so now we're
going to get the position of those lines on screen.
And this is important 'cause it will handle things
like line wrapping 'cause you'll see
right here that we skipped this line.
It's not just a repeating pattern because we
asked the layout manager where is this line.
It tells us and then we know where to draw it.
And that's really all you need to do.
It's-- you can check out the sample code.
I encourage you to look it up and now I'm going to hand
it back to Aki, who is going to show you some more tips.
[ Applause ]
>> Aki Inoue: Thank you, Dan.
OK, before going to details, let
me show you a demo first here.
This is the application Dan showed earlier.
I am opening a new document.
You can select a range of text and
execute a menu item called fold lines,
and it folds the lines into-- attach the UIObject.
Clicking on them, we should-- it revealed a hidden text.
So, this functionality hides the
part of the text from the users
but actually it's not touching
the content of the text itself.
By going into the other view, the
original content is still intact.
In fact, if you go into the folded text, select
it and copy it, open a new document here, and paste.
You can extract the original content because the
actual content is not touched by this functionality.
I will be spending the rest of the session
explaining how you can do these kind of techniques.
The first technique you're going to be learning is how
to customize control character handling in a text system.
Since the layout process executes paragraph by paragraph,
you need to concatenate all the paragraphs inside the
selected range in order to fold into a single line unit.
The typesetter is the object that's
responsible for that action.
NSTypesetter performs actual line layout operation.
It determines the soft line break position,
calculates the line position inside the text container.
And finally, it places each characters inside the line.
NSTypesetter is an abstract class declaring
interface, communicating the rest of the layout system,
the Cocoa text system via NSLayoutManager.
It's abstract class so that actually you can subclass
and provide your own custom layout engine that works
with Cocoa text system in harmony if desired.
For most of the developers, we have the default
system-- we have the system-default complete subclass,
NSATSTypesetter that encapsulates the
magic of the advanced typographic features.
Finally, the method layoutParagraphAtPoint
is the core of the NSTypesetter.
It performs the actual layout process.
Let's take a look at the typesetting process in detail.
Whenever text storage notifies layout manager about
modifications, it requests typesetter to produce layout
by calling layoutCharactersInRange
forLayoutManager maximumNumberOfLineFragments.
Inside in this method implementation, the
typesetter try to determine the next paragraph range
by scanning the string contents
for paragraph separated characters.
Once it finds the paragraph boundary, it calls
setParagraphGlyphRange separatorGlyphRange to self preparing
to preparing in short its internal state
for the next paragraphs range processing,
and it layouts by calling layoutParagraphAtPoint.
Note the argument here, lineFragmentOrigin.
It's a pointer to the NSPoint.
It's the caller's responsibility to fill this
variable with the next lineFragmentOrigin.
Upon return from this method, it is updated
to point to the next lineFragmentOrigin.
Once finished in layouting the paragraph, it goes
back to the step 2 until it exhausts the text layout.
So, you might already guessed in
order to concatenate the paragraph,
the key is to control the paragraph
separated character behavior.
There are many control characters in the Unicode
standard, a character set the Cocoa is based on.
And right now, there are 5 paragraph separator
defined and recognized by the Cocoa text system.
For many of these nonprinted characters,
they are classified as Tab, White Space,
Line Break, Paragraph Break, and Container Break.
Others are simply treated as nonadvancing action.
That means the typesetting process ignores those characters.
And the typesetter method actionForControlCharacterAtIndex
determines the action
to be taken for the character at specified index.
Note that this method could be invoked multiple
times during the course of layout process.
One way of timing is when the typesetter is
trying to determine the paragraph boundary.
It calls this method for each control
character it's scanning and trying to determine
if the control character is supposed
to be treated as paragraph separator.
So, with our subclass of NSTypesetter,
we define a custom attribute,
lineFoldingAttributeName that's supposed to be NSNumber.
Inside our overwrite of actionForControlCharacterAtIndex,
we query the attribute at the specified index.
And if the value exists and returns true, we'll return
NSTypesetterZeroAdvancementAction, so that control character
at that point is just a node from the text system.
Otherwise, we're going to just call super to
let the text system handle the default behavior.
We'll learn how to customize the control character behavior.
Let's make the two texts disappear.
By customizing glyph mapping, you can make text disappear.
Let's take a look.
What is a glyph then?
A glyph is the index for a graphical
element inside the font.
So for example, if you have a letter A, capital letter A
rendered by Chalkboard form that glyph ID, glyph index is 37.
With another font, Zapfino, however, it's totally different.
The glyph ID is 4 in this case and it is
possible the same letter can be mapped
to multiple glyphs inside a single font.
For example, there could be the normal version
of letter A glyph and small cap version
of the letter A could be inside the font if the
font is advanced typographic font like Zapfino.
So, the process for mapping Unicode characters
to glyph ID is called glyph generation.
This is the first step in the typesetting process.
And most of the advanced font architecture
such as industry standard open type structures,
the information inside the font so that
it can be accessed through the glyph IDs.
So by customizing glyph mapping at the first step,
you can influence the rest of the layered process.
And as the name implies, NSGlyphGenerator is
the object that performs a glyph generation.
So, you might think you can just subclass this method
and overwrite to customize a glyph generation process.
Not quite, and this glyph generator is an abstract class for
a class cluster, and the glyph generation logic is increment
in concrete subclass hidden inside a cluster.
But you can access the instance of the complete
subclass using the NSGlyphGenerator factory
method sharedGlyphGenerator.
Once you get the shared instance,
you can request it to generate glyphs
by calling generateGlyphsForGlyphRange,
desiredNumberOfCharacters, glyphIndex, characterIndex.
Note that first item is glyph storage.
It's an object-incrementing NSGlyphStorage protocol.
And this layoutManager itself confirms this
protocol and pass self when invoking this method.
In return, the result is sent back to the
originator using the NSGlyphStorage method.
The core of this protocol is insertGlyphs,
lengths, forStartingGlyphAtIndex, characterIndex.
So exactly how you customize the glyph generation now.
You can actually have a subclass NSGlyphGenerator in
preventing, in conforming to the NSGlyphStorage protocol.
OK, this is the standard configuration.
You have layout manager and shared instance.
The layout manager request glyph generation and in return
the result is sent back using NSGlyphStorage protocol.
Your custom glyph generator can
be in between of those objects.
And your object is implementing in NSGlyphStorage protocol.
The lab manager asks you to generate glyphs and
you pass on the request to the shared instance.
But in this case, you pass self as glyph storage argument.
This short instance sends back the results and
you capture it at point and modify the result,
forward it to the originator layout manager.
So this is our subclass of glyph
generator, line folding glyph generator.
It conforms with the NSGlyphStorage protocol and it has
an instance variable for holding back original requester.
In the implementation of generateGlyphsForGlyphRange beside
the number of characters, glyph index character index
that we have the glyph generate argument.
Then we query the shared instance.
We stash the glyph storage inside instance variable
and forward a request to the shared instance.
In this case, we are sending self as a glyph storage.
In our inside glyphs length for
certain glyph at index matter.
We are customizing the code we receive from the
shared instance and forward the modified result back
to their original requestor, NSLayoutManager here.
What line folding glyph generater does?
It maps the first character inside
the selected range into NSControlGlyph
that tells the layout system to
treat a character as a control glyph.
Remember, we learn how to use the action full control
character index because default implementation
of this method doesn't do anything about characters.
Not the control characters.
It just use the default zero advancement action so
that for the types and purpose this glyph is ignored.
The rest of the branch is mapped to NSNullGlyph.
This is the indication that character at this
index is absorbed by the previous character.
And so we're going to have a range of text.
The attachment is only showing and
the rest are hidden from the users.
We learn how to customize control characters.
Since we hid the text from the users, we are supposed
to provide some kind of visual feedback to the users.
So what we're going to do is try to embed UI widgets inline.
Embedding arbitrary objects is
straightforward using text attachments.
Let's take a look at how to embed
object inside a text system.
As a text system image embedding is like built in.
All you have to do is go into interface
builder and flip a switch.
Attaching of files inside your document is also easy.
All you have to do is implement an NSTextViewDelegate method
that returns or refrains to the file that's being attached.
In fact the whole thing is designed so that you
can embed arbitrary object inside the text contents
using NSTextAttachment.
It's not just about punching holes inside the text
layer so that you can have a space to render images.
Because of the image's design, we have title integration
between text attachment, text view, layout manager,
and they can work in harmony to have
very generic text embedding architecture.
So NSTextAttachment, it encapsulates both storage and icons.
And by reference, NSFileWrapper, it can represent
storage for the document you are attaching.
Also, it can reference NSTextAttachmentCell
that represents that user interaction.
You can feel this is a complete
suite of API for object embedding.
One example of this custom fixed attachment
is, probably you are familiar, NSTokenField,
that all tokens are implemented as a custom text attachment.
So we're using the text system building
block to provide a new functionality.
Whereas, NSTextAttachmentCell, you can customize
the look and feel of your UI objects inline.
For customize or rendering, you can override
drawWithFrame, inView, characterIndex, layoutManager.
For affecting layout, you can overwrite
cellFrameForTextContainer,
proposedLineFragment, glyphPosition, characterIndex.
For interaction with the users, you can customize,
you can overwrite wantsToTrackMouseForEvent,
inRect, ofView, atCharacterIndex.
That provides a hit testing for you, and you once you
decided the mouse pointer is inside your attachment object,
you can have-- you can handle the mouse event using
trackMouse, inRect, ofView, atCharacterIndex, untilMouseUp.
You know how to customize the TextAttachmentCell now.
But as you've seen, we don't want to patch the contents
of the text to show the text attachment, do we?
If you modify text contents, the text attachment
might appear at an intimate place in your application.
So what you want to do here is synthesize
the TextAttachmentAttribute on the fly.
It's pretty easy.
While subclassing NSTextStorage object itself,
we have a subclass of NSTextStorage
called LineFoldingTextStorage
that has a property lineFoldingEnabled.
And whenever this property is on, we want to synthesize
the TextAttachmentAttribute and return to the caller.
This is attributes at index FF2 range.
This is one of the primary methods you want to
overwrite when you're subclassing NSAttributedString.
You can go to the head of file on
NSAttributedString or NSTextStorage to learn how
to subclass the NSTextStorage subclass class tenure.
Inside that-- inside this method, we can
access our backing store, attributed string.
This is the object that actually provides
the storage for string and attributes.
You could use another NSTextStorage using the base
class or NSAttribute-- NSMutableAttributedString.
Now, we're going to ask the attributes at index,
specify, if we have the line folding enabled.
We're going to add custom text attachment attribute to
the return attributes and send it back to the caller.
Of course, you want to control when you
want to synthesize these attributes.
When the property is on, you want to
synthesize the attribute on a fly.
When, only when the text system is rendering the glyphs on
the screen or into some other devices or it's laying out.
Since you've learned how the layout system works so far, you
can determine to overwrite and enable this property easily.
There are two places, two good places to overwrite.
The one is a layout manager method,
drawGlyphsForGlyphRange:atPoint.
This is when that layout system renders the glyphs
on screen or printer, or some other devices.
Another method, NSATSTypestter, this is our
default concrete subclass over the NSTypesetter.
We've seen layoutParagraphAtPoint.
This is where the heart of the
typesetting process is executed.
So, you can subclass NSATSTypesetter and overwrite this
method to enable the line folding enabled property.
So, in between these setting, we can call
super to execute the layouting process
or rendering process provided by the base classes.
We've learned how to control characters.
We learned how to customize glyph generation.
And we've learned how to use the attachment and zipfile
by the text attachment on the fly
by subclassing NSTextStorage.
So, we've already learned how to
overwrite many text system primary classes,
let's cover how to animate text with the text system.
Since you've learned the details of a layout
process, now, you can apply the knowledge
to manipulate a text just as a normal graphic elements.
So, you know, text is nothing special.
It's just bits on a screen.
And since it's a graphical element just like
image, you can move it around, scale it, rotate it.
There's nothing special about it.
But there are something you need to remember when you want
to animate, move around the text inside your applications.
First, you might get tempted to animate in smooth chance.
You know, if your character flies
around, it might feel cool.
But you have to consider the performance implications here.
Since there are small units moving around inside
the application, that could be hidden over there.
So often, it is effective enough to animate by work.
Another important part is know when
to capture the animation frames.
It's often critical to determine the
starting and endpoint in doing the animation.
You might consider simply to just toggle once layout
property in NSTextView if you want to do text animation.
We actually don't recommend to use this approach.
Instead, you can attach your own overlay
view on top of the TextView on the fly.
So, you know, you can have overlay
view with layer enabled that copies,
the content of the text you're
animating can attach to the TextView.
And note, you can use the visible rect to determine
what kind of size you want to animate here.
There are some advantage using this technique.
By using techniques, you can simplify your animation logic.
Whenever using NSTextView on a screen,
you know, there are ordinary objects
that already show NSView that's
attached to the NSTextView structure.
There are often you can find NSScrollView, NSScroller,
NSClipView that's surrounding NSTextView object itself.
And by using overlay technique, you don't
have to worry about the interactions
with this ordinary object when animating.
Also, since you are not modifying the
display contents of TextView while animating,
it's much easier to determine when
to capture the animation frames.
So, you know, you can safely use the layout manager attached
to the TextView to determine the rectangular boundingRect
for your animation GlyphRange or you can let the
layoutManager to render into your overlay at will.
And since you are ensuring to enable the layers only
to the overlay views that's visible to the users,
you know that you are not enabling some hidden costs to
the ordinary objects, you can manage efficient animation
without worrying about additional layer objects
enabled by flipping a single view once layer property.
Also, since the layout background
was overlaid, it's under control.
It's under your control.
You can easily prevent the font smoothing issues.
OK. What is a font smoothing issues?
Probably you've seen these issues a lot
when you are trying to use CoreAnimation.
Font smoothing, also known as subpixel
rendering, is taking advantage of the fact
that the LCD display is outlining
the LGB pixels horizontally.
And by controlling these individual glyphs
instead of treating as the LGB pixel
as a single unit, you can increase the virtual resolution.
This is a pretty new trick.
And you can make the font really crisp and
readable and smooth as the name implies.
But unfortunately, this technology does
not work with transfer and background.
Well, you know, if you know how the font smoothing
technology works, it's pretty obvious because it has
to control each color pixel to show the smooth edge.
In order to choose the right color,
the font smoothing graphic system needs
to know the final destination background color.
So, if you are rendering into non-opaque
background layer, that force cannot determine
which pixel to enable for font smoothing.
So, to prevent that, the most obvious choice is to
use opaque layer background as much as possible.
With our example, we are using the TextView's
background color while animating the text.
And if it's not possible to use that opaque background,
it's OK to do smooth font smoothing while animating.
The difference is subtle and not too legible
while the text is moving around on your screen.
When you do that, you might want to fudge up the
edges by applying the shadow to the animating text,
and try to provide smooth transition by dissolving
that non-smooth text into the final rendering.
So, with our sample applications, we provide this overlay
that covers the entire visible rect of the TextView.
And we have another subview of the
base overlay and animating overlay
that captures the content of the current selected range.
And by moving the overlay view using the standard
Cocoa Animation API, you can move the text.
It's easy.
So, this is our overlay object.
It's an NSView subclass, and it defines a
property holding a-- rendering logic as a block.
Inside your rect, it simply invokes this rendering block.
So, how you want to cache the text into your layer?
First, you have to determine the
boundingRect for the text you are animating.
In this case, we're using layoutManager method
boundingRectForGlyphRange inTextContainer.
In this case, the boundingRect return is
in the TextContainer coordinate system.
So, it's inside a virtual text layout coordinate system.
You want to translate the bounds so that
the glyph range is at the overlay origin.
You can render the glyphs inside the layer
using the method we've seen before layoutManager
drawGlyphsForGlyphRange atPoint.
In order to ensure that the caching operation is executed
at the right moment, you can manually code this by method.
This is one of the places, you know,
calling the display method is recommended.
OK. Another way you can control how
you capture the animation frames.
You can use the textStorage transaction
model to control the layout process.
So, you are capturing the animation
frames at the right moment.
There are textStorage method beginEditing and endEditing.
In pair, it should provides and represents the transaction.
So, inside this transaction, you can capture
animation state while modifying the text contents.
Since the layer process is delayed until
endEditing is performed, unless you, you know,
did drastic change like deleting text or inserting text,
you are OK here as long as the change affects the layout.
This is convenient because you might be changing and
caching the layout frames and uncontinuous ranges like this.
It uses selected multiple ranges.
It's convenient to execute in one chunk
inside the block the enumerateObject method.
OK. We'll learn how to use the primary classes to
provide flexible images configurations and learn how
to use a layout view, and how to
subclass and customize the layout process.
And we touched the text attachment [inaudible]
user interface, and cover the text animation.
In summary, the Cocoa text system provides
virtually unlimited customizability.
It is designed to serve very high-end applications
like word processor or page design tools.
Its modular design based on NBC design panning
allows the customization at the right level.
Finally, if you are trying to customize, try to find
the customization point where is the primary classes
like TextView, there are many NSTextView delegate
method you can use to customize virtually all
of the user interaction that text system provides.
If we cannot find the right customization
point with the primary class,
you can dug deeper to the helper classes we discussed today.
We have sessions coming up.
And you can attend.
By attending the sessions, you can complement
your understanding of the text system.
For more information, you can contact our
Evangelist Bill Dudney and we have fabulous set
of technical documentation explaining the text architecture.
You can go to this Cocoa Text Architecture Guide
and it points to other detailed documentation.
And of course, Apple Developer Forum
is a good place to ask questions.