/* * Copyright 2022 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkCombinationBuilder_DEFINED #define SkCombinationBuilder_DEFINED #include "include/core/SkTypes.h" #ifdef SK_ENABLE_PRECOMPILE #include #include #include #include "include/core/SkBlendMode.h" #include "include/core/SkSpan.h" #include "include/core/SkTileMode.h" #include "include/private/SkTArray.h" #include "include/private/SkTHash.h" class SkArenaAllocWithReset; class SkCombinationBuilder; class SkKeyContext; class SkOption; class SkPaintParamsKeyBuilder; class SkShaderCodeDictionary; class SkUniquePaintParamsID; namespace skgpu::graphite { class Context; } enum class SkShaderType : uint32_t { kSolidColor, kLinearGradient, kRadialGradient, kSweepGradient, kConicalGradient, kLocalMatrix, kImage, kBlendShader, kLast = kBlendShader }; static constexpr int kSkShaderTypeCount = static_cast(SkShaderType::kLast) + 1; struct SkTileModePair { SkTileMode fX; SkTileMode fY; bool operator==(const SkTileModePair& other) const { return fX == other.fX && fY == other.fY; } bool operator!=(const SkTileModePair& other) const { return !(*this == other); } }; // TODO: add SkShaderID and SkColorFilterID too class SkBlenderID { public: SkBlenderID() : fID(0) {} // 0 is an invalid blender ID SkBlenderID(const SkBlenderID& src) : fID(src.fID) {} bool isValid() const { return fID > 0; } bool operator==(const SkBlenderID& other) const { return fID == other.fID; } SkBlenderID& operator=(const SkBlenderID& src) { fID = src.fID; return *this; } private: friend class SkShaderCodeDictionary; // for ctor and asUInt access friend class SkCombinationBuilder; // for asUInt access SkBlenderID(uint32_t id) : fID(id) {} uint32_t asUInt() const { return fID; } uint32_t fID; }; // When combination options are added to the combination builder an SkCombinationOption // object is frequently returned. This allows options to be added, recursively, to the // previously added options. // Note: SkCombinationOptions are stable memory-wise so, once returned, they are valid // until SkCombinationBuilder::reset is called. class SkCombinationOption { public: SkCombinationOption addChildOption(int childIndex, SkShaderType); SkCombinationOption addChildOption(int childIndex, SkShaderType, int minNumStops, int maxNumStops); SkCombinationOption addChildOption(int childIndex, SkShaderType, SkSpan tileModes); bool isValid() const { return fDataInArena; } private: friend class SkCombinationBuilder; // for ctor friend class CombinationBuilderTestAccess; SkCombinationOption(SkCombinationBuilder* builder, SkOption* dataInArena) : fBuilder(builder) , fDataInArena(dataInArena) {} SkShaderType type() const; int numChildSlots() const; SkDEBUGCODE(int epoch() const;) SkCombinationBuilder* fBuilder; SkOption* fDataInArena; }; class SkCombinationBuilder { public: enum class BlendModeGroup { kPorterDuff, // [ kClear .. kScreen ] kAdvanced, // [ kOverlay .. kMultiply ] kColorAware, // [ kHue .. kLuminosity ] kAll }; SkCombinationBuilder(SkShaderCodeDictionary*); ~SkCombinationBuilder(); // Blend Modes void addOption(SkBlendMode); void addOption(SkBlendMode rangeStart, SkBlendMode rangeEnd); // inclusive void addOption(BlendModeGroup); // TODO: have this variant return an SkCombinationOption object void addOption(SkBlenderID); // Shaders SkCombinationOption addOption(SkShaderType); SkCombinationOption addOption(SkShaderType, int minNumStops, int maxNumStops); // inclusive SkCombinationOption addOption(SkShaderType, SkSpan tileModes); void reset(); private: friend class skgpu::graphite::Context; // for access to 'buildCombinations' friend class SkCombinationOption; // for 'addOptionInternal' and 'arena' friend class CombinationBuilderTestAccess; // for 'num*Combinations' and 'epoch' int numShaderCombinations() const; int numBlendModeCombinations() const; int numCombinations() { return this->numShaderCombinations() * this->numBlendModeCombinations(); } // 'desiredCombination' must be less than numCombinations void createKey(const SkKeyContext&, int desiredCombination, SkPaintParamsKeyBuilder*); #ifdef SK_DEBUG void dump() const; int epoch() const { return fEpoch; } #endif SkArenaAllocWithReset* arena() { return fArena.get(); } template SkOption* allocInArena(Args&&... args); SkOption* addOptionInternal(SkShaderType); SkOption* addOptionInternal(SkShaderType, int minNumStops, int maxNumStops); SkOption* addOptionInternal(SkShaderType, SkSpan tileModes); void buildCombinations(SkShaderCodeDictionary*, const std::function&); SkShaderCodeDictionary* fDictionary; std::unique_ptr fArena; SkTArray fShaderOptions; uint32_t fBlendModes; // TODO: store the SkBlender-based blenders in the arena SkTHashSet fBlenders; SkDEBUGCODE(int fEpoch = 0;) }; #endif // SK_ENABLE_PRECOMPILE #endif // SkCombinationBuilder_DEFINED