Extract glyph generation code into separate class.

Plus some additional cleanup.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@26523 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Fred Kiefer 2008-05-13 19:40:20 +00:00
parent 50f7974d7c
commit f59bbe5aa8
8 changed files with 1295 additions and 844 deletions

View file

@ -1,3 +1,18 @@
2008-05-13 Fred Kiefer <FredKiefer@gmx.de>
* Headers/AppKit/NSGlyphGenerator.h,
* Source/NSGlyphGenerator.m: New file.
* Source/GNUmakefile: Add new files.
* Headers/Additions/GNUstepGUI/GSLayoutManager_internal.h: More
efficient memory usage for glyph runs.
* Headers/Additions/GNUstepGUI/GSLayoutManager.h: Add ivar for
glyph generator and some MacOSX methods.
* Source/GSLayoutManager.m: Use objc_malloc, objc_free and
objc_realloc. Move glyph generation into seperate class. Add
documentation. General cleanup. Implement some of the additional
methods.
* Source/NSLayoutManager.m: Adopt to changes in super class.
2008-05-13 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSOpenPanel.m:

View file

@ -31,6 +31,7 @@
#include <Foundation/NSObject.h>
#include <Foundation/NSGeometry.h>
#include <AppKit/NSFont.h>
#include <AppKit/NSGlyphGenerator.h>
@class GSTypesetter;
@class NSTextStorage,NSTextContainer;
@ -44,10 +45,15 @@ typedef enum
NSGlyphInscribeOverBelow = 4
} NSGlyphInscription;
#if OS_API_VERSION(MAC_OS_X_VERSION_10_3, GS_API_LATEST)
@interface GSLayoutManager : NSObject <NSGlyphStorage, NSCoding>
#else
@interface GSLayoutManager : NSObject
#endif
{
@protected
NSTextStorage *_textStorage;
NSGlyphGenerator *_glyphGenerator;
id _delegate;
@ -101,6 +107,8 @@ how it's supposed to work. It's functional and correct, but it isn't fast. */
- (void) setTextStorage: (NSTextStorage *)aTextStorage;
- (void) replaceTextStorage: (NSTextStorage *)newTextStorage;
- (NSGlyphGenerator *) glyphGenerator;
- (void) setGlyphGenerator: (NSGlyphGenerator *)glyphGenerator;
- (id) delegate;
- (void) setDelegate: (id)aDelegate;
@ -216,9 +224,11 @@ it isn't NULL. */
/* These can be used to set arbitrary tags on individual glyphs.
Non-negative tags are reserved. You must provide storage yourself (by
subclassing). */
#if !OS_API_VERSION(MAC_OS_X_VERSION_10_3, GS_API_LATEST)
- (void) setIntAttribute: (int)attributeTag
value: (int)anInt
forGlyphAtIndex: (unsigned int)glyphIndex;
#endif
- (int) intAttribute: (int)attributeTag
forGlyphAtIndex: (unsigned int)glyphIndex;

View file

@ -99,11 +99,12 @@ typedef struct
typedef struct GSLayoutManager_glyph_run_s
{
glyph_run_head_t head;
// Pointer to the previous leaf. Invariant: t->head->next->prev == t
glyph_run_head_t *prev;
/* Zero-based, so it's really the number of heads in addition to the
one included in glyph_run_t. */
int level;
unsigned int level:4;
/* All glyph-generation-affecting attributes are same as last run. This
doesn't have to be set if a run is continued, but if it is set, it must
@ -121,25 +122,19 @@ typedef struct GSLayoutManager_glyph_run_s
/* TODO2: these aren't filled in or used anywhere yet */
unsigned int bidi_level:6;
/* Font for this run. */
NSFont *font;
int ligature;
int ligature:5;
/* YES if there's an explicit kern attribute. Currently, ligatures aren't
used when explicit kerning is available (TODO). */
BOOL explicit_kern;
unsigned int explicit_kern:1;
/* Font for this run. */
NSFont *font;
glyph_t *glyphs;
} glyph_run_t;
@interface GSLayoutManager (backend)
-(unsigned int) _findSafeBreakMovingBackwardFrom: (unsigned int)ch;
-(unsigned int) _findSafeBreakMovingForwardFrom: (unsigned int)ch;
-(void) _generateGlyphsForRun: (glyph_run_t *)run at: (unsigned int)pos;
@end
/* All positions and lengths in glyphs */
typedef struct
{

View file

@ -0,0 +1,74 @@
/* -*-objc-*-
NSGlyphGenerator.h
Interfaces for glyph generation and storage.
Copyright (C) 1996 Free Software Foundation, Inc.
Author: H. N. Schaller <hns@computer.org>
Date: Jun 2006 - aligned with 10.4
This file is part of the GNUstep GUI Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; see the file COPYING.LIB.
If not, see <http://www.gnu.org/licenses/> or write to the
Free Software Foundation, 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef _GNUstep_H_NSGlyphGenerator
#define _GNUstep_H_NSGlyphGenerator
#import <GNUstepBase/GSVersionMacros.h>
#import <Foundation/Foundation.h>
// define NSGlyph
#import <AppKit/NSFont.h>
#if OS_API_VERSION(MAC_OS_X_VERSION_10_3, GS_API_LATEST)
enum
{
NSShowControlGlyphs = 1,
NSShowInvisibleGlyphs = 2,
NSWantsBidiLevels = 4
};
@protocol NSGlyphStorage
- (NSAttributedString*) attributedString;
- (void) insertGlyphs: (const NSGlyph*)glyphs
length: (NSUInteger)length
forStartingGlyphAtIndex: (NSUInteger)glyph
characterIndex: (NSUInteger)index;
- (NSUInteger) layoutOptions;
- (void) setIntAttribute: (NSInteger)tag
value: (NSInteger)value
forGlyphAtIndex: (NSUInteger)index;
@end
@interface NSGlyphGenerator : NSObject
+ (id) sharedGlyphGenerator;
- (void) generateGlyphsForGlyphStorage: (id <NSGlyphStorage>)storage
desiredNumberOfCharacters: (NSUInteger)num
glyphIndex: (NSUInteger*)glyph
characterIndex: (NSUInteger*)index;
@end
#endif // MAC_OS_X_VERSION_10_3
#endif // _GNUstep_H_NSGlyphGenerator

View file

@ -94,6 +94,7 @@ NSFontManager.m \
NSFontPanel.m \
NSForm.m \
NSFormCell.m \
NSGlyphGenerator.m \
NSGraphicsContext.m \
NSHelpPanel.m \
NSHelpManager.m \
@ -287,6 +288,7 @@ NSFontManager.h \
NSFontPanel.h \
NSForm.h \
NSFormCell.h \
NSGlyphGenerator.h \
NSGraphicsContext.h \
NSHelpPanel.h \
NSHelpManager.h \

File diff suppressed because it is too large Load diff

281
Source/NSGlyphGenerator.m Normal file
View file

@ -0,0 +1,281 @@
/*
NSGlyphGenerator.m
Copyright (C) 2008 Free Software Foundation, Inc.
Author: Fred Kiefer <fredkiefer@gmx.de>
Date: April 2008
This file is part of the GNUstep GUI Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; see the file COPYING.LIB.
If not, see <http://www.gnu.org/licenses/> or write to the
Free Software Foundation, 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <Foundation/NSDictionary.h>
#include <GNUstepBase/Unicode.h>
#include "AppKit/NSAttributedString.h"
#include "AppKit/NSFont.h"
#include "AppKit/NSGlyphGenerator.h"
/* just for NSAttachmentCharacter */
#include "AppKit/NSTextAttachment.h"
#include "GNUstepGUI/GSFontInfo.h"
static NSGlyphGenerator* instance;
@interface NSGlyphGenerator (Private)
- (NSFont *) fontForCharactersWithAttributes: (NSDictionary *)attributes;
@end
@implementation NSGlyphGenerator
+ (id) sharedGlyphGenerator
{
if (!instance)
instance = [[NSGlyphGenerator alloc] init];
return instance;
}
// Send a run of glyphs where each glyph corresponds to one character.
#define SEND_GLYPHS() \
{ \
NSUInteger length; \
\
if ((length = g - glyphs)) \
{ \
[storage insertGlyphs: glyphs \
length: length \
forStartingGlyphAtIndex: *glyph \
characterIndex: *index]; \
*index += i - cstart + 1; \
*glyph += length; \
g = glyphs; \
cstart = i + 1; \
} \
}
/*
This is a fairly simple implementation. It will use "ff", "fl", "fi",
"ffl", and "ffi" ligatures if available.
TODO: how should words like "pfffffffffff" be handled?
0066 'f'
0069 'i'
006c 'l'
fb00 'ff'
fb01 'fi'
fb02 'fl'
fb03 'ffi'
fb04 'ffl'
*/
- (void) generateGlyphsForGlyphStorage: (id <NSGlyphStorage>)storage
desiredNumberOfCharacters: (NSUInteger)num
glyphIndex: (NSUInteger*)glyph
characterIndex: (NSUInteger*)index
{
// Try to get enough space for all glyphs
NSGlyph glyphs[2 * num];
NSGlyph *g;
NSGlyph gl;
NSAttributedString *attrstr = [storage attributedString];
GSFontInfo *fi;
int i;
unichar buf[num];
unsigned int cstart = 0;
NSRange maxRange = NSMakeRange(*index, num);
NSRange curRange;
NSDictionary *attributes;
NSNumber *n;
int ligature;
BOOL surr;
NSCharacterSet *cs = [NSCharacterSet controlCharacterSet];
SEL cim_sel = @selector(characterIsMember:);
BOOL (*characterIsMember)(id, SEL, unichar)
= (BOOL(*)(id, SEL, unichar)) [cs methodForSelector: cim_sel];
SEL gfc_sel = @selector(glyphForCharacter:);
NSGlyph (*glyphForCharacter)(id, SEL, unichar);
[[attrstr string] getCharacters: buf range: maxRange];
attributes = [attrstr attributesAtIndex: *index
longestEffectiveRange: &curRange
inRange: maxRange];
fi = [[self fontForCharactersWithAttributes: attributes] fontInfo];
glyphForCharacter = (NSGlyph(*)(id, SEL, unichar)) [fi methodForSelector: gfc_sel];
n = [attributes objectForKey: NSLigatureAttributeName];
if (n)
ligature = [n intValue];
else
ligature = 1;
g = glyphs;
for (i = 0; i < num; i++)
{
unsigned int ch, ch2;
ch = buf[i];
if (characterIsMember(cs, cim_sel, ch))
{
*g = NSControlGlyph;
g++;
continue;
}
if (ch == NSAttachmentCharacter)
{
*g = GSAttachmentGlyph;
g++;
continue;
}
// Simple ligature processing
if ((ligature >= 1) && (i + 1 < num))
{
ch2 = buf[i + 1];
if (ch == 'f')
{
if ((i + 2 < num) && (ch2 == 'f'))
{
// ffl
if ((buf[i + 2] == 'l')
&& (NSNullGlyph != (gl = glyphForCharacter(fi, gfc_sel, 0xfb04))))
{
*g = gl;
g++;
i += 2;
SEND_GLYPHS();
continue;
}
// ffi
if ((buf[i + 2] == 'i')
&& (NSNullGlyph != (gl = glyphForCharacter(fi, gfc_sel, 0xfb03))))
{
*g = gl;
g++;
i += 2;
SEND_GLYPHS();
continue;
}
}
// ff
if ((ch2 == 'f')
&& (NSNullGlyph != (gl = glyphForCharacter(fi, gfc_sel, 0xfb00))))
{
*g = gl;
g++;
i++;
SEND_GLYPHS();
continue;
}
// fi
if ((ch2 == 'i')
&& (NSNullGlyph != (gl = glyphForCharacter(fi, gfc_sel, 0xfb01))))
{
*g = gl;
g++;
i++;
SEND_GLYPHS();
continue;
}
// fl
if ((ch2 == 'l')
&& (NSNullGlyph != (gl = glyphForCharacter(fi, gfc_sel, 0xfb02))))
{
*g = gl;
g++;
i++;
SEND_GLYPHS();
continue;
}
}
}
surr = NO;
// Check for surrogate pairs
if (ch >= 0xd800 && ch <= 0xdfff)
{
if (ch >= 0xd800 && ch < 0xdc00
&& (i + 1 < num) && (ch2 = buf[i + 1]) >= 0xdc00
&& ch2 <= 0xdfff)
{
ch = ((ch & 0x3ff) << 10) + (ch2 & 0x3ff) + 0x10000;
i++;
surr = YES;
}
else
{
ch = 0xfffd;
}
}
gl = glyphForCharacter(fi, gfc_sel, ch);
if (gl != NSNullGlyph)
{
*g = gl;
g++;
if (surr)
SEND_GLYPHS();
}
else if (ch < 0x10000)
{
unichar *decomp;
decomp = uni_is_decomp(ch);
if (decomp)
{
for (; *decomp; decomp++)
{
gl = glyphForCharacter(fi, gfc_sel, *decomp);
if (gl == NSNullGlyph)
{
break;
}
*g = gl;
g++;
SEND_GLYPHS();
}
}
}
else
{
// On a NSNullGLyph, send all previous glyphs
SEND_GLYPHS();
}
}
// Send all remaining glyphs
SEND_GLYPHS();
}
@end
@implementation NSGlyphGenerator (Private)
- (NSFont *) fontForCharactersWithAttributes: (NSDictionary *)attributes
{
NSFont *f = [attributes valueForKey: NSFontAttributeName];
if (!f)
f = [NSFont userFontOfSize: 0];
//f = [storage substituteFontForFont: f];
return f;
}
@end

View file

@ -383,7 +383,7 @@ container? necessary? */
if (num_rects == rect_array_size)
{
rect_array_size += 4;
rect_array = realloc(rect_array, sizeof(NSRect) * rect_array_size);
rect_array = objc_realloc(rect_array, sizeof(NSRect) * rect_array_size);
}
rect_array[num_rects++] = r;
}
@ -2036,12 +2036,12 @@ this file describes this.
}
if (lf->points)
{
free(lf->points);
objc_free(lf->points);
lf->points = NULL;
}
if (lf->attachments)
{
free(lf->attachments);
objc_free(lf->attachments);
lf->attachments = NULL;
}
}
@ -2156,12 +2156,12 @@ no_soft_invalidation:
{
if (lf->points)
{
free(lf->points);
objc_free(lf->points);
lf->points = NULL;
}
if (lf->attachments)
{
free(lf->attachments);
objc_free(lf->attachments);
lf->attachments = NULL;
}
}