Index: ui/gfx/render_text_linux.cc |
diff --git a/ui/gfx/render_text_linux.cc b/ui/gfx/render_text_linux.cc |
index 3d3cdefa62618e4a5441799c6830cccfa211e468..4808147839593d97daae78f485647f579cab6e62 100644 |
--- a/ui/gfx/render_text_linux.cc |
+++ b/ui/gfx/render_text_linux.cc |
@@ -325,26 +325,32 @@ void RenderTextLinux::EnsureLayout() { |
void RenderTextLinux::SetupPangoAttributes(PangoLayout* layout) { |
PangoAttrList* attrs = pango_attr_list_new(); |
- int default_font_style = font_list().GetFontStyle(); |
- for (StyleRanges::const_iterator i = style_ranges().begin(); |
- i < style_ranges().end(); ++i) { |
- // In Pango, different fonts means different runs, and it breaks Arabic |
- // shaping across run boundaries. So, set font only when it is different |
- // from the default font. |
- // TODO(xji): We'll eventually need to split up StyleRange into components |
- // (ColorRange, FontRange, etc.) so that we can combine adjacent ranges |
- // with the same Fonts (to avoid unnecessarily splitting up runs). |
- if (i->font_style != default_font_style) { |
- FontList derived_font_list = font_list().DeriveFontList(i->font_style); |
+ // Splitting text runs to accomodate styling can break Arabic glyph shaping. |
+ // Only split text runs as needed for bold and italic font styles changes. |
+ std::vector<StyleBreak>::const_iterator bold = styles(BOLD).begin(); |
+ std::vector<StyleBreak>::const_iterator italic = styles(ITALIC).begin(); |
+ while (bold != styles(BOLD).end() && italic != styles(ITALIC).end()) { |
+ const int style = (bold->second ? Font::BOLD : 0) | |
+ (italic->second ? Font::ITALIC : 0); |
+ const size_t bold_end = GetBreakEnd(styles(BOLD), bold); |
+ const size_t italic_end = GetBreakEnd(styles(ITALIC), italic); |
+ const size_t end = std::min(bold_end, italic_end); |
+ if (style != Font::NORMAL) { |
+ FontList derived_font_list = font_list().DeriveFontList(style); |
ScopedPangoFontDescription desc(pango_font_description_from_string( |
derived_font_list.GetFontDescriptionString().c_str())); |
PangoAttribute* pango_attr = pango_attr_font_desc_new(desc.get()); |
- pango_attr->start_index = TextIndexToLayoutIndex(i->range.start()); |
- pango_attr->end_index = TextIndexToLayoutIndex(i->range.end()); |
+ pango_attr->start_index = |
+ TextIndexToLayoutIndex(std::max(bold->first, italic->first)); |
+ pango_attr->end_index = TextIndexToLayoutIndex(end); |
pango_attr_list_insert(attrs, pango_attr); |
} |
+ bold += bold_end == end ? 1 : 0; |
+ italic += italic_end == end ? 1 : 0; |
} |
+ DCHECK(bold == styles(BOLD).end()); |
+ DCHECK(italic == styles(ITALIC).end()); |
pango_layout_set_attributes(layout, attrs); |
pango_attr_list_unref(attrs); |
@@ -363,20 +369,6 @@ void RenderTextLinux::DrawVisualText(Canvas* canvas) { |
std::vector<SkPoint> pos; |
std::vector<uint16> glyphs; |
- StyleRanges styles(style_ranges()); |
- ApplyCompositionAndSelectionStyles(&styles); |
- |
- // Pre-calculate UTF8 indices from UTF16 indices. |
- // TODO(asvitkine): Can we cache these? |
- std::vector<ui::Range> style_ranges_utf8; |
- style_ranges_utf8.reserve(styles.size()); |
- size_t start_index = 0; |
- for (size_t i = 0; i < styles.size(); ++i) { |
- size_t end_index = TextIndexToLayoutIndex(styles[i].range.end()); |
- style_ranges_utf8.push_back(ui::Range(start_index, end_index)); |
- start_index = end_index; |
- } |
- |
internal::SkiaTextRenderer renderer(canvas); |
ApplyFadeEffects(&renderer); |
ApplyTextShadows(&renderer); |
@@ -391,27 +383,31 @@ void RenderTextLinux::DrawVisualText(Canvas* canvas) { |
render_params.antialiasing, |
use_subpixel_rendering && !background_is_transparent()); |
+ // Adjust the text colors to reflect the selection range. |
+ std::vector<ColorBreak> adjusted_colors(colors()); |
+ ApplySelectionColor(&adjusted_colors); |
+ |
+ // Adjust the underline styling to reflect composition ranges. |
+ const std::vector<StyleBreak>* adjusted_styles[NUM_TEXT_STYLES]; |
+ for (size_t i = 0; i < NUM_TEXT_STYLES; ++i) |
+ adjusted_styles[i] = &styles(static_cast<TextStyle>(i)); |
+ std::vector<StyleBreak> adjusted_underlines(styles(UNDERLINE)); |
+ ApplyCompositionStyle(&adjusted_underlines); |
+ adjusted_styles[UNDERLINE] = &adjusted_underlines; |
+ |
+ // Track the current color and style with iterators. |
+ std::vector<ColorBreak>::const_iterator color = adjusted_colors.begin(); |
+ std::vector<StyleBreak>::const_iterator style[NUM_TEXT_STYLES]; |
+ for (size_t i = 0; i < NUM_TEXT_STYLES; ++i) |
+ style[i] = adjusted_styles[i]->begin(); |
+ size_t style_end[NUM_TEXT_STYLES]; |
+ |
for (GSList* it = current_line_->runs; it; it = it->next) { |
PangoLayoutRun* run = reinterpret_cast<PangoLayoutRun*>(it->data); |
int glyph_count = run->glyphs->num_glyphs; |
if (glyph_count == 0) |
continue; |
- size_t run_start = run->item->offset; |
- size_t first_glyph_byte_index = run_start + run->glyphs->log_clusters[0]; |
- size_t style_increment = IsForwardMotion(CURSOR_RIGHT, run->item) ? 1 : -1; |
- |
- // Find the initial style for this run. |
- // TODO(asvitkine): Can we avoid looping here, e.g. by caching this per run? |
- int style = -1; |
- for (size_t i = 0; i < style_ranges_utf8.size(); ++i) { |
- if (IndexInRange(style_ranges_utf8[i], first_glyph_byte_index)) { |
- style = i; |
- break; |
- } |
- } |
- DCHECK_GE(style, 0); |
- |
ScopedPangoFontDescription desc( |
pango_font_describe(run->item->analysis.font)); |
@@ -429,48 +425,59 @@ void RenderTextLinux::DrawVisualText(Canvas* canvas) { |
for (int i = 0; i < glyph_count; ++i) { |
const PangoGlyphInfo& glyph = run->glyphs->glyphs[i]; |
glyphs[i] = static_cast<uint16>(glyph.glyph); |
- // Use pango_units_to_double() rather than PANGO_PIXELS() here so that |
- // units won't get rounded to the pixel grid if we're using subpixel |
- // positioning. |
+ // Use pango_units_to_double() rather than PANGO_PIXELS() here so units |
+ // are not rounded to the pixel grid if subpixel positioning is enabled. |
pos[i].set(glyph_x + pango_units_to_double(glyph.geometry.x_offset), |
y + pango_units_to_double(glyph.geometry.y_offset)); |
- // If this glyph is beyond the current style, draw the glyphs so far and |
- // advance to the next style. |
- size_t glyph_byte_index = run_start + run->glyphs->log_clusters[i]; |
- DCHECK_GE(style, 0); |
- DCHECK_LT(style, static_cast<int>(styles.size())); |
- if (!IndexInRange(style_ranges_utf8[style], glyph_byte_index)) { |
+ // Find the end of the current ranged style. If this glyph is beyond the |
+ // current style, draw the glyphs so far and advance to the next style. |
+ size_t glyph_index = run->item->offset + run->glyphs->log_clusters[i]; |
+ const size_t color_end = GetBreakEnd(adjusted_colors, color); |
+ size_t style_end_index = color_end; |
+ for (size_t j = 0; j < NUM_TEXT_STYLES; ++j) { |
+ style_end[j] = GetBreakEnd(*adjusted_styles[j], style[j]); |
+ style_end_index = std::min(style_end_index, style_end[j]); |
+ } |
+ if (glyph_index >= TextIndexToLayoutIndex(style_end_index)) { |
// TODO(asvitkine): For cases like "fi", where "fi" is a single glyph |
// but can span multiple styles, Pango splits the |
// styles evenly over the glyph. We can do this too by |
// clipping and drawing the glyph several times. |
- renderer.SetForegroundColor(styles[style].foreground); |
- renderer.SetFontFamilyWithStyle(family_name, styles[style].font_style); |
+ renderer.SetForegroundColor(color->second); |
+ const int font_style = (style[BOLD]->second ? Font::BOLD : 0) | |
+ (style[ITALIC]->second ? Font::ITALIC : 0); |
+ renderer.SetFontFamilyWithStyle(family_name, font_style); |
renderer.DrawPosText(&pos[start], &glyphs[start], i - start); |
- if (styles[style].underline) |
+ if (style[UNDERLINE]->second) |
SetPangoUnderlineMetrics(desc.get(), &renderer); |
- renderer.DrawDecorations(start_x, y, glyph_x - start_x, styles[style]); |
+ renderer.DrawDecorations(start_x, y, glyph_x - start_x, |
+ style[UNDERLINE]->second, style[STRIKE]->second, |
+ style[DIAGONAL_STRIKE]->second); |
start = i; |
start_x = glyph_x; |
- // Loop to find the next style, in case the glyph spans multiple styles. |
- do { |
- style += style_increment; |
- } while (style >= 0 && style < static_cast<int>(styles.size()) && |
- !IndexInRange(style_ranges_utf8[style], glyph_byte_index)); |
+ |
+ color += color_end == style_end_index ? 1 : 0; |
+ for (size_t j = 0; j < NUM_TEXT_STYLES; ++j) |
+ style[j] += style_end[j] == style_end_index ? 1 : 0; |
} |
glyph_x += pango_units_to_double(glyph.geometry.width); |
} |
// Draw the remaining glyphs. |
- renderer.SetForegroundColor(styles[style].foreground); |
- renderer.SetFontFamilyWithStyle(family_name, styles[style].font_style); |
+ renderer.SetForegroundColor(color->second); |
+ const int font_style = (style[BOLD]->second ? Font::BOLD : 0) | |
+ (style[ITALIC]->second ? Font::ITALIC : 0); |
+ renderer.SetFontFamilyWithStyle(family_name, font_style); |
renderer.DrawPosText(&pos[start], &glyphs[start], glyph_count - start); |
- if (styles[style].underline) |
+ if (style[UNDERLINE]->second) |
SetPangoUnderlineMetrics(desc.get(), &renderer); |
- renderer.DrawDecorations(start_x, y, glyph_x - start_x, styles[style]); |
+ renderer.DrawDecorations(start_x, y, glyph_x - start_x, |
+ style[UNDERLINE]->second, style[STRIKE]->second, |
+ style[DIAGONAL_STRIKE]->second); |
+ |
x = glyph_x; |
} |
} |