18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
22fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    documentation and/or other materials provided with the distribution.
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
13643ca7872b450ea4efacab6188849e5aac2ba161Steve Block * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14643ca7872b450ea4efacab6188849e5aac2ba161Steve Block * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15643ca7872b450ea4efacab6188849e5aac2ba161Steve Block * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16643ca7872b450ea4efacab6188849e5aac2ba161Steve Block * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17643ca7872b450ea4efacab6188849e5aac2ba161Steve Block * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18643ca7872b450ea4efacab6188849e5aac2ba161Steve Block * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19643ca7872b450ea4efacab6188849e5aac2ba161Steve Block * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20643ca7872b450ea4efacab6188849e5aac2ba161Steve Block * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21643ca7872b450ea4efacab6188849e5aac2ba161Steve Block * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22643ca7872b450ea4efacab6188849e5aac2ba161Steve Block * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
26643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#include "ComplexTextController.h"
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2821939df44de1705786c545cd1bf519d47250322dBen Murdoch#include "FloatSize.h"
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Font.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "TextBreakIterator.h"
31ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch#include "TextRun.h"
322fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include <ApplicationServices/ApplicationServices.h>
33d0825bca7fe65beaee391d30da42e937db621564Steve Block#include <wtf/StdLibExtras.h>
342fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include <wtf/unicode/CharacterNames.h>
35d0825bca7fe65beaee391d30da42e937db621564Steve Block
36d0825bca7fe65beaee391d30da42e937db621564Steve Block#if defined(BUILDING_ON_LEOPARD)
37d0825bca7fe65beaee391d30da42e937db621564Steve Block// Undefined when compiling agains the 10.5 SDK.
38d0825bca7fe65beaee391d30da42e937db621564Steve Block#define kCTVersionNumber10_6 0x00030000
39d0825bca7fe65beaee391d30da42e937db621564Steve Block#endif
40d0825bca7fe65beaee391d30da42e937db621564Steve Block
418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace std;
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline CGFloat roundCGFloat(CGFloat f)
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (sizeof(CGFloat) == sizeof(float))
488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return roundf(static_cast<float>(f));
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return static_cast<CGFloat>(round(f));
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
52f05b935882198ccf7d81675736e3aeb089c5113aBen MurdochComplexTextController::ComplexTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts, bool forTextEmphasis)
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    : m_font(*font)
548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_run(run)
558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection)
56f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    , m_forTextEmphasis(forTextEmphasis)
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_currentCharacter(0)
588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_end(run.length())
598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_totalWidth(0)
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_runWidthSoFar(0)
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_numGlyphsSoFar(0)
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_currentRun(0)
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_glyphInCurrentRun(0)
64643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    , m_characterInCurrentGlyph(0)
652fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    , m_expansion(run.expansion())
662bde8e466a4451c7319e3a072d118917957d6554Steve Block    , m_leadingExpansion(0)
672bde8e466a4451c7319e3a072d118917957d6554Steve Block    , m_afterExpansion(!run.allowsLeadingExpansion())
685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    , m_fallbackFonts(fallbackFonts)
69dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    , m_minGlyphBoundingBoxX(numeric_limits<float>::max())
70dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    , m_maxGlyphBoundingBoxX(numeric_limits<float>::min())
71dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    , m_minGlyphBoundingBoxY(numeric_limits<float>::max())
72dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    , m_maxGlyphBoundingBoxY(numeric_limits<float>::min())
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (!m_expansion)
752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        m_expansionPerOpportunity = 0;
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else {
772bde8e466a4451c7319e3a072d118917957d6554Steve Block        bool isAfterExpansion = m_afterExpansion;
782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        unsigned expansionOpportunityCount = Font::expansionOpportunityCount(m_run.characters(), m_end, m_run.ltr() ? LTR : RTL, isAfterExpansion);
792fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if (isAfterExpansion && !m_run.allowsTrailingExpansion())
802fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            expansionOpportunityCount--;
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if (!expansionOpportunityCount)
832fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            m_expansionPerOpportunity = 0;
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        else
852fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            m_expansionPerOpportunity = m_expansion / expansionOpportunityCount;
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
88643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    collectComplexTextRuns();
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    adjustGlyphsAndAdvances();
902bde8e466a4451c7319e3a072d118917957d6554Steve Block
912bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_runWidthSoFar = m_leadingExpansion;
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsenint ComplexTextController::offsetForPosition(float h, bool includePartialGlyphs)
958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (h >= m_totalWidth)
978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return m_run.ltr() ? m_end : 0;
982bde8e466a4451c7319e3a072d118917957d6554Steve Block
992bde8e466a4451c7319e3a072d118917957d6554Steve Block    h -= m_leadingExpansion;
1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (h < 0)
1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return m_run.ltr() ? 0 : m_end;
1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGFloat x = h;
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
105643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    size_t runCount = m_complexTextRuns.size();
1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    size_t offsetIntoAdjustedGlyphs = 0;
1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (size_t r = 0; r < runCount; ++r) {
109643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        const ComplexTextRun& complexTextRun = *m_complexTextRuns[r];
110643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        for (unsigned j = 0; j < complexTextRun.glyphCount(); ++j) {
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            CGFloat adjustedAdvance = m_adjustedAdvances[offsetIntoAdjustedGlyphs + j].width;
112643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            if (x < adjustedAdvance) {
113643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                CFIndex hitGlyphStart = complexTextRun.indexAt(j);
114643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                CFIndex hitGlyphEnd;
115643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                if (m_run.ltr())
1162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                    hitGlyphEnd = max<CFIndex>(hitGlyphStart, j + 1 < complexTextRun.glyphCount() ? complexTextRun.indexAt(j + 1) : static_cast<CFIndex>(complexTextRun.indexEnd()));
117643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                else
1182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                    hitGlyphEnd = max<CFIndex>(hitGlyphStart, j > 0 ? complexTextRun.indexAt(j - 1) : static_cast<CFIndex>(complexTextRun.indexEnd()));
119643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
120d0825bca7fe65beaee391d30da42e937db621564Steve Block                // FIXME: Instead of dividing the glyph's advance equally between the characters, this
121643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                // could use the glyph's "ligature carets". However, there is no Core Text API to get the
122643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                // ligature carets.
123643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                CFIndex hitIndex = hitGlyphStart + (hitGlyphEnd - hitGlyphStart) * (m_run.ltr() ? x / adjustedAdvance : 1 - x / adjustedAdvance);
124643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                int stringLength = complexTextRun.stringLength();
125643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                TextBreakIterator* cursorPositionIterator = cursorMovementIterator(complexTextRun.characters(), stringLength);
1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                int clusterStart;
1275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                if (isTextBreak(cursorPositionIterator, hitIndex))
1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    clusterStart = hitIndex;
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                else {
1305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                    clusterStart = textBreakPreceding(cursorPositionIterator, hitIndex);
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    if (clusterStart == TextBreakDone)
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        clusterStart = 0;
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                }
1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (!includePartialGlyphs)
136643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                    return complexTextRun.stringLocation() + clusterStart;
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                int clusterEnd = textBreakFollowing(cursorPositionIterator, hitIndex);
1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (clusterEnd == TextBreakDone)
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    clusterEnd = stringLength;
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
142643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                CGFloat clusterWidth;
143643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                // FIXME: The search stops at the boundaries of complexTextRun. In theory, it should go on into neighboring ComplexTextRuns
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // derived from the same CTLine. In practice, we do not expect there to be more than one CTRun in a CTLine, as no
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // reordering and on font fallback should occur within a CTLine.
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (clusterEnd - clusterStart > 1) {
147643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                    clusterWidth = adjustedAdvance;
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    int firstGlyphBeforeCluster = j - 1;
149643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                    while (firstGlyphBeforeCluster >= 0 && complexTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) {
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        CGFloat width = m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width;
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        clusterWidth += width;
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        x += width;
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        firstGlyphBeforeCluster--;
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    }
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    unsigned firstGlyphAfterCluster = j + 1;
156643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                    while (firstGlyphAfterCluster < complexTextRun.glyphCount() && complexTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) {
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        clusterWidth += m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphAfterCluster].width;
1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        firstGlyphAfterCluster++;
1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    }
160643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                } else {
161643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                    clusterWidth = adjustedAdvance / (hitGlyphEnd - hitGlyphStart);
162643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                    x -=  clusterWidth * (m_run.ltr() ? hitIndex - hitGlyphStart : hitGlyphEnd - hitIndex - 1);
1638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                }
1648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (x <= clusterWidth / 2)
165643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                    return complexTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd);
1668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                else
167643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                    return complexTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart);
1688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
1698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            x -= adjustedAdvance;
1708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
171643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        offsetIntoAdjustedGlyphs += complexTextRun.glyphCount();
1728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT_NOT_REACHED();
1758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return 0;
1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
178643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockvoid ComplexTextController::collectComplexTextRuns()
1798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_end)
1818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
1828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // We break up glyph run generation for the string by FontData and (if needed) the use of small caps.
1848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const UChar* cp = m_run.characters();
1858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
186bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    if (m_font.isSmallCaps())
1878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_smallCapsBuffer.resize(m_end);
1888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned indexOfFontTransition = m_run.rtl() ? m_end - 1 : 0;
1908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const UChar* curr = m_run.rtl() ? cp + m_end  - 1 : cp;
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const UChar* end = m_run.rtl() ? cp - 1 : cp + m_end;
1928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    GlyphData glyphData;
1948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    GlyphData nextGlyphData;
1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool isSurrogate = U16_IS_SURROGATE(*curr);
1978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (isSurrogate) {
1988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (m_run.ltr()) {
1998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (!U16_IS_SURROGATE_LEAD(curr[0]) || curr + 1 == end || !U16_IS_TRAIL(curr[1]))
2008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                return;
2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[0], curr[1]), false);
2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (!U16_IS_TRAIL(curr[0]) || curr -1 == end || !U16_IS_SURROGATE_LEAD(curr[-1]))
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                return;
2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[-1], curr[0]), false);
2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else
2088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        nextGlyphData = m_font.glyphDataForCharacter(*curr, false);
2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UChar newC = 0;
2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool isSmallCaps;
2138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool nextIsSmallCaps = !isSurrogate && m_font.isSmallCaps() && !(U_GET_GC_MASK(*curr) & U_GC_M_MASK) && (newC = u_toupper(*curr)) != *curr;
2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (nextIsSmallCaps)
2168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_smallCapsBuffer[curr - cp] = newC;
2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (true) {
2198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        curr = m_run.rtl() ? curr - (isSurrogate ? 2 : 1) : curr + (isSurrogate ? 2 : 1);
2208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (curr == end)
2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
2228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        glyphData = nextGlyphData;
2248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        isSmallCaps = nextIsSmallCaps;
2258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int index = curr - cp;
2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        isSurrogate = U16_IS_SURROGATE(*curr);
2278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        UChar c = *curr;
2288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        bool forceSmallCaps = !isSurrogate && isSmallCaps && (U_GET_GC_MASK(c) & U_GC_M_MASK);
2298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (isSurrogate) {
2308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (m_run.ltr()) {
2318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (!U16_IS_SURROGATE_LEAD(curr[0]) || curr + 1 == end || !U16_IS_TRAIL(curr[1]))
2328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    return;
2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[0], curr[1]), false);
2348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else {
2358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (!U16_IS_TRAIL(curr[0]) || curr -1 == end || !U16_IS_SURROGATE_LEAD(curr[-1]))
2368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    return;
2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[-1], curr[0]), false);
2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else
240f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            nextGlyphData = m_font.glyphDataForCharacter(*curr, false, forceSmallCaps ? SmallCapsVariant : AutoVariant);
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!isSurrogate && m_font.isSmallCaps()) {
2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            nextIsSmallCaps = forceSmallCaps || (newC = u_toupper(c)) != c;
2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (nextIsSmallCaps)
2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                m_smallCapsBuffer[index] = forceSmallCaps ? c : newC;
2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (nextGlyphData.fontData != glyphData.fontData || nextIsSmallCaps != isSmallCaps || !nextGlyphData.glyph != !glyphData.glyph) {
24906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            int itemStart = m_run.rtl() ? index + 1 : static_cast<int>(indexOfFontTransition);
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            int itemLength = m_run.rtl() ? indexOfFontTransition - index : index - indexOfFontTransition;
251643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            collectComplexTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, glyphData.glyph ? glyphData.fontData : 0);
2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            indexOfFontTransition = index;
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
256bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    int itemLength = m_run.rtl() ? indexOfFontTransition + 1 : m_end - indexOfFontTransition;
2578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (itemLength) {
2588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int itemStart = m_run.rtl() ? 0 : indexOfFontTransition;
259643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        collectComplexTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, nextGlyphData.glyph ? nextGlyphData.fontData : 0);
2608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
263d0825bca7fe65beaee391d30da42e937db621564Steve Block#if USE(CORE_TEXT) && USE(ATSUI)
264d0825bca7fe65beaee391d30da42e937db621564Steve Blockstatic inline bool shouldUseATSUIAPI()
265d0825bca7fe65beaee391d30da42e937db621564Steve Block{
266d0825bca7fe65beaee391d30da42e937db621564Steve Block    enum TypeRenderingAPIToUse { UnInitialized, UseATSUI, UseCoreText };
2676c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    static TypeRenderingAPIToUse apiToUse = UnInitialized;
268d0825bca7fe65beaee391d30da42e937db621564Steve Block
269d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (UNLIKELY(apiToUse == UnInitialized)) {
270d0825bca7fe65beaee391d30da42e937db621564Steve Block        if (&CTGetCoreTextVersion != 0 && CTGetCoreTextVersion() >= kCTVersionNumber10_6)
271d0825bca7fe65beaee391d30da42e937db621564Steve Block            apiToUse = UseCoreText;
272d0825bca7fe65beaee391d30da42e937db621564Steve Block        else
273d0825bca7fe65beaee391d30da42e937db621564Steve Block            apiToUse = UseATSUI;
274d0825bca7fe65beaee391d30da42e937db621564Steve Block    }
275d0825bca7fe65beaee391d30da42e937db621564Steve Block
276d0825bca7fe65beaee391d30da42e937db621564Steve Block    return apiToUse == UseATSUI;
277d0825bca7fe65beaee391d30da42e937db621564Steve Block}
278d0825bca7fe65beaee391d30da42e937db621564Steve Block#endif
279d0825bca7fe65beaee391d30da42e937db621564Steve Block
280d0825bca7fe65beaee391d30da42e937db621564Steve BlockCFIndex ComplexTextController::ComplexTextRun::indexAt(size_t i) const
281d0825bca7fe65beaee391d30da42e937db621564Steve Block{
282d0825bca7fe65beaee391d30da42e937db621564Steve Block#if USE(CORE_TEXT) && USE(ATSUI)
283d0825bca7fe65beaee391d30da42e937db621564Steve Block    return shouldUseATSUIAPI() ? m_atsuiIndices[i] : m_coreTextIndices[i];
284d0825bca7fe65beaee391d30da42e937db621564Steve Block#elif USE(ATSUI)
285d0825bca7fe65beaee391d30da42e937db621564Steve Block    return m_atsuiIndices[i];
286d0825bca7fe65beaee391d30da42e937db621564Steve Block#elif USE(CORE_TEXT)
287d0825bca7fe65beaee391d30da42e937db621564Steve Block    return m_coreTextIndices[i];
288d0825bca7fe65beaee391d30da42e937db621564Steve Block#endif
289d0825bca7fe65beaee391d30da42e937db621564Steve Block}
290d0825bca7fe65beaee391d30da42e937db621564Steve Block
291d0825bca7fe65beaee391d30da42e937db621564Steve Blockvoid ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
292d0825bca7fe65beaee391d30da42e937db621564Steve Block{
293d0825bca7fe65beaee391d30da42e937db621564Steve Block#if USE(CORE_TEXT) && USE(ATSUI)
294d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (shouldUseATSUIAPI())
295d0825bca7fe65beaee391d30da42e937db621564Steve Block        return collectComplexTextRunsForCharactersATSUI(cp, length, stringLocation, fontData);
296d0825bca7fe65beaee391d30da42e937db621564Steve Block    return collectComplexTextRunsForCharactersCoreText(cp, length, stringLocation, fontData);
297d0825bca7fe65beaee391d30da42e937db621564Steve Block#elif USE(ATSUI)
298d0825bca7fe65beaee391d30da42e937db621564Steve Block    return collectComplexTextRunsForCharactersATSUI(cp, length, stringLocation, fontData);
299d0825bca7fe65beaee391d30da42e937db621564Steve Block#elif USE(CORE_TEXT)
300d0825bca7fe65beaee391d30da42e937db621564Steve Block    return collectComplexTextRunsForCharactersCoreText(cp, length, stringLocation, fontData);
301d0825bca7fe65beaee391d30da42e937db621564Steve Block#endif
302d0825bca7fe65beaee391d30da42e937db621564Steve Block}
303d0825bca7fe65beaee391d30da42e937db621564Steve Block
304d0825bca7fe65beaee391d30da42e937db621564Steve BlockComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr)
305d0825bca7fe65beaee391d30da42e937db621564Steve Block    : m_fontData(fontData)
306d0825bca7fe65beaee391d30da42e937db621564Steve Block    , m_characters(characters)
307d0825bca7fe65beaee391d30da42e937db621564Steve Block    , m_stringLocation(stringLocation)
308d0825bca7fe65beaee391d30da42e937db621564Steve Block    , m_stringLength(stringLength)
3092fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    , m_indexEnd(stringLength)
3108a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    , m_isMonotonic(true)
311d0825bca7fe65beaee391d30da42e937db621564Steve Block{
312d0825bca7fe65beaee391d30da42e937db621564Steve Block#if USE(CORE_TEXT) && USE(ATSUI)
313d0825bca7fe65beaee391d30da42e937db621564Steve Block    shouldUseATSUIAPI() ? createTextRunFromFontDataATSUI(ltr) : createTextRunFromFontDataCoreText(ltr);
314d0825bca7fe65beaee391d30da42e937db621564Steve Block#elif USE(ATSUI)
315d0825bca7fe65beaee391d30da42e937db621564Steve Block    createTextRunFromFontDataATSUI(ltr);
316d0825bca7fe65beaee391d30da42e937db621564Steve Block#elif USE(CORE_TEXT)
317d0825bca7fe65beaee391d30da42e937db621564Steve Block    createTextRunFromFontDataCoreText(ltr);
318d0825bca7fe65beaee391d30da42e937db621564Steve Block#endif
319d0825bca7fe65beaee391d30da42e937db621564Steve Block}
320d0825bca7fe65beaee391d30da42e937db621564Steve Block
3218a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blockvoid ComplexTextController::ComplexTextRun::setIsNonMonotonic()
3228a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block{
3238a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    ASSERT(m_isMonotonic);
3248a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    m_isMonotonic = false;
3258a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
3268a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    Vector<bool, 64> mappedIndices(m_stringLength);
3278a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    for (size_t i = 0; i < m_glyphCount; ++i) {
3288a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        ASSERT(indexAt(i) < static_cast<CFIndex>(m_stringLength));
3298a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        mappedIndices[indexAt(i)] = true;
3308a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    }
3318a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
3328a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    m_glyphEndOffsets.grow(m_glyphCount);
3338a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    for (size_t i = 0; i < m_glyphCount; ++i) {
3342fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        CFIndex nextMappedIndex = m_indexEnd;
3358a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        for (size_t j = indexAt(i) + 1; j < m_stringLength; ++j) {
3368a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            if (mappedIndices[j]) {
3378a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                nextMappedIndex = j;
3388a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                break;
3398a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            }
3408a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        }
3418a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        m_glyphEndOffsets[i] = nextMappedIndex;
3428a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    }
3438a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block}
3448a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
345643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockvoid ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer)
3468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (static_cast<int>(offset) > m_end)
3488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        offset = m_end;
3498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (offset <= m_currentCharacter)
3518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
3528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_currentCharacter = offset;
3548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
355643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    size_t runCount = m_complexTextRuns.size();
3568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool ltr = m_run.ltr();
3588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned k = ltr ? m_numGlyphsSoFar : m_adjustedGlyphs.size() - 1 - m_numGlyphsSoFar;
3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (m_currentRun < runCount) {
361643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        const ComplexTextRun& complexTextRun = *m_complexTextRuns[ltr ? m_currentRun : runCount - 1 - m_currentRun];
362643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        size_t glyphCount = complexTextRun.glyphCount();
3638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        unsigned g = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun;
3648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (m_glyphInCurrentRun < glyphCount) {
365643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            unsigned glyphStartOffset = complexTextRun.indexAt(g);
366643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            unsigned glyphEndOffset;
3678a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            if (complexTextRun.isMonotonic()) {
3688a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                if (ltr)
3692fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                    glyphEndOffset = max<unsigned>(glyphStartOffset, static_cast<unsigned>(g + 1 < glyphCount ? complexTextRun.indexAt(g + 1) : complexTextRun.indexEnd()));
3708a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                else
3712fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                    glyphEndOffset = max<unsigned>(glyphStartOffset, static_cast<unsigned>(g > 0 ? complexTextRun.indexAt(g - 1) : complexTextRun.indexEnd()));
3728a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            } else
3738a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                glyphEndOffset = complexTextRun.endOffsetAt(g);
374643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
3758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            CGSize adjustedAdvance = m_adjustedAdvances[k];
376643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
377643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            if (glyphStartOffset + complexTextRun.stringLocation() >= m_currentCharacter)
378643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                return;
379643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
380643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            if (glyphBuffer && !m_characterInCurrentGlyph)
381643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                glyphBuffer->add(m_adjustedGlyphs[k], complexTextRun.fontData(), adjustedAdvance);
382643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
383643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            unsigned oldCharacterInCurrentGlyph = m_characterInCurrentGlyph;
384643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            m_characterInCurrentGlyph = min(m_currentCharacter - complexTextRun.stringLocation(), glyphEndOffset) - glyphStartOffset;
3852fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            // FIXME: Instead of dividing the glyph's advance equally between the characters, this
386643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            // could use the glyph's "ligature carets". However, there is no Core Text API to get the
387643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            // ligature carets.
388dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            if (glyphStartOffset == glyphEndOffset) {
389dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                // When there are multiple glyphs per character we need to advance by the full width of the glyph.
390dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                ASSERT(m_characterInCurrentGlyph == oldCharacterInCurrentGlyph);
391dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                m_runWidthSoFar += adjustedAdvance.width;
392dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            } else
393dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                m_runWidthSoFar += adjustedAdvance.width * (m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset);
394643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
395643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            if (glyphEndOffset + complexTextRun.stringLocation() > m_currentCharacter)
396643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                return;
397643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
3988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_numGlyphsSoFar++;
3998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_glyphInCurrentRun++;
400643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            m_characterInCurrentGlyph = 0;
4018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (ltr) {
4028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                g++;
4038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                k++;
4048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else {
4058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                g--;
4068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                k--;
4078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
4088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
4098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_currentRun++;
4108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_glyphInCurrentRun = 0;
4118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
414643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockvoid ComplexTextController::adjustGlyphsAndAdvances()
4158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
41681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    CGFloat widthSinceLastCommit = 0;
417643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    size_t runCount = m_complexTextRuns.size();
4182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    bool hasExtraSpacing = (m_font.letterSpacing() || m_font.wordSpacing() || m_expansion) && !m_run.spacingDisabled();
4198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (size_t r = 0; r < runCount; ++r) {
4208a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        ComplexTextRun& complexTextRun = *m_complexTextRuns[r];
421643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        unsigned glyphCount = complexTextRun.glyphCount();
422643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        const SimpleFontData* fontData = complexTextRun.fontData();
4238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
424643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        const CGGlyph* glyphs = complexTextRun.glyphs();
425643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        const CGSize* advances = complexTextRun.advances();
4268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        bool lastRun = r + 1 == runCount;
4288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        bool roundsAdvances = !m_font.isPrinterFont() && fontData->platformData().roundsGlyphAdvances();
42981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        const UChar* cp = complexTextRun.characters();
430dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        CGPoint glyphOrigin = CGPointZero;
4318a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        CFIndex lastCharacterIndex = m_run.ltr() ? numeric_limits<CFIndex>::min() : numeric_limits<CFIndex>::max();
4328a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        bool isMonotonic = true;
4338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        for (unsigned i = 0; i < glyphCount; i++) {
435643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            CFIndex characterIndex = complexTextRun.indexAt(i);
4368a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            if (m_run.ltr()) {
4378a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                if (characterIndex < lastCharacterIndex)
4388a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                    isMonotonic = false;
4398a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            } else {
4408a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                if (characterIndex > lastCharacterIndex)
4418a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                    isMonotonic = false;
4428a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            }
4438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            UChar ch = *(cp + characterIndex);
4448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            bool lastGlyph = lastRun && i + 1 == glyphCount;
4458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            UChar nextCh;
4468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (lastGlyph)
4478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                nextCh = ' ';
4488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            else if (i + 1 < glyphCount)
449643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                nextCh = *(cp + complexTextRun.indexAt(i + 1));
4508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            else
451643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                nextCh = *(m_complexTextRuns[r + 1]->characters() + m_complexTextRuns[r + 1]->indexAt(0));
4528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            bool treatAsSpace = Font::treatAsSpace(ch);
4545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            CGGlyph glyph = treatAsSpace ? fontData->spaceGlyph() : glyphs[i];
4555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            CGSize advance = treatAsSpace ? CGSizeMake(fontData->spaceWidth(), advances[i].height) : advances[i];
4568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (ch == '\t' && m_run.allowTabs()) {
458967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                float tabWidth = m_font.tabWidth(*fontData);
45981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                advance.width = tabWidth - fmodf(m_run.xPos() + m_totalWidth + widthSinceLastCommit, tabWidth);
460f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            } else if (ch == zeroWidthSpace || (Font::treatAsZeroWidthSpace(ch) && !treatAsSpace)) {
4618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                advance.width = 0;
4625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                glyph = fontData->spaceGlyph();
4638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
4648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            float roundedAdvanceWidth = roundf(advance.width);
4668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (roundsAdvances)
4678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                advance.width = roundedAdvanceWidth;
4688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            advance.width += fontData->syntheticBoldOffset();
4708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (hasExtraSpacing) {
4728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // If we're a glyph with an advance, go ahead and add in letter-spacing.
4738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // That way we weed out zero width lurkers.  This behavior matches the fast text code path.
4748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (advance.width && m_font.letterSpacing())
4758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    advance.width += m_font.letterSpacing();
4768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // Handle justification and word-spacing.
4782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                if (treatAsSpace || Font::isCJKIdeographOrSymbol(ch)) {
4792fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                    // Distribute the run's total expansion evenly over all expansion opportunities in the run.
4802bde8e466a4451c7319e3a072d118917957d6554Steve Block                    if (m_expansion) {
4812fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                        if (!treatAsSpace && !m_afterExpansion) {
4822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                            // Take the expansion opportunity before this ideograph.
4832fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                            m_expansion -= m_expansionPerOpportunity;
48481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                            m_totalWidth += m_expansionPerOpportunity;
4852bde8e466a4451c7319e3a072d118917957d6554Steve Block                            if (m_adjustedAdvances.isEmpty())
4862bde8e466a4451c7319e3a072d118917957d6554Steve Block                                m_leadingExpansion = m_expansionPerOpportunity;
4872bde8e466a4451c7319e3a072d118917957d6554Steve Block                            else
4882bde8e466a4451c7319e3a072d118917957d6554Steve Block                                m_adjustedAdvances.last().width += m_expansionPerOpportunity;
4892bde8e466a4451c7319e3a072d118917957d6554Steve Block                        }
4902bde8e466a4451c7319e3a072d118917957d6554Steve Block                        if (!lastGlyph || m_run.allowsTrailingExpansion()) {
4912bde8e466a4451c7319e3a072d118917957d6554Steve Block                            m_expansion -= m_expansionPerOpportunity;
4922bde8e466a4451c7319e3a072d118917957d6554Steve Block                            advance.width += m_expansionPerOpportunity;
4932bde8e466a4451c7319e3a072d118917957d6554Steve Block                            m_afterExpansion = true;
4948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        }
4952fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                    } else
4962fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                        m_afterExpansion = false;
4978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    // Account for word-spacing.
4992fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                    if (treatAsSpace && characterIndex > 0 && !Font::treatAsSpace(*m_run.data(characterIndex - 1)) && m_font.wordSpacing())
5008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        advance.width += m_font.wordSpacing();
5012fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                } else
5022fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                    m_afterExpansion = false;
5038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
5048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
50581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            widthSinceLastCommit += advance.width;
5068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
507f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            // FIXME: Combining marks should receive a text emphasis mark if they are combine with a space.
508f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            if (m_forTextEmphasis && (!Font::canReceiveTextEmphasis(ch) || (U_GET_GC_MASK(ch) & U_GC_M_MASK)))
509f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                glyph = 0;
510f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
5118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            advance.height *= -1;
5128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_adjustedAdvances.append(advance);
5138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_adjustedGlyphs.append(glyph);
514dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
51521939df44de1705786c545cd1bf519d47250322dBen Murdoch            FloatRect glyphBounds = fontData->boundsForGlyph(glyph);
51621939df44de1705786c545cd1bf519d47250322dBen Murdoch            glyphBounds.move(glyphOrigin.x, glyphOrigin.y);
51721939df44de1705786c545cd1bf519d47250322dBen Murdoch            m_minGlyphBoundingBoxX = min(m_minGlyphBoundingBoxX, glyphBounds.x());
5182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            m_maxGlyphBoundingBoxX = max(m_maxGlyphBoundingBoxX, glyphBounds.maxX());
51921939df44de1705786c545cd1bf519d47250322dBen Murdoch            m_minGlyphBoundingBoxY = min(m_minGlyphBoundingBoxY, glyphBounds.y());
5202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, glyphBounds.maxY());
521dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            glyphOrigin.x += advance.width;
522dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            glyphOrigin.y += advance.height;
523dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
5248a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            lastCharacterIndex = characterIndex;
5258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
5268a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        if (!isMonotonic)
5278a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            complexTextRun.setIsNonMonotonic();
5288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
52981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    m_totalWidth += widthSinceLastCommit;
5308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} // namespace WebCore
533