[SCM] WebKit Debian packaging branch, debian/unstable, updated. debian/1.1.15-1-40151-g37bb677

rjw rjw at 268f45cc-cd09-0410-ab3c-d52691b4dbfc
Sat Sep 26 06:11:42 UTC 2009


The following commit has been merged in the debian/unstable branch:
commit d6fa07c3f6e65ed4a2732a417531744cccd29f83
Author: rjw <rjw at 268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Thu May 9 03:05:18 2002 +0000

        Added optimizations for text rendering.
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@1114 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebKit/ChangeLog b/WebKit/ChangeLog
index 1d67a35..62df26d 100644
--- a/WebKit/ChangeLog
+++ b/WebKit/ChangeLog
@@ -1,3 +1,23 @@
+2002-05-08  Richard J. Williamson  <rjw at apple.com>
+
+    Added optimizations for text rendering.
+    
+	* WebCoreSupport.subproj/IFTextRenderer.h:
+	* WebCoreSupport.subproj/IFTextRenderer.m:
+	(freeWidthMap):
+	(freeGlyphMap):
+	(glyphForCharacter):
+	(widthForGlyph):
+	(widthForCharacter):
+	(-[IFTextRenderer substituteFontForCharacters:length:]):
+	(-[IFTextRenderer convertCharacters:length:glyphs:]):
+	(-[IFTextRenderer dealloc]):
+	(-[IFTextRenderer drawString:atPoint:withColor:]):
+	(-[IFTextRenderer drawUnderlineForString:atPoint:withColor:]):
+	(-[IFTextRenderer widthForCharacters:length:]):
+	(-[IFTextRenderer extendCharacterToGlyphMapToInclude:]):
+	(-[IFTextRenderer extendGlyphToWidthMapToInclude:]):
+
 2002-05-08  Darin Adler  <darin at apple.com>
 
 	* Misc.subproj/IFCache.h: Add more JavaScript object statistics.
diff --git a/WebKit/ChangeLog-2002-12-03 b/WebKit/ChangeLog-2002-12-03
index 1d67a35..62df26d 100644
--- a/WebKit/ChangeLog-2002-12-03
+++ b/WebKit/ChangeLog-2002-12-03
@@ -1,3 +1,23 @@
+2002-05-08  Richard J. Williamson  <rjw at apple.com>
+
+    Added optimizations for text rendering.
+    
+	* WebCoreSupport.subproj/IFTextRenderer.h:
+	* WebCoreSupport.subproj/IFTextRenderer.m:
+	(freeWidthMap):
+	(freeGlyphMap):
+	(glyphForCharacter):
+	(widthForGlyph):
+	(widthForCharacter):
+	(-[IFTextRenderer substituteFontForCharacters:length:]):
+	(-[IFTextRenderer convertCharacters:length:glyphs:]):
+	(-[IFTextRenderer dealloc]):
+	(-[IFTextRenderer drawString:atPoint:withColor:]):
+	(-[IFTextRenderer drawUnderlineForString:atPoint:withColor:]):
+	(-[IFTextRenderer widthForCharacters:length:]):
+	(-[IFTextRenderer extendCharacterToGlyphMapToInclude:]):
+	(-[IFTextRenderer extendGlyphToWidthMapToInclude:]):
+
 2002-05-08  Darin Adler  <darin at apple.com>
 
 	* Misc.subproj/IFCache.h: Add more JavaScript object statistics.
diff --git a/WebKit/WebCoreSupport.subproj/IFTextRenderer.h b/WebKit/WebCoreSupport.subproj/IFTextRenderer.h
index 4914a28..6583237 100644
--- a/WebKit/WebCoreSupport.subproj/IFTextRenderer.h
+++ b/WebKit/WebCoreSupport.subproj/IFTextRenderer.h
@@ -11,24 +11,42 @@
 
 typedef float IFGlyphWidth;
 
+
+typedef struct _WidthMap {
+    ATSGlyphRef startRange;
+    ATSGlyphRef endRange;
+    struct _WidthMap *next;
+    IFGlyphWidth *widths;
+} WidthMap;
+
+typedef struct _GlyphMap {
+    UniChar startRange;
+    UniChar endRange;
+    struct _GlyphMap *next;
+    ATSGlyphRef *glyphs;
+} GlyphMap;
+
 @interface IFTextRenderer : NSObject <WebCoreTextRenderer>
 {
+ at public
     NSFont *font;
     int ascent;
     int descent;
     int lineSpacing;
     
     ATSStyleGroupPtr styleGroup;
-    ATSGlyphVector glyphVector;
     unsigned int widthCacheSize;
     IFGlyphWidth *widthCache;
-    ATSGlyphRef *characterToGlyph;
+    GlyphMap *characterToGlyphMap;
+    WidthMap *glyphToWidthMap;
     
     NSArray *substituteFontRenderers;
 }
 
 - initWithFont:(NSFont *)font;
-- (NSFont *)convertCharacters: (const unichar *)characters length: (int)numCharacters glyphs: (ATSGlyphVector *)glyphs;
+- (void)convertCharacters: (const unichar *)characters length: (int)numCharacters glyphs: (ATSGlyphVector *)glyphs;
+- (ATSGlyphRef)extendCharacterToGlyphMapToInclude:(UniChar) c;
+- (WidthMap *)extendGlyphToWidthMapToInclude:(ATSGlyphRef)glyphID;
 
 
 @end
diff --git a/WebKit/WebCoreSupport.subproj/IFTextRenderer.m b/WebKit/WebCoreSupport.subproj/IFTextRenderer.m
index 47e46de..b043f29 100644
--- a/WebKit/WebCoreSupport.subproj/IFTextRenderer.m
+++ b/WebKit/WebCoreSupport.subproj/IFTextRenderer.m
@@ -26,26 +26,21 @@
 #define INITIAL_GLYPH_CACHE_MAX 512
 #define INCREMENTAL_GLYPH_CACHE_BLOCK 1024
 
-#define UNINITIALIZED_GLYPH_WIDTH 65535
+// Covers most of latin1.
+#define INITIAL_BLOCK_SIZE 0x200
 
-static CFCharacterSetRef nonBaseChars = NULL;
+// Get additional blocks of glyphs and widths in bigger chunks.
+// This will typically be for other character sets.
+#define INCREMENTAL_BLOCK_SIZE 0x400
+
+#define UNINITIALIZED_GLYPH_WIDTH 65535
 
 // combining char, hangul jamo, or Apple corporate variant tag
 #define JunseongStart 0x1160
 #define JonseongEnd 0x11F9
 #define IsHangulConjoiningJamo(X) (X >= JunseongStart && X <= JonseongEnd)
-#define IsNonBaseChar(X) ((CFCharacterSetIsCharacterMember(nonBaseChars, X) || IsHangulConjoiningJamo(X) || (X & 0x1FFFF0) == 0xF870))
-
-
-// These definitions are used to bound the character-to-glyph mapping cache.  The
-// range is limited to LATIN1.  When accessing the cache a check must be made to
-// determine that a character range does not include a composable charcter.
+#define IsNonBaseChar(X) ((CFCharacterSetIsCharacterMember(nonBaseChars, X) || IsHangulConjoiningJamo(X) || (((X) & 0x1FFFF0) == 0xF870)))
 
-// The first displayable character in latin1. (SPACE)
-#define FIRST_CACHE_CHARACTER (0x20)
-
-// The last character in latin1 extended A. (LATIN SMALL LETTER LONG S)
-#define LAST_CACHE_CHARACTER (0x17F)
 
 @interface NSLanguage : NSObject 
 {
@@ -53,7 +48,6 @@ static CFCharacterSetRef nonBaseChars = NULL;
 + (NSLanguage *)defaultLanguage;
 @end
 
-
 @interface NSFont (IFPrivate)
 - (ATSUFontID)_atsFontID;
 - (CGFontRef)_backingCGSFont;
@@ -62,37 +56,85 @@ static CFCharacterSetRef nonBaseChars = NULL;
 + (NSFont *) findFontLike:(NSFont *)aFont forString:(NSString *)string withRange:(NSRange)range inLanguage:(NSLanguage *) language;
 @end
 
-static void InitATSGlyphVector(ATSGlyphVector *glyphVector, UInt32 numGlyphs)
+ at class NSCGSFont;
+
+
+static CFCharacterSetRef nonBaseChars = NULL;
+
+
+static void freeWidthMap (WidthMap *map)
+{
+    if (map->next)
+        freeWidthMap (map->next);
+    free (map->widths);
+    free (map);
+}
+
+
+static void freeGlyphMap (GlyphMap *map)
 {
-    if (glyphVector->numAllocatedGlyphs == 0) {
-        ATSInitializeGlyphVector(numGlyphs, 0, glyphVector);
-
-//#warning Aki: 6/28/00 Need to reconsider these when we do bidi
-        ATSFree(glyphVector->levelIndexes);
-        glyphVector->levelIndexes = NULL;
-    } else if (glyphVector->numAllocatedGlyphs < numGlyphs) {
-        ATSGrowGlyphVector(numGlyphs - glyphVector->numAllocatedGlyphs, glyphVector);
+    if (map->next)
+        freeGlyphMap (map->next);
+    free (map->glyphs);
+    free (map);
+}
+
+
+static inline ATSGlyphRef glyphForCharacter (GlyphMap *map, UniChar c)
+{
+    if (map == 0)
+        return nonGlyphID;
+        
+    if (c >= map->startRange && c <= map->endRange)
+        return ((ATSGlyphRef *)map->glyphs)[c-map->startRange];
+        
+    return glyphForCharacter (map->next, c);
+}
+ 
+ 
+#ifdef _TIMING        
+static double totalCGGetAdvancesTime = 0;
+#endif
+
+static inline IFGlyphWidth widthForGlyph (IFTextRenderer *renderer, WidthMap *map, ATSGlyphRef glyph)
+{
+    IFGlyphWidth width;
+    bool errorResult;
+    
+    if (map == 0){
+        map = [renderer extendGlyphToWidthMapToInclude: glyph];
+        return widthForGlyph (renderer, map, glyph);
+    }
+        
+    if (glyph >= map->startRange && glyph <= map->endRange){
+        width = ((IFGlyphWidth *)map->widths)[glyph-map->startRange];
+        if (width == UNINITIALIZED_GLYPH_WIDTH){
+
+#ifdef _TIMING        
+            double startTime = CFAbsoluteTimeGetCurrent();
+#endif
+            errorResult = CGFontGetGlyphScaledAdvances ([renderer->font _backingCGSFont], &glyph, 1, &map->widths[glyph-map->startRange], [renderer->font pointSize]);
+            if (errorResult == 0)
+                [NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation:  unable to cache glyph widths - for %@ %f",  [renderer->font displayName], [renderer->font pointSize]];
+    
+#ifdef _TIMING        
+            double thisTime = CFAbsoluteTimeGetCurrent() - startTime;
+            totalCGGetAdvancesTime += thisTime;
+#endif
+            return ((IFGlyphWidth *)map->widths)[glyph-map->startRange];
+        }
+        return width;
     }
+
+    return widthForGlyph (renderer, map->next, glyph);
 }
 
-static void ResetATSGlyphVector(ATSGlyphVector *glyphVector)
+
+static inline  IFGlyphWidth widthForCharacter (IFTextRenderer *renderer, UniChar c)
 {
-    ATSGlyphVector tmpVector = *glyphVector;
-
-    // Prevents glyph array & style settings from deallocated
-    glyphVector->firstRecord = NULL;
-    glyphVector->styleSettings = NULL;
-    glyphVector->levelIndexes = NULL;
-    ATSClearGlyphVector(glyphVector);
-
-    glyphVector->numAllocatedGlyphs = tmpVector.numAllocatedGlyphs;
-    glyphVector->recordSize = tmpVector.recordSize;
-    glyphVector->firstRecord = tmpVector.firstRecord;
-    glyphVector->styleSettings = tmpVector.styleSettings;
-    glyphVector->levelIndexes = tmpVector.levelIndexes;
+    return widthForGlyph (renderer, renderer->glyphToWidthMap, glyphForCharacter(renderer->characterToGlyphMap, c));
 }
 
- at class NSCGSFont;
 
 static void FillStyleWithAttributes(ATSUStyle style, NSFont *theFont)
 {
@@ -141,13 +183,29 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     nonBaseChars = CFCharacterSetGetPredefined(kCFCharacterSetNonBase);
 }
 
+
+- (NSFont *)substituteFontForCharacters: (const unichar *)characters length: (int)numCharacters
+{
+    NSFont *substituteFont;
+    NSString *string = [[NSString alloc] initWithCharactersNoCopy:(unichar *)characters length: numCharacters freeWhenDone: NO];
+
+    substituteFont = [NSFont findFontLike:font forString:string withRange:NSMakeRange (0,numCharacters) inLanguage:[NSLanguage defaultLanguage]];
+    [string release];
+    
+    if ([substituteFont isEqual: font])
+        return nil;
+        
+    return substituteFont;
+}
+
+
 /* Convert non-breaking spaces into spaces. */
-- (NSFont *)convertCharacters: (const unichar *)characters length: (int)numCharacters glyphs: (ATSGlyphVector *)glyphs
+- (void)convertCharacters: (const unichar *)characters length: (int)numCharacters glyphs: (ATSGlyphVector *)glyphs
 {
     int i;
     UniChar localBuffer[LOCAL_GLYPH_BUFFER_SIZE];
     UniChar *buffer = localBuffer;
-    NSFont *fontToBeUsed = nil;
+    OSStatus status;
     
     for (i = 0; i < numCharacters; i++) {
         if (characters[i] == NON_BREAKING_SPACE) {
@@ -175,84 +233,9 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
         free(buffer);
     }
     
-    (void)ATSUConvertCharToGlyphs(styleGroup, characters, 0, numCharacters, 0, glyphs);
-    
-    if (hasMissingGlyphs(glyphs) == YES){
-        NSString *string = [[NSString alloc] initWithCharactersNoCopy:(unichar *)characters length: numCharacters freeWhenDone: NO];
-
-        fontToBeUsed = [NSFont findFontLike:font forString:string withRange:NSMakeRange (0,numCharacters) inLanguage:[NSLanguage defaultLanguage]];
-        [string release];
-    }
-    
-    return fontToBeUsed;
+    status = ATSUConvertCharToGlyphs(styleGroup, characters, 0, numCharacters, 0, glyphs);
 }
 
-- (void)initializeCaches
-{
-    unsigned int i, glyphsToCache;
-    int errorResult;
-    size_t numGlyphsInFont = CGFontGetNumberOfGlyphs([font _backingCGSFont]);
-    short unsigned int sequentialGlyphs[INITIAL_GLYPH_CACHE_MAX];
-    ATSLayoutRecord *glyphRecords;
-    NSFont *fontToUse;
-
-    WEBKITDEBUGLEVEL (WEBKIT_LOG_FONTCACHE, "Caching %s %.0f (%ld glyphs) ascent = %f, descent = %f, defaultLineHeightForFont = %f\n", [[font displayName] cString], [font pointSize], numGlyphsInFont, [font ascender], [font descender], [font defaultLineHeightForFont]); 
-
-    // Initially just cache the max of number of glyphs in font or
-    // INITIAL_GLYPH_CACHE_MAX.  Holes in the cache will be filled on demand
-    // in INCREMENTAL_GLYPH_CACHE_BLOCK chunks. 
-    if (numGlyphsInFont > INITIAL_GLYPH_CACHE_MAX)
-        glyphsToCache = INITIAL_GLYPH_CACHE_MAX;
-    else
-        glyphsToCache = numGlyphsInFont;
-    widthCacheSize = (int)numGlyphsInFont;
-    for (i = 0; i < glyphsToCache; i++)
-        sequentialGlyphs[i] = i;
-        
-    widthCache = (IFGlyphWidth *)calloc (1, widthCacheSize * sizeof(IFGlyphWidth));
-    
-    // Some glyphs can have zero width, so we have to use a non-zero value
-    // in empty slots to indicate they are uninitialized.
-    for (i = glyphsToCache; i < widthCacheSize; i++){
-        widthCache[i] = UNINITIALIZED_GLYPH_WIDTH;
-    }
-    
-    CGContextRef cgContext;
-
-    cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
-    errorResult = CGFontGetGlyphScaledAdvances ([font _backingCGSFont], &sequentialGlyphs[0], glyphsToCache, widthCache, [font pointSize]);
-    if (errorResult == 0)
-        [NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation:  unable to cache glyph advances - for %@ %f", self, [font displayName], [font pointSize]];
-
-    unsigned int latinCount = LAST_CACHE_CHARACTER - FIRST_CACHE_CHARACTER + 1;
-    short unsigned int latinBuffer[LAST_CACHE_CHARACTER+1];
-    
-    for (i = FIRST_CACHE_CHARACTER; i <= LAST_CACHE_CHARACTER; i++){
-        latinBuffer[i] = i;
-    }
-
-    ATSGlyphVector latinGlyphVector;
-    ATSInitializeGlyphVector(latinCount, 0, &latinGlyphVector);
-    fontToUse = [self convertCharacters: &latinBuffer[FIRST_CACHE_CHARACTER] length: latinCount glyphs: &latinGlyphVector];
-    if (latinGlyphVector.numGlyphs != latinCount)
-        [NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation:  ascii and glyphID count not equal - for %@ %f", self, [font displayName], [font pointSize]];
-        
-    unsigned int numGlyphs = latinGlyphVector.numGlyphs;
-    characterToGlyph = (ATSGlyphRef *)calloc (1, latinGlyphVector.numGlyphs * sizeof(ATSGlyphRef));
-    glyphRecords = (ATSLayoutRecord *)latinGlyphVector.firstRecord;
-    for (i = 0; i < numGlyphs; i++){
-        characterToGlyph[i] = glyphRecords[i].glyphID;
-    }
-    ATSClearGlyphVector(&latinGlyphVector);
-
-#define DEBUG_CACHE_SIZE
-#ifdef DEBUG_CACHE_SIZE
-    static int totalCacheSize = 0;
-    
-    totalCacheSize += widthCacheSize * sizeof(IFGlyphWidth) + numGlyphs * sizeof(ATSGlyphRef) + sizeof(*self);
-    WEBKITDEBUGLEVEL (WEBKIT_LOG_MEMUSAGE, "memory usage in bytes:  widths = %ld, latin1 ext. character-to-glyph = %ld, total this cache = %ld, total all caches %d\n", widthCacheSize * sizeof(IFGlyphWidth), numGlyphs * sizeof(ATSGlyphRef), widthCacheSize * sizeof(IFGlyphWidth) + numGlyphs * sizeof(ATSGlyphRef) + sizeof(*self), totalCacheSize); 
-#endif
-}
 
 - initWithFont:(NSFont *)f
 {
@@ -280,20 +263,22 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     return self;
 }
 
+
 - (void)dealloc
 {
     [font release];
 
     if (styleGroup)
         ATSUDisposeStyleGroup(styleGroup);
-    if (glyphVector.numAllocatedGlyphs > 0)
-        ATSClearGlyphVector(&glyphVector);
+
     free(widthCache);
-    free(characterToGlyph);
+    freeWidthMap (glyphToWidthMap);
+    freeGlyphMap (characterToGlyphMap);
     
     [super dealloc];
 }
 
+
 - (int)widthForString:(NSString *)string
 {
     UniChar localBuffer[LOCAL_GLYPH_BUFFER_SIZE];
@@ -311,6 +296,7 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     return [self widthForCharacters:internalBuffer length:[string length]];
 }
 
+
 - (int)ascent
 {
     if (ascent < 0)  {
@@ -319,6 +305,7 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     return ascent;
 }
 
+
 - (int)descent
 {
     if (descent < 0)  {
@@ -327,6 +314,7 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     return descent;
 }
 
+
 - (int)lineSpacing
 {
     if (lineSpacing < 0) {
@@ -335,12 +323,15 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     return lineSpacing;
 }
 
+
 - (void)drawString:(NSString *)string atPoint:(NSPoint)point withColor:(NSColor *)color
 {
     NSFont *substituteFont;
     UniChar localBuffer[LOCAL_GLYPH_BUFFER_SIZE];
     const UniChar *_internalBuffer = CFStringGetCharactersPtr ((CFStringRef)string);
     const UniChar *internalBuffer;
+    ATSGlyphVector _glyphVector;
+    CGContextRef cgContext;
 
     if (!_internalBuffer){
         // FIXME: Handle case where length > LOCAL_GLYPH_BUFFER_SIZE
@@ -350,15 +341,15 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     else
         internalBuffer = _internalBuffer;
 
-    CGContextRef cgContext;
-
-    InitATSGlyphVector(&glyphVector, [string length]);
-
-    substituteFont = [self convertCharacters: internalBuffer length: [string length] glyphs: &glyphVector];
-    if (substituteFont){
-        ResetATSGlyphVector(&glyphVector);
-        [[(IFTextRendererFactory *)[IFTextRendererFactory sharedFactory] rendererWithFont: substituteFont] drawString: string atPoint: point withColor: color];
-        return;
+    ATSInitializeGlyphVector([string length], 0, &_glyphVector);
+    [self convertCharacters: internalBuffer length: [string length] glyphs: &_glyphVector];
+    if (hasMissingGlyphs (&_glyphVector)){
+        substituteFont = [self substituteFontForCharacters: internalBuffer length: [string length]];
+        ATSClearGlyphVector(&_glyphVector);
+        if (substituteFont){
+            [[(IFTextRendererFactory *)[IFTextRendererFactory sharedFactory] rendererWithFont: substituteFont] drawString: string atPoint: point withColor: color];
+            return;
+        }
     }
     
     // This will draw the text from the top of the bounding box down.
@@ -374,10 +365,10 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
         [NSException raise:NSInternalInconsistencyException format:@"%@: Don't know how to deal with font %@", self, [font displayName]];
         
     {
-        int i, numGlyphs = glyphVector.numGlyphs;
+        int i, numGlyphs = _glyphVector.numGlyphs;
         char localGlyphBuf[LOCAL_GLYPH_BUFFER_SIZE];
         char *usedGlyphBuf, *glyphBufPtr, *glyphBuf = 0;
-        ATSLayoutRecord *glyphRecords = (ATSLayoutRecord *)glyphVector.firstRecord;
+        ATSLayoutRecord *glyphRecords = (ATSLayoutRecord *)_glyphVector.firstRecord;
         
         if (numGlyphs > LOCAL_GLYPH_BUFFER_SIZE/2)
             usedGlyphBuf = glyphBufPtr = glyphBuf = (char *)malloc (numGlyphs * 2);
@@ -398,12 +389,14 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
             free (glyphBuf);
     }
 
-    ResetATSGlyphVector(&glyphVector);
+    ATSClearGlyphVector(&_glyphVector);
 }
 
+
 - (void)drawUnderlineForString:(NSString *)string atPoint:(NSPoint)point withColor:(NSColor *)color
 {
     NSFont *substituteFont;
+    ATSGlyphVector _glyphVector;
     UniChar localBuffer[LOCAL_GLYPH_BUFFER_SIZE];
     const UniChar *_internalBuffer = CFStringGetCharactersPtr ((CFStringRef)string);
     const UniChar *internalBuffer;
@@ -416,13 +409,17 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     else
         internalBuffer = _internalBuffer;
 
-    InitATSGlyphVector(&glyphVector, [string length]);
-    substituteFont = [self convertCharacters: internalBuffer length: [string length] glyphs: &glyphVector];
-    ResetATSGlyphVector(&glyphVector);
-    if (substituteFont){
-        [[(IFTextRendererFactory *)[IFTextRendererFactory sharedFactory] rendererWithFont: substituteFont] drawUnderlineForString: string atPoint: point withColor: color];
-        return;
+    ATSInitializeGlyphVector([string length], 0, &_glyphVector);
+    [self convertCharacters: internalBuffer length: [string length] glyphs: &_glyphVector];
+    if (hasMissingGlyphs (&_glyphVector)){
+        substituteFont = [self substituteFontForCharacters: internalBuffer length: [string length]];
+        ATSClearGlyphVector(&_glyphVector);
+        if (substituteFont){
+            [[(IFTextRendererFactory *)[IFTextRendererFactory sharedFactory] rendererWithFont: substituteFont] drawUnderlineForString: string atPoint: point withColor: color];
+            return;
+        }
     }
+    ATSClearGlyphVector(&_glyphVector);
     
     // This will draw the text from the top of the bounding box down.
     // Qt expects to draw from the baseline.
@@ -456,129 +453,78 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     [graphicsContext setShouldAntialias: flag];
 }
 
+
 - (int)widthForCharacters:(const UniChar *)characters length:(unsigned)length
 {
     float totalWidth = 0;
-    unsigned int i, index;
-    int glyphID;
+    unsigned int i;
     ATSLayoutRecord *glyphRecords;
     unsigned int numGlyphs;
     NSFont *substituteFont;
-    
-    ATSGlyphRef localCharacterToGlyph[LOCAL_GLYPH_BUFFER_SIZE];
-    ATSGlyphRef *usedCharacterToGlyph, *allocateCharacterToGlyph = 0;
-    
     BOOL needCharToGlyphLookup = NO;
 
 
-    // Best case, and common case for latin1, performance will require two iterations over
-    // the internalBuffer.
-    // Pass 1 (on characters):  
-    //      Determine if we can use character-to-glyph map by comparing characters to cache
-    //      range.
-    // Pass 2 (on characters):  
-    //      Sum the widths using the character-to-glyph map and width cache.
-    
-    // FIXME:  For non-latin1 character sets we don't optimize.
-    // Worst case performance we must lookup the character-to-glyph map and lookup the glyph
-    // widths.
-    
     if ([font glyphPacking] != NSNativeShortGlyphPacking &&
         [font glyphPacking] != NSTwoByteGlyphPacking)
-	[NSException raise:NSInternalInconsistencyException format:@"%@: Don't know how to pack glyphs for font %@ %f", self, [font displayName], [font pointSize]];
-    
-    if (widthCache == 0)
-        [self initializeCaches];
-    
-    // Pass 1:
-    // Check if we can use the cached character-to-glyph map.  We only use the character-to-glyph map
-    // if ALL the characters in the string fall in the safe cache range.  This must be done
-    // to ensure that we don't match composable characters incorrectly.  This check could
-    // be smarter.  Also the character-to-glyph could be extended to support other ranges
-    // of unicode.  For now, we only optimize for latin1.
+        [NSException raise:NSInternalInconsistencyException format:@"%@: Don't know how to pack glyphs for font %@ %f", self, [font displayName], [font pointSize]];
+        
     for (i = 0; i < length; i++){
-        if (characters[i] < FIRST_CACHE_CHARACTER || characters[i] > LAST_CACHE_CHARACTER){
+        UniChar c = characters[i];
+        
+        if (c == NON_BREAKING_SPACE)
+        	c = SPACE;
+        	
+        if (IsNonBaseChar(c)){
+
+            WEBKITDEBUGLEVEL (WEBKIT_LOG_FONTCACHE, "%s (0x%04x) non base character, slower measurment required\n", DEBUG_OBJECT([font displayName]), c);
+
             needCharToGlyphLookup = YES;
             break;
         }
-    }
-
-    // 1.  Check if the string contains only base characters.
-    //     If it does check to see that our cache contains that character.
-    
-    // If we can't use the cached map, then calculate a map for this string.   Expensive.
-    if (needCharToGlyphLookup){
-        
-        WEBKITDEBUGLEVEL(WEBKIT_LOG_FONTCACHECHARMISS, "character-to-glyph cache miss for character 0x%04x in %s, %.0f\n", characters[i], [[font displayName] lossyCString], [font pointSize]);
-        InitATSGlyphVector(&glyphVector, length);
-        
-        // Do the character to glyph conversion.
-        substituteFont = [self convertCharacters: characters length: length glyphs: &glyphVector];
-        if (substituteFont){
-            ResetATSGlyphVector(&glyphVector);
-            return [[(IFTextRendererFactory *)[IFTextRendererFactory sharedFactory] rendererWithFont: substituteFont] widthForCharacters: characters length: length];
+        if (glyphForCharacter(characterToGlyphMap, c) == nonGlyphID){
+            [self extendCharacterToGlyphMapToInclude: c];
         }
         
-        glyphRecords = (ATSLayoutRecord *)glyphVector.firstRecord;
-        numGlyphs = glyphVector.numGlyphs;
-
-        if (numGlyphs > LOCAL_GLYPH_BUFFER_SIZE)
-            usedCharacterToGlyph = allocateCharacterToGlyph = (ATSGlyphRef *)calloc (1, numGlyphs * sizeof(ATSGlyphRef));
-        else
-            usedCharacterToGlyph = &localCharacterToGlyph[0];
-            
-        for (i = 0; i < numGlyphs; i++){
-            glyphID = glyphRecords[i].glyphID;
-            usedCharacterToGlyph[i] = glyphID;
-            
-            // Fill the block of glyphs for the glyph needed. If we're going to incur the overhead
-            // of calling into CG, we may as well get a block of scaled glyph advances.
-            if (widthCache[glyphID] == UNINITIALIZED_GLYPH_WIDTH) {
-                short unsigned int sequentialGlyphs[INCREMENTAL_GLYPH_CACHE_BLOCK];
-                unsigned int blockStart, blockEnd, blockID;
-                int errorResult;
-                
-                blockStart = (glyphID / INCREMENTAL_GLYPH_CACHE_BLOCK) * INCREMENTAL_GLYPH_CACHE_BLOCK;
-                blockEnd = blockStart + INCREMENTAL_GLYPH_CACHE_BLOCK;
-                if (blockEnd > widthCacheSize)
-                    blockEnd = widthCacheSize;
-                WEBKITDEBUGLEVEL (WEBKIT_LOG_FONTCACHE, "width cache miss for glyph 0x%04x in %s, %.0f, filling block 0x%04x to 0x%04x\n", glyphID, [[font displayName] cString], [font pointSize], blockStart, blockEnd);
-                for (blockID = blockStart; blockID < blockEnd; blockID++)
-                    sequentialGlyphs[blockID-blockStart] = blockID;
-
-                errorResult = CGFontGetGlyphScaledAdvances ([font _backingCGSFont], &sequentialGlyphs[0], blockEnd-blockStart, &widthCache[blockStart], [font pointSize]);
-                if (errorResult == 0)
-                    [NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation:  unable to cache glyph widths - for %@ %f", self, [font displayName], [font pointSize]];
+        // Try to find a substitute font if this font didn't have a glyph for a character in the
+        // string.  If one isn't find we end up drawing and measuring a box.
+        if (glyphForCharacter(characterToGlyphMap, c) == 0){
+            substituteFont = [self substituteFontForCharacters: characters length: length];
+            if (substituteFont){
+                WEBKITDEBUGLEVEL (WEBKIT_LOG_FONTCACHE, "substituting %s for %s, missing 0x%04x\n", DEBUG_OBJECT([substituteFont displayName]), DEBUG_OBJECT([font displayName]), c);
+                return [[(IFTextRendererFactory *)[IFTextRendererFactory sharedFactory] rendererWithFont: substituteFont] widthForCharacters: characters length: length];
             }
         }
-
-        ResetATSGlyphVector(&glyphVector);
     }
-    else {
-        numGlyphs = length;
-        usedCharacterToGlyph = characterToGlyph;
-    }
-    
-    // Pass 2:
-    // Sum the widths for all the glyphs.
+
     if (needCharToGlyphLookup){
+        ATSGlyphVector _glyphVector;
+        IFGlyphWidth glyphWidth;
+        
+        ATSInitializeGlyphVector(length, 0, &_glyphVector);
+        [self convertCharacters: (const unichar *)characters length: (int)length glyphs: (ATSGlyphVector *)&_glyphVector];
+        numGlyphs = _glyphVector.numGlyphs;
+        glyphRecords = (ATSLayoutRecord *)_glyphVector.firstRecord;
         for (i = 0; i < numGlyphs; i++){
-            totalWidth += widthCache[usedCharacterToGlyph[i]];
+            ATSGlyphRef glyphID = glyphRecords[i].glyphID;
+            glyphWidth = widthForGlyph(self, glyphToWidthMap, glyphID);
+            totalWidth += glyphWidth;
         }
-        
-        if (allocateCharacterToGlyph)
-            free (allocateCharacterToGlyph);
+        ATSClearGlyphVector(&_glyphVector);
     }
     else {
-        for (i = 0; i < numGlyphs; i++){
-            index = characters[i]-FIRST_CACHE_CHARACTER;
-            totalWidth += widthCache[usedCharacterToGlyph[index]];
+        for (i = 0; i < length; i++){
+			UniChar c = characters[i];
+			
+			if (c == NON_BREAKING_SPACE)
+				c = SPACE;
+            totalWidth += widthForCharacter(self, c);
         }
     }
     
     return ROUND_TO_INT(totalWidth);
 }
 
+
 - (void)drawString:(NSString *)string inRect:(NSRect)rect withColor:(NSColor *)color paragraphStyle:(NSParagraphStyle *)style
 {
     [string drawInRect:rect withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
@@ -588,4 +534,112 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
         nil]];
 }
 
+
+- (ATSGlyphRef)extendCharacterToGlyphMapToInclude:(UniChar) c
+{
+    GlyphMap *map = (GlyphMap *)calloc (1, sizeof(GlyphMap));
+    ATSLayoutRecord *glyphRecords;
+    ATSGlyphVector _glyphVector;
+    UniChar end, start;
+    unsigned int _end;
+    unsigned int blockSize;
+    
+    if (characterToGlyphMap == 0)
+        blockSize = INITIAL_BLOCK_SIZE;
+    else
+        blockSize = INCREMENTAL_BLOCK_SIZE;
+    start = (c / blockSize) * blockSize;
+    _end = ((unsigned int)start) + blockSize; 
+    if (_end > 0xffff)
+        end = 0xffff;
+    else
+        end = _end;
+        
+    WEBKITDEBUGLEVEL (WEBKIT_LOG_FONTCACHE, "%s (0x%04x) adding glyphs for 0x%04x to 0x%04x\n", DEBUG_OBJECT(font), c, start, end);
+
+    map->startRange = start;
+    map->endRange = end;
+    
+    unsigned int i, count = end - start + 1;
+    short unsigned int buffer[INCREMENTAL_BLOCK_SIZE+2];
+    
+    for (i = 0; i < count; i++){
+        if (IsNonBaseChar(i+start))
+            buffer[i] = 0;
+        else
+            buffer[i] = i+start;
+    }
+
+    ATSInitializeGlyphVector(count, 0, &_glyphVector);
+    [self convertCharacters: &buffer[0] length: count glyphs: &_glyphVector];
+    if (_glyphVector.numGlyphs != count)
+        [NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation:  count and glyphID count not equal - for %@ %f", self, [font displayName], [font pointSize]];
+            
+    map->glyphs = (ATSGlyphRef *)malloc (count * sizeof(ATSGlyphRef));
+    glyphRecords = (ATSLayoutRecord *)_glyphVector.firstRecord;
+    for (i = 0; i < count; i++){
+        ATSGlyphRef glyphID = glyphRecords[i].glyphID;
+        map->glyphs[i] = glyphID;
+    }
+    ATSClearGlyphVector(&_glyphVector);
+    
+    if (characterToGlyphMap == 0)
+        characterToGlyphMap = map;
+    else {
+        GlyphMap *lastMap = characterToGlyphMap;
+        while (lastMap->next != 0)
+            lastMap = lastMap->next;
+        lastMap->next = map;
+    }
+
+    return map->glyphs[c - start];
+}
+
+
+- (WidthMap *)extendGlyphToWidthMapToInclude:(ATSGlyphRef)glyphID
+{
+    WidthMap *map = (WidthMap *)calloc (1, sizeof(WidthMap));
+    unsigned int end;
+    ATSGlyphRef start;
+    unsigned int blockSize;
+    
+    if (glyphToWidthMap == 0)
+        blockSize = INITIAL_BLOCK_SIZE;
+    else
+        blockSize = INCREMENTAL_BLOCK_SIZE;
+    start = (glyphID / blockSize) * blockSize;
+    end = ((unsigned int)start) + blockSize; 
+    if (end > 0xffff)
+        end = 0xffff;
+
+    unsigned int i, count = end - start + 1;
+
+    WEBKITDEBUGLEVEL (WEBKIT_LOG_FONTCACHE, "%s (0x%04x) adding widths for range 0x%04x to 0x%04x\n", DEBUG_OBJECT(font), glyphID, start, end);
+
+    map->startRange = start;
+    map->endRange = end;
+
+    map->widths = (IFGlyphWidth *)malloc (count * sizeof(IFGlyphWidth));
+
+    for (i = 0; i < count; i++){
+        map->widths[i] = UNINITIALIZED_GLYPH_WIDTH;
+    }
+
+    if (glyphToWidthMap == 0)
+        glyphToWidthMap = map;
+    else {
+        WidthMap *lastMap = glyphToWidthMap;
+        while (lastMap->next != 0)
+            lastMap = lastMap->next;
+        lastMap->next = map;
+    }
+
+#ifdef _TIMING
+    WEBKITDEBUGLEVEL (WEBKIT_LOG_FONTCACHE, "%s total time to advances lookup %f seconds\n", DEBUG_OBJECT(font), totalCGGetAdvancesTime);
+#endif
+    return map;
+}
+
+
 @end
+
diff --git a/WebKit/WebCoreSupport.subproj/WebTextRenderer.h b/WebKit/WebCoreSupport.subproj/WebTextRenderer.h
index 4914a28..6583237 100644
--- a/WebKit/WebCoreSupport.subproj/WebTextRenderer.h
+++ b/WebKit/WebCoreSupport.subproj/WebTextRenderer.h
@@ -11,24 +11,42 @@
 
 typedef float IFGlyphWidth;
 
+
+typedef struct _WidthMap {
+    ATSGlyphRef startRange;
+    ATSGlyphRef endRange;
+    struct _WidthMap *next;
+    IFGlyphWidth *widths;
+} WidthMap;
+
+typedef struct _GlyphMap {
+    UniChar startRange;
+    UniChar endRange;
+    struct _GlyphMap *next;
+    ATSGlyphRef *glyphs;
+} GlyphMap;
+
 @interface IFTextRenderer : NSObject <WebCoreTextRenderer>
 {
+ at public
     NSFont *font;
     int ascent;
     int descent;
     int lineSpacing;
     
     ATSStyleGroupPtr styleGroup;
-    ATSGlyphVector glyphVector;
     unsigned int widthCacheSize;
     IFGlyphWidth *widthCache;
-    ATSGlyphRef *characterToGlyph;
+    GlyphMap *characterToGlyphMap;
+    WidthMap *glyphToWidthMap;
     
     NSArray *substituteFontRenderers;
 }
 
 - initWithFont:(NSFont *)font;
-- (NSFont *)convertCharacters: (const unichar *)characters length: (int)numCharacters glyphs: (ATSGlyphVector *)glyphs;
+- (void)convertCharacters: (const unichar *)characters length: (int)numCharacters glyphs: (ATSGlyphVector *)glyphs;
+- (ATSGlyphRef)extendCharacterToGlyphMapToInclude:(UniChar) c;
+- (WidthMap *)extendGlyphToWidthMapToInclude:(ATSGlyphRef)glyphID;
 
 
 @end
diff --git a/WebKit/WebCoreSupport.subproj/WebTextRenderer.m b/WebKit/WebCoreSupport.subproj/WebTextRenderer.m
index 47e46de..b043f29 100644
--- a/WebKit/WebCoreSupport.subproj/WebTextRenderer.m
+++ b/WebKit/WebCoreSupport.subproj/WebTextRenderer.m
@@ -26,26 +26,21 @@
 #define INITIAL_GLYPH_CACHE_MAX 512
 #define INCREMENTAL_GLYPH_CACHE_BLOCK 1024
 
-#define UNINITIALIZED_GLYPH_WIDTH 65535
+// Covers most of latin1.
+#define INITIAL_BLOCK_SIZE 0x200
 
-static CFCharacterSetRef nonBaseChars = NULL;
+// Get additional blocks of glyphs and widths in bigger chunks.
+// This will typically be for other character sets.
+#define INCREMENTAL_BLOCK_SIZE 0x400
+
+#define UNINITIALIZED_GLYPH_WIDTH 65535
 
 // combining char, hangul jamo, or Apple corporate variant tag
 #define JunseongStart 0x1160
 #define JonseongEnd 0x11F9
 #define IsHangulConjoiningJamo(X) (X >= JunseongStart && X <= JonseongEnd)
-#define IsNonBaseChar(X) ((CFCharacterSetIsCharacterMember(nonBaseChars, X) || IsHangulConjoiningJamo(X) || (X & 0x1FFFF0) == 0xF870))
-
-
-// These definitions are used to bound the character-to-glyph mapping cache.  The
-// range is limited to LATIN1.  When accessing the cache a check must be made to
-// determine that a character range does not include a composable charcter.
+#define IsNonBaseChar(X) ((CFCharacterSetIsCharacterMember(nonBaseChars, X) || IsHangulConjoiningJamo(X) || (((X) & 0x1FFFF0) == 0xF870)))
 
-// The first displayable character in latin1. (SPACE)
-#define FIRST_CACHE_CHARACTER (0x20)
-
-// The last character in latin1 extended A. (LATIN SMALL LETTER LONG S)
-#define LAST_CACHE_CHARACTER (0x17F)
 
 @interface NSLanguage : NSObject 
 {
@@ -53,7 +48,6 @@ static CFCharacterSetRef nonBaseChars = NULL;
 + (NSLanguage *)defaultLanguage;
 @end
 
-
 @interface NSFont (IFPrivate)
 - (ATSUFontID)_atsFontID;
 - (CGFontRef)_backingCGSFont;
@@ -62,37 +56,85 @@ static CFCharacterSetRef nonBaseChars = NULL;
 + (NSFont *) findFontLike:(NSFont *)aFont forString:(NSString *)string withRange:(NSRange)range inLanguage:(NSLanguage *) language;
 @end
 
-static void InitATSGlyphVector(ATSGlyphVector *glyphVector, UInt32 numGlyphs)
+ at class NSCGSFont;
+
+
+static CFCharacterSetRef nonBaseChars = NULL;
+
+
+static void freeWidthMap (WidthMap *map)
+{
+    if (map->next)
+        freeWidthMap (map->next);
+    free (map->widths);
+    free (map);
+}
+
+
+static void freeGlyphMap (GlyphMap *map)
 {
-    if (glyphVector->numAllocatedGlyphs == 0) {
-        ATSInitializeGlyphVector(numGlyphs, 0, glyphVector);
-
-//#warning Aki: 6/28/00 Need to reconsider these when we do bidi
-        ATSFree(glyphVector->levelIndexes);
-        glyphVector->levelIndexes = NULL;
-    } else if (glyphVector->numAllocatedGlyphs < numGlyphs) {
-        ATSGrowGlyphVector(numGlyphs - glyphVector->numAllocatedGlyphs, glyphVector);
+    if (map->next)
+        freeGlyphMap (map->next);
+    free (map->glyphs);
+    free (map);
+}
+
+
+static inline ATSGlyphRef glyphForCharacter (GlyphMap *map, UniChar c)
+{
+    if (map == 0)
+        return nonGlyphID;
+        
+    if (c >= map->startRange && c <= map->endRange)
+        return ((ATSGlyphRef *)map->glyphs)[c-map->startRange];
+        
+    return glyphForCharacter (map->next, c);
+}
+ 
+ 
+#ifdef _TIMING        
+static double totalCGGetAdvancesTime = 0;
+#endif
+
+static inline IFGlyphWidth widthForGlyph (IFTextRenderer *renderer, WidthMap *map, ATSGlyphRef glyph)
+{
+    IFGlyphWidth width;
+    bool errorResult;
+    
+    if (map == 0){
+        map = [renderer extendGlyphToWidthMapToInclude: glyph];
+        return widthForGlyph (renderer, map, glyph);
+    }
+        
+    if (glyph >= map->startRange && glyph <= map->endRange){
+        width = ((IFGlyphWidth *)map->widths)[glyph-map->startRange];
+        if (width == UNINITIALIZED_GLYPH_WIDTH){
+
+#ifdef _TIMING        
+            double startTime = CFAbsoluteTimeGetCurrent();
+#endif
+            errorResult = CGFontGetGlyphScaledAdvances ([renderer->font _backingCGSFont], &glyph, 1, &map->widths[glyph-map->startRange], [renderer->font pointSize]);
+            if (errorResult == 0)
+                [NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation:  unable to cache glyph widths - for %@ %f",  [renderer->font displayName], [renderer->font pointSize]];
+    
+#ifdef _TIMING        
+            double thisTime = CFAbsoluteTimeGetCurrent() - startTime;
+            totalCGGetAdvancesTime += thisTime;
+#endif
+            return ((IFGlyphWidth *)map->widths)[glyph-map->startRange];
+        }
+        return width;
     }
+
+    return widthForGlyph (renderer, map->next, glyph);
 }
 
-static void ResetATSGlyphVector(ATSGlyphVector *glyphVector)
+
+static inline  IFGlyphWidth widthForCharacter (IFTextRenderer *renderer, UniChar c)
 {
-    ATSGlyphVector tmpVector = *glyphVector;
-
-    // Prevents glyph array & style settings from deallocated
-    glyphVector->firstRecord = NULL;
-    glyphVector->styleSettings = NULL;
-    glyphVector->levelIndexes = NULL;
-    ATSClearGlyphVector(glyphVector);
-
-    glyphVector->numAllocatedGlyphs = tmpVector.numAllocatedGlyphs;
-    glyphVector->recordSize = tmpVector.recordSize;
-    glyphVector->firstRecord = tmpVector.firstRecord;
-    glyphVector->styleSettings = tmpVector.styleSettings;
-    glyphVector->levelIndexes = tmpVector.levelIndexes;
+    return widthForGlyph (renderer, renderer->glyphToWidthMap, glyphForCharacter(renderer->characterToGlyphMap, c));
 }
 
- at class NSCGSFont;
 
 static void FillStyleWithAttributes(ATSUStyle style, NSFont *theFont)
 {
@@ -141,13 +183,29 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     nonBaseChars = CFCharacterSetGetPredefined(kCFCharacterSetNonBase);
 }
 
+
+- (NSFont *)substituteFontForCharacters: (const unichar *)characters length: (int)numCharacters
+{
+    NSFont *substituteFont;
+    NSString *string = [[NSString alloc] initWithCharactersNoCopy:(unichar *)characters length: numCharacters freeWhenDone: NO];
+
+    substituteFont = [NSFont findFontLike:font forString:string withRange:NSMakeRange (0,numCharacters) inLanguage:[NSLanguage defaultLanguage]];
+    [string release];
+    
+    if ([substituteFont isEqual: font])
+        return nil;
+        
+    return substituteFont;
+}
+
+
 /* Convert non-breaking spaces into spaces. */
-- (NSFont *)convertCharacters: (const unichar *)characters length: (int)numCharacters glyphs: (ATSGlyphVector *)glyphs
+- (void)convertCharacters: (const unichar *)characters length: (int)numCharacters glyphs: (ATSGlyphVector *)glyphs
 {
     int i;
     UniChar localBuffer[LOCAL_GLYPH_BUFFER_SIZE];
     UniChar *buffer = localBuffer;
-    NSFont *fontToBeUsed = nil;
+    OSStatus status;
     
     for (i = 0; i < numCharacters; i++) {
         if (characters[i] == NON_BREAKING_SPACE) {
@@ -175,84 +233,9 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
         free(buffer);
     }
     
-    (void)ATSUConvertCharToGlyphs(styleGroup, characters, 0, numCharacters, 0, glyphs);
-    
-    if (hasMissingGlyphs(glyphs) == YES){
-        NSString *string = [[NSString alloc] initWithCharactersNoCopy:(unichar *)characters length: numCharacters freeWhenDone: NO];
-
-        fontToBeUsed = [NSFont findFontLike:font forString:string withRange:NSMakeRange (0,numCharacters) inLanguage:[NSLanguage defaultLanguage]];
-        [string release];
-    }
-    
-    return fontToBeUsed;
+    status = ATSUConvertCharToGlyphs(styleGroup, characters, 0, numCharacters, 0, glyphs);
 }
 
-- (void)initializeCaches
-{
-    unsigned int i, glyphsToCache;
-    int errorResult;
-    size_t numGlyphsInFont = CGFontGetNumberOfGlyphs([font _backingCGSFont]);
-    short unsigned int sequentialGlyphs[INITIAL_GLYPH_CACHE_MAX];
-    ATSLayoutRecord *glyphRecords;
-    NSFont *fontToUse;
-
-    WEBKITDEBUGLEVEL (WEBKIT_LOG_FONTCACHE, "Caching %s %.0f (%ld glyphs) ascent = %f, descent = %f, defaultLineHeightForFont = %f\n", [[font displayName] cString], [font pointSize], numGlyphsInFont, [font ascender], [font descender], [font defaultLineHeightForFont]); 
-
-    // Initially just cache the max of number of glyphs in font or
-    // INITIAL_GLYPH_CACHE_MAX.  Holes in the cache will be filled on demand
-    // in INCREMENTAL_GLYPH_CACHE_BLOCK chunks. 
-    if (numGlyphsInFont > INITIAL_GLYPH_CACHE_MAX)
-        glyphsToCache = INITIAL_GLYPH_CACHE_MAX;
-    else
-        glyphsToCache = numGlyphsInFont;
-    widthCacheSize = (int)numGlyphsInFont;
-    for (i = 0; i < glyphsToCache; i++)
-        sequentialGlyphs[i] = i;
-        
-    widthCache = (IFGlyphWidth *)calloc (1, widthCacheSize * sizeof(IFGlyphWidth));
-    
-    // Some glyphs can have zero width, so we have to use a non-zero value
-    // in empty slots to indicate they are uninitialized.
-    for (i = glyphsToCache; i < widthCacheSize; i++){
-        widthCache[i] = UNINITIALIZED_GLYPH_WIDTH;
-    }
-    
-    CGContextRef cgContext;
-
-    cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
-    errorResult = CGFontGetGlyphScaledAdvances ([font _backingCGSFont], &sequentialGlyphs[0], glyphsToCache, widthCache, [font pointSize]);
-    if (errorResult == 0)
-        [NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation:  unable to cache glyph advances - for %@ %f", self, [font displayName], [font pointSize]];
-
-    unsigned int latinCount = LAST_CACHE_CHARACTER - FIRST_CACHE_CHARACTER + 1;
-    short unsigned int latinBuffer[LAST_CACHE_CHARACTER+1];
-    
-    for (i = FIRST_CACHE_CHARACTER; i <= LAST_CACHE_CHARACTER; i++){
-        latinBuffer[i] = i;
-    }
-
-    ATSGlyphVector latinGlyphVector;
-    ATSInitializeGlyphVector(latinCount, 0, &latinGlyphVector);
-    fontToUse = [self convertCharacters: &latinBuffer[FIRST_CACHE_CHARACTER] length: latinCount glyphs: &latinGlyphVector];
-    if (latinGlyphVector.numGlyphs != latinCount)
-        [NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation:  ascii and glyphID count not equal - for %@ %f", self, [font displayName], [font pointSize]];
-        
-    unsigned int numGlyphs = latinGlyphVector.numGlyphs;
-    characterToGlyph = (ATSGlyphRef *)calloc (1, latinGlyphVector.numGlyphs * sizeof(ATSGlyphRef));
-    glyphRecords = (ATSLayoutRecord *)latinGlyphVector.firstRecord;
-    for (i = 0; i < numGlyphs; i++){
-        characterToGlyph[i] = glyphRecords[i].glyphID;
-    }
-    ATSClearGlyphVector(&latinGlyphVector);
-
-#define DEBUG_CACHE_SIZE
-#ifdef DEBUG_CACHE_SIZE
-    static int totalCacheSize = 0;
-    
-    totalCacheSize += widthCacheSize * sizeof(IFGlyphWidth) + numGlyphs * sizeof(ATSGlyphRef) + sizeof(*self);
-    WEBKITDEBUGLEVEL (WEBKIT_LOG_MEMUSAGE, "memory usage in bytes:  widths = %ld, latin1 ext. character-to-glyph = %ld, total this cache = %ld, total all caches %d\n", widthCacheSize * sizeof(IFGlyphWidth), numGlyphs * sizeof(ATSGlyphRef), widthCacheSize * sizeof(IFGlyphWidth) + numGlyphs * sizeof(ATSGlyphRef) + sizeof(*self), totalCacheSize); 
-#endif
-}
 
 - initWithFont:(NSFont *)f
 {
@@ -280,20 +263,22 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     return self;
 }
 
+
 - (void)dealloc
 {
     [font release];
 
     if (styleGroup)
         ATSUDisposeStyleGroup(styleGroup);
-    if (glyphVector.numAllocatedGlyphs > 0)
-        ATSClearGlyphVector(&glyphVector);
+
     free(widthCache);
-    free(characterToGlyph);
+    freeWidthMap (glyphToWidthMap);
+    freeGlyphMap (characterToGlyphMap);
     
     [super dealloc];
 }
 
+
 - (int)widthForString:(NSString *)string
 {
     UniChar localBuffer[LOCAL_GLYPH_BUFFER_SIZE];
@@ -311,6 +296,7 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     return [self widthForCharacters:internalBuffer length:[string length]];
 }
 
+
 - (int)ascent
 {
     if (ascent < 0)  {
@@ -319,6 +305,7 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     return ascent;
 }
 
+
 - (int)descent
 {
     if (descent < 0)  {
@@ -327,6 +314,7 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     return descent;
 }
 
+
 - (int)lineSpacing
 {
     if (lineSpacing < 0) {
@@ -335,12 +323,15 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     return lineSpacing;
 }
 
+
 - (void)drawString:(NSString *)string atPoint:(NSPoint)point withColor:(NSColor *)color
 {
     NSFont *substituteFont;
     UniChar localBuffer[LOCAL_GLYPH_BUFFER_SIZE];
     const UniChar *_internalBuffer = CFStringGetCharactersPtr ((CFStringRef)string);
     const UniChar *internalBuffer;
+    ATSGlyphVector _glyphVector;
+    CGContextRef cgContext;
 
     if (!_internalBuffer){
         // FIXME: Handle case where length > LOCAL_GLYPH_BUFFER_SIZE
@@ -350,15 +341,15 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     else
         internalBuffer = _internalBuffer;
 
-    CGContextRef cgContext;
-
-    InitATSGlyphVector(&glyphVector, [string length]);
-
-    substituteFont = [self convertCharacters: internalBuffer length: [string length] glyphs: &glyphVector];
-    if (substituteFont){
-        ResetATSGlyphVector(&glyphVector);
-        [[(IFTextRendererFactory *)[IFTextRendererFactory sharedFactory] rendererWithFont: substituteFont] drawString: string atPoint: point withColor: color];
-        return;
+    ATSInitializeGlyphVector([string length], 0, &_glyphVector);
+    [self convertCharacters: internalBuffer length: [string length] glyphs: &_glyphVector];
+    if (hasMissingGlyphs (&_glyphVector)){
+        substituteFont = [self substituteFontForCharacters: internalBuffer length: [string length]];
+        ATSClearGlyphVector(&_glyphVector);
+        if (substituteFont){
+            [[(IFTextRendererFactory *)[IFTextRendererFactory sharedFactory] rendererWithFont: substituteFont] drawString: string atPoint: point withColor: color];
+            return;
+        }
     }
     
     // This will draw the text from the top of the bounding box down.
@@ -374,10 +365,10 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
         [NSException raise:NSInternalInconsistencyException format:@"%@: Don't know how to deal with font %@", self, [font displayName]];
         
     {
-        int i, numGlyphs = glyphVector.numGlyphs;
+        int i, numGlyphs = _glyphVector.numGlyphs;
         char localGlyphBuf[LOCAL_GLYPH_BUFFER_SIZE];
         char *usedGlyphBuf, *glyphBufPtr, *glyphBuf = 0;
-        ATSLayoutRecord *glyphRecords = (ATSLayoutRecord *)glyphVector.firstRecord;
+        ATSLayoutRecord *glyphRecords = (ATSLayoutRecord *)_glyphVector.firstRecord;
         
         if (numGlyphs > LOCAL_GLYPH_BUFFER_SIZE/2)
             usedGlyphBuf = glyphBufPtr = glyphBuf = (char *)malloc (numGlyphs * 2);
@@ -398,12 +389,14 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
             free (glyphBuf);
     }
 
-    ResetATSGlyphVector(&glyphVector);
+    ATSClearGlyphVector(&_glyphVector);
 }
 
+
 - (void)drawUnderlineForString:(NSString *)string atPoint:(NSPoint)point withColor:(NSColor *)color
 {
     NSFont *substituteFont;
+    ATSGlyphVector _glyphVector;
     UniChar localBuffer[LOCAL_GLYPH_BUFFER_SIZE];
     const UniChar *_internalBuffer = CFStringGetCharactersPtr ((CFStringRef)string);
     const UniChar *internalBuffer;
@@ -416,13 +409,17 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     else
         internalBuffer = _internalBuffer;
 
-    InitATSGlyphVector(&glyphVector, [string length]);
-    substituteFont = [self convertCharacters: internalBuffer length: [string length] glyphs: &glyphVector];
-    ResetATSGlyphVector(&glyphVector);
-    if (substituteFont){
-        [[(IFTextRendererFactory *)[IFTextRendererFactory sharedFactory] rendererWithFont: substituteFont] drawUnderlineForString: string atPoint: point withColor: color];
-        return;
+    ATSInitializeGlyphVector([string length], 0, &_glyphVector);
+    [self convertCharacters: internalBuffer length: [string length] glyphs: &_glyphVector];
+    if (hasMissingGlyphs (&_glyphVector)){
+        substituteFont = [self substituteFontForCharacters: internalBuffer length: [string length]];
+        ATSClearGlyphVector(&_glyphVector);
+        if (substituteFont){
+            [[(IFTextRendererFactory *)[IFTextRendererFactory sharedFactory] rendererWithFont: substituteFont] drawUnderlineForString: string atPoint: point withColor: color];
+            return;
+        }
     }
+    ATSClearGlyphVector(&_glyphVector);
     
     // This will draw the text from the top of the bounding box down.
     // Qt expects to draw from the baseline.
@@ -456,129 +453,78 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
     [graphicsContext setShouldAntialias: flag];
 }
 
+
 - (int)widthForCharacters:(const UniChar *)characters length:(unsigned)length
 {
     float totalWidth = 0;
-    unsigned int i, index;
-    int glyphID;
+    unsigned int i;
     ATSLayoutRecord *glyphRecords;
     unsigned int numGlyphs;
     NSFont *substituteFont;
-    
-    ATSGlyphRef localCharacterToGlyph[LOCAL_GLYPH_BUFFER_SIZE];
-    ATSGlyphRef *usedCharacterToGlyph, *allocateCharacterToGlyph = 0;
-    
     BOOL needCharToGlyphLookup = NO;
 
 
-    // Best case, and common case for latin1, performance will require two iterations over
-    // the internalBuffer.
-    // Pass 1 (on characters):  
-    //      Determine if we can use character-to-glyph map by comparing characters to cache
-    //      range.
-    // Pass 2 (on characters):  
-    //      Sum the widths using the character-to-glyph map and width cache.
-    
-    // FIXME:  For non-latin1 character sets we don't optimize.
-    // Worst case performance we must lookup the character-to-glyph map and lookup the glyph
-    // widths.
-    
     if ([font glyphPacking] != NSNativeShortGlyphPacking &&
         [font glyphPacking] != NSTwoByteGlyphPacking)
-	[NSException raise:NSInternalInconsistencyException format:@"%@: Don't know how to pack glyphs for font %@ %f", self, [font displayName], [font pointSize]];
-    
-    if (widthCache == 0)
-        [self initializeCaches];
-    
-    // Pass 1:
-    // Check if we can use the cached character-to-glyph map.  We only use the character-to-glyph map
-    // if ALL the characters in the string fall in the safe cache range.  This must be done
-    // to ensure that we don't match composable characters incorrectly.  This check could
-    // be smarter.  Also the character-to-glyph could be extended to support other ranges
-    // of unicode.  For now, we only optimize for latin1.
+        [NSException raise:NSInternalInconsistencyException format:@"%@: Don't know how to pack glyphs for font %@ %f", self, [font displayName], [font pointSize]];
+        
     for (i = 0; i < length; i++){
-        if (characters[i] < FIRST_CACHE_CHARACTER || characters[i] > LAST_CACHE_CHARACTER){
+        UniChar c = characters[i];
+        
+        if (c == NON_BREAKING_SPACE)
+        	c = SPACE;
+        	
+        if (IsNonBaseChar(c)){
+
+            WEBKITDEBUGLEVEL (WEBKIT_LOG_FONTCACHE, "%s (0x%04x) non base character, slower measurment required\n", DEBUG_OBJECT([font displayName]), c);
+
             needCharToGlyphLookup = YES;
             break;
         }
-    }
-
-    // 1.  Check if the string contains only base characters.
-    //     If it does check to see that our cache contains that character.
-    
-    // If we can't use the cached map, then calculate a map for this string.   Expensive.
-    if (needCharToGlyphLookup){
-        
-        WEBKITDEBUGLEVEL(WEBKIT_LOG_FONTCACHECHARMISS, "character-to-glyph cache miss for character 0x%04x in %s, %.0f\n", characters[i], [[font displayName] lossyCString], [font pointSize]);
-        InitATSGlyphVector(&glyphVector, length);
-        
-        // Do the character to glyph conversion.
-        substituteFont = [self convertCharacters: characters length: length glyphs: &glyphVector];
-        if (substituteFont){
-            ResetATSGlyphVector(&glyphVector);
-            return [[(IFTextRendererFactory *)[IFTextRendererFactory sharedFactory] rendererWithFont: substituteFont] widthForCharacters: characters length: length];
+        if (glyphForCharacter(characterToGlyphMap, c) == nonGlyphID){
+            [self extendCharacterToGlyphMapToInclude: c];
         }
         
-        glyphRecords = (ATSLayoutRecord *)glyphVector.firstRecord;
-        numGlyphs = glyphVector.numGlyphs;
-
-        if (numGlyphs > LOCAL_GLYPH_BUFFER_SIZE)
-            usedCharacterToGlyph = allocateCharacterToGlyph = (ATSGlyphRef *)calloc (1, numGlyphs * sizeof(ATSGlyphRef));
-        else
-            usedCharacterToGlyph = &localCharacterToGlyph[0];
-            
-        for (i = 0; i < numGlyphs; i++){
-            glyphID = glyphRecords[i].glyphID;
-            usedCharacterToGlyph[i] = glyphID;
-            
-            // Fill the block of glyphs for the glyph needed. If we're going to incur the overhead
-            // of calling into CG, we may as well get a block of scaled glyph advances.
-            if (widthCache[glyphID] == UNINITIALIZED_GLYPH_WIDTH) {
-                short unsigned int sequentialGlyphs[INCREMENTAL_GLYPH_CACHE_BLOCK];
-                unsigned int blockStart, blockEnd, blockID;
-                int errorResult;
-                
-                blockStart = (glyphID / INCREMENTAL_GLYPH_CACHE_BLOCK) * INCREMENTAL_GLYPH_CACHE_BLOCK;
-                blockEnd = blockStart + INCREMENTAL_GLYPH_CACHE_BLOCK;
-                if (blockEnd > widthCacheSize)
-                    blockEnd = widthCacheSize;
-                WEBKITDEBUGLEVEL (WEBKIT_LOG_FONTCACHE, "width cache miss for glyph 0x%04x in %s, %.0f, filling block 0x%04x to 0x%04x\n", glyphID, [[font displayName] cString], [font pointSize], blockStart, blockEnd);
-                for (blockID = blockStart; blockID < blockEnd; blockID++)
-                    sequentialGlyphs[blockID-blockStart] = blockID;
-
-                errorResult = CGFontGetGlyphScaledAdvances ([font _backingCGSFont], &sequentialGlyphs[0], blockEnd-blockStart, &widthCache[blockStart], [font pointSize]);
-                if (errorResult == 0)
-                    [NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation:  unable to cache glyph widths - for %@ %f", self, [font displayName], [font pointSize]];
+        // Try to find a substitute font if this font didn't have a glyph for a character in the
+        // string.  If one isn't find we end up drawing and measuring a box.
+        if (glyphForCharacter(characterToGlyphMap, c) == 0){
+            substituteFont = [self substituteFontForCharacters: characters length: length];
+            if (substituteFont){
+                WEBKITDEBUGLEVEL (WEBKIT_LOG_FONTCACHE, "substituting %s for %s, missing 0x%04x\n", DEBUG_OBJECT([substituteFont displayName]), DEBUG_OBJECT([font displayName]), c);
+                return [[(IFTextRendererFactory *)[IFTextRendererFactory sharedFactory] rendererWithFont: substituteFont] widthForCharacters: characters length: length];
             }
         }
-
-        ResetATSGlyphVector(&glyphVector);
     }
-    else {
-        numGlyphs = length;
-        usedCharacterToGlyph = characterToGlyph;
-    }
-    
-    // Pass 2:
-    // Sum the widths for all the glyphs.
+
     if (needCharToGlyphLookup){
+        ATSGlyphVector _glyphVector;
+        IFGlyphWidth glyphWidth;
+        
+        ATSInitializeGlyphVector(length, 0, &_glyphVector);
+        [self convertCharacters: (const unichar *)characters length: (int)length glyphs: (ATSGlyphVector *)&_glyphVector];
+        numGlyphs = _glyphVector.numGlyphs;
+        glyphRecords = (ATSLayoutRecord *)_glyphVector.firstRecord;
         for (i = 0; i < numGlyphs; i++){
-            totalWidth += widthCache[usedCharacterToGlyph[i]];
+            ATSGlyphRef glyphID = glyphRecords[i].glyphID;
+            glyphWidth = widthForGlyph(self, glyphToWidthMap, glyphID);
+            totalWidth += glyphWidth;
         }
-        
-        if (allocateCharacterToGlyph)
-            free (allocateCharacterToGlyph);
+        ATSClearGlyphVector(&_glyphVector);
     }
     else {
-        for (i = 0; i < numGlyphs; i++){
-            index = characters[i]-FIRST_CACHE_CHARACTER;
-            totalWidth += widthCache[usedCharacterToGlyph[index]];
+        for (i = 0; i < length; i++){
+			UniChar c = characters[i];
+			
+			if (c == NON_BREAKING_SPACE)
+				c = SPACE;
+            totalWidth += widthForCharacter(self, c);
         }
     }
     
     return ROUND_TO_INT(totalWidth);
 }
 
+
 - (void)drawString:(NSString *)string inRect:(NSRect)rect withColor:(NSColor *)color paragraphStyle:(NSParagraphStyle *)style
 {
     [string drawInRect:rect withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
@@ -588,4 +534,112 @@ static bool hasMissingGlyphs(ATSGlyphVector *glyphs)
         nil]];
 }
 
+
+- (ATSGlyphRef)extendCharacterToGlyphMapToInclude:(UniChar) c
+{
+    GlyphMap *map = (GlyphMap *)calloc (1, sizeof(GlyphMap));
+    ATSLayoutRecord *glyphRecords;
+    ATSGlyphVector _glyphVector;
+    UniChar end, start;
+    unsigned int _end;
+    unsigned int blockSize;
+    
+    if (characterToGlyphMap == 0)
+        blockSize = INITIAL_BLOCK_SIZE;
+    else
+        blockSize = INCREMENTAL_BLOCK_SIZE;
+    start = (c / blockSize) * blockSize;
+    _end = ((unsigned int)start) + blockSize; 
+    if (_end > 0xffff)
+        end = 0xffff;
+    else
+        end = _end;
+        
+    WEBKITDEBUGLEVEL (WEBKIT_LOG_FONTCACHE, "%s (0x%04x) adding glyphs for 0x%04x to 0x%04x\n", DEBUG_OBJECT(font), c, start, end);
+
+    map->startRange = start;
+    map->endRange = end;
+    
+    unsigned int i, count = end - start + 1;
+    short unsigned int buffer[INCREMENTAL_BLOCK_SIZE+2];
+    
+    for (i = 0; i < count; i++){
+        if (IsNonBaseChar(i+start))
+            buffer[i] = 0;
+        else
+            buffer[i] = i+start;
+    }
+
+    ATSInitializeGlyphVector(count, 0, &_glyphVector);
+    [self convertCharacters: &buffer[0] length: count glyphs: &_glyphVector];
+    if (_glyphVector.numGlyphs != count)
+        [NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation:  count and glyphID count not equal - for %@ %f", self, [font displayName], [font pointSize]];
+            
+    map->glyphs = (ATSGlyphRef *)malloc (count * sizeof(ATSGlyphRef));
+    glyphRecords = (ATSLayoutRecord *)_glyphVector.firstRecord;
+    for (i = 0; i < count; i++){
+        ATSGlyphRef glyphID = glyphRecords[i].glyphID;
+        map->glyphs[i] = glyphID;
+    }
+    ATSClearGlyphVector(&_glyphVector);
+    
+    if (characterToGlyphMap == 0)
+        characterToGlyphMap = map;
+    else {
+        GlyphMap *lastMap = characterToGlyphMap;
+        while (lastMap->next != 0)
+            lastMap = lastMap->next;
+        lastMap->next = map;
+    }
+
+    return map->glyphs[c - start];
+}
+
+
+- (WidthMap *)extendGlyphToWidthMapToInclude:(ATSGlyphRef)glyphID
+{
+    WidthMap *map = (WidthMap *)calloc (1, sizeof(WidthMap));
+    unsigned int end;
+    ATSGlyphRef start;
+    unsigned int blockSize;
+    
+    if (glyphToWidthMap == 0)
+        blockSize = INITIAL_BLOCK_SIZE;
+    else
+        blockSize = INCREMENTAL_BLOCK_SIZE;
+    start = (glyphID / blockSize) * blockSize;
+    end = ((unsigned int)start) + blockSize; 
+    if (end > 0xffff)
+        end = 0xffff;
+
+    unsigned int i, count = end - start + 1;
+
+    WEBKITDEBUGLEVEL (WEBKIT_LOG_FONTCACHE, "%s (0x%04x) adding widths for range 0x%04x to 0x%04x\n", DEBUG_OBJECT(font), glyphID, start, end);
+
+    map->startRange = start;
+    map->endRange = end;
+
+    map->widths = (IFGlyphWidth *)malloc (count * sizeof(IFGlyphWidth));
+
+    for (i = 0; i < count; i++){
+        map->widths[i] = UNINITIALIZED_GLYPH_WIDTH;
+    }
+
+    if (glyphToWidthMap == 0)
+        glyphToWidthMap = map;
+    else {
+        WidthMap *lastMap = glyphToWidthMap;
+        while (lastMap->next != 0)
+            lastMap = lastMap->next;
+        lastMap->next = map;
+    }
+
+#ifdef _TIMING
+    WEBKITDEBUGLEVEL (WEBKIT_LOG_FONTCACHE, "%s total time to advances lookup %f seconds\n", DEBUG_OBJECT(font), totalCGGetAdvancesTime);
+#endif
+    return map;
+}
+
+
 @end
+

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list