summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--third_party/WebKit/Source/platform/blink_platform.gypi5
-rw-r--r--third_party/WebKit/Source/platform/fonts/Font.cpp1
-rw-r--r--third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h1
-rw-r--r--third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp18
-rw-r--r--third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp534
-rw-r--r--third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h65
-rw-r--r--third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp49
-rw-r--r--third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h7
-rw-r--r--third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp502
-rw-r--r--third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h108
-rw-r--r--third_party/WebKit/Source/platform/fonts/shaping/ShapeResultInlineHeaders.h92
-rw-r--r--third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.cpp42
-rw-r--r--third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.h25
-rw-r--r--third_party/WebKit/Source/platform/fonts/shaping/Shaper.cpp11
-rw-r--r--third_party/WebKit/Source/platform/fonts/shaping/Shaper.h13
15 files changed, 833 insertions, 640 deletions
diff --git a/third_party/WebKit/Source/platform/blink_platform.gypi b/third_party/WebKit/Source/platform/blink_platform.gypi
index e47addd..0aaf6ce 100644
--- a/third_party/WebKit/Source/platform/blink_platform.gypi
+++ b/third_party/WebKit/Source/platform/blink_platform.gypi
@@ -432,6 +432,11 @@
'fonts/shaping/RunSegmenter.h',
'fonts/shaping/RunSegmenter.cpp',
'fonts/shaping/ShapeCache.h',
+ 'fonts/shaping/ShapeResult.cpp',
+ 'fonts/shaping/ShapeResult.h',
+ 'fonts/shaping/ShapeResultInlineHeaders.h',
+ 'fonts/shaping/ShapeResultTestInfo.cpp',
+ 'fonts/shaping/ShapeResultTestInfo.h',
'fonts/shaping/Shaper.cpp',
'fonts/shaping/Shaper.h',
'fonts/shaping/SimpleShaper.cpp',
diff --git a/third_party/WebKit/Source/platform/fonts/Font.cpp b/third_party/WebKit/Source/platform/fonts/Font.cpp
index 79f7842a..0d9f480 100644
--- a/third_party/WebKit/Source/platform/fonts/Font.cpp
+++ b/third_party/WebKit/Source/platform/fonts/Font.cpp
@@ -35,6 +35,7 @@
#include "platform/fonts/GlyphBuffer.h"
#include "platform/fonts/GlyphPageTreeNode.h"
#include "platform/fonts/SimpleFontData.h"
+#include "platform/fonts/shaping/CachingWordShaper.h"
#include "platform/fonts/shaping/HarfBuzzFace.h"
#include "platform/fonts/shaping/HarfBuzzShaper.h"
#include "platform/fonts/shaping/SimpleShaper.h"
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h
index d66080e3..65d2ee7 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h
@@ -26,6 +26,7 @@
#ifndef CachingWordShapeIterator_h
#define CachingWordShapeIterator_h
+#include "platform/fonts/Font.h"
#include "platform/fonts/SimpleFontData.h"
#include "platform/fonts/shaping/CachingWordShapeIterator.h"
#include "platform/fonts/shaping/HarfBuzzShaper.h"
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp
index 51d2360..048cc5d 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp
@@ -7,6 +7,7 @@
#include "platform/fonts/FontCache.h"
#include "platform/fonts/GlyphBuffer.h"
#include "platform/fonts/shaping/CachingWordShapeIterator.h"
+#include "platform/fonts/shaping/ShapeResultTestInfo.h"
#include <gtest/gtest.h>
namespace blink {
@@ -42,6 +43,11 @@ protected:
hb_script_t script = HB_SCRIPT_INVALID;
};
+static inline ShapeResultTestInfo* testInfo(RefPtr<ShapeResult>& result)
+{
+ return static_cast<ShapeResultTestInfo*>(result.get());
+}
+
TEST_F(CachingWordShaperTest, LatinLeftToRightByWord)
{
TextRun textRun(reinterpret_cast<const LChar*>("ABC DEF."), 8);
@@ -49,19 +55,19 @@ TEST_F(CachingWordShaperTest, LatinLeftToRightByWord)
RefPtr<ShapeResult> result;
CachingWordShapeIterator iterator(cache, textRun, font);
ASSERT_TRUE(iterator.next(&result));
- ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
EXPECT_EQ(0u, startIndex);
EXPECT_EQ(3u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_LATIN, script);
ASSERT_TRUE(iterator.next(&result));
- ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
EXPECT_EQ(0u, startIndex);
EXPECT_EQ(1u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_COMMON, script);
ASSERT_TRUE(iterator.next(&result));
- ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
EXPECT_EQ(0u, startIndex);
EXPECT_EQ(4u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_LATIN, script);
@@ -78,21 +84,21 @@ TEST_F(CachingWordShaperTest, CommonAccentLeftToRightByWord)
RefPtr<ShapeResult> result;
CachingWordShapeIterator iterator(cache, textRun, font);
ASSERT_TRUE(iterator.next(&result));
- ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
EXPECT_EQ(0u, offset + startIndex);
EXPECT_EQ(3u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_COMMON, script);
offset += result->numCharacters();
ASSERT_TRUE(iterator.next(&result));
- ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
EXPECT_EQ(3u, offset + startIndex);
EXPECT_EQ(1u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_COMMON, script);
offset += result->numCharacters();
ASSERT_TRUE(iterator.next(&result));
- ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
EXPECT_EQ(4u, offset + startIndex);
EXPECT_EQ(1u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_COMMON, script);
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
index c118ab6..0678568 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
@@ -32,7 +32,6 @@
#include "config.h"
#include "platform/fonts/shaping/HarfBuzzShaper.h"
-#include "hb.h"
#include "platform/Logging.h"
#include "platform/fonts/Character.h"
#include "platform/fonts/Font.h"
@@ -41,549 +40,20 @@
#include "platform/fonts/UTF16TextIterator.h"
#include "platform/fonts/shaping/HarfBuzzFace.h"
#include "platform/fonts/shaping/RunSegmenter.h"
+#include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
#include "platform/text/TextBreakIterator.h"
#include "wtf/Compiler.h"
#include "wtf/MathExtras.h"
#include "wtf/text/Unicode.h"
#include <algorithm>
+#include <hb.h>
#include <unicode/normlzr.h>
#include <unicode/uchar.h>
#include <unicode/uscript.h>
namespace blink {
-struct HarfBuzzRunGlyphData {
- uint16_t glyph;
- uint16_t characterIndex;
- float advance;
- FloatSize offset;
-};
-
-struct ShapeResult::RunInfo {
- RunInfo(const SimpleFontData* font, hb_direction_t dir, hb_script_t script,
- unsigned startIndex, unsigned numGlyphs, unsigned numCharacters)
- : m_fontData(const_cast<SimpleFontData*>(font)), m_direction(dir), m_script(script)
- , m_startIndex(startIndex), m_numCharacters(numCharacters)
- , m_numGlyphs(numGlyphs), m_width(0.0f)
- {
- m_glyphData.resize(m_numGlyphs);
- }
-
- bool rtl() const { return HB_DIRECTION_IS_BACKWARD(m_direction); }
- float xPositionForVisualOffset(unsigned) const;
- float xPositionForOffset(unsigned) const;
- int characterIndexForXPosition(float) const;
- void setGlyphAndPositions(unsigned index, uint16_t glyphId, float advance,
- float offsetX, float offsetY);
-
- void addAdvance(unsigned index, float advance)
- {
- m_glyphData[index].advance += advance;
- }
-
- size_t glyphToCharacterIndex(size_t i) const
- {
- return m_startIndex + m_glyphData[i].characterIndex;
- }
-
- RefPtr<SimpleFontData> m_fontData;
- hb_direction_t m_direction;
- hb_script_t m_script;
- Vector<HarfBuzzRunGlyphData> m_glyphData;
- unsigned m_startIndex;
- unsigned m_numCharacters;
- unsigned m_numGlyphs;
- float m_width;
-};
-
-float ShapeResult::RunInfo::xPositionForVisualOffset(unsigned offset) const
-{
- ASSERT(offset < m_numCharacters);
- if (rtl())
- offset = m_numCharacters - offset - 1;
- return xPositionForOffset(offset);
-}
-
-float ShapeResult::RunInfo::xPositionForOffset(unsigned offset) const
-{
- ASSERT(offset <= m_numCharacters);
- unsigned glyphIndex = 0;
- float position = 0;
- if (rtl()) {
- while (glyphIndex < m_numGlyphs && m_glyphData[glyphIndex].characterIndex > offset) {
- position += m_glyphData[glyphIndex].advance;
- ++glyphIndex;
- }
- // For RTL, we need to return the right side boundary of the character.
- // Add advance of glyphs which are part of the character.
- while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex) {
- position += m_glyphData[glyphIndex].advance;
- ++glyphIndex;
- }
- position += m_glyphData[glyphIndex].advance;
- } else {
- while (glyphIndex < m_numGlyphs && m_glyphData[glyphIndex].characterIndex < offset) {
- position += m_glyphData[glyphIndex].advance;
- ++glyphIndex;
- }
- }
- return position;
-}
-
-int ShapeResult::RunInfo::characterIndexForXPosition(float targetX) const
-{
- ASSERT(targetX <= m_width);
- float currentX = 0;
- float currentAdvance = m_glyphData[0].advance;
- unsigned glyphIndex = 0;
-
- // Sum up advances that belong to the first character.
- while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex)
- currentAdvance += m_glyphData[++glyphIndex].advance;
- currentAdvance = currentAdvance / 2.0;
- if (targetX <= currentAdvance)
- return rtl() ? m_numCharacters : 0;
-
- currentX = currentAdvance;
- ++glyphIndex;
- while (glyphIndex < m_numGlyphs) {
- unsigned prevCharacterIndex = m_glyphData[glyphIndex - 1].characterIndex;
- float prevAdvance = currentAdvance;
- currentAdvance = m_glyphData[glyphIndex].advance;
- while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex)
- currentAdvance += m_glyphData[++glyphIndex].advance;
- currentAdvance = currentAdvance / 2.0;
- float nextX = currentX + prevAdvance + currentAdvance;
- if (currentX <= targetX && targetX <= nextX)
- return rtl() ? prevCharacterIndex : m_glyphData[glyphIndex].characterIndex;
- currentX = nextX;
- ++glyphIndex;
- }
-
- return rtl() ? 0 : m_numCharacters;
-}
-
-void ShapeResult::RunInfo::setGlyphAndPositions(unsigned index,
- uint16_t glyphId, float advance, float offsetX, float offsetY)
-{
- HarfBuzzRunGlyphData& data = m_glyphData[index];
- data.glyph = glyphId;
- data.advance = advance;
- data.offset = FloatSize(offsetX, offsetY);
-}
-
-ShapeResult::ShapeResult(const Font* font, unsigned numCharacters, TextDirection direction)
- : m_width(0)
- , m_primaryFont(const_cast<SimpleFontData*>(font->primaryFont()))
- , m_numCharacters(numCharacters)
- , m_numGlyphs(0)
- , m_direction(direction)
-{
-}
-
-ShapeResult::~ShapeResult()
-{
-}
-
-static inline void addGlyphToBuffer(GlyphBuffer* glyphBuffer, float advance,
- hb_direction_t direction, const SimpleFontData* fontData,
- const HarfBuzzRunGlyphData& glyphData)
-{
- FloatPoint startOffset = HB_DIRECTION_IS_HORIZONTAL(direction)
- ? FloatPoint(advance, 0)
- : FloatPoint(0, advance);
- glyphBuffer->add(glyphData.glyph, fontData, startOffset + glyphData.offset);
-}
-
-template<TextDirection direction>
-float ShapeResult::fillGlyphBufferForRun(GlyphBuffer* glyphBuffer,
- const RunInfo* run, float initialAdvance, unsigned from, unsigned to,
- unsigned runOffset)
-{
- if (!run)
- return 0;
- float advanceSoFar = initialAdvance;
- unsigned numGlyphs = run->m_numGlyphs;
- for (unsigned i = 0; i < numGlyphs; ++i) {
- const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i];
- uint16_t currentCharacterIndex = run->m_startIndex +
- glyphData.characterIndex + runOffset;
- if ((direction == RTL && currentCharacterIndex >= to)
- || (direction == LTR && currentCharacterIndex < from)) {
- advanceSoFar += glyphData.advance;
- } else if ((direction == RTL && currentCharacterIndex >= from)
- || (direction == LTR && currentCharacterIndex < to)) {
- addGlyphToBuffer(glyphBuffer, advanceSoFar, run->m_direction,
- run->m_fontData.get(), glyphData);
- advanceSoFar += glyphData.advance;
- }
- }
- return advanceSoFar - initialAdvance;
-}
-
-static inline unsigned countGraphemesInCluster(const UChar* str,
- unsigned strLength, uint16_t startIndex, uint16_t endIndex)
-{
- if (startIndex > endIndex) {
- uint16_t tempIndex = startIndex;
- startIndex = endIndex;
- endIndex = tempIndex;
- }
- uint16_t length = endIndex - startIndex;
- ASSERT(static_cast<unsigned>(startIndex + length) <= strLength);
- TextBreakIterator* cursorPosIterator = cursorMovementIterator(&str[startIndex], length);
-
- int cursorPos = cursorPosIterator->current();
- int numGraphemes = -1;
- while (0 <= cursorPos) {
- cursorPos = cursorPosIterator->next();
- numGraphemes++;
- }
- return std::max(0, numGraphemes);
-}
-
-static inline void addEmphasisMark(GlyphBuffer* buffer,
- const GlyphData* emphasisData, FloatPoint glyphCenter,
- float midGlyphOffset)
-{
- ASSERT(buffer);
- ASSERT(emphasisData);
-
- const SimpleFontData* emphasisFontData = emphasisData->fontData;
- ASSERT(emphasisFontData);
-
- bool isVertical = emphasisFontData->platformData().isVerticalAnyUpright()
- && emphasisFontData->verticalData();
-
- if (!isVertical) {
- buffer->add(emphasisData->glyph, emphasisFontData,
- midGlyphOffset - glyphCenter.x());
- } else {
- buffer->add(emphasisData->glyph, emphasisFontData,
- FloatPoint(-glyphCenter.x(), midGlyphOffset - glyphCenter.y()));
- }
-}
-
-float ShapeResult::fillGlyphBufferForTextEmphasisRun(GlyphBuffer* glyphBuffer,
- const RunInfo* run, const TextRun& textRun, const GlyphData* emphasisData,
- float initialAdvance, unsigned from, unsigned to, unsigned runOffset)
-{
- if (!run)
- return 0;
-
- unsigned graphemesInCluster = 1;
- float clusterAdvance = 0;
-
- FloatPoint glyphCenter = emphasisData->fontData->
- boundsForGlyph(emphasisData->glyph).center();
-
- TextDirection direction = textRun.direction();
-
- // A "cluster" in this context means a cluster as it is used by HarfBuzz:
- // The minimal group of characters and corresponding glyphs, that cannot be broken
- // down further from a text shaping point of view.
- // A cluster can contain multiple glyphs and grapheme clusters, with mutually
- // overlapping boundaries. Below we count grapheme clusters per HarfBuzz clusters,
- // then linearly split the sum of corresponding glyph advances by the number of
- // grapheme clusters in order to find positions for emphasis mark drawing.
- uint16_t clusterStart = direction == RTL
- ? run->m_startIndex + run->m_numCharacters + runOffset
- : run->glyphToCharacterIndex(0) + runOffset;
-
- float advanceSoFar = initialAdvance;
- unsigned numGlyphs = run->m_numGlyphs;
- for (unsigned i = 0; i < numGlyphs; ++i) {
- const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i];
- uint16_t currentCharacterIndex = run->m_startIndex + glyphData.characterIndex + runOffset;
- bool isRunEnd = (i + 1 == numGlyphs);
- bool isClusterEnd = isRunEnd || (run->glyphToCharacterIndex(i + 1) + runOffset != currentCharacterIndex);
-
- if ((direction == RTL && currentCharacterIndex >= to) || (direction != RTL && currentCharacterIndex < from)) {
- advanceSoFar += glyphData.advance;
- direction == RTL ? --clusterStart : ++clusterStart;
- continue;
- }
-
- clusterAdvance += glyphData.advance;
-
- if (textRun.is8Bit()) {
- float glyphAdvanceX = glyphData.advance;
- if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex])) {
- addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceSoFar + glyphAdvanceX / 2);
- }
- advanceSoFar += glyphAdvanceX;
- } else if (isClusterEnd) {
- uint16_t clusterEnd;
- if (direction == RTL)
- clusterEnd = currentCharacterIndex;
- else
- clusterEnd = isRunEnd ? run->m_startIndex + run->m_numCharacters + runOffset : run->glyphToCharacterIndex(i + 1) + runOffset;
-
- graphemesInCluster = countGraphemesInCluster(textRun.characters16(), textRun.charactersLength(), clusterStart, clusterEnd);
- if (!graphemesInCluster || !clusterAdvance)
- continue;
-
- float glyphAdvanceX = clusterAdvance / graphemesInCluster;
- for (unsigned j = 0; j < graphemesInCluster; ++j) {
- // Do not put emphasis marks on space, separator, and control characters.
- if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex]))
- addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceSoFar + glyphAdvanceX / 2);
- advanceSoFar += glyphAdvanceX;
- }
- clusterStart = clusterEnd;
- clusterAdvance = 0;
- }
- }
- return advanceSoFar - initialAdvance;
-}
-
-float ShapeResult::fillGlyphBuffer(Vector<RefPtr<ShapeResult>>& results,
- GlyphBuffer* glyphBuffer, const TextRun& textRun,
- unsigned from, unsigned to)
-{
- float advance = 0;
- if (textRun.rtl()) {
- unsigned wordOffset = textRun.length();
- for (unsigned j = 0; j < results.size(); j++) {
- unsigned resolvedIndex = results.size() - 1 - j;
- RefPtr<ShapeResult>& wordResult = results[resolvedIndex];
- for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
- advance += wordResult->fillGlyphBufferForRun<RTL>(glyphBuffer,
- wordResult->m_runs[i].get(), advance, from, to,
- wordOffset - wordResult->numCharacters());
- }
- wordOffset -= wordResult->numCharacters();
- }
- } else {
- unsigned wordOffset = 0;
- for (unsigned j = 0; j < results.size(); j++) {
- RefPtr<ShapeResult>& wordResult = results[j];
- for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
- advance += wordResult->fillGlyphBufferForRun<LTR>(glyphBuffer,
- wordResult->m_runs[i].get(), advance, from, to, wordOffset);
- }
- wordOffset += wordResult->numCharacters();
- }
- }
-
- return advance;
-}
-
-float ShapeResult::fillGlyphBufferForTextEmphasis(
- Vector<RefPtr<ShapeResult>>& results, GlyphBuffer* glyphBuffer,
- const TextRun& textRun, const GlyphData* emphasisData,
- unsigned from, unsigned to)
-{
- float advance = 0;
- unsigned wordOffset = textRun.rtl() ? textRun.length() : 0;
- for (unsigned j = 0; j < results.size(); j++) {
- unsigned resolvedIndex = textRun.rtl() ? results.size() - 1 - j : j;
- RefPtr<ShapeResult>& wordResult = results[resolvedIndex];
- for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
- unsigned resolvedOffset = wordOffset -
- (textRun.rtl() ? wordResult->numCharacters() : 0);
- advance += wordResult->fillGlyphBufferForTextEmphasisRun(
- glyphBuffer, wordResult->m_runs[i].get(), textRun, emphasisData,
- advance, from, to, resolvedOffset);
- }
- wordOffset += wordResult->numCharacters() * (textRun.rtl() ? -1 : 1);
- }
-
- return advance;
-}
-
-FloatRect ShapeResult::selectionRect(Vector<RefPtr<ShapeResult>>& results,
- TextDirection direction, float totalWidth, const FloatPoint& point,
- int height, unsigned absoluteFrom, unsigned absoluteTo)
-{
- float currentX = 0;
- float fromX = 0;
- float toX = 0;
- bool foundFromX = false;
- bool foundToX = false;
-
- if (direction == RTL)
- currentX = totalWidth;
-
- // The absoluteFrom and absoluteTo arguments represent the start/end offset
- // for the entire run, from/to are continuously updated to be relative to
- // the current word (ShapeResult instance).
- int from = absoluteFrom;
- int to = absoluteTo;
-
- unsigned totalNumCharacters = 0;
- for (unsigned j = 0; j < results.size(); j++) {
- RefPtr<ShapeResult> result = results[j];
- if (direction == RTL) {
- // Convert logical offsets to visual offsets, because results are in
- // logical order while runs are in visual order.
- if (!foundFromX && from >= 0 && static_cast<unsigned>(from) < result->numCharacters())
- from = result->numCharacters() - from - 1;
- if (!foundToX && to >= 0 && static_cast<unsigned>(to) < result->numCharacters())
- to = result->numCharacters() - to - 1;
- currentX -= result->width();
- }
- for (unsigned i = 0; i < result->m_runs.size(); i++) {
- if (!result->m_runs[i])
- continue;
- ASSERT((direction == RTL) == result->m_runs[i]->rtl());
- int numCharacters = result->m_runs[i]->m_numCharacters;
- if (!foundFromX && from >= 0 && from < numCharacters) {
- fromX = result->m_runs[i]->xPositionForVisualOffset(from) + currentX;
- foundFromX = true;
- } else {
- from -= numCharacters;
- }
-
- if (!foundToX && to >= 0 && to < numCharacters) {
- toX = result->m_runs[i]->xPositionForVisualOffset(to) + currentX;
- foundToX = true;
- } else {
- to -= numCharacters;
- }
-
- if (foundFromX && foundToX)
- break;
- currentX += result->m_runs[i]->m_width;
- }
- if (direction == RTL)
- currentX -= result->width();
- totalNumCharacters += result->numCharacters();
- }
-
- // The position in question might be just after the text.
- if (!foundFromX && absoluteFrom == totalNumCharacters) {
- fromX = direction == RTL ? 0 : totalWidth;
- foundFromX = true;
- }
- if (!foundToX && absoluteTo == totalNumCharacters) {
- toX = direction == RTL ? 0 : totalWidth;
- foundToX = true;
- }
- if (!foundFromX)
- fromX = 0;
- if (!foundToX)
- toX = direction == RTL ? 0 : totalWidth;
-
- // None of our runs is part of the selection, possibly invalid arguments.
- if (!foundToX && !foundFromX)
- fromX = toX = 0;
- if (fromX < toX)
- return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
- return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
-}
-
-int ShapeResult::offsetForPosition(Vector<RefPtr<ShapeResult>>& results,
- const TextRun& run, float targetX)
-{
- unsigned totalOffset;
- if (run.rtl()) {
- totalOffset = run.length();
- for (unsigned i = results.size(); i; --i) {
- const RefPtr<ShapeResult>& wordResult = results[i - 1];
- if (!wordResult)
- continue;
- totalOffset -= wordResult->numCharacters();
- if (targetX >= 0 && targetX <= wordResult->width()) {
- int offsetForWord = wordResult->offsetForPosition(targetX);
- return totalOffset + offsetForWord;
- }
- targetX -= wordResult->width();
- }
- } else {
- totalOffset = 0;
- for (auto& wordResult : results) {
- if (!wordResult)
- continue;
- int offsetForWord = wordResult->offsetForPosition(targetX);
- ASSERT(offsetForWord >= 0);
- totalOffset += offsetForWord;
- if (targetX >= 0 && targetX <= wordResult->width())
- return totalOffset;
- targetX -= wordResult->width();
- }
- }
- return totalOffset;
-}
-
-int ShapeResult::offsetForPosition(float targetX)
-{
- int charactersSoFar = 0;
- float currentX = 0;
-
- if (m_direction == RTL) {
- charactersSoFar = m_numCharacters;
- for (unsigned i = 0; i < m_runs.size(); ++i) {
- if (!m_runs[i])
- continue;
- charactersSoFar -= m_runs[i]->m_numCharacters;
- float nextX = currentX + m_runs[i]->m_width;
- float offsetForRun = targetX - currentX;
- if (offsetForRun >= 0 && offsetForRun <= m_runs[i]->m_width) {
- // The x value in question is within this script run.
- const unsigned index = m_runs[i]->characterIndexForXPosition(offsetForRun);
- return charactersSoFar + index;
- }
- currentX = nextX;
- }
- } else {
- for (unsigned i = 0; i < m_runs.size(); ++i) {
- if (!m_runs[i])
- continue;
- float nextX = currentX + m_runs[i]->m_width;
- float offsetForRun = targetX - currentX;
- if (offsetForRun >= 0 && offsetForRun <= m_runs[i]->m_width) {
- const unsigned index = m_runs[i]->characterIndexForXPosition(offsetForRun);
- return charactersSoFar + index;
- }
- charactersSoFar += m_runs[i]->m_numCharacters;
- currentX = nextX;
- }
- }
-
- return charactersSoFar;
-}
-
-void ShapeResult::fallbackFonts(HashSet<const SimpleFontData*>* fallback) const
-{
- ASSERT(fallback);
- ASSERT(m_primaryFont);
- for (unsigned i = 0; i < m_runs.size(); ++i) {
- if (m_runs[i] && m_runs[i]->m_fontData != m_primaryFont
- && !m_runs[i]->m_fontData->isTextOrientationFallbackOf(m_primaryFont.get())) {
- fallback->add(m_runs[i]->m_fontData.get());
- }
- }
-}
-
-unsigned ShapeResult::numberOfRunsForTesting() const
-{
- return m_runs.size();
-}
-
-bool ShapeResult::runInfoForTesting(unsigned runIndex, unsigned& startIndex,
- unsigned& numGlyphs, hb_script_t& script)
-{
- if (runIndex < m_runs.size() && m_runs[runIndex]) {
- startIndex = m_runs[runIndex]->m_startIndex;
- numGlyphs = m_runs[runIndex]->m_numGlyphs;
- script = m_runs[runIndex]->m_script;
- return true;
- }
- return false;
-}
-
-uint16_t ShapeResult::glyphForTesting(unsigned runIndex, size_t glyphIndex)
-{
- return m_runs[runIndex]->m_glyphData[glyphIndex].glyph;
-}
-
-float ShapeResult::advanceForTesting(unsigned runIndex, size_t glyphIndex)
-{
- return m_runs[runIndex]->m_glyphData[glyphIndex].advance;
-}
-
template<typename T>
class HarfBuzzScopedPtr {
public:
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h
index 71141f6..ea7817b 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h
@@ -32,6 +32,7 @@
#define HarfBuzzShaper_h
#include "hb.h"
+#include "platform/fonts/shaping/ShapeResult.h"
#include "platform/fonts/shaping/Shaper.h"
#include "platform/geometry/FloatPoint.h"
#include "platform/geometry/FloatRect.h"
@@ -52,70 +53,6 @@ class GlyphBuffer;
class SimpleFontData;
class HarfBuzzShaper;
-class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> {
-public:
- static PassRefPtr<ShapeResult> create(const Font* font,
- unsigned numCharacters, TextDirection direction)
- {
- return adoptRef(new ShapeResult(font, numCharacters, direction));
- }
- static PassRefPtr<ShapeResult> createForTabulationCharacters(const Font*,
- const TextRun&, float positionOffset, unsigned count);
- ~ShapeResult();
-
- float width() { return m_width; }
- FloatRect bounds() { return m_glyphBoundingBox; }
- unsigned numCharacters() const { return m_numCharacters; }
- void fallbackFonts(HashSet<const SimpleFontData*>*) const;
-
- static int offsetForPosition(Vector<RefPtr<ShapeResult>>&,
- const TextRun&, float targetX);
- static float fillGlyphBuffer(Vector<RefPtr<ShapeResult>>&,
- GlyphBuffer*, const TextRun&, unsigned from, unsigned to);
- static float fillGlyphBufferForTextEmphasis(Vector<RefPtr<ShapeResult>>&,
- GlyphBuffer*, const TextRun&, const GlyphData* emphasisData,
- unsigned from, unsigned to);
- static FloatRect selectionRect(Vector<RefPtr<ShapeResult>>&,
- TextDirection, float totalWidth, const FloatPoint&, int height,
- unsigned from, unsigned to);
-
- unsigned numberOfRunsForTesting() const;
- bool runInfoForTesting(unsigned runIndex, unsigned& startIndex,
- unsigned& numGlyphs, hb_script_t&);
- uint16_t glyphForTesting(unsigned runIndex, size_t glyphIndex);
- float advanceForTesting(unsigned runIndex, size_t glyphIndex);
-
-private:
- struct RunInfo;
-
- ShapeResult(const Font*, unsigned numCharacters, TextDirection);
-
- int offsetForPosition(float targetX);
- template<TextDirection>
- float fillGlyphBufferForRun(GlyphBuffer*, const RunInfo*,
- float initialAdvance, unsigned from, unsigned to, unsigned runOffset);
-
- float fillGlyphBufferForTextEmphasisRun(GlyphBuffer*, const RunInfo*,
- const TextRun&, const GlyphData*, float initialAdvance,
- unsigned from, unsigned to, unsigned runOffset);
-
- float m_width;
- FloatRect m_glyphBoundingBox;
- Vector<OwnPtr<RunInfo>> m_runs;
- RefPtr<SimpleFontData> m_primaryFont;
-
- unsigned m_numCharacters;
- unsigned m_numGlyphs : 31;
-
- // Overall direction for the TextRun, dictates which order each individual
- // sub run (represented by RunInfo structs in the m_runs vector) can have a
- // different text direction.
- unsigned m_direction : 1;
-
- friend class HarfBuzzShaper;
-};
-
-
// Shaping text runs is split into several stages: Run segmentation, shaping the
// initial segment, identify shaped and non-shaped sequences of the shaping
// result, and processing sub-runs by trying to shape them with a fallback font
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp
index e09e2fa..2d239f4 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp
@@ -8,6 +8,7 @@
#include "platform/fonts/Font.h"
#include "platform/fonts/FontCache.h"
#include "platform/fonts/GlyphPage.h"
+#include "platform/fonts/shaping/ShapeResultTestInfo.h"
#include "platform/text/TextRun.h"
#include "wtf/Vector.h"
#include <gtest/gtest.h>
@@ -37,6 +38,10 @@ protected:
hb_script_t script = HB_SCRIPT_INVALID;
};
+static inline ShapeResultTestInfo* testInfo(RefPtr<ShapeResult>& result)
+{
+ return static_cast<ShapeResultTestInfo*>(result.get());
+}
TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsLatin)
{
@@ -44,8 +49,8 @@ TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsLatin)
HarfBuzzShaper shaper(font, latinCommon);
RefPtr<ShapeResult> result = shaper.shapeResult();
- ASSERT_EQ(1u, result->numberOfRunsForTesting());
- ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+ ASSERT_EQ(1u, testInfo(result)->numberOfRunsForTesting());
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
EXPECT_EQ(0u, startIndex);
EXPECT_EQ(8u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_LATIN, script);
@@ -57,8 +62,8 @@ TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsLeadingCommon)
HarfBuzzShaper shaper(font, leadingCommon);
RefPtr<ShapeResult> result = shaper.shapeResult();
- ASSERT_EQ(1u, result->numberOfRunsForTesting());
- ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+ ASSERT_EQ(1u, testInfo(result)->numberOfRunsForTesting());
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
EXPECT_EQ(0u, startIndex);
EXPECT_EQ(8u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_LATIN, script);
@@ -83,8 +88,8 @@ TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsUnicodeVariants)
HarfBuzzShaper shaper(font, run);
RefPtr<ShapeResult> result = shaper.shapeResult();
- EXPECT_EQ(1u, result->numberOfRunsForTesting()) << test.name;
- ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script)) << test.name;
+ EXPECT_EQ(1u, testInfo(result)->numberOfRunsForTesting()) << test.name;
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script)) << test.name;
EXPECT_EQ(0u, startIndex) << test.name;
if (numGlyphs == 2) {
// If the specified VS is not in the font, it's mapped to .notdef.
@@ -93,9 +98,9 @@ TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsUnicodeVariants)
// OpenType recommends Glyph ID 3 for a space; not a hard requirement though.
// https://www.microsoft.com/typography/otspec/recom.htm
#if !OS(MACOSX)
- EXPECT_EQ(3u, result->glyphForTesting(0, 1)) << test.name;
+ EXPECT_EQ(3u, testInfo(result)->glyphForTesting(0, 1)) << test.name;
#endif
- EXPECT_EQ(0.f, result->advanceForTesting(0, 1)) << test.name;
+ EXPECT_EQ(0.f, testInfo(result)->advanceForTesting(0, 1)) << test.name;
} else {
EXPECT_EQ(1u, numGlyphs) << test.name;
}
@@ -110,13 +115,13 @@ TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsDevanagariCommon)
HarfBuzzShaper shaper(font, devanagariCommonLatin);
RefPtr<ShapeResult> result = shaper.shapeResult();
- ASSERT_EQ(2u, result->numberOfRunsForTesting());
- ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+ ASSERT_EQ(2u, testInfo(result)->numberOfRunsForTesting());
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
EXPECT_EQ(0u, startIndex);
EXPECT_EQ(1u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_DEVANAGARI, script);
- ASSERT_TRUE(result->runInfoForTesting(1, startIndex, numGlyphs, script));
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(1, startIndex, numGlyphs, script));
EXPECT_EQ(3u, startIndex);
EXPECT_EQ(3u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_DEVANAGARI, script);
@@ -129,18 +134,18 @@ TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsDevanagariCommonLatinCommon)
HarfBuzzShaper shaper(font, devanagariCommonLatin);
RefPtr<ShapeResult> result = shaper.shapeResult();
- ASSERT_EQ(3u, result->numberOfRunsForTesting());
- ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+ ASSERT_EQ(3u, testInfo(result)->numberOfRunsForTesting());
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
EXPECT_EQ(0u, startIndex);
EXPECT_EQ(1u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_DEVANAGARI, script);
- ASSERT_TRUE(result->runInfoForTesting(1, startIndex, numGlyphs, script));
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(1, startIndex, numGlyphs, script));
EXPECT_EQ(3u, startIndex);
EXPECT_EQ(1u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_DEVANAGARI, script);
- ASSERT_TRUE(result->runInfoForTesting(2, startIndex, numGlyphs, script));
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(2, startIndex, numGlyphs, script));
EXPECT_EQ(4u, startIndex);
EXPECT_EQ(3u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_LATIN, script);
@@ -153,23 +158,23 @@ TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsArabicThaiHanLatin)
HarfBuzzShaper shaper(font, mixed);
RefPtr<ShapeResult> result = shaper.shapeResult();
- ASSERT_EQ(4u, result->numberOfRunsForTesting());
- ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+ ASSERT_EQ(4u, testInfo(result)->numberOfRunsForTesting());
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
EXPECT_EQ(0u, startIndex);
EXPECT_EQ(3u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_ARABIC, script);
- ASSERT_TRUE(result->runInfoForTesting(1, startIndex, numGlyphs, script));
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(1, startIndex, numGlyphs, script));
EXPECT_EQ(3u, startIndex);
EXPECT_EQ(1u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_THAI, script);
- ASSERT_TRUE(result->runInfoForTesting(2, startIndex, numGlyphs, script));
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(2, startIndex, numGlyphs, script));
EXPECT_EQ(4u, startIndex);
EXPECT_EQ(1u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_HAN, script);
- ASSERT_TRUE(result->runInfoForTesting(3, startIndex, numGlyphs, script));
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(3, startIndex, numGlyphs, script));
EXPECT_EQ(5u, startIndex);
EXPECT_EQ(1u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_LATIN, script);
@@ -182,8 +187,8 @@ TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsArabic)
HarfBuzzShaper shaper(font, arabic);
RefPtr<ShapeResult> result = shaper.shapeResult();
- ASSERT_EQ(1u, result->numberOfRunsForTesting());
- ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+ ASSERT_EQ(1u, testInfo(result)->numberOfRunsForTesting());
+ ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
EXPECT_EQ(0u, startIndex);
EXPECT_EQ(3u, numGlyphs);
EXPECT_EQ(HB_SCRIPT_ARABIC, script);
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h
index ac8278c..9755ed3 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h
@@ -27,7 +27,7 @@
#ifndef ShapeCache_h
#define ShapeCache_h
-#include "platform/fonts/shaping/HarfBuzzShaper.h"
+#include "platform/fonts/shaping/ShapeResult.h"
#include "platform/text/TextRun.h"
#include "wtf/Forward.h"
#include "wtf/HashFunctions.h"
@@ -40,7 +40,6 @@ namespace blink {
class Font;
class GlyphBuffer;
class SimpleFontData;
-class HarfBuzzShaper;
struct ShapeCacheEntry {
ShapeCacheEntry()
@@ -171,10 +170,8 @@ private:
value = &addResult.storedValue->value;
}
- // Cache hit: ramp up by sampling the next few words.
- if (!isNewEntry) {
+ if (!isNewEntry)
return value;
- }
if (m_singleCharMap.size() + m_shortStringMap.size() < s_maxSize) {
return value;
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp
new file mode 100644
index 0000000..1d015a7
--- /dev/null
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "platform/fonts/shaping/ShapeResult.h"
+
+#include "platform/fonts/Font.h"
+#include "platform/fonts/GlyphBuffer.h"
+#include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
+#include "platform/text/TextBreakIterator.h"
+
+namespace blink {
+
+float ShapeResult::RunInfo::xPositionForVisualOffset(unsigned offset) const
+{
+ ASSERT(offset < m_numCharacters);
+ if (rtl())
+ offset = m_numCharacters - offset - 1;
+ return xPositionForOffset(offset);
+}
+
+float ShapeResult::RunInfo::xPositionForOffset(unsigned offset) const
+{
+ ASSERT(offset <= m_numCharacters);
+ unsigned glyphIndex = 0;
+ float position = 0;
+ if (rtl()) {
+ while (glyphIndex < m_numGlyphs && m_glyphData[glyphIndex].characterIndex > offset) {
+ position += m_glyphData[glyphIndex].advance;
+ ++glyphIndex;
+ }
+ // For RTL, we need to return the right side boundary of the character.
+ // Add advance of glyphs which are part of the character.
+ while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex) {
+ position += m_glyphData[glyphIndex].advance;
+ ++glyphIndex;
+ }
+ position += m_glyphData[glyphIndex].advance;
+ } else {
+ while (glyphIndex < m_numGlyphs && m_glyphData[glyphIndex].characterIndex < offset) {
+ position += m_glyphData[glyphIndex].advance;
+ ++glyphIndex;
+ }
+ }
+ return position;
+}
+
+int ShapeResult::RunInfo::characterIndexForXPosition(float targetX) const
+{
+ ASSERT(targetX <= m_width);
+ float currentX = 0;
+ float currentAdvance = m_glyphData[0].advance;
+ unsigned glyphIndex = 0;
+
+ // Sum up advances that belong to the first character.
+ while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex)
+ currentAdvance += m_glyphData[++glyphIndex].advance;
+ currentAdvance = currentAdvance / 2.0;
+ if (targetX <= currentAdvance)
+ return rtl() ? m_numCharacters : 0;
+
+ currentX = currentAdvance;
+ ++glyphIndex;
+ while (glyphIndex < m_numGlyphs) {
+ unsigned prevCharacterIndex = m_glyphData[glyphIndex - 1].characterIndex;
+ float prevAdvance = currentAdvance;
+ currentAdvance = m_glyphData[glyphIndex].advance;
+ while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex)
+ currentAdvance += m_glyphData[++glyphIndex].advance;
+ currentAdvance = currentAdvance / 2.0;
+ float nextX = currentX + prevAdvance + currentAdvance;
+ if (currentX <= targetX && targetX <= nextX)
+ return rtl() ? prevCharacterIndex : m_glyphData[glyphIndex].characterIndex;
+ currentX = nextX;
+ ++glyphIndex;
+ }
+
+ return rtl() ? 0 : m_numCharacters;
+}
+
+void ShapeResult::RunInfo::setGlyphAndPositions(unsigned index,
+ uint16_t glyphId, float advance, float offsetX, float offsetY)
+{
+ HarfBuzzRunGlyphData& data = m_glyphData[index];
+ data.glyph = glyphId;
+ data.advance = advance;
+ data.offset = FloatSize(offsetX, offsetY);
+}
+
+ShapeResult::ShapeResult(const Font* font, unsigned numCharacters, TextDirection direction)
+ : m_width(0)
+ , m_primaryFont(const_cast<SimpleFontData*>(font->primaryFont()))
+ , m_numCharacters(numCharacters)
+ , m_numGlyphs(0)
+ , m_direction(direction)
+{
+}
+
+ShapeResult::~ShapeResult()
+{
+}
+
+static inline void addGlyphToBuffer(GlyphBuffer* glyphBuffer, float advance,
+ hb_direction_t direction, const SimpleFontData* fontData,
+ const HarfBuzzRunGlyphData& glyphData)
+{
+ FloatPoint startOffset = HB_DIRECTION_IS_HORIZONTAL(direction)
+ ? FloatPoint(advance, 0)
+ : FloatPoint(0, advance);
+ glyphBuffer->add(glyphData.glyph, fontData, startOffset + glyphData.offset);
+}
+
+template<TextDirection direction>
+float ShapeResult::fillGlyphBufferForRun(GlyphBuffer* glyphBuffer,
+ const RunInfo* run, float initialAdvance, unsigned from, unsigned to,
+ unsigned runOffset)
+{
+ if (!run)
+ return 0;
+ float advanceSoFar = initialAdvance;
+ unsigned numGlyphs = run->m_numGlyphs;
+ for (unsigned i = 0; i < numGlyphs; ++i) {
+ const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i];
+ uint16_t currentCharacterIndex = run->m_startIndex +
+ glyphData.characterIndex + runOffset;
+ if ((direction == RTL && currentCharacterIndex >= to)
+ || (direction == LTR && currentCharacterIndex < from)) {
+ advanceSoFar += glyphData.advance;
+ } else if ((direction == RTL && currentCharacterIndex >= from)
+ || (direction == LTR && currentCharacterIndex < to)) {
+ addGlyphToBuffer(glyphBuffer, advanceSoFar, run->m_direction,
+ run->m_fontData.get(), glyphData);
+ advanceSoFar += glyphData.advance;
+ }
+ }
+ return advanceSoFar - initialAdvance;
+}
+
+static inline unsigned countGraphemesInCluster(const UChar* str,
+ unsigned strLength, uint16_t startIndex, uint16_t endIndex)
+{
+ if (startIndex > endIndex) {
+ uint16_t tempIndex = startIndex;
+ startIndex = endIndex;
+ endIndex = tempIndex;
+ }
+ uint16_t length = endIndex - startIndex;
+ ASSERT(static_cast<unsigned>(startIndex + length) <= strLength);
+ TextBreakIterator* cursorPosIterator = cursorMovementIterator(&str[startIndex], length);
+
+ int cursorPos = cursorPosIterator->current();
+ int numGraphemes = -1;
+ while (0 <= cursorPos) {
+ cursorPos = cursorPosIterator->next();
+ numGraphemes++;
+ }
+ return std::max(0, numGraphemes);
+}
+
+static inline void addEmphasisMark(GlyphBuffer* buffer,
+ const GlyphData* emphasisData, FloatPoint glyphCenter,
+ float midGlyphOffset)
+{
+ ASSERT(buffer);
+ ASSERT(emphasisData);
+
+ const SimpleFontData* emphasisFontData = emphasisData->fontData;
+ ASSERT(emphasisFontData);
+
+ bool isVertical = emphasisFontData->platformData().isVerticalAnyUpright()
+ && emphasisFontData->verticalData();
+
+ if (!isVertical) {
+ buffer->add(emphasisData->glyph, emphasisFontData,
+ midGlyphOffset - glyphCenter.x());
+ } else {
+ buffer->add(emphasisData->glyph, emphasisFontData,
+ FloatPoint(-glyphCenter.x(), midGlyphOffset - glyphCenter.y()));
+ }
+}
+
+float ShapeResult::fillGlyphBufferForTextEmphasisRun(GlyphBuffer* glyphBuffer,
+ const RunInfo* run, const TextRun& textRun, const GlyphData* emphasisData,
+ float initialAdvance, unsigned from, unsigned to, unsigned runOffset)
+{
+ if (!run)
+ return 0;
+
+ unsigned graphemesInCluster = 1;
+ float clusterAdvance = 0;
+
+ FloatPoint glyphCenter = emphasisData->fontData->
+ boundsForGlyph(emphasisData->glyph).center();
+
+ TextDirection direction = textRun.direction();
+
+ // A "cluster" in this context means a cluster as it is used by HarfBuzz:
+ // The minimal group of characters and corresponding glyphs, that cannot be broken
+ // down further from a text shaping point of view.
+ // A cluster can contain multiple glyphs and grapheme clusters, with mutually
+ // overlapping boundaries. Below we count grapheme clusters per HarfBuzz clusters,
+ // then linearly split the sum of corresponding glyph advances by the number of
+ // grapheme clusters in order to find positions for emphasis mark drawing.
+ uint16_t clusterStart = direction == RTL
+ ? run->m_startIndex + run->m_numCharacters + runOffset
+ : run->glyphToCharacterIndex(0) + runOffset;
+
+ float advanceSoFar = initialAdvance;
+ unsigned numGlyphs = run->m_numGlyphs;
+ for (unsigned i = 0; i < numGlyphs; ++i) {
+ const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i];
+ uint16_t currentCharacterIndex = run->m_startIndex + glyphData.characterIndex + runOffset;
+ bool isRunEnd = (i + 1 == numGlyphs);
+ bool isClusterEnd = isRunEnd || (run->glyphToCharacterIndex(i + 1) + runOffset != currentCharacterIndex);
+
+ if ((direction == RTL && currentCharacterIndex >= to) || (direction != RTL && currentCharacterIndex < from)) {
+ advanceSoFar += glyphData.advance;
+ direction == RTL ? --clusterStart : ++clusterStart;
+ continue;
+ }
+
+ clusterAdvance += glyphData.advance;
+
+ if (textRun.is8Bit()) {
+ float glyphAdvanceX = glyphData.advance;
+ if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex])) {
+ addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceSoFar + glyphAdvanceX / 2);
+ }
+ advanceSoFar += glyphAdvanceX;
+ } else if (isClusterEnd) {
+ uint16_t clusterEnd;
+ if (direction == RTL)
+ clusterEnd = currentCharacterIndex;
+ else
+ clusterEnd = isRunEnd ? run->m_startIndex + run->m_numCharacters + runOffset : run->glyphToCharacterIndex(i + 1) + runOffset;
+
+ graphemesInCluster = countGraphemesInCluster(textRun.characters16(), textRun.charactersLength(), clusterStart, clusterEnd);
+ if (!graphemesInCluster || !clusterAdvance)
+ continue;
+
+ float glyphAdvanceX = clusterAdvance / graphemesInCluster;
+ for (unsigned j = 0; j < graphemesInCluster; ++j) {
+ // Do not put emphasis marks on space, separator, and control characters.
+ if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex]))
+ addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceSoFar + glyphAdvanceX / 2);
+ advanceSoFar += glyphAdvanceX;
+ }
+ clusterStart = clusterEnd;
+ clusterAdvance = 0;
+ }
+ }
+ return advanceSoFar - initialAdvance;
+}
+
+float ShapeResult::fillGlyphBuffer(Vector<RefPtr<ShapeResult>>& results,
+ GlyphBuffer* glyphBuffer, const TextRun& textRun,
+ unsigned from, unsigned to)
+{
+ float advance = 0;
+ if (textRun.rtl()) {
+ unsigned wordOffset = textRun.length();
+ for (unsigned j = 0; j < results.size(); j++) {
+ unsigned resolvedIndex = results.size() - 1 - j;
+ RefPtr<ShapeResult>& wordResult = results[resolvedIndex];
+ for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
+ advance += wordResult->fillGlyphBufferForRun<RTL>(glyphBuffer,
+ wordResult->m_runs[i].get(), advance, from, to,
+ wordOffset - wordResult->numCharacters());
+ }
+ wordOffset -= wordResult->numCharacters();
+ }
+ } else {
+ unsigned wordOffset = 0;
+ for (unsigned j = 0; j < results.size(); j++) {
+ RefPtr<ShapeResult>& wordResult = results[j];
+ for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
+ advance += wordResult->fillGlyphBufferForRun<LTR>(glyphBuffer,
+ wordResult->m_runs[i].get(), advance, from, to, wordOffset);
+ }
+ wordOffset += wordResult->numCharacters();
+ }
+ }
+
+ return advance;
+}
+
+float ShapeResult::fillGlyphBufferForTextEmphasis(
+ Vector<RefPtr<ShapeResult>>& results, GlyphBuffer* glyphBuffer,
+ const TextRun& textRun, const GlyphData* emphasisData,
+ unsigned from, unsigned to)
+{
+ float advance = 0;
+ unsigned wordOffset = textRun.rtl() ? textRun.length() : 0;
+ for (unsigned j = 0; j < results.size(); j++) {
+ unsigned resolvedIndex = textRun.rtl() ? results.size() - 1 - j : j;
+ RefPtr<ShapeResult>& wordResult = results[resolvedIndex];
+ for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
+ unsigned resolvedOffset = wordOffset -
+ (textRun.rtl() ? wordResult->numCharacters() : 0);
+ advance += wordResult->fillGlyphBufferForTextEmphasisRun(
+ glyphBuffer, wordResult->m_runs[i].get(), textRun, emphasisData,
+ advance, from, to, resolvedOffset);
+ }
+ wordOffset += wordResult->numCharacters() * (textRun.rtl() ? -1 : 1);
+ }
+
+ return advance;
+}
+
+FloatRect ShapeResult::selectionRect(Vector<RefPtr<ShapeResult>>& results,
+ TextDirection direction, float totalWidth, const FloatPoint& point,
+ int height, unsigned absoluteFrom, unsigned absoluteTo)
+{
+ float currentX = 0;
+ float fromX = 0;
+ float toX = 0;
+ bool foundFromX = false;
+ bool foundToX = false;
+
+ if (direction == RTL)
+ currentX = totalWidth;
+
+ // The absoluteFrom and absoluteTo arguments represent the start/end offset
+ // for the entire run, from/to are continuously updated to be relative to
+ // the current word (ShapeResult instance).
+ int from = absoluteFrom;
+ int to = absoluteTo;
+
+ unsigned totalNumCharacters = 0;
+ for (unsigned j = 0; j < results.size(); j++) {
+ RefPtr<ShapeResult> result = results[j];
+ if (direction == RTL) {
+ // Convert logical offsets to visual offsets, because results are in
+ // logical order while runs are in visual order.
+ if (!foundFromX && from >= 0 && static_cast<unsigned>(from) < result->numCharacters())
+ from = result->numCharacters() - from - 1;
+ if (!foundToX && to >= 0 && static_cast<unsigned>(to) < result->numCharacters())
+ to = result->numCharacters() - to - 1;
+ currentX -= result->width();
+ }
+ for (unsigned i = 0; i < result->m_runs.size(); i++) {
+ if (!result->m_runs[i])
+ continue;
+ ASSERT((direction == RTL) == result->m_runs[i]->rtl());
+ int numCharacters = result->m_runs[i]->m_numCharacters;
+ if (!foundFromX && from >= 0 && from < numCharacters) {
+ fromX = result->m_runs[i]->xPositionForVisualOffset(from) + currentX;
+ foundFromX = true;
+ } else {
+ from -= numCharacters;
+ }
+
+ if (!foundToX && to >= 0 && to < numCharacters) {
+ toX = result->m_runs[i]->xPositionForVisualOffset(to) + currentX;
+ foundToX = true;
+ } else {
+ to -= numCharacters;
+ }
+
+ if (foundFromX && foundToX)
+ break;
+ currentX += result->m_runs[i]->m_width;
+ }
+ if (direction == RTL)
+ currentX -= result->width();
+ totalNumCharacters += result->numCharacters();
+ }
+
+ // The position in question might be just after the text.
+ if (!foundFromX && absoluteFrom == totalNumCharacters) {
+ fromX = direction == RTL ? 0 : totalWidth;
+ foundFromX = true;
+ }
+ if (!foundToX && absoluteTo == totalNumCharacters) {
+ toX = direction == RTL ? 0 : totalWidth;
+ foundToX = true;
+ }
+ if (!foundFromX)
+ fromX = 0;
+ if (!foundToX)
+ toX = direction == RTL ? 0 : totalWidth;
+
+ // None of our runs is part of the selection, possibly invalid arguments.
+ if (!foundToX && !foundFromX)
+ fromX = toX = 0;
+ if (fromX < toX)
+ return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
+ return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
+}
+
+int ShapeResult::offsetForPosition(Vector<RefPtr<ShapeResult>>& results,
+ const TextRun& run, float targetX)
+{
+ unsigned totalOffset;
+ if (run.rtl()) {
+ totalOffset = run.length();
+ for (unsigned i = results.size(); i; --i) {
+ const RefPtr<ShapeResult>& wordResult = results[i - 1];
+ if (!wordResult)
+ continue;
+ totalOffset -= wordResult->numCharacters();
+ if (targetX >= 0 && targetX <= wordResult->width()) {
+ int offsetForWord = wordResult->offsetForPosition(targetX);
+ return totalOffset + offsetForWord;
+ }
+ targetX -= wordResult->width();
+ }
+ } else {
+ totalOffset = 0;
+ for (auto& wordResult : results) {
+ if (!wordResult)
+ continue;
+ int offsetForWord = wordResult->offsetForPosition(targetX);
+ ASSERT(offsetForWord >= 0);
+ totalOffset += offsetForWord;
+ if (targetX >= 0 && targetX <= wordResult->width())
+ return totalOffset;
+ targetX -= wordResult->width();
+ }
+ }
+ return totalOffset;
+}
+
+int ShapeResult::offsetForPosition(float targetX)
+{
+ int charactersSoFar = 0;
+ float currentX = 0;
+
+ if (m_direction == RTL) {
+ charactersSoFar = m_numCharacters;
+ for (unsigned i = 0; i < m_runs.size(); ++i) {
+ if (!m_runs[i])
+ continue;
+ charactersSoFar -= m_runs[i]->m_numCharacters;
+ float nextX = currentX + m_runs[i]->m_width;
+ float offsetForRun = targetX - currentX;
+ if (offsetForRun >= 0 && offsetForRun <= m_runs[i]->m_width) {
+ // The x value in question is within this script run.
+ const unsigned index = m_runs[i]->characterIndexForXPosition(offsetForRun);
+ return charactersSoFar + index;
+ }
+ currentX = nextX;
+ }
+ } else {
+ for (unsigned i = 0; i < m_runs.size(); ++i) {
+ if (!m_runs[i])
+ continue;
+ float nextX = currentX + m_runs[i]->m_width;
+ float offsetForRun = targetX - currentX;
+ if (offsetForRun >= 0 && offsetForRun <= m_runs[i]->m_width) {
+ const unsigned index = m_runs[i]->characterIndexForXPosition(offsetForRun);
+ return charactersSoFar + index;
+ }
+ charactersSoFar += m_runs[i]->m_numCharacters;
+ currentX = nextX;
+ }
+ }
+
+ return charactersSoFar;
+}
+
+void ShapeResult::fallbackFonts(HashSet<const SimpleFontData*>* fallback) const
+{
+ ASSERT(fallback);
+ ASSERT(m_primaryFont);
+ for (unsigned i = 0; i < m_runs.size(); ++i) {
+ if (m_runs[i] && m_runs[i]->m_fontData != m_primaryFont
+ && !m_runs[i]->m_fontData->isTextOrientationFallbackOf(m_primaryFont.get())) {
+ fallback->add(m_runs[i]->m_fontData.get());
+ }
+ }
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h
new file mode 100644
index 0000000..811232c
--- /dev/null
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ShapeResult_h
+#define ShapeResult_h
+
+#include "platform/geometry/FloatPoint.h"
+#include "platform/geometry/FloatRect.h"
+#include "platform/text/TextRun.h"
+#include "wtf/HashSet.h"
+#include "wtf/OwnPtr.h"
+#include "wtf/Vector.h"
+
+namespace blink {
+
+class Font;
+class GlyphBuffer;
+class SimpleFontData;
+class HarfBuzzShaper;
+struct GlyphData;
+
+class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> {
+public:
+ static PassRefPtr<ShapeResult> create(const Font* font,
+ unsigned numCharacters, TextDirection direction)
+ {
+ return adoptRef(new ShapeResult(font, numCharacters, direction));
+ }
+ static PassRefPtr<ShapeResult> createForTabulationCharacters(const Font*,
+ const TextRun&, float positionOffset, unsigned count);
+ ~ShapeResult();
+
+ float width() { return m_width; }
+ FloatRect bounds() { return m_glyphBoundingBox; }
+ unsigned numCharacters() const { return m_numCharacters; }
+ void fallbackFonts(HashSet<const SimpleFontData*>*) const;
+
+ static int offsetForPosition(Vector<RefPtr<ShapeResult>>&,
+ const TextRun&, float targetX);
+ static float fillGlyphBuffer(Vector<RefPtr<ShapeResult>>&,
+ GlyphBuffer*, const TextRun&, unsigned from, unsigned to);
+ static float fillGlyphBufferForTextEmphasis(Vector<RefPtr<ShapeResult>>&,
+ GlyphBuffer*, const TextRun&, const GlyphData* emphasisData,
+ unsigned from, unsigned to);
+ static FloatRect selectionRect(Vector<RefPtr<ShapeResult>>&,
+ TextDirection, float totalWidth, const FloatPoint&, int height,
+ unsigned from, unsigned to);
+
+protected:
+ struct RunInfo;
+
+ ShapeResult(const Font*, unsigned numCharacters, TextDirection);
+
+ int offsetForPosition(float targetX);
+ template<TextDirection>
+ float fillGlyphBufferForRun(GlyphBuffer*, const RunInfo*,
+ float initialAdvance, unsigned from, unsigned to, unsigned runOffset);
+
+ float fillGlyphBufferForTextEmphasisRun(GlyphBuffer*, const RunInfo*,
+ const TextRun&, const GlyphData*, float initialAdvance,
+ unsigned from, unsigned to, unsigned runOffset);
+
+ float m_width;
+ FloatRect m_glyphBoundingBox;
+ Vector<OwnPtr<RunInfo>> m_runs;
+ RefPtr<SimpleFontData> m_primaryFont;
+
+ unsigned m_numCharacters;
+ unsigned m_numGlyphs : 31;
+
+ // Overall direction for the TextRun, dictates which order each individual
+ // sub run (represented by RunInfo structs in the m_runs vector) can have a
+ // different text direction.
+ unsigned m_direction : 1;
+
+ friend class HarfBuzzShaper;
+};
+
+} // namespace blink
+
+#endif // ShapeResult_h
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultInlineHeaders.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultInlineHeaders.h
new file mode 100644
index 0000000..c0985a2
--- /dev/null
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultInlineHeaders.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ShapeResultInlineHeaders_h
+#define ShapeResultInlineHeaders_h
+
+#include "platform/fonts/shaping/ShapeResult.h"
+
+#include <hb.h>
+
+namespace blink {
+
+class Font;
+class GlyphBuffer;
+class SimpleFontData;
+class HarfBuzzShaper;
+
+struct HarfBuzzRunGlyphData {
+ uint16_t glyph;
+ uint16_t characterIndex;
+ float advance;
+ FloatSize offset;
+};
+
+struct ShapeResult::RunInfo {
+ RunInfo(const SimpleFontData* font, hb_direction_t dir, hb_script_t script,
+ unsigned startIndex, unsigned numGlyphs, unsigned numCharacters)
+ : m_fontData(const_cast<SimpleFontData*>(font)), m_direction(dir)
+ , m_script(script), m_startIndex(startIndex)
+ , m_numCharacters(numCharacters) , m_numGlyphs(numGlyphs), m_width(0.0f)
+ {
+ m_glyphData.resize(m_numGlyphs);
+ }
+
+ bool rtl() const { return HB_DIRECTION_IS_BACKWARD(m_direction); }
+ float xPositionForVisualOffset(unsigned) const;
+ float xPositionForOffset(unsigned) const;
+ int characterIndexForXPosition(float) const;
+ void setGlyphAndPositions(unsigned index, uint16_t glyphId, float advance,
+ float offsetX, float offsetY);
+
+ void addAdvance(unsigned index, float advance)
+ {
+ m_glyphData[index].advance += advance;
+ }
+
+ size_t glyphToCharacterIndex(size_t i) const
+ {
+ return m_startIndex + m_glyphData[i].characterIndex;
+ }
+
+ RefPtr<SimpleFontData> m_fontData;
+ hb_direction_t m_direction;
+ hb_script_t m_script;
+ Vector<HarfBuzzRunGlyphData> m_glyphData;
+ unsigned m_startIndex;
+ unsigned m_numCharacters;
+ unsigned m_numGlyphs;
+ float m_width;
+};
+
+} // namespace blink
+
+#endif // ShapeResultInlineHeaders_h
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.cpp
new file mode 100644
index 0000000..e9fedda
--- /dev/null
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.cpp
@@ -0,0 +1,42 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "platform/fonts/shaping/ShapeResultTestInfo.h"
+
+#include "platform/fonts/Font.h"
+#include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
+
+namespace blink {
+
+unsigned ShapeResultTestInfo::numberOfRunsForTesting() const
+{
+ return m_runs.size();
+}
+
+bool ShapeResultTestInfo::runInfoForTesting(unsigned runIndex,
+ unsigned& startIndex, unsigned& numGlyphs, hb_script_t& script)
+{
+ if (runIndex < m_runs.size() && m_runs[runIndex]) {
+ startIndex = m_runs[runIndex]->m_startIndex;
+ numGlyphs = m_runs[runIndex]->m_numGlyphs;
+ script = m_runs[runIndex]->m_script;
+ return true;
+ }
+ return false;
+}
+
+uint16_t ShapeResultTestInfo::glyphForTesting(unsigned runIndex,
+ size_t glyphIndex)
+{
+ return m_runs[runIndex]->m_glyphData[glyphIndex].glyph;
+}
+
+float ShapeResultTestInfo::advanceForTesting(unsigned runIndex,
+ size_t glyphIndex)
+{
+ return m_runs[runIndex]->m_glyphData[glyphIndex].advance;
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.h
new file mode 100644
index 0000000..d8dd283
--- /dev/null
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.h
@@ -0,0 +1,25 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ShapeResultTestInfo_h
+#define ShapeResultTestInfo_h
+
+#include "platform/fonts/shaping/HarfBuzzShaper.h"
+
+#include <hb.h>
+
+namespace blink {
+
+class PLATFORM_EXPORT ShapeResultTestInfo : public ShapeResult {
+public:
+ unsigned numberOfRunsForTesting() const;
+ bool runInfoForTesting(unsigned runIndex, unsigned& startIndex,
+ unsigned& numGlyphs, hb_script_t&);
+ uint16_t glyphForTesting(unsigned runIndex, size_t glyphIndex);
+ float advanceForTesting(unsigned runIndex, size_t glyphIndex);
+};
+
+} // namespace blink
+
+#endif // ShapeResultTestInfo_h
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/Shaper.cpp b/third_party/WebKit/Source/platform/fonts/shaping/Shaper.cpp
index d3c0db4..3a63f49 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/Shaper.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/Shaper.cpp
@@ -31,6 +31,7 @@
#include "config.h"
#include "platform/fonts/shaping/Shaper.h"
+#include "platform/fonts/Font.h"
#include "platform/fonts/GlyphBuffer.h"
#include "platform/fonts/GlyphPage.h"
#include "platform/text/TextRun.h"
@@ -74,4 +75,14 @@ void Shaper::addEmphasisMark(GlyphBuffer* buffer, float midGlyphOffset) const
}
}
+void Shaper::trackNonPrimaryFallbackFont(const SimpleFontData* fontData)
+{
+ ASSERT(m_fallbackFonts);
+
+ if (fontData == m_font->primaryFont())
+ return;
+
+ m_fallbackFonts->add(fontData);
+}
+
} // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/Shaper.h b/third_party/WebKit/Source/platform/fonts/shaping/Shaper.h
index 42fc1fe..ba3b5fb 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/Shaper.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/Shaper.h
@@ -32,12 +32,13 @@
#define Shaper_h
#include "platform/PlatformExport.h"
-#include "platform/fonts/Font.h"
+#include "platform/geometry/FloatPoint.h"
#include "wtf/HashSet.h"
namespace blink {
class FloatRect;
+class Font;
class GlyphBuffer;
class SimpleFontData;
class TextRun;
@@ -70,16 +71,6 @@ private:
FloatPoint m_emphasisGlyphCenter;
};
-inline void Shaper::trackNonPrimaryFallbackFont(const SimpleFontData* fontData)
-{
- ASSERT(m_fallbackFonts);
-
- if (fontData == m_font->primaryFont())
- return;
-
- m_fallbackFonts->add(fontData);
-}
-
} // namespace blink
#endif // Shaper_h