[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 05:57:46 UTC 2009


The following commit has been merged in the debian/unstable branch:
commit 22a7248ed1c2ce25e9f7105d698b99e331c972f0
Author: rjw <rjw at 268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Mon Mar 18 05:45:49 2002 +0000

    Implementation of replacement code for NSLayoutManager.  Huge
    performance gains.
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@768 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog-2002-12-03 b/WebCore/ChangeLog-2002-12-03
index 508308d..eff12c6 100644
--- a/WebCore/ChangeLog-2002-12-03
+++ b/WebCore/ChangeLog-2002-12-03
@@ -1,3 +1,24 @@
+2002-03-17  Richard Williamson  <rjw at apple.com>
+
+        Implementation of replacement code for NSLayoutManager.  Huge
+        performance gains.
+        
+	* src/kdelibs/khtml/rendering/render_text.cpp: (RenderText::calcMinMaxWidth),
+	(RenderText::width):
+	* src/kwq/KWQFontMetrics.mm: (ROUND_TO_INT), (__IFInitATSGlyphVector),
+	(__IFResetATSGlyphVector), (__IFFillStyleWithAttributes), (-[KWQLayoutInfo
+	drawString:atPoint:withFont:color:]), (+[KWQLayoutInfo
+	drawString:atPoint:withFont:color:]), (-[KWQLayoutInfo
+	drawUnderlineForString:atPoint:withFont:color:]), (+[KWQLayoutInfo
+	drawUnderlineForString:atPoint:withFont:color:]), (-[KWQLayoutInfo
+	initWithFont:]), (-[KWQLayoutInfo _initializeCaches]), (_rectForString),
+	(-[KWQLayoutInfo rectForString:]), (-[KWQLayoutInfo attributes]),
+	(-[KWQLayoutInfo lineHeight]), (-[KWQLayoutInfo font]), (-[KWQLayoutInfo
+	dealloc]), (QFontMetrics::_width):
+	* src/kwq/KWQMetrics.h:
+	* src/kwq/Makefile.am:
+	* src/kwq/qt/qfontmetrics.h:
+
 2002-03-16  Richard Williamson  <rjw at apple.com>
 
         Fixed error handling.  Removed ObjC code for url handle client from KHTMLPart.
diff --git a/WebCore/ChangeLog-2003-10-25 b/WebCore/ChangeLog-2003-10-25
index 508308d..eff12c6 100644
--- a/WebCore/ChangeLog-2003-10-25
+++ b/WebCore/ChangeLog-2003-10-25
@@ -1,3 +1,24 @@
+2002-03-17  Richard Williamson  <rjw at apple.com>
+
+        Implementation of replacement code for NSLayoutManager.  Huge
+        performance gains.
+        
+	* src/kdelibs/khtml/rendering/render_text.cpp: (RenderText::calcMinMaxWidth),
+	(RenderText::width):
+	* src/kwq/KWQFontMetrics.mm: (ROUND_TO_INT), (__IFInitATSGlyphVector),
+	(__IFResetATSGlyphVector), (__IFFillStyleWithAttributes), (-[KWQLayoutInfo
+	drawString:atPoint:withFont:color:]), (+[KWQLayoutInfo
+	drawString:atPoint:withFont:color:]), (-[KWQLayoutInfo
+	drawUnderlineForString:atPoint:withFont:color:]), (+[KWQLayoutInfo
+	drawUnderlineForString:atPoint:withFont:color:]), (-[KWQLayoutInfo
+	initWithFont:]), (-[KWQLayoutInfo _initializeCaches]), (_rectForString),
+	(-[KWQLayoutInfo rectForString:]), (-[KWQLayoutInfo attributes]),
+	(-[KWQLayoutInfo lineHeight]), (-[KWQLayoutInfo font]), (-[KWQLayoutInfo
+	dealloc]), (QFontMetrics::_width):
+	* src/kwq/KWQMetrics.h:
+	* src/kwq/Makefile.am:
+	* src/kwq/qt/qfontmetrics.h:
+
 2002-03-16  Richard Williamson  <rjw at apple.com>
 
         Fixed error handling.  Removed ObjC code for url handle client from KHTMLPart.
diff --git a/WebCore/ChangeLog-2005-08-23 b/WebCore/ChangeLog-2005-08-23
index 508308d..eff12c6 100644
--- a/WebCore/ChangeLog-2005-08-23
+++ b/WebCore/ChangeLog-2005-08-23
@@ -1,3 +1,24 @@
+2002-03-17  Richard Williamson  <rjw at apple.com>
+
+        Implementation of replacement code for NSLayoutManager.  Huge
+        performance gains.
+        
+	* src/kdelibs/khtml/rendering/render_text.cpp: (RenderText::calcMinMaxWidth),
+	(RenderText::width):
+	* src/kwq/KWQFontMetrics.mm: (ROUND_TO_INT), (__IFInitATSGlyphVector),
+	(__IFResetATSGlyphVector), (__IFFillStyleWithAttributes), (-[KWQLayoutInfo
+	drawString:atPoint:withFont:color:]), (+[KWQLayoutInfo
+	drawString:atPoint:withFont:color:]), (-[KWQLayoutInfo
+	drawUnderlineForString:atPoint:withFont:color:]), (+[KWQLayoutInfo
+	drawUnderlineForString:atPoint:withFont:color:]), (-[KWQLayoutInfo
+	initWithFont:]), (-[KWQLayoutInfo _initializeCaches]), (_rectForString),
+	(-[KWQLayoutInfo rectForString:]), (-[KWQLayoutInfo attributes]),
+	(-[KWQLayoutInfo lineHeight]), (-[KWQLayoutInfo font]), (-[KWQLayoutInfo
+	dealloc]), (QFontMetrics::_width):
+	* src/kwq/KWQMetrics.h:
+	* src/kwq/Makefile.am:
+	* src/kwq/qt/qfontmetrics.h:
+
 2002-03-16  Richard Williamson  <rjw at apple.com>
 
         Fixed error handling.  Removed ObjC code for url handle client from KHTMLPart.
diff --git a/WebCore/khtml/rendering/render_text.cpp b/WebCore/khtml/rendering/render_text.cpp
index 03b27f2..effdfe3 100644
--- a/WebCore/khtml/rendering/render_text.cpp
+++ b/WebCore/khtml/rendering/render_text.cpp
@@ -45,9 +45,6 @@
 
 #ifdef APPLE_CHANGES
 #define OPTIMIZE_STRING_USAGE
-#ifdef OPTIMIZE_STRING_USAGE
-static CFMutableStringRef reuseableString = 0;
-#endif
 #endif
 
 
@@ -695,7 +692,7 @@ void RenderText::calcMinMaxWidth()
         if (wordlen)
         {
 #if (defined(APPLE_CHANGES) && defined(OPTIMIZE_STRING_USAGE))
-            int w = _fm._width(QString::gstring_toCFString(&reuseableString, (UniChar *)(str->s+i), wordlen));
+            int w = _fm._width((const UniChar *)(str->s+i), wordlen);
 #else
             int w = _fm.width(QConstString(str->s+i, wordlen).string());
 #endif
@@ -718,7 +715,7 @@ void RenderText::calcMinMaxWidth()
                 if(currMinWidth > m_minWidth) m_minWidth = currMinWidth;
                 currMinWidth = 0;
 #if (defined(APPLE_CHANGES) && defined(OPTIMIZE_STRING_USAGE))
-                currMaxWidth += _fm._width(QString::gstring_toCFString(&reuseableString, (UniChar *)(str->s+i+wordlen), 1));
+                currMaxWidth += _fm._width((const UniChar *)(str->s+i+wordlen), 1);
 #else
                 currMaxWidth += _fm.width( *(str->s+i+wordlen) );
 #endif
@@ -900,7 +897,7 @@ unsigned int RenderText::width(unsigned int from, unsigned int len, QFontMetrics
         w = _fm->width( *(str->s+from) );
     else
 #if (defined(APPLE_CHANGES) && defined(OPTIMIZE_STRING_USAGE))
-        w = _fm->_width(QString::gstring_toCFString(&reuseableString, (UniChar *)(str->s+from), len));
+        w = _fm->_width((const UniChar *)(str->s+from), len);
 #else
         w = _fm->width(QConstString(str->s+from, len).string());
 #endif
diff --git a/WebCore/kwq/KWQFontMetrics.h b/WebCore/kwq/KWQFontMetrics.h
index b462a8e..3e38d50 100644
--- a/WebCore/kwq/KWQFontMetrics.h
+++ b/WebCore/kwq/KWQFontMetrics.h
@@ -71,6 +71,7 @@ public:
     int width(const QString &, int len=-1) const;
 #if (defined(__APPLE__))
     int _width (CFStringRef string) const;
+    int _width (const UniChar *uchars, int len) const;
 #endif
 
     int descent() const;
diff --git a/WebCore/kwq/KWQFontMetrics.mm b/WebCore/kwq/KWQFontMetrics.mm
index 30b6d2d..4195628 100644
--- a/WebCore/kwq/KWQFontMetrics.mm
+++ b/WebCore/kwq/KWQFontMetrics.mm
@@ -28,13 +28,26 @@
 #include <qfontmetrics.h>
 
 #import <Cocoa/Cocoa.h>
+
+#define DIRECT_TO_CG
+
 #import <KWQMetrics.h>
 #import <KWQTextStorage.h>
 #import <KWQTextContainer.h>
 
 #define FLOOR_TO_INT(x) (int)(floor(x))
-#define ROUND_TO_INT(x) (int)(((x) > (floor(x) + .5)) ? ceil(x) : floor(x))
-//#define ROUND_TO_INT(f) ((int)(rint(f)))
+//#define ROUND_TO_INT(x) (int)(((x) > (floor(x) + .5)) ? ceil(x) : floor(x))
+#define ROUND_TO_INT(x) (int)(x+.5)
+#ifdef FOOOOFOOO
+static inline int ROUND_TO_INT (float x)
+{
+    int floored = (int)(x);
+    
+    if (((float)x) > ((float)(floored) + .5))
+        return (int)ceil(x);
+    return floored;
+}
+#endif
 
 @implementation KWQSmallLayoutFragment
 - (NSRange)glyphRange
@@ -142,41 +155,180 @@ static NSMutableDictionary *metricsCache = nil;
 */
 @implementation KWQLayoutInfo
 
-+ (void)drawString: (NSString *)string atPoint: (NSPoint)p withFont: (NSFont *)font color: (NSColor *)color
+#ifdef DIRECT_TO_CG
+
+static void __IFInitATSGlyphVector(ATSGlyphVector *glyphVector, UInt32 numGlyphs) {
+    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);
+    }
+}
+
+static void __IFResetATSGlyphVector(ATSGlyphVector *glyphVector) {
+    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;
+}
+
+ at class NSCGSFont;
+
+static void __IFFillStyleWithAttributes(ATSUStyle style, NSFont *theFont) {
+    if (theFont) {
+        ATSUFontID fontId = (ATSUFontID)[theFont _atsFontID];
+        ATSUAttributeTag tag = kATSUFontTag;
+        ByteCount size = sizeof(ATSUFontID);
+        ATSUFontID *valueArray[1] = {&fontId};
+
+        if (fontId) {
+            if (ATSUSetAttributes(style, 1, &tag, &size, (const ATSUAttributeValuePtr)valueArray) != noErr)
+                [NSException raise:NSInternalInconsistencyException format:@"Failed to set font (%@) ATSUStyle 0x%X", theFont, style];
+
+#if 1
+//#warning Aki 7/20/2000 This code should be disabled once the brain dead bug 2499383 is fixed
+            {
+                ATSUFontFeatureType types[8] = {kDiacriticsType, kTypographicExtrasType, kFractionsType, kSmartSwashType, kSmartSwashType, kSmartSwashType, kSmartSwashType, kSmartSwashType};
+                ATSUFontFeatureSelector selectors[8] = {kDecomposeDiacriticsSelector, kSmartQuotesOffSelector, kNoFractionsSelector, kWordInitialSwashesOffSelector, kWordFinalSwashesOffSelector, kLineInitialSwashesOffSelector, kLineFinalSwashesOffSelector, kNonFinalSwashesOffSelector};
+                ATSUSetFontFeatures(style, 8, types, selectors);
+            }
+#endif
+        }
+    }
+}
+#endif
+
+- (void)drawString: (NSString *)string atPoint: (NSPoint)p withFont: (NSFont *)aFont color: (NSColor *)color
 {
-    KWQLayoutInfo *layoutInfo = [KWQLayoutInfo getMetricsForFont: font];
-    NSLayoutManager *manager = [layoutInfo layoutManager];
-    KWQTextStorage *storage = [layoutInfo textStorage];
+#ifdef DIRECT_TO_CG
+    UniChar localBuffer[LOCAL_GLYPH_BUFFER_SIZE];
+    const UniChar *_internalBuffer = CFStringGetCharactersPtr ((CFStringRef)string);
+    const UniChar *internalBuffer;
 
-    if (manager != nil){
-        id <KWQLayoutFragment> frag = [storage getFragmentForString: (NSString *)string];
+    if (!_internalBuffer){
+        CFStringGetCharacters((CFStringRef)string, CFRangeMake(0, CFStringGetLength((CFStringRef)string)), &localBuffer[0]);
+        internalBuffer = &localBuffer[0];
+    }
+    else
+        internalBuffer = _internalBuffer;
+
+    CGContextRef cgContext;
 
-        [layoutInfo setColor: color];
-        [layoutInfo setFont: font];
-        [[layoutInfo textStorage] setAttributes: [layoutInfo attributes]];
-        [[layoutInfo textStorage] setString: string];
-        [manager drawGlyphsForGlyphRange:[frag glyphRange] atPoint:p];
+    __IFInitATSGlyphVector(&_glyphVector, [string length]);
+
+    (void)ATSUConvertCharToGlyphs(_styleGroup, internalBuffer, 0, [string length], 0, (ATSGlyphVector *)&_glyphVector);
+
+    [color set];
+    [aFont set];
+    
+    if ([aFont glyphPacking] != NSNativeShortGlyphPacking &&
+        [aFont glyphPacking] != NSTwoByteGlyphPacking)
+        [NSException raise:NSInternalInconsistencyException format:@"%@: Don't know how to deal with font %@", self, [aFont displayName]];
+        
+    {
+        int i, numGlyphs = _glyphVector.numGlyphs;
+        char localGlyphBuf[LOCAL_GLYPH_BUFFER_SIZE];
+        char *usedGlyphBuf, *glyphBufPtr, *glyphBuf = 0;
+        ATSLayoutRecord *glyphRecords = _glyphVector.firstRecord;
+        
+        if (numGlyphs > LOCAL_GLYPH_BUFFER_SIZE/2)
+            usedGlyphBuf = glyphBufPtr = glyphBuf = (char *)malloc (numGlyphs * 2);
+        else
+            usedGlyphBuf = glyphBufPtr = &localGlyphBuf[0];
+            
+        for (i = 0; i < numGlyphs; i++){
+            *glyphBufPtr++ = (char)((glyphRecords->glyphID >> 8) & 0x00FF);
+            *glyphBufPtr++ = (char)(glyphRecords->glyphID & 0x00FF);
+            glyphRecords++;
+        }
+        cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+        CGContextSetCharacterSpacing(cgContext, 0.0);
+        //CGContextShowGlyphsAtPoint (cgContext, p.x, p.y + [frag boundingRect].size.height + (int)[font descender] - 1, (const short unsigned int *)usedGlyphBuf, numGlyphs);
+        CGContextShowGlyphsAtPoint (cgContext, p.x, p.y + lineHeight - 1, (const short unsigned int *)usedGlyphBuf, numGlyphs);
+        
+        if (glyphBuf)
+            free (glyphBuf);
     }
+
+    __IFResetATSGlyphVector(&_glyphVector);
+#else
+    id <KWQLayoutFragment> frag = [storage getFragmentForString: (NSString *)string];
+    NSLog (@"WARNING:  Unable to use CG for drawString:atPoint:withFont:color:\n");
+
+    [self setColor: color];
+    [textStorage setAttributes: [layoutInfo attributes]];
+    [textStorage setString: string];
+    [layoutManager drawGlyphsForGlyphRange:[frag glyphRange] atPoint:p];
+#endif
 }
 
-+ (void)drawUnderlineForString: (NSString *)string atPoint: (NSPoint)p withFont: (NSFont *)font color: (NSColor *)color
+
++ (void)drawString: (NSString *)string atPoint: (NSPoint)p withFont: (NSFont *)aFont color: (NSColor *)color
 {
-    KWQLayoutInfo *layoutInfo = [KWQLayoutInfo getMetricsForFont: font];
-    NSLayoutManager *manager = [layoutInfo layoutManager];
-    KWQTextStorage *storage = [layoutInfo textStorage];
+    KWQLayoutInfo *layoutInfo = [KWQLayoutInfo getMetricsForFont: aFont];
+    [layoutInfo drawString: string atPoint: p withFont: aFont color: color];
+}
 
-    if (manager != nil){
-        id <KWQLayoutFragment>frag = [storage getFragmentForString: (NSString *)string];
 
-        [layoutInfo setColor: color];
-        [layoutInfo setFont: font];
-        [[layoutInfo textStorage] setAttributes: [layoutInfo attributes]];
-        [[layoutInfo textStorage] setString: string];
-        NSRect lineRect = [manager lineFragmentRectForGlyphAtIndex: 0 effectiveRange: 0];
-        [manager underlineGlyphRange:[frag glyphRange] underlineType:NSSingleUnderlineStyle lineFragmentRect:lineRect lineFragmentGlyphRange:[frag glyphRange] containerOrigin:p];
+- (void)drawUnderlineForString: (NSString *)string atPoint: (NSPoint)p withFont: (NSFont *)aFont color: (NSColor *)color
+{
+#ifdef DIRECT_TO_CG
+    NSRect rect = [self rectForString: string];
+    NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext];
+    CGContextRef cgContext;
+    float lineWidth;
+    
+    [color set];
+
+    BOOL flag = [graphicsContext shouldAntialias];
+
+    [graphicsContext setShouldAntialias: NO];
+
+    cgContext = (CGContextRef)[graphicsContext graphicsPort];
+    lineWidth = 0.0;
+    if ([graphicsContext isDrawingToScreen] && lineWidth == 0.0) {
+        CGSize size = CGSizeApplyAffineTransform(CGSizeMake(1.0, 1.0), CGAffineTransformInvert(CGContextGetCTM(cgContext)));
+        lineWidth = size.width;
     }
+    CGContextSetLineWidth(cgContext, lineWidth);
+    CGContextMoveToPoint(cgContext, p.x, p.y + lineHeight + 0.5);
+    CGContextAddLineToPoint(cgContext, p.x + rect.size.width, p.y + lineHeight + 0.5);
+    CGContextStrokePath(cgContext);
+
+    [graphicsContext setShouldAntialias: flag];
+    
+#else
+    id <KWQLayoutFragment>frag = [storage getFragmentForString: (NSString *)string];
+
+    [self setColor: color];
+    [textStorage setAttributes: [self attributes]];
+    [textStorage setString: string];
+    NSRect lineRect = [self lineFragmentRectForGlyphAtIndex: 0 effectiveRange: 0];
+    [self underlineGlyphRange:[frag glyphRange] underlineType:NSSingleUnderlineStyle lineFragmentRect:lineRect lineFragmentGlyphRange:[frag glyphRange] containerOrigin:p];
+#endif
+}
+
++ (void)drawUnderlineForString: (NSString *)string atPoint: (NSPoint)p withFont: (NSFont *)aFont color: (NSColor *)color
+{
+    KWQLayoutInfo *layoutInfo = [KWQLayoutInfo getMetricsForFont: aFont];
+    
+    [layoutInfo drawUnderlineForString: string atPoint: p withFont: aFont color: color];
 }
 
+
 #ifdef _DEBUG_LAYOUT_FRAGMENT
 + (void)_dumpLayoutCache: (NSDictionary *)fragCache
 {
@@ -245,9 +397,34 @@ static NSMutableDictionary *metricsCache = nil;
 
 - initWithFont: (NSFont *)aFont
 {
+    OSStatus errCode;
+
     [super init];
     attributes = [[NSMutableDictionary dictionaryWithObjectsAndKeys:aFont, NSFontAttributeName, nil] retain];
 
+    font = [aFont retain];
+    lineHeight = ROUND_TO_INT([font ascender]) - ROUND_TO_INT([font descender]) + 1;
+
+#ifdef DIRECT_TO_CG
+    if ((errCode = ATSUCreateStyle(&_style)) != noErr)
+        [NSException raise:NSInternalInconsistencyException format:@"%@: Failed to alloc ATSUStyle %d", self, errCode];
+
+    __IFFillStyleWithAttributes(_style, aFont);
+
+    if ((errCode = ATSUGetStyleGroup(_style, &_styleGroup)) != noErr) {
+        [NSException raise:NSInternalInconsistencyException format:@"%@: Failed to create attribute group from ATSUStyle 0x%X %d", self, _style, errCode];
+    }            
+
+    if ((errCode = ATSUCreateStyle(&_asciiStyle)) != noErr)
+        [NSException raise:NSInternalInconsistencyException format:@"%@: Failed to alloc ATSUStyle %d", self, errCode];
+
+    __IFFillStyleWithAttributes(_asciiStyle, aFont);
+
+    if ((errCode = ATSUGetStyleGroup(_asciiStyle, &_asciiStyleGroup)) != noErr) {
+        [NSException raise:NSInternalInconsistencyException format:@"%@: Failed to create attribute group from ATSUStyle 0x%X %d", self, _style, errCode];
+    }            
+#endif
+
     textStorage = [[KWQTextStorage alloc] initWithFontAttribute: attributes];
     layoutManager = [[NSLayoutManager alloc] init];
 
@@ -269,14 +446,196 @@ static NSMutableDictionary *metricsCache = nil;
     return textStorage;
 }
 
+#ifdef DIRECT_TO_CG
+- (void)_initializeCaches
+{
+    int i, errorResult;
+    size_t numGlyphsInFont = CGFontGetNumberOfGlyphs([font _backingCGSFont]);
+    short unsigned int sequentialGlyphs[GLYPH_CACHE_MAX];
+            
+    if (numGlyphsInFont > GLYPH_CACHE_MAX)
+        widthCacheSize = GLYPH_CACHE_MAX;
+    else
+        widthCacheSize = (int)numGlyphsInFont;
+
+    for (i = 0; i < widthCacheSize; i++)
+        sequentialGlyphs[i] = i;
+        
+    fprintf (stdout, "number of glyphs in font %s %f = %ld\n", [[font displayName] cString], [font pointSize], CGFontGetNumberOfGlyphs([font _backingCGSFont])); 
+    widthCache = (float *)calloc (1, widthCacheSize * sizeof(float));
+    errorResult = CGFontGetGlyphScaledAdvances ([font _backingCGSFont], &sequentialGlyphs[0], widthCacheSize, 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 asciiCount = LAST_ASCII_CHAR - FIRST_ASCII_CHAR + 1;
+    short unsigned int asciiBuffer[LAST_ASCII_CHAR+1];
+    for (i = FIRST_ASCII_CHAR; i <= LAST_ASCII_CHAR; i++){
+        asciiBuffer[i] = i;
+    }
+    
+    __IFInitATSGlyphVector(&_asciiCacheGlyphVector, asciiCount);
+    (void)ATSUConvertCharToGlyphs(_asciiStyleGroup, &asciiBuffer[FIRST_ASCII_CHAR], 0, asciiCount, 0, (ATSGlyphVector *)&_asciiCacheGlyphVector);
+    if (_asciiCacheGlyphVector.numGlyphs != asciiCount)
+        [NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation:  ascii and glyphID count not equal - for %@ %f", self, [font displayName], [font pointSize]];
+}
+#endif
+
+#ifdef DIRECT_TO_CG
+static NSRect _rectForString (KWQLayoutInfo *self, const UniChar *internalBuffer, unsigned int stringLength)
+{
+    CGContextRef cgContext;
+    int totalWidth = 0;
+    unsigned int i, numGlyphs, index;
+    int glyphID;
+    ATSLayoutRecord *glyphRecords, *glyphRecordsPtr;
+    NSFont *font = [self font];
+    BOOL needGlyphAdvanceLookup = NO;
+    BOOL needCharToGlyphLookup = NO;
+
+
+    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]];
+        
+    cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+
+    if (self->widthCache == 0)
+        [self _initializeCaches];
+
+    // 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 ASCII range.
+    for (i = 0; i < stringLength; i++){
+        if (internalBuffer[i] < FIRST_ASCII_CHAR || internalBuffer[i] > LAST_ASCII_CHAR){
+            //fprintf (stdout, "char to glyph cache miss because of character 0x%04x\n", internalBuffer[i]);
+            needCharToGlyphLookup = YES;
+            break;
+        }
+    }
+
+    // If we can't use the cached map, the calculate a map for this string.
+    if (needCharToGlyphLookup){
+        __IFInitATSGlyphVector(&self->_glyphVector, stringLength);
+        (void)ATSUConvertCharToGlyphs(self->_styleGroup, internalBuffer, 0, stringLength, 0, (ATSGlyphVector *)&self->_glyphVector);
+        glyphRecords = self->_glyphVector.firstRecord;
+        numGlyphs = self->_glyphVector.numGlyphs;
+    }
+    else {
+        glyphRecords = self->_asciiCacheGlyphVector.firstRecord;
+        numGlyphs = stringLength;
+    }
+    
+    // Now we have the glyphs, determine if we can use the cached glyph measurements.
+    for (i = 0; i < numGlyphs; i++){
+        if (needCharToGlyphLookup)
+            index = i;
+        else
+            index = internalBuffer[i]-FIRST_ASCII_CHAR;
+        glyphID = glyphRecords[index].glyphID;
+        if (glyphID > self->widthCacheSize){
+            needGlyphAdvanceLookup = YES;
+            break;
+        }
+    }
+
+    // If we can't use the cached glyph measurement ask CG for the measurements.
+    if (needGlyphAdvanceLookup){
+        char localGlyphBuf[LOCAL_GLYPH_BUFFER_SIZE];
+        char *usedGlyphBuf, *glyphBufPtr, *allocatedGlyphBuf = 0;
+
+        fprintf (stdout, "glyph measurement cache miss\n");
+        
+        // Now construct the glyph buffer.
+        if (numGlyphs > LOCAL_GLYPH_BUFFER_SIZE/2)
+            usedGlyphBuf = glyphBufPtr = allocatedGlyphBuf = (char *)malloc (numGlyphs * 2);
+        else
+            usedGlyphBuf = glyphBufPtr = &localGlyphBuf[0];
+                
+        if (needCharToGlyphLookup){
+            int glyphID;
+
+            glyphRecordsPtr = glyphRecords;
+            for (i = 0; i < numGlyphs; i++){
+                glyphID = glyphRecordsPtr->glyphID;
+                *glyphBufPtr++ = (char)((glyphID >> 8) & 0x00FF);
+                *glyphBufPtr++ = (char)(glyphID & 0x00FF);
+                glyphRecordsPtr++;
+            }
+        }
+        else {
+            int glyphID;
+            
+            for (i = 0; i < numGlyphs; i++){
+                index = internalBuffer[i]-FIRST_ASCII_CHAR;
+                glyphID = glyphRecords[index].glyphID;
+                *glyphBufPtr++ = (char)((glyphID >> 8) & 0x00FF);
+                *glyphBufPtr++ = (char)(glyphID & 0x00FF);
+            }
+        }
+        
+        float localAdvanceBuf[LOCAL_GLYPH_BUFFER_SIZE];
+        float *usedAdvanceBuf, *allocatedAdvanceBuf = 0;
+
+        if (numGlyphs > LOCAL_GLYPH_BUFFER_SIZE)
+            usedAdvanceBuf = allocatedAdvanceBuf = (float *)malloc (numGlyphs * sizeof(float));
+        else
+            usedAdvanceBuf = &localAdvanceBuf[0];
+        
+        if (numGlyphs < LOCAL_GLYPH_BUFFER_SIZE){
+            CGFontGetGlyphScaledAdvances ([font _backingCGSFont], (const short unsigned int *)usedGlyphBuf, numGlyphs, usedAdvanceBuf, [font pointSize]);
+            for (i = 0; i < numGlyphs; i++){
+                //totalWidth += ScaleEmToUnits (advance[i], info->unitsPerEm);
+                totalWidth += ROUND_TO_INT(usedAdvanceBuf[i]);
+            }
+        }
+        
+        if (allocatedAdvanceBuf)
+            free (allocatedAdvanceBuf);
+
+        if (allocatedGlyphBuf)
+            free (allocatedGlyphBuf);
+    } 
+    else {
+        float *widthCache = self->widthCache;
+        for (i = 0; i < numGlyphs; i++){
+            if (needCharToGlyphLookup)
+                index = i;
+            else
+                index = internalBuffer[i]-FIRST_ASCII_CHAR;
+            totalWidth += ROUND_TO_INT(widthCache[glyphRecords[index].glyphID]);
+        }
+    }
+    
+    if (needCharToGlyphLookup)
+        __IFResetATSGlyphVector(&self->_glyphVector);
+            
+    return NSMakeRect (0,0,(float)totalWidth, (float)self->lineHeight);
+}
+#endif
+
 
 - (NSRect)rectForString:(NSString *)string
  {
+#ifdef DIRECT_TO_CG
+    UniChar localBuffer[LOCAL_GLYPH_BUFFER_SIZE];
+    const UniChar *_internalBuffer = CFStringGetCharactersPtr ((CFStringRef)string);
+    const UniChar *internalBuffer;
+
+    if (!_internalBuffer){
+        CFStringGetCharacters((CFStringRef)string, CFRangeMake(0, CFStringGetLength((CFStringRef)string)), &localBuffer[0]);
+        internalBuffer = &localBuffer[0];
+    }
+    else
+        internalBuffer = _internalBuffer;
+
+    return _rectForString (self, internalBuffer, [string length]);
+#else
     id <KWQLayoutFragment> cachedFragment;
 
     cachedFragment = [textStorage getFragmentForString: string];
     
     return [cachedFragment boundingRect];
+#endif
 }
 
 
@@ -285,18 +644,24 @@ static NSMutableDictionary *metricsCache = nil;
     [attributes setObject: color forKey: NSForegroundColorAttributeName];
 }
 
-- (void)setFont: (NSFont *)aFont
+- (NSDictionary *)attributes
 {
-    [attributes setObject: aFont forKey: NSFontAttributeName];
+    return attributes;
 }
 
-- (NSDictionary *)attributes
+- (int)lineHeight
 {
-    return attributes;
+    return lineHeight;
+}
+
+- (NSFont *)font
+{
+    return font;
 }
 
 - (void)dealloc
 {
+    [font release];
     [attributes release];
     [super dealloc];
 }
@@ -419,6 +784,13 @@ int QFontMetrics::width(const QString &qstring, int len) const
     return stringWidth;
 }
 
+int QFontMetrics::_width(const UniChar *uchars, int len) const
+{
+    int stringWidth = ROUND_TO_INT(_rectForString(data->info, uchars, len).size.width);
+    return stringWidth;
+}
+
+
 int QFontMetrics::_width(CFStringRef string) const
 {
     return ROUND_TO_INT([data->info rectForString: (NSString *)string].size.width);
diff --git a/WebCore/kwq/KWQMetrics.h b/WebCore/kwq/KWQMetrics.h
index 29225ca..b7246e0 100644
--- a/WebCore/kwq/KWQMetrics.h
+++ b/WebCore/kwq/KWQMetrics.h
@@ -29,11 +29,57 @@
 
 @class KWQTextStorage;
 
+
+#ifdef DIRECT_TO_CG
+
+#define LOCAL_GLYPH_BUFFER_SIZE 1024
+#define GLYPH_CACHE_MAX 1024
+
+#define FIRST_ASCII_CHAR ((int)' ')
+#define LAST_ASCII_CHAR ((int)'}')
+
+#define Boolean MacBoolean
+#define Fixed MacFixed
+#define Rect MacRect
+
+#import <ApplicationServices/ApplicationServices.h>
+#import <ATSUnicodePriv.h>
+
+#undef Fixed
+#undef Rect
+#undef Boolean
+
+ at interface NSFont (IFPrivate)
+- (ATSUFontID)_atsFontID;
+- (CGFontRef) _backingCGSFont;
+ at end
+
+extern "C" {
+
+CG_EXTERN int CGFontGetGlyphScaledAdvances(CGFontRef font, const CGGlyph glyph[], size_t count, float advance[], float scale);
+CG_EXTERN size_t CGFontGetNumberOfGlyphs(CGFontRef font);
+
+}
+
+#endif
+
 @interface KWQLayoutInfo : NSObject
 {
     NSMutableDictionary *attributes;
     NSLayoutManager *layoutManager;
     KWQTextStorage *textStorage;
+    NSFont *font;
+    int lineHeight;
+#ifdef DIRECT_TO_CG
+    ATSStyleGroupPtr _styleGroup;
+    ATSUStyle _style;
+    ATSGlyphVector _glyphVector;
+    ATSStyleGroupPtr _asciiStyleGroup;
+    ATSUStyle _asciiStyle;
+    ATSGlyphVector _asciiCacheGlyphVector;
+    int widthCacheSize;
+    float *widthCache;
+#endif
 }
 
 + (void)drawString: (NSString *)string atPoint: (NSPoint)p withFont: (NSFont *)font color: (NSColor *)color;
@@ -45,8 +91,9 @@
 - (NSLayoutManager *)layoutManager;
 - (KWQTextStorage *)textStorage;
 - (void)setColor: (NSColor *)color;
-- (void)setFont: (NSFont *)aFont;
 - (NSDictionary *)attributes;
+- (int)lineHeight;
+- (NSFont *)font;
 @end
 
 @protocol KWQLayoutFragment
diff --git a/WebCore/kwq/Makefile.am b/WebCore/kwq/Makefile.am
index 6298ff1..e5e9cc5 100644
--- a/WebCore/kwq/Makefile.am
+++ b/WebCore/kwq/Makefile.am
@@ -150,6 +150,9 @@ INCLUDES = \
 	$(KWQ_INCLUDES) \
 	$(KDELIBS_INCLUDES) \
 	$(WEBCORE_INCLUDES) \
+	-I/System/Library/Frameworks/ApplicationServices.framework/Frameworks/ \
+	-F/System/Library/Frameworks/ApplicationServices.framework/Frameworks \
+	-I/System/Library/Frameworks/ApplicationServices.framework/Frameworks/QD.framework/PrivateHeaders \
 	-F$(SYMROOTS) \
 	$(NULL)
 
diff --git a/WebCore/kwq/qt/qfontmetrics.h b/WebCore/kwq/qt/qfontmetrics.h
index b462a8e..3e38d50 100644
--- a/WebCore/kwq/qt/qfontmetrics.h
+++ b/WebCore/kwq/qt/qfontmetrics.h
@@ -71,6 +71,7 @@ public:
     int width(const QString &, int len=-1) const;
 #if (defined(__APPLE__))
     int _width (CFStringRef string) const;
+    int _width (const UniChar *uchars, int len) const;
 #endif
 
     int descent() const;
diff --git a/WebCore/src/kdelibs/khtml/rendering/render_text.cpp b/WebCore/src/kdelibs/khtml/rendering/render_text.cpp
index 03b27f2..effdfe3 100644
--- a/WebCore/src/kdelibs/khtml/rendering/render_text.cpp
+++ b/WebCore/src/kdelibs/khtml/rendering/render_text.cpp
@@ -45,9 +45,6 @@
 
 #ifdef APPLE_CHANGES
 #define OPTIMIZE_STRING_USAGE
-#ifdef OPTIMIZE_STRING_USAGE
-static CFMutableStringRef reuseableString = 0;
-#endif
 #endif
 
 
@@ -695,7 +692,7 @@ void RenderText::calcMinMaxWidth()
         if (wordlen)
         {
 #if (defined(APPLE_CHANGES) && defined(OPTIMIZE_STRING_USAGE))
-            int w = _fm._width(QString::gstring_toCFString(&reuseableString, (UniChar *)(str->s+i), wordlen));
+            int w = _fm._width((const UniChar *)(str->s+i), wordlen);
 #else
             int w = _fm.width(QConstString(str->s+i, wordlen).string());
 #endif
@@ -718,7 +715,7 @@ void RenderText::calcMinMaxWidth()
                 if(currMinWidth > m_minWidth) m_minWidth = currMinWidth;
                 currMinWidth = 0;
 #if (defined(APPLE_CHANGES) && defined(OPTIMIZE_STRING_USAGE))
-                currMaxWidth += _fm._width(QString::gstring_toCFString(&reuseableString, (UniChar *)(str->s+i+wordlen), 1));
+                currMaxWidth += _fm._width((const UniChar *)(str->s+i+wordlen), 1);
 #else
                 currMaxWidth += _fm.width( *(str->s+i+wordlen) );
 #endif
@@ -900,7 +897,7 @@ unsigned int RenderText::width(unsigned int from, unsigned int len, QFontMetrics
         w = _fm->width( *(str->s+from) );
     else
 #if (defined(APPLE_CHANGES) && defined(OPTIMIZE_STRING_USAGE))
-        w = _fm->_width(QString::gstring_toCFString(&reuseableString, (UniChar *)(str->s+from), len));
+        w = _fm->_width((const UniChar *)(str->s+from), len);
 #else
         w = _fm->width(QConstString(str->s+from, len).string());
 #endif
diff --git a/WebCore/src/kwq/KWQFontMetrics.mm b/WebCore/src/kwq/KWQFontMetrics.mm
index 30b6d2d..4195628 100644
--- a/WebCore/src/kwq/KWQFontMetrics.mm
+++ b/WebCore/src/kwq/KWQFontMetrics.mm
@@ -28,13 +28,26 @@
 #include <qfontmetrics.h>
 
 #import <Cocoa/Cocoa.h>
+
+#define DIRECT_TO_CG
+
 #import <KWQMetrics.h>
 #import <KWQTextStorage.h>
 #import <KWQTextContainer.h>
 
 #define FLOOR_TO_INT(x) (int)(floor(x))
-#define ROUND_TO_INT(x) (int)(((x) > (floor(x) + .5)) ? ceil(x) : floor(x))
-//#define ROUND_TO_INT(f) ((int)(rint(f)))
+//#define ROUND_TO_INT(x) (int)(((x) > (floor(x) + .5)) ? ceil(x) : floor(x))
+#define ROUND_TO_INT(x) (int)(x+.5)
+#ifdef FOOOOFOOO
+static inline int ROUND_TO_INT (float x)
+{
+    int floored = (int)(x);
+    
+    if (((float)x) > ((float)(floored) + .5))
+        return (int)ceil(x);
+    return floored;
+}
+#endif
 
 @implementation KWQSmallLayoutFragment
 - (NSRange)glyphRange
@@ -142,41 +155,180 @@ static NSMutableDictionary *metricsCache = nil;
 */
 @implementation KWQLayoutInfo
 
-+ (void)drawString: (NSString *)string atPoint: (NSPoint)p withFont: (NSFont *)font color: (NSColor *)color
+#ifdef DIRECT_TO_CG
+
+static void __IFInitATSGlyphVector(ATSGlyphVector *glyphVector, UInt32 numGlyphs) {
+    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);
+    }
+}
+
+static void __IFResetATSGlyphVector(ATSGlyphVector *glyphVector) {
+    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;
+}
+
+ at class NSCGSFont;
+
+static void __IFFillStyleWithAttributes(ATSUStyle style, NSFont *theFont) {
+    if (theFont) {
+        ATSUFontID fontId = (ATSUFontID)[theFont _atsFontID];
+        ATSUAttributeTag tag = kATSUFontTag;
+        ByteCount size = sizeof(ATSUFontID);
+        ATSUFontID *valueArray[1] = {&fontId};
+
+        if (fontId) {
+            if (ATSUSetAttributes(style, 1, &tag, &size, (const ATSUAttributeValuePtr)valueArray) != noErr)
+                [NSException raise:NSInternalInconsistencyException format:@"Failed to set font (%@) ATSUStyle 0x%X", theFont, style];
+
+#if 1
+//#warning Aki 7/20/2000 This code should be disabled once the brain dead bug 2499383 is fixed
+            {
+                ATSUFontFeatureType types[8] = {kDiacriticsType, kTypographicExtrasType, kFractionsType, kSmartSwashType, kSmartSwashType, kSmartSwashType, kSmartSwashType, kSmartSwashType};
+                ATSUFontFeatureSelector selectors[8] = {kDecomposeDiacriticsSelector, kSmartQuotesOffSelector, kNoFractionsSelector, kWordInitialSwashesOffSelector, kWordFinalSwashesOffSelector, kLineInitialSwashesOffSelector, kLineFinalSwashesOffSelector, kNonFinalSwashesOffSelector};
+                ATSUSetFontFeatures(style, 8, types, selectors);
+            }
+#endif
+        }
+    }
+}
+#endif
+
+- (void)drawString: (NSString *)string atPoint: (NSPoint)p withFont: (NSFont *)aFont color: (NSColor *)color
 {
-    KWQLayoutInfo *layoutInfo = [KWQLayoutInfo getMetricsForFont: font];
-    NSLayoutManager *manager = [layoutInfo layoutManager];
-    KWQTextStorage *storage = [layoutInfo textStorage];
+#ifdef DIRECT_TO_CG
+    UniChar localBuffer[LOCAL_GLYPH_BUFFER_SIZE];
+    const UniChar *_internalBuffer = CFStringGetCharactersPtr ((CFStringRef)string);
+    const UniChar *internalBuffer;
 
-    if (manager != nil){
-        id <KWQLayoutFragment> frag = [storage getFragmentForString: (NSString *)string];
+    if (!_internalBuffer){
+        CFStringGetCharacters((CFStringRef)string, CFRangeMake(0, CFStringGetLength((CFStringRef)string)), &localBuffer[0]);
+        internalBuffer = &localBuffer[0];
+    }
+    else
+        internalBuffer = _internalBuffer;
+
+    CGContextRef cgContext;
 
-        [layoutInfo setColor: color];
-        [layoutInfo setFont: font];
-        [[layoutInfo textStorage] setAttributes: [layoutInfo attributes]];
-        [[layoutInfo textStorage] setString: string];
-        [manager drawGlyphsForGlyphRange:[frag glyphRange] atPoint:p];
+    __IFInitATSGlyphVector(&_glyphVector, [string length]);
+
+    (void)ATSUConvertCharToGlyphs(_styleGroup, internalBuffer, 0, [string length], 0, (ATSGlyphVector *)&_glyphVector);
+
+    [color set];
+    [aFont set];
+    
+    if ([aFont glyphPacking] != NSNativeShortGlyphPacking &&
+        [aFont glyphPacking] != NSTwoByteGlyphPacking)
+        [NSException raise:NSInternalInconsistencyException format:@"%@: Don't know how to deal with font %@", self, [aFont displayName]];
+        
+    {
+        int i, numGlyphs = _glyphVector.numGlyphs;
+        char localGlyphBuf[LOCAL_GLYPH_BUFFER_SIZE];
+        char *usedGlyphBuf, *glyphBufPtr, *glyphBuf = 0;
+        ATSLayoutRecord *glyphRecords = _glyphVector.firstRecord;
+        
+        if (numGlyphs > LOCAL_GLYPH_BUFFER_SIZE/2)
+            usedGlyphBuf = glyphBufPtr = glyphBuf = (char *)malloc (numGlyphs * 2);
+        else
+            usedGlyphBuf = glyphBufPtr = &localGlyphBuf[0];
+            
+        for (i = 0; i < numGlyphs; i++){
+            *glyphBufPtr++ = (char)((glyphRecords->glyphID >> 8) & 0x00FF);
+            *glyphBufPtr++ = (char)(glyphRecords->glyphID & 0x00FF);
+            glyphRecords++;
+        }
+        cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+        CGContextSetCharacterSpacing(cgContext, 0.0);
+        //CGContextShowGlyphsAtPoint (cgContext, p.x, p.y + [frag boundingRect].size.height + (int)[font descender] - 1, (const short unsigned int *)usedGlyphBuf, numGlyphs);
+        CGContextShowGlyphsAtPoint (cgContext, p.x, p.y + lineHeight - 1, (const short unsigned int *)usedGlyphBuf, numGlyphs);
+        
+        if (glyphBuf)
+            free (glyphBuf);
     }
+
+    __IFResetATSGlyphVector(&_glyphVector);
+#else
+    id <KWQLayoutFragment> frag = [storage getFragmentForString: (NSString *)string];
+    NSLog (@"WARNING:  Unable to use CG for drawString:atPoint:withFont:color:\n");
+
+    [self setColor: color];
+    [textStorage setAttributes: [layoutInfo attributes]];
+    [textStorage setString: string];
+    [layoutManager drawGlyphsForGlyphRange:[frag glyphRange] atPoint:p];
+#endif
 }
 
-+ (void)drawUnderlineForString: (NSString *)string atPoint: (NSPoint)p withFont: (NSFont *)font color: (NSColor *)color
+
++ (void)drawString: (NSString *)string atPoint: (NSPoint)p withFont: (NSFont *)aFont color: (NSColor *)color
 {
-    KWQLayoutInfo *layoutInfo = [KWQLayoutInfo getMetricsForFont: font];
-    NSLayoutManager *manager = [layoutInfo layoutManager];
-    KWQTextStorage *storage = [layoutInfo textStorage];
+    KWQLayoutInfo *layoutInfo = [KWQLayoutInfo getMetricsForFont: aFont];
+    [layoutInfo drawString: string atPoint: p withFont: aFont color: color];
+}
 
-    if (manager != nil){
-        id <KWQLayoutFragment>frag = [storage getFragmentForString: (NSString *)string];
 
-        [layoutInfo setColor: color];
-        [layoutInfo setFont: font];
-        [[layoutInfo textStorage] setAttributes: [layoutInfo attributes]];
-        [[layoutInfo textStorage] setString: string];
-        NSRect lineRect = [manager lineFragmentRectForGlyphAtIndex: 0 effectiveRange: 0];
-        [manager underlineGlyphRange:[frag glyphRange] underlineType:NSSingleUnderlineStyle lineFragmentRect:lineRect lineFragmentGlyphRange:[frag glyphRange] containerOrigin:p];
+- (void)drawUnderlineForString: (NSString *)string atPoint: (NSPoint)p withFont: (NSFont *)aFont color: (NSColor *)color
+{
+#ifdef DIRECT_TO_CG
+    NSRect rect = [self rectForString: string];
+    NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext];
+    CGContextRef cgContext;
+    float lineWidth;
+    
+    [color set];
+
+    BOOL flag = [graphicsContext shouldAntialias];
+
+    [graphicsContext setShouldAntialias: NO];
+
+    cgContext = (CGContextRef)[graphicsContext graphicsPort];
+    lineWidth = 0.0;
+    if ([graphicsContext isDrawingToScreen] && lineWidth == 0.0) {
+        CGSize size = CGSizeApplyAffineTransform(CGSizeMake(1.0, 1.0), CGAffineTransformInvert(CGContextGetCTM(cgContext)));
+        lineWidth = size.width;
     }
+    CGContextSetLineWidth(cgContext, lineWidth);
+    CGContextMoveToPoint(cgContext, p.x, p.y + lineHeight + 0.5);
+    CGContextAddLineToPoint(cgContext, p.x + rect.size.width, p.y + lineHeight + 0.5);
+    CGContextStrokePath(cgContext);
+
+    [graphicsContext setShouldAntialias: flag];
+    
+#else
+    id <KWQLayoutFragment>frag = [storage getFragmentForString: (NSString *)string];
+
+    [self setColor: color];
+    [textStorage setAttributes: [self attributes]];
+    [textStorage setString: string];
+    NSRect lineRect = [self lineFragmentRectForGlyphAtIndex: 0 effectiveRange: 0];
+    [self underlineGlyphRange:[frag glyphRange] underlineType:NSSingleUnderlineStyle lineFragmentRect:lineRect lineFragmentGlyphRange:[frag glyphRange] containerOrigin:p];
+#endif
+}
+
++ (void)drawUnderlineForString: (NSString *)string atPoint: (NSPoint)p withFont: (NSFont *)aFont color: (NSColor *)color
+{
+    KWQLayoutInfo *layoutInfo = [KWQLayoutInfo getMetricsForFont: aFont];
+    
+    [layoutInfo drawUnderlineForString: string atPoint: p withFont: aFont color: color];
 }
 
+
 #ifdef _DEBUG_LAYOUT_FRAGMENT
 + (void)_dumpLayoutCache: (NSDictionary *)fragCache
 {
@@ -245,9 +397,34 @@ static NSMutableDictionary *metricsCache = nil;
 
 - initWithFont: (NSFont *)aFont
 {
+    OSStatus errCode;
+
     [super init];
     attributes = [[NSMutableDictionary dictionaryWithObjectsAndKeys:aFont, NSFontAttributeName, nil] retain];
 
+    font = [aFont retain];
+    lineHeight = ROUND_TO_INT([font ascender]) - ROUND_TO_INT([font descender]) + 1;
+
+#ifdef DIRECT_TO_CG
+    if ((errCode = ATSUCreateStyle(&_style)) != noErr)
+        [NSException raise:NSInternalInconsistencyException format:@"%@: Failed to alloc ATSUStyle %d", self, errCode];
+
+    __IFFillStyleWithAttributes(_style, aFont);
+
+    if ((errCode = ATSUGetStyleGroup(_style, &_styleGroup)) != noErr) {
+        [NSException raise:NSInternalInconsistencyException format:@"%@: Failed to create attribute group from ATSUStyle 0x%X %d", self, _style, errCode];
+    }            
+
+    if ((errCode = ATSUCreateStyle(&_asciiStyle)) != noErr)
+        [NSException raise:NSInternalInconsistencyException format:@"%@: Failed to alloc ATSUStyle %d", self, errCode];
+
+    __IFFillStyleWithAttributes(_asciiStyle, aFont);
+
+    if ((errCode = ATSUGetStyleGroup(_asciiStyle, &_asciiStyleGroup)) != noErr) {
+        [NSException raise:NSInternalInconsistencyException format:@"%@: Failed to create attribute group from ATSUStyle 0x%X %d", self, _style, errCode];
+    }            
+#endif
+
     textStorage = [[KWQTextStorage alloc] initWithFontAttribute: attributes];
     layoutManager = [[NSLayoutManager alloc] init];
 
@@ -269,14 +446,196 @@ static NSMutableDictionary *metricsCache = nil;
     return textStorage;
 }
 
+#ifdef DIRECT_TO_CG
+- (void)_initializeCaches
+{
+    int i, errorResult;
+    size_t numGlyphsInFont = CGFontGetNumberOfGlyphs([font _backingCGSFont]);
+    short unsigned int sequentialGlyphs[GLYPH_CACHE_MAX];
+            
+    if (numGlyphsInFont > GLYPH_CACHE_MAX)
+        widthCacheSize = GLYPH_CACHE_MAX;
+    else
+        widthCacheSize = (int)numGlyphsInFont;
+
+    for (i = 0; i < widthCacheSize; i++)
+        sequentialGlyphs[i] = i;
+        
+    fprintf (stdout, "number of glyphs in font %s %f = %ld\n", [[font displayName] cString], [font pointSize], CGFontGetNumberOfGlyphs([font _backingCGSFont])); 
+    widthCache = (float *)calloc (1, widthCacheSize * sizeof(float));
+    errorResult = CGFontGetGlyphScaledAdvances ([font _backingCGSFont], &sequentialGlyphs[0], widthCacheSize, 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 asciiCount = LAST_ASCII_CHAR - FIRST_ASCII_CHAR + 1;
+    short unsigned int asciiBuffer[LAST_ASCII_CHAR+1];
+    for (i = FIRST_ASCII_CHAR; i <= LAST_ASCII_CHAR; i++){
+        asciiBuffer[i] = i;
+    }
+    
+    __IFInitATSGlyphVector(&_asciiCacheGlyphVector, asciiCount);
+    (void)ATSUConvertCharToGlyphs(_asciiStyleGroup, &asciiBuffer[FIRST_ASCII_CHAR], 0, asciiCount, 0, (ATSGlyphVector *)&_asciiCacheGlyphVector);
+    if (_asciiCacheGlyphVector.numGlyphs != asciiCount)
+        [NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation:  ascii and glyphID count not equal - for %@ %f", self, [font displayName], [font pointSize]];
+}
+#endif
+
+#ifdef DIRECT_TO_CG
+static NSRect _rectForString (KWQLayoutInfo *self, const UniChar *internalBuffer, unsigned int stringLength)
+{
+    CGContextRef cgContext;
+    int totalWidth = 0;
+    unsigned int i, numGlyphs, index;
+    int glyphID;
+    ATSLayoutRecord *glyphRecords, *glyphRecordsPtr;
+    NSFont *font = [self font];
+    BOOL needGlyphAdvanceLookup = NO;
+    BOOL needCharToGlyphLookup = NO;
+
+
+    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]];
+        
+    cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+
+    if (self->widthCache == 0)
+        [self _initializeCaches];
+
+    // 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 ASCII range.
+    for (i = 0; i < stringLength; i++){
+        if (internalBuffer[i] < FIRST_ASCII_CHAR || internalBuffer[i] > LAST_ASCII_CHAR){
+            //fprintf (stdout, "char to glyph cache miss because of character 0x%04x\n", internalBuffer[i]);
+            needCharToGlyphLookup = YES;
+            break;
+        }
+    }
+
+    // If we can't use the cached map, the calculate a map for this string.
+    if (needCharToGlyphLookup){
+        __IFInitATSGlyphVector(&self->_glyphVector, stringLength);
+        (void)ATSUConvertCharToGlyphs(self->_styleGroup, internalBuffer, 0, stringLength, 0, (ATSGlyphVector *)&self->_glyphVector);
+        glyphRecords = self->_glyphVector.firstRecord;
+        numGlyphs = self->_glyphVector.numGlyphs;
+    }
+    else {
+        glyphRecords = self->_asciiCacheGlyphVector.firstRecord;
+        numGlyphs = stringLength;
+    }
+    
+    // Now we have the glyphs, determine if we can use the cached glyph measurements.
+    for (i = 0; i < numGlyphs; i++){
+        if (needCharToGlyphLookup)
+            index = i;
+        else
+            index = internalBuffer[i]-FIRST_ASCII_CHAR;
+        glyphID = glyphRecords[index].glyphID;
+        if (glyphID > self->widthCacheSize){
+            needGlyphAdvanceLookup = YES;
+            break;
+        }
+    }
+
+    // If we can't use the cached glyph measurement ask CG for the measurements.
+    if (needGlyphAdvanceLookup){
+        char localGlyphBuf[LOCAL_GLYPH_BUFFER_SIZE];
+        char *usedGlyphBuf, *glyphBufPtr, *allocatedGlyphBuf = 0;
+
+        fprintf (stdout, "glyph measurement cache miss\n");
+        
+        // Now construct the glyph buffer.
+        if (numGlyphs > LOCAL_GLYPH_BUFFER_SIZE/2)
+            usedGlyphBuf = glyphBufPtr = allocatedGlyphBuf = (char *)malloc (numGlyphs * 2);
+        else
+            usedGlyphBuf = glyphBufPtr = &localGlyphBuf[0];
+                
+        if (needCharToGlyphLookup){
+            int glyphID;
+
+            glyphRecordsPtr = glyphRecords;
+            for (i = 0; i < numGlyphs; i++){
+                glyphID = glyphRecordsPtr->glyphID;
+                *glyphBufPtr++ = (char)((glyphID >> 8) & 0x00FF);
+                *glyphBufPtr++ = (char)(glyphID & 0x00FF);
+                glyphRecordsPtr++;
+            }
+        }
+        else {
+            int glyphID;
+            
+            for (i = 0; i < numGlyphs; i++){
+                index = internalBuffer[i]-FIRST_ASCII_CHAR;
+                glyphID = glyphRecords[index].glyphID;
+                *glyphBufPtr++ = (char)((glyphID >> 8) & 0x00FF);
+                *glyphBufPtr++ = (char)(glyphID & 0x00FF);
+            }
+        }
+        
+        float localAdvanceBuf[LOCAL_GLYPH_BUFFER_SIZE];
+        float *usedAdvanceBuf, *allocatedAdvanceBuf = 0;
+
+        if (numGlyphs > LOCAL_GLYPH_BUFFER_SIZE)
+            usedAdvanceBuf = allocatedAdvanceBuf = (float *)malloc (numGlyphs * sizeof(float));
+        else
+            usedAdvanceBuf = &localAdvanceBuf[0];
+        
+        if (numGlyphs < LOCAL_GLYPH_BUFFER_SIZE){
+            CGFontGetGlyphScaledAdvances ([font _backingCGSFont], (const short unsigned int *)usedGlyphBuf, numGlyphs, usedAdvanceBuf, [font pointSize]);
+            for (i = 0; i < numGlyphs; i++){
+                //totalWidth += ScaleEmToUnits (advance[i], info->unitsPerEm);
+                totalWidth += ROUND_TO_INT(usedAdvanceBuf[i]);
+            }
+        }
+        
+        if (allocatedAdvanceBuf)
+            free (allocatedAdvanceBuf);
+
+        if (allocatedGlyphBuf)
+            free (allocatedGlyphBuf);
+    } 
+    else {
+        float *widthCache = self->widthCache;
+        for (i = 0; i < numGlyphs; i++){
+            if (needCharToGlyphLookup)
+                index = i;
+            else
+                index = internalBuffer[i]-FIRST_ASCII_CHAR;
+            totalWidth += ROUND_TO_INT(widthCache[glyphRecords[index].glyphID]);
+        }
+    }
+    
+    if (needCharToGlyphLookup)
+        __IFResetATSGlyphVector(&self->_glyphVector);
+            
+    return NSMakeRect (0,0,(float)totalWidth, (float)self->lineHeight);
+}
+#endif
+
 
 - (NSRect)rectForString:(NSString *)string
  {
+#ifdef DIRECT_TO_CG
+    UniChar localBuffer[LOCAL_GLYPH_BUFFER_SIZE];
+    const UniChar *_internalBuffer = CFStringGetCharactersPtr ((CFStringRef)string);
+    const UniChar *internalBuffer;
+
+    if (!_internalBuffer){
+        CFStringGetCharacters((CFStringRef)string, CFRangeMake(0, CFStringGetLength((CFStringRef)string)), &localBuffer[0]);
+        internalBuffer = &localBuffer[0];
+    }
+    else
+        internalBuffer = _internalBuffer;
+
+    return _rectForString (self, internalBuffer, [string length]);
+#else
     id <KWQLayoutFragment> cachedFragment;
 
     cachedFragment = [textStorage getFragmentForString: string];
     
     return [cachedFragment boundingRect];
+#endif
 }
 
 
@@ -285,18 +644,24 @@ static NSMutableDictionary *metricsCache = nil;
     [attributes setObject: color forKey: NSForegroundColorAttributeName];
 }
 
-- (void)setFont: (NSFont *)aFont
+- (NSDictionary *)attributes
 {
-    [attributes setObject: aFont forKey: NSFontAttributeName];
+    return attributes;
 }
 
-- (NSDictionary *)attributes
+- (int)lineHeight
 {
-    return attributes;
+    return lineHeight;
+}
+
+- (NSFont *)font
+{
+    return font;
 }
 
 - (void)dealloc
 {
+    [font release];
     [attributes release];
     [super dealloc];
 }
@@ -419,6 +784,13 @@ int QFontMetrics::width(const QString &qstring, int len) const
     return stringWidth;
 }
 
+int QFontMetrics::_width(const UniChar *uchars, int len) const
+{
+    int stringWidth = ROUND_TO_INT(_rectForString(data->info, uchars, len).size.width);
+    return stringWidth;
+}
+
+
 int QFontMetrics::_width(CFStringRef string) const
 {
     return ROUND_TO_INT([data->info rectForString: (NSString *)string].size.width);
diff --git a/WebCore/src/kwq/KWQMetrics.h b/WebCore/src/kwq/KWQMetrics.h
index 29225ca..b7246e0 100644
--- a/WebCore/src/kwq/KWQMetrics.h
+++ b/WebCore/src/kwq/KWQMetrics.h
@@ -29,11 +29,57 @@
 
 @class KWQTextStorage;
 
+
+#ifdef DIRECT_TO_CG
+
+#define LOCAL_GLYPH_BUFFER_SIZE 1024
+#define GLYPH_CACHE_MAX 1024
+
+#define FIRST_ASCII_CHAR ((int)' ')
+#define LAST_ASCII_CHAR ((int)'}')
+
+#define Boolean MacBoolean
+#define Fixed MacFixed
+#define Rect MacRect
+
+#import <ApplicationServices/ApplicationServices.h>
+#import <ATSUnicodePriv.h>
+
+#undef Fixed
+#undef Rect
+#undef Boolean
+
+ at interface NSFont (IFPrivate)
+- (ATSUFontID)_atsFontID;
+- (CGFontRef) _backingCGSFont;
+ at end
+
+extern "C" {
+
+CG_EXTERN int CGFontGetGlyphScaledAdvances(CGFontRef font, const CGGlyph glyph[], size_t count, float advance[], float scale);
+CG_EXTERN size_t CGFontGetNumberOfGlyphs(CGFontRef font);
+
+}
+
+#endif
+
 @interface KWQLayoutInfo : NSObject
 {
     NSMutableDictionary *attributes;
     NSLayoutManager *layoutManager;
     KWQTextStorage *textStorage;
+    NSFont *font;
+    int lineHeight;
+#ifdef DIRECT_TO_CG
+    ATSStyleGroupPtr _styleGroup;
+    ATSUStyle _style;
+    ATSGlyphVector _glyphVector;
+    ATSStyleGroupPtr _asciiStyleGroup;
+    ATSUStyle _asciiStyle;
+    ATSGlyphVector _asciiCacheGlyphVector;
+    int widthCacheSize;
+    float *widthCache;
+#endif
 }
 
 + (void)drawString: (NSString *)string atPoint: (NSPoint)p withFont: (NSFont *)font color: (NSColor *)color;
@@ -45,8 +91,9 @@
 - (NSLayoutManager *)layoutManager;
 - (KWQTextStorage *)textStorage;
 - (void)setColor: (NSColor *)color;
-- (void)setFont: (NSFont *)aFont;
 - (NSDictionary *)attributes;
+- (int)lineHeight;
+- (NSFont *)font;
 @end
 
 @protocol KWQLayoutFragment
diff --git a/WebCore/src/kwq/Makefile.am b/WebCore/src/kwq/Makefile.am
index 6298ff1..e5e9cc5 100644
--- a/WebCore/src/kwq/Makefile.am
+++ b/WebCore/src/kwq/Makefile.am
@@ -150,6 +150,9 @@ INCLUDES = \
 	$(KWQ_INCLUDES) \
 	$(KDELIBS_INCLUDES) \
 	$(WEBCORE_INCLUDES) \
+	-I/System/Library/Frameworks/ApplicationServices.framework/Frameworks/ \
+	-F/System/Library/Frameworks/ApplicationServices.framework/Frameworks \
+	-I/System/Library/Frameworks/ApplicationServices.framework/Frameworks/QD.framework/PrivateHeaders \
 	-F$(SYMROOTS) \
 	$(NULL)
 
diff --git a/WebCore/src/kwq/qt/qfontmetrics.h b/WebCore/src/kwq/qt/qfontmetrics.h
index b462a8e..3e38d50 100644
--- a/WebCore/src/kwq/qt/qfontmetrics.h
+++ b/WebCore/src/kwq/qt/qfontmetrics.h
@@ -71,6 +71,7 @@ public:
     int width(const QString &, int len=-1) const;
 #if (defined(__APPLE__))
     int _width (CFStringRef string) const;
+    int _width (const UniChar *uchars, int len) const;
 #endif
 
     int descent() const;

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list