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

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

Issue 8536047: Separate selection highlight from pango layout (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: fix an lint error Created 9 years, 1 month 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
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_linux.h" 5 #include "ui/gfx/render_text_linux.h"
6 6
7 #include <pango/pangocairo.h> 7 #include <pango/pangocairo.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 10
(...skipping 20 matching lines...) Expand all
31 31
32 namespace gfx { 32 namespace gfx {
33 33
34 RenderTextLinux::RenderTextLinux() 34 RenderTextLinux::RenderTextLinux()
35 : layout_(NULL), 35 : layout_(NULL),
36 current_line_(NULL), 36 current_line_(NULL),
37 log_attrs_(NULL), 37 log_attrs_(NULL),
38 num_log_attrs_(0), 38 num_log_attrs_(0),
39 layout_text_(NULL), 39 layout_text_(NULL),
40 layout_text_len_(0) { 40 layout_text_len_(0) {
41 selection_visual_bounds_.clear();
msw 2011/11/28 20:01:17 This isn't necessary.
xji 2011/11/29 01:37:02 removed.
41 } 42 }
42 43
43 RenderTextLinux::~RenderTextLinux() { 44 RenderTextLinux::~RenderTextLinux() {
44 ResetLayout(); 45 ResetLayout();
45 } 46 }
46 47
47 RenderText* RenderText::CreateRenderText() { 48 RenderText* RenderText::CreateRenderText() {
48 return new RenderTextLinux; 49 return new RenderTextLinux;
49 } 50 }
50 51
51 base::i18n::TextDirection RenderTextLinux::GetTextDirection() { 52 base::i18n::TextDirection RenderTextLinux::GetTextDirection() {
52 EnsureLayout(); 53 EnsureLayout();
53 54
54 PangoDirection base_dir = pango_find_base_dir(layout_text_, -1); 55 PangoDirection base_dir = pango_find_base_dir(layout_text_, -1);
55 if (base_dir == PANGO_DIRECTION_RTL || base_dir == PANGO_DIRECTION_WEAK_RTL) 56 if (base_dir == PANGO_DIRECTION_RTL || base_dir == PANGO_DIRECTION_WEAK_RTL)
56 return base::i18n::RIGHT_TO_LEFT; 57 return base::i18n::RIGHT_TO_LEFT;
57 return base::i18n::LEFT_TO_RIGHT; 58 return base::i18n::LEFT_TO_RIGHT;
58 } 59 }
59 60
60 int RenderTextLinux::GetStringWidth() { 61 int RenderTextLinux::GetStringWidth() {
61 PangoLayout* layout = EnsureLayout(); 62 PangoLayout* layout = EnsureLayout();
62 int width; 63 int width;
63 pango_layout_get_pixel_size(layout, &width, NULL); 64 pango_layout_get_pixel_size(layout, &width, NULL);
64 return width; 65 return width;
65 } 66 }
66 67
67 void RenderTextLinux::Draw(Canvas* canvas) { 68 void RenderTextLinux::Draw(Canvas* canvas) {
68 PangoLayout* layout = EnsureLayout(); 69 EnsureLayout();
69 Rect bounds(display_rect()); 70 RenderText::Draw(canvas);
70
71 // Clip the canvas to the text display area.
72 SkCanvas* canvas_skia = canvas->GetSkCanvas();
73
74 skia::ScopedPlatformPaint scoped_platform_paint(canvas_skia);
75 cairo_t* cr = scoped_platform_paint.GetPlatformSurface();
76 cairo_save(cr);
77 cairo_rectangle(cr, bounds.x(), bounds.y(), bounds.width(), bounds.height());
78 cairo_clip(cr);
79
80 int text_width, text_height;
81 pango_layout_get_pixel_size(layout, &text_width, &text_height);
82 Point offset(ToViewPoint(Point()));
83 // Vertically centered.
84 int text_y = offset.y() + ((bounds.height() - text_height) / 2);
85 // TODO(xji): need to use SkCanvas->drawPosText() for gpu acceleration.
86 cairo_move_to(cr, offset.x(), text_y);
87 pango_cairo_show_layout(cr, layout);
88
89 cairo_restore(cr);
90
91 // Paint cursor.
92 bounds = GetUpdatedCursorBounds();
93 if (cursor_visible() && focused())
94 canvas->DrawRectInt(kCursorColor,
95 bounds.x(),
96 bounds.y(),
97 bounds.width(),
98 bounds.height());
99 } 71 }
100 72
101 SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) { 73 SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) {
102 PangoLayout* layout = EnsureLayout(); 74 PangoLayout* layout = EnsureLayout();
103 75
104 if (text().empty()) 76 if (text().empty())
105 return SelectionModel(0, 0, SelectionModel::LEADING); 77 return SelectionModel(0, 0, SelectionModel::LEADING);
106 78
107 Point p(ToTextPoint(point)); 79 Point p(ToTextPoint(point));
108 80
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 return SelectionModel(text().length(), caret, SelectionModel::TRAILING); 185 return SelectionModel(text().length(), caret, SelectionModel::TRAILING);
214 } else { // RTL. 186 } else { // RTL.
215 size_t caret = Utf8IndexToUtf16Index(item->offset); 187 size_t caret = Utf8IndexToUtf16Index(item->offset);
216 return SelectionModel(text().length(), caret, SelectionModel::LEADING); 188 return SelectionModel(text().length(), caret, SelectionModel::LEADING);
217 } 189 }
218 } 190 }
219 } 191 }
220 return SelectionModel(0, 0, SelectionModel::LEADING); 192 return SelectionModel(0, 0, SelectionModel::LEADING);
221 } 193 }
222 194
195 std::vector<Rect> RenderTextLinux::GetSubstringBounds(size_t from, size_t to) {
196 DCHECK(from <= text().length() && to <= text().length());
msw 2011/11/28 20:01:17 This should be two separate DCHECK statements.
xji 2011/11/29 01:37:02 Done.
197 std::vector<Rect> bounds;
198 if (from == to)
199 return bounds;
200
201 EnsureLayout();
202
203 if (from == GetSelectionStart() && to == GetCursorPosition()) {
204 if (selection_visual_bounds_.empty())
msw 2011/11/28 20:01:17 Does the inefficiency or recalculating selection b
xji 2011/11/29 01:37:02 I am not worried too much about the calculation pa
205 GetSubstringBounds(from, to, &selection_visual_bounds_);
206 return selection_visual_bounds_;
Alexei Svitkine (slow) 2011/11/28 19:56:14 I think it would be cleaner to have a function Get
xji 2011/11/29 01:37:02 Introduced GetSelectionBounds().
207 } else {
208 GetSubstringBounds(from, to, &bounds);
209 return bounds;
210 }
211 }
212
213 void RenderTextLinux::SetSelectionModel(const SelectionModel& selection_model) {
214 size_t start = GetSelectionStart();
215 size_t end = GetCursorPosition();
216 size_t new_start = selection_model.selection_start();
217 size_t new_end = selection_model.selection_end();
218 if (!(start == new_start && end == new_end) &&
219 !(start == new_end && end == new_start))
msw 2011/11/28 20:01:17 Are the bounds always the same when the start and
xji 2011/11/29 01:37:02 I think they are.
220 selection_visual_bounds_.clear();
221
222 RenderText::SetSelectionModel(selection_model);
223 }
224
225
223 bool RenderTextLinux::IsCursorablePosition(size_t position) { 226 bool RenderTextLinux::IsCursorablePosition(size_t position) {
224 if (position == 0 && text().empty()) 227 if (position == 0 && text().empty())
225 return true; 228 return true;
226 229
227 EnsureLayout(); 230 EnsureLayout();
228 return (position < static_cast<size_t>(num_log_attrs_) && 231 return (position < static_cast<size_t>(num_log_attrs_) &&
229 log_attrs_[position].is_cursor_position); 232 log_attrs_[position].is_cursor_position);
230 } 233 }
231 234
232 void RenderTextLinux::UpdateLayout() { 235 void RenderTextLinux::UpdateLayout() {
233 ResetLayout(); 236 ResetLayout();
234 } 237 }
235 238
239 void RenderTextLinux::DrawVisualText(Canvas* canvas) {
msw 2011/11/28 20:01:17 Sync up with Alexei, he's re-writing this to use S
240 Rect bounds(display_rect());
241
242 // Clip the canvas to the text display area.
243 SkCanvas* canvas_skia = canvas->GetSkCanvas();
244
245 skia::ScopedPlatformPaint scoped_platform_paint(canvas_skia);
246 cairo_t* cr = scoped_platform_paint.GetPlatformSurface();
247 cairo_save(cr);
248 cairo_rectangle(cr, bounds.x(), bounds.y(), bounds.width(), bounds.height());
249 cairo_clip(cr);
250
251 int text_width, text_height;
252 pango_layout_get_pixel_size(layout_, &text_width, &text_height);
253 Point offset(ToViewPoint(Point()));
254 // Vertically centered.
255 int text_y = offset.y() + ((bounds.height() - text_height) / 2);
256 // TODO(xji): need to use SkCanvas->drawPosText() for gpu acceleration.
257 cairo_move_to(cr, offset.x(), text_y);
258 pango_cairo_show_layout(cr, layout_);
259
260 cairo_restore(cr);
261 }
262
236 size_t RenderTextLinux::IndexOfAdjacentGrapheme(size_t index, bool next) { 263 size_t RenderTextLinux::IndexOfAdjacentGrapheme(size_t index, bool next) {
237 EnsureLayout(); 264 EnsureLayout();
238 return Utf16IndexOfAdjacentGrapheme(Utf16IndexToUtf8Index(index), next); 265 return Utf16IndexOfAdjacentGrapheme(Utf16IndexToUtf8Index(index), next);
239 } 266 }
240 267
241 GSList* RenderTextLinux::GetRunContainingPosition(size_t position) const { 268 GSList* RenderTextLinux::GetRunContainingPosition(size_t position) const {
242 GSList* run = current_line_->runs; 269 GSList* run = current_line_->runs;
243 while (run) { 270 while (run) {
244 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; 271 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item;
245 size_t run_start = Utf8IndexToUtf16Index(item->offset); 272 size_t run_start = Utf8IndexToUtf16Index(item->offset);
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
518 } 545 }
519 if (current_line_) { 546 if (current_line_) {
520 pango_layout_line_unref(current_line_); 547 pango_layout_line_unref(current_line_);
521 current_line_ = NULL; 548 current_line_ = NULL;
522 } 549 }
523 if (log_attrs_) { 550 if (log_attrs_) {
524 g_free(log_attrs_); 551 g_free(log_attrs_);
525 log_attrs_ = NULL; 552 log_attrs_ = NULL;
526 num_log_attrs_ = 0; 553 num_log_attrs_ = 0;
527 } 554 }
555 if (!selection_visual_bounds_.empty())
556 selection_visual_bounds_.clear();
528 layout_text_ = NULL; 557 layout_text_ = NULL;
529 layout_text_len_ = 0; 558 layout_text_len_ = 0;
530 } 559 }
531 560
532 void RenderTextLinux::SetupPangoAttributes(PangoLayout* layout) { 561 void RenderTextLinux::SetupPangoAttributes(PangoLayout* layout) {
533 PangoAttrList* attrs = pango_attr_list_new(); 562 PangoAttrList* attrs = pango_attr_list_new();
534 // Set selection background color.
535 // TODO(xji): There's a bug in pango that it can't use two colors in one
msw 2011/11/28 20:01:17 Is this no longer true?
536 // glyph. Please refer to https://bugzilla.gnome.org/show_bug.cgi?id=648157
537 // for detail. So for example, if a font has "ffi" ligature, but you select
538 // half of that glyph, you either get the entire "ffi" ligature
539 // selection-colored, or none of it.
540 // We could use clipping to render selection.
541 // Use pango_glyph_item_get_logical_widths to find the exact boundaries of
542 // selection, then cairo_clip that, paint background, set color to white and
543 // redraw the layout.
544 SkColor selection_color =
545 focused() ? kFocusedSelectionColor : kUnfocusedSelectionColor;
546 size_t start = std::min(MinOfSelection(), text().length());
547 size_t end = std::min(MaxOfSelection(), text().length());
548 PangoAttribute* pango_attr;
549 if (end > start) {
550 pango_attr = pango_attr_background_new(
551 ConvertColorFrom8BitTo16Bit(SkColorGetR(selection_color)),
552 ConvertColorFrom8BitTo16Bit(SkColorGetG(selection_color)),
553 ConvertColorFrom8BitTo16Bit(SkColorGetB(selection_color)));
554 AppendPangoAttribute(start, end, pango_attr, attrs);
555 }
556 563
557 StyleRanges ranges_of_style(style_ranges()); 564 StyleRanges ranges_of_style(style_ranges());
558 ApplyCompositionAndSelectionStyles(&ranges_of_style); 565 ApplyCompositionAndSelectionStyles(&ranges_of_style);
559 566
560 PlatformFont* default_platform_font = default_style().font.platform_font(); 567 PlatformFont* default_platform_font = default_style().font.platform_font();
561 568
569 PangoAttribute* pango_attr;
562 for (StyleRanges::const_iterator i = ranges_of_style.begin(); 570 for (StyleRanges::const_iterator i = ranges_of_style.begin();
563 i < ranges_of_style.end(); ++i) { 571 i < ranges_of_style.end(); ++i) {
564 start = std::min(i->range.start(), text().length()); 572 size_t start = std::min(i->range.start(), text().length());
565 end = std::min(i->range.end(), text().length()); 573 size_t end = std::min(i->range.end(), text().length());
566 if (start >= end) 574 if (start >= end)
567 continue; 575 continue;
568 576
569 const Font& font = i->font; 577 const Font& font = i->font;
570 // In Pango, different fonts means different runs, and it breaks Arabic 578 // In Pango, different fonts means different runs, and it breaks Arabic
571 // shaping acorss run boundaries. So, set font only when it is different 579 // shaping acorss run boundaries. So, set font only when it is different
572 // from the default faont. 580 // from the default faont.
573 // TODO(xji): we'll eventually need to split up StyleRange into components 581 // TODO(xji): we'll eventually need to split up StyleRange into components
574 // (ColorRange, FontRange, etc.) so that we can combine adjacent ranges 582 // (ColorRange, FontRange, etc.) so that we can combine adjacent ranges
575 // with the same Fonts (to avoid unnecessarily splitting up runs) 583 // with the same Fonts (to avoid unnecessarily splitting up runs)
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
650 658
651 size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const { 659 size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const {
652 int32_t utf16_index = 0; 660 int32_t utf16_index = 0;
653 UErrorCode ec = U_ZERO_ERROR; 661 UErrorCode ec = U_ZERO_ERROR;
654 u_strFromUTF8(NULL, 0, &utf16_index, layout_text_, index, &ec); 662 u_strFromUTF8(NULL, 0, &utf16_index, layout_text_, index, &ec);
655 DCHECK(ec == U_BUFFER_OVERFLOW_ERROR || 663 DCHECK(ec == U_BUFFER_OVERFLOW_ERROR ||
656 ec == U_STRING_NOT_TERMINATED_WARNING); 664 ec == U_STRING_NOT_TERMINATED_WARNING);
657 return utf16_index; 665 return utf16_index;
658 } 666 }
659 667
668 void RenderTextLinux::GetSubstringBounds(size_t from,
669 size_t to,
670 std::vector<Rect>* bounds) {
671 int* ranges;
672 int n_ranges;
673 size_t from_in_utf8 = Utf16IndexToUtf8Index(from);
674 size_t to_in_utf8 = Utf16IndexToUtf8Index(to);
675 pango_layout_line_get_x_ranges(current_line_,
msw 2011/11/28 20:01:17 I believe this argument should be on a new line, i
xji 2011/11/29 01:37:02 done. but I think this is the style for function d
676 std::min(from_in_utf8, to_in_utf8),
677 std::max(from_in_utf8, to_in_utf8), &ranges, &n_ranges);
msw 2011/11/28 20:01:17 |&ranges| and |&n_ranges| should be on new lines.
xji 2011/11/29 01:37:02 Done.
678
679 int height;
680 pango_layout_get_pixel_size(layout_, NULL, &height);
681
682 for (int i = 0; i < 2 * n_ranges; ++i) {
msw 2011/11/28 20:01:17 Shouldn't |i| be less than n_ranges? Otherwise we
behdad_google 2011/11/28 23:17:40 Agreed.
xji 2011/11/29 01:37:02 Thanks for catching this!
683 int x = PANGO_PIXELS(ranges[2 * i]);
684 int w = PANGO_PIXELS(ranges[2 * i + 1] - ranges[2 * i]);
Alexei Svitkine (slow) 2011/11/28 19:56:14 Nit: Rename to 'width'.
msw 2011/11/28 20:01:17 Is ranges guaranteed to include an extra terminati
behdad_google 2011/11/28 23:17:40 The array is guaranteed to be of length 2*n_ranges
xji 2011/11/29 01:37:02 Done.
xji 2011/11/29 01:37:02 hm... why "w = PANGO_PIXELS(ranges[2 * i + 1]) - x
685 Rect rect(x, 0, w, height);
behdad_google 2011/11/28 23:17:40 You may need "w-1" instead of w, depending on what
xji 2011/11/29 01:37:02 Are you talking about skia's pixel model, such as
686 rect.Offset(0, (display_rect().height() - height) / 2);
Alexei Svitkine (slow) 2011/11/28 19:56:14 Nit: Move y = (display_rect().height() - height) /
xji 2011/11/29 01:37:02 Done.
687 rect.set_origin(ToViewPoint(rect.origin()));
688 bounds->push_back(rect);
689 }
690 g_free(ranges);
691 }
692
660 } // namespace gfx 693 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698