mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-05-31 19:10:48 +00:00
Layout manager glyph implementation ... initial hack complete.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@8749 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
0450dd0ef1
commit
fe387730fc
3 changed files with 352 additions and 173 deletions
|
@ -1,3 +1,11 @@
|
||||||
|
2001-01-22 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
|
* Source/NSLayoutManager.m: loads of glyph changes - added some
|
||||||
|
implementation notes. Implemented gaps in the glyphs stream.
|
||||||
|
I think all glyph methods are implemented now (probably).
|
||||||
|
Really needs someone elses eye casting over it, to try to
|
||||||
|
catch any obvious bugs.
|
||||||
|
|
||||||
2001-01-20 Fred Kiefer <FredKiefer@gmx.de>
|
2001-01-20 Fred Kiefer <FredKiefer@gmx.de>
|
||||||
|
|
||||||
* Source/NSBezierPath.m
|
* Source/NSBezierPath.m
|
||||||
|
|
|
@ -109,11 +109,12 @@ typedef enum {
|
||||||
NSTypesetter *_typesetter;
|
NSTypesetter *_typesetter;
|
||||||
|
|
||||||
void *_glyphData; // Private glyph storage.
|
void *_glyphData; // Private glyph storage.
|
||||||
void *_currentGlyphs;
|
void *_currentGlyphs; // Current chunk pointer.
|
||||||
|
unsigned _currentGlyph; // Current glyph index.
|
||||||
void *_glyphGaps; // Gaps in character mapping.
|
void *_glyphGaps; // Gaps in character mapping.
|
||||||
unsigned _chunkIndex;
|
unsigned _chunkIndex; // Current chunk in glyph stream.
|
||||||
unsigned _glyphIndex;
|
unsigned _glyphIndex; // Current glyph in chunk.
|
||||||
unsigned _endCharIndex; // After last char with generated glyph.
|
unsigned _numberOfGlyphs; // After last generated glyph.
|
||||||
|
|
||||||
NSGlyphGenerator *_glyphGenerator;
|
NSGlyphGenerator *_glyphGenerator;
|
||||||
NSStorage *_containerUsedRects;
|
NSStorage *_containerUsedRects;
|
||||||
|
|
|
@ -190,6 +190,58 @@ offsetSort(GSIArrayItem i0, GSIArrayItem i1)
|
||||||
return NSOrderedSame;
|
return NSOrderedSame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Glyph management implementation notes (January 2001)
|
||||||
|
* Author - Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
*
|
||||||
|
* An NSLayoutManager object maintains a 'glyph stream' which contains the
|
||||||
|
* actual symbols to be displayed in text. This glyph stream is conceptually
|
||||||
|
* an array of glyphs and certain attributes.
|
||||||
|
*
|
||||||
|
* Each glyph has an associated index of the corresponding character in the
|
||||||
|
* text storage object. Since more than one character may map to a single
|
||||||
|
* glyphs, the character index for a glyph is the index of the first
|
||||||
|
* character corresponing to the glyph. Since more than one glyph may map
|
||||||
|
* on to the same character, adjacent glyphs in the glyph stream may have
|
||||||
|
* the same character index.
|
||||||
|
*
|
||||||
|
* Other attributes of a glyph include flags to say whether the glyph is to
|
||||||
|
* be drawn or not, and how it should be layed out with respect to the
|
||||||
|
* preceeding glyph in the stream (allowing for overstrike etc).
|
||||||
|
*
|
||||||
|
* Since the state of the text storage object may change, glyphs may be
|
||||||
|
* deleted from the stream from time to time, leaving a situation where
|
||||||
|
* not all characters in the text storage have corresponding glyphs in
|
||||||
|
* the glyph stream. This state is called a 'gap'. We maintain an array
|
||||||
|
* of the locations of the gaps in the glyph stream. When we attempt to
|
||||||
|
* access a glyph, we must generate new glyphs from the text storage to
|
||||||
|
* fill any gaps in the glyphs stream and insert them into the stream.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* The glyph stream is actually implemented as an array of 'chunks' -
|
||||||
|
* where a chunk contains an array of glyphs, and array of the glyph
|
||||||
|
* attributes, and the glyph and character indices of the first glyph
|
||||||
|
* in the chunk. The remaining character/glyph indices are calculated
|
||||||
|
* as offsets from the first glyph in the chunk.
|
||||||
|
*
|
||||||
|
* This implementation is used for speed of manipulation of very large
|
||||||
|
* documents - modifications to a single chunk may have their effects
|
||||||
|
* to some degree localised to that chunk.
|
||||||
|
*
|
||||||
|
* Invariants ...
|
||||||
|
* 1. The glyph stream is a continuous array of glyphs ranging from 0 up.
|
||||||
|
* 2. The character index of a glyph in the glyph stream is greater than
|
||||||
|
* or equal to that of the glyph that preceeds it.
|
||||||
|
* 3. The gap array contains glyph indices in numeric order and where no
|
||||||
|
* index exceeds the length of the glyph stream.
|
||||||
|
* 4. The glyph stream consists of at least one chunk whose glyph index
|
||||||
|
* is zero.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Structure to handle the storage of the glyph stream.
|
* Structure to handle the storage of the glyph stream.
|
||||||
* This is done as an array of chunks.
|
* This is done as an array of chunks.
|
||||||
|
@ -242,13 +294,13 @@ glyphIndexSort(GSIArrayItem i0, GSIArrayItem i1)
|
||||||
* Glyph management functions.
|
* Glyph management functions.
|
||||||
*/
|
*/
|
||||||
static GSGlyphChunk*
|
static GSGlyphChunk*
|
||||||
GSCreateGlyphChunk(unsigned charIndex)
|
GSCreateGlyphChunk(unsigned glyphIndex, unsigned charIndex)
|
||||||
{
|
{
|
||||||
GSGlyphChunk *chunk;
|
GSGlyphChunk *chunk;
|
||||||
|
|
||||||
chunk = NSZoneMalloc(NSDefaultMallocZone(), sizeof(GSGlyphChunk));
|
chunk = NSZoneMalloc(NSDefaultMallocZone(), sizeof(GSGlyphChunk));
|
||||||
chunk->charIndex = charIndex;
|
chunk->charIndex = charIndex;
|
||||||
chunk->glyphIndex = 0;
|
chunk->glyphIndex = glyphIndex;
|
||||||
GSIArrayInitWithZoneAndCapacity(&chunk->glyphs, NSDefaultMallocZone(), 8);
|
GSIArrayInitWithZoneAndCapacity(&chunk->glyphs, NSDefaultMallocZone(), 8);
|
||||||
GSIArrayInitWithZoneAndCapacity(&chunk->attrs, NSDefaultMallocZone(), 8);
|
GSIArrayInitWithZoneAndCapacity(&chunk->attrs, NSDefaultMallocZone(), 8);
|
||||||
return chunk;
|
return chunk;
|
||||||
|
@ -262,43 +314,6 @@ GSDestroyGlyphChunk(GSGlyphChunk *chunk)
|
||||||
NSZoneFree(NSDefaultMallocZone(), chunk);
|
NSZoneFree(NSDefaultMallocZone(), chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
GSDestroyChunks(GSIArray *where)
|
|
||||||
{
|
|
||||||
if (*where != 0)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Release all glyph chunk information
|
|
||||||
*/
|
|
||||||
i = GSIArrayCount(*where);
|
|
||||||
while (i-- > 0)
|
|
||||||
{
|
|
||||||
GSGlyphChunk *chunk;
|
|
||||||
|
|
||||||
chunk = (GSGlyphChunk*)(GSIArrayItemAtIndex(*where, i).ptr);
|
|
||||||
GSDestroyGlyphChunk(chunk);
|
|
||||||
}
|
|
||||||
GSIArrayEmpty(*where);
|
|
||||||
NSZoneFree(NSDefaultMallocZone(), *where);
|
|
||||||
*where = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GSGlyphChunk*
|
|
||||||
GSCreateChunks(GSIArray *where)
|
|
||||||
{
|
|
||||||
GSGlyphChunk *chunk;
|
|
||||||
|
|
||||||
GSDestroyChunks(where);
|
|
||||||
*where = NSZoneMalloc(NSDefaultMallocZone(), sizeof(GSIArray_t));
|
|
||||||
GSIArrayInitWithZoneAndCapacity(*where, NSDefaultMallocZone(), 8);
|
|
||||||
chunk = GSCreateGlyphChunk(0);
|
|
||||||
GSIArrayInsertItem(*where, (GSIArrayItem)(void*)chunk, 0);
|
|
||||||
return chunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned
|
static inline unsigned
|
||||||
GSCharIndexForGlyphInChunk(GSGlyphChunk *chunk, unsigned index)
|
GSCharIndexForGlyphInChunk(GSGlyphChunk *chunk, unsigned index)
|
||||||
{
|
{
|
||||||
|
@ -354,12 +369,12 @@ typedef struct {
|
||||||
|
|
||||||
#define _chunks ((GSIArray)(((lmDefs)lm)->_glyphData))
|
#define _chunks ((GSIArray)(((lmDefs)lm)->_glyphData))
|
||||||
#define _chunk ((GSGlyphChunk*)(((lmDefs)lm)->_currentGlyphs))
|
#define _chunk ((GSGlyphChunk*)(((lmDefs)lm)->_currentGlyphs))
|
||||||
#define _index ((lmDefs)lm)->_chunkIndex
|
#define _current (((lmDefs)lm)->_currentGlyph)
|
||||||
#define _offset ((lmDefs)lm)->_glyphIndex
|
#define _index (((lmDefs)lm)->_chunkIndex)
|
||||||
|
#define _offset (((lmDefs)lm)->_glyphIndex)
|
||||||
#define _gaps ((GSIArray)(((lmDefs)lm)->_glyphGaps))
|
#define _gaps ((GSIArray)(((lmDefs)lm)->_glyphGaps))
|
||||||
|
|
||||||
|
|
||||||
static void _Adjust(NSLayoutManager *lm, unsigned from, int by);
|
|
||||||
static GSGlyphAttrs _Attrs(NSLayoutManager *lm);
|
static GSGlyphAttrs _Attrs(NSLayoutManager *lm);
|
||||||
static BOOL _Back(NSLayoutManager *lm);
|
static BOOL _Back(NSLayoutManager *lm);
|
||||||
static unsigned _CharIndex(NSLayoutManager *lm);
|
static unsigned _CharIndex(NSLayoutManager *lm);
|
||||||
|
@ -372,54 +387,13 @@ static void _SetGlyph(NSLayoutManager *lm, NSGlyph g);
|
||||||
static BOOL _Step(NSLayoutManager *lm);
|
static BOOL _Step(NSLayoutManager *lm);
|
||||||
|
|
||||||
|
|
||||||
static inline GSGlyphAttrs
|
|
||||||
_Attrs(NSLayoutManager *lm)
|
|
||||||
{
|
|
||||||
return GSIArrayItemAtIndex(&_chunk->attrs, _offset).ext;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
_SetAttrs(NSLayoutManager *lm, GSGlyphAttrs a)
|
|
||||||
{
|
|
||||||
GSIArraySetItemAtIndex(&_chunk->attrs, (GSIArrayItem)a, _offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_Adjust(NSLayoutManager *lm, unsigned from, int lengthChange)
|
|
||||||
{
|
|
||||||
if (from < [((lmDefs)lm)->_textStorage length])
|
|
||||||
{
|
|
||||||
_JumpToGlyph(lm, from);
|
|
||||||
/*
|
|
||||||
* Adjust character offsets for all glyphs in this chunk.
|
|
||||||
*/
|
|
||||||
if (_offset > 0)
|
|
||||||
{
|
|
||||||
while (_offset < GSIArrayCount(&_chunk->glyphs))
|
|
||||||
{
|
|
||||||
GSGlyphAttrs attrs = _Attrs(lm);
|
|
||||||
|
|
||||||
attrs.offset += lengthChange;
|
|
||||||
_SetAttrs(lm, attrs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Now adjust character offsets for remaining chunks.
|
|
||||||
*/
|
|
||||||
while (++_index < GSIArrayCount(_chunks))
|
|
||||||
{
|
|
||||||
_chunk = (GSGlyphChunk*)GSIArrayItemAtIndex(_chunks, _index).ptr;
|
|
||||||
_chunk->charIndex += lengthChange;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline BOOL
|
static inline BOOL
|
||||||
_Back(NSLayoutManager *lm)
|
_Back(NSLayoutManager *lm)
|
||||||
{
|
{
|
||||||
if (_offset > 0)
|
if (_offset > 0)
|
||||||
{
|
{
|
||||||
_offset--;
|
_offset--;
|
||||||
|
_current--;
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
else if (_index > 0)
|
else if (_index > 0)
|
||||||
|
@ -427,6 +401,7 @@ _Back(NSLayoutManager *lm)
|
||||||
_index--;
|
_index--;
|
||||||
_chunk = (GSGlyphChunk*)GSIArrayItemAtIndex(_chunks, _index).ptr;
|
_chunk = (GSGlyphChunk*)GSIArrayItemAtIndex(_chunks, _index).ptr;
|
||||||
_offset = GSIArrayCount(&_chunk->glyphs) - 1;
|
_offset = GSIArrayCount(&_chunk->glyphs) - 1;
|
||||||
|
_current--;
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -435,6 +410,79 @@ _Back(NSLayoutManager *lm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline BOOL
|
||||||
|
_Step(NSLayoutManager *lm)
|
||||||
|
{
|
||||||
|
if (_offset < GSIArrayCount(&_chunk->glyphs) - 1)
|
||||||
|
{
|
||||||
|
_offset++;
|
||||||
|
_current++;
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_index < GSIArrayCount(_chunks) - 1)
|
||||||
|
{
|
||||||
|
_index++;
|
||||||
|
_chunk = (GSGlyphChunk*)GSIArrayItemAtIndex(_chunks, _index).ptr;
|
||||||
|
_offset = 0;
|
||||||
|
_current++;
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adjust the character indices for all the glyphs from the specified
|
||||||
|
* location onwards. Leave the current glyphs set to the 'from' location.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
_Adjust(NSLayoutManager *lm, unsigned from, int lengthChange)
|
||||||
|
{
|
||||||
|
if (_JumpToGlyph(lm, from) == YES)
|
||||||
|
{
|
||||||
|
GSGlyphChunk *chunk = _chunk;
|
||||||
|
unsigned index = _index;
|
||||||
|
unsigned offset = _offset;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adjust character offsets for all glyphs in this chunk.
|
||||||
|
*/
|
||||||
|
if (offset > 0)
|
||||||
|
{
|
||||||
|
while (offset < GSIArrayCount(&chunk->glyphs))
|
||||||
|
{
|
||||||
|
GSGlyphAttrs a;
|
||||||
|
|
||||||
|
a = GSIArrayItemAtIndex(&chunk->attrs, offset).ext;
|
||||||
|
a.offset += lengthChange;
|
||||||
|
GSIArraySetItemAtIndex(&chunk->attrs, (GSIArrayItem)a, offset);
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now adjust character offsets for remaining chunks.
|
||||||
|
*/
|
||||||
|
while (index < GSIArrayCount(_chunks))
|
||||||
|
{
|
||||||
|
chunk = (GSGlyphChunk*)GSIArrayItemAtIndex(_chunks, index).ptr;
|
||||||
|
index++;
|
||||||
|
chunk->charIndex += lengthChange;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline GSGlyphAttrs
|
||||||
|
_Attrs(NSLayoutManager *lm)
|
||||||
|
{
|
||||||
|
return GSIArrayItemAtIndex(&_chunk->attrs, _offset).ext;
|
||||||
|
}
|
||||||
|
|
||||||
static inline unsigned
|
static inline unsigned
|
||||||
_CharIndex(NSLayoutManager *lm)
|
_CharIndex(NSLayoutManager *lm)
|
||||||
{
|
{
|
||||||
|
@ -485,6 +533,7 @@ _JumpToChar(NSLayoutManager *lm, unsigned charIndex)
|
||||||
_chunk = c;
|
_chunk = c;
|
||||||
_index = i;
|
_index = i;
|
||||||
_offset = o;
|
_offset = o;
|
||||||
|
_current = c->glyphIndex + o;
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,6 +544,24 @@ _JumpToGlyph(NSLayoutManager *lm, unsigned glyphIndex)
|
||||||
unsigned i;
|
unsigned i;
|
||||||
unsigned o;
|
unsigned o;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attempt a little optimisation based on the current glyph index -
|
||||||
|
* avoid binary search through glyph chunks if a simpler operation
|
||||||
|
* will suffice.
|
||||||
|
*/
|
||||||
|
if (glyphIndex == _current)
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
else if (glyphIndex == _current + 1)
|
||||||
|
{
|
||||||
|
return _Step(lm);
|
||||||
|
}
|
||||||
|
else if (glyphIndex == _current - 1)
|
||||||
|
{
|
||||||
|
return _Back(lm);
|
||||||
|
}
|
||||||
|
|
||||||
i = GSChunkForGlyphIndex(_chunks, glyphIndex);
|
i = GSChunkForGlyphIndex(_chunks, glyphIndex);
|
||||||
c = (GSGlyphChunk*)GSIArrayItemAtIndex(_chunks, i).ptr;
|
c = (GSGlyphChunk*)GSIArrayItemAtIndex(_chunks, i).ptr;
|
||||||
o = glyphIndex - c->glyphIndex;
|
o = glyphIndex - c->glyphIndex;
|
||||||
|
@ -503,6 +570,7 @@ _JumpToGlyph(NSLayoutManager *lm, unsigned glyphIndex)
|
||||||
_chunk = c;
|
_chunk = c;
|
||||||
_index = i;
|
_index = i;
|
||||||
_offset = o;
|
_offset = o;
|
||||||
|
_current = c->glyphIndex + o;
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -511,36 +579,18 @@ _JumpToGlyph(NSLayoutManager *lm, unsigned glyphIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
_SetAttrs(NSLayoutManager *lm, GSGlyphAttrs a)
|
||||||
|
{
|
||||||
|
GSIArraySetItemAtIndex(&_chunk->attrs, (GSIArrayItem)a, _offset);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
_SetGlyph(NSLayoutManager *lm, NSGlyph g)
|
_SetGlyph(NSLayoutManager *lm, NSGlyph g)
|
||||||
{
|
{
|
||||||
GSIArraySetItemAtIndex(&_chunk->glyphs, (GSIArrayItem)g, _offset);
|
GSIArraySetItemAtIndex(&_chunk->glyphs, (GSIArrayItem)g, _offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline BOOL
|
|
||||||
_Step(NSLayoutManager *lm)
|
|
||||||
{
|
|
||||||
if (_offset < GSIArrayCount(&_chunk->glyphs) - 1)
|
|
||||||
{
|
|
||||||
_offset++;
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_index < GSIArrayCount(_chunks) - 1)
|
|
||||||
{
|
|
||||||
_index++;
|
|
||||||
_chunk = (GSGlyphChunk*)GSIArrayItemAtIndex(_chunks, _index).ptr;
|
|
||||||
_offset = 0;
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@interface GSRunStorage : NSObject
|
@interface GSRunStorage : NSObject
|
||||||
|
@ -749,15 +799,20 @@ _Step(NSLayoutManager *lm)
|
||||||
* Initialise glyph storage and ivars to contain 'current' glyph
|
* Initialise glyph storage and ivars to contain 'current' glyph
|
||||||
* location information.
|
* location information.
|
||||||
*/
|
*/
|
||||||
_currentGlyphs = GSCreateChunks((GSIArray*)&_glyphData);
|
_glyphData = NSZoneMalloc(NSDefaultMallocZone(), sizeof(GSIArray_t));
|
||||||
|
GSIArrayInitWithZoneAndCapacity(glyphChunks, NSDefaultMallocZone(), 8);
|
||||||
|
_currentGlyphs = GSCreateGlyphChunk(0, 0);
|
||||||
|
GSIArrayInsertItem(glyphChunks, (GSIArrayItem)_currentGlyphs, 0);
|
||||||
_chunkIndex = 0;
|
_chunkIndex = 0;
|
||||||
_glyphIndex = 0;
|
_glyphIndex = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialise storage of holes in the glyph stream.
|
* Initialise storage of gaps in the glyph stream.
|
||||||
|
* The initial glyph stream is one big gap starting at index 0!
|
||||||
*/
|
*/
|
||||||
a = NSZoneMalloc(NSDefaultMallocZone(), sizeof(GSIArray_t));
|
a = NSZoneMalloc(NSDefaultMallocZone(), sizeof(GSIArray_t));
|
||||||
GSIArrayInitWithZoneAndCapacity(a, NSDefaultMallocZone(), 8);
|
GSIArrayInitWithZoneAndCapacity(a, NSDefaultMallocZone(), 8);
|
||||||
|
GSIArrayInsertItem(a, (GSIArrayItem)(unsigned long)0, 0);
|
||||||
_glyphGaps = a;
|
_glyphGaps = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -766,7 +821,22 @@ _Step(NSLayoutManager *lm)
|
||||||
|
|
||||||
- (void) dealloc
|
- (void) dealloc
|
||||||
{
|
{
|
||||||
GSDestroyChunks((GSIArray*)&_glyphData);
|
unsigned i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Release all glyph chunk information
|
||||||
|
*/
|
||||||
|
i = GSIArrayCount(glyphChunks);
|
||||||
|
while (i-- > 0)
|
||||||
|
{
|
||||||
|
GSGlyphChunk *chunk;
|
||||||
|
|
||||||
|
chunk = (GSGlyphChunk*)(GSIArrayItemAtIndex(glyphChunks, i).ptr);
|
||||||
|
GSDestroyGlyphChunk(chunk);
|
||||||
|
}
|
||||||
|
GSIArrayEmpty(glyphChunks);
|
||||||
|
NSZoneFree(NSDefaultMallocZone(), _glyphData);
|
||||||
|
_glyphData = 0;
|
||||||
|
|
||||||
GSIArrayEmpty((GSIArray)_glyphGaps);
|
GSIArrayEmpty((GSIArray)_glyphGaps);
|
||||||
NSZoneFree(NSDefaultMallocZone(), _glyphGaps);
|
NSZoneFree(NSDefaultMallocZone(), _glyphGaps);
|
||||||
|
@ -937,7 +1007,33 @@ _Step(NSLayoutManager *lm)
|
||||||
/*
|
/*
|
||||||
* Now adjust character locations for glyphs if necessary.
|
* Now adjust character locations for glyphs if necessary.
|
||||||
*/
|
*/
|
||||||
_Adjust(self, NSMaxRange(cRange), lengthChange);
|
_Adjust(self, gRange.location, lengthChange);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unless the 'lengthChange' accounts for the entire character range
|
||||||
|
* that we deleted glyphs for, we must note the presence of a gap.
|
||||||
|
*/
|
||||||
|
if (cRange.length + lengthChange > 0)
|
||||||
|
{
|
||||||
|
unsigned pos;
|
||||||
|
|
||||||
|
for (pos = 0; pos < GSIArrayCount((GSIArray)_glyphGaps); pos++)
|
||||||
|
{
|
||||||
|
unsigned val;
|
||||||
|
|
||||||
|
val = (unsigned)GSIArrayItemAtIndex((GSIArray)_glyphGaps, pos).ulng;
|
||||||
|
if (val == gRange.location)
|
||||||
|
{
|
||||||
|
break; // Gap already marked here.
|
||||||
|
}
|
||||||
|
if (val > gRange.location)
|
||||||
|
{
|
||||||
|
GSIArrayInsertItem((GSIArray)_glyphGaps,
|
||||||
|
(GSIArrayItem)gRange.location, pos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME - should invalidate the character range ... but what does that mean?
|
// FIXME - should invalidate the character range ... but what does that mean?
|
||||||
}
|
}
|
||||||
|
@ -1093,8 +1189,7 @@ invalidatedRange.length);
|
||||||
* Invariants ...
|
* Invariants ...
|
||||||
* a) Glyph chunks are ordered sequentially from zero by character index.
|
* a) Glyph chunks are ordered sequentially from zero by character index.
|
||||||
* b) Glyph chunks are ordered sequentially from zero by glyph index.
|
* b) Glyph chunks are ordered sequentially from zero by glyph index.
|
||||||
* c) Adjacent glyphs in the same chunk may share a character index.
|
* c) Adjacent glyphs may share a character index.
|
||||||
* d) _endCharIndex is the index one after the last character in the glyphs.
|
|
||||||
*/
|
*/
|
||||||
- (void) insertGlyph: (NSGlyph)aGlyph
|
- (void) insertGlyph: (NSGlyph)aGlyph
|
||||||
atGlyphIndex: (unsigned)glyphIndex
|
atGlyphIndex: (unsigned)glyphIndex
|
||||||
|
@ -1103,6 +1198,7 @@ invalidatedRange.length);
|
||||||
unsigned chunkCount = GSIArrayCount(glyphChunks);
|
unsigned chunkCount = GSIArrayCount(glyphChunks);
|
||||||
GSGlyphAttrs attrs = { 0 };
|
GSGlyphAttrs attrs = { 0 };
|
||||||
GSGlyphChunk *chunk;
|
GSGlyphChunk *chunk;
|
||||||
|
unsigned pos;
|
||||||
|
|
||||||
if (glyphIndex == 0 && chunkCount == 0)
|
if (glyphIndex == 0 && chunkCount == 0)
|
||||||
{
|
{
|
||||||
|
@ -1110,7 +1206,7 @@ invalidatedRange.length);
|
||||||
* Special case - if there are no chunks, this is the
|
* Special case - if there are no chunks, this is the
|
||||||
* very first glyph and can simply be added to a new chunk.
|
* very first glyph and can simply be added to a new chunk.
|
||||||
*/
|
*/
|
||||||
chunk = GSCreateGlyphChunk(charIndex);
|
chunk = GSCreateGlyphChunk(glyphIndex, charIndex);
|
||||||
GSIArrayAddItem(&chunk->glyphs, (GSIArrayItem)aGlyph);
|
GSIArrayAddItem(&chunk->glyphs, (GSIArrayItem)aGlyph);
|
||||||
GSIArrayAddItem(&chunk->attrs, (GSIArrayItem)attrs);
|
GSIArrayAddItem(&chunk->attrs, (GSIArrayItem)attrs);
|
||||||
GSIArrayAddItem(glyphChunks, (GSIArrayItem)(void*)chunk);
|
GSIArrayAddItem(glyphChunks, (GSIArrayItem)(void*)chunk);
|
||||||
|
@ -1120,7 +1216,6 @@ invalidatedRange.length);
|
||||||
unsigned glyphCount;
|
unsigned glyphCount;
|
||||||
unsigned glyphOffset;
|
unsigned glyphOffset;
|
||||||
unsigned chunkIndex;
|
unsigned chunkIndex;
|
||||||
unsigned pos;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Locate the chunk that we should insert into - the last one with
|
* Locate the chunk that we should insert into - the last one with
|
||||||
|
@ -1274,8 +1369,8 @@ invalidatedRange.length);
|
||||||
*/
|
*/
|
||||||
splitChar
|
splitChar
|
||||||
= (GSIArrayItemAtIndex(&chunk->attrs, splitAt).ext).offset;
|
= (GSIArrayItemAtIndex(&chunk->attrs, splitAt).ext).offset;
|
||||||
newChunk = GSCreateGlyphChunk(chunk->charIndex + splitChar);
|
newChunk = GSCreateGlyphChunk(chunk->glyphIndex + splitAt,
|
||||||
newChunk->glyphIndex = chunk->glyphIndex + splitAt;
|
chunk->charIndex + splitChar);
|
||||||
GSIArrayInsertItem(glyphChunks, (GSIArrayItem)(void*)newChunk,
|
GSIArrayInsertItem(glyphChunks, (GSIArrayItem)(void*)newChunk,
|
||||||
chunkIndex+1);
|
chunkIndex+1);
|
||||||
pos = 0;
|
pos = 0;
|
||||||
|
@ -1359,6 +1454,25 @@ invalidatedRange.length);
|
||||||
chunk->glyphIndex++;
|
chunk->glyphIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_numberOfGlyphs++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now adjust gaps to handle glyph insertion.
|
||||||
|
*/
|
||||||
|
pos = 0;
|
||||||
|
while (pos < GSIArrayCount((GSIArray)_glyphGaps))
|
||||||
|
{
|
||||||
|
unsigned long val;
|
||||||
|
|
||||||
|
val = GSIArrayItemAtIndex((GSIArray)_glyphGaps, pos).ulng;
|
||||||
|
if (val >= glyphIndex)
|
||||||
|
{
|
||||||
|
GSIArraySetItemAtIndex((GSIArray)_glyphGaps, (GSIArrayItem)(val+1),
|
||||||
|
pos);
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are any holes in the glyph stream this will cause glyph
|
// If there are any holes in the glyph stream this will cause glyph
|
||||||
|
@ -1385,40 +1499,60 @@ invalidatedRange.length);
|
||||||
isValidIndex: (BOOL*)flag
|
isValidIndex: (BOOL*)flag
|
||||||
{
|
{
|
||||||
#if USE_GLYPHS
|
#if USE_GLYPHS
|
||||||
/*
|
if (GSIArrayCount((GSIArray)_glyphGaps) > 0
|
||||||
* If the chunk located doesn't contain the index we want,
|
&& (GSIArrayItemAtIndex((GSIArray)_glyphGaps, 0).ulng) <= index)
|
||||||
* we must need to generate more glyphs from the text.
|
|
||||||
*/
|
|
||||||
if (_JumpToGlyph(self, index) == NO)
|
|
||||||
{
|
{
|
||||||
GSGlyphChunk *chunk = (GSGlyphChunk*)_currentGlyphs;
|
|
||||||
unsigned pos = _chunkIndex;
|
|
||||||
unsigned numChars;
|
|
||||||
unsigned numGlyphs;
|
|
||||||
NSString *string;
|
NSString *string;
|
||||||
|
unsigned long gap;
|
||||||
|
unsigned textLength;
|
||||||
|
|
||||||
numChars = [_textStorage length];
|
|
||||||
numGlyphs = chunk->glyphIndex + GSIArrayCount(&chunk->glyphs);
|
|
||||||
string = [_textStorage string];
|
string = [_textStorage string];
|
||||||
|
textLength = [string length];
|
||||||
|
|
||||||
/*
|
while (GSIArrayCount((GSIArray)_glyphGaps) > 0
|
||||||
* FIXME
|
&& (gap = GSIArrayItemAtIndex((GSIArray)_glyphGaps, 0).ulng) <= index)
|
||||||
* Here we put some simple-minded code to generate glyphs from
|
|
||||||
* characters assuming that a glyph is the same as a character.
|
|
||||||
*/
|
|
||||||
while (_endCharIndex < numChars
|
|
||||||
&& chunk->glyphIndex + GSIArrayCount(&chunk->glyphs) <= index)
|
|
||||||
{
|
{
|
||||||
unichar c = [string characterAtIndex: _endCharIndex];
|
unsigned endChar;
|
||||||
|
unsigned startChar;
|
||||||
|
|
||||||
[self insertGlyph: (NSGlyph)c
|
if (gap == 0)
|
||||||
atGlyphIndex: numGlyphs++
|
|
||||||
characterIndex: _endCharIndex++];
|
|
||||||
if (pos != GSIArrayCount(glyphChunks) - 1)
|
|
||||||
{
|
{
|
||||||
pos++;
|
startChar = 0;
|
||||||
chunk
|
}
|
||||||
= (GSGlyphChunk*)(GSIArrayItemAtIndex(glyphChunks, pos).ptr);
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Locate the glyph that preceeds the gap, and start with the
|
||||||
|
* a character one beyond the one that generated the glyph.
|
||||||
|
* This guarantees that we won't try to re-generate the
|
||||||
|
* preceeding glyph.
|
||||||
|
*/
|
||||||
|
_JumpToGlyph(self, gap - 1);
|
||||||
|
startChar = _CharIndex(self) + 1;
|
||||||
|
}
|
||||||
|
if (gap == _numberOfGlyphs)
|
||||||
|
{
|
||||||
|
endChar = textLength;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_JumpToGlyph(self, gap);
|
||||||
|
endChar = _CharIndex(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME
|
||||||
|
* Here we put some simple-minded code to generate glyphs from
|
||||||
|
* characters assuming that a glyph is the same as a character.
|
||||||
|
*/
|
||||||
|
GSIArrayRemoveItemAtIndex((GSIArray)_glyphGaps, 0); // Remove gap.
|
||||||
|
while (startChar < endChar)
|
||||||
|
{
|
||||||
|
unichar c = [string characterAtIndex: startChar];
|
||||||
|
|
||||||
|
[self insertGlyph: (NSGlyph)c
|
||||||
|
atGlyphIndex: gap++
|
||||||
|
characterIndex: startChar++];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1504,12 +1638,19 @@ invalidatedRange.length);
|
||||||
|
|
||||||
if (aRange.length == 0)
|
if (aRange.length == 0)
|
||||||
{
|
{
|
||||||
return;
|
return; // Nothing to delete.
|
||||||
|
}
|
||||||
|
pos = GSIArrayCount(glyphChunks) - 1;
|
||||||
|
chunk = (GSGlyphChunk*)GSIArrayItemAtIndex(glyphChunks, pos).ptr;
|
||||||
|
pos = chunk->glyphIndex + GSIArrayCount(&chunk->glyphs);
|
||||||
|
if (aRange.location >= pos)
|
||||||
|
{
|
||||||
|
return; // Range is beyond glyphs.
|
||||||
|
}
|
||||||
|
if (NSMaxRange(aRange) > pos)
|
||||||
|
{
|
||||||
|
aRange.length = pos - aRange.location; // Truncate range to glyphs.
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* Force range to be complete.
|
|
||||||
*/
|
|
||||||
[self glyphAtIndex: NSMaxRange(aRange)-1];
|
|
||||||
|
|
||||||
chunkStart = GSChunkForGlyphIndex(glyphChunks, aRange.location);
|
chunkStart = GSChunkForGlyphIndex(glyphChunks, aRange.location);
|
||||||
chunkEnd = GSChunkForGlyphIndex(glyphChunks, NSMaxRange(aRange)-1);
|
chunkEnd = GSChunkForGlyphIndex(glyphChunks, NSMaxRange(aRange)-1);
|
||||||
|
@ -1575,6 +1716,33 @@ invalidatedRange.length);
|
||||||
chunk = (GSGlyphChunk*)GSIArrayItemAtIndex(glyphChunks, chunkEnd).ptr;
|
chunk = (GSGlyphChunk*)GSIArrayItemAtIndex(glyphChunks, chunkEnd).ptr;
|
||||||
chunk->glyphIndex -= aRange.length;
|
chunk->glyphIndex -= aRange.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove any gaps that were in the deleted range and adjust the
|
||||||
|
* indices of any remaining gaps to allow for the deletion.
|
||||||
|
*/
|
||||||
|
pos = 0;
|
||||||
|
while (pos < GSIArrayCount((GSIArray)_glyphGaps))
|
||||||
|
{
|
||||||
|
unsigned val = GSIArrayItemAtIndex((GSIArray)_glyphGaps, pos).ulng;
|
||||||
|
|
||||||
|
if (val < aRange.location)
|
||||||
|
{
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
else if (val < aRange.length)
|
||||||
|
{
|
||||||
|
GSIArrayRemoveItemAtIndex((GSIArray)_glyphGaps, pos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
val -= aRange.length;
|
||||||
|
GSIArraySetItemAtIndex((GSIArray)_glyphGaps, (GSIArrayItem)val, pos);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_numberOfGlyphs -= aRange.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are any holes in the glyph stream, this will cause all
|
// If there are any holes in the glyph stream, this will cause all
|
||||||
|
@ -1582,10 +1750,7 @@ invalidatedRange.length);
|
||||||
- (unsigned) numberOfGlyphs
|
- (unsigned) numberOfGlyphs
|
||||||
{
|
{
|
||||||
#if USE_GLYPHS
|
#if USE_GLYPHS
|
||||||
GSGlyphChunk *chunk;
|
if (GSIArrayCount((GSIArray)_glyphGaps) > 0)
|
||||||
unsigned pos;
|
|
||||||
|
|
||||||
if (_endCharIndex < [_textStorage length])
|
|
||||||
{
|
{
|
||||||
BOOL valid;
|
BOOL valid;
|
||||||
|
|
||||||
|
@ -1594,9 +1759,7 @@ invalidatedRange.length);
|
||||||
*/
|
*/
|
||||||
[self glyphAtIndex: 0x7fffffff isValidIndex: &valid];
|
[self glyphAtIndex: 0x7fffffff isValidIndex: &valid];
|
||||||
}
|
}
|
||||||
pos = GSChunkForGlyphIndex(glyphChunks, 0x7fffffff);
|
return _numberOfGlyphs;
|
||||||
chunk = (GSGlyphChunk*)(GSIArrayItemAtIndex(glyphChunks, pos).ptr);
|
|
||||||
return chunk->glyphIndex + GSIArrayCount(&chunk->glyphs);
|
|
||||||
#else
|
#else
|
||||||
return [_textStorage length];
|
return [_textStorage length];
|
||||||
#endif
|
#endif
|
||||||
|
@ -1729,28 +1892,35 @@ invalidatedRange.length);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
BOOL exists;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure that the last glyph in the range exists.
|
* Make sure that the last glyph in the range exists.
|
||||||
*/
|
*/
|
||||||
[self glyphAtIndex: NSMaxRange(glyphRange)-1];
|
[self glyphAtIndex: NSMaxRange(glyphRange)
|
||||||
|
isValidIndex: &exists];
|
||||||
/*
|
if (exists == YES)
|
||||||
* Locate the glyph immediately beyond the range.
|
|
||||||
*/
|
|
||||||
if (_JumpToGlyph(self, NSMaxRange(glyphRange)) == NO)
|
|
||||||
{
|
{
|
||||||
pos = _endCharIndex - 1;
|
_JumpToGlyph(self, NSMaxRange(glyphRange));
|
||||||
gRange.length = _GlyphIndex(self) - gRange.location;
|
gRange.length = _GlyphIndex(self) - gRange.location;
|
||||||
|
pos = _CharIndex(self);
|
||||||
|
}
|
||||||
|
else if (_numberOfGlyphs == NSMaxRange(glyphRange)-1)
|
||||||
|
{
|
||||||
|
_JumpToGlyph(self, NSMaxRange(glyphRange)-1);
|
||||||
|
gRange.length = _numberOfGlyphs - gRange.location;
|
||||||
|
pos = [_textStorage length];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pos = _CharIndex(self);
|
[NSException raise: NSRangeException
|
||||||
gRange.length = _GlyphIndex(self) - gRange.location;
|
format: @"glyph index out of range"];
|
||||||
while (_Back(self) == YES && _CharIndex(self) == pos)
|
|
||||||
{
|
|
||||||
gRange.length--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
while (_Back(self) == YES && _CharIndex(self) == pos)
|
||||||
|
{
|
||||||
|
gRange.length--;
|
||||||
|
}
|
||||||
|
|
||||||
cRange.length = pos - cRange.location;
|
cRange.length = pos - cRange.location;
|
||||||
}
|
}
|
||||||
if (actualGlyphRange != 0)
|
if (actualGlyphRange != 0)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue