Changeset 23154 in webkit


Ignore:
Timestamp:
Mar 21, 2007 4:37:42 PM (17 years ago)
Author:
hyatt
Message:

Advanced text improvements.

Location:
branches/WindowsMerge/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/WindowsMerge/WebCore/ChangeLog

    r23137 r23154  
     12007-03-21  Dave Hyatt  <hyatt@apple.com>
     2
     3        Fix numerous bugs in RTL support.  Only use a directional override if the run
     4        tells us to.  Uniscribe will give incorrect results when measuring RTL runs as LTR if the
     5        directional override is set.  Switch from logical order for glyphs to visual order
     6        instead.  This is more similar to ATSUI (less similar to the fast code path, which always uses
     7        logical ordering for glyph generation).  Using visual ordering forces a lot of games to be played
     8        (have to walk the script items in backwards order for RTL for example), but Uniscribe does not combine
     9        glyphs properly if visual ordering is not used.
     10       
     11        Add support for justification, letter-spacing, word-spacing and rounding hacks.  The CG vs. ATSUI layout
     12        test now passes with identical results to the Mac.  The ATSUI spacing features layout test now
     13        generates correct results (although they are different from the Mac because we fall back to Arial for
     14        Hebrew instead of Lucida Grande).
     15
     16        Reviewed by NOBODY (OOPS!).
     17
     18        WARNING: NO TEST CASES ADDED OR CHANGED
     19
     20        * platform/win/UniscribeController.cpp:
     21        (WebCore::UniscribeController::UniscribeController):
     22        (WebCore::UniscribeController::resetControlAndState):
     23        (WebCore::UniscribeController::shapeAndPlaceItem):
     24        (WebCore::UniscribeController::shape):
     25        * platform/win/UniscribeController.h:
     26
    1272007-03-20  Adam Roben  <aroben@apple.com>
    228
  • branches/WindowsMerge/WebCore/platform/win/UniscribeController.cpp

    r23128 r23154  
    3636namespace WebCore {
    3737
     38// FIXME: Rearchitect this to be more like WidthIterator in Font.cpp.  Have an advance() method
     39// that does stuff in that method instead of doing everything in the constructor.  Have advance()
     40// take the GlyphBuffer as an arg so that we don't have to populate the glyph buffer when
     41// measuring.
    3842UniscribeController::UniscribeController(const Font* font, const TextRun& run, const TextStyle& style,
    3943                                         GraphicsContext* graphicsContext)
     
    4448, m_width(0)
    4549{
     50    m_padding = m_style.padding();
     51    if (!m_padding)
     52        m_padPerSpace = 0;
     53    else {
     54        float numSpaces = 0;
     55        for (int s = 0; s < m_run.length(); s++)
     56            if (Font::treatAsSpace(m_run[s]))
     57                numSpaces++;
     58
     59        if (numSpaces == 0)
     60            m_padPerSpace = 0;
     61        else
     62            m_padPerSpace = ceilf(m_style.padding() / numSpaces);
     63    }
     64
    4665    // Null out our uniscribe structs
    4766    resetControlAndState();
     
    6382    m_items.resize(numItems + 1);
    6483
    65     for (unsigned i = 0; i < m_items.size() - 1; i++)
    66         shapeAndPlaceItem(i);   
     84    if (m_style.rtl()) {
     85        for (int i = m_items.size() - 2; i >= 0; i--)
     86            shapeAndPlaceItem(i);
     87    } else {
     88        for (unsigned i = 0; i < m_items.size() - 1; i++)
     89            shapeAndPlaceItem(i); 
     90    }
    6791}
    6892
     
    7599    m_state.uBidiLevel = m_style.rtl();
    76100   
    77     // Lock the correct directional override.  This is much simpler than ATSUI.  We don't
    78     // need to access style.directionalOverride(), since Uniscribe just supports an absolute
    79     // override.
    80     m_state.fOverrideDirection = true;
     101    // Lock the correct directional override.
     102    m_state.fOverrideDirection = m_style.directionalOverride();
    81103}
    82104
     
    113135        if (shape(str, len, item, fontData, glyphs, clusters, visualAttributes))
    114136            break;
    115         else {
    116             // Try again with the next font in the list.
    117             if (lastResortFontTried) {
    118                 fontData = 0;
    119                 break;
    120             } else {
    121                 fontData = m_font.fontDataAt(++dataIndex);
    122                 if (!fontData) {
    123                     // Out of fonts.  Get a font data based on the actual characters.
    124                     fontData = m_font.fontDataForCharacters(str, len);
    125                     lastResortFontTried = true;
    126                 }
    127             }
     137       
     138        // Try again with the next font in the list.
     139        if (lastResortFontTried) {
     140            fontData = 0;
     141            break;
     142        }
     143       
     144        fontData = m_font.fontDataAt(++dataIndex);
     145        if (!fontData) {
     146            // Out of fonts.  Get a font data based on the actual characters.
     147            fontData = m_font.fontDataForCharacters(str, len);
     148            lastResortFontTried = true;
    128149        }
    129150    }
     
    157178    }
    158179   
    159     if (FAILED(placeResult))
     180    if (FAILED(placeResult) || glyphs.isEmpty())
    160181        return;
    161182
     183    // Convert all chars that should be treated as spaces to use the space glyph.
     184    // We also create a map that allows us to quickly go from space glyphs or rounding
     185    // hack glyphs back to their corresponding characters.
     186    Vector<int> spaceCharacters(glyphs.size());
     187    spaceCharacters.fill(-1);
     188    Vector<int> roundingHackCharacters(glyphs.size());
     189    roundingHackCharacters.fill(-1);
     190    Vector<int> roundingHackWordBoundaries(glyphs.size());
     191    roundingHackWordBoundaries.fill(-1);
     192    unsigned logicalSpaceWidth = fontData->m_spaceWidth * 32.0f;
     193    float roundedSpaceWidth = roundf(fontData->m_spaceWidth);
     194
     195    unsigned k;
     196    for (k = 0; k < len; k++) {
     197        UChar ch = *(str + k);
     198        if (Font::treatAsSpace(ch)) {
     199            // Substitute in the space glyph at the appropriate place in the glyphs
     200            // array.
     201            glyphs[clusters[k]] = fontData->m_spaceGlyph;
     202            advances[clusters[k]] = logicalSpaceWidth;
     203            spaceCharacters[clusters[k]] = k + m_items[i].iCharPos;
     204        }
     205
     206        if (Font::isRoundingHackCharacter(ch))
     207            roundingHackCharacters[clusters[k]] = k + m_items[i].iCharPos;
     208
     209        if (k + m_items[i].iCharPos < m_run.length() &&
     210            Font::isRoundingHackCharacter(*(str + k + 1)))
     211            roundingHackWordBoundaries[clusters[k]] = k + m_items[i].iCharPos;
     212    }
     213
    162214    // Populate our glyph buffer with this information.
    163     for (unsigned i = 0; i < glyphs.size(); i++) {
    164         Glyph glyph = glyphs[i];
    165         float advance = advances[i] / 32.0f;
     215    bool hasExtraSpacing = m_font.letterSpacing() || m_font.wordSpacing() || m_padding;
     216   
     217    for (k = 0; k < glyphs.size(); k++) {
     218        Glyph glyph = glyphs[k];
     219        float advance = advances[k] / 32.0f;
     220
     221        // Match AppKit's rules for the integer vs. non-integer rendering modes.
     222        float roundedAdvance = roundf(advance);
    166223        if (!m_font.isPrinterFont() && !fontData->isSystemFont())
    167             advance = lroundf(advance);
    168         GOFFSET offset = offsets[i]; // FIXME: What the heck do i do with this?
     224            advance = roundedAdvance;
     225       
     226        // We special case spaces in two ways when applying word rounding.
     227        // First, we round spaces to an adjusted width in all fonts.
     228        // Second, in fixed-pitch fonts we ensure that all glyphs that
     229        // match the width of the space glyph have the same width as the space glyph.
     230        if (roundedAdvance == roundedSpaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) &&
     231            m_style.applyWordRounding())
     232            advance = fontData->m_adjustedSpaceWidth;
     233
     234        if (hasExtraSpacing) {
     235            // If we're a glyph with an advance, go ahead and add in letter-spacing.
     236            // That way we weed out zero width lurkers.  This behavior matches the fast text code path.
     237            if (advance && m_font.letterSpacing())
     238                advance += m_font.letterSpacing();
     239
     240            // Handle justification and word-spacing.
     241            if (glyph == fontData->m_spaceGlyph) {
     242                // Account for padding. WebCore uses space padding to justify text.
     243                // We distribute the specified padding over the available spaces in the run.
     244                if (m_padding) {
     245                    // Use leftover padding if not evenly divisible by number of spaces.
     246                    if (m_padding < m_padPerSpace) {
     247                        advance += m_padding;
     248                        m_padding = 0;
     249                    } else {
     250                        advance += m_padPerSpace;
     251                        m_padding -= m_padPerSpace;
     252                    }
     253                }
     254
     255                // Account for word-spacing.
     256                int characterIndex = spaceCharacters[k];
     257                if (characterIndex > 0 && !Font::treatAsSpace(m_run.characters()[characterIndex-1]) && m_font.wordSpacing())
     258                    advance += m_font.wordSpacing();
     259            }
     260        }
     261
     262        // Deal with the float/integer impedance mismatch between CG and WebCore. "Words" (characters
     263        // followed by a character defined by isRoundingHackCharacter()) are always an integer width.
     264        // We adjust the width of the last character of a "word" to ensure an integer width.
     265        // Force characters that are used to determine word boundaries for the rounding hack
     266        // to be integer width, so the following words will start on an integer boundary.
     267        int roundingHackIndex = roundingHackCharacters[k];
     268        if (m_style.applyWordRounding() && roundingHackIndex != -1)
     269            advance = ceilf(advance);
     270
     271        // Check to see if the next character is a "rounding hack character", if so, adjust the
     272        // width so that the total run width will be on an integer boundary.
     273        bool lastGlyph = (k == glyphs.size() - 1) && (m_style.rtl() ? i == 0 : i == m_items.size() - 2); // FIXME: This won't always be correct once we support m_run.to().
     274        if ((m_style.applyWordRounding() && roundingHackWordBoundaries[k] != -1) ||
     275            (m_style.applyRunRounding() && lastGlyph)) {
     276            float totalWidth = m_width + advance;
     277            advance += ceilf(totalWidth) - totalWidth;
     278        }
     279
    169280        m_width += advance;
     281
     282        // FIXME: We need to take the GOFFSETS for combining glyphs and store them in the glyph buffer
     283        // as well, so that when the time comes to draw those glyphs, we can apply the appropriate
     284        // translation.
    170285        m_glyphBuffer.add(glyph, fontData, advance);
    171286    }
    172 
    173     // Swap the order of the glyphs if right-to-left.
    174     if (m_style.rtl())
    175         for (int j = 0, end = m_glyphBuffer.size() - 1; j < m_glyphBuffer.size() / 2; ++j, --end)
    176             m_glyphBuffer.swap(j, end);
    177287}
    178288
     
    186296    int glyphCount = 0;
    187297    do {
    188         item.a.fLogicalOrder = true;
    189298        shapeResult = ScriptShape(hdc, fontData->scriptCache(), str, len, glyphs.size(), &item.a,
    190299                                  glyphs.data(), clusters.data(), visualAttributes.data(), &glyphCount);
  • branches/WindowsMerge/WebCore/platform/win/UniscribeController.h

    r23128 r23154  
    6666    float m_width;
    6767    GlyphBuffer m_glyphBuffer;
     68
     69    float m_padding;
     70    float m_padPerSpace;
    6871};
    6972
Note: See TracChangeset for help on using the changeset viewer.