Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / fonts / harfbuzz / HarfBuzzShaper.cpp
index 4ac6eb0..10abf50 100644 (file)
 #include "config.h"
 #include "platform/fonts/harfbuzz/HarfBuzzShaper.h"
 
-#include "RuntimeEnabledFeatures.h"
 #include "hb.h"
+#include "platform/LayoutUnit.h"
+#include "platform/RuntimeEnabledFeatures.h"
 #include "platform/fonts/Character.h"
 #include "platform/fonts/Font.h"
+#include "platform/fonts/GlyphBuffer.h"
 #include "platform/fonts/harfbuzz/HarfBuzzFace.h"
 #include "platform/text/SurrogatePairAwareTextIterator.h"
 #include "platform/text/TextBreakIterator.h"
@@ -50,7 +52,7 @@
 #include <map>
 #include <string>
 
-namespace WebCore {
+namespace blink {
 
 template<typename T>
 class HarfBuzzScopedPtr {
@@ -85,12 +87,13 @@ typedef std::map<std::wstring, CachedShapingResults*> CachedShapingResultsMap;
 typedef std::list<CachedShapingResultsLRUNode*> CachedShapingResultsLRU;
 
 struct CachedShapingResults {
-    CachedShapingResults(hb_buffer_t* harfBuzzBuffer, const Font* runFont, hb_direction_t runDir);
+    CachedShapingResults(hb_buffer_t* harfBuzzBuffer, const Font* runFont, hb_direction_t runDir, const String& newLocale);
     ~CachedShapingResults();
 
     hb_buffer_t* buffer;
     Font font;
     hb_direction_t dir;
+    String locale;
     CachedShapingResultsLRU::iterator lru;
 };
 
@@ -101,10 +104,11 @@ struct CachedShapingResultsLRUNode {
     CachedShapingResultsMap::iterator entry;
 };
 
-CachedShapingResults::CachedShapingResults(hb_buffer_t* harfBuzzBuffer, const Font* fontData, hb_direction_t dirData)
+CachedShapingResults::CachedShapingResults(hb_buffer_t* harfBuzzBuffer, const Font* fontData, hb_direction_t dirData, const String& newLocale)
     : buffer(harfBuzzBuffer)
     , font(*fontData)
     , dir(dirData)
+    , locale(newLocale)
 {
 }
 
@@ -301,6 +305,7 @@ int HarfBuzzShaper::HarfBuzzRun::characterIndexForXPosition(float targetX)
     if (targetX <= currentAdvance)
         return rtl() ? m_numCharacters : 0;
 
+    currentX = currentAdvance;
     ++glyphIndex;
     while (glyphIndex < m_numGlyphs) {
         unsigned prevCharacterIndex = m_glyphToCharacterIndexes[glyphIndex - 1];
@@ -313,7 +318,6 @@ int HarfBuzzShaper::HarfBuzzRun::characterIndexForXPosition(float targetX)
         if (currentX <= targetX && targetX <= nextX)
             return rtl() ? prevCharacterIndex : m_glyphToCharacterIndexes[glyphIndex];
         currentX = nextX;
-        prevAdvance = currentAdvance;
         ++glyphIndex;
     }
 
@@ -518,6 +522,23 @@ void HarfBuzzShaper::setFontFeatures()
         break;
     }
 
+    static hb_feature_t hwid = { HB_TAG('h', 'w', 'i', 'd'), 1, 0, static_cast<unsigned>(-1) };
+    static hb_feature_t twid = { HB_TAG('t', 'w', 'i', 'd'), 1, 0, static_cast<unsigned>(-1) };
+    static hb_feature_t qwid = { HB_TAG('d', 'w', 'i', 'd'), 1, 0, static_cast<unsigned>(-1) };
+    switch (description.widthVariant()) {
+    case HalfWidth:
+        m_features.append(hwid);
+        break;
+    case ThirdWidth:
+        m_features.append(twid);
+        break;
+    case QuarterWidth:
+        m_features.append(qwid);
+        break;
+    case RegularWidth:
+        break;
+    }
+
     FontFeatureSettings* settings = description.featureSettings();
     if (!settings)
         return;
@@ -641,7 +662,6 @@ static inline bool collectCandidateRuns(const UChar* normalizedBuffer,
         CandidateRun run = { character, startIndexOfCurrentRun, iterator.currentCharacter(), currentFontData, currentScript };
         runs->append(run);
 
-        currentFontData = nextFontData;
         startIndexOfCurrentRun = iterator.currentCharacter();
     } while (iterator.consume(character, clusterLength));
 
@@ -793,6 +813,9 @@ bool HarfBuzzShaper::shapeHarfBuzzRuns()
     HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_destroy);
 
     HarfBuzzRunCache& runCache = harfBuzzRunCache();
+    const FontDescription& fontDescription = m_font->fontDescription();
+    const String& localeString = fontDescription.locale();
+    CString locale = localeString.latin1();
 
     for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
         unsigned runIndex = m_run.rtl() ? m_harfBuzzRuns.size() - i - 1 : i;
@@ -806,6 +829,7 @@ bool HarfBuzzShaper::shapeHarfBuzzRuns()
         if (!face)
             return false;
 
+        hb_buffer_set_language(harfBuzzBuffer.get(), hb_language_from_string(locale.data(), locale.length()));
         hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script());
         hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
 
@@ -817,7 +841,7 @@ bool HarfBuzzShaper::shapeHarfBuzzRuns()
 
         CachedShapingResults* cachedResults = runCache.find(key);
         if (cachedResults) {
-            if (cachedResults->dir == props.direction && cachedResults->font == *m_font) {
+            if (cachedResults->dir == props.direction && cachedResults->font == *m_font && cachedResults->locale == localeString) {
                 currentRun->applyShapeResult(cachedResults->buffer);
                 setGlyphPositionsForHarfBuzzRun(currentRun, cachedResults->buffer);
 
@@ -836,16 +860,15 @@ bool HarfBuzzShaper::shapeHarfBuzzRuns()
         static const uint16_t preContext = ' ';
         hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0);
 
-        if (m_font->fontDescription().variant() && u_islower(m_normalizedBuffer[currentRun->startIndex()])) {
+        if (fontDescription.variant() == FontVariantSmallCaps && u_islower(m_normalizedBuffer[currentRun->startIndex()])) {
             String upperText = String(m_normalizedBuffer.get() + currentRun->startIndex(), currentRun->numCharacters()).upper();
-            currentFontData = m_font->glyphDataForCharacter(upperText[0], false, SmallCapsVariant).fontData;
             ASSERT(!upperText.is8Bit()); // m_normalizedBuffer is 16 bit, therefore upperText is 16 bit, even after we call makeUpper().
             hb_buffer_add_utf16(harfBuzzBuffer.get(), toUint16(upperText.characters16()), currentRun->numCharacters(), 0, currentRun->numCharacters());
         } else {
             hb_buffer_add_utf16(harfBuzzBuffer.get(), toUint16(m_normalizedBuffer.get() + currentRun->startIndex()), currentRun->numCharacters(), 0, currentRun->numCharacters());
         }
 
-        if (m_font->fontDescription().orientation() == Vertical)
+        if (fontDescription.orientation() == Vertical)
             face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get());
 
         HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_destroy);
@@ -854,7 +877,7 @@ bool HarfBuzzShaper::shapeHarfBuzzRuns()
         currentRun->applyShapeResult(harfBuzzBuffer.get());
         setGlyphPositionsForHarfBuzzRun(currentRun, harfBuzzBuffer.get());
 
-        runCache.insert(key, new CachedShapingResults(harfBuzzBuffer.get(), m_font, props.direction));
+        runCache.insert(key, new CachedShapingResults(harfBuzzBuffer.get(), m_font, props.direction, localeString));
 
         harfBuzzBuffer.set(hb_buffer_create());
     }
@@ -942,12 +965,12 @@ void HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, Ha
             if (currentCharacterIndex >= m_toIndex)
                 m_startOffset.move(glyphAdvanceX, glyphAdvanceY);
             else if (currentCharacterIndex >= m_fromIndex)
-                glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY));
+                glyphBuffer->add(glyphs[i], currentRun->fontData(), FloatSize(glyphAdvanceX, glyphAdvanceY));
         } else {
             if (currentCharacterIndex < m_fromIndex)
                 m_startOffset.move(glyphAdvanceX, glyphAdvanceY);
             else if (currentCharacterIndex < m_toIndex)
-                glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY));
+                glyphBuffer->add(glyphs[i], currentRun->fontData(), FloatSize(glyphAdvanceX, glyphAdvanceY));
         }
     }
 }
@@ -997,8 +1020,8 @@ void HarfBuzzShaper::fillGlyphBufferForTextEmphasis(GlyphBuffer* glyphBuffer, Ha
             float glyphAdvanceX = clusterAdvance / graphemesInCluster;
             for (unsigned j = 0; j < graphemesInCluster; ++j) {
                 // Do not put emphasis marks on space, separator, and control characters.
-                GlyphBufferGlyph glyphToAdd = Character::canReceiveTextEmphasis(m_run[currentCharacterIndex]) ? 1 : 0;
-                glyphBuffer->add(glyphToAdd, currentRun->fontData(), createGlyphBufferAdvance(glyphAdvanceX, 0));
+                Glyph glyphToAdd = Character::canReceiveTextEmphasis(m_run[currentCharacterIndex]) ? 1 : 0;
+                glyphBuffer->add(glyphToAdd, currentRun->fontData(), glyphAdvanceX);
             }
             clusterStart = clusterEnd;
             clusterAdvance = 0;
@@ -1013,6 +1036,10 @@ bool HarfBuzzShaper::fillGlyphBuffer(GlyphBuffer* glyphBuffer)
         m_startOffset = m_harfBuzzRuns.last()->offsets()[0];
         for (int runIndex = numRuns - 1; runIndex >= 0; --runIndex) {
             HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
+            if (!currentRun->hasGlyphToCharacterIndexes()) {
+                // FIXME: bug 337886, 359664
+                continue;
+            }
             FloatPoint firstOffsetOfNextRun = !runIndex ? FloatPoint() : m_harfBuzzRuns[runIndex - 1]->offsets()[0];
             if (m_forTextEmphasis == ForTextEmphasis)
                 fillGlyphBufferForTextEmphasis(glyphBuffer, currentRun);
@@ -1023,6 +1050,10 @@ bool HarfBuzzShaper::fillGlyphBuffer(GlyphBuffer* glyphBuffer)
         m_startOffset = m_harfBuzzRuns.first()->offsets()[0];
         for (unsigned runIndex = 0; runIndex < numRuns; ++runIndex) {
             HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
+            if (!currentRun->hasGlyphToCharacterIndexes()) {
+                // FIXME: bug 337886, 359664
+                continue;
+            }
             FloatPoint firstOffsetOfNextRun = runIndex == numRuns - 1 ? FloatPoint() : m_harfBuzzRuns[runIndex + 1]->offsets()[0];
             if (m_forTextEmphasis == ForTextEmphasis)
                 fillGlyphBufferForTextEmphasis(glyphBuffer, currentRun);
@@ -1105,10 +1136,15 @@ FloatRect HarfBuzzShaper::selectionRect(const FloatPoint& point, int height, int
     if (!foundToX)
         toX = m_run.rtl() ? 0 : m_totalWidth;
 
-    // Using floorf() and roundf() as the same as mac port.
-    if (fromX < toX)
-        return FloatRect(floorf(point.x() + fromX), point.y(), roundf(toX - fromX), height);
-    return FloatRect(floorf(point.x() + toX), point.y(), roundf(fromX - toX), height);
+    if (fromX < toX) {
+        return Font::pixelSnappedSelectionRect(
+            point.x() + fromX, point.x() + toX,
+            point.y(), height);
+    }
+
+    return Font::pixelSnappedSelectionRect(
+        point.x() + toX, point.x() + fromX,
+        point.y(), height);
 }
 
-} // namespace WebCore
+} // namespace blink