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

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

Issue 11535014: Replace StyleRange with BreakList; update RenderText, etc. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix RenderTextMac style iteration. Created 7 years, 10 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.cc ('k') | ui/gfx/render_text_mac.h » ('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) 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_linux.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>
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 315
316 SetupPangoAttributes(layout_); 316 SetupPangoAttributes(layout_);
317 317
318 current_line_ = pango_layout_get_line_readonly(layout_, 0); 318 current_line_ = pango_layout_get_line_readonly(layout_, 0);
319 pango_layout_line_ref(current_line_); 319 pango_layout_line_ref(current_line_);
320 320
321 pango_layout_get_log_attrs(layout_, &log_attrs_, &num_log_attrs_); 321 pango_layout_get_log_attrs(layout_, &log_attrs_, &num_log_attrs_);
322 } 322 }
323 } 323 }
324 324
325 void RenderTextLinux::SetupPangoAttributes(PangoLayout* layout) { 325 void RenderTextLinux::SetupPangoAttributes(PangoLayout* layout) {
Alexei Svitkine (slow) 2013/01/29 22:07:25 Is it possible to add a test for this function? S
msw 2013/01/31 01:48:54 Done.
326 PangoAttrList* attrs = pango_attr_list_new(); 326 PangoAttrList* attrs = pango_attr_list_new();
327 327
328 int default_font_style = font_list().GetFontStyle(); 328 // Splitting text runs to accommodate styling can break Arabic glyph shaping.
329 for (StyleRanges::const_iterator i = style_ranges().begin(); 329 // Only split text runs as needed for bold and italic font styles changes.
330 i < style_ranges().end(); ++i) { 330 BreakList<bool>::const_iterator bold = styles()[BOLD].breaks().begin();
331 // In Pango, different fonts means different runs, and it breaks Arabic 331 BreakList<bool>::const_iterator italic = styles()[ITALIC].breaks().begin();
332 // shaping across run boundaries. So, set font only when it is different 332 while (bold != styles()[BOLD].breaks().end() &&
333 // from the default font. 333 italic != styles()[ITALIC].breaks().end()) {
334 // TODO(xji): We'll eventually need to split up StyleRange into components 334 const int style = (bold->second ? Font::BOLD : 0) |
335 // (ColorRange, FontRange, etc.) so that we can combine adjacent ranges 335 (italic->second ? Font::ITALIC : 0);
336 // with the same Fonts (to avoid unnecessarily splitting up runs). 336 const size_t bold_end = TextIndexToLayoutIndex(std::min(text().length(),
Alexei Svitkine (slow) 2013/01/29 22:07:25 Can you add the std::min() logic to style.GetNextB
msw 2013/01/31 01:48:54 I revised BreakList to support a max value. StyleI
337 if (i->font_style != default_font_style) { 337 styles()[BOLD].GetBreakEnd(bold)));
338 FontList derived_font_list = font_list().DeriveFontList(i->font_style); 338 const size_t italic_end = TextIndexToLayoutIndex(std::min(text().length(),
339 styles()[ITALIC].GetBreakEnd(italic)));
340 const size_t end = std::min(bold_end, italic_end);
341 if (style != Font::NORMAL) {
Alexei Svitkine (slow) 2013/01/29 22:07:25 Shouldn't you compare it to the style of the font
msw 2013/01/31 01:48:54 Done.
342 FontList derived_font_list = font_list().DeriveFontList(style);
339 ScopedPangoFontDescription desc(pango_font_description_from_string( 343 ScopedPangoFontDescription desc(pango_font_description_from_string(
340 derived_font_list.GetFontDescriptionString().c_str())); 344 derived_font_list.GetFontDescriptionString().c_str()));
341 345
342 PangoAttribute* pango_attr = pango_attr_font_desc_new(desc.get()); 346 PangoAttribute* pango_attr = pango_attr_font_desc_new(desc.get());
343 pango_attr->start_index = TextIndexToLayoutIndex(i->range.start()); 347 pango_attr->start_index =
344 pango_attr->end_index = TextIndexToLayoutIndex(i->range.end()); 348 TextIndexToLayoutIndex(std::max(bold->first, italic->first));
349 pango_attr->end_index = end;
345 pango_attr_list_insert(attrs, pango_attr); 350 pango_attr_list_insert(attrs, pango_attr);
346 } 351 }
352 bold += bold_end == end ? 1 : 0;
353 italic += italic_end == end ? 1 : 0;
347 } 354 }
355 DCHECK(bold == styles()[BOLD].breaks().end());
356 DCHECK(italic == styles()[ITALIC].breaks().end());
348 357
349 pango_layout_set_attributes(layout, attrs); 358 pango_layout_set_attributes(layout, attrs);
350 pango_attr_list_unref(attrs); 359 pango_attr_list_unref(attrs);
351 } 360 }
352 361
353 void RenderTextLinux::DrawVisualText(Canvas* canvas) { 362 void RenderTextLinux::DrawVisualText(Canvas* canvas) {
354 DCHECK(layout_); 363 DCHECK(layout_);
355 364
356 Vector2d offset(GetOffsetForDrawing()); 365 Vector2d offset(GetOffsetForDrawing());
357 // Skia will draw glyphs with respect to the baseline. 366 // Skia will draw glyphs with respect to the baseline.
358 offset += Vector2d(0, PANGO_PIXELS(pango_layout_get_baseline(layout_))); 367 offset += Vector2d(0, PANGO_PIXELS(pango_layout_get_baseline(layout_)));
359 368
360 SkScalar x = SkIntToScalar(offset.x()); 369 SkScalar x = SkIntToScalar(offset.x());
361 SkScalar y = SkIntToScalar(offset.y()); 370 SkScalar y = SkIntToScalar(offset.y());
362 371
363 std::vector<SkPoint> pos; 372 std::vector<SkPoint> pos;
364 std::vector<uint16> glyphs; 373 std::vector<uint16> glyphs;
365 374
366 StyleRanges styles(style_ranges());
367 ApplyCompositionAndSelectionStyles(&styles);
368
369 // Pre-calculate UTF8 indices from UTF16 indices.
370 // TODO(asvitkine): Can we cache these?
371 std::vector<ui::Range> style_ranges_utf8;
372 style_ranges_utf8.reserve(styles.size());
373 size_t start_index = 0;
374 for (size_t i = 0; i < styles.size(); ++i) {
375 size_t end_index = TextIndexToLayoutIndex(styles[i].range.end());
376 style_ranges_utf8.push_back(ui::Range(start_index, end_index));
377 start_index = end_index;
378 }
379
380 internal::SkiaTextRenderer renderer(canvas); 375 internal::SkiaTextRenderer renderer(canvas);
381 ApplyFadeEffects(&renderer); 376 ApplyFadeEffects(&renderer);
382 ApplyTextShadows(&renderer); 377 ApplyTextShadows(&renderer);
383 378
384 // TODO(derat): Use font-specific params: http://crbug.com/125235 379 // TODO(derat): Use font-specific params: http://crbug.com/125235
385 const gfx::FontRenderParams& render_params = 380 const gfx::FontRenderParams& render_params =
386 gfx::GetDefaultFontRenderParams(); 381 gfx::GetDefaultFontRenderParams();
387 const bool use_subpixel_rendering = 382 const bool use_subpixel_rendering =
388 render_params.subpixel_rendering != 383 render_params.subpixel_rendering !=
389 gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE; 384 gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE;
390 renderer.SetFontSmoothingSettings( 385 renderer.SetFontSmoothingSettings(
391 render_params.antialiasing, 386 render_params.antialiasing,
392 use_subpixel_rendering && !background_is_transparent()); 387 use_subpixel_rendering && !background_is_transparent());
393 388
389 // Temporarily apply composition underlines and selection colors.
390 ApplyCompositionAndSelectionStyles();
391
392 internal::StyleIterator style(colors(), styles());
394 for (GSList* it = current_line_->runs; it; it = it->next) { 393 for (GSList* it = current_line_->runs; it; it = it->next) {
395 PangoLayoutRun* run = reinterpret_cast<PangoLayoutRun*>(it->data); 394 PangoLayoutRun* run = reinterpret_cast<PangoLayoutRun*>(it->data);
396 int glyph_count = run->glyphs->num_glyphs; 395 int glyph_count = run->glyphs->num_glyphs;
397 if (glyph_count == 0) 396 if (glyph_count == 0)
398 continue; 397 continue;
399 398
400 size_t run_start = run->item->offset;
401 size_t first_glyph_byte_index = run_start + run->glyphs->log_clusters[0];
402 size_t style_increment = IsForwardMotion(CURSOR_RIGHT, run->item) ? 1 : -1;
403
404 // Find the initial style for this run.
405 // TODO(asvitkine): Can we avoid looping here, e.g. by caching this per run?
406 int style = -1;
407 for (size_t i = 0; i < style_ranges_utf8.size(); ++i) {
408 if (IndexInRange(style_ranges_utf8[i], first_glyph_byte_index)) {
409 style = i;
410 break;
411 }
412 }
413 DCHECK_GE(style, 0);
414
415 ScopedPangoFontDescription desc( 399 ScopedPangoFontDescription desc(
416 pango_font_describe(run->item->analysis.font)); 400 pango_font_describe(run->item->analysis.font));
417 401
418 const std::string family_name = 402 const std::string family_name =
419 pango_font_description_get_family(desc.get()); 403 pango_font_description_get_family(desc.get());
420 renderer.SetTextSize(GetPangoFontSizeInPixels(desc.get())); 404 renderer.SetTextSize(GetPangoFontSizeInPixels(desc.get()));
421 405
422 SkScalar glyph_x = x; 406 SkScalar glyph_x = x;
423 SkScalar start_x = x; 407 SkScalar start_x = x;
424 int start = 0; 408 int start = 0;
425 409
426 glyphs.resize(glyph_count); 410 glyphs.resize(glyph_count);
427 pos.resize(glyph_count); 411 pos.resize(glyph_count);
428 412
429 for (int i = 0; i < glyph_count; ++i) { 413 for (int i = 0; i < glyph_count; ++i) {
430 const PangoGlyphInfo& glyph = run->glyphs->glyphs[i]; 414 const PangoGlyphInfo& glyph = run->glyphs->glyphs[i];
431 glyphs[i] = static_cast<uint16>(glyph.glyph); 415 glyphs[i] = static_cast<uint16>(glyph.glyph);
432 // Use pango_units_to_double() rather than PANGO_PIXELS() here so that 416 // Use pango_units_to_double() rather than PANGO_PIXELS() here so units
433 // units won't get rounded to the pixel grid if we're using subpixel 417 // are not rounded to the pixel grid if subpixel positioning is enabled.
434 // positioning.
435 pos[i].set(glyph_x + pango_units_to_double(glyph.geometry.x_offset), 418 pos[i].set(glyph_x + pango_units_to_double(glyph.geometry.x_offset),
436 y + pango_units_to_double(glyph.geometry.y_offset)); 419 y + pango_units_to_double(glyph.geometry.y_offset));
437 420
438 // If this glyph is beyond the current style, draw the glyphs so far and 421 // Find the end of the current ranged style. If this glyph is beyond the
439 // advance to the next style. 422 // current style, draw the glyphs so far and advance to the next style.
440 size_t glyph_byte_index = run_start + run->glyphs->log_clusters[i]; 423 size_t glyph_index = run->item->offset + run->glyphs->log_clusters[i];
441 DCHECK_GE(style, 0); 424 const size_t style_end_index = TextIndexToLayoutIndex(
442 DCHECK_LT(style, static_cast<int>(styles.size())); 425 std::min(text().length(), style.GetNextBreak()));
443 if (!IndexInRange(style_ranges_utf8[style], glyph_byte_index)) { 426 if (glyph_index >= style_end_index) {
444 // TODO(asvitkine): For cases like "fi", where "fi" is a single glyph 427 // TODO(asvitkine): For cases like "fi", where "fi" is a single glyph
445 // but can span multiple styles, Pango splits the 428 // but can span multiple styles, Pango splits the
446 // styles evenly over the glyph. We can do this too by 429 // styles evenly over the glyph. We can do this too by
447 // clipping and drawing the glyph several times. 430 // clipping and drawing the glyph several times.
448 renderer.SetForegroundColor(styles[style].foreground); 431 renderer.SetForegroundColor(style.color());
449 renderer.SetFontFamilyWithStyle(family_name, styles[style].font_style); 432 const int font_style = (style.style(BOLD) ? Font::BOLD : 0) |
433 (style.style(ITALIC) ? Font::ITALIC : 0);
434 renderer.SetFontFamilyWithStyle(family_name, font_style);
450 renderer.DrawPosText(&pos[start], &glyphs[start], i - start); 435 renderer.DrawPosText(&pos[start], &glyphs[start], i - start);
451 if (styles[style].underline) 436 if (style.style(UNDERLINE))
452 SetPangoUnderlineMetrics(desc.get(), &renderer); 437 SetPangoUnderlineMetrics(desc.get(), &renderer);
453 renderer.DrawDecorations(start_x, y, glyph_x - start_x, styles[style]); 438 renderer.DrawDecorations(start_x, y, glyph_x - start_x,
439 style.style(UNDERLINE), style.style(STRIKE),
440 style.style(DIAGONAL_STRIKE));
454 441
455 start = i; 442 start = i;
456 start_x = glyph_x; 443 start_x = glyph_x;
457 // Loop to find the next style, in case the glyph spans multiple styles. 444 style.UpdatePosition(LayoutIndexToTextIndex(style_end_index));
Alexei Svitkine (slow) 2013/01/29 22:07:25 Are you sure that |style_end_index| is correct for
msw 2013/01/31 01:48:54 You are right, my previous patch set was wrong; th
458 do {
459 style += style_increment;
460 } while (style >= 0 && style < static_cast<int>(styles.size()) &&
461 !IndexInRange(style_ranges_utf8[style], glyph_byte_index));
462 } 445 }
463 446
464 glyph_x += pango_units_to_double(glyph.geometry.width); 447 glyph_x += pango_units_to_double(glyph.geometry.width);
465 } 448 }
466 449
467 // Draw the remaining glyphs. 450 // Draw the remaining glyphs.
468 renderer.SetForegroundColor(styles[style].foreground); 451 renderer.SetForegroundColor(style.color());
469 renderer.SetFontFamilyWithStyle(family_name, styles[style].font_style); 452 const int font_style = (style.style(BOLD) ? Font::BOLD : 0) |
453 (style.style(ITALIC) ? Font::ITALIC : 0);
454 renderer.SetFontFamilyWithStyle(family_name, font_style);
470 renderer.DrawPosText(&pos[start], &glyphs[start], glyph_count - start); 455 renderer.DrawPosText(&pos[start], &glyphs[start], glyph_count - start);
471 if (styles[style].underline) 456 if (style.style(UNDERLINE))
472 SetPangoUnderlineMetrics(desc.get(), &renderer); 457 SetPangoUnderlineMetrics(desc.get(), &renderer);
473 renderer.DrawDecorations(start_x, y, glyph_x - start_x, styles[style]); 458 renderer.DrawDecorations(start_x, y, glyph_x - start_x,
459 style.style(UNDERLINE), style.style(STRIKE),
460 style.style(DIAGONAL_STRIKE));
461
474 x = glyph_x; 462 x = glyph_x;
475 } 463 }
464
465 // Undo the temporarily applied composition underlines and selection colors.
466 UndoCompositionAndSelectionStyles();
476 } 467 }
477 468
478 GSList* RenderTextLinux::GetRunContainingCaret( 469 GSList* RenderTextLinux::GetRunContainingCaret(
479 const SelectionModel& caret) const { 470 const SelectionModel& caret) const {
480 size_t position = TextIndexToLayoutIndex(caret.caret_pos()); 471 size_t position = TextIndexToLayoutIndex(caret.caret_pos());
481 LogicalCursorDirection affinity = caret.caret_affinity(); 472 LogicalCursorDirection affinity = caret.caret_affinity();
482 GSList* run = current_line_->runs; 473 GSList* run = current_line_->runs;
483 while (run) { 474 while (run) {
484 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; 475 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item;
485 ui::Range item_range(item->offset, item->offset + item->length); 476 ui::Range item_range(item->offset, item->offset + item->length);
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 if (selection_visual_bounds_.empty()) 527 if (selection_visual_bounds_.empty())
537 selection_visual_bounds_ = CalculateSubstringBounds(selection()); 528 selection_visual_bounds_ = CalculateSubstringBounds(selection());
538 return selection_visual_bounds_; 529 return selection_visual_bounds_;
539 } 530 }
540 531
541 RenderText* RenderText::CreateInstance() { 532 RenderText* RenderText::CreateInstance() {
542 return new RenderTextLinux; 533 return new RenderTextLinux;
543 } 534 }
544 535
545 } // namespace gfx 536 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text.cc ('k') | ui/gfx/render_text_mac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698