| Index: ui/gfx/render_text.cc
 | 
| diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc
 | 
| index c4f841dfcf7898f4b590f31839f865e8afbdac74..ae4638c800a72ad12ae97f5c72bb179085f0dd47 100644
 | 
| --- a/ui/gfx/render_text.cc
 | 
| +++ b/ui/gfx/render_text.cc
 | 
| @@ -174,6 +174,25 @@ SkPaint::Hinting FontRenderParamsHintingToSkPaintHinting(
 | 
|    return SkPaint::kNo_Hinting;
 | 
|  }
 | 
|  
 | 
| +// Make sure ranges don't break text graphemes.  If a range in |break_list|
 | 
| +// does break a grapheme in |render_text|, the range will be slightly
 | 
| +// extended to encompass the grapheme.
 | 
| +template <typename T>
 | 
| +void RestoreBreakList(RenderText* render_text, BreakList<T>& break_list) {
 | 
| +  break_list.SetMax(render_text->text().length());
 | 
| +  Range range;
 | 
| +  while (range.end() < break_list.max()) {
 | 
| +    const auto& current_break = break_list.GetBreak(range.end());
 | 
| +    range = break_list.GetRange(current_break);
 | 
| +    if (range.end() < break_list.max() &&
 | 
| +        !render_text->IsValidCursorIndex(range.end())) {
 | 
| +      range.set_end(
 | 
| +          render_text->IndexOfAdjacentGrapheme(range.end(), CURSOR_FORWARD));
 | 
| +      break_list.ApplyValue(current_break->second, range);
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
|  }  // namespace
 | 
|  
 | 
|  namespace internal {
 | 
| @@ -349,10 +368,11 @@ void SkiaTextRenderer::DiagonalStrike::Draw() {
 | 
|  }
 | 
|  
 | 
|  StyleIterator::StyleIterator(const BreakList<SkColor>& colors,
 | 
| -                             const std::vector<BreakList<bool> >& styles)
 | 
| -    : colors_(colors),
 | 
| -      styles_(styles) {
 | 
| +                             const BreakList<BaselineStyle>& baselines,
 | 
| +                             const std::vector<BreakList<bool>>& styles)
 | 
| +    : colors_(colors), baselines_(baselines), styles_(styles) {
 | 
|    color_ = colors_.breaks().begin();
 | 
| +  baseline_ = baselines_.breaks().begin();
 | 
|    for (size_t i = 0; i < styles_.size(); ++i)
 | 
|      style_.push_back(styles_[i].breaks().begin());
 | 
|  }
 | 
| @@ -361,6 +381,7 @@ StyleIterator::~StyleIterator() {}
 | 
|  
 | 
|  Range StyleIterator::GetRange() const {
 | 
|    Range range(colors_.GetRange(color_));
 | 
| +  range = range.Intersect(baselines_.GetRange(baseline_));
 | 
|    for (size_t i = 0; i < NUM_TEXT_STYLES; ++i)
 | 
|      range = range.Intersect(styles_[i].GetRange(style_[i]));
 | 
|    return range;
 | 
| @@ -368,6 +389,7 @@ Range StyleIterator::GetRange() const {
 | 
|  
 | 
|  void StyleIterator::UpdatePosition(size_t position) {
 | 
|    color_ = colors_.GetBreak(position);
 | 
| +  baseline_ = baselines_.GetBreak(position);
 | 
|    for (size_t i = 0; i < NUM_TEXT_STYLES; ++i)
 | 
|      style_[i] = styles_[i].GetBreak(position);
 | 
|  }
 | 
| @@ -423,11 +445,13 @@ void RenderText::SetText(const base::string16& text) {
 | 
|      return;
 | 
|    text_ = text;
 | 
|  
 | 
| -  // Adjust ranged styles and colors to accommodate a new text length.
 | 
| -  // Clear style ranges as they might break new text graphemes and apply
 | 
| +  // Adjust ranged styles, baselines, and colors to accommodate a new text
 | 
| +  // length. Clear style ranges as they might break new text graphemes and apply
 | 
|    // the first style to the whole text instead.
 | 
|    const size_t text_length = text_.length();
 | 
|    colors_.SetMax(text_length);
 | 
| +  baselines_.SetValue(baselines_.breaks().begin()->second);
 | 
| +  baselines_.SetMax(text_length);
 | 
|    for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) {
 | 
|      BreakList<bool>& break_list = styles_[style];
 | 
|      break_list.SetValue(break_list.breaks().begin()->second);
 | 
| @@ -670,6 +694,14 @@ void RenderText::ApplyColor(SkColor value, const Range& range) {
 | 
|    colors_.ApplyValue(value, range);
 | 
|  }
 | 
|  
 | 
| +void RenderText::SetBaselineStyle(BaselineStyle value) {
 | 
| +  baselines_.SetValue(value);
 | 
| +}
 | 
| +
 | 
| +void RenderText::ApplyBaselineStyle(BaselineStyle value, const Range& range) {
 | 
| +  baselines_.ApplyValue(value, range);
 | 
| +}
 | 
| +
 | 
|  void RenderText::SetStyle(TextStyle style, bool value) {
 | 
|    styles_[style].SetValue(value);
 | 
|  
 | 
| @@ -910,6 +942,7 @@ RenderText::RenderText()
 | 
|        focused_(false),
 | 
|        composition_range_(Range::InvalidRange()),
 | 
|        colors_(kDefaultColor),
 | 
| +      baselines_(NORMAL_BASELINE),
 | 
|        styles_(NUM_TEXT_STYLES),
 | 
|        composition_and_selection_styles_applied_(false),
 | 
|        obscured_(false),
 | 
| @@ -1283,6 +1316,7 @@ base::string16 RenderText::Elide(const base::string16& text,
 | 
|    render_text->SetCursorEnabled(cursor_enabled_);
 | 
|    render_text->set_truncate_length(truncate_length_);
 | 
|    render_text->styles_ = styles_;
 | 
| +  render_text->baselines_ = baselines_;
 | 
|    render_text->colors_ = colors_;
 | 
|    if (text_width == 0) {
 | 
|      render_text->SetText(text);
 | 
| @@ -1336,24 +1370,11 @@ base::string16 RenderText::Elide(const base::string16& text,
 | 
|        render_text->SetText(new_text);
 | 
|      }
 | 
|  
 | 
| -    // Restore styles. Make sure style ranges don't break new text graphemes.
 | 
| +    // Restore styles and baselines without breaking multi-character graphemes.
 | 
|      render_text->styles_ = styles_;
 | 
| -    for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) {
 | 
| -      BreakList<bool>& break_list = render_text->styles_[style];
 | 
| -      break_list.SetMax(render_text->text_.length());
 | 
| -      Range range;
 | 
| -      while (range.end() < break_list.max()) {
 | 
| -        BreakList<bool>::const_iterator current_break =
 | 
| -            break_list.GetBreak(range.end());
 | 
| -        range = break_list.GetRange(current_break);
 | 
| -        if (range.end() < break_list.max() &&
 | 
| -            !render_text->IsValidCursorIndex(range.end())) {
 | 
| -          range.set_end(render_text->IndexOfAdjacentGrapheme(range.end(),
 | 
| -                                                             CURSOR_FORWARD));
 | 
| -          break_list.ApplyValue(current_break->second, range);
 | 
| -        }
 | 
| -      }
 | 
| -    }
 | 
| +    for (size_t style = 0; style < NUM_TEXT_STYLES; ++style)
 | 
| +      RestoreBreakList(render_text.get(), render_text->styles_[style]);
 | 
| +    RestoreBreakList(render_text.get(), baselines_);
 | 
|  
 | 
|      // We check the width of the whole desired string at once to ensure we
 | 
|      // handle kerning/ligatures/etc. correctly.
 | 
| 
 |