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

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

Issue 7511029: Implement Pango RenderText for Linux. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/gfx/render_text_linux.h ('k') | ui/ui.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/gfx/render_text_linux.h" 5 #include "ui/gfx/render_text_linux.h"
6 6
7 #include <pango/pangocairo.h>
8
9 #include <algorithm>
10
11 #include "base/logging.h"
12 #include "ui/gfx/canvas_skia.h"
13 #include "ui/gfx/pango_util.h"
14 #include "unicode/uchar.h"
15 #include "unicode/ustring.h"
16
17 namespace {
18
19 // TODO(xji): instead of converting each R or G or B from 8-bit to 16-bit,
20 // it should also massage A in the conversion.
21 int ConvertColorFrom8BitTo16Bit(int c) {
22 return (c << 8) + c;
23 }
24
25 } // namespace
26
27 // TODO(xji): index saved in upper layer is utf16 index. Pango uses utf8 index.
28 // Since caret_pos is used internally, we could save utf8 index for caret_pos
29 // to avoid conversion.
behdad_google 2011/09/09 18:25:30 Alternatively, we can just cache the mapping betwe
30
7 namespace gfx { 31 namespace gfx {
8 32
9 RenderTextLinux::RenderTextLinux() 33 RenderTextLinux::RenderTextLinux()
10 : RenderText() { 34 : layout_(NULL),
35 current_line_(NULL),
36 log_attrs_(NULL),
37 num_log_attrs_(0),
38 layout_text_(NULL),
39 layout_text_len_(0) {
11 } 40 }
12 41
13 RenderTextLinux::~RenderTextLinux() { 42 RenderTextLinux::~RenderTextLinux() {
43 ResetLayout();
14 } 44 }
15 45
16 RenderText* RenderText::CreateRenderText() { 46 RenderText* RenderText::CreateRenderText() {
17 return new RenderTextLinux; 47 return new RenderTextLinux;
18 } 48 }
19 49
50 void RenderTextLinux::SetText(const string16& text) {
51 RenderText::SetText(text);
52 ResetLayout();
53 }
54
55 void RenderTextLinux::SetDisplayRect(const Rect&r) {
56 RenderText::SetDisplayRect(r);
57 ResetLayout();
58 }
59
60 void RenderTextLinux::SetCompositionRange(const ui::Range& composition_range) {
61 RenderText::SetCompositionRange(composition_range);
62 ResetLayout();
63 }
64
65 void RenderTextLinux::ApplyStyleRange(StyleRange style_range) {
66 RenderText::ApplyStyleRange(style_range);
67 ResetLayout();
68 }
69
70 void RenderTextLinux::ApplyDefaultStyle() {
71 RenderText::ApplyDefaultStyle();
72 ResetLayout();
73 }
74
75 base::i18n::TextDirection RenderTextLinux::GetTextDirection() {
76 EnsureLayout();
77
78 PangoDirection base_dir = pango_find_base_dir(layout_text_, -1);
79 if (base_dir == PANGO_DIRECTION_RTL || base_dir == PANGO_DIRECTION_WEAK_RTL)
80 return base::i18n::RIGHT_TO_LEFT;
81 return base::i18n::LEFT_TO_RIGHT;
82 }
83
84 int RenderTextLinux::GetStringWidth() {
85 PangoLayout* layout = EnsureLayout();
86 int width;
87 pango_layout_get_pixel_size(layout, &width, NULL);
88 return width;
89 }
90
91 void RenderTextLinux::Draw(Canvas* canvas) {
92 PangoLayout* layout = EnsureLayout();
93 Rect bounds(display_rect());
94
95 // Clip the canvas to the text display area.
96 CanvasSkia* canvas_skia = canvas->AsCanvasSkia();
97
98 skia::ScopedPlatformPaint scoped_platform_paint(canvas_skia);
99 cairo_t* cr = scoped_platform_paint.GetPlatformSurface();
100 cairo_save(cr);
101 cairo_rectangle(cr, bounds.x(), bounds.y(), bounds.width(), bounds.height());
102 cairo_clip(cr);
103
104 int text_width, text_height;
105 pango_layout_get_pixel_size(layout, &text_width, &text_height);
106 Point offset(ToViewPoint(Point()));
107 // Vertically centered.
108 int text_y = offset.y() + ((bounds.height() - text_height) / 2);
109 // TODO(xji): need to use SkCanvas->drawPosText() for gpu acceleration.
110 cairo_move_to(cr, offset.x(), text_y);
111 pango_cairo_show_layout(cr, layout);
112
113 cairo_restore(cr);
114
115 // Paint cursor.
116 bounds = GetUpdatedCursorBounds();
117 if (cursor_visible() && focused())
118 canvas->DrawRectInt(kCursorColor,
119 bounds.x(),
120 bounds.y(),
121 bounds.width(),
122 bounds.height());
123 }
124
125 SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) {
126 // TODO(xji): when points outside of text, return HOME/END position.
127 PangoLayout* layout = EnsureLayout();
128
129 if (text().empty())
130 return SelectionModel(0, 0, SelectionModel::LEADING);
131
132 Point p(ToTextPoint(point));
133 int caret_pos, trailing;
134 pango_layout_xy_to_index(layout, p.x() * PANGO_SCALE, p.y() * PANGO_SCALE,
135 &caret_pos, &trailing);
136
137 size_t selection_end = caret_pos;
138 if (trailing > 0) {
139 const char* ch = g_utf8_offset_to_pointer(layout_text_ + caret_pos,
140 trailing);
141 DCHECK_GE(ch, layout_text_);
142 DCHECK_LE(ch, layout_text_ + layout_text_len_);
143 selection_end = ch - layout_text_;
144 }
145
146 return SelectionModel(
147 Utf8IndexToUtf16Index(selection_end),
148 Utf8IndexToUtf16Index(caret_pos),
149 trailing > 0 ? SelectionModel::TRAILING : SelectionModel::LEADING);
150 }
151
152 Rect RenderTextLinux::GetCursorBounds(const SelectionModel& selection,
153 bool insert_mode) {
154 PangoLayout* layout = EnsureLayout();
155
156 size_t caret_pos = insert_mode ? selection.caret_pos() :
157 selection.selection_end();
158 PangoRectangle pos;
159 pango_layout_index_to_pos(layout, Utf16IndexToUtf8Index(caret_pos), &pos);
160
161 SelectionModel::CaretPlacement caret_placement = selection.caret_placement();
162 int x = pos.x;
163 if ((insert_mode && caret_placement == SelectionModel::TRAILING) ||
164 (!insert_mode && pos.width < 0))
165 x += pos.width;
166 x = PANGO_PIXELS(x);
167
168 int h = std::min(display_rect().height(), PANGO_PIXELS(pos.height));
169 Rect bounds(x, (display_rect().height() - h) / 2, 0, h);
170 bounds.set_origin(ToViewPoint(bounds.origin()));
171
172 if (!insert_mode)
173 bounds.set_width(std::abs(pos.width));
174
175 return bounds;
176 }
177
178 SelectionModel RenderTextLinux::GetLeftSelectionModel(
179 const SelectionModel& current,
180 BreakType break_type) {
181 EnsureLayout();
182
183 if (break_type == LINE_BREAK || text().empty())
184 return LeftEndSelectionModel();
185 if (break_type == CHARACTER_BREAK)
186 return LeftSelectionModel(current);
187 // TODO(xji): not implemented yet.
188 return RenderText::GetLeftSelectionModel(current, break_type);
189 }
190
191 SelectionModel RenderTextLinux::GetRightSelectionModel(
192 const SelectionModel& current,
193 BreakType break_type) {
194 EnsureLayout();
195
196 if (break_type == LINE_BREAK || text().empty())
197 return RightEndSelectionModel();
198 if (break_type == CHARACTER_BREAK)
199 return RightSelectionModel(current);
200 // TODO(xji): not implemented yet.
201 return RenderText::GetRightSelectionModel(current, break_type);
202 }
203
204 SelectionModel RenderTextLinux::LeftEndSelectionModel() {
205 if (GetTextDirection() == base::i18n::RIGHT_TO_LEFT) {
206 if (current_line_->runs) {
207 PangoLayoutRun* first_visual_run =
208 reinterpret_cast<PangoLayoutRun*>(current_line_->runs->data);
209 PangoItem* item = first_visual_run->item;
210 if (item->analysis.level % 2 == 0) { // LTR.
211 size_t caret = Utf8IndexToUtf16Index(item->offset);
212 return SelectionModel(text().length(), caret, SelectionModel::LEADING);
213 } else { // RTL.
214 size_t caret = Utf16IndexOfAdjacentGrapheme(item->offset + item->length,
215 PREVIOUS);
216 return SelectionModel(text().length(), caret, SelectionModel::TRAILING);
217 }
218 }
219 }
220 return SelectionModel(0, 0, SelectionModel::LEADING);
221 }
222
223 SelectionModel RenderTextLinux::RightEndSelectionModel() {
224 if (GetTextDirection() == base::i18n::LEFT_TO_RIGHT) {
225 PangoLayoutRun* last_visual_run = GetLastRun();
226 if (last_visual_run) {
227 PangoItem* item = last_visual_run->item;
228 if (item->analysis.level % 2 == 0) { // LTR.
229 size_t caret = Utf16IndexOfAdjacentGrapheme(item->offset + item->length,
230 PREVIOUS);
231 return SelectionModel(text().length(), caret, SelectionModel::TRAILING);
232 } else { // RTL.
233 size_t caret = Utf8IndexToUtf16Index(item->offset);
234 return SelectionModel(text().length(), caret, SelectionModel::LEADING);
235 }
236 }
237 }
238 return SelectionModel(0, 0, SelectionModel::LEADING);
239 }
240
241 size_t RenderTextLinux::GetIndexOfPreviousGrapheme(size_t position) {
242 EnsureLayout();
243 size_t index = Utf16IndexToUtf8Index(position);
244 return Utf16IndexOfAdjacentGrapheme(index, PREVIOUS);
245 }
246
247 size_t RenderTextLinux::GetIndexOfNextGrapheme(size_t position) {
248 EnsureLayout();
249 size_t index = Utf16IndexToUtf8Index(position);
250 return Utf16IndexOfAdjacentGrapheme(index, NEXT);
251 }
252
253 GSList* RenderTextLinux::GetRunContainingPosition(size_t position) const {
254 GSList* run = current_line_->runs;
255 while (run) {
256 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item;
257 size_t run_start = Utf8IndexToUtf16Index(item->offset);
258 size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length);
259
260 if (position >= run_start && position < run_end)
261 return run;
262 run = run->next;
263 }
264 return NULL;
265 }
266
267 size_t RenderTextLinux::Utf8IndexOfAdjacentGrapheme(
268 size_t utf8_index_of_current_grapheme,
269 RelativeLogicalPosition pos) const {
270 const char* ch = layout_text_ + utf8_index_of_current_grapheme;
271 int char_offset = static_cast<int>(g_utf8_pointer_to_offset(layout_text_,
272 ch));
273 int start_char_offset = char_offset;
274 if (pos == PREVIOUS) {
275 if (char_offset > 0) {
276 do {
277 --char_offset;
278 } while (char_offset > 0 && !log_attrs_[char_offset].is_cursor_position);
279 }
280 } else {
281 if (char_offset < num_log_attrs_ - 1) {
282 do {
283 ++char_offset;
284 } while (char_offset < num_log_attrs_ - 1 &&
285 !log_attrs_[char_offset].is_cursor_position);
286 }
287 }
288
289 ch = g_utf8_offset_to_pointer(ch, char_offset - start_char_offset);
290 return static_cast<size_t>(ch - layout_text_);
291 }
292
293 size_t RenderTextLinux::Utf16IndexOfAdjacentGrapheme(
294 size_t utf8_index_of_current_grapheme,
295 RelativeLogicalPosition pos) const {
296 size_t utf8_index = Utf8IndexOfAdjacentGrapheme(
297 utf8_index_of_current_grapheme, pos);
298 return Utf8IndexToUtf16Index(utf8_index);
299 }
300
301 SelectionModel RenderTextLinux::FirstSelectionModelInsideRun(
302 const PangoItem* item) const {
303 size_t caret = Utf8IndexToUtf16Index(item->offset);
304 size_t cursor = Utf16IndexOfAdjacentGrapheme(item->offset, NEXT);
305 return SelectionModel(cursor, caret, SelectionModel::TRAILING);
306 }
307
308 SelectionModel RenderTextLinux::LastSelectionModelInsideRun(
309 const PangoItem* item) const {
310 size_t caret = Utf16IndexOfAdjacentGrapheme(item->offset + item->length,
311 PREVIOUS);
312 return SelectionModel(caret, caret, SelectionModel::LEADING);
313 }
314
315 // Assume caret_pos in |current| is n, 'l' represents leading in
316 // caret_placement and 't' represents trailing in caret_placement. Following
317 // is the calculation from (caret_pos, caret_placement) in |current| to
318 // (selection_end, caret_pos, caret_placement) when moving cursor left by
319 // one grapheme (for simplicity, assume each grapheme is one character).
320 // If n is in LTR run,
321 // (n, t) ---> (n, n, l).
322 // (n, l) ---> (n-1, n-1, l) if n is inside run (not at boundary).
323 // (n, l) ---> goto across run case if n is at run boundary.
324 // If n is in RTL run,
325 // (n, l) --> (n+1, n, t).
326 // (n, t) --> (n+2, n+1, t) if n is inside run.
327 // (n, t) --> goto across run case if n is at run boundary.
328 // If n is at run boundary, get its visually left run,
329 // If left run is LTR run,
330 // (n, t) --> (left run's end, left run's end, l).
331 // If left run is RTL run,
332 // (n, t) --> (left run's begin + 1, left run's begin, t).
333 SelectionModel RenderTextLinux::LeftSelectionModel(
334 const SelectionModel& selection) {
335 size_t caret = selection.caret_pos();
336 SelectionModel::CaretPlacement caret_placement = selection.caret_placement();
337 GSList* run = GetRunContainingPosition(caret);
338 DCHECK(run);
339
340 PangoLayoutRun* layout_run = reinterpret_cast<PangoLayoutRun*>(run->data);
341 PangoItem* item = layout_run->item;
342 size_t run_start = Utf8IndexToUtf16Index(item->offset);
343 size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length);
344
345 if (item->analysis.level % 2 == 0) { // LTR run.
346 if (caret_placement == SelectionModel::TRAILING)
347 return SelectionModel(caret, caret, SelectionModel::LEADING);
348 else if (caret > run_start) {
349 caret = GetIndexOfPreviousGrapheme(caret);
350 return SelectionModel(caret, caret, SelectionModel::LEADING);
351 }
352 } else { // RTL run.
353 if (caret_placement == SelectionModel::LEADING) {
354 size_t cursor = GetIndexOfNextGrapheme(caret);
355 return SelectionModel(cursor, caret, SelectionModel::TRAILING);
356 } else if (selection.selection_end() < run_end) {
357 caret = GetIndexOfNextGrapheme(caret);
358 size_t cursor = GetIndexOfNextGrapheme(caret);
359 return SelectionModel(cursor, caret, SelectionModel::TRAILING);
360 }
361 }
362
363 // The character is at the begin of its run; advance to the previous visual
364 // run.
365 PangoLayoutRun* prev_run = GetPreviousRun(layout_run);
366 if (!prev_run)
367 return LeftEndSelectionModel();
368
369 item = prev_run->item;
370 return (item->analysis.level % 2) ? FirstSelectionModelInsideRun(item) :
371 LastSelectionModelInsideRun(item);
372 }
373
374 // Assume caret_pos in |current| is n, 'l' represents leading in
375 // caret_placement and 't' represents trailing in caret_placement. Following
376 // is the calculation from (caret_pos, caret_placement) in |current| to
377 // (selection_end, caret_pos, caret_placement) when moving cursor right by
378 // one grapheme (for simplicity, assume each grapheme is one character).
379 // If n is in LTR run,
380 // (n, l) ---> (n+1, n, t).
381 // (n, t) ---> (n+2, n+1, t) if n is inside run (not at boundary).
382 // (n, t) ---> goto across run case if n is at run boundary.
383 // If n is in RTL run,
384 // (n, t) --> (n, n, l).
385 // (n, l) --> (n-1, n-1, l) if n is inside run.
386 // (n, l) --> goto across run case if n is at run boundary.
387 // If n is at run boundary, get its visually right run,
388 // If right run is LTR run,
389 // (n, t) --> (right run's begin + 1, right run's begin, t).
390 // If right run is RTL run,
391 // (n, t) --> (right run's end, right run's end, l).
392 SelectionModel RenderTextLinux::RightSelectionModel(
393 const SelectionModel& selection) {
394 size_t caret = selection.caret_pos();
395 SelectionModel::CaretPlacement caret_placement = selection.caret_placement();
396 GSList* run = GetRunContainingPosition(caret);
397 DCHECK(run);
398
399 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item;
400 size_t run_start = Utf8IndexToUtf16Index(item->offset);
401 size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length);
402
403 if (item->analysis.level % 2 == 0) { // LTR run.
404 if (caret_placement == SelectionModel::LEADING) {
405 size_t cursor = GetIndexOfNextGrapheme(caret);
406 return SelectionModel(cursor, caret, SelectionModel::TRAILING);
407 } else if (selection.selection_end() < run_end) {
408 caret = GetIndexOfNextGrapheme(caret);
409 size_t cursor = GetIndexOfNextGrapheme(caret);
410 return SelectionModel(cursor, caret, SelectionModel::TRAILING);
411 }
412 } else { // RTL run.
413 if (caret_placement == SelectionModel::TRAILING)
414 return SelectionModel(caret, caret, SelectionModel::LEADING);
415 else if (caret > run_start) {
416 caret = GetIndexOfPreviousGrapheme(caret);
417 return SelectionModel(caret, caret, SelectionModel::LEADING);
418 }
419 }
420
421 // The character is at the end of its run; advance to the next visual run.
422 GSList* next_run = run->next;
423 if (!next_run)
424 return RightEndSelectionModel();
425
426 item = reinterpret_cast<PangoLayoutRun*>(next_run->data)->item;
427 return (item->analysis.level % 2) ? LastSelectionModelInsideRun(item) :
428 FirstSelectionModelInsideRun(item);
429 }
430
431 PangoLayout* RenderTextLinux::EnsureLayout() {
432 if (layout_ == NULL) {
433 CanvasSkia canvas(display_rect().width(), display_rect().height(), false);
434 skia::ScopedPlatformPaint scoped_platform_paint(&canvas);
435 cairo_t* cr = scoped_platform_paint.GetPlatformSurface();
436
437 layout_ = pango_cairo_create_layout(cr);
438 SetupPangoLayout(
439 layout_,
440 text(),
441 default_style().font,
442 display_rect().width(),
443 base::i18n::GetFirstStrongCharacterDirection(text()),
444 CanvasSkia::DefaultCanvasTextAlignment());
445
446 // No width set so that the x-axis position is relative to the start of the
447 // text. ToViewPoint and ToTextPoint take care of the position conversion
448 // between text space and view spaces.
449 pango_layout_set_width(layout_, -1);
450 // TODO(xji): If RenderText will be used for displaying purpose, such as
451 // label, we will need to remove the single-line-mode setting.
452 pango_layout_set_single_paragraph_mode(layout_, true);
453 SetupPangoAttributes(layout_);
454
455 current_line_ = pango_layout_get_line_readonly(layout_, 0);
456 pango_layout_line_ref(current_line_);
457
458 pango_layout_get_log_attrs(layout_, &log_attrs_, &num_log_attrs_);
459
460 layout_text_ = pango_layout_get_text(layout_);
461 layout_text_len_ = strlen(layout_text_);
462 }
463 return layout_;
464 }
465
466 void RenderTextLinux::ResetLayout() {
467 // set_cached_bounds_and_offset_valid(false) is done in RenderText for every
468 // operation that triggers ResetLayout().
469 if (layout_) {
470 g_object_unref(layout_);
471 layout_ = NULL;
472 }
473 if (current_line_) {
474 pango_layout_line_unref(current_line_);
475 current_line_ = NULL;
476 }
477 if (log_attrs_) {
478 g_free(log_attrs_);
479 log_attrs_ = NULL;
480 num_log_attrs_ = 0;
481 }
482 layout_text_ = NULL;
483 layout_text_len_ = 0;
484 }
485
486 void RenderTextLinux::SetupPangoAttributes(PangoLayout* layout) {
487 PangoAttrList* attrs = pango_attr_list_new();
488 // Set selection background color.
489 SkColor selection_color =
490 focused() ? kFocusedSelectionColor : kUnfocusedSelectionColor;
491 size_t start = std::min(MinOfSelection(), text().length());
492 size_t end = std::min(MaxOfSelection(), text().length());
493 PangoAttribute* pango_attr;
494 if (end > start) {
495 pango_attr = pango_attr_background_new(
496 ConvertColorFrom8BitTo16Bit(SkColorGetR(selection_color)),
497 ConvertColorFrom8BitTo16Bit(SkColorGetG(selection_color)),
498 ConvertColorFrom8BitTo16Bit(SkColorGetB(selection_color)));
499 AppendPangoAttribute(start, end, pango_attr, attrs);
500 }
501
502 StyleRanges ranges_of_style(style_ranges());
503 ApplyCompositionAndSelectionStyles(&ranges_of_style);
504
505 for (StyleRanges::const_iterator i = ranges_of_style.begin();
506 i < ranges_of_style.end(); ++i) {
507 start = std::min(i->range.start(), text().length());
508 end = std::min(i->range.end(), text().length());
509 if (start >= end)
510 continue;
511
512 const Font& font = !i->underline ? i->font :
513 i->font.DeriveFont(0, i->font.GetStyle() | Font::UNDERLINED);
514 PangoFontDescription* desc = font.GetNativeFont();
515 pango_attr = pango_attr_font_desc_new(desc);
516 AppendPangoAttribute(start, end, pango_attr, attrs);
517 pango_font_description_free(desc);
518
519 SkColor foreground = i->foreground;
520 pango_attr = pango_attr_foreground_new(
521 ConvertColorFrom8BitTo16Bit(SkColorGetR(foreground)),
522 ConvertColorFrom8BitTo16Bit(SkColorGetG(foreground)),
523 ConvertColorFrom8BitTo16Bit(SkColorGetB(foreground)));
524 AppendPangoAttribute(start, end, pango_attr, attrs);
525
526 if (i->strike) {
527 pango_attr = pango_attr_strikethrough_new(true);
528 AppendPangoAttribute(start, end, pango_attr, attrs);
529 }
530 }
531
532 pango_layout_set_attributes(layout, attrs);
533 pango_attr_list_unref(attrs);
534 }
535
536 void RenderTextLinux::AppendPangoAttribute(size_t start,
537 size_t end,
538 PangoAttribute* pango_attr,
539 PangoAttrList* attrs) {
540 pango_attr->start_index = Utf16IndexToUtf8Index(start);
541 pango_attr->end_index = Utf16IndexToUtf8Index(end);
542 pango_attr_list_insert(attrs, pango_attr);
543 }
544
545 PangoLayoutRun* RenderTextLinux::GetPreviousRun(PangoLayoutRun* run) const {
546 GSList* current = current_line_->runs;
547 GSList* prev = NULL;
548 while (current) {
549 if (reinterpret_cast<PangoLayoutRun*>(current->data) == run)
550 return prev ? reinterpret_cast<PangoLayoutRun*>(prev->data) : NULL;
551 prev = current;
552 current = current->next;
553 }
554 return NULL;
555 }
556
557 PangoLayoutRun* RenderTextLinux::GetLastRun() const {
558 GSList* current = current_line_->runs;
559 while (current && current->next) {
560 current = current->next;
561 }
562 return current ? reinterpret_cast<PangoLayoutRun*>(current->data) : NULL;
563 }
564
565 size_t RenderTextLinux::Utf16IndexToUtf8Index(size_t index) const {
566 int32_t utf8_index = 0;
567 UErrorCode ec = U_ZERO_ERROR;
568 u_strToUTF8(NULL, 0, &utf8_index, text().data(), index, &ec);
569 // Even given a destination buffer as NULL and destination capacity as 0,
570 // if the output length is equal to or greater than the capacity, then the
571 // UErrorCode is set to U_STRING_NOT_TERMINATED_WARNING or
572 // U_BUFFER_OVERFLOW_ERROR respectively.
573 // Please refer to
574 // http://userguide.icu-project.org/strings#TOC-Using-C-Strings:-NUL-Terminate d-vs
575 // for detail (search for "Note that" below "Preflighting").
576 DCHECK(ec == U_BUFFER_OVERFLOW_ERROR ||
577 ec == U_STRING_NOT_TERMINATED_WARNING);
578 return utf8_index;
579 }
580
581 size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const {
582 int32_t utf16_index = 0;
583 UErrorCode ec = U_ZERO_ERROR;
584 u_strFromUTF8(NULL, 0, &utf16_index, layout_text_, index, &ec);
585 DCHECK(ec == U_BUFFER_OVERFLOW_ERROR ||
586 ec == U_STRING_NOT_TERMINATED_WARNING);
587 return utf16_index;
588 }
589
20 } // namespace gfx 590 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text_linux.h ('k') | ui/ui.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698