Commit fc5c8f98 authored by eae's avatar eae Committed by Commit bot

Move blobalizer implementation to ShapeResultBloberizer

Move blobalizer logic out of CachingWordShaper and ShapeResultBuffer and
into ShapeResultBloberizer, thereby containing all blobalizer logic in a
single file and removing dependencies on it from the results and shaper.

This will also help in reusing much of the text blob logic for LayoutNG.

R=drott@chromium.org
TEST=Source/platform/fonts/shaping/ShapeResultBloberizerTest.cpp

Review-Url: https://codereview.chromium.org/2835103002
Cr-Commit-Position: refs/heads/master@{#466891}
parent e5ad8bea
......@@ -142,7 +142,10 @@ bool Font::DrawText(PaintCanvas* canvas,
return false;
ShapeResultBloberizer bloberizer(*this, device_scale_factor);
CachingWordShaper(*this).FillGlyphs(run_info, bloberizer);
CachingWordShaper word_shaper(*this);
ShapeResultBuffer buffer;
word_shaper.FillResultBuffer(run_info, &buffer);
bloberizer.FillGlyphs(run_info, buffer);
DrawBlobs(canvas, flags, bloberizer.Blobs(), point);
return true;
}
......@@ -178,6 +181,7 @@ bool Font::DrawBidiText(PaintCanvas* canvas,
FloatPoint curr_point = point;
BidiCharacterRun* bidi_run = bidi_runs.FirstRun();
CachingWordShaper word_shaper(*this);
while (bidi_run) {
TextRun subrun =
run.SubRun(bidi_run->Start(), bidi_run->Stop() - bidi_run->Start());
......@@ -189,8 +193,9 @@ bool Font::DrawBidiText(PaintCanvas* canvas,
subrun_info.bounds = run_info.bounds;
ShapeResultBloberizer bloberizer(*this, device_scale_factor);
float run_width =
CachingWordShaper(*this).FillGlyphs(subrun_info, bloberizer);
ShapeResultBuffer buffer;
word_shaper.FillResultBuffer(subrun_info, &buffer);
float run_width = bloberizer.FillGlyphs(subrun_info, buffer);
DrawBlobs(canvas, flags, bloberizer.Blobs(), curr_point);
bidi_run = bidi_run->Next();
......@@ -217,8 +222,10 @@ void Font::DrawEmphasisMarks(PaintCanvas* canvas,
return;
ShapeResultBloberizer bloberizer(*this, device_scale_factor);
CachingWordShaper(*this).FillTextEmphasisGlyphs(run_info, emphasis_glyph_data,
bloberizer);
CachingWordShaper word_shaper(*this);
ShapeResultBuffer buffer;
word_shaper.FillResultBuffer(run_info, &buffer);
bloberizer.FillTextEmphasisGlyphs(run_info, emphasis_glyph_data, buffer);
DrawBlobs(canvas, flags, bloberizer.Blobs(), point);
}
......@@ -267,7 +274,12 @@ void Font::GetTextIntercepts(const TextRunPaintInfo& run_info,
ShapeResultBloberizer bloberizer(
*this, device_scale_factor, ShapeResultBloberizer::Type::kTextIntercepts);
CachingWordShaper(*this).FillGlyphs(run_info, bloberizer);
CachingWordShaper word_shaper(*this);
ShapeResultBuffer buffer;
word_shaper.FillResultBuffer(run_info, &buffer);
bloberizer.FillGlyphs(run_info, buffer);
const auto& blobs = bloberizer.Blobs();
// Get the number of intervals, without copying the actual values by
......
......@@ -88,22 +88,10 @@ int CachingWordShaper::OffsetForPosition(const TextRun& run,
return buffer.OffsetForPosition(run, target_x, include_partial_glyphs);
}
float CachingWordShaper::FillGlyphs(const TextRunPaintInfo& run_info,
ShapeResultBloberizer& bloberizer) {
ShapeResultBuffer buffer;
ShapeResultsForRun(GetShapeCache(), &font_, run_info.run, &buffer);
return buffer.FillGlyphs(run_info, bloberizer);
}
void CachingWordShaper::FillTextEmphasisGlyphs(
const TextRunPaintInfo& run_info,
const GlyphData& emphasis_data,
ShapeResultBloberizer& bloberizer) {
ShapeResultBuffer buffer;
ShapeResultsForRun(GetShapeCache(), &font_, run_info.run, &buffer);
buffer.FillTextEmphasisGlyphs(run_info, emphasis_data, bloberizer);
void CachingWordShaper::FillResultBuffer(const TextRunPaintInfo& run_info,
ShapeResultBuffer* buffer) {
DCHECK(buffer);
ShapeResultsForRun(GetShapeCache(), &font_, run_info.run, buffer);
}
CharacterRange CachingWordShaper::GetCharacterRange(const TextRun& run,
......
......@@ -39,7 +39,6 @@ struct CharacterRange;
class Font;
class ShapeCache;
class SimpleFontData;
class ShapeResultBloberizer;
struct GlyphData;
class PLATFORM_EXPORT CachingWordShaper final {
......@@ -57,10 +56,7 @@ class PLATFORM_EXPORT CachingWordShaper final {
float target_x,
bool include_partial_glyphs);
float FillGlyphs(const TextRunPaintInfo&, ShapeResultBloberizer&);
void FillTextEmphasisGlyphs(const TextRunPaintInfo&,
const GlyphData& emphasis_data,
ShapeResultBloberizer&);
void FillResultBuffer(const TextRunPaintInfo&, ShapeResultBuffer*);
CharacterRange GetCharacterRange(const TextRun&, unsigned from, unsigned to);
Vector<CharacterRange> IndividualCharacterRanges(const TextRun&);
......
......@@ -5,7 +5,6 @@
#include "platform/fonts/shaping/CachingWordShaper.h"
#include <memory>
#include "platform/fonts/CharacterRange.h"
#include "platform/fonts/FontCache.h"
#include "platform/fonts/shaping/CachingWordShapeIterator.h"
#include "platform/fonts/shaping/ShapeResultTestInfo.h"
......@@ -108,89 +107,6 @@ TEST_F(CachingWordShaperTest, CommonAccentLeftToRightByWord) {
ASSERT_FALSE(iterator.Next(&result));
}
// Tests that filling a glyph buffer for a specific range returns the same
// results when shaping word by word as when shaping the full run in one go.
TEST_F(CachingWordShaperTest, CommonAccentLeftToRightFillGlyphBuffer) {
// "/. ." with an accent mark over the first dot.
const UChar kStr[] = {0x2F, 0x301, 0x2E, 0x20, 0x2E, 0x0};
TextRun text_run(kStr, 5);
TextRunPaintInfo run_info(text_run);
run_info.to = 3;
ShapeResultBloberizer bloberizer(font, 1);
CachingWordShaper(font).FillGlyphs(run_info, bloberizer);
Font reference_font(font_description);
reference_font.Update(nullptr);
reference_font.SetCanShapeWordByWordForTesting(false);
ShapeResultBloberizer reference_bloberizer(reference_font, 1);
CachingWordShaper(reference_font).FillGlyphs(run_info, reference_bloberizer);
const auto& glyphs =
ShapeResultBloberizerTestInfo::PendingRunGlyphs(bloberizer);
ASSERT_EQ(glyphs.size(), 3ul);
const auto reference_glyphs =
ShapeResultBloberizerTestInfo::PendingRunGlyphs(reference_bloberizer);
ASSERT_EQ(reference_glyphs.size(), 3ul);
EXPECT_EQ(reference_glyphs[0], glyphs[0]);
EXPECT_EQ(reference_glyphs[1], glyphs[1]);
EXPECT_EQ(reference_glyphs[2], glyphs[2]);
}
// Tests that filling a glyph buffer for a specific range returns the same
// results when shaping word by word as when shaping the full run in one go.
TEST_F(CachingWordShaperTest, CommonAccentRightToLeftFillGlyphBuffer) {
// "[] []" with an accent mark over the last square bracket.
const UChar kStr[] = {0x5B, 0x5D, 0x20, 0x5B, 0x301, 0x5D, 0x0};
TextRun text_run(kStr, 6);
text_run.SetDirection(TextDirection::kRtl);
TextRunPaintInfo run_info(text_run);
run_info.from = 1;
ShapeResultBloberizer bloberizer(font, 1);
CachingWordShaper(font).FillGlyphs(run_info, bloberizer);
Font reference_font(font_description);
reference_font.Update(nullptr);
reference_font.SetCanShapeWordByWordForTesting(false);
ShapeResultBloberizer reference_bloberizer(reference_font, 1);
CachingWordShaper(reference_font).FillGlyphs(run_info, reference_bloberizer);
const auto& glyphs =
ShapeResultBloberizerTestInfo::PendingRunGlyphs(bloberizer);
ASSERT_EQ(5u, glyphs.size());
const auto reference_glyphs =
ShapeResultBloberizerTestInfo::PendingRunGlyphs(reference_bloberizer);
ASSERT_EQ(5u, reference_glyphs.size());
EXPECT_EQ(reference_glyphs[0], glyphs[0]);
EXPECT_EQ(reference_glyphs[1], glyphs[1]);
EXPECT_EQ(reference_glyphs[2], glyphs[2]);
EXPECT_EQ(reference_glyphs[3], glyphs[3]);
EXPECT_EQ(reference_glyphs[4], glyphs[4]);
}
// Tests that runs with zero glyphs (the ZWJ non-printable character in this
// case) are handled correctly. This test passes if it does not cause a crash.
TEST_F(CachingWordShaperTest, SubRunWithZeroGlyphs) {
// "Foo &zwnj; bar"
const UChar kStr[] = {0x46, 0x6F, 0x6F, 0x20, 0x200C,
0x20, 0x62, 0x61, 0x71, 0x0};
TextRun text_run(kStr, 9);
CachingWordShaper shaper(font);
FloatRect glyph_bounds;
ASSERT_GT(shaper.Width(text_run, nullptr, &glyph_bounds), 0);
ShapeResultBloberizer bloberizer(font, 1);
TextRunPaintInfo run_info(text_run);
run_info.to = 8;
shaper.FillGlyphs(run_info, bloberizer);
shaper.GetCharacterRange(text_run, 0, 8);
}
TEST_F(CachingWordShaperTest, SegmentCJKByCharacter) {
const UChar kStr[] = {0x56FD, 0x56FD, // CJK Unified Ideograph
'a', 'b',
......
......@@ -126,6 +126,7 @@ class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> {
friend class HarfBuzzShaper;
friend class ShapeResultBuffer;
friend class ShapeResultBloberizer;
};
} // namespace blink
......
......@@ -8,6 +8,7 @@
#include "platform/PlatformExport.h"
#include "platform/fonts/Glyph.h"
#include "platform/fonts/SimpleFontData.h"
#include "platform/fonts/shaping/ShapeResultBuffer.h"
#include "platform/geometry/FloatPoint.h"
#include "platform/wtf/Allocator.h"
#include "platform/wtf/Vector.h"
......@@ -30,6 +31,11 @@ class PLATFORM_EXPORT ShapeResultBloberizer {
Type GetType() const { return type_; }
float FillGlyphs(const TextRunPaintInfo&, const ShapeResultBuffer&);
void FillTextEmphasisGlyphs(const TextRunPaintInfo&,
const GlyphData& emphasis_data,
const ShapeResultBuffer&);
void Add(Glyph glyph, const SimpleFontData* font_data, float h_offset) {
// cannot mix x-only/xy offsets
DCHECK(!HasPendingVerticalOffsets());
......@@ -81,6 +87,17 @@ class PLATFORM_EXPORT ShapeResultBloberizer {
private:
friend class ShapeResultBloberizerTestInfo;
float FillGlyphsForResult(const ShapeResult&,
const TextRunPaintInfo&,
float initial_advance,
unsigned run_offset);
float FillFastHorizontalGlyphs(const ShapeResultBuffer&, const TextRun&);
float FillTextEmphasisGlyphsForRun(const ShapeResult::RunInfo*,
const TextRunPaintInfo&,
const GlyphData& emphasis_data,
float initial_advance,
unsigned run_offset);
void CommitPendingRun();
void CommitPendingBlob();
......
......@@ -4,9 +4,11 @@
#include "platform/fonts/shaping/ShapeResultBloberizer.h"
#include "platform/fonts/CharacterRange.h"
#include "platform/fonts/Font.h"
#include "platform/fonts/SimpleFontData.h"
#include "platform/fonts/opentype/OpenTypeVerticalData.h"
#include "platform/fonts/shaping/CachingWordShaper.h"
#include "platform/fonts/shaping/ShapeResultTestInfo.h"
#include "platform/wtf/Optional.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -36,9 +38,34 @@ class TestSimpleFontData : public SimpleFontData {
: SimpleFontData(platform_data, std::move(vertical_data)) {}
};
class ShapeResultBloberizerTest : public ::testing::Test {
protected:
void SetUp() override {
font_description.SetComputedSize(12.0);
font_description.SetLocale(LayoutLocale::Get("en"));
ASSERT_EQ(USCRIPT_LATIN, font_description.GetScript());
font_description.SetGenericFamily(FontDescription::kStandardFamily);
font = Font(font_description);
font.Update(nullptr);
ASSERT_TRUE(font.CanShapeWordByWord());
fallback_fonts = nullptr;
cache = WTF::MakeUnique<ShapeCache>();
}
FontCachePurgePreventer font_cache_purge_preventer;
FontDescription font_description;
Font font;
std::unique_ptr<ShapeCache> cache;
HashSet<const SimpleFontData*>* fallback_fonts;
unsigned start_index = 0;
unsigned num_glyphs = 0;
hb_script_t script = HB_SCRIPT_INVALID;
};
} // anonymous namespace
TEST(ShapeResultBloberizerTest, StartsEmpty) {
TEST_F(ShapeResultBloberizerTest, StartsEmpty) {
Font font;
ShapeResultBloberizer bloberizer(font, 1);
......@@ -57,7 +84,7 @@ TEST(ShapeResultBloberizerTest, StartsEmpty) {
EXPECT_TRUE(bloberizer.Blobs().IsEmpty());
}
TEST(ShapeResultBloberizerTest, StoresGlyphsOffsets) {
TEST_F(ShapeResultBloberizerTest, StoresGlyphsOffsets) {
Font font;
ShapeResultBloberizer bloberizer(font, 1);
......@@ -117,7 +144,7 @@ TEST(ShapeResultBloberizerTest, StoresGlyphsOffsets) {
EXPECT_EQ(bloberizer.Blobs().size(), 1ul);
}
TEST(ShapeResultBloberizerTest, StoresGlyphsVerticalOffsets) {
TEST_F(ShapeResultBloberizerTest, StoresGlyphsVerticalOffsets) {
Font font;
ShapeResultBloberizer bloberizer(font, 1);
......@@ -180,7 +207,7 @@ TEST(ShapeResultBloberizerTest, StoresGlyphsVerticalOffsets) {
EXPECT_EQ(bloberizer.Blobs().size(), 1ul);
}
TEST(ShapeResultBloberizerTest, MixedBlobRotation) {
TEST_F(ShapeResultBloberizerTest, MixedBlobRotation) {
Font font;
ShapeResultBloberizer bloberizer(font, 1);
......@@ -235,4 +262,105 @@ TEST(ShapeResultBloberizerTest, MixedBlobRotation) {
EXPECT_EQ(4u, bloberizer.Blobs().size());
}
// Tests that filling a glyph buffer for a specific range returns the same
// results when shaping word by word as when shaping the full run in one go.
TEST_F(ShapeResultBloberizerTest, CommonAccentLeftToRightFillGlyphBuffer) {
// "/. ." with an accent mark over the first dot.
const UChar kStr[] = {0x2F, 0x301, 0x2E, 0x20, 0x2E, 0x0};
TextRun text_run(kStr, 5);
TextRunPaintInfo run_info(text_run);
run_info.to = 3;
ShapeResultBloberizer bloberizer(font, 1);
CachingWordShaper word_shaper(font);
ShapeResultBuffer buffer;
word_shaper.FillResultBuffer(run_info, &buffer);
bloberizer.FillGlyphs(run_info, buffer);
Font reference_font(font_description);
reference_font.Update(nullptr);
reference_font.SetCanShapeWordByWordForTesting(false);
ShapeResultBloberizer reference_bloberizer(reference_font, 1);
CachingWordShaper reference_word_shaper(font);
ShapeResultBuffer reference_buffer;
reference_word_shaper.FillResultBuffer(run_info, &reference_buffer);
reference_bloberizer.FillGlyphs(run_info, reference_buffer);
const auto& glyphs =
ShapeResultBloberizerTestInfo::PendingRunGlyphs(bloberizer);
ASSERT_EQ(glyphs.size(), 3ul);
const auto reference_glyphs =
ShapeResultBloberizerTestInfo::PendingRunGlyphs(reference_bloberizer);
ASSERT_EQ(reference_glyphs.size(), 3ul);
EXPECT_EQ(reference_glyphs[0], glyphs[0]);
EXPECT_EQ(reference_glyphs[1], glyphs[1]);
EXPECT_EQ(reference_glyphs[2], glyphs[2]);
}
// Tests that filling a glyph buffer for a specific range returns the same
// results when shaping word by word as when shaping the full run in one go.
TEST_F(ShapeResultBloberizerTest, CommonAccentRightToLeftFillGlyphBuffer) {
// "[] []" with an accent mark over the last square bracket.
const UChar kStr[] = {0x5B, 0x5D, 0x20, 0x5B, 0x301, 0x5D, 0x0};
TextRun text_run(kStr, 6);
text_run.SetDirection(TextDirection::kRtl);
TextRunPaintInfo run_info(text_run);
run_info.from = 1;
ShapeResultBloberizer bloberizer(font, 1);
CachingWordShaper word_shaper(font);
ShapeResultBuffer buffer;
word_shaper.FillResultBuffer(run_info, &buffer);
bloberizer.FillGlyphs(run_info, buffer);
Font reference_font(font_description);
reference_font.Update(nullptr);
reference_font.SetCanShapeWordByWordForTesting(false);
ShapeResultBloberizer reference_bloberizer(reference_font, 1);
CachingWordShaper reference_word_shaper(font);
ShapeResultBuffer reference_buffer;
reference_word_shaper.FillResultBuffer(run_info, &reference_buffer);
reference_bloberizer.FillGlyphs(run_info, reference_buffer);
const auto& glyphs =
ShapeResultBloberizerTestInfo::PendingRunGlyphs(bloberizer);
ASSERT_EQ(5u, glyphs.size());
const auto reference_glyphs =
ShapeResultBloberizerTestInfo::PendingRunGlyphs(reference_bloberizer);
ASSERT_EQ(5u, reference_glyphs.size());
EXPECT_EQ(reference_glyphs[0], glyphs[0]);
EXPECT_EQ(reference_glyphs[1], glyphs[1]);
EXPECT_EQ(reference_glyphs[2], glyphs[2]);
EXPECT_EQ(reference_glyphs[3], glyphs[3]);
EXPECT_EQ(reference_glyphs[4], glyphs[4]);
}
// Tests that runs with zero glyphs (the ZWJ non-printable character in this
// case) are handled correctly. This test passes if it does not cause a crash.
TEST_F(ShapeResultBloberizerTest, SubRunWithZeroGlyphs) {
// "Foo &zwnj; bar"
const UChar kStr[] = {0x46, 0x6F, 0x6F, 0x20, 0x200C,
0x20, 0x62, 0x61, 0x71, 0x0};
TextRun text_run(kStr, 9);
CachingWordShaper shaper(font);
FloatRect glyph_bounds;
ASSERT_GT(shaper.Width(text_run, nullptr, &glyph_bounds), 0);
ShapeResultBloberizer bloberizer(font, 1);
TextRunPaintInfo run_info(text_run);
run_info.to = 8;
CachingWordShaper word_shaper(font);
ShapeResultBuffer buffer;
word_shaper.FillResultBuffer(run_info, &buffer);
bloberizer.FillGlyphs(run_info, buffer);
shaper.GetCharacterRange(text_run, 0, 8);
}
} // namespace blink
......@@ -18,7 +18,6 @@ class FontDescription;
struct GlyphData;
class ShapeResultBloberizer;
class TextRun;
struct TextRunPaintInfo;
class PLATFORM_EXPORT ShapeResultBuffer {
WTF_MAKE_NONCOPYABLE(ShapeResultBuffer);
......@@ -34,10 +33,6 @@ class PLATFORM_EXPORT ShapeResultBuffer {
bool HasVerticalOffsets() const { return has_vertical_offsets_; }
float FillGlyphs(const TextRunPaintInfo&, ShapeResultBloberizer&) const;
void FillTextEmphasisGlyphs(const TextRunPaintInfo&,
const GlyphData& emphasis_data,
ShapeResultBloberizer&) const;
int OffsetForPosition(const TextRun&,
float target_x,
bool include_partial_glyphs) const;
......@@ -64,6 +59,7 @@ class PLATFORM_EXPORT ShapeResultBuffer {
GlyphData EmphasisMarkGlyphData(const FontDescription&) const;
private:
friend class ShapeResultBloberizer;
static CharacterRange GetCharacterRangeInternal(
const Vector<RefPtr<const ShapeResult>, 64>&,
TextDirection,
......@@ -71,20 +67,6 @@ class PLATFORM_EXPORT ShapeResultBuffer {
unsigned from,
unsigned to);
float FillFastHorizontalGlyphs(const TextRun&, ShapeResultBloberizer&) const;
static float FillGlyphsForResult(ShapeResultBloberizer&,
const ShapeResult&,
const TextRunPaintInfo&,
float initial_advance,
unsigned run_offset);
static float FillTextEmphasisGlyphsForRun(ShapeResultBloberizer&,
const ShapeResult::RunInfo*,
const TextRunPaintInfo&,
const GlyphData&,
float initial_advance,
unsigned run_offset);
static void AddRunInfoRanges(const ShapeResult::RunInfo&,
float offset,
Vector<CharacterRange>&);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment