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

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: remaining style nit Created 7 years, 3 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/char_iterator.h" 10 #include "base/i18n/char_iterator.h"
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 } else { 149 } else {
150 result = gfx::Range(run.logical_clusters[run_range.start()], 150 result = gfx::Range(run.logical_clusters[run_range.start()],
151 run_range.end() < run.range.length() ? 151 run_range.end() < run.range.length() ?
152 run.logical_clusters[run_range.end()] : run.glyph_count); 152 run.logical_clusters[run_range.end()] : run.glyph_count);
153 } 153 }
154 DCHECK(!result.is_reversed()); 154 DCHECK(!result.is_reversed());
155 DCHECK(gfx::Range(0, run.glyph_count).Contains(result)); 155 DCHECK(gfx::Range(0, run.glyph_count).Contains(result));
156 return result; 156 return result;
157 } 157 }
158 158
159 // Starting from |start_char|, finds a suitable line break position at or before
160 // |available_width| using word break info from |breaks|. If |empty_line| is
161 // true, this function will not roll back to |start_char| and |*next_char| will
162 // be greater than |start_char| (to avoid constructing empty lines).
163 // TODO(ckocagil): Do not break ligatures and diacritics.
164 // TextRun::logical_clusters might help.
165 // TODO(ckocagil): We might have to reshape after breaking at ligatures.
166 // See whether resolving the TODO above resolves this too.
167 // TODO(ckocagil): Do not reserve width for whitespace at the end of lines.
168 void BreakRunAtWidth(const internal::TextRun& run,
169 const BreakList<size_t>& breaks,
170 size_t start_char,
171 int available_width,
172 bool empty_line,
173 int* width,
174 size_t* next_char) {
175 DCHECK(run.range.Contains(Range(start_char, start_char + 1)));
176 BreakList<size_t>::const_iterator word = breaks.GetBreak(start_char);
177 BreakList<size_t>::const_iterator next_word = word + 1;
178 // Width from |std::max(word->first, start_char)| to the current character.
179 int word_width = 0;
180 *width = 0;
181
182 for (size_t i = start_char; i < run.range.end(); ++i) {
183 // |word| holds the word boundary at or before |i|, and |next_word| holds
184 // the word boundary right after |i|. Advance both |word| and |next_word|
185 // when |i| reaches |next_word|.
186 if (next_word != breaks.breaks().end() && i >= next_word->first) {
187 word = next_word++;
188 word_width = 0;
189 }
190
191 Range glyph_range = CharRangeToGlyphRange(run, Range(i, i + 1));
192 int char_width = 0;
193 for (size_t j = glyph_range.start(); j < glyph_range.end(); ++j)
194 char_width += run.advance_widths[j];
195
196 *width += char_width;
197 word_width += char_width;
198
199 if (*width > available_width) {
200 if (!empty_line || word_width < *width) {
201 *width -= word_width;
202 *next_char = std::max(word->first, start_char);
203 } else if (char_width < *width) {
204 *width -= char_width;
205 *next_char = i;
206 } else {
207 *next_char = i + 1;
208 }
209
210 return;
211 }
212 }
213
214 *next_char = run.range.end();
215 }
216
217 // For segments in the same run, checks the continuity and order of |x_range|
218 // and |char_range| fields.
219 void CheckLineIntegrity(const std::vector<internal::Line>& lines,
220 const ScopedVector<internal::TextRun>& runs) {
221 size_t previous_segment_line = 0;
222 const internal::LineSegment* previous_segment = NULL;
223
224 for (size_t i = 0; i < lines.size(); ++i) {
225 for (size_t j = 0; j < lines[i].segments.size(); ++j) {
226 const internal::LineSegment* segment = &lines[i].segments[j];
227 internal::TextRun* run = runs[segment->run];
228
229 if (!previous_segment) {
230 previous_segment = segment;
231 } else if (runs[previous_segment->run] != run) {
232 previous_segment = NULL;
233 } else {
234 DCHECK_EQ(previous_segment->char_range.end(),
235 segment->char_range.start());
236 if (!run->script_analysis.fRTL) {
237 DCHECK_EQ(previous_segment->x_range.end(), segment->x_range.start());
238 } else {
239 DCHECK_EQ(segment->x_range.end(), previous_segment->x_range.start());
240 }
241
242 previous_segment = segment;
243 previous_segment_line = i;
244 }
245 }
246 }
247 }
248
159 } // namespace 249 } // namespace
160 250
161 namespace internal { 251 namespace internal {
162 252
163 TextRun::TextRun() 253 TextRun::TextRun()
164 : font_style(0), 254 : font_style(0),
165 strike(false), 255 strike(false),
166 diagonal_strike(false), 256 diagonal_strike(false),
167 underline(false), 257 underline(false),
168 width(0), 258 width(0),
(...skipping 23 matching lines...) Expand all
192 run->glyph_count, 282 run->glyph_count,
193 run->logical_clusters.get(), 283 run->logical_clusters.get(),
194 run->visible_attributes.get(), 284 run->visible_attributes.get(),
195 run->advance_widths.get(), 285 run->advance_widths.get(),
196 &run->script_analysis, 286 &run->script_analysis,
197 &x); 287 &x);
198 DCHECK(SUCCEEDED(hr)); 288 DCHECK(SUCCEEDED(hr));
199 return run->preceding_run_widths + x; 289 return run->preceding_run_widths + x;
200 } 290 }
201 291
292 // Internal class to generate Line structures. If |multiline| is true, the text
293 // is broken into lines at |words| boundaries such that each line is no longer
294 // than |max_width|. If |multiline| is false, only outputs a single Line from
295 // the given runs. |empty_baseline| and |empty_height| are the baseline and
296 // height of an empty line.
297 // TODO(ckocagil): Expose the interface of this class in the header and test
298 // this class directly.
299 class LineBreaker {
300 public:
301 LineBreaker(int max_width,
302 int empty_baseline,
303 int empty_height,
304 bool multiline,
305 const BreakList<size_t>* words,
306 const ScopedVector<TextRun>& runs)
307 : max_width_(max_width),
308 empty_baseline_(empty_baseline),
309 empty_height_(empty_height),
310 multiline_(multiline),
311 words_(words),
312 runs_(runs),
313 text_x_(0),
314 line_x_(0),
315 line_ascent_(0),
316 line_descent_(0) {
317 AdvanceLine();
318 }
319
320 // Breaks the run at given |run_index| into Line structs.
321 void AddRun(int run_index) {
322 const TextRun* run = runs_[run_index];
323 if (multiline_ && line_x_ + run->width > max_width_)
324 BreakRun(run_index);
325 else
326 AddSegment(run_index, run->range, run->width);
327 }
328
329 // Finishes line breaking and outputs the results. Can be called at most once.
330 void Finalize(std::vector<Line>* lines, Size* size) {
331 DCHECK(!lines_.empty());
332 // Add an empty line to finish the line size calculation and remove it.
333 AdvanceLine();
334 lines_.pop_back();
335 *size = total_size_;
336 lines->swap(lines_);
337 }
338
339 private:
340 // A (line index, segment index) pair that specifies a segment in |lines_|.
341 typedef std::pair<size_t, size_t> SegmentHandle;
342
343 LineSegment* SegmentFromHandle(const SegmentHandle& handle) {
344 return &lines_[handle.first].segments[handle.second];
345 }
346
347 // Breaks a run into segments that fit in the last line in |lines_| and adds
348 // them. Adds a new Line to the back of |lines_| whenever a new segment can't
349 // be added without the Line's width exceeding |max_width_|.
350 void BreakRun(int run_index) {
351 DCHECK(words_);
352 const TextRun* const run = runs_[run_index];
353 int width = 0;
354 size_t next_char = run->range.start();
355
356 // Break the run until it fits the current line.
357 while (next_char < run->range.end()) {
358 const size_t current_char = next_char;
359 BreakRunAtWidth(*run, *words_, current_char, max_width_ - line_x_,
360 line_x_ == 0, &width, &next_char);
361 AddSegment(run_index, Range(current_char, next_char), width);
362 if (next_char < run->range.end())
363 AdvanceLine();
364 }
365 }
366
367 // RTL runs are broken in logical order but displayed in visual order. To find
368 // the text-space coordinate (where it would fall in a single-line text)
369 // |x_range| of RTL segments, segment widths are applied in reverse order.
370 // e.g. {[5, 10], [10, 40]} will become {[35, 40], [5, 35]}.
371 void UpdateRTLSegmentRanges() {
372 if (rtl_segments_.empty())
373 return;
374 int x = SegmentFromHandle(rtl_segments_[0])->x_range.start();
375 for (size_t i = rtl_segments_.size(); i > 0; --i) {
376 LineSegment* segment = SegmentFromHandle(rtl_segments_[i - 1]);
377 const size_t segment_width = segment->x_range.length();
378 segment->x_range = Range(x, x + segment_width);
379 x += segment_width;
380 }
381 rtl_segments_.clear();
382 }
383
384 // Finishes the size calculations of the last Line in |lines_|. Adds a new
385 // Line to the back of |lines_|.
386 void AdvanceLine() {
387 if (!lines_.empty()) {
388 Line* line = &lines_.back();
389 // Set the single-line mode Line's size to match |RenderText::font_list()|
390 // metrics to not break the current single-line code.
391 // TODO(ckocagil): Determine optimal multi-line height behavior.
392 if (!multiline_ || line_ascent_ + line_descent_ == 0) {
393 line_ascent_ = empty_baseline_;
394 line_descent_ = empty_height_ - empty_baseline_;
395 }
396 line->baseline = line_ascent_;
397 line->size.set_height(line_ascent_ + line_descent_);
398 line->preceding_heights = total_size_.height();
399 total_size_.set_height(total_size_.height() + line->size.height());
400 total_size_.set_width(std::max(total_size_.width(), line->size.width()));
401 }
402 line_x_ = 0;
403 line_ascent_ = 0;
404 line_descent_ = 0;
405 lines_.push_back(Line());
406 }
407
408 // Adds a new segment with the given properties to |lines_.back()|.
409 void AddSegment(int run_index, Range char_range, int width) {
410 if (char_range.is_empty()) {
411 DCHECK_EQ(width, 0);
412 return;
413 }
414 const TextRun* run = runs_[run_index];
415 line_ascent_ = std::max(line_ascent_, run->font.GetBaseline());
416 line_descent_ = std::max(line_descent_,
417 run->font.GetHeight() - run->font.GetBaseline());
418
419 LineSegment segment;
420 segment.run = run_index;
421 segment.char_range = char_range;
422 segment.x_range = Range(text_x_, text_x_ + width);
423
424 Line* line = &lines_.back();
425 line->segments.push_back(segment);
426 line->size.set_width(line->size.width() + segment.x_range.length());
427 if (run->script_analysis.fRTL) {
428 rtl_segments_.push_back(SegmentHandle(lines_.size() - 1,
429 line->segments.size() - 1));
430 // If this is the last segment of an RTL run, reprocess the text-space x
431 // ranges of all segments from the run.
432 if (char_range.end() == run->range.end())
433 UpdateRTLSegmentRanges();
434 }
435 text_x_ += width;
436 line_x_ += width;
437 }
438
439 const int max_width_;
440 const int empty_baseline_;
441 const int empty_height_;
442 const bool multiline_;
443 const BreakList<size_t>* const words_;
444 const ScopedVector<TextRun>& runs_;
445
446 // Stores the resulting lines.
447 std::vector<Line> lines_;
448
449 // Text space and line space x coordinates of the next segment to be added.
450 int text_x_;
451 int line_x_;
452
453 // Size of the multiline text, not including the currently processed line.
454 Size total_size_;
455
456 // Ascent and descent values of the current line, |lines_.back()|.
457 int line_ascent_;
458 int line_descent_;
459
460 // The current RTL run segments, to be applied by |UpdateRTLSegmentRanges()|.
461 std::vector<SegmentHandle> rtl_segments_;
462
463 DISALLOW_COPY_AND_ASSIGN(LineBreaker);
464 };
465
202 } // namespace internal 466 } // namespace internal
203 467
204 // static 468 // static
205 HDC RenderTextWin::cached_hdc_ = NULL; 469 HDC RenderTextWin::cached_hdc_ = NULL;
206 470
207 // static 471 // static
208 std::map<std::string, Font> RenderTextWin::successful_substitute_fonts_; 472 std::map<std::string, Font> RenderTextWin::successful_substitute_fonts_;
209 473
210 RenderTextWin::RenderTextWin() 474 RenderTextWin::RenderTextWin()
211 : RenderText(), 475 : RenderText(),
212 common_baseline_(0),
213 needs_layout_(false) { 476 needs_layout_(false) {
214 set_truncate_length(kMaxUniscribeTextLength); 477 set_truncate_length(kMaxUniscribeTextLength);
215 478
216 memset(&script_control_, 0, sizeof(script_control_)); 479 memset(&script_control_, 0, sizeof(script_control_));
217 memset(&script_state_, 0, sizeof(script_state_)); 480 memset(&script_state_, 0, sizeof(script_state_));
218 481
219 MoveCursorTo(EdgeSelectionModel(CURSOR_LEFT)); 482 MoveCursorTo(EdgeSelectionModel(CURSOR_LEFT));
220 } 483 }
221 484
222 RenderTextWin::~RenderTextWin() { 485 RenderTextWin::~RenderTextWin() {
223 } 486 }
224 487
225 Size RenderTextWin::GetStringSize() { 488 Size RenderTextWin::GetStringSize() {
226 EnsureLayout(); 489 EnsureLayout();
227 return string_size_; 490 return multiline_string_size_;
228 } 491 }
229 492
230 int RenderTextWin::GetBaseline() { 493 int RenderTextWin::GetBaseline() {
231 EnsureLayout(); 494 EnsureLayout();
232 return common_baseline_; 495 return lines()[0].baseline;
233 } 496 }
234 497
235 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) { 498 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) {
236 if (text().empty()) 499 if (text().empty())
237 return SelectionModel(); 500 return SelectionModel();
238 501
239 EnsureLayout(); 502 EnsureLayout();
240 // Find the run that contains the point and adjust the argument location. 503 // Find the run that contains the point and adjust the argument location.
241 int x = ToTextPoint(point).x(); 504 int x = ToTextPoint(point).x();
242 size_t run_index = GetRunContainingXCoord(x); 505 size_t run_index = GetRunContainingXCoord(x);
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 } 627 }
365 } 628 }
366 return SelectionModel(pos, CURSOR_FORWARD); 629 return SelectionModel(pos, CURSOR_FORWARD);
367 } 630 }
368 631
369 gfx::Range RenderTextWin::GetGlyphBounds(size_t index) { 632 gfx::Range RenderTextWin::GetGlyphBounds(size_t index) {
370 const size_t run_index = 633 const size_t run_index =
371 GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD)); 634 GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD));
372 // Return edge bounds if the index is invalid or beyond the layout text size. 635 // Return edge bounds if the index is invalid or beyond the layout text size.
373 if (run_index >= runs_.size()) 636 if (run_index >= runs_.size())
374 return gfx::Range(string_size_.width()); 637 return Range(string_width_);
375 internal::TextRun* run = runs_[run_index]; 638 internal::TextRun* run = runs_[run_index];
376 const size_t layout_index = TextIndexToLayoutIndex(index); 639 const size_t layout_index = TextIndexToLayoutIndex(index);
377 return gfx::Range(GetGlyphXBoundary(run, layout_index, false), 640 return gfx::Range(GetGlyphXBoundary(run, layout_index, false),
378 GetGlyphXBoundary(run, layout_index, true)); 641 GetGlyphXBoundary(run, layout_index, true));
379 } 642 }
380 643
381 std::vector<Rect> RenderTextWin::GetSubstringBounds(const gfx::Range& range) { 644 std::vector<Rect> RenderTextWin::GetSubstringBounds(const gfx::Range& range) {
382 DCHECK(!needs_layout_); 645 DCHECK(!needs_layout_);
383 DCHECK(gfx::Range(0, text().length()).Contains(range)); 646 DCHECK(gfx::Range(0, text().length()).Contains(range));
384 gfx::Range layout_range(TextIndexToLayoutIndex(range.start()), 647 gfx::Range layout_range(TextIndexToLayoutIndex(range.start()),
385 TextIndexToLayoutIndex(range.end())); 648 TextIndexToLayoutIndex(range.end()));
386 DCHECK(gfx::Range(0, GetLayoutText().length()).Contains(layout_range)); 649 DCHECK(gfx::Range(0, GetLayoutText().length()).Contains(layout_range));
387 650
388 std::vector<Rect> bounds; 651 std::vector<Rect> rects;
389 if (layout_range.is_empty()) 652 if (layout_range.is_empty())
390 return bounds; 653 return rects;
654 std::vector<Range> bounds;
391 655
392 // Add a Rect for each run/selection intersection. 656 // Add a Range for each run/selection intersection.
393 // TODO(msw): The bounds should probably not always be leading the range ends. 657 // TODO(msw): The bounds should probably not always be leading the range ends.
394 for (size_t i = 0; i < runs_.size(); ++i) { 658 for (size_t i = 0; i < runs_.size(); ++i) {
395 const internal::TextRun* run = runs_[visual_to_logical_[i]]; 659 const internal::TextRun* run = runs_[visual_to_logical_[i]];
396 gfx::Range intersection = run->range.Intersect(layout_range); 660 gfx::Range intersection = run->range.Intersect(layout_range);
397 if (intersection.IsValid()) { 661 if (intersection.IsValid()) {
398 DCHECK(!intersection.is_reversed()); 662 DCHECK(!intersection.is_reversed());
399 gfx::Range range_x(GetGlyphXBoundary(run, intersection.start(), false), 663 gfx::Range range_x(GetGlyphXBoundary(run, intersection.start(), false),
400 GetGlyphXBoundary(run, intersection.end(), false)); 664 GetGlyphXBoundary(run, intersection.end(), false));
401 Rect rect(range_x.GetMin(), 0, range_x.length(), run->font.GetHeight()); 665 if (range_x.is_empty())
402 rect.set_origin(ToViewPoint(rect.origin())); 666 continue;
403 // Union this with the last rect if they're adjacent. 667 range_x = Range(range_x.GetMin(), range_x.GetMax());
404 if (!bounds.empty() && rect.SharesEdgeWith(bounds.back())) { 668 // Union this with the last range if they're adjacent.
405 rect.Union(bounds.back()); 669 DCHECK(bounds.empty() || bounds.back().GetMax() <= range_x.GetMin());
670 if (!bounds.empty() && bounds.back().GetMax() == range_x.GetMin()) {
671 range_x = Range(bounds.back().GetMin(), range_x.GetMax());
406 bounds.pop_back(); 672 bounds.pop_back();
407 } 673 }
408 bounds.push_back(rect); 674 bounds.push_back(range_x);
409 } 675 }
410 } 676 }
411 return bounds; 677 for (size_t i = 0; i < bounds.size(); ++i) {
678 std::vector<Rect> current_rects = TextBoundsToViewBounds(bounds[i]);
679 rects.insert(rects.end(), current_rects.begin(), current_rects.end());
680 }
681 return rects;
412 } 682 }
413 683
414 size_t RenderTextWin::TextIndexToLayoutIndex(size_t index) const { 684 size_t RenderTextWin::TextIndexToLayoutIndex(size_t index) const {
415 DCHECK_LE(index, text().length()); 685 DCHECK_LE(index, text().length());
416 ptrdiff_t i = obscured() ? ui::UTF16IndexToOffset(text(), 0, index) : index; 686 ptrdiff_t i = obscured() ? ui::UTF16IndexToOffset(text(), 0, index) : index;
417 CHECK_GE(i, 0); 687 CHECK_GE(i, 0);
418 // Clamp layout indices to the length of the text actually used for layout. 688 // Clamp layout indices to the length of the text actually used for layout.
419 return std::min<size_t>(GetLayoutText().length(), i); 689 return std::min<size_t>(GetLayoutText().length(), i);
420 } 690 }
421 691
(...skipping 21 matching lines...) Expand all
443 position < LayoutIndexToTextIndex(GetLayoutText().length()) && 713 position < LayoutIndexToTextIndex(GetLayoutText().length()) &&
444 GetGlyphBounds(position) != GetGlyphBounds(position - 1); 714 GetGlyphBounds(position) != GetGlyphBounds(position - 1);
445 } 715 }
446 716
447 void RenderTextWin::ResetLayout() { 717 void RenderTextWin::ResetLayout() {
448 // Layout is performed lazily as needed for drawing/metrics. 718 // Layout is performed lazily as needed for drawing/metrics.
449 needs_layout_ = true; 719 needs_layout_ = true;
450 } 720 }
451 721
452 void RenderTextWin::EnsureLayout() { 722 void RenderTextWin::EnsureLayout() {
453 if (!needs_layout_) 723 if (needs_layout_) {
454 return; 724 // TODO(msw): Skip complex processing if ScriptIsComplex returns false.
455 // TODO(msw): Skip complex processing if ScriptIsComplex returns false. 725 ItemizeLogicalText();
456 ItemizeLogicalText(); 726 if (!runs_.empty())
457 if (!runs_.empty()) 727 LayoutVisualText();
458 LayoutVisualText(); 728 needs_layout_ = false;
459 needs_layout_ = false; 729 std::vector<internal::Line> lines;
730 set_lines(&lines);
731 }
732
733 // Compute lines if they're not valid. This is separate from the layout steps
734 // above to avoid text layout and shaping when we resize |display_rect_|.
735 if (lines().empty()) {
736 DCHECK(!needs_layout_);
737 std::vector<internal::Line> lines;
738 internal::LineBreaker line_breaker(display_rect().width() - 1,
739 font_list().GetBaseline(),
740 font_list().GetHeight(), multiline(),
741 multiline() ? &GetLineBreaks() : NULL,
742 runs_);
743 for (size_t i = 0; i < runs_.size(); ++i)
744 line_breaker.AddRun(visual_to_logical_[i]);
745 line_breaker.Finalize(&lines, &multiline_string_size_);
746 DCHECK(!lines.empty());
747 #ifndef NDEBUG
748 CheckLineIntegrity(lines, runs_);
749 #endif
750 set_lines(&lines);
751 }
460 } 752 }
461 753
462 void RenderTextWin::DrawVisualText(Canvas* canvas) { 754 void RenderTextWin::DrawVisualText(Canvas* canvas) {
463 DCHECK(!needs_layout_); 755 DCHECK(!needs_layout_);
464 756 DCHECK(!lines().empty());
465 // Skia will draw glyphs with respect to the baseline.
466 Vector2d offset(GetTextOffset() + Vector2d(0, common_baseline_));
467
468 SkScalar x = SkIntToScalar(offset.x());
469 SkScalar y = SkIntToScalar(offset.y());
470 757
471 std::vector<SkPoint> pos; 758 std::vector<SkPoint> pos;
472 759
473 internal::SkiaTextRenderer renderer(canvas); 760 internal::SkiaTextRenderer renderer(canvas);
474 ApplyFadeEffects(&renderer); 761 ApplyFadeEffects(&renderer);
475 ApplyTextShadows(&renderer); 762 ApplyTextShadows(&renderer);
476 763
477 bool smoothing_enabled; 764 bool smoothing_enabled;
478 bool cleartype_enabled; 765 bool cleartype_enabled;
479 GetCachedFontSmoothingSettings(&smoothing_enabled, &cleartype_enabled); 766 GetCachedFontSmoothingSettings(&smoothing_enabled, &cleartype_enabled);
480 // Note that |cleartype_enabled| corresponds to Skia's |enable_lcd_text|. 767 // Note that |cleartype_enabled| corresponds to Skia's |enable_lcd_text|.
481 renderer.SetFontSmoothingSettings( 768 renderer.SetFontSmoothingSettings(
482 smoothing_enabled, cleartype_enabled && !background_is_transparent()); 769 smoothing_enabled, cleartype_enabled && !background_is_transparent());
483 770
484 ApplyCompositionAndSelectionStyles(); 771 ApplyCompositionAndSelectionStyles();
485 772
486 for (size_t i = 0; i < runs_.size(); ++i) { 773 for (size_t i = 0; i < lines().size(); ++i) {
487 // Get the run specified by the visual-to-logical map. 774 const internal::Line& line = lines()[i];
488 internal::TextRun* run = runs_[visual_to_logical_[i]]; 775 const Vector2d line_offset = GetLineOffset(i);
489 776
490 // Skip painting empty runs and runs outside the display rect area. 777 // Skip painting empty lines or lines outside the display rect area.
491 if ((run->glyph_count == 0) || (x >= display_rect().right()) || 778 if (!display_rect().Intersects(Rect(PointAtOffsetFromOrigin(line_offset),
492 (x + run->width <= display_rect().x())) { 779 line.size)))
493 x += run->width;
494 continue; 780 continue;
781
782 const Vector2d text_offset = line_offset + Vector2d(0, line.baseline);
783 int preceding_segment_widths = 0;
784
785 for (size_t j = 0; j < line.segments.size(); ++j) {
786 const internal::LineSegment* segment = &line.segments[j];
787 const int segment_width = segment->x_range.length();
788 const internal::TextRun* run = runs_[segment->run];
789 DCHECK(!segment->char_range.is_empty());
790 DCHECK(run->range.Contains(segment->char_range));
791 Range glyph_range = CharRangeToGlyphRange(*run, segment->char_range);
792 DCHECK(!glyph_range.is_empty());
793 // Skip painting segments outside the display rect area.
794 if (!multiline()) {
795 const Rect segment_bounds(PointAtOffsetFromOrigin(line_offset) +
796 Vector2d(preceding_segment_widths, 0),
797 Size(segment_width, line.size.height()));
798 if (!display_rect().Intersects(segment_bounds)) {
799 preceding_segment_widths += segment_width;
800 continue;
801 }
802 }
803
804 // |pos| contains the positions of glyphs. An extra terminal |pos| entry
805 // is added to simplify width calculations.
806 int segment_x = preceding_segment_widths;
807 pos.resize(glyph_range.length() + 1);
808 for (size_t k = glyph_range.start(); k < glyph_range.end(); ++k) {
809 pos[k - glyph_range.start()].set(
810 SkIntToScalar(text_offset.x() + run->offsets[k].du + segment_x),
811 SkIntToScalar(text_offset.y() + run->offsets[k].dv));
812 segment_x += run->advance_widths[k];
813 }
814 pos.back().set(SkIntToScalar(text_offset.x() + segment_x),
815 SkIntToScalar(text_offset.y()));
816
817 renderer.SetTextSize(run->font.GetFontSize());
818 renderer.SetFontFamilyWithStyle(run->font.GetFontName(), run->font_style);
819
820 for (BreakList<SkColor>::const_iterator it =
821 colors().GetBreak(segment->char_range.start());
822 it != colors().breaks().end() &&
823 it->first < segment->char_range.end();
824 ++it) {
825 const Range intersection =
826 colors().GetRange(it).Intersect(segment->char_range);
827 const Range colored_glyphs = CharRangeToGlyphRange(*run, intersection);
828 DCHECK(glyph_range.Contains(colored_glyphs));
829 DCHECK(!colored_glyphs.is_empty());
830 const SkPoint& start_pos =
831 pos[colored_glyphs.start() - glyph_range.start()];
832 const SkPoint& end_pos =
833 pos[colored_glyphs.end() - glyph_range.start()];
834
835 renderer.SetForegroundColor(it->second);
836 renderer.DrawPosText(&start_pos, &run->glyphs[colored_glyphs.start()],
837 colored_glyphs.length());
838 renderer.DrawDecorations(start_pos.x(), text_offset.y(),
839 SkScalarCeilToInt(end_pos.x() - start_pos.x()),
840 run->underline, run->strike,
841 run->diagonal_strike);
842 }
843
844 preceding_segment_widths += segment_width;
495 } 845 }
496
497 // Based on WebCore::skiaDrawText. |pos| contains the positions of glyphs.
498 // An extra terminal |pos| entry is added to simplify width calculations.
499 pos.resize(run->glyph_count + 1);
500 SkScalar glyph_x = x;
501 for (int glyph = 0; glyph < run->glyph_count; glyph++) {
502 pos[glyph].set(glyph_x + run->offsets[glyph].du,
503 y + run->offsets[glyph].dv);
504 glyph_x += SkIntToScalar(run->advance_widths[glyph]);
505 }
506 pos.back().set(glyph_x, y);
507
508 renderer.SetTextSize(run->font.GetFontSize());
509 renderer.SetFontFamilyWithStyle(run->font.GetFontName(), run->font_style);
510
511 for (BreakList<SkColor>::const_iterator it =
512 colors().GetBreak(run->range.start());
513 it != colors().breaks().end() && it->first < run->range.end();
514 ++it) {
515 const gfx::Range glyph_range = CharRangeToGlyphRange(*run,
516 colors().GetRange(it).Intersect(run->range));
517 if (glyph_range.is_empty())
518 continue;
519 renderer.SetForegroundColor(it->second);
520 renderer.DrawPosText(&pos[glyph_range.start()],
521 &run->glyphs[glyph_range.start()],
522 glyph_range.length());
523 const SkScalar width = pos[glyph_range.end()].x() -
524 pos[glyph_range.start()].x();
525 renderer.DrawDecorations(pos[glyph_range.start()].x(), y,
526 SkScalarCeilToInt(width), run->underline,
527 run->strike, run->diagonal_strike);
528 }
529
530 DCHECK_EQ(glyph_x - x, run->width);
531 x = glyph_x;
532 } 846 }
533 847
534 UndoCompositionAndSelectionStyles(); 848 UndoCompositionAndSelectionStyles();
535 } 849 }
536 850
537 void RenderTextWin::ItemizeLogicalText() { 851 void RenderTextWin::ItemizeLogicalText() {
538 runs_.clear(); 852 runs_.clear();
539 // Make |string_size_|'s height and |common_baseline_| tall enough to draw 853 string_width_ = 0;
540 // often-used characters which are rendered with fonts in the font list. 854 multiline_string_size_ = Size();
541 string_size_ = Size(0, font_list().GetHeight());
542 common_baseline_ = font_list().GetBaseline();
543 855
544 // Set Uniscribe's base text direction. 856 // Set Uniscribe's base text direction.
545 script_state_.uBidiLevel = 857 script_state_.uBidiLevel =
546 (GetTextDirection() == base::i18n::RIGHT_TO_LEFT) ? 1 : 0; 858 (GetTextDirection() == base::i18n::RIGHT_TO_LEFT) ? 1 : 0;
547 859
548 const base::string16& layout_text = GetLayoutText(); 860 const base::string16& layout_text = GetLayoutText();
549 if (layout_text.empty()) 861 if (layout_text.empty())
550 return; 862 return;
551 863
552 HRESULT hr = E_OUTOFMEMORY; 864 HRESULT hr = E_OUTOFMEMORY;
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
662 run->glyphs.get(), 974 run->glyphs.get(),
663 run->glyph_count, 975 run->glyph_count,
664 run->visible_attributes.get(), 976 run->visible_attributes.get(),
665 &(run->script_analysis), 977 &(run->script_analysis),
666 run->advance_widths.get(), 978 run->advance_widths.get(),
667 run->offsets.get(), 979 run->offsets.get(),
668 &(run->abc_widths)); 980 &(run->abc_widths));
669 DCHECK(SUCCEEDED(hr)); 981 DCHECK(SUCCEEDED(hr));
670 } 982 }
671 } 983 }
672 string_size_.set_height(ascent + descent);
673 common_baseline_ = ascent;
674 984
675 // Build the array of bidirectional embedding levels. 985 // Build the array of bidirectional embedding levels.
676 scoped_ptr<BYTE[]> levels(new BYTE[runs_.size()]); 986 scoped_ptr<BYTE[]> levels(new BYTE[runs_.size()]);
677 for (size_t i = 0; i < runs_.size(); ++i) 987 for (size_t i = 0; i < runs_.size(); ++i)
678 levels[i] = runs_[i]->script_analysis.s.uBidiLevel; 988 levels[i] = runs_[i]->script_analysis.s.uBidiLevel;
679 989
680 // Get the maps between visual and logical run indices. 990 // Get the maps between visual and logical run indices.
681 visual_to_logical_.reset(new int[runs_.size()]); 991 visual_to_logical_.reset(new int[runs_.size()]);
682 logical_to_visual_.reset(new int[runs_.size()]); 992 logical_to_visual_.reset(new int[runs_.size()]);
683 hr = ScriptLayout(runs_.size(), 993 hr = ScriptLayout(runs_.size(),
684 levels.get(), 994 levels.get(),
685 visual_to_logical_.get(), 995 visual_to_logical_.get(),
686 logical_to_visual_.get()); 996 logical_to_visual_.get());
687 DCHECK(SUCCEEDED(hr)); 997 DCHECK(SUCCEEDED(hr));
688 998
689 // Precalculate run width information. 999 // Precalculate run width information.
690 size_t preceding_run_widths = 0; 1000 size_t preceding_run_widths = 0;
691 for (size_t i = 0; i < runs_.size(); ++i) { 1001 for (size_t i = 0; i < runs_.size(); ++i) {
692 internal::TextRun* run = runs_[visual_to_logical_[i]]; 1002 internal::TextRun* run = runs_[visual_to_logical_[i]];
693 run->preceding_run_widths = preceding_run_widths; 1003 run->preceding_run_widths = preceding_run_widths;
694 const ABC& abc = run->abc_widths; 1004 const ABC& abc = run->abc_widths;
695 run->width = abc.abcA + abc.abcB + abc.abcC; 1005 run->width = abc.abcA + abc.abcB + abc.abcC;
696 preceding_run_widths += run->width; 1006 preceding_run_widths += run->width;
697 } 1007 }
698 string_size_.set_width(preceding_run_widths); 1008 string_width_ = preceding_run_widths;
699 } 1009 }
700 1010
701 void RenderTextWin::LayoutTextRun(internal::TextRun* run) { 1011 void RenderTextWin::LayoutTextRun(internal::TextRun* run) {
702 const size_t run_length = run->range.length(); 1012 const size_t run_length = run->range.length();
703 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]); 1013 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]);
704 Font original_font = run->font; 1014 Font original_font = run->font;
705 LinkedFontsIterator fonts(original_font); 1015 LinkedFontsIterator fonts(original_font);
706 bool tried_cached_font = false; 1016 bool tried_cached_font = false;
707 bool tried_fallback = false; 1017 bool tried_fallback = false;
708 // Keep track of the font that is able to display the greatest number of 1018 // Keep track of the font that is able to display the greatest number of
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
922 size_t position = LayoutIndexToTextIndex(run->range.end()); 1232 size_t position = LayoutIndexToTextIndex(run->range.end());
923 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); 1233 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD);
924 return SelectionModel(position, CURSOR_FORWARD); 1234 return SelectionModel(position, CURSOR_FORWARD);
925 } 1235 }
926 1236
927 RenderText* RenderText::CreateInstance() { 1237 RenderText* RenderText::CreateInstance() {
928 return new RenderTextWin; 1238 return new RenderTextWin;
929 } 1239 }
930 1240
931 } // namespace gfx 1241 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698