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