OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/render_text_linux.h" | 5 #include "ui/gfx/render_text_pango.h" |
6 | 6 |
7 #include <pango/pangocairo.h> | 7 #include <pango/pangocairo.h> |
8 #include <algorithm> | 8 #include <algorithm> |
9 #include <string> | 9 #include <string> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/i18n/break_iterator.h" | 12 #include "base/i18n/break_iterator.h" |
13 #include "base/logging.h" | 13 #include "base/logging.h" |
14 #include "third_party/skia/include/core/SkTypeface.h" | 14 #include "third_party/skia/include/core/SkTypeface.h" |
15 #include "ui/gfx/canvas.h" | 15 #include "ui/gfx/canvas.h" |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
60 renderer->SetUnderlineMetrics(PANGO_PIXELS(thickness), | 60 renderer->SetUnderlineMetrics(PANGO_PIXELS(thickness), |
61 PANGO_PIXELS(position)); | 61 PANGO_PIXELS(position)); |
62 } | 62 } |
63 | 63 |
64 } // namespace | 64 } // namespace |
65 | 65 |
66 // TODO(xji): index saved in upper layer is utf16 index. Pango uses utf8 index. | 66 // TODO(xji): index saved in upper layer is utf16 index. Pango uses utf8 index. |
67 // Since caret_pos is used internally, we could save utf8 index for caret_pos | 67 // Since caret_pos is used internally, we could save utf8 index for caret_pos |
68 // to avoid conversion. | 68 // to avoid conversion. |
69 | 69 |
70 RenderTextLinux::RenderTextLinux() | 70 RenderTextPango::RenderTextPango() |
71 : layout_(NULL), | 71 : layout_(NULL), |
72 current_line_(NULL), | 72 current_line_(NULL), |
73 log_attrs_(NULL), | 73 log_attrs_(NULL), |
74 num_log_attrs_(0), | 74 num_log_attrs_(0), |
75 layout_text_(NULL) { | 75 layout_text_(NULL) { |
76 } | 76 } |
77 | 77 |
78 RenderTextLinux::~RenderTextLinux() { | 78 RenderTextPango::~RenderTextPango() { |
79 ResetLayout(); | 79 ResetLayout(); |
80 } | 80 } |
81 | 81 |
82 Size RenderTextLinux::GetStringSize() { | 82 Size RenderTextPango::GetStringSize() { |
83 EnsureLayout(); | 83 EnsureLayout(); |
84 int width = 0, height = 0; | 84 int width = 0, height = 0; |
85 pango_layout_get_pixel_size(layout_, &width, &height); | 85 pango_layout_get_pixel_size(layout_, &width, &height); |
86 // Keep a consistent height between this particular string's PangoLayout and | 86 // Keep a consistent height between this particular string's PangoLayout and |
87 // potentially larger text supported by the FontList. | 87 // potentially larger text supported by the FontList. |
88 // For example, if a text field contains a Japanese character, which is | 88 // For example, if a text field contains a Japanese character, which is |
89 // smaller than Latin ones, and then later a Latin one is inserted, this | 89 // smaller than Latin ones, and then later a Latin one is inserted, this |
90 // ensures that the text baseline does not shift. | 90 // ensures that the text baseline does not shift. |
91 return Size(width, std::max(height, font_list().GetHeight())); | 91 return Size(width, std::max(height, font_list().GetHeight())); |
92 } | 92 } |
93 | 93 |
94 SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) { | 94 SelectionModel RenderTextPango::FindCursorPosition(const Point& point) { |
95 EnsureLayout(); | 95 EnsureLayout(); |
96 | 96 |
97 if (text().empty()) | 97 if (text().empty()) |
98 return SelectionModel(0, CURSOR_FORWARD); | 98 return SelectionModel(0, CURSOR_FORWARD); |
99 | 99 |
100 Point p(ToTextPoint(point)); | 100 Point p(ToTextPoint(point)); |
101 | 101 |
102 // When the point is outside of text, return HOME/END position. | 102 // When the point is outside of text, return HOME/END position. |
103 if (p.x() < 0) | 103 if (p.x() < 0) |
104 return EdgeSelectionModel(CURSOR_LEFT); | 104 return EdgeSelectionModel(CURSOR_LEFT); |
105 if (p.x() > GetStringSize().width()) | 105 if (p.x() > GetStringSize().width()) |
106 return EdgeSelectionModel(CURSOR_RIGHT); | 106 return EdgeSelectionModel(CURSOR_RIGHT); |
107 | 107 |
108 int caret_pos = 0, trailing = 0; | 108 int caret_pos = 0, trailing = 0; |
109 pango_layout_xy_to_index(layout_, p.x() * PANGO_SCALE, p.y() * PANGO_SCALE, | 109 pango_layout_xy_to_index(layout_, p.x() * PANGO_SCALE, p.y() * PANGO_SCALE, |
110 &caret_pos, &trailing); | 110 &caret_pos, &trailing); |
111 | 111 |
112 DCHECK_GE(trailing, 0); | 112 DCHECK_GE(trailing, 0); |
113 if (trailing > 0) { | 113 if (trailing > 0) { |
114 caret_pos = g_utf8_offset_to_pointer(layout_text_ + caret_pos, | 114 caret_pos = g_utf8_offset_to_pointer(layout_text_ + caret_pos, |
115 trailing) - layout_text_; | 115 trailing) - layout_text_; |
116 DCHECK_LE(static_cast<size_t>(caret_pos), strlen(layout_text_)); | 116 DCHECK_LE(static_cast<size_t>(caret_pos), strlen(layout_text_)); |
117 } | 117 } |
118 | 118 |
119 return SelectionModel(LayoutIndexToTextIndex(caret_pos), | 119 return SelectionModel(LayoutIndexToTextIndex(caret_pos), |
120 (trailing > 0) ? CURSOR_BACKWARD : CURSOR_FORWARD); | 120 (trailing > 0) ? CURSOR_BACKWARD : CURSOR_FORWARD); |
121 } | 121 } |
122 | 122 |
123 std::vector<RenderText::FontSpan> RenderTextLinux::GetFontSpansForTesting() { | 123 std::vector<RenderText::FontSpan> RenderTextPango::GetFontSpansForTesting() { |
124 EnsureLayout(); | 124 EnsureLayout(); |
125 | 125 |
126 std::vector<RenderText::FontSpan> spans; | 126 std::vector<RenderText::FontSpan> spans; |
127 for (GSList* it = current_line_->runs; it; it = it->next) { | 127 for (GSList* it = current_line_->runs; it; it = it->next) { |
128 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(it->data)->item; | 128 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(it->data)->item; |
129 const int start = LayoutIndexToTextIndex(item->offset); | 129 const int start = LayoutIndexToTextIndex(item->offset); |
130 const int end = LayoutIndexToTextIndex(item->offset + item->length); | 130 const int end = LayoutIndexToTextIndex(item->offset + item->length); |
131 const Range range(start, end); | 131 const Range range(start, end); |
132 | 132 |
133 ScopedPangoFontDescription desc(pango_font_describe(item->analysis.font)); | 133 ScopedPangoFontDescription desc(pango_font_describe(item->analysis.font)); |
134 spans.push_back(RenderText::FontSpan(Font(desc.get()), range)); | 134 spans.push_back(RenderText::FontSpan(Font(desc.get()), range)); |
135 } | 135 } |
136 | 136 |
137 return spans; | 137 return spans; |
138 } | 138 } |
139 | 139 |
140 int RenderTextLinux::GetLayoutTextBaseline() { | 140 int RenderTextPango::GetLayoutTextBaseline() { |
141 EnsureLayout(); | 141 EnsureLayout(); |
142 return PANGO_PIXELS(pango_layout_get_baseline(layout_)); | 142 return PANGO_PIXELS(pango_layout_get_baseline(layout_)); |
143 } | 143 } |
144 | 144 |
145 SelectionModel RenderTextLinux::AdjacentCharSelectionModel( | 145 SelectionModel RenderTextPango::AdjacentCharSelectionModel( |
146 const SelectionModel& selection, | 146 const SelectionModel& selection, |
147 VisualCursorDirection direction) { | 147 VisualCursorDirection direction) { |
148 GSList* run = GetRunContainingCaret(selection); | 148 GSList* run = GetRunContainingCaret(selection); |
149 if (!run) { | 149 if (!run) { |
150 // The cursor is not in any run: we're at the visual and logical edge. | 150 // The cursor is not in any run: we're at the visual and logical edge. |
151 SelectionModel edge = EdgeSelectionModel(direction); | 151 SelectionModel edge = EdgeSelectionModel(direction); |
152 if (edge.caret_pos() == selection.caret_pos()) | 152 if (edge.caret_pos() == selection.caret_pos()) |
153 return edge; | 153 return edge; |
154 else | 154 else |
155 run = (direction == CURSOR_RIGHT) ? | 155 run = (direction == CURSOR_RIGHT) ? |
(...skipping 19 matching lines...) Expand all Loading... |
175 run = (direction == CURSOR_RIGHT) ? | 175 run = (direction == CURSOR_RIGHT) ? |
176 run->next : GSListPrevious(current_line_->runs, run); | 176 run->next : GSListPrevious(current_line_->runs, run); |
177 if (!run) | 177 if (!run) |
178 return EdgeSelectionModel(direction); | 178 return EdgeSelectionModel(direction); |
179 } | 179 } |
180 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; | 180 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; |
181 return IsForwardMotion(direction, item) ? | 181 return IsForwardMotion(direction, item) ? |
182 FirstSelectionModelInsideRun(item) : LastSelectionModelInsideRun(item); | 182 FirstSelectionModelInsideRun(item) : LastSelectionModelInsideRun(item); |
183 } | 183 } |
184 | 184 |
185 SelectionModel RenderTextLinux::AdjacentWordSelectionModel( | 185 SelectionModel RenderTextPango::AdjacentWordSelectionModel( |
186 const SelectionModel& selection, | 186 const SelectionModel& selection, |
187 VisualCursorDirection direction) { | 187 VisualCursorDirection direction) { |
188 if (obscured()) | 188 if (obscured()) |
189 return EdgeSelectionModel(direction); | 189 return EdgeSelectionModel(direction); |
190 | 190 |
191 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); | 191 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); |
192 bool success = iter.Init(); | 192 bool success = iter.Init(); |
193 DCHECK(success); | 193 DCHECK(success); |
194 if (!success) | 194 if (!success) |
195 return selection; | 195 return selection; |
196 | 196 |
197 SelectionModel cur(selection); | 197 SelectionModel cur(selection); |
198 for (;;) { | 198 for (;;) { |
199 cur = AdjacentCharSelectionModel(cur, direction); | 199 cur = AdjacentCharSelectionModel(cur, direction); |
200 GSList* run = GetRunContainingCaret(cur); | 200 GSList* run = GetRunContainingCaret(cur); |
201 if (!run) | 201 if (!run) |
202 break; | 202 break; |
203 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; | 203 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; |
204 size_t cursor = cur.caret_pos(); | 204 size_t cursor = cur.caret_pos(); |
205 if (IsForwardMotion(direction, item) ? | 205 if (IsForwardMotion(direction, item) ? |
206 iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor)) | 206 iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor)) |
207 break; | 207 break; |
208 } | 208 } |
209 | 209 |
210 return cur; | 210 return cur; |
211 } | 211 } |
212 | 212 |
213 Range RenderTextLinux::GetGlyphBounds(size_t index) { | 213 Range RenderTextPango::GetGlyphBounds(size_t index) { |
214 PangoRectangle pos; | 214 PangoRectangle pos; |
215 pango_layout_index_to_pos(layout_, TextIndexToLayoutIndex(index), &pos); | 215 pango_layout_index_to_pos(layout_, TextIndexToLayoutIndex(index), &pos); |
216 // TODO(derat): Support fractional ranges for subpixel positioning? | 216 // TODO(derat): Support fractional ranges for subpixel positioning? |
217 return Range(PANGO_PIXELS(pos.x), PANGO_PIXELS(pos.x + pos.width)); | 217 return Range(PANGO_PIXELS(pos.x), PANGO_PIXELS(pos.x + pos.width)); |
218 } | 218 } |
219 | 219 |
220 std::vector<Rect> RenderTextLinux::GetSubstringBounds(const Range& range) { | 220 std::vector<Rect> RenderTextPango::GetSubstringBounds(const Range& range) { |
221 DCHECK_LE(range.GetMax(), text().length()); | 221 DCHECK_LE(range.GetMax(), text().length()); |
222 if (range.is_empty()) | 222 if (range.is_empty()) |
223 return std::vector<Rect>(); | 223 return std::vector<Rect>(); |
224 | 224 |
225 EnsureLayout(); | 225 EnsureLayout(); |
226 int* ranges = NULL; | 226 int* ranges = NULL; |
227 int n_ranges = 0; | 227 int n_ranges = 0; |
228 pango_layout_line_get_x_ranges(current_line_, | 228 pango_layout_line_get_x_ranges(current_line_, |
229 TextIndexToLayoutIndex(range.GetMin()), | 229 TextIndexToLayoutIndex(range.GetMin()), |
230 TextIndexToLayoutIndex(range.GetMax()), | 230 TextIndexToLayoutIndex(range.GetMax()), |
231 &ranges, | 231 &ranges, |
232 &n_ranges); | 232 &n_ranges); |
233 | 233 |
234 const int height = GetStringSize().height(); | 234 const int height = GetStringSize().height(); |
235 | 235 |
236 std::vector<Rect> bounds; | 236 std::vector<Rect> bounds; |
237 for (int i = 0; i < n_ranges; ++i) { | 237 for (int i = 0; i < n_ranges; ++i) { |
238 // TODO(derat): Support fractional bounds for subpixel positioning? | 238 // TODO(derat): Support fractional bounds for subpixel positioning? |
239 int x = PANGO_PIXELS(ranges[2 * i]); | 239 int x = PANGO_PIXELS(ranges[2 * i]); |
240 int width = PANGO_PIXELS(ranges[2 * i + 1]) - x; | 240 int width = PANGO_PIXELS(ranges[2 * i + 1]) - x; |
241 Rect rect(x, 0, width, height); | 241 Rect rect(x, 0, width, height); |
242 rect.set_origin(ToViewPoint(rect.origin())); | 242 rect.set_origin(ToViewPoint(rect.origin())); |
243 bounds.push_back(rect); | 243 bounds.push_back(rect); |
244 } | 244 } |
245 g_free(ranges); | 245 g_free(ranges); |
246 return bounds; | 246 return bounds; |
247 } | 247 } |
248 | 248 |
249 size_t RenderTextLinux::TextIndexToLayoutIndex(size_t index) const { | 249 size_t RenderTextPango::TextIndexToLayoutIndex(size_t index) const { |
250 DCHECK(layout_); | 250 DCHECK(layout_); |
251 ptrdiff_t offset = gfx::UTF16IndexToOffset(text(), 0, index); | 251 ptrdiff_t offset = gfx::UTF16IndexToOffset(text(), 0, index); |
252 // Clamp layout indices to the length of the text actually used for layout. | 252 // Clamp layout indices to the length of the text actually used for layout. |
253 offset = std::min<size_t>(offset, g_utf8_strlen(layout_text_, -1)); | 253 offset = std::min<size_t>(offset, g_utf8_strlen(layout_text_, -1)); |
254 const char* layout_pointer = g_utf8_offset_to_pointer(layout_text_, offset); | 254 const char* layout_pointer = g_utf8_offset_to_pointer(layout_text_, offset); |
255 return (layout_pointer - layout_text_); | 255 return (layout_pointer - layout_text_); |
256 } | 256 } |
257 | 257 |
258 size_t RenderTextLinux::LayoutIndexToTextIndex(size_t index) const { | 258 size_t RenderTextPango::LayoutIndexToTextIndex(size_t index) const { |
259 DCHECK(layout_); | 259 DCHECK(layout_); |
260 const char* layout_pointer = layout_text_ + index; | 260 const char* layout_pointer = layout_text_ + index; |
261 const long offset = g_utf8_pointer_to_offset(layout_text_, layout_pointer); | 261 const long offset = g_utf8_pointer_to_offset(layout_text_, layout_pointer); |
262 return gfx::UTF16OffsetToIndex(text(), 0, offset); | 262 return gfx::UTF16OffsetToIndex(text(), 0, offset); |
263 } | 263 } |
264 | 264 |
265 bool RenderTextLinux::IsCursorablePosition(size_t position) { | 265 bool RenderTextPango::IsCursorablePosition(size_t position) { |
266 if (position == 0 && text().empty()) | 266 if (position == 0 && text().empty()) |
267 return true; | 267 return true; |
268 if (position >= text().length()) | 268 if (position >= text().length()) |
269 return position == text().length(); | 269 return position == text().length(); |
270 if (!gfx::IsValidCodePointIndex(text(), position)) | 270 if (!gfx::IsValidCodePointIndex(text(), position)) |
271 return false; | 271 return false; |
272 | 272 |
273 EnsureLayout(); | 273 EnsureLayout(); |
274 ptrdiff_t offset = gfx::UTF16IndexToOffset(text(), 0, position); | 274 ptrdiff_t offset = gfx::UTF16IndexToOffset(text(), 0, position); |
275 // Check that the index corresponds with a valid text code point, that it is | 275 // Check that the index corresponds with a valid text code point, that it is |
276 // marked as a legitimate cursor position by Pango, and that it is not | 276 // marked as a legitimate cursor position by Pango, and that it is not |
277 // truncated from layout text (its glyph is shown on screen). | 277 // truncated from layout text (its glyph is shown on screen). |
278 return (offset < num_log_attrs_ && log_attrs_[offset].is_cursor_position && | 278 return (offset < num_log_attrs_ && log_attrs_[offset].is_cursor_position && |
279 offset < g_utf8_strlen(layout_text_, -1)); | 279 offset < g_utf8_strlen(layout_text_, -1)); |
280 } | 280 } |
281 | 281 |
282 void RenderTextLinux::ResetLayout() { | 282 void RenderTextPango::ResetLayout() { |
283 // set_cached_bounds_and_offset_valid(false) is done in RenderText for every | 283 // set_cached_bounds_and_offset_valid(false) is done in RenderText for every |
284 // operation that triggers ResetLayout(). | 284 // operation that triggers ResetLayout(). |
285 if (layout_) { | 285 if (layout_) { |
286 // TODO(msw): Keep |layout_| across text changes, etc.; it can be re-used. | 286 // TODO(msw): Keep |layout_| across text changes, etc.; it can be re-used. |
287 g_object_unref(layout_); | 287 g_object_unref(layout_); |
288 layout_ = NULL; | 288 layout_ = NULL; |
289 } | 289 } |
290 if (current_line_) { | 290 if (current_line_) { |
291 pango_layout_line_unref(current_line_); | 291 pango_layout_line_unref(current_line_); |
292 current_line_ = NULL; | 292 current_line_ = NULL; |
293 } | 293 } |
294 if (log_attrs_) { | 294 if (log_attrs_) { |
295 g_free(log_attrs_); | 295 g_free(log_attrs_); |
296 log_attrs_ = NULL; | 296 log_attrs_ = NULL; |
297 num_log_attrs_ = 0; | 297 num_log_attrs_ = 0; |
298 } | 298 } |
299 layout_text_ = NULL; | 299 layout_text_ = NULL; |
300 } | 300 } |
301 | 301 |
302 void RenderTextLinux::EnsureLayout() { | 302 void RenderTextPango::EnsureLayout() { |
303 if (layout_ == NULL) { | 303 if (layout_ == NULL) { |
304 cairo_surface_t* surface = | 304 cairo_surface_t* surface = |
305 cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); | 305 cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); |
306 CHECK_EQ(CAIRO_STATUS_SUCCESS, cairo_surface_status(surface)); | 306 CHECK_EQ(CAIRO_STATUS_SUCCESS, cairo_surface_status(surface)); |
307 cairo_t* cr = cairo_create(surface); | 307 cairo_t* cr = cairo_create(surface); |
308 CHECK_EQ(CAIRO_STATUS_SUCCESS, cairo_status(cr)); | 308 CHECK_EQ(CAIRO_STATUS_SUCCESS, cairo_status(cr)); |
309 | 309 |
310 layout_ = pango_cairo_create_layout(cr); | 310 layout_ = pango_cairo_create_layout(cr); |
311 CHECK_NE(static_cast<PangoLayout*>(NULL), layout_); | 311 CHECK_NE(static_cast<PangoLayout*>(NULL), layout_); |
312 cairo_destroy(cr); | 312 cairo_destroy(cr); |
(...skipping 18 matching lines...) Expand all Loading... |
331 SetupPangoAttributes(layout_); | 331 SetupPangoAttributes(layout_); |
332 | 332 |
333 current_line_ = pango_layout_get_line_readonly(layout_, 0); | 333 current_line_ = pango_layout_get_line_readonly(layout_, 0); |
334 CHECK_NE(static_cast<PangoLayoutLine*>(NULL), current_line_); | 334 CHECK_NE(static_cast<PangoLayoutLine*>(NULL), current_line_); |
335 pango_layout_line_ref(current_line_); | 335 pango_layout_line_ref(current_line_); |
336 | 336 |
337 pango_layout_get_log_attrs(layout_, &log_attrs_, &num_log_attrs_); | 337 pango_layout_get_log_attrs(layout_, &log_attrs_, &num_log_attrs_); |
338 } | 338 } |
339 } | 339 } |
340 | 340 |
341 void RenderTextLinux::SetupPangoAttributes(PangoLayout* layout) { | 341 void RenderTextPango::SetupPangoAttributes(PangoLayout* layout) { |
342 PangoAttrList* attrs = pango_attr_list_new(); | 342 PangoAttrList* attrs = pango_attr_list_new(); |
343 | 343 |
344 // Splitting text runs to accommodate styling can break Arabic glyph shaping. | 344 // Splitting text runs to accommodate styling can break Arabic glyph shaping. |
345 // Only split text runs as needed for bold and italic font styles changes. | 345 // Only split text runs as needed for bold and italic font styles changes. |
346 BreakList<bool>::const_iterator bold = styles()[BOLD].breaks().begin(); | 346 BreakList<bool>::const_iterator bold = styles()[BOLD].breaks().begin(); |
347 BreakList<bool>::const_iterator italic = styles()[ITALIC].breaks().begin(); | 347 BreakList<bool>::const_iterator italic = styles()[ITALIC].breaks().begin(); |
348 while (bold != styles()[BOLD].breaks().end() && | 348 while (bold != styles()[BOLD].breaks().end() && |
349 italic != styles()[ITALIC].breaks().end()) { | 349 italic != styles()[ITALIC].breaks().end()) { |
350 const int style = (bold->second ? Font::BOLD : 0) | | 350 const int style = (bold->second ? Font::BOLD : 0) | |
351 (italic->second ? Font::ITALIC : 0); | 351 (italic->second ? Font::ITALIC : 0); |
(...skipping 14 matching lines...) Expand all Loading... |
366 bold += bold_end == style_end ? 1 : 0; | 366 bold += bold_end == style_end ? 1 : 0; |
367 italic += italic_end == style_end ? 1 : 0; | 367 italic += italic_end == style_end ? 1 : 0; |
368 } | 368 } |
369 DCHECK(bold == styles()[BOLD].breaks().end()); | 369 DCHECK(bold == styles()[BOLD].breaks().end()); |
370 DCHECK(italic == styles()[ITALIC].breaks().end()); | 370 DCHECK(italic == styles()[ITALIC].breaks().end()); |
371 | 371 |
372 pango_layout_set_attributes(layout, attrs); | 372 pango_layout_set_attributes(layout, attrs); |
373 pango_attr_list_unref(attrs); | 373 pango_attr_list_unref(attrs); |
374 } | 374 } |
375 | 375 |
376 void RenderTextLinux::DrawVisualText(Canvas* canvas) { | 376 void RenderTextPango::DrawVisualText(Canvas* canvas) { |
377 DCHECK(layout_); | 377 DCHECK(layout_); |
378 | 378 |
379 // Skia will draw glyphs with respect to the baseline. | 379 // Skia will draw glyphs with respect to the baseline. |
380 Vector2d offset(GetLineOffset(0) + Vector2d(0, GetLayoutTextBaseline())); | 380 Vector2d offset(GetLineOffset(0) + Vector2d(0, GetLayoutTextBaseline())); |
381 | 381 |
382 SkScalar x = SkIntToScalar(offset.x()); | 382 SkScalar x = SkIntToScalar(offset.x()); |
383 SkScalar y = SkIntToScalar(offset.y()); | 383 SkScalar y = SkIntToScalar(offset.y()); |
384 | 384 |
385 std::vector<SkPoint> pos; | 385 std::vector<SkPoint> pos; |
386 std::vector<uint16> glyphs; | 386 std::vector<uint16> glyphs; |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
465 style_start_glyph_index = glyph_index; | 465 style_start_glyph_index = glyph_index; |
466 style_start_x = x; | 466 style_start_x = x; |
467 } | 467 } |
468 } while (glyph_index < glyph_count); | 468 } while (glyph_index < glyph_count); |
469 } | 469 } |
470 | 470 |
471 // Undo the temporarily applied composition underlines and selection colors. | 471 // Undo the temporarily applied composition underlines and selection colors. |
472 UndoCompositionAndSelectionStyles(); | 472 UndoCompositionAndSelectionStyles(); |
473 } | 473 } |
474 | 474 |
475 GSList* RenderTextLinux::GetRunContainingCaret( | 475 GSList* RenderTextPango::GetRunContainingCaret( |
476 const SelectionModel& caret) const { | 476 const SelectionModel& caret) const { |
477 size_t position = TextIndexToLayoutIndex(caret.caret_pos()); | 477 size_t position = TextIndexToLayoutIndex(caret.caret_pos()); |
478 LogicalCursorDirection affinity = caret.caret_affinity(); | 478 LogicalCursorDirection affinity = caret.caret_affinity(); |
479 GSList* run = current_line_->runs; | 479 GSList* run = current_line_->runs; |
480 while (run) { | 480 while (run) { |
481 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; | 481 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; |
482 Range item_range(item->offset, item->offset + item->length); | 482 Range item_range(item->offset, item->offset + item->length); |
483 if (RangeContainsCaret(item_range, position, affinity)) | 483 if (RangeContainsCaret(item_range, position, affinity)) |
484 return run; | 484 return run; |
485 run = run->next; | 485 run = run->next; |
486 } | 486 } |
487 return NULL; | 487 return NULL; |
488 } | 488 } |
489 | 489 |
490 SelectionModel RenderTextLinux::FirstSelectionModelInsideRun( | 490 SelectionModel RenderTextPango::FirstSelectionModelInsideRun( |
491 const PangoItem* item) { | 491 const PangoItem* item) { |
492 size_t caret = IndexOfAdjacentGrapheme( | 492 size_t caret = IndexOfAdjacentGrapheme( |
493 LayoutIndexToTextIndex(item->offset), CURSOR_FORWARD); | 493 LayoutIndexToTextIndex(item->offset), CURSOR_FORWARD); |
494 return SelectionModel(caret, CURSOR_BACKWARD); | 494 return SelectionModel(caret, CURSOR_BACKWARD); |
495 } | 495 } |
496 | 496 |
497 SelectionModel RenderTextLinux::LastSelectionModelInsideRun( | 497 SelectionModel RenderTextPango::LastSelectionModelInsideRun( |
498 const PangoItem* item) { | 498 const PangoItem* item) { |
499 size_t caret = IndexOfAdjacentGrapheme( | 499 size_t caret = IndexOfAdjacentGrapheme( |
500 LayoutIndexToTextIndex(item->offset + item->length), CURSOR_BACKWARD); | 500 LayoutIndexToTextIndex(item->offset + item->length), CURSOR_BACKWARD); |
501 return SelectionModel(caret, CURSOR_FORWARD); | 501 return SelectionModel(caret, CURSOR_FORWARD); |
502 } | 502 } |
503 | 503 |
504 size_t RenderTextLinux::GetGlyphTextIndex(PangoLayoutRun* run, | 504 size_t RenderTextPango::GetGlyphTextIndex(PangoLayoutRun* run, |
505 int glyph_index) const { | 505 int glyph_index) const { |
506 return LayoutIndexToTextIndex(run->item->offset + | 506 return LayoutIndexToTextIndex(run->item->offset + |
507 run->glyphs->log_clusters[glyph_index]); | 507 run->glyphs->log_clusters[glyph_index]); |
508 } | 508 } |
509 | 509 |
510 RenderText* RenderText::CreateInstance() { | 510 RenderText* RenderText::CreateInstance() { |
511 return new RenderTextLinux; | 511 return new RenderTextPango; |
512 } | 512 } |
513 | 513 |
514 } // namespace gfx | 514 } // namespace gfx |
OLD | NEW |