From d9bc2f5604e5cfef7deef2f813751e0cd46a515d Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Mon, 19 Jun 2017 15:21:41 -0700 Subject: [PATCH] Reland "Initial integration of libtxt with Flutter alongside Blink." (flutter/engine#3793) * Transition to Hybrid lib/txt and blink text system. --- DEPS | 3 + engine/src/flutter/BUILD.gn | 3 + engine/src/flutter/common/settings.h | 1 + engine/src/flutter/lib/ui/BUILD.gn | 8 + engine/src/flutter/lib/ui/text/paragraph.cc | 132 ++------ engine/src/flutter/lib/ui/text/paragraph.h | 18 +- .../flutter/lib/ui/text/paragraph_builder.cc | 292 ++++++++++++------ .../flutter/lib/ui/text/paragraph_builder.h | 7 + .../src/flutter/lib/ui/text/paragraph_impl.cc | 7 + .../src/flutter/lib/ui/text/paragraph_impl.h | 45 +++ .../lib/ui/text/paragraph_impl_blink.cc | 180 +++++++++++ .../lib/ui/text/paragraph_impl_blink.h | 49 +++ .../flutter/lib/ui/text/paragraph_impl_txt.cc | 75 +++++ .../flutter/lib/ui/text/paragraph_impl_txt.h | 44 +++ engine/src/flutter/shell/common/shell.cc | 3 + engine/src/flutter/shell/common/switches.h | 3 + .../flutter/app/FlutterActivityDelegate.java | 3 + .../flutter/sky/packages/sky_engine/LICENSE | 1 + 18 files changed, 671 insertions(+), 203 deletions(-) create mode 100644 engine/src/flutter/lib/ui/text/paragraph_impl.cc create mode 100644 engine/src/flutter/lib/ui/text/paragraph_impl.h create mode 100644 engine/src/flutter/lib/ui/text/paragraph_impl_blink.cc create mode 100644 engine/src/flutter/lib/ui/text/paragraph_impl_blink.h create mode 100644 engine/src/flutter/lib/ui/text/paragraph_impl_txt.cc create mode 100644 engine/src/flutter/lib/ui/text/paragraph_impl_txt.h diff --git a/DEPS b/DEPS index 2e0a1ae93c8..e76c0f0459c 100644 --- a/DEPS +++ b/DEPS @@ -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', diff --git a/engine/src/flutter/BUILD.gn b/engine/src/flutter/BUILD.gn index 936c8cb4079..9e997b05eb6 100644 --- a/engine/src/flutter/BUILD.gn +++ b/engine/src/flutter/BUILD.gn @@ -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 ] } } diff --git a/engine/src/flutter/common/settings.h b/engine/src/flutter/common/settings.h index 8fd9de59d93..0846264f726 100644 --- a/engine/src/flutter/common/settings.h +++ b/engine/src/flutter/common/settings.h @@ -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; diff --git a/engine/src/flutter/lib/ui/BUILD.gn b/engine/src/flutter/lib/ui/BUILD.gn index fd02dab3592..517dd70cfd0 100644 --- a/engine/src/flutter/lib/ui/BUILD.gn +++ b/engine/src/flutter/lib/ui/BUILD.gn @@ -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", ] } diff --git a/engine/src/flutter/lib/ui/text/paragraph.cc b/engine/src/flutter/lib/ui/text/paragraph.cc index 9f29d3d089e..c7fd4e42225 100644 --- a/engine/src/flutter/lib/ui/text/paragraph.cc +++ b/engine/src/flutter/lib/ui/text/paragraph.cc @@ -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) - : m_renderView(renderView) {} + : m_paragraphImpl(std::make_unique(renderView)) {} + +Paragraph::Paragraph(std::unique_ptr paragraph) + : m_paragraphImpl( + std::make_unique(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(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 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 Paragraph::getRectsForRange(unsigned start, unsigned end) { - if (end <= start || start == end) - return std::vector(); - - unsigned offset = 0; - std::vector 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(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 diff --git a/engine/src/flutter/lib/ui/text/paragraph.h b/engine/src/flutter/lib/ui/text/paragraph.h index e75025b07a0..0e8525b0ab3 100644 --- a/engine/src/flutter/lib/ui/text/paragraph.h +++ b/engine/src/flutter/lib/ui/text/paragraph.h @@ -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, FRIEND_MAKE_REF_COUNTED(Paragraph); public: - static ftl::RefPtr create(PassOwnPtr renderView) { + static ftl::RefPtr Create(PassOwnPtr renderView) { return ftl::MakeRefCounted(renderView); } + static ftl::RefPtr Create( + std::unique_ptr paragraph) { + return ftl::MakeRefCounted(std::move(paragraph)); + } + ~Paragraph() override; double width(); @@ -48,12 +58,14 @@ class Paragraph : public ftl::RefCountedThreadSafe, static void RegisterNatives(tonic::DartLibraryNatives* natives); private: + std::unique_ptr m_paragraphImpl; + RenderBox* firstChildBox() const { return m_renderView->firstChildBox(); } - int absoluteOffsetForPosition(const PositionWithAffinity& position); - explicit Paragraph(PassOwnPtr renderView); + explicit Paragraph(std::unique_ptr paragraph); + OwnPtr m_renderView; }; diff --git a/engine/src/flutter/lib/ui/text/paragraph_builder.cc b/engine/src/flutter/lib/ui/text/paragraph_builder.cc index f25331869ba..a65762e1805 100644 --- a/engine/src/flutter/lib/ui/text/paragraph_builder.cc +++ b/engine/src/flutter/lib/ui/text/paragraph_builder.cc @@ -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 decodeParagraphStyle( - RenderStyle* parentStyle, - tonic::Int32List& encoded, - const std::string& fontFamily, - double fontSize, - double lineHeight, - const std::string& ellipsis) { +PassRefPtr 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 style = RenderStyle::create(); @@ -187,8 +193,8 @@ ftl::RefPtr ParagraphBuilder::create( double fontSize, double lineHeight, const std::string& ellipsis) { - return ftl::MakeRefCounted( - encoded, fontFamily, fontSize, lineHeight, ellipsis); + return ftl::MakeRefCounted(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 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(encoded[psFontWeightIndex]); - m_renderParagraph = new RenderParagraph(); - m_renderParagraph->setStyle(paragraphStyle.release()); + if (mask & psFontStyleMask) + style.font_style = + static_cast(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 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 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(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(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(encoded[tsFontWeightIndex])); - - if (mask & tsFontStyleMask) - fontDescription.setStyle( - static_cast(encoded[tsFontStyleIndex])); - - if (mask & tsFontFamilyMask) { - FontFamily family; - family.setFamily(String::fromUTF8(fontFamily)); - fontDescription.setFamily(family); + if (mask & tsTextDecorationMask) { + tstyle.decoration = + static_cast(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( + 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(encoded[tsFontWeightIndex]); - if (mask & tsWordSpacingMask) - fontDescription.setWordSpacing(wordSpacing); + if (mask & tsFontStyleMask) + tstyle.font_style = + static_cast(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 style = RenderStyle::create(); + style->inheritFrom(m_currentRenderObject->style()); + + if (mask & tsColorMask) + style->setColor(getColorFromARGB(encoded[tsColorIndex])); + + if (mask & tsTextDecorationMask) { + style->setTextDecoration( + static_cast(encoded[tsTextDecorationIndex])); + style->applyTextDecorations(); + } + + if (mask & tsTextDecorationColorMask) + style->setTextDecorationColor( + StyleColor(getColorFromARGB(encoded[tsTextDecorationColorIndex]))); + + if (mask & tsTextDecorationStyleMask) + style->setTextDecorationStyle(static_cast( + 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(encoded[tsFontWeightIndex])); + + if (mask & tsFontStyleMask) + fontDescription.setStyle( + static_cast(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 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 style = RenderStyle::create(); + style->inheritFrom(m_currentRenderObject->style()); + renderText->setStyle(style.release()); + m_currentRenderObject->addChild(renderText); + } } ftl::RefPtr 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() { diff --git a/engine/src/flutter/lib/ui/text/paragraph_builder.h b/engine/src/flutter/lib/ui/text/paragraph_builder.h index 7a156f23c2d..6d6cba03345 100644 --- a/engine/src/flutter/lib/ui/text/paragraph_builder.h +++ b/engine/src/flutter/lib/ui/text/paragraph_builder.h @@ -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, public tonic::DartWrappable { DEFINE_WRAPPERTYPEINFO(); @@ -35,6 +40,7 @@ class ParagraphBuilder : public ftl::RefCountedThreadSafe, double letterSpacing, double wordSpacing, double height); + void pop(); void addText(const std::string& text); @@ -55,6 +61,7 @@ class ParagraphBuilder : public ftl::RefCountedThreadSafe, OwnPtr m_renderView; RenderObject* m_renderParagraph; RenderObject* m_currentRenderObject; + txt::ParagraphBuilder m_paragraphBuilder; }; } // namespace blink diff --git a/engine/src/flutter/lib/ui/text/paragraph_impl.cc b/engine/src/flutter/lib/ui/text/paragraph_impl.cc new file mode 100644 index 00000000000..65483a8b681 --- /dev/null +++ b/engine/src/flutter/lib/ui/text/paragraph_impl.cc @@ -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 diff --git a/engine/src/flutter/lib/ui/text/paragraph_impl.h b/engine/src/flutter/lib/ui/text/paragraph_impl.h new file mode 100644 index 00000000000..f8e1ef09d4b --- /dev/null +++ b/engine/src/flutter/lib/ui/text/paragraph_impl.h @@ -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 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_ diff --git a/engine/src/flutter/lib/ui/text/paragraph_impl_blink.cc b/engine/src/flutter/lib/ui/text/paragraph_impl_blink.cc new file mode 100644 index 00000000000..55b5f05b7f5 --- /dev/null +++ b/engine/src/flutter/lib/ui/text/paragraph_impl_blink.cc @@ -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) + : 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(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 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 ParagraphImplBlink::getRectsForRange(unsigned start, + unsigned end) { + if (end <= start || start == end) + return std::vector(); + + unsigned offset = 0; + std::vector 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(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 diff --git a/engine/src/flutter/lib/ui/text/paragraph_impl_blink.h b/engine/src/flutter/lib/ui/text/paragraph_impl_blink.h new file mode 100644 index 00000000000..7557139d2de --- /dev/null +++ b/engine/src/flutter/lib/ui/text/paragraph_impl_blink.h @@ -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); + + 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 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 m_renderView; +}; + +} // namespace blink + +#endif // FLUTTER_LIB_UI_TEXT_PARAGRAPH_IMPL_BLINK_H_ diff --git a/engine/src/flutter/lib/ui/text/paragraph_impl_txt.cc b/engine/src/flutter/lib/ui/text/paragraph_impl_txt.cc new file mode 100644 index 00000000000..3ac12e6b3df --- /dev/null +++ b/engine/src/flutter/lib/ui/text/paragraph_impl_txt.cc @@ -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 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 ParagraphImplTxt::getRectsForRange(unsigned start, + unsigned end) { + return std::vector{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 diff --git a/engine/src/flutter/lib/ui/text/paragraph_impl_txt.h b/engine/src/flutter/lib/ui/text/paragraph_impl_txt.h new file mode 100644 index 00000000000..20f786a4326 --- /dev/null +++ b/engine/src/flutter/lib/ui/text/paragraph_impl_txt.h @@ -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 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 getRectsForRange(unsigned start, unsigned end) override; + Dart_Handle getPositionForOffset(double dx, double dy) override; + Dart_Handle getWordBoundary(unsigned offset) override; + + private: + std::unique_ptr m_paragraph; + double m_width = -1.0; +}; + +} // namespace blink + +#endif // FLUTTER_LIB_UI_TEXT_PARAGRAPH_IMPL_TXT_H_ diff --git a/engine/src/flutter/shell/common/shell.cc b/engine/src/flutter/shell/common/shell.cc index 21eb3c916f0..f2a679d700c 100644 --- a/engine/src/flutter/shell/common/shell.cc +++ b/engine/src/flutter/shell/common/shell.cc @@ -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)); diff --git a/engine/src/flutter/shell/common/switches.h b/engine/src/flutter/shell/common/switches.h index fe68fe13d6a..ac43b92126f 100644 --- a/engine/src/flutter/shell/common/switches.h +++ b/engine/src/flutter/shell/common/switches.h @@ -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.") diff --git a/engine/src/flutter/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java b/engine/src/flutter/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java index f299a08708f..e28523a7599 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java @@ -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); diff --git a/engine/src/flutter/sky/packages/sky_engine/LICENSE b/engine/src/flutter/sky/packages/sky_engine/LICENSE index 172952f2610..5402bfb2fbb 100644 --- a/engine/src/flutter/sky/packages/sky_engine/LICENSE +++ b/engine/src/flutter/sky/packages/sky_engine/LICENSE @@ -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