OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/render_text_harfbuzz.h" | 5 #include "ui/gfx/render_text_harfbuzz.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 #include <map> | 8 #include <map> |
9 | 9 |
10 #include "base/i18n/bidi_line_iterator.h" | 10 #include "base/i18n/bidi_line_iterator.h" |
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
296 hb_font_make_immutable(harfbuzz_font); | 296 hb_font_make_immutable(harfbuzz_font); |
297 return harfbuzz_font; | 297 return harfbuzz_font; |
298 } | 298 } |
299 | 299 |
300 // Returns true if characters of |block_code| may trigger font fallback. | 300 // Returns true if characters of |block_code| may trigger font fallback. |
301 bool IsUnusualBlockCode(UBlockCode block_code) { | 301 bool IsUnusualBlockCode(UBlockCode block_code) { |
302 return block_code == UBLOCK_GEOMETRIC_SHAPES || | 302 return block_code == UBLOCK_GEOMETRIC_SHAPES || |
303 block_code == UBLOCK_MISCELLANEOUS_SYMBOLS; | 303 block_code == UBLOCK_MISCELLANEOUS_SYMBOLS; |
304 } | 304 } |
305 | 305 |
306 // Returns the index of the first unusual character after a usual character or | 306 bool IsBracket(UChar32 character) { |
307 // vice versa. Unusual characters are defined by |IsUnusualBlockCode|. | 307 static const char kBrackets[] = { '(', ')', '{', '}', '<', '>', }; |
308 size_t FindUnusualCharacter(const base::string16& text, | 308 static const char* kBracketsEnd = kBrackets + arraysize(kBrackets); |
309 size_t run_start, | 309 return std::find(kBrackets, kBracketsEnd, character) != kBracketsEnd; |
310 size_t run_break) { | 310 } |
311 | |
312 // Returns the boundary between a special and a regular character. Special | |
313 // characters are brackets or characters that satisfy |IsUnusualBlockCode|. | |
314 size_t FindRunBreakingCharacter(const base::string16& text, | |
315 size_t run_start, | |
316 size_t run_break) { | |
311 const int32 run_length = static_cast<int32>(run_break - run_start); | 317 const int32 run_length = static_cast<int32>(run_break - run_start); |
312 base::i18n::UTF16CharIterator iter(text.c_str() + run_start, | 318 base::i18n::UTF16CharIterator iter(text.c_str() + run_start, run_length); |
313 run_length); | 319 const UChar32 first_char = iter.get(); |
314 const UBlockCode first_block_code = ublock_getCode(iter.get()); | 320 const UBlockCode first_block = ublock_getCode(first_char); |
315 const bool first_block_unusual = IsUnusualBlockCode(first_block_code); | 321 const bool first_bracket = IsBracket(first_char); |
msw
2014/09/03 18:14:58
nit: order this before or after the |first_block[_
| |
322 const bool first_block_unusual = IsUnusualBlockCode(first_block); | |
323 | |
316 while (iter.Advance() && iter.array_pos() < run_length) { | 324 while (iter.Advance() && iter.array_pos() < run_length) { |
317 const UBlockCode current_block_code = ublock_getCode(iter.get()); | 325 const UChar32 current_char = iter.get(); |
318 if (current_block_code != first_block_code && | 326 const UBlockCode current_block = ublock_getCode(current_char); |
319 (first_block_unusual || IsUnusualBlockCode(current_block_code))) { | 327 const bool block_break = current_block != first_block && |
328 (first_block_unusual || IsUnusualBlockCode(current_block)); | |
329 if (block_break || first_bracket != IsBracket(current_char)) | |
320 return run_start + iter.array_pos(); | 330 return run_start + iter.array_pos(); |
321 } | |
322 } | 331 } |
323 return run_break; | 332 return run_break; |
324 } | 333 } |
325 | 334 |
326 // If the given scripts match, returns the one that isn't USCRIPT_COMMON or | 335 // If the given scripts match, returns the one that isn't USCRIPT_COMMON or |
327 // USCRIPT_INHERITED, i.e. the more specific one. Otherwise returns | 336 // USCRIPT_INHERITED, i.e. the more specific one. Otherwise returns |
328 // USCRIPT_INVALID_CODE. | 337 // USCRIPT_INVALID_CODE. |
329 UScriptCode ScriptIntersect(UScriptCode first, UScriptCode second) { | 338 UScriptCode ScriptIntersect(UScriptCode first, UScriptCode second) { |
330 if (first == second || | 339 if (first == second || |
331 (second > USCRIPT_INVALID_CODE && second <= USCRIPT_INHERITED)) { | 340 (second > USCRIPT_INVALID_CODE && second <= USCRIPT_INHERITED)) { |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
600 if (offset < end) { | 609 if (offset < end) { |
601 return SelectionModel(LayoutIndexToTextIndex( | 610 return SelectionModel(LayoutIndexToTextIndex( |
602 run.glyph_to_char[i] + (run.is_rtl ? 0 : 1)), | 611 run.glyph_to_char[i] + (run.is_rtl ? 0 : 1)), |
603 (run.is_rtl ? CURSOR_FORWARD : CURSOR_BACKWARD)); | 612 (run.is_rtl ? CURSOR_FORWARD : CURSOR_BACKWARD)); |
604 } | 613 } |
605 } | 614 } |
606 return EdgeSelectionModel(CURSOR_RIGHT); | 615 return EdgeSelectionModel(CURSOR_RIGHT); |
607 } | 616 } |
608 | 617 |
609 std::vector<RenderText::FontSpan> RenderTextHarfBuzz::GetFontSpansForTesting() { | 618 std::vector<RenderText::FontSpan> RenderTextHarfBuzz::GetFontSpansForTesting() { |
610 NOTIMPLEMENTED(); | 619 EnsureLayout(); |
611 return std::vector<RenderText::FontSpan>(); | 620 |
621 std::vector<RenderText::FontSpan> spans; | |
622 for (size_t i = 0; i < runs_.size(); ++i) { | |
623 SkString family_name; | |
624 runs_[i]->skia_face->getFamilyName(&family_name); | |
625 Font font(family_name.c_str(), runs_[i]->font_size); | |
626 spans.push_back(RenderText::FontSpan(font, | |
627 Range(LayoutIndexToTextIndex(runs_[i]->range.start()), | |
628 LayoutIndexToTextIndex(runs_[i]->range.end())))); | |
629 } | |
630 | |
631 return spans; | |
612 } | 632 } |
613 | 633 |
614 Range RenderTextHarfBuzz::GetGlyphBounds(size_t index) { | 634 Range RenderTextHarfBuzz::GetGlyphBounds(size_t index) { |
615 EnsureLayout(); | 635 EnsureLayout(); |
616 const size_t run_index = | 636 const size_t run_index = |
617 GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD)); | 637 GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD)); |
618 // Return edge bounds if the index is invalid or beyond the layout text size. | 638 // Return edge bounds if the index is invalid or beyond the layout text size. |
619 if (run_index >= runs_.size()) | 639 if (run_index >= runs_.size()) |
620 return Range(GetStringSize().width()); | 640 return Range(GetStringSize().width()); |
621 const size_t layout_index = TextIndexToLayoutIndex(index); | 641 const size_t layout_index = TextIndexToLayoutIndex(index); |
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1010 // Odd BiDi embedding levels correspond to RTL runs. | 1030 // Odd BiDi embedding levels correspond to RTL runs. |
1011 run->is_rtl = (run->level % 2) == 1; | 1031 run->is_rtl = (run->level % 2) == 1; |
1012 // Find the length and script of this script run. | 1032 // Find the length and script of this script run. |
1013 script_item_break = ScriptInterval(text, run_break, | 1033 script_item_break = ScriptInterval(text, run_break, |
1014 script_item_break - run_break, &run->script) + run_break; | 1034 script_item_break - run_break, &run->script) + run_break; |
1015 | 1035 |
1016 // Find the next break and advance the iterators as needed. | 1036 // Find the next break and advance the iterators as needed. |
1017 run_break = std::min(static_cast<size_t>(script_item_break), | 1037 run_break = std::min(static_cast<size_t>(script_item_break), |
1018 TextIndexToLayoutIndex(style.GetRange().end())); | 1038 TextIndexToLayoutIndex(style.GetRange().end())); |
1019 | 1039 |
1020 // Break runs adjacent to character substrings in certain code blocks. | 1040 // Break runs at certain characters that need to be rendered separately to |
1021 // This avoids using their fallback fonts for more characters than needed, | 1041 // prevent either an unusual character from forcing a fallback font on the |
1022 // in cases like "\x25B6 Media Title", etc. http://crbug.com/278913 | 1042 // entire run, or brackets from being affected by a fallback font. |
1043 // http://crbug.com/278913, http://crbug.com/396776 | |
1023 if (run_break > run->range.start()) | 1044 if (run_break > run->range.start()) |
1024 run_break = FindUnusualCharacter(text, run->range.start(), run_break); | 1045 run_break = FindRunBreakingCharacter(text, run->range.start(), run_break); |
1025 | 1046 |
1026 DCHECK(IsValidCodePointIndex(text, run_break)); | 1047 DCHECK(IsValidCodePointIndex(text, run_break)); |
1027 style.UpdatePosition(LayoutIndexToTextIndex(run_break)); | 1048 style.UpdatePosition(LayoutIndexToTextIndex(run_break)); |
1028 run->range.set_end(run_break); | 1049 run->range.set_end(run_break); |
1029 | 1050 |
1030 runs_.push_back(run); | 1051 runs_.push_back(run); |
1031 } | 1052 } |
1032 | 1053 |
1033 // Undo the temporarily applied composition underlines and selection colors. | 1054 // Undo the temporarily applied composition underlines and selection colors. |
1034 UndoCompositionAndSelectionStyles(); | 1055 UndoCompositionAndSelectionStyles(); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1160 run->width = std::floor(run->width + 0.5f); | 1181 run->width = std::floor(run->width + 0.5f); |
1161 #endif | 1182 #endif |
1162 } | 1183 } |
1163 | 1184 |
1164 hb_buffer_destroy(buffer); | 1185 hb_buffer_destroy(buffer); |
1165 hb_font_destroy(harfbuzz_font); | 1186 hb_font_destroy(harfbuzz_font); |
1166 return true; | 1187 return true; |
1167 } | 1188 } |
1168 | 1189 |
1169 } // namespace gfx | 1190 } // namespace gfx |
OLD | NEW |