/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. */ #ifndef ANDROID_HWUI_BAKED_OP_STATE_H #define ANDROID_HWUI_BAKED_OP_STATE_H #include "Matrix.h" #include "RecordedOp.h" #include "Rect.h" #include "Snapshot.h" namespace android { namespace uirenderer { namespace OpClipSideFlags { enum { None = 0x0, Left = 0x1, Top = 0x2, Right = 0x4, Bottom = 0x8, Full = 0xF, // ConservativeFull = 0x1F needed? }; } /** * Holds a list of BakedOpStates of ops that can be drawn together */ struct MergedBakedOpList { const BakedOpState*const* states; size_t count; int clipSideFlags; Rect clip; }; /** * Holds the resolved clip, transform, and bounds of a recordedOp, when replayed with a snapshot */ class ResolvedRenderState { public: ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke); // Constructor for unbounded ops *with* transform/clip ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot, const Matrix4& localTransform, const ClipBase* localClip); // Constructor for unbounded ops without transform/clip (namely shadows) ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot); // Constructor for primitive ops provided clip, and no transform ResolvedRenderState(const ClipRect* viewportRect, const Rect& dstRect); Rect computeLocalSpaceClip() const { Matrix4 inverse; inverse.loadInverse(transform); Rect outClip(clipRect()); inverse.mapRect(outClip); return outClip; } const Rect& clipRect() const { return clipState->rect; } bool requiresClip() const { return clipSideFlags != OpClipSideFlags::None || CC_UNLIKELY(clipState->mode != ClipMode::Rectangle); } // returns the clip if it's needed to draw the operation, otherwise nullptr const ClipBase* getClipIfNeeded() const { return requiresClip() ? clipState : nullptr; } Matrix4 transform; const ClipBase* clipState = nullptr; Rect clippedBounds; int clipSideFlags = 0; const SkPath* localProjectionPathMask = nullptr; bool opaqueOverClippedBounds = false; }; /** * Self-contained op wrapper, containing all resolved state required to draw the op. * * Stashed pointers within all point to longer lived objects, with no ownership implied. */ class BakedOpState { public: static BakedOpState* tryConstruct(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp); static BakedOpState* tryConstructUnbounded(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp); enum class StrokeBehavior { // stroking is forced, regardless of style on paint (such as for lines) Forced, // stroking is defined by style on paint StyleDefined, }; static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior); static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator, Snapshot& snapshot, const ShadowOp* shadowOpPtr); static BakedOpState* directConstruct(LinearAllocator& allocator, const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp); // Set opaqueOverClippedBounds. If this method isn't called, the op is assumed translucent. void setupOpacity(const SkPaint* paint); // computed state: ResolvedRenderState computedState; // simple state (straight pointer/value storage): const float alpha; const RoundRectClipState* roundRectClipState; const RecordedOp* op; private: friend class LinearAllocator; BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke) : computedState(allocator, snapshot, recordedOp, expandForStroke) , alpha(snapshot.alpha) , roundRectClipState(snapshot.roundRectClipState) , op(&recordedOp) {} // TODO: fix this brittleness BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp) : computedState(allocator, snapshot, recordedOp.localMatrix, recordedOp.localClip) , alpha(snapshot.alpha) , roundRectClipState(snapshot.roundRectClipState) , op(&recordedOp) {} BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const ShadowOp* shadowOpPtr) : computedState(allocator, snapshot) , alpha(snapshot.alpha) , roundRectClipState(snapshot.roundRectClipState) , op(shadowOpPtr) {} BakedOpState(const ClipRect* clipRect, const Rect& dstRect, const RecordedOp& recordedOp) : computedState(clipRect, dstRect) , alpha(1.0f) , roundRectClipState(nullptr) , op(&recordedOp) {} }; }; // namespace uirenderer }; // namespace android #endif // ANDROID_HWUI_BAKED_OP_STATE_H