Reland "Initial integration of libtxt with Flutter alongside Blink." (flutter/engine#3793)

* Transition to Hybrid lib/txt and blink text system.
This commit is contained in:
Gary Qian 2017-06-19 15:21:41 -07:00 committed by GitHub
parent ec07bed91f
commit d9bc2f5604
18 changed files with 671 additions and 203 deletions

3
DEPS
View File

@ -71,6 +71,9 @@ deps = {
'src/lib/zip':
Var('fuchsia_git') + '/zip' + '@' + '92dc87ca645fe8e9f5151ef6dac86d8311a7222f',
'src/lib/txt':
Var('fuchsia_git') + '/txt' + '@' + 'b44e28c2fd75d7d4b9dcc862bb2c01a090bb53e1',
'src/third_party/gtest':
Var('fuchsia_git') + '/third_party/gtest' + '@' + 'c00f82917331efbbd27124b537e4ccc915a02b72',

View File

@ -8,6 +8,7 @@ group("flutter") {
deps = [
"//flutter/lib/snapshot:generate_snapshot_bin",
"//flutter/sky",
"//lib/txt",
]
if (is_fuchsia) {
@ -30,6 +31,8 @@ group("flutter") {
"//flutter/sky/engine/wtf:wtf_unittests",
"//flutter/synchronization:synchronization_unittests",
"//lib/ftl:ftl_unittests",
"//lib/txt/examples:txt_example($host_toolchain)",
"//lib/txt/tests($host_toolchain)", # txt_unittests
]
}
}

View File

@ -27,6 +27,7 @@ struct Settings {
bool use_test_fonts = false;
bool dart_non_checked_mode = false;
bool enable_software_rendering = false;
bool using_blink = true;
std::string aot_snapshot_path;
std::string aot_vm_snapshot_data_filename;
std::string aot_vm_snapshot_instr_filename;

View File

@ -3,6 +3,7 @@
# found in the LICENSE file.
source_set("ui") {
sources = [
"compositing/scene.cc",
"compositing/scene.h",
@ -55,6 +56,12 @@ source_set("ui") {
"text/paragraph.h",
"text/paragraph_builder.cc",
"text/paragraph_builder.h",
"text/paragraph_impl.cc",
"text/paragraph_impl.h",
"text/paragraph_impl_blink.cc",
"text/paragraph_impl_blink.h",
"text/paragraph_impl_txt.cc",
"text/paragraph_impl_txt.h",
"text/text_box.cc",
"text/text_box.h",
"ui_dart_state.cc",
@ -83,5 +90,6 @@ source_set("ui") {
"//lib/tonic",
"//third_party/skia",
"//third_party/skia:gpu",
"//lib/txt",
]
}

View File

@ -4,14 +4,16 @@
#include "flutter/lib/ui/text/paragraph.h"
#include "flutter/common/settings.h"
#include "flutter/common/threads.h"
#include "flutter/sky/engine/core/rendering/PaintInfo.h"
#include "flutter/sky/engine/core/rendering/RenderText.h"
#include "flutter/sky/engine/core/rendering/RenderParagraph.h"
#include "flutter/sky/engine/core/rendering/RenderText.h"
#include "flutter/sky/engine/core/rendering/style/RenderStyle.h"
#include "flutter/sky/engine/platform/fonts/FontCache.h"
#include "flutter/sky/engine/platform/graphics/GraphicsContext.h"
#include "flutter/sky/engine/platform/text/TextBoundaries.h"
#include "flutter/sky/engine/wtf/PassOwnPtr.h"
#include "lib/ftl/tasks/task_runner.h"
#include "lib/tonic/converter/dart_converter.h"
#include "lib/tonic/dart_args.h"
@ -31,7 +33,7 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Paragraph);
V(Paragraph, maxIntrinsicWidth) \
V(Paragraph, alphabeticBaseline) \
V(Paragraph, ideographicBaseline) \
V(Paragraph, didExceedMaxLines) \
V(Paragraph, didExceedMaxLines) \
V(Paragraph, layout) \
V(Paragraph, paint) \
V(Paragraph, getWordBoundary) \
@ -41,155 +43,65 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Paragraph);
DART_BIND_ALL(Paragraph, FOR_EACH_BINDING)
Paragraph::Paragraph(PassOwnPtr<RenderView> renderView)
: m_renderView(renderView) {}
: m_paragraphImpl(std::make_unique<ParagraphImplBlink>(renderView)) {}
Paragraph::Paragraph(std::unique_ptr<txt::Paragraph> paragraph)
: m_paragraphImpl(
std::make_unique<ParagraphImplTxt>(std::move(paragraph))) {}
Paragraph::~Paragraph() {
if (m_renderView) {
RenderView* renderView = m_renderView.leakPtr();
Threads::UI()->PostTask(
[renderView]() { renderView->destroy(); });
Threads::UI()->PostTask([renderView]() { renderView->destroy(); });
}
}
double Paragraph::width() {
return firstChildBox()->width();
return m_paragraphImpl->width();
}
double Paragraph::height() {
return firstChildBox()->height();
return m_paragraphImpl->height();
}
double Paragraph::minIntrinsicWidth() {
return firstChildBox()->minPreferredLogicalWidth();
return m_paragraphImpl->minIntrinsicWidth();
}
double Paragraph::maxIntrinsicWidth() {
return firstChildBox()->maxPreferredLogicalWidth();
return m_paragraphImpl->maxIntrinsicWidth();
}
double Paragraph::alphabeticBaseline() {
return firstChildBox()->firstLineBoxBaseline(
FontBaselineOrAuto(AlphabeticBaseline));
return m_paragraphImpl->alphabeticBaseline();
}
double Paragraph::ideographicBaseline() {
return firstChildBox()->firstLineBoxBaseline(
FontBaselineOrAuto(IdeographicBaseline));
return m_paragraphImpl->ideographicBaseline();
}
bool Paragraph::didExceedMaxLines() {
RenderBox* box = firstChildBox();
ASSERT(box->isRenderParagraph());
RenderParagraph* paragraph = static_cast<RenderParagraph*>(box);
return paragraph->didExceedMaxLines();
return m_paragraphImpl->didExceedMaxLines();
}
void Paragraph::layout(double width) {
FontCachePurgePreventer fontCachePurgePreventer;
int maxWidth = LayoutUnit(width); // Handles infinity properly.
m_renderView->setFrameViewSize(IntSize(maxWidth, intMaxForLayoutUnit));
m_renderView->layout();
m_paragraphImpl->layout(width);
}
void Paragraph::paint(Canvas* canvas, double x, double y) {
SkCanvas* skCanvas = canvas->canvas();
if (!skCanvas)
return;
FontCachePurgePreventer fontCachePurgePreventer;
// Very simplified painting to allow painting an arbitrary (layer-less)
// subtree.
RenderBox* box = firstChildBox();
skCanvas->translate(x, y);
GraphicsContext context(skCanvas);
Vector<RenderBox*> layers;
LayoutRect bounds = box->absoluteBoundingBoxRect();
FTL_DCHECK(bounds.x() == 0 && bounds.y() == 0);
PaintInfo paintInfo(&context, enclosingIntRect(bounds), box);
box->paint(paintInfo, LayoutPoint(), layers);
// Note we're ignoring any layers encountered.
// TODO(abarth): Remove the concept of RenderLayers.
skCanvas->translate(-x, -y);
m_paragraphImpl->paint(canvas, x, y);
}
std::vector<TextBox> Paragraph::getRectsForRange(unsigned start, unsigned end) {
if (end <= start || start == end)
return std::vector<TextBox>();
unsigned offset = 0;
std::vector<TextBox> boxes;
for (RenderObject* object = m_renderView.get(); object;
object = object->nextInPreOrder()) {
if (!object->isText())
continue;
RenderText* text = toRenderText(object);
unsigned length = text->textLength();
if (offset + length > start) {
unsigned startOffset = offset > start ? 0 : start - offset;
unsigned endOffset = end - offset;
text->appendAbsoluteTextBoxesForRange(boxes, startOffset, endOffset);
}
offset += length;
if (offset >= end)
break;
}
return boxes;
}
int Paragraph::absoluteOffsetForPosition(const PositionWithAffinity& position) {
FTL_DCHECK(position.renderer());
unsigned offset = 0;
for (RenderObject* object = m_renderView.get(); object;
object = object->nextInPreOrder()) {
if (object == position.renderer())
return offset + position.offset();
if (object->isText()) {
RenderText* text = toRenderText(object);
offset += text->textLength();
}
}
FTL_DCHECK(false);
return 0;
return m_paragraphImpl->getRectsForRange(start, end);
}
Dart_Handle Paragraph::getPositionForOffset(double dx, double dy) {
LayoutPoint point(dx, dy);
PositionWithAffinity position = m_renderView->positionForPoint(point);
Dart_Handle result = Dart_NewList(2);
Dart_ListSetAt(result, 0, ToDart(absoluteOffsetForPosition(position)));
Dart_ListSetAt(result, 1, ToDart(static_cast<int>(position.affinity())));
return result;
return m_paragraphImpl->getPositionForOffset(dx, dy);
}
Dart_Handle Paragraph::getWordBoundary(unsigned offset) {
String text;
int start = 0, end = 0;
for (RenderObject* object = m_renderView.get(); object;
object = object->nextInPreOrder()) {
if (!object->isText())
continue;
RenderText* renderText = toRenderText(object);
text.append(renderText->text());
}
TextBreakIterator* it = wordBreakIterator(text, 0, text.length());
if (it) {
end = it->following(offset);
if (end < 0)
end = it->last();
start = it->previous();
}
Dart_Handle result = Dart_NewList(2);
Dart_ListSetAt(result, 0, ToDart(start));
Dart_ListSetAt(result, 1, ToDart(end));
return result;
return m_paragraphImpl->getWordBoundary(offset);
}
} // namespace blink

View File

@ -6,9 +6,14 @@
#define FLUTTER_LIB_UI_TEXT_PARAGRAPH_H_
#include "flutter/lib/ui/painting/canvas.h"
#include "flutter/lib/ui/text/paragraph_impl.h"
#include "flutter/lib/ui/text/paragraph_impl_blink.h"
#include "flutter/lib/ui/text/paragraph_impl_txt.h"
#include "flutter/lib/ui/text/text_box.h"
#include "flutter/sky/engine/core/rendering/RenderView.h"
#include "flutter/sky/engine/wtf/PassOwnPtr.h"
#include "lib/tonic/dart_wrappable.h"
#include "lib/txt/src/paragraph.h"
namespace tonic {
class DartLibraryNatives;
@ -22,10 +27,15 @@ class Paragraph : public ftl::RefCountedThreadSafe<Paragraph>,
FRIEND_MAKE_REF_COUNTED(Paragraph);
public:
static ftl::RefPtr<Paragraph> create(PassOwnPtr<RenderView> renderView) {
static ftl::RefPtr<Paragraph> Create(PassOwnPtr<RenderView> renderView) {
return ftl::MakeRefCounted<Paragraph>(renderView);
}
static ftl::RefPtr<Paragraph> Create(
std::unique_ptr<txt::Paragraph> paragraph) {
return ftl::MakeRefCounted<Paragraph>(std::move(paragraph));
}
~Paragraph() override;
double width();
@ -48,12 +58,14 @@ class Paragraph : public ftl::RefCountedThreadSafe<Paragraph>,
static void RegisterNatives(tonic::DartLibraryNatives* natives);
private:
std::unique_ptr<ParagraphImpl> m_paragraphImpl;
RenderBox* firstChildBox() const { return m_renderView->firstChildBox(); }
int absoluteOffsetForPosition(const PositionWithAffinity& position);
explicit Paragraph(PassOwnPtr<RenderView> renderView);
explicit Paragraph(std::unique_ptr<txt::Paragraph> paragraph);
OwnPtr<RenderView> m_renderView;
};

View File

@ -4,6 +4,7 @@
#include "flutter/lib/ui/text/paragraph_builder.h"
#include "flutter/common/settings.h"
#include "flutter/common/threads.h"
#include "flutter/lib/ui/ui_dart_state.h"
#include "flutter/sky/engine/core/rendering/RenderInline.h"
@ -16,6 +17,12 @@
#include "lib/tonic/dart_args.h"
#include "lib/tonic/dart_binding_macros.h"
#include "lib/tonic/dart_library_natives.h"
#include "lib/txt/src/font_style.h"
#include "lib/txt/src/font_weight.h"
#include "lib/txt/src/paragraph_style.h"
#include "lib/txt/src/text_align.h"
#include "lib/txt/src/text_decoration.h"
#include "lib/txt/src/text_style.h"
namespace blink {
namespace {
@ -95,13 +102,12 @@ void createFontForDocument(RenderStyle* style) {
style->font().update(UIDartState::Current()->font_selector());
}
PassRefPtr<RenderStyle> decodeParagraphStyle(
RenderStyle* parentStyle,
tonic::Int32List& encoded,
const std::string& fontFamily,
double fontSize,
double lineHeight,
const std::string& ellipsis) {
PassRefPtr<RenderStyle> decodeParagraphStyle(RenderStyle* parentStyle,
tonic::Int32List& encoded,
const std::string& fontFamily,
double fontSize,
double lineHeight,
const std::string& ellipsis) {
FTL_DCHECK(encoded.num_elements() == 5);
RefPtr<RenderStyle> style = RenderStyle::create();
@ -187,8 +193,8 @@ ftl::RefPtr<ParagraphBuilder> ParagraphBuilder::create(
double fontSize,
double lineHeight,
const std::string& ellipsis) {
return ftl::MakeRefCounted<ParagraphBuilder>(
encoded, fontFamily, fontSize, lineHeight, ellipsis);
return ftl::MakeRefCounted<ParagraphBuilder>(encoded, fontFamily, fontSize,
lineHeight, ellipsis);
}
ParagraphBuilder::ParagraphBuilder(tonic::Int32List& encoded,
@ -196,24 +202,61 @@ ParagraphBuilder::ParagraphBuilder(tonic::Int32List& encoded,
double fontSize,
double lineHeight,
const std::string& ellipsis) {
createRenderView();
if (!Settings::Get().using_blink) {
int32_t mask = encoded[0];
txt::ParagraphStyle style;
if (mask & psTextAlignMask)
style.text_align = txt::TextAlign(encoded[psTextAlignIndex]);
RefPtr<RenderStyle> paragraphStyle = decodeParagraphStyle(
m_renderView->style(), encoded, fontFamily, fontSize, lineHeight, ellipsis);
encoded.Release();
if (mask & (psFontWeightMask | psFontStyleMask | psFontFamilyMask |
psFontSizeMask)) {
if (mask & psFontWeightMask)
style.font_weight =
static_cast<txt::FontWeight>(encoded[psFontWeightIndex]);
m_renderParagraph = new RenderParagraph();
m_renderParagraph->setStyle(paragraphStyle.release());
if (mask & psFontStyleMask)
style.font_style =
static_cast<txt::FontStyle>(encoded[psFontStyleIndex]);
m_currentRenderObject = m_renderParagraph;
m_renderView->addChild(m_currentRenderObject);
}
if (mask & psFontFamilyMask)
style.font_family = fontFamily;
if (mask & psFontSizeMask)
style.font_size = fontSize;
}
if (mask & psLineHeightMask)
style.line_height = lineHeight;
if (mask & psMaxLinesMask)
style.max_lines = encoded[psMaxLinesIndex];
if (mask & psEllipsisMask)
style.ellipsis = ellipsis;
m_paragraphBuilder.SetParagraphStyle(style);
} else {
// Blink version.
createRenderView();
RefPtr<RenderStyle> paragraphStyle =
decodeParagraphStyle(m_renderView->style(), encoded, fontFamily,
fontSize, lineHeight, ellipsis);
encoded.Release();
m_renderParagraph = new RenderParagraph();
m_renderParagraph->setStyle(paragraphStyle.release());
m_currentRenderObject = m_renderParagraph;
m_renderView->addChild(m_currentRenderObject);
}
} // namespace blink
ParagraphBuilder::~ParagraphBuilder() {
if (m_renderView) {
RenderView* renderView = m_renderView.leakPtr();
Threads::UI()->PostTask(
[renderView]() { renderView->destroy(); });
Threads::UI()->PostTask([renderView]() { renderView->destroy(); });
}
}
@ -224,98 +267,167 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded,
double wordSpacing,
double height) {
FTL_DCHECK(encoded.num_elements() == 8);
RefPtr<RenderStyle> style = RenderStyle::create();
style->inheritFrom(m_currentRenderObject->style());
int32_t mask = encoded[0];
if (mask & tsColorMask)
style->setColor(getColorFromARGB(encoded[tsColorIndex]));
if (!Settings::Get().using_blink) {
txt::TextStyle tstyle;
if (mask & tsTextDecorationMask) {
style->setTextDecoration(
static_cast<TextDecoration>(encoded[tsTextDecorationIndex]));
style->applyTextDecorations();
}
if (mask & tsColorMask)
tstyle.color = encoded[tsColorIndex];
if (mask & tsTextDecorationColorMask)
style->setTextDecorationColor(
StyleColor(getColorFromARGB(encoded[tsTextDecorationColorIndex])));
if (mask & tsTextDecorationStyleMask)
style->setTextDecorationStyle(
static_cast<TextDecorationStyle>(encoded[tsTextDecorationStyleIndex]));
if (mask & tsTextBaselineMask) {
// TODO(abarth): Implement TextBaseline. The CSS version of this
// property wasn't wired up either.
}
if (mask & (tsFontWeightMask | tsFontStyleMask | tsFontFamilyMask |
tsFontSizeMask | tsLetterSpacingMask | tsWordSpacingMask)) {
FontDescription fontDescription = style->fontDescription();
if (mask & tsFontWeightMask)
fontDescription.setWeight(
static_cast<FontWeight>(encoded[tsFontWeightIndex]));
if (mask & tsFontStyleMask)
fontDescription.setStyle(
static_cast<FontStyle>(encoded[tsFontStyleIndex]));
if (mask & tsFontFamilyMask) {
FontFamily family;
family.setFamily(String::fromUTF8(fontFamily));
fontDescription.setFamily(family);
if (mask & tsTextDecorationMask) {
tstyle.decoration =
static_cast<txt::TextDecoration>(encoded[tsTextDecorationIndex]);
}
if (mask & tsFontSizeMask) {
fontDescription.setSpecifiedSize(fontSize);
fontDescription.setIsAbsoluteSize(true);
fontDescription.setComputedSize(
getComputedSizeFromSpecifiedSize(fontSize));
if (mask & tsTextDecorationColorMask)
tstyle.decoration_color = encoded[tsTextDecorationColorIndex];
if (mask & tsTextDecorationStyleMask)
tstyle.decoration_style = static_cast<txt::TextDecorationStyle>(
encoded[tsTextDecorationStyleIndex]);
if (mask & tsTextBaselineMask) {
// TODO(abarth): Implement TextBaseline. The CSS version of this
// property wasn't wired up either.
}
if (mask & tsLetterSpacingMask)
fontDescription.setLetterSpacing(letterSpacing);
if (mask & (tsFontWeightMask | tsFontStyleMask | tsFontFamilyMask |
tsFontSizeMask | tsLetterSpacingMask | tsWordSpacingMask)) {
if (mask & tsFontWeightMask)
tstyle.font_weight =
static_cast<txt::FontWeight>(encoded[tsFontWeightIndex]);
if (mask & tsWordSpacingMask)
fontDescription.setWordSpacing(wordSpacing);
if (mask & tsFontStyleMask)
tstyle.font_style =
static_cast<txt::FontStyle>(encoded[tsFontStyleIndex]);
style->setFontDescription(fontDescription);
style->font().update(UIDartState::Current()->font_selector());
if (mask & tsFontFamilyMask)
tstyle.font_family = fontFamily;
if (mask & tsFontSizeMask)
tstyle.font_size = fontSize;
if (mask & tsLetterSpacingMask)
tstyle.letter_spacing = letterSpacing;
if (mask & tsWordSpacingMask)
tstyle.word_spacing = wordSpacing;
}
if (mask & tsHeightMask) {
tstyle.height = height;
}
m_paragraphBuilder.PushStyle(tstyle);
} else {
// Blink Version.
RefPtr<RenderStyle> style = RenderStyle::create();
style->inheritFrom(m_currentRenderObject->style());
if (mask & tsColorMask)
style->setColor(getColorFromARGB(encoded[tsColorIndex]));
if (mask & tsTextDecorationMask) {
style->setTextDecoration(
static_cast<TextDecoration>(encoded[tsTextDecorationIndex]));
style->applyTextDecorations();
}
if (mask & tsTextDecorationColorMask)
style->setTextDecorationColor(
StyleColor(getColorFromARGB(encoded[tsTextDecorationColorIndex])));
if (mask & tsTextDecorationStyleMask)
style->setTextDecorationStyle(static_cast<TextDecorationStyle>(
encoded[tsTextDecorationStyleIndex]));
if (mask & tsTextBaselineMask) {
// TODO(abarth): Implement TextBaseline. The CSS version of this
// property wasn't wired up either.
}
if (mask & (tsFontWeightMask | tsFontStyleMask | tsFontFamilyMask |
tsFontSizeMask | tsLetterSpacingMask | tsWordSpacingMask)) {
FontDescription fontDescription = style->fontDescription();
if (mask & tsFontWeightMask)
fontDescription.setWeight(
static_cast<FontWeight>(encoded[tsFontWeightIndex]));
if (mask & tsFontStyleMask)
fontDescription.setStyle(
static_cast<FontStyle>(encoded[tsFontStyleIndex]));
if (mask & tsFontFamilyMask) {
FontFamily family;
family.setFamily(String::fromUTF8(fontFamily));
fontDescription.setFamily(family);
}
if (mask & tsFontSizeMask) {
fontDescription.setSpecifiedSize(fontSize);
fontDescription.setIsAbsoluteSize(true);
fontDescription.setComputedSize(
getComputedSizeFromSpecifiedSize(fontSize));
}
if (mask & tsLetterSpacingMask)
fontDescription.setLetterSpacing(letterSpacing);
if (mask & tsWordSpacingMask)
fontDescription.setWordSpacing(wordSpacing);
style->setFontDescription(fontDescription);
style->font().update(UIDartState::Current()->font_selector());
}
if (mask & tsHeightMask) {
style->setLineHeight(Length(height * 100.0, Percent));
}
encoded.Release();
RenderObject* span = new RenderInline();
span->setStyle(style.release());
m_currentRenderObject->addChild(span);
m_currentRenderObject = span;
}
if (mask & tsHeightMask) {
style->setLineHeight(Length(height * 100.0, Percent));
}
encoded.Release();
RenderObject* span = new RenderInline();
span->setStyle(style.release());
m_currentRenderObject->addChild(span);
m_currentRenderObject = span;
}
void ParagraphBuilder::pop() {
if (m_currentRenderObject)
m_currentRenderObject = m_currentRenderObject->parent();
if (!Settings::Get().using_blink) {
m_paragraphBuilder.Pop();
} else {
// Blink Version.
if (m_currentRenderObject)
m_currentRenderObject = m_currentRenderObject->parent();
}
}
void ParagraphBuilder::addText(const std::string& text) {
if (!m_currentRenderObject)
return;
RenderText* renderText = new RenderText(String::fromUTF8(text).impl());
RefPtr<RenderStyle> style = RenderStyle::create();
style->inheritFrom(m_currentRenderObject->style());
renderText->setStyle(style.release());
m_currentRenderObject->addChild(renderText);
if (!Settings::Get().using_blink) {
m_paragraphBuilder.AddText(text);
} else {
// Blink Version.
if (!m_currentRenderObject)
return;
RenderText* renderText = new RenderText(String::fromUTF8(text).impl());
RefPtr<RenderStyle> style = RenderStyle::create();
style->inheritFrom(m_currentRenderObject->style());
renderText->setStyle(style.release());
m_currentRenderObject->addChild(renderText);
}
}
ftl::RefPtr<Paragraph> ParagraphBuilder::build() {
m_currentRenderObject = nullptr;
return Paragraph::create(m_renderView.release());
if (!Settings::Get().using_blink) {
return Paragraph::Create(m_paragraphBuilder.Build());
} else {
return Paragraph::Create(m_renderView.release());
}
}
void ParagraphBuilder::createRenderView() {

View File

@ -6,8 +6,11 @@
#define FLUTTER_LIB_UI_TEXT_PARAGRAPH_BUILDER_H_
#include "flutter/lib/ui/text/paragraph.h"
#include "flutter/sky/engine/core/rendering/RenderObject.h"
#include "flutter/sky/engine/wtf/OwnPtr.h"
#include "lib/tonic/dart_wrappable.h"
#include "lib/tonic/typed_data/int32_list.h"
#include "lib/txt/src/paragraph_builder.h"
namespace tonic {
class DartLibraryNatives;
@ -15,6 +18,8 @@ class DartLibraryNatives;
namespace blink {
class Paragraph;
class ParagraphBuilder : public ftl::RefCountedThreadSafe<ParagraphBuilder>,
public tonic::DartWrappable {
DEFINE_WRAPPERTYPEINFO();
@ -35,6 +40,7 @@ class ParagraphBuilder : public ftl::RefCountedThreadSafe<ParagraphBuilder>,
double letterSpacing,
double wordSpacing,
double height);
void pop();
void addText(const std::string& text);
@ -55,6 +61,7 @@ class ParagraphBuilder : public ftl::RefCountedThreadSafe<ParagraphBuilder>,
OwnPtr<RenderView> m_renderView;
RenderObject* m_renderParagraph;
RenderObject* m_currentRenderObject;
txt::ParagraphBuilder m_paragraphBuilder;
};
} // namespace blink

View File

@ -0,0 +1,7 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/lib/ui/text/paragraph_impl.h"
namespace blink {} // namespace blink

View File

@ -0,0 +1,45 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_LIB_UI_TEXT_PARAGRAPH_IMPL_H_
#define FLUTTER_LIB_UI_TEXT_PARAGRAPH_IMPL_H_
#include "flutter/lib/ui/painting/canvas.h"
#include "flutter/lib/ui/text/text_box.h"
namespace blink {
class ParagraphImpl {
public:
virtual ~ParagraphImpl(){};
virtual double width() = 0;
virtual double height() = 0;
virtual double minIntrinsicWidth() = 0;
virtual double maxIntrinsicWidth() = 0;
virtual double alphabeticBaseline() = 0;
virtual double ideographicBaseline() = 0;
virtual bool didExceedMaxLines() = 0;
virtual void layout(double width) = 0;
virtual void paint(Canvas* canvas, double x, double y) = 0;
virtual std::vector<TextBox> getRectsForRange(unsigned start,
unsigned end) = 0;
virtual Dart_Handle getPositionForOffset(double dx, double dy) = 0;
virtual Dart_Handle getWordBoundary(unsigned offset) = 0;
};
} // namespace blink
#endif // FLUTTER_LIB_UI_TEXT_PARAGRAPH_IMPL_H_

View File

@ -0,0 +1,180 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/lib/ui/text/paragraph_impl_blink.h"
#include "flutter/common/threads.h"
#include "flutter/lib/ui/text/paragraph.h"
#include "flutter/lib/ui/text/paragraph_impl.h"
#include "flutter/sky/engine/core/rendering/PaintInfo.h"
#include "flutter/sky/engine/core/rendering/RenderParagraph.h"
#include "flutter/sky/engine/core/rendering/RenderText.h"
#include "flutter/sky/engine/core/rendering/style/RenderStyle.h"
#include "flutter/sky/engine/platform/fonts/FontCache.h"
#include "flutter/sky/engine/platform/graphics/GraphicsContext.h"
#include "flutter/sky/engine/platform/text/TextBoundaries.h"
#include "lib/ftl/tasks/task_runner.h"
#include "lib/tonic/converter/dart_converter.h"
#include "lib/tonic/dart_args.h"
#include "lib/tonic/dart_binding_macros.h"
#include "lib/tonic/dart_library_natives.h"
using tonic::ToDart;
namespace blink {
ParagraphImplBlink::ParagraphImplBlink(PassOwnPtr<RenderView> renderView)
: m_renderView(renderView) {}
ParagraphImplBlink::~ParagraphImplBlink() {
if (m_renderView) {
RenderView* renderView = m_renderView.leakPtr();
Threads::UI()->PostTask([renderView]() { renderView->destroy(); });
}
}
double ParagraphImplBlink::width() {
return firstChildBox()->width();
}
double ParagraphImplBlink::height() {
return firstChildBox()->height();
}
double ParagraphImplBlink::minIntrinsicWidth() {
return firstChildBox()->minPreferredLogicalWidth();
}
double ParagraphImplBlink::maxIntrinsicWidth() {
return firstChildBox()->maxPreferredLogicalWidth();
}
double ParagraphImplBlink::alphabeticBaseline() {
return firstChildBox()->firstLineBoxBaseline(
FontBaselineOrAuto(AlphabeticBaseline));
}
double ParagraphImplBlink::ideographicBaseline() {
return firstChildBox()->firstLineBoxBaseline(
FontBaselineOrAuto(IdeographicBaseline));
}
bool ParagraphImplBlink::didExceedMaxLines() {
RenderBox* box = firstChildBox();
ASSERT(box->isRenderParagraph());
RenderParagraph* paragraph = static_cast<RenderParagraph*>(box);
return paragraph->didExceedMaxLines();
}
void ParagraphImplBlink::layout(double width) {
FontCachePurgePreventer fontCachePurgePreventer;
int maxWidth = LayoutUnit(width); // Handles infinity properly.
m_renderView->setFrameViewSize(IntSize(maxWidth, intMaxForLayoutUnit));
m_renderView->layout();
}
void ParagraphImplBlink::paint(Canvas* canvas, double x, double y) {
SkCanvas* skCanvas = canvas->canvas();
if (!skCanvas)
return;
FontCachePurgePreventer fontCachePurgePreventer;
// Very simplified painting to allow painting an arbitrary (layer-less)
// subtree.
RenderBox* box = firstChildBox();
skCanvas->translate(x, y);
GraphicsContext context(skCanvas);
Vector<RenderBox*> layers;
LayoutRect bounds = box->absoluteBoundingBoxRect();
FTL_DCHECK(bounds.x() == 0 && bounds.y() == 0);
PaintInfo paintInfo(&context, enclosingIntRect(bounds), box);
box->paint(paintInfo, LayoutPoint(), layers);
// Note we're ignoring any layers encountered.
// TODO(abarth): Remove the concept of RenderLayers.
skCanvas->translate(-x, -y);
}
std::vector<TextBox> ParagraphImplBlink::getRectsForRange(unsigned start,
unsigned end) {
if (end <= start || start == end)
return std::vector<TextBox>();
unsigned offset = 0;
std::vector<TextBox> boxes;
for (RenderObject* object = m_renderView.get(); object;
object = object->nextInPreOrder()) {
if (!object->isText())
continue;
RenderText* text = toRenderText(object);
unsigned length = text->textLength();
if (offset + length > start) {
unsigned startOffset = offset > start ? 0 : start - offset;
unsigned endOffset = end - offset;
text->appendAbsoluteTextBoxesForRange(boxes, startOffset, endOffset);
}
offset += length;
if (offset >= end)
break;
}
return boxes;
}
int ParagraphImplBlink::absoluteOffsetForPosition(
const PositionWithAffinity& position) {
FTL_DCHECK(position.renderer());
unsigned offset = 0;
for (RenderObject* object = m_renderView.get(); object;
object = object->nextInPreOrder()) {
if (object == position.renderer())
return offset + position.offset();
if (object->isText()) {
RenderText* text = toRenderText(object);
offset += text->textLength();
}
}
FTL_DCHECK(false);
return 0;
}
Dart_Handle ParagraphImplBlink::getPositionForOffset(double dx, double dy) {
LayoutPoint point(dx, dy);
PositionWithAffinity position = m_renderView->positionForPoint(point);
Dart_Handle result = Dart_NewList(2);
Dart_ListSetAt(result, 0, ToDart(absoluteOffsetForPosition(position)));
Dart_ListSetAt(result, 1, ToDart(static_cast<int>(position.affinity())));
return result;
}
Dart_Handle ParagraphImplBlink::getWordBoundary(unsigned offset) {
String text;
int start = 0, end = 0;
for (RenderObject* object = m_renderView.get(); object;
object = object->nextInPreOrder()) {
if (!object->isText())
continue;
RenderText* renderText = toRenderText(object);
text.append(renderText->text());
}
TextBreakIterator* it = wordBreakIterator(text, 0, text.length());
if (it) {
end = it->following(offset);
if (end < 0)
end = it->last();
start = it->previous();
}
Dart_Handle result = Dart_NewList(2);
Dart_ListSetAt(result, 0, ToDart(start));
Dart_ListSetAt(result, 1, ToDart(end));
return result;
}
} // namespace blink

View File

@ -0,0 +1,49 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_LIB_UI_TEXT_PARAGRAPH_IMPL_BLINK_H_
#define FLUTTER_LIB_UI_TEXT_PARAGRAPH_IMPL_BLINK_H_
#include "flutter/lib/ui/painting/canvas.h"
#include "flutter/lib/ui/text/paragraph_impl.h"
#include "flutter/lib/ui/text/text_box.h"
#include "flutter/sky/engine/core/rendering/RenderView.h"
#include "lib/txt/src/paragraph.h"
namespace blink {
class ParagraphImplBlink : public ParagraphImpl {
public:
~ParagraphImplBlink() override;
explicit ParagraphImplBlink(PassOwnPtr<RenderView> renderView);
double width() override;
double height() override;
double minIntrinsicWidth() override;
double maxIntrinsicWidth() override;
double alphabeticBaseline() override;
double ideographicBaseline() override;
bool didExceedMaxLines() override;
void layout(double width) override;
void paint(Canvas* canvas, double x, double y) override;
std::vector<TextBox> getRectsForRange(unsigned start, unsigned end) override;
Dart_Handle getPositionForOffset(double dx, double dy) override;
Dart_Handle getWordBoundary(unsigned offset) override;
RenderView* renderView() const { return m_renderView.get(); }
private:
RenderBox* firstChildBox() const { return m_renderView->firstChildBox(); }
int absoluteOffsetForPosition(const PositionWithAffinity& position);
OwnPtr<RenderView> m_renderView;
};
} // namespace blink
#endif // FLUTTER_LIB_UI_TEXT_PARAGRAPH_IMPL_BLINK_H_

View File

@ -0,0 +1,75 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/lib/ui/text/paragraph_impl_txt.h"
#include "flutter/common/threads.h"
#include "flutter/lib/ui/text/paragraph.h"
#include "flutter/lib/ui/text/paragraph_impl.h"
#include "lib/ftl/tasks/task_runner.h"
#include "lib/txt/src/paragraph_constraints.h"
namespace blink {
ParagraphImplTxt::ParagraphImplTxt(std::unique_ptr<txt::Paragraph> paragraph)
: m_paragraph(std::move(paragraph)) {}
ParagraphImplTxt::~ParagraphImplTxt() {}
double ParagraphImplTxt::width() {
return m_width;
}
double ParagraphImplTxt::height() {
return m_paragraph->GetHeight();
}
double ParagraphImplTxt::minIntrinsicWidth() {
return m_paragraph->GetMinIntrinsicWidth();
}
double ParagraphImplTxt::maxIntrinsicWidth() {
return m_paragraph->GetMaxIntrinsicWidth();
}
double ParagraphImplTxt::alphabeticBaseline() {
return m_paragraph->GetAlphabeticBaseline();
}
double ParagraphImplTxt::ideographicBaseline() {
return m_paragraph->GetIdeographicBaseline();
}
bool ParagraphImplTxt::didExceedMaxLines() {
return m_paragraph->DidExceedMaxLines();
}
void ParagraphImplTxt::layout(double width) {
m_width = width;
m_paragraph->Layout(txt::ParagraphConstraints{width});
}
void ParagraphImplTxt::paint(Canvas* canvas, double x, double y) {
SkCanvas* sk_canvas = canvas->canvas();
if (!sk_canvas)
return;
m_paragraph->Paint(sk_canvas, x, y);
}
std::vector<TextBox> ParagraphImplTxt::getRectsForRange(unsigned start,
unsigned end) {
return std::vector<TextBox>{0ull};
}
Dart_Handle ParagraphImplTxt::getPositionForOffset(double dx, double dy) {
// TODO(garyq): Implement in the library.
return nullptr;
}
Dart_Handle ParagraphImplTxt::getWordBoundary(unsigned offset) {
// TODO(garyq): Implement in the library.
return nullptr;
}
} // namespace blink

View File

@ -0,0 +1,44 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_LIB_UI_TEXT_PARAGRAPH_IMPL_TXT_H_
#define FLUTTER_LIB_UI_TEXT_PARAGRAPH_IMPL_TXT_H_
#include "flutter/lib/ui/painting/canvas.h"
#include "flutter/lib/ui/text/paragraph_impl.h"
#include "flutter/lib/ui/text/paragraph_impl_blink.h"
#include "flutter/lib/ui/text/text_box.h"
#include "lib/txt/src/paragraph.h"
namespace blink {
class ParagraphImplTxt : public ParagraphImpl {
public:
~ParagraphImplTxt() override;
explicit ParagraphImplTxt(std::unique_ptr<txt::Paragraph> paragraph);
double width() override;
double height() override;
double minIntrinsicWidth() override;
double maxIntrinsicWidth() override;
double alphabeticBaseline() override;
double ideographicBaseline() override;
bool didExceedMaxLines() override;
void layout(double width) override;
void paint(Canvas* canvas, double x, double y) override;
std::vector<TextBox> getRectsForRange(unsigned start, unsigned end) override;
Dart_Handle getPositionForOffset(double dx, double dy) override;
Dart_Handle getWordBoundary(unsigned offset) override;
private:
std::unique_ptr<txt::Paragraph> m_paragraph;
double m_width = -1.0;
};
} // namespace blink
#endif // FLUTTER_LIB_UI_TEXT_PARAGRAPH_IMPL_TXT_H_

View File

@ -147,6 +147,9 @@ void Shell::InitStandalone(ftl::CommandLine command_line,
settings.enable_software_rendering =
command_line.HasOption(FlagForSwitch(Switch::EnableSoftwareRendering));
settings.using_blink =
!command_line.HasOption(FlagForSwitch(Switch::EnableTxt));
settings.endless_trace_buffer =
command_line.HasOption(FlagForSwitch(Switch::EndlessTraceBuffer));

View File

@ -63,6 +63,9 @@ DEF_SWITCH(EnableSoftwareRendering,
"Enable rendering using the Skia software backend. This is useful"
"when testing Flutter on emulators. By default, Flutter will"
"attempt to either use OpenGL or Vulkan.")
DEF_SWITCH(EnableTxt,
"enable-txt",
"Enable libtxt as the text shaping library instead of Blink.")
DEF_SWITCH(FLX, "flx", "Specify the the FLX path.")
DEF_SWITCH(Help, "help", "Display this help text.")
DEF_SWITCH(LogTag, "log-tag", "Tag associated with log messages.")

View File

@ -245,6 +245,9 @@ public final class FlutterActivityDelegate
if (intent.getBooleanExtra("enable-software-rendering", false)) {
args.add("--enable-software-rendering");
}
if (intent.getBooleanExtra("enable-txt", false)) {
args.add("--enable-txt");
}
if (!args.isEmpty()) {
String[] argsArray = new String[args.size()];
return args.toArray(argsArray);

View File

@ -9162,6 +9162,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
etc1
lib
observatory_pub_packages
skia
vulkan