Add MultiDisplayList + memory leak fixes

MultiDisplayList can contain either a SkiaDisplayList
or a CanvasOpBuffer. However DisplayList itself
still points to the SkiaDisplayList-only wrapper
to avoid any std::variant or std::visit overhead
just yet.

Also fixes a memory leak in CanvasFrontend from an
uninitialized std::optional and a few minor leaks
in unit tests.

Test: build & hwui_unit passes

Fixes: 184680809
Change-Id: Ifa6b723b6456f5d3eeac1201e76f337250103d6f
Merged-In: Ifa6b723b6456f5d3eeac1201e76f337250103d6f
(cherry picked from commit d34d6cec97c8f1be92f676aeb79c83d57cf8c6ba)
diff --git a/libs/hwui/canvas/CanvasOpBuffer.h b/libs/hwui/canvas/CanvasOpBuffer.h
index 07e079a..af797ca 100644
--- a/libs/hwui/canvas/CanvasOpBuffer.h
+++ b/libs/hwui/canvas/CanvasOpBuffer.h
@@ -19,10 +19,17 @@
 #include <SkMatrix.h>
 
 #include "CanvasOpTypes.h"
+#include "CanvasTransform.h"
 #include "OpBuffer.h"
+#include "TreeInfo.h"
+#include "private/hwui/WebViewFunctor.h"
+
+#include <functional>
 
 namespace android::uirenderer {
 
+class RenderNode;
+
 template <CanvasOpType T>
 struct CanvasOp;
 
@@ -53,12 +60,74 @@
 };
 
 extern template class OpBuffer<CanvasOpType, CanvasOpContainer>;
-class CanvasOpBuffer final : public OpBuffer<CanvasOpType, CanvasOpContainer> {
+class CanvasOpBuffer final : private OpBuffer<CanvasOpType, CanvasOpContainer> {
+private:
+    using SUPER = OpBuffer<CanvasOpType, CanvasOpContainer>;
+
 public:
+    // Expose select superclass methods publicly
+    using SUPER::for_each;
+    using SUPER::size;
+    using SUPER::resize;
+
     template <CanvasOpType T>
     void push(CanvasOp<T>&& op) {
         push_container(CanvasOpContainer<T>(std::move(op)));
     }
+
+    template <CanvasOpType T>
+    void push_container(CanvasOpContainer<T>&& op) {
+        if constexpr (IsDrawOp(T)) {
+            mHas.content = true;
+        }
+        if constexpr (T == CanvasOpType::DrawRenderNode) {
+            mHas.children = true;
+            // use staging property, since recording on UI thread
+            if (op->renderNode->stagingProperties().isProjectionReceiver()) {
+                mHas.projectionReceiver = true;
+            }
+        }
+        SUPER::push_container(std::move(op));
+    }
+
+    void clear() {
+        mHas = Contains{};
+        SUPER::clear();
+    }
+
+    void updateChildren(std::function<void(RenderNode*)> updateFn);
+    bool prepareListAndChildren(
+            TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
+            std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn);
+    void syncContents(const WebViewSyncData& data);
+    void applyColorTransform(ColorTransform transform);
+
+    [[nodiscard]] bool isEmpty() const { return !mHas.content; }
+    [[nodiscard]] bool hasText() const { return mHas.text; }
+    [[nodiscard]] bool hasVectorDrawables() const { return mHas.vectorDrawable; }
+    [[nodiscard]] bool containsProjectionReceiver() const { return mHas.projectionReceiver; }
+    [[nodiscard]] bool hasFunctor() const { return mHas.functor; }
+
+    [[nodiscard]] size_t getUsedSize() const {
+        return size();
+    }
+
+    [[nodiscard]] size_t getAllocatedSize() const {
+        return capacity();
+    }
+
+    void output(std::ostream& output, uint32_t level) const;
+
+private:
+    struct Contains {
+        bool content : 1 = false;
+        bool children : 1 = false;
+        bool projectionReceiver : 1 = false;
+        bool text : 1 = false;
+        bool vectorDrawable : 1 = false;
+        bool functor : 1 = false;
+    };
+    Contains mHas;
 };
 
 }  // namespace android::uirenderer