|
17 | 17 | #include "paragraph.h"
|
18 | 18 |
|
19 | 19 | #include <hb.h>
|
| 20 | +#include <minikin/Layout.h> |
| 21 | + |
20 | 22 | #include <algorithm>
|
21 | 23 | #include <limits>
|
22 | 24 | #include <map>
|
23 | 25 | #include <numeric>
|
24 | 26 | #include <utility>
|
25 | 27 | #include <vector>
|
26 | 28 |
|
27 |
| -#include <minikin/Layout.h> |
28 | 29 | #include "flutter/fml/logging.h"
|
29 | 30 | #include "font_collection.h"
|
30 | 31 | #include "font_skia.h"
|
|
34 | 35 | #include "minikin/LayoutUtils.h"
|
35 | 36 | #include "minikin/LineBreaker.h"
|
36 | 37 | #include "minikin/MinikinFont.h"
|
37 |
| -#include "unicode/ubidi.h" |
38 |
| -#include "unicode/utf16.h" |
39 |
| - |
40 | 38 | #include "third_party/skia/include/core/SkCanvas.h"
|
41 | 39 | #include "third_party/skia/include/core/SkFont.h"
|
42 | 40 | #include "third_party/skia/include/core/SkFontMetrics.h"
|
|
46 | 44 | #include "third_party/skia/include/core/SkTypeface.h"
|
47 | 45 | #include "third_party/skia/include/effects/SkDashPathEffect.h"
|
48 | 46 | #include "third_party/skia/include/effects/SkDiscretePathEffect.h"
|
| 47 | +#include "unicode/ubidi.h" |
| 48 | +#include "unicode/utf16.h" |
49 | 49 |
|
50 | 50 | namespace txt {
|
51 | 51 | namespace {
|
@@ -552,28 +552,39 @@ void Paragraph::Layout(double width, bool force) {
|
552 | 552 | // Find the runs comprising this line.
|
553 | 553 | std::vector<BidiRun> line_runs;
|
554 | 554 | for (const BidiRun& bidi_run : bidi_runs) {
|
555 |
| - if (bidi_run.start() < line_end_index && |
556 |
| - bidi_run.end() > line_range.start) { |
557 |
| - line_runs.emplace_back(std::max(bidi_run.start(), line_range.start), |
558 |
| - std::min(bidi_run.end(), line_end_index), |
559 |
| - bidi_run.direction(), bidi_run.style()); |
560 |
| - } |
561 | 555 | // A "ghost" run is a run that does not impact the layout, breaking,
|
562 |
| - // alignment, width, etc but is still "visible" though getRectsForRange. |
| 556 | + // alignment, width, etc but is still "visible" through getRectsForRange. |
563 | 557 | // For example, trailing whitespace on centered text can be scrolled
|
564 | 558 | // through with the caret but will not wrap the line.
|
565 | 559 | //
|
566 | 560 | // Here, we add an additional run for the whitespace, but dont
|
567 | 561 | // let it impact metrics. After layout of the whitespace run, we do not
|
568 | 562 | // add its width into the x-offset adjustment, effectively nullifying its
|
569 | 563 | // impact on the layout.
|
| 564 | + std::unique_ptr<BidiRun> ghost_run = nullptr; |
570 | 565 | if (paragraph_style_.ellipsis.empty() &&
|
571 | 566 | line_range.end_excluding_whitespace < line_range.end &&
|
572 | 567 | bidi_run.start() <= line_range.end &&
|
573 | 568 | bidi_run.end() > line_end_index) {
|
574 |
| - line_runs.emplace_back(std::max(bidi_run.start(), line_end_index), |
575 |
| - std::min(bidi_run.end(), line_range.end), |
576 |
| - bidi_run.direction(), bidi_run.style(), true); |
| 569 | + ghost_run = std::make_unique<BidiRun>( |
| 570 | + std::max(bidi_run.start(), line_end_index), |
| 571 | + std::min(bidi_run.end(), line_range.end), bidi_run.direction(), |
| 572 | + bidi_run.style(), true); |
| 573 | + } |
| 574 | + // Include the ghost run before normal run if RTL |
| 575 | + if (bidi_run.direction() == TextDirection::rtl && ghost_run != nullptr) { |
| 576 | + line_runs.push_back(*ghost_run); |
| 577 | + } |
| 578 | + // Emplace a normal line run. |
| 579 | + if (bidi_run.start() < line_end_index && |
| 580 | + bidi_run.end() > line_range.start) { |
| 581 | + line_runs.emplace_back(std::max(bidi_run.start(), line_range.start), |
| 582 | + std::min(bidi_run.end(), line_end_index), |
| 583 | + bidi_run.direction(), bidi_run.style()); |
| 584 | + } |
| 585 | + // Include the ghost run after normal run if LTR |
| 586 | + if (bidi_run.direction() == TextDirection::ltr && ghost_run != nullptr) { |
| 587 | + line_runs.push_back(*ghost_run); |
577 | 588 | }
|
578 | 589 | }
|
579 | 590 | bool line_runs_all_rtl =
|
@@ -661,6 +672,17 @@ void Paragraph::Layout(double width, bool force) {
|
661 | 672 | if (layout.nGlyphs() == 0)
|
662 | 673 | continue;
|
663 | 674 |
|
| 675 | + // When laying out RTL ghost runs, shift the run_x_offset here by the |
| 676 | + // advance so that the ghost run is positioned to the left of the first |
| 677 | + // real run of text in the line. However, since we do not want it to |
| 678 | + // impact the layout of real text, this advance is subsequently added |
| 679 | + // back into the run_x_offset after the ghost run positions have been |
| 680 | + // calcuated and before the next real run of text is laid out, ensuring |
| 681 | + // later runs are laid out in the same position as if there were no ghost |
| 682 | + // run. |
| 683 | + if (run.is_ghost() && run.is_rtl()) |
| 684 | + run_x_offset -= layout.getAdvance(); |
| 685 | + |
664 | 686 | std::vector<float> layout_advances(text_count);
|
665 | 687 | layout.getAdvances(layout_advances.data());
|
666 | 688 |
|
@@ -808,21 +830,25 @@ void Paragraph::Layout(double width, bool force) {
|
808 | 830 | [](const GlyphPosition& a, const GlyphPosition& b) {
|
809 | 831 | return a.code_units.start < b.code_units.start;
|
810 | 832 | });
|
| 833 | + |
811 | 834 | line_code_unit_runs.emplace_back(
|
812 | 835 | std::move(code_unit_positions),
|
813 | 836 | Range<size_t>(run.start(), run.end()),
|
814 | 837 | Range<double>(glyph_positions.front().x_pos.start,
|
815 | 838 | glyph_positions.back().x_pos.end),
|
816 | 839 | line_number, metrics, run.direction());
|
817 | 840 |
|
818 |
| - min_left_ = std::min(min_left_, glyph_positions.front().x_pos.start); |
819 |
| - max_right_ = std::max(max_right_, glyph_positions.back().x_pos.end); |
| 841 | + if (!run.is_ghost()) { |
| 842 | + min_left_ = std::min(min_left_, glyph_positions.front().x_pos.start); |
| 843 | + max_right_ = std::max(max_right_, glyph_positions.back().x_pos.end); |
| 844 | + } |
820 | 845 | } // for each in glyph_blobs
|
821 |
| - |
822 |
| - // Do not increase x offset for trailing ghost runs as it should not |
823 |
| - // impact the layout of visible glyphs. We do keep the record though so |
824 |
| - // GetRectsForRange() can find metrics for trailing spaces. |
825 |
| - if (!run.is_ghost()) { |
| 846 | + // Do not increase x offset for LTR trailing ghost runs as it should not |
| 847 | + // impact the layout of visible glyphs. RTL tailing ghost runs have the |
| 848 | + // advance subtracted, so we do add the advance here to reset the |
| 849 | + // run_x_offset. We do keep the record though so GetRectsForRange() can |
| 850 | + // find metrics for trailing spaces. |
| 851 | + if (!run.is_ghost() || run.is_rtl()) { |
826 | 852 | run_x_offset += layout.getAdvance();
|
827 | 853 | }
|
828 | 854 | } // for each in line_runs
|
|
0 commit comments