mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Minimal integration with the Skia text shaper module (flutter/engine#9556)
This converts the libtxt Paragraph and ParagraphBuilder classes into interfaces with Minikin and SkShaper/SkParagraph based implementations. Use the --enable-skshaper GN flag to select the Skia shaper implementation at build time.
This commit is contained in:
parent
ea163fd95e
commit
20bc546d69
@ -1068,6 +1068,10 @@ FILE: ../../../flutter/third_party/txt/src/minikin/SparseBitSet.cpp
|
||||
FILE: ../../../flutter/third_party/txt/src/minikin/SparseBitSet.h
|
||||
FILE: ../../../flutter/third_party/txt/src/minikin/WordBreaker.cpp
|
||||
FILE: ../../../flutter/third_party/txt/src/minikin/WordBreaker.h
|
||||
FILE: ../../../flutter/third_party/txt/src/skia/paragraph_builder_skia.cc
|
||||
FILE: ../../../flutter/third_party/txt/src/skia/paragraph_builder_skia.h
|
||||
FILE: ../../../flutter/third_party/txt/src/skia/paragraph_skia.cc
|
||||
FILE: ../../../flutter/third_party/txt/src/skia/paragraph_skia.h
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/asset_font_manager.cc
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/asset_font_manager.h
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/font_asset_provider.cc
|
||||
@ -1082,12 +1086,15 @@ FILE: ../../../flutter/third_party/txt/src/txt/font_style.h
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/font_weight.h
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/paint_record.cc
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/paint_record.h
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/paragraph.cc
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/paragraph.h
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/paragraph_builder.cc
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/paragraph_builder.h
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/paragraph_builder_txt.cc
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/paragraph_builder_txt.h
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/paragraph_style.cc
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/paragraph_style.h
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/paragraph_txt.cc
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/paragraph_txt.h
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/placeholder_run.cc
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/placeholder_run.h
|
||||
FILE: ../../../flutter/third_party/txt/src/txt/styled_runs.cc
|
||||
|
||||
@ -17,6 +17,9 @@ if (target_cpu == "arm" || target_cpu == "arm64") {
|
||||
declare_args() {
|
||||
# The runtime mode ("debug", "profile", or "release")
|
||||
flutter_runtime_mode = "debug"
|
||||
|
||||
# Whether to use the Skia text shaper module
|
||||
flutter_enable_skshaper = false
|
||||
}
|
||||
|
||||
# feature_defines_list ---------------------------------------------------------
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//build/fuchsia/sdk.gni")
|
||||
import("$flutter_root/common/config.gni")
|
||||
import("$flutter_root/testing/testing.gni")
|
||||
|
||||
source_set("ui") {
|
||||
@ -126,6 +127,10 @@ source_set("ui") {
|
||||
"$flutter_root/third_party/txt",
|
||||
]
|
||||
|
||||
if (flutter_enable_skshaper) {
|
||||
defines = [ "FLUTTER_ENABLE_SKSHAPER" ]
|
||||
}
|
||||
|
||||
if (is_fuchsia) {
|
||||
sources += [
|
||||
"compositing/scene_host.cc",
|
||||
|
||||
@ -283,9 +283,16 @@ ParagraphBuilder::ParagraphBuilder(
|
||||
|
||||
FontCollection& font_collection =
|
||||
UIDartState::Current()->window()->client()->GetFontCollection();
|
||||
m_paragraphBuilder = std::make_unique<txt::ParagraphBuilder>(
|
||||
style, font_collection.GetFontCollection());
|
||||
} // namespace flutter
|
||||
|
||||
#if FLUTTER_ENABLE_SKSHAPER
|
||||
#define FLUTTER_PARAGRAPH_BUILDER txt::ParagraphBuilder::CreateSkiaBuilder
|
||||
#else
|
||||
#define FLUTTER_PARAGRAPH_BUILDER txt::ParagraphBuilder::CreateTxtBuilder
|
||||
#endif
|
||||
|
||||
m_paragraphBuilder =
|
||||
FLUTTER_PARAGRAPH_BUILDER(style, font_collection.GetFontCollection());
|
||||
}
|
||||
|
||||
ParagraphBuilder::~ParagraphBuilder() = default;
|
||||
|
||||
|
||||
21
engine/src/flutter/third_party/txt/BUILD.gn
vendored
21
engine/src/flutter/third_party/txt/BUILD.gn
vendored
@ -12,6 +12,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("$flutter_root/common/config.gni")
|
||||
|
||||
declare_args() {
|
||||
flutter_use_fontconfig = false
|
||||
}
|
||||
@ -30,6 +32,9 @@ source_set("txt") {
|
||||
if (flutter_use_fontconfig) {
|
||||
defines += [ "FLUTTER_USE_FONTCONFIG" ]
|
||||
}
|
||||
if (flutter_enable_skshaper) {
|
||||
defines += [ "FLUTTER_ENABLE_SKSHAPER" ]
|
||||
}
|
||||
|
||||
sources = [
|
||||
"src/log/log.cc",
|
||||
@ -84,12 +89,15 @@ source_set("txt") {
|
||||
"src/txt/font_weight.h",
|
||||
"src/txt/paint_record.cc",
|
||||
"src/txt/paint_record.h",
|
||||
"src/txt/paragraph.cc",
|
||||
"src/txt/paragraph.h",
|
||||
"src/txt/paragraph_builder.cc",
|
||||
"src/txt/paragraph_builder.h",
|
||||
"src/txt/paragraph_builder_txt.cc",
|
||||
"src/txt/paragraph_builder_txt.h",
|
||||
"src/txt/paragraph_style.cc",
|
||||
"src/txt/paragraph_style.h",
|
||||
"src/txt/paragraph_txt.cc",
|
||||
"src/txt/paragraph_txt.h",
|
||||
"src/txt/placeholder_run.cc",
|
||||
"src/txt/placeholder_run.h",
|
||||
"src/txt/platform.h",
|
||||
@ -130,6 +138,17 @@ source_set("txt") {
|
||||
deps += [ "//third_party/fontconfig" ]
|
||||
}
|
||||
|
||||
if (flutter_enable_skshaper) {
|
||||
sources += [
|
||||
"src/skia/paragraph_builder_skia.cc",
|
||||
"src/skia/paragraph_builder_skia.h",
|
||||
"src/skia/paragraph_skia.cc",
|
||||
"src/skia/paragraph_skia.h",
|
||||
]
|
||||
|
||||
deps += [ "//third_party/skia/modules/skparagraph" ]
|
||||
}
|
||||
|
||||
if (is_mac || is_ios) {
|
||||
sources += [ "src/txt/platform_mac.mm" ]
|
||||
deps += [ "$flutter_root/fml" ]
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
#include "txt/font_style.h"
|
||||
#include "txt/font_weight.h"
|
||||
#include "txt/paragraph.h"
|
||||
#include "txt/paragraph_builder.h"
|
||||
#include "txt/paragraph_builder_txt.h"
|
||||
|
||||
namespace txt {
|
||||
|
||||
@ -45,15 +45,15 @@ static void BM_ParagraphShortLayout(benchmark::State& state) {
|
||||
txt::TextStyle text_style;
|
||||
text_style.font_families = std::vector<std::string>(1, "Roboto");
|
||||
text_style.color = SK_ColorBLACK;
|
||||
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
|
||||
|
||||
builder.PushStyle(text_style);
|
||||
builder.AddText(u16_text);
|
||||
builder.Pop();
|
||||
auto paragraph = builder.Build();
|
||||
auto paragraph = BuildParagraph(builder);
|
||||
while (state.KeepRunning()) {
|
||||
paragraph->SetDirty();
|
||||
paragraph->Layout(300, true);
|
||||
paragraph->Layout(300);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_ParagraphShortLayout);
|
||||
@ -87,15 +87,15 @@ static void BM_ParagraphLongLayout(benchmark::State& state) {
|
||||
text_style.font_families = std::vector<std::string>(1, "Roboto");
|
||||
text_style.color = SK_ColorBLACK;
|
||||
|
||||
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
|
||||
|
||||
builder.PushStyle(text_style);
|
||||
builder.AddText(u16_text);
|
||||
builder.Pop();
|
||||
auto paragraph = builder.Build();
|
||||
auto paragraph = BuildParagraph(builder);
|
||||
while (state.KeepRunning()) {
|
||||
paragraph->SetDirty();
|
||||
paragraph->Layout(300, true);
|
||||
paragraph->Layout(300);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_ParagraphLongLayout);
|
||||
@ -130,15 +130,15 @@ static void BM_ParagraphJustifyLayout(benchmark::State& state) {
|
||||
text_style.font_families = std::vector<std::string>(1, "Roboto");
|
||||
text_style.color = SK_ColorBLACK;
|
||||
|
||||
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
|
||||
|
||||
builder.PushStyle(text_style);
|
||||
builder.AddText(u16_text);
|
||||
builder.Pop();
|
||||
auto paragraph = builder.Build();
|
||||
auto paragraph = BuildParagraph(builder);
|
||||
while (state.KeepRunning()) {
|
||||
paragraph->SetDirty();
|
||||
paragraph->Layout(300, true);
|
||||
paragraph->Layout(300);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_ParagraphJustifyLayout);
|
||||
@ -154,15 +154,15 @@ static void BM_ParagraphManyStylesLayout(benchmark::State& state) {
|
||||
txt::TextStyle text_style;
|
||||
text_style.font_families = std::vector<std::string>(1, "Roboto");
|
||||
text_style.color = SK_ColorBLACK;
|
||||
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
builder.PushStyle(text_style);
|
||||
builder.AddText(u16_text);
|
||||
}
|
||||
auto paragraph = builder.Build();
|
||||
auto paragraph = BuildParagraph(builder);
|
||||
while (state.KeepRunning()) {
|
||||
paragraph->SetDirty();
|
||||
paragraph->Layout(300, true);
|
||||
paragraph->Layout(300);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_ParagraphManyStylesLayout);
|
||||
@ -181,15 +181,15 @@ static void BM_ParagraphTextBigO(benchmark::State& state) {
|
||||
text_style.font_families = std::vector<std::string>(1, "Roboto");
|
||||
text_style.color = SK_ColorBLACK;
|
||||
|
||||
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
|
||||
|
||||
builder.PushStyle(text_style);
|
||||
builder.AddText(u16_text);
|
||||
builder.Pop();
|
||||
auto paragraph = builder.Build();
|
||||
auto paragraph = BuildParagraph(builder);
|
||||
while (state.KeepRunning()) {
|
||||
paragraph->SetDirty();
|
||||
paragraph->Layout(300, true);
|
||||
paragraph->Layout(300);
|
||||
}
|
||||
state.SetComplexityN(state.range(0));
|
||||
}
|
||||
@ -210,16 +210,16 @@ static void BM_ParagraphStylesBigO(benchmark::State& state) {
|
||||
text_style.font_families = std::vector<std::string>(1, "Roboto");
|
||||
text_style.color = SK_ColorBLACK;
|
||||
|
||||
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
|
||||
|
||||
for (int i = 0; i < state.range(0); ++i) {
|
||||
builder.PushStyle(text_style);
|
||||
builder.AddText(u16_text);
|
||||
}
|
||||
auto paragraph = builder.Build();
|
||||
auto paragraph = BuildParagraph(builder);
|
||||
while (state.KeepRunning()) {
|
||||
paragraph->SetDirty();
|
||||
paragraph->Layout(300, true);
|
||||
paragraph->Layout(300);
|
||||
}
|
||||
state.SetComplexityN(state.range(0));
|
||||
}
|
||||
@ -239,11 +239,11 @@ static void BM_ParagraphPaintSimple(benchmark::State& state) {
|
||||
txt::TextStyle text_style;
|
||||
text_style.font_families = std::vector<std::string>(1, "Roboto");
|
||||
text_style.color = SK_ColorBLACK;
|
||||
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
|
||||
builder.PushStyle(text_style);
|
||||
builder.AddText(u16_text);
|
||||
auto paragraph = builder.Build();
|
||||
paragraph->Layout(300, true);
|
||||
auto paragraph = BuildParagraph(builder);
|
||||
paragraph->Layout(300);
|
||||
|
||||
std::unique_ptr<SkBitmap> bitmap = std::make_unique<SkBitmap>();
|
||||
bitmap->allocN32Pixels(1000, 1000);
|
||||
@ -286,11 +286,11 @@ static void BM_ParagraphPaintLarge(benchmark::State& state) {
|
||||
txt::TextStyle text_style;
|
||||
text_style.font_families = std::vector<std::string>(1, "Roboto");
|
||||
text_style.color = SK_ColorBLACK;
|
||||
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
|
||||
builder.PushStyle(text_style);
|
||||
builder.AddText(u16_text);
|
||||
auto paragraph = builder.Build();
|
||||
paragraph->Layout(300, true);
|
||||
auto paragraph = BuildParagraph(builder);
|
||||
paragraph->Layout(300);
|
||||
|
||||
std::unique_ptr<SkBitmap> bitmap = std::make_unique<SkBitmap>();
|
||||
bitmap->allocN32Pixels(1000, 1000);
|
||||
@ -322,7 +322,7 @@ static void BM_ParagraphPaintDecoration(benchmark::State& state) {
|
||||
text_style.decoration_style = TextDecorationStyle(kSolid);
|
||||
text_style.color = SK_ColorBLACK;
|
||||
|
||||
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
|
||||
|
||||
builder.PushStyle(text_style);
|
||||
builder.AddText(u16_text);
|
||||
@ -335,8 +335,8 @@ static void BM_ParagraphPaintDecoration(benchmark::State& state) {
|
||||
builder.PushStyle(text_style);
|
||||
builder.AddText(u16_text);
|
||||
|
||||
auto paragraph = builder.Build();
|
||||
paragraph->Layout(300, true);
|
||||
auto paragraph = BuildParagraph(builder);
|
||||
paragraph->Layout(300);
|
||||
|
||||
std::unique_ptr<SkBitmap> bitmap = std::make_unique<SkBitmap>();
|
||||
bitmap->allocN32Pixels(1000, 1000);
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
#include "txt/font_style.h"
|
||||
#include "txt/font_weight.h"
|
||||
#include "txt/paragraph.h"
|
||||
#include "txt/paragraph_builder.h"
|
||||
#include "txt/paragraph_builder_txt.h"
|
||||
|
||||
namespace txt {
|
||||
|
||||
@ -31,7 +31,7 @@ static void BM_ParagraphBuilderConstruction(benchmark::State& state) {
|
||||
txt::ParagraphStyle paragraph_style;
|
||||
auto font_collection = GetTestFontCollection();
|
||||
while (state.KeepRunning()) {
|
||||
txt::ParagraphBuilder builder(paragraph_style, font_collection);
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, font_collection);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_ParagraphBuilderConstruction);
|
||||
@ -43,7 +43,7 @@ static void BM_ParagraphBuilderPushStyle(benchmark::State& state) {
|
||||
text_style.color = SK_ColorBLACK;
|
||||
auto font_collection = GetTestFontCollection();
|
||||
while (state.KeepRunning()) {
|
||||
txt::ParagraphBuilder builder(paragraph_style, font_collection);
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, font_collection);
|
||||
builder.PushStyle(text_style);
|
||||
}
|
||||
}
|
||||
@ -51,7 +51,7 @@ BENCHMARK(BM_ParagraphBuilderPushStyle);
|
||||
|
||||
static void BM_ParagraphBuilderPushPop(benchmark::State& state) {
|
||||
txt::ParagraphStyle paragraph_style;
|
||||
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection());
|
||||
|
||||
txt::TextStyle text_style;
|
||||
text_style.color = SK_ColorBLACK;
|
||||
@ -70,7 +70,7 @@ static void BM_ParagraphBuilderAddTextString(benchmark::State& state) {
|
||||
txt::ParagraphStyle paragraph_style;
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
txt::ParagraphBuilder builder(paragraph_style, font_collection);
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, font_collection);
|
||||
builder.AddText(text);
|
||||
}
|
||||
}
|
||||
@ -82,7 +82,7 @@ static void BM_ParagraphBuilderAddTextChar(benchmark::State& state) {
|
||||
txt::ParagraphStyle paragraph_style;
|
||||
auto font_collection = GetTestFontCollection();
|
||||
while (state.KeepRunning()) {
|
||||
txt::ParagraphBuilder builder(paragraph_style, font_collection);
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, font_collection);
|
||||
builder.AddText(text);
|
||||
}
|
||||
}
|
||||
@ -97,7 +97,7 @@ static void BM_ParagraphBuilderAddTextU16stringShort(benchmark::State& state) {
|
||||
txt::ParagraphStyle paragraph_style;
|
||||
auto font_collection = GetTestFontCollection();
|
||||
while (state.KeepRunning()) {
|
||||
txt::ParagraphBuilder builder(paragraph_style, font_collection);
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, font_collection);
|
||||
builder.AddText(u16_text);
|
||||
}
|
||||
}
|
||||
@ -131,7 +131,7 @@ static void BM_ParagraphBuilderAddTextU16stringLong(benchmark::State& state) {
|
||||
txt::ParagraphStyle paragraph_style;
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
txt::ParagraphBuilder builder(paragraph_style, font_collection);
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, font_collection);
|
||||
builder.AddText(u16_text);
|
||||
}
|
||||
}
|
||||
@ -150,7 +150,7 @@ static void BM_ParagraphBuilderShortParagraphConstruct(
|
||||
text_style.color = SK_ColorBLACK;
|
||||
auto font_collection = GetTestFontCollection();
|
||||
while (state.KeepRunning()) {
|
||||
txt::ParagraphBuilder builder(paragraph_style, font_collection);
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, font_collection);
|
||||
builder.PushStyle(text_style);
|
||||
builder.AddText(u16_text);
|
||||
builder.Pop();
|
||||
@ -188,7 +188,7 @@ static void BM_ParagraphBuilderLongParagraphConstruct(benchmark::State& state) {
|
||||
text_style.color = SK_ColorBLACK;
|
||||
auto font_collection = GetTestFontCollection();
|
||||
while (state.KeepRunning()) {
|
||||
txt::ParagraphBuilder builder(paragraph_style, font_collection);
|
||||
txt::ParagraphBuilderTxt builder(paragraph_style, font_collection);
|
||||
builder.PushStyle(text_style);
|
||||
builder.AddText(u16_text);
|
||||
builder.Pop();
|
||||
|
||||
164
engine/src/flutter/third_party/txt/src/skia/paragraph_builder_skia.cc
vendored
Normal file
164
engine/src/flutter/third_party/txt/src/skia/paragraph_builder_skia.cc
vendored
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "paragraph_builder_skia.h"
|
||||
#include "paragraph_skia.h"
|
||||
|
||||
#include "third_party/skia/modules/skparagraph/include/ParagraphStyle.h"
|
||||
#include "third_party/skia/modules/skparagraph/include/TextStyle.h"
|
||||
#include "txt/paragraph_style.h"
|
||||
|
||||
namespace skt = skia::textlayout;
|
||||
|
||||
namespace txt {
|
||||
|
||||
namespace {
|
||||
|
||||
// Convert txt::FontWeight values (ranging from 0-8) to SkFontStyle::Weight
|
||||
// values (ranging from 100-900).
|
||||
SkFontStyle::Weight GetSkFontStyleWeight(txt::FontWeight font_weight) {
|
||||
return static_cast<SkFontStyle::Weight>(static_cast<int>(font_weight) * 100 +
|
||||
100);
|
||||
}
|
||||
|
||||
SkFontStyle MakeSkFontStyle(txt::FontWeight font_weight,
|
||||
txt::FontStyle font_style) {
|
||||
return SkFontStyle(
|
||||
GetSkFontStyleWeight(font_weight), SkFontStyle::Width::kNormal_Width,
|
||||
font_style == txt::FontStyle::normal ? SkFontStyle::Slant::kUpright_Slant
|
||||
: SkFontStyle::Slant::kItalic_Slant);
|
||||
}
|
||||
|
||||
skt::ParagraphStyle TxtToSkia(const ParagraphStyle& txt) {
|
||||
skt::ParagraphStyle skia;
|
||||
skt::TextStyle text_style;
|
||||
|
||||
text_style.setFontStyle(MakeSkFontStyle(txt.font_weight, txt.font_style));
|
||||
text_style.setFontSize(SkDoubleToScalar(txt.font_size));
|
||||
text_style.setHeight(SkDoubleToScalar(txt.height));
|
||||
text_style.setFontFamilies({SkString(txt.font_family.c_str())});
|
||||
text_style.setLocale(SkString(txt.locale.c_str()));
|
||||
skia.setTextStyle(text_style);
|
||||
|
||||
skt::StrutStyle strut_style;
|
||||
strut_style.setFontStyle(
|
||||
MakeSkFontStyle(txt.strut_font_weight, txt.strut_font_style));
|
||||
strut_style.setFontSize(SkDoubleToScalar(txt.strut_font_size));
|
||||
strut_style.setHeight(SkDoubleToScalar(txt.strut_height));
|
||||
|
||||
std::vector<SkString> strut_fonts;
|
||||
std::transform(txt.strut_font_families.begin(), txt.strut_font_families.end(),
|
||||
std::back_inserter(strut_fonts),
|
||||
[](const std::string& f) { return SkString(f.c_str()); });
|
||||
strut_style.setFontFamilies(strut_fonts);
|
||||
strut_style.setLeading(txt.strut_leading);
|
||||
strut_style.setForceStrutHeight(txt.force_strut_height);
|
||||
strut_style.setStrutEnabled(txt.strut_enabled);
|
||||
skia.setStrutStyle(strut_style);
|
||||
|
||||
skia.setTextAlign(static_cast<skt::TextAlign>(txt.text_align));
|
||||
skia.setTextDirection(static_cast<skt::TextDirection>(txt.text_direction));
|
||||
skia.setMaxLines(txt.max_lines);
|
||||
skia.setEllipsis(txt.ellipsis);
|
||||
|
||||
skia.turnHintingOff();
|
||||
|
||||
return skia;
|
||||
}
|
||||
|
||||
skt::TextStyle TxtToSkia(const TextStyle& txt) {
|
||||
skt::TextStyle skia;
|
||||
|
||||
skia.setColor(txt.color);
|
||||
skia.setDecoration(static_cast<skt::TextDecoration>(txt.decoration));
|
||||
skia.setDecorationColor(txt.decoration_color);
|
||||
skia.setDecorationStyle(
|
||||
static_cast<skt::TextDecorationStyle>(txt.decoration_style));
|
||||
skia.setDecorationThicknessMultiplier(
|
||||
SkDoubleToScalar(txt.decoration_thickness_multiplier));
|
||||
skia.setFontStyle(MakeSkFontStyle(txt.font_weight, txt.font_style));
|
||||
skia.setTextBaseline(static_cast<skt::TextBaseline>(txt.text_baseline));
|
||||
|
||||
std::vector<SkString> skia_fonts;
|
||||
std::transform(txt.font_families.begin(), txt.font_families.end(),
|
||||
std::back_inserter(skia_fonts),
|
||||
[](const std::string& f) { return SkString(f.c_str()); });
|
||||
skia.setFontFamilies(skia_fonts);
|
||||
|
||||
skia.setFontSize(SkDoubleToScalar(txt.font_size));
|
||||
skia.setLetterSpacing(SkDoubleToScalar(txt.letter_spacing));
|
||||
skia.setWordSpacing(SkDoubleToScalar(txt.word_spacing));
|
||||
skia.setHeight(SkDoubleToScalar(txt.height));
|
||||
|
||||
skia.setLocale(SkString(txt.locale.c_str()));
|
||||
if (txt.has_background) {
|
||||
skia.setBackgroundColor(txt.background);
|
||||
}
|
||||
if (txt.has_foreground) {
|
||||
skia.setForegroundColor(txt.foreground);
|
||||
}
|
||||
|
||||
skia.resetShadows();
|
||||
for (const txt::TextShadow& txt_shadow : txt.text_shadows) {
|
||||
skt::TextShadow shadow;
|
||||
shadow.fOffset = txt_shadow.offset;
|
||||
shadow.fBlurRadius = txt_shadow.blur_radius;
|
||||
shadow.fColor = txt_shadow.color;
|
||||
skia.addShadow(shadow);
|
||||
}
|
||||
|
||||
return skia;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
ParagraphBuilderSkia::ParagraphBuilderSkia(
|
||||
const ParagraphStyle& style,
|
||||
std::shared_ptr<FontCollection> font_collection)
|
||||
: builder_(skt::ParagraphBuilder::make(
|
||||
TxtToSkia(style),
|
||||
font_collection->CreateSktFontCollection())),
|
||||
base_style_(style.GetTextStyle()) {}
|
||||
|
||||
ParagraphBuilderSkia::~ParagraphBuilderSkia() = default;
|
||||
|
||||
void ParagraphBuilderSkia::PushStyle(const TextStyle& style) {
|
||||
builder_->pushStyle(TxtToSkia(style));
|
||||
txt_style_stack_.push(style);
|
||||
}
|
||||
|
||||
void ParagraphBuilderSkia::Pop() {
|
||||
builder_->pop();
|
||||
txt_style_stack_.pop();
|
||||
}
|
||||
|
||||
const TextStyle& ParagraphBuilderSkia::PeekStyle() {
|
||||
return txt_style_stack_.empty() ? base_style_ : txt_style_stack_.top();
|
||||
}
|
||||
|
||||
void ParagraphBuilderSkia::AddText(const std::u16string& text) {
|
||||
builder_->addText(text);
|
||||
}
|
||||
|
||||
void ParagraphBuilderSkia::AddPlaceholder(PlaceholderRun& span) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
std::unique_ptr<Paragraph> ParagraphBuilderSkia::Build() {
|
||||
return std::make_unique<ParagraphSkia>(builder_->Build());
|
||||
}
|
||||
|
||||
} // namespace txt
|
||||
49
engine/src/flutter/third_party/txt/src/skia/paragraph_builder_skia.h
vendored
Normal file
49
engine/src/flutter/third_party/txt/src/skia/paragraph_builder_skia.h
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef LIB_TXT_SRC_PARAGRAPH_BUILDER_SKIA_H_
|
||||
#define LIB_TXT_SRC_PARAGRAPH_BUILDER_SKIA_H_
|
||||
|
||||
#include "txt/paragraph_builder.h"
|
||||
|
||||
#include "third_party/skia/modules/skparagraph/include/ParagraphBuilder.h"
|
||||
|
||||
namespace txt {
|
||||
|
||||
// Implementation of ParagraphBuilder based on Skia's text layout module.
|
||||
class ParagraphBuilderSkia : public ParagraphBuilder {
|
||||
public:
|
||||
ParagraphBuilderSkia(const ParagraphStyle& style,
|
||||
std::shared_ptr<FontCollection> font_collection);
|
||||
|
||||
virtual ~ParagraphBuilderSkia();
|
||||
|
||||
virtual void PushStyle(const TextStyle& style) override;
|
||||
virtual void Pop() override;
|
||||
virtual const TextStyle& PeekStyle() override;
|
||||
virtual void AddText(const std::u16string& text) override;
|
||||
virtual void AddPlaceholder(PlaceholderRun& span) override;
|
||||
virtual std::unique_ptr<Paragraph> Build() override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<skia::textlayout::ParagraphBuilder> builder_;
|
||||
TextStyle base_style_;
|
||||
std::stack<TextStyle> txt_style_stack_;
|
||||
};
|
||||
|
||||
} // namespace txt
|
||||
|
||||
#endif // LIB_TXT_SRC_PARAGRAPH_BUILDER_SKIA_H_
|
||||
105
engine/src/flutter/third_party/txt/src/skia/paragraph_skia.cc
vendored
Normal file
105
engine/src/flutter/third_party/txt/src/skia/paragraph_skia.cc
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "paragraph_skia.h"
|
||||
|
||||
namespace txt {
|
||||
|
||||
namespace skt = skia::textlayout;
|
||||
|
||||
ParagraphSkia::ParagraphSkia(std::unique_ptr<skt::Paragraph> paragraph)
|
||||
: paragraph_(std::move(paragraph)) {}
|
||||
|
||||
double ParagraphSkia::GetMaxWidth() {
|
||||
return paragraph_->getMaxWidth();
|
||||
}
|
||||
|
||||
double ParagraphSkia::GetHeight() {
|
||||
return paragraph_->getHeight();
|
||||
}
|
||||
|
||||
double ParagraphSkia::GetLongestLine() {
|
||||
// TODO: implement
|
||||
return 0;
|
||||
}
|
||||
|
||||
double ParagraphSkia::GetMinIntrinsicWidth() {
|
||||
return paragraph_->getMinIntrinsicWidth();
|
||||
}
|
||||
|
||||
double ParagraphSkia::GetMaxIntrinsicWidth() {
|
||||
return paragraph_->getMaxIntrinsicWidth();
|
||||
}
|
||||
|
||||
double ParagraphSkia::GetAlphabeticBaseline() {
|
||||
return paragraph_->getAlphabeticBaseline();
|
||||
}
|
||||
|
||||
double ParagraphSkia::GetIdeographicBaseline() {
|
||||
return paragraph_->getIdeographicBaseline();
|
||||
}
|
||||
|
||||
bool ParagraphSkia::DidExceedMaxLines() {
|
||||
return paragraph_->didExceedMaxLines();
|
||||
}
|
||||
|
||||
void ParagraphSkia::Layout(double width) {
|
||||
paragraph_->layout(width);
|
||||
}
|
||||
|
||||
void ParagraphSkia::Paint(SkCanvas* canvas, double x, double y) {
|
||||
paragraph_->paint(canvas, x, y);
|
||||
}
|
||||
|
||||
std::vector<Paragraph::TextBox> ParagraphSkia::GetRectsForRange(
|
||||
size_t start,
|
||||
size_t end,
|
||||
RectHeightStyle rect_height_style,
|
||||
RectWidthStyle rect_width_style) {
|
||||
std::vector<skt::TextBox> skia_boxes = paragraph_->getRectsForRange(
|
||||
start, end, static_cast<skt::RectHeightStyle>(rect_height_style),
|
||||
static_cast<skt::RectWidthStyle>(rect_width_style));
|
||||
|
||||
std::vector<Paragraph::TextBox> boxes;
|
||||
for (const skt::TextBox skia_box : skia_boxes) {
|
||||
boxes.emplace_back(skia_box.rect,
|
||||
static_cast<TextDirection>(skia_box.direction));
|
||||
}
|
||||
|
||||
return boxes;
|
||||
}
|
||||
|
||||
std::vector<Paragraph::TextBox> ParagraphSkia::GetRectsForPlaceholders() {
|
||||
// TODO: implement
|
||||
return {};
|
||||
}
|
||||
|
||||
Paragraph::PositionWithAffinity ParagraphSkia::GetGlyphPositionAtCoordinate(
|
||||
double dx,
|
||||
double dy) {
|
||||
skt::PositionWithAffinity skia_pos =
|
||||
paragraph_->getGlyphPositionAtCoordinate(dx, dy);
|
||||
|
||||
return ParagraphSkia::PositionWithAffinity(
|
||||
skia_pos.position, static_cast<Affinity>(skia_pos.affinity));
|
||||
}
|
||||
|
||||
Paragraph::Range<size_t> ParagraphSkia::GetWordBoundary(size_t offset) {
|
||||
skt::SkRange<size_t> range = paragraph_->getWordBoundary(offset);
|
||||
return Paragraph::Range<size_t>(range.start, range.end);
|
||||
}
|
||||
|
||||
} // namespace txt
|
||||
72
engine/src/flutter/third_party/txt/src/skia/paragraph_skia.h
vendored
Normal file
72
engine/src/flutter/third_party/txt/src/skia/paragraph_skia.h
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef LIB_TXT_SRC_PARAGRAPH_SKIA_H_
|
||||
#define LIB_TXT_SRC_PARAGRAPH_SKIA_H_
|
||||
|
||||
#include "txt/paragraph.h"
|
||||
|
||||
#include "third_party/skia/modules/skparagraph/include/Paragraph.h"
|
||||
|
||||
namespace txt {
|
||||
|
||||
// Implementation of Paragraph based on Skia's text layout module.
|
||||
class ParagraphSkia : public Paragraph {
|
||||
public:
|
||||
ParagraphSkia(std::unique_ptr<skia::textlayout::Paragraph> paragraph);
|
||||
|
||||
virtual ~ParagraphSkia() = default;
|
||||
|
||||
double GetMaxWidth() override;
|
||||
|
||||
double GetHeight() override;
|
||||
|
||||
double GetLongestLine() override;
|
||||
|
||||
double GetMinIntrinsicWidth() override;
|
||||
|
||||
double GetMaxIntrinsicWidth() override;
|
||||
|
||||
double GetAlphabeticBaseline() override;
|
||||
|
||||
double GetIdeographicBaseline() override;
|
||||
|
||||
bool DidExceedMaxLines() override;
|
||||
|
||||
void Layout(double width) override;
|
||||
|
||||
void Paint(SkCanvas* canvas, double x, double y) override;
|
||||
|
||||
std::vector<TextBox> GetRectsForRange(
|
||||
size_t start,
|
||||
size_t end,
|
||||
RectHeightStyle rect_height_style,
|
||||
RectWidthStyle rect_width_style) override;
|
||||
|
||||
std::vector<TextBox> GetRectsForPlaceholders() override;
|
||||
|
||||
PositionWithAffinity GetGlyphPositionAtCoordinate(double dx,
|
||||
double dy) override;
|
||||
|
||||
Range<size_t> GetWordBoundary(size_t offset) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<skia::textlayout::Paragraph> paragraph_;
|
||||
};
|
||||
|
||||
} // namespace txt
|
||||
|
||||
#endif // LIB_TXT_SRC_PARAGRAPH_SKIA_H_
|
||||
@ -302,4 +302,25 @@ void FontCollection::ClearFontFamilyCache() {
|
||||
font_collections_cache_.clear();
|
||||
}
|
||||
|
||||
#if FLUTTER_ENABLE_SKSHAPER
|
||||
|
||||
sk_sp<skia::textlayout::FontCollection>
|
||||
FontCollection::CreateSktFontCollection() {
|
||||
sk_sp<skia::textlayout::FontCollection> skt_collection =
|
||||
sk_make_sp<skia::textlayout::FontCollection>();
|
||||
|
||||
skt_collection->setDefaultFontManager(default_font_manager_,
|
||||
GetDefaultFontFamily().c_str());
|
||||
skt_collection->setAssetFontManager(asset_font_manager_);
|
||||
skt_collection->setDynamicFontManager(dynamic_font_manager_);
|
||||
skt_collection->setTestFontManager(test_font_manager_);
|
||||
if (!enable_font_fallback_) {
|
||||
skt_collection->disableFontFallback();
|
||||
}
|
||||
|
||||
return skt_collection;
|
||||
}
|
||||
|
||||
#endif // FLUTTER_ENABLE_SKSHAPER
|
||||
|
||||
} // namespace txt
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#include "third_party/googletest/googletest/include/gtest/gtest_prod.h" // nogncheck
|
||||
#include "third_party/skia/include/core/SkFontMgr.h"
|
||||
#include "third_party/skia/include/core/SkRefCnt.h"
|
||||
#include "third_party/skia/modules/skparagraph/include/FontCollection.h"
|
||||
#include "txt/asset_font_manager.h"
|
||||
#include "txt/text_style.h"
|
||||
|
||||
@ -63,6 +64,13 @@ class FontCollection : public std::enable_shared_from_this<FontCollection> {
|
||||
// Remove all entries in the font family cache.
|
||||
void ClearFontFamilyCache();
|
||||
|
||||
#if FLUTTER_ENABLE_SKSHAPER
|
||||
|
||||
// Construct a Skia text layout FontCollection based on this collection.
|
||||
sk_sp<skia::textlayout::FontCollection> CreateSktFontCollection();
|
||||
|
||||
#endif // FLUTTER_ENABLE_SKSHAPER
|
||||
|
||||
private:
|
||||
struct FamilyKey {
|
||||
FamilyKey(const std::vector<std::string>& families, const std::string& loc);
|
||||
|
||||
@ -17,52 +17,17 @@
|
||||
#ifndef LIB_TXT_SRC_PARAGRAPH_H_
|
||||
#define LIB_TXT_SRC_PARAGRAPH_H_
|
||||
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "flutter/fml/compiler_specific.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "font_collection.h"
|
||||
#include "minikin/LineBreaker.h"
|
||||
#include "paint_record.h"
|
||||
#include "paragraph_style.h"
|
||||
#include "placeholder_run.h"
|
||||
#include "styled_runs.h"
|
||||
#include "third_party/googletest/googletest/include/gtest/gtest_prod.h" // nogncheck
|
||||
#include "third_party/skia/include/core/SkFontMetrics.h"
|
||||
#include "third_party/skia/include/core/SkRect.h"
|
||||
#include "utils/WindowsUtils.h"
|
||||
|
||||
class SkCanvas;
|
||||
|
||||
namespace txt {
|
||||
|
||||
using GlyphID = uint32_t;
|
||||
|
||||
// Constant with the unicode codepoint for the "Object replacement character".
|
||||
// Used as a stand-in character for Placeholder boxes.
|
||||
const int objReplacementChar = 0xFFFC;
|
||||
// Constant with the unicode codepoint for the "Replacement character". This is
|
||||
// the character that commonly renders as a black diamond with a white question
|
||||
// mark. Used to replace non-placeholder instances of 0xFFFC in the text buffer.
|
||||
const int replacementChar = 0xFFFD;
|
||||
|
||||
// Paragraph provides Layout, metrics, and painting capabilities for text. Once
|
||||
// a Paragraph is constructed with ParagraphBuilder::Build(), an example basic
|
||||
// workflow can be this:
|
||||
//
|
||||
// std::unique_ptr<Paragraph> paragraph = paragraph_builder.Build();
|
||||
// paragraph->Layout(<somewidthgoeshere>);
|
||||
// paragraph->Paint(<someSkCanvas>, <xpos>, <ypos>);
|
||||
// Interface for text layout engines. The original implementation was based on
|
||||
// the Minikin text layout library used by Android. Another implementation is
|
||||
// available based on Skia's SkShaper/SkParagraph text layout module.
|
||||
class Paragraph {
|
||||
public:
|
||||
// Constructor. It is highly recommended to construct a paragraph with a
|
||||
// ParagraphBuilder.
|
||||
Paragraph();
|
||||
|
||||
~Paragraph();
|
||||
|
||||
enum Affinity { UPSTREAM, DOWNSTREAM };
|
||||
|
||||
// Options for various types of bounding boxes provided by
|
||||
@ -135,69 +100,57 @@ class Paragraph {
|
||||
}
|
||||
};
|
||||
|
||||
// Minikin Layout doLayout() and LineBreaker addStyleRun() has an
|
||||
// O(N^2) (according to benchmarks) time complexity where N is the total
|
||||
// number of characters. However, this is not significant for reasonably sized
|
||||
// paragraphs. It is currently recommended to break up very long paragraphs
|
||||
// (10k+ characters) to ensure speedy layout.
|
||||
//
|
||||
// Layout calculates the positioning of all the glyphs. Must call this method
|
||||
// before Painting and getting any statistics from this class.
|
||||
void Layout(double width, bool force = false);
|
||||
|
||||
// Paints the Laid out text onto the supplied SkCanvas at (x, y) offset from
|
||||
// the origin. Only valid after Layout() is called.
|
||||
void Paint(SkCanvas* canvas, double x, double y);
|
||||
|
||||
// Getter for paragraph_style_.
|
||||
const ParagraphStyle& GetParagraphStyle() const;
|
||||
|
||||
// Returns the number of characters/unicode characters. AKA text_.size()
|
||||
size_t TextSize() const;
|
||||
|
||||
// Returns the height of the laid out paragraph. NOTE this is not a tight
|
||||
// bounding height of the glyphs, as some glyphs do not reach as low as they
|
||||
// can.
|
||||
double GetHeight() const;
|
||||
virtual ~Paragraph() = default;
|
||||
|
||||
// Returns the width provided in the Layout() method. This is the maximum
|
||||
// width any line in the laid out paragraph can occupy. We expect that
|
||||
// GetMaxWidth() >= GetLayoutWidth().
|
||||
double GetMaxWidth() const;
|
||||
virtual double GetMaxWidth() = 0;
|
||||
|
||||
// Returns the height of the laid out paragraph. NOTE this is not a tight
|
||||
// bounding height of the glyphs, as some glyphs do not reach as low as they
|
||||
// can.
|
||||
virtual double GetHeight() = 0;
|
||||
|
||||
// Returns the width of the longest line as found in Layout(), which is
|
||||
// defined as the horizontal distance from the left edge of the leftmost glyph
|
||||
// to the right edge of the rightmost glyph. We expect that
|
||||
// GetLongestLine() <= GetMaxWidth().
|
||||
double GetLongestLine() const;
|
||||
virtual double GetLongestLine() = 0;
|
||||
|
||||
// Returns the actual max width of the longest line after Layout().
|
||||
virtual double GetMinIntrinsicWidth() = 0;
|
||||
|
||||
// Returns the total width covered by the paragraph without linebreaking.
|
||||
virtual double GetMaxIntrinsicWidth() = 0;
|
||||
|
||||
// Distance from top of paragraph to the Alphabetic baseline of the first
|
||||
// line. Used for alphabetic fonts (A-Z, a-z, greek, etc.)
|
||||
double GetAlphabeticBaseline() const;
|
||||
virtual double GetAlphabeticBaseline() = 0;
|
||||
|
||||
// Distance from top of paragraph to the Ideographic baseline of the first
|
||||
// line. Used for ideographic fonts (Chinese, Japanese, Korean, etc.)
|
||||
double GetIdeographicBaseline() const;
|
||||
virtual double GetIdeographicBaseline() = 0;
|
||||
|
||||
// Returns the total width covered by the paragraph without linebreaking.
|
||||
double GetMaxIntrinsicWidth() const;
|
||||
// Checks if the layout extends past the maximum lines and had to be
|
||||
// truncated.
|
||||
virtual bool DidExceedMaxLines() = 0;
|
||||
|
||||
// Currently, calculated similarly to as GetLayoutWidth(), however this is not
|
||||
// nessecarily 100% correct in all cases.
|
||||
//
|
||||
// Returns the actual max width of the longest line after Layout().
|
||||
double GetMinIntrinsicWidth() const;
|
||||
// Layout calculates the positioning of all the glyphs. Must call this method
|
||||
// before Painting and getting any statistics from this class.
|
||||
virtual void Layout(double width) = 0;
|
||||
|
||||
// Paints the laid out text onto the supplied SkCanvas at (x, y) offset from
|
||||
// the origin. Only valid after Layout() is called.
|
||||
virtual void Paint(SkCanvas* canvas, double x, double y) = 0;
|
||||
|
||||
// Returns a vector of bounding boxes that enclose all text between start and
|
||||
// end glyph indexes, including start and excluding end.
|
||||
std::vector<TextBox> GetRectsForRange(size_t start,
|
||||
size_t end,
|
||||
RectHeightStyle rect_height_style,
|
||||
RectWidthStyle rect_width_style) const;
|
||||
|
||||
// Returns the index of the glyph that corresponds to the provided coordinate,
|
||||
// with the top left corner as the origin, and +y direction as down.
|
||||
PositionWithAffinity GetGlyphPositionAtCoordinate(double dx, double dy) const;
|
||||
virtual std::vector<TextBox> GetRectsForRange(
|
||||
size_t start,
|
||||
size_t end,
|
||||
RectHeightStyle rect_height_style,
|
||||
RectWidthStyle rect_width_style) = 0;
|
||||
|
||||
// Returns a vector of bounding boxes that bound all inline placeholders in
|
||||
// the paragraph.
|
||||
@ -208,301 +161,16 @@ class Paragraph {
|
||||
//
|
||||
// More granular boxes may be obtained through GetRectsForRange, which will
|
||||
// return bounds on both text as well as inline placeholders.
|
||||
std::vector<Paragraph::TextBox> GetRectsForPlaceholders() const;
|
||||
virtual std::vector<TextBox> GetRectsForPlaceholders() = 0;
|
||||
|
||||
// Returns the index of the glyph that corresponds to the provided coordinate,
|
||||
// with the top left corner as the origin, and +y direction as down.
|
||||
virtual PositionWithAffinity GetGlyphPositionAtCoordinate(double dx,
|
||||
double dy) = 0;
|
||||
|
||||
// Finds the first and last glyphs that define a word containing the glyph at
|
||||
// index offset.
|
||||
Range<size_t> GetWordBoundary(size_t offset) const;
|
||||
|
||||
// Returns the number of lines the paragraph takes up. If the text exceeds the
|
||||
// amount width and maxlines provides, Layout() truncates the extra text from
|
||||
// the layout and this will return the max lines allowed.
|
||||
size_t GetLineCount() const;
|
||||
|
||||
// Checks if the layout extends past the maximum lines and had to be
|
||||
// truncated.
|
||||
bool DidExceedMaxLines() const;
|
||||
|
||||
// Sets the needs_layout_ to dirty. When Layout() is called, a new Layout will
|
||||
// be performed when this is set to true. Can also be used to prevent a new
|
||||
// Layout from being calculated by setting to false.
|
||||
void SetDirty(bool dirty = true);
|
||||
|
||||
private:
|
||||
friend class ParagraphBuilder;
|
||||
FRIEND_TEST(ParagraphTest, SimpleParagraph);
|
||||
FRIEND_TEST(ParagraphTest, SimpleRedParagraph);
|
||||
FRIEND_TEST(ParagraphTest, RainbowParagraph);
|
||||
FRIEND_TEST(ParagraphTest, DefaultStyleParagraph);
|
||||
FRIEND_TEST(ParagraphTest, BoldParagraph);
|
||||
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, LeftAlignParagraph);
|
||||
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, RightAlignParagraph);
|
||||
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, CenterAlignParagraph);
|
||||
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, JustifyAlignParagraph);
|
||||
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, JustifyRTL);
|
||||
FRIEND_TEST(ParagraphTest, DecorationsParagraph);
|
||||
FRIEND_TEST(ParagraphTest, ItalicsParagraph);
|
||||
FRIEND_TEST(ParagraphTest, ChineseParagraph);
|
||||
FRIEND_TEST(ParagraphTest, DISABLED_ArabicParagraph);
|
||||
FRIEND_TEST(ParagraphTest, SpacingParagraph);
|
||||
FRIEND_TEST(ParagraphTest, LongWordParagraph);
|
||||
FRIEND_TEST(ParagraphTest, KernScaleParagraph);
|
||||
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, NewlineParagraph);
|
||||
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, EmojiParagraph);
|
||||
FRIEND_TEST(ParagraphTest, HyphenBreakParagraph);
|
||||
FRIEND_TEST(ParagraphTest, RepeatLayoutParagraph);
|
||||
FRIEND_TEST(ParagraphTest, Ellipsize);
|
||||
FRIEND_TEST(ParagraphTest, UnderlineShiftParagraph);
|
||||
FRIEND_TEST(ParagraphTest, WavyDecorationParagraph);
|
||||
FRIEND_TEST(ParagraphTest, SimpleShadow);
|
||||
FRIEND_TEST(ParagraphTest, ComplexShadow);
|
||||
FRIEND_TEST(ParagraphTest, FontFallbackParagraph);
|
||||
FRIEND_TEST(ParagraphTest, InlinePlaceholder0xFFFCParagraph);
|
||||
FRIEND_TEST(ParagraphTest, FontFeaturesParagraph);
|
||||
|
||||
// Starting data to layout.
|
||||
std::vector<uint16_t> text_;
|
||||
// A vector of PlaceholderRuns, which detail the sizes, positioning and break
|
||||
// behavior of the empty spaces to leave. Each placeholder span corresponds to
|
||||
// a 0xFFFC (object replacement character) in text_, which indicates the
|
||||
// position in the text where the placeholder will occur. There should be an
|
||||
// equal number of 0xFFFC characters and elements in this vector.
|
||||
std::vector<PlaceholderRun> inline_placeholders_;
|
||||
// The indexes of the boxes that correspond to an inline placeholder.
|
||||
std::vector<size_t> inline_placeholder_boxes_;
|
||||
// The indexes of instances of 0xFFFC that correspond to placeholders. This is
|
||||
// necessary since the user may pass in manually entered 0xFFFC values using
|
||||
// AddText().
|
||||
std::unordered_set<size_t> obj_replacement_char_indexes_;
|
||||
StyledRuns runs_;
|
||||
ParagraphStyle paragraph_style_;
|
||||
std::shared_ptr<FontCollection> font_collection_;
|
||||
|
||||
minikin::LineBreaker breaker_;
|
||||
mutable std::unique_ptr<icu::BreakIterator> word_breaker_;
|
||||
|
||||
struct LineRange {
|
||||
LineRange(size_t s, size_t e, size_t eew, size_t ein, bool h)
|
||||
: start(s),
|
||||
end(e),
|
||||
end_excluding_whitespace(eew),
|
||||
end_including_newline(ein),
|
||||
hard_break(h) {}
|
||||
size_t start, end;
|
||||
size_t end_excluding_whitespace;
|
||||
size_t end_including_newline;
|
||||
bool hard_break;
|
||||
};
|
||||
std::vector<LineRange> line_ranges_;
|
||||
std::vector<double> line_widths_;
|
||||
|
||||
// Stores the result of Layout().
|
||||
std::vector<PaintRecord> records_;
|
||||
|
||||
std::vector<double> line_heights_;
|
||||
std::vector<double> line_baselines_;
|
||||
bool did_exceed_max_lines_;
|
||||
|
||||
// Strut metrics of zero will have no effect on the layout.
|
||||
struct StrutMetrics {
|
||||
double ascent = 0; // Positive value to keep signs clear.
|
||||
double descent = 0;
|
||||
double leading = 0;
|
||||
double half_leading = 0;
|
||||
double line_height = 0;
|
||||
bool force_strut = false;
|
||||
};
|
||||
|
||||
StrutMetrics strut_;
|
||||
|
||||
// Metrics for use in GetRectsForRange(...);
|
||||
// Per-line max metrics over all runs in a given line.
|
||||
std::vector<SkScalar> line_max_spacings_;
|
||||
std::vector<SkScalar> line_max_descent_;
|
||||
std::vector<SkScalar> line_max_ascent_;
|
||||
// Overall left and right extremes over all lines.
|
||||
double max_right_;
|
||||
double min_left_;
|
||||
|
||||
class BidiRun {
|
||||
public:
|
||||
// Constructs a BidiRun with is_ghost defaulted to false.
|
||||
BidiRun(size_t s, size_t e, TextDirection d, const TextStyle& st)
|
||||
: start_(s), end_(e), direction_(d), style_(&st), is_ghost_(false) {}
|
||||
|
||||
// Constructs a BidiRun with a custom is_ghost flag.
|
||||
BidiRun(size_t s,
|
||||
size_t e,
|
||||
TextDirection d,
|
||||
const TextStyle& st,
|
||||
bool is_ghost)
|
||||
: start_(s), end_(e), direction_(d), style_(&st), is_ghost_(is_ghost) {}
|
||||
|
||||
// Constructs a placeholder bidi run.
|
||||
BidiRun(size_t s,
|
||||
size_t e,
|
||||
TextDirection d,
|
||||
const TextStyle& st,
|
||||
PlaceholderRun& placeholder)
|
||||
: start_(s),
|
||||
end_(e),
|
||||
direction_(d),
|
||||
style_(&st),
|
||||
placeholder_run_(&placeholder) {}
|
||||
|
||||
size_t start() const { return start_; }
|
||||
size_t end() const { return end_; }
|
||||
size_t size() const { return end_ - start_; }
|
||||
TextDirection direction() const { return direction_; }
|
||||
const TextStyle& style() const { return *style_; }
|
||||
PlaceholderRun* placeholder_run() const { return placeholder_run_; }
|
||||
bool is_rtl() const { return direction_ == TextDirection::rtl; }
|
||||
// Tracks if the run represents trailing whitespace.
|
||||
bool is_ghost() const { return is_ghost_; }
|
||||
bool is_placeholder_run() const { return placeholder_run_ != nullptr; }
|
||||
|
||||
private:
|
||||
size_t start_, end_;
|
||||
TextDirection direction_;
|
||||
const TextStyle* style_;
|
||||
bool is_ghost_;
|
||||
PlaceholderRun* placeholder_run_ = nullptr;
|
||||
};
|
||||
|
||||
struct GlyphPosition {
|
||||
Range<size_t> code_units;
|
||||
Range<double> x_pos;
|
||||
|
||||
GlyphPosition(double x_start,
|
||||
double x_advance,
|
||||
size_t code_unit_index,
|
||||
size_t code_unit_width);
|
||||
|
||||
void Shift(double delta);
|
||||
};
|
||||
|
||||
struct GlyphLine {
|
||||
// Glyph positions sorted by x coordinate.
|
||||
const std::vector<GlyphPosition> positions;
|
||||
const size_t total_code_units;
|
||||
|
||||
GlyphLine(std::vector<GlyphPosition>&& p, size_t tcu);
|
||||
};
|
||||
|
||||
struct CodeUnitRun {
|
||||
// Glyph positions sorted by code unit index.
|
||||
std::vector<GlyphPosition> positions;
|
||||
Range<size_t> code_units;
|
||||
Range<double> x_pos;
|
||||
size_t line_number;
|
||||
SkFontMetrics font_metrics;
|
||||
TextDirection direction;
|
||||
const PlaceholderRun* placeholder_run;
|
||||
|
||||
CodeUnitRun(std::vector<GlyphPosition>&& p,
|
||||
Range<size_t> cu,
|
||||
Range<double> x,
|
||||
size_t line,
|
||||
const SkFontMetrics& metrics,
|
||||
TextDirection dir,
|
||||
const PlaceholderRun* placeholder);
|
||||
|
||||
void Shift(double delta);
|
||||
};
|
||||
|
||||
// Holds the laid out x positions of each glyph.
|
||||
std::vector<GlyphLine> glyph_lines_;
|
||||
|
||||
// Holds the positions of each range of code units in the text.
|
||||
// Sorted in code unit index order.
|
||||
std::vector<CodeUnitRun> code_unit_runs_;
|
||||
// Holds the positions of the inline placeholders.
|
||||
std::vector<CodeUnitRun> inline_placeholder_code_unit_runs_;
|
||||
|
||||
// The max width of the paragraph as provided in the most recent Layout()
|
||||
// call.
|
||||
double width_ = -1.0f;
|
||||
double longest_line_ = -1.0f;
|
||||
double max_intrinsic_width_ = 0;
|
||||
double min_intrinsic_width_ = 0;
|
||||
double alphabetic_baseline_ = FLT_MAX;
|
||||
double ideographic_baseline_ = FLT_MAX;
|
||||
|
||||
bool needs_layout_ = true;
|
||||
|
||||
struct WaveCoordinates {
|
||||
double x_start;
|
||||
double y_start;
|
||||
double x_end;
|
||||
double y_end;
|
||||
|
||||
WaveCoordinates(double x_s, double y_s, double x_e, double y_e)
|
||||
: x_start(x_s), y_start(y_s), x_end(x_e), y_end(y_e) {}
|
||||
};
|
||||
|
||||
// Passes in the text and Styled Runs. text_ and runs_ will later be passed
|
||||
// into breaker_ in InitBreaker(), which is called in Layout().
|
||||
void SetText(std::vector<uint16_t> text, StyledRuns runs);
|
||||
|
||||
void SetParagraphStyle(const ParagraphStyle& style);
|
||||
|
||||
void SetFontCollection(std::shared_ptr<FontCollection> font_collection);
|
||||
|
||||
void SetInlinePlaceholders(
|
||||
std::vector<PlaceholderRun> inline_placeholders,
|
||||
std::unordered_set<size_t> obj_replacement_char_indexes);
|
||||
|
||||
// Break the text into lines.
|
||||
bool ComputeLineBreaks();
|
||||
|
||||
// Break the text into runs based on LTR/RTL text direction.
|
||||
bool ComputeBidiRuns(std::vector<BidiRun>* result);
|
||||
|
||||
// Calculates and populates strut based on paragraph_style_ strut info.
|
||||
void ComputeStrut(StrutMetrics* strut, SkFont& font);
|
||||
|
||||
// Adjusts the ascent and descent based on the existence and type of
|
||||
// placeholder. This method sets the proper metrics to achieve the different
|
||||
// PlaceholderAlignment options.
|
||||
void ComputePlaceholder(PlaceholderRun* placeholder_run,
|
||||
double& ascent,
|
||||
double& descent);
|
||||
|
||||
bool IsStrutValid() const;
|
||||
|
||||
// Calculate the starting X offset of a line based on the line's width and
|
||||
// alignment.
|
||||
double GetLineXOffset(double line_total_advance);
|
||||
|
||||
// Creates and draws the decorations onto the canvas.
|
||||
void PaintDecorations(SkCanvas* canvas,
|
||||
const PaintRecord& record,
|
||||
SkPoint base_offset);
|
||||
|
||||
// Computes the beziers for a wavy decoration. The results will be
|
||||
// applied to path.
|
||||
void ComputeWavyDecoration(SkPath& path,
|
||||
double x,
|
||||
double y,
|
||||
double width,
|
||||
double thickness);
|
||||
|
||||
// Draws the background onto the canvas.
|
||||
void PaintBackground(SkCanvas* canvas,
|
||||
const PaintRecord& record,
|
||||
SkPoint base_offset);
|
||||
|
||||
// Draws the shadows onto the canvas.
|
||||
void PaintShadow(SkCanvas* canvas, const PaintRecord& record, SkPoint offset);
|
||||
|
||||
// Obtain a Minikin font collection matching this text style.
|
||||
std::shared_ptr<minikin::FontCollection> GetMinikinFontCollectionForStyle(
|
||||
const TextStyle& style);
|
||||
|
||||
// Get a default SkTypeface for a text style.
|
||||
sk_sp<SkTypeface> GetDefaultSkiaTypeface(const TextStyle& style);
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(Paragraph);
|
||||
virtual Range<size_t> GetWordBoundary(size_t offset) = 0;
|
||||
};
|
||||
|
||||
} // namespace txt
|
||||
|
||||
@ -13,75 +13,29 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "flutter/fml/logging.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "paragraph_builder.h"
|
||||
#include "flutter/third_party/txt/src/skia/paragraph_builder_skia.h"
|
||||
#include "paragraph_builder_txt.h"
|
||||
#include "paragraph_style.h"
|
||||
#include "third_party/icu/source/common/unicode/unistr.h"
|
||||
|
||||
namespace txt {
|
||||
|
||||
ParagraphBuilder::ParagraphBuilder(
|
||||
ParagraphStyle style,
|
||||
std::shared_ptr<FontCollection> font_collection)
|
||||
: font_collection_(std::move(font_collection)) {
|
||||
SetParagraphStyle(style);
|
||||
std::unique_ptr<ParagraphBuilder> ParagraphBuilder::CreateTxtBuilder(
|
||||
const ParagraphStyle& style,
|
||||
std::shared_ptr<FontCollection> font_collection) {
|
||||
return std::make_unique<ParagraphBuilderTxt>(style, font_collection);
|
||||
}
|
||||
|
||||
ParagraphBuilder::~ParagraphBuilder() = default;
|
||||
#if FLUTTER_ENABLE_SKSHAPER
|
||||
|
||||
void ParagraphBuilder::SetParagraphStyle(const ParagraphStyle& style) {
|
||||
paragraph_style_ = style;
|
||||
paragraph_style_index_ = runs_.AddStyle(style.GetTextStyle());
|
||||
runs_.StartRun(paragraph_style_index_, text_.size());
|
||||
std::unique_ptr<ParagraphBuilder> ParagraphBuilder::CreateSkiaBuilder(
|
||||
const ParagraphStyle& style,
|
||||
std::shared_ptr<FontCollection> font_collection) {
|
||||
return std::make_unique<ParagraphBuilderSkia>(style, font_collection);
|
||||
}
|
||||
|
||||
void ParagraphBuilder::PushStyle(const TextStyle& style) {
|
||||
size_t style_index = runs_.AddStyle(style);
|
||||
style_stack_.push_back(style_index);
|
||||
runs_.StartRun(style_index, text_.size());
|
||||
}
|
||||
|
||||
void ParagraphBuilder::Pop() {
|
||||
if (style_stack_.empty())
|
||||
return;
|
||||
style_stack_.pop_back();
|
||||
runs_.StartRun(PeekStyleIndex(), text_.size());
|
||||
}
|
||||
|
||||
size_t ParagraphBuilder::PeekStyleIndex() const {
|
||||
return style_stack_.size() ? style_stack_.back() : paragraph_style_index_;
|
||||
}
|
||||
|
||||
const TextStyle& ParagraphBuilder::PeekStyle() const {
|
||||
return runs_.GetStyle(PeekStyleIndex());
|
||||
}
|
||||
|
||||
void ParagraphBuilder::AddText(const std::u16string& text) {
|
||||
text_.insert(text_.end(), text.begin(), text.end());
|
||||
}
|
||||
|
||||
void ParagraphBuilder::AddPlaceholder(PlaceholderRun& span) {
|
||||
obj_replacement_char_indexes_.insert(text_.size());
|
||||
runs_.StartRun(PeekStyleIndex(), text_.size());
|
||||
AddText(std::u16string(1ull, objReplacementChar));
|
||||
runs_.StartRun(PeekStyleIndex(), text_.size());
|
||||
inline_placeholders_.push_back(span);
|
||||
}
|
||||
|
||||
std::unique_ptr<Paragraph> ParagraphBuilder::Build() {
|
||||
runs_.EndRunIfNeeded(text_.size());
|
||||
|
||||
std::unique_ptr<Paragraph> paragraph = std::make_unique<Paragraph>();
|
||||
paragraph->SetText(std::move(text_), std::move(runs_));
|
||||
paragraph->SetInlinePlaceholders(std::move(inline_placeholders_),
|
||||
std::move(obj_replacement_char_indexes_));
|
||||
paragraph->SetParagraphStyle(paragraph_style_);
|
||||
paragraph->SetFontCollection(font_collection_);
|
||||
SetParagraphStyle(paragraph_style_);
|
||||
return paragraph;
|
||||
}
|
||||
#endif // FLUTTER_ENABLE_SKSHAPER
|
||||
|
||||
} // namespace txt
|
||||
|
||||
@ -25,21 +25,27 @@
|
||||
#include "paragraph.h"
|
||||
#include "paragraph_style.h"
|
||||
#include "placeholder_run.h"
|
||||
#include "styled_runs.h"
|
||||
#include "text_style.h"
|
||||
|
||||
namespace txt {
|
||||
|
||||
class ParagraphBuilder {
|
||||
public:
|
||||
ParagraphBuilder(ParagraphStyle style,
|
||||
std::shared_ptr<FontCollection> font_collection);
|
||||
static std::unique_ptr<ParagraphBuilder> CreateTxtBuilder(
|
||||
const ParagraphStyle& style,
|
||||
std::shared_ptr<FontCollection> font_collection);
|
||||
|
||||
~ParagraphBuilder();
|
||||
#if FLUTTER_ENABLE_SKSHAPER
|
||||
static std::unique_ptr<ParagraphBuilder> CreateSkiaBuilder(
|
||||
const ParagraphStyle& style,
|
||||
std::shared_ptr<FontCollection> font_collection);
|
||||
#endif
|
||||
|
||||
virtual ~ParagraphBuilder() = default;
|
||||
|
||||
// Push a style to the stack. The corresponding text added with AddText will
|
||||
// use the top-most style.
|
||||
void PushStyle(const TextStyle& style);
|
||||
virtual void PushStyle(const TextStyle& style) = 0;
|
||||
|
||||
// Remove a style from the stack. Useful to apply different styles to chunks
|
||||
// of text such as bolding.
|
||||
@ -52,14 +58,14 @@ class ParagraphBuilder {
|
||||
//
|
||||
// builder.Pop();
|
||||
// builder.AddText(" Back to normal again.");
|
||||
void Pop();
|
||||
virtual void Pop() = 0;
|
||||
|
||||
// Returns the last TextStyle on the stack.
|
||||
const TextStyle& PeekStyle() const;
|
||||
virtual const TextStyle& PeekStyle() = 0;
|
||||
|
||||
// Adds text to the builder. Forms the proper runs to use the upper-most style
|
||||
// on the style_stack_;
|
||||
void AddText(const std::u16string& text);
|
||||
virtual void AddText(const std::u16string& text) = 0;
|
||||
|
||||
// Pushes the information requried to leave an open space, where Flutter may
|
||||
// draw a custom placeholder into.
|
||||
@ -67,33 +73,16 @@ class ParagraphBuilder {
|
||||
// Internally, this method adds a single object replacement character (0xFFFC)
|
||||
// and emplaces a new PlaceholderRun instance to the vector of inline
|
||||
// placeholders.
|
||||
void AddPlaceholder(PlaceholderRun& span);
|
||||
|
||||
void SetParagraphStyle(const ParagraphStyle& style);
|
||||
virtual void AddPlaceholder(PlaceholderRun& span) = 0;
|
||||
|
||||
// Constructs a Paragraph object that can be used to layout and paint the text
|
||||
// to a SkCanvas.
|
||||
std::unique_ptr<Paragraph> Build();
|
||||
virtual std::unique_ptr<Paragraph> Build() = 0;
|
||||
|
||||
protected:
|
||||
ParagraphBuilder() = default;
|
||||
|
||||
private:
|
||||
std::vector<uint16_t> text_;
|
||||
// A vector of PlaceholderRuns, which detail the sizes, positioning and break
|
||||
// behavior of the empty spaces to leave. Each placeholder span corresponds to
|
||||
// a 0xFFFC (object replacement character) in text_, which indicates the
|
||||
// position in the text where the placeholder will occur. There should be an
|
||||
// equal number of 0xFFFC characters and elements in this vector.
|
||||
std::vector<PlaceholderRun> inline_placeholders_;
|
||||
// The indexes of the obj replacement characters added through
|
||||
// ParagraphBuilder::addPlaceholder().
|
||||
std::unordered_set<size_t> obj_replacement_char_indexes_;
|
||||
std::vector<size_t> style_stack_;
|
||||
std::shared_ptr<FontCollection> font_collection_;
|
||||
StyledRuns runs_;
|
||||
ParagraphStyle paragraph_style_;
|
||||
size_t paragraph_style_index_;
|
||||
|
||||
size_t PeekStyleIndex() const;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(ParagraphBuilder);
|
||||
};
|
||||
|
||||
|
||||
84
engine/src/flutter/third_party/txt/src/txt/paragraph_builder_txt.cc
vendored
Normal file
84
engine/src/flutter/third_party/txt/src/txt/paragraph_builder_txt.cc
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "paragraph_builder_txt.h"
|
||||
#include "paragraph_txt.h"
|
||||
|
||||
namespace txt {
|
||||
|
||||
ParagraphBuilderTxt::ParagraphBuilderTxt(
|
||||
const ParagraphStyle& style,
|
||||
std::shared_ptr<FontCollection> font_collection)
|
||||
: font_collection_(std::move(font_collection)) {
|
||||
SetParagraphStyle(style);
|
||||
}
|
||||
|
||||
ParagraphBuilderTxt::~ParagraphBuilderTxt() = default;
|
||||
|
||||
void ParagraphBuilderTxt::SetParagraphStyle(const ParagraphStyle& style) {
|
||||
paragraph_style_ = style;
|
||||
paragraph_style_index_ = runs_.AddStyle(style.GetTextStyle());
|
||||
runs_.StartRun(paragraph_style_index_, text_.size());
|
||||
}
|
||||
|
||||
void ParagraphBuilderTxt::PushStyle(const TextStyle& style) {
|
||||
size_t style_index = runs_.AddStyle(style);
|
||||
style_stack_.push_back(style_index);
|
||||
runs_.StartRun(style_index, text_.size());
|
||||
}
|
||||
|
||||
void ParagraphBuilderTxt::Pop() {
|
||||
if (style_stack_.empty()) {
|
||||
return;
|
||||
}
|
||||
style_stack_.pop_back();
|
||||
runs_.StartRun(PeekStyleIndex(), text_.size());
|
||||
}
|
||||
|
||||
size_t ParagraphBuilderTxt::PeekStyleIndex() const {
|
||||
return style_stack_.size() ? style_stack_.back() : paragraph_style_index_;
|
||||
}
|
||||
|
||||
const TextStyle& ParagraphBuilderTxt::PeekStyle() {
|
||||
return runs_.GetStyle(PeekStyleIndex());
|
||||
}
|
||||
|
||||
void ParagraphBuilderTxt::AddText(const std::u16string& text) {
|
||||
text_.insert(text_.end(), text.begin(), text.end());
|
||||
}
|
||||
|
||||
void ParagraphBuilderTxt::AddPlaceholder(PlaceholderRun& span) {
|
||||
obj_replacement_char_indexes_.insert(text_.size());
|
||||
runs_.StartRun(PeekStyleIndex(), text_.size());
|
||||
AddText(std::u16string(1ull, objReplacementChar));
|
||||
runs_.StartRun(PeekStyleIndex(), text_.size());
|
||||
inline_placeholders_.push_back(span);
|
||||
}
|
||||
|
||||
std::unique_ptr<Paragraph> ParagraphBuilderTxt::Build() {
|
||||
runs_.EndRunIfNeeded(text_.size());
|
||||
|
||||
std::unique_ptr<ParagraphTxt> paragraph = std::make_unique<ParagraphTxt>();
|
||||
paragraph->SetText(std::move(text_), std::move(runs_));
|
||||
paragraph->SetInlinePlaceholders(std::move(inline_placeholders_),
|
||||
std::move(obj_replacement_char_indexes_));
|
||||
paragraph->SetParagraphStyle(paragraph_style_);
|
||||
paragraph->SetFontCollection(font_collection_);
|
||||
SetParagraphStyle(paragraph_style_);
|
||||
return paragraph;
|
||||
}
|
||||
|
||||
} // namespace txt
|
||||
65
engine/src/flutter/third_party/txt/src/txt/paragraph_builder_txt.h
vendored
Normal file
65
engine/src/flutter/third_party/txt/src/txt/paragraph_builder_txt.h
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef LIB_TXT_SRC_PARAGRAPH_BUILDER_TXT_H_
|
||||
#define LIB_TXT_SRC_PARAGRAPH_BUILDER_TXT_H_
|
||||
|
||||
#include "paragraph_builder.h"
|
||||
#include "styled_runs.h"
|
||||
|
||||
namespace txt {
|
||||
|
||||
// Implementation of ParagraphBuilder that produces paragraphs backed by the
|
||||
// Minikin text layout library.
|
||||
class ParagraphBuilderTxt : public ParagraphBuilder {
|
||||
public:
|
||||
ParagraphBuilderTxt(const ParagraphStyle& style,
|
||||
std::shared_ptr<FontCollection> font_collection);
|
||||
|
||||
virtual ~ParagraphBuilderTxt();
|
||||
|
||||
virtual void PushStyle(const TextStyle& style) override;
|
||||
virtual void Pop() override;
|
||||
virtual const TextStyle& PeekStyle() override;
|
||||
virtual void AddText(const std::u16string& text) override;
|
||||
virtual void AddPlaceholder(PlaceholderRun& span) override;
|
||||
virtual std::unique_ptr<Paragraph> Build() override;
|
||||
|
||||
private:
|
||||
std::vector<uint16_t> text_;
|
||||
// A vector of PlaceholderRuns, which detail the sizes, positioning and break
|
||||
// behavior of the empty spaces to leave. Each placeholder span corresponds to
|
||||
// a 0xFFFC (object replacement character) in text_, which indicates the
|
||||
// position in the text where the placeholder will occur. There should be an
|
||||
// equal number of 0xFFFC characters and elements in this vector.
|
||||
std::vector<PlaceholderRun> inline_placeholders_;
|
||||
// The indexes of the obj replacement characters added through
|
||||
// ParagraphBuilder::addPlaceholder().
|
||||
std::unordered_set<size_t> obj_replacement_char_indexes_;
|
||||
std::vector<size_t> style_stack_;
|
||||
std::shared_ptr<FontCollection> font_collection_;
|
||||
StyledRuns runs_;
|
||||
ParagraphStyle paragraph_style_;
|
||||
size_t paragraph_style_index_;
|
||||
|
||||
void SetParagraphStyle(const ParagraphStyle& style);
|
||||
|
||||
size_t PeekStyleIndex() const;
|
||||
};
|
||||
|
||||
} // namespace txt
|
||||
|
||||
#endif // LIB_TXT_SRC_PARAGRAPH_BUILDER_TXT_H_
|
||||
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "paragraph.h"
|
||||
#include "paragraph_txt.h"
|
||||
|
||||
#include <hb.h>
|
||||
#include <minikin/Layout.h>
|
||||
@ -190,27 +190,27 @@ void FindWords(const std::vector<uint16_t>& text,
|
||||
|
||||
static const float kDoubleDecorationSpacing = 3.0f;
|
||||
|
||||
Paragraph::GlyphPosition::GlyphPosition(double x_start,
|
||||
double x_advance,
|
||||
size_t code_unit_index,
|
||||
size_t code_unit_width)
|
||||
ParagraphTxt::GlyphPosition::GlyphPosition(double x_start,
|
||||
double x_advance,
|
||||
size_t code_unit_index,
|
||||
size_t code_unit_width)
|
||||
: code_units(code_unit_index, code_unit_index + code_unit_width),
|
||||
x_pos(x_start, x_start + x_advance) {}
|
||||
|
||||
void Paragraph::GlyphPosition::Shift(double delta) {
|
||||
void ParagraphTxt::GlyphPosition::Shift(double delta) {
|
||||
x_pos.Shift(delta);
|
||||
}
|
||||
|
||||
Paragraph::GlyphLine::GlyphLine(std::vector<GlyphPosition>&& p, size_t tcu)
|
||||
ParagraphTxt::GlyphLine::GlyphLine(std::vector<GlyphPosition>&& p, size_t tcu)
|
||||
: positions(std::move(p)), total_code_units(tcu) {}
|
||||
|
||||
Paragraph::CodeUnitRun::CodeUnitRun(std::vector<GlyphPosition>&& p,
|
||||
Range<size_t> cu,
|
||||
Range<double> x,
|
||||
size_t line,
|
||||
const SkFontMetrics& metrics,
|
||||
TextDirection dir,
|
||||
const PlaceholderRun* placeholder)
|
||||
ParagraphTxt::CodeUnitRun::CodeUnitRun(std::vector<GlyphPosition>&& p,
|
||||
Range<size_t> cu,
|
||||
Range<double> x,
|
||||
size_t line,
|
||||
const SkFontMetrics& metrics,
|
||||
TextDirection dir,
|
||||
const PlaceholderRun* placeholder)
|
||||
: positions(std::move(p)),
|
||||
code_units(cu),
|
||||
x_pos(x),
|
||||
@ -219,19 +219,19 @@ Paragraph::CodeUnitRun::CodeUnitRun(std::vector<GlyphPosition>&& p,
|
||||
direction(dir),
|
||||
placeholder_run(placeholder) {}
|
||||
|
||||
void Paragraph::CodeUnitRun::Shift(double delta) {
|
||||
void ParagraphTxt::CodeUnitRun::Shift(double delta) {
|
||||
x_pos.Shift(delta);
|
||||
for (GlyphPosition& position : positions)
|
||||
position.Shift(delta);
|
||||
}
|
||||
|
||||
Paragraph::Paragraph() {
|
||||
ParagraphTxt::ParagraphTxt() {
|
||||
breaker_.setLocale(icu::Locale(), nullptr);
|
||||
}
|
||||
|
||||
Paragraph::~Paragraph() = default;
|
||||
ParagraphTxt::~ParagraphTxt() = default;
|
||||
|
||||
void Paragraph::SetText(std::vector<uint16_t> text, StyledRuns runs) {
|
||||
void ParagraphTxt::SetText(std::vector<uint16_t> text, StyledRuns runs) {
|
||||
needs_layout_ = true;
|
||||
if (text.size() == 0)
|
||||
return;
|
||||
@ -239,7 +239,7 @@ void Paragraph::SetText(std::vector<uint16_t> text, StyledRuns runs) {
|
||||
runs_ = std::move(runs);
|
||||
}
|
||||
|
||||
void Paragraph::SetInlinePlaceholders(
|
||||
void ParagraphTxt::SetInlinePlaceholders(
|
||||
std::vector<PlaceholderRun> inline_placeholders,
|
||||
std::unordered_set<size_t> obj_replacement_char_indexes) {
|
||||
needs_layout_ = true;
|
||||
@ -247,7 +247,7 @@ void Paragraph::SetInlinePlaceholders(
|
||||
obj_replacement_char_indexes_ = std::move(obj_replacement_char_indexes);
|
||||
}
|
||||
|
||||
bool Paragraph::ComputeLineBreaks() {
|
||||
bool ParagraphTxt::ComputeLineBreaks() {
|
||||
line_ranges_.clear();
|
||||
line_widths_.clear();
|
||||
max_intrinsic_width_ = 0;
|
||||
@ -379,7 +379,7 @@ bool Paragraph::ComputeLineBreaks() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Paragraph::ComputeBidiRuns(std::vector<BidiRun>* result) {
|
||||
bool ParagraphTxt::ComputeBidiRuns(std::vector<BidiRun>* result) {
|
||||
if (text_.empty())
|
||||
return true;
|
||||
|
||||
@ -496,13 +496,13 @@ bool Paragraph::ComputeBidiRuns(std::vector<BidiRun>* result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Paragraph::IsStrutValid() const {
|
||||
bool ParagraphTxt::IsStrutValid() const {
|
||||
// Font size must be positive.
|
||||
return (paragraph_style_.strut_enabled &&
|
||||
paragraph_style_.strut_font_size >= 0);
|
||||
}
|
||||
|
||||
void Paragraph::ComputeStrut(StrutMetrics* strut, SkFont& font) {
|
||||
void ParagraphTxt::ComputeStrut(StrutMetrics* strut, SkFont& font) {
|
||||
strut->ascent = 0;
|
||||
strut->descent = 0;
|
||||
strut->leading = 0;
|
||||
@ -567,9 +567,9 @@ void Paragraph::ComputeStrut(StrutMetrics* strut, SkFont& font) {
|
||||
}
|
||||
}
|
||||
|
||||
void Paragraph::ComputePlaceholder(PlaceholderRun* placeholder_run,
|
||||
double& ascent,
|
||||
double& descent) {
|
||||
void ParagraphTxt::ComputePlaceholder(PlaceholderRun* placeholder_run,
|
||||
double& ascent,
|
||||
double& descent) {
|
||||
if (placeholder_run != nullptr) {
|
||||
// Calculate how much to shift the ascent and descent to account
|
||||
// for the baseline choice.
|
||||
@ -641,10 +641,10 @@ void Paragraph::ComputePlaceholder(PlaceholderRun* placeholder_run,
|
||||
// -Apply letter spacing, alignment, justification, etc
|
||||
// -Calculate line vertical layout (ascent, descent, etc)
|
||||
// -Store per-line metrics
|
||||
void Paragraph::Layout(double width, bool force) {
|
||||
void ParagraphTxt::Layout(double width) {
|
||||
double rounded_width = floor(width);
|
||||
// Do not allow calling layout multiple times without changing anything.
|
||||
if (!needs_layout_ && rounded_width == width_ && !force) {
|
||||
if (!needs_layout_ && rounded_width == width_) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1174,7 +1174,7 @@ void Paragraph::Layout(double width, bool force) {
|
||||
longest_line_ = max_right_ - min_left_;
|
||||
}
|
||||
|
||||
double Paragraph::GetLineXOffset(double line_total_advance) {
|
||||
double ParagraphTxt::GetLineXOffset(double line_total_advance) {
|
||||
if (isinf(width_))
|
||||
return 0;
|
||||
|
||||
@ -1189,56 +1189,56 @@ double Paragraph::GetLineXOffset(double line_total_advance) {
|
||||
}
|
||||
}
|
||||
|
||||
const ParagraphStyle& Paragraph::GetParagraphStyle() const {
|
||||
const ParagraphStyle& ParagraphTxt::GetParagraphStyle() const {
|
||||
return paragraph_style_;
|
||||
}
|
||||
|
||||
double Paragraph::GetAlphabeticBaseline() const {
|
||||
double ParagraphTxt::GetAlphabeticBaseline() {
|
||||
// Currently -fAscent
|
||||
return alphabetic_baseline_;
|
||||
}
|
||||
|
||||
double Paragraph::GetIdeographicBaseline() const {
|
||||
double ParagraphTxt::GetIdeographicBaseline() {
|
||||
// TODO(garyq): Currently -fAscent + fUnderlinePosition. Verify this.
|
||||
return ideographic_baseline_;
|
||||
}
|
||||
|
||||
double Paragraph::GetMaxIntrinsicWidth() const {
|
||||
double ParagraphTxt::GetMaxIntrinsicWidth() {
|
||||
return max_intrinsic_width_;
|
||||
}
|
||||
|
||||
double Paragraph::GetMinIntrinsicWidth() const {
|
||||
double ParagraphTxt::GetMinIntrinsicWidth() {
|
||||
return min_intrinsic_width_;
|
||||
}
|
||||
|
||||
size_t Paragraph::TextSize() const {
|
||||
size_t ParagraphTxt::TextSize() const {
|
||||
return text_.size();
|
||||
}
|
||||
|
||||
double Paragraph::GetHeight() const {
|
||||
double ParagraphTxt::GetHeight() {
|
||||
return line_heights_.size() ? line_heights_.back() : 0;
|
||||
}
|
||||
|
||||
double Paragraph::GetMaxWidth() const {
|
||||
double ParagraphTxt::GetMaxWidth() {
|
||||
return width_;
|
||||
}
|
||||
|
||||
double Paragraph::GetLongestLine() const {
|
||||
double ParagraphTxt::GetLongestLine() {
|
||||
return longest_line_;
|
||||
}
|
||||
|
||||
void Paragraph::SetParagraphStyle(const ParagraphStyle& style) {
|
||||
void ParagraphTxt::SetParagraphStyle(const ParagraphStyle& style) {
|
||||
needs_layout_ = true;
|
||||
paragraph_style_ = style;
|
||||
}
|
||||
|
||||
void Paragraph::SetFontCollection(
|
||||
void ParagraphTxt::SetFontCollection(
|
||||
std::shared_ptr<FontCollection> font_collection) {
|
||||
font_collection_ = std::move(font_collection);
|
||||
}
|
||||
|
||||
std::shared_ptr<minikin::FontCollection>
|
||||
Paragraph::GetMinikinFontCollectionForStyle(const TextStyle& style) {
|
||||
ParagraphTxt::GetMinikinFontCollectionForStyle(const TextStyle& style) {
|
||||
std::string locale;
|
||||
if (!style.locale.empty()) {
|
||||
uint32_t language_list_id =
|
||||
@ -1254,7 +1254,7 @@ Paragraph::GetMinikinFontCollectionForStyle(const TextStyle& style) {
|
||||
style.font_families, locale);
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> Paragraph::GetDefaultSkiaTypeface(const TextStyle& style) {
|
||||
sk_sp<SkTypeface> ParagraphTxt::GetDefaultSkiaTypeface(const TextStyle& style) {
|
||||
std::shared_ptr<minikin::FontCollection> collection =
|
||||
GetMinikinFontCollectionForStyle(style);
|
||||
if (!collection) {
|
||||
@ -1267,7 +1267,7 @@ sk_sp<SkTypeface> Paragraph::GetDefaultSkiaTypeface(const TextStyle& style) {
|
||||
|
||||
// The x,y coordinates will be the very top left corner of the rendered
|
||||
// paragraph.
|
||||
void Paragraph::Paint(SkCanvas* canvas, double x, double y) {
|
||||
void ParagraphTxt::Paint(SkCanvas* canvas, double x, double y) {
|
||||
SkPoint base_offset = SkPoint::Make(x, y);
|
||||
SkPaint paint;
|
||||
// Paint the background first before painting any text to prevent
|
||||
@ -1291,9 +1291,9 @@ void Paragraph::Paint(SkCanvas* canvas, double x, double y) {
|
||||
}
|
||||
}
|
||||
|
||||
void Paragraph::PaintDecorations(SkCanvas* canvas,
|
||||
const PaintRecord& record,
|
||||
SkPoint base_offset) {
|
||||
void ParagraphTxt::PaintDecorations(SkCanvas* canvas,
|
||||
const PaintRecord& record,
|
||||
SkPoint base_offset) {
|
||||
if (record.style().decoration == TextDecoration::kNone)
|
||||
return;
|
||||
|
||||
@ -1443,11 +1443,11 @@ void Paragraph::PaintDecorations(SkCanvas* canvas,
|
||||
}
|
||||
}
|
||||
|
||||
void Paragraph::ComputeWavyDecoration(SkPath& path,
|
||||
double x,
|
||||
double y,
|
||||
double width,
|
||||
double thickness) {
|
||||
void ParagraphTxt::ComputeWavyDecoration(SkPath& path,
|
||||
double x,
|
||||
double y,
|
||||
double width,
|
||||
double thickness) {
|
||||
int wave_count = 0;
|
||||
double x_start = 0;
|
||||
// One full wavelength is 4 * thickness.
|
||||
@ -1485,9 +1485,9 @@ void Paragraph::ComputeWavyDecoration(SkPath& path,
|
||||
path.rQuadTo(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
void Paragraph::PaintBackground(SkCanvas* canvas,
|
||||
const PaintRecord& record,
|
||||
SkPoint base_offset) {
|
||||
void ParagraphTxt::PaintBackground(SkCanvas* canvas,
|
||||
const PaintRecord& record,
|
||||
SkPoint base_offset) {
|
||||
if (!record.style().has_background)
|
||||
return;
|
||||
|
||||
@ -1498,9 +1498,9 @@ void Paragraph::PaintBackground(SkCanvas* canvas,
|
||||
canvas->drawRect(rect, record.style().background);
|
||||
}
|
||||
|
||||
void Paragraph::PaintShadow(SkCanvas* canvas,
|
||||
const PaintRecord& record,
|
||||
SkPoint offset) {
|
||||
void ParagraphTxt::PaintShadow(SkCanvas* canvas,
|
||||
const PaintRecord& record,
|
||||
SkPoint offset) {
|
||||
if (record.style().text_shadows.size() == 0)
|
||||
return;
|
||||
for (TextShadow text_shadow : record.style().text_shadows) {
|
||||
@ -1519,11 +1519,11 @@ void Paragraph::PaintShadow(SkCanvas* canvas,
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Paragraph::TextBox> Paragraph::GetRectsForRange(
|
||||
std::vector<Paragraph::TextBox> ParagraphTxt::GetRectsForRange(
|
||||
size_t start,
|
||||
size_t end,
|
||||
RectHeightStyle rect_height_style,
|
||||
RectWidthStyle rect_width_style) const {
|
||||
RectWidthStyle rect_width_style) {
|
||||
// Struct that holds calculated metrics for each line.
|
||||
struct LineBoxMetrics {
|
||||
std::vector<Paragraph::TextBox> boxes;
|
||||
@ -1742,9 +1742,9 @@ std::vector<Paragraph::TextBox> Paragraph::GetRectsForRange(
|
||||
return boxes;
|
||||
}
|
||||
|
||||
Paragraph::PositionWithAffinity Paragraph::GetGlyphPositionAtCoordinate(
|
||||
Paragraph::PositionWithAffinity ParagraphTxt::GetGlyphPositionAtCoordinate(
|
||||
double dx,
|
||||
double dy) const {
|
||||
double dy) {
|
||||
if (line_heights_.empty())
|
||||
return PositionWithAffinity(0, DOWNSTREAM);
|
||||
|
||||
@ -1803,7 +1803,7 @@ Paragraph::PositionWithAffinity Paragraph::GetGlyphPositionAtCoordinate(
|
||||
|
||||
// We don't cache this because since this returns all boxes, it is usually
|
||||
// unnecessary to call this multiple times in succession.
|
||||
std::vector<Paragraph::TextBox> Paragraph::GetRectsForPlaceholders() const {
|
||||
std::vector<Paragraph::TextBox> ParagraphTxt::GetRectsForPlaceholders() {
|
||||
// Struct that holds calculated metrics for each line.
|
||||
struct LineBoxMetrics {
|
||||
std::vector<Paragraph::TextBox> boxes;
|
||||
@ -1841,7 +1841,7 @@ std::vector<Paragraph::TextBox> Paragraph::GetRectsForPlaceholders() const {
|
||||
return boxes;
|
||||
}
|
||||
|
||||
Paragraph::Range<size_t> Paragraph::GetWordBoundary(size_t offset) const {
|
||||
Paragraph::Range<size_t> ParagraphTxt::GetWordBoundary(size_t offset) {
|
||||
if (text_.size() == 0)
|
||||
return Range<size_t>(0, 0);
|
||||
|
||||
@ -1864,15 +1864,15 @@ Paragraph::Range<size_t> Paragraph::GetWordBoundary(size_t offset) const {
|
||||
return Range<size_t>(prev_boundary, next_boundary);
|
||||
}
|
||||
|
||||
size_t Paragraph::GetLineCount() const {
|
||||
size_t ParagraphTxt::GetLineCount() {
|
||||
return line_heights_.size();
|
||||
}
|
||||
|
||||
bool Paragraph::DidExceedMaxLines() const {
|
||||
bool ParagraphTxt::DidExceedMaxLines() {
|
||||
return did_exceed_max_lines_;
|
||||
}
|
||||
|
||||
void Paragraph::SetDirty(bool dirty) {
|
||||
void ParagraphTxt::SetDirty(bool dirty) {
|
||||
needs_layout_ = dirty;
|
||||
}
|
||||
|
||||
400
engine/src/flutter/third_party/txt/src/txt/paragraph_txt.h
vendored
Normal file
400
engine/src/flutter/third_party/txt/src/txt/paragraph_txt.h
vendored
Normal file
@ -0,0 +1,400 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef LIB_TXT_SRC_PARAGRAPH_TXT_H_
|
||||
#define LIB_TXT_SRC_PARAGRAPH_TXT_H_
|
||||
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "flutter/fml/compiler_specific.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "font_collection.h"
|
||||
#include "minikin/LineBreaker.h"
|
||||
#include "paint_record.h"
|
||||
#include "paragraph.h"
|
||||
#include "paragraph_style.h"
|
||||
#include "placeholder_run.h"
|
||||
#include "styled_runs.h"
|
||||
#include "third_party/googletest/googletest/include/gtest/gtest_prod.h" // nogncheck
|
||||
#include "third_party/skia/include/core/SkFontMetrics.h"
|
||||
#include "third_party/skia/include/core/SkRect.h"
|
||||
#include "utils/WindowsUtils.h"
|
||||
|
||||
namespace txt {
|
||||
|
||||
using GlyphID = uint32_t;
|
||||
|
||||
// Constant with the unicode codepoint for the "Object replacement character".
|
||||
// Used as a stand-in character for Placeholder boxes.
|
||||
const int objReplacementChar = 0xFFFC;
|
||||
// Constant with the unicode codepoint for the "Replacement character". This is
|
||||
// the character that commonly renders as a black diamond with a white question
|
||||
// mark. Used to replace non-placeholder instances of 0xFFFC in the text buffer.
|
||||
const int replacementChar = 0xFFFD;
|
||||
|
||||
// Paragraph provides Layout, metrics, and painting capabilities for text. Once
|
||||
// a Paragraph is constructed with ParagraphBuilder::Build(), an example basic
|
||||
// workflow can be this:
|
||||
//
|
||||
// std::unique_ptr<Paragraph> paragraph = paragraph_builder.Build();
|
||||
// paragraph->Layout(<somewidthgoeshere>);
|
||||
// paragraph->Paint(<someSkCanvas>, <xpos>, <ypos>);
|
||||
class ParagraphTxt : public Paragraph {
|
||||
public:
|
||||
// Constructor. It is highly recommended to construct a paragraph with a
|
||||
// ParagraphBuilder.
|
||||
ParagraphTxt();
|
||||
|
||||
virtual ~ParagraphTxt();
|
||||
|
||||
// Minikin Layout doLayout() and LineBreaker addStyleRun() has an
|
||||
// O(N^2) (according to benchmarks) time complexity where N is the total
|
||||
// number of characters. However, this is not significant for reasonably sized
|
||||
// paragraphs. It is currently recommended to break up very long paragraphs
|
||||
// (10k+ characters) to ensure speedy layout.
|
||||
virtual void Layout(double width) override;
|
||||
|
||||
virtual void Paint(SkCanvas* canvas, double x, double y) override;
|
||||
|
||||
// Getter for paragraph_style_.
|
||||
const ParagraphStyle& GetParagraphStyle() const;
|
||||
|
||||
// Returns the number of characters/unicode characters. AKA text_.size()
|
||||
size_t TextSize() const;
|
||||
|
||||
double GetHeight() override;
|
||||
|
||||
double GetMaxWidth() override;
|
||||
|
||||
double GetLongestLine() override;
|
||||
|
||||
double GetAlphabeticBaseline() override;
|
||||
|
||||
double GetIdeographicBaseline() override;
|
||||
|
||||
double GetMaxIntrinsicWidth() override;
|
||||
|
||||
// Currently, calculated similarly to as GetLayoutWidth(), however this is not
|
||||
// necessarily 100% correct in all cases.
|
||||
double GetMinIntrinsicWidth() override;
|
||||
|
||||
std::vector<TextBox> GetRectsForRange(
|
||||
size_t start,
|
||||
size_t end,
|
||||
RectHeightStyle rect_height_style,
|
||||
RectWidthStyle rect_width_style) override;
|
||||
|
||||
PositionWithAffinity GetGlyphPositionAtCoordinate(double dx,
|
||||
double dy) override;
|
||||
|
||||
std::vector<Paragraph::TextBox> GetRectsForPlaceholders() override;
|
||||
|
||||
Range<size_t> GetWordBoundary(size_t offset) override;
|
||||
|
||||
// Returns the number of lines the paragraph takes up. If the text exceeds the
|
||||
// amount width and maxlines provides, Layout() truncates the extra text from
|
||||
// the layout and this will return the max lines allowed.
|
||||
size_t GetLineCount();
|
||||
|
||||
bool DidExceedMaxLines() override;
|
||||
|
||||
// Sets the needs_layout_ to dirty. When Layout() is called, a new Layout will
|
||||
// be performed when this is set to true. Can also be used to prevent a new
|
||||
// Layout from being calculated by setting to false.
|
||||
void SetDirty(bool dirty = true);
|
||||
|
||||
private:
|
||||
friend class ParagraphBuilderTxt;
|
||||
FRIEND_TEST(ParagraphTest, SimpleParagraph);
|
||||
FRIEND_TEST(ParagraphTest, SimpleRedParagraph);
|
||||
FRIEND_TEST(ParagraphTest, RainbowParagraph);
|
||||
FRIEND_TEST(ParagraphTest, DefaultStyleParagraph);
|
||||
FRIEND_TEST(ParagraphTest, BoldParagraph);
|
||||
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, LeftAlignParagraph);
|
||||
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, RightAlignParagraph);
|
||||
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, CenterAlignParagraph);
|
||||
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, JustifyAlignParagraph);
|
||||
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, JustifyRTL);
|
||||
FRIEND_TEST(ParagraphTest, DecorationsParagraph);
|
||||
FRIEND_TEST(ParagraphTest, ItalicsParagraph);
|
||||
FRIEND_TEST(ParagraphTest, ChineseParagraph);
|
||||
FRIEND_TEST(ParagraphTest, DISABLED_ArabicParagraph);
|
||||
FRIEND_TEST(ParagraphTest, SpacingParagraph);
|
||||
FRIEND_TEST(ParagraphTest, LongWordParagraph);
|
||||
FRIEND_TEST(ParagraphTest, KernScaleParagraph);
|
||||
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, NewlineParagraph);
|
||||
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, EmojiParagraph);
|
||||
FRIEND_TEST(ParagraphTest, HyphenBreakParagraph);
|
||||
FRIEND_TEST(ParagraphTest, RepeatLayoutParagraph);
|
||||
FRIEND_TEST(ParagraphTest, Ellipsize);
|
||||
FRIEND_TEST(ParagraphTest, UnderlineShiftParagraph);
|
||||
FRIEND_TEST(ParagraphTest, WavyDecorationParagraph);
|
||||
FRIEND_TEST(ParagraphTest, SimpleShadow);
|
||||
FRIEND_TEST(ParagraphTest, ComplexShadow);
|
||||
FRIEND_TEST(ParagraphTest, FontFallbackParagraph);
|
||||
FRIEND_TEST(ParagraphTest, InlinePlaceholder0xFFFCParagraph);
|
||||
FRIEND_TEST(ParagraphTest, FontFeaturesParagraph);
|
||||
|
||||
// Starting data to layout.
|
||||
std::vector<uint16_t> text_;
|
||||
// A vector of PlaceholderRuns, which detail the sizes, positioning and break
|
||||
// behavior of the empty spaces to leave. Each placeholder span corresponds to
|
||||
// a 0xFFFC (object replacement character) in text_, which indicates the
|
||||
// position in the text where the placeholder will occur. There should be an
|
||||
// equal number of 0xFFFC characters and elements in this vector.
|
||||
std::vector<PlaceholderRun> inline_placeholders_;
|
||||
// The indexes of the boxes that correspond to an inline placeholder.
|
||||
std::vector<size_t> inline_placeholder_boxes_;
|
||||
// The indexes of instances of 0xFFFC that correspond to placeholders. This is
|
||||
// necessary since the user may pass in manually entered 0xFFFC values using
|
||||
// AddText().
|
||||
std::unordered_set<size_t> obj_replacement_char_indexes_;
|
||||
StyledRuns runs_;
|
||||
ParagraphStyle paragraph_style_;
|
||||
std::shared_ptr<FontCollection> font_collection_;
|
||||
|
||||
minikin::LineBreaker breaker_;
|
||||
mutable std::unique_ptr<icu::BreakIterator> word_breaker_;
|
||||
|
||||
struct LineRange {
|
||||
LineRange(size_t s, size_t e, size_t eew, size_t ein, bool h)
|
||||
: start(s),
|
||||
end(e),
|
||||
end_excluding_whitespace(eew),
|
||||
end_including_newline(ein),
|
||||
hard_break(h) {}
|
||||
size_t start, end;
|
||||
size_t end_excluding_whitespace;
|
||||
size_t end_including_newline;
|
||||
bool hard_break;
|
||||
};
|
||||
std::vector<LineRange> line_ranges_;
|
||||
std::vector<double> line_widths_;
|
||||
|
||||
// Stores the result of Layout().
|
||||
std::vector<PaintRecord> records_;
|
||||
|
||||
std::vector<double> line_heights_;
|
||||
std::vector<double> line_baselines_;
|
||||
bool did_exceed_max_lines_;
|
||||
|
||||
// Strut metrics of zero will have no effect on the layout.
|
||||
struct StrutMetrics {
|
||||
double ascent = 0; // Positive value to keep signs clear.
|
||||
double descent = 0;
|
||||
double leading = 0;
|
||||
double half_leading = 0;
|
||||
double line_height = 0;
|
||||
bool force_strut = false;
|
||||
};
|
||||
|
||||
StrutMetrics strut_;
|
||||
|
||||
// Metrics for use in GetRectsForRange(...);
|
||||
// Per-line max metrics over all runs in a given line.
|
||||
std::vector<SkScalar> line_max_spacings_;
|
||||
std::vector<SkScalar> line_max_descent_;
|
||||
std::vector<SkScalar> line_max_ascent_;
|
||||
// Overall left and right extremes over all lines.
|
||||
double max_right_;
|
||||
double min_left_;
|
||||
|
||||
class BidiRun {
|
||||
public:
|
||||
// Constructs a BidiRun with is_ghost defaulted to false.
|
||||
BidiRun(size_t s, size_t e, TextDirection d, const TextStyle& st)
|
||||
: start_(s), end_(e), direction_(d), style_(&st), is_ghost_(false) {}
|
||||
|
||||
// Constructs a BidiRun with a custom is_ghost flag.
|
||||
BidiRun(size_t s,
|
||||
size_t e,
|
||||
TextDirection d,
|
||||
const TextStyle& st,
|
||||
bool is_ghost)
|
||||
: start_(s), end_(e), direction_(d), style_(&st), is_ghost_(is_ghost) {}
|
||||
|
||||
// Constructs a placeholder bidi run.
|
||||
BidiRun(size_t s,
|
||||
size_t e,
|
||||
TextDirection d,
|
||||
const TextStyle& st,
|
||||
PlaceholderRun& placeholder)
|
||||
: start_(s),
|
||||
end_(e),
|
||||
direction_(d),
|
||||
style_(&st),
|
||||
placeholder_run_(&placeholder) {}
|
||||
|
||||
size_t start() const { return start_; }
|
||||
size_t end() const { return end_; }
|
||||
size_t size() const { return end_ - start_; }
|
||||
TextDirection direction() const { return direction_; }
|
||||
const TextStyle& style() const { return *style_; }
|
||||
PlaceholderRun* placeholder_run() const { return placeholder_run_; }
|
||||
bool is_rtl() const { return direction_ == TextDirection::rtl; }
|
||||
// Tracks if the run represents trailing whitespace.
|
||||
bool is_ghost() const { return is_ghost_; }
|
||||
bool is_placeholder_run() const { return placeholder_run_ != nullptr; }
|
||||
|
||||
private:
|
||||
size_t start_, end_;
|
||||
TextDirection direction_;
|
||||
const TextStyle* style_;
|
||||
bool is_ghost_;
|
||||
PlaceholderRun* placeholder_run_ = nullptr;
|
||||
};
|
||||
|
||||
struct GlyphPosition {
|
||||
Range<size_t> code_units;
|
||||
Range<double> x_pos;
|
||||
|
||||
GlyphPosition(double x_start,
|
||||
double x_advance,
|
||||
size_t code_unit_index,
|
||||
size_t code_unit_width);
|
||||
|
||||
void Shift(double delta);
|
||||
};
|
||||
|
||||
struct GlyphLine {
|
||||
// Glyph positions sorted by x coordinate.
|
||||
const std::vector<GlyphPosition> positions;
|
||||
const size_t total_code_units;
|
||||
|
||||
GlyphLine(std::vector<GlyphPosition>&& p, size_t tcu);
|
||||
};
|
||||
|
||||
struct CodeUnitRun {
|
||||
// Glyph positions sorted by code unit index.
|
||||
std::vector<GlyphPosition> positions;
|
||||
Range<size_t> code_units;
|
||||
Range<double> x_pos;
|
||||
size_t line_number;
|
||||
SkFontMetrics font_metrics;
|
||||
TextDirection direction;
|
||||
const PlaceholderRun* placeholder_run;
|
||||
|
||||
CodeUnitRun(std::vector<GlyphPosition>&& p,
|
||||
Range<size_t> cu,
|
||||
Range<double> x,
|
||||
size_t line,
|
||||
const SkFontMetrics& metrics,
|
||||
TextDirection dir,
|
||||
const PlaceholderRun* placeholder);
|
||||
|
||||
void Shift(double delta);
|
||||
};
|
||||
|
||||
// Holds the laid out x positions of each glyph.
|
||||
std::vector<GlyphLine> glyph_lines_;
|
||||
|
||||
// Holds the positions of each range of code units in the text.
|
||||
// Sorted in code unit index order.
|
||||
std::vector<CodeUnitRun> code_unit_runs_;
|
||||
// Holds the positions of the inline placeholders.
|
||||
std::vector<CodeUnitRun> inline_placeholder_code_unit_runs_;
|
||||
|
||||
// The max width of the paragraph as provided in the most recent Layout()
|
||||
// call.
|
||||
double width_ = -1.0f;
|
||||
double longest_line_ = -1.0f;
|
||||
double max_intrinsic_width_ = 0;
|
||||
double min_intrinsic_width_ = 0;
|
||||
double alphabetic_baseline_ = FLT_MAX;
|
||||
double ideographic_baseline_ = FLT_MAX;
|
||||
|
||||
bool needs_layout_ = true;
|
||||
|
||||
struct WaveCoordinates {
|
||||
double x_start;
|
||||
double y_start;
|
||||
double x_end;
|
||||
double y_end;
|
||||
|
||||
WaveCoordinates(double x_s, double y_s, double x_e, double y_e)
|
||||
: x_start(x_s), y_start(y_s), x_end(x_e), y_end(y_e) {}
|
||||
};
|
||||
|
||||
// Passes in the text and Styled Runs. text_ and runs_ will later be passed
|
||||
// into breaker_ in InitBreaker(), which is called in Layout().
|
||||
void SetText(std::vector<uint16_t> text, StyledRuns runs);
|
||||
|
||||
void SetParagraphStyle(const ParagraphStyle& style);
|
||||
|
||||
void SetFontCollection(std::shared_ptr<FontCollection> font_collection);
|
||||
|
||||
void SetInlinePlaceholders(
|
||||
std::vector<PlaceholderRun> inline_placeholders,
|
||||
std::unordered_set<size_t> obj_replacement_char_indexes);
|
||||
|
||||
// Break the text into lines.
|
||||
bool ComputeLineBreaks();
|
||||
|
||||
// Break the text into runs based on LTR/RTL text direction.
|
||||
bool ComputeBidiRuns(std::vector<BidiRun>* result);
|
||||
|
||||
// Calculates and populates strut based on paragraph_style_ strut info.
|
||||
void ComputeStrut(StrutMetrics* strut, SkFont& font);
|
||||
|
||||
// Adjusts the ascent and descent based on the existence and type of
|
||||
// placeholder. This method sets the proper metrics to achieve the different
|
||||
// PlaceholderAlignment options.
|
||||
void ComputePlaceholder(PlaceholderRun* placeholder_run,
|
||||
double& ascent,
|
||||
double& descent);
|
||||
|
||||
bool IsStrutValid() const;
|
||||
|
||||
// Calculate the starting X offset of a line based on the line's width and
|
||||
// alignment.
|
||||
double GetLineXOffset(double line_total_advance);
|
||||
|
||||
// Creates and draws the decorations onto the canvas.
|
||||
void PaintDecorations(SkCanvas* canvas,
|
||||
const PaintRecord& record,
|
||||
SkPoint base_offset);
|
||||
|
||||
// Computes the beziers for a wavy decoration. The results will be
|
||||
// applied to path.
|
||||
void ComputeWavyDecoration(SkPath& path,
|
||||
double x,
|
||||
double y,
|
||||
double width,
|
||||
double thickness);
|
||||
|
||||
// Draws the background onto the canvas.
|
||||
void PaintBackground(SkCanvas* canvas,
|
||||
const PaintRecord& record,
|
||||
SkPoint base_offset);
|
||||
|
||||
// Draws the shadows onto the canvas.
|
||||
void PaintShadow(SkCanvas* canvas, const PaintRecord& record, SkPoint offset);
|
||||
|
||||
// Obtain a Minikin font collection matching this text style.
|
||||
std::shared_ptr<minikin::FontCollection> GetMinikinFontCollectionForStyle(
|
||||
const TextStyle& style);
|
||||
|
||||
// Get a default SkTypeface for a text style.
|
||||
sk_sp<SkTypeface> GetDefaultSkiaTypeface(const TextStyle& style);
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(ParagraphTxt);
|
||||
};
|
||||
|
||||
} // namespace txt
|
||||
|
||||
#endif // LIB_TXT_SRC_PARAGRAPH_TXT_H_
|
||||
File diff suppressed because it is too large
Load Diff
@ -118,4 +118,12 @@ std::shared_ptr<FontCollection> GetTestFontCollection() {
|
||||
return collection;
|
||||
}
|
||||
|
||||
// Build a paragraph and return it as a ParagraphTxt usable by tests that need
|
||||
// access to ParagraphTxt internals.
|
||||
std::unique_ptr<ParagraphTxt> BuildParagraph(
|
||||
txt::ParagraphBuilderTxt& builder) {
|
||||
return std::unique_ptr<txt::ParagraphTxt>(
|
||||
static_cast<txt::ParagraphTxt*>(builder.Build().release()));
|
||||
}
|
||||
|
||||
} // namespace txt
|
||||
|
||||
@ -18,6 +18,8 @@
|
||||
|
||||
#include "flutter/fml/command_line.h"
|
||||
#include "txt/font_collection.h"
|
||||
#include "txt/paragraph_builder_txt.h"
|
||||
#include "txt/paragraph_txt.h"
|
||||
|
||||
namespace txt {
|
||||
|
||||
@ -31,4 +33,6 @@ void SetCommandLine(fml::CommandLine cmd);
|
||||
|
||||
std::shared_ptr<FontCollection> GetTestFontCollection();
|
||||
|
||||
std::unique_ptr<ParagraphTxt> BuildParagraph(ParagraphBuilderTxt& builder);
|
||||
|
||||
} // namespace txt
|
||||
|
||||
@ -93,6 +93,7 @@ def to_gn_args(args):
|
||||
gn_args['skia_use_expat'] = args.target_os == 'android'
|
||||
gn_args['skia_use_fontconfig'] = args.enable_fontconfig
|
||||
gn_args['flutter_use_fontconfig'] = args.enable_fontconfig
|
||||
gn_args['flutter_enable_skshaper'] = args.enable_skshaper
|
||||
gn_args['is_official_build'] = True # Disable Skia test utilities.
|
||||
gn_args['dart_component_kind'] = 'static_library' # Always link Dart in statically.
|
||||
gn_args['is_debug'] = args.unoptimized
|
||||
@ -307,6 +308,7 @@ def parse_args(args):
|
||||
parser.add_argument('--enable-metal', action='store_true', default=False)
|
||||
|
||||
parser.add_argument('--enable-fontconfig', action='store_true', default=False)
|
||||
parser.add_argument('--enable-skshaper', action='store_true', default=False)
|
||||
|
||||
parser.add_argument('--embedder-for-target', dest='embedder_for_target', action='store_true', default=False)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user