[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