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 "ComplexTextController.h"
27
28#include "FloatSize.h"
29#include "Font.h"
30#include "RenderBlock.h"
31#include "RenderText.h"
32#include "TextBreakIterator.h"
33#include "TextRun.h"
34#if !PLATFORM(IOS)
35#include <ApplicationServices/ApplicationServices.h>
36#else
37#include <CoreText/CoreText.h>
38#endif
39#include <wtf/StdLibExtras.h>
40#include <wtf/unicode/CharacterNames.h>
41
42namespace WebCore {
43
44class TextLayout {
45public:
46    static bool isNeeded(RenderText* text, const Font& font)
47    {
48        TextRun run = RenderBlock::constructTextRun(text, font, text, text->style());
49        return font.codePath(run) == Font::Complex;
50    }
51
52    TextLayout(RenderText* text, const Font& font, float xPos)
53        : m_font(font)
54        , m_run(constructTextRun(text, font, xPos))
55        , m_controller(adoptPtr(new ComplexTextController(&m_font, m_run, true)))
56    {
57    }
58
59    float width(unsigned from, unsigned len, HashSet<const SimpleFontData*>* fallbackFonts)
60    {
61        m_controller->advance(from, 0, ByWholeGlyphs, fallbackFonts);
62        float beforeWidth = m_controller->runWidthSoFar();
63        if (m_font.wordSpacing() && from && Font::treatAsSpace(m_run[from]))
64            beforeWidth += m_font.wordSpacing();
65        m_controller->advance(from + len, 0, ByWholeGlyphs, fallbackFonts);
66        float afterWidth = m_controller->runWidthSoFar();
67        return afterWidth - beforeWidth;
68    }
69
70private:
71    static TextRun constructTextRun(RenderText* text, const Font& font, float xPos)
72    {
73        TextRun run = RenderBlock::constructTextRun(text, font, text, text->style());
74        run.setCharactersLength(text->textLength());
75        ASSERT(run.charactersLength() >= run.length());
76
77        run.setXPos(xPos);
78        return run;
79    }
80
81    // ComplexTextController has only references to its Font and TextRun so they must be kept alive here.
82    Font m_font;
83    TextRun m_run;
84    OwnPtr<ComplexTextController> m_controller;
85};
86
87PassOwnPtr<TextLayout> Font::createLayout(RenderText* text, float xPos, bool collapseWhiteSpace) const
88{
89    if (!collapseWhiteSpace || !TextLayout::isNeeded(text, *this))
90        return nullptr;
91    return adoptPtr(new TextLayout(text, *this, xPos));
92}
93
94void Font::deleteLayout(TextLayout* layout)
95{
96    delete layout;
97}
98
99float Font::width(TextLayout& layout, unsigned from, unsigned len, HashSet<const SimpleFontData*>* fallbackFonts)
100{
101    return layout.width(from, len, fallbackFonts);
102}
103
104static inline CGFloat roundCGFloat(CGFloat f)
105{
106    if (sizeof(CGFloat) == sizeof(float))
107        return roundf(static_cast<float>(f));
108    return static_cast<CGFloat>(round(f));
109}
110
111static inline CGFloat ceilCGFloat(CGFloat f)
112{
113    if (sizeof(CGFloat) == sizeof(float))
114        return ceilf(static_cast<float>(f));
115    return static_cast<CGFloat>(ceil(f));
116}
117
118ComplexTextController::ComplexTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts, bool forTextEmphasis)
119    : m_font(*font)
120    , m_run(run)
121    , m_isLTROnly(true)
122    , m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection)
123    , m_forTextEmphasis(forTextEmphasis)
124    , m_currentCharacter(0)
125    , m_end(run.length())
126    , m_totalWidth(0)
127    , m_runWidthSoFar(0)
128    , m_numGlyphsSoFar(0)
129    , m_currentRun(0)
130    , m_glyphInCurrentRun(0)
131    , m_characterInCurrentGlyph(0)
132    , m_finalRoundingWidth(0)
133    , m_expansion(run.expansion())
134    , m_leadingExpansion(0)
135    , m_afterExpansion(!run.allowsLeadingExpansion())
136    , m_fallbackFonts(fallbackFonts)
137    , m_minGlyphBoundingBoxX(std::numeric_limits<float>::max())
138    , m_maxGlyphBoundingBoxX(std::numeric_limits<float>::min())
139    , m_minGlyphBoundingBoxY(std::numeric_limits<float>::max())
140    , m_maxGlyphBoundingBoxY(std::numeric_limits<float>::min())
141    , m_lastRoundingGlyph(0)
142{
143    if (!m_expansion)
144        m_expansionPerOpportunity = 0;
145    else {
146        bool isAfterExpansion = m_afterExpansion;
147        unsigned expansionOpportunityCount;
148        if (m_run.is8Bit())
149            expansionOpportunityCount = Font::expansionOpportunityCount(m_run.characters8(), m_end, m_run.ltr() ? LTR : RTL, isAfterExpansion);
150         else
151             expansionOpportunityCount = Font::expansionOpportunityCount(m_run.characters16(), m_end, m_run.ltr() ? LTR : RTL, isAfterExpansion);
152        if (isAfterExpansion && !m_run.allowsTrailingExpansion())
153            expansionOpportunityCount--;
154
155        if (!expansionOpportunityCount)
156            m_expansionPerOpportunity = 0;
157        else
158            m_expansionPerOpportunity = m_expansion / expansionOpportunityCount;
159    }
160
161    collectComplexTextRuns();
162    adjustGlyphsAndAdvances();
163
164    if (!m_isLTROnly) {
165        m_runIndices.reserveInitialCapacity(m_complexTextRuns.size());
166
167        m_glyphCountFromStartToIndex.reserveInitialCapacity(m_complexTextRuns.size());
168        unsigned glyphCountSoFar = 0;
169        for (unsigned i = 0; i < m_complexTextRuns.size(); ++i) {
170            m_glyphCountFromStartToIndex.uncheckedAppend(glyphCountSoFar);
171            glyphCountSoFar += m_complexTextRuns[i]->glyphCount();
172        }
173    }
174
175    m_runWidthSoFar = m_leadingExpansion;
176}
177
178int ComplexTextController::offsetForPosition(float h, bool includePartialGlyphs)
179{
180    if (h >= m_totalWidth)
181        return m_run.ltr() ? m_end : 0;
182
183    h -= m_leadingExpansion;
184    if (h < 0)
185        return m_run.ltr() ? 0 : m_end;
186
187    CGFloat x = h;
188
189    size_t runCount = m_complexTextRuns.size();
190    size_t offsetIntoAdjustedGlyphs = 0;
191
192    for (size_t r = 0; r < runCount; ++r) {
193        const ComplexTextRun& complexTextRun = *m_complexTextRuns[r];
194        for (unsigned j = 0; j < complexTextRun.glyphCount(); ++j) {
195            size_t index = offsetIntoAdjustedGlyphs + j;
196            CGFloat adjustedAdvance = m_adjustedAdvances[index].width;
197            if (!index)
198                adjustedAdvance += complexTextRun.initialAdvance().width;
199            if (x < adjustedAdvance) {
200                CFIndex hitGlyphStart = complexTextRun.indexAt(j);
201                CFIndex hitGlyphEnd;
202                if (m_run.ltr())
203                    hitGlyphEnd = std::max<CFIndex>(hitGlyphStart, j + 1 < complexTextRun.glyphCount() ? complexTextRun.indexAt(j + 1) : static_cast<CFIndex>(complexTextRun.indexEnd()));
204                else
205                    hitGlyphEnd = std::max<CFIndex>(hitGlyphStart, j > 0 ? complexTextRun.indexAt(j - 1) : static_cast<CFIndex>(complexTextRun.indexEnd()));
206
207                // FIXME: Instead of dividing the glyph's advance equally between the characters, this
208                // could use the glyph's "ligature carets". However, there is no Core Text API to get the
209                // ligature carets.
210                CFIndex hitIndex = hitGlyphStart + (hitGlyphEnd - hitGlyphStart) * (m_run.ltr() ? x / adjustedAdvance : 1 - x / adjustedAdvance);
211                int stringLength = complexTextRun.stringLength();
212                TextBreakIterator* cursorPositionIterator = cursorMovementIterator(StringView(complexTextRun.characters(), stringLength));
213                int clusterStart;
214                if (isTextBreak(cursorPositionIterator, hitIndex))
215                    clusterStart = hitIndex;
216                else {
217                    clusterStart = textBreakPreceding(cursorPositionIterator, hitIndex);
218                    if (clusterStart == TextBreakDone)
219                        clusterStart = 0;
220                }
221
222                if (!includePartialGlyphs)
223                    return complexTextRun.stringLocation() + clusterStart;
224
225                int clusterEnd = textBreakFollowing(cursorPositionIterator, hitIndex);
226                if (clusterEnd == TextBreakDone)
227                    clusterEnd = stringLength;
228
229                CGFloat clusterWidth;
230                // FIXME: The search stops at the boundaries of complexTextRun. In theory, it should go on into neighboring ComplexTextRuns
231                // derived from the same CTLine. In practice, we do not expect there to be more than one CTRun in a CTLine, as no
232                // reordering and no font fallback should occur within a CTLine.
233                if (clusterEnd - clusterStart > 1) {
234                    clusterWidth = adjustedAdvance;
235                    int firstGlyphBeforeCluster = j - 1;
236                    while (firstGlyphBeforeCluster >= 0 && complexTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) {
237                        CGFloat width = m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width;
238                        clusterWidth += width;
239                        x += width;
240                        firstGlyphBeforeCluster--;
241                    }
242                    unsigned firstGlyphAfterCluster = j + 1;
243                    while (firstGlyphAfterCluster < complexTextRun.glyphCount() && complexTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) {
244                        clusterWidth += m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphAfterCluster].width;
245                        firstGlyphAfterCluster++;
246                    }
247                } else {
248                    clusterWidth = adjustedAdvance / (hitGlyphEnd - hitGlyphStart);
249                    x -=  clusterWidth * (m_run.ltr() ? hitIndex - hitGlyphStart : hitGlyphEnd - hitIndex - 1);
250                }
251                if (x <= clusterWidth / 2)
252                    return complexTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd);
253                else
254                    return complexTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart);
255            }
256            x -= adjustedAdvance;
257        }
258        offsetIntoAdjustedGlyphs += complexTextRun.glyphCount();
259    }
260
261    ASSERT_NOT_REACHED();
262    return 0;
263}
264
265static bool advanceByCombiningCharacterSequence(const UChar*& iterator, const UChar* end, UChar32& baseCharacter, unsigned& markCount)
266{
267    ASSERT(iterator < end);
268
269    markCount = 0;
270
271    unsigned i = 0;
272    unsigned remainingCharacters = end - iterator;
273    U16_NEXT(iterator, i, remainingCharacters, baseCharacter);
274    iterator = iterator + i;
275
276    if (U_IS_SURROGATE(baseCharacter))
277        return false;
278
279    // Consume marks.
280    while (iterator < end) {
281        UChar32 nextCharacter;
282        int markLength = 0;
283        U16_NEXT(iterator, markLength, end - iterator, nextCharacter);
284        if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK))
285            break;
286        markCount += markLength;
287        iterator += markLength;
288    }
289
290    return true;
291}
292
293void ComplexTextController::collectComplexTextRuns()
294{
295    if (!m_end)
296        return;
297
298    // We break up glyph run generation for the string by FontData.
299    const UChar* cp;
300
301    if (m_run.is8Bit()) {
302        String stringFor8BitRun = String::make16BitFrom8BitSource(m_run.characters8(), m_run.length());
303        cp = stringFor8BitRun.characters16();
304        m_stringsFor8BitRuns.append(stringFor8BitRun);
305    } else
306        cp = m_run.characters16();
307
308    if (m_font.isSmallCaps())
309        m_smallCapsBuffer.resize(m_end);
310
311    unsigned indexOfFontTransition = 0;
312    const UChar* curr = cp;
313    const UChar* end = cp + m_end;
314
315    const SimpleFontData* fontData;
316    bool isMissingGlyph;
317    const SimpleFontData* nextFontData;
318    bool nextIsMissingGlyph;
319
320    unsigned markCount;
321    const UChar* sequenceStart = curr;
322    UChar32 baseCharacter;
323    if (!advanceByCombiningCharacterSequence(curr, end, baseCharacter, markCount))
324        return;
325
326    UChar uppercaseCharacter = 0;
327
328    bool isSmallCaps;
329    bool nextIsSmallCaps = m_font.isSmallCaps() && !(U_GET_GC_MASK(baseCharacter) & U_GC_M_MASK) && (uppercaseCharacter = u_toupper(baseCharacter)) != baseCharacter;
330    ASSERT(uppercaseCharacter == 0 || u_toupper(baseCharacter) <= 0xFFFF);
331
332    if (nextIsSmallCaps) {
333        m_smallCapsBuffer[sequenceStart - cp] = uppercaseCharacter;
334        for (unsigned i = 0; i < markCount; ++i)
335            m_smallCapsBuffer[sequenceStart - cp + i + 1] = sequenceStart[i + 1];
336    }
337
338    nextIsMissingGlyph = false;
339    nextFontData = m_font.fontDataForCombiningCharacterSequence(sequenceStart, curr - sequenceStart, nextIsSmallCaps ? SmallCapsVariant : NormalVariant);
340    if (!nextFontData)
341        nextIsMissingGlyph = true;
342
343    while (curr < end) {
344        fontData = nextFontData;
345        isMissingGlyph = nextIsMissingGlyph;
346        isSmallCaps = nextIsSmallCaps;
347        int index = curr - cp;
348
349        if (!advanceByCombiningCharacterSequence(curr, end, baseCharacter, markCount))
350            return;
351
352        if (m_font.isSmallCaps()) {
353            ASSERT(u_toupper(baseCharacter) <= 0xFFFF);
354            uppercaseCharacter = u_toupper(baseCharacter);
355            nextIsSmallCaps = uppercaseCharacter != baseCharacter;
356            if (nextIsSmallCaps) {
357                m_smallCapsBuffer[index] = uppercaseCharacter;
358                for (unsigned i = 0; i < markCount; ++i)
359                    m_smallCapsBuffer[index + i + 1] = cp[index + i + 1];
360            }
361        }
362
363        nextIsMissingGlyph = false;
364        if (baseCharacter == zeroWidthJoiner)
365            nextFontData = fontData;
366        else {
367            nextFontData = m_font.fontDataForCombiningCharacterSequence(cp + index, curr - cp - index, nextIsSmallCaps ? SmallCapsVariant : NormalVariant);
368            if (!nextFontData)
369                nextIsMissingGlyph = true;
370        }
371
372        if (nextFontData != fontData || nextIsMissingGlyph != isMissingGlyph) {
373            int itemStart = static_cast<int>(indexOfFontTransition);
374            int itemLength = index - indexOfFontTransition;
375            collectComplexTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, !isMissingGlyph ? fontData : 0);
376            indexOfFontTransition = index;
377        }
378    }
379
380    int itemLength = m_end - indexOfFontTransition;
381    if (itemLength) {
382        int itemStart = indexOfFontTransition;
383        collectComplexTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, !nextIsMissingGlyph ? nextFontData : 0);
384    }
385
386    if (!m_run.ltr())
387        m_complexTextRuns.reverse();
388}
389
390CFIndex ComplexTextController::ComplexTextRun::indexAt(size_t i) const
391{
392    ASSERT(i < m_glyphCount);
393
394    return m_coreTextIndices[i];
395}
396
397void ComplexTextController::ComplexTextRun::setIsNonMonotonic()
398{
399    ASSERT(m_isMonotonic);
400    m_isMonotonic = false;
401
402    Vector<bool, 64> mappedIndices(m_stringLength);
403    for (size_t i = 0; i < m_glyphCount; ++i) {
404        ASSERT(indexAt(i) < static_cast<CFIndex>(m_stringLength));
405        mappedIndices[indexAt(i)] = true;
406    }
407
408    m_glyphEndOffsets.grow(m_glyphCount);
409    for (size_t i = 0; i < m_glyphCount; ++i) {
410        CFIndex nextMappedIndex = m_indexEnd;
411        for (size_t j = indexAt(i) + 1; j < m_stringLength; ++j) {
412            if (mappedIndices[j]) {
413                nextMappedIndex = j;
414                break;
415            }
416        }
417        m_glyphEndOffsets[i] = nextMappedIndex;
418    }
419}
420
421unsigned ComplexTextController::indexOfCurrentRun(unsigned& leftmostGlyph)
422{
423    leftmostGlyph = 0;
424
425    size_t runCount = m_complexTextRuns.size();
426    if (m_currentRun >= runCount)
427        return runCount;
428
429    if (m_isLTROnly) {
430        for (unsigned i = 0; i < m_currentRun; ++i)
431            leftmostGlyph += m_complexTextRuns[i]->glyphCount();
432        return m_currentRun;
433    }
434
435    if (m_runIndices.isEmpty()) {
436        unsigned firstRun = 0;
437        unsigned firstRunOffset = stringBegin(*m_complexTextRuns[0]);
438        for (unsigned i = 1; i < runCount; ++i) {
439            unsigned offset = stringBegin(*m_complexTextRuns[i]);
440            if (offset < firstRunOffset) {
441                firstRun = i;
442                firstRunOffset = offset;
443            }
444        }
445        m_runIndices.uncheckedAppend(firstRun);
446    }
447
448    while (m_runIndices.size() <= m_currentRun) {
449        unsigned offset = stringEnd(*m_complexTextRuns[m_runIndices.last()]);
450
451        for (unsigned i = 0; i < runCount; ++i) {
452            if (offset == stringBegin(*m_complexTextRuns[i])) {
453                m_runIndices.uncheckedAppend(i);
454                break;
455            }
456        }
457    }
458
459    unsigned currentRunIndex = m_runIndices[m_currentRun];
460    leftmostGlyph = m_glyphCountFromStartToIndex[currentRunIndex];
461    return currentRunIndex;
462}
463
464unsigned ComplexTextController::incrementCurrentRun(unsigned& leftmostGlyph)
465{
466    if (m_isLTROnly) {
467        leftmostGlyph += m_complexTextRuns[m_currentRun++]->glyphCount();
468        return m_currentRun;
469    }
470
471    m_currentRun++;
472    leftmostGlyph = 0;
473    return indexOfCurrentRun(leftmostGlyph);
474}
475
476void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer, GlyphIterationStyle iterationStyle, HashSet<const SimpleFontData*>* fallbackFonts)
477{
478    if (static_cast<int>(offset) > m_end)
479        offset = m_end;
480
481    if (offset <= m_currentCharacter) {
482        m_runWidthSoFar = m_leadingExpansion;
483        m_numGlyphsSoFar = 0;
484        m_currentRun = 0;
485        m_glyphInCurrentRun = 0;
486        m_characterInCurrentGlyph = 0;
487    }
488
489    m_currentCharacter = offset;
490
491    size_t runCount = m_complexTextRuns.size();
492
493    unsigned leftmostGlyph = 0;
494    unsigned currentRunIndex = indexOfCurrentRun(leftmostGlyph);
495    while (m_currentRun < runCount) {
496        const ComplexTextRun& complexTextRun = *m_complexTextRuns[currentRunIndex];
497        bool ltr = complexTextRun.isLTR();
498        size_t glyphCount = complexTextRun.glyphCount();
499        unsigned g = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun;
500        unsigned k = leftmostGlyph + g;
501        if (fallbackFonts && complexTextRun.fontData() != m_font.primaryFont())
502            fallbackFonts->add(complexTextRun.fontData());
503
504        // We must store the initial advance for the first glyph we are going to draw.
505        // When leftmostGlyph is 0, it represents the first glyph to draw, taking into
506        // account the text direction.
507        if (glyphBuffer && !leftmostGlyph)
508            glyphBuffer->setInitialAdvance(complexTextRun.initialAdvance());
509
510        while (m_glyphInCurrentRun < glyphCount) {
511            unsigned glyphStartOffset = complexTextRun.indexAt(g);
512            unsigned glyphEndOffset;
513            if (complexTextRun.isMonotonic()) {
514                if (ltr)
515                    glyphEndOffset = std::max<unsigned>(glyphStartOffset, static_cast<unsigned>(g + 1 < glyphCount ? complexTextRun.indexAt(g + 1) : complexTextRun.indexEnd()));
516                else
517                    glyphEndOffset = std::max<unsigned>(glyphStartOffset, static_cast<unsigned>(g > 0 ? complexTextRun.indexAt(g - 1) : complexTextRun.indexEnd()));
518            } else
519                glyphEndOffset = complexTextRun.endOffsetAt(g);
520
521            CGSize adjustedAdvance = m_adjustedAdvances[k];
522
523            if (glyphStartOffset + complexTextRun.stringLocation() >= m_currentCharacter)
524                return;
525
526            if (glyphBuffer && !m_characterInCurrentGlyph)
527                glyphBuffer->add(m_adjustedGlyphs[k], complexTextRun.fontData(), adjustedAdvance, complexTextRun.indexAt(m_glyphInCurrentRun));
528
529            unsigned oldCharacterInCurrentGlyph = m_characterInCurrentGlyph;
530            m_characterInCurrentGlyph = std::min(m_currentCharacter - complexTextRun.stringLocation(), glyphEndOffset) - glyphStartOffset;
531            // FIXME: Instead of dividing the glyph's advance equally between the characters, this
532            // could use the glyph's "ligature carets". However, there is no Core Text API to get the
533            // ligature carets.
534            if (glyphStartOffset == glyphEndOffset) {
535                // When there are multiple glyphs per character we need to advance by the full width of the glyph.
536                ASSERT(m_characterInCurrentGlyph == oldCharacterInCurrentGlyph);
537                m_runWidthSoFar += adjustedAdvance.width;
538            } else if (iterationStyle == ByWholeGlyphs) {
539                if (!oldCharacterInCurrentGlyph)
540                    m_runWidthSoFar += adjustedAdvance.width;
541            } else
542                m_runWidthSoFar += adjustedAdvance.width * (m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset);
543
544            if (glyphEndOffset + complexTextRun.stringLocation() > m_currentCharacter)
545                return;
546
547            m_numGlyphsSoFar++;
548            m_glyphInCurrentRun++;
549            m_characterInCurrentGlyph = 0;
550            if (ltr) {
551                g++;
552                k++;
553            } else {
554                g--;
555                k--;
556            }
557        }
558        currentRunIndex = incrementCurrentRun(leftmostGlyph);
559        m_glyphInCurrentRun = 0;
560    }
561    if (!m_run.ltr() && m_numGlyphsSoFar == m_adjustedAdvances.size())
562        m_runWidthSoFar += m_finalRoundingWidth;
563}
564
565void ComplexTextController::adjustGlyphsAndAdvances()
566{
567    CGFloat widthSinceLastCommit = 0;
568    size_t runCount = m_complexTextRuns.size();
569    bool hasExtraSpacing = (m_font.letterSpacing() || m_font.wordSpacing() || m_expansion) && !m_run.spacingDisabled();
570    for (size_t r = 0; r < runCount; ++r) {
571        ComplexTextRun& complexTextRun = *m_complexTextRuns[r];
572        unsigned glyphCount = complexTextRun.glyphCount();
573        const SimpleFontData* fontData = complexTextRun.fontData();
574#if PLATFORM(IOS)
575        bool isEmoji = fontData->platformData().m_isEmoji;
576#endif
577
578        // Represent the initial advance for a text run by adjusting the advance
579        // of the last glyph of the previous text run in the glyph buffer.
580        if (r && m_adjustedAdvances.size()) {
581            CGSize previousAdvance = m_adjustedAdvances.last();
582            previousAdvance.width += complexTextRun.initialAdvance().width;
583            previousAdvance.height -= complexTextRun.initialAdvance().height;
584            m_adjustedAdvances[m_adjustedAdvances.size() - 1] = previousAdvance;
585        }
586        widthSinceLastCommit += complexTextRun.initialAdvance().width;
587
588        if (!complexTextRun.isLTR())
589            m_isLTROnly = false;
590
591        const CGGlyph* glyphs = complexTextRun.glyphs();
592        const CGSize* advances = complexTextRun.advances();
593
594        bool lastRun = r + 1 == runCount;
595        bool roundsAdvances = !m_font.isPrinterFont() && fontData->platformData().roundsGlyphAdvances();
596        float spaceWidth = fontData->spaceWidth() - fontData->syntheticBoldOffset();
597        CGFloat roundedSpaceWidth = roundCGFloat(spaceWidth);
598        const UChar* cp = complexTextRun.characters();
599        CGPoint glyphOrigin = CGPointZero;
600        CFIndex lastCharacterIndex = m_run.ltr() ? std::numeric_limits<CFIndex>::min() : std::numeric_limits<CFIndex>::max();
601        bool isMonotonic = true;
602
603        for (unsigned i = 0; i < glyphCount; i++) {
604            CFIndex characterIndex = complexTextRun.indexAt(i);
605            if (m_run.ltr()) {
606                if (characterIndex < lastCharacterIndex)
607                    isMonotonic = false;
608            } else {
609                if (characterIndex > lastCharacterIndex)
610                    isMonotonic = false;
611            }
612            UChar ch = *(cp + characterIndex);
613            bool lastGlyph = lastRun && i + 1 == glyphCount;
614            UChar nextCh;
615            if (lastGlyph)
616                nextCh = ' ';
617            else if (i + 1 < glyphCount)
618                nextCh = *(cp + complexTextRun.indexAt(i + 1));
619            else
620                nextCh = *(m_complexTextRuns[r + 1]->characters() + m_complexTextRuns[r + 1]->indexAt(0));
621
622            bool treatAsSpace = Font::treatAsSpace(ch);
623            CGGlyph glyph = treatAsSpace ? fontData->spaceGlyph() : glyphs[i];
624            CGSize advance = treatAsSpace ? CGSizeMake(spaceWidth, advances[i].height) : advances[i];
625#if PLATFORM(IOS)
626            if (isEmoji && advance.width)
627                advance.width = fontData->widthForGlyph(glyph);
628#endif
629
630            if (ch == '\t' && m_run.allowTabs())
631                advance.width = m_font.tabWidth(*fontData, m_run.tabSize(), m_run.xPos() + m_totalWidth + widthSinceLastCommit);
632            else if (Font::treatAsZeroWidthSpace(ch) && !treatAsSpace) {
633                advance.width = 0;
634                glyph = fontData->spaceGlyph();
635            }
636
637            float roundedAdvanceWidth = roundf(advance.width);
638            if (roundsAdvances)
639                advance.width = roundedAdvanceWidth;
640
641            advance.width += fontData->syntheticBoldOffset();
642
643
644            // We special case spaces in two ways when applying word rounding.
645            // First, we round spaces to an adjusted width in all fonts.
646            // Second, in fixed-pitch fonts we ensure that all glyphs that
647            // match the width of the space glyph have the same width as the space glyph.
648            if (m_run.applyWordRounding() && roundedAdvanceWidth == roundedSpaceWidth && (fontData->pitch() == FixedPitch || glyph == fontData->spaceGlyph()))
649                advance.width = fontData->adjustedSpaceWidth();
650
651            if (hasExtraSpacing) {
652                // If we're a glyph with an advance, go ahead and add in letter-spacing.
653                // That way we weed out zero width lurkers.  This behavior matches the fast text code path.
654                if (advance.width && m_font.letterSpacing())
655                    advance.width += m_font.letterSpacing();
656
657                // Handle justification and word-spacing.
658                if (treatAsSpace || Font::isCJKIdeographOrSymbol(ch)) {
659                    // Distribute the run's total expansion evenly over all expansion opportunities in the run.
660                    if (m_expansion) {
661                        float previousExpansion = m_expansion;
662                        if (!treatAsSpace && !m_afterExpansion) {
663                            // Take the expansion opportunity before this ideograph.
664                            m_expansion -= m_expansionPerOpportunity;
665                            float expansionAtThisOpportunity = !m_run.applyWordRounding() ? m_expansionPerOpportunity : roundf(previousExpansion) - roundf(m_expansion);
666                            m_totalWidth += expansionAtThisOpportunity;
667                            if (m_adjustedAdvances.isEmpty())
668                                m_leadingExpansion = expansionAtThisOpportunity;
669                            else
670                                m_adjustedAdvances.last().width += expansionAtThisOpportunity;
671                            previousExpansion = m_expansion;
672                        }
673                        if (!lastGlyph || m_run.allowsTrailingExpansion()) {
674                            m_expansion -= m_expansionPerOpportunity;
675                            advance.width += !m_run.applyWordRounding() ? m_expansionPerOpportunity : roundf(previousExpansion) - roundf(m_expansion);
676                            m_afterExpansion = true;
677                        }
678                    } else
679                        m_afterExpansion = false;
680
681                    // Account for word-spacing.
682                    if (treatAsSpace && (ch != '\t' || !m_run.allowTabs()) && (characterIndex > 0 || r > 0) && m_font.wordSpacing())
683                        advance.width += m_font.wordSpacing();
684                } else
685                    m_afterExpansion = false;
686            }
687
688            // Apply rounding hacks if needed.
689            // We adjust the width of the last character of a "word" to ensure an integer width.
690            // Force characters that are used to determine word boundaries for the rounding hack
691            // to be integer width, so the following words will start on an integer boundary.
692            if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(ch))
693                advance.width = ceilCGFloat(advance.width);
694
695            // Check to see if the next character is a "rounding hack character", if so, adjust the
696            // width so that the total run width will be on an integer boundary.
697            if ((m_run.applyWordRounding() && !lastGlyph && Font::isRoundingHackCharacter(nextCh)) || (m_run.applyRunRounding() && lastGlyph)) {
698                CGFloat totalWidth = widthSinceLastCommit + advance.width;
699                widthSinceLastCommit = ceilCGFloat(totalWidth);
700                CGFloat extraWidth = widthSinceLastCommit - totalWidth;
701                if (m_run.ltr())
702                    advance.width += extraWidth;
703                else {
704                    if (m_lastRoundingGlyph)
705                        m_adjustedAdvances[m_lastRoundingGlyph - 1].width += extraWidth;
706                    else
707                        m_finalRoundingWidth = extraWidth;
708                    m_lastRoundingGlyph = m_adjustedAdvances.size() + 1;
709                }
710                m_totalWidth += widthSinceLastCommit;
711                widthSinceLastCommit = 0;
712            } else
713                widthSinceLastCommit += advance.width;
714
715            // FIXME: Combining marks should receive a text emphasis mark if they are combine with a space.
716            if (m_forTextEmphasis && (!Font::canReceiveTextEmphasis(ch) || (U_GET_GC_MASK(ch) & U_GC_M_MASK)))
717                glyph = 0;
718
719            advance.height *= -1;
720            m_adjustedAdvances.append(advance);
721            m_adjustedGlyphs.append(glyph);
722
723            FloatRect glyphBounds = fontData->boundsForGlyph(glyph);
724            glyphBounds.move(glyphOrigin.x, glyphOrigin.y);
725            m_minGlyphBoundingBoxX = std::min(m_minGlyphBoundingBoxX, glyphBounds.x());
726            m_maxGlyphBoundingBoxX = std::max(m_maxGlyphBoundingBoxX, glyphBounds.maxX());
727            m_minGlyphBoundingBoxY = std::min(m_minGlyphBoundingBoxY, glyphBounds.y());
728            m_maxGlyphBoundingBoxY = std::max(m_maxGlyphBoundingBoxY, glyphBounds.maxY());
729            glyphOrigin.x += advance.width;
730            glyphOrigin.y += advance.height;
731
732            lastCharacterIndex = characterIndex;
733        }
734        if (!isMonotonic)
735            complexTextRun.setIsNonMonotonic();
736    }
737    m_totalWidth += widthSinceLastCommit;
738}
739
740} // namespace WebCore
741