OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |