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

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

Issue 16867016: Windows implementation of multiline RenderText (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: fix ComputeLines and rects Created 7 years, 5 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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_win.h" 5 #include "ui/gfx/render_text_win.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/i18n/break_iterator.h" 9 #include "base/i18n/break_iterator.h"
10 #include "base/i18n/rtl.h" 10 #include "base/i18n/rtl.h"
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 bool IsUnicodeBidiControlCharacter(char16 c) { 118 bool IsUnicodeBidiControlCharacter(char16 c) {
119 return c == base::i18n::kRightToLeftMark || 119 return c == base::i18n::kRightToLeftMark ||
120 c == base::i18n::kLeftToRightMark || 120 c == base::i18n::kLeftToRightMark ||
121 c == base::i18n::kLeftToRightEmbeddingMark || 121 c == base::i18n::kLeftToRightEmbeddingMark ||
122 c == base::i18n::kRightToLeftEmbeddingMark || 122 c == base::i18n::kRightToLeftEmbeddingMark ||
123 c == base::i18n::kPopDirectionalFormatting || 123 c == base::i18n::kPopDirectionalFormatting ||
124 c == base::i18n::kLeftToRightOverride || 124 c == base::i18n::kLeftToRightOverride ||
125 c == base::i18n::kRightToLeftOverride; 125 c == base::i18n::kRightToLeftOverride;
126 } 126 }
127 127
128 ui::Range CharRangeToGlyphRange(const ui::Range& range,
Alexei Svitkine (slow) 2013/07/09 15:35:13 Add a comment.
ckocagil 2013/07/13 16:05:10 Done.
129 internal::TextRun* run) {
Alexei Svitkine (slow) 2013/07/09 15:35:13 This should be const and possibly by ref to preven
ckocagil 2013/07/13 16:05:10 Done.
130 DCHECK_GE(range.start(), 0u);
131 DCHECK_LE(range.end(), run->range.length());
msw 2013/07/10 04:01:56 nit: Can you just [D]CHECK(run->range.Contains(ran
ckocagil 2013/07/13 16:05:10 Done. Done. Done.
132 DCHECK_LE(range.start(), range.end());
133 bool rtl = run->script_analysis.fRTL;
Alexei Svitkine (slow) 2013/07/09 15:35:13 Inline this, since you only use it once.
ckocagil 2013/07/13 16:05:10 Done.
134 int start_char = range.start();
135 int end_char = range.end();
Alexei Svitkine (slow) 2013/07/09 15:35:13 Nit: You don't need local vars for start_char and
ckocagil 2013/07/13 16:05:10 Done.
136 int start, end;
Alexei Svitkine (slow) 2013/07/09 15:35:13 Nit: Separate lines.
msw 2013/07/10 04:01:56 Also, explicitly init each to 0.
ckocagil 2013/07/13 16:05:10 Both done.
137 if (rtl) {
138 start = run->logical_clusters[end_char - 1];
139 end = start_char > 0 ? run->logical_clusters[start_char - 1]
140 : run->glyph_count;
141 } else {
142 start = run->logical_clusters[start_char];
143 end = end_char < run->glyph_count ? run->logical_clusters[end_char]
msw 2013/07/10 04:01:56 Shouldn't this be end_char < run->range.length() ?
ckocagil 2013/07/13 16:05:10 Shame on me, this would be a subtle bug. Thanks! D
144 : run->glyph_count;
145 }
146 return ui::Range(start, end);
147 }
148
128 } // namespace 149 } // namespace
129 150
130 namespace internal { 151 namespace internal {
131 152
132 TextRun::TextRun() 153 TextRun::TextRun()
133 : foreground(0), 154 : foreground(0),
134 font_style(0), 155 font_style(0),
135 strike(false), 156 strike(false),
136 diagonal_strike(false), 157 diagonal_strike(false),
137 underline(false), 158 underline(false),
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 memset(&script_state_, 0, sizeof(script_state_)); 206 memset(&script_state_, 0, sizeof(script_state_));
186 207
187 MoveCursorTo(EdgeSelectionModel(CURSOR_LEFT)); 208 MoveCursorTo(EdgeSelectionModel(CURSOR_LEFT));
188 } 209 }
189 210
190 RenderTextWin::~RenderTextWin() { 211 RenderTextWin::~RenderTextWin() {
191 } 212 }
192 213
193 Size RenderTextWin::GetStringSize() { 214 Size RenderTextWin::GetStringSize() {
194 EnsureLayout(); 215 EnsureLayout();
195 return string_size_; 216 // TODO: is this the right place to add +1 for cursor?
217 return Size(string_size_.width() + 1, string_size_.height());
Alexei Svitkine (slow) 2013/07/09 15:35:13 Can you explain why this is needed (and why it was
msw 2013/07/10 04:01:56 I think it's already handled by RenderText::GetCon
ckocagil 2013/07/13 16:05:10 Yes, I later noticed it. Removing the +1 here.
218 }
219
220 Size RenderTextWin::GetMultilineTextSize() {
221 EnsureLayout();
222 if (!multiline())
223 return Size(display_rect().width(), string_size_.height());
224 ComputeLines();
msw 2013/07/10 04:01:56 Do this as needed in EnsureLayout().
ckocagil 2013/07/13 16:05:10 Done.
225 return Size(display_rect().width(),
226 string_size_.height() * lines().size());
Alexei Svitkine (slow) 2013/07/09 15:35:13 Are all lines guaranteed to have the same height?
ckocagil 2013/07/13 16:05:10 Done, we use per-line heights now.
196 } 227 }
197 228
198 int RenderTextWin::GetBaseline() { 229 int RenderTextWin::GetBaseline() {
199 EnsureLayout(); 230 EnsureLayout();
200 return common_baseline_; 231 return common_baseline_;
201 } 232 }
202 233
203 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) { 234 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) {
204 if (text().empty()) 235 if (text().empty())
205 return SelectionModel(); 236 return SelectionModel();
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 GetGlyphXBoundary(run, layout_index, true)); 383 GetGlyphXBoundary(run, layout_index, true));
353 } 384 }
354 385
355 std::vector<Rect> RenderTextWin::GetSubstringBounds(const ui::Range& range) { 386 std::vector<Rect> RenderTextWin::GetSubstringBounds(const ui::Range& range) {
356 DCHECK(!needs_layout_); 387 DCHECK(!needs_layout_);
357 DCHECK(ui::Range(0, text().length()).Contains(range)); 388 DCHECK(ui::Range(0, text().length()).Contains(range));
358 ui::Range layout_range(TextIndexToLayoutIndex(range.start()), 389 ui::Range layout_range(TextIndexToLayoutIndex(range.start()),
359 TextIndexToLayoutIndex(range.end())); 390 TextIndexToLayoutIndex(range.end()));
360 DCHECK(ui::Range(0, GetLayoutText().length()).Contains(layout_range)); 391 DCHECK(ui::Range(0, GetLayoutText().length()).Contains(layout_range));
361 392
362 std::vector<Rect> bounds; 393 std::vector<ui::Range> bounds;
394 std::vector<Rect> rects;
363 if (layout_range.is_empty()) 395 if (layout_range.is_empty())
364 return bounds; 396 return rects;
365 397
366 // Add a Rect for each run/selection intersection. 398 // Add a Rect for each run/selection intersection.
367 // TODO(msw): The bounds should probably not always be leading the range ends. 399 // TODO(msw): The bounds should probably not always be leading the range ends.
368 for (size_t i = 0; i < runs_.size(); ++i) { 400 for (size_t i = 0; i < runs_.size(); ++i) {
369 const internal::TextRun* run = runs_[visual_to_logical_[i]]; 401 const internal::TextRun* run = runs_[visual_to_logical_[i]];
370 ui::Range intersection = run->range.Intersect(layout_range); 402 ui::Range intersection = run->range.Intersect(layout_range);
371 if (intersection.IsValid()) { 403 if (intersection.IsValid()) {
372 DCHECK(!intersection.is_reversed()); 404 DCHECK(!intersection.is_reversed());
373 ui::Range range_x(GetGlyphXBoundary(run, intersection.start(), false), 405 ui::Range range_x(GetGlyphXBoundary(run, intersection.start(), false),
374 GetGlyphXBoundary(run, intersection.end(), false)); 406 GetGlyphXBoundary(run, intersection.end(), false));
375 Rect rect(range_x.GetMin(), 0, range_x.length(), run->font.GetHeight()); 407 range_x = ui::Range(range_x.GetMin(), range_x.GetMax());
376 rect.set_origin(ToViewPoint(rect.origin())); 408 // Union this with the last range if they're adjacent.
377 // Union this with the last rect if they're adjacent. 409 if (!bounds.empty() && bounds.back().GetMax() == range_x.GetMin()) {
msw 2013/07/10 04:01:56 This will miss cases where range_x.GetMax() == bou
ckocagil 2013/07/13 16:05:10 Added a DCHECK for this case but it doesn't seem t
378 if (!bounds.empty() && rect.SharesEdgeWith(bounds.back())) { 410 range_x = ui::Range(bounds.back().GetMin(), range_x.GetMax());
379 rect.Union(bounds.back());
380 bounds.pop_back(); 411 bounds.pop_back();
381 } 412 }
382 bounds.push_back(rect); 413 bounds.push_back(range_x);
383 } 414 }
384 } 415 }
385 return bounds; 416 for (size_t i = 0; i < bounds.size(); ++i) {
417 std::vector<Rect> current_rects = RangeToViewRects(bounds[i], 0);
418 rects.insert(rects.end(), current_rects.begin(), current_rects.end());
419 }
420 return rects;
386 } 421 }
387 422
388 size_t RenderTextWin::TextIndexToLayoutIndex(size_t index) const { 423 size_t RenderTextWin::TextIndexToLayoutIndex(size_t index) const {
389 if (!obscured()) 424 if (!obscured())
390 return index; 425 return index;
391 426
392 DCHECK_LE(index, text().length()); 427 DCHECK_LE(index, text().length());
393 const ptrdiff_t offset = ui::UTF16IndexToOffset(text(), 0, index); 428 const ptrdiff_t offset = ui::UTF16IndexToOffset(text(), 0, index);
394 DCHECK_GE(offset, 0); 429 DCHECK_GE(offset, 0);
395 DCHECK_LE(static_cast<size_t>(offset), GetLayoutText().length()); 430 DCHECK_LE(static_cast<size_t>(offset), GetLayoutText().length());
(...skipping 17 matching lines...) Expand all
413 448
414 // Check if the index is at a valid code point (not mid-surrgate-pair) with 449 // Check if the index is at a valid code point (not mid-surrgate-pair) with
415 // distinct glyph bounds (not mid-multi-character-grapheme, eg. \x0915\x093f). 450 // distinct glyph bounds (not mid-multi-character-grapheme, eg. \x0915\x093f).
416 return ui::IsValidCodePointIndex(text(), position) && 451 return ui::IsValidCodePointIndex(text(), position) &&
417 GetGlyphBounds(position) != GetGlyphBounds(position - 1); 452 GetGlyphBounds(position) != GetGlyphBounds(position - 1);
418 } 453 }
419 454
420 void RenderTextWin::ResetLayout() { 455 void RenderTextWin::ResetLayout() {
421 // Layout is performed lazily as needed for drawing/metrics. 456 // Layout is performed lazily as needed for drawing/metrics.
422 needs_layout_ = true; 457 needs_layout_ = true;
458 set_lines_valid(false); // TODO: do we need this?
msw 2013/07/10 04:01:56 I think lines_valid_ should implicitly be part of
ckocagil 2013/07/13 16:05:10 Done.
423 } 459 }
424 460
425 void RenderTextWin::EnsureLayout() { 461 void RenderTextWin::EnsureLayout() {
426 if (!needs_layout_) 462 if (!needs_layout_)
427 return; 463 return;
464
428 // TODO(msw): Skip complex processing if ScriptIsComplex returns false. 465 // TODO(msw): Skip complex processing if ScriptIsComplex returns false.
429 ItemizeLogicalText(); 466 ItemizeLogicalText();
430 if (!runs_.empty()) 467 if (!runs_.empty())
431 LayoutVisualText(); 468 LayoutVisualText();
469
432 needs_layout_ = false; 470 needs_layout_ = false;
433 } 471 }
434 472
473 void RenderTextWin::ComputeLines() {
474 if (lines_valid() || !multiline())
475 return;
476
477 EnsureLayout();
478
479 std::vector<ScopedVector<internal::LineSegment> > lines;
msw 2013/07/10 04:01:56 Should these be LineSegmentWin?
ckocagil 2013/07/13 16:05:10 We now use Line structs here.
480 lines.push_back(ScopedVector<internal::LineSegment>());
481
482 int max_width = display_rect().width();
483
484 std::vector<size_t> breaks = line_breaks();
485 for (size_t i = 0; i < runs_.size(); ++i)
486 breaks.push_back(runs_[i]->range.start());
487 breaks.push_back(0); // TODO: necessary?
msw 2013/07/10 04:01:56 Probably not necessary, resolve the TODO.
ckocagil 2013/07/13 16:05:10 We need at least one element, now I'm only adding
488 breaks.push_back(-1);
msw 2013/07/10 04:01:56 What's this unsigned wraparound max size_t used fo
ckocagil 2013/07/13 16:05:10 This was used as an anchor so we didn't go past th
489 std::sort(breaks.begin(), breaks.end());
490 std::unique(breaks.begin(), breaks.end());
Alexei Svitkine (slow) 2013/07/09 15:35:13 Is this needed? If so, perhaps add a test that wil
ckocagil 2013/07/13 16:05:10 This shouldn't be needed. Removing.
491
492 size_t* last_break = &breaks[0];
493
494 int line_x = 0; // x from the line beginning
495 int text_x = 0; // x from the text beginning
496 size_t segment_start_char = 0; // offset of current segment beginning
497 int segment_start_pos = 0; // position of current segment beginning
498 internal::TextRun* run;
499 size_t line_beginning = 0;
500
501 for (size_t i = 0; i < runs_.size(); ++i) {
msw 2013/07/10 04:01:56 This function needs comments explaining what it's
ckocagil 2013/07/13 16:05:10 Added a comment explaining what this function does
502 // TODO: might need |line_break = range.start| to break at run beginnings
msw 2013/07/10 04:01:56 nit: resolve TODO
ckocagil 2013/07/13 16:05:10 Done.
503 run = runs_[visual_to_logical_[i]];
504 bool rtl = run->script_analysis.fRTL;
505 int break_x = 0;
506
507 last_break = &breaks[0];
508
509 segment_start_char = run->range.start();
510 segment_start_pos = text_x;
511
512 int run_beginning_x = text_x;
513 typedef std::pair<internal::LineSegment*, int> RtlWidth;
msw 2013/07/10 04:01:56 Comment here, what's an RtlWidth?
ckocagil 2013/07/13 16:05:10 Done.
514 std::vector<RtlWidth> rtl_widths;
515
516 for (size_t c = 0; c < run->range.length(); ++c) {
Alexei Svitkine (slow) 2013/07/09 15:35:13 Use i, j, k for loops, so this should be j and the
msw 2013/07/10 04:01:56 There must be a better approach than fitting lines
ckocagil 2013/07/13 16:05:10 Actually I have thought about most of the stuff yo
ckocagil 2013/07/13 16:05:10 Done.
517 size_t offset = c + run->range.start();
518 while (offset >= *(last_break + 1)) {
Alexei Svitkine (slow) 2013/07/09 15:35:13 Can you you use ui/gfx/break_list.h or are the sem
ckocagil 2013/07/13 16:05:10 I can use a break list but then every time I use G
519 ++last_break;
520 break_x = 0;
521 }
522
523 ui::Range glyphs = CharRangeToGlyphRange(ui::Range(c, c + 1), run);
524 int start = glyphs.start();
525 int end = glyphs.end();
526
527 int char_width = 0;
528 for (int g = start; g < end; ++g)
529 char_width += run->advance_widths[g];
530
531 line_x += char_width;
532 text_x += char_width;
533 break_x += char_width;
534
535 if (line_x > max_width) {
536 if (*last_break > line_beginning) {
537 // Roll back to last break.
538 text_x -= break_x;
539 c = *last_break - run->range.start() - 1;
540 offset = *last_break;
541 } else if (line_x != char_width) {
542 // Roll back one character.
543 text_x -= char_width;
544 --c;
545 } // else: Assume the current character fits; continue from next line.
546 line_beginning = offset;
547 line_x = 0;
548 break_x = 0;
549
550 internal::LineSegmentWin* segment = new internal::LineSegmentWin;
551 if (rtl)
552 rtl_widths.push_back(RtlWidth(segment, text_x - segment_start_pos));
553 else
554 segment->x_pos = ui::Range(segment_start_pos, text_x);
555 segment->char_pos = ui::Range(segment_start_char, offset);
556 segment->run = run;
557 lines.back().push_back(segment);
558 lines.push_back(ScopedVector<internal::LineSegment>());
559
560 segment_start_pos = text_x;
561 segment_start_char = offset;
562 continue;
563 }
564 }
565 if (segment_start_char != run->range.end()) {
566 internal::LineSegmentWin* segment = new internal::LineSegmentWin;
567 if (rtl)
568 rtl_widths.push_back(RtlWidth(segment, text_x - segment_start_pos));
569 else
570 segment->x_pos = ui::Range(segment_start_pos, text_x);
571 segment->char_pos = ui::Range(segment_start_char, run->range.end());
572 segment->run = run;
573 lines.back().push_back(segment);
574 segment_start_char = run->range.end();
575 segment_start_pos = text_x;
576 }
577
578 int rtl_total_widths = 0;
579 while (!rtl_widths.empty()) {
580 const RtlWidth& rtl_width = rtl_widths.back();
581 rtl_width.first->x_pos = ui::Range(run_beginning_x + rtl_total_widths,
582 run_beginning_x + rtl_total_widths + rtl_width.second);
583 rtl_widths.pop_back();
584 rtl_total_widths += rtl_width.second;
585 }
586 }
587
588 set_lines(&lines);
589 set_lines_valid(true);
590 }
591
435 void RenderTextWin::DrawVisualText(Canvas* canvas) { 592 void RenderTextWin::DrawVisualText(Canvas* canvas) {
436 DCHECK(!needs_layout_); 593 DCHECK(!needs_layout_);
437 594
438 // Skia will draw glyphs with respect to the baseline. 595 if (multiline())
439 Vector2d offset(GetTextOffset() + Vector2d(0, common_baseline_)); 596 ComputeLines();
msw 2013/07/10 04:01:56 I think ComputeLines should be done as a step in E
ckocagil 2013/07/13 16:05:10 Done.
440
441 SkScalar x = SkIntToScalar(offset.x());
442 SkScalar y = SkIntToScalar(offset.y());
443 597
444 std::vector<SkPoint> pos; 598 std::vector<SkPoint> pos;
445 599
446 internal::SkiaTextRenderer renderer(canvas); 600 internal::SkiaTextRenderer renderer(canvas);
447 ApplyFadeEffects(&renderer); 601 ApplyFadeEffects(&renderer);
448 ApplyTextShadows(&renderer); 602 ApplyTextShadows(&renderer);
449 603
450 bool smoothing_enabled; 604 bool smoothing_enabled;
451 bool cleartype_enabled; 605 bool cleartype_enabled;
452 GetCachedFontSmoothingSettings(&smoothing_enabled, &cleartype_enabled); 606 GetCachedFontSmoothingSettings(&smoothing_enabled, &cleartype_enabled);
453 // Note that |cleartype_enabled| corresponds to Skia's |enable_lcd_text|. 607 // Note that |cleartype_enabled| corresponds to Skia's |enable_lcd_text|.
454 renderer.SetFontSmoothingSettings( 608 renderer.SetFontSmoothingSettings(
455 smoothing_enabled, cleartype_enabled && !background_is_transparent()); 609 smoothing_enabled, cleartype_enabled && !background_is_transparent());
456 610
457 for (size_t i = 0; i < runs_.size(); ++i) { 611 SkScalar glyph_x = SkIntToScalar(0);
458 // Get the run specified by the visual-to-logical map. 612 SkScalar glyph_y = SkIntToScalar(0);
459 internal::TextRun* run = runs_[visual_to_logical_[i]];
460 613
461 if (run->glyph_count == 0) 614 if (!multiline()) {
462 continue; 615 // Skia will draw glyphs with respect to the baseline.
616 Vector2d offset(0, common_baseline_);
617 offset += GetTextOffset(GetContentWidth());
463 618
464 // Based on WebCore::skiaDrawText. 619 for (size_t i = 0; i < runs_.size(); ++i) {
465 pos.resize(run->glyph_count); 620 // Get the run specified by the visual-to-logical map.
466 SkScalar glyph_x = x; 621 internal::TextRun* run = runs_[visual_to_logical_[i]];
467 for (int glyph = 0; glyph < run->glyph_count; glyph++) { 622
468 pos[glyph].set(glyph_x + run->offsets[glyph].du, 623 if (run->glyph_count == 0)
469 y + run->offsets[glyph].dv); 624 continue;
470 glyph_x += SkIntToScalar(run->advance_widths[glyph]); 625
626 // Based on WebCore::skiaDrawText.
627 pos.resize(run->glyph_count);
628 SkScalar run_x = glyph_x;
629 for (int glyph = 0; glyph < run->glyph_count; glyph++) {
630 pos[glyph].set(offset.x() + glyph_x + run->offsets[glyph].du,
631 offset.y() + run->offsets[glyph].dv);
632 glyph_x += SkIntToScalar(run->advance_widths[glyph]);
633 }
634
635 renderer.SetTextSize(run->font.GetFontSize());
636 renderer.SetFontFamilyWithStyle(run->font.GetFontName(), run->font_style);
637 renderer.SetForegroundColor(run->foreground);
638 renderer.DrawPosText(&pos[0], run->glyphs.get(), run->glyph_count);
639 renderer.DrawDecorations(run_x, offset.y(), run->width, run->underline,
640 run->strike, run->diagonal_strike);
471 } 641 }
642 return;
643 }
472 644
473 renderer.SetTextSize(run->font.GetFontSize()); 645 for (size_t line = 0; line < lines().size(); ++line) {
Alexei Svitkine (slow) 2013/07/09 15:35:13 Ideally, I'd like to see a single codepath that ha
ckocagil 2013/07/13 16:05:10 Done, added TODO.
474 renderer.SetFontFamilyWithStyle(run->font.GetFontName(), run->font_style); 646 Vector2d offset(0, common_baseline_);
475 renderer.SetForegroundColor(run->foreground); 647 offset += GetTextOffset(LineWidth(line));
476 renderer.DrawPosText(&pos[0], run->glyphs.get(), run->glyph_count); 648 for (size_t i = 0; i < lines()[line].size(); ++i) {
477 renderer.DrawDecorations(x, y, run->width, run->underline, run->strike, 649 const internal::LineSegmentWin* segment =
478 run->diagonal_strike); 650 static_cast<const internal::LineSegmentWin*>(lines()[line][i]);
479 651 if (segment->char_pos.is_empty())
480 x = glyph_x; 652 continue; // TODO: maybe prevent this from happening in the first place?
653 int segment_start_pos = glyph_x;
654 internal::TextRun* run = segment->run;
655 DCHECK_GE(segment->char_pos.start(), run->range.start());
656 DCHECK_LT(segment->char_pos.start(),
657 run->range.start() + run->glyph_count);
658 int start_char = segment->char_pos.start() - run->range.start();
659 int end_char = start_char + segment->char_pos.length();
660 ui::Range glyphs = CharRangeToGlyphRange(ui::Range(start_char, end_char),
661 run);
662 int start = glyphs.start();
663 int end = glyphs.end();
664 DCHECK_LE(start, end);
665 pos.resize(end - start);
666 for (int g = start; g < end; ++g) {
667 pos[g - start].set(glyph_x + offset.x() + run->offsets[g].du,
668 glyph_y + offset.y() + run->offsets[g].dv);
669 glyph_x += SkIntToScalar(run->advance_widths[g]);
670 }
671 renderer.SetTextSize(run->font.GetFontSize());
672 renderer.SetFontFamilyWithStyle(run->font.GetFontName(), run->font_style);
673 renderer.SetForegroundColor(run->foreground);
674 renderer.DrawPosText(&pos[0], &run->glyphs[start], end - start);
675 renderer.DrawDecorations(segment_start_pos + offset.x(),
676 glyph_y + offset.y(), segment->x_pos.length(),
677 run->underline, run->strike,
678 run->diagonal_strike);
679 }
680 glyph_x = SkIntToScalar(0);
681 glyph_y += SkIntToScalar(string_size_.height());
481 } 682 }
482 } 683 }
483 684
484 void RenderTextWin::ItemizeLogicalText() { 685 void RenderTextWin::ItemizeLogicalText() {
485 runs_.clear(); 686 runs_.clear();
486 string_size_ = Size(0, GetFont().GetHeight()); 687 string_size_ = Size(0, GetFont().GetHeight());
487 common_baseline_ = 0; 688 common_baseline_ = 0;
488 689
489 // Set Uniscribe's base text direction. 690 // Set Uniscribe's base text direction.
490 script_state_.uBidiLevel = 691 script_state_.uBidiLevel =
(...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after
828 size_t position = LayoutIndexToTextIndex(run->range.end()); 1029 size_t position = LayoutIndexToTextIndex(run->range.end());
829 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); 1030 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD);
830 return SelectionModel(position, CURSOR_FORWARD); 1031 return SelectionModel(position, CURSOR_FORWARD);
831 } 1032 }
832 1033
833 RenderText* RenderText::CreateInstance() { 1034 RenderText* RenderText::CreateInstance() {
834 return new RenderTextWin; 1035 return new RenderTextWin;
835 } 1036 }
836 1037
837 } // namespace gfx 1038 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698