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

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: 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
« no previous file with comments | « ui/gfx/render_text_harfbuzz.h ('k') | ui/gfx/render_text_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 18 matching lines...) Expand all
258 AdvanceLine(); 260 AdvanceLine();
259 lines_.pop_back(); 261 lines_.pop_back();
260 *size = total_size_; 262 *size = total_size_;
261 lines->swap(lines_); 263 lines->swap(lines_);
262 } 264 }
263 265
264 private: 266 private:
265 // A (line index, segment index) pair that specifies a segment in |lines_|. 267 // A (line index, segment index) pair that specifies a segment in |lines_|.
266 typedef std::pair<size_t, size_t> SegmentHandle; 268 typedef std::pair<size_t, size_t> SegmentHandle;
267 269
270 struct SortByVisualPosition {
ckocagil 2015/02/13 19:05:25 Make this comparator a lambda expression and defin
Jun Mukai 2015/02/13 21:57:58 Done.
271 explicit SortByVisualPosition(const std::vector<int32_t>& logical_to_visual)
272 : logical_to_visual(logical_to_visual) {}
273
274 bool operator()(const internal::LineSegment& segment1,
275 const internal::LineSegment& segment2) {
276 return logical_to_visual[segment1.run] < logical_to_visual[segment2.run];
277 }
278
279 const std::vector<int32_t>& logical_to_visual;
280 };
281
268 internal::LineSegment* SegmentFromHandle(const SegmentHandle& handle) { 282 internal::LineSegment* SegmentFromHandle(const SegmentHandle& handle) {
269 return &lines_[handle.first].segments[handle.second]; 283 return &lines_[handle.first].segments[handle.second];
270 } 284 }
271 285
272 // Breaks a run into segments that fit in the last line in |lines_| and adds 286 // Breaks a run into segments that fit in the last line in |lines_| and adds
273 // them. Adds a new Line to the back of |lines_| whenever a new segment can't 287 // them. Adds a new Line to the back of |lines_| whenever a new segment can't
274 // be added without the Line's width exceeding |max_width_|. 288 // be added without the Line's width exceeding |max_width_|.
275 void BreakRun(int run_index) { 289 void BreakRun(int run_index) {
276 const internal::TextRunHarfBuzz& run = *runs_[run_index]; 290 const internal::TextRunHarfBuzz& run = *runs_[run_index];
277 SkScalar width = 0; 291 SkScalar width = 0;
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
366 x += segment_width; 380 x += segment_width;
367 } 381 }
368 rtl_segments_.clear(); 382 rtl_segments_.clear();
369 } 383 }
370 384
371 // Finishes the size calculations of the last Line in |lines_|. Adds a new 385 // Finishes the size calculations of the last Line in |lines_|. Adds a new
372 // Line to the back of |lines_|. 386 // Line to the back of |lines_|.
373 void AdvanceLine() { 387 void AdvanceLine() {
374 if (!lines_.empty()) { 388 if (!lines_.empty()) {
375 internal::Line* line = &lines_.back(); 389 internal::Line* line = &lines_.back();
390 std::sort(line->segments.begin(), line->segments.end(),
391 SortByVisualPosition(logical_to_visual_));
376 line->size.set_height(std::max(min_height_, max_descent_ + max_ascent_)); 392 line->size.set_height(std::max(min_height_, max_descent_ + max_ascent_));
377 line->baseline = 393 line->baseline =
378 std::max(min_baseline_, SkScalarRoundToInt(max_ascent_)); 394 std::max(min_baseline_, SkScalarRoundToInt(max_ascent_));
379 line->preceding_heights = std::ceil(total_size_.height()); 395 line->preceding_heights = std::ceil(total_size_.height());
380 total_size_.set_height(total_size_.height() + line->size.height()); 396 total_size_.set_height(total_size_.height() + line->size.height());
381 total_size_.set_width(std::max(total_size_.width(), line->size.width())); 397 total_size_.set_width(std::max(total_size_.width(), line->size.width()));
382 } 398 }
383 max_descent_ = 0; 399 max_descent_ = 0;
384 max_ascent_ = 0; 400 max_ascent_ = 0;
385 line_x_ = 0; 401 line_x_ = 0;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 } 443 }
428 text_x_ += SkFloatToScalar(width); 444 text_x_ += SkFloatToScalar(width);
429 line_x_ += SkFloatToScalar(width); 445 line_x_ += SkFloatToScalar(width);
430 } 446 }
431 447
432 const SkScalar max_width_; 448 const SkScalar max_width_;
433 const int min_baseline_; 449 const int min_baseline_;
434 const float min_height_; 450 const float min_height_;
435 const bool multiline_; 451 const bool multiline_;
436 const base::string16& text_; 452 const base::string16& text_;
453 const std::vector<int32_t>& logical_to_visual_;
437 const BreakList<size_t>* const words_; 454 const BreakList<size_t>* const words_;
438 const ScopedVector<internal::TextRunHarfBuzz>& runs_; 455 const ScopedVector<internal::TextRunHarfBuzz>& runs_;
439 456
440 // Stores the resulting lines. 457 // Stores the resulting lines.
441 std::vector<internal::Line> lines_; 458 std::vector<internal::Line> lines_;
442 459
443 // Text space and line space x coordinates of the next segment to be added. 460 // Text space and line space x coordinates of the next segment to be added.
444 SkScalar text_x_; 461 SkScalar text_x_;
445 SkScalar line_x_; 462 SkScalar line_x_;
446 463
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after
916 933
917 if (lines().empty()) { 934 if (lines().empty()) {
918 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. 935 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed.
919 tracked_objects::ScopedTracker tracking_profile2( 936 tracked_objects::ScopedTracker tracking_profile2(
920 FROM_HERE_WITH_EXPLICIT_FUNCTION( 937 FROM_HERE_WITH_EXPLICIT_FUNCTION(
921 "431326 RenderTextHarfBuzz::EnsureLayout2")); 938 "431326 RenderTextHarfBuzz::EnsureLayout2"));
922 939
923 HarfBuzzLineBreaker line_breaker( 940 HarfBuzzLineBreaker line_breaker(
924 display_rect().width(), font_list().GetBaseline(), 941 display_rect().width(), font_list().GetBaseline(),
925 std::max(font_list().GetHeight(), min_line_height()), multiline(), 942 std::max(font_list().GetHeight(), min_line_height()), multiline(),
926 GetLayoutText(), multiline() ? &GetLineBreaks() : nullptr, runs_); 943 GetLayoutText(), logical_to_visual_,
944 multiline() ? &GetLineBreaks() : nullptr, runs_);
927 945
928 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. 946 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed.
929 tracked_objects::ScopedTracker tracking_profile3( 947 tracked_objects::ScopedTracker tracking_profile3(
930 FROM_HERE_WITH_EXPLICIT_FUNCTION( 948 FROM_HERE_WITH_EXPLICIT_FUNCTION(
931 "431326 RenderTextHarfBuzz::EnsureLayout3")); 949 "431326 RenderTextHarfBuzz::EnsureLayout3"));
932 950
933 for (size_t i = 0; i < runs_.size(); ++i) 951 for (size_t i = 0; i < runs_.size(); ++i)
934 line_breaker.AddRun(visual_to_logical_[i]); 952 line_breaker.AddRun(i);
935 std::vector<internal::Line> lines; 953 std::vector<internal::Line> lines;
936 line_breaker.Finalize(&lines, &total_size_); 954 line_breaker.Finalize(&lines, &total_size_);
937 set_lines(&lines); 955 set_lines(&lines);
938 } 956 }
939 } 957 }
940 958
941 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { 959 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) {
960 internal::SkiaTextRenderer renderer(canvas);
961 DrawVisualTextInternal(&renderer);
962 }
963
964 void RenderTextHarfBuzz::DrawVisualTextInternal(
965 internal::SkiaTextRenderer* renderer) {
942 DCHECK(!needs_layout_); 966 DCHECK(!needs_layout_);
943 if (lines().empty()) 967 if (lines().empty())
944 return; 968 return;
945 969
946 internal::SkiaTextRenderer renderer(canvas); 970 ApplyFadeEffects(renderer);
947 ApplyFadeEffects(&renderer); 971 ApplyTextShadows(renderer);
948 ApplyTextShadows(&renderer);
949 ApplyCompositionAndSelectionStyles(); 972 ApplyCompositionAndSelectionStyles();
950 973
951 for (size_t i = 0; i < lines().size(); ++i) { 974 for (size_t i = 0; i < lines().size(); ++i) {
952 const internal::Line& line = lines()[i]; 975 const internal::Line& line = lines()[i];
953 const Vector2d origin = GetLineOffset(i) + Vector2d(0, line.baseline); 976 const Vector2d origin = GetLineOffset(i) + Vector2d(0, line.baseline);
954 SkScalar preceding_segment_widths = 0; 977 SkScalar preceding_segment_widths = 0;
955 for (const internal::LineSegment& segment : line.segments) { 978 for (const internal::LineSegment& segment : line.segments) {
956 const internal::TextRunHarfBuzz& run = *runs_[segment.run]; 979 const internal::TextRunHarfBuzz& run = *runs_[segment.run];
957 renderer.SetTypeface(run.skia_face.get()); 980 renderer->SetTypeface(run.skia_face.get());
958 renderer.SetTextSize(SkIntToScalar(run.font_size)); 981 renderer->SetTextSize(SkIntToScalar(run.font_size));
959 renderer.SetFontRenderParams(run.render_params, 982 renderer->SetFontRenderParams(run.render_params,
960 background_is_transparent()); 983 background_is_transparent());
961 Range glyphs_range = run.CharRangeToGlyphRange(segment.char_range); 984 Range glyphs_range = run.CharRangeToGlyphRange(segment.char_range);
962 scoped_ptr<SkPoint[]> positions(new SkPoint[glyphs_range.length()]); 985 scoped_ptr<SkPoint[]> positions(new SkPoint[glyphs_range.length()]);
963 SkScalar offset_x = 986 SkScalar offset_x =
964 preceding_segment_widths - run.positions[glyphs_range.start()].x(); 987 preceding_segment_widths - run.positions[glyphs_range.start()].x();
965 for (size_t j = 0; j < glyphs_range.length(); ++j) { 988 for (size_t j = 0; j < glyphs_range.length(); ++j) {
966 positions[j] = run.positions[(glyphs_range.is_reversed()) ? 989 positions[j] = run.positions[(glyphs_range.is_reversed()) ?
967 (glyphs_range.start() - j) : 990 (glyphs_range.start() - j) :
968 (glyphs_range.start() + j)]; 991 (glyphs_range.start() + j)];
969 positions[j].offset(SkIntToScalar(origin.x()) + offset_x, 992 positions[j].offset(SkIntToScalar(origin.x()) + offset_x,
970 SkIntToScalar(origin.y())); 993 SkIntToScalar(origin.y()));
971 } 994 }
972 for (BreakList<SkColor>::const_iterator it = 995 for (BreakList<SkColor>::const_iterator it =
973 colors().GetBreak(segment.char_range.start()); 996 colors().GetBreak(segment.char_range.start());
974 it != colors().breaks().end() && 997 it != colors().breaks().end() &&
975 it->first < segment.char_range.end(); 998 it->first < segment.char_range.end();
976 ++it) { 999 ++it) {
977 const Range intersection = 1000 const Range intersection =
978 colors().GetRange(it).Intersect(segment.char_range); 1001 colors().GetRange(it).Intersect(segment.char_range);
979 const Range colored_glyphs = run.CharRangeToGlyphRange(intersection); 1002 const Range colored_glyphs = run.CharRangeToGlyphRange(intersection);
980 // The range may be empty if a portion of a multi-character grapheme is 1003 // 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 1004 // 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, 1005 // paints the glyph with a single style, but it should paint it twice,
983 // clipped according to selection bounds. See http://crbug.com/366786 1006 // clipped according to selection bounds. See http://crbug.com/366786
984 if (colored_glyphs.is_empty()) 1007 if (colored_glyphs.is_empty())
985 continue; 1008 continue;
986 1009
987 renderer.SetForegroundColor(it->second); 1010 renderer->SetForegroundColor(it->second);
988 renderer.DrawPosText( 1011 renderer->DrawPosText(
989 &positions[colored_glyphs.start() - glyphs_range.start()], 1012 &positions[colored_glyphs.start() - glyphs_range.start()],
990 &run.glyphs[colored_glyphs.start()], colored_glyphs.length()); 1013 &run.glyphs[colored_glyphs.start()], colored_glyphs.length());
991 int start_x = SkScalarRoundToInt( 1014 int start_x = SkScalarRoundToInt(
992 positions[colored_glyphs.start() - glyphs_range.start()].x()); 1015 positions[colored_glyphs.start() - glyphs_range.start()].x());
993 int end_x = SkScalarRoundToInt( 1016 int end_x = SkScalarRoundToInt(
994 (colored_glyphs.end() == glyphs_range.end()) 1017 (colored_glyphs.end() == glyphs_range.end())
995 ? (SkFloatToScalar(segment.width) + preceding_segment_widths + 1018 ? (SkFloatToScalar(segment.width) + preceding_segment_widths +
996 SkIntToScalar(origin.x())) 1019 SkIntToScalar(origin.x()))
997 : positions[colored_glyphs.end() - glyphs_range.start()].x()); 1020 : positions[colored_glyphs.end() - glyphs_range.start()].x());
998 renderer.DrawDecorations(start_x, origin.y(), end_x - start_x, 1021 renderer->DrawDecorations(start_x, origin.y(), end_x - start_x,
999 run.underline, run.strike, 1022 run.underline, run.strike,
1000 run.diagonal_strike); 1023 run.diagonal_strike);
1001 } 1024 }
1002 preceding_segment_widths += SkFloatToScalar(segment.width); 1025 preceding_segment_widths += SkFloatToScalar(segment.width);
1003 } 1026 }
1004 } 1027 }
1005 1028
1006 renderer.EndDiagonalStrike(); 1029 renderer->EndDiagonalStrike();
1007 1030
1008 UndoCompositionAndSelectionStyles(); 1031 UndoCompositionAndSelectionStyles();
1009 } 1032 }
1010 1033
1011 size_t RenderTextHarfBuzz::GetRunContainingCaret( 1034 size_t RenderTextHarfBuzz::GetRunContainingCaret(
1012 const SelectionModel& caret) const { 1035 const SelectionModel& caret) const {
1013 DCHECK(!needs_layout_); 1036 DCHECK(!needs_layout_);
1014 size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos()); 1037 size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos());
1015 LogicalCursorDirection affinity = caret.caret_affinity(); 1038 LogicalCursorDirection affinity = caret.caret_affinity();
1016 for (size_t run = 0; run < runs_.size(); ++run) { 1039 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")); 1334 "431326 RenderTextHarfBuzz::ShapeRunWithFont3"));
1312 1335
1313 for (size_t i = 0; i < run->glyph_count; ++i) { 1336 for (size_t i = 0; i < run->glyph_count; ++i) {
1314 DCHECK_LE(infos[i].codepoint, std::numeric_limits<uint16>::max()); 1337 DCHECK_LE(infos[i].codepoint, std::numeric_limits<uint16>::max());
1315 run->glyphs[i] = static_cast<uint16>(infos[i].codepoint); 1338 run->glyphs[i] = static_cast<uint16>(infos[i].codepoint);
1316 run->glyph_to_char[i] = infos[i].cluster; 1339 run->glyph_to_char[i] = infos[i].cluster;
1317 const SkScalar x_offset = SkFixedToScalar(hb_positions[i].x_offset); 1340 const SkScalar x_offset = SkFixedToScalar(hb_positions[i].x_offset);
1318 const SkScalar y_offset = SkFixedToScalar(hb_positions[i].y_offset); 1341 const SkScalar y_offset = SkFixedToScalar(hb_positions[i].y_offset);
1319 run->positions[i].set(run->width + x_offset, -y_offset); 1342 run->positions[i].set(run->width + x_offset, -y_offset);
1320 run->width += (glyph_width_for_test_ > 0) 1343 run->width += (glyph_width_for_test_ > 0)
1321 ? SkIntToScalar(glyph_width_for_test_) 1344 ? glyph_width_for_test_
1322 : SkFixedToScalar(hb_positions[i].x_advance); 1345 : SkFixedToFloat(hb_positions[i].x_advance);
1323 // Round run widths if subpixel positioning is off to match native behavior. 1346 // Round run widths if subpixel positioning is off to match native behavior.
1324 if (!run->render_params.subpixel_positioning) 1347 if (!run->render_params.subpixel_positioning)
1325 run->width = std::floor(run->width + 0.5f); 1348 run->width = std::floor(run->width + 0.5f);
1326 } 1349 }
1327 1350
1328 hb_buffer_destroy(buffer); 1351 hb_buffer_destroy(buffer);
1329 hb_font_destroy(harfbuzz_font); 1352 hb_font_destroy(harfbuzz_font);
1330 return true; 1353 return true;
1331 } 1354 }
1332 1355
1333 } // namespace gfx 1356 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text_harfbuzz.h ('k') | ui/gfx/render_text_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698