[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:53 UTC 2009
The following commit has been merged in the debian/unstable branch:
commit 02d533d25b0fd291745ff973d3ecf09aca9c50ec
Author: rjw <rjw at 268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date: Tue Mar 19 18:23:17 2002 +0000
Improved cache-miss case for non-latin1 characters.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@780 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/ChangeLog-2002-12-03 b/WebCore/ChangeLog-2002-12-03
index 121711a..108aa03 100644
--- a/WebCore/ChangeLog-2002-12-03
+++ b/WebCore/ChangeLog-2002-12-03
@@ -1,3 +1,14 @@
+2002-03-19 Richard Williamson <rjw at apple.com>
+
+ Improved cache-miss case for non-latin1 characters.
+
+ * src/kwq/KWQFontMetrics.mm: (-[KWQLayoutInfo initWithFont:]), (-[KWQLayoutInfo
+ layoutManager]), (-[KWQLayoutInfo textStorage]), (-[KWQLayoutInfo
+ _initializeCaches]), (_rectForString), (-[KWQLayoutInfo setColor:]),
+ (-[KWQLayoutInfo attributes]), (-[KWQLayoutInfo dealloc]):
+ * src/kwq/KWQMetrics.h:
+ * src/kwq/kwqdebug.h:
+
2002-03-18 Darin Adler <darin at apple.com>
* src/kwq/KWQListImpl.mm: (KWQListImpl::sort): Use insertion sort for
diff --git a/WebCore/ChangeLog-2003-10-25 b/WebCore/ChangeLog-2003-10-25
index 121711a..108aa03 100644
--- a/WebCore/ChangeLog-2003-10-25
+++ b/WebCore/ChangeLog-2003-10-25
@@ -1,3 +1,14 @@
+2002-03-19 Richard Williamson <rjw at apple.com>
+
+ Improved cache-miss case for non-latin1 characters.
+
+ * src/kwq/KWQFontMetrics.mm: (-[KWQLayoutInfo initWithFont:]), (-[KWQLayoutInfo
+ layoutManager]), (-[KWQLayoutInfo textStorage]), (-[KWQLayoutInfo
+ _initializeCaches]), (_rectForString), (-[KWQLayoutInfo setColor:]),
+ (-[KWQLayoutInfo attributes]), (-[KWQLayoutInfo dealloc]):
+ * src/kwq/KWQMetrics.h:
+ * src/kwq/kwqdebug.h:
+
2002-03-18 Darin Adler <darin at apple.com>
* src/kwq/KWQListImpl.mm: (KWQListImpl::sort): Use insertion sort for
diff --git a/WebCore/ChangeLog-2005-08-23 b/WebCore/ChangeLog-2005-08-23
index 121711a..108aa03 100644
--- a/WebCore/ChangeLog-2005-08-23
+++ b/WebCore/ChangeLog-2005-08-23
@@ -1,3 +1,14 @@
+2002-03-19 Richard Williamson <rjw at apple.com>
+
+ Improved cache-miss case for non-latin1 characters.
+
+ * src/kwq/KWQFontMetrics.mm: (-[KWQLayoutInfo initWithFont:]), (-[KWQLayoutInfo
+ layoutManager]), (-[KWQLayoutInfo textStorage]), (-[KWQLayoutInfo
+ _initializeCaches]), (_rectForString), (-[KWQLayoutInfo setColor:]),
+ (-[KWQLayoutInfo attributes]), (-[KWQLayoutInfo dealloc]):
+ * src/kwq/KWQMetrics.h:
+ * src/kwq/kwqdebug.h:
+
2002-03-18 Darin Adler <darin at apple.com>
* src/kwq/KWQListImpl.mm: (KWQListImpl::sort): Use insertion sort for
diff --git a/WebCore/kwq/KWQFontMetrics.mm b/WebCore/kwq/KWQFontMetrics.mm
index 18b848c..5ae38c8 100644
--- a/WebCore/kwq/KWQFontMetrics.mm
+++ b/WebCore/kwq/KWQFontMetrics.mm
@@ -400,7 +400,6 @@ static void __IFFillStyleWithAttributes(ATSUStyle style, NSFont *theFont) {
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;
@@ -423,64 +422,85 @@ static void __IFFillStyleWithAttributes(ATSUStyle style, NSFont *theFont) {
if ((errCode = ATSUGetStyleGroup(_latinStyle, &_latinStyleGroup)) != noErr) {
[NSException raise:NSInternalInconsistencyException format:@"%@: Failed to create attribute group from ATSUStyle 0x%X %d", self, _style, errCode];
}
-#endif
-
+#else
textStorage = [[KWQTextStorage alloc] initWithFontAttribute: attributes];
layoutManager = [[NSLayoutManager alloc] init];
[layoutManager addTextContainer: [KWQTextContainer sharedInstance]];
[textStorage addLayoutManager: layoutManager];
+ attributes = [[NSMutableDictionary dictionaryWithObjectsAndKeys:aFont, NSFontAttributeName, nil] retain];
+#endif
return self;
}
- (NSLayoutManager *)layoutManager
{
+#ifdef DIRECT_TO_CG
+ return nil;
+#else
return layoutManager;
+#endif
}
- (KWQTextStorage *)textStorage
{
+#ifdef DIRECT_TO_CG
+ return nil;
+#else
return textStorage;
+#endif
}
#ifdef DIRECT_TO_CG
- (void)_initializeCaches
{
- int i, errorResult;
+ unsigned int i, glyphsToCache;
+ int errorResult;
size_t numGlyphsInFont = CGFontGetNumberOfGlyphs([font _backingCGSFont]);
- short unsigned int sequentialGlyphs[GLYPH_CACHE_MAX];
+ short unsigned int sequentialGlyphs[INITIAL_GLYPH_CACHE_MAX];
ATSLayoutRecord *glyphRecords;
- if (numGlyphsInFont > GLYPH_CACHE_MAX)
- widthCacheSize = GLYPH_CACHE_MAX;
- else
- widthCacheSize = (int)numGlyphsInFont;
+ KWQDEBUGLEVEL3 (KWQ_LOG_FONTCACHE, "Caching %s %.0f (%ld glyphs)\n", [[font displayName] cString], [font pointSize], numGlyphsInFont);
- for (i = 0; i < widthCacheSize; i++)
+ // Initially just cache the max of number of glyphs in font or
+ // INITIAL_GLYPH_CACHE_MAX. Holes in the cache will be filled on demand
+ // in INCREMENTAL_GLYPH_CACHE_BLOCK chunks.
+ if (numGlyphsInFont > INITIAL_GLYPH_CACHE_MAX)
+ glyphsToCache = INITIAL_GLYPH_CACHE_MAX;
+ else
+ glyphsToCache = numGlyphsInFont;
+ widthCacheSize = (int)numGlyphsInFont;
+ for (i = 0; i < glyphsToCache; i++)
sequentialGlyphs[i] = i;
- widthCache = (float *)calloc (1, widthCacheSize * sizeof(float));
- errorResult = CGFontGetGlyphScaledAdvances ([font _backingCGSFont], &sequentialGlyphs[0], widthCacheSize, widthCache, [font pointSize]);
+ widthCache = (_IFGlyphWidth *)calloc (1, widthCacheSize * sizeof(_IFGlyphWidth));
+
+ // Some glyphs can have zero width, so we have to use a non-zero value
+ // in empty slots to indicate they are uninitialized.
+ for (i = glyphsToCache; i < widthCacheSize; i++){
+ widthCache[i] = UNITIALIZED_GLYPH_WIDTH;
+ }
+
+ errorResult = CGFontGetGlyphScaledAdvances ([font _backingCGSFont], &sequentialGlyphs[0], glyphsToCache, widthCache, [font pointSize]);
if (errorResult == 0)
[NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation: unable to cache glyph advances - for %@ %f", self, [font displayName], [font pointSize]];
-
- unsigned int latinCount = LAST_CACHE_CHAR - FIRST_CACHE_CHAR + 1;
- short unsigned int latinBuffer[LAST_CACHE_CHAR+1];
+ unsigned int latinCount = LAST_CACHE_CHARACTER - FIRST_CACHE_CHARACTER + 1;
+ short unsigned int latinBuffer[LAST_CACHE_CHARACTER+1];
- for (i = FIRST_CACHE_CHAR; i <= LAST_CACHE_CHAR; i++){
+ for (i = FIRST_CACHE_CHARACTER; i <= LAST_CACHE_CHARACTER; i++){
latinBuffer[i] = i;
}
__IFInitATSGlyphVector(&_latinCacheGlyphVector, latinCount);
- (void)ATSUConvertCharToGlyphs(_latinStyleGroup, &latinBuffer[FIRST_CACHE_CHAR], 0, latinCount, 0, (ATSGlyphVector *)&_latinCacheGlyphVector);
+ (void)ATSUConvertCharToGlyphs(_latinStyleGroup, &latinBuffer[FIRST_CACHE_CHARACTER], 0, latinCount, 0, (ATSGlyphVector *)&_latinCacheGlyphVector);
if (_latinCacheGlyphVector.numGlyphs != latinCount)
[NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation: ascii and glyphID count not equal - for %@ %f", self, [font displayName], [font pointSize]];
- int numGlyphs = _latinCacheGlyphVector.numGlyphs;
+ unsigned int numGlyphs = _latinCacheGlyphVector.numGlyphs;
characterToGlyph = (ATSGlyphRef *)calloc (1, _latinCacheGlyphVector.numGlyphs * sizeof(ATSGlyphRef));
glyphRecords = _latinCacheGlyphVector.firstRecord;
for (i = 0; i < numGlyphs; i++){
@@ -492,26 +512,25 @@ static void __IFFillStyleWithAttributes(ATSUStyle style, NSFont *theFont) {
#ifdef DEBUG_CACHE_SIZE
static int totalCacheSize = 0;
- totalCacheSize += widthCacheSize * sizeof(float) + numGlyphs * sizeof(ATSGlyphRef) + sizeof(KWQLayoutInfo);
- KWQDEBUGLEVEL7 (KWQ_LOG_MEMUSAGE, "Cache initialized for font %s %f (%ld font glyphs), memory usage in bytes: widths = %ld, latin1 ext. character-to-glyph = %ld, total this cache = %ld, total all caches %d\n", [[font displayName] cString], [font pointSize], numGlyphsInFont, widthCacheSize * sizeof(float), numGlyphs * sizeof(ATSGlyphRef), widthCacheSize * sizeof(float) + numGlyphs * sizeof(ATSGlyphRef) + sizeof(KWQLayoutInfo), totalCacheSize);
+ totalCacheSize += widthCacheSize * sizeof(_IFGlyphWidth) + numGlyphs * sizeof(ATSGlyphRef) + sizeof(KWQLayoutInfo);
+ KWQDEBUGLEVEL4 (KWQ_LOG_MEMUSAGE, "memory usage in bytes: widths = %ld, latin1 ext. character-to-glyph = %ld, total this cache = %ld, total all caches %d\n", widthCacheSize * sizeof(_IFGlyphWidth), numGlyphs * sizeof(ATSGlyphRef), widthCacheSize * sizeof(_IFGlyphWidth) + numGlyphs * sizeof(ATSGlyphRef) + sizeof(KWQLayoutInfo), totalCacheSize);
#endif
}
-#endif
-#ifdef DIRECT_TO_CG
+
static NSRect _rectForString (KWQLayoutInfo *self, const UniChar *internalBuffer, unsigned int stringLength)
{
- CGContextRef cgContext;
int totalWidth = 0;
unsigned int i, index;
int glyphID;
- ATSLayoutRecord *glyphRecords, *glyphRecordsPtr;
+ ATSLayoutRecord *glyphRecords;
NSFont *font = [self font];
+ unsigned int numGlyphs;
+ _IFGlyphWidth *widthCache;
ATSGlyphRef localCharacterToGlyph[LOCAL_GLYPH_BUFFER_SIZE];
- ATSGlyphRef *usedCharacterToGlyph, *allocateCharacterToGlyph;
+ ATSGlyphRef *usedCharacterToGlyph, *allocateCharacterToGlyph = 0;
- BOOL needGlyphAdvanceLookup = NO;
BOOL needCharToGlyphLookup = NO;
@@ -533,23 +552,25 @@ static NSRect _rectForString (KWQLayoutInfo *self, const UniChar *internalBuffer
if (self->widthCache == 0)
[self _initializeCaches];
-
+ widthCache = self->widthCache;
+
+ // Pass 1:
// Check if we can use the cached character-to-glyph map. We only use the character-to-glyph map
// if ALL the characters in the string fall in the safe cache range. This must be done
// to ensure that we don't match composable characters incorrectly. This check could
// be smarter. Also the character-to-glyph could be extended to support other ranges
// of unicode. For now, we only optimize for latin1.
for (i = 0; i < stringLength; i++){
- if (internalBuffer[i] < FIRST_CACHE_CHAR || internalBuffer[i] > LAST_CACHE_CHAR){
- //fprintf (stdout, "char to glyph cache miss because of character 0x%04x\n", internalBuffer[i]);
+ if (internalBuffer[i] < FIRST_CACHE_CHARACTER || internalBuffer[i] > LAST_CACHE_CHARACTER){
needCharToGlyphLookup = YES;
break;
}
}
- // If we can't use the cached map, the calculate a map for this string. Expensive.
+ // If we can't use the cached map, then calculate a map for this string. Expensive.
if (needCharToGlyphLookup){
- unsigned int numGlyphs;
+
+ KWQDEBUGLEVEL3 (KWQ_LOG_FONTCACHECHARMISS, "character-to-glyph cache miss for character 0x%04x in %s, %.0f\n", internalBuffer[i], [[font displayName] cString], [font pointSize])
__IFInitATSGlyphVector(&self->_glyphVector, stringLength);
(void)ATSUConvertCharToGlyphs(self->_styleGroup, internalBuffer, 0, stringLength, 0, (ATSGlyphVector *)&self->_glyphVector);
@@ -561,87 +582,52 @@ static NSRect _rectForString (KWQLayoutInfo *self, const UniChar *internalBuffer
else
usedCharacterToGlyph = &localCharacterToGlyph[0];
- for (i = 0; i < numGlyphs; i++)
- usedCharacterToGlyph[i] = glyphRecords[i].glyphID;
-
- __IFResetATSGlyphVector(&self->_glyphVector);
-
- // Now we have the glyphs, determine if we can use the cached glyph measurements.
for (i = 0; i < numGlyphs; i++){
glyphID = glyphRecords[i].glyphID;
- if (glyphID >= self->widthCacheSize){
- needGlyphAdvanceLookup = YES;
- break;
- }
- }
-
- // If we can't use the cached glyph measurement ask CG for the measurements. Expensive.
- if (needGlyphAdvanceLookup){
- char localGlyphBuf[LOCAL_GLYPH_BUFFER_SIZE];
- char *usedGlyphBuf, *glyphBufPtr, *allocatedGlyphBuf = 0;
-
- fprintf (stdout, "glyph measurement cache miss\n");
+ usedCharacterToGlyph[i] = glyphID;
- // 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;
+ // Fill the block of glyphs for the glyph needed.
+ if (self->widthCache[glyphID] == UNITIALIZED_GLYPH_WIDTH){
+ short unsigned int sequentialGlyphs[INCREMENTAL_GLYPH_CACHE_BLOCK];
+ unsigned int blockStart, blockEnd, blockID;
+ int errorResult;
- for (i = 0; i < numGlyphs; i++){
- index = internalBuffer[i]-FIRST_CACHE_CHAR;
- glyphID = glyphRecords[index].glyphID;
- *glyphBufPtr++ = (char)((glyphID >> 8) & 0x00FF);
- *glyphBufPtr++ = (char)(glyphID & 0x00FF);
- }
+ blockStart = (glyphID / INCREMENTAL_GLYPH_CACHE_BLOCK) * INCREMENTAL_GLYPH_CACHE_BLOCK;
+ blockEnd = blockStart + INCREMENTAL_GLYPH_CACHE_BLOCK;
+ if (blockEnd > self->widthCacheSize)
+ blockEnd = self->widthCacheSize;
+ KWQDEBUGLEVEL5 (KWQ_LOG_FONTCACHE, "width cache miss for glyph 0x%04x in %s, %.0f, filling block 0x%04x to 0x%04x\n", glyphID, [[font displayName] cString], [font pointSize], blockStart, blockEnd);
+ for (blockID = blockStart; blockID < blockEnd; blockID++)
+ sequentialGlyphs[blockID-blockStart] = blockID;
+ errorResult = CGFontGetGlyphScaledAdvances ([font _backingCGSFont], &sequentialGlyphs[0], blockEnd-blockStart, &widthCache[blockStart], [font pointSize]);
+ if (errorResult == 0)
+ [NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation: unable to cache glyph widths - for %@ %f", self, [font displayName], [font pointSize]];
}
-
- 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];
-
- cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
- 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);
- }
+ }
+
+ __IFResetATSGlyphVector(&self->_glyphVector);
}
- else
+ else {
+ numGlyphs = stringLength;
usedCharacterToGlyph = self->characterToGlyph;
+ }
- if (!needGlyphAdvanceLookup){
- float *widthCache = self->widthCache;
- for (i = 0; i < stringLength; i++){
- if (needCharToGlyphLookup)
- index = i;
- else
- index = internalBuffer[i]-FIRST_CACHE_CHAR;
+ // Pass 2:
+ // Sum the widths for all the glyphs.
+
+ // Optimization: This loop could sum pre-rounded unsigned shorts. Storing
+ // the glyph widths as shorts would cut space in half.
+ if (needCharToGlyphLookup){
+ for (i = 0; i < numGlyphs; i++){
+ totalWidth += ROUND_TO_INT(widthCache[usedCharacterToGlyph[i]]);
+ }
+
+ if (allocateCharacterToGlyph)
+ free (allocateCharacterToGlyph);
+ }
+ else {
+ for (i = 0; i < numGlyphs; i++){
+ index = internalBuffer[i]-FIRST_CACHE_CHARACTER;
totalWidth += ROUND_TO_INT(widthCache[usedCharacterToGlyph[index]]);
}
}
@@ -678,12 +664,18 @@ static NSRect _rectForString (KWQLayoutInfo *self, const UniChar *internalBuffer
- (void)setColor: (NSColor *)color
{
+#ifndef DIRECT_TO_CG
[attributes setObject: color forKey: NSForegroundColorAttributeName];
+#endif
}
- (NSDictionary *)attributes
{
+#ifdef DIRECT_TO_CG
+ return nil;
+#else
return attributes;
+#endif
}
- (int)lineHeight
@@ -699,7 +691,9 @@ static NSRect _rectForString (KWQLayoutInfo *self, const UniChar *internalBuffer
- (void)dealloc
{
[font release];
+#ifndef DIRECT_TO_CG
[attributes release];
+#endif
[super dealloc];
}
diff --git a/WebCore/kwq/KWQMetrics.h b/WebCore/kwq/KWQMetrics.h
index 088a079..288af19 100644
--- a/WebCore/kwq/KWQMetrics.h
+++ b/WebCore/kwq/KWQMetrics.h
@@ -33,17 +33,21 @@
#ifdef DIRECT_TO_CG
#define LOCAL_GLYPH_BUFFER_SIZE 1024
-#define GLYPH_CACHE_MAX 1024
+
+#define INITIAL_GLYPH_CACHE_MAX 512
+#define INCREMENTAL_GLYPH_CACHE_BLOCK 512
+
+#define UNITIALIZED_GLYPH_WIDTH FLT_MAX
// These definitions are used to bound the character-to-glyph mapping cache. The
-// range is limited to LATIN1. Also a check must be made to determine that a
-// character range does not include a composable charcter.
+// range is limited to LATIN1. When accessing the cache a check must be made to
+// determine that a character range does not include a composable charcter.
// The first displayable character in latin1. (SPACE)
-#define FIRST_CACHE_CHAR (0x20)
+#define FIRST_CACHE_CHARACTER (0x20)
// The last character in latin1 extended A. (LATIN SMALL LETTER LONG S)
-#define LAST_CACHE_CHAR (0x17F)
+#define LAST_CACHE_CHARACTER (0x17F)
#define Boolean MacBoolean
#define Fixed MacFixed
@@ -68,13 +72,12 @@ CG_EXTERN size_t CGFontGetNumberOfGlyphs(CGFontRef font);
}
+typedef float _IFGlyphWidth;
+
#endif
@interface KWQLayoutInfo : NSObject
{
- NSMutableDictionary *attributes;
- NSLayoutManager *layoutManager;
- KWQTextStorage *textStorage;
NSFont *font;
int lineHeight;
#ifdef DIRECT_TO_CG
@@ -84,9 +87,13 @@ CG_EXTERN size_t CGFontGetNumberOfGlyphs(CGFontRef font);
ATSStyleGroupPtr _latinStyleGroup;
ATSUStyle _latinStyle;
ATSGlyphVector _latinCacheGlyphVector;
- int widthCacheSize;
- float *widthCache;
+ unsigned int widthCacheSize;
+ _IFGlyphWidth *widthCache;
ATSGlyphRef *characterToGlyph;
+#else
+ NSMutableDictionary *attributes;
+ NSLayoutManager *layoutManager;
+ KWQTextStorage *textStorage;
#endif
}
diff --git a/WebCore/kwq/kwqdebug.h b/WebCore/kwq/kwqdebug.h
index 59bf968..17c22df 100644
--- a/WebCore/kwq/kwqdebug.h
+++ b/WebCore/kwq/kwqdebug.h
@@ -51,6 +51,8 @@ long _GetMillisecondsSinceEpoch();
#define KWQ_LOG_TIMING 0x00000020
#define KWQ_LOG_LOADING 0x00000040
#define KWQ_LOG_MEMUSAGE 0x00000080
+#define KWQ_LOG_FONTCACHE 0x00000100
+#define KWQ_LOG_FONTCACHECHARMISS 0x00000200
#define KWQ_LOG_NONE 0
diff --git a/WebCore/src/kwq/KWQFontMetrics.mm b/WebCore/src/kwq/KWQFontMetrics.mm
index 18b848c..5ae38c8 100644
--- a/WebCore/src/kwq/KWQFontMetrics.mm
+++ b/WebCore/src/kwq/KWQFontMetrics.mm
@@ -400,7 +400,6 @@ static void __IFFillStyleWithAttributes(ATSUStyle style, NSFont *theFont) {
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;
@@ -423,64 +422,85 @@ static void __IFFillStyleWithAttributes(ATSUStyle style, NSFont *theFont) {
if ((errCode = ATSUGetStyleGroup(_latinStyle, &_latinStyleGroup)) != noErr) {
[NSException raise:NSInternalInconsistencyException format:@"%@: Failed to create attribute group from ATSUStyle 0x%X %d", self, _style, errCode];
}
-#endif
-
+#else
textStorage = [[KWQTextStorage alloc] initWithFontAttribute: attributes];
layoutManager = [[NSLayoutManager alloc] init];
[layoutManager addTextContainer: [KWQTextContainer sharedInstance]];
[textStorage addLayoutManager: layoutManager];
+ attributes = [[NSMutableDictionary dictionaryWithObjectsAndKeys:aFont, NSFontAttributeName, nil] retain];
+#endif
return self;
}
- (NSLayoutManager *)layoutManager
{
+#ifdef DIRECT_TO_CG
+ return nil;
+#else
return layoutManager;
+#endif
}
- (KWQTextStorage *)textStorage
{
+#ifdef DIRECT_TO_CG
+ return nil;
+#else
return textStorage;
+#endif
}
#ifdef DIRECT_TO_CG
- (void)_initializeCaches
{
- int i, errorResult;
+ unsigned int i, glyphsToCache;
+ int errorResult;
size_t numGlyphsInFont = CGFontGetNumberOfGlyphs([font _backingCGSFont]);
- short unsigned int sequentialGlyphs[GLYPH_CACHE_MAX];
+ short unsigned int sequentialGlyphs[INITIAL_GLYPH_CACHE_MAX];
ATSLayoutRecord *glyphRecords;
- if (numGlyphsInFont > GLYPH_CACHE_MAX)
- widthCacheSize = GLYPH_CACHE_MAX;
- else
- widthCacheSize = (int)numGlyphsInFont;
+ KWQDEBUGLEVEL3 (KWQ_LOG_FONTCACHE, "Caching %s %.0f (%ld glyphs)\n", [[font displayName] cString], [font pointSize], numGlyphsInFont);
- for (i = 0; i < widthCacheSize; i++)
+ // Initially just cache the max of number of glyphs in font or
+ // INITIAL_GLYPH_CACHE_MAX. Holes in the cache will be filled on demand
+ // in INCREMENTAL_GLYPH_CACHE_BLOCK chunks.
+ if (numGlyphsInFont > INITIAL_GLYPH_CACHE_MAX)
+ glyphsToCache = INITIAL_GLYPH_CACHE_MAX;
+ else
+ glyphsToCache = numGlyphsInFont;
+ widthCacheSize = (int)numGlyphsInFont;
+ for (i = 0; i < glyphsToCache; i++)
sequentialGlyphs[i] = i;
- widthCache = (float *)calloc (1, widthCacheSize * sizeof(float));
- errorResult = CGFontGetGlyphScaledAdvances ([font _backingCGSFont], &sequentialGlyphs[0], widthCacheSize, widthCache, [font pointSize]);
+ widthCache = (_IFGlyphWidth *)calloc (1, widthCacheSize * sizeof(_IFGlyphWidth));
+
+ // Some glyphs can have zero width, so we have to use a non-zero value
+ // in empty slots to indicate they are uninitialized.
+ for (i = glyphsToCache; i < widthCacheSize; i++){
+ widthCache[i] = UNITIALIZED_GLYPH_WIDTH;
+ }
+
+ errorResult = CGFontGetGlyphScaledAdvances ([font _backingCGSFont], &sequentialGlyphs[0], glyphsToCache, widthCache, [font pointSize]);
if (errorResult == 0)
[NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation: unable to cache glyph advances - for %@ %f", self, [font displayName], [font pointSize]];
-
- unsigned int latinCount = LAST_CACHE_CHAR - FIRST_CACHE_CHAR + 1;
- short unsigned int latinBuffer[LAST_CACHE_CHAR+1];
+ unsigned int latinCount = LAST_CACHE_CHARACTER - FIRST_CACHE_CHARACTER + 1;
+ short unsigned int latinBuffer[LAST_CACHE_CHARACTER+1];
- for (i = FIRST_CACHE_CHAR; i <= LAST_CACHE_CHAR; i++){
+ for (i = FIRST_CACHE_CHARACTER; i <= LAST_CACHE_CHARACTER; i++){
latinBuffer[i] = i;
}
__IFInitATSGlyphVector(&_latinCacheGlyphVector, latinCount);
- (void)ATSUConvertCharToGlyphs(_latinStyleGroup, &latinBuffer[FIRST_CACHE_CHAR], 0, latinCount, 0, (ATSGlyphVector *)&_latinCacheGlyphVector);
+ (void)ATSUConvertCharToGlyphs(_latinStyleGroup, &latinBuffer[FIRST_CACHE_CHARACTER], 0, latinCount, 0, (ATSGlyphVector *)&_latinCacheGlyphVector);
if (_latinCacheGlyphVector.numGlyphs != latinCount)
[NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation: ascii and glyphID count not equal - for %@ %f", self, [font displayName], [font pointSize]];
- int numGlyphs = _latinCacheGlyphVector.numGlyphs;
+ unsigned int numGlyphs = _latinCacheGlyphVector.numGlyphs;
characterToGlyph = (ATSGlyphRef *)calloc (1, _latinCacheGlyphVector.numGlyphs * sizeof(ATSGlyphRef));
glyphRecords = _latinCacheGlyphVector.firstRecord;
for (i = 0; i < numGlyphs; i++){
@@ -492,26 +512,25 @@ static void __IFFillStyleWithAttributes(ATSUStyle style, NSFont *theFont) {
#ifdef DEBUG_CACHE_SIZE
static int totalCacheSize = 0;
- totalCacheSize += widthCacheSize * sizeof(float) + numGlyphs * sizeof(ATSGlyphRef) + sizeof(KWQLayoutInfo);
- KWQDEBUGLEVEL7 (KWQ_LOG_MEMUSAGE, "Cache initialized for font %s %f (%ld font glyphs), memory usage in bytes: widths = %ld, latin1 ext. character-to-glyph = %ld, total this cache = %ld, total all caches %d\n", [[font displayName] cString], [font pointSize], numGlyphsInFont, widthCacheSize * sizeof(float), numGlyphs * sizeof(ATSGlyphRef), widthCacheSize * sizeof(float) + numGlyphs * sizeof(ATSGlyphRef) + sizeof(KWQLayoutInfo), totalCacheSize);
+ totalCacheSize += widthCacheSize * sizeof(_IFGlyphWidth) + numGlyphs * sizeof(ATSGlyphRef) + sizeof(KWQLayoutInfo);
+ KWQDEBUGLEVEL4 (KWQ_LOG_MEMUSAGE, "memory usage in bytes: widths = %ld, latin1 ext. character-to-glyph = %ld, total this cache = %ld, total all caches %d\n", widthCacheSize * sizeof(_IFGlyphWidth), numGlyphs * sizeof(ATSGlyphRef), widthCacheSize * sizeof(_IFGlyphWidth) + numGlyphs * sizeof(ATSGlyphRef) + sizeof(KWQLayoutInfo), totalCacheSize);
#endif
}
-#endif
-#ifdef DIRECT_TO_CG
+
static NSRect _rectForString (KWQLayoutInfo *self, const UniChar *internalBuffer, unsigned int stringLength)
{
- CGContextRef cgContext;
int totalWidth = 0;
unsigned int i, index;
int glyphID;
- ATSLayoutRecord *glyphRecords, *glyphRecordsPtr;
+ ATSLayoutRecord *glyphRecords;
NSFont *font = [self font];
+ unsigned int numGlyphs;
+ _IFGlyphWidth *widthCache;
ATSGlyphRef localCharacterToGlyph[LOCAL_GLYPH_BUFFER_SIZE];
- ATSGlyphRef *usedCharacterToGlyph, *allocateCharacterToGlyph;
+ ATSGlyphRef *usedCharacterToGlyph, *allocateCharacterToGlyph = 0;
- BOOL needGlyphAdvanceLookup = NO;
BOOL needCharToGlyphLookup = NO;
@@ -533,23 +552,25 @@ static NSRect _rectForString (KWQLayoutInfo *self, const UniChar *internalBuffer
if (self->widthCache == 0)
[self _initializeCaches];
-
+ widthCache = self->widthCache;
+
+ // Pass 1:
// Check if we can use the cached character-to-glyph map. We only use the character-to-glyph map
// if ALL the characters in the string fall in the safe cache range. This must be done
// to ensure that we don't match composable characters incorrectly. This check could
// be smarter. Also the character-to-glyph could be extended to support other ranges
// of unicode. For now, we only optimize for latin1.
for (i = 0; i < stringLength; i++){
- if (internalBuffer[i] < FIRST_CACHE_CHAR || internalBuffer[i] > LAST_CACHE_CHAR){
- //fprintf (stdout, "char to glyph cache miss because of character 0x%04x\n", internalBuffer[i]);
+ if (internalBuffer[i] < FIRST_CACHE_CHARACTER || internalBuffer[i] > LAST_CACHE_CHARACTER){
needCharToGlyphLookup = YES;
break;
}
}
- // If we can't use the cached map, the calculate a map for this string. Expensive.
+ // If we can't use the cached map, then calculate a map for this string. Expensive.
if (needCharToGlyphLookup){
- unsigned int numGlyphs;
+
+ KWQDEBUGLEVEL3 (KWQ_LOG_FONTCACHECHARMISS, "character-to-glyph cache miss for character 0x%04x in %s, %.0f\n", internalBuffer[i], [[font displayName] cString], [font pointSize])
__IFInitATSGlyphVector(&self->_glyphVector, stringLength);
(void)ATSUConvertCharToGlyphs(self->_styleGroup, internalBuffer, 0, stringLength, 0, (ATSGlyphVector *)&self->_glyphVector);
@@ -561,87 +582,52 @@ static NSRect _rectForString (KWQLayoutInfo *self, const UniChar *internalBuffer
else
usedCharacterToGlyph = &localCharacterToGlyph[0];
- for (i = 0; i < numGlyphs; i++)
- usedCharacterToGlyph[i] = glyphRecords[i].glyphID;
-
- __IFResetATSGlyphVector(&self->_glyphVector);
-
- // Now we have the glyphs, determine if we can use the cached glyph measurements.
for (i = 0; i < numGlyphs; i++){
glyphID = glyphRecords[i].glyphID;
- if (glyphID >= self->widthCacheSize){
- needGlyphAdvanceLookup = YES;
- break;
- }
- }
-
- // If we can't use the cached glyph measurement ask CG for the measurements. Expensive.
- if (needGlyphAdvanceLookup){
- char localGlyphBuf[LOCAL_GLYPH_BUFFER_SIZE];
- char *usedGlyphBuf, *glyphBufPtr, *allocatedGlyphBuf = 0;
-
- fprintf (stdout, "glyph measurement cache miss\n");
+ usedCharacterToGlyph[i] = glyphID;
- // 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;
+ // Fill the block of glyphs for the glyph needed.
+ if (self->widthCache[glyphID] == UNITIALIZED_GLYPH_WIDTH){
+ short unsigned int sequentialGlyphs[INCREMENTAL_GLYPH_CACHE_BLOCK];
+ unsigned int blockStart, blockEnd, blockID;
+ int errorResult;
- for (i = 0; i < numGlyphs; i++){
- index = internalBuffer[i]-FIRST_CACHE_CHAR;
- glyphID = glyphRecords[index].glyphID;
- *glyphBufPtr++ = (char)((glyphID >> 8) & 0x00FF);
- *glyphBufPtr++ = (char)(glyphID & 0x00FF);
- }
+ blockStart = (glyphID / INCREMENTAL_GLYPH_CACHE_BLOCK) * INCREMENTAL_GLYPH_CACHE_BLOCK;
+ blockEnd = blockStart + INCREMENTAL_GLYPH_CACHE_BLOCK;
+ if (blockEnd > self->widthCacheSize)
+ blockEnd = self->widthCacheSize;
+ KWQDEBUGLEVEL5 (KWQ_LOG_FONTCACHE, "width cache miss for glyph 0x%04x in %s, %.0f, filling block 0x%04x to 0x%04x\n", glyphID, [[font displayName] cString], [font pointSize], blockStart, blockEnd);
+ for (blockID = blockStart; blockID < blockEnd; blockID++)
+ sequentialGlyphs[blockID-blockStart] = blockID;
+ errorResult = CGFontGetGlyphScaledAdvances ([font _backingCGSFont], &sequentialGlyphs[0], blockEnd-blockStart, &widthCache[blockStart], [font pointSize]);
+ if (errorResult == 0)
+ [NSException raise:NSInternalInconsistencyException format:@"Optimization assumption violation: unable to cache glyph widths - for %@ %f", self, [font displayName], [font pointSize]];
}
-
- 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];
-
- cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
- 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);
- }
+ }
+
+ __IFResetATSGlyphVector(&self->_glyphVector);
}
- else
+ else {
+ numGlyphs = stringLength;
usedCharacterToGlyph = self->characterToGlyph;
+ }
- if (!needGlyphAdvanceLookup){
- float *widthCache = self->widthCache;
- for (i = 0; i < stringLength; i++){
- if (needCharToGlyphLookup)
- index = i;
- else
- index = internalBuffer[i]-FIRST_CACHE_CHAR;
+ // Pass 2:
+ // Sum the widths for all the glyphs.
+
+ // Optimization: This loop could sum pre-rounded unsigned shorts. Storing
+ // the glyph widths as shorts would cut space in half.
+ if (needCharToGlyphLookup){
+ for (i = 0; i < numGlyphs; i++){
+ totalWidth += ROUND_TO_INT(widthCache[usedCharacterToGlyph[i]]);
+ }
+
+ if (allocateCharacterToGlyph)
+ free (allocateCharacterToGlyph);
+ }
+ else {
+ for (i = 0; i < numGlyphs; i++){
+ index = internalBuffer[i]-FIRST_CACHE_CHARACTER;
totalWidth += ROUND_TO_INT(widthCache[usedCharacterToGlyph[index]]);
}
}
@@ -678,12 +664,18 @@ static NSRect _rectForString (KWQLayoutInfo *self, const UniChar *internalBuffer
- (void)setColor: (NSColor *)color
{
+#ifndef DIRECT_TO_CG
[attributes setObject: color forKey: NSForegroundColorAttributeName];
+#endif
}
- (NSDictionary *)attributes
{
+#ifdef DIRECT_TO_CG
+ return nil;
+#else
return attributes;
+#endif
}
- (int)lineHeight
@@ -699,7 +691,9 @@ static NSRect _rectForString (KWQLayoutInfo *self, const UniChar *internalBuffer
- (void)dealloc
{
[font release];
+#ifndef DIRECT_TO_CG
[attributes release];
+#endif
[super dealloc];
}
diff --git a/WebCore/src/kwq/KWQMetrics.h b/WebCore/src/kwq/KWQMetrics.h
index 088a079..288af19 100644
--- a/WebCore/src/kwq/KWQMetrics.h
+++ b/WebCore/src/kwq/KWQMetrics.h
@@ -33,17 +33,21 @@
#ifdef DIRECT_TO_CG
#define LOCAL_GLYPH_BUFFER_SIZE 1024
-#define GLYPH_CACHE_MAX 1024
+
+#define INITIAL_GLYPH_CACHE_MAX 512
+#define INCREMENTAL_GLYPH_CACHE_BLOCK 512
+
+#define UNITIALIZED_GLYPH_WIDTH FLT_MAX
// These definitions are used to bound the character-to-glyph mapping cache. The
-// range is limited to LATIN1. Also a check must be made to determine that a
-// character range does not include a composable charcter.
+// range is limited to LATIN1. When accessing the cache a check must be made to
+// determine that a character range does not include a composable charcter.
// The first displayable character in latin1. (SPACE)
-#define FIRST_CACHE_CHAR (0x20)
+#define FIRST_CACHE_CHARACTER (0x20)
// The last character in latin1 extended A. (LATIN SMALL LETTER LONG S)
-#define LAST_CACHE_CHAR (0x17F)
+#define LAST_CACHE_CHARACTER (0x17F)
#define Boolean MacBoolean
#define Fixed MacFixed
@@ -68,13 +72,12 @@ CG_EXTERN size_t CGFontGetNumberOfGlyphs(CGFontRef font);
}
+typedef float _IFGlyphWidth;
+
#endif
@interface KWQLayoutInfo : NSObject
{
- NSMutableDictionary *attributes;
- NSLayoutManager *layoutManager;
- KWQTextStorage *textStorage;
NSFont *font;
int lineHeight;
#ifdef DIRECT_TO_CG
@@ -84,9 +87,13 @@ CG_EXTERN size_t CGFontGetNumberOfGlyphs(CGFontRef font);
ATSStyleGroupPtr _latinStyleGroup;
ATSUStyle _latinStyle;
ATSGlyphVector _latinCacheGlyphVector;
- int widthCacheSize;
- float *widthCache;
+ unsigned int widthCacheSize;
+ _IFGlyphWidth *widthCache;
ATSGlyphRef *characterToGlyph;
+#else
+ NSMutableDictionary *attributes;
+ NSLayoutManager *layoutManager;
+ KWQTextStorage *textStorage;
#endif
}
diff --git a/WebCore/src/kwq/kwqdebug.h b/WebCore/src/kwq/kwqdebug.h
index 59bf968..17c22df 100644
--- a/WebCore/src/kwq/kwqdebug.h
+++ b/WebCore/src/kwq/kwqdebug.h
@@ -51,6 +51,8 @@ long _GetMillisecondsSinceEpoch();
#define KWQ_LOG_TIMING 0x00000020
#define KWQ_LOG_LOADING 0x00000040
#define KWQ_LOG_MEMUSAGE 0x00000080
+#define KWQ_LOG_FONTCACHE 0x00000100
+#define KWQ_LOG_FONTCACHECHARMISS 0x00000200
#define KWQ_LOG_NONE 0
--
WebKit Debian packaging
More information about the Pkg-webkit-commits
mailing list