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

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

Issue 8536047: Separate selection highlight from pango layout (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: address comments Created 9 years 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 | Annotate | Revision Log
« no previous file with comments | « ui/gfx/render_text_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/logging.h" 9 #include "base/logging.h"
10 #include "base/stl_util.h" 10 #include "base/stl_util.h"
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 166
167 RenderTextWin::~RenderTextWin() { 167 RenderTextWin::~RenderTextWin() {
168 STLDeleteContainerPointers(runs_.begin(), runs_.end()); 168 STLDeleteContainerPointers(runs_.begin(), runs_.end());
169 } 169 }
170 170
171 int RenderTextWin::GetStringWidth() { 171 int RenderTextWin::GetStringWidth() {
172 EnsureLayout(); 172 EnsureLayout();
173 return string_width_; 173 return string_width_;
174 } 174 }
175 175
176 void RenderTextWin::Draw(Canvas* canvas) {
177 EnsureLayout();
178 DrawSelection(canvas);
179 DrawVisualText(canvas);
180 DrawCursor(canvas);
181 }
182
183 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) { 176 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) {
184 if (text().empty()) 177 if (text().empty())
185 return SelectionModel(); 178 return SelectionModel();
186 179
187 EnsureLayout(); 180 EnsureLayout();
188 // Find the run that contains the point and adjust the argument location. 181 // Find the run that contains the point and adjust the argument location.
189 Point p(ToTextPoint(point)); 182 Point p(ToTextPoint(point));
190 size_t run_index = GetRunContainingPoint(p); 183 size_t run_index = GetRunContainingPoint(p);
191 if (run_index == runs_.size()) 184 if (run_index == runs_.size())
192 return (p.x() < 0) ? LeftEndSelectionModel() : RightEndSelectionModel(); 185 return (p.x() < 0) ? LeftEndSelectionModel() : RightEndSelectionModel();
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 EnsureLayout(); 305 EnsureLayout();
313 size_t cursor = base::i18n::IsRTL() ? 0 : text().length(); 306 size_t cursor = base::i18n::IsRTL() ? 0 : text().length();
314 internal::TextRun* run = runs_[visual_to_logical_[runs_.size() - 1]]; 307 internal::TextRun* run = runs_[visual_to_logical_[runs_.size() - 1]];
315 bool rtl = run->script_analysis.fRTL; 308 bool rtl = run->script_analysis.fRTL;
316 size_t caret = rtl ? run->range.start() : run->range.end() - 1; 309 size_t caret = rtl ? run->range.start() : run->range.end() - 1;
317 SelectionModel::CaretPlacement placement = 310 SelectionModel::CaretPlacement placement =
318 rtl ? SelectionModel::LEADING : SelectionModel::TRAILING; 311 rtl ? SelectionModel::LEADING : SelectionModel::TRAILING;
319 return SelectionModel(cursor, caret, placement); 312 return SelectionModel(cursor, caret, placement);
320 } 313 }
321 314
322 std::vector<Rect> RenderTextWin::GetSubstringBounds(size_t from, size_t to) { 315 void RenderTextWin::GetSubstringBounds(size_t from,
316 size_t to,
317 std::vector<Rect>* bounds) {
323 DCHECK(!needs_layout_); 318 DCHECK(!needs_layout_);
324 ui::Range range(from, to); 319 ui::Range range(from, to);
325 DCHECK(ui::Range(0, text().length()).Contains(range)); 320 DCHECK(ui::Range(0, text().length()).Contains(range));
326 Point display_offset(GetUpdatedDisplayOffset()); 321 Point display_offset(GetUpdatedDisplayOffset());
327 std::vector<Rect> bounds;
328 HRESULT hr = 0; 322 HRESULT hr = 0;
329 323
324 bounds->clear();
325 if (from == to)
326 return;
327
330 // Add a Rect for each run/selection intersection. 328 // Add a Rect for each run/selection intersection.
331 // TODO(msw): The bounds should probably not always be leading the range ends. 329 // TODO(msw): The bounds should probably not always be leading the range ends.
332 for (size_t i = 0; i < runs_.size(); ++i) { 330 for (size_t i = 0; i < runs_.size(); ++i) {
333 internal::TextRun* run = runs_[visual_to_logical_[i]]; 331 internal::TextRun* run = runs_[visual_to_logical_[i]];
334 ui::Range intersection = run->range.Intersect(range); 332 ui::Range intersection = run->range.Intersect(range);
335 if (intersection.IsValid()) { 333 if (intersection.IsValid()) {
336 DCHECK(!intersection.is_reversed()); 334 DCHECK(!intersection.is_reversed());
337 int start_offset = 0; 335 int start_offset = 0;
338 hr = ScriptCPtoX(intersection.start() - run->range.start(), 336 hr = ScriptCPtoX(intersection.start() - run->range.start(),
339 false, 337 false,
(...skipping 17 matching lines...) Expand all
357 &end_offset); 355 &end_offset);
358 DCHECK(SUCCEEDED(hr)); 356 DCHECK(SUCCEEDED(hr));
359 if (start_offset > end_offset) 357 if (start_offset > end_offset)
360 std::swap(start_offset, end_offset); 358 std::swap(start_offset, end_offset);
361 Rect rect(run->preceding_run_widths + start_offset, 0, 359 Rect rect(run->preceding_run_widths + start_offset, 0,
362 end_offset - start_offset, run->font.GetHeight()); 360 end_offset - start_offset, run->font.GetHeight());
363 // Center the rect vertically in the display area. 361 // Center the rect vertically in the display area.
364 rect.Offset(0, (display_rect().height() - rect.height()) / 2); 362 rect.Offset(0, (display_rect().height() - rect.height()) / 2);
365 rect.set_origin(ToViewPoint(rect.origin())); 363 rect.set_origin(ToViewPoint(rect.origin()));
366 // Union this with the last rect if they're adjacent. 364 // Union this with the last rect if they're adjacent.
367 if (!bounds.empty() && rect.SharesEdgeWith(bounds.back())) { 365 if (!bounds->empty() && rect.SharesEdgeWith(bounds->back())) {
368 rect = rect.Union(bounds.back()); 366 rect = rect.Union(bounds->back());
369 bounds.pop_back(); 367 bounds->pop_back();
370 } 368 }
371 bounds.push_back(rect); 369 bounds->push_back(rect);
372 } 370 }
373 } 371 }
374 return bounds;
375 } 372 }
376 373
377 bool RenderTextWin::IsCursorablePosition(size_t position) { 374 bool RenderTextWin::IsCursorablePosition(size_t position) {
378 if (position == 0 || position == text().length()) 375 if (position == 0 || position == text().length())
379 return true; 376 return true;
380 377
381 EnsureLayout(); 378 EnsureLayout();
382 size_t run_index = GetRunContainingPosition(position); 379 size_t run_index = GetRunContainingPosition(position);
383 if (run_index >= runs_.size()) 380 if (run_index >= runs_.size())
384 return false; 381 return false;
385 382
386 internal::TextRun* run = runs_[run_index]; 383 internal::TextRun* run = runs_[run_index];
387 size_t start = run->range.start(); 384 size_t start = run->range.start();
388 if (position == start) 385 if (position == start)
389 return true; 386 return true;
390 return run->logical_clusters[position - start] != 387 return run->logical_clusters[position - start] !=
391 run->logical_clusters[position - start - 1]; 388 run->logical_clusters[position - start - 1];
392 } 389 }
393 390
394 void RenderTextWin::UpdateLayout() { 391 void RenderTextWin::UpdateLayout() {
395 // Layout is performed lazily as needed for drawing/metrics. 392 // Layout is performed lazily as needed for drawing/metrics.
396 needs_layout_ = true; 393 needs_layout_ = true;
397 } 394 }
398 395
396 void RenderTextWin::EnsureLayout() {
397 if (!needs_layout_)
398 return;
399 // TODO(msw): Skip complex processing if ScriptIsComplex returns false.
400 ItemizeLogicalText();
401 if (!runs_.empty())
402 LayoutVisualText();
403 needs_layout_ = false;
404 }
405
406 void RenderTextWin::DrawVisualText(Canvas* canvas) {
407 SkCanvas* canvas_skia = canvas->GetSkCanvas();
408
409 Point offset(ToViewPoint(Point()));
410 // TODO(msw): Establish a vertical baseline for strings of mixed font heights.
411 size_t height = default_style().font.GetHeight();
412
413 SkScalar x = SkIntToScalar(offset.x());
414 SkScalar y = SkIntToScalar(offset.y());
415 // Center the text vertically in the display area.
416 y += (display_rect().height() - height) / 2;
417 // Offset by the font size to account for Skia expecting y to be the bottom.
418 y += default_style().font.GetFontSize();
419
420 SkPaint paint;
421 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
422 paint.setStyle(SkPaint::kFill_Style);
423 paint.setAntiAlias(true);
424 paint.setSubpixelText(true);
425 paint.setLCDRenderText(true);
426
427 std::vector<SkPoint> pos;
428 for (size_t i = 0; i < runs_.size(); ++i) {
429 // Get the run specified by the visual-to-logical map.
430 internal::TextRun* run = runs_[visual_to_logical_[i]];
431
432 // TODO(msw): Font default/fallback and style integration.
433 SkTypeface::Style style = SkTypeface::kNormal;
434 SkTypeface* typeface =
435 SkTypeface::CreateFromName(run->font.GetFontName().c_str(), style);
436 if (typeface) {
437 paint.setTypeface(typeface);
438 // |paint| adds its own ref. Release the ref from CreateFromName.
439 typeface->unref();
440 }
441 paint.setTextSize(run->font.GetFontSize());
442 paint.setColor(run->foreground);
443
444 SkScalar run_x = x;
445
446 // Based on WebCore::skiaDrawText.
447 pos.resize(run->glyph_count);
448 for (int glyph = 0; glyph < run->glyph_count; glyph++) {
449 pos[glyph].set(x + run->offsets[glyph].du,
450 y + run->offsets[glyph].dv);
451 x += SkIntToScalar(run->advance_widths[glyph]);
452 }
453
454 size_t byte_length = run->glyph_count * sizeof(WORD);
455 canvas_skia->drawPosText(run->glyphs.get(), byte_length, &pos[0], paint);
456
457 if (run->strike || run->underline)
458 DrawTextRunDecorations(canvas_skia, paint, *run, run_x, y);
459 }
460 }
461
399 size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) { 462 size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) {
400 EnsureLayout(); 463 EnsureLayout();
401 size_t run_index = GetRunContainingPosition(index); 464 size_t run_index = GetRunContainingPosition(index);
402 internal::TextRun* run = run_index < runs_.size() ? runs_[run_index] : NULL; 465 internal::TextRun* run = run_index < runs_.size() ? runs_[run_index] : NULL;
403 int start = run ? run->range.start() : 0; 466 int start = run ? run->range.start() : 0;
404 int length = run ? run->range.length() : text().length(); 467 int length = run ? run->range.length() : text().length();
405 int ch = index - start; 468 int ch = index - start;
406 WORD cluster = run ? run->logical_clusters[ch] : 0; 469 WORD cluster = run ? run->logical_clusters[ch] : 0;
407 470
408 if (!next) { 471 if (!next) {
409 do { 472 do {
410 ch--; 473 ch--;
411 } while (ch >= 0 && run && run->logical_clusters[ch] == cluster); 474 } while (ch >= 0 && run && run->logical_clusters[ch] == cluster);
412 } else { 475 } else {
413 while (ch < length && run && run->logical_clusters[ch] == cluster) 476 while (ch < length && run && run->logical_clusters[ch] == cluster)
414 ch++; 477 ch++;
415 } 478 }
416 return std::max(std::min(ch, length) + start, 0); 479 return std::max(std::min(ch, length) + start, 0);
417 } 480 }
418 481
419 void RenderTextWin::EnsureLayout() {
420 if (!needs_layout_)
421 return;
422 // TODO(msw): Skip complex processing if ScriptIsComplex returns false.
423 ItemizeLogicalText();
424 if (!runs_.empty())
425 LayoutVisualText();
426 needs_layout_ = false;
427 }
428
429 void RenderTextWin::ItemizeLogicalText() { 482 void RenderTextWin::ItemizeLogicalText() {
430 STLDeleteContainerPointers(runs_.begin(), runs_.end()); 483 STLDeleteContainerPointers(runs_.begin(), runs_.end());
431 runs_.clear(); 484 runs_.clear();
432 string_width_ = 0; 485 string_width_ = 0;
433 if (text().empty()) 486 if (text().empty())
434 return; 487 return;
435 488
436 const wchar_t* raw_text = text().c_str(); 489 const wchar_t* raw_text = text().c_str();
437 const int text_length = text().length(); 490 const int text_length = text().length();
438 491
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
683 736
684 // The character is at the end of its run; go to the next visual run. 737 // The character is at the end of its run; go to the next visual run.
685 size_t visual_index = logical_to_visual_[run_index]; 738 size_t visual_index = logical_to_visual_[run_index];
686 if (visual_index == runs_.size() - 1) 739 if (visual_index == runs_.size() - 1)
687 return RightEndSelectionModel(); 740 return RightEndSelectionModel();
688 internal::TextRun* next = runs_[visual_to_logical_[visual_index + 1]]; 741 internal::TextRun* next = runs_[visual_to_logical_[visual_index + 1]];
689 return next->script_analysis.fRTL ? LastSelectionModelInsideRun(next) : 742 return next->script_analysis.fRTL ? LastSelectionModelInsideRun(next) :
690 FirstSelectionModelInsideRun(next); 743 FirstSelectionModelInsideRun(next);
691 } 744 }
692 745
693 void RenderTextWin::DrawSelection(Canvas* canvas) {
694 std::vector<Rect> sel(
695 GetSubstringBounds(GetSelectionStart(), GetCursorPosition()));
696 SkColor color = focused() ? kFocusedSelectionColor : kUnfocusedSelectionColor;
697 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i)
698 canvas->FillRect(color, *i);
699 }
700
701 void RenderTextWin::DrawVisualText(Canvas* canvas) {
702 if (text().empty())
703 return;
704
705 SkCanvas* canvas_skia = canvas->GetSkCanvas();
706
707 Point offset(ToViewPoint(Point()));
708 // TODO(msw): Establish a vertical baseline for strings of mixed font heights.
709 size_t height = default_style().font.GetHeight();
710
711 SkScalar x = SkIntToScalar(offset.x());
712 SkScalar y = SkIntToScalar(offset.y());
713 // Center the text vertically in the display area.
714 y += (display_rect().height() - height) / 2;
715 // Offset by the font size to account for Skia expecting y to be the bottom.
716 y += default_style().font.GetFontSize();
717
718 SkPaint paint;
719 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
720 paint.setStyle(SkPaint::kFill_Style);
721 paint.setAntiAlias(true);
722 paint.setSubpixelText(true);
723 paint.setLCDRenderText(true);
724
725 std::vector<SkPoint> pos;
726 for (size_t i = 0; i < runs_.size(); ++i) {
727 // Get the run specified by the visual-to-logical map.
728 internal::TextRun* run = runs_[visual_to_logical_[i]];
729
730 // TODO(msw): Font default/fallback and style integration.
731 SkTypeface::Style style = SkTypeface::kNormal;
732 SkTypeface* typeface =
733 SkTypeface::CreateFromName(run->font.GetFontName().c_str(), style);
734 if (typeface) {
735 paint.setTypeface(typeface);
736 // |paint| adds its own ref. Release the ref from CreateFromName.
737 typeface->unref();
738 }
739 paint.setTextSize(run->font.GetFontSize());
740 paint.setColor(run->foreground);
741
742 SkScalar run_x = x;
743
744 // Based on WebCore::skiaDrawText.
745 pos.resize(run->glyph_count);
746 for (int glyph = 0; glyph < run->glyph_count; glyph++) {
747 pos[glyph].set(x + run->offsets[glyph].du,
748 y + run->offsets[glyph].dv);
749 x += SkIntToScalar(run->advance_widths[glyph]);
750 }
751
752 size_t byte_length = run->glyph_count * sizeof(WORD);
753 canvas_skia->drawPosText(run->glyphs.get(), byte_length, &pos[0], paint);
754
755 if (run->strike || run->underline)
756 DrawTextRunDecorations(canvas_skia, paint, *run, run_x, y);
757 }
758 }
759
760 void RenderTextWin::DrawCursor(Canvas* canvas) {
761 // Paint cursor. Replace cursor is drawn as rectangle for now.
762 // TODO(msw): Draw a better cursor with a better indication of association.
763 if (cursor_visible() && focused()) {
764 Rect r(GetUpdatedCursorBounds());
765 canvas->DrawRectInt(kCursorColor, r.x(), r.y(), r.width(), r.height());
766 }
767 }
768
769 RenderText* RenderText::CreateRenderText() { 746 RenderText* RenderText::CreateRenderText() {
770 return new RenderTextWin; 747 return new RenderTextWin;
771 } 748 }
772 749
773 } // namespace gfx 750 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698