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