| 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 |