diff options
Diffstat (limited to 'gfx/skia/skia/src/core/SkRecordPattern.h')
-rw-r--r-- | gfx/skia/skia/src/core/SkRecordPattern.h | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/core/SkRecordPattern.h b/gfx/skia/skia/src/core/SkRecordPattern.h new file mode 100644 index 0000000000..4244fbb3e6 --- /dev/null +++ b/gfx/skia/skia/src/core/SkRecordPattern.h @@ -0,0 +1,177 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRecordPattern_DEFINED +#define SkRecordPattern_DEFINED + +#include "include/private/base/SkTLogic.h" +#include "src/core/SkRecord.h" + +namespace SkRecords { + +// First, some matchers. These match a single command in the SkRecord, +// and may hang onto some data from it. If so, you can get the data by calling .get(). + +// Matches a command of type T, and stores that command. +template <typename T> +class Is { +public: + Is() : fPtr(nullptr) {} + + typedef T type; + type* get() { return fPtr; } + + bool operator()(T* ptr) { + fPtr = ptr; + return true; + } + + template <typename U> + bool operator()(U*) { + fPtr = nullptr; + return false; + } + +private: + type* fPtr; +}; + +// Matches any command that draws, and stores its paint. +class IsDraw { +public: + IsDraw() : fPaint(nullptr) {} + + typedef SkPaint type; + type* get() { return fPaint; } + + template <typename T> + std::enable_if_t<(T::kTags & kDrawWithPaint_Tag) == kDrawWithPaint_Tag, bool> + operator()(T* draw) { + fPaint = AsPtr(draw->paint); + return true; + } + + template <typename T> + std::enable_if_t<(T::kTags & kDrawWithPaint_Tag) == kDraw_Tag, bool> operator()(T* draw) { + fPaint = nullptr; + return true; + } + + template <typename T> + std::enable_if_t<!(T::kTags & kDraw_Tag), bool> operator()(T* draw) { + fPaint = nullptr; + return false; + } + +private: + // Abstracts away whether the paint is always part of the command or optional. + template <typename T> static T* AsPtr(SkRecords::Optional<T>& x) { return x; } + template <typename T> static T* AsPtr(T& x) { return &x; } + + type* fPaint; +}; + +// Matches if Matcher doesn't. Stores nothing. +template <typename Matcher> +struct Not { + template <typename T> + bool operator()(T* ptr) { return !Matcher()(ptr); } +}; + +// Matches if any of First or Rest... does. Stores nothing. +template <typename First, typename... Rest> +struct Or { + template <typename T> + bool operator()(T* ptr) { return First()(ptr) || Or<Rest...>()(ptr); } +}; +template <typename First> +struct Or<First> { + template <typename T> + bool operator()(T* ptr) { return First()(ptr); } +}; + + +// Greedy is a special matcher that greedily matches Matcher 0 or more times. Stores nothing. +template <typename Matcher> +struct Greedy { + template <typename T> + bool operator()(T* ptr) { return Matcher()(ptr); } +}; + +// Pattern matches each of its matchers in order. +// +// This is the main entry point to pattern matching, and so provides a couple of extra API bits: +// - search scans through the record to look for matches; +// - first, second, third, ... return the data stored by their respective matchers in the pattern. + +template <typename... Matchers> class Pattern; + +template <> class Pattern<> { +public: + // Bottoms out recursion. Just return whatever i the front decided on. + int match(SkRecord*, int i) { return i; } +}; + +template <typename First, typename... Rest> +class Pattern<First, Rest...> { +public: + // If this pattern matches the SkRecord starting from i, + // return the index just past the end of the pattern, otherwise return 0. + SK_ALWAYS_INLINE int match(SkRecord* record, int i) { + i = this->matchFirst(&fFirst, record, i); + return i > 0 ? fRest.match(record, i) : 0; + } + + // Starting from *end, walk through the SkRecord to find the first span matching this pattern. + // If there is no such span, return false. If there is, return true and set [*begin, *end). + SK_ALWAYS_INLINE bool search(SkRecord* record, int* begin, int* end) { + for (*begin = *end; *begin < record->count(); ++(*begin)) { + *end = this->match(record, *begin); + if (*end != 0) { + return true; + } + } + return false; + } + + // TODO: some sort of smart get<i>() + template <typename T> T* first() { return fFirst.get(); } + template <typename T> T* second() { return fRest.template first<T>(); } + template <typename T> T* third() { return fRest.template second<T>(); } + template <typename T> T* fourth() { return fRest.template third<T>(); } + +private: + // If first isn't a Greedy, try to match at i once. + template <typename T> + int matchFirst(T* first, SkRecord* record, int i) { + if (i < record->count()) { + if (record->mutate(i, *first)) { + return i+1; + } + } + return 0; + } + + // If first is a Greedy, walk i until it doesn't match. + template <typename T> + int matchFirst(Greedy<T>* first, SkRecord* record, int i) { + while (i < record->count()) { + if (!record->mutate(i, *first)) { + return i; + } + i++; + } + return 0; + } + + First fFirst; + Pattern<Rest...> fRest; +}; + +} // namespace SkRecords + +#endif//SkRecordPattern_DEFINED |