From 2645a9d3df8f97eb9ab022e8a7f272a0741bd3bb Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Tue, 3 Mar 2020 23:09:16 -0800 Subject: [PATCH 01/23] Fork Skia's r-tree --- third_party/skia/.clang-format | 194 ++++++++++++++++++++++++ third_party/skia/AUTHORS | 66 ++++++++ third_party/skia/BUILD.gn | 15 ++ third_party/skia/LICENSE | 29 ++++ third_party/skia/platform_view_rtree.cc | 182 ++++++++++++++++++++++ third_party/skia/platform_view_rtree.h | 84 ++++++++++ 6 files changed, 570 insertions(+) create mode 100644 third_party/skia/.clang-format create mode 100644 third_party/skia/AUTHORS create mode 100644 third_party/skia/BUILD.gn create mode 100644 third_party/skia/LICENSE create mode 100644 third_party/skia/platform_view_rtree.cc create mode 100644 third_party/skia/platform_view_rtree.h diff --git a/third_party/skia/.clang-format b/third_party/skia/.clang-format new file mode 100644 index 0000000000000..93e44c56fa17f --- /dev/null +++ b/third_party/skia/.clang-format @@ -0,0 +1,194 @@ +--- +# Typical usage is to apply this to the lines you've modified in a local +# change. Stage your changes with "git add" and then run: +# $ git clang-format +# You can optionally use the "--" file filter to restrict formatting to certain +# files or directories. The tool will display the list of files that were +# modified. These have been modified without being staged. You can review the +# modifications using "git diff". +# +# IF YOU UPDATE THE CPP SECTION ALSO UPDATE THE OBJECTIVE-C SECTION. IF YOU +# KNOW HOW TO SHARE SETTINGS BETWEEN THE TWO YOU'RE A TRUE HERO. + +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: true +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: true +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 100 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeCategories: + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 4 +UseTab: Never +--- +Language: ObjC +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: true +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: true +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 100 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeCategories: + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 4 +UseTab: Never diff --git a/third_party/skia/AUTHORS b/third_party/skia/AUTHORS new file mode 100644 index 0000000000000..838af91e91d6f --- /dev/null +++ b/third_party/skia/AUTHORS @@ -0,0 +1,66 @@ +# This is the official list of Skia authors for copyright purposes. +# +# Names should be added to this file with one of the following patterns: +# +# For individual contributors: +# Name +# +# For corporate contributors: +# Organization +# See examples below or python fnmatch module documentation for more information. +# +# Please keep the list sorted alphabetically. + +Aaron O'Mullan +ACCESS CO., LTD. <*@access-company.com> +Amazon, Inc <*@amazon.com> +Anthony Catel +ARM <*@arm.com> +Bharat Ahuja +Dawson Coleman +Deepak Mohan +Ehsan Akhgari +Facebook, Inc. <*fb.com> +George Wright +GiWan Go +Google Inc. <*@google.com> +Herb Derby +Igalia <*@igalia.com> +Intel <*@intel.com> +Ion Rosca +Jacek Caban +Jeff Muizelaar +Jongdeok Kim +Lee Salzman +Marcin Kazmierczak +Matthew Leibowitz +Microsoft <*@microsoft.com> +MIPS <*@imgtec.com> +Noah Lavine +NVIDIA <*@nvidia.com> +Opera Software ASA <*@opera.com> +Pavel Krajcevski +Petar Kirov +Raul Tambre +Samsung <*@samsung.com> +Samsung Open Source Group <*@osg.samsung.com> +Sergey Melnikov +Shachar Langbeheim +Skia <*@skia.org> +Skia Buildbots +Sony Mobile Communications Inc. <*@sonymobile.com> +Steve Singer +Sylvestre Ledru +The Chromium Authors <*@chromium.org> +Thiago Fransosi Farina +Jose Mayol +Linaro <*@linaro.org> +Christian Plesner Hansen +Marco Alesiani +Adobe Systems Incorporated <*@adobe.com> +Yandex LLC <*@yandex-team.ru> +Kaloyan Donev +Yong-Hwan Baek +Alexander Khovansky +Zhuo Qingliang +Mainframe North <*@mainframe.co.uk> diff --git a/third_party/skia/BUILD.gn b/third_party/skia/BUILD.gn new file mode 100644 index 0000000000000..f4231bf32634d --- /dev/null +++ b/third_party/skia/BUILD.gn @@ -0,0 +1,15 @@ +# Copyright 2016 Google Inc. +# +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("skia") { + sources = [ + "platform_view_rtree.cc", + "platform_view_rtree.h", + ] + + deps = [ + "//third_party/skia", + ] +} diff --git a/third_party/skia/LICENSE b/third_party/skia/LICENSE new file mode 100644 index 0000000000000..e32636d5668d5 --- /dev/null +++ b/third_party/skia/LICENSE @@ -0,0 +1,29 @@ +Copyright (c) 2011 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/skia/platform_view_rtree.cc b/third_party/skia/platform_view_rtree.cc new file mode 100644 index 0000000000000..9b514d515112d --- /dev/null +++ b/third_party/skia/platform_view_rtree.cc @@ -0,0 +1,182 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "skia/platform_view_rtree.h" + +SkRTree::SkRTree() : fCount(0) {} + +void SkRTree::insert(const SkRect boundsArray[], + const SkBBoxHierarchy::Metadata metadata[], + int N) { + SkASSERT(0 == fCount); + + std::vector branches; + branches.reserve(N); + + for (int i = 0; i < N; i++) { + const SkRect& bounds = boundsArray[i]; + if (bounds.isEmpty()) { + continue; + } + Branch b; + b.fBounds = bounds; + b.fOpIndex = i; + branches.push_back(b); + } + Branch b; + b.fBounds = bounds; + b.fOpIndex = i; + branches.push_back(b); +} + +fCount = (int)branches.size(); +if (fCount) { + if (1 == fCount) { + fNodes.reserve(1); + Node* n = this->allocateNodeAtLevel(0); + n->fNumChildren = 1; + n->fChildren[0] = branches[0]; + fRoot.fSubtree = n; + fRoot.fBounds = branches[0].fBounds; + } else { + fNodes.reserve(CountNodes(fCount)); + fRoot = this->bulkLoad(&branches); + } +} + +void SkRTree::insert(const SkRect boundsArray[], int N) { + insert(boundsArray, nullptr, N); +} + +SkRTree::Node* SkRTree::allocateNodeAtLevel(uint16_t level) { + SkDEBUGCODE(Node* p = fNodes.data()); + fNodes.push_back(Node{}); + Node& out = fNodes.back(); + SkASSERT(fNodes.data() == p); // If this fails, we didn't reserve() enough. + out.fNumChildren = 0; + out.fLevel = level; + return &out; +} + +// This function parallels bulkLoad, but just counts how many nodes bulkLoad +// would allocate. +int SkRTree::CountNodes(int branches) { + if (branches == 1) { + return 1; + } + int numBranches = branches / kMaxChildren; + int remainder = branches % kMaxChildren; + if (remainder > 0) { + numBranches++; + if (remainder >= kMinChildren) { + remainder = 0; + } else { + remainder = kMinChildren - remainder; + } + } + int currentBranch = 0; + int nodes = 0; + while (currentBranch < branches) { + int incrementBy = kMaxChildren; + if (remainder != 0) { + if (remainder <= kMaxChildren - kMinChildren) { + incrementBy -= remainder; + remainder = 0; + } else { + incrementBy = kMinChildren; + remainder -= kMaxChildren - kMinChildren; + } + } + nodes++; + currentBranch++; + for (int k = 1; k < incrementBy && currentBranch < branches; ++k) { + currentBranch++; + } + } + return nodes + CountNodes(nodes); +} + +SkRTree::Branch SkRTree::bulkLoad(std::vector* branches, int level) { + if (branches->size() == 1) { // Only one branch. It will be the root. + return (*branches)[0]; + } + + // We might sort our branches here, but we expect Blink gives us a reasonable + // x,y order. Skipping a call to sort (in Y) here resulted in a 17% win for + // recording with negligible difference in playback speed. + int numBranches = (int)branches->size() / kMaxChildren; + int remainder = (int)branches->size() % kMaxChildren; + int newBranches = 0; + + if (remainder > 0) { + ++numBranches; + // If the remainder isn't enough to fill a node, we'll add fewer nodes to + // other branches. + if (remainder >= kMinChildren) { + remainder = 0; + } else { + remainder = kMinChildren - remainder; + } + } + + int currentBranch = 0; + while (currentBranch < (int)branches->size()) { + int incrementBy = kMaxChildren; + if (remainder != 0) { + // if need be, omit some nodes to make up for remainder + if (remainder <= kMaxChildren - kMinChildren) { + incrementBy -= remainder; + remainder = 0; + } else { + incrementBy = kMinChildren; + remainder -= kMaxChildren - kMinChildren; + } + } + Node* n = allocateNodeAtLevel(level); + n->fNumChildren = 1; + n->fChildren[0] = (*branches)[currentBranch]; + Branch b; + b.fBounds = (*branches)[currentBranch].fBounds; + b.fSubtree = n; + ++currentBranch; + for (int k = 1; k < incrementBy && currentBranch < (int)branches->size(); ++k) { + b.fBounds.join((*branches)[currentBranch].fBounds); + n->fChildren[k] = (*branches)[currentBranch]; + ++n->fNumChildren; + ++currentBranch; + } + (*branches)[newBranches] = b; + ++newBranches; + } + branches->resize(newBranches); + return this->bulkLoad(branches, level + 1); +} + +void SkRTree::search(const SkRect& query, std::vector* results) const { + if (fCount > 0 && SkRect::Intersects(fRoot.fBounds, query)) { + this->search(fRoot.fSubtree, query, results); + } +} + +void SkRTree::search(Node* node, const SkRect& query, std::vector* results) const { + for (int i = 0; i < node->fNumChildren; ++i) { + if (!SkRect::Intersects(node->fChildren[i].fBounds, query)) { + continue; + } + if (0 != node->fLevel) { + this->search(node->fChildren[i].fSubtree, query, results); + continue; + } + results->push_back(node->fChildren[i].fOpIndex); + } +} + +size_t SkRTree::bytesUsed() const { + size_t byteCount = sizeof(SkRTree); + byteCount += fNodes.capacity() * sizeof(Node); + return byteCount; +} diff --git a/third_party/skia/platform_view_rtree.h b/third_party/skia/platform_view_rtree.h new file mode 100644 index 0000000000000..700438f7c219e --- /dev/null +++ b/third_party/skia/platform_view_rtree.h @@ -0,0 +1,84 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKIA_PLATFORM_VIEW_RTREE_H_ +#define SKIA_PLATFORM_VIEW_RTREE_H_ + +#include "third_party/skia/include/core/SkBBHFactory.h" +#include "third_party/skia/include/core/SkTypes.h" + +/** + * An R-Tree implementation. In short, it is a balanced n-ary tree containing a hierarchy of + * bounding rectangles. + * + * It only supports bulk-loading, i.e. creation from a batch of bounding rectangles. + * This performs a bottom-up bulk load using the STR (sort-tile-recursive) algorithm. + * + * TODO: Experiment with other bulk-load algorithms (in particular the Hilbert pack variant, + * which groups rects by position on the Hilbert curve, is probably worth a look). There also + * exist top-down bulk load variants (VAMSplit, TopDownGreedy, etc). + * + * For more details see: + * + * Beckmann, N.; Kriegel, H. P.; Schneider, R.; Seeger, B. (1990). "The R*-tree: + * an efficient and robust access method for points and rectangles" + */ +class SkRTree : public SkBBoxHierarchy { +public: + SkRTree(); + + void insert(const SkRect[], const SkBBoxHierarchy::Metadata[], int N) override; + void insert(const SkRect[], int N) override; + void search(const SkRect& query, std::vector* results) const override; + + size_t bytesUsed() const override; + + // Methods and constants below here are only public for tests. + + // Return the depth of the tree structure. + int getDepth() const { return fCount ? fRoot.fSubtree->fLevel + 1 : 0; } + // Insertion count (not overall node count, which may be greater). + int getCount() const { return fCount; } + + // These values were empirically determined to produce reasonable performance + // in most cases. + static const int kMinChildren = 6, kMaxChildren = 11; + +private: + struct Node; + + struct Branch { + union { + Node* fSubtree; + int fOpIndex; + }; + SkRect fBounds; + }; + + struct Node { + uint16_t fNumChildren; + uint16_t fLevel; + Branch fChildren[kMaxChildren]; + }; + + void search(Node* root, const SkRect& query, std::vector* results) const; + + // Consumes the input array. + Branch bulkLoad(std::vector* branches, int level = 0); + + // How many times will bulkLoad() call allocateNodeAtLevel()? + static int CountNodes(int branches); + + Node* allocateNodeAtLevel(uint16_t level); + + // This is the count of data elements (rather than total nodes in the tree) + int fCount; + Branch fRoot; + std::vector fNodes; +}; + +#endif // SKIA_PLATFORM_VIEW_RTREE_H_ From 1ff3abf943d59aa8194a4bd5bf95ac99dce3794a Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Wed, 4 Mar 2020 22:30:12 -0800 Subject: [PATCH 02/23] Implement searchRects method --- third_party/skia/platform_view_rtree.cc | 87 +++++++++++++++--- third_party/skia/platform_view_rtree.h | 20 ++++- .../skia/platform_view_rtree_unittests.cc | 89 +++++++++++++++++++ 3 files changed, 184 insertions(+), 12 deletions(-) create mode 100644 third_party/skia/platform_view_rtree_unittests.cc diff --git a/third_party/skia/platform_view_rtree.cc b/third_party/skia/platform_view_rtree.cc index 9b514d515112d..90fa0af054acd 100644 --- a/third_party/skia/platform_view_rtree.cc +++ b/third_party/skia/platform_view_rtree.cc @@ -7,9 +7,9 @@ #include "skia/platform_view_rtree.h" -SkRTree::SkRTree() : fCount(0) {} +PlatformViewRTree::PlatformViewRTree() : fCount(0) {} -void SkRTree::insert(const SkRect boundsArray[], +void PlatformViewRTree::insert(const SkRect boundsArray[], const SkBBoxHierarchy::Metadata metadata[], int N) { SkASSERT(0 == fCount); @@ -30,6 +30,7 @@ void SkRTree::insert(const SkRect boundsArray[], Branch b; b.fBounds = bounds; b.fOpIndex = i; + b.isDraw = (metadata == nullptr) ? false : metadata[i].isDraw; branches.push_back(b); } @@ -48,11 +49,11 @@ if (fCount) { } } -void SkRTree::insert(const SkRect boundsArray[], int N) { +void PlatformViewRTree::insert(const SkRect boundsArray[], int N) { insert(boundsArray, nullptr, N); } -SkRTree::Node* SkRTree::allocateNodeAtLevel(uint16_t level) { +PlatformViewRTree::Node* PlatformViewRTree::allocateNodeAtLevel(uint16_t level) { SkDEBUGCODE(Node* p = fNodes.data()); fNodes.push_back(Node{}); Node& out = fNodes.back(); @@ -64,7 +65,7 @@ SkRTree::Node* SkRTree::allocateNodeAtLevel(uint16_t level) { // This function parallels bulkLoad, but just counts how many nodes bulkLoad // would allocate. -int SkRTree::CountNodes(int branches) { +int PlatformViewRTree::CountNodes(int branches) { if (branches == 1) { return 1; } @@ -100,7 +101,7 @@ int SkRTree::CountNodes(int branches) { return nodes + CountNodes(nodes); } -SkRTree::Branch SkRTree::bulkLoad(std::vector* branches, int level) { +PlatformViewRTree::Branch PlatformViewRTree::bulkLoad(std::vector* branches, int level) { if (branches->size() == 1) { // Only one branch. It will be the root. return (*branches)[0]; } @@ -156,13 +157,13 @@ SkRTree::Branch SkRTree::bulkLoad(std::vector* branches, int level) { return this->bulkLoad(branches, level + 1); } -void SkRTree::search(const SkRect& query, std::vector* results) const { +void PlatformViewRTree::search(const SkRect& query, std::vector* results) const { if (fCount > 0 && SkRect::Intersects(fRoot.fBounds, query)) { this->search(fRoot.fSubtree, query, results); } } -void SkRTree::search(Node* node, const SkRect& query, std::vector* results) const { +void PlatformViewRTree::search(Node* node, const SkRect& query, std::vector* results) const { for (int i = 0; i < node->fNumChildren; ++i) { if (!SkRect::Intersects(node->fChildren[i].fBounds, query)) { continue; @@ -175,8 +176,74 @@ void SkRTree::search(Node* node, const SkRect& query, std::vector* results) } } -size_t SkRTree::bytesUsed() const { - size_t byteCount = sizeof(SkRTree); +void PlatformViewRTree::searchRects(const SkRect& query, std::vector* results) const { + if (fCount > 0 && SkRect::Intersects(fRoot.fBounds, query)) { + this->searchRects(fRoot.fSubtree, query, results); + } +} + +void PlatformViewRTree::searchRects(Node* node, + const SkRect& query, + std::vector* results) const { + if (!SkRect::Intersects(fRoot.fBounds, query)) { + return; + } + for (int i = 0; i < node->fNumChildren; ++i) { + if (!SkRect::Intersects(node->fChildren[i].fBounds, query)) { + continue; + } + // Non-leaf node + if (0 != node->fLevel) { + this->searchRects(node->fChildren[i].fSubtree, query, results); + continue; + } + // Ignore records that don't draw anything. + if (!node->fChildren[i].isDraw) { + continue; + } + SkRect* currentRecordRect = &node->fChildren[i].fBounds; + std::vector currentResults = *results; + bool replacedExistingRect = false; + // If the current record rect intersects with any of the rects in the + // result vector, then join them, and update the rect in results. + size_t joiningRectIdx = currentResults.size(); + size_t resultIdx = 0; + while (resultIdx < results->size()) { + if (SkRect::Intersects(*currentResults[resultIdx], *currentRecordRect)) { + joiningRectIdx = resultIdx; + replacedExistingRect = true; + currentResults[joiningRectIdx]->join(*currentRecordRect); + break; + } + resultIdx++; + } + resultIdx = joiningRectIdx + 1; + // It's possible that after joining rects will result in duplicated + // rects in the results vector. For example, consider a result vector + // that contains rects A, B. If a new rect C is a superset of A and B, + // then A and B are the same set after the merge. As a result, find such + // cases and remove them from the result vector. + while (replacedExistingRect && resultIdx < results->size()) { + if (SkRect::Intersects(*currentResults[resultIdx], *currentResults[joiningRectIdx])) { + currentResults[joiningRectIdx]->join(*currentResults[resultIdx]); + results->erase(results->begin() + resultIdx); + } else { + resultIdx++; + } + } + if (!replacedExistingRect) { + results->push_back(currentRecordRect); + } + } +} + +size_t PlatformViewRTree::bytesUsed() const { + size_t byteCount = sizeof(PlatformViewRTree); byteCount += fNodes.capacity() * sizeof(Node); return byteCount; } + +PlatformViewRTreeFactory::PlatformViewRTreeFactory(sk_sp& r_tree) + : r_tree_(r_tree) {} + +sk_sp PlatformViewRTreeFactory::operator()() const { return r_tree_; } diff --git a/third_party/skia/platform_view_rtree.h b/third_party/skia/platform_view_rtree.h index 700438f7c219e..d61b874fbd81c 100644 --- a/third_party/skia/platform_view_rtree.h +++ b/third_party/skia/platform_view_rtree.h @@ -27,14 +27,19 @@ * Beckmann, N.; Kriegel, H. P.; Schneider, R.; Seeger, B. (1990). "The R*-tree: * an efficient and robust access method for points and rectangles" */ -class SkRTree : public SkBBoxHierarchy { +class PlatformViewRTree : public SkBBoxHierarchy { public: - SkRTree(); + PlatformViewRTree(); void insert(const SkRect[], const SkBBoxHierarchy::Metadata[], int N) override; void insert(const SkRect[], int N) override; void search(const SkRect& query, std::vector* results) const override; + // Finds the rects in the tree that intersect with the query rect. Each of the + // entries in the result vector don't intersect with each other. In other words, + // the entries are mutually exclusive. + void searchRects(const SkRect& query, std::vector* results) const; + size_t bytesUsed() const override; // Methods and constants below here are only public for tests. @@ -56,6 +61,7 @@ class SkRTree : public SkBBoxHierarchy { Node* fSubtree; int fOpIndex; }; + bool isDraw; SkRect fBounds; }; @@ -66,6 +72,7 @@ class SkRTree : public SkBBoxHierarchy { }; void search(Node* root, const SkRect& query, std::vector* results) const; + void searchRects(Node* root, const SkRect& query, std::vector* results) const; // Consumes the input array. Branch bulkLoad(std::vector* branches, int level = 0); @@ -81,4 +88,13 @@ class SkRTree : public SkBBoxHierarchy { std::vector fNodes; }; +class PlatformViewRTreeFactory : public SkBBHFactory { +public: + PlatformViewRTreeFactory(sk_sp& r_tree); + sk_sp operator()() const override; + +private: + sk_sp r_tree_; +}; + #endif // SKIA_PLATFORM_VIEW_RTREE_H_ diff --git a/third_party/skia/platform_view_rtree_unittests.cc b/third_party/skia/platform_view_rtree_unittests.cc new file mode 100644 index 0000000000000..32a6bf2be9832 --- /dev/null +++ b/third_party/skia/platform_view_rtree_unittests.cc @@ -0,0 +1,89 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "flutter/testing/testing.h" +#include "flutter/testing/thread_test.h" + +#include "skia/platform_view_rtree.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkPictureRecorder.h" + +namespace flutter { +namespace testing { + +using PlatformViewRTreeTest = ThreadTest; + +TEST_F(PlatformViewRTreeTest, NoIntersection) { + auto r_tree = sk_make_sp(); + auto rtree_factory = PlatformViewRTreeFactory(r_tree); + auto recorder = std::make_unique(); + auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); + + auto rect_paint = SkPaint(); + rect_paint.setColor(SkColors::kCyan); + rect_paint.setStyle(SkPaint::Style::kFill_Style); + + recording_canvas->drawRect(SkRect::MakeXYWH(20, 20, 20, 20), rect_paint); + recorder->finishRecordingAsPicture(); + + auto hits = std::vector(); + auto unobstructed = SkRect::MakeXYWH(40, 40, 20, 20); + + r_tree->searchRects(unobstructed, &hits); + ASSERT_TRUE(hits.empty()); +} + +TEST_F(PlatformViewRTreeTest, Intersection) { + auto r_tree = sk_make_sp(); + auto rtree_factory = PlatformViewRTreeFactory(r_tree); + auto recorder = std::make_unique(); + auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); + + auto rect_paint = SkPaint(); + rect_paint.setColor(SkColors::kCyan); + rect_paint.setStyle(SkPaint::Style::kFill_Style); + + recording_canvas->drawRect(SkRect::MakeXYWH(120, 120, 40, 40), rect_paint); + + recorder->finishRecordingAsPicture(); + + // Hits that partially overlap with a drawn area return bboxes describing the + // intersection of the query and the drawn area. + auto one_hit = SkRect::MakeXYWH(140, 140, 40, 40); + auto hits = std::vector(); + + r_tree->searchRects(one_hit, &hits); + ASSERT_EQ(1UL, hits.size()); + ASSERT_EQ(*hits[0], SkRect::MakeXYWH(120, 120, 40, 40)); +} + +TEST_F(PlatformViewRTreeTest, JoinRectsWhenIntersected) { + auto r_tree = sk_make_sp(); + auto rtree_factory = PlatformViewRTreeFactory(r_tree); + auto recorder = std::make_unique(); + auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); + + auto rect_paint = SkPaint(); + rect_paint.setColor(SkColors::kCyan); + rect_paint.setStyle(SkPaint::Style::kFill_Style); + + recording_canvas->drawRect(SkRect::MakeXYWH(120, 120, 40, 40), rect_paint); + recording_canvas->drawRect(SkRect::MakeXYWH(140, 140, 40, 40), rect_paint); + + recorder->finishRecordingAsPicture(); + + // Hits that partially overlap with a drawn area return bboxes describing the + // intersection of the query and the drawn area. + auto one_hit = SkRect::MakeXYWH(142, 142, 10, 10); + auto hits = std::vector(); + + r_tree->searchRects(one_hit, &hits); + ASSERT_EQ(1UL, hits.size()); + ASSERT_EQ(*hits[0], SkRect::MakeXYWH(120, 120, 60, 60)); +} + +} // namespace testing +} // namespace flutter From c71cf491a7b4f2814647d50ebb31b5e08bc2a11c Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Wed, 4 Mar 2020 23:19:51 -0800 Subject: [PATCH 03/23] Add more tests for the searchRect method --- .../skia/platform_view_rtree_unittests.cc | 110 +++++++++++++----- 1 file changed, 83 insertions(+), 27 deletions(-) diff --git a/third_party/skia/platform_view_rtree_unittests.cc b/third_party/skia/platform_view_rtree_unittests.cc index 32a6bf2be9832..b5a1f3467d3c8 100644 --- a/third_party/skia/platform_view_rtree_unittests.cc +++ b/third_party/skia/platform_view_rtree_unittests.cc @@ -4,21 +4,22 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ + #include "flutter/testing/testing.h" #include "flutter/testing/thread_test.h" - #include "skia/platform_view_rtree.h" + #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPictureRecorder.h" namespace flutter { namespace testing { -using PlatformViewRTreeTest = ThreadTest; +using PlatformViewRTree = ThreadTest; -TEST_F(PlatformViewRTreeTest, NoIntersection) { - auto r_tree = sk_make_sp(); - auto rtree_factory = PlatformViewRTreeFactory(r_tree); +TEST_F(PlatformViewRTree, NoIntersection) { + auto r_tree = sk_make_sp(); + auto rtree_factory = FlutterRTreeFactory(r_tree); auto recorder = std::make_unique(); auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); @@ -26,19 +27,44 @@ TEST_F(PlatformViewRTreeTest, NoIntersection) { rect_paint.setColor(SkColors::kCyan); rect_paint.setStyle(SkPaint::Style::kFill_Style); - recording_canvas->drawRect(SkRect::MakeXYWH(20, 20, 20, 20), rect_paint); + // If no rect is intersected with the query rect, then the result vector is empty. + recording_canvas->drawRect(SkRect::MakeLTRB(20, 20, 40, 40), rect_paint); recorder->finishRecordingAsPicture(); auto hits = std::vector(); - auto unobstructed = SkRect::MakeXYWH(40, 40, 20, 20); + auto query = SkRect::MakeLTRB(40, 40, 80, 80); - r_tree->searchRects(unobstructed, &hits); + r_tree->searchRects(query, &hits); ASSERT_TRUE(hits.empty()); } -TEST_F(PlatformViewRTreeTest, Intersection) { - auto r_tree = sk_make_sp(); - auto rtree_factory = PlatformViewRTreeFactory(r_tree); +TEST_F(PlatformViewRTree, Intersection) { + auto r_tree = sk_make_sp(); + auto rtree_factory = FlutterRTreeFactory(r_tree); + auto recorder = std::make_unique(); + auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); + + auto rect_paint = SkPaint(); + rect_paint.setColor(SkColors::kCyan); + rect_paint.setStyle(SkPaint::Style::kFill_Style); + + // Given a single rect A that intersects with the query rect, + // the result vector contains this rect. + recording_canvas->drawRect(SkRect::MakeLTRB(120, 120, 160, 160), rect_paint); + + recorder->finishRecordingAsPicture(); + + auto query = SkRect::MakeLTRB(140, 140, 150, 150); + auto hits = std::vector(); + + r_tree->searchRects(query, &hits); + ASSERT_EQ(1UL, hits.size()); + ASSERT_EQ(*hits[0], SkRect::MakeLTRB(120, 120, 160, 160)); +} + +TEST_F(PlatformViewRTree, JoinRectsWhenIntersectedCase1) { + auto r_tree = sk_make_sp(); + auto rtree_factory = FlutterRTreeFactory(r_tree); auto recorder = std::make_unique(); auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); @@ -46,23 +72,35 @@ TEST_F(PlatformViewRTreeTest, Intersection) { rect_paint.setColor(SkColors::kCyan); rect_paint.setStyle(SkPaint::Style::kFill_Style); - recording_canvas->drawRect(SkRect::MakeXYWH(120, 120, 40, 40), rect_paint); + // Given the A, and B rects, which intersect with the query rect, + // the result vector contains the rect resulting from the union of A and B. + // + // +-----+ + // | A | + // | +-----+ + // | | C | + // | +-----+ + // | | + // +-----+ + + // A + recording_canvas->drawRect(SkRect::MakeLTRB(100, 100, 150, 150), rect_paint); + // B + recording_canvas->drawRect(SkRect::MakeLTRB(125, 125, 175, 175), rect_paint); recorder->finishRecordingAsPicture(); - // Hits that partially overlap with a drawn area return bboxes describing the - // intersection of the query and the drawn area. - auto one_hit = SkRect::MakeXYWH(140, 140, 40, 40); + auto query = SkRect::MakeXYWH(120, 120, 126, 126); auto hits = std::vector(); - r_tree->searchRects(one_hit, &hits); + r_tree->searchRects(query, &hits); ASSERT_EQ(1UL, hits.size()); - ASSERT_EQ(*hits[0], SkRect::MakeXYWH(120, 120, 40, 40)); + ASSERT_EQ(*hits[0], SkRect::MakeLTRB(100, 100, 175, 175)); } -TEST_F(PlatformViewRTreeTest, JoinRectsWhenIntersected) { - auto r_tree = sk_make_sp(); - auto rtree_factory = PlatformViewRTreeFactory(r_tree); +TEST_F(PlatformViewRTree, JoinRectsWhenIntersectedCase2) { + auto r_tree = sk_make_sp(); + auto rtree_factory = FlutterRTreeFactory(r_tree); auto recorder = std::make_unique(); auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); @@ -70,19 +108,37 @@ TEST_F(PlatformViewRTreeTest, JoinRectsWhenIntersected) { rect_paint.setColor(SkColors::kCyan); rect_paint.setStyle(SkPaint::Style::kFill_Style); - recording_canvas->drawRect(SkRect::MakeXYWH(120, 120, 40, 40), rect_paint); - recording_canvas->drawRect(SkRect::MakeXYWH(140, 140, 40, 40), rect_paint); + // Given the A, B, and C rects that intersect with the query rect, + // there should be only C in the result vector, + // since A and B are contained in C. + // + // +---------------------+ + // | C | + // | +-----+ +-----+ | + // | | A | | B | | + // | +-----+ +-----+ | + // +---------------------+ + // +-----+ + // | D | + // +-----+ + + // A + recording_canvas->drawRect(SkRect::MakeLTRB(100, 100, 200, 200), rect_paint); + // B + recording_canvas->drawRect(SkRect::MakeLTRB(300, 100, 400, 200), rect_paint); + // C + recording_canvas->drawRect(SkRect::MakeLTRB(50, 50, 500, 250), rect_paint); + // D + recording_canvas->drawRect(SkRect::MakeLTRB(280, 100, 280, 320), rect_paint); recorder->finishRecordingAsPicture(); - // Hits that partially overlap with a drawn area return bboxes describing the - // intersection of the query and the drawn area. - auto one_hit = SkRect::MakeXYWH(142, 142, 10, 10); + auto query = SkRect::MakeLTRB(30, 30, 550, 270); auto hits = std::vector(); - r_tree->searchRects(one_hit, &hits); + r_tree->searchRects(query, &hits); ASSERT_EQ(1UL, hits.size()); - ASSERT_EQ(*hits[0], SkRect::MakeXYWH(120, 120, 60, 60)); + ASSERT_EQ(*hits[0], SkRect::MakeLTRB(50, 50, 500, 250)); } } // namespace testing From e2c5dbdc458becd7f93bc510094a6810622308fc Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 5 Mar 2020 10:13:05 -0800 Subject: [PATCH 04/23] Add additional rtree unit test --- .../skia/platform_view_rtree_unittests.cc | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/third_party/skia/platform_view_rtree_unittests.cc b/third_party/skia/platform_view_rtree_unittests.cc index b5a1f3467d3c8..9f360112b93b5 100644 --- a/third_party/skia/platform_view_rtree_unittests.cc +++ b/third_party/skia/platform_view_rtree_unittests.cc @@ -141,5 +141,50 @@ TEST_F(PlatformViewRTree, JoinRectsWhenIntersectedCase2) { ASSERT_EQ(*hits[0], SkRect::MakeLTRB(50, 50, 500, 250)); } +TEST_F(PlatformViewRTree, JoinRectsWhenIntersectedCase3) { + auto r_tree = sk_make_sp(); + auto rtree_factory = FlutterRTreeFactory(r_tree); + auto recorder = std::make_unique(); + auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); + + auto rect_paint = SkPaint(); + rect_paint.setColor(SkColors::kCyan); + rect_paint.setStyle(SkPaint::Style::kFill_Style); + + // Given the A, B, C and D rects that intersect with the query rect, + // there should be only D in the result vector, + // since A, B, and C are contained in C. + // + // +------------------------------+ + // | D | + // | +-----+ +-----+ +-----+ | + // | | A | | B | | C | | + // | +-----+ +-----+ +-----+ | + // +------------------------------+ + // +-----+ + // | E | + // +-----+ + + // A + recording_canvas->drawRect(SkRect::MakeLTRB(100, 100, 200, 200), rect_paint); + // B + recording_canvas->drawRect(SkRect::MakeLTRB(300, 100, 400, 200), rect_paint); + // C + recording_canvas->drawRect(SkRect::MakeLTRB(500, 100, 600, 300), rect_paint); + // D + recording_canvas->drawRect(SkRect::MakeLTRB(50, 50, 620, 250), rect_paint); + // E + recording_canvas->drawRect(SkRect::MakeLTRB(280, 100, 280, 320), rect_paint); + + recorder->finishRecordingAsPicture(); + + auto query = SkRect::MakeLTRB(30, 30, 550, 270); + auto hits = std::vector(); + + r_tree->searchRects(query, &hits); + ASSERT_EQ(1UL, hits.size()); + ASSERT_EQ(*hits[0], SkRect::MakeLTRB(50, 50, 620, 250)); +} + } // namespace testing } // namespace flutter From efc58472625465ffeb4d6206081de88f8992b74d Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 5 Mar 2020 10:16:22 -0800 Subject: [PATCH 05/23] typo --- third_party/skia/platform_view_rtree_unittests.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/skia/platform_view_rtree_unittests.cc b/third_party/skia/platform_view_rtree_unittests.cc index 9f360112b93b5..a6743907c1cc3 100644 --- a/third_party/skia/platform_view_rtree_unittests.cc +++ b/third_party/skia/platform_view_rtree_unittests.cc @@ -153,7 +153,7 @@ TEST_F(PlatformViewRTree, JoinRectsWhenIntersectedCase3) { // Given the A, B, C and D rects that intersect with the query rect, // there should be only D in the result vector, - // since A, B, and C are contained in C. + // since A, B, and C are contained in D. // // +------------------------------+ // | D | From 1f2eb576079e0c7dcb4cf419debb8da975c0fe8b Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 5 Mar 2020 10:59:22 -0800 Subject: [PATCH 06/23] Remove ThreadTest --- third_party/skia/platform_view_rtree_unittests.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/third_party/skia/platform_view_rtree_unittests.cc b/third_party/skia/platform_view_rtree_unittests.cc index a6743907c1cc3..31330b5fc6dd1 100644 --- a/third_party/skia/platform_view_rtree_unittests.cc +++ b/third_party/skia/platform_view_rtree_unittests.cc @@ -15,8 +15,6 @@ namespace flutter { namespace testing { -using PlatformViewRTree = ThreadTest; - TEST_F(PlatformViewRTree, NoIntersection) { auto r_tree = sk_make_sp(); auto rtree_factory = FlutterRTreeFactory(r_tree); From 3f9b3cbcde437a36b65e6e754e2d2bf6d73c9654 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 5 Mar 2020 14:16:33 -0800 Subject: [PATCH 07/23] Address Chinmay comments --- BUILD.gn | 1 + testing/run_tests.py | 2 + third_party/skia/BUILD.gn | 21 +++ third_party/skia/main_unittests.cc | 15 ++ third_party/skia/platform_view_rtree.cc | 74 +++++----- third_party/skia/platform_view_rtree.h | 4 +- .../skia/platform_view_rtree_unittests.cc | 129 ++++++++++++------ 7 files changed, 161 insertions(+), 85 deletions(-) create mode 100644 third_party/skia/main_unittests.cc diff --git a/BUILD.gn b/BUILD.gn index 25006866ca896..f8298b22e731d 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -79,6 +79,7 @@ group("flutter") { "//flutter/shell/platform/embedder:embedder_unittests", "//flutter/shell/platform/glfw/client_wrapper:client_wrapper_glfw_unittests", "//flutter/testing:testing_unittests", + "//flutter/third_party/skia:skia_unittests", "//flutter/third_party/txt:txt_unittests", ] diff --git a/testing/run_tests.py b/testing/run_tests.py index cb11932eae934..9f1b71eab2216 100755 --- a/testing/run_tests.py +++ b/testing/run_tests.py @@ -147,6 +147,8 @@ def RunCCTests(build_dir, filter): if IsLinux(): RunEngineExecutable(build_dir, 'txt_unittests', filter, shuffle_flags) + RunEngineExecutable(build_dir, 'skia_unittests', filter, shuffle_flags) + def RunEngineBenchmarks(build_dir, filter): print("Running Engine Benchmarks.") diff --git a/third_party/skia/BUILD.gn b/third_party/skia/BUILD.gn index f4231bf32634d..043d55693fd78 100644 --- a/third_party/skia/BUILD.gn +++ b/third_party/skia/BUILD.gn @@ -3,6 +3,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//flutter/testing/testing.gni") + source_set("skia") { sources = [ "platform_view_rtree.cc", @@ -13,3 +15,22 @@ source_set("skia") { "//third_party/skia", ] } + +test_fixtures("skia_fixtures") { + fixtures = [] +} + +executable("skia_unittests") { + testonly = true + sources = [ + "platform_view_rtree_unittests.cc", + "main_unittests.cc", + ] + deps = [ + ":skia", + ":skia_fixtures", + "//flutter/testing:testing_lib", + "//third_party/dart/runtime:libdart_jit", # For logging. + "//third_party/skia", + ] +} diff --git a/third_party/skia/main_unittests.cc b/third_party/skia/main_unittests.cc new file mode 100644 index 0000000000000..d42e66aaaa80f --- /dev/null +++ b/third_party/skia/main_unittests.cc @@ -0,0 +1,15 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "flutter/testing/testing.h" + +#include + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/third_party/skia/platform_view_rtree.cc b/third_party/skia/platform_view_rtree.cc index 90fa0af054acd..e6c565b240ffc 100644 --- a/third_party/skia/platform_view_rtree.cc +++ b/third_party/skia/platform_view_rtree.cc @@ -5,7 +5,7 @@ * found in the LICENSE file. */ -#include "skia/platform_view_rtree.h" +#include "platform_view_rtree.h" PlatformViewRTree::PlatformViewRTree() : fCount(0) {} @@ -25,27 +25,23 @@ void PlatformViewRTree::insert(const SkRect boundsArray[], Branch b; b.fBounds = bounds; b.fOpIndex = i; + b.isDraw = (metadata == nullptr) ? false : metadata[i].isDraw; branches.push_back(b); } - Branch b; - b.fBounds = bounds; - b.fOpIndex = i; - b.isDraw = (metadata == nullptr) ? false : metadata[i].isDraw; - branches.push_back(b); -} -fCount = (int)branches.size(); -if (fCount) { - if (1 == fCount) { - fNodes.reserve(1); - Node* n = this->allocateNodeAtLevel(0); - n->fNumChildren = 1; - n->fChildren[0] = branches[0]; - fRoot.fSubtree = n; - fRoot.fBounds = branches[0].fBounds; - } else { - fNodes.reserve(CountNodes(fCount)); - fRoot = this->bulkLoad(&branches); + fCount = (int)branches.size(); + if (fCount) { + if (1 == fCount) { + fNodes.reserve(1); + Node* n = this->allocateNodeAtLevel(0); + n->fNumChildren = 1; + n->fChildren[0] = branches[0]; + fRoot.fSubtree = n; + fRoot.fBounds = branches[0].fBounds; + } else { + fNodes.reserve(CountNodes(fCount)); + fRoot = this->bulkLoad(&branches); + } } } @@ -176,15 +172,17 @@ void PlatformViewRTree::search(Node* node, const SkRect& query, std::vector } } -void PlatformViewRTree::searchRects(const SkRect& query, std::vector* results) const { +std::vector PlatformViewRTree::searchRects(const SkRect& query) const { + std::vector results; if (fCount > 0 && SkRect::Intersects(fRoot.fBounds, query)) { this->searchRects(fRoot.fSubtree, query, results); } + return results; } void PlatformViewRTree::searchRects(Node* node, const SkRect& query, - std::vector* results) const { + std::vector& results) const { if (!SkRect::Intersects(fRoot.fBounds, query)) { return; } @@ -201,38 +199,36 @@ void PlatformViewRTree::searchRects(Node* node, if (!node->fChildren[i].isDraw) { continue; } - SkRect* currentRecordRect = &node->fChildren[i].fBounds; - std::vector currentResults = *results; + SkRect currentRecordRect = node->fChildren[i].fBounds; bool replacedExistingRect = false; - // If the current record rect intersects with any of the rects in the - // result vector, then join them, and update the rect in results. - size_t joiningRectIdx = currentResults.size(); + // // If the current record rect intersects with any of the rects in the + // // result vector, then join them, and update the rect in results. + size_t joiningRectIdx = results.size(); size_t resultIdx = 0; - while (resultIdx < results->size()) { - if (SkRect::Intersects(*currentResults[resultIdx], *currentRecordRect)) { + while (resultIdx < results.size()) { + if (SkRect::Intersects(results[resultIdx], currentRecordRect)) { joiningRectIdx = resultIdx; replacedExistingRect = true; - currentResults[joiningRectIdx]->join(*currentRecordRect); + results[joiningRectIdx].join(currentRecordRect); break; } resultIdx++; } resultIdx = joiningRectIdx + 1; - // It's possible that after joining rects will result in duplicated - // rects in the results vector. For example, consider a result vector - // that contains rects A, B. If a new rect C is a superset of A and B, - // then A and B are the same set after the merge. As a result, find such - // cases and remove them from the result vector. - while (replacedExistingRect && resultIdx < results->size()) { - if (SkRect::Intersects(*currentResults[resultIdx], *currentResults[joiningRectIdx])) { - currentResults[joiningRectIdx]->join(*currentResults[resultIdx]); - results->erase(results->begin() + resultIdx); + // It's possible that the result contains duplicated rects at this point. + // For example, consider a result vector that contains rects A, B. If a + // new rect C is a superset of A and B, then A and B are the same set after + // the merge. As a result, find such cases and remove them from the result vector. + while (replacedExistingRect && resultIdx < results.size()) { + if (SkRect::Intersects(results[resultIdx], results[joiningRectIdx])) { + results[joiningRectIdx].join(results[resultIdx]); + results.erase(results.begin() + resultIdx); } else { resultIdx++; } } if (!replacedExistingRect) { - results->push_back(currentRecordRect); + results.push_back(currentRecordRect); } } } diff --git a/third_party/skia/platform_view_rtree.h b/third_party/skia/platform_view_rtree.h index d61b874fbd81c..0d9743f78b9b5 100644 --- a/third_party/skia/platform_view_rtree.h +++ b/third_party/skia/platform_view_rtree.h @@ -38,7 +38,7 @@ class PlatformViewRTree : public SkBBoxHierarchy { // Finds the rects in the tree that intersect with the query rect. Each of the // entries in the result vector don't intersect with each other. In other words, // the entries are mutually exclusive. - void searchRects(const SkRect& query, std::vector* results) const; + std::vector searchRects(const SkRect& query) const; size_t bytesUsed() const override; @@ -72,7 +72,7 @@ class PlatformViewRTree : public SkBBoxHierarchy { }; void search(Node* root, const SkRect& query, std::vector* results) const; - void searchRects(Node* root, const SkRect& query, std::vector* results) const; + void searchRects(Node* root, const SkRect& query, std::vector& results) const; // Consumes the input array. Branch bulkLoad(std::vector* branches, int level = 0); diff --git a/third_party/skia/platform_view_rtree_unittests.cc b/third_party/skia/platform_view_rtree_unittests.cc index 31330b5fc6dd1..232236175489b 100644 --- a/third_party/skia/platform_view_rtree_unittests.cc +++ b/third_party/skia/platform_view_rtree_unittests.cc @@ -6,8 +6,7 @@ */ #include "flutter/testing/testing.h" -#include "flutter/testing/thread_test.h" -#include "skia/platform_view_rtree.h" +#include "platform_view_rtree.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPictureRecorder.h" @@ -15,9 +14,9 @@ namespace flutter { namespace testing { -TEST_F(PlatformViewRTree, NoIntersection) { - auto r_tree = sk_make_sp(); - auto rtree_factory = FlutterRTreeFactory(r_tree); +TEST(PlatformViewRTree, NoIntersection) { + auto r_tree = sk_make_sp(); + auto rtree_factory = PlatformViewRTreeFactory(r_tree); auto recorder = std::make_unique(); auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); @@ -29,16 +28,13 @@ TEST_F(PlatformViewRTree, NoIntersection) { recording_canvas->drawRect(SkRect::MakeLTRB(20, 20, 40, 40), rect_paint); recorder->finishRecordingAsPicture(); - auto hits = std::vector(); - auto query = SkRect::MakeLTRB(40, 40, 80, 80); - - r_tree->searchRects(query, &hits); + auto hits = r_tree->searchRects(SkRect::MakeLTRB(40, 40, 80, 80)); ASSERT_TRUE(hits.empty()); } -TEST_F(PlatformViewRTree, Intersection) { - auto r_tree = sk_make_sp(); - auto rtree_factory = FlutterRTreeFactory(r_tree); +TEST(PlatformViewRTree, SingleRectIntersection) { + auto r_tree = sk_make_sp(); + auto rtree_factory = PlatformViewRTreeFactory(r_tree); auto recorder = std::make_unique(); auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); @@ -52,17 +48,70 @@ TEST_F(PlatformViewRTree, Intersection) { recorder->finishRecordingAsPicture(); - auto query = SkRect::MakeLTRB(140, 140, 150, 150); - auto hits = std::vector(); + auto hits = r_tree->searchRects(SkRect::MakeLTRB(140, 140, 150, 150)); + ASSERT_EQ(1UL, hits.size()); + ASSERT_EQ(hits[0], SkRect::MakeLTRB(120, 120, 160, 160)); +} + +TEST(PlatformViewRTree, IgnoresNonDrawingRecords) { + auto r_tree = sk_make_sp(); + auto rtree_factory = PlatformViewRTreeFactory(r_tree); + auto recorder = std::make_unique(); + auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); + + auto rect_paint = SkPaint(); + rect_paint.setColor(SkColors::kCyan); + rect_paint.setStyle(SkPaint::Style::kFill_Style); + + // Creates two non drawing records. + recording_canvas->translate(100, 100); + // The result vector should only contain the clipping rect. + recording_canvas->clipRect(SkRect::MakeLTRB(40, 40, 50, 50), SkClipOp::kIntersect); + recording_canvas->drawRect(SkRect::MakeLTRB(20, 20, 80, 80), rect_paint); + + recorder->finishRecordingAsPicture(); + + // The rtree has a translate, a clip and a rect record. + ASSERT_EQ(3, r_tree->getCount()); - r_tree->searchRects(query, &hits); + auto hits = r_tree->searchRects(SkRect::MakeLTRB(0, 0, 1000, 1000)); ASSERT_EQ(1UL, hits.size()); - ASSERT_EQ(*hits[0], SkRect::MakeLTRB(120, 120, 160, 160)); + ASSERT_EQ(hits[0], SkRect::MakeLTRB(120, 120, 180, 180)); +} + +TEST(PlatformViewRTree, MultipleRectIntersection) { + auto r_tree = sk_make_sp(); + auto rtree_factory = PlatformViewRTreeFactory(r_tree); + auto recorder = std::make_unique(); + auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); + + auto rect_paint = SkPaint(); + rect_paint.setColor(SkColors::kCyan); + rect_paint.setStyle(SkPaint::Style::kFill_Style); + + // Given the A, B that intersect with the query rect, + // there should be A and B in the result vector since + // they don't intersect with each other. + // + // +-----+ +-----+ + // | A | | B | + // +-----+ +-----+ + // A + recording_canvas->drawRect(SkRect::MakeLTRB(100, 100, 200, 200), rect_paint); + // B + recording_canvas->drawRect(SkRect::MakeLTRB(300, 100, 400, 200), rect_paint); + + recorder->finishRecordingAsPicture(); + + auto hits = r_tree->searchRects(SkRect::MakeLTRB(0, 0, 1000, 1050)); + ASSERT_EQ(2UL, hits.size()); + ASSERT_EQ(hits[0], SkRect::MakeLTRB(100, 100, 200, 200)); + ASSERT_EQ(hits[1], SkRect::MakeLTRB(300, 100, 400, 200)); } -TEST_F(PlatformViewRTree, JoinRectsWhenIntersectedCase1) { - auto r_tree = sk_make_sp(); - auto rtree_factory = FlutterRTreeFactory(r_tree); +TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase1) { + auto r_tree = sk_make_sp(); + auto rtree_factory = PlatformViewRTreeFactory(r_tree); auto recorder = std::make_unique(); auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); @@ -88,17 +137,14 @@ TEST_F(PlatformViewRTree, JoinRectsWhenIntersectedCase1) { recorder->finishRecordingAsPicture(); - auto query = SkRect::MakeXYWH(120, 120, 126, 126); - auto hits = std::vector(); - - r_tree->searchRects(query, &hits); + auto hits = r_tree->searchRects(SkRect::MakeXYWH(120, 120, 126, 126)); ASSERT_EQ(1UL, hits.size()); - ASSERT_EQ(*hits[0], SkRect::MakeLTRB(100, 100, 175, 175)); + ASSERT_EQ(hits[0], SkRect::MakeLTRB(100, 100, 175, 175)); } -TEST_F(PlatformViewRTree, JoinRectsWhenIntersectedCase2) { - auto r_tree = sk_make_sp(); - auto rtree_factory = FlutterRTreeFactory(r_tree); +TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase2) { + auto r_tree = sk_make_sp(); + auto rtree_factory = PlatformViewRTreeFactory(r_tree); auto recorder = std::make_unique(); auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); @@ -131,17 +177,14 @@ TEST_F(PlatformViewRTree, JoinRectsWhenIntersectedCase2) { recorder->finishRecordingAsPicture(); - auto query = SkRect::MakeLTRB(30, 30, 550, 270); - auto hits = std::vector(); - - r_tree->searchRects(query, &hits); + auto hits = r_tree->searchRects(SkRect::MakeLTRB(30, 30, 550, 270)); ASSERT_EQ(1UL, hits.size()); - ASSERT_EQ(*hits[0], SkRect::MakeLTRB(50, 50, 500, 250)); + ASSERT_EQ(hits[0], SkRect::MakeLTRB(50, 50, 500, 250)); } -TEST_F(PlatformViewRTree, JoinRectsWhenIntersectedCase3) { - auto r_tree = sk_make_sp(); - auto rtree_factory = FlutterRTreeFactory(r_tree); +TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase3) { + auto r_tree = sk_make_sp(); + auto rtree_factory = PlatformViewRTreeFactory(r_tree); auto recorder = std::make_unique(); auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); @@ -150,15 +193,16 @@ TEST_F(PlatformViewRTree, JoinRectsWhenIntersectedCase3) { rect_paint.setStyle(SkPaint::Style::kFill_Style); // Given the A, B, C and D rects that intersect with the query rect, - // there should be only D in the result vector, - // since A, B, and C are contained in D. + // the result vector contains a single rect, which is the union of + // these four rects. // // +------------------------------+ // | D | // | +-----+ +-----+ +-----+ | // | | A | | B | | C | | - // | +-----+ +-----+ +-----+ | - // +------------------------------+ + // | +-----+ +-----+ | | | + // +----------------------| |-+ + // +-----+ // +-----+ // | E | // +-----+ @@ -176,12 +220,9 @@ TEST_F(PlatformViewRTree, JoinRectsWhenIntersectedCase3) { recorder->finishRecordingAsPicture(); - auto query = SkRect::MakeLTRB(30, 30, 550, 270); - auto hits = std::vector(); - - r_tree->searchRects(query, &hits); + auto hits = r_tree->searchRects(SkRect::MakeLTRB(30, 30, 550, 270)); ASSERT_EQ(1UL, hits.size()); - ASSERT_EQ(*hits[0], SkRect::MakeLTRB(50, 50, 620, 250)); + ASSERT_EQ(hits[0], SkRect::MakeLTRB(50, 50, 620, 300)); } } // namespace testing From 78e8f22661cae1d091f51e90ffd0c1a604841e45 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 5 Mar 2020 15:14:14 -0800 Subject: [PATCH 08/23] Address comments --- third_party/skia/platform_view_rtree.h | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/third_party/skia/platform_view_rtree.h b/third_party/skia/platform_view_rtree.h index 0d9743f78b9b5..97069c6d0388c 100644 --- a/third_party/skia/platform_view_rtree.h +++ b/third_party/skia/platform_view_rtree.h @@ -26,6 +26,11 @@ * * Beckmann, N.; Kriegel, H. P.; Schneider, R.; Seeger, B. (1990). "The R*-tree: * an efficient and robust access method for points and rectangles" + * + * The original source code can be found on + * https://github.com/google/skia/blob/508fd32091afe334d4e1dd6cdaa63168a53acb26/src/core/SkRTree.h + * + * This copy includes a searchRects method. */ class PlatformViewRTree : public SkBBoxHierarchy { public: @@ -35,9 +40,20 @@ class PlatformViewRTree : public SkBBoxHierarchy { void insert(const SkRect[], int N) override; void search(const SkRect& query, std::vector* results) const override; - // Finds the rects in the tree that intersect with the query rect. Each of the - // entries in the result vector don't intersect with each other. In other words, - // the entries are mutually exclusive. + // Finds the rects in the tree that represent drawing operations and intersect + // with the query rect. + // + // When two rects intersect with each other, they are joined into a single rect + // which also intersects with the query rect. In other words, the bounds of each + // rect in the result vector are mutually exclusive. + // + // Since this method is used when compositing platform views, the rects in the + // result vector represent UIViews that are composed on top of the platform view. + // + // However, Skia uses this tree to tracks operations that don't have any context + // on how they relate to each other when compositing the final scene in Flutter. + // For example, they may include matrix changes, clips or rects that are stacked + // on top of each other. std::vector searchRects(const SkRect& query) const; size_t bytesUsed() const override; From 60bfda473de50de8a542cb1c117883eb14e609b1 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 5 Mar 2020 15:14:27 -0800 Subject: [PATCH 09/23] Format gn --- third_party/skia/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/skia/BUILD.gn b/third_party/skia/BUILD.gn index 043d55693fd78..ba72aa9f9e12b 100644 --- a/third_party/skia/BUILD.gn +++ b/third_party/skia/BUILD.gn @@ -23,8 +23,8 @@ test_fixtures("skia_fixtures") { executable("skia_unittests") { testonly = true sources = [ - "platform_view_rtree_unittests.cc", "main_unittests.cc", + "platform_view_rtree_unittests.cc", ] deps = [ ":skia", From bb131870380b2327f41759292e5f915e44344eb9 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 5 Mar 2020 16:06:52 -0800 Subject: [PATCH 10/23] Address comments --- third_party/skia/platform_view_rtree.cc | 34 +++++++++---------- third_party/skia/platform_view_rtree.h | 7 ++-- .../skia/platform_view_rtree_unittests.cc | 14 ++++---- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/third_party/skia/platform_view_rtree.cc b/third_party/skia/platform_view_rtree.cc index e6c565b240ffc..299e12f7cd2ba 100644 --- a/third_party/skia/platform_view_rtree.cc +++ b/third_party/skia/platform_view_rtree.cc @@ -5,6 +5,8 @@ * found in the LICENSE file. */ +#include + #include "platform_view_rtree.h" PlatformViewRTree::PlatformViewRTree() : fCount(0) {} @@ -172,8 +174,8 @@ void PlatformViewRTree::search(Node* node, const SkRect& query, std::vector } } -std::vector PlatformViewRTree::searchRects(const SkRect& query) const { - std::vector results; +std::list PlatformViewRTree::searchRects(const SkRect& query) const { + std::list results; if (fCount > 0 && SkRect::Intersects(fRoot.fBounds, query)) { this->searchRects(fRoot.fSubtree, query, results); } @@ -182,7 +184,7 @@ std::vector PlatformViewRTree::searchRects(const SkRect& query) const { void PlatformViewRTree::searchRects(Node* node, const SkRect& query, - std::vector& results) const { + std::list& results) const { if (!SkRect::Intersects(fRoot.fBounds, query)) { return; } @@ -203,29 +205,27 @@ void PlatformViewRTree::searchRects(Node* node, bool replacedExistingRect = false; // // If the current record rect intersects with any of the rects in the // // result vector, then join them, and update the rect in results. - size_t joiningRectIdx = results.size(); - size_t resultIdx = 0; - while (resultIdx < results.size()) { - if (SkRect::Intersects(results[resultIdx], currentRecordRect)) { - joiningRectIdx = resultIdx; + std::list::iterator firstIntersectingRectItr = results.begin(); + while (firstIntersectingRectItr != results.end()) { + if (SkRect::Intersects(*firstIntersectingRectItr, currentRecordRect)) { replacedExistingRect = true; - results[joiningRectIdx].join(currentRecordRect); + firstIntersectingRectItr->join(currentRecordRect); break; } - resultIdx++; + firstIntersectingRectItr++; } - resultIdx = joiningRectIdx + 1; // It's possible that the result contains duplicated rects at this point. // For example, consider a result vector that contains rects A, B. If a // new rect C is a superset of A and B, then A and B are the same set after // the merge. As a result, find such cases and remove them from the result vector. - while (replacedExistingRect && resultIdx < results.size()) { - if (SkRect::Intersects(results[resultIdx], results[joiningRectIdx])) { - results[joiningRectIdx].join(results[resultIdx]); - results.erase(results.begin() + resultIdx); - } else { - resultIdx++; + std::list::iterator currRectItr = firstIntersectingRectItr; + currRectItr++; + while (replacedExistingRect && currRectItr != results.end()) { + if (SkRect::Intersects(*currRectItr, *firstIntersectingRectItr)) { + firstIntersectingRectItr->join(*currRectItr); + results.erase(currRectItr); } + currRectItr++; } if (!replacedExistingRect) { results.push_back(currentRecordRect); diff --git a/third_party/skia/platform_view_rtree.h b/third_party/skia/platform_view_rtree.h index 97069c6d0388c..cceb5334e4d60 100644 --- a/third_party/skia/platform_view_rtree.h +++ b/third_party/skia/platform_view_rtree.h @@ -8,6 +8,8 @@ #ifndef SKIA_PLATFORM_VIEW_RTREE_H_ #define SKIA_PLATFORM_VIEW_RTREE_H_ +#include + #include "third_party/skia/include/core/SkBBHFactory.h" #include "third_party/skia/include/core/SkTypes.h" @@ -54,7 +56,7 @@ class PlatformViewRTree : public SkBBoxHierarchy { // on how they relate to each other when compositing the final scene in Flutter. // For example, they may include matrix changes, clips or rects that are stacked // on top of each other. - std::vector searchRects(const SkRect& query) const; + std::list searchRects(const SkRect& query) const; size_t bytesUsed() const override; @@ -77,6 +79,7 @@ class PlatformViewRTree : public SkBBoxHierarchy { Node* fSubtree; int fOpIndex; }; + // True if the current bounds represent a drawing operation. bool isDraw; SkRect fBounds; }; @@ -88,7 +91,7 @@ class PlatformViewRTree : public SkBBoxHierarchy { }; void search(Node* root, const SkRect& query, std::vector* results) const; - void searchRects(Node* root, const SkRect& query, std::vector& results) const; + void searchRects(Node* root, const SkRect& query, std::list& results) const; // Consumes the input array. Branch bulkLoad(std::vector* branches, int level = 0); diff --git a/third_party/skia/platform_view_rtree_unittests.cc b/third_party/skia/platform_view_rtree_unittests.cc index 232236175489b..a32ad2f5e5f7d 100644 --- a/third_party/skia/platform_view_rtree_unittests.cc +++ b/third_party/skia/platform_view_rtree_unittests.cc @@ -50,7 +50,7 @@ TEST(PlatformViewRTree, SingleRectIntersection) { auto hits = r_tree->searchRects(SkRect::MakeLTRB(140, 140, 150, 150)); ASSERT_EQ(1UL, hits.size()); - ASSERT_EQ(hits[0], SkRect::MakeLTRB(120, 120, 160, 160)); + ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(120, 120, 160, 160)); } TEST(PlatformViewRTree, IgnoresNonDrawingRecords) { @@ -76,7 +76,7 @@ TEST(PlatformViewRTree, IgnoresNonDrawingRecords) { auto hits = r_tree->searchRects(SkRect::MakeLTRB(0, 0, 1000, 1000)); ASSERT_EQ(1UL, hits.size()); - ASSERT_EQ(hits[0], SkRect::MakeLTRB(120, 120, 180, 180)); + ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(120, 120, 180, 180)); } TEST(PlatformViewRTree, MultipleRectIntersection) { @@ -105,8 +105,8 @@ TEST(PlatformViewRTree, MultipleRectIntersection) { auto hits = r_tree->searchRects(SkRect::MakeLTRB(0, 0, 1000, 1050)); ASSERT_EQ(2UL, hits.size()); - ASSERT_EQ(hits[0], SkRect::MakeLTRB(100, 100, 200, 200)); - ASSERT_EQ(hits[1], SkRect::MakeLTRB(300, 100, 400, 200)); + ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(100, 100, 200, 200)); + ASSERT_EQ(*std::next(hits.begin(), 1), SkRect::MakeLTRB(300, 100, 400, 200)); } TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase1) { @@ -139,7 +139,7 @@ TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase1) { auto hits = r_tree->searchRects(SkRect::MakeXYWH(120, 120, 126, 126)); ASSERT_EQ(1UL, hits.size()); - ASSERT_EQ(hits[0], SkRect::MakeLTRB(100, 100, 175, 175)); + ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(100, 100, 175, 175)); } TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase2) { @@ -179,7 +179,7 @@ TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase2) { auto hits = r_tree->searchRects(SkRect::MakeLTRB(30, 30, 550, 270)); ASSERT_EQ(1UL, hits.size()); - ASSERT_EQ(hits[0], SkRect::MakeLTRB(50, 50, 500, 250)); + ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(50, 50, 500, 250)); } TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase3) { @@ -222,7 +222,7 @@ TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase3) { auto hits = r_tree->searchRects(SkRect::MakeLTRB(30, 30, 550, 270)); ASSERT_EQ(1UL, hits.size()); - ASSERT_EQ(hits[0], SkRect::MakeLTRB(50, 50, 620, 300)); + ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(50, 50, 620, 300)); } } // namespace testing From e28d37146f412b82340d1769179136ae11e41a41 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 5 Mar 2020 16:15:47 -0800 Subject: [PATCH 11/23] Remove unneccessary import --- third_party/skia/main_unittests.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/third_party/skia/main_unittests.cc b/third_party/skia/main_unittests.cc index d42e66aaaa80f..f4e7489c73560 100644 --- a/third_party/skia/main_unittests.cc +++ b/third_party/skia/main_unittests.cc @@ -7,8 +7,6 @@ #include "flutter/testing/testing.h" -#include - int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From 4cb64cf84358f8e75bdc8cd5d3eff9479d8111bb Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 5 Mar 2020 16:17:43 -0800 Subject: [PATCH 12/23] vector -> list --- third_party/skia/platform_view_rtree.cc | 6 +++--- third_party/skia/platform_view_rtree.h | 4 ++-- third_party/skia/platform_view_rtree_unittests.cc | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/third_party/skia/platform_view_rtree.cc b/third_party/skia/platform_view_rtree.cc index 299e12f7cd2ba..a3c35f5f00faf 100644 --- a/third_party/skia/platform_view_rtree.cc +++ b/third_party/skia/platform_view_rtree.cc @@ -204,7 +204,7 @@ void PlatformViewRTree::searchRects(Node* node, SkRect currentRecordRect = node->fChildren[i].fBounds; bool replacedExistingRect = false; // // If the current record rect intersects with any of the rects in the - // // result vector, then join them, and update the rect in results. + // // result list, then join them, and update the rect in results. std::list::iterator firstIntersectingRectItr = results.begin(); while (firstIntersectingRectItr != results.end()) { if (SkRect::Intersects(*firstIntersectingRectItr, currentRecordRect)) { @@ -215,9 +215,9 @@ void PlatformViewRTree::searchRects(Node* node, firstIntersectingRectItr++; } // It's possible that the result contains duplicated rects at this point. - // For example, consider a result vector that contains rects A, B. If a + // For example, consider a result list that contains rects A, B. If a // new rect C is a superset of A and B, then A and B are the same set after - // the merge. As a result, find such cases and remove them from the result vector. + // the merge. As a result, find such cases and remove them from the result list. std::list::iterator currRectItr = firstIntersectingRectItr; currRectItr++; while (replacedExistingRect && currRectItr != results.end()) { diff --git a/third_party/skia/platform_view_rtree.h b/third_party/skia/platform_view_rtree.h index cceb5334e4d60..d9e95f296d634 100644 --- a/third_party/skia/platform_view_rtree.h +++ b/third_party/skia/platform_view_rtree.h @@ -47,10 +47,10 @@ class PlatformViewRTree : public SkBBoxHierarchy { // // When two rects intersect with each other, they are joined into a single rect // which also intersects with the query rect. In other words, the bounds of each - // rect in the result vector are mutually exclusive. + // rect in the result list are mutually exclusive. // // Since this method is used when compositing platform views, the rects in the - // result vector represent UIViews that are composed on top of the platform view. + // result list represent UIViews that are composed on top of the platform view. // // However, Skia uses this tree to tracks operations that don't have any context // on how they relate to each other when compositing the final scene in Flutter. diff --git a/third_party/skia/platform_view_rtree_unittests.cc b/third_party/skia/platform_view_rtree_unittests.cc index a32ad2f5e5f7d..55e5ec946c19e 100644 --- a/third_party/skia/platform_view_rtree_unittests.cc +++ b/third_party/skia/platform_view_rtree_unittests.cc @@ -24,7 +24,7 @@ TEST(PlatformViewRTree, NoIntersection) { rect_paint.setColor(SkColors::kCyan); rect_paint.setStyle(SkPaint::Style::kFill_Style); - // If no rect is intersected with the query rect, then the result vector is empty. + // If no rect is intersected with the query rect, then the result list is empty. recording_canvas->drawRect(SkRect::MakeLTRB(20, 20, 40, 40), rect_paint); recorder->finishRecordingAsPicture(); @@ -43,7 +43,7 @@ TEST(PlatformViewRTree, SingleRectIntersection) { rect_paint.setStyle(SkPaint::Style::kFill_Style); // Given a single rect A that intersects with the query rect, - // the result vector contains this rect. + // the result list contains this rect. recording_canvas->drawRect(SkRect::MakeLTRB(120, 120, 160, 160), rect_paint); recorder->finishRecordingAsPicture(); @@ -65,7 +65,7 @@ TEST(PlatformViewRTree, IgnoresNonDrawingRecords) { // Creates two non drawing records. recording_canvas->translate(100, 100); - // The result vector should only contain the clipping rect. + // The result list should only contain the clipping rect. recording_canvas->clipRect(SkRect::MakeLTRB(40, 40, 50, 50), SkClipOp::kIntersect); recording_canvas->drawRect(SkRect::MakeLTRB(20, 20, 80, 80), rect_paint); @@ -90,7 +90,7 @@ TEST(PlatformViewRTree, MultipleRectIntersection) { rect_paint.setStyle(SkPaint::Style::kFill_Style); // Given the A, B that intersect with the query rect, - // there should be A and B in the result vector since + // there should be A and B in the result list since // they don't intersect with each other. // // +-----+ +-----+ @@ -120,7 +120,7 @@ TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase1) { rect_paint.setStyle(SkPaint::Style::kFill_Style); // Given the A, and B rects, which intersect with the query rect, - // the result vector contains the rect resulting from the union of A and B. + // the result list contains the rect resulting from the union of A and B. // // +-----+ // | A | @@ -153,7 +153,7 @@ TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase2) { rect_paint.setStyle(SkPaint::Style::kFill_Style); // Given the A, B, and C rects that intersect with the query rect, - // there should be only C in the result vector, + // there should be only C in the result list, // since A and B are contained in C. // // +---------------------+ @@ -193,7 +193,7 @@ TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase3) { rect_paint.setStyle(SkPaint::Style::kFill_Style); // Given the A, B, C and D rects that intersect with the query rect, - // the result vector contains a single rect, which is the union of + // the result list contains a single rect, which is the union of // these four rects. // // +------------------------------+ From 93c053d4534d215dab208c29f62dd36100a28a3b Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 5 Mar 2020 18:41:07 -0800 Subject: [PATCH 13/23] Don't increase iterator if it's the end of it --- third_party/skia/platform_view_rtree.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/third_party/skia/platform_view_rtree.cc b/third_party/skia/platform_view_rtree.cc index a3c35f5f00faf..b44a0edbbc222 100644 --- a/third_party/skia/platform_view_rtree.cc +++ b/third_party/skia/platform_view_rtree.cc @@ -219,7 +219,9 @@ void PlatformViewRTree::searchRects(Node* node, // new rect C is a superset of A and B, then A and B are the same set after // the merge. As a result, find such cases and remove them from the result list. std::list::iterator currRectItr = firstIntersectingRectItr; - currRectItr++; + if (currRectItr != results.end()) { + currRectItr++; + } while (replacedExistingRect && currRectItr != results.end()) { if (SkRect::Intersects(*currRectItr, *firstIntersectingRectItr)) { firstIntersectingRectItr->join(*currRectItr); From 878084240b2eee9ae84381983637c2dd31367bc4 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 5 Mar 2020 19:19:39 -0800 Subject: [PATCH 14/23] Update licenses --- ci/licenses_golden/licenses_flutter | 75 ++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index d0182f4580ab0..f884c354bb2d4 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1,6 +1,39 @@ UNUSED LICENSES: +==================================================================================================== +ORIGIN: ../../../flutter/third_party/skia/LICENSE +TYPE: LicenseType.bsd +---------------------------------------------------------------------------------------------------- +Copyright (c) 2011 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +==================================================================================================== ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USED LICENSES: @@ -1582,4 +1615,44 @@ 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. ==================================================================================================== -Total license count: 2 + +==================================================================================================== +LIBRARY: skia +ORIGIN: ../../../flutter/third_party/skia/main_unittests.cc + ../../../flutter/third_party/skia/LICENSE +TYPE: LicenseType.bsd +FILE: ../../../flutter/third_party/skia/main_unittests.cc +FILE: ../../../flutter/third_party/skia/platform_view_rtree.cc +FILE: ../../../flutter/third_party/skia/platform_view_rtree.h +FILE: ../../../flutter/third_party/skia/platform_view_rtree_unittests.cc +---------------------------------------------------------------------------------------------------- +Copyright 2012 Google Inc. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +==================================================================================================== +Total license count: 4 From 3fd5562c1369bba56db30c17f6eeca20a3b0fcc9 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 5 Mar 2020 19:39:36 -0800 Subject: [PATCH 15/23] Format --- third_party/skia/platform_view_rtree.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/skia/platform_view_rtree.cc b/third_party/skia/platform_view_rtree.cc index b44a0edbbc222..1f6d164608daf 100644 --- a/third_party/skia/platform_view_rtree.cc +++ b/third_party/skia/platform_view_rtree.cc @@ -220,7 +220,7 @@ void PlatformViewRTree::searchRects(Node* node, // the merge. As a result, find such cases and remove them from the result list. std::list::iterator currRectItr = firstIntersectingRectItr; if (currRectItr != results.end()) { - currRectItr++; + currRectItr++; } while (replacedExistingRect && currRectItr != results.end()) { if (SkRect::Intersects(*currRectItr, *firstIntersectingRectItr)) { From eea45d493a663efae5a0a1daf74896a96473e9d6 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 5 Mar 2020 22:01:18 -0800 Subject: [PATCH 16/23] Updated expected license count --- ci/licenses.sh | 4 +++- ci/licenses_golden/licenses_flutter | 2 +- third_party/skia/BUILD.gn | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ci/licenses.sh b/ci/licenses.sh index 58b06ea8a179e..d9b0d561f8447 100755 --- a/ci/licenses.sh +++ b/ci/licenses.sh @@ -55,7 +55,7 @@ fi echo "Checking license count in licenses_flutter..." actualLicenseCount=`tail -n 1 flutter/ci/licenses_golden/licenses_flutter | tr -dc '0-9'` -expectedLicenseCount=2 # When changing this number: Update the error message below as well describing all expected license types. +expectedLicenseCount=3 # When changing this number: Update the error message below as well describing all expected license types. if [ "$actualLicenseCount" -ne "$expectedLicenseCount" ] then @@ -67,6 +67,8 @@ then echo "header with the following copyright:" echo " Copyright 2013 The Flutter Authors. All rights reserved." echo "Files in 'third_party/txt' may have an Apache license header instead." + echo "Files in 'third_party/skia' may have the following copyright:" + echo " Copyright 2012 Google Inc." echo "If you're absolutely sure that the change in license count is" echo "intentional, update 'flutter/ci/licenses.sh' with the new count." echo "=================================================================" diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index f884c354bb2d4..967003fb55b54 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1655,4 +1655,4 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== -Total license count: 4 +Total license count: 3 diff --git a/third_party/skia/BUILD.gn b/third_party/skia/BUILD.gn index ba72aa9f9e12b..4c37ff6773264 100644 --- a/third_party/skia/BUILD.gn +++ b/third_party/skia/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright 2016 Google Inc. +# Copyright 2012 Google Inc. # # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. From 56e7f27d703d991e157da5d69d62099e98600098 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 5 Mar 2020 22:23:46 -0800 Subject: [PATCH 17/23] Fix cannot increment value-initialized list iterator on Windows --- third_party/skia/platform_view_rtree.cc | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/third_party/skia/platform_view_rtree.cc b/third_party/skia/platform_view_rtree.cc index 1f6d164608daf..fcf5916e4c042 100644 --- a/third_party/skia/platform_view_rtree.cc +++ b/third_party/skia/platform_view_rtree.cc @@ -205,23 +205,20 @@ void PlatformViewRTree::searchRects(Node* node, bool replacedExistingRect = false; // // If the current record rect intersects with any of the rects in the // // result list, then join them, and update the rect in results. - std::list::iterator firstIntersectingRectItr = results.begin(); - while (firstIntersectingRectItr != results.end()) { - if (SkRect::Intersects(*firstIntersectingRectItr, currentRecordRect)) { + std::list::iterator currRectItr = results.begin(); + std::list::iterator firstIntersectingRectItr; + while (!replacedExistingRect && currRectItr != results.end()) { + if (SkRect::Intersects(*currRectItr, currentRecordRect)) { replacedExistingRect = true; - firstIntersectingRectItr->join(currentRecordRect); - break; + firstIntersectingRectItr = currRectItr; + currRectItr->join(currentRecordRect); } - firstIntersectingRectItr++; + currRectItr++; } // It's possible that the result contains duplicated rects at this point. // For example, consider a result list that contains rects A, B. If a // new rect C is a superset of A and B, then A and B are the same set after // the merge. As a result, find such cases and remove them from the result list. - std::list::iterator currRectItr = firstIntersectingRectItr; - if (currRectItr != results.end()) { - currRectItr++; - } while (replacedExistingRect && currRectItr != results.end()) { if (SkRect::Intersects(*currRectItr, *firstIntersectingRectItr)) { firstIntersectingRectItr->join(*currRectItr); From c0f58d876de8066c52ad921c5fff24c647f0e5c7 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Fri, 6 Mar 2020 10:47:33 -0800 Subject: [PATCH 18/23] Feedback --- ci/licenses.sh | 2 +- ci/licenses_golden/licenses_flutter | 8 +- third_party/skia/BUILD.gn | 6 +- .../skia/{platform_view_rtree.cc => rtree.cc} | 45 +++--- .../skia/{platform_view_rtree.h => rtree.h} | 32 ++-- ..._rtree_unittests.cc => rtree_unittests.cc} | 143 ++++++++++++++---- 6 files changed, 156 insertions(+), 80 deletions(-) rename third_party/skia/{platform_view_rtree.cc => rtree.cc} (82%) rename third_party/skia/{platform_view_rtree.h => rtree.h} (77%) rename third_party/skia/{platform_view_rtree_unittests.cc => rtree_unittests.cc} (61%) diff --git a/ci/licenses.sh b/ci/licenses.sh index d9b0d561f8447..c62e424415c57 100755 --- a/ci/licenses.sh +++ b/ci/licenses.sh @@ -55,7 +55,7 @@ fi echo "Checking license count in licenses_flutter..." actualLicenseCount=`tail -n 1 flutter/ci/licenses_golden/licenses_flutter | tr -dc '0-9'` -expectedLicenseCount=3 # When changing this number: Update the error message below as well describing all expected license types. +expectedLicenseCount=4 # When changing this number: Update the error message below as well describing all expected license types. if [ "$actualLicenseCount" -ne "$expectedLicenseCount" ] then diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 967003fb55b54..ce79daa9a1b1e 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1621,9 +1621,9 @@ LIBRARY: skia ORIGIN: ../../../flutter/third_party/skia/main_unittests.cc + ../../../flutter/third_party/skia/LICENSE TYPE: LicenseType.bsd FILE: ../../../flutter/third_party/skia/main_unittests.cc -FILE: ../../../flutter/third_party/skia/platform_view_rtree.cc -FILE: ../../../flutter/third_party/skia/platform_view_rtree.h -FILE: ../../../flutter/third_party/skia/platform_view_rtree_unittests.cc +FILE: ../../../flutter/third_party/skia/rtree.cc +FILE: ../../../flutter/third_party/skia/rtree.h +FILE: ../../../flutter/third_party/skia/rtree_unittests.cc ---------------------------------------------------------------------------------------------------- Copyright 2012 Google Inc. @@ -1655,4 +1655,4 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== -Total license count: 3 +Total license count: 4 diff --git a/third_party/skia/BUILD.gn b/third_party/skia/BUILD.gn index 4c37ff6773264..5a0fe83ee7b34 100644 --- a/third_party/skia/BUILD.gn +++ b/third_party/skia/BUILD.gn @@ -7,8 +7,8 @@ import("//flutter/testing/testing.gni") source_set("skia") { sources = [ - "platform_view_rtree.cc", - "platform_view_rtree.h", + "rtree.cc", + "rtree.h", ] deps = [ @@ -24,7 +24,7 @@ executable("skia_unittests") { testonly = true sources = [ "main_unittests.cc", - "platform_view_rtree_unittests.cc", + "rtree_unittests.cc", ] deps = [ ":skia", diff --git a/third_party/skia/platform_view_rtree.cc b/third_party/skia/rtree.cc similarity index 82% rename from third_party/skia/platform_view_rtree.cc rename to third_party/skia/rtree.cc index fcf5916e4c042..420c74b9eb7fa 100644 --- a/third_party/skia/platform_view_rtree.cc +++ b/third_party/skia/rtree.cc @@ -7,13 +7,11 @@ #include -#include "platform_view_rtree.h" +#include "rtree.h" -PlatformViewRTree::PlatformViewRTree() : fCount(0) {} +RTree::RTree() : fCount(0) {} -void PlatformViewRTree::insert(const SkRect boundsArray[], - const SkBBoxHierarchy::Metadata metadata[], - int N) { +void RTree::insert(const SkRect boundsArray[], const SkBBoxHierarchy::Metadata metadata[], int N) { SkASSERT(0 == fCount); std::vector branches; @@ -47,11 +45,9 @@ void PlatformViewRTree::insert(const SkRect boundsArray[], } } -void PlatformViewRTree::insert(const SkRect boundsArray[], int N) { - insert(boundsArray, nullptr, N); -} +void RTree::insert(const SkRect boundsArray[], int N) { insert(boundsArray, nullptr, N); } -PlatformViewRTree::Node* PlatformViewRTree::allocateNodeAtLevel(uint16_t level) { +RTree::Node* RTree::allocateNodeAtLevel(uint16_t level) { SkDEBUGCODE(Node* p = fNodes.data()); fNodes.push_back(Node{}); Node& out = fNodes.back(); @@ -63,7 +59,7 @@ PlatformViewRTree::Node* PlatformViewRTree::allocateNodeAtLevel(uint16_t level) // This function parallels bulkLoad, but just counts how many nodes bulkLoad // would allocate. -int PlatformViewRTree::CountNodes(int branches) { +int RTree::CountNodes(int branches) { if (branches == 1) { return 1; } @@ -99,7 +95,7 @@ int PlatformViewRTree::CountNodes(int branches) { return nodes + CountNodes(nodes); } -PlatformViewRTree::Branch PlatformViewRTree::bulkLoad(std::vector* branches, int level) { +RTree::Branch RTree::bulkLoad(std::vector* branches, int level) { if (branches->size() == 1) { // Only one branch. It will be the root. return (*branches)[0]; } @@ -155,13 +151,13 @@ PlatformViewRTree::Branch PlatformViewRTree::bulkLoad(std::vector* branc return this->bulkLoad(branches, level + 1); } -void PlatformViewRTree::search(const SkRect& query, std::vector* results) const { +void RTree::search(const SkRect& query, std::vector* results) const { if (fCount > 0 && SkRect::Intersects(fRoot.fBounds, query)) { this->search(fRoot.fSubtree, query, results); } } -void PlatformViewRTree::search(Node* node, const SkRect& query, std::vector* results) const { +void RTree::search(Node* node, const SkRect& query, std::vector* results) const { for (int i = 0; i < node->fNumChildren; ++i) { if (!SkRect::Intersects(node->fChildren[i].fBounds, query)) { continue; @@ -174,17 +170,17 @@ void PlatformViewRTree::search(Node* node, const SkRect& query, std::vector } } -std::list PlatformViewRTree::searchRects(const SkRect& query) const { +std::list RTree::searchNonOverlappingDrawnRects(const SkRect& query) const { std::list results; if (fCount > 0 && SkRect::Intersects(fRoot.fBounds, query)) { - this->searchRects(fRoot.fSubtree, query, results); + this->searchNonOverlappingDrawnRects(fRoot.fSubtree, query, results); } return results; } -void PlatformViewRTree::searchRects(Node* node, - const SkRect& query, - std::list& results) const { +void RTree::searchNonOverlappingDrawnRects(Node* node, + const SkRect& query, + std::list& results) const { if (!SkRect::Intersects(fRoot.fBounds, query)) { return; } @@ -194,7 +190,7 @@ void PlatformViewRTree::searchRects(Node* node, } // Non-leaf node if (0 != node->fLevel) { - this->searchRects(node->fChildren[i].fSubtree, query, results); + this->searchNonOverlappingDrawnRects(node->fChildren[i].fSubtree, query, results); continue; } // Ignore records that don't draw anything. @@ -232,13 +228,14 @@ void PlatformViewRTree::searchRects(Node* node, } } -size_t PlatformViewRTree::bytesUsed() const { - size_t byteCount = sizeof(PlatformViewRTree); +size_t RTree::bytesUsed() const { + size_t byteCount = sizeof(RTree); byteCount += fNodes.capacity() * sizeof(Node); return byteCount; } -PlatformViewRTreeFactory::PlatformViewRTreeFactory(sk_sp& r_tree) - : r_tree_(r_tree) {} +RTreeFactory::RTreeFactory() { r_tree_ = sk_make_sp(); } + +sk_sp RTreeFactory::getInstance() { return r_tree_; } -sk_sp PlatformViewRTreeFactory::operator()() const { return r_tree_; } +sk_sp RTreeFactory::operator()() const { return r_tree_; } diff --git a/third_party/skia/platform_view_rtree.h b/third_party/skia/rtree.h similarity index 77% rename from third_party/skia/platform_view_rtree.h rename to third_party/skia/rtree.h index d9e95f296d634..827f91bb25199 100644 --- a/third_party/skia/platform_view_rtree.h +++ b/third_party/skia/rtree.h @@ -5,8 +5,8 @@ * found in the LICENSE file. */ -#ifndef SKIA_PLATFORM_VIEW_RTREE_H_ -#define SKIA_PLATFORM_VIEW_RTREE_H_ +#ifndef SKIA_RTREE_H_ +#define SKIA_RTREE_H_ #include @@ -34,9 +34,9 @@ * * This copy includes a searchRects method. */ -class PlatformViewRTree : public SkBBoxHierarchy { +class RTree : public SkBBoxHierarchy { public: - PlatformViewRTree(); + RTree(); void insert(const SkRect[], const SkBBoxHierarchy::Metadata[], int N) override; void insert(const SkRect[], int N) override; @@ -48,15 +48,7 @@ class PlatformViewRTree : public SkBBoxHierarchy { // When two rects intersect with each other, they are joined into a single rect // which also intersects with the query rect. In other words, the bounds of each // rect in the result list are mutually exclusive. - // - // Since this method is used when compositing platform views, the rects in the - // result list represent UIViews that are composed on top of the platform view. - // - // However, Skia uses this tree to tracks operations that don't have any context - // on how they relate to each other when compositing the final scene in Flutter. - // For example, they may include matrix changes, clips or rects that are stacked - // on top of each other. - std::list searchRects(const SkRect& query) const; + std::list searchNonOverlappingDrawnRects(const SkRect& query) const; size_t bytesUsed() const override; @@ -91,7 +83,8 @@ class PlatformViewRTree : public SkBBoxHierarchy { }; void search(Node* root, const SkRect& query, std::vector* results) const; - void searchRects(Node* root, const SkRect& query, std::list& results) const; + void searchNonOverlappingDrawnRects(Node* root, const SkRect& query, + std::list& results) const; // Consumes the input array. Branch bulkLoad(std::vector* branches, int level = 0); @@ -107,13 +100,16 @@ class PlatformViewRTree : public SkBBoxHierarchy { std::vector fNodes; }; -class PlatformViewRTreeFactory : public SkBBHFactory { +class RTreeFactory : public SkBBHFactory { public: - PlatformViewRTreeFactory(sk_sp& r_tree); + RTreeFactory(); + + // Gets the instance to the R-tree. + sk_sp getInstance(); sk_sp operator()() const override; private: - sk_sp r_tree_; + sk_sp r_tree_; }; -#endif // SKIA_PLATFORM_VIEW_RTREE_H_ +#endif // SKIA_RTREE_H_ diff --git a/third_party/skia/platform_view_rtree_unittests.cc b/third_party/skia/rtree_unittests.cc similarity index 61% rename from third_party/skia/platform_view_rtree_unittests.cc rename to third_party/skia/rtree_unittests.cc index 55e5ec946c19e..72eb15eec73c0 100644 --- a/third_party/skia/platform_view_rtree_unittests.cc +++ b/third_party/skia/rtree_unittests.cc @@ -6,17 +6,17 @@ */ #include "flutter/testing/testing.h" -#include "platform_view_rtree.h" +#include "rtree.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPictureRecorder.h" +#include "third_party/skia/include/utils/SkRandom.h" namespace flutter { namespace testing { -TEST(PlatformViewRTree, NoIntersection) { - auto r_tree = sk_make_sp(); - auto rtree_factory = PlatformViewRTreeFactory(r_tree); +TEST(RTree, searchNonOverlappingDrawnRects_NoIntersection) { + auto rtree_factory = RTreeFactory(); auto recorder = std::make_unique(); auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); @@ -28,13 +28,13 @@ TEST(PlatformViewRTree, NoIntersection) { recording_canvas->drawRect(SkRect::MakeLTRB(20, 20, 40, 40), rect_paint); recorder->finishRecordingAsPicture(); - auto hits = r_tree->searchRects(SkRect::MakeLTRB(40, 40, 80, 80)); + auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( + SkRect::MakeLTRB(40, 40, 80, 80)); ASSERT_TRUE(hits.empty()); } -TEST(PlatformViewRTree, SingleRectIntersection) { - auto r_tree = sk_make_sp(); - auto rtree_factory = PlatformViewRTreeFactory(r_tree); +TEST(RTree, searchNonOverlappingDrawnRects_SingleRectIntersection) { + auto rtree_factory = RTreeFactory(); auto recorder = std::make_unique(); auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); @@ -48,14 +48,14 @@ TEST(PlatformViewRTree, SingleRectIntersection) { recorder->finishRecordingAsPicture(); - auto hits = r_tree->searchRects(SkRect::MakeLTRB(140, 140, 150, 150)); + auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( + SkRect::MakeLTRB(140, 140, 150, 150)); ASSERT_EQ(1UL, hits.size()); ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(120, 120, 160, 160)); } -TEST(PlatformViewRTree, IgnoresNonDrawingRecords) { - auto r_tree = sk_make_sp(); - auto rtree_factory = PlatformViewRTreeFactory(r_tree); +TEST(RTree, searchNonOverlappingDrawnRects_IgnoresNonDrawingRecords) { + auto rtree_factory = RTreeFactory(); auto recorder = std::make_unique(); auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); @@ -72,16 +72,16 @@ TEST(PlatformViewRTree, IgnoresNonDrawingRecords) { recorder->finishRecordingAsPicture(); // The rtree has a translate, a clip and a rect record. - ASSERT_EQ(3, r_tree->getCount()); + ASSERT_EQ(3, rtree_factory.getInstance()->getCount()); - auto hits = r_tree->searchRects(SkRect::MakeLTRB(0, 0, 1000, 1000)); + auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( + SkRect::MakeLTRB(0, 0, 1000, 1000)); ASSERT_EQ(1UL, hits.size()); ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(120, 120, 180, 180)); } -TEST(PlatformViewRTree, MultipleRectIntersection) { - auto r_tree = sk_make_sp(); - auto rtree_factory = PlatformViewRTreeFactory(r_tree); +TEST(RTree, searchNonOverlappingDrawnRects_MultipleRectIntersection) { + auto rtree_factory = RTreeFactory(); auto recorder = std::make_unique(); auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); @@ -103,15 +103,15 @@ TEST(PlatformViewRTree, MultipleRectIntersection) { recorder->finishRecordingAsPicture(); - auto hits = r_tree->searchRects(SkRect::MakeLTRB(0, 0, 1000, 1050)); + auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( + SkRect::MakeLTRB(0, 0, 1000, 1050)); ASSERT_EQ(2UL, hits.size()); ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(100, 100, 200, 200)); ASSERT_EQ(*std::next(hits.begin(), 1), SkRect::MakeLTRB(300, 100, 400, 200)); } -TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase1) { - auto r_tree = sk_make_sp(); - auto rtree_factory = PlatformViewRTreeFactory(r_tree); +TEST(RTree, searchNonOverlappingDrawnRects_JoinRectsWhenIntersectedCase1) { + auto rtree_factory = RTreeFactory(); auto recorder = std::make_unique(); auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); @@ -137,14 +137,14 @@ TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase1) { recorder->finishRecordingAsPicture(); - auto hits = r_tree->searchRects(SkRect::MakeXYWH(120, 120, 126, 126)); + auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( + SkRect::MakeXYWH(120, 120, 126, 126)); ASSERT_EQ(1UL, hits.size()); ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(100, 100, 175, 175)); } -TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase2) { - auto r_tree = sk_make_sp(); - auto rtree_factory = PlatformViewRTreeFactory(r_tree); +TEST(RTree, searchNonOverlappingDrawnRects_JoinRectsWhenIntersectedCase2) { + auto rtree_factory = RTreeFactory(); auto recorder = std::make_unique(); auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); @@ -177,14 +177,14 @@ TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase2) { recorder->finishRecordingAsPicture(); - auto hits = r_tree->searchRects(SkRect::MakeLTRB(30, 30, 550, 270)); + auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( + SkRect::MakeLTRB(30, 30, 550, 270)); ASSERT_EQ(1UL, hits.size()); ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(50, 50, 500, 250)); } -TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase3) { - auto r_tree = sk_make_sp(); - auto rtree_factory = PlatformViewRTreeFactory(r_tree); +TEST(RTree, searchNonOverlappingDrawnRects_JoinRectsWhenIntersectedCase3) { + auto rtree_factory = RTreeFactory(); auto recorder = std::make_unique(); auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); @@ -220,10 +220,93 @@ TEST(PlatformViewRTree, JoinRectsWhenIntersectedCase3) { recorder->finishRecordingAsPicture(); - auto hits = r_tree->searchRects(SkRect::MakeLTRB(30, 30, 550, 270)); + auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( + SkRect::MakeLTRB(30, 30, 550, 270)); ASSERT_EQ(1UL, hits.size()); ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(50, 50, 620, 300)); } +// Existing Skia tests from +// https://github.com/google/skia/blob/508fd32091afe334d4e1dd6cdaa63168a53acb26/tests/RTreeTest.cpp + +static const int NUM_RECTS = 200; +static const size_t NUM_ITERATIONS = 100; +static const size_t NUM_QUERIES = 50; + +static SkRect random_rect(SkRandom& rand) { + SkRect rect = {0, 0, 0, 0}; + while (rect.isEmpty()) { + rect.fLeft = rand.nextRangeF(0, 1000); + rect.fRight = rand.nextRangeF(0, 1000); + rect.fTop = rand.nextRangeF(0, 1000); + rect.fBottom = rand.nextRangeF(0, 1000); + rect.sort(); + } + return rect; +} + +static bool verify_query(SkRect query, SkRect rects[], std::vector& found) { + std::vector expected; + // manually intersect with every rectangle + for (int i = 0; i < NUM_RECTS; ++i) { + if (SkRect::Intersects(query, rects[i])) { + expected.push_back(i); + } + } + + if (expected.size() != found.size()) { + return false; + } + if (0 == expected.size()) { + return true; + } + return found == expected; +} + +static void run_queries(SkRandom& rand, SkRect rects[], const RTree& tree) { + for (size_t i = 0; i < NUM_QUERIES; ++i) { + std::vector hits; + SkRect query = random_rect(rand); + tree.search(query, &hits); + ASSERT_TRUE(verify_query(query, rects, hits)); + } +} + +TEST(RTree, existingSkiaTest) { + int expectedDepthMin = -1; + int tmp = NUM_RECTS; + while (tmp > 0) { + tmp -= static_cast(pow(static_cast(RTree::kMaxChildren), + static_cast(expectedDepthMin + 1))); + ++expectedDepthMin; + } + + int expectedDepthMax = -1; + tmp = NUM_RECTS; + while (tmp > 0) { + tmp -= static_cast(pow(static_cast(RTree::kMinChildren), + static_cast(expectedDepthMax + 1))); + ++expectedDepthMax; + } + + SkRandom rand; + SkAutoTMalloc rects(NUM_RECTS); + for (size_t i = 0; i < NUM_ITERATIONS; ++i) { + RTree rtree; + ASSERT_EQ(0, rtree.getCount()); + + for (int j = 0; j < NUM_RECTS; j++) { + rects[j] = random_rect(rand); + } + + rtree.insert(rects.get(), NUM_RECTS); + SkASSERT(rects); // RTree doesn't take ownership of rects. + + run_queries(rand, rects, rtree); + ASSERT_EQ(NUM_RECTS, rtree.getCount()); + ASSERT_TRUE(expectedDepthMin <= rtree.getDepth() && expectedDepthMax >= rtree.getDepth()); + } +} + } // namespace testing } // namespace flutter From 464ab7ddc5400efe1864993abe76fee1befefe06 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Fri, 6 Mar 2020 11:26:35 -0800 Subject: [PATCH 19/23] Attempt to fix 'cannot increment value-initialized list iterator' --- third_party/skia/rtree.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/third_party/skia/rtree.cc b/third_party/skia/rtree.cc index 420c74b9eb7fa..a69fe83b1acb6 100644 --- a/third_party/skia/rtree.cc +++ b/third_party/skia/rtree.cc @@ -218,9 +218,10 @@ void RTree::searchNonOverlappingDrawnRects(Node* node, while (replacedExistingRect && currRectItr != results.end()) { if (SkRect::Intersects(*currRectItr, *firstIntersectingRectItr)) { firstIntersectingRectItr->join(*currRectItr); - results.erase(currRectItr); + currRectItr = results.erase(currRectItr); + } else { + currRectItr++; } - currRectItr++; } if (!replacedExistingRect) { results.push_back(currentRecordRect); From 3709ea634d9adcfa41b9d721ddde20a09ce13d39 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Mon, 9 Mar 2020 14:20:39 -0700 Subject: [PATCH 20/23] Add flutter namespace --- flow/rtree.h | 65 +++++++++++++++++++++++++++++++++++++++ third_party/skia/rtree.cc | 4 +++ third_party/skia/rtree.h | 3 ++ 3 files changed, 72 insertions(+) create mode 100644 flow/rtree.h diff --git a/flow/rtree.h b/flow/rtree.h new file mode 100644 index 0000000000000..35c74137243c8 --- /dev/null +++ b/flow/rtree.h @@ -0,0 +1,65 @@ +// Copyright 2013 The Flutter 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_FLOW_RTREE_H_ +#define FLUTTER_FLOW_RTREE_H_ + +#include +#include + +#include "third_party/skia/include/core/SkBBHFactory.h" +#include "third_party/skia/include/core/SkTypes.h" + +namespace flutter { +/** + * An R-Tree implementation that forwards calls to an SkRTree. + * + * This implementation provides a searchNonOverlappingDrawnRects method, + * which can be used to query the rects for the operations recorded in the tree. + */ +class RTree : public SkBBoxHierarchy { + public: + RTree(); + + void insert(const SkRect[], + const SkBBoxHierarchy::Metadata[], + int N) override; + void insert(const SkRect[], int N) override; + void search(const SkRect& query, std::vector* results) const override; + size_t bytesUsed() const override; + + // Finds the rects in the tree that represent drawing operations and intersect + // with the query rect. + // + // When two rects intersect with each other, they are joined into a single + // rect which also intersects with the query rect. In other words, the bounds + // of each rect in the result list are mutually exclusive. + std::list searchNonOverlappingDrawnRects(const SkRect& query) const; + + // Insertion count (not overall node count, which may be greater). + int getCount() const { return all_ops_count_; } + + private: + // A map containing the draw operation rects keyed off the operation index + // in the insert call. + std::map draw_op_; + sk_sp bbh_; + int all_ops_count_; +}; + +class RTreeFactory : public SkBBHFactory { + public: + RTreeFactory(); + + // Gets the instance to the R-tree. + sk_sp getInstance(); + sk_sp operator()() const override; + + private: + sk_sp r_tree_; +}; + +} // namespace flutter + +#endif // FLUTTER_FLOW_RTREE_H_ diff --git a/third_party/skia/rtree.cc b/third_party/skia/rtree.cc index a69fe83b1acb6..03211f539e69a 100644 --- a/third_party/skia/rtree.cc +++ b/third_party/skia/rtree.cc @@ -9,6 +9,8 @@ #include "rtree.h" +namespace flutter { + RTree::RTree() : fCount(0) {} void RTree::insert(const SkRect boundsArray[], const SkBBoxHierarchy::Metadata metadata[], int N) { @@ -240,3 +242,5 @@ RTreeFactory::RTreeFactory() { r_tree_ = sk_make_sp(); } sk_sp RTreeFactory::getInstance() { return r_tree_; } sk_sp RTreeFactory::operator()() const { return r_tree_; } + +} // namespace flutter diff --git a/third_party/skia/rtree.h b/third_party/skia/rtree.h index 827f91bb25199..610085163d007 100644 --- a/third_party/skia/rtree.h +++ b/third_party/skia/rtree.h @@ -13,6 +13,7 @@ #include "third_party/skia/include/core/SkBBHFactory.h" #include "third_party/skia/include/core/SkTypes.h" +namespace flutter { /** * An R-Tree implementation. In short, it is a balanced n-ary tree containing a hierarchy of * bounding rectangles. @@ -113,3 +114,5 @@ class RTreeFactory : public SkBBHFactory { }; #endif // SKIA_RTREE_H_ + +} // namespace flutter From c6563b5ecada3fc207c275dfd30055faf0962559 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Mon, 9 Mar 2020 14:20:47 -0700 Subject: [PATCH 21/23] Rename target --- BUILD.gn | 2 +- testing/run_tests.py | 2 +- third_party/skia/BUILD.gn | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/BUILD.gn b/BUILD.gn index f8298b22e731d..62b3cfe1f7b3d 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -79,7 +79,7 @@ group("flutter") { "//flutter/shell/platform/embedder:embedder_unittests", "//flutter/shell/platform/glfw/client_wrapper:client_wrapper_glfw_unittests", "//flutter/testing:testing_unittests", - "//flutter/third_party/skia:skia_unittests", + "//flutter/third_party/skia:rtree_unittests", "//flutter/third_party/txt:txt_unittests", ] diff --git a/testing/run_tests.py b/testing/run_tests.py index 9f1b71eab2216..3f8a334354592 100755 --- a/testing/run_tests.py +++ b/testing/run_tests.py @@ -147,7 +147,7 @@ def RunCCTests(build_dir, filter): if IsLinux(): RunEngineExecutable(build_dir, 'txt_unittests', filter, shuffle_flags) - RunEngineExecutable(build_dir, 'skia_unittests', filter, shuffle_flags) + RunEngineExecutable(build_dir, 'rtree_unittests', filter, shuffle_flags) def RunEngineBenchmarks(build_dir, filter): diff --git a/third_party/skia/BUILD.gn b/third_party/skia/BUILD.gn index 5a0fe83ee7b34..65bc4661988fd 100644 --- a/third_party/skia/BUILD.gn +++ b/third_party/skia/BUILD.gn @@ -5,7 +5,7 @@ import("//flutter/testing/testing.gni") -source_set("skia") { +source_set("rtree") { sources = [ "rtree.cc", "rtree.h", @@ -16,19 +16,19 @@ source_set("skia") { ] } -test_fixtures("skia_fixtures") { +test_fixtures("rtree_fixtures") { fixtures = [] } -executable("skia_unittests") { +executable("rtree_unittests") { testonly = true sources = [ "main_unittests.cc", "rtree_unittests.cc", ] deps = [ - ":skia", - ":skia_fixtures", + ":rtree", + ":rtree_fixtures", "//flutter/testing:testing_lib", "//third_party/dart/runtime:libdart_jit", # For logging. "//third_party/skia", From 331675709da9b2b527487ab38490e747be545712 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Mon, 9 Mar 2020 17:54:34 -0700 Subject: [PATCH 22/23] Don't duplicate SkRTree --- BUILD.gn | 1 - ci/licenses.sh | 4 +- ci/licenses_golden/licenses_flutter | 78 +------ flow/BUILD.gn | 3 + flow/rtree.cc | 100 +++++++++ flow/rtree_unittests.cc | 235 +++++++++++++++++++++ testing/run_tests.py | 2 - third_party/skia/.clang-format | 194 ----------------- third_party/skia/AUTHORS | 66 ------ third_party/skia/BUILD.gn | 36 ---- third_party/skia/LICENSE | 29 --- third_party/skia/main_unittests.cc | 13 -- third_party/skia/rtree.cc | 246 ---------------------- third_party/skia/rtree.h | 118 ----------- third_party/skia/rtree_unittests.cc | 312 ---------------------------- 15 files changed, 343 insertions(+), 1094 deletions(-) create mode 100644 flow/rtree.cc create mode 100644 flow/rtree_unittests.cc delete mode 100644 third_party/skia/.clang-format delete mode 100644 third_party/skia/AUTHORS delete mode 100644 third_party/skia/BUILD.gn delete mode 100644 third_party/skia/LICENSE delete mode 100644 third_party/skia/main_unittests.cc delete mode 100644 third_party/skia/rtree.cc delete mode 100644 third_party/skia/rtree.h delete mode 100644 third_party/skia/rtree_unittests.cc diff --git a/BUILD.gn b/BUILD.gn index 62b3cfe1f7b3d..25006866ca896 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -79,7 +79,6 @@ group("flutter") { "//flutter/shell/platform/embedder:embedder_unittests", "//flutter/shell/platform/glfw/client_wrapper:client_wrapper_glfw_unittests", "//flutter/testing:testing_unittests", - "//flutter/third_party/skia:rtree_unittests", "//flutter/third_party/txt:txt_unittests", ] diff --git a/ci/licenses.sh b/ci/licenses.sh index c62e424415c57..58b06ea8a179e 100755 --- a/ci/licenses.sh +++ b/ci/licenses.sh @@ -55,7 +55,7 @@ fi echo "Checking license count in licenses_flutter..." actualLicenseCount=`tail -n 1 flutter/ci/licenses_golden/licenses_flutter | tr -dc '0-9'` -expectedLicenseCount=4 # When changing this number: Update the error message below as well describing all expected license types. +expectedLicenseCount=2 # When changing this number: Update the error message below as well describing all expected license types. if [ "$actualLicenseCount" -ne "$expectedLicenseCount" ] then @@ -67,8 +67,6 @@ then echo "header with the following copyright:" echo " Copyright 2013 The Flutter Authors. All rights reserved." echo "Files in 'third_party/txt' may have an Apache license header instead." - echo "Files in 'third_party/skia' may have the following copyright:" - echo " Copyright 2012 Google Inc." echo "If you're absolutely sure that the change in license count is" echo "intentional, update 'flutter/ci/licenses.sh' with the new count." echo "=================================================================" diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index ce79daa9a1b1e..3d758d0a63861 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1,39 +1,6 @@ UNUSED LICENSES: -==================================================================================================== -ORIGIN: ../../../flutter/third_party/skia/LICENSE -TYPE: LicenseType.bsd ----------------------------------------------------------------------------------------------------- -Copyright (c) 2011 Google Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -==================================================================================================== ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USED LICENSES: @@ -125,6 +92,9 @@ FILE: ../../../flutter/flow/raster_cache.h FILE: ../../../flutter/flow/raster_cache_key.cc FILE: ../../../flutter/flow/raster_cache_key.h FILE: ../../../flutter/flow/raster_cache_unittests.cc +FILE: ../../../flutter/flow/rtree.cc +FILE: ../../../flutter/flow/rtree.h +FILE: ../../../flutter/flow/rtree_unittests.cc FILE: ../../../flutter/flow/scene_update_context.cc FILE: ../../../flutter/flow/scene_update_context.h FILE: ../../../flutter/flow/skia_gpu_object.cc @@ -1615,44 +1585,4 @@ 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. ==================================================================================================== - -==================================================================================================== -LIBRARY: skia -ORIGIN: ../../../flutter/third_party/skia/main_unittests.cc + ../../../flutter/third_party/skia/LICENSE -TYPE: LicenseType.bsd -FILE: ../../../flutter/third_party/skia/main_unittests.cc -FILE: ../../../flutter/third_party/skia/rtree.cc -FILE: ../../../flutter/third_party/skia/rtree.h -FILE: ../../../flutter/third_party/skia/rtree_unittests.cc ----------------------------------------------------------------------------------------------------- -Copyright 2012 Google Inc. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -==================================================================================================== -Total license count: 4 +Total license count: 2 diff --git a/flow/BUILD.gn b/flow/BUILD.gn index c194d35ea628d..cfe3b2eb253b9 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -58,6 +58,8 @@ source_set("flow") { "raster_cache.h", "raster_cache_key.cc", "raster_cache_key.h", + "rtree.h", + "rtree.cc", "skia_gpu_object.cc", "skia_gpu_object.h", "texture.cc", @@ -150,6 +152,7 @@ executable("flow_unittests") { "matrix_decomposition_unittests.cc", "mutators_stack_unittests.cc", "raster_cache_unittests.cc", + "rtree_unittests.cc", "skia_gpu_object_unittests.cc", "testing/mock_layer_unittests.cc", "testing/mock_texture_unittests.cc", diff --git a/flow/rtree.cc b/flow/rtree.cc new file mode 100644 index 0000000000000..a6df0d903c303 --- /dev/null +++ b/flow/rtree.cc @@ -0,0 +1,100 @@ +// Copyright 2013 The Flutter 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 "rtree.h" + +#include + +#include "flutter/fml/logging.h" +#include "third_party/skia/include/core/SkBBHFactory.h" + +namespace flutter { + +RTree::RTree() : bbh_{SkRTreeFactory{}()}, all_ops_count_(0) {} + +void RTree::insert(const SkRect boundsArray[], + const SkBBoxHierarchy::Metadata metadata[], + int N) { + FML_DCHECK(0 == all_ops_count_); + bbh_->insert(boundsArray, metadata, N); + for (int i = 0; i < N; i++) { + if (metadata != nullptr && metadata[i].isDraw) { + draw_op_[i] = boundsArray[i]; + } + } + all_ops_count_ = N; +} + +void RTree::insert(const SkRect boundsArray[], int N) { + insert(boundsArray, nullptr, N); +} + +void RTree::search(const SkRect& query, std::vector* results) const { + bbh_->search(query, results); +} + +std::list RTree::searchNonOverlappingDrawnRects( + const SkRect& query) const { + // Get the indexes for the operations that intersect with the query rect. + std::vector intermediary_results; + search(query, &intermediary_results); + + std::list final_results; + for (int index : intermediary_results) { + auto draw_op = draw_op_.find(index); + // Ignore records that don't draw anything. + if (draw_op == draw_op_.end()) { + continue; + } + auto current_record_rect = draw_op->second; + auto replaced_existing_rect = false; + // // If the current record rect intersects with any of the rects in the + // // result list, then join them, and update the rect in final_results. + std::list::iterator curr_rect_itr = final_results.begin(); + std::list::iterator first_intersecting_rect_itr; + while (!replaced_existing_rect && curr_rect_itr != final_results.end()) { + if (SkRect::Intersects(*curr_rect_itr, current_record_rect)) { + replaced_existing_rect = true; + first_intersecting_rect_itr = curr_rect_itr; + curr_rect_itr->join(current_record_rect); + } + curr_rect_itr++; + } + // It's possible that the result contains duplicated rects at this point. + // For example, consider a result list that contains rects A, B. If a + // new rect C is a superset of A and B, then A and B are the same set after + // the merge. As a result, find such cases and remove them from the result + // list. + while (replaced_existing_rect && curr_rect_itr != final_results.end()) { + if (SkRect::Intersects(*curr_rect_itr, *first_intersecting_rect_itr)) { + first_intersecting_rect_itr->join(*curr_rect_itr); + curr_rect_itr = final_results.erase(curr_rect_itr); + } else { + curr_rect_itr++; + } + } + if (!replaced_existing_rect) { + final_results.push_back(current_record_rect); + } + } + return final_results; +} + +size_t RTree::bytesUsed() const { + return bbh_->bytesUsed(); +} + +RTreeFactory::RTreeFactory() { + r_tree_ = sk_make_sp(); +} + +sk_sp RTreeFactory::getInstance() { + return r_tree_; +} + +sk_sp RTreeFactory::operator()() const { + return r_tree_; +} + +} // namespace flutter diff --git a/flow/rtree_unittests.cc b/flow/rtree_unittests.cc new file mode 100644 index 0000000000000..f3e82e00ebc4f --- /dev/null +++ b/flow/rtree_unittests.cc @@ -0,0 +1,235 @@ +// Copyright 2013 The Flutter 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 "rtree.h" + +#include "flutter/testing/testing.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkPictureRecorder.h" + +namespace flutter { +namespace testing { + +TEST(RTree, searchNonOverlappingDrawnRects_NoIntersection) { + auto rtree_factory = RTreeFactory(); + auto recorder = std::make_unique(); + auto recording_canvas = + recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); + + auto rect_paint = SkPaint(); + rect_paint.setColor(SkColors::kCyan); + rect_paint.setStyle(SkPaint::Style::kFill_Style); + + // If no rect is intersected with the query rect, then the result list is + // empty. + recording_canvas->drawRect(SkRect::MakeLTRB(20, 20, 40, 40), rect_paint); + recorder->finishRecordingAsPicture(); + + auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( + SkRect::MakeLTRB(40, 40, 80, 80)); + ASSERT_TRUE(hits.empty()); +} + +TEST(RTree, searchNonOverlappingDrawnRects_SingleRectIntersection) { + auto rtree_factory = RTreeFactory(); + auto recorder = std::make_unique(); + auto recording_canvas = + recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); + + auto rect_paint = SkPaint(); + rect_paint.setColor(SkColors::kCyan); + rect_paint.setStyle(SkPaint::Style::kFill_Style); + + // Given a single rect A that intersects with the query rect, + // the result list contains this rect. + recording_canvas->drawRect(SkRect::MakeLTRB(120, 120, 160, 160), rect_paint); + + recorder->finishRecordingAsPicture(); + + auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( + SkRect::MakeLTRB(140, 140, 150, 150)); + ASSERT_EQ(1UL, hits.size()); + ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(120, 120, 160, 160)); +} + +TEST(RTree, searchNonOverlappingDrawnRects_IgnoresNonDrawingRecords) { + auto rtree_factory = RTreeFactory(); + auto recorder = std::make_unique(); + auto recording_canvas = + recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); + + auto rect_paint = SkPaint(); + rect_paint.setColor(SkColors::kCyan); + rect_paint.setStyle(SkPaint::Style::kFill_Style); + + // Creates two non drawing records. + recording_canvas->translate(100, 100); + // The result list should only contain the clipping rect. + recording_canvas->clipRect(SkRect::MakeLTRB(40, 40, 50, 50), + SkClipOp::kIntersect); + recording_canvas->drawRect(SkRect::MakeLTRB(20, 20, 80, 80), rect_paint); + + recorder->finishRecordingAsPicture(); + + // The rtree has a translate, a clip and a rect record. + ASSERT_EQ(3, rtree_factory.getInstance()->getCount()); + + auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( + SkRect::MakeLTRB(0, 0, 1000, 1000)); + ASSERT_EQ(1UL, hits.size()); + ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(120, 120, 180, 180)); +} + +TEST(RTree, searchNonOverlappingDrawnRects_MultipleRectIntersection) { + auto rtree_factory = RTreeFactory(); + auto recorder = std::make_unique(); + auto recording_canvas = + recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); + + auto rect_paint = SkPaint(); + rect_paint.setColor(SkColors::kCyan); + rect_paint.setStyle(SkPaint::Style::kFill_Style); + + // Given the A, B that intersect with the query rect, + // there should be A and B in the result list since + // they don't intersect with each other. + // + // +-----+ +-----+ + // | A | | B | + // +-----+ +-----+ + // A + recording_canvas->drawRect(SkRect::MakeLTRB(100, 100, 200, 200), rect_paint); + // B + recording_canvas->drawRect(SkRect::MakeLTRB(300, 100, 400, 200), rect_paint); + + recorder->finishRecordingAsPicture(); + + auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( + SkRect::MakeLTRB(0, 0, 1000, 1050)); + ASSERT_EQ(2UL, hits.size()); + ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(100, 100, 200, 200)); + ASSERT_EQ(*std::next(hits.begin(), 1), SkRect::MakeLTRB(300, 100, 400, 200)); +} + +TEST(RTree, searchNonOverlappingDrawnRects_JoinRectsWhenIntersectedCase1) { + auto rtree_factory = RTreeFactory(); + auto recorder = std::make_unique(); + auto recording_canvas = + recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); + + auto rect_paint = SkPaint(); + rect_paint.setColor(SkColors::kCyan); + rect_paint.setStyle(SkPaint::Style::kFill_Style); + + // Given the A, and B rects, which intersect with the query rect, + // the result list contains the rect resulting from the union of A and B. + // + // +-----+ + // | A | + // | +-----+ + // | | C | + // | +-----+ + // | | + // +-----+ + + // A + recording_canvas->drawRect(SkRect::MakeLTRB(100, 100, 150, 150), rect_paint); + // B + recording_canvas->drawRect(SkRect::MakeLTRB(125, 125, 175, 175), rect_paint); + + recorder->finishRecordingAsPicture(); + + auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( + SkRect::MakeXYWH(120, 120, 126, 126)); + ASSERT_EQ(1UL, hits.size()); + ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(100, 100, 175, 175)); +} + +TEST(RTree, searchNonOverlappingDrawnRects_JoinRectsWhenIntersectedCase2) { + auto rtree_factory = RTreeFactory(); + auto recorder = std::make_unique(); + auto recording_canvas = + recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); + + auto rect_paint = SkPaint(); + rect_paint.setColor(SkColors::kCyan); + rect_paint.setStyle(SkPaint::Style::kFill_Style); + + // Given the A, B, and C rects that intersect with the query rect, + // there should be only C in the result list, + // since A and B are contained in C. + // + // +---------------------+ + // | C | + // | +-----+ +-----+ | + // | | A | | B | | + // | +-----+ +-----+ | + // +---------------------+ + // +-----+ + // | D | + // +-----+ + + // A + recording_canvas->drawRect(SkRect::MakeLTRB(100, 100, 200, 200), rect_paint); + // B + recording_canvas->drawRect(SkRect::MakeLTRB(300, 100, 400, 200), rect_paint); + // C + recording_canvas->drawRect(SkRect::MakeLTRB(50, 50, 500, 250), rect_paint); + // D + recording_canvas->drawRect(SkRect::MakeLTRB(280, 100, 280, 320), rect_paint); + + recorder->finishRecordingAsPicture(); + + auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( + SkRect::MakeLTRB(30, 30, 550, 270)); + ASSERT_EQ(1UL, hits.size()); + ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(50, 50, 500, 250)); +} + +TEST(RTree, searchNonOverlappingDrawnRects_JoinRectsWhenIntersectedCase3) { + auto rtree_factory = RTreeFactory(); + auto recorder = std::make_unique(); + auto recording_canvas = + recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); + + auto rect_paint = SkPaint(); + rect_paint.setColor(SkColors::kCyan); + rect_paint.setStyle(SkPaint::Style::kFill_Style); + + // Given the A, B, C and D rects that intersect with the query rect, + // the result list contains a single rect, which is the union of + // these four rects. + // + // +------------------------------+ + // | D | + // | +-----+ +-----+ +-----+ | + // | | A | | B | | C | | + // | +-----+ +-----+ | | | + // +----------------------| |-+ + // +-----+ + // +-----+ + // | E | + // +-----+ + + // A + recording_canvas->drawRect(SkRect::MakeLTRB(100, 100, 200, 200), rect_paint); + // B + recording_canvas->drawRect(SkRect::MakeLTRB(300, 100, 400, 200), rect_paint); + // C + recording_canvas->drawRect(SkRect::MakeLTRB(500, 100, 600, 300), rect_paint); + // D + recording_canvas->drawRect(SkRect::MakeLTRB(50, 50, 620, 250), rect_paint); + // E + recording_canvas->drawRect(SkRect::MakeLTRB(280, 100, 280, 320), rect_paint); + + recorder->finishRecordingAsPicture(); + + auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( + SkRect::MakeLTRB(30, 30, 550, 270)); + ASSERT_EQ(1UL, hits.size()); + ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(50, 50, 620, 300)); +} + +} // namespace testing +} // namespace flutter diff --git a/testing/run_tests.py b/testing/run_tests.py index 3f8a334354592..cb11932eae934 100755 --- a/testing/run_tests.py +++ b/testing/run_tests.py @@ -147,8 +147,6 @@ def RunCCTests(build_dir, filter): if IsLinux(): RunEngineExecutable(build_dir, 'txt_unittests', filter, shuffle_flags) - RunEngineExecutable(build_dir, 'rtree_unittests', filter, shuffle_flags) - def RunEngineBenchmarks(build_dir, filter): print("Running Engine Benchmarks.") diff --git a/third_party/skia/.clang-format b/third_party/skia/.clang-format deleted file mode 100644 index 93e44c56fa17f..0000000000000 --- a/third_party/skia/.clang-format +++ /dev/null @@ -1,194 +0,0 @@ ---- -# Typical usage is to apply this to the lines you've modified in a local -# change. Stage your changes with "git add" and then run: -# $ git clang-format -# You can optionally use the "--" file filter to restrict formatting to certain -# files or directories. The tool will display the list of files that were -# modified. These have been modified without being staged. You can review the -# modifications using "git diff". -# -# IF YOU UPDATE THE CPP SECTION ALSO UPDATE THE OBJECTIVE-C SECTION. IF YOU -# KNOW HOW TO SHARE SETTINGS BETWEEN THE TWO YOU'RE A TRUE HERO. - -Language: Cpp -# BasedOnStyle: Google -AccessModifierOffset: -4 -AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: false -AlignConsecutiveDeclarations: false -AlignEscapedNewlinesLeft: true -AlignOperands: true -AlignTrailingComments: true -AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: false -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: All -AllowShortIfStatementsOnASingleLine: true -AllowShortLoopsOnASingleLine: true -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: true -AlwaysBreakTemplateDeclarations: false -BinPackArguments: true -BinPackParameters: true -BraceWrapping: - AfterClass: false - AfterControlStatement: false - AfterEnum: false - AfterFunction: false - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - BeforeCatch: false - BeforeElse: false - IndentBraces: false -BreakBeforeBinaryOperators: None -BreakBeforeBraces: Custom -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: true -BreakAfterJavaFieldAnnotations: false -BreakStringLiterals: true -ColumnLimit: 100 -CommentPragmas: '^ IWYU pragma:' -ConstructorInitializerAllOnOneLineOrOnePerLine: true -ConstructorInitializerIndentWidth: 8 -ContinuationIndentWidth: 8 -Cpp11BracedListStyle: true -DerivePointerAlignment: false -DisableFormat: false -ExperimentalAutoDetectBinPacking: true -ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] -IncludeCategories: - - Regex: '^<.*\.h>' - Priority: 1 - - Regex: '^<.*' - Priority: 2 - - Regex: '.*' - Priority: 3 -IncludeIsMainRegex: '([-_](test|unittest))?$' -IndentCaseLabels: true -IndentWidth: 4 -IndentWrappedFunctionNames: false -JavaScriptQuotes: Leave -JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: false -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCBlockIndentWidth: 2 -ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: false -PenaltyBreakBeforeFirstCallParameter: 1 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakString: 1000 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 200 -PointerAlignment: Left -ReflowComments: true -SortIncludes: true -SpaceAfterCStyleCast: false -SpaceAfterTemplateKeyword: true -SpaceBeforeAssignmentOperators: true -SpaceBeforeParens: ControlStatements -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 2 -SpacesInAngles: false -SpacesInContainerLiterals: true -SpacesInCStyleCastParentheses: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -Standard: Auto -TabWidth: 4 -UseTab: Never ---- -Language: ObjC -AccessModifierOffset: -4 -AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: false -AlignConsecutiveDeclarations: false -AlignEscapedNewlinesLeft: true -AlignOperands: true -AlignTrailingComments: true -AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: false -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: All -AllowShortIfStatementsOnASingleLine: true -AllowShortLoopsOnASingleLine: true -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: true -AlwaysBreakTemplateDeclarations: false -BinPackArguments: true -BinPackParameters: true -BraceWrapping: - AfterClass: false - AfterControlStatement: false - AfterEnum: false - AfterFunction: false - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - BeforeCatch: false - BeforeElse: false - IndentBraces: false -BreakBeforeBinaryOperators: None -BreakBeforeBraces: Custom -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: true -BreakAfterJavaFieldAnnotations: false -BreakStringLiterals: true -ColumnLimit: 100 -CommentPragmas: '^ IWYU pragma:' -ConstructorInitializerAllOnOneLineOrOnePerLine: true -ConstructorInitializerIndentWidth: 8 -ContinuationIndentWidth: 8 -Cpp11BracedListStyle: true -DerivePointerAlignment: false -DisableFormat: false -ExperimentalAutoDetectBinPacking: true -ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] -IncludeCategories: - - Regex: '^<.*\.h>' - Priority: 1 - - Regex: '^<.*' - Priority: 2 - - Regex: '.*' - Priority: 3 -IncludeIsMainRegex: '([-_](test|unittest))?$' -IndentCaseLabels: true -IndentWidth: 4 -IndentWrappedFunctionNames: false -JavaScriptQuotes: Leave -JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: false -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCBlockIndentWidth: 2 -ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: false -PenaltyBreakBeforeFirstCallParameter: 1 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakString: 1000 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 200 -PointerAlignment: Left -ReflowComments: true -SortIncludes: true -SpaceAfterCStyleCast: false -SpaceAfterTemplateKeyword: true -SpaceBeforeAssignmentOperators: true -SpaceBeforeParens: ControlStatements -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 2 -SpacesInAngles: false -SpacesInContainerLiterals: true -SpacesInCStyleCastParentheses: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -Standard: Auto -TabWidth: 4 -UseTab: Never diff --git a/third_party/skia/AUTHORS b/third_party/skia/AUTHORS deleted file mode 100644 index 838af91e91d6f..0000000000000 --- a/third_party/skia/AUTHORS +++ /dev/null @@ -1,66 +0,0 @@ -# This is the official list of Skia authors for copyright purposes. -# -# Names should be added to this file with one of the following patterns: -# -# For individual contributors: -# Name -# -# For corporate contributors: -# Organization -# See examples below or python fnmatch module documentation for more information. -# -# Please keep the list sorted alphabetically. - -Aaron O'Mullan -ACCESS CO., LTD. <*@access-company.com> -Amazon, Inc <*@amazon.com> -Anthony Catel -ARM <*@arm.com> -Bharat Ahuja -Dawson Coleman -Deepak Mohan -Ehsan Akhgari -Facebook, Inc. <*fb.com> -George Wright -GiWan Go -Google Inc. <*@google.com> -Herb Derby -Igalia <*@igalia.com> -Intel <*@intel.com> -Ion Rosca -Jacek Caban -Jeff Muizelaar -Jongdeok Kim -Lee Salzman -Marcin Kazmierczak -Matthew Leibowitz -Microsoft <*@microsoft.com> -MIPS <*@imgtec.com> -Noah Lavine -NVIDIA <*@nvidia.com> -Opera Software ASA <*@opera.com> -Pavel Krajcevski -Petar Kirov -Raul Tambre -Samsung <*@samsung.com> -Samsung Open Source Group <*@osg.samsung.com> -Sergey Melnikov -Shachar Langbeheim -Skia <*@skia.org> -Skia Buildbots -Sony Mobile Communications Inc. <*@sonymobile.com> -Steve Singer -Sylvestre Ledru -The Chromium Authors <*@chromium.org> -Thiago Fransosi Farina -Jose Mayol -Linaro <*@linaro.org> -Christian Plesner Hansen -Marco Alesiani -Adobe Systems Incorporated <*@adobe.com> -Yandex LLC <*@yandex-team.ru> -Kaloyan Donev -Yong-Hwan Baek -Alexander Khovansky -Zhuo Qingliang -Mainframe North <*@mainframe.co.uk> diff --git a/third_party/skia/BUILD.gn b/third_party/skia/BUILD.gn deleted file mode 100644 index 65bc4661988fd..0000000000000 --- a/third_party/skia/BUILD.gn +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2012 Google Inc. -# -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//flutter/testing/testing.gni") - -source_set("rtree") { - sources = [ - "rtree.cc", - "rtree.h", - ] - - deps = [ - "//third_party/skia", - ] -} - -test_fixtures("rtree_fixtures") { - fixtures = [] -} - -executable("rtree_unittests") { - testonly = true - sources = [ - "main_unittests.cc", - "rtree_unittests.cc", - ] - deps = [ - ":rtree", - ":rtree_fixtures", - "//flutter/testing:testing_lib", - "//third_party/dart/runtime:libdart_jit", # For logging. - "//third_party/skia", - ] -} diff --git a/third_party/skia/LICENSE b/third_party/skia/LICENSE deleted file mode 100644 index e32636d5668d5..0000000000000 --- a/third_party/skia/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -Copyright (c) 2011 Google Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/skia/main_unittests.cc b/third_party/skia/main_unittests.cc deleted file mode 100644 index f4e7489c73560..0000000000000 --- a/third_party/skia/main_unittests.cc +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "flutter/testing/testing.h" - -int main(int argc, char** argv) { - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/third_party/skia/rtree.cc b/third_party/skia/rtree.cc deleted file mode 100644 index 03211f539e69a..0000000000000 --- a/third_party/skia/rtree.cc +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include - -#include "rtree.h" - -namespace flutter { - -RTree::RTree() : fCount(0) {} - -void RTree::insert(const SkRect boundsArray[], const SkBBoxHierarchy::Metadata metadata[], int N) { - SkASSERT(0 == fCount); - - std::vector branches; - branches.reserve(N); - - for (int i = 0; i < N; i++) { - const SkRect& bounds = boundsArray[i]; - if (bounds.isEmpty()) { - continue; - } - Branch b; - b.fBounds = bounds; - b.fOpIndex = i; - b.isDraw = (metadata == nullptr) ? false : metadata[i].isDraw; - branches.push_back(b); - } - - fCount = (int)branches.size(); - if (fCount) { - if (1 == fCount) { - fNodes.reserve(1); - Node* n = this->allocateNodeAtLevel(0); - n->fNumChildren = 1; - n->fChildren[0] = branches[0]; - fRoot.fSubtree = n; - fRoot.fBounds = branches[0].fBounds; - } else { - fNodes.reserve(CountNodes(fCount)); - fRoot = this->bulkLoad(&branches); - } - } -} - -void RTree::insert(const SkRect boundsArray[], int N) { insert(boundsArray, nullptr, N); } - -RTree::Node* RTree::allocateNodeAtLevel(uint16_t level) { - SkDEBUGCODE(Node* p = fNodes.data()); - fNodes.push_back(Node{}); - Node& out = fNodes.back(); - SkASSERT(fNodes.data() == p); // If this fails, we didn't reserve() enough. - out.fNumChildren = 0; - out.fLevel = level; - return &out; -} - -// This function parallels bulkLoad, but just counts how many nodes bulkLoad -// would allocate. -int RTree::CountNodes(int branches) { - if (branches == 1) { - return 1; - } - int numBranches = branches / kMaxChildren; - int remainder = branches % kMaxChildren; - if (remainder > 0) { - numBranches++; - if (remainder >= kMinChildren) { - remainder = 0; - } else { - remainder = kMinChildren - remainder; - } - } - int currentBranch = 0; - int nodes = 0; - while (currentBranch < branches) { - int incrementBy = kMaxChildren; - if (remainder != 0) { - if (remainder <= kMaxChildren - kMinChildren) { - incrementBy -= remainder; - remainder = 0; - } else { - incrementBy = kMinChildren; - remainder -= kMaxChildren - kMinChildren; - } - } - nodes++; - currentBranch++; - for (int k = 1; k < incrementBy && currentBranch < branches; ++k) { - currentBranch++; - } - } - return nodes + CountNodes(nodes); -} - -RTree::Branch RTree::bulkLoad(std::vector* branches, int level) { - if (branches->size() == 1) { // Only one branch. It will be the root. - return (*branches)[0]; - } - - // We might sort our branches here, but we expect Blink gives us a reasonable - // x,y order. Skipping a call to sort (in Y) here resulted in a 17% win for - // recording with negligible difference in playback speed. - int numBranches = (int)branches->size() / kMaxChildren; - int remainder = (int)branches->size() % kMaxChildren; - int newBranches = 0; - - if (remainder > 0) { - ++numBranches; - // If the remainder isn't enough to fill a node, we'll add fewer nodes to - // other branches. - if (remainder >= kMinChildren) { - remainder = 0; - } else { - remainder = kMinChildren - remainder; - } - } - - int currentBranch = 0; - while (currentBranch < (int)branches->size()) { - int incrementBy = kMaxChildren; - if (remainder != 0) { - // if need be, omit some nodes to make up for remainder - if (remainder <= kMaxChildren - kMinChildren) { - incrementBy -= remainder; - remainder = 0; - } else { - incrementBy = kMinChildren; - remainder -= kMaxChildren - kMinChildren; - } - } - Node* n = allocateNodeAtLevel(level); - n->fNumChildren = 1; - n->fChildren[0] = (*branches)[currentBranch]; - Branch b; - b.fBounds = (*branches)[currentBranch].fBounds; - b.fSubtree = n; - ++currentBranch; - for (int k = 1; k < incrementBy && currentBranch < (int)branches->size(); ++k) { - b.fBounds.join((*branches)[currentBranch].fBounds); - n->fChildren[k] = (*branches)[currentBranch]; - ++n->fNumChildren; - ++currentBranch; - } - (*branches)[newBranches] = b; - ++newBranches; - } - branches->resize(newBranches); - return this->bulkLoad(branches, level + 1); -} - -void RTree::search(const SkRect& query, std::vector* results) const { - if (fCount > 0 && SkRect::Intersects(fRoot.fBounds, query)) { - this->search(fRoot.fSubtree, query, results); - } -} - -void RTree::search(Node* node, const SkRect& query, std::vector* results) const { - for (int i = 0; i < node->fNumChildren; ++i) { - if (!SkRect::Intersects(node->fChildren[i].fBounds, query)) { - continue; - } - if (0 != node->fLevel) { - this->search(node->fChildren[i].fSubtree, query, results); - continue; - } - results->push_back(node->fChildren[i].fOpIndex); - } -} - -std::list RTree::searchNonOverlappingDrawnRects(const SkRect& query) const { - std::list results; - if (fCount > 0 && SkRect::Intersects(fRoot.fBounds, query)) { - this->searchNonOverlappingDrawnRects(fRoot.fSubtree, query, results); - } - return results; -} - -void RTree::searchNonOverlappingDrawnRects(Node* node, - const SkRect& query, - std::list& results) const { - if (!SkRect::Intersects(fRoot.fBounds, query)) { - return; - } - for (int i = 0; i < node->fNumChildren; ++i) { - if (!SkRect::Intersects(node->fChildren[i].fBounds, query)) { - continue; - } - // Non-leaf node - if (0 != node->fLevel) { - this->searchNonOverlappingDrawnRects(node->fChildren[i].fSubtree, query, results); - continue; - } - // Ignore records that don't draw anything. - if (!node->fChildren[i].isDraw) { - continue; - } - SkRect currentRecordRect = node->fChildren[i].fBounds; - bool replacedExistingRect = false; - // // If the current record rect intersects with any of the rects in the - // // result list, then join them, and update the rect in results. - std::list::iterator currRectItr = results.begin(); - std::list::iterator firstIntersectingRectItr; - while (!replacedExistingRect && currRectItr != results.end()) { - if (SkRect::Intersects(*currRectItr, currentRecordRect)) { - replacedExistingRect = true; - firstIntersectingRectItr = currRectItr; - currRectItr->join(currentRecordRect); - } - currRectItr++; - } - // It's possible that the result contains duplicated rects at this point. - // For example, consider a result list that contains rects A, B. If a - // new rect C is a superset of A and B, then A and B are the same set after - // the merge. As a result, find such cases and remove them from the result list. - while (replacedExistingRect && currRectItr != results.end()) { - if (SkRect::Intersects(*currRectItr, *firstIntersectingRectItr)) { - firstIntersectingRectItr->join(*currRectItr); - currRectItr = results.erase(currRectItr); - } else { - currRectItr++; - } - } - if (!replacedExistingRect) { - results.push_back(currentRecordRect); - } - } -} - -size_t RTree::bytesUsed() const { - size_t byteCount = sizeof(RTree); - byteCount += fNodes.capacity() * sizeof(Node); - return byteCount; -} - -RTreeFactory::RTreeFactory() { r_tree_ = sk_make_sp(); } - -sk_sp RTreeFactory::getInstance() { return r_tree_; } - -sk_sp RTreeFactory::operator()() const { return r_tree_; } - -} // namespace flutter diff --git a/third_party/skia/rtree.h b/third_party/skia/rtree.h deleted file mode 100644 index 610085163d007..0000000000000 --- a/third_party/skia/rtree.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SKIA_RTREE_H_ -#define SKIA_RTREE_H_ - -#include - -#include "third_party/skia/include/core/SkBBHFactory.h" -#include "third_party/skia/include/core/SkTypes.h" - -namespace flutter { -/** - * An R-Tree implementation. In short, it is a balanced n-ary tree containing a hierarchy of - * bounding rectangles. - * - * It only supports bulk-loading, i.e. creation from a batch of bounding rectangles. - * This performs a bottom-up bulk load using the STR (sort-tile-recursive) algorithm. - * - * TODO: Experiment with other bulk-load algorithms (in particular the Hilbert pack variant, - * which groups rects by position on the Hilbert curve, is probably worth a look). There also - * exist top-down bulk load variants (VAMSplit, TopDownGreedy, etc). - * - * For more details see: - * - * Beckmann, N.; Kriegel, H. P.; Schneider, R.; Seeger, B. (1990). "The R*-tree: - * an efficient and robust access method for points and rectangles" - * - * The original source code can be found on - * https://github.com/google/skia/blob/508fd32091afe334d4e1dd6cdaa63168a53acb26/src/core/SkRTree.h - * - * This copy includes a searchRects method. - */ -class RTree : public SkBBoxHierarchy { -public: - RTree(); - - void insert(const SkRect[], const SkBBoxHierarchy::Metadata[], int N) override; - void insert(const SkRect[], int N) override; - void search(const SkRect& query, std::vector* results) const override; - - // Finds the rects in the tree that represent drawing operations and intersect - // with the query rect. - // - // When two rects intersect with each other, they are joined into a single rect - // which also intersects with the query rect. In other words, the bounds of each - // rect in the result list are mutually exclusive. - std::list searchNonOverlappingDrawnRects(const SkRect& query) const; - - size_t bytesUsed() const override; - - // Methods and constants below here are only public for tests. - - // Return the depth of the tree structure. - int getDepth() const { return fCount ? fRoot.fSubtree->fLevel + 1 : 0; } - // Insertion count (not overall node count, which may be greater). - int getCount() const { return fCount; } - - // These values were empirically determined to produce reasonable performance - // in most cases. - static const int kMinChildren = 6, kMaxChildren = 11; - -private: - struct Node; - - struct Branch { - union { - Node* fSubtree; - int fOpIndex; - }; - // True if the current bounds represent a drawing operation. - bool isDraw; - SkRect fBounds; - }; - - struct Node { - uint16_t fNumChildren; - uint16_t fLevel; - Branch fChildren[kMaxChildren]; - }; - - void search(Node* root, const SkRect& query, std::vector* results) const; - void searchNonOverlappingDrawnRects(Node* root, const SkRect& query, - std::list& results) const; - - // Consumes the input array. - Branch bulkLoad(std::vector* branches, int level = 0); - - // How many times will bulkLoad() call allocateNodeAtLevel()? - static int CountNodes(int branches); - - Node* allocateNodeAtLevel(uint16_t level); - - // This is the count of data elements (rather than total nodes in the tree) - int fCount; - Branch fRoot; - std::vector fNodes; -}; - -class RTreeFactory : public SkBBHFactory { -public: - RTreeFactory(); - - // Gets the instance to the R-tree. - sk_sp getInstance(); - sk_sp operator()() const override; - -private: - sk_sp r_tree_; -}; - -#endif // SKIA_RTREE_H_ - -} // namespace flutter diff --git a/third_party/skia/rtree_unittests.cc b/third_party/skia/rtree_unittests.cc deleted file mode 100644 index 72eb15eec73c0..0000000000000 --- a/third_party/skia/rtree_unittests.cc +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "flutter/testing/testing.h" -#include "rtree.h" - -#include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkPictureRecorder.h" -#include "third_party/skia/include/utils/SkRandom.h" - -namespace flutter { -namespace testing { - -TEST(RTree, searchNonOverlappingDrawnRects_NoIntersection) { - auto rtree_factory = RTreeFactory(); - auto recorder = std::make_unique(); - auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); - - auto rect_paint = SkPaint(); - rect_paint.setColor(SkColors::kCyan); - rect_paint.setStyle(SkPaint::Style::kFill_Style); - - // If no rect is intersected with the query rect, then the result list is empty. - recording_canvas->drawRect(SkRect::MakeLTRB(20, 20, 40, 40), rect_paint); - recorder->finishRecordingAsPicture(); - - auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( - SkRect::MakeLTRB(40, 40, 80, 80)); - ASSERT_TRUE(hits.empty()); -} - -TEST(RTree, searchNonOverlappingDrawnRects_SingleRectIntersection) { - auto rtree_factory = RTreeFactory(); - auto recorder = std::make_unique(); - auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); - - auto rect_paint = SkPaint(); - rect_paint.setColor(SkColors::kCyan); - rect_paint.setStyle(SkPaint::Style::kFill_Style); - - // Given a single rect A that intersects with the query rect, - // the result list contains this rect. - recording_canvas->drawRect(SkRect::MakeLTRB(120, 120, 160, 160), rect_paint); - - recorder->finishRecordingAsPicture(); - - auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( - SkRect::MakeLTRB(140, 140, 150, 150)); - ASSERT_EQ(1UL, hits.size()); - ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(120, 120, 160, 160)); -} - -TEST(RTree, searchNonOverlappingDrawnRects_IgnoresNonDrawingRecords) { - auto rtree_factory = RTreeFactory(); - auto recorder = std::make_unique(); - auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); - - auto rect_paint = SkPaint(); - rect_paint.setColor(SkColors::kCyan); - rect_paint.setStyle(SkPaint::Style::kFill_Style); - - // Creates two non drawing records. - recording_canvas->translate(100, 100); - // The result list should only contain the clipping rect. - recording_canvas->clipRect(SkRect::MakeLTRB(40, 40, 50, 50), SkClipOp::kIntersect); - recording_canvas->drawRect(SkRect::MakeLTRB(20, 20, 80, 80), rect_paint); - - recorder->finishRecordingAsPicture(); - - // The rtree has a translate, a clip and a rect record. - ASSERT_EQ(3, rtree_factory.getInstance()->getCount()); - - auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( - SkRect::MakeLTRB(0, 0, 1000, 1000)); - ASSERT_EQ(1UL, hits.size()); - ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(120, 120, 180, 180)); -} - -TEST(RTree, searchNonOverlappingDrawnRects_MultipleRectIntersection) { - auto rtree_factory = RTreeFactory(); - auto recorder = std::make_unique(); - auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); - - auto rect_paint = SkPaint(); - rect_paint.setColor(SkColors::kCyan); - rect_paint.setStyle(SkPaint::Style::kFill_Style); - - // Given the A, B that intersect with the query rect, - // there should be A and B in the result list since - // they don't intersect with each other. - // - // +-----+ +-----+ - // | A | | B | - // +-----+ +-----+ - // A - recording_canvas->drawRect(SkRect::MakeLTRB(100, 100, 200, 200), rect_paint); - // B - recording_canvas->drawRect(SkRect::MakeLTRB(300, 100, 400, 200), rect_paint); - - recorder->finishRecordingAsPicture(); - - auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( - SkRect::MakeLTRB(0, 0, 1000, 1050)); - ASSERT_EQ(2UL, hits.size()); - ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(100, 100, 200, 200)); - ASSERT_EQ(*std::next(hits.begin(), 1), SkRect::MakeLTRB(300, 100, 400, 200)); -} - -TEST(RTree, searchNonOverlappingDrawnRects_JoinRectsWhenIntersectedCase1) { - auto rtree_factory = RTreeFactory(); - auto recorder = std::make_unique(); - auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); - - auto rect_paint = SkPaint(); - rect_paint.setColor(SkColors::kCyan); - rect_paint.setStyle(SkPaint::Style::kFill_Style); - - // Given the A, and B rects, which intersect with the query rect, - // the result list contains the rect resulting from the union of A and B. - // - // +-----+ - // | A | - // | +-----+ - // | | C | - // | +-----+ - // | | - // +-----+ - - // A - recording_canvas->drawRect(SkRect::MakeLTRB(100, 100, 150, 150), rect_paint); - // B - recording_canvas->drawRect(SkRect::MakeLTRB(125, 125, 175, 175), rect_paint); - - recorder->finishRecordingAsPicture(); - - auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( - SkRect::MakeXYWH(120, 120, 126, 126)); - ASSERT_EQ(1UL, hits.size()); - ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(100, 100, 175, 175)); -} - -TEST(RTree, searchNonOverlappingDrawnRects_JoinRectsWhenIntersectedCase2) { - auto rtree_factory = RTreeFactory(); - auto recorder = std::make_unique(); - auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); - - auto rect_paint = SkPaint(); - rect_paint.setColor(SkColors::kCyan); - rect_paint.setStyle(SkPaint::Style::kFill_Style); - - // Given the A, B, and C rects that intersect with the query rect, - // there should be only C in the result list, - // since A and B are contained in C. - // - // +---------------------+ - // | C | - // | +-----+ +-----+ | - // | | A | | B | | - // | +-----+ +-----+ | - // +---------------------+ - // +-----+ - // | D | - // +-----+ - - // A - recording_canvas->drawRect(SkRect::MakeLTRB(100, 100, 200, 200), rect_paint); - // B - recording_canvas->drawRect(SkRect::MakeLTRB(300, 100, 400, 200), rect_paint); - // C - recording_canvas->drawRect(SkRect::MakeLTRB(50, 50, 500, 250), rect_paint); - // D - recording_canvas->drawRect(SkRect::MakeLTRB(280, 100, 280, 320), rect_paint); - - recorder->finishRecordingAsPicture(); - - auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( - SkRect::MakeLTRB(30, 30, 550, 270)); - ASSERT_EQ(1UL, hits.size()); - ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(50, 50, 500, 250)); -} - -TEST(RTree, searchNonOverlappingDrawnRects_JoinRectsWhenIntersectedCase3) { - auto rtree_factory = RTreeFactory(); - auto recorder = std::make_unique(); - auto recording_canvas = recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); - - auto rect_paint = SkPaint(); - rect_paint.setColor(SkColors::kCyan); - rect_paint.setStyle(SkPaint::Style::kFill_Style); - - // Given the A, B, C and D rects that intersect with the query rect, - // the result list contains a single rect, which is the union of - // these four rects. - // - // +------------------------------+ - // | D | - // | +-----+ +-----+ +-----+ | - // | | A | | B | | C | | - // | +-----+ +-----+ | | | - // +----------------------| |-+ - // +-----+ - // +-----+ - // | E | - // +-----+ - - // A - recording_canvas->drawRect(SkRect::MakeLTRB(100, 100, 200, 200), rect_paint); - // B - recording_canvas->drawRect(SkRect::MakeLTRB(300, 100, 400, 200), rect_paint); - // C - recording_canvas->drawRect(SkRect::MakeLTRB(500, 100, 600, 300), rect_paint); - // D - recording_canvas->drawRect(SkRect::MakeLTRB(50, 50, 620, 250), rect_paint); - // E - recording_canvas->drawRect(SkRect::MakeLTRB(280, 100, 280, 320), rect_paint); - - recorder->finishRecordingAsPicture(); - - auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( - SkRect::MakeLTRB(30, 30, 550, 270)); - ASSERT_EQ(1UL, hits.size()); - ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(50, 50, 620, 300)); -} - -// Existing Skia tests from -// https://github.com/google/skia/blob/508fd32091afe334d4e1dd6cdaa63168a53acb26/tests/RTreeTest.cpp - -static const int NUM_RECTS = 200; -static const size_t NUM_ITERATIONS = 100; -static const size_t NUM_QUERIES = 50; - -static SkRect random_rect(SkRandom& rand) { - SkRect rect = {0, 0, 0, 0}; - while (rect.isEmpty()) { - rect.fLeft = rand.nextRangeF(0, 1000); - rect.fRight = rand.nextRangeF(0, 1000); - rect.fTop = rand.nextRangeF(0, 1000); - rect.fBottom = rand.nextRangeF(0, 1000); - rect.sort(); - } - return rect; -} - -static bool verify_query(SkRect query, SkRect rects[], std::vector& found) { - std::vector expected; - // manually intersect with every rectangle - for (int i = 0; i < NUM_RECTS; ++i) { - if (SkRect::Intersects(query, rects[i])) { - expected.push_back(i); - } - } - - if (expected.size() != found.size()) { - return false; - } - if (0 == expected.size()) { - return true; - } - return found == expected; -} - -static void run_queries(SkRandom& rand, SkRect rects[], const RTree& tree) { - for (size_t i = 0; i < NUM_QUERIES; ++i) { - std::vector hits; - SkRect query = random_rect(rand); - tree.search(query, &hits); - ASSERT_TRUE(verify_query(query, rects, hits)); - } -} - -TEST(RTree, existingSkiaTest) { - int expectedDepthMin = -1; - int tmp = NUM_RECTS; - while (tmp > 0) { - tmp -= static_cast(pow(static_cast(RTree::kMaxChildren), - static_cast(expectedDepthMin + 1))); - ++expectedDepthMin; - } - - int expectedDepthMax = -1; - tmp = NUM_RECTS; - while (tmp > 0) { - tmp -= static_cast(pow(static_cast(RTree::kMinChildren), - static_cast(expectedDepthMax + 1))); - ++expectedDepthMax; - } - - SkRandom rand; - SkAutoTMalloc rects(NUM_RECTS); - for (size_t i = 0; i < NUM_ITERATIONS; ++i) { - RTree rtree; - ASSERT_EQ(0, rtree.getCount()); - - for (int j = 0; j < NUM_RECTS; j++) { - rects[j] = random_rect(rand); - } - - rtree.insert(rects.get(), NUM_RECTS); - SkASSERT(rects); // RTree doesn't take ownership of rects. - - run_queries(rand, rects, rtree); - ASSERT_EQ(NUM_RECTS, rtree.getCount()); - ASSERT_TRUE(expectedDepthMin <= rtree.getDepth() && expectedDepthMax >= rtree.getDepth()); - } -} - -} // namespace testing -} // namespace flutter From 1fd3de556f52e20cff01f015b793933a3cfad501 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Mon, 9 Mar 2020 18:35:33 -0700 Subject: [PATCH 23/23] Format BUILD.gn --- flow/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flow/BUILD.gn b/flow/BUILD.gn index cfe3b2eb253b9..14ceec4dadc5c 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -58,8 +58,8 @@ source_set("flow") { "raster_cache.h", "raster_cache_key.cc", "raster_cache_key.h", - "rtree.h", "rtree.cc", + "rtree.h", "skia_gpu_object.cc", "skia_gpu_object.h", "texture.cc",