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

Unified Diff: ui/gfx/render_text_unittest.cc

Issue 2348143003: MacViews: Implement Force Touch/Mac dictionary lookup for Textfields. (Closed)
Patch Set: Call EnsureLayout in GetDecoratedTextForRange. Created 4 years, 2 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 side-by-side diff with in-line comments
Download patch
Index: ui/gfx/render_text_unittest.cc
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc
index e2b37c105430797eb0f3a97556643534f06f8bf3..ffaf22d9e002ebde06153f0278eedd1f58520f14 100644
--- a/ui/gfx/render_text_unittest.cc
+++ b/ui/gfx/render_text_unittest.cc
@@ -28,6 +28,7 @@
#include "ui/gfx/break_list.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_utils.h"
+#include "ui/gfx/decorated_text.h"
#include "ui/gfx/font.h"
#include "ui/gfx/font_names_testing.h"
#include "ui/gfx/geometry/point.h"
@@ -153,6 +154,14 @@ const wchar_t kLtrRtlLtr[] = L"a" L"\x5d1" L"b";
const wchar_t kRtlLtr[] = L"\x5d0\x5d1" L"a";
const wchar_t kRtlLtrRtl[] = L"\x5d0" L"a" L"\x5d1";
+// Bitmasks based on gfx::TextStyle.
+enum {
+ ITALIC_MASK = 1 << ITALIC,
+ STRIKE_MASK = 1 << STRIKE,
+ DIAGONAL_STRIKE_MASK = 1 << DIAGONAL_STRIKE,
+ UNDERLINE_MASK = 1 << UNDERLINE,
+};
+
// Checks whether |range| contains |index|. This is not the same as calling
// range.Contains(Range(index)), which returns true if |index| == |range.end()|.
bool IndexInRange(const Range& range, size_t index) {
@@ -207,6 +216,73 @@ void RunMoveCursorLeftRightTest(RenderText* render_text,
EXPECT_EQ(expected.back(), render_text->selection_model());
}
+// Creates a RangedAttribute instance for a single character range at the
+// given |index| with the given |weight| and |style_mask|. |index| is the
+// index of the character in the DecoratedText instance and |font_index| is
+// used to retrieve the font used from |font_spans|.
+DecoratedText::RangedAttribute CreateRangedAttribute(
+ const std::vector<RenderText::FontSpan>& font_spans,
+ int index,
+ int font_index,
+ Font::Weight weight,
+ int style_mask) {
+ const auto iter =
+ std::find_if(font_spans.begin(), font_spans.end(),
+ [font_index](const RenderText::FontSpan& span) {
+ return IndexInRange(span.second, font_index);
+ });
+ DCHECK(font_spans.end() != iter);
+ const Font& font = iter->first;
+
+ int font_style = Font::NORMAL;
+ if (style_mask & ITALIC_MASK)
+ font_style |= Font::ITALIC;
+ if (style_mask & UNDERLINE_MASK)
+ font_style |= Font::UNDERLINE;
+
+ const Font font_with_style = font.Derive(0, font_style, weight);
+ DecoratedText::RangedAttribute attributes(gfx::Range(index, index + 1),
tapted 2016/10/05 06:20:54 nit: no gfx::, more below (gfx::Rect, gfx::Range,
karandeepb 2016/10/06 01:07:05 Done.
+ font_with_style);
+ attributes.strike = style_mask & STRIKE_MASK;
+ attributes.diagonal_strike = style_mask & DIAGONAL_STRIKE_MASK;
+ return attributes;
+}
+
+// Verifies the given DecoratedText instances are equal by comparing the
+// respective strings and attributes for each index. Note, corresponding
+// ranged attributes from |expected| and |actual| can't be compared since the
+// partition of |actual| into RangedAttributes will depend on the text runs
+// generated.
+void VerifyDecoratedWordsAreEqual(const DecoratedText& expected,
+ const DecoratedText& actual) {
+ ASSERT_EQ(expected.text, actual.text);
+
+ // Compare attributes for each index.
+ for (size_t i = 0; i < expected.text.length(); i++) {
+ SCOPED_TRACE(base::StringPrintf("Comparing index[%" PRIuS "]", i));
+ auto find_attribute_func = [i](const DecoratedText::RangedAttribute& attr) {
+ return IndexInRange(attr.range, i);
+ };
+ const auto expected_attr =
+ std::find_if(expected.attributes.begin(), expected.attributes.end(),
+ find_attribute_func);
+ const auto actual_attr =
+ std::find_if(actual.attributes.begin(), actual.attributes.end(),
+ find_attribute_func);
+ ASSERT_NE(expected.attributes.end(), expected_attr);
+ ASSERT_NE(actual.attributes.end(), actual_attr);
+
+ EXPECT_EQ(expected_attr->strike, actual_attr->strike);
+ EXPECT_EQ(expected_attr->diagonal_strike, actual_attr->diagonal_strike);
+ EXPECT_EQ(expected_attr->font.GetFontName(),
+ actual_attr->font.GetFontName());
+ EXPECT_EQ(expected_attr->font.GetFontSize(),
+ actual_attr->font.GetFontSize());
+ EXPECT_EQ(expected_attr->font.GetWeight(), actual_attr->font.GetWeight());
+ EXPECT_EQ(expected_attr->font.GetStyle(), actual_attr->font.GetStyle());
+ }
+}
+
// The class which records the drawing operations so that the test case can
// verify where exactly the glyphs are drawn.
class TestSkiaTextRenderer : public internal::SkiaTextRenderer {
@@ -3786,6 +3862,189 @@ TEST_P(RenderTextTest, SubpixelRenderingSuppressed) {
EXPECT_FALSE(GetRendererPaint().isLCDRenderText());
}
+// Verify GetDecoratedWordAtPoint returns the correct baseline point and
+// decorated word for an LTR string.
+TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_LTR) {
+ const base::string16 ltr = ASCIIToUTF16(" ab c ");
+ const int kWordOneStartIndex = 2;
+ const int kWordTwoStartIndex = 6;
+
+ RenderText* render_text = GetRenderText();
+ render_text->SetDisplayRect(gfx::Rect(100, 30));
+ render_text->SetText(ltr);
+ render_text->ApplyWeight(Font::Weight::SEMIBOLD, gfx::Range(0, 3));
+ render_text->ApplyStyle(UNDERLINE, true, gfx::Range(1, 5));
+ render_text->ApplyStyle(ITALIC, true, gfx::Range(3, 8));
+ render_text->ApplyStyle(DIAGONAL_STRIKE, true, gfx::Range(5, 7));
+ render_text->ApplyStyle(STRIKE, true, gfx::Range(1, 7));
+
+ const std::vector<RenderText::FontSpan> font_spans =
+ render_text->GetFontSpansForTesting();
+
+ // Create expected decorated text instances.
+ DecoratedText expected_word_1;
+ expected_word_1.text = ASCIIToUTF16("ab");
+ // Attributes for the characters 'a' and 'b' at logical indices 2 and 3
+ // respectively.
+ expected_word_1.attributes.push_back(CreateRangedAttribute(
+ font_spans, 0, kWordOneStartIndex, Font::Weight::SEMIBOLD,
+ UNDERLINE_MASK | STRIKE_MASK));
+ expected_word_1.attributes.push_back(CreateRangedAttribute(
+ font_spans, 1, kWordOneStartIndex + 1, Font::Weight::NORMAL,
+ UNDERLINE_MASK | ITALIC_MASK | STRIKE_MASK));
+ const Rect left_glyph_word_1 = render_text->GetCursorBounds(
+ SelectionModel(kWordOneStartIndex, CURSOR_FORWARD), false);
+
+ DecoratedText expected_word_2;
+ expected_word_2.text = ASCIIToUTF16("c");
+ // Attributes for character 'c' at logical index |kWordTwoStartIndex|.
+ expected_word_2.attributes.push_back(CreateRangedAttribute(
+ font_spans, 0, kWordTwoStartIndex, Font::Weight::NORMAL,
+ ITALIC_MASK | DIAGONAL_STRIKE_MASK | STRIKE_MASK));
+ const Rect left_glyph_word_2 = render_text->GetCursorBounds(
+ SelectionModel(kWordTwoStartIndex, CURSOR_FORWARD), false);
+
+ // Query outside the text bounds.
+ DecoratedText decorated_word;
+ Point baseline_point;
+ EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(
+ gfx::Point(-5, 5), &decorated_word, &baseline_point));
+ VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word);
tapted 2016/10/05 06:20:54 nit: wrapping calls to VerifyDecoratedWordsAreEqua
karandeepb 2016/10/06 01:07:05 But that'll only work for a fatal failure right? H
tapted 2016/10/06 02:03:19 Acknowledged. Yeah - it does look like gtest is mi
+ EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point));
+
+ EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(
+ gfx::Point(105, 5), &decorated_word, &baseline_point));
+ VerifyDecoratedWordsAreEqual(expected_word_2, decorated_word);
+ EXPECT_TRUE(left_glyph_word_2.Contains(baseline_point));
+
+ for (size_t i = 0; i < render_text->text().length(); i++) {
+ SCOPED_TRACE(base::StringPrintf("Case[%" PRIuS "]", i));
+ // Query the decorated word using the origin of the i'th glyph's bounds.
+ const Point query =
+ render_text->GetCursorBounds(SelectionModel(i, CURSOR_FORWARD), false)
+ .origin();
+
+ EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(query, &decorated_word,
+ &baseline_point));
+
+ if (i < kWordTwoStartIndex) {
+ VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word);
+ EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point));
+ } else {
+ VerifyDecoratedWordsAreEqual(expected_word_2, decorated_word);
+ EXPECT_TRUE(left_glyph_word_2.Contains(baseline_point));
+ }
+ }
+}
+
+// Verify GetDecoratedWordAtPoint returns the correct baseline point and
+// decorated word for an RTL string.
+TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_RTL) {
+ const base::string16 rtl = WideToUTF16(
+ L" "
+ L"\x0634\x0632"
+ L" "
+ L"\x0634");
+ const int kWordOneStartIndex = 1;
+ const int kWordTwoStartIndex = 5;
+
+ RenderText* render_text = GetRenderText();
+ render_text->SetDisplayRect(gfx::Rect(100, 30));
+ render_text->SetText(rtl);
+ render_text->ApplyWeight(Font::Weight::SEMIBOLD, gfx::Range(2, 3));
+ render_text->ApplyStyle(UNDERLINE, true, gfx::Range(3, 6));
+ render_text->ApplyStyle(ITALIC, true, gfx::Range(0, 3));
+ render_text->ApplyStyle(DIAGONAL_STRIKE, true, gfx::Range(0, 2));
+ render_text->ApplyStyle(STRIKE, true, gfx::Range(2, 5));
+
+ const std::vector<RenderText::FontSpan> font_spans =
+ render_text->GetFontSpansForTesting();
+
+ // Create expected decorated text instance.
+ DecoratedText expected_word_1;
+ expected_word_1.text = WideToUTF16(L"\x0634\x0632");
+ // Attributes for characters at logical indices 1 and 2.
+ expected_word_1.attributes.push_back(CreateRangedAttribute(
+ font_spans, 0, kWordOneStartIndex, Font::Weight::NORMAL,
+ ITALIC_MASK | DIAGONAL_STRIKE_MASK));
+ expected_word_1.attributes.push_back(
+ CreateRangedAttribute(font_spans, 1, kWordOneStartIndex + 1,
+ Font::Weight::SEMIBOLD, ITALIC_MASK | STRIKE_MASK));
+ // The leftmost glyph is the one at logical index 2.
+ const Rect left_glyph_word_1 = render_text->GetCursorBounds(
+ SelectionModel(kWordOneStartIndex + 1, CURSOR_FORWARD), false);
+
+ DecoratedText expected_word_2;
+ expected_word_2.text = WideToUTF16(L"\x0634");
+ // Attributes for character at logical index |kWordTwoStartIndex|.
+ expected_word_2.attributes.push_back(CreateRangedAttribute(
+ font_spans, 0, kWordTwoStartIndex, Font::Weight::NORMAL, UNDERLINE_MASK));
+ const Rect left_glyph_word_2 = render_text->GetCursorBounds(
+ SelectionModel(kWordTwoStartIndex, CURSOR_FORWARD), false);
+
+ // Query outside the text bounds.
+ DecoratedText decorated_word;
+ Point baseline_point;
+ EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(
+ gfx::Point(-5, 5), &decorated_word, &baseline_point));
+ VerifyDecoratedWordsAreEqual(expected_word_2, decorated_word);
+ EXPECT_TRUE(left_glyph_word_2.Contains(baseline_point));
+
+ EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(
+ gfx::Point(105, 5), &decorated_word, &baseline_point));
+ VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word);
+ EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point));
+
+ for (size_t i = 0; i < render_text->text().length(); i++) {
+ SCOPED_TRACE(base::StringPrintf("Case[%" PRIuS "]", i));
+
+ // Query the decorated word using the top right point of the i'th glyph's
+ // bounds.
+ const Point query =
+ render_text->GetCursorBounds(SelectionModel(i, CURSOR_FORWARD), false)
+ .top_right();
+
+ EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(query, &decorated_word,
+ &baseline_point));
+ if (i < kWordTwoStartIndex) {
+ VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word);
+ EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point));
+ } else {
+ VerifyDecoratedWordsAreEqual(expected_word_2, decorated_word);
+ EXPECT_TRUE(left_glyph_word_2.Contains(baseline_point));
+ }
+ }
+}
+
+// Verify the boolean return value of GetDecoratedWordAtPoint.
+TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_Return) {
tapted 2016/10/05 06:20:54 can this be a RenderTextTest already, since it doe
karandeepb 2016/10/06 01:07:05 For an RTM instance, GetDecoratedWordAtPoint will
tapted 2016/10/06 02:03:19 Acknowledged.
+ RenderText* render_text = GetRenderText();
+ render_text->SetText(ASCIIToUTF16("..."));
+
+ DecoratedText decorated_word;
+ Point baseline_point;
+
+ // False should be returned, when the text does not contain any word.
+ Point query =
+ render_text->GetCursorBounds(SelectionModel(0, CURSOR_FORWARD), false)
+ .origin();
+ EXPECT_FALSE(render_text->GetDecoratedWordAtPoint(query, &decorated_word,
+ &baseline_point));
+
+ render_text->SetText(ASCIIToUTF16("abc"));
+ query = render_text->GetCursorBounds(SelectionModel(0, CURSOR_FORWARD), false)
+ .origin();
+ EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(query, &decorated_word,
+ &baseline_point));
+
+ // False should be returned for obscured text.
+ render_text->SetObscured(true);
+ query = render_text->GetCursorBounds(SelectionModel(0, CURSOR_FORWARD), false)
+ .origin();
+ EXPECT_FALSE(render_text->GetDecoratedWordAtPoint(query, &decorated_word,
+ &baseline_point));
+}
+
// Prefix for test instantiations intentionally left blank since each test
// fixture class has a single parameterization.
#if defined(OS_MACOSX)

Powered by Google App Engine
This is Rietveld 408576698