| 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 <map> | 7 #include <map> |
| 8 | 8 |
| 9 #include "base/i18n/bidi_line_iterator.h" |
| 9 #include "base/i18n/break_iterator.h" | 10 #include "base/i18n/break_iterator.h" |
| 10 #include "base/i18n/char_iterator.h" | 11 #include "base/i18n/char_iterator.h" |
| 11 #include "third_party/harfbuzz-ng/src/hb.h" | 12 #include "third_party/harfbuzz-ng/src/hb.h" |
| 12 #include "third_party/icu/source/common/unicode/ubidi.h" | 13 #include "third_party/icu/source/common/unicode/ubidi.h" |
| 13 #include "third_party/skia/include/core/SkColor.h" | 14 #include "third_party/skia/include/core/SkColor.h" |
| 14 #include "third_party/skia/include/core/SkTypeface.h" | 15 #include "third_party/skia/include/core/SkTypeface.h" |
| 15 #include "ui/gfx/canvas.h" | 16 #include "ui/gfx/canvas.h" |
| 16 #include "ui/gfx/utf16_indexing.h" | 17 #include "ui/gfx/utf16_indexing.h" |
| 17 | 18 |
| 18 #if defined(OS_WIN) | 19 #if defined(OS_WIN) |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 321 return hb_script_from_string(uscript_getShortName(script), -1); | 322 return hb_script_from_string(uscript_getShortName(script), -1); |
| 322 } | 323 } |
| 323 | 324 |
| 324 } // namespace | 325 } // namespace |
| 325 | 326 |
| 326 namespace internal { | 327 namespace internal { |
| 327 | 328 |
| 328 TextRunHarfBuzz::TextRunHarfBuzz() | 329 TextRunHarfBuzz::TextRunHarfBuzz() |
| 329 : width(0), | 330 : width(0), |
| 330 preceding_run_widths(0), | 331 preceding_run_widths(0), |
| 331 direction(UBIDI_LTR), | 332 is_rtl(false), |
| 332 level(0), | 333 level(0), |
| 333 script(USCRIPT_INVALID_CODE), | 334 script(USCRIPT_INVALID_CODE), |
| 334 glyph_count(-1), | 335 glyph_count(-1), |
| 335 font_size(0), | 336 font_size(0), |
| 336 font_style(0), | 337 font_style(0), |
| 337 strike(false), | 338 strike(false), |
| 338 diagonal_strike(false), | 339 diagonal_strike(false), |
| 339 underline(false) {} | 340 underline(false) {} |
| 340 | 341 |
| 341 TextRunHarfBuzz::~TextRunHarfBuzz() {} | 342 TextRunHarfBuzz::~TextRunHarfBuzz() {} |
| 342 | 343 |
| 343 size_t TextRunHarfBuzz::CharToGlyph(size_t pos) const { | 344 size_t TextRunHarfBuzz::CharToGlyph(size_t pos) const { |
| 344 DCHECK(range.start() <= pos && pos < range.end()); | 345 DCHECK(range.start() <= pos && pos < range.end()); |
| 345 | 346 |
| 346 if (direction == UBIDI_LTR) { | 347 if (!is_rtl) { |
| 347 for (size_t i = 0; i < glyph_count - 1; ++i) { | 348 for (size_t i = 0; i < glyph_count - 1; ++i) { |
| 348 if (pos < glyph_to_char[i + 1]) | 349 if (pos < glyph_to_char[i + 1]) |
| 349 return i; | 350 return i; |
| 350 } | 351 } |
| 351 return glyph_count - 1; | 352 return glyph_count - 1; |
| 352 } | 353 } |
| 353 | 354 |
| 354 for (size_t i = 0; i < glyph_count; ++i) { | 355 for (size_t i = 0; i < glyph_count; ++i) { |
| 355 if (pos >= glyph_to_char[i]) | 356 if (pos >= glyph_to_char[i]) |
| 356 return i; | 357 return i; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 379 return true; | 380 return true; |
| 380 } | 381 } |
| 381 return false; | 382 return false; |
| 382 } | 383 } |
| 383 | 384 |
| 384 int TextRunHarfBuzz::GetGlyphXBoundary(size_t text_index, bool trailing) const { | 385 int TextRunHarfBuzz::GetGlyphXBoundary(size_t text_index, bool trailing) const { |
| 385 int x = preceding_run_widths; | 386 int x = preceding_run_widths; |
| 386 Range glyph_range; | 387 Range glyph_range; |
| 387 if (text_index == range.end()) { | 388 if (text_index == range.end()) { |
| 388 trailing = true; | 389 trailing = true; |
| 389 glyph_range = direction == UBIDI_LTR ? | 390 glyph_range = is_rtl ? Range(0, 1) : Range(glyph_count - 1, glyph_count); |
| 390 Range(glyph_count - 1, glyph_count) : Range(0, 1); | |
| 391 } else { | 391 } else { |
| 392 glyph_range = CharRangeToGlyphRange(Range(text_index, text_index + 1)); | 392 glyph_range = CharRangeToGlyphRange(Range(text_index, text_index + 1)); |
| 393 } | 393 } |
| 394 const int trailing_step = trailing ? 1 : 0; | 394 const int trailing_step = trailing ? 1 : 0; |
| 395 const size_t glyph_pos = glyph_range.start() + | 395 const size_t glyph_pos = |
| 396 (direction == UBIDI_LTR ? trailing_step : (1 - trailing_step)); | 396 glyph_range.start() + (is_rtl ? (1 - trailing_step) : trailing_step); |
| 397 x += glyph_pos < glyph_count ? | 397 x += glyph_pos < glyph_count ? |
| 398 SkScalarRoundToInt(positions[glyph_pos].x()) : width; | 398 SkScalarRoundToInt(positions[glyph_pos].x()) : width; |
| 399 return x; | 399 return x; |
| 400 } | 400 } |
| 401 | 401 |
| 402 } // namespace internal | 402 } // namespace internal |
| 403 | 403 |
| 404 RenderTextHarfBuzz::RenderTextHarfBuzz() | 404 RenderTextHarfBuzz::RenderTextHarfBuzz() |
| 405 : RenderText(), | 405 : RenderText(), |
| 406 needs_layout_(false) {} | 406 needs_layout_(false) {} |
| (...skipping 12 matching lines...) Expand all Loading... |
| 419 int offset = 0; | 419 int offset = 0; |
| 420 size_t run_index = GetRunContainingXCoord(x, &offset); | 420 size_t run_index = GetRunContainingXCoord(x, &offset); |
| 421 if (run_index >= runs_.size()) | 421 if (run_index >= runs_.size()) |
| 422 return EdgeSelectionModel((x < 0) ? CURSOR_LEFT : CURSOR_RIGHT); | 422 return EdgeSelectionModel((x < 0) ? CURSOR_LEFT : CURSOR_RIGHT); |
| 423 const internal::TextRunHarfBuzz& run = *runs_[run_index]; | 423 const internal::TextRunHarfBuzz& run = *runs_[run_index]; |
| 424 | 424 |
| 425 for (size_t i = 0; i < run.glyph_count; ++i) { | 425 for (size_t i = 0; i < run.glyph_count; ++i) { |
| 426 const SkScalar end = | 426 const SkScalar end = |
| 427 i + 1 == run.glyph_count ? run.width : run.positions[i + 1].x(); | 427 i + 1 == run.glyph_count ? run.width : run.positions[i + 1].x(); |
| 428 const SkScalar middle = (end + run.positions[i].x()) / 2; | 428 const SkScalar middle = (end + run.positions[i].x()) / 2; |
| 429 const bool is_rtl = run.direction == UBIDI_RTL; | 429 |
| 430 if (offset < middle) { | 430 if (offset < middle) { |
| 431 return SelectionModel(LayoutIndexToTextIndex( | 431 return SelectionModel(LayoutIndexToTextIndex( |
| 432 run.glyph_to_char[i] + (is_rtl ? 1 : 0)), | 432 run.glyph_to_char[i] + (run.is_rtl ? 1 : 0)), |
| 433 (is_rtl ? CURSOR_BACKWARD : CURSOR_FORWARD)); | 433 (run.is_rtl ? CURSOR_BACKWARD : CURSOR_FORWARD)); |
| 434 } | 434 } |
| 435 if (offset < end) { | 435 if (offset < end) { |
| 436 return SelectionModel(LayoutIndexToTextIndex( | 436 return SelectionModel(LayoutIndexToTextIndex( |
| 437 run.glyph_to_char[i] + (is_rtl ? 0 : 1)), | 437 run.glyph_to_char[i] + (run.is_rtl ? 0 : 1)), |
| 438 (is_rtl ? CURSOR_FORWARD : CURSOR_BACKWARD)); | 438 (run.is_rtl ? CURSOR_FORWARD : CURSOR_BACKWARD)); |
| 439 } | 439 } |
| 440 } | 440 } |
| 441 return EdgeSelectionModel(CURSOR_RIGHT); | 441 return EdgeSelectionModel(CURSOR_RIGHT); |
| 442 } | 442 } |
| 443 | 443 |
| 444 std::vector<RenderText::FontSpan> RenderTextHarfBuzz::GetFontSpansForTesting() { | 444 std::vector<RenderText::FontSpan> RenderTextHarfBuzz::GetFontSpansForTesting() { |
| 445 NOTIMPLEMENTED(); | 445 NOTIMPLEMENTED(); |
| 446 return std::vector<RenderText::FontSpan>(); | 446 return std::vector<RenderText::FontSpan>(); |
| 447 } | 447 } |
| 448 | 448 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 462 SelectionModel edge = EdgeSelectionModel(direction); | 462 SelectionModel edge = EdgeSelectionModel(direction); |
| 463 if (edge.caret_pos() == selection.caret_pos()) | 463 if (edge.caret_pos() == selection.caret_pos()) |
| 464 return edge; | 464 return edge; |
| 465 int visual_index = (direction == CURSOR_RIGHT) ? 0 : runs_.size() - 1; | 465 int visual_index = (direction == CURSOR_RIGHT) ? 0 : runs_.size() - 1; |
| 466 run = runs_[visual_to_logical_[visual_index]]; | 466 run = runs_[visual_to_logical_[visual_index]]; |
| 467 } else { | 467 } else { |
| 468 // If the cursor is moving within the current run, just move it by one | 468 // If the cursor is moving within the current run, just move it by one |
| 469 // grapheme in the appropriate direction. | 469 // grapheme in the appropriate direction. |
| 470 run = runs_[run_index]; | 470 run = runs_[run_index]; |
| 471 size_t caret = selection.caret_pos(); | 471 size_t caret = selection.caret_pos(); |
| 472 bool forward_motion = | 472 bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT); |
| 473 (run->direction == UBIDI_RTL) == (direction == CURSOR_LEFT); | |
| 474 if (forward_motion) { | 473 if (forward_motion) { |
| 475 if (caret < LayoutIndexToTextIndex(run->range.end())) { | 474 if (caret < LayoutIndexToTextIndex(run->range.end())) { |
| 476 caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); | 475 caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); |
| 477 return SelectionModel(caret, CURSOR_BACKWARD); | 476 return SelectionModel(caret, CURSOR_BACKWARD); |
| 478 } | 477 } |
| 479 } else { | 478 } else { |
| 480 if (caret > LayoutIndexToTextIndex(run->range.start())) { | 479 if (caret > LayoutIndexToTextIndex(run->range.start())) { |
| 481 caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD); | 480 caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD); |
| 482 return SelectionModel(caret, CURSOR_FORWARD); | 481 return SelectionModel(caret, CURSOR_FORWARD); |
| 483 } | 482 } |
| 484 } | 483 } |
| 485 // The cursor is at the edge of a run; move to the visually adjacent run. | 484 // The cursor is at the edge of a run; move to the visually adjacent run. |
| 486 int visual_index = logical_to_visual_[run_index]; | 485 int visual_index = logical_to_visual_[run_index]; |
| 487 visual_index += (direction == CURSOR_LEFT) ? -1 : 1; | 486 visual_index += (direction == CURSOR_LEFT) ? -1 : 1; |
| 488 if (visual_index < 0 || visual_index >= static_cast<int>(runs_.size())) | 487 if (visual_index < 0 || visual_index >= static_cast<int>(runs_.size())) |
| 489 return EdgeSelectionModel(direction); | 488 return EdgeSelectionModel(direction); |
| 490 run = runs_[visual_to_logical_[visual_index]]; | 489 run = runs_[visual_to_logical_[visual_index]]; |
| 491 } | 490 } |
| 492 bool forward_motion = | 491 bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT); |
| 493 (run->direction == UBIDI_RTL) == (direction == CURSOR_LEFT); | |
| 494 return forward_motion ? FirstSelectionModelInsideRun(run) : | 492 return forward_motion ? FirstSelectionModelInsideRun(run) : |
| 495 LastSelectionModelInsideRun(run); | 493 LastSelectionModelInsideRun(run); |
| 496 } | 494 } |
| 497 | 495 |
| 498 SelectionModel RenderTextHarfBuzz::AdjacentWordSelectionModel( | 496 SelectionModel RenderTextHarfBuzz::AdjacentWordSelectionModel( |
| 499 const SelectionModel& selection, | 497 const SelectionModel& selection, |
| 500 VisualCursorDirection direction) { | 498 VisualCursorDirection direction) { |
| 501 // TODO(ckocagil): This implementation currently matches RenderTextWin, but it | 499 // TODO(ckocagil): This implementation currently matches RenderTextWin, but it |
| 502 // should match the native behavior on other platforms. | 500 // should match the native behavior on other platforms. |
| 503 if (obscured()) | 501 if (obscured()) |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 787 | 785 |
| 788 SelectionModel RenderTextHarfBuzz::LastSelectionModelInsideRun( | 786 SelectionModel RenderTextHarfBuzz::LastSelectionModelInsideRun( |
| 789 const internal::TextRunHarfBuzz* run) { | 787 const internal::TextRunHarfBuzz* run) { |
| 790 size_t position = LayoutIndexToTextIndex(run->range.end()); | 788 size_t position = LayoutIndexToTextIndex(run->range.end()); |
| 791 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); | 789 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); |
| 792 return SelectionModel(position, CURSOR_FORWARD); | 790 return SelectionModel(position, CURSOR_FORWARD); |
| 793 } | 791 } |
| 794 | 792 |
| 795 void RenderTextHarfBuzz::ItemizeText() { | 793 void RenderTextHarfBuzz::ItemizeText() { |
| 796 const base::string16& text = GetLayoutText(); | 794 const base::string16& text = GetLayoutText(); |
| 797 const bool is_rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT; | 795 const bool is_text_rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT; |
| 798 DCHECK_NE(0U, text.length()); | 796 DCHECK_NE(0U, text.length()); |
| 799 | 797 |
| 800 // If ICU fails to itemize the text, we set |fake_runs| and create a run that | 798 // If ICU fails to itemize the text, we set |fake_runs| and create a run that |
| 801 // spans the entire text. This is needed because early returning and leaving | 799 // spans the entire text. This is needed because early returning and leaving |
| 802 // the runs set empty causes some clients to crash/misbehave since they expect | 800 // the runs set empty causes some clients to crash/misbehave since they expect |
| 803 // non-zero text metrics from a non-empty text. | 801 // non-zero text metrics from a non-empty text. |
| 804 bool fake_runs = false; | 802 base::i18n::BiDiLineIterator bidi_iterator; |
| 805 UErrorCode result = U_ZERO_ERROR; | 803 bool fake_runs = !bidi_iterator.Open(text, is_text_rtl, false); |
| 806 | |
| 807 UBiDi* line = ubidi_openSized(text.length(), 0, &result); | |
| 808 if (U_FAILURE(result)) { | |
| 809 NOTREACHED(); | |
| 810 fake_runs = true; | |
| 811 } else { | |
| 812 ubidi_setPara(line, text.c_str(), text.length(), | |
| 813 is_rtl ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR, NULL, | |
| 814 &result); | |
| 815 if (U_FAILURE(result)) { | |
| 816 NOTREACHED(); | |
| 817 fake_runs = true; | |
| 818 } | |
| 819 } | |
| 820 | 804 |
| 821 // Temporarily apply composition underlines and selection colors. | 805 // Temporarily apply composition underlines and selection colors. |
| 822 ApplyCompositionAndSelectionStyles(); | 806 ApplyCompositionAndSelectionStyles(); |
| 823 | 807 |
| 824 // Build the list of runs from the script items and ranged styles. Use an | 808 // Build the list of runs from the script items and ranged styles. Use an |
| 825 // empty color BreakList to avoid breaking runs at color boundaries. | 809 // empty color BreakList to avoid breaking runs at color boundaries. |
| 826 BreakList<SkColor> empty_colors; | 810 BreakList<SkColor> empty_colors; |
| 827 empty_colors.SetMax(text.length()); | 811 empty_colors.SetMax(text.length()); |
| 828 internal::StyleIterator style(empty_colors, styles()); | 812 internal::StyleIterator style(empty_colors, styles()); |
| 829 | 813 |
| 830 for (size_t run_break = 0; run_break < text.length();) { | 814 for (size_t run_break = 0; run_break < text.length();) { |
| 831 internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz; | 815 internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz; |
| 832 run->range.set_start(run_break); | 816 run->range.set_start(run_break); |
| 833 run->font_style = (style.style(BOLD) ? Font::BOLD : 0) | | 817 run->font_style = (style.style(BOLD) ? Font::BOLD : 0) | |
| 834 (style.style(ITALIC) ? Font::ITALIC : 0); | 818 (style.style(ITALIC) ? Font::ITALIC : 0); |
| 835 run->strike = style.style(STRIKE); | 819 run->strike = style.style(STRIKE); |
| 836 run->diagonal_strike = style.style(DIAGONAL_STRIKE); | 820 run->diagonal_strike = style.style(DIAGONAL_STRIKE); |
| 837 run->underline = style.style(UNDERLINE); | 821 run->underline = style.style(UNDERLINE); |
| 838 | 822 |
| 839 if (fake_runs) { | 823 if (fake_runs) { |
| 840 run_break = text.length(); | 824 run_break = text.length(); |
| 841 } else { | 825 } else { |
| 842 int32 script_item_break = 0; | 826 int32 script_item_break = 0; |
| 843 ubidi_getLogicalRun(line, run_break, &script_item_break, &run->level); | 827 bidi_iterator.GetLogicalRun(run_break, &script_item_break, &run->level); |
| 844 // Find the length and script of this script run. | 828 // Find the length and script of this script run. |
| 845 script_item_break = ScriptInterval(text, run_break, | 829 script_item_break = ScriptInterval(text, run_break, |
| 846 script_item_break - run_break, &run->script) + run_break; | 830 script_item_break - run_break, &run->script) + run_break; |
| 847 | 831 |
| 848 // Find the next break and advance the iterators as needed. | 832 // Find the next break and advance the iterators as needed. |
| 849 run_break = std::min(static_cast<size_t>(script_item_break), | 833 run_break = std::min(static_cast<size_t>(script_item_break), |
| 850 TextIndexToLayoutIndex(style.GetRange().end())); | 834 TextIndexToLayoutIndex(style.GetRange().end())); |
| 851 | 835 |
| 852 // Break runs adjacent to character substrings in certain code blocks. | 836 // Break runs adjacent to character substrings in certain code blocks. |
| 853 // This avoids using their fallback fonts for more characters than needed, | 837 // This avoids using their fallback fonts for more characters than needed, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 866 run_break = run_start + iter.array_pos(); | 850 run_break = run_start + iter.array_pos(); |
| 867 break; | 851 break; |
| 868 } | 852 } |
| 869 } | 853 } |
| 870 } | 854 } |
| 871 } | 855 } |
| 872 | 856 |
| 873 DCHECK(IsValidCodePointIndex(text, run_break)); | 857 DCHECK(IsValidCodePointIndex(text, run_break)); |
| 874 style.UpdatePosition(LayoutIndexToTextIndex(run_break)); | 858 style.UpdatePosition(LayoutIndexToTextIndex(run_break)); |
| 875 run->range.set_end(run_break); | 859 run->range.set_end(run_break); |
| 876 const UChar* uchar_start = ubidi_getText(line); | 860 UBiDiDirection direction = ubidi_getBaseDirection( |
| 877 // TODO(ckocagil): Add |ubidi_getBaseDirection| to i18n::BiDiLineIterator | 861 text.c_str() + run->range.start(), run->range.length()); |
| 878 // and remove the bare ICU use here. | 862 if (direction == UBIDI_NEUTRAL) |
| 879 run->direction = ubidi_getBaseDirection(uchar_start + run->range.start(), | 863 run->is_rtl = is_text_rtl; |
| 880 run->range.length()); | 864 else |
| 881 if (run->direction == UBIDI_NEUTRAL) | 865 run->is_rtl = direction == UBIDI_RTL; |
| 882 run->direction = is_rtl ? UBIDI_RTL : UBIDI_LTR; | |
| 883 runs_.push_back(run); | 866 runs_.push_back(run); |
| 884 } | 867 } |
| 885 | 868 |
| 886 ubidi_close(line); | |
| 887 | |
| 888 // Undo the temporarily applied composition underlines and selection colors. | 869 // Undo the temporarily applied composition underlines and selection colors. |
| 889 UndoCompositionAndSelectionStyles(); | 870 UndoCompositionAndSelectionStyles(); |
| 890 | 871 |
| 891 const size_t num_runs = runs_.size(); | 872 const size_t num_runs = runs_.size(); |
| 892 std::vector<UBiDiLevel> levels(num_runs); | 873 std::vector<UBiDiLevel> levels(num_runs); |
| 893 for (size_t i = 0; i < num_runs; ++i) | 874 for (size_t i = 0; i < num_runs; ++i) |
| 894 levels[i] = runs_[i]->level; | 875 levels[i] = runs_[i]->level; |
| 895 visual_to_logical_.resize(num_runs); | 876 visual_to_logical_.resize(num_runs); |
| 896 ubidi_reorderVisual(&levels[0], num_runs, &visual_to_logical_[0]); | 877 ubidi_reorderVisual(&levels[0], num_runs, &visual_to_logical_[0]); |
| 897 logical_to_visual_.resize(num_runs); | 878 logical_to_visual_.resize(num_runs); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 910 run->font_size); | 891 run->font_size); |
| 911 | 892 |
| 912 // Create a HarfBuzz buffer and add the string to be shaped. The HarfBuzz | 893 // Create a HarfBuzz buffer and add the string to be shaped. The HarfBuzz |
| 913 // buffer holds our text, run information to be used by the shaping engine, | 894 // buffer holds our text, run information to be used by the shaping engine, |
| 914 // and the resulting glyph data. | 895 // and the resulting glyph data. |
| 915 hb_buffer_t* buffer = hb_buffer_create(); | 896 hb_buffer_t* buffer = hb_buffer_create(); |
| 916 hb_buffer_add_utf16(buffer, reinterpret_cast<const uint16*>(text.c_str()), | 897 hb_buffer_add_utf16(buffer, reinterpret_cast<const uint16*>(text.c_str()), |
| 917 text.length(), run->range.start(), run->range.length()); | 898 text.length(), run->range.start(), run->range.length()); |
| 918 hb_buffer_set_script(buffer, ICUScriptToHBScript(run->script)); | 899 hb_buffer_set_script(buffer, ICUScriptToHBScript(run->script)); |
| 919 hb_buffer_set_direction(buffer, | 900 hb_buffer_set_direction(buffer, |
| 920 run->direction == UBIDI_LTR ? HB_DIRECTION_LTR : HB_DIRECTION_RTL); | 901 run->is_rtl ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); |
| 921 // TODO(ckocagil): Should we determine the actual language? | 902 // TODO(ckocagil): Should we determine the actual language? |
| 922 hb_buffer_set_language(buffer, hb_language_get_default()); | 903 hb_buffer_set_language(buffer, hb_language_get_default()); |
| 923 | 904 |
| 924 // Shape the text. | 905 // Shape the text. |
| 925 hb_shape(harfbuzz_font, buffer, NULL, 0); | 906 hb_shape(harfbuzz_font, buffer, NULL, 0); |
| 926 | 907 |
| 927 // Populate the run fields with the resulting glyph data in the buffer. | 908 // Populate the run fields with the resulting glyph data in the buffer. |
| 928 unsigned int glyph_count = 0; | 909 unsigned int glyph_count = 0; |
| 929 hb_glyph_info_t* infos = hb_buffer_get_glyph_infos(buffer, &glyph_count); | 910 hb_glyph_info_t* infos = hb_buffer_get_glyph_infos(buffer, &glyph_count); |
| 930 hb_glyph_position_t* hb_positions = hb_buffer_get_glyph_positions(buffer, | 911 hb_glyph_position_t* hb_positions = hb_buffer_get_glyph_positions(buffer, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 943 run->positions[i].set(run->width + x_offset, y_offset); | 924 run->positions[i].set(run->width + x_offset, y_offset); |
| 944 run->width += | 925 run->width += |
| 945 SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_advance)); | 926 SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_advance)); |
| 946 } | 927 } |
| 947 | 928 |
| 948 hb_buffer_destroy(buffer); | 929 hb_buffer_destroy(buffer); |
| 949 hb_font_destroy(harfbuzz_font); | 930 hb_font_destroy(harfbuzz_font); |
| 950 } | 931 } |
| 951 | 932 |
| 952 } // namespace gfx | 933 } // namespace gfx |
| OLD | NEW |