Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / fonts / mac / ComplexTextController.cpp
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 blink {
41
42 ComplexTextController::ComplexTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts, bool forTextEmphasis)
43     : m_font(*font)
44     , m_run(run)
45     , m_isLTROnly(true)
46     , m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection)
47     , m_forTextEmphasis(forTextEmphasis)
48     , m_currentCharacter(0)
49     , m_end(run.length())
50     , m_totalWidth(0)
51     , m_runWidthSoFar(0)
52     , m_numGlyphsSoFar(0)
53     , m_currentRun(0)
54     , m_glyphInCurrentRun(0)
55     , m_characterInCurrentGlyph(0)
56     , m_expansion(run.expansion())
57     , m_leadingExpansion(0)
58     , m_afterExpansion(!run.allowsLeadingExpansion())
59     , m_fallbackFonts(fallbackFonts)
60     , m_minGlyphBoundingBoxX(numeric_limits<float>::max())
61     , m_maxGlyphBoundingBoxX(numeric_limits<float>::min())
62     , m_minGlyphBoundingBoxY(numeric_limits<float>::max())
63     , m_maxGlyphBoundingBoxY(numeric_limits<float>::min())
64 {
65     if (!m_expansion)
66         m_expansionPerOpportunity = 0;
67     else {
68         bool isAfterExpansion = m_afterExpansion;
69         unsigned expansionOpportunityCount;
70         if (m_run.is8Bit())
71             expansionOpportunityCount = Character::expansionOpportunityCount(m_run.characters8(), m_end, m_run.direction(), isAfterExpansion);
72          else
73             expansionOpportunityCount = Character::expansionOpportunityCount(m_run.characters16(), m_end, m_run.direction(), isAfterExpansion);
74         if (isAfterExpansion && !m_run.allowsTrailingExpansion())
75             expansionOpportunityCount--;
76
77         if (!expansionOpportunityCount)
78             m_expansionPerOpportunity = 0;
79         else
80             m_expansionPerOpportunity = m_expansion / expansionOpportunityCount;
81     }
82
83     collectComplexTextRuns();
84     adjustGlyphsAndAdvances();
85
86     if (!m_isLTROnly) {
87         m_runIndices.reserveInitialCapacity(m_complexTextRuns.size());
88
89         m_glyphCountFromStartToIndex.reserveInitialCapacity(m_complexTextRuns.size());
90         unsigned glyphCountSoFar = 0;
91         for (unsigned i = 0; i < m_complexTextRuns.size(); ++i) {
92             m_glyphCountFromStartToIndex.uncheckedAppend(glyphCountSoFar);
93             glyphCountSoFar += m_complexTextRuns[i]->glyphCount();
94         }
95     }
96
97     m_runWidthSoFar = m_leadingExpansion;
98 }
99
100 int ComplexTextController::offsetForPosition(float h, bool includePartialGlyphs)
101 {
102     if (h >= m_totalWidth)
103         return m_run.ltr() ? m_end : 0;
104
105     h -= m_leadingExpansion;
106     if (h < 0)
107         return m_run.ltr() ? 0 : m_end;
108
109     CGFloat x = h;
110
111     size_t runCount = m_complexTextRuns.size();
112     size_t offsetIntoAdjustedGlyphs = 0;
113
114     for (size_t r = 0; r < runCount; ++r) {
115         const ComplexTextRun& complexTextRun = *m_complexTextRuns[r];
116         for (unsigned j = 0; j < complexTextRun.glyphCount(); ++j) {
117             CGFloat adjustedAdvance = m_adjustedAdvances[offsetIntoAdjustedGlyphs + j].width;
118             if (x < adjustedAdvance) {
119                 CFIndex hitGlyphStart = complexTextRun.indexAt(j);
120                 CFIndex hitGlyphEnd;
121                 if (m_run.ltr())
122                     hitGlyphEnd = max<CFIndex>(hitGlyphStart, j + 1 < complexTextRun.glyphCount() ? complexTextRun.indexAt(j + 1) : static_cast<CFIndex>(complexTextRun.indexEnd()));
123                 else
124                     hitGlyphEnd = max<CFIndex>(hitGlyphStart, j > 0 ? complexTextRun.indexAt(j - 1) : static_cast<CFIndex>(complexTextRun.indexEnd()));
125
126                 // FIXME: Instead of dividing the glyph's advance equally between the characters, this
127                 // could use the glyph's "ligature carets". However, there is no Core Text API to get the
128                 // ligature carets.
129                 CFIndex hitIndex = hitGlyphStart + (hitGlyphEnd - hitGlyphStart) * (m_run.ltr() ? x / adjustedAdvance : 1 - x / adjustedAdvance);
130                 int stringLength = complexTextRun.stringLength();
131                 TextBreakIterator* cursorPositionIterator = cursorMovementIterator(complexTextRun.characters(), stringLength);
132                 int clusterStart;
133                 if (cursorPositionIterator->isBoundary(hitIndex))
134                     clusterStart = hitIndex;
135                 else {
136                     clusterStart = cursorPositionIterator->preceding(hitIndex);
137                     if (clusterStart == TextBreakDone)
138                         clusterStart = 0;
139                 }
140
141                 if (!includePartialGlyphs)
142                     return complexTextRun.stringLocation() + clusterStart;
143
144                 int clusterEnd = cursorPositionIterator->following(hitIndex);
145                 if (clusterEnd == TextBreakDone)
146                     clusterEnd = stringLength;
147
148                 CGFloat clusterWidth;
149                 // FIXME: The search stops at the boundaries of complexTextRun. In theory, it should go on into neighboring ComplexTextRuns
150                 // derived from the same CTLine. In practice, we do not expect there to be more than one CTRun in a CTLine, as no
151                 // reordering and no font fallback should occur within a CTLine.
152                 if (clusterEnd - clusterStart > 1) {
153                     clusterWidth = adjustedAdvance;
154                     int firstGlyphBeforeCluster = j - 1;
155                     while (firstGlyphBeforeCluster >= 0 && complexTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) {
156                         CGFloat width = m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width;
157                         clusterWidth += width;
158                         x += width;
159                         firstGlyphBeforeCluster--;
160                     }
161                     unsigned firstGlyphAfterCluster = j + 1;
162                     while (firstGlyphAfterCluster < complexTextRun.glyphCount() && complexTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) {
163                         clusterWidth += m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphAfterCluster].width;
164                         firstGlyphAfterCluster++;
165                     }
166                 } else {
167                     clusterWidth = adjustedAdvance / (hitGlyphEnd - hitGlyphStart);
168                     x -=  clusterWidth * (m_run.ltr() ? hitIndex - hitGlyphStart : hitGlyphEnd - hitIndex - 1);
169                 }
170                 if (x <= clusterWidth / 2)
171                     return complexTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd);
172                 else
173                     return complexTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart);
174             }
175             x -= adjustedAdvance;
176         }
177         offsetIntoAdjustedGlyphs += complexTextRun.glyphCount();
178     }
179
180     ASSERT_NOT_REACHED();
181     return 0;
182 }
183
184 static bool advanceByCombiningCharacterSequence(const UChar*& iterator, const UChar* end, UChar32& baseCharacter, unsigned& markCount)
185 {
186     ASSERT(iterator < end);
187
188     markCount = 0;
189
190     baseCharacter = *iterator++;
191
192     if (U16_IS_SURROGATE(baseCharacter)) {
193         if (!U16_IS_LEAD(baseCharacter))
194             return false;
195         if (iterator == end)
196             return false;
197         UChar trail = *iterator++;
198         if (!U16_IS_TRAIL(trail))
199             return false;
200         baseCharacter = U16_GET_SUPPLEMENTARY(baseCharacter, trail);
201     }
202
203     // Consume marks.
204     while (iterator < end) {
205         UChar32 nextCharacter;
206         int markLength = 0;
207         U16_NEXT(iterator, markLength, end - iterator, nextCharacter);
208         if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK))
209             break;
210         markCount += markLength;
211         iterator += markLength;
212     }
213
214     return true;
215 }
216
217 void ComplexTextController::collectComplexTextRuns()
218 {
219     if (!m_end)
220         return;
221
222     // We break up glyph run generation for the string by FontData.
223     const UChar* cp;
224
225     if (m_run.is8Bit()) {
226         String stringFor8BitRun = String::make16BitFrom8BitSource(m_run.characters8(), m_run.length());
227         cp = stringFor8BitRun.characters16();
228         m_stringsFor8BitRuns.append(stringFor8BitRun);
229     } else
230         cp = m_run.characters16();
231
232     if (m_font.fontDescription().variant() == FontVariantSmallCaps)
233         m_smallCapsBuffer.resize(m_end);
234
235     unsigned indexOfFontTransition = 0;
236     const UChar* curr = cp;
237     const UChar* end = cp + m_end;
238
239     const SimpleFontData* fontData;
240     bool isMissingGlyph;
241     const SimpleFontData* nextFontData;
242     bool nextIsMissingGlyph;
243
244     unsigned markCount;
245     const UChar* sequenceStart = curr;
246     UChar32 baseCharacter;
247     if (!advanceByCombiningCharacterSequence(curr, end, baseCharacter, markCount))
248         return;
249
250     UChar uppercaseCharacter = 0;
251
252     bool isSmallCaps;
253     bool nextIsSmallCaps = m_font.fontDescription().variant() == FontVariantSmallCaps && !(U_GET_GC_MASK(baseCharacter) & U_GC_M_MASK) && (uppercaseCharacter = u_toupper(baseCharacter)) != baseCharacter;
254
255     if (nextIsSmallCaps) {
256         m_smallCapsBuffer[sequenceStart - cp] = uppercaseCharacter;
257         for (unsigned i = 0; i < markCount; ++i)
258             m_smallCapsBuffer[sequenceStart - cp + i + 1] = sequenceStart[i + 1];
259     }
260
261     nextIsMissingGlyph = false;
262     nextFontData = m_font.fontDataForCombiningCharacterSequence(sequenceStart, curr - sequenceStart, nextIsSmallCaps ? SmallCapsVariant : NormalVariant);
263     if (!nextFontData)
264         nextIsMissingGlyph = true;
265
266     while (curr < end) {
267         fontData = nextFontData;
268         isMissingGlyph = nextIsMissingGlyph;
269         isSmallCaps = nextIsSmallCaps;
270         int index = curr - cp;
271
272         if (!advanceByCombiningCharacterSequence(curr, end, baseCharacter, markCount))
273             return;
274
275         if (m_font.fontDescription().variant()) {
276             nextIsSmallCaps = (uppercaseCharacter = u_toupper(baseCharacter)) != baseCharacter;
277             if (nextIsSmallCaps) {
278                 m_smallCapsBuffer[index] = uppercaseCharacter;
279                 for (unsigned i = 0; i < markCount; ++i)
280                     m_smallCapsBuffer[index + i + 1] = cp[index + i + 1];
281             }
282         }
283
284         nextIsMissingGlyph = false;
285         if (baseCharacter == zeroWidthJoiner)
286             nextFontData = fontData;
287         else {
288             nextFontData = m_font.fontDataForCombiningCharacterSequence(cp + index, curr - cp - index, nextIsSmallCaps ? SmallCapsVariant : NormalVariant);
289             if (!nextFontData)
290                 nextIsMissingGlyph = true;
291         }
292
293         if (nextFontData != fontData || nextIsMissingGlyph != isMissingGlyph) {
294             int itemStart = static_cast<int>(indexOfFontTransition);
295             int itemLength = index - indexOfFontTransition;
296             collectComplexTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, !isMissingGlyph ? fontData : 0);
297             indexOfFontTransition = index;
298         }
299     }
300
301     int itemLength = m_end - indexOfFontTransition;
302     if (itemLength) {
303         int itemStart = indexOfFontTransition;
304         collectComplexTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, !nextIsMissingGlyph ? nextFontData : 0);
305     }
306
307     if (!m_run.ltr())
308         m_complexTextRuns.reverse();
309 }
310
311 CFIndex ComplexTextController::ComplexTextRun::indexAt(size_t i) const
312 {
313     return m_coreTextIndices[i];
314 }
315
316 void ComplexTextController::ComplexTextRun::setIsNonMonotonic()
317 {
318     ASSERT(m_isMonotonic);
319     m_isMonotonic = false;
320
321     Vector<bool, 64> mappedIndices(m_stringLength);
322     for (size_t i = 0; i < m_glyphCount; ++i) {
323         ASSERT(indexAt(i) < static_cast<CFIndex>(m_stringLength));
324         mappedIndices[indexAt(i)] = true;
325     }
326
327     m_glyphEndOffsets.grow(m_glyphCount);
328     for (size_t i = 0; i < m_glyphCount; ++i) {
329         CFIndex nextMappedIndex = m_indexEnd;
330         for (size_t j = indexAt(i) + 1; j < m_stringLength; ++j) {
331             if (mappedIndices[j]) {
332                 nextMappedIndex = j;
333                 break;
334             }
335         }
336         m_glyphEndOffsets[i] = nextMappedIndex;
337     }
338 }
339
340 unsigned ComplexTextController::findNextRunIndex(unsigned runIndex) const
341 {
342     const unsigned runOffset = stringEnd(*m_complexTextRuns[runIndex]);
343
344     // Finds the run with the lowest stringBegin() offset that starts at or
345     // after |runOffset|.
346     //
347     // Note that this can't just find a run whose stringBegin() equals the
348     // stringEnd() of the previous run because CoreText on Mac OS X 10.6 does
349     // not return runs covering BiDi control chars, so this has to handle the
350     // resulting gaps.
351     unsigned result = 0;
352     unsigned lowestOffset = UINT_MAX;
353     for (unsigned i = 0; i < m_complexTextRuns.size(); ++i) {
354         unsigned offset = stringBegin(*m_complexTextRuns[i]);
355         if (i != runIndex && offset >= runOffset && offset < lowestOffset) {
356             lowestOffset = offset;
357             result = i;
358         }
359     }
360
361     ASSERT(lowestOffset != UINT_MAX);
362     return result;
363 }
364
365 unsigned ComplexTextController::indexOfCurrentRun(unsigned& leftmostGlyph)
366 {
367     leftmostGlyph = 0;
368
369     size_t runCount = m_complexTextRuns.size();
370     if (m_currentRun >= runCount)
371         return runCount;
372
373     if (m_isLTROnly) {
374         for (unsigned i = 0; i < m_currentRun; ++i)
375             leftmostGlyph += m_complexTextRuns[i]->glyphCount();
376         return m_currentRun;
377     }
378
379     if (m_runIndices.isEmpty()) {
380         unsigned firstRun = 0;
381         unsigned firstRunOffset = stringBegin(*m_complexTextRuns[0]);
382         for (unsigned i = 1; i < runCount; ++i) {
383             unsigned offset = stringBegin(*m_complexTextRuns[i]);
384             if (offset < firstRunOffset) {
385                 firstRun = i;
386                 firstRunOffset = offset;
387             }
388         }
389         m_runIndices.uncheckedAppend(firstRun);
390     }
391
392     while (m_runIndices.size() <= m_currentRun) {
393         m_runIndices.uncheckedAppend(findNextRunIndex(m_runIndices.last()));
394     }
395
396     unsigned currentRunIndex = m_runIndices[m_currentRun];
397     leftmostGlyph = m_glyphCountFromStartToIndex[currentRunIndex];
398     return currentRunIndex;
399 }
400
401 unsigned ComplexTextController::incrementCurrentRun(unsigned& leftmostGlyph)
402 {
403     if (m_isLTROnly) {
404         leftmostGlyph += m_complexTextRuns[m_currentRun++]->glyphCount();
405         return m_currentRun;
406     }
407
408     m_currentRun++;
409     leftmostGlyph = 0;
410     return indexOfCurrentRun(leftmostGlyph);
411 }
412
413 void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer, GlyphIterationStyle iterationStyle, HashSet<const SimpleFontData*>* fallbackFonts)
414 {
415     if (static_cast<int>(offset) > m_end)
416         offset = m_end;
417
418     if (offset <= m_currentCharacter) {
419         m_runWidthSoFar = m_leadingExpansion;
420         m_numGlyphsSoFar = 0;
421         m_currentRun = 0;
422         m_glyphInCurrentRun = 0;
423         m_characterInCurrentGlyph = 0;
424     }
425
426     m_currentCharacter = offset;
427
428     size_t runCount = m_complexTextRuns.size();
429
430     unsigned leftmostGlyph = 0;
431     unsigned currentRunIndex = indexOfCurrentRun(leftmostGlyph);
432     while (m_currentRun < runCount) {
433         const ComplexTextRun& complexTextRun = *m_complexTextRuns[currentRunIndex];
434         bool ltr = complexTextRun.isLTR();
435         size_t glyphCount = complexTextRun.glyphCount();
436         unsigned g = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun;
437         unsigned k = leftmostGlyph + g;
438         if (fallbackFonts && complexTextRun.fontData() != m_font.primaryFont())
439             fallbackFonts->add(complexTextRun.fontData());
440
441         while (m_glyphInCurrentRun < glyphCount) {
442             unsigned glyphStartOffset = complexTextRun.indexAt(g);
443             unsigned glyphEndOffset;
444             if (complexTextRun.isMonotonic()) {
445                 if (ltr)
446                     glyphEndOffset = max<unsigned>(glyphStartOffset, static_cast<unsigned>(g + 1 < glyphCount ? complexTextRun.indexAt(g + 1) : complexTextRun.indexEnd()));
447                 else
448                     glyphEndOffset = max<unsigned>(glyphStartOffset, static_cast<unsigned>(g > 0 ? complexTextRun.indexAt(g - 1) : complexTextRun.indexEnd()));
449             } else
450                 glyphEndOffset = complexTextRun.endOffsetAt(g);
451
452             CGSize adjustedAdvance = m_adjustedAdvances[k];
453
454             if (glyphStartOffset + complexTextRun.stringLocation() >= m_currentCharacter)
455                 return;
456
457             if (glyphBuffer && !m_characterInCurrentGlyph)
458                 glyphBuffer->add(m_adjustedGlyphs[k], complexTextRun.fontData(), FloatSize(adjustedAdvance));
459
460             unsigned oldCharacterInCurrentGlyph = m_characterInCurrentGlyph;
461             m_characterInCurrentGlyph = min(m_currentCharacter - complexTextRun.stringLocation(), glyphEndOffset) - glyphStartOffset;
462             // FIXME: Instead of dividing the glyph's advance equally between the characters, this
463             // could use the glyph's "ligature carets". However, there is no Core Text API to get the
464             // ligature carets.
465             if (glyphStartOffset == glyphEndOffset) {
466                 // When there are multiple glyphs per character we need to advance by the full width of the glyph.
467                 ASSERT(m_characterInCurrentGlyph == oldCharacterInCurrentGlyph);
468                 m_runWidthSoFar += adjustedAdvance.width;
469             } else if (iterationStyle == ByWholeGlyphs) {
470                 if (!oldCharacterInCurrentGlyph)
471                     m_runWidthSoFar += adjustedAdvance.width;
472             } else
473                 m_runWidthSoFar += adjustedAdvance.width * (m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset);
474
475             if (glyphEndOffset + complexTextRun.stringLocation() > m_currentCharacter)
476                 return;
477
478             m_numGlyphsSoFar++;
479             m_glyphInCurrentRun++;
480             m_characterInCurrentGlyph = 0;
481             if (ltr) {
482                 g++;
483                 k++;
484             } else {
485                 g--;
486                 k--;
487             }
488         }
489         currentRunIndex = incrementCurrentRun(leftmostGlyph);
490         m_glyphInCurrentRun = 0;
491     }
492 }
493
494 void ComplexTextController::adjustGlyphsAndAdvances()
495 {
496     CGFloat widthSinceLastCommit = 0;
497     size_t runCount = m_complexTextRuns.size();
498     bool hasExtraSpacing = (m_font.fontDescription().letterSpacing() || m_font.fontDescription().wordSpacing() || m_expansion) && !m_run.spacingDisabled();
499     for (size_t r = 0; r < runCount; ++r) {
500         ComplexTextRun& complexTextRun = *m_complexTextRuns[r];
501         unsigned glyphCount = complexTextRun.glyphCount();
502         const SimpleFontData* fontData = complexTextRun.fontData();
503
504         if (!complexTextRun.isLTR())
505             m_isLTROnly = false;
506
507         const CGGlyph* glyphs = complexTextRun.glyphs();
508         const CGSize* advances = complexTextRun.advances();
509
510         bool lastRun = r + 1 == runCount;
511         bool roundsAdvances = fontData->platformData().roundsGlyphAdvances();
512         float spaceWidth = fontData->spaceWidth() - fontData->syntheticBoldOffset();
513         const UChar* cp = complexTextRun.characters();
514         CGPoint glyphOrigin = CGPointZero;
515         CFIndex lastCharacterIndex = m_run.ltr() ? numeric_limits<CFIndex>::min() : numeric_limits<CFIndex>::max();
516         bool isMonotonic = true;
517
518         for (unsigned i = 0; i < glyphCount; i++) {
519             CFIndex characterIndex = complexTextRun.indexAt(i);
520             if (m_run.ltr()) {
521                 if (characterIndex < lastCharacterIndex)
522                     isMonotonic = false;
523             } else {
524                 if (characterIndex > lastCharacterIndex)
525                     isMonotonic = false;
526             }
527             UChar ch = *(cp + characterIndex);
528             bool lastGlyph = lastRun && i + 1 == glyphCount;
529             UChar nextCh;
530             if (lastGlyph)
531                 nextCh = ' ';
532             else if (i + 1 < glyphCount)
533                 nextCh = *(cp + complexTextRun.indexAt(i + 1));
534             else
535                 nextCh = *(m_complexTextRuns[r + 1]->characters() + m_complexTextRuns[r + 1]->indexAt(0));
536
537             bool treatAsSpace = Character::treatAsSpace(ch);
538             CGGlyph glyph = treatAsSpace ? fontData->spaceGlyph() : glyphs[i];
539             CGSize advance = treatAsSpace ? CGSizeMake(spaceWidth, advances[i].height) : advances[i];
540
541             if (ch == '\t' && m_run.allowTabs()) {
542                 advance.width = m_font.tabWidth(*fontData, m_run.tabSize(), m_run.xPos() + m_totalWidth + widthSinceLastCommit);
543             } else if (Character::treatAsZeroWidthSpace(ch) && !treatAsSpace) {
544                 advance.width = 0;
545                 glyph = fontData->spaceGlyph();
546             }
547
548             float roundedAdvanceWidth = roundf(advance.width);
549             if (roundsAdvances)
550                 advance.width = roundedAdvanceWidth;
551
552             advance.width += fontData->syntheticBoldOffset();
553
554             if (hasExtraSpacing) {
555                 // If we're a glyph with an advance, go ahead and add in letter-spacing.
556                 // That way we weed out zero width lurkers.  This behavior matches the fast text code path.
557                 if (advance.width && m_font.fontDescription().letterSpacing())
558                     advance.width += m_font.fontDescription().letterSpacing();
559
560                 // Handle justification and word-spacing.
561                 if (treatAsSpace || Character::isCJKIdeographOrSymbol(ch)) {
562                     // Distribute the run's total expansion evenly over all expansion opportunities in the run.
563                     if (m_expansion) {
564                         if (!treatAsSpace && !m_afterExpansion) {
565                             // Take the expansion opportunity before this ideograph.
566                             m_expansion -= m_expansionPerOpportunity;
567                             float expansionAtThisOpportunity = m_expansionPerOpportunity;
568                             m_totalWidth += expansionAtThisOpportunity;
569                             if (m_adjustedAdvances.isEmpty())
570                                 m_leadingExpansion = expansionAtThisOpportunity;
571                             else
572                                 m_adjustedAdvances.last().width += expansionAtThisOpportunity;
573                         }
574                         if (!lastGlyph || m_run.allowsTrailingExpansion()) {
575                             m_expansion -= m_expansionPerOpportunity;
576                             advance.width += m_expansionPerOpportunity;
577                             m_afterExpansion = true;
578                         }
579                     } else
580                         m_afterExpansion = false;
581
582                     // Account for word-spacing.
583                     if (treatAsSpace && (ch != '\t' || !m_run.allowTabs()) && (characterIndex > 0 || r > 0) && m_font.fontDescription().wordSpacing())
584                         advance.width += m_font.fontDescription().wordSpacing();
585                 } else
586                     m_afterExpansion = false;
587             }
588
589             widthSinceLastCommit += advance.width;
590
591             // FIXME: Combining marks should receive a text emphasis mark if they are combine with a space.
592             if (m_forTextEmphasis && (!Character::canReceiveTextEmphasis(ch) || (U_GET_GC_MASK(ch) & U_GC_M_MASK)))
593                 glyph = 0;
594
595             advance.height *= -1;
596             m_adjustedAdvances.append(advance);
597             m_adjustedGlyphs.append(glyph);
598
599             FloatRect glyphBounds = fontData->boundsForGlyph(glyph);
600             glyphBounds.move(glyphOrigin.x, glyphOrigin.y);
601             m_minGlyphBoundingBoxX = min(m_minGlyphBoundingBoxX, glyphBounds.x());
602             m_maxGlyphBoundingBoxX = max(m_maxGlyphBoundingBoxX, glyphBounds.maxX());
603             m_minGlyphBoundingBoxY = min(m_minGlyphBoundingBoxY, glyphBounds.y());
604             m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, glyphBounds.maxY());
605             glyphOrigin.x += advance.width;
606             glyphOrigin.y += advance.height;
607
608             lastCharacterIndex = characterIndex;
609         }
610         if (!isMonotonic)
611             complexTextRun.setIsNonMonotonic();
612     }
613     m_totalWidth += widthSinceLastCommit;
614 }
615
616 } // namespace blink