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

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: fit whole runs, remove single-line stuff 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 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 bool IsUnicodeBidiControlCharacter(char16 c) { 122 bool IsUnicodeBidiControlCharacter(char16 c) {
123 return c == base::i18n::kRightToLeftMark || 123 return c == base::i18n::kRightToLeftMark ||
124 c == base::i18n::kLeftToRightMark || 124 c == base::i18n::kLeftToRightMark ||
125 c == base::i18n::kLeftToRightEmbeddingMark || 125 c == base::i18n::kLeftToRightEmbeddingMark ||
126 c == base::i18n::kRightToLeftEmbeddingMark || 126 c == base::i18n::kRightToLeftEmbeddingMark ||
127 c == base::i18n::kPopDirectionalFormatting || 127 c == base::i18n::kPopDirectionalFormatting ||
128 c == base::i18n::kLeftToRightOverride || 128 c == base::i18n::kLeftToRightOverride ||
129 c == base::i18n::kRightToLeftOverride; 129 c == base::i18n::kRightToLeftOverride;
130 } 130 }
131 131
132 // Returns the corresponding glyph range of the given character range.
133 ui::Range CharRangeToGlyphRange(const ui::Range& range,
134 const internal::TextRun& run) {
135 CHECK(run.range.Contains(ui::Range(range.start() + run.range.start(),
136 range.end() + run.range.start())));
137 CHECK(!range.is_reversed());
138 CHECK(!range.is_empty());
139 int start = 0;
140 int end = 0;
141 if (run.script_analysis.fRTL) {
142 start = run.logical_clusters[range.end() - 1];
143 end = range.start() > 0 ? run.logical_clusters[range.start() - 1]
144 : run.glyph_count;
145 } else {
146 start = run.logical_clusters[range.start()];
147 end = range.end() < run.range.length() ? run.logical_clusters[range.end()]
148 : run.glyph_count;
149 }
150 return ui::Range(start, end);
151 }
152
132 } // namespace 153 } // namespace
133 154
134 namespace internal { 155 namespace internal {
135 156
136 TextRun::TextRun() 157 TextRun::TextRun()
137 : foreground(0), 158 : foreground(0),
138 font_style(0), 159 font_style(0),
139 strike(false), 160 strike(false),
140 diagonal_strike(false), 161 diagonal_strike(false),
141 underline(false), 162 underline(false),
(...skipping 24 matching lines...) Expand all
166 run->glyph_count, 187 run->glyph_count,
167 run->logical_clusters.get(), 188 run->logical_clusters.get(),
168 run->visible_attributes.get(), 189 run->visible_attributes.get(),
169 run->advance_widths.get(), 190 run->advance_widths.get(),
170 &run->script_analysis, 191 &run->script_analysis,
171 &x); 192 &x);
172 DCHECK(SUCCEEDED(hr)); 193 DCHECK(SUCCEEDED(hr));
173 return run->preceding_run_widths + x; 194 return run->preceding_run_widths + x;
174 } 195 }
175 196
197 struct LineSegmentWin : LineSegment {
198 internal::TextRun* run;
199 };
200
176 } // namespace internal 201 } // namespace internal
177 202
178 // static 203 // static
179 HDC RenderTextWin::cached_hdc_ = NULL; 204 HDC RenderTextWin::cached_hdc_ = NULL;
180 205
181 // static 206 // static
182 std::map<std::string, Font> RenderTextWin::successful_substitute_fonts_; 207 std::map<std::string, Font> RenderTextWin::successful_substitute_fonts_;
183 208
184 RenderTextWin::RenderTextWin() 209 RenderTextWin::RenderTextWin()
185 : RenderText(), 210 : RenderText(),
186 common_baseline_(0), 211 common_baseline_(0),
187 needs_layout_(false) { 212 needs_layout_(false) {
188 set_truncate_length(kMaxUniscribeTextLength); 213 set_truncate_length(kMaxUniscribeTextLength);
189 214
190 memset(&script_control_, 0, sizeof(script_control_)); 215 memset(&script_control_, 0, sizeof(script_control_));
191 memset(&script_state_, 0, sizeof(script_state_)); 216 memset(&script_state_, 0, sizeof(script_state_));
192 217
193 MoveCursorTo(EdgeSelectionModel(CURSOR_LEFT)); 218 MoveCursorTo(EdgeSelectionModel(CURSOR_LEFT));
194 } 219 }
195 220
196 RenderTextWin::~RenderTextWin() { 221 RenderTextWin::~RenderTextWin() {
197 } 222 }
198 223
199 Size RenderTextWin::GetStringSize() { 224 Size RenderTextWin::GetStringSize() {
200 EnsureLayout(); 225 EnsureLayout();
201 return string_size_; 226 return Size(string_size_.width(), string_size_.height());
227 }
228
229 Size RenderTextWin::GetMultilineTextSize() {
230 EnsureLayout();
231 if (!multiline())
232 return Size(display_rect().width(), string_size_.height());
233 return Size(display_rect().width(),
234 lines().back().preceding_heights + lines().back().height);
202 } 235 }
203 236
204 int RenderTextWin::GetBaseline() { 237 int RenderTextWin::GetBaseline() {
205 EnsureLayout(); 238 EnsureLayout();
206 return common_baseline_; 239 return common_baseline_;
207 } 240 }
208 241
209 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) { 242 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) {
210 if (text().empty()) 243 if (text().empty())
211 return SelectionModel(); 244 return SelectionModel();
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 GetGlyphXBoundary(run, layout_index, true)); 393 GetGlyphXBoundary(run, layout_index, true));
361 } 394 }
362 395
363 std::vector<Rect> RenderTextWin::GetSubstringBounds(const ui::Range& range) { 396 std::vector<Rect> RenderTextWin::GetSubstringBounds(const ui::Range& range) {
364 DCHECK(!needs_layout_); 397 DCHECK(!needs_layout_);
365 DCHECK(ui::Range(0, text().length()).Contains(range)); 398 DCHECK(ui::Range(0, text().length()).Contains(range));
366 ui::Range layout_range(TextIndexToLayoutIndex(range.start()), 399 ui::Range layout_range(TextIndexToLayoutIndex(range.start()),
367 TextIndexToLayoutIndex(range.end())); 400 TextIndexToLayoutIndex(range.end()));
368 DCHECK(ui::Range(0, GetLayoutText().length()).Contains(layout_range)); 401 DCHECK(ui::Range(0, GetLayoutText().length()).Contains(layout_range));
369 402
370 std::vector<Rect> bounds; 403 std::vector<ui::Range> bounds;
404 std::vector<Rect> rects;
371 if (layout_range.is_empty()) 405 if (layout_range.is_empty())
372 return bounds; 406 return rects;
373 407
374 // Add a Rect for each run/selection intersection. 408 // Add a Rect for each run/selection intersection.
375 // TODO(msw): The bounds should probably not always be leading the range ends. 409 // TODO(msw): The bounds should probably not always be leading the range ends.
376 for (size_t i = 0; i < runs_.size(); ++i) { 410 for (size_t i = 0; i < runs_.size(); ++i) {
377 const internal::TextRun* run = runs_[visual_to_logical_[i]]; 411 const internal::TextRun* run = runs_[visual_to_logical_[i]];
378 ui::Range intersection = run->range.Intersect(layout_range); 412 ui::Range intersection = run->range.Intersect(layout_range);
379 if (intersection.IsValid()) { 413 if (intersection.IsValid()) {
380 DCHECK(!intersection.is_reversed()); 414 DCHECK(!intersection.is_reversed());
381 ui::Range range_x(GetGlyphXBoundary(run, intersection.start(), false), 415 ui::Range range_x(GetGlyphXBoundary(run, intersection.start(), false),
382 GetGlyphXBoundary(run, intersection.end(), false)); 416 GetGlyphXBoundary(run, intersection.end(), false));
383 Rect rect(range_x.GetMin(), 0, range_x.length(), run->font.GetHeight()); 417 range_x = ui::Range(range_x.GetMin(), range_x.GetMax());
384 rect.set_origin(ToViewPoint(rect.origin())); 418 // Union this with the last range if they're adjacent.
385 // Union this with the last rect if they're adjacent. 419 DCHECK(bounds.empty() || bounds.back().GetMin() != range_x.GetMax());
386 if (!bounds.empty() && rect.SharesEdgeWith(bounds.back())) { 420 if (!bounds.empty() && bounds.back().GetMax() == range_x.GetMin()) {
387 rect.Union(bounds.back()); 421 range_x = ui::Range(bounds.back().GetMin(), range_x.GetMax());
388 bounds.pop_back(); 422 bounds.pop_back();
389 } 423 }
390 bounds.push_back(rect); 424 bounds.push_back(range_x);
391 } 425 }
392 } 426 }
393 return bounds; 427 for (size_t i = 0; i < bounds.size(); ++i) {
428 std::vector<Rect> current_rects = RangeToViewRects(bounds[i]);
429 rects.insert(rects.end(), current_rects.begin(), current_rects.end());
430 }
431 return rects;
394 } 432 }
395 433
396 size_t RenderTextWin::TextIndexToLayoutIndex(size_t index) const { 434 size_t RenderTextWin::TextIndexToLayoutIndex(size_t index) const {
397 DCHECK_LE(index, text().length()); 435 DCHECK_LE(index, text().length());
398 ptrdiff_t i = obscured() ? ui::UTF16IndexToOffset(text(), 0, index) : index; 436 ptrdiff_t i = obscured() ? ui::UTF16IndexToOffset(text(), 0, index) : index;
399 CHECK_GE(i, 0); 437 CHECK_GE(i, 0);
400 // Clamp layout indices to the length of the text actually used for layout. 438 // Clamp layout indices to the length of the text actually used for layout.
401 return std::min<size_t>(GetLayoutText().length(), i); 439 return std::min<size_t>(GetLayoutText().length(), i);
402 } 440 }
403 441
(...skipping 17 matching lines...) Expand all
421 return ui::IsValidCodePointIndex(text(), position) && 459 return ui::IsValidCodePointIndex(text(), position) &&
422 GetGlyphBounds(position) != GetGlyphBounds(position - 1); 460 GetGlyphBounds(position) != GetGlyphBounds(position - 1);
423 } 461 }
424 462
425 void RenderTextWin::ResetLayout() { 463 void RenderTextWin::ResetLayout() {
426 // Layout is performed lazily as needed for drawing/metrics. 464 // Layout is performed lazily as needed for drawing/metrics.
427 needs_layout_ = true; 465 needs_layout_ = true;
428 } 466 }
429 467
430 void RenderTextWin::EnsureLayout() { 468 void RenderTextWin::EnsureLayout() {
431 if (!needs_layout_) 469 if (needs_layout_) {
432 return; 470 // TODO(msw): Skip complex processing if ScriptIsComplex returns false.
433 // TODO(msw): Skip complex processing if ScriptIsComplex returns false. 471 ItemizeLogicalText();
434 ItemizeLogicalText(); 472 if (!runs_.empty())
435 if (!runs_.empty()) 473 LayoutVisualText();
436 LayoutVisualText(); 474 needs_layout_ = false;
437 needs_layout_ = false; 475 set_lines_valid(false);
476 }
477 if (!lines_valid()) {
msw 2013/07/17 06:47:18 Why is this a separate step at all? I figure multi
ckocagil 2013/07/19 19:40:50 Yes, the separate step is to avoid itemizing, glyp
478 ComputeLines();
479 set_lines_valid(true);
480 }
481 }
482
483 void RenderTextWin::ComputeLines() {
ckocagil 2013/07/19 19:40:50 I refactored this method, sorry for not doing this
484 DCHECK(!needs_layout_);
485
486 std::vector<internal::Line> lines;
487 lines.push_back(internal::Line());
488
489 int max_width = display_rect().width();
msw 2013/07/17 06:47:18 nit: const.
490
491 std::vector<size_t> breaks = line_breaks();
492 for (size_t i = 0; i < runs_.size(); ++i)
493 breaks.push_back(runs_[i]->range.start());
494 if (breaks.empty())
495 breaks.push_back(0);
496 std::sort(breaks.begin(), breaks.end());
msw 2013/07/17 06:47:18 Is this necessary? The BreakIterator advancement s
497
498 size_t* last_break = &breaks[0];
499
500 int line_x = 0; // x from the line beginning
501 int text_x = 0; // x from the text beginning
502 size_t segment_start_char = 0; // offset of current segment beginning
503 int segment_start_pos = 0; // position of current segment beginning
504 internal::TextRun* run;
505 size_t line_beginning = 0;
506 int preceeding_line_heights = 0;
507
508 // Traverse all runs in visual order. If a run doesn't fit the current line,
509 // iterate over each character in the run in logical order until the next
510 // character doesn't fit the current line, then do the one of the following:
511 // - If the last line break before current character is not a line beginning,
512 // roll back there and skip a line.
513 // - If the last line break is at the line beginning and there are more than
514 // one characters in the line, roll back one character and skip a line.
515 // - If neither conditions are met, assume we could fit this character and
516 // skip a line.
517 for (size_t i = 0; i < runs_.size(); ++i) {
msw 2013/07/17 06:47:18 This whole loop is still pretty difficult to follo
518 run = runs_[visual_to_logical_[i]];
519
520 if (!multiline() || line_x + run->width <= max_width) {
msw 2013/07/17 06:47:18 nit: an example comment here would be: // The whol
521 internal::LineSegmentWin* segment = new internal::LineSegmentWin;
522 segment->char_pos = run->range;
523 segment->x_pos = ui::Range(text_x, text_x + run->width);
524 segment->run = run;
525 lines.back().segments.push_back(segment);
526 lines.back().width += run->width;
527 lines.back().height = std::max(lines.back().height,
msw 2013/07/17 06:47:18 This height and baseline calculation should work s
528 run->font.GetHeight());
529 lines.back().baseline = std::max(lines.back().baseline,
530 run->font.GetBaseline());
531 segment_start_char += run->range.length();
532 segment_start_pos += run->width;
533 line_x += run->width;
534 text_x += run->width;
535 continue;
536 }
537
538 bool rtl = run->script_analysis.fRTL;
539 int break_x = 0;
msw 2013/07/17 06:47:18 Comment on what this is.
540
541 last_break = &breaks[0];
542
543 segment_start_char = run->range.start();
544 segment_start_pos = text_x;
545
546 int run_beginning_x = text_x;
547 // To find the text coordinates of RTL LineSegments, store their widths in a
msw 2013/07/17 06:47:18 I'm still having trouble understanding exactly how
548 // vector and apply them after processing all segments in the run.
549 typedef std::pair<internal::LineSegment*, int> RtlWidth;
550 std::vector<RtlWidth> rtl_widths;
551
552 for (size_t j = 0; j < run->range.length(); ++j) {
msw 2013/07/17 06:47:18 I think you'll need to check IsCursorablePosition
553 size_t offset = j + run->range.start();
554 while (last_break != &breaks.back() && offset >= *(last_break + 1)) {
msw 2013/07/17 06:47:18 Comment on what this is doing; it's not obvious.
555 ++last_break;
556 break_x = 0;
msw 2013/07/17 06:47:18 Must this be reset in the loop to correspond with
557 }
558
559 ui::Range glyphs = CharRangeToGlyphRange(ui::Range(j, j + 1), *run);
msw 2013/07/17 06:47:18 CharRangeToGlyphRange is a decent example of a sim
560
561 int char_width = 0;
562 for (size_t k = glyphs.start(); k < glyphs.end(); ++k)
563 char_width += run->advance_widths[k];
564
565 line_x += char_width;
566 text_x += char_width;
567 break_x += char_width;
568
569 if (line_x > max_width) {
msw 2013/07/17 06:47:18 Could this check "|| j == (run.range.length() - 1)
570 if (*last_break > line_beginning) {
571 // Roll back to last break.
572 text_x -= break_x;
573 j = *last_break - run->range.start() - 1;
574 offset = *last_break;
575 } else if (line_x != char_width) {
msw 2013/07/17 06:47:18 nit: should this be line_x > char_width?
576 // Roll back one character.
577 text_x -= char_width;
578 --j;
579 } // else: Assume the current character fits; continue from next line.
msw 2013/07/17 06:47:18 Does this mean that the if last condition failed t
580 line_beginning = offset;
581 line_x = 0;
582 break_x = 0;
583
584 internal::LineSegmentWin* segment = new internal::LineSegmentWin;
585 if (rtl)
586 rtl_widths.push_back(RtlWidth(segment, text_x - segment_start_pos));
587 else
588 segment->x_pos = ui::Range(segment_start_pos, text_x);
589 segment->char_pos = ui::Range(segment_start_char, offset);
590 segment->run = run;
591 lines.back().segments.push_back(segment);
592 lines.back().width += text_x - segment_start_pos;
593 lines.back().height = std::max(lines.back().height,
594 segment->run->font.GetHeight());
595 preceeding_line_heights += lines.back().height;
596 lines.back().baseline = std::max(lines.back().baseline,
597 segment->run->font.GetBaseline());
598
599 lines.push_back(internal::Line());
600 lines.back().preceding_heights = preceeding_line_heights;
601
602 segment_start_pos = text_x;
603 segment_start_char = offset;
604 continue;
605 }
606 }
607 if (segment_start_char != run->range.end()) {
msw 2013/07/17 06:47:18 Add a blank line above and comment here, what is t
608 internal::LineSegmentWin* segment = new internal::LineSegmentWin;
609 if (rtl)
610 rtl_widths.push_back(RtlWidth(segment, text_x - segment_start_pos));
611 else
612 segment->x_pos = ui::Range(segment_start_pos, text_x);
613 segment->char_pos = ui::Range(segment_start_char, run->range.end());
614 segment->run = run;
615 lines.back().segments.push_back(segment);
616 lines.back().width += text_x - segment_start_pos;
617 lines.back().height = std::max(lines.back().height,
618 segment->run->font.GetHeight());
619 lines.back().baseline = std::max(lines.back().baseline,
620 segment->run->font.GetBaseline());
621 segment_start_char = run->range.end();
622 segment_start_pos = text_x;
623 }
624
625 int rtl_total_widths = 0;
626 while (!rtl_widths.empty()) {
627 const RtlWidth& rtl_width = rtl_widths.back();
628 rtl_width.first->x_pos = ui::Range(run_beginning_x + rtl_total_widths,
629 run_beginning_x + rtl_total_widths + rtl_width.second);
630 rtl_widths.pop_back();
631 rtl_total_widths += rtl_width.second;
632 }
633 }
634
635 set_lines(&lines);
438 } 636 }
439 637
440 void RenderTextWin::DrawVisualText(Canvas* canvas) { 638 void RenderTextWin::DrawVisualText(Canvas* canvas) {
441 DCHECK(!needs_layout_); 639 DCHECK(!needs_layout_);
442 640 DCHECK(!multiline() || lines_valid());
443 // Skia will draw glyphs with respect to the baseline.
444 Vector2d offset(GetTextOffset() + Vector2d(0, common_baseline_));
445
446 SkScalar x = SkIntToScalar(offset.x());
447 SkScalar y = SkIntToScalar(offset.y());
448 641
449 std::vector<SkPoint> pos; 642 std::vector<SkPoint> pos;
450 643
451 internal::SkiaTextRenderer renderer(canvas); 644 internal::SkiaTextRenderer renderer(canvas);
452 ApplyFadeEffects(&renderer); 645 ApplyFadeEffects(&renderer);
453 ApplyTextShadows(&renderer); 646 ApplyTextShadows(&renderer);
454 647
455 bool smoothing_enabled; 648 bool smoothing_enabled;
456 bool cleartype_enabled; 649 bool cleartype_enabled;
457 GetCachedFontSmoothingSettings(&smoothing_enabled, &cleartype_enabled); 650 GetCachedFontSmoothingSettings(&smoothing_enabled, &cleartype_enabled);
458 // Note that |cleartype_enabled| corresponds to Skia's |enable_lcd_text|. 651 // Note that |cleartype_enabled| corresponds to Skia's |enable_lcd_text|.
459 renderer.SetFontSmoothingSettings( 652 renderer.SetFontSmoothingSettings(
460 smoothing_enabled, cleartype_enabled && !background_is_transparent()); 653 smoothing_enabled, cleartype_enabled && !background_is_transparent());
461 654
462 for (size_t i = 0; i < runs_.size(); ++i) { 655 SkScalar glyph_x = SkIntToScalar(0);
463 // Get the run specified by the visual-to-logical map.
464 internal::TextRun* run = runs_[visual_to_logical_[i]];
465 656
466 if (run->glyph_count == 0) 657 for (size_t line = 0; line < lines().size(); ++line) {
467 continue; 658 Vector2d offset(0, lines()[line].baseline);
468 659 offset += GetLineOffset(line);
469 // Based on WebCore::skiaDrawText. 660 for (size_t i = 0; i < lines()[line].segments.size(); ++i) {
470 pos.resize(run->glyph_count); 661 const internal::LineSegmentWin* segment =
471 SkScalar glyph_x = x; 662 static_cast<internal::LineSegmentWin*>(lines()[line].segments[i]);
472 for (int glyph = 0; glyph < run->glyph_count; glyph++) { 663 // TODO(ckocagil): necessary? maybe prevent this from happening.
msw 2013/07/17 06:47:18 Does it currently happen? Can you just [D]CHECK ag
ckocagil 2013/07/19 19:40:50 Done.
473 pos[glyph].set(glyph_x + run->offsets[glyph].du, 664 if (segment->char_pos.is_empty())
474 y + run->offsets[glyph].dv); 665 continue;
475 glyph_x += SkIntToScalar(run->advance_widths[glyph]); 666 int segment_start_pos = glyph_x;
667 internal::TextRun* run = segment->run;
668 DCHECK_GE(segment->char_pos.start(), run->range.start());
669 DCHECK_LT(segment->char_pos.start(),
msw 2013/07/17 06:47:18 Did you mean segment->char_pos.end()?
ckocagil 2013/07/19 19:40:50 I changed this to use ui::Range::Contains.
670 run->range.start() + run->glyph_count);
msw 2013/07/17 06:47:18 Did you mean run->range.start() + run->range.lengt
ckocagil 2013/07/19 19:40:50 Same as above.
671 int start_char = segment->char_pos.start() - run->range.start();
msw 2013/07/17 06:47:18 nit: const here and for the three ints below too.
ckocagil 2013/07/19 19:40:50 I inlined these three ints.
672 int end_char = start_char + segment->char_pos.length();
673 ui::Range glyphs = CharRangeToGlyphRange(ui::Range(start_char, end_char),
674 *run);
675 int start = glyphs.start();
msw 2013/07/17 06:47:18 Consider just inlining use of the |glyphs| range i
ckocagil 2013/07/19 19:40:50 Done.
676 int end = glyphs.end();
677 DCHECK_LE(start, end);
msw 2013/07/17 06:47:18 Will this code work okay if start == end?
ckocagil 2013/07/19 19:40:50 It now skips this case and DCHECKs that the segmen
678 pos.resize(end - start);
679 for (int g = start; g < end; ++g) {
680 pos[g - start].set(glyph_x + offset.x() + run->offsets[g].du,
681 offset.y() + run->offsets[g].dv);
682 glyph_x += SkIntToScalar(run->advance_widths[g]);
683 }
684 renderer.SetTextSize(run->font.GetFontSize());
685 renderer.SetFontFamilyWithStyle(run->font.GetFontName(), run->font_style);
686 renderer.SetForegroundColor(run->foreground);
687 renderer.DrawPosText(&pos[0], &run->glyphs[start], end - start);
688 renderer.DrawDecorations(segment_start_pos + offset.x(),
689 offset.y(), segment->x_pos.length(),
690 run->underline, run->strike,
691 run->diagonal_strike);
476 } 692 }
477 693 glyph_x = SkIntToScalar(0);
478 renderer.SetTextSize(run->font.GetFontSize());
479 renderer.SetFontFamilyWithStyle(run->font.GetFontName(), run->font_style);
480 renderer.SetForegroundColor(run->foreground);
481 renderer.DrawPosText(&pos[0], run->glyphs.get(), run->glyph_count);
482 renderer.DrawDecorations(x, y, run->width, run->underline, run->strike,
483 run->diagonal_strike);
484
485 x = glyph_x;
486 } 694 }
487 } 695 }
488 696
489 void RenderTextWin::ItemizeLogicalText() { 697 void RenderTextWin::ItemizeLogicalText() {
490 runs_.clear(); 698 runs_.clear();
491 string_size_ = Size(0, GetFont().GetHeight()); 699 string_size_ = Size(0, GetFont().GetHeight());
492 common_baseline_ = 0; 700 common_baseline_ = 0;
493 701
494 // Set Uniscribe's base text direction. 702 // Set Uniscribe's base text direction.
495 script_state_.uBidiLevel = 703 script_state_.uBidiLevel =
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
829 size_t position = LayoutIndexToTextIndex(run->range.end()); 1037 size_t position = LayoutIndexToTextIndex(run->range.end());
830 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); 1038 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD);
831 return SelectionModel(position, CURSOR_FORWARD); 1039 return SelectionModel(position, CURSOR_FORWARD);
832 } 1040 }
833 1041
834 RenderText* RenderText::CreateInstance() { 1042 RenderText* RenderText::CreateInstance() {
835 return new RenderTextWin; 1043 return new RenderTextWin;
836 } 1044 }
837 1045
838 } // namespace gfx 1046 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698