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

Side by Side Diff: ui/gfx/render_text_harfbuzz.cc

Issue 924773002: Fix multiline behaviors for RTL text. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix Created 5 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
OLDNEW
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 8
9 #include "base/i18n/bidi_line_iterator.h" 9 #include "base/i18n/bidi_line_iterator.h"
10 #include "base/i18n/break_iterator.h" 10 #include "base/i18n/break_iterator.h"
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 // height for each line. 213 // height for each line.
214 // TODO(ckocagil): Expose the interface of this class in the header and test 214 // TODO(ckocagil): Expose the interface of this class in the header and test
215 // this class directly. 215 // this class directly.
216 class HarfBuzzLineBreaker { 216 class HarfBuzzLineBreaker {
217 public: 217 public:
218 HarfBuzzLineBreaker(size_t max_width, 218 HarfBuzzLineBreaker(size_t max_width,
219 int min_baseline, 219 int min_baseline,
220 float min_height, 220 float min_height,
221 bool multiline, 221 bool multiline,
222 const base::string16& text, 222 const base::string16& text,
223 const std::vector<int32_t>& logical_to_visual,
223 const BreakList<size_t>* words, 224 const BreakList<size_t>* words,
224 const ScopedVector<internal::TextRunHarfBuzz>& runs) 225 const ScopedVector<internal::TextRunHarfBuzz>& runs)
225 : max_width_((max_width == 0) ? SK_ScalarMax : SkIntToScalar(max_width)), 226 : max_width_((max_width == 0) ? SK_ScalarMax : SkIntToScalar(max_width)),
226 min_baseline_(min_baseline), 227 min_baseline_(min_baseline),
227 min_height_(min_height), 228 min_height_(min_height),
228 multiline_(multiline), 229 multiline_(multiline),
229 text_(text), 230 text_(text),
231 logical_to_visual_(logical_to_visual),
230 words_(words), 232 words_(words),
231 runs_(runs), 233 runs_(runs),
232 text_x_(0), 234 text_x_(0),
233 line_x_(0), 235 line_x_(0),
234 max_descent_(0), 236 max_descent_(0),
235 max_ascent_(0) { 237 max_ascent_(0) {
236 DCHECK_EQ(multiline_, (words_ != nullptr)); 238 DCHECK_EQ(multiline_, (words_ != nullptr));
237 AdvanceLine(); 239 AdvanceLine();
238 } 240 }
239 241
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
366 x += segment_width; 368 x += segment_width;
367 } 369 }
368 rtl_segments_.clear(); 370 rtl_segments_.clear();
369 } 371 }
370 372
371 // Finishes the size calculations of the last Line in |lines_|. Adds a new 373 // Finishes the size calculations of the last Line in |lines_|. Adds a new
372 // Line to the back of |lines_|. 374 // Line to the back of |lines_|.
373 void AdvanceLine() { 375 void AdvanceLine() {
374 if (!lines_.empty()) { 376 if (!lines_.empty()) {
375 internal::Line* line = &lines_.back(); 377 internal::Line* line = &lines_.back();
378 std::sort(line->segments.begin(), line->segments.end(),
379 [this](const internal::LineSegment& s1,
380 const internal::LineSegment& s2) -> bool {
381 return logical_to_visual_[s1.run] < logical_to_visual_[s2.run];
382 });
376 line->size.set_height(std::max(min_height_, max_descent_ + max_ascent_)); 383 line->size.set_height(std::max(min_height_, max_descent_ + max_ascent_));
377 line->baseline = 384 line->baseline =
378 std::max(min_baseline_, SkScalarRoundToInt(max_ascent_)); 385 std::max(min_baseline_, SkScalarRoundToInt(max_ascent_));
379 line->preceding_heights = std::ceil(total_size_.height()); 386 line->preceding_heights = std::ceil(total_size_.height());
380 total_size_.set_height(total_size_.height() + line->size.height()); 387 total_size_.set_height(total_size_.height() + line->size.height());
381 total_size_.set_width(std::max(total_size_.width(), line->size.width())); 388 total_size_.set_width(std::max(total_size_.width(), line->size.width()));
382 } 389 }
383 max_descent_ = 0; 390 max_descent_ = 0;
384 max_ascent_ = 0; 391 max_ascent_ = 0;
385 line_x_ = 0; 392 line_x_ = 0;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 } 434 }
428 text_x_ += SkFloatToScalar(width); 435 text_x_ += SkFloatToScalar(width);
429 line_x_ += SkFloatToScalar(width); 436 line_x_ += SkFloatToScalar(width);
430 } 437 }
431 438
432 const SkScalar max_width_; 439 const SkScalar max_width_;
433 const int min_baseline_; 440 const int min_baseline_;
434 const float min_height_; 441 const float min_height_;
435 const bool multiline_; 442 const bool multiline_;
436 const base::string16& text_; 443 const base::string16& text_;
444 const std::vector<int32_t>& logical_to_visual_;
437 const BreakList<size_t>* const words_; 445 const BreakList<size_t>* const words_;
438 const ScopedVector<internal::TextRunHarfBuzz>& runs_; 446 const ScopedVector<internal::TextRunHarfBuzz>& runs_;
439 447
440 // Stores the resulting lines. 448 // Stores the resulting lines.
441 std::vector<internal::Line> lines_; 449 std::vector<internal::Line> lines_;
442 450
443 // Text space and line space x coordinates of the next segment to be added. 451 // Text space and line space x coordinates of the next segment to be added.
444 SkScalar text_x_; 452 SkScalar text_x_;
445 SkScalar line_x_; 453 SkScalar line_x_;
446 454
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after
916 924
917 if (lines().empty()) { 925 if (lines().empty()) {
918 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. 926 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed.
919 tracked_objects::ScopedTracker tracking_profile2( 927 tracked_objects::ScopedTracker tracking_profile2(
920 FROM_HERE_WITH_EXPLICIT_FUNCTION( 928 FROM_HERE_WITH_EXPLICIT_FUNCTION(
921 "431326 RenderTextHarfBuzz::EnsureLayout2")); 929 "431326 RenderTextHarfBuzz::EnsureLayout2"));
922 930
923 HarfBuzzLineBreaker line_breaker( 931 HarfBuzzLineBreaker line_breaker(
924 display_rect().width(), font_list().GetBaseline(), 932 display_rect().width(), font_list().GetBaseline(),
925 std::max(font_list().GetHeight(), min_line_height()), multiline(), 933 std::max(font_list().GetHeight(), min_line_height()), multiline(),
926 GetLayoutText(), multiline() ? &GetLineBreaks() : nullptr, runs_); 934 GetLayoutText(), logical_to_visual_,
935 multiline() ? &GetLineBreaks() : nullptr, runs_);
927 936
928 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. 937 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed.
929 tracked_objects::ScopedTracker tracking_profile3( 938 tracked_objects::ScopedTracker tracking_profile3(
930 FROM_HERE_WITH_EXPLICIT_FUNCTION( 939 FROM_HERE_WITH_EXPLICIT_FUNCTION(
931 "431326 RenderTextHarfBuzz::EnsureLayout3")); 940 "431326 RenderTextHarfBuzz::EnsureLayout3"));
932 941
933 for (size_t i = 0; i < runs_.size(); ++i) 942 for (size_t i = 0; i < runs_.size(); ++i)
934 line_breaker.AddRun(visual_to_logical_[i]); 943 line_breaker.AddRun(i);
935 std::vector<internal::Line> lines; 944 std::vector<internal::Line> lines;
936 line_breaker.Finalize(&lines, &total_size_); 945 line_breaker.Finalize(&lines, &total_size_);
937 set_lines(&lines); 946 set_lines(&lines);
938 } 947 }
939 } 948 }
940 949
941 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { 950 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) {
951 internal::SkiaTextRenderer renderer(canvas);
952 DrawVisualTextInternal(&renderer);
953 }
954
955 void RenderTextHarfBuzz::DrawVisualTextInternal(
956 internal::SkiaTextRenderer* renderer) {
942 DCHECK(!needs_layout_); 957 DCHECK(!needs_layout_);
943 if (lines().empty()) 958 if (lines().empty())
944 return; 959 return;
945 960
946 internal::SkiaTextRenderer renderer(canvas); 961 ApplyFadeEffects(renderer);
947 ApplyFadeEffects(&renderer); 962 ApplyTextShadows(renderer);
948 ApplyTextShadows(&renderer);
949 ApplyCompositionAndSelectionStyles(); 963 ApplyCompositionAndSelectionStyles();
950 964
951 for (size_t i = 0; i < lines().size(); ++i) { 965 for (size_t i = 0; i < lines().size(); ++i) {
952 const internal::Line& line = lines()[i]; 966 const internal::Line& line = lines()[i];
953 const Vector2d origin = GetLineOffset(i) + Vector2d(0, line.baseline); 967 const Vector2d origin = GetLineOffset(i) + Vector2d(0, line.baseline);
954 SkScalar preceding_segment_widths = 0; 968 SkScalar preceding_segment_widths = 0;
955 for (const internal::LineSegment& segment : line.segments) { 969 for (const internal::LineSegment& segment : line.segments) {
956 const internal::TextRunHarfBuzz& run = *runs_[segment.run]; 970 const internal::TextRunHarfBuzz& run = *runs_[segment.run];
957 renderer.SetTypeface(run.skia_face.get()); 971 renderer->SetTypeface(run.skia_face.get());
958 renderer.SetTextSize(SkIntToScalar(run.font_size)); 972 renderer->SetTextSize(SkIntToScalar(run.font_size));
959 renderer.SetFontRenderParams(run.render_params, 973 renderer->SetFontRenderParams(run.render_params,
960 background_is_transparent()); 974 background_is_transparent());
961 Range glyphs_range = run.CharRangeToGlyphRange(segment.char_range); 975 Range glyphs_range = run.CharRangeToGlyphRange(segment.char_range);
962 scoped_ptr<SkPoint[]> positions(new SkPoint[glyphs_range.length()]); 976 scoped_ptr<SkPoint[]> positions(new SkPoint[glyphs_range.length()]);
963 SkScalar offset_x = 977 SkScalar offset_x =
964 preceding_segment_widths - run.positions[glyphs_range.start()].x(); 978 preceding_segment_widths - run.positions[glyphs_range.start()].x();
965 for (size_t j = 0; j < glyphs_range.length(); ++j) { 979 for (size_t j = 0; j < glyphs_range.length(); ++j) {
966 positions[j] = run.positions[(glyphs_range.is_reversed()) ? 980 positions[j] = run.positions[(glyphs_range.is_reversed()) ?
967 (glyphs_range.start() - j) : 981 (glyphs_range.start() - j) :
968 (glyphs_range.start() + j)]; 982 (glyphs_range.start() + j)];
969 positions[j].offset(SkIntToScalar(origin.x()) + offset_x, 983 positions[j].offset(SkIntToScalar(origin.x()) + offset_x,
970 SkIntToScalar(origin.y())); 984 SkIntToScalar(origin.y()));
971 } 985 }
972 for (BreakList<SkColor>::const_iterator it = 986 for (BreakList<SkColor>::const_iterator it =
973 colors().GetBreak(segment.char_range.start()); 987 colors().GetBreak(segment.char_range.start());
974 it != colors().breaks().end() && 988 it != colors().breaks().end() &&
975 it->first < segment.char_range.end(); 989 it->first < segment.char_range.end();
976 ++it) { 990 ++it) {
977 const Range intersection = 991 const Range intersection =
978 colors().GetRange(it).Intersect(segment.char_range); 992 colors().GetRange(it).Intersect(segment.char_range);
979 const Range colored_glyphs = run.CharRangeToGlyphRange(intersection); 993 const Range colored_glyphs = run.CharRangeToGlyphRange(intersection);
980 // The range may be empty if a portion of a multi-character grapheme is 994 // The range may be empty if a portion of a multi-character grapheme is
981 // selected, yielding two colors for a single glyph. For now, this just 995 // selected, yielding two colors for a single glyph. For now, this just
982 // paints the glyph with a single style, but it should paint it twice, 996 // paints the glyph with a single style, but it should paint it twice,
983 // clipped according to selection bounds. See http://crbug.com/366786 997 // clipped according to selection bounds. See http://crbug.com/366786
984 if (colored_glyphs.is_empty()) 998 if (colored_glyphs.is_empty())
985 continue; 999 continue;
986 1000
987 renderer.SetForegroundColor(it->second); 1001 renderer->SetForegroundColor(it->second);
988 renderer.DrawPosText( 1002 renderer->DrawPosText(
989 &positions[colored_glyphs.start() - glyphs_range.start()], 1003 &positions[colored_glyphs.start() - glyphs_range.start()],
990 &run.glyphs[colored_glyphs.start()], colored_glyphs.length()); 1004 &run.glyphs[colored_glyphs.start()], colored_glyphs.length());
991 int start_x = SkScalarRoundToInt( 1005 int start_x = SkScalarRoundToInt(
992 positions[colored_glyphs.start() - glyphs_range.start()].x()); 1006 positions[colored_glyphs.start() - glyphs_range.start()].x());
993 int end_x = SkScalarRoundToInt( 1007 int end_x = SkScalarRoundToInt(
994 (colored_glyphs.end() == glyphs_range.end()) 1008 (colored_glyphs.end() == glyphs_range.end())
995 ? (SkFloatToScalar(segment.width) + preceding_segment_widths + 1009 ? (SkFloatToScalar(segment.width) + preceding_segment_widths +
996 SkIntToScalar(origin.x())) 1010 SkIntToScalar(origin.x()))
997 : positions[colored_glyphs.end() - glyphs_range.start()].x()); 1011 : positions[colored_glyphs.end() - glyphs_range.start()].x());
998 renderer.DrawDecorations(start_x, origin.y(), end_x - start_x, 1012 renderer->DrawDecorations(start_x, origin.y(), end_x - start_x,
999 run.underline, run.strike, 1013 run.underline, run.strike,
1000 run.diagonal_strike); 1014 run.diagonal_strike);
1001 } 1015 }
1002 preceding_segment_widths += SkFloatToScalar(segment.width); 1016 preceding_segment_widths += SkFloatToScalar(segment.width);
1003 } 1017 }
1004 } 1018 }
1005 1019
1006 renderer.EndDiagonalStrike(); 1020 renderer->EndDiagonalStrike();
1007 1021
1008 UndoCompositionAndSelectionStyles(); 1022 UndoCompositionAndSelectionStyles();
1009 } 1023 }
1010 1024
1011 size_t RenderTextHarfBuzz::GetRunContainingCaret( 1025 size_t RenderTextHarfBuzz::GetRunContainingCaret(
1012 const SelectionModel& caret) const { 1026 const SelectionModel& caret) const {
1013 DCHECK(!needs_layout_); 1027 DCHECK(!needs_layout_);
1014 size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos()); 1028 size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos());
1015 LogicalCursorDirection affinity = caret.caret_affinity(); 1029 LogicalCursorDirection affinity = caret.caret_affinity();
1016 for (size_t run = 0; run < runs_.size(); ++run) { 1030 for (size_t run = 0; run < runs_.size(); ++run) {
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after
1311 "431326 RenderTextHarfBuzz::ShapeRunWithFont3")); 1325 "431326 RenderTextHarfBuzz::ShapeRunWithFont3"));
1312 1326
1313 for (size_t i = 0; i < run->glyph_count; ++i) { 1327 for (size_t i = 0; i < run->glyph_count; ++i) {
1314 DCHECK_LE(infos[i].codepoint, std::numeric_limits<uint16>::max()); 1328 DCHECK_LE(infos[i].codepoint, std::numeric_limits<uint16>::max());
1315 run->glyphs[i] = static_cast<uint16>(infos[i].codepoint); 1329 run->glyphs[i] = static_cast<uint16>(infos[i].codepoint);
1316 run->glyph_to_char[i] = infos[i].cluster; 1330 run->glyph_to_char[i] = infos[i].cluster;
1317 const SkScalar x_offset = SkFixedToScalar(hb_positions[i].x_offset); 1331 const SkScalar x_offset = SkFixedToScalar(hb_positions[i].x_offset);
1318 const SkScalar y_offset = SkFixedToScalar(hb_positions[i].y_offset); 1332 const SkScalar y_offset = SkFixedToScalar(hb_positions[i].y_offset);
1319 run->positions[i].set(run->width + x_offset, -y_offset); 1333 run->positions[i].set(run->width + x_offset, -y_offset);
1320 run->width += (glyph_width_for_test_ > 0) 1334 run->width += (glyph_width_for_test_ > 0)
1321 ? SkIntToScalar(glyph_width_for_test_) 1335 ? glyph_width_for_test_
1322 : SkFixedToScalar(hb_positions[i].x_advance); 1336 : SkFixedToFloat(hb_positions[i].x_advance);
1323 // Round run widths if subpixel positioning is off to match native behavior. 1337 // Round run widths if subpixel positioning is off to match native behavior.
1324 if (!run->render_params.subpixel_positioning) 1338 if (!run->render_params.subpixel_positioning)
1325 run->width = std::floor(run->width + 0.5f); 1339 run->width = std::floor(run->width + 0.5f);
1326 } 1340 }
1327 1341
1328 hb_buffer_destroy(buffer); 1342 hb_buffer_destroy(buffer);
1329 hb_font_destroy(harfbuzz_font); 1343 hb_font_destroy(harfbuzz_font);
1330 return true; 1344 return true;
1331 } 1345 }
1332 1346
1333 } // namespace gfx 1347 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698