Home | History | Annotate | Download | only in mac
      1 /*
      2  * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23  */
     24 
     25 #include "config.h"
     26 #include "platform/fonts/mac/ComplexTextController.h"
     27 
     28 #include "platform/fonts/Character.h"
     29 #include "platform/fonts/Font.h"
     30 #include "platform/fonts/GlyphBuffer.h"
     31 #include "platform/geometry/FloatSize.h"
     32 #include "platform/text/TextBreakIterator.h"
     33 #include "platform/text/TextRun.h"
     34 #include "wtf/StdLibExtras.h"
     35 #include "wtf/unicode/CharacterNames.h"
     36 #include <ApplicationServices/ApplicationServices.h>
     37 
     38 using namespace std;
     39 
     40 namespace WebCore {
     41 
     42 static inline CGFloat roundCGFloat(CGFloat f)
     43 {
     44     if (sizeof(CGFloat) == sizeof(float))
     45         return roundf(static_cast<float>(f));
     46     return static_cast<CGFloat>(round(f));
     47 }
     48 
     49 static inline CGFloat ceilCGFloat(CGFloat f)
     50 {
     51     if (sizeof(CGFloat) == sizeof(float))
     52         return ceilf(static_cast<float>(f));
     53     return static_cast<CGFloat>(ceil(f));
     54 }
     55 
     56 ComplexTextController::ComplexTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts, bool forTextEmphasis)
     57     : m_font(*font)
     58     , m_run(run)
     59     , m_isLTROnly(true)
     60     , m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection)
     61     , m_forTextEmphasis(forTextEmphasis)
     62     , m_currentCharacter(0)
     63     , m_end(run.length())
     64     , m_totalWidth(0)
     65     , m_runWidthSoFar(0)
     66     , m_numGlyphsSoFar(0)
     67     , m_currentRun(0)
     68     , m_glyphInCurrentRun(0)
     69     , m_characterInCurrentGlyph(0)
     70     , m_finalRoundingWidth(0)
     71     , m_expansion(run.expansion())
     72     , m_leadingExpansion(0)
     73     , m_afterExpansion(!run.allowsLeadingExpansion())
     74     , m_fallbackFonts(fallbackFonts)
     75     , m_minGlyphBoundingBoxX(numeric_limits<float>::max())
     76     , m_maxGlyphBoundingBoxX(numeric_limits<float>::min())
     77     , m_minGlyphBoundingBoxY(numeric_limits<float>::max())
     78     , m_maxGlyphBoundingBoxY(numeric_limits<float>::min())
     79     , m_lastRoundingGlyph(0)
     80 {
     81     if (!m_expansion)
     82         m_expansionPerOpportunity = 0;
     83     else {
     84         bool isAfterExpansion = m_afterExpansion;
     85         unsigned expansionOpportunityCount;
     86         if (m_run.is8Bit())
     87             expansionOpportunityCount = Character::expansionOpportunityCount(m_run.characters8(), m_end, m_run.direction(), isAfterExpansion);
     88          else
     89             expansionOpportunityCount = Character::expansionOpportunityCount(m_run.characters16(), m_end, m_run.direction(), isAfterExpansion);
     90         if (isAfterExpansion && !m_run.allowsTrailingExpansion())
     91             expansionOpportunityCount--;
     92 
     93         if (!expansionOpportunityCount)
     94             m_expansionPerOpportunity = 0;
     95         else
     96             m_expansionPerOpportunity = m_expansion / expansionOpportunityCount;
     97     }
     98 
     99     collectComplexTextRuns();
    100     adjustGlyphsAndAdvances();
    101 
    102     if (!m_isLTROnly) {
    103         m_runIndices.reserveInitialCapacity(m_complexTextRuns.size());
    104 
    105         m_glyphCountFromStartToIndex.reserveInitialCapacity(m_complexTextRuns.size());
    106         unsigned glyphCountSoFar = 0;
    107         for (unsigned i = 0; i < m_complexTextRuns.size(); ++i) {
    108             m_glyphCountFromStartToIndex.uncheckedAppend(glyphCountSoFar);
    109             glyphCountSoFar += m_complexTextRuns[i]->glyphCount();
    110         }
    111     }
    112 
    113     m_runWidthSoFar = m_leadingExpansion;
    114 }
    115 
    116 int ComplexTextController::offsetForPosition(float h, bool includePartialGlyphs)
    117 {
    118     if (h >= m_totalWidth)
    119         return m_run.ltr() ? m_end : 0;
    120 
    121     h -= m_leadingExpansion;
    122     if (h < 0)
    123         return m_run.ltr() ? 0 : m_end;
    124 
    125     CGFloat x = h;
    126 
    127     size_t runCount = m_complexTextRuns.size();
    128     size_t offsetIntoAdjustedGlyphs = 0;
    129 
    130     for (size_t r = 0; r < runCount; ++r) {
    131         const ComplexTextRun& complexTextRun = *m_complexTextRuns[r];
    132         for (unsigned j = 0; j < complexTextRun.glyphCount(); ++j) {
    133             CGFloat adjustedAdvance = m_adjustedAdvances[offsetIntoAdjustedGlyphs + j].width;
    134             if (x < adjustedAdvance) {
    135                 CFIndex hitGlyphStart = complexTextRun.indexAt(j);
    136                 CFIndex hitGlyphEnd;
    137                 if (m_run.ltr())
    138                     hitGlyphEnd = max<CFIndex>(hitGlyphStart, j + 1 < complexTextRun.glyphCount() ? complexTextRun.indexAt(j + 1) : static_cast<CFIndex>(complexTextRun.indexEnd()));
    139                 else
    140                     hitGlyphEnd = max<CFIndex>(hitGlyphStart, j > 0 ? complexTextRun.indexAt(j - 1) : static_cast<CFIndex>(complexTextRun.indexEnd()));
    141 
    142                 // FIXME: Instead of dividing the glyph's advance equally between the characters, this
    143                 // could use the glyph's "ligature carets". However, there is no Core Text API to get the
    144                 // ligature carets.
    145                 CFIndex hitIndex = hitGlyphStart + (hitGlyphEnd - hitGlyphStart) * (m_run.ltr() ? x / adjustedAdvance : 1 - x / adjustedAdvance);
    146                 int stringLength = complexTextRun.stringLength();
    147                 TextBreakIterator* cursorPositionIterator = cursorMovementIterator(complexTextRun.characters(), stringLength);
    148                 int clusterStart;
    149                 if (cursorPositionIterator->isBoundary(hitIndex))
    150                     clusterStart = hitIndex;
    151                 else {
    152                     clusterStart = cursorPositionIterator->preceding(hitIndex);
    153                     if (clusterStart == TextBreakDone)
    154                         clusterStart = 0;
    155                 }
    156 
    157                 if (!includePartialGlyphs)
    158                     return complexTextRun.stringLocation() + clusterStart;
    159 
    160                 int clusterEnd = cursorPositionIterator->following(hitIndex);
    161                 if (clusterEnd == TextBreakDone)
    162                     clusterEnd = stringLength;
    163 
    164                 CGFloat clusterWidth;
    165                 // FIXME: The search stops at the boundaries of complexTextRun. In theory, it should go on into neighboring ComplexTextRuns
    166                 // derived from the same CTLine. In practice, we do not expect there to be more than one CTRun in a CTLine, as no
    167                 // reordering and no font fallback should occur within a CTLine.
    168                 if (clusterEnd - clusterStart > 1) {
    169                     clusterWidth = adjustedAdvance;
    170                     int firstGlyphBeforeCluster = j - 1;
    171                     while (firstGlyphBeforeCluster >= 0 && complexTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) {
    172                         CGFloat width = m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width;
    173                         clusterWidth += width;
    174                         x += width;
    175                         firstGlyphBeforeCluster--;
    176                     }
    177                     unsigned firstGlyphAfterCluster = j + 1;
    178                     while (firstGlyphAfterCluster < complexTextRun.glyphCount() && complexTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) {
    179                         clusterWidth += m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphAfterCluster].width;
    180                         firstGlyphAfterCluster++;
    181                     }
    182                 } else {
    183                     clusterWidth = adjustedAdvance / (hitGlyphEnd - hitGlyphStart);
    184                     x -=  clusterWidth * (m_run.ltr() ? hitIndex - hitGlyphStart : hitGlyphEnd - hitIndex - 1);
    185                 }
    186                 if (x <= clusterWidth / 2)
    187                     return complexTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd);
    188                 else
    189                     return complexTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart);
    190             }
    191             x -= adjustedAdvance;
    192         }
    193         offsetIntoAdjustedGlyphs += complexTextRun.glyphCount();
    194     }
    195 
    196     ASSERT_NOT_REACHED();
    197     return 0;
    198 }
    199 
    200 static bool advanceByCombiningCharacterSequence(const UChar*& iterator, const UChar* end, UChar32& baseCharacter, unsigned& markCount)
    201 {
    202     ASSERT(iterator < end);
    203 
    204     markCount = 0;
    205 
    206     baseCharacter = *iterator++;
    207 
    208     if (U16_IS_SURROGATE(baseCharacter)) {
    209         if (!U16_IS_LEAD(baseCharacter))
    210             return false;
    211         if (iterator == end)
    212             return false;
    213         UChar trail = *iterator++;
    214         if (!U16_IS_TRAIL(trail))
    215             return false;
    216         baseCharacter = U16_GET_SUPPLEMENTARY(baseCharacter, trail);
    217     }
    218 
    219     // Consume marks.
    220     while (iterator < end) {
    221         UChar32 nextCharacter;
    222         int markLength = 0;
    223         U16_NEXT(iterator, markLength, end - iterator, nextCharacter);
    224         if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK))
    225             break;
    226         markCount += markLength;
    227         iterator += markLength;
    228     }
    229 
    230     return true;
    231 }
    232 
    233 void ComplexTextController::collectComplexTextRuns()
    234 {
    235     if (!m_end)
    236         return;
    237 
    238     // We break up glyph run generation for the string by FontData.
    239     const UChar* cp;
    240 
    241     if (m_run.is8Bit()) {
    242         String stringFor8BitRun = String::make16BitFrom8BitSource(m_run.characters8(), m_run.length());
    243         cp = stringFor8BitRun.characters16();
    244         m_stringsFor8BitRuns.append(stringFor8BitRun);
    245     } else
    246         cp = m_run.characters16();
    247 
    248     if (m_font.fontDescription().variant() == FontVariantSmallCaps)
    249         m_smallCapsBuffer.resize(m_end);
    250 
    251     unsigned indexOfFontTransition = 0;
    252     const UChar* curr = cp;
    253     const UChar* end = cp + m_end;
    254 
    255     const SimpleFontData* fontData;
    256     bool isMissingGlyph;
    257     const SimpleFontData* nextFontData;
    258     bool nextIsMissingGlyph;
    259 
    260     unsigned markCount;
    261     const UChar* sequenceStart = curr;
    262     UChar32 baseCharacter;
    263     if (!advanceByCombiningCharacterSequence(curr, end, baseCharacter, markCount))
    264         return;
    265 
    266     UChar uppercaseCharacter = 0;
    267 
    268     bool isSmallCaps;
    269     bool nextIsSmallCaps = m_font.fontDescription().variant() == FontVariantSmallCaps && !(U_GET_GC_MASK(baseCharacter) & U_GC_M_MASK) && (uppercaseCharacter = u_toupper(baseCharacter)) != baseCharacter;
    270 
    271     if (nextIsSmallCaps) {
    272         m_smallCapsBuffer[sequenceStart - cp] = uppercaseCharacter;
    273         for (unsigned i = 0; i < markCount; ++i)
    274             m_smallCapsBuffer[sequenceStart - cp + i + 1] = sequenceStart[i + 1];
    275     }
    276 
    277     nextIsMissingGlyph = false;
    278     nextFontData = m_font.fontDataForCombiningCharacterSequence(sequenceStart, curr - sequenceStart, nextIsSmallCaps ? SmallCapsVariant : NormalVariant);
    279     if (!nextFontData)
    280         nextIsMissingGlyph = true;
    281 
    282     while (curr < end) {
    283         fontData = nextFontData;
    284         isMissingGlyph = nextIsMissingGlyph;
    285         isSmallCaps = nextIsSmallCaps;
    286         int index = curr - cp;
    287 
    288         if (!advanceByCombiningCharacterSequence(curr, end, baseCharacter, markCount))
    289             return;
    290 
    291         if (m_font.fontDescription().variant()) {
    292             nextIsSmallCaps = (uppercaseCharacter = u_toupper(baseCharacter)) != baseCharacter;
    293             if (nextIsSmallCaps) {
    294                 m_smallCapsBuffer[index] = uppercaseCharacter;
    295                 for (unsigned i = 0; i < markCount; ++i)
    296                     m_smallCapsBuffer[index + i + 1] = cp[index + i + 1];
    297             }
    298         }
    299 
    300         nextIsMissingGlyph = false;
    301         if (baseCharacter == zeroWidthJoiner)
    302             nextFontData = fontData;
    303         else {
    304             nextFontData = m_font.fontDataForCombiningCharacterSequence(cp + index, curr - cp - index, nextIsSmallCaps ? SmallCapsVariant : NormalVariant);
    305             if (!nextFontData)
    306                 nextIsMissingGlyph = true;
    307         }
    308 
    309         if (nextFontData != fontData || nextIsMissingGlyph != isMissingGlyph) {
    310             int itemStart = static_cast<int>(indexOfFontTransition);
    311             int itemLength = index - indexOfFontTransition;
    312             collectComplexTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, !isMissingGlyph ? fontData : 0);
    313             indexOfFontTransition = index;
    314         }
    315     }
    316 
    317     int itemLength = m_end - indexOfFontTransition;
    318     if (itemLength) {
    319         int itemStart = indexOfFontTransition;
    320         collectComplexTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, !nextIsMissingGlyph ? nextFontData : 0);
    321     }
    322 
    323     if (!m_run.ltr())
    324         m_complexTextRuns.reverse();
    325 }
    326 
    327 CFIndex ComplexTextController::ComplexTextRun::indexAt(size_t i) const
    328 {
    329     return m_coreTextIndices[i];
    330 }
    331 
    332 void ComplexTextController::ComplexTextRun::setIsNonMonotonic()
    333 {
    334     ASSERT(m_isMonotonic);
    335     m_isMonotonic = false;
    336 
    337     Vector<bool, 64> mappedIndices(m_stringLength);
    338     for (size_t i = 0; i < m_glyphCount; ++i) {
    339         ASSERT(indexAt(i) < static_cast<CFIndex>(m_stringLength));
    340         mappedIndices[indexAt(i)] = true;
    341     }
    342 
    343     m_glyphEndOffsets.grow(m_glyphCount);
    344     for (size_t i = 0; i < m_glyphCount; ++i) {
    345         CFIndex nextMappedIndex = m_indexEnd;
    346         for (size_t j = indexAt(i) + 1; j < m_stringLength; ++j) {
    347             if (mappedIndices[j]) {
    348                 nextMappedIndex = j;
    349                 break;
    350             }
    351         }
    352         m_glyphEndOffsets[i] = nextMappedIndex;
    353     }
    354 }
    355 
    356 unsigned ComplexTextController::findNextRunIndex(unsigned runIndex) const
    357 {
    358     const unsigned runOffset = stringEnd(*m_complexTextRuns[runIndex]);
    359 
    360     // Finds the run with the lowest stringBegin() offset that starts at or
    361     // after |runOffset|.
    362     //
    363     // Note that this can't just find a run whose stringBegin() equals the
    364     // stringEnd() of the previous run because CoreText on Mac OS X 10.6 does
    365     // not return runs covering BiDi control chars, so this has to handle the
    366     // resulting gaps.
    367     unsigned result = 0;
    368     unsigned lowestOffset = UINT_MAX;
    369     for (unsigned i = 0; i < m_complexTextRuns.size(); ++i) {
    370         unsigned offset = stringBegin(*m_complexTextRuns[i]);
    371         if (i != runIndex && offset >= runOffset && offset < lowestOffset) {
    372             lowestOffset = offset;
    373             result = i;
    374         }
    375     }
    376 
    377     ASSERT(lowestOffset != UINT_MAX);
    378     return result;
    379 }
    380 
    381 unsigned ComplexTextController::indexOfCurrentRun(unsigned& leftmostGlyph)
    382 {
    383     leftmostGlyph = 0;
    384 
    385     size_t runCount = m_complexTextRuns.size();
    386     if (m_currentRun >= runCount)
    387         return runCount;
    388 
    389     if (m_isLTROnly) {
    390         for (unsigned i = 0; i < m_currentRun; ++i)
    391             leftmostGlyph += m_complexTextRuns[i]->glyphCount();
    392         return m_currentRun;
    393     }
    394 
    395     if (m_runIndices.isEmpty()) {
    396         unsigned firstRun = 0;
    397         unsigned firstRunOffset = stringBegin(*m_complexTextRuns[0]);
    398         for (unsigned i = 1; i < runCount; ++i) {
    399             unsigned offset = stringBegin(*m_complexTextRuns[i]);
    400             if (offset < firstRunOffset) {
    401                 firstRun = i;
    402                 firstRunOffset = offset;
    403             }
    404         }
    405         m_runIndices.uncheckedAppend(firstRun);
    406     }
    407 
    408     while (m_runIndices.size() <= m_currentRun) {
    409         m_runIndices.uncheckedAppend(findNextRunIndex(m_runIndices.last()));
    410     }
    411 
    412     unsigned currentRunIndex = m_runIndices[m_currentRun];
    413     leftmostGlyph = m_glyphCountFromStartToIndex[currentRunIndex];
    414     return currentRunIndex;
    415 }
    416 
    417 unsigned ComplexTextController::incrementCurrentRun(unsigned& leftmostGlyph)
    418 {
    419     if (m_isLTROnly) {
    420         leftmostGlyph += m_complexTextRuns[m_currentRun++]->glyphCount();
    421         return m_currentRun;
    422     }
    423 
    424     m_currentRun++;
    425     leftmostGlyph = 0;
    426     return indexOfCurrentRun(leftmostGlyph);
    427 }
    428 
    429 void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer, GlyphIterationStyle iterationStyle, HashSet<const SimpleFontData*>* fallbackFonts)
    430 {
    431     if (static_cast<int>(offset) > m_end)
    432         offset = m_end;
    433 
    434     if (offset <= m_currentCharacter) {
    435         m_runWidthSoFar = m_leadingExpansion;
    436         m_numGlyphsSoFar = 0;
    437         m_currentRun = 0;
    438         m_glyphInCurrentRun = 0;
    439         m_characterInCurrentGlyph = 0;
    440     }
    441 
    442     m_currentCharacter = offset;
    443 
    444     size_t runCount = m_complexTextRuns.size();
    445 
    446     unsigned leftmostGlyph = 0;
    447     unsigned currentRunIndex = indexOfCurrentRun(leftmostGlyph);
    448     while (m_currentRun < runCount) {
    449         const ComplexTextRun& complexTextRun = *m_complexTextRuns[currentRunIndex];
    450         bool ltr = complexTextRun.isLTR();
    451         size_t glyphCount = complexTextRun.glyphCount();
    452         unsigned g = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun;
    453         unsigned k = leftmostGlyph + g;
    454         if (fallbackFonts && complexTextRun.fontData() != m_font.primaryFont())
    455             fallbackFonts->add(complexTextRun.fontData());
    456 
    457         while (m_glyphInCurrentRun < glyphCount) {
    458             unsigned glyphStartOffset = complexTextRun.indexAt(g);
    459             unsigned glyphEndOffset;
    460             if (complexTextRun.isMonotonic()) {
    461                 if (ltr)
    462                     glyphEndOffset = max<unsigned>(glyphStartOffset, static_cast<unsigned>(g + 1 < glyphCount ? complexTextRun.indexAt(g + 1) : complexTextRun.indexEnd()));
    463                 else
    464                     glyphEndOffset = max<unsigned>(glyphStartOffset, static_cast<unsigned>(g > 0 ? complexTextRun.indexAt(g - 1) : complexTextRun.indexEnd()));
    465             } else
    466                 glyphEndOffset = complexTextRun.endOffsetAt(g);
    467 
    468             CGSize adjustedAdvance = m_adjustedAdvances[k];
    469 
    470             if (glyphStartOffset + complexTextRun.stringLocation() >= m_currentCharacter)
    471                 return;
    472 
    473             if (glyphBuffer && !m_characterInCurrentGlyph)
    474                 glyphBuffer->add(m_adjustedGlyphs[k], complexTextRun.fontData(), FloatSize(adjustedAdvance));
    475 
    476             unsigned oldCharacterInCurrentGlyph = m_characterInCurrentGlyph;
    477             m_characterInCurrentGlyph = min(m_currentCharacter - complexTextRun.stringLocation(), glyphEndOffset) - glyphStartOffset;
    478             // FIXME: Instead of dividing the glyph's advance equally between the characters, this
    479             // could use the glyph's "ligature carets". However, there is no Core Text API to get the
    480             // ligature carets.
    481             if (glyphStartOffset == glyphEndOffset) {
    482                 // When there are multiple glyphs per character we need to advance by the full width of the glyph.
    483                 ASSERT(m_characterInCurrentGlyph == oldCharacterInCurrentGlyph);
    484                 m_runWidthSoFar += adjustedAdvance.width;
    485             } else if (iterationStyle == ByWholeGlyphs) {
    486                 if (!oldCharacterInCurrentGlyph)
    487                     m_runWidthSoFar += adjustedAdvance.width;
    488             } else
    489                 m_runWidthSoFar += adjustedAdvance.width * (m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset);
    490 
    491             if (glyphEndOffset + complexTextRun.stringLocation() > m_currentCharacter)
    492                 return;
    493 
    494             m_numGlyphsSoFar++;
    495             m_glyphInCurrentRun++;
    496             m_characterInCurrentGlyph = 0;
    497             if (ltr) {
    498                 g++;
    499                 k++;
    500             } else {
    501                 g--;
    502                 k--;
    503             }
    504         }
    505         currentRunIndex = incrementCurrentRun(leftmostGlyph);
    506         m_glyphInCurrentRun = 0;
    507     }
    508     if (!m_run.ltr() && m_numGlyphsSoFar == m_adjustedAdvances.size())
    509         m_runWidthSoFar += m_finalRoundingWidth;
    510 }
    511 
    512 void ComplexTextController::adjustGlyphsAndAdvances()
    513 {
    514     CGFloat widthSinceLastCommit = 0;
    515     size_t runCount = m_complexTextRuns.size();
    516     bool hasExtraSpacing = (m_font.fontDescription().letterSpacing() || m_font.fontDescription().wordSpacing() || m_expansion) && !m_run.spacingDisabled();
    517     for (size_t r = 0; r < runCount; ++r) {
    518         ComplexTextRun& complexTextRun = *m_complexTextRuns[r];
    519         unsigned glyphCount = complexTextRun.glyphCount();
    520         const SimpleFontData* fontData = complexTextRun.fontData();
    521 
    522         if (!complexTextRun.isLTR())
    523             m_isLTROnly = false;
    524 
    525         const CGGlyph* glyphs = complexTextRun.glyphs();
    526         const CGSize* advances = complexTextRun.advances();
    527 
    528         bool lastRun = r + 1 == runCount;
    529         bool roundsAdvances = fontData->platformData().roundsGlyphAdvances();
    530         float spaceWidth = fontData->spaceWidth() - fontData->syntheticBoldOffset();
    531         CGFloat roundedSpaceWidth = roundCGFloat(spaceWidth);
    532         const UChar* cp = complexTextRun.characters();
    533         CGPoint glyphOrigin = CGPointZero;
    534         CFIndex lastCharacterIndex = m_run.ltr() ? numeric_limits<CFIndex>::min() : numeric_limits<CFIndex>::max();
    535         bool isMonotonic = true;
    536 
    537         for (unsigned i = 0; i < glyphCount; i++) {
    538             CFIndex characterIndex = complexTextRun.indexAt(i);
    539             if (m_run.ltr()) {
    540                 if (characterIndex < lastCharacterIndex)
    541                     isMonotonic = false;
    542             } else {
    543                 if (characterIndex > lastCharacterIndex)
    544                     isMonotonic = false;
    545             }
    546             UChar ch = *(cp + characterIndex);
    547             bool lastGlyph = lastRun && i + 1 == glyphCount;
    548             UChar nextCh;
    549             if (lastGlyph)
    550                 nextCh = ' ';
    551             else if (i + 1 < glyphCount)
    552                 nextCh = *(cp + complexTextRun.indexAt(i + 1));
    553             else
    554                 nextCh = *(m_complexTextRuns[r + 1]->characters() + m_complexTextRuns[r + 1]->indexAt(0));
    555 
    556             bool treatAsSpace = Character::treatAsSpace(ch);
    557             CGGlyph glyph = treatAsSpace ? fontData->spaceGlyph() : glyphs[i];
    558             CGSize advance = treatAsSpace ? CGSizeMake(spaceWidth, advances[i].height) : advances[i];
    559 
    560             if (ch == '\t' && m_run.allowTabs()) {
    561                 advance.width = m_font.tabWidth(*fontData, m_run.tabSize(), m_run.xPos() + m_totalWidth + widthSinceLastCommit);
    562             } else if (Character::treatAsZeroWidthSpace(ch) && !treatAsSpace) {
    563                 advance.width = 0;
    564                 glyph = fontData->spaceGlyph();
    565             }
    566 
    567             float roundedAdvanceWidth = roundf(advance.width);
    568             if (roundsAdvances)
    569                 advance.width = roundedAdvanceWidth;
    570 
    571             advance.width += fontData->syntheticBoldOffset();
    572 
    573 
    574             // We special case spaces in two ways when applying word rounding.
    575             // First, we round spaces to an adjusted width in all fonts.
    576             // Second, in fixed-pitch fonts we ensure that all glyphs that
    577             // match the width of the space glyph have the same width as the space glyph.
    578             if (m_run.applyWordRounding() && roundedAdvanceWidth == roundedSpaceWidth && (fontData->pitch() == FixedPitch || glyph == fontData->spaceGlyph()))
    579                 advance.width = fontData->adjustedSpaceWidth();
    580 
    581             if (hasExtraSpacing) {
    582                 // If we're a glyph with an advance, go ahead and add in letter-spacing.
    583                 // That way we weed out zero width lurkers.  This behavior matches the fast text code path.
    584                 if (advance.width && m_font.fontDescription().letterSpacing())
    585                     advance.width += m_font.fontDescription().letterSpacing();
    586 
    587                 // Handle justification and word-spacing.
    588                 if (treatAsSpace || Character::isCJKIdeographOrSymbol(ch)) {
    589                     // Distribute the run's total expansion evenly over all expansion opportunities in the run.
    590                     if (m_expansion) {
    591                         float previousExpansion = m_expansion;
    592                         if (!treatAsSpace && !m_afterExpansion) {
    593                             // Take the expansion opportunity before this ideograph.
    594                             m_expansion -= m_expansionPerOpportunity;
    595                             float expansionAtThisOpportunity = !m_run.applyWordRounding() ? m_expansionPerOpportunity : roundf(previousExpansion) - roundf(m_expansion);
    596                             m_totalWidth += expansionAtThisOpportunity;
    597                             if (m_adjustedAdvances.isEmpty())
    598                                 m_leadingExpansion = expansionAtThisOpportunity;
    599                             else
    600                                 m_adjustedAdvances.last().width += expansionAtThisOpportunity;
    601                             previousExpansion = m_expansion;
    602                         }
    603                         if (!lastGlyph || m_run.allowsTrailingExpansion()) {
    604                             m_expansion -= m_expansionPerOpportunity;
    605                             advance.width += !m_run.applyWordRounding() ? m_expansionPerOpportunity : roundf(previousExpansion) - roundf(m_expansion);
    606                             m_afterExpansion = true;
    607                         }
    608                     } else
    609                         m_afterExpansion = false;
    610 
    611                     // Account for word-spacing.
    612                     if (treatAsSpace && (ch != '\t' || !m_run.allowTabs()) && (characterIndex > 0 || r > 0) && m_font.fontDescription().wordSpacing())
    613                         advance.width += m_font.fontDescription().wordSpacing();
    614                 } else
    615                     m_afterExpansion = false;
    616             }
    617 
    618             // Apply rounding hacks if needed.
    619             // We adjust the width of the last character of a "word" to ensure an integer width.
    620             // Force characters that are used to determine word boundaries for the rounding hack
    621             // to be integer width, so the following words will start on an integer boundary.
    622             if (m_run.applyWordRounding() && Character::isRoundingHackCharacter(ch))
    623                 advance.width = ceilCGFloat(advance.width);
    624 
    625             // Check to see if the next character is a "rounding hack character", if so, adjust the
    626             // width so that the total run width will be on an integer boundary.
    627             if ((m_run.applyWordRounding() && !lastGlyph && Character::isRoundingHackCharacter(nextCh)) || (m_run.applyRunRounding() && lastGlyph)) {
    628                 CGFloat totalWidth = widthSinceLastCommit + advance.width;
    629                 widthSinceLastCommit = ceilCGFloat(totalWidth);
    630                 CGFloat extraWidth = widthSinceLastCommit - totalWidth;
    631                 if (m_run.ltr())
    632                     advance.width += extraWidth;
    633                 else {
    634                     if (m_lastRoundingGlyph)
    635                         m_adjustedAdvances[m_lastRoundingGlyph - 1].width += extraWidth;
    636                     else
    637                         m_finalRoundingWidth = extraWidth;
    638                     m_lastRoundingGlyph = m_adjustedAdvances.size() + 1;
    639                 }
    640                 m_totalWidth += widthSinceLastCommit;
    641                 widthSinceLastCommit = 0;
    642             } else
    643                 widthSinceLastCommit += advance.width;
    644 
    645             // FIXME: Combining marks should receive a text emphasis mark if they are combine with a space.
    646             if (m_forTextEmphasis && (!Character::canReceiveTextEmphasis(ch) || (U_GET_GC_MASK(ch) & U_GC_M_MASK)))
    647                 glyph = 0;
    648 
    649             advance.height *= -1;
    650             m_adjustedAdvances.append(advance);
    651             m_adjustedGlyphs.append(glyph);
    652 
    653             FloatRect glyphBounds = fontData->boundsForGlyph(glyph);
    654             glyphBounds.move(glyphOrigin.x, glyphOrigin.y);
    655             m_minGlyphBoundingBoxX = min(m_minGlyphBoundingBoxX, glyphBounds.x());
    656             m_maxGlyphBoundingBoxX = max(m_maxGlyphBoundingBoxX, glyphBounds.maxX());
    657             m_minGlyphBoundingBoxY = min(m_minGlyphBoundingBoxY, glyphBounds.y());
    658             m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, glyphBounds.maxY());
    659             glyphOrigin.x += advance.width;
    660             glyphOrigin.y += advance.height;
    661 
    662             lastCharacterIndex = characterIndex;
    663         }
    664         if (!isMonotonic)
    665             complexTextRun.setIsNonMonotonic();
    666     }
    667     m_totalWidth += widthSinceLastCommit;
    668 }
    669 
    670 } // namespace WebCore
    671