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

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: 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
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
9 #include <algorithm> 8 #include <algorithm>
10 9
11 #include "base/i18n/break_iterator.h" 10 #include "base/i18n/break_iterator.h"
12 #include "base/logging.h" 11 #include "base/logging.h"
13 #include "ui/gfx/canvas_skia.h" 12 #include "ui/gfx/canvas_skia.h"
14 #include "ui/gfx/pango_util.h" 13 #include "ui/gfx/pango_util.h"
15 #include "unicode/uchar.h" 14 #include "unicode/uchar.h"
16 #include "unicode/ustring.h" 15 #include "unicode/ustring.h"
17 16
18 namespace { 17 namespace {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
58 } 57 }
59 58
60 int RenderTextLinux::GetStringWidth() { 59 int RenderTextLinux::GetStringWidth() {
61 PangoLayout* layout = EnsureLayout(); 60 PangoLayout* layout = EnsureLayout();
62 int width; 61 int width;
63 pango_layout_get_pixel_size(layout, &width, NULL); 62 pango_layout_get_pixel_size(layout, &width, NULL);
64 return width; 63 return width;
65 } 64 }
66 65
67 void RenderTextLinux::Draw(Canvas* canvas) { 66 void RenderTextLinux::Draw(Canvas* canvas) {
68 PangoLayout* layout = EnsureLayout(); 67 EnsureLayout();
69 Rect bounds(display_rect()); 68 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 } 69 }
100 70
101 SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) { 71 SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) {
102 PangoLayout* layout = EnsureLayout(); 72 PangoLayout* layout = EnsureLayout();
103 73
104 if (text().empty()) 74 if (text().empty())
105 return SelectionModel(0, 0, SelectionModel::LEADING); 75 return SelectionModel(0, 0, SelectionModel::LEADING);
106 76
107 Point p(ToTextPoint(point)); 77 Point p(ToTextPoint(point));
108 78
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 return SelectionModel(text().length(), caret, SelectionModel::TRAILING); 183 return SelectionModel(text().length(), caret, SelectionModel::TRAILING);
214 } else { // RTL. 184 } else { // RTL.
215 size_t caret = Utf8IndexToUtf16Index(item->offset); 185 size_t caret = Utf8IndexToUtf16Index(item->offset);
216 return SelectionModel(text().length(), caret, SelectionModel::LEADING); 186 return SelectionModel(text().length(), caret, SelectionModel::LEADING);
217 } 187 }
218 } 188 }
219 } 189 }
220 return SelectionModel(0, 0, SelectionModel::LEADING); 190 return SelectionModel(0, 0, SelectionModel::LEADING);
221 } 191 }
222 192
193 void RenderTextLinux::SetSelectionModel(const SelectionModel& selection_model) {
194 if (GetSelectionStart() != selection_model.selection_start() ||
195 GetCursorPosition() != selection_model.selection_end())
196 selection_visual_bounds_.clear();
Alexei Svitkine (slow) 2011/11/29 15:41:37 Nit: Enclose in {}'s.
xji 2011/11/29 23:07:15 Done. But is it that if the conditional body (not
Alexei Svitkine (slow) 2011/11/29 23:22:01 I think the preference is to have {}'s unless both
197
198 RenderText::SetSelectionModel(selection_model);
199 }
200
201 void RenderTextLinux::GetSubstringBounds(size_t from,
202 size_t to,
203 std::vector<Rect>* bounds) {
204 DCHECK(from <= text().length());
205 DCHECK(to <= text().length());
206
207 bounds->clear();
208 if (from == to)
209 return;
210
211 EnsureLayout();
212
213 if (from == GetSelectionStart() && to == GetCursorPosition())
214 GetSelectionBounds(bounds);
215 else
216 CalculateSubstringBounds(from, to, bounds);
217 }
218
223 bool RenderTextLinux::IsCursorablePosition(size_t position) { 219 bool RenderTextLinux::IsCursorablePosition(size_t position) {
224 if (position == 0 && text().empty()) 220 if (position == 0 && text().empty())
225 return true; 221 return true;
226 222
227 EnsureLayout(); 223 EnsureLayout();
228 return (position < static_cast<size_t>(num_log_attrs_) && 224 return (position < static_cast<size_t>(num_log_attrs_) &&
229 log_attrs_[position].is_cursor_position); 225 log_attrs_[position].is_cursor_position);
230 } 226 }
231 227
232 void RenderTextLinux::UpdateLayout() { 228 void RenderTextLinux::UpdateLayout() {
233 ResetLayout(); 229 ResetLayout();
234 } 230 }
235 231
232 void RenderTextLinux::DrawVisualText(Canvas* canvas) {
233 Rect bounds(display_rect());
234
235 // Clip the canvas to the text display area.
236 SkCanvas* canvas_skia = canvas->GetSkCanvas();
237
238 skia::ScopedPlatformPaint scoped_platform_paint(canvas_skia);
239 cairo_t* cr = scoped_platform_paint.GetPlatformSurface();
240 cairo_save(cr);
241 cairo_rectangle(cr, bounds.x(), bounds.y(), bounds.width(), bounds.height());
242 cairo_clip(cr);
243
244 int text_width, text_height;
245 pango_layout_get_pixel_size(layout_, &text_width, &text_height);
246 Point offset(ToViewPoint(Point()));
247 // Vertically centered.
248 int text_y = offset.y() + ((bounds.height() - text_height) / 2);
249 // TODO(xji): need to use SkCanvas->drawPosText() for gpu acceleration.
250 cairo_move_to(cr, offset.x(), text_y);
251 pango_cairo_show_layout(cr, layout_);
252
253 cairo_restore(cr);
254 }
255
236 size_t RenderTextLinux::IndexOfAdjacentGrapheme(size_t index, bool next) { 256 size_t RenderTextLinux::IndexOfAdjacentGrapheme(size_t index, bool next) {
237 EnsureLayout(); 257 EnsureLayout();
238 return Utf16IndexOfAdjacentGrapheme(Utf16IndexToUtf8Index(index), next); 258 return Utf16IndexOfAdjacentGrapheme(Utf16IndexToUtf8Index(index), next);
239 } 259 }
240 260
241 GSList* RenderTextLinux::GetRunContainingPosition(size_t position) const { 261 GSList* RenderTextLinux::GetRunContainingPosition(size_t position) const {
242 GSList* run = current_line_->runs; 262 GSList* run = current_line_->runs;
243 while (run) { 263 while (run) {
244 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; 264 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item;
245 size_t run_start = Utf8IndexToUtf16Index(item->offset); 265 size_t run_start = Utf8IndexToUtf16Index(item->offset);
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
518 } 538 }
519 if (current_line_) { 539 if (current_line_) {
520 pango_layout_line_unref(current_line_); 540 pango_layout_line_unref(current_line_);
521 current_line_ = NULL; 541 current_line_ = NULL;
522 } 542 }
523 if (log_attrs_) { 543 if (log_attrs_) {
524 g_free(log_attrs_); 544 g_free(log_attrs_);
525 log_attrs_ = NULL; 545 log_attrs_ = NULL;
526 num_log_attrs_ = 0; 546 num_log_attrs_ = 0;
527 } 547 }
548 if (!selection_visual_bounds_.empty())
549 selection_visual_bounds_.clear();
528 layout_text_ = NULL; 550 layout_text_ = NULL;
529 layout_text_len_ = 0; 551 layout_text_len_ = 0;
530 } 552 }
531 553
532 void RenderTextLinux::SetupPangoAttributes(PangoLayout* layout) { 554 void RenderTextLinux::SetupPangoAttributes(PangoLayout* layout) {
533 PangoAttrList* attrs = pango_attr_list_new(); 555 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
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 556
557 StyleRanges ranges_of_style(style_ranges()); 557 StyleRanges ranges_of_style(style_ranges());
558 ApplyCompositionAndSelectionStyles(&ranges_of_style); 558 ApplyCompositionAndSelectionStyles(&ranges_of_style);
559 559
560 PlatformFont* default_platform_font = default_style().font.platform_font(); 560 PlatformFont* default_platform_font = default_style().font.platform_font();
561 561
562 PangoAttribute* pango_attr;
562 for (StyleRanges::const_iterator i = ranges_of_style.begin(); 563 for (StyleRanges::const_iterator i = ranges_of_style.begin();
563 i < ranges_of_style.end(); ++i) { 564 i < ranges_of_style.end(); ++i) {
564 start = std::min(i->range.start(), text().length()); 565 size_t start = std::min(i->range.start(), text().length());
565 end = std::min(i->range.end(), text().length()); 566 size_t end = std::min(i->range.end(), text().length());
566 if (start >= end) 567 if (start >= end)
567 continue; 568 continue;
568 569
569 const Font& font = i->font; 570 const Font& font = i->font;
570 // In Pango, different fonts means different runs, and it breaks Arabic 571 // In Pango, different fonts means different runs, and it breaks Arabic
571 // shaping acorss run boundaries. So, set font only when it is different 572 // shaping acorss run boundaries. So, set font only when it is different
572 // from the default faont. 573 // from the default faont.
573 // TODO(xji): we'll eventually need to split up StyleRange into components 574 // TODO(xji): we'll eventually need to split up StyleRange into components
574 // (ColorRange, FontRange, etc.) so that we can combine adjacent ranges 575 // (ColorRange, FontRange, etc.) so that we can combine adjacent ranges
575 // with the same Fonts (to avoid unnecessarily splitting up runs) 576 // with the same Fonts (to avoid unnecessarily splitting up runs)
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
650 651
651 size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const { 652 size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const {
652 int32_t utf16_index = 0; 653 int32_t utf16_index = 0;
653 UErrorCode ec = U_ZERO_ERROR; 654 UErrorCode ec = U_ZERO_ERROR;
654 u_strFromUTF8(NULL, 0, &utf16_index, layout_text_, index, &ec); 655 u_strFromUTF8(NULL, 0, &utf16_index, layout_text_, index, &ec);
655 DCHECK(ec == U_BUFFER_OVERFLOW_ERROR || 656 DCHECK(ec == U_BUFFER_OVERFLOW_ERROR ||
656 ec == U_STRING_NOT_TERMINATED_WARNING); 657 ec == U_STRING_NOT_TERMINATED_WARNING);
657 return utf16_index; 658 return utf16_index;
658 } 659 }
659 660
661 void RenderTextLinux::CalculateSubstringBounds(size_t from,
662 size_t to,
663 std::vector<Rect>* bounds) {
664 int* ranges;
665 int n_ranges;
666 size_t from_in_utf8 = Utf16IndexToUtf8Index(from);
667 size_t to_in_utf8 = Utf16IndexToUtf8Index(to);
668 pango_layout_line_get_x_ranges(
669 current_line_,
670 std::min(from_in_utf8, to_in_utf8),
671 std::max(from_in_utf8, to_in_utf8),
672 &ranges,
673 &n_ranges);
674
675 int height;
676 pango_layout_get_pixel_size(layout_, NULL, &height);
677
678 int y = (display_rect().height() - height) / 2;
679
680 for (int i = 0; i < n_ranges; ++i) {
681 int x = PANGO_PIXELS(ranges[2 * i]);
682 int width = PANGO_PIXELS(ranges[2 * i + 1]) - x;
683 Rect rect(x, y, width, height);
684 rect.set_origin(ToViewPoint(rect.origin()));
685 bounds->push_back(rect);
686 }
687 g_free(ranges);
688 }
689
690 void RenderTextLinux::GetSelectionBounds(std::vector<Rect>* bounds) {
691 if (selection_visual_bounds_.empty())
692 CalculateSubstringBounds(GetSelectionStart(), GetCursorPosition(),
693 &selection_visual_bounds_);
694 *bounds = selection_visual_bounds_;
695 }
696
660 } // namespace gfx 697 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698