Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(481)

Side by Side Diff: Source/platform/fonts/harfbuzz/HarfBuzzShaper.cpp

Issue 130433006: Implement CSS Emphasis Marks for complex text (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: countGraphemesInCluster needs 8bit support Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/platform/fonts/harfbuzz/HarfBuzzShaper.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « Source/platform/fonts/harfbuzz/HarfBuzzShaper.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698