[webkit-changes] cvs commit: WebKit/WebCoreSupport.subproj WebTextRenderer.m

David harrison at opensource.apple.com
Fri Aug 5 11:02:07 PDT 2005


harrison    05/08/05 11:02:07

  Modified:    .        Tag: Safari-2-0-branch ChangeLog
               WebCoreSupport.subproj Tag: Safari-2-0-branch
                        WebTextRenderer.m
  Log:
          Merged fix from TOT
  
          <rdar://problem/3792529> REGRESSION (Mail): Tabs do not work the way they did in Panther (especially useful in plain text mail)
  
          Basic strategy is to put tabs into spans with white-space:pre style, and
          render them with tabs stops every 8th space, where the space width and
          the left margin are those of the enclosing block.
  
          * WebCoreSupport.subproj/WebTextRenderer.m:
          (isSpace):
          (isRoundingHackCharacter):
          (getUncachedWidth):
          (-[WebTextRenderer drawLineForCharacters:yOffset:width:color:thickness:]):
          (-[WebTextRenderer _computeWidthForSpace]):
          (_drawGlyphs):
          (-[WebTextRenderer _CG_drawHighlightForRun:style:geometry:]):
          (-[WebTextRenderer _CG_floatWidthForRun:style:widths:fonts:glyphs:startPosition:numGlyphs:]):
          (-[WebTextRenderer _extendCharacterToGlyphMapToInclude:]):
          (-[WebTextRenderer _CG_pointToOffset:style:position:reversed:includePartialGlyphs:]):
          (glyphForCharacter):
          (initializeCharacterWidthIterator):
          (ceilCurrentWidth):
          (widthForNextCharacter):
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.3118.4.32 +26 -0     WebKit/ChangeLog
  
  Index: ChangeLog
  ===================================================================
  RCS file: /cvs/root/WebKit/ChangeLog,v
  retrieving revision 1.3118.4.31
  retrieving revision 1.3118.4.32
  diff -u -r1.3118.4.31 -r1.3118.4.32
  --- ChangeLog	3 Aug 2005 21:49:37 -0000	1.3118.4.31
  +++ ChangeLog	5 Aug 2005 18:01:57 -0000	1.3118.4.32
  @@ -1,3 +1,29 @@
  +2005-08-05  David Harrison  <harrison at apple.com>
  +
  +        Merged fix from TOT
  +
  +        <rdar://problem/3792529> REGRESSION (Mail): Tabs do not work the way they did in Panther (especially useful in plain text mail)
  +        
  +        Basic strategy is to put tabs into spans with white-space:pre style, and
  +        render them with tabs stops every 8th space, where the space width and
  +        the left margin are those of the enclosing block.
  +
  +        * WebCoreSupport.subproj/WebTextRenderer.m:
  +        (isSpace):
  +        (isRoundingHackCharacter):
  +        (getUncachedWidth):
  +        (-[WebTextRenderer drawLineForCharacters:yOffset:width:color:thickness:]):
  +        (-[WebTextRenderer _computeWidthForSpace]):
  +        (_drawGlyphs):
  +        (-[WebTextRenderer _CG_drawHighlightForRun:style:geometry:]):
  +        (-[WebTextRenderer _CG_floatWidthForRun:style:widths:fonts:glyphs:startPosition:numGlyphs:]):
  +        (-[WebTextRenderer _extendCharacterToGlyphMapToInclude:]):
  +        (-[WebTextRenderer _CG_pointToOffset:style:position:reversed:includePartialGlyphs:]):
  +        (glyphForCharacter):
  +        (initializeCharacterWidthIterator):
  +        (ceilCurrentWidth):
  +        (widthForNextCharacter):
  +
   2005-08-03  Adele Peterson  <adele at apple.com>
   
           Merged fix from TOT.  Also fixes:
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.165.8.3 +90 -87    WebKit/WebCoreSupport.subproj/WebTextRenderer.m
  
  Index: WebTextRenderer.m
  ===================================================================
  RCS file: /cvs/root/WebKit/WebCoreSupport.subproj/WebTextRenderer.m,v
  retrieving revision 1.165.8.2
  retrieving revision 1.165.8.3
  diff -u -r1.165.8.2 -r1.165.8.3
  --- WebTextRenderer.m	22 Jul 2005 03:10:03 -0000	1.165.8.2
  +++ WebTextRenderer.m	5 Aug 2005 18:02:06 -0000	1.165.8.3
  @@ -49,10 +49,6 @@
   #define NO_BREAK_SPACE 0x00A0
   #define ZERO_WIDTH_SPACE 0x200B
   
  -// Lose precision beyond 1000ths place. This is to work around an apparent
  -// bug in CoreGraphics where there seem to be small errors to some metrics.
  -#define CEIL_TO_INT(x) ((int)(x + 0.999)) /* ((int)(x + 1.0 - FLT_EPSILON)) */
  -
   // MAX_GLYPH_EXPANSION is the maximum numbers of glyphs that may be
   // use to represent a single Unicode code point.
   #define MAX_GLYPH_EXPANSION 4
  @@ -69,7 +65,7 @@
   
   #define ATSFontRefFromNSFont(font) (FMGetATSFontRefFromFont((FMFont)[font _atsFontID]))
   
  -#define SMALLCAPS_FONTSIZE_MULTIPLIER 0.7
  +#define SMALLCAPS_FONTSIZE_MULTIPLIER 0.7F
   #define INVALID_WIDTH -(__FLT_MAX__)
   
   #if !defined(ScaleEmToUnits)
  @@ -126,8 +122,8 @@
       unsigned currentCharacter;
       float runWidthSoFar;
       float widthToStart;
  -    int padding;
  -    int padPerSpace;
  +    float padding;
  +    float padPerSpace;
   };
   
   // Internal API
  @@ -173,11 +169,11 @@
   
   static inline BOOL isSpace(UniChar c)
   {
  -    return c == SPACE || c == '\n' || c == NO_BREAK_SPACE;
  +    return c == SPACE || c == '\t' || c == '\n' || c == NO_BREAK_SPACE;
   }
   
   static const uint8_t isRoundingHackCharacterTable[0x100] = {
  -    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*\n*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  +    0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*\t*/, 1 /*\n*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       1 /*space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*-*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*?*/,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  @@ -189,7 +185,7 @@
   
   static inline BOOL isRoundingHackCharacter(UniChar c)
   {
  -    return (c & ~0xFF) == 0 && isRoundingHackCharacterTable[c];
  +    return (((c & ~0xFF) == 0 && isRoundingHackCharacterTable[c]));
   }
   
   // Map utility functions
  @@ -214,7 +210,7 @@
   
       if (!CGFontGetGlyphScaledAdvances ([font _backingCGSFont], &glyph, 1, &width, [font pointSize])) {
           ERROR ("Unable to cache glyph widths for %@ %f",  [font displayName], [font pointSize]);
  -	return 0.;
  +	return 0.0F;
       }
   
       return width;
  @@ -579,36 +575,27 @@
       cgContext = (CGContextRef)[graphicsContext graphicsPort];
   
       // hack to make thickness 2 underlines for internation text input look right
  -    if (thickness > 1.5 && thickness < 2.5) {
  -        yOffset += .5;
  +    if (thickness > 1.5F && thickness < 2.5F) {
  +        yOffset += .5F;
       }
   
  -    if (thickness == 0.0) {
  -        CGSize size = CGSizeApplyAffineTransform(CGSizeMake(1.0, 1.0), CGAffineTransformInvert(CGContextGetCTM(cgContext)));
  +    if (thickness == 0.0F) {
  +        CGSize size = CGSizeApplyAffineTransform(CGSizeMake(1.0F, 1.0F), CGAffineTransformInvert(CGContextGetCTM(cgContext)));
           CGContextSetLineWidth(cgContext, size.width);
       } else {
           CGContextSetLineWidth(cgContext, thickness);
       }
   
   
  -    // With Q2DX turned on CGContextStrokeLineSegments sometimes fails to draw lines.  See 3952084.
  -    // So, it has been requested that we turn off use of the new API until 3952084 is fixed.
  -#if 1         
  -//#if BUILDING_ON_PANTHER         
  -    CGContextMoveToPoint(cgContext, point.x, point.y + [self lineSpacing] + 1.5 - [self descent] + yOffset);
  -    // Subtract 1 to ensure that the line is always within bounds of element.
  -    CGContextAddLineToPoint(cgContext, point.x + width - 1.0, point.y + [self lineSpacing] + 1.5 - [self descent] + yOffset);
  -    CGContextStrokePath(cgContext);
  -#else
       // Use CGContextStrokeLineSegments on Tiger.  J. Burkey says this will be a big performance win.
  -
  +    // With Q2DX turned on CGContextStrokeLineSegments sometimes fails to draw lines.  See 3952084.
  +    // Tiger shipped with Q2DX disabled, tho, so we can use CGContextStrokeLineSegments.
       CGPoint linePoints[2];
       linePoints[0].x = point.x;
  -    linePoints[0].y = point.y + [self lineSpacing] + 1.5 - [self descent] + yOffset;
  -    linePoints[1].x = point.x + width - 1.0;
  +    linePoints[0].y = point.y + [self lineSpacing] + 1.5F - [self descent] + yOffset;
  +    linePoints[1].x = point.x + width - 1.0F;
       linePoints[1].y = linePoints[0].y;
       CGContextStrokeLineSegments (cgContext, linePoints, 2);
  -#endif
   
       [graphicsContext setShouldAntialias: flag];
   }
  @@ -874,7 +861,7 @@
       spaceWidth = width;
   
       treatAsFixedPitch = [[WebTextRendererFactory sharedFactory] isFontFixedPitch:font];
  -    adjustedSpaceWidth = treatAsFixedPitch ? CEIL_TO_INT(width) : (int)ROUND_TO_INT(width);
  +    adjustedSpaceWidth = treatAsFixedPitch ? ceilf(width) : (int)ROUND_TO_INT(width);
       
       return YES;
   }
  @@ -995,7 +982,7 @@
           float flip = [v isFlipped] ? -1 : 1;
           CGContextSetTextMatrix(cgContext, CGAffineTransformMake(matrix[0], matrix[1] * flip, matrix[2], matrix[3] * flip, matrix[4], matrix[5]));
           CGContextSetFontRenderingMode (cgContext, _AppkitGetCGRenderingMode(drawFont));
  -        CGContextSetFontSize(cgContext, 1.0);
  +        CGContextSetFontSize(cgContext, 1.0F);
   #endif
   
           [color set];
  @@ -1028,7 +1015,7 @@
       }
       float startX = startPosition + geometry->point.x;
       
  -    float backgroundWidth = 0.0;
  +    float backgroundWidth = 0.0F;
       while (widthIterator.currentCharacter < (unsigned)run->to) {
           backgroundWidth += widthForNextCharacter(&widthIterator, 0, 0);
       }
  @@ -1210,7 +1197,7 @@
   
   - (float)_CG_floatWidthForRun:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style widths: (float *)widthBuffer fonts: (NSFont **)fontBuffer glyphs: (CGGlyph *)glyphBuffer startPosition:(float *)startPosition numGlyphs: (int *)_numGlyphs
   {
  -    float _totalWidth = 0, _nextWidth;
  +    float _nextWidth;
       CharacterWidthIterator widthIterator;
       NSFont *fontUsed = 0;
       ATSGlyphRef glyphUsed;
  @@ -1219,7 +1206,10 @@
       initializeCharacterWidthIterator(&widthIterator, self, run, style);
       if (startPosition)
           *startPosition = widthIterator.widthToStart;
  -    while ((_nextWidth = widthForNextCharacter(&widthIterator, &glyphUsed, &fontUsed)) != INVALID_WIDTH){
  +    while (widthIterator.currentCharacter < (unsigned)widthIterator.run->to) {
  +        _nextWidth = widthForNextCharacter(&widthIterator, &glyphUsed, &fontUsed);
  +        if (_nextWidth == INVALID_WIDTH)
  +            break;
           if (fontBuffer)
               fontBuffer[numGlyphs] = fontUsed;
           if (glyphBuffer)
  @@ -1227,13 +1217,12 @@
           if (widthBuffer)
               widthBuffer[numGlyphs] = _nextWidth;
           numGlyphs++;
  -        _totalWidth += _nextWidth;
       }
           
       if (_numGlyphs)
           *_numGlyphs = numGlyphs;
   
  -    return _totalWidth;
  +    return widthIterator.runWidthSoFar;
   }
   
   - (ATSGlyphRef)_extendUnicodeCharacterToGlyphMapToInclude:(UnicodeChar)c
  @@ -1355,8 +1344,9 @@
               buffer[i] = ZERO_WIDTH_SPACE;
           buffer[0x7F] = ZERO_WIDTH_SPACE;
   
  -        // But both \n and nonbreaking space must render as a space.
  +        // But \n, \t, and nonbreaking space must render as a space.
           buffer['\n'] = ' ';
  +        buffer['\t'] = ' ';
           buffer[NO_BREAK_SPACE] = ' ';
       }
   
  @@ -1776,7 +1766,7 @@
   - (int)_CG_pointToOffset:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style position:(int)x reversed:(BOOL)reversed includePartialGlyphs:(BOOL)includePartialGlyphs
   {
       float delta = (float)x;
  -    float width;
  +    float width;   ///  FIX: CHECK THIS
       unsigned offset = run->from;
       CharacterWidthIterator widthIterator;
       
  @@ -1870,13 +1860,17 @@
   {
       if (map == 0)
           return nonGlyphID;
  -        
  +    
  +    // this loop is hot, so it is written to avoid LSU stalls
       while (map) {
  -        if (c >= map->startRange && c <= map->endRange){
  -            *font = map->glyphs[c-map->startRange].font;
  -            return map->glyphs[c-map->startRange].glyph;
  +        UniChar start = map->startRange;
  +        GlyphMap *nextMap = map->next;
  +        if (c >= start && c <= map->endRange){
  +            GlyphEntry *ge = &map->glyphs[c-start];
  +            *font = ge->font;
  +            return ge->glyph;
           }
  -        map = map->next;
  +        map = nextMap;
       }
       return nonGlyphID;
   }
  @@ -1945,7 +1939,7 @@
                   numSpaces++;
               }
           }
  -        iterator->padPerSpace = CEIL_TO_INT ((((float)style->padding) / ((float)numSpaces)));
  +        iterator->padPerSpace = ceilf((((float)style->padding) / ((float)numSpaces)));
       }
       else {
           iterator->padPerSpace = 0;
  @@ -1972,7 +1966,8 @@
   
   static inline float ceilCurrentWidth (CharacterWidthIterator *iterator)
   {
  -    float delta = CEIL_TO_INT(iterator->widthToStart + iterator->runWidthSoFar) - (iterator->widthToStart + iterator->runWidthSoFar);
  +    float totalWidth = iterator->widthToStart + iterator->runWidthSoFar;
  +    float delta = ceilf(totalWidth) - totalWidth;
       iterator->runWidthSoFar += delta;
       return delta;
   }
  @@ -1989,15 +1984,10 @@
       unsigned currentCharacter = iterator->currentCharacter;
   
       NSFont *_fontUsed = nil;
  -    ATSGlyphRef _glyphUsed;
  -
  -    if (!fontUsed)
  -        fontUsed = &_fontUsed;
  -    if (!glyphUsed)
  -        glyphUsed = &_glyphUsed;
  -        
  +    ATSGlyphRef _glyphUsed = nil;
  +    
  +    // Check for end of run.
       if (currentCharacter >= (unsigned)run->to)
  -        // Error! Offset specified beyond end of run.
           return INVALID_WIDTH;
   
       const UniChar *cp = &run->characters[currentCharacter];
  @@ -2064,14 +2054,14 @@
       }
       
       if (c <= 0xFFFF) {
  -        *glyphUsed = glyphForCharacter(renderer->characterToGlyphMap, c, fontUsed);
  -        if (*glyphUsed == nonGlyphID) {
  -            *glyphUsed = [renderer _extendCharacterToGlyphMapToInclude:c];
  +        _glyphUsed = glyphForCharacter(renderer->characterToGlyphMap, c, &_fontUsed);
  +        if (_glyphUsed == nonGlyphID) {
  +            _glyphUsed = [renderer _extendCharacterToGlyphMapToInclude:c];
           }
       } else {
  -        *glyphUsed = glyphForUnicodeCharacter(renderer->unicodeCharacterToGlyphMap, c, fontUsed);
  -        if (*glyphUsed == nonGlyphID) {
  -            *glyphUsed = [renderer _extendUnicodeCharacterToGlyphMapToInclude:c];
  +        _glyphUsed = glyphForUnicodeCharacter(renderer->unicodeCharacterToGlyphMap, c, &_fontUsed);
  +        if (_glyphUsed == nonGlyphID) {
  +            _glyphUsed = [renderer _extendUnicodeCharacterToGlyphMapToInclude:c];
           }
       }
   
  @@ -2079,28 +2069,32 @@
       // ASSUMPTION:  We assume the same font in a smaller size has
       // the same glyphs as the large font.
       if (useSmallCapsFont) {
  -        if (*fontUsed == nil)
  -            *fontUsed = [renderer _smallCapsFont];
  +        if (_fontUsed == nil)
  +            _fontUsed = [renderer _smallCapsFont];
           else {
               // Potential for optimization.  This path should only be taken if we're
               // using a cached substituted font.
  -            *fontUsed = [[NSFontManager sharedFontManager] convertFont:*fontUsed toSize:[*fontUsed pointSize] * SMALLCAPS_FONTSIZE_MULTIPLIER];
  +            _fontUsed = [[NSFontManager sharedFontManager] convertFont:_fontUsed toSize:[_fontUsed pointSize] * SMALLCAPS_FONTSIZE_MULTIPLIER];
           }
       }
   
       // Now that we have glyph and font, get its width.
  -    WebGlyphWidth width = widthForGlyph(renderer, *glyphUsed, *fontUsed);
  +    WebGlyphWidth width;
  +    if (style->tabWidth != 0.0F && c == '\t') {
  +        width = style->tabWidth - fmodf(style->xpos+iterator->widthToStart+iterator->runWidthSoFar, style->tabWidth);
  +    } else {
  +        width = widthForGlyph(renderer, _glyphUsed, _fontUsed);
  +        // We special case spaces in two ways when applying word rounding.
  +        // First, we round spaces to an adjusted width in all fonts.
  +        // Second, in fixed-pitch fonts we ensure that all characters that
  +        // match the width of the space character have the same width as the space character.
  +        if (style->applyWordRounding && (renderer->treatAsFixedPitch ? width == renderer->spaceWidth : _glyphUsed == renderer->spaceGlyph))
  +            width = renderer->adjustedSpaceWidth;
  +    }
       
  -    // We special case spaces in two ways when applying word rounding.
  -    // First, we round spaces to an adjusted width in all fonts.
  -    // Second, in fixed-pitch fonts we ensure that all characters that
  -    // match the width of the space character have the same width as the space character.
  -    if ((renderer->treatAsFixedPitch ? width == renderer->spaceWidth : *glyphUsed == renderer->spaceGlyph) && iterator->style->applyWordRounding)
  -        width = renderer->adjustedSpaceWidth;
  -
       // Try to find a substitute font if this font didn't have a glyph for a character in the
       // string.  If one isn't found we end up drawing and measuring the 0 glyph, usually a box.
  -    if (*glyphUsed == 0 && iterator->style->attemptFontSubstitution) {
  +    if (_glyphUsed == 0 && style->attemptFontSubstitution) {
           UniChar characterArray[2];
           unsigned characterArrayLength;
           
  @@ -2114,7 +2108,7 @@
           }
           
           NSFont *substituteFont = [renderer _substituteFontForCharacters:characterArray length:characterArrayLength
  -            families:iterator->style->families];
  +            families:style->families];
           if (substituteFont) {
               int cNumGlyphs = 0;
               ATSGlyphRef localGlyphBuffer[MAX_GLYPH_EXPANSION];
  @@ -2137,8 +2131,8 @@
                               startPosition:nil
                               numGlyphs:&cNumGlyphs];
               
  -            *fontUsed = substituteFont;
  -            *glyphUsed = localGlyphBuffer[0];
  +            _fontUsed = substituteFont;
  +            _glyphUsed = localGlyphBuffer[0];
               
               if (c <= 0xFFFF && cNumGlyphs == 1 && localGlyphBuffer[0] != 0){
                   [renderer _updateGlyphEntryForCharacter:c glyphID:localGlyphBuffer[0] font:substituteFont];
  @@ -2146,18 +2140,18 @@
           }
       }
   
  -    if (!*fontUsed)
  -        *fontUsed = renderer->font;
  +    if (!_fontUsed)
  +        _fontUsed = renderer->font;
   
       // Force characters that are used to determine word boundaries for the rounding hack
       // to be integer width, so following words will start on an integer boundary.
  -    if (isRoundingHackCharacter(c) && iterator->style->applyWordRounding) {
  -        width = CEIL_TO_INT(width);
  +    if (style->applyWordRounding && isRoundingHackCharacter(c)) {
  +        width = ceilf(width);
       }
       
       // Account for letter-spacing
  -    if (iterator->style->letterSpacing && width > 0)
  -        width += iterator->style->letterSpacing;
  +    if (style->letterSpacing && width > 0)
  +        width += style->letterSpacing;
   
       // Account for padding.  khtml uses space padding to justify text.  We
       // distribute the specified padding over the available spaces in the run.
  @@ -2178,7 +2172,7 @@
           // Account for word-spacing.  We apply additional space between "words" by
           // adding width to the space character.
           if (currentCharacter > 0 && !isSpace(cp[-1]))
  -            width += iterator->style->wordSpacing;
  +            width += style->wordSpacing;
       }
   
       iterator->runWidthSoFar += width;
  @@ -2187,21 +2181,30 @@
       currentCharacter += clusterLength;
       iterator->currentCharacter = currentCharacter;
   
  -    int len = run->to - run->from;
  -
       // Account for float/integer impedance mismatch between CG and khtml.  "Words" (characters 
       // followed by a character defined by isSpace()) are always an integer width.  We adjust the 
       // width of the last character of a "word" to ensure an integer width.  When we move khtml to
       // floats we can remove this (and related) hacks.
       //
       // Check to see if the next character is a "RoundingHackCharacter", if so, adjust.
  -    if (currentCharacter < run->length && isRoundingHackCharacter(cp[clusterLength]) && iterator->style->applyWordRounding) {
  -        width += ceilCurrentWidth(iterator);
  -    }
  -    else if (currentCharacter >= (unsigned)run->to && (len > 1 || run->length == 1) && iterator->style->applyRunRounding) {
  -        width += ceilCurrentWidth(iterator);
  +    if (style->applyWordRounding && currentCharacter < run->length && isRoundingHackCharacter(cp[clusterLength])) {
  +        float delta = ceilCurrentWidth(iterator);
  +        if (delta)
  +            width += delta;
  +    } else {
  +        if (style->applyRunRounding && currentCharacter >= (unsigned)run->to && (run->length == 1 || run->to - run->from > 1)) {
  +            float delta = ceilCurrentWidth(iterator);
  +            if (delta)
  +                width += delta;
  +        }
       }
  +
  +    if (fontUsed)
  +        *fontUsed = _fontUsed;
       
  +    if (glyphUsed)
  +        *glyphUsed = _glyphUsed;
  +
       return width;
   }
   
  
  
  



More information about the webkit-changes mailing list