Changeset 95391 in webkit


Ignore:
Timestamp:
Sep 18, 2011 9:52:31 AM (13 years ago)
Author:
mitz@apple.com
Message:

Source/WebCore: Allow Core Text to choose the fallback font for rendering a combining character sequence

Fixes <rdar://problem/7860281> Decomposed text is displayed incorrectly when Verdana is specified
https://bugs.webkit.org/show_bug.cgi?id=68287

Reviewed by Dave Hyatt.

Test: platform/mac/fast/text/combining-character-sequence-fallback.html

  • WebCore.xcodeproj/project.pbxproj: Compile ComplexTextControllerCoreText.cpp as Objective-C++.

I am going to rename this file in a followup patch.

  • platform/graphics/Font.h: Declared fontDataForCombiningCharacterSequence().
  • platform/graphics/SimpleFontData.h: Declared canRenderCombiningCharacterSequence() and added

a member variable to cache the results of calling this function.

  • platform/graphics/mac/ComplexTextController.cpp:

(WebCore::ComplexTextController::offsetForPosition): Fixed a typo in a comment.
(WebCore::advanceByCombiningCharacterSequence): Added this helper function, which iterates over
characters until the end of a sequence of combining characters, zero-width joiners and zero-width
non-joiners. A single base characater followed by such a (possibly-empty) sequence is known as
a combining character sequence. This stretches the definition a little because the base character
may be a combining character as well. Returns false if an invalid UTF-16 sequence is encountered,
true otherwise.
(WebCore::ComplexTextController::collectComplexTextRuns): - Replaced the glyphData and nextGlyphData
variables each with a pair of variables, a SimpleFontData* and a boolean indicating whether a
character mapped to the missing glyph. This clarifies that this function does not use glyph IDs.

  • Renamed the local variable newC to uppercaseCharacter.
  • Changed to use advanceByCombiningCharacterSequence().
  • Changed to use Font::fontDataForCombiningCharacterSequence() instead of Font::glyphDataForCharacter(). If there are combining marks and none of the fonts in the fallback list can render the sequence alone, use the systemFallbackFontData() constant to indicate to collectComplexTextRunsForCharactersCoreText() to allow Core Text to perform its own fallback.
  • Stopped checking isSmallCaps against nextIsSmallCaps. It was redundant, since the small caps FontData differs from the normal variant.

(WebCore::ComplexTextController::collectComplexTextRunsForCharacters): Moved the common logic to
handle the 0 fontData case from the ATSUI and Core Text continuations of this function into this function.

  • platform/graphics/mac/ComplexTextController.h:

(WebCore::ComplexTextController::systemFallbackFontData): Added. This constant is used to indicate to
collectComplexTextRunsForCharactersCoreText() that it should allow Core Text to perform its own font
fallback.

  • platform/graphics/mac/ComplexTextControllerATSUI.cpp:

(WebCore::ComplexTextController::collectComplexTextRunsForCharactersATSUI): Handle systemFallbackFontData()
by using the primary font data.

  • platform/graphics/mac/ComplexTextControllerCoreText.cpp:

(-[CascadeList initWithFont:WebCore::character:]): Added.
(-[CascadeList count]): Added.
(-[CascadeList objectAtIndex:]): Added. Returns an entry from a cascade list of CTFontDescriptorRef
objects based on the font’s fallback list for the character. The list is initialized lazily.
(WebCore::ComplexTextController::collectComplexTextRunsForCharactersCoreText): Handle systemFallbackFontData()
by allowing Core Text to perform font fallback, starting with a cascade list based on the font’s fallback
list and possibly continuing with system fallback.

  • platform/graphics/mac/FontMac.mm:

(WebCore::Font::fontDataForCombiningCharacterSequence): Added. If the sequence is only a base character,
calls through to glyphDataForCharacter(). Otherwise, iterates over the font’s fallback list for the
base character (and the system fallback font for that character), returning the first font that can
render the sequence, or 0 if there is none.

  • platform/graphics/mac/SimpleFontDataMac.mm:

(WebCore::provideStringAndAttributes): Added this Core Text callback.
(WebCore::SimpleFontData::canRenderCombiningCharacterSequence): Added. Checks if Core Text can render
the sequence using only this font. Caches the result.

LayoutTests: <rdar://problem/7860281> Decomposed text is displayed incorrectly when Verdana is specified
https://bugs.webkit.org/show_bug.cgi?id=68287

Reviewed by Dave Hyatt.

  • platform/mac/fast/text/combining-character-sequence-fallback.html: Added.
  • platform/mac/platform/mac/fast/text/combining-character-sequence-fallback-expected.png: Added.
  • platform/mac/platform/mac/fast/text/combining-character-sequence-fallback-expected.txt: Added.
Location:
trunk
Files:
3 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r95390 r95391  
     12011-09-18  Dan Bernstein  <mitz@apple.com>
     2
     3        <rdar://problem/7860281> Decomposed text is displayed incorrectly when Verdana is specified
     4        https://bugs.webkit.org/show_bug.cgi?id=68287
     5
     6        Reviewed by Dave Hyatt.
     7
     8        * platform/mac/fast/text/combining-character-sequence-fallback.html: Added.
     9        * platform/mac/platform/mac/fast/text/combining-character-sequence-fallback-expected.png: Added.
     10        * platform/mac/platform/mac/fast/text/combining-character-sequence-fallback-expected.txt: Added.
     11
    1122011-09-18  Dan Bernstein  <mitz@apple.com>
    213
  • trunk/Source/WebCore/ChangeLog

    r95387 r95391  
     12011-09-18  Dan Bernstein  <mitz@apple.com>
     2
     3        Allow Core Text to choose the fallback font for rendering a combining character sequence
     4
     5        Fixes <rdar://problem/7860281> Decomposed text is displayed incorrectly when Verdana is specified
     6        https://bugs.webkit.org/show_bug.cgi?id=68287
     7
     8        Reviewed by Dave Hyatt.
     9
     10        Test: platform/mac/fast/text/combining-character-sequence-fallback.html
     11
     12        * WebCore.xcodeproj/project.pbxproj: Compile ComplexTextControllerCoreText.cpp as Objective-C++.
     13        I am going to rename this file in a followup patch.
     14
     15        * platform/graphics/Font.h: Declared fontDataForCombiningCharacterSequence().
     16
     17        * platform/graphics/SimpleFontData.h: Declared canRenderCombiningCharacterSequence() and added
     18        a member variable to cache the results of calling this function.
     19
     20        * platform/graphics/mac/ComplexTextController.cpp:
     21        (WebCore::ComplexTextController::offsetForPosition): Fixed a typo in a comment.
     22        (WebCore::advanceByCombiningCharacterSequence): Added this helper function, which iterates over
     23        characters until the end of a sequence of combining characters, zero-width joiners and zero-width
     24        non-joiners. A single base characater followed by such a (possibly-empty) sequence is known as
     25        a combining character sequence. This stretches the definition a little because the base character
     26        may be a combining character as well. Returns false if an invalid UTF-16 sequence is encountered,
     27        true otherwise.
     28        (WebCore::ComplexTextController::collectComplexTextRuns): - Replaced the glyphData and nextGlyphData
     29        variables each with a pair of variables, a SimpleFontData* and a boolean indicating whether a
     30        character mapped to the missing glyph. This clarifies that this function does not use glyph IDs.
     31        - Renamed the local variable newC to uppercaseCharacter.
     32        - Changed to use advanceByCombiningCharacterSequence().
     33        - Changed to use Font::fontDataForCombiningCharacterSequence() instead of Font::glyphDataForCharacter().
     34          If there are combining marks and none of the fonts in the fallback list can render the sequence alone,
     35          use the systemFallbackFontData() constant to indicate to collectComplexTextRunsForCharactersCoreText()
     36          to allow Core Text to perform its own fallback.
     37        - Stopped checking isSmallCaps against nextIsSmallCaps. It was redundant, since the small caps FontData
     38          differs from the normal variant.
     39        (WebCore::ComplexTextController::collectComplexTextRunsForCharacters): Moved the common logic to
     40        handle the 0 fontData case from the ATSUI and Core Text continuations of this function into this function.
     41
     42        * platform/graphics/mac/ComplexTextController.h:
     43        (WebCore::ComplexTextController::systemFallbackFontData): Added. This constant is used to indicate to
     44        collectComplexTextRunsForCharactersCoreText() that it should allow Core Text to perform its own font
     45        fallback.
     46
     47        * platform/graphics/mac/ComplexTextControllerATSUI.cpp:
     48        (WebCore::ComplexTextController::collectComplexTextRunsForCharactersATSUI): Handle systemFallbackFontData()
     49        by using the primary font data.
     50
     51        * platform/graphics/mac/ComplexTextControllerCoreText.cpp:
     52        (-[CascadeList initWithFont:WebCore::character:]): Added.
     53        (-[CascadeList count]): Added.
     54        (-[CascadeList objectAtIndex:]): Added. Returns an entry from a cascade list of CTFontDescriptorRef
     55        objects based on the font’s fallback list for the character. The list is initialized lazily.
     56        (WebCore::ComplexTextController::collectComplexTextRunsForCharactersCoreText): Handle systemFallbackFontData()
     57        by allowing Core Text to perform font fallback, starting with a cascade list based on the font’s fallback
     58        list and possibly continuing with system fallback.
     59
     60        * platform/graphics/mac/FontMac.mm:
     61        (WebCore::Font::fontDataForCombiningCharacterSequence): Added. If the sequence is only a base character,
     62        calls through to glyphDataForCharacter(). Otherwise, iterates over the font’s fallback list for the
     63        base character (and the system fallback font for that character), returning the first font that can
     64        render the sequence, or 0 if there is none.
     65
     66        * platform/graphics/mac/SimpleFontDataMac.mm:
     67        (WebCore::provideStringAndAttributes): Added this Core Text callback.
     68        (WebCore::SimpleFontData::canRenderCombiningCharacterSequence): Added. Checks if Core Text can render
     69        the sequence using only this font. Caches the result.
     70
    1712011-09-17  Mihai Parparita  <mihaip@chromium.org>
    272
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r95372 r95391  
    74467446                37C2360F1097EE7700EF9F72 /* ComplexTextController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ComplexTextController.h; sourceTree = "<group>"; };
    74477447                37C2381F1098C84200EF9F72 /* ComplexTextControllerATSUI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ComplexTextControllerATSUI.cpp; sourceTree = "<group>"; };
    7448                 37C238201098C84200EF9F72 /* ComplexTextControllerCoreText.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ComplexTextControllerCoreText.cpp; sourceTree = "<group>"; };
     7448                37C238201098C84200EF9F72 /* ComplexTextControllerCoreText.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = ComplexTextControllerCoreText.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
    74497449                37C28A6710F659CC008C7813 /* TypesettingFeatures.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypesettingFeatures.h; sourceTree = "<group>"; };
    74507450                37C61F0012095C87007A3C67 /* AtomicStringKeyedMRUCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AtomicStringKeyedMRUCache.h; sourceTree = "<group>"; };
  • trunk/Source/WebCore/platform/graphics/Font.h

    r89733 r95391  
    140140    const FontData* fontDataAt(unsigned) const;
    141141    GlyphData glyphDataForCharacter(UChar32, bool mirror, FontDataVariant = AutoVariant) const;
     142#if PLATFORM(MAC)
     143    const SimpleFontData* fontDataForCombiningCharacterSequence(const UChar*, size_t length, FontDataVariant) const;
     144#endif
    142145    std::pair<GlyphData, GlyphPage*> glyphDataAndPageForCharacter(UChar32, bool mirror, FontDataVariant = AutoVariant) const;
    143146    bool primaryFontHasGlyphForCharacter(UChar32) const;
  • trunk/Source/WebCore/platform/graphics/SimpleFontData.h

    r90167 r95391  
    3535#include <wtf/OwnPtr.h>
    3636#include <wtf/PassOwnPtr.h>
     37#include <wtf/text/StringHash.h>
    3738
    3839#if USE(ATSUI)
     
    177178#endif
    178179
     180#if PLATFORM(MAC)
     181    bool canRenderCombiningCharacterSequence(const UChar*, size_t) const;
     182#endif
     183
    179184#if USE(ATSUI)
    180185    void checkShapesArabic() const;
     
    290295#endif
    291296
     297#if PLATFORM(MAC)
     298    mutable OwnPtr<HashMap<String, bool> > m_combiningCharacterSequenceSupport;
     299#endif
     300
    292301#if PLATFORM(WIN) || (OS(WINDOWS) && PLATFORM(WX))
    293302    bool m_isSystemFont;
  • trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp

    r90798 r95391  
    152152                // FIXME: The search stops at the boundaries of complexTextRun. In theory, it should go on into neighboring ComplexTextRuns
    153153                // derived from the same CTLine. In practice, we do not expect there to be more than one CTRun in a CTLine, as no
    154                 // reordering and on font fallback should occur within a CTLine.
     154                // reordering and no font fallback should occur within a CTLine.
    155155                if (clusterEnd - clusterStart > 1) {
    156156                    clusterWidth = adjustedAdvance;
     
    185185}
    186186
     187static bool advanceByCombiningCharacterSequence(const UChar*& iterator, const UChar* end, UChar32& baseCharacter, unsigned& markCount)
     188{
     189    ASSERT(iterator < end);
     190
     191    markCount = 0;
     192
     193    baseCharacter = *iterator++;
     194
     195    if (U16_IS_SURROGATE(baseCharacter)) {
     196        if (!U16_IS_LEAD(baseCharacter))
     197            return false;
     198        if (iterator == end)
     199            return false;
     200        UChar trail = *iterator++;
     201        if (!U16_IS_TRAIL(trail))
     202            return false;
     203        baseCharacter = U16_GET_SUPPLEMENTARY(baseCharacter, trail);
     204    }
     205
     206    // Consume marks.
     207    while (iterator < end && ((U_GET_GC_MASK(*iterator) & U_GC_M_MASK) || *iterator == zeroWidthJoiner || *iterator == zeroWidthNonJoiner)) {
     208        iterator++;
     209        markCount++;
     210    }
     211
     212    return true;
     213}
     214
    187215void ComplexTextController::collectComplexTextRuns()
    188216{
     
    190218        return;
    191219
    192     // We break up glyph run generation for the string by FontData and (if needed) the use of small caps.
     220    // We break up glyph run generation for the string by FontData.
    193221    const UChar* cp = m_run.characters();
    194222
     
    200228    const UChar* end = cp + m_end;
    201229
    202     GlyphData glyphData;
    203     GlyphData nextGlyphData;
    204 
    205     bool isSurrogate = U16_IS_SURROGATE(*curr);
    206     if (isSurrogate) {
    207         if (!U16_IS_SURROGATE_LEAD(curr[0]) || curr + 1 == end || !U16_IS_TRAIL(curr[1]))
    208             return;
    209         nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[0], curr[1]), false);
    210     } else
    211         nextGlyphData = m_font.glyphDataForCharacter(*curr, false);
    212 
    213     UChar newC = 0;
     230    const SimpleFontData* fontData;
     231    bool isMissingGlyph;
     232    const SimpleFontData* nextFontData;
     233    bool nextIsMissingGlyph;
     234
     235    unsigned markCount;
     236    const UChar* sequenceStart = curr;
     237    UChar32 baseCharacter;
     238    if (!advanceByCombiningCharacterSequence(curr, end, baseCharacter, markCount))
     239        return;
     240
     241    UChar uppercaseCharacter = 0;
    214242
    215243    bool isSmallCaps;
    216     bool nextIsSmallCaps = !isSurrogate && m_font.isSmallCaps() && !(U_GET_GC_MASK(*curr) & U_GC_M_MASK) && (newC = u_toupper(*curr)) != *curr;
    217 
    218     if (nextIsSmallCaps)
    219         m_smallCapsBuffer[curr - cp] = newC;
    220 
    221     while (true) {
    222         curr = curr + (isSurrogate ? 2 : 1);
    223         if (curr == end)
    224             break;
    225 
    226         glyphData = nextGlyphData;
     244    bool nextIsSmallCaps = m_font.isSmallCaps() && !(U_GET_GC_MASK(baseCharacter) & U_GC_M_MASK) && (uppercaseCharacter = u_toupper(baseCharacter)) != baseCharacter;
     245
     246    if (nextIsSmallCaps) {
     247        m_smallCapsBuffer[sequenceStart - cp] = uppercaseCharacter;
     248        for (unsigned i = 0; i < markCount; ++i)
     249            m_smallCapsBuffer[sequenceStart - cp + i + 1] = sequenceStart[i + 1];
     250    }
     251
     252    nextIsMissingGlyph = false;
     253    nextFontData = m_font.fontDataForCombiningCharacterSequence(sequenceStart, curr - sequenceStart, nextIsSmallCaps ? SmallCapsVariant : NormalVariant);
     254    if (!nextFontData) {
     255        if (markCount)
     256            nextFontData = systemFallbackFontData();
     257        else
     258            nextIsMissingGlyph = true;
     259    }
     260
     261    while (curr < end) {
     262        fontData = nextFontData;
     263        isMissingGlyph = nextIsMissingGlyph;
    227264        isSmallCaps = nextIsSmallCaps;
    228265        int index = curr - cp;
    229         isSurrogate = U16_IS_SURROGATE(*curr);
    230         UChar c = *curr;
    231         bool forceSmallCaps = !isSurrogate && isSmallCaps && (U_GET_GC_MASK(c) & U_GC_M_MASK);
    232         if (isSurrogate) {
    233             if (!U16_IS_SURROGATE_LEAD(curr[0]) || curr + 1 == end || !U16_IS_TRAIL(curr[1]))
    234                 return;
    235             nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[0], curr[1]), false);
    236         } else
    237             nextGlyphData = m_font.glyphDataForCharacter(*curr, false, forceSmallCaps ? SmallCapsVariant : AutoVariant);
    238 
    239         if (!isSurrogate && m_font.isSmallCaps()) {
    240             nextIsSmallCaps = forceSmallCaps || (newC = u_toupper(c)) != c;
    241             if (nextIsSmallCaps)
    242                 m_smallCapsBuffer[index] = forceSmallCaps ? c : newC;
     266
     267        if (!advanceByCombiningCharacterSequence(curr, end, baseCharacter, markCount))
     268            return;
     269
     270        if (m_font.isSmallCaps()) {
     271            nextIsSmallCaps = (uppercaseCharacter = u_toupper(baseCharacter)) != baseCharacter;
     272            if (nextIsSmallCaps) {
     273                m_smallCapsBuffer[index] = uppercaseCharacter;
     274                for (unsigned i = 0; i < markCount; ++i)
     275                    m_smallCapsBuffer[index + i + 1] = cp[index + i + 1];
     276            }
    243277        }
    244278
    245         if (nextGlyphData.fontData != glyphData.fontData || nextIsSmallCaps != isSmallCaps || !nextGlyphData.glyph != !glyphData.glyph) {
     279        nextIsMissingGlyph = false;
     280        nextFontData = m_font.fontDataForCombiningCharacterSequence(cp + index, curr - cp - index, nextIsSmallCaps ? SmallCapsVariant : NormalVariant);
     281        if (!nextFontData) {
     282            if (markCount)
     283                nextFontData = systemFallbackFontData();
     284            else
     285                nextIsMissingGlyph = true;
     286        }
     287
     288        if (nextFontData != fontData || nextIsMissingGlyph != isMissingGlyph) {
    246289            int itemStart = static_cast<int>(indexOfFontTransition);
    247290            int itemLength = index - indexOfFontTransition;
    248             collectComplexTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, glyphData.glyph ? glyphData.fontData : 0);
     291            collectComplexTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, !isMissingGlyph ? fontData : 0);
    249292            indexOfFontTransition = index;
    250293        }
     
    254297    if (itemLength) {
    255298        int itemStart = indexOfFontTransition;
    256         collectComplexTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, nextGlyphData.glyph ? nextGlyphData.fontData : 0);
     299        collectComplexTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, !nextIsMissingGlyph ? nextFontData : 0);
    257300    }
    258301
     
    291334void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
    292335{
     336    if (!fontData) {
     337        // Create a run of missing glyphs from the primary font.
     338        m_complexTextRuns.append(ComplexTextRun::create(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr()));
     339        return;
     340    }
     341
    293342#if USE(CORE_TEXT) && USE(ATSUI)
    294343    if (shouldUseATSUIAPI())
  • trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.h

    r89733 r95391  
    8181   
    8282private:
     83    static const SimpleFontData* systemFallbackFontData() { return reinterpret_cast<const SimpleFontData*>(-1); }
     84
    8385    class ComplexTextRun : public RefCounted<ComplexTextRun> {
    8486    public:
  • trunk/Source/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp

    r85507 r95391  
    316316void ComplexTextController::collectComplexTextRunsForCharactersATSUI(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
    317317{
    318     if (!fontData) {
    319         // Create a run of missing glyphs from the primary font.
    320         m_complexTextRuns.append(ComplexTextRun::create(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr()));
    321         return;
    322     }
     318    ASSERT_ARG(fontData, fontData);
     319
     320    if (fontData == systemFallbackFont())
     321        fontData = m_font.primaryFont();
    323322
    324323    if (m_fallbackFonts && fontData != m_font.primaryFont())
  • trunk/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp

    r88487 r95391  
    11/*
    2  * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
     2 * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3030
    3131#include "Font.h"
     32#include "FontCache.h"
    3233#include "TextRun.h"
    3334#include "WebCoreSystemInterface.h"
     
    4748}
    4849#endif
     50
     51@interface CascadeList : NSArray {
     52    @private
     53    const WebCore::Font* _font;
     54    UChar32 _character;
     55    NSUInteger _count;
     56    Vector<RetainPtr<CTFontDescriptorRef>, 16> _fontDescriptors;
     57}
     58
     59- (id)initWithFont:(const WebCore::Font*)font character:(UChar32)character;
     60
     61@end
     62
     63@implementation CascadeList
     64
     65- (id)initWithFont:(const WebCore::Font*)font character:(UChar32)character
     66{
     67    if (!(self = [super init]))
     68        return nil;
     69
     70    _font = font;
     71    _character = character;
     72
     73    for (const WebCore::FontFamily* family = &font->family(); family; family = family->next())
     74        _count++;
     75
     76    return self;
     77}
     78
     79- (NSUInteger)count
     80{
     81    return _count;
     82}
     83
     84- (id)objectAtIndex:(NSUInteger)index
     85{
     86    CTFontDescriptorRef fontDescriptor;
     87    if (index < _fontDescriptors.size()) {
     88        if ((fontDescriptor = _fontDescriptors[index].get()))
     89            return (id)fontDescriptor;
     90    } else
     91        _fontDescriptors.grow(index + 1);
     92
     93    const WebCore::SimpleFontData* fontData = _font->fontDataAt(index)->fontDataForCharacter(_character);
     94    fontDescriptor = CTFontCopyFontDescriptor(fontData->platformData().ctFont());
     95    _fontDescriptors[index] = RetainPtr<CTFontDescriptorRef>(AdoptCF, fontDescriptor);
     96    return (id)fontDescriptor;
     97}
     98
     99@end
    49100
    50101namespace WebCore {
     
    130181void ComplexTextController::collectComplexTextRunsForCharactersCoreText(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
    131182{
    132     if (!fontData) {
    133         // Create a run of missing glyphs from the primary font.
    134         m_complexTextRuns.append(ComplexTextRun::create(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr()));
    135         return;
    136     }
    137 
    138     if (m_fallbackFonts && fontData != m_font.primaryFont())
    139         m_fallbackFonts->add(fontData);
     183    ASSERT_ARG(fontData, fontData);
     184
     185    bool isSystemFallback = false;
     186
     187    RetainPtr<CFDictionaryRef> stringAttributes;
     188    if (fontData == systemFallbackFontData()) {
     189        // FIXME: This code path does not support small caps.
     190        isSystemFallback = true;
     191
     192        UChar32 baseCharacter;
     193        U16_GET(cp, 0, 0, length, baseCharacter);
     194        fontData = m_font.fontDataAt(0)->fontDataForCharacter(baseCharacter);
     195
     196        RetainPtr<CascadeList> cascadeList(AdoptNS, [[CascadeList alloc] initWithFont:&m_font character:baseCharacter]);
     197
     198        stringAttributes.adoptCF(CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, fontData->getCFStringAttributes(m_font.typesettingFeatures(), fontData->platformData().orientation())));
     199        static const void* attributeKeys[] = { kCTFontCascadeListAttribute };
     200        const void* values[] = { cascadeList.get() };
     201        RetainPtr<CFDictionaryRef> attributes(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, attributeKeys, values, sizeof(attributeKeys) / sizeof(*attributeKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
     202        RetainPtr<CTFontDescriptorRef> fontDescriptor(AdoptCF, CTFontDescriptorCreateWithAttributes(attributes.get()));
     203        RetainPtr<CTFontRef> fontWithCascadeList(AdoptCF, CTFontCreateCopyWithAttributes(fontData->platformData().ctFont(), m_font.pixelSize(), 0, fontDescriptor.get()));
     204        CFDictionarySetValue((CFMutableDictionaryRef)stringAttributes.get(), kCTFontAttributeName, fontWithCascadeList.get());
     205    } else
     206        stringAttributes = fontData->getCFStringAttributes(m_font.typesettingFeatures(), fontData->platformData().orientation());
    140207
    141208    RetainPtr<CTLineRef> line;
     
    151218
    152219#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
    153         ProviderInfo info = { cp, length, fontData->getCFStringAttributes(m_font.typesettingFeatures(), fontData->platformData().orientation()) };
     220        ProviderInfo info = { cp, length, stringAttributes.get() };
    154221        RetainPtr<CTTypesetterRef> typesetter(AdoptCF, wkCreateCTTypesetterWithUniCharProviderAndOptions(&provideStringAndAttributes, 0, &info, m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions));
    155222#else
    156223        RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, cp, length, kCFAllocatorNull));
    157         RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(m_font.typesettingFeatures(), fontData->platformData().orientation())));
     224        RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), stringAttributes.get()));
    158225        RetainPtr<CTTypesetterRef> typesetter(AdoptCF, CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions));
    159226#endif
     
    161228        line.adoptCF(CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0)));
    162229    } else {
    163         ProviderInfo info = { cp, length, fontData->getCFStringAttributes(m_font.typesettingFeatures(), fontData->platformData().orientation()) };
     230        ProviderInfo info = { cp, length, stringAttributes.get() };
    164231
    165232        line.adoptCF(wkCreateCTLineWithUniCharProvider(&provideStringAndAttributes, 0, &info));
     
    176243        ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());
    177244        CFRange runRange = CTRunGetStringRange(ctRun);
    178         m_complexTextRuns.append(ComplexTextRun::create(ctRun, fontData, cp, stringLocation, length, runRange));
     245        const SimpleFontData* runFontData = fontData;
     246        if (isSystemFallback) {
     247            CFDictionaryRef runAttributes = CTRunGetAttributes(ctRun);
     248            CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(runAttributes, kCTFontAttributeName));
     249            ASSERT(CFGetTypeID(runFont) == CTFontGetTypeID());
     250            if (!CFEqual(runFont, fontData->platformData().ctFont())) {
     251                // Rather than using runFont as an NSFont and wrapping it in a FontPlatformData, go through
     252                // the font cache and ultimately through NSFontManager in order to get an NSFont with the right
     253                // NSFontRenderingMode.
     254                RetainPtr<CFStringRef> fontName(AdoptCF, CTFontCopyPostScriptName(runFont));
     255                if (CFEqual(fontName.get(), CFSTR("LastResort"))) {
     256                    m_complexTextRuns.append(ComplexTextRun::create(m_font.primaryFont(), cp, stringLocation + runRange.location, runRange.length, m_run.ltr()));
     257                    continue;
     258                }
     259                runFontData = fontCache()->getCachedFontData(m_font.fontDescription(), fontName.get(), false, FontCache::DoNotRetain);
     260                if (m_fallbackFonts && runFontData != m_font.primaryFont())
     261                    m_fallbackFonts->add(runFontData);
     262            }
     263        }
     264        if (m_fallbackFonts && runFontData != m_font.primaryFont())
     265            m_fallbackFonts->add(fontData);
     266
     267        m_complexTextRuns.append(ComplexTextRun::create(ctRun, runFontData, cp, stringLocation, length, runRange));
    179268    }
    180269}
  • trunk/Source/WebCore/platform/graphics/mac/FontMac.mm

    r95070 r95391  
    33 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
    44 *           (C) 2000 Dirk Mueller (mueller@kde.org)
    5  * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 Apple Inc.
     5 * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc.
    66 *
    77 * This library is free software; you can redistribute it and/or
     
    250250}
    251251
    252 }
     252const SimpleFontData* Font::fontDataForCombiningCharacterSequence(const UChar* characters, size_t length, FontDataVariant variant) const
     253{
     254    UChar32 baseCharacter;
     255    size_t baseCharacterLength = 0;
     256    U16_NEXT(characters, baseCharacterLength, length, baseCharacter);
     257
     258    GlyphData baseCharacterGlyphData = glyphDataForCharacter(baseCharacter, false, variant);
     259
     260    if (length == baseCharacterLength)
     261        return baseCharacterGlyphData.glyph ? baseCharacterGlyphData.fontData : 0;
     262
     263    bool triedBaseCharacterFontData = false;
     264
     265    unsigned i = 0;
     266    for (const FontData* fontData = fontDataAt(0); fontData; fontData = fontDataAt(++i)) {
     267        const SimpleFontData* simpleFontData = fontData->fontDataForCharacter(baseCharacter);
     268        if (variant != NormalVariant) {
     269            if (const SimpleFontData* variantFontData = simpleFontData->variantFontData(m_fontDescription, variant))
     270                simpleFontData = variantFontData;
     271        }
     272
     273        if (simpleFontData == baseCharacterGlyphData.fontData)
     274            triedBaseCharacterFontData = true;
     275
     276        if (simpleFontData->canRenderCombiningCharacterSequence(characters, length))
     277            return simpleFontData;
     278    }
     279
     280    if (!triedBaseCharacterFontData && baseCharacterGlyphData.fontData && baseCharacterGlyphData.fontData->canRenderCombiningCharacterSequence(characters, length))
     281        return baseCharacterGlyphData.fontData;
     282
     283    return 0;
     284}
     285
     286}
  • trunk/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm

    r93376 r95391  
    11/*
    2  * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
     2 * Copyright (C) 2005, 2006, 2010, 2011 Apple Inc. All rights reserved.
    33 * Copyright (C) 2006 Alexey Proskuryakov
    44 *
     
    66 * modification, are permitted provided that the following conditions
    77 * are met:
     8 * 1. Redistributions of source code must retain the above copyright
     9 *    notice, this list of conditions and the following disclaimer.
     10 * 2. Redistributions in binary form must reproduce the above copyright
     11 *    notice, this list of conditions and the following disclaimer in the
     12 *    documentation and/or other materials provided with the distribution.
    813 *
    9  * 1.  Redistributions of source code must retain the above copyright
    10  *     notice, this list of conditions and the following disclaimer.
    11  * 2.  Redistributions in binary form must reproduce the above copyright
    12  *     notice, this list of conditions and the following disclaimer in the
    13  *     documentation and/or other materials provided with the distribution.
    14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
    15  *     its contributors may be used to endorse or promote products derived
    16  *     from this software without specific prior written permission.
    17  *
    18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
    19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
    22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     24 * THE POSSIBILITY OF SUCH DAMAGE.
    2825 */
    2926
     
    417414}
    418415
     416struct ProviderInfo {
     417    const UChar* characters;
     418    size_t length;
     419    CFDictionaryRef attributes;
     420};
     421
     422static const UniChar* provideStringAndAttributes(CFIndex stringIndex, CFIndex* count, CFDictionaryRef* attributes, void* context)
     423{
     424    ProviderInfo* info = static_cast<struct ProviderInfo*>(context);
     425    if (stringIndex < 0 || static_cast<size_t>(stringIndex) >= info->length)
     426        return 0;
     427
     428    *count = info->length - stringIndex;
     429    *attributes = info->attributes;
     430    return info->characters + stringIndex;
     431}
     432
     433bool SimpleFontData::canRenderCombiningCharacterSequence(const UChar* characters, size_t length) const
     434{
     435    ASSERT(isMainThread());
     436
     437    if (!m_combiningCharacterSequenceSupport)
     438        m_combiningCharacterSequenceSupport = adoptPtr(new HashMap<String, bool>);
     439
     440    pair<WTF::HashMap<String, bool>::iterator, bool> addResult = m_combiningCharacterSequenceSupport->add(String(characters, length), false);
     441    if (!addResult.second)
     442        return addResult.first->second;
     443
     444    RetainPtr<CGFontRef> cgFont(AdoptCF, CTFontCopyGraphicsFont(platformData().ctFont(), 0));
     445
     446    ProviderInfo info = { characters, length, getCFStringAttributes(0, platformData().orientation()) };
     447    RetainPtr<CTLineRef> line(AdoptCF, wkCreateCTLineWithUniCharProvider(&provideStringAndAttributes, 0, &info));
     448
     449    CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
     450    CFIndex runCount = CFArrayGetCount(runArray);
     451
     452    for (CFIndex r = 0; r < runCount; r++) {
     453        CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
     454        ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());
     455        CFDictionaryRef runAttributes = CTRunGetAttributes(ctRun);
     456        CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(runAttributes, kCTFontAttributeName));
     457        RetainPtr<CGFontRef> runCGFont(AdoptCF, CTFontCopyGraphicsFont(runFont, 0));
     458        if (!CFEqual(runCGFont.get(), cgFont.get()))
     459            return false;
     460    }
     461
     462    addResult.first->second = true;
     463    return true;
     464}
     465
    419466} // namespace WebCore
Note: See TracChangeset for help on using the changeset viewer.