blob: 9ce988029fd690ffe6a2a40699dbde136df21ee4 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h"
#include <unicode/uscript.h>
#include "base/time/time.h"
#include "cc/base/lap_timer.h"
#include "third_party/blink/renderer/platform/fonts/font.h"
#include "third_party/blink/renderer/platform/fonts/font_cache.h"
#include "third_party/blink/renderer/platform/fonts/font_test_utilities.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
#include "third_party/blink/renderer/platform/text/text_break_iterator.h"
#include "third_party/blink/renderer/platform/text/text_run.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
namespace blink {
namespace {
static const int kTimeLimitMillis = 2000;
static const int kWarmupRuns = 5;
static const int kTimeCheckInterval = 10;
struct HarfBuzzShaperCallbackContext {
const HarfBuzzShaper* shaper;
const Font* font;
TextDirection direction;
};
scoped_refptr<ShapeResult> HarfBuzzShaperCallback(void* untyped_context,
unsigned start,
unsigned end) {
HarfBuzzShaperCallbackContext* context =
static_cast<HarfBuzzShaperCallbackContext*>(untyped_context);
return context->shaper->Shape(context->font, context->direction, start, end);
}
LayoutUnit ShapeText(ShapingLineBreaker* breaker,
LayoutUnit available_space,
unsigned string_length) {
unsigned break_offset = 0;
LayoutUnit total_width;
ShapingLineBreaker::Result result;
scoped_refptr<const ShapeResultView> shape_result;
while (break_offset < string_length) {
shape_result = breaker->ShapeLine(break_offset, available_space, &result);
break_offset = result.break_offset;
total_width += shape_result->SnappedWidth();
}
return total_width;
}
} // anonymous namespace
class ShapingLineBreakerPerfTest : public testing::Test {
public:
ShapingLineBreakerPerfTest()
: timer_(kWarmupRuns,
base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
kTimeCheckInterval) {}
void SetUp() override {
font_description.SetComputedSize(12.0);
font = Font(font_description);
font.Update(nullptr);
}
void TearDown() override {}
FontCachePurgePreventer font_cache_purge_preventer;
FontDescription font_description;
Font font;
unsigned start_index = 0;
unsigned num_glyphs = 0;
hb_script_t script = HB_SCRIPT_INVALID;
cc::LapTimer timer_;
};
TEST_F(ShapingLineBreakerPerfTest, ShapeLatinText) {
// "My Brother's Keeper?"
// By William Arthur Dunkerley (John Oxenham)
// In the public domain.
String string(
"\"Am I my brother's keeper?\""
"Yes, of a truth!"
"Thine asking is thine answer."
"That self-condemning cry of Cain"
"Has been the plea of every selfish soul since then,"
"Which hath its brother slain."
"God's word is plain,"
"And doth thy shrinking soul arraign."
""
"Thy brother's keeper?"
"Yea, of a truth thou art!"
"For if not--who?"
"Are ye not both,--both thou and he"
"Of God's great family?"
"How rid thee of thy soul's responsibility?"
"For every ill in all the world"
"Each soul is sponsor and account must bear."
"And He, and he thy brother of despair,"
"Claim, of thy overmuch, their share."
""
"Thou hast had good, and he the strangled days;"
"But now,--the old things pass."
"No longer of thy grace"
"Is he content to live in evil case"
"For the anointing of thy shining face."
"The old things pass.--Beware lest ye pass with them,"
"And your place"
"Become an emptiness!"
""
"Beware! Lest, when the \"Have-nots\" claim,"
"From those who have, their rightful share,"
"Thy borders be swept bare"
"As by the final flame."
"Better to share before than after."
"\"After?\" ... For thee may be no after!"
"Only the howl of mocking laughter"
"At thy belated care. Make no mistake!--"
"\"After\" will be too late."
"When once the \"Have-nots\" claim ... they take."
"\"After!\" ... When that full claim is made,"
"You and your golden gods may all lie dead."
""
"Set now your house in order,"
"Ere it be too late!"
"For, once the storm of hate"
"Be loosed, no man shall stay it till"
"Its thirst has slaked its fill,"
"And you, poor victims of this last \"too late,\""
"Shall in the shadows mourn your lost estate.");
unsigned len = string.length();
LazyLineBreakIterator break_iterator(string, "en-US", LineBreakType::kNormal);
TextDirection direction = TextDirection::kLtr;
HarfBuzzShaper shaper(string);
scoped_refptr<const ShapeResult> reference_result =
shaper.Shape(&font, direction);
HarfBuzzShaperCallbackContext context{&shaper, &font,
reference_result->Direction()};
ShapingLineBreaker reference_breaker(reference_result, &break_iterator,
nullptr, HarfBuzzShaperCallback,
&context);
scoped_refptr<const ShapeResult> line;
LayoutUnit available_width_px(500);
LayoutUnit expected_width =
ShapeText(&reference_breaker, available_width_px, len);
timer_.Reset();
do {
scoped_refptr<const ShapeResult> result = shaper.Shape(&font, direction);
ShapingLineBreaker breaker(result, &break_iterator, nullptr,
HarfBuzzShaperCallback, &context);
LayoutUnit width = ShapeText(&breaker, available_width_px, len);
EXPECT_EQ(expected_width, width);
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
perf_test::PrintResult("ShapingLineBreakerPerfTest", "shape latin text", "",
timer_.LapsPerSecond(), "runs/s", true);
}
} // namespace blink