1 // Copyright (c) 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/strings/string_number_conversions.h"
6 #include "base/time/time.h"
7 #include "base/timer/lap_timer.h"
8 #include "build/build_config.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "testing/perf/perf_result_reporter.h"
11 #include "third_party/blink/renderer/platform/fonts/font.h"
12 #include "third_party/blink/renderer/platform/fonts/font_description.h"
13 #include "third_party/blink/renderer/platform/testing/font_test_helpers.h"
14 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
15 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
16 
17 using blink::test::CreateTestFont;
18 
19 namespace blink {
20 
21 static const int kTimeLimitMillis = 3000;
22 static const int kWarmupRuns = 10000;
23 static const int kTimeCheckInterval = 1000000;
24 
25 namespace {
26 
27 constexpr char kMetricPrefixOffsetForPosition[] = "OffsetForPosition.";
28 constexpr char kMetricPrefixCharacterRange[] = "CharacterRange.";
29 constexpr char kMetricThroughput[] = "throughput";
30 
31 }  // namespace
32 
33 class ShapeResultPerfTest {
34   USING_FAST_MALLOC(ShapeResultPerfTest);
35 
36  public:
37   enum FontName {
38     ahem,
39     amiri,
40     megalopolis,
41     roboto,
42   };
43 
ShapeResultPerfTest()44   ShapeResultPerfTest()
45       : timer(kWarmupRuns,
46               base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
47               kTimeCheckInterval) {}
48 
49  protected:
SetupFont(FontName font_name,const String & text,bool ltr)50   TextRun SetupFont(FontName font_name, const String& text, bool ltr) {
51     FontDescription::VariantLigatures ligatures(
52         FontDescription::kEnabledLigaturesState);
53     font = CreateTestFont(
54         "TestFont",
55         test::PlatformTestDataPath(font_path.find(font_name)->value), 100,
56         &ligatures);
57 
58     return TextRun(
59         text, /* xpos */ 0, /* expansion */ 0,
60         TextRun::kAllowTrailingExpansion | TextRun::kForbidLeadingExpansion,
61         ltr ? TextDirection::kLtr : TextDirection::kRtl, false);
62   }
63 
ReportResult(const std::string & metric_prefix,const std::string & story_prefix)64   void ReportResult(const std::string& metric_prefix,
65                     const std::string& story_prefix) {
66     std::string story = story_prefix + "_" + param_string;
67     perf_test::PerfResultReporter reporter(metric_prefix, story);
68     reporter.RegisterImportantMetric(kMetricThroughput, "runs/s");
69     reporter.AddResult(kMetricThroughput, timer.LapsPerSecond());
70   }
71 
72   Font font;
73 
74   HashMap<FontName, String, WTF::IntHash<FontName>> font_path = {
75       {ahem, "Ahem.woff"},
76       {amiri, "third_party/Amiri/amiri_arabic.woff2"},
77       {megalopolis, "third_party/MEgalopolis/MEgalopolisExtra.woff"},
78       {roboto, "third_party/Roboto/roboto-regular.woff2"},
79   };
80 
81   base::LapTimer timer;
82   std::string param_string;
83 };
84 
85 class OffsetForPositionPerfTest : public ShapeResultPerfTest,
86                                   public testing::TestWithParam<float> {
87  public:
OffsetForPosition(TextRun & run,IncludePartialGlyphsOption partial,BreakGlyphsOption breakopt)88   void OffsetForPosition(TextRun& run,
89                          IncludePartialGlyphsOption partial,
90                          BreakGlyphsOption breakopt) {
91     timer.Reset();
92     float position = GetParam();
93     param_string = base::NumberToString(position);
94     do {
95       font.OffsetForPosition(run, position, partial, breakopt);
96       timer.NextLap();
97     } while (!timer.HasTimeLimitExpired());
98   }
99 
100  protected:
ReportResult(const std::string & story_prefix)101   void ReportResult(const std::string& story_prefix) {
102     ShapeResultPerfTest::ReportResult(kMetricPrefixOffsetForPosition,
103                                       story_prefix);
104   }
105 };
106 
107 class CharacterRangePerfTest : public ShapeResultPerfTest,
108                                public testing::TestWithParam<int> {
109  public:
GetCharacter(TextRun & run)110   void GetCharacter(TextRun& run) {
111     timer.Reset();
112     int endpos = GetParam();
113     param_string = base::NumberToString(endpos);
114     do {
115       font.SelectionRectForText(run, FloatPoint(), 100, 0, endpos);
116       timer.NextLap();
117     } while (!timer.HasTimeLimitExpired());
118   }
119 
120  protected:
ReportResult(const std::string & story_prefix)121   void ReportResult(const std::string& story_prefix) {
122     ShapeResultPerfTest::ReportResult(kMetricPrefixCharacterRange,
123                                       story_prefix);
124   }
125 };
126 
TEST_P(OffsetForPositionPerfTest,LTROffsetForPositionFullBreak)127 TEST_P(OffsetForPositionPerfTest, LTROffsetForPositionFullBreak) {
128   TextRun run = SetupFont(ahem, "FURACOLO", true);
129   OffsetForPosition(run, OnlyFullGlyphs, BreakGlyphs);
130   ReportResult("LTR_full_break");
131 }
132 
TEST_P(OffsetForPositionPerfTest,LTROffsetForPositionFullDontBreak)133 TEST_P(OffsetForPositionPerfTest, LTROffsetForPositionFullDontBreak) {
134   TextRun run = SetupFont(ahem, "FURACOLO", true);
135   OffsetForPosition(run, OnlyFullGlyphs, DontBreakGlyphs);
136   ReportResult("LTR_full");
137 }
138 
TEST_P(OffsetForPositionPerfTest,LTROffsetForPositionIncludePartialBreak)139 TEST_P(OffsetForPositionPerfTest, LTROffsetForPositionIncludePartialBreak) {
140   TextRun run = SetupFont(ahem, "FURACOLO", true);
141   OffsetForPosition(run, IncludePartialGlyphs, BreakGlyphs);
142   ReportResult("LTR_partial_break");
143 }
144 
TEST_P(OffsetForPositionPerfTest,LTROffsetForPositionIncludePartialDontBreak)145 TEST_P(OffsetForPositionPerfTest, LTROffsetForPositionIncludePartialDontBreak) {
146   TextRun run = SetupFont(ahem, "FURACOLO", true);
147   OffsetForPosition(run, IncludePartialGlyphs, DontBreakGlyphs);
148   ReportResult("LTR_partial");
149 }
150 
TEST_P(OffsetForPositionPerfTest,RTLOffsetForPositionFullBreak)151 TEST_P(OffsetForPositionPerfTest, RTLOffsetForPositionFullBreak) {
152   TextRun run = SetupFont(ahem, "OLOCARUF", false);
153   OffsetForPosition(run, OnlyFullGlyphs, BreakGlyphs);
154   ReportResult("RTL_full_break");
155 }
156 
TEST_P(OffsetForPositionPerfTest,RTLOffsetForPositionFullDontBreak)157 TEST_P(OffsetForPositionPerfTest, RTLOffsetForPositionFullDontBreak) {
158   TextRun run = SetupFont(ahem, "OLOCARUF", false);
159   OffsetForPosition(run, OnlyFullGlyphs, DontBreakGlyphs);
160   ReportResult("RTL_full");
161 }
162 
TEST_P(OffsetForPositionPerfTest,RTLOffsetForPositionIncludePartialBreak)163 TEST_P(OffsetForPositionPerfTest, RTLOffsetForPositionIncludePartialBreak) {
164   TextRun run = SetupFont(ahem, "OLOCARUF", false);
165   OffsetForPosition(run, IncludePartialGlyphs, BreakGlyphs);
166   ReportResult("RTL_partial_break");
167 }
168 
TEST_P(OffsetForPositionPerfTest,RTLOffsetForPositionIncludePartialDontBreak)169 TEST_P(OffsetForPositionPerfTest, RTLOffsetForPositionIncludePartialDontBreak) {
170   TextRun run = SetupFont(ahem, "OLOCARUF", false);
171   OffsetForPosition(run, IncludePartialGlyphs, DontBreakGlyphs);
172   ReportResult("RTL_partial");
173 }
174 
175 INSTANTIATE_TEST_SUITE_P(OffsetForPosition,
176                          OffsetForPositionPerfTest,
177                          testing::Values(0, 10, 60, 100, 200, 350));
178 
TEST_P(CharacterRangePerfTest,LTRCharacterForPosition)179 TEST_P(CharacterRangePerfTest, LTRCharacterForPosition) {
180   TextRun run = SetupFont(ahem, "FURACOLO", true);
181   GetCharacter(run);
182   ReportResult("LTR");
183 }
184 
TEST_P(CharacterRangePerfTest,RTLCharacterForPosition)185 TEST_P(CharacterRangePerfTest, RTLCharacterForPosition) {
186   TextRun run = SetupFont(ahem, "OLOCARUF", false);
187   GetCharacter(run);
188   ReportResult("RTL");
189 }
190 
191 INSTANTIATE_TEST_SUITE_P(CharacterRange,
192                          CharacterRangePerfTest,
193                          testing::Values(0, 1, 2, 4, 8));
194 
195 }  // namespace blink
196