OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2012 Google Inc. All rights reserved. | 2 * Copyright (c) 2012 Google Inc. All rights reserved. |
3 * Copyright (C) 2013 BlackBerry Limited. All rights reserved. | 3 * Copyright (C) 2013 BlackBerry Limited. All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are | 6 * modification, are permitted provided that the following conditions are |
7 * met: | 7 * met: |
8 * | 8 * |
9 * * Redistributions of source code must retain the above copyright | 9 * * Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
(...skipping 20 matching lines...) Expand all Loading... | |
31 | 31 |
32 #include "config.h" | 32 #include "config.h" |
33 #include "platform/fonts/harfbuzz/HarfBuzzShaper.h" | 33 #include "platform/fonts/harfbuzz/HarfBuzzShaper.h" |
34 | 34 |
35 #include "RuntimeEnabledFeatures.h" | 35 #include "RuntimeEnabledFeatures.h" |
36 #include "hb-icu.h" | 36 #include "hb-icu.h" |
37 #include "platform/fonts/Character.h" | 37 #include "platform/fonts/Character.h" |
38 #include "platform/fonts/Font.h" | 38 #include "platform/fonts/Font.h" |
39 #include "platform/fonts/harfbuzz/HarfBuzzFace.h" | 39 #include "platform/fonts/harfbuzz/HarfBuzzFace.h" |
40 #include "platform/text/SurrogatePairAwareTextIterator.h" | 40 #include "platform/text/SurrogatePairAwareTextIterator.h" |
41 #include "platform/text/TextBreakIterator.h" | |
41 #include "wtf/MathExtras.h" | 42 #include "wtf/MathExtras.h" |
42 #include "wtf/unicode/Unicode.h" | 43 #include "wtf/unicode/Unicode.h" |
43 #include <unicode/normlzr.h> | 44 #include <unicode/normlzr.h> |
44 #include <unicode/uchar.h> | 45 #include <unicode/uchar.h> |
45 | 46 |
46 #include <list> | 47 #include <list> |
47 #include <map> | 48 #include <map> |
48 #include <string> | 49 #include <string> |
49 | 50 |
50 namespace WebCore { | 51 namespace WebCore { |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
201 { | 202 { |
202 DEFINE_STATIC_LOCAL(HarfBuzzRunCache, globalHarfBuzzRunCache, ()); | 203 DEFINE_STATIC_LOCAL(HarfBuzzRunCache, globalHarfBuzzRunCache, ()); |
203 return globalHarfBuzzRunCache; | 204 return globalHarfBuzzRunCache; |
204 } | 205 } |
205 | 206 |
206 static inline float harfBuzzPositionToFloat(hb_position_t value) | 207 static inline float harfBuzzPositionToFloat(hb_position_t value) |
207 { | 208 { |
208 return static_cast<float>(value) / (1 << 16); | 209 return static_cast<float>(value) / (1 << 16); |
209 } | 210 } |
210 | 211 |
212 static inline unsigned countGraphemesInCluster(const TextRun& run, uint16_t star tIndex, uint16_t endIndex) | |
213 { | |
214 if (startIndex > endIndex) { | |
215 uint16_t tempIndex = startIndex; | |
216 startIndex = endIndex; | |
217 endIndex = tempIndex; | |
218 } | |
219 uint16_t length = endIndex - startIndex; | |
220 TextRun subRun = run.subRun(startIndex, length); | |
221 | |
222 const UChar* source; | |
223 String stringFor8BitRun; | |
224 if (run.is8Bit()) { | |
225 stringFor8BitRun = String::make16BitFrom8BitSource(subRun.characters8(), subRun.length()); | |
eae
2014/02/14 11:15:35
I don't suppose we could have this method use m_no
| |
226 source = stringFor8BitRun.characters16(); | |
227 } else { | |
228 source = subRun.characters16(); | |
229 } | |
230 TextBreakIterator* cursorPosIterator = cursorMovementIterator(source, subRun .length()); | |
231 | |
232 int cursorPos = cursorPosIterator->current(); | |
233 int numGraphemes = -1; | |
234 while (0 <= cursorPos) { | |
235 cursorPos = cursorPosIterator->next(); | |
236 numGraphemes++; | |
237 } | |
238 return numGraphemes < 0 ? 0 : numGraphemes; | |
239 } | |
240 | |
211 inline HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const SimpleFontData* fontData, unsigned startIndex, unsigned numCharacters, TextDirection direction, hb_script_ t script) | 241 inline HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const SimpleFontData* fontData, unsigned startIndex, unsigned numCharacters, TextDirection direction, hb_script_ t script) |
212 : m_fontData(fontData) | 242 : m_fontData(fontData) |
213 , m_startIndex(startIndex) | 243 , m_startIndex(startIndex) |
214 , m_numCharacters(numCharacters) | 244 , m_numCharacters(numCharacters) |
215 , m_numGlyphs(0) | 245 , m_numGlyphs(0) |
216 , m_direction(direction) | 246 , m_direction(direction) |
217 , m_script(script) | 247 , m_script(script) |
218 , m_width(0) | 248 , m_width(0) |
219 { | 249 { |
220 } | 250 } |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
342 // Don't normalize tabs as they are not treated as spaces for word-end. | 372 // Don't normalize tabs as they are not treated as spaces for word-end. |
343 if (Character::treatAsSpace(character) && character != '\t') | 373 if (Character::treatAsSpace(character) && character != '\t') |
344 character = ' '; | 374 character = ' '; |
345 else if (Character::treatAsZeroWidthSpaceInComplexScript(character)) | 375 else if (Character::treatAsZeroWidthSpaceInComplexScript(character)) |
346 character = zeroWidthSpace; | 376 character = zeroWidthSpace; |
347 U16_APPEND(destination, *destinationLength, length, character, error); | 377 U16_APPEND(destination, *destinationLength, length, character, error); |
348 ASSERT_UNUSED(error, !error); | 378 ASSERT_UNUSED(error, !error); |
349 } | 379 } |
350 } | 380 } |
351 | 381 |
352 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run) | 382 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run, ForTextEmph asisOrNot forTextEmphasis) |
353 : m_font(font) | 383 : m_font(font) |
354 , m_normalizedBufferLength(0) | 384 , m_normalizedBufferLength(0) |
355 , m_run(run) | 385 , m_run(run) |
356 , m_wordSpacingAdjustment(font->fontDescription().wordSpacing()) | 386 , m_wordSpacingAdjustment(font->fontDescription().wordSpacing()) |
357 , m_padding(0) | 387 , m_padding(0) |
358 , m_padPerWordBreak(0) | 388 , m_padPerWordBreak(0) |
359 , m_padError(0) | 389 , m_padError(0) |
360 , m_letterSpacing(font->fontDescription().letterSpacing()) | 390 , m_letterSpacing(font->fontDescription().letterSpacing()) |
361 , m_fromIndex(0) | 391 , m_fromIndex(0) |
362 , m_toIndex(m_run.length()) | 392 , m_toIndex(m_run.length()) |
393 , m_forTextEmphasis(forTextEmphasis) | |
363 { | 394 { |
364 m_normalizedBuffer = adoptArrayPtr(new UChar[m_run.length() + 1]); | 395 m_normalizedBuffer = adoptArrayPtr(new UChar[m_run.length() + 1]); |
365 normalizeCharacters(m_run, m_run.length(), m_normalizedBuffer.get(), &m_norm alizedBufferLength); | 396 normalizeCharacters(m_run, m_run.length(), m_normalizedBuffer.get(), &m_norm alizedBufferLength); |
366 setPadding(m_run.expansion()); | 397 setPadding(m_run.expansion()); |
367 setFontFeatures(); | 398 setFontFeatures(); |
368 } | 399 } |
369 | 400 |
370 static void normalizeSpacesAndMirrorChars(const UChar* source, unsigned length, UChar* destination, unsigned* destinationLength, HarfBuzzShaper::NormalizeMode n ormalizeMode) | 401 static void normalizeSpacesAndMirrorChars(const UChar* source, unsigned length, UChar* destination, unsigned* destinationLength, HarfBuzzShaper::NormalizeMode n ormalizeMode) |
371 { | 402 { |
372 unsigned position = 0; | 403 unsigned position = 0; |
(...skipping 575 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
948 m_totalWidth += currentRun->width(); | 979 m_totalWidth += currentRun->width(); |
949 } | 980 } |
950 | 981 |
951 void HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, Ha rfBuzzRun* currentRun, FloatPoint& firstOffsetOfNextRun) | 982 void HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, Ha rfBuzzRun* currentRun, FloatPoint& firstOffsetOfNextRun) |
952 { | 983 { |
953 FloatPoint* offsets = currentRun->offsets(); | 984 FloatPoint* offsets = currentRun->offsets(); |
954 uint16_t* glyphs = currentRun->glyphs(); | 985 uint16_t* glyphs = currentRun->glyphs(); |
955 float* advances = currentRun->advances(); | 986 float* advances = currentRun->advances(); |
956 unsigned numGlyphs = currentRun->numGlyphs(); | 987 unsigned numGlyphs = currentRun->numGlyphs(); |
957 uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes(); | 988 uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes(); |
958 | |
959 for (unsigned i = 0; i < numGlyphs; ++i) { | 989 for (unsigned i = 0; i < numGlyphs; ++i) { |
960 uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToChara cterIndexes[i]; | 990 uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToChara cterIndexes[i]; |
961 FloatPoint& currentOffset = offsets[i]; | 991 FloatPoint& currentOffset = offsets[i]; |
962 FloatPoint& nextOffset = (i == numGlyphs - 1) ? firstOffsetOfNextRun : o ffsets[i + 1]; | 992 FloatPoint& nextOffset = (i == numGlyphs - 1) ? firstOffsetOfNextRun : o ffsets[i + 1]; |
963 float glyphAdvanceX = advances[i] + nextOffset.x() - currentOffset.x(); | 993 float glyphAdvanceX = advances[i] + nextOffset.x() - currentOffset.x(); |
964 float glyphAdvanceY = nextOffset.y() - currentOffset.y(); | 994 float glyphAdvanceY = nextOffset.y() - currentOffset.y(); |
965 if (m_run.rtl()) { | 995 if (m_run.rtl()) { |
966 if (currentCharacterIndex >= m_toIndex) | 996 if (currentCharacterIndex >= m_toIndex) |
967 m_startOffset.move(glyphAdvanceX, glyphAdvanceY); | 997 m_startOffset.move(glyphAdvanceX, glyphAdvanceY); |
968 else if (currentCharacterIndex >= m_fromIndex) | 998 else if (currentCharacterIndex >= m_fromIndex) |
969 glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphB ufferAdvance(glyphAdvanceX, glyphAdvanceY)); | 999 glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphB ufferAdvance(glyphAdvanceX, glyphAdvanceY)); |
970 } else { | 1000 } else { |
971 if (currentCharacterIndex < m_fromIndex) | 1001 if (currentCharacterIndex < m_fromIndex) |
972 m_startOffset.move(glyphAdvanceX, glyphAdvanceY); | 1002 m_startOffset.move(glyphAdvanceX, glyphAdvanceY); |
973 else if (currentCharacterIndex < m_toIndex) | 1003 else if (currentCharacterIndex < m_toIndex) |
974 glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphB ufferAdvance(glyphAdvanceX, glyphAdvanceY)); | 1004 glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphB ufferAdvance(glyphAdvanceX, glyphAdvanceY)); |
975 } | 1005 } |
976 } | 1006 } |
977 } | 1007 } |
978 | 1008 |
1009 void HarfBuzzShaper::fillGlyphBufferForTextEmphasis(GlyphBuffer* glyphBuffer, Ha rfBuzzRun* currentRun) | |
1010 { | |
1011 // FIXME: Instead of generating a synthetic GlyphBuffer here which is then u sed by the | |
1012 // drawEmphasisMarks method of FontFastPath, we should roll our own emphasis mark drawing function. | |
1013 | |
1014 float* advances = currentRun->advances(); | |
1015 unsigned numGlyphs = currentRun->numGlyphs(); | |
1016 uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes(); | |
1017 unsigned graphemesInCluster = 1; | |
1018 float clusterAdvance = 0; | |
1019 uint16_t clusterStart; | |
1020 | |
1021 // A "cluster" in this context means a cluster as it is used by HarfBuzz: | |
1022 // The minimal group of characters and corresponding glyphs, that cannot be broken | |
1023 // down further from a text shaping point of view. | |
1024 // A cluster can contain multiple glyphs and grapheme clusters, with mutuall y | |
1025 // overlapping boundaries. Below we count grapheme clusters per HarfBuzz clu sters, | |
1026 // then linearly split the sum of corresponding glyph advances by the number of | |
1027 // grapheme clusters in order to find positions for emphasis mark drawing. | |
1028 | |
1029 if (m_run.rtl()) | |
1030 clusterStart = currentRun->startIndex() + currentRun->numCharacters(); | |
1031 else | |
1032 clusterStart = currentRun->startIndex() + glyphToCharacterIndexes[0]; | |
1033 | |
1034 for (unsigned i = 0; i < numGlyphs; ++i) { | |
1035 uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToChara cterIndexes[i]; | |
1036 bool isRunEnd = (i + 1 == numGlyphs); | |
1037 bool isClusterEnd = isRunEnd || (currentRun->startIndex() + glyphToChar acterIndexes[i + 1] != currentCharacterIndex); | |
1038 clusterAdvance += advances[i]; | |
1039 | |
1040 if (isClusterEnd) { | |
1041 uint16_t clusterEnd; | |
1042 if (m_run.rtl()) | |
1043 clusterEnd = currentCharacterIndex; | |
1044 else | |
1045 clusterEnd = isRunEnd ? currentRun->startIndex() + currentRun->n umCharacters() : currentRun->startIndex() + glyphToCharacterIndexes[i + 1]; | |
1046 | |
1047 graphemesInCluster = countGraphemesInCluster(m_run, clusterStart, cl usterEnd); | |
1048 if (!graphemesInCluster || !clusterAdvance) | |
1049 continue; | |
1050 | |
1051 float glyphAdvanceX = clusterAdvance / graphemesInCluster; | |
1052 for (unsigned j = 0; j < graphemesInCluster; ++j) { | |
1053 // Do not put emphasis marks on space, separator, and control ch aracters. | |
1054 GlyphBufferGlyph glyphToAdd = Character::canReceiveTextEmphasis( m_run[currentCharacterIndex]) ? 1 : 0; | |
1055 glyphBuffer->add(glyphToAdd, currentRun->fontData(), createGlyph BufferAdvance(glyphAdvanceX, 0)); | |
1056 } | |
1057 clusterStart = clusterEnd; | |
1058 clusterAdvance = 0; | |
1059 } | |
1060 } | |
1061 } | |
1062 | |
979 bool HarfBuzzShaper::fillGlyphBuffer(GlyphBuffer* glyphBuffer) | 1063 bool HarfBuzzShaper::fillGlyphBuffer(GlyphBuffer* glyphBuffer) |
980 { | 1064 { |
981 unsigned numRuns = m_harfBuzzRuns.size(); | 1065 unsigned numRuns = m_harfBuzzRuns.size(); |
982 if (m_run.rtl()) { | 1066 if (m_run.rtl()) { |
983 m_startOffset = m_harfBuzzRuns.last()->offsets()[0]; | 1067 m_startOffset = m_harfBuzzRuns.last()->offsets()[0]; |
984 for (int runIndex = numRuns - 1; runIndex >= 0; --runIndex) { | 1068 for (int runIndex = numRuns - 1; runIndex >= 0; --runIndex) { |
985 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); | 1069 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); |
986 FloatPoint firstOffsetOfNextRun = !runIndex ? FloatPoint() : m_harfB uzzRuns[runIndex - 1]->offsets()[0]; | 1070 FloatPoint firstOffsetOfNextRun = !runIndex ? FloatPoint() : m_harfB uzzRuns[runIndex - 1]->offsets()[0]; |
987 fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetO fNextRun); | 1071 if (m_forTextEmphasis == ForTextEmphasis) |
1072 fillGlyphBufferForTextEmphasis(glyphBuffer, currentRun); | |
1073 else | |
1074 fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOff setOfNextRun); | |
988 } | 1075 } |
989 } else { | 1076 } else { |
990 m_startOffset = m_harfBuzzRuns.first()->offsets()[0]; | 1077 m_startOffset = m_harfBuzzRuns.first()->offsets()[0]; |
991 for (unsigned runIndex = 0; runIndex < numRuns; ++runIndex) { | 1078 for (unsigned runIndex = 0; runIndex < numRuns; ++runIndex) { |
992 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); | 1079 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); |
993 FloatPoint firstOffsetOfNextRun = runIndex == numRuns - 1 ? FloatPoi nt() : m_harfBuzzRuns[runIndex + 1]->offsets()[0]; | 1080 FloatPoint firstOffsetOfNextRun = runIndex == numRuns - 1 ? FloatPoi nt() : m_harfBuzzRuns[runIndex + 1]->offsets()[0]; |
994 fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetO fNextRun); | 1081 if (m_forTextEmphasis == ForTextEmphasis) |
1082 fillGlyphBufferForTextEmphasis(glyphBuffer, currentRun); | |
1083 else | |
1084 fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOff setOfNextRun); | |
995 } | 1085 } |
996 } | 1086 } |
997 return glyphBuffer->size(); | 1087 return glyphBuffer->size(); |
998 } | 1088 } |
999 | 1089 |
1000 int HarfBuzzShaper::offsetForPosition(float targetX) | 1090 int HarfBuzzShaper::offsetForPosition(float targetX) |
1001 { | 1091 { |
1002 int charactersSoFar = 0; | 1092 int charactersSoFar = 0; |
1003 float currentX = 0; | 1093 float currentX = 0; |
1004 | 1094 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1069 if (!foundToX) | 1159 if (!foundToX) |
1070 toX = m_run.rtl() ? 0 : m_totalWidth; | 1160 toX = m_run.rtl() ? 0 : m_totalWidth; |
1071 | 1161 |
1072 // Using floorf() and roundf() as the same as mac port. | 1162 // Using floorf() and roundf() as the same as mac port. |
1073 if (fromX < toX) | 1163 if (fromX < toX) |
1074 return FloatRect(floorf(point.x() + fromX), point.y(), roundf(toX - from X), height); | 1164 return FloatRect(floorf(point.x() + fromX), point.y(), roundf(toX - from X), height); |
1075 return FloatRect(floorf(point.x() + toX), point.y(), roundf(fromX - toX), he ight); | 1165 return FloatRect(floorf(point.x() + toX), point.y(), roundf(fromX - toX), he ight); |
1076 } | 1166 } |
1077 | 1167 |
1078 } // namespace WebCore | 1168 } // namespace WebCore |
OLD | NEW |