| Index: ui/gfx/render_text_unittest.cc
 | 
| diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc
 | 
| index e274a266eaa9acfd18bfbaca370a327215f5f7f8..432d4ab1c2b4662cb7aab3caccf6d36842d3a85d 100644
 | 
| --- a/ui/gfx/render_text_unittest.cc
 | 
| +++ b/ui/gfx/render_text_unittest.cc
 | 
| @@ -163,6 +163,48 @@ class TestSkiaTextRenderer : public internal::SkiaTextRenderer {
 | 
|    DISALLOW_COPY_AND_ASSIGN(TestSkiaTextRenderer);
 | 
|  };
 | 
|  
 | 
| +// Given a buffer to test against, this can be used to test various areas of the
 | 
| +// rectangular buffer against a specific color value.
 | 
| +class TestRectangleBuffer {
 | 
| + public:
 | 
| +  TestRectangleBuffer(const wchar_t* string,
 | 
| +                      const SkColor* buffer,
 | 
| +                      uint32_t stride,
 | 
| +                      uint32_t row_count)
 | 
| +      : string_(string),
 | 
| +        buffer_(buffer),
 | 
| +        stride_(stride),
 | 
| +        row_count_(row_count) {}
 | 
| +
 | 
| +  // Test if any values in the rectangular area are anything other than |color|.
 | 
| +  void EnsureSolidRect(SkColor color,
 | 
| +                       int left,
 | 
| +                       int top,
 | 
| +                       int width,
 | 
| +                       int height) const {
 | 
| +    ASSERT_LT(top, row_count_) << string_;
 | 
| +    ASSERT_LE(top + height, row_count_) << string_;
 | 
| +    ASSERT_LT(left, stride_) << string_;
 | 
| +    ASSERT_LE(left + width, stride_) << string_ << ", left " << left
 | 
| +                                     << ", width " << width << ", stride_ "
 | 
| +                                     << stride_;
 | 
| +    for (int y = top; y < top + height; ++y) {
 | 
| +      for (int x = left; x < left + width; ++x) {
 | 
| +        SkColor color = buffer_[x + y * stride_];
 | 
| +        EXPECT_EQ(SK_ColorWHITE, color) << string_ << " at " << x << ", " << y;
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  const wchar_t* string_;
 | 
| +  const SkColor* buffer_;
 | 
| +  int stride_;
 | 
| +  int row_count_;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(TestRectangleBuffer);
 | 
| +};
 | 
| +
 | 
|  }  // namespace
 | 
|  
 | 
|  class RenderTextTest : public testing::Test {
 | 
| @@ -175,6 +217,8 @@ TEST_F(RenderTextTest, DefaultStyle) {
 | 
|    const wchar_t* const cases[] = { kWeak, kLtr, L"Hello", kRtl, L"", L"" };
 | 
|    for (size_t i = 0; i < arraysize(cases); ++i) {
 | 
|      EXPECT_TRUE(render_text->colors().EqualsValueForTesting(SK_ColorBLACK));
 | 
| +    EXPECT_TRUE(
 | 
| +        render_text->baselines().EqualsValueForTesting(NORMAL_BASELINE));
 | 
|      for (size_t style = 0; style < NUM_TEXT_STYLES; ++style)
 | 
|        EXPECT_TRUE(render_text->styles()[style].EqualsValueForTesting(false));
 | 
|      render_text->SetText(WideToUTF16(cases[i]));
 | 
| @@ -186,11 +230,13 @@ TEST_F(RenderTextTest, SetColorAndStyle) {
 | 
|    scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
 | 
|    const SkColor color = SK_ColorRED;
 | 
|    render_text->SetColor(color);
 | 
| +  render_text->SetBaselineStyle(SUPERSCRIPT);
 | 
|    render_text->SetStyle(BOLD, true);
 | 
|    render_text->SetStyle(UNDERLINE, false);
 | 
|    const wchar_t* const cases[] = { kWeak, kLtr, L"Hello", kRtl, L"", L"" };
 | 
|    for (size_t i = 0; i < arraysize(cases); ++i) {
 | 
|      EXPECT_TRUE(render_text->colors().EqualsValueForTesting(color));
 | 
| +    EXPECT_TRUE(render_text->baselines().EqualsValueForTesting(SUPERSCRIPT));
 | 
|      EXPECT_TRUE(render_text->styles()[BOLD].EqualsValueForTesting(true));
 | 
|      EXPECT_TRUE(render_text->styles()[UNDERLINE].EqualsValueForTesting(false));
 | 
|      render_text->SetText(WideToUTF16(cases[i]));
 | 
| @@ -209,32 +255,51 @@ TEST_F(RenderTextTest, ApplyColorAndStyle) {
 | 
|  
 | 
|    // Apply a ranged color and style and check the resulting breaks.
 | 
|    render_text->ApplyColor(SK_ColorRED, Range(1, 4));
 | 
| +  render_text->ApplyBaselineStyle(SUPERIOR, Range(2, 4));
 | 
|    render_text->ApplyStyle(BOLD, true, Range(2, 5));
 | 
|    std::vector<std::pair<size_t, SkColor> > expected_color;
 | 
|    expected_color.push_back(std::pair<size_t, SkColor>(0, SK_ColorBLACK));
 | 
|    expected_color.push_back(std::pair<size_t, SkColor>(1, SK_ColorRED));
 | 
|    expected_color.push_back(std::pair<size_t, SkColor>(4, SK_ColorBLACK));
 | 
|    EXPECT_TRUE(render_text->colors().EqualsForTesting(expected_color));
 | 
| +  std::vector<std::pair<size_t, BaselineStyle>> expected_baseline_style;
 | 
| +  expected_baseline_style.push_back(
 | 
| +      std::pair<size_t, BaselineStyle>(0, NORMAL_BASELINE));
 | 
| +  expected_baseline_style.push_back(
 | 
| +      std::pair<size_t, BaselineStyle>(2, SUPERIOR));
 | 
| +  expected_baseline_style.push_back(
 | 
| +      std::pair<size_t, BaselineStyle>(4, NORMAL_BASELINE));
 | 
| +  EXPECT_TRUE(
 | 
| +      render_text->baselines().EqualsForTesting(expected_baseline_style));
 | 
|    std::vector<std::pair<size_t, bool> > expected_style;
 | 
|    expected_style.push_back(std::pair<size_t, bool>(0, false));
 | 
|    expected_style.push_back(std::pair<size_t, bool>(2, true));
 | 
|    expected_style.push_back(std::pair<size_t, bool>(5, false));
 | 
|    EXPECT_TRUE(render_text->styles()[BOLD].EqualsForTesting(expected_style));
 | 
|  
 | 
| -  // Ensure setting a color and style overrides the ranged colors and styles.
 | 
| +  // Ensure setting a color, baseline, and style overrides the ranged colors,
 | 
| +  // baseline, and styles.
 | 
|    render_text->SetColor(SK_ColorBLUE);
 | 
|    EXPECT_TRUE(render_text->colors().EqualsValueForTesting(SK_ColorBLUE));
 | 
| +  render_text->SetBaselineStyle(SUBSCRIPT);
 | 
| +  EXPECT_TRUE(render_text->baselines().EqualsValueForTesting(SUBSCRIPT));
 | 
|    render_text->SetStyle(BOLD, false);
 | 
|    EXPECT_TRUE(render_text->styles()[BOLD].EqualsValueForTesting(false));
 | 
|  
 | 
| -  // Apply a color and style over the text end and check the resulting breaks.
 | 
| -  // (INT_MAX should be used instead of the text length for the range end)
 | 
| +  // Apply a color, baseline, and style over the text end and check the
 | 
| +  // resulting breaks (INT_MAX should be used instead of the text length for
 | 
| +  // the range end)
 | 
|    const size_t text_length = render_text->text().length();
 | 
|    render_text->ApplyColor(SK_ColorRED, Range(0, text_length));
 | 
| +  render_text->ApplyBaselineStyle(SUPERIOR, Range(0, text_length));
 | 
|    render_text->ApplyStyle(BOLD, true, Range(2, text_length));
 | 
|    std::vector<std::pair<size_t, SkColor> > expected_color_end;
 | 
|    expected_color_end.push_back(std::pair<size_t, SkColor>(0, SK_ColorRED));
 | 
|    EXPECT_TRUE(render_text->colors().EqualsForTesting(expected_color_end));
 | 
| +  std::vector<std::pair<size_t, BaselineStyle>> expected_baseline_end;
 | 
| +  expected_baseline_end.push_back(
 | 
| +      std::pair<size_t, BaselineStyle>(0, SUPERIOR));
 | 
| +  EXPECT_TRUE(render_text->baselines().EqualsForTesting(expected_baseline_end));
 | 
|    std::vector<std::pair<size_t, bool> > expected_style_end;
 | 
|    expected_style_end.push_back(std::pair<size_t, bool>(0, false));
 | 
|    expected_style_end.push_back(std::pair<size_t, bool>(2, true));
 | 
| @@ -2588,40 +2653,152 @@ TEST_F(RenderTextTest, HarfBuzz_UnicodeFallback) {
 | 
|  #endif  // defined(OS_WIN) || defined(OS_MACOSX)
 | 
|  
 | 
|  // Ensure that the width reported by RenderText is sufficient for drawing. Draws
 | 
| -// to a canvas and checks whether any pixel beyond the width is colored.
 | 
| +// to a canvas and checks whether any pixel beyond the bounding rectangle is
 | 
| +// colored.
 | 
|  TEST_F(RenderTextTest, TextDoesntClip) {
 | 
| -  const wchar_t* kTestStrings[] = { L"Save", L"Remove", L"TEST", L"W", L"WWW" };
 | 
| +  const wchar_t* kTestStrings[] = {
 | 
| +      L"            ",
 | 
| +      // TODO(dschuyler): Underscores draw outside GetStringSize;
 | 
| +      // crbug.com/459812.  This appears to be a preexisting issue that wasn't
 | 
| +      // revealed by the prior unit tests.
 | 
| +      // L"TEST_______",
 | 
| +      L"TEST some stuff",
 | 
| +      L"WWWWWWWWWW",
 | 
| +      L"gAXAXAXAXAXAXA",
 | 
| +      // TODO(dschuyler): A-Ring draws outside GetStringSize; crbug.com/459812.
 | 
| +      // L"g\x00C5X\x00C5X\x00C5X\x00C5X\x00C5X\x00C5X\x00C5",
 | 
| +      L"\x0647\x0654\x0647\x0654\x0647\x0654\x0647\x0654\x0645\x0631\x062D"
 | 
| +      L"\x0628\x0627"};
 | 
|    const Size kCanvasSize(300, 50);
 | 
| -  const int kTestWidth = 10;
 | 
| +  const int kTestSize = 10;
 | 
|  
 | 
|    skia::RefPtr<SkSurface> surface = skia::AdoptRef(
 | 
|        SkSurface::NewRasterN32Premul(kCanvasSize.width(), kCanvasSize.height()));
 | 
|    scoped_ptr<Canvas> canvas(
 | 
|        Canvas::CreateCanvasWithoutScaling(surface->getCanvas(), 1.0f));
 | 
|    scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
 | 
| -  render_text->SetDisplayRect(Rect(kCanvasSize));
 | 
| -  render_text->SetHorizontalAlignment(gfx::ALIGN_LEFT);
 | 
| +  render_text->SetHorizontalAlignment(ALIGN_LEFT);
 | 
|    render_text->SetColor(SK_ColorBLACK);
 | 
|  
 | 
|    for (auto string : kTestStrings) {
 | 
|      surface->getCanvas()->clear(SK_ColorWHITE);
 | 
|      render_text->SetText(WideToUTF16(string));
 | 
| +    const Size string_size = render_text->GetStringSize();
 | 
| +    render_text->ApplyBaselineStyle(SUPERSCRIPT, Range(1, 2));
 | 
| +    render_text->ApplyBaselineStyle(SUPERIOR, Range(3, 4));
 | 
| +    render_text->ApplyBaselineStyle(INFERIOR, Range(5, 6));
 | 
| +    render_text->ApplyBaselineStyle(SUBSCRIPT, Range(7, 8));
 | 
|      render_text->SetStyle(BOLD, true);
 | 
| +    render_text->SetDisplayRect(
 | 
| +        Rect(kTestSize, kTestSize, string_size.width(), string_size.height()));
 | 
| +    // Allow the RenderText to paint outside of its display rect.
 | 
| +    render_text->set_clip_to_display_rect(false);
 | 
| +    ASSERT_LE(string_size.width() + kTestSize * 2, kCanvasSize.width());
 | 
| +
 | 
|      render_text->Draw(canvas.get());
 | 
| -    int width = render_text->GetStringSize().width();
 | 
| -    ASSERT_LT(width + kTestWidth, kCanvasSize.width());
 | 
| -    const uint32* buffer = static_cast<const uint32*>(
 | 
| -        surface->peekPixels(NULL, NULL));
 | 
| +    ASSERT_LT(string_size.width() + kTestSize, kCanvasSize.width());
 | 
| +    const uint32* buffer =
 | 
| +        static_cast<const uint32*>(surface->peekPixels(nullptr, nullptr));
 | 
|      ASSERT_NE(nullptr, buffer);
 | 
| +    TestRectangleBuffer rect_buffer(string, buffer, kCanvasSize.width(),
 | 
| +                                    kCanvasSize.height());
 | 
| +    {
 | 
| +#if !defined(OS_CHROMEOS)
 | 
| +      // TODO(dschuyler): On ChromeOS text draws above the GetStringSize rect.
 | 
| +      SCOPED_TRACE("TextDoesntClip Top Side");
 | 
| +      rect_buffer.EnsureSolidRect(SK_ColorWHITE, 0, 0, kCanvasSize.width(),
 | 
| +                                  kTestSize);
 | 
| +#endif
 | 
| +    }
 | 
| +    {
 | 
| +      SCOPED_TRACE("TextDoesntClip Bottom Side");
 | 
| +      rect_buffer.EnsureSolidRect(SK_ColorWHITE, 0,
 | 
| +                                  kTestSize + string_size.height(),
 | 
| +                                  kCanvasSize.width(), kTestSize);
 | 
| +    }
 | 
| +    {
 | 
| +      SCOPED_TRACE("TextDoesntClip Left Side");
 | 
| +#if defined(OS_WIN)
 | 
| +      // TODO(dschuyler): On Windows XP the Unicode test draws to the left edge
 | 
| +      // as if it is ignoring the SetDisplayRect shift by kTestSize.  This
 | 
| +      // appears to be a preexisting issue that wasn't revealed by the prior
 | 
| +      // unit tests.
 | 
| +#elif defined(OS_MACOSX)
 | 
| +      // TODO(dschuyler): On Windows (non-XP) and Mac smoothing draws left of
 | 
| +      // text.  his appears to be a preexisting issue that wasn't revealed by
 | 
| +      // the prior unit tests.
 | 
| +      rect_buffer.EnsureSolidRect(SK_ColorWHITE, 0, kTestSize, kTestSize - 1,
 | 
| +                                  string_size.height());
 | 
| +#else
 | 
| +      rect_buffer.EnsureSolidRect(SK_ColorWHITE, 0, kTestSize, kTestSize,
 | 
| +                                  string_size.height());
 | 
| +#endif
 | 
| +    }
 | 
| +    {
 | 
| +      SCOPED_TRACE("TextDoesntClip Right Side");
 | 
| +#if !defined(OS_MACOSX)
 | 
| +      // TODO(dschuyler): On Mac text draws to right of GetStringSize.  This
 | 
| +      // appears to be a preexisting issue that wasn't revealed by the prior
 | 
| +      // unit tests.
 | 
| +      rect_buffer.EnsureSolidRect(SK_ColorWHITE,
 | 
| +                                  kTestSize + string_size.width(), kTestSize,
 | 
| +                                  kTestSize, string_size.height());
 | 
| +#endif
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
|  
 | 
| -    for (int y = 0; y < kCanvasSize.height(); ++y) {
 | 
| -      // Allow one column of anti-aliased pixels past the expected width.
 | 
| -      SkColor color = buffer[width + y * kCanvasSize.width()];
 | 
| -      EXPECT_LT(220U, color_utils::GetLuminanceForColor(color)) << string;
 | 
| -      for (int x = 1; x < kTestWidth; ++x) {
 | 
| -        color = buffer[width + x + y * kCanvasSize.width()];
 | 
| -        EXPECT_EQ(SK_ColorWHITE, color) << string;
 | 
| -      }
 | 
| +// Ensure that the text will clip to the display rect. Draws to a canvas and
 | 
| +// checks whether any pixel beyond the bounding rectangle is colored.
 | 
| +TEST_F(RenderTextTest, TextDoesClip) {
 | 
| +  const wchar_t* kTestStrings[] = {L"TEST", L"W", L"WWWW", L"gAXAXWWWW"};
 | 
| +  const Size kCanvasSize(300, 50);
 | 
| +  const int kTestSize = 10;
 | 
| +
 | 
| +  skia::RefPtr<SkSurface> surface = skia::AdoptRef(
 | 
| +      SkSurface::NewRasterN32Premul(kCanvasSize.width(), kCanvasSize.height()));
 | 
| +  scoped_ptr<Canvas> canvas(
 | 
| +      Canvas::CreateCanvasWithoutScaling(surface->getCanvas(), 1.0f));
 | 
| +  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
 | 
| +  render_text->SetHorizontalAlignment(ALIGN_LEFT);
 | 
| +  render_text->SetColor(SK_ColorBLACK);
 | 
| +
 | 
| +  for (auto string : kTestStrings) {
 | 
| +    surface->getCanvas()->clear(SK_ColorWHITE);
 | 
| +    render_text->SetText(WideToUTF16(string));
 | 
| +    const Size string_size = render_text->GetStringSize();
 | 
| +    int fake_width = string_size.width() / 2;
 | 
| +    int fake_height = string_size.height() / 2;
 | 
| +    render_text->SetDisplayRect(
 | 
| +        Rect(kTestSize, kTestSize, fake_width, fake_height));
 | 
| +    render_text->set_clip_to_display_rect(true);
 | 
| +    render_text->Draw(canvas.get());
 | 
| +    ASSERT_LT(string_size.width() + kTestSize, kCanvasSize.width());
 | 
| +    const uint32* buffer =
 | 
| +        static_cast<const uint32*>(surface->peekPixels(nullptr, nullptr));
 | 
| +    ASSERT_NE(nullptr, buffer);
 | 
| +    TestRectangleBuffer rect_buffer(string, buffer, kCanvasSize.width(),
 | 
| +                                    kCanvasSize.height());
 | 
| +    {
 | 
| +      SCOPED_TRACE("TextDoesClip Top Side");
 | 
| +      rect_buffer.EnsureSolidRect(SK_ColorWHITE, 0, 0, kCanvasSize.width(),
 | 
| +                                  kTestSize);
 | 
| +    }
 | 
| +
 | 
| +    {
 | 
| +      SCOPED_TRACE("TextDoesClip Bottom Side");
 | 
| +      rect_buffer.EnsureSolidRect(SK_ColorWHITE, 0, kTestSize + fake_height,
 | 
| +                                  kCanvasSize.width(), kTestSize);
 | 
| +    }
 | 
| +    {
 | 
| +      SCOPED_TRACE("TextDoesClip Left Side");
 | 
| +      rect_buffer.EnsureSolidRect(SK_ColorWHITE, 0, kTestSize, kTestSize,
 | 
| +                                  fake_height);
 | 
| +    }
 | 
| +    {
 | 
| +      SCOPED_TRACE("TextDoesClip Right Side");
 | 
| +      rect_buffer.EnsureSolidRect(SK_ColorWHITE, kTestSize + fake_width,
 | 
| +                                  kTestSize, kTestSize, fake_height);
 | 
|      }
 | 
|    }
 | 
|  }
 | 
| 
 |