Migrate from ints to unsigneds when referring to indices into strings
[WebKit-https.git] / Source / WebCore / platform / graphics / harfbuzz / HarfBuzzShaper.cpp
1 /*
2  * Copyright (c) 2012 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "HarfBuzzShaper.h"
33
34 #include "FontCascade.h"
35 #include "HarfBuzzFace.h"
36 #include "SurrogatePairAwareTextIterator.h"
37 #include <hb-icu.h>
38 #include <unicode/normlzr.h>
39 #include <unicode/uchar.h>
40 #include <wtf/MathExtras.h>
41 #include <wtf/StdLibExtras.h>
42 #include <wtf/Vector.h>
43 #include <wtf/text/StringView.h>
44
45 namespace WebCore {
46
47 template<typename T>
48 class HarfBuzzScopedPtr {
49 public:
50     typedef void (*DestroyFunction)(T*);
51
52     HarfBuzzScopedPtr(T* ptr, DestroyFunction destroy)
53         : m_ptr(ptr)
54         , m_destroy(destroy)
55     {
56         ASSERT(m_destroy);
57     }
58     ~HarfBuzzScopedPtr()
59     {
60         if (m_ptr)
61             (*m_destroy)(m_ptr);
62     }
63
64     T* get() { return m_ptr; }
65 private:
66     T* m_ptr;
67     DestroyFunction m_destroy;
68 };
69
70 static inline float harfBuzzPositionToFloat(hb_position_t value)
71 {
72     return static_cast<float>(value) / (1 << 16);
73 }
74
75 HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const Font* fontData, unsigned startIndex, unsigned numCharacters, TextDirection direction, hb_script_t script)
76     : m_fontData(fontData)
77     , m_startIndex(startIndex)
78     , m_numCharacters(numCharacters)
79     , m_direction(direction)
80     , m_script(script)
81 {
82 }
83
84 void HarfBuzzShaper::HarfBuzzRun::applyShapeResult(hb_buffer_t* harfBuzzBuffer)
85 {
86     m_numGlyphs = hb_buffer_get_length(harfBuzzBuffer);
87     m_glyphs.resize(m_numGlyphs);
88     m_advances.resize(m_numGlyphs);
89     m_glyphToCharacterIndexes.resize(m_numGlyphs);
90     m_offsets.resize(m_numGlyphs);
91 }
92
93 void HarfBuzzShaper::HarfBuzzRun::setGlyphAndPositions(unsigned index, uint16_t glyphId, float advance, float offsetX, float offsetY)
94 {
95     m_glyphs[index] = glyphId;
96     m_advances[index] = advance;
97     m_offsets[index] = FloatPoint(offsetX, offsetY);
98 }
99
100 unsigned HarfBuzzShaper::HarfBuzzRun::characterIndexForXPosition(float targetX)
101 {
102     ASSERT(targetX <= m_width);
103     float currentX = 0;
104     float currentAdvance = m_advances[0];
105     unsigned glyphIndex = 0;
106
107     // Sum up advances that belong to a character.
108     while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIndex] == m_glyphToCharacterIndexes[glyphIndex + 1])
109         currentAdvance += m_advances[++glyphIndex];
110     currentAdvance = currentAdvance / 2.0;
111     if (targetX <= currentAdvance)
112         return rtl() ? m_numCharacters : 0;
113
114     ++glyphIndex;
115     while (glyphIndex < m_numGlyphs) {
116         unsigned prevCharacterIndex = m_glyphToCharacterIndexes[glyphIndex - 1];
117         float prevAdvance = currentAdvance;
118         currentAdvance = m_advances[glyphIndex];
119         while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIndex] == m_glyphToCharacterIndexes[glyphIndex + 1])
120             currentAdvance += m_advances[++glyphIndex];
121         currentAdvance = currentAdvance / 2.0;
122         float nextX = currentX + prevAdvance + currentAdvance;
123         if (currentX <= targetX && targetX <= nextX)
124             return rtl() ? prevCharacterIndex : m_glyphToCharacterIndexes[glyphIndex];
125         currentX = nextX;
126         prevAdvance = currentAdvance;
127         ++glyphIndex;
128     }
129
130     return rtl() ? 0 : m_numCharacters;
131 }
132
133 float HarfBuzzShaper::HarfBuzzRun::xPositionForOffset(unsigned offset)
134 {
135     ASSERT(offset < m_numCharacters);
136     unsigned glyphIndex = 0;
137     float position = 0;
138     if (rtl()) {
139         while (glyphIndex < m_numGlyphs && m_glyphToCharacterIndexes[glyphIndex] > offset) {
140             position += m_advances[glyphIndex];
141             ++glyphIndex;
142         }
143         // For RTL, we need to return the right side boundary of the character.
144         // Add advance of glyphs which are part of the character.
145         while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIndex] == m_glyphToCharacterIndexes[glyphIndex + 1]) {
146             position += m_advances[glyphIndex];
147             ++glyphIndex;
148         }
149         position += m_advances[glyphIndex];
150     } else {
151         while (glyphIndex < m_numGlyphs && m_glyphToCharacterIndexes[glyphIndex] < offset) {
152             position += m_advances[glyphIndex];
153             ++glyphIndex;
154         }
155     }
156     return position;
157 }
158
159 static void normalizeCharacters(const TextRun& run, UChar* destination, unsigned length)
160 {
161     unsigned position = 0;
162     bool error = false;
163     const UChar* source;
164     String stringFor8BitRun;
165     if (run.is8Bit()) {
166         stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), run.length());
167         source = stringFor8BitRun.characters16();
168     } else
169         source = run.characters16();
170
171     while (position < length) {
172         UChar32 character;
173         unsigned nextPosition = position;
174         U16_NEXT(source, nextPosition, length, character);
175         // Don't normalize tabs as they are not treated as spaces for word-end.
176         if (FontCascade::treatAsSpace(character) && character != '\t')
177             character = ' ';
178         else if (FontCascade::treatAsZeroWidthSpaceInComplexScript(character))
179             character = zeroWidthSpace;
180         U16_APPEND(destination, position, length, character, error);
181         ASSERT_UNUSED(error, !error);
182         position = nextPosition;
183     }
184 }
185
186 HarfBuzzShaper::HarfBuzzShaper(const FontCascade* font, const TextRun& run)
187     : m_font(font)
188     , m_normalizedBufferLength(0)
189     , m_run(run)
190     , m_wordSpacingAdjustment(font->wordSpacing())
191     , m_padding(0)
192     , m_padPerWordBreak(0)
193     , m_padError(0)
194     , m_letterSpacing(font->letterSpacing())
195 {
196     m_normalizedBuffer = std::make_unique<UChar[]>(m_run.length() + 1);
197     m_normalizedBufferLength = m_run.length();
198     normalizeCharacters(m_run, m_normalizedBuffer.get(), m_normalizedBufferLength);
199     setPadding(m_run.expansion());
200     setFontFeatures();
201 }
202
203 HarfBuzzShaper::~HarfBuzzShaper()
204 {
205 }
206
207 static void normalizeSpacesAndMirrorChars(const UChar* source, UChar* destination, unsigned length, HarfBuzzShaper::NormalizeMode normalizeMode)
208 {
209     unsigned position = 0;
210     bool error = false;
211     // Iterate characters in source and mirror character if needed.
212     while (position < length) {
213         UChar32 character;
214         unsigned nextPosition = position;
215         U16_NEXT(source, nextPosition, length, character);
216         // Don't normalize tabs as they are not treated as spaces for word-end
217         if (FontCascade::treatAsSpace(character) && character != '\t')
218             character = ' ';
219         else if (FontCascade::treatAsZeroWidthSpace(character))
220             character = zeroWidthSpace;
221         else if (normalizeMode == HarfBuzzShaper::NormalizeMirrorChars)
222             character = u_charMirror(character);
223         U16_APPEND(destination, position, length, character, error);
224         ASSERT_UNUSED(error, !error);
225         position = nextPosition;
226     }
227 }
228
229 void HarfBuzzShaper::setNormalizedBuffer(NormalizeMode normalizeMode)
230 {
231     // Normalize the text run in three ways:
232     // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks
233     // (U+0300..) are used in the run. This conversion is necessary since most OpenType
234     // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in
235     // their GSUB tables.
236     //
237     // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since
238     // the API returns FALSE (= not normalized) for complex runs that don't require NFC
239     // normalization (e.g., Arabic text). Unless the run contains the diacritical marks,
240     // HarfBuzz will do the same thing for us using the GSUB table.
241     // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs
242     // for characters like '\n' otherwise.
243     // 3) Convert mirrored characters such as parenthesis for rtl text.
244
245     // Convert to NFC form if the text has diacritical marks.
246     icu::UnicodeString normalizedString;
247     UErrorCode error = U_ZERO_ERROR;
248
249     const UChar* runCharacters;
250     String stringFor8BitRun;
251     if (m_run.is8Bit()) {
252         stringFor8BitRun = String::make16BitFrom8BitSource(m_run.characters8(), m_run.length());
253         runCharacters = stringFor8BitRun.characters16();
254     } else
255         runCharacters = m_run.characters16();
256
257     for (unsigned i = 0; i < m_run.length(); ++i) {
258         UChar ch = runCharacters[i];
259         if (::ublock_getCode(ch) == UBLOCK_COMBINING_DIACRITICAL_MARKS) {
260             icu::Normalizer::normalize(icu::UnicodeString(runCharacters,
261                 m_run.length()), UNORM_NFC, 0 /* no options */,
262                 normalizedString, error);
263             if (U_FAILURE(error))
264                 normalizedString.remove();
265             break;
266         }
267     }
268
269     const UChar* sourceText;
270     if (normalizedString.isEmpty()) {
271         m_normalizedBufferLength = m_run.length();
272         sourceText = runCharacters;
273     } else {
274         m_normalizedBufferLength = normalizedString.length();
275         sourceText = normalizedString.getBuffer();
276     }
277
278     m_normalizedBuffer = std::make_unique<UChar[]>(m_normalizedBufferLength + 1);
279     normalizeSpacesAndMirrorChars(sourceText, m_normalizedBuffer.get(), m_normalizedBufferLength, normalizeMode);
280 }
281
282 bool HarfBuzzShaper::isWordEnd(unsigned index)
283 {
284     // This could refer a high-surrogate, but should work.
285     return index && isCodepointSpace(m_normalizedBuffer[index]);
286 }
287
288 int HarfBuzzShaper::determineWordBreakSpacing()
289 {
290     int wordBreakSpacing = m_wordSpacingAdjustment;
291
292     if (m_padding > 0) {
293         int toPad = roundf(m_padPerWordBreak + m_padError);
294         m_padError += m_padPerWordBreak - toPad;
295
296         if (m_padding < toPad)
297             toPad = m_padding;
298         m_padding -= toPad;
299         wordBreakSpacing += toPad;
300     }
301     return wordBreakSpacing;
302 }
303
304 // setPadding sets a number of pixels to be distributed across the TextRun.
305 // WebKit uses this to justify text.
306 void HarfBuzzShaper::setPadding(int padding)
307 {
308     m_padding = padding;
309     m_padError = 0;
310     if (!m_padding)
311         return;
312
313     // If we have padding to distribute, then we try to give an equal
314     // amount to each space. The last space gets the smaller amount, if
315     // any.
316     unsigned numWordEnds = 0;
317
318     for (unsigned i = 0; i < m_normalizedBufferLength; i++) {
319         if (isWordEnd(i))
320             numWordEnds++;
321     }
322
323     if (numWordEnds)
324         m_padPerWordBreak = m_padding / numWordEnds;
325     else
326         m_padPerWordBreak = 0;
327 }
328
329 void HarfBuzzShaper::setFontFeatures()
330 {
331     const auto& description = m_font->fontDescription();
332     if (description.orientation() == Vertical) {
333         static hb_feature_t vert = { HarfBuzzFace::vertTag, 1, 0, static_cast<unsigned>(-1) };
334         static hb_feature_t vrt2 = { HarfBuzzFace::vrt2Tag, 1, 0, static_cast<unsigned>(-1) };
335         m_features.append(vert);
336         m_features.append(vrt2);
337     }
338
339     hb_feature_t kerning = { HarfBuzzFace::kernTag, 0, 0, static_cast<unsigned>(-1) };
340     switch (description.kerning()) {
341     case Kerning::Normal:
342         kerning.value = 1;
343         m_features.append(kerning);
344         break;
345     case Kerning::NoShift:
346         kerning.value = 0;
347         m_features.append(kerning);
348         break;
349     case Kerning::Auto:
350         break;
351     default:
352         ASSERT_NOT_REACHED();
353     }
354
355     const FontFeatureSettings& settings = description.featureSettings();
356
357     unsigned numFeatures = settings.size();
358     for (unsigned i = 0; i < numFeatures; ++i) {
359         hb_feature_t feature;
360         auto& tag = settings[i].tag();
361         feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]);
362         feature.value = settings[i].value();
363         feature.start = 0;
364         feature.end = static_cast<unsigned>(-1);
365         m_features.append(feature);
366     }
367 }
368
369 bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer)
370 {
371     if (!collectHarfBuzzRuns())
372         return false;
373
374     m_totalWidth = 0;
375     // WebKit doesn't set direction when calulating widths. Leave the direction setting to
376     // HarfBuzz when we are calculating widths (except when directionalOverride() is set).
377     if (!shapeHarfBuzzRuns(glyphBuffer || m_run.directionalOverride()))
378         return false;
379     m_totalWidth = roundf(m_totalWidth);
380
381     if (glyphBuffer && !fillGlyphBuffer(glyphBuffer))
382         return false;
383
384     return true;
385 }
386
387 FloatPoint HarfBuzzShaper::adjustStartPoint(const FloatPoint& point)
388 {
389     return point + m_startOffset;
390 }
391
392 bool HarfBuzzShaper::collectHarfBuzzRuns()
393 {
394     const UChar* normalizedBufferEnd = m_normalizedBuffer.get() + m_normalizedBufferLength;
395     SurrogatePairAwareTextIterator iterator(m_normalizedBuffer.get(), 0, m_normalizedBufferLength, m_normalizedBufferLength);
396     UChar32 character;
397     unsigned clusterLength = 0;
398     unsigned startIndexOfCurrentRun = 0;
399     if (!iterator.consume(character, clusterLength))
400         return false;
401
402     const Font* nextFontData = m_font->glyphDataForCharacter(character, false).font;
403     UErrorCode errorCode = U_ZERO_ERROR;
404     UScriptCode nextScript = uscript_getScript(character, &errorCode);
405     if (U_FAILURE(errorCode))
406         return false;
407
408     do {
409         const UChar* currentCharacterPosition = iterator.characters();
410         const Font* currentFontData = nextFontData;
411         if (!currentFontData)
412             currentFontData = &m_font->primaryFont();
413         UScriptCode currentScript = nextScript;
414
415         for (iterator.advance(clusterLength); iterator.consume(character, clusterLength); iterator.advance(clusterLength)) {
416             if (FontCascade::treatAsZeroWidthSpace(character))
417                 continue;
418
419             if (U_GET_GC_MASK(character) & U_GC_M_MASK) {
420                 unsigned markLength = clusterLength;
421                 const UChar* markCharactersEnd = iterator.characters() + clusterLength;
422                 while (markCharactersEnd < normalizedBufferEnd) {
423                     UChar32 nextCharacter;
424                     unsigned nextCharacterLength = 0;
425                     U16_NEXT(markCharactersEnd, nextCharacterLength, normalizedBufferEnd - markCharactersEnd, nextCharacter);
426                     if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK))
427                         break;
428                     markLength += nextCharacterLength;
429                     markCharactersEnd += nextCharacterLength;
430                 }
431
432                 if (currentFontData->canRenderCombiningCharacterSequence(currentCharacterPosition, markCharactersEnd - currentCharacterPosition)) {
433                     clusterLength = markLength;
434                     continue;
435                 }
436                 nextFontData = m_font->glyphDataForCharacter(character, false).font;
437             } else
438                 nextFontData = m_font->glyphDataForCharacter(character, false).font;
439
440             nextScript = uscript_getScript(character, &errorCode);
441             if (U_FAILURE(errorCode))
442                 return false;
443             if ((nextFontData != currentFontData) || ((currentScript != nextScript) && (nextScript != USCRIPT_INHERITED) && (!uscript_hasScript(character, currentScript))))
444                 break;
445             if (nextScript == USCRIPT_INHERITED)
446                 nextScript = currentScript;
447             currentCharacterPosition = iterator.characters();
448         }
449         unsigned numCharactersOfCurrentRun = iterator.currentIndex() - startIndexOfCurrentRun;
450         hb_script_t script = hb_icu_script_to_script(currentScript);
451         m_harfBuzzRuns.append(std::make_unique<HarfBuzzRun>(currentFontData, startIndexOfCurrentRun, numCharactersOfCurrentRun, m_run.direction(), script));
452         currentFontData = nextFontData;
453         startIndexOfCurrentRun = iterator.currentIndex();
454     } while (iterator.consume(character, clusterLength));
455
456     return !m_harfBuzzRuns.isEmpty();
457 }
458
459 bool HarfBuzzShaper::shapeHarfBuzzRuns(bool shouldSetDirection)
460 {
461     HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_destroy);
462
463     hb_buffer_set_unicode_funcs(harfBuzzBuffer.get(), hb_icu_get_unicode_funcs());
464
465     for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
466         unsigned runIndex = m_run.rtl() ? m_harfBuzzRuns.size() - i - 1 : i;
467         HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
468         const Font* currentFontData = currentRun->fontData();
469
470         hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script());
471         if (shouldSetDirection)
472             hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
473         else
474             // Leaving direction to HarfBuzz to guess is *really* bad, but will do for now.
475             hb_buffer_guess_segment_properties(harfBuzzBuffer.get());
476
477         // Add a space as pre-context to the buffer. This prevents showing dotted-circle
478         // for combining marks at the beginning of runs.
479         static const uint16_t preContext = ' ';
480         hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0);
481
482         if (m_font->isSmallCaps() && u_islower(m_normalizedBuffer[currentRun->startIndex()])) {
483             String upperText = String(m_normalizedBuffer.get() + currentRun->startIndex(), currentRun->numCharacters()).convertToUppercaseWithoutLocale();
484             currentFontData = m_font->glyphDataForCharacter(upperText[0], false, SmallCapsVariant).font;
485             const UChar* characters = StringView(upperText).upconvertedCharacters();
486             hb_buffer_add_utf16(harfBuzzBuffer.get(), reinterpret_cast<const uint16_t*>(characters), currentRun->numCharacters(), 0, currentRun->numCharacters());
487         } else
488             hb_buffer_add_utf16(harfBuzzBuffer.get(), reinterpret_cast<const uint16_t*>(m_normalizedBuffer.get() + currentRun->startIndex()), currentRun->numCharacters(), 0, currentRun->numCharacters());
489
490         FontPlatformData* platformData = const_cast<FontPlatformData*>(&currentFontData->platformData());
491         HarfBuzzFace* face = platformData->harfBuzzFace();
492         if (!face)
493             return false;
494
495         if (m_font->fontDescription().orientation() == Vertical)
496             face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get());
497
498         HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_destroy);
499
500         hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size());
501
502         currentRun->applyShapeResult(harfBuzzBuffer.get());
503         setGlyphPositionsForHarfBuzzRun(currentRun, harfBuzzBuffer.get());
504
505         hb_buffer_reset(harfBuzzBuffer.get());
506     }
507
508     return true;
509 }
510
511 void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(HarfBuzzRun* currentRun, hb_buffer_t* harfBuzzBuffer)
512 {
513     const Font* currentFontData = currentRun->fontData();
514     hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0);
515     hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfBuzzBuffer, 0);
516
517     unsigned numGlyphs = currentRun->numGlyphs();
518     uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes();
519     float totalAdvance = 0;
520
521     // HarfBuzz returns the shaping result in visual order. We need not to flip for RTL.
522     for (size_t i = 0; i < numGlyphs; ++i) {
523         bool runEnd = i + 1 == numGlyphs;
524         uint16_t glyph = glyphInfos[i].codepoint;
525         float offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset);
526         float offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset);
527         float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance);
528
529         unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i].cluster;
530         bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1].cluster;
531         float spacing = 0;
532
533         glyphToCharacterIndexes[i] = glyphInfos[i].cluster;
534
535         if (isClusterEnd && !FontCascade::treatAsZeroWidthSpace(m_normalizedBuffer[currentCharacterIndex]))
536             spacing += m_letterSpacing;
537
538         if (isClusterEnd && isWordEnd(currentCharacterIndex))
539             spacing += determineWordBreakSpacing();
540
541         if (currentFontData->isZeroWidthSpaceGlyph(glyph)) {
542             currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0);
543             continue;
544         }
545
546         advance += spacing;
547         if (m_run.rtl()) {
548             // In RTL, spacing should be added to left side of glyphs.
549             offsetX += spacing;
550             if (!isClusterEnd)
551                 offsetX += m_letterSpacing;
552         }
553
554         currentRun->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY);
555
556         totalAdvance += advance;
557     }
558     currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0);
559     m_totalWidth += currentRun->width();
560 }
561
562 void HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, HarfBuzzRun* currentRun, FloatPoint& firstOffsetOfNextRun)
563 {
564     FloatPoint* offsets = currentRun->offsets();
565     uint16_t* glyphs = currentRun->glyphs();
566     float* advances = currentRun->advances();
567     unsigned numGlyphs = currentRun->numGlyphs();
568     uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes();
569
570     for (unsigned i = 0; i < numGlyphs; ++i) {
571         uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToCharacterIndexes[i];
572         FloatPoint& currentOffset = offsets[i];
573         FloatPoint& nextOffset = (i == numGlyphs - 1) ? firstOffsetOfNextRun : offsets[i + 1];
574         float glyphAdvanceX = advances[i] + nextOffset.x() - currentOffset.x();
575         float glyphAdvanceY = nextOffset.y() - currentOffset.y();
576         if (m_run.rtl()) {
577             if (currentCharacterIndex > m_run.length())
578                 m_startOffset.move(glyphAdvanceX, glyphAdvanceY);
579             else
580                 glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY), currentCharacterIndex);
581         } else {
582             if (currentCharacterIndex < m_run.length())
583                 glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY), currentCharacterIndex);
584         }
585     }
586 }
587
588 bool HarfBuzzShaper::fillGlyphBuffer(GlyphBuffer* glyphBuffer)
589 {
590     unsigned numRuns = m_harfBuzzRuns.size();
591     if (m_run.rtl()) {
592         m_startOffset = m_harfBuzzRuns.last()->offsets()[0];
593         for (int runIndex = numRuns - 1; runIndex >= 0; --runIndex) {
594             HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
595             FloatPoint firstOffsetOfNextRun = !runIndex ? FloatPoint() : m_harfBuzzRuns[runIndex - 1]->offsets()[0];
596             fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun);
597         }
598     } else {
599         m_startOffset = m_harfBuzzRuns.first()->offsets()[0];
600         for (unsigned runIndex = 0; runIndex < numRuns; ++runIndex) {
601             HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
602             FloatPoint firstOffsetOfNextRun = runIndex == numRuns - 1 ? FloatPoint() : m_harfBuzzRuns[runIndex + 1]->offsets()[0];
603             fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun);
604         }
605     }
606     return glyphBuffer->size();
607 }
608
609 int HarfBuzzShaper::offsetForPosition(float targetX)
610 {
611     int charactersSoFar = 0;
612     float currentX = 0;
613
614     if (m_run.rtl()) {
615         charactersSoFar = m_normalizedBufferLength;
616         for (int i = m_harfBuzzRuns.size() - 1; i >= 0; --i) {
617             charactersSoFar -= m_harfBuzzRuns[i]->numCharacters();
618             float nextX = currentX + m_harfBuzzRuns[i]->width();
619             float offsetForRun = targetX - currentX;
620             if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) {
621                 // The x value in question is within this script run.
622                 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosition(offsetForRun);
623                 return charactersSoFar + index;
624             }
625             currentX = nextX;
626         }
627     } else {
628         for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
629             float nextX = currentX + m_harfBuzzRuns[i]->width();
630             float offsetForRun = targetX - currentX;
631             if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) {
632                 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosition(offsetForRun);
633                 return charactersSoFar + index;
634             }
635             charactersSoFar += m_harfBuzzRuns[i]->numCharacters();
636             currentX = nextX;
637         }
638     }
639
640     return charactersSoFar;
641 }
642
643 FloatRect HarfBuzzShaper::selectionRect(const FloatPoint& point, int height, unsigned from, unsigned to)
644 {
645     float currentX = 0;
646     float fromX = 0;
647     float toX = 0;
648     bool foundFromX = false;
649     bool foundToX = false;
650
651     if (m_run.rtl())
652         currentX = m_totalWidth;
653     for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
654         if (m_run.rtl())
655             currentX -= m_harfBuzzRuns[i]->width();
656         unsigned numCharacters = m_harfBuzzRuns[i]->numCharacters();
657         if (!foundFromX && from < numCharacters) {
658             fromX = m_harfBuzzRuns[i]->xPositionForOffset(from) + currentX;
659             foundFromX = true;
660         } else {
661             ASSERT(from >= numCharacters);
662             from -= numCharacters;
663         }
664
665         if (!foundToX && to < numCharacters) {
666             toX = m_harfBuzzRuns[i]->xPositionForOffset(to) + currentX;
667             foundToX = true;
668         } else {
669             ASSERT(to >= numCharacters);
670             to -= numCharacters;
671         }
672
673         if (foundFromX && foundToX)
674             break;
675         if (!m_run.rtl())
676             currentX += m_harfBuzzRuns[i]->width();
677     }
678
679     // The position in question might be just after the text.
680     if (!foundFromX)
681         fromX = 0;
682     if (!foundToX)
683         toX = m_run.rtl() ? 0 : m_totalWidth;
684
685     // Using floorf() and roundf() as the same as mac port.
686     if (fromX < toX)
687         return FloatRect(floorf(point.x() + fromX), point.y(), roundf(toX - fromX), height);
688     return FloatRect(floorf(point.x() + toX), point.y(), roundf(fromX - toX), height);
689 }
690
691 } // namespace WebCore