15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/gfx/render_text_pango.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <pango/pangocairo.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/break_iterator.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkTypeface.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/font.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/font_render_params_linux.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/pango_util.h" 19d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/utf16_indexing.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace gfx { 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the preceding element in a GSList (O(n)). 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GSList* GSListPrevious(GSList* head, GSList* item) { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GSList* prev = NULL; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (GSList* cur = head; cur != item; cur = cur->next) { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(cur); 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prev = cur; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return prev; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if the given visual cursor |direction| is logically forward 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// motion in the given Pango |item|. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsForwardMotion(VisualCursorDirection direction, const PangoItem* item) { 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool rtl = item->analysis.level & 1; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rtl == (direction == CURSOR_LEFT); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Checks whether |range| contains |index|. This is not the same as calling 4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// |range.Contains(gfx::Range(index))| - as that would return true when 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |index| == |range.end()|. 45d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)bool IndexInRange(const Range& range, size_t index) { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return index >= range.start() && index < range.end(); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Sets underline metrics on |renderer| according to Pango font |desc|. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetPangoUnderlineMetrics(PangoFontDescription *desc, 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) internal::SkiaTextRenderer* renderer) { 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PangoFontMetrics* metrics = GetPangoFontMetrics(desc); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int thickness = pango_font_metrics_get_underline_thickness(metrics); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Pango returns the position "above the baseline". Change its sign to convert 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it to a vertical offset from the baseline. 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int position = -pango_font_metrics_get_underline_position(metrics); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_quantize_line_geometry(&thickness, &position); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: pango_quantize_line_geometry() guarantees pixel boundaries, so 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // PANGO_PIXELS() is safe to use. 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) renderer->SetUnderlineMetrics(PANGO_PIXELS(thickness), 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PANGO_PIXELS(position)); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(xji): index saved in upper layer is utf16 index. Pango uses utf8 index. 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Since caret_pos is used internally, we could save utf8 index for caret_pos 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to avoid conversion. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)RenderTextPango::RenderTextPango() 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : layout_(NULL), 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_line_(NULL), 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) log_attrs_(NULL), 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_log_attrs_(0), 757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch layout_text_(NULL) { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)RenderTextPango::~RenderTextPango() { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResetLayout(); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Size RenderTextPango::GetStringSize() { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureLayout(); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int width = 0, height = 0; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_get_pixel_size(layout_, &width, &height); 86ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // Keep a consistent height between this particular string's PangoLayout and 87ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // potentially larger text supported by the FontList. 88a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // For example, if a text field contains a Japanese character, which is 89a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // smaller than Latin ones, and then later a Latin one is inserted, this 90a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // ensures that the text baseline does not shift. 91ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return Size(width, std::max(height, font_list().GetHeight())); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SelectionModel RenderTextPango::FindCursorPosition(const Point& point) { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureLayout(); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (text().empty()) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SelectionModel(0, CURSOR_FORWARD); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Point p(ToTextPoint(point)); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When the point is outside of text, return HOME/END position. 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (p.x() < 0) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return EdgeSelectionModel(CURSOR_LEFT); 10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (p.x() > GetStringSize().width()) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return EdgeSelectionModel(CURSOR_RIGHT); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int caret_pos = 0, trailing = 0; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_xy_to_index(layout_, p.x() * PANGO_SCALE, p.y() * PANGO_SCALE, 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &caret_pos, &trailing); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GE(trailing, 0); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (trailing > 0) { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) caret_pos = g_utf8_offset_to_pointer(layout_text_ + caret_pos, 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trailing) - layout_text_; 1167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch DCHECK_LE(static_cast<size_t>(caret_pos), strlen(layout_text_)); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SelectionModel(LayoutIndexToTextIndex(caret_pos), 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (trailing > 0) ? CURSOR_BACKWARD : CURSOR_FORWARD); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)std::vector<RenderText::FontSpan> RenderTextPango::GetFontSpansForTesting() { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureLayout(); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<RenderText::FontSpan> spans; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (GSList* it = current_line_->runs; it; it = it->next) { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PangoItem* item = reinterpret_cast<PangoLayoutRun*>(it->data)->item; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int start = LayoutIndexToTextIndex(item->offset); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int end = LayoutIndexToTextIndex(item->offset + item->length); 131d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const Range range(start, end); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedPangoFontDescription desc(pango_font_describe(item->analysis.font)); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) spans.push_back(RenderText::FontSpan(Font(desc.get()), range)); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return spans; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)int RenderTextPango::GetLayoutTextBaseline() { 1410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) EnsureLayout(); 1420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return PANGO_PIXELS(pango_layout_get_baseline(layout_)); 1430f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} 1440f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SelectionModel RenderTextPango::AdjacentCharSelectionModel( 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SelectionModel& selection, 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VisualCursorDirection direction) { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GSList* run = GetRunContainingCaret(selection); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!run) { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The cursor is not in any run: we're at the visual and logical edge. 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SelectionModel edge = EdgeSelectionModel(direction); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (edge.caret_pos() == selection.caret_pos()) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return edge; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run = (direction == CURSOR_RIGHT) ? 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_line_->runs : g_slist_last(current_line_->runs); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the cursor is moving within the current run, just move it by one 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // grapheme in the appropriate direction. 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t caret = selection.caret_pos(); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsForwardMotion(direction, item)) { 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (caret < LayoutIndexToTextIndex(item->offset + item->length)) { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SelectionModel(caret, CURSOR_BACKWARD); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (caret > LayoutIndexToTextIndex(item->offset)) { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SelectionModel(caret, CURSOR_FORWARD); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The cursor is at the edge of a run; move to the visually adjacent run. 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(xji): Keep a vector of runs to avoid using a singly-linked list. 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run = (direction == CURSOR_RIGHT) ? 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run->next : GSListPrevious(current_line_->runs, run); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!run) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return EdgeSelectionModel(direction); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return IsForwardMotion(direction, item) ? 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FirstSelectionModelInsideRun(item) : LastSelectionModelInsideRun(item); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SelectionModel RenderTextPango::AdjacentWordSelectionModel( 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SelectionModel& selection, 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VisualCursorDirection direction) { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (obscured()) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return EdgeSelectionModel(direction); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool success = iter.Init(); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(success); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!success) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return selection; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SelectionModel cur(selection); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (;;) { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cur = AdjacentCharSelectionModel(cur, direction); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GSList* run = GetRunContainingCaret(cur); 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!run) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t cursor = cur.caret_pos(); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsForwardMotion(direction, item) ? 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor)) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return cur; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Range RenderTextPango::GetGlyphBounds(size_t index) { 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PangoRectangle pos; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_index_to_pos(layout_, TextIndexToLayoutIndex(index), &pos); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(derat): Support fractional ranges for subpixel positioning? 217d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return Range(PANGO_PIXELS(pos.x), PANGO_PIXELS(pos.x + pos.width)); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)std::vector<Rect> RenderTextPango::GetSubstringBounds(const Range& range) { 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LE(range.GetMax(), text().length()); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (range.is_empty()) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::vector<Rect>(); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureLayout(); 226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int* ranges = NULL; 227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int n_ranges = 0; 228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) pango_layout_line_get_x_ranges(current_line_, 229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) TextIndexToLayoutIndex(range.GetMin()), 230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) TextIndexToLayoutIndex(range.GetMax()), 231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &ranges, 232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &n_ranges); 233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 234a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const int height = GetStringSize().height(); 235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<Rect> bounds; 237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int i = 0; i < n_ranges; ++i) { 238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TODO(derat): Support fractional bounds for subpixel positioning? 239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int x = PANGO_PIXELS(ranges[2 * i]); 240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int width = PANGO_PIXELS(ranges[2 * i + 1]) - x; 24190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Rect rect(x, 0, width, height); 242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) rect.set_origin(ToViewPoint(rect.origin())); 243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bounds.push_back(rect); 244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) g_free(ranges); 246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return bounds; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)size_t RenderTextPango::TextIndexToLayoutIndex(size_t index) const { 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(layout_); 251d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ptrdiff_t offset = gfx::UTF16IndexToOffset(text(), 0, index); 2527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // Clamp layout indices to the length of the text actually used for layout. 2537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch offset = std::min<size_t>(offset, g_utf8_strlen(layout_text_, -1)); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* layout_pointer = g_utf8_offset_to_pointer(layout_text_, offset); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (layout_pointer - layout_text_); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)size_t RenderTextPango::LayoutIndexToTextIndex(size_t index) const { 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(layout_); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* layout_pointer = layout_text_ + index; 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const long offset = g_utf8_pointer_to_offset(layout_text_, layout_pointer); 262d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return gfx::UTF16OffsetToIndex(text(), 0, offset); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool RenderTextPango::IsCursorablePosition(size_t position) { 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (position == 0 && text().empty()) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (position >= text().length()) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return position == text().length(); 270d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (!gfx::IsValidCodePointIndex(text(), position)) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureLayout(); 274d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ptrdiff_t offset = gfx::UTF16IndexToOffset(text(), 0, position); 275558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch // Check that the index corresponds with a valid text code point, that it is 276558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch // marked as a legitimate cursor position by Pango, and that it is not 277558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch // truncated from layout text (its glyph is shown on screen). 278558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch return (offset < num_log_attrs_ && log_attrs_[offset].is_cursor_position && 279558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch offset < g_utf8_strlen(layout_text_, -1)); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void RenderTextPango::ResetLayout() { 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // set_cached_bounds_and_offset_valid(false) is done in RenderText for every 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // operation that triggers ResetLayout(). 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (layout_) { 28668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // TODO(msw): Keep |layout_| across text changes, etc.; it can be re-used. 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_object_unref(layout_); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) layout_ = NULL; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (current_line_) { 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_line_unref(current_line_); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_line_ = NULL; 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (log_attrs_) { 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_free(log_attrs_); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) log_attrs_ = NULL; 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_log_attrs_ = 0; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) layout_text_ = NULL; 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void RenderTextPango::EnsureLayout() { 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (layout_ == NULL) { 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_surface_t* surface = 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); 30668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) CHECK_EQ(CAIRO_STATUS_SUCCESS, cairo_surface_status(surface)); 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_t* cr = cairo_create(surface); 30868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) CHECK_EQ(CAIRO_STATUS_SUCCESS, cairo_status(cr)); 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) layout_ = pango_cairo_create_layout(cr); 31168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) CHECK_NE(static_cast<PangoLayout*>(NULL), layout_); 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_destroy(cr); 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cairo_surface_destroy(surface); 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetupPangoLayoutWithFontDescription(layout_, 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetLayoutText(), 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) font_list().GetFontDescriptionString(), 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetTextDirection(), 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Canvas::DefaultCanvasTextAlignment()); 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No width set so that the x-axis position is relative to the start of the 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // text. ToViewPoint and ToTextPoint take care of the position conversion 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // between text space and view spaces. 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_set_width(layout_, -1); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(xji): If RenderText will be used for displaying purpose, such as 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // label, we will need to remove the single-line-mode setting. 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_set_single_paragraph_mode(layout_, true); 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) layout_text_ = pango_layout_get_text(layout_); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetupPangoAttributes(layout_); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_line_ = pango_layout_get_line_readonly(layout_, 0); 33468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) CHECK_NE(static_cast<PangoLayoutLine*>(NULL), current_line_); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_line_ref(current_line_); 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_get_log_attrs(layout_, &log_attrs_, &num_log_attrs_); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 341f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void RenderTextPango::SetupPangoAttributes(PangoLayout* layout) { 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PangoAttrList* attrs = pango_attr_list_new(); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Splitting text runs to accommodate styling can break Arabic glyph shaping. 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Only split text runs as needed for bold and italic font styles changes. 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BreakList<bool>::const_iterator bold = styles()[BOLD].breaks().begin(); 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BreakList<bool>::const_iterator italic = styles()[ITALIC].breaks().begin(); 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (bold != styles()[BOLD].breaks().end() && 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) italic != styles()[ITALIC].breaks().end()) { 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int style = (bold->second ? Font::BOLD : 0) | 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (italic->second ? Font::ITALIC : 0); 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const size_t bold_end = styles()[BOLD].GetRange(bold).end(); 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const size_t italic_end = styles()[ITALIC].GetRange(italic).end(); 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const size_t style_end = std::min(bold_end, italic_end); 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (style != font_list().GetFontStyle()) { 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FontList derived_font_list = font_list().DeriveFontList(style); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedPangoFontDescription desc(pango_font_description_from_string( 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) derived_font_list.GetFontDescriptionString().c_str())); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PangoAttribute* pango_attr = pango_attr_font_desc_new(desc.get()); 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pango_attr->start_index = 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TextIndexToLayoutIndex(std::max(bold->first, italic->first)); 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pango_attr->end_index = TextIndexToLayoutIndex(style_end); 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_attr_list_insert(attrs, pango_attr); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bold += bold_end == style_end ? 1 : 0; 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) italic += italic_end == style_end ? 1 : 0; 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(bold == styles()[BOLD].breaks().end()); 3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(italic == styles()[ITALIC].breaks().end()); 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_layout_set_attributes(layout, attrs); 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_attr_list_unref(attrs); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void RenderTextPango::DrawVisualText(Canvas* canvas) { 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(layout_); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skia will draw glyphs with respect to the baseline. 3800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) Vector2d offset(GetLineOffset(0) + Vector2d(0, GetLayoutTextBaseline())); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkScalar x = SkIntToScalar(offset.x()); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkScalar y = SkIntToScalar(offset.y()); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<SkPoint> pos; 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<uint16> glyphs; 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) internal::SkiaTextRenderer renderer(canvas); 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ApplyFadeEffects(&renderer); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ApplyTextShadows(&renderer); 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(derat): Use font-specific params: http://crbug.com/125235 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::FontRenderParams& render_params = 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::GetDefaultFontRenderParams(); 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool use_subpixel_rendering = 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) render_params.subpixel_rendering != 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE; 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) renderer.SetFontSmoothingSettings( 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) render_params.antialiasing, 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_subpixel_rendering && !background_is_transparent()); 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Temporarily apply composition underlines and selection colors. 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ApplyCompositionAndSelectionStyles(); 4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) internal::StyleIterator style(colors(), styles()); 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (GSList* it = current_line_->runs; it; it = it->next) { 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PangoLayoutRun* run = reinterpret_cast<PangoLayoutRun*>(it->data); 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int glyph_count = run->glyphs->num_glyphs; 409a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch // TODO(msw): Skip painting runs outside the display rect area, like Win. 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (glyph_count == 0) 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedPangoFontDescription desc( 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_font_describe(run->item->analysis.font)); 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string family_name = 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pango_font_description_get_family(desc.get()); 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) renderer.SetTextSize(GetPangoFontSizeInPixels(desc.get())); 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) glyphs.resize(glyph_count); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pos.resize(glyph_count); 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Track the current glyph and the glyph at the start of its styled range. 4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int glyph_index = 0; 4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int style_start_glyph_index = glyph_index; 4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Track the x-coordinates for each styled range (|x| marks the current). 4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkScalar style_start_x = x; 4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Track the current style and its text (not layout) index range. 4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) style.UpdatePosition(GetGlyphTextIndex(run, style_start_glyph_index)); 432d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) Range style_range = style.GetRange(); 4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) do { 4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const PangoGlyphInfo& glyph = run->glyphs->glyphs[glyph_index]; 4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) glyphs[glyph_index] = static_cast<uint16>(glyph.glyph); 4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Use pango_units_to_double() rather than PANGO_PIXELS() here, so units 4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // are not rounded to the pixel grid if subpixel positioning is enabled. 4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pos[glyph_index].set(x + pango_units_to_double(glyph.geometry.x_offset), 4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) y + pango_units_to_double(glyph.geometry.y_offset)); 4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) x += pango_units_to_double(glyph.geometry.width); 4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++glyph_index; 4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const size_t glyph_text_index = (glyph_index == glyph_count) ? 4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) style_range.end() : GetGlyphTextIndex(run, glyph_index); 4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!IndexInRange(style_range, glyph_text_index)) { 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(asvitkine): For cases like "fi", where "fi" is a single glyph 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but can span multiple styles, Pango splits the 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // styles evenly over the glyph. We can do this too by 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // clipping and drawing the glyph several times. 4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) renderer.SetForegroundColor(style.color()); 4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int font_style = (style.style(BOLD) ? Font::BOLD : 0) | 4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (style.style(ITALIC) ? Font::ITALIC : 0); 4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) renderer.SetFontFamilyWithStyle(family_name, font_style); 4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) renderer.DrawPosText(&pos[style_start_glyph_index], 4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &glyphs[style_start_glyph_index], 4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) glyph_index - style_start_glyph_index); 4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (style.style(UNDERLINE)) 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetPangoUnderlineMetrics(desc.get(), &renderer); 4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) renderer.DrawDecorations(style_start_x, y, x - style_start_x, 4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) style.style(UNDERLINE), style.style(STRIKE), 4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) style.style(DIAGONAL_STRIKE)); 4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) style.UpdatePosition(glyph_text_index); 4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) style_range = style.GetRange(); 4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) style_start_glyph_index = glyph_index; 4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) style_start_x = x; 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } while (glyph_index < glyph_count); 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Undo the temporarily applied composition underlines and selection colors. 4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UndoCompositionAndSelectionStyles(); 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)GSList* RenderTextPango::GetRunContainingCaret( 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SelectionModel& caret) const { 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t position = TextIndexToLayoutIndex(caret.caret_pos()); 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LogicalCursorDirection affinity = caret.caret_affinity(); 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GSList* run = current_line_->runs; 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (run) { 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; 482d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) Range item_range(item->offset, item->offset + item->length); 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (RangeContainsCaret(item_range, position, affinity)) 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return run; 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run = run->next; 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 490f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SelectionModel RenderTextPango::FirstSelectionModelInsideRun( 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const PangoItem* item) { 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t caret = IndexOfAdjacentGrapheme( 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LayoutIndexToTextIndex(item->offset), CURSOR_FORWARD); 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SelectionModel(caret, CURSOR_BACKWARD); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 497f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SelectionModel RenderTextPango::LastSelectionModelInsideRun( 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const PangoItem* item) { 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t caret = IndexOfAdjacentGrapheme( 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LayoutIndexToTextIndex(item->offset + item->length), CURSOR_BACKWARD); 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SelectionModel(caret, CURSOR_FORWARD); 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 504f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)size_t RenderTextPango::GetGlyphTextIndex(PangoLayoutRun* run, 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int glyph_index) const { 5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return LayoutIndexToTextIndex(run->item->offset + 5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) run->glyphs->log_clusters[glyph_index]); 5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RenderText* RenderText::CreateInstance() { 511f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return new RenderTextPango; 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace gfx 515