910e62b5创建于 1月15日历史提交
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CC_PAINT_DRAW_LOOPER_H_
#define CC_PAINT_DRAW_LOOPER_H_

#include <memory>
#include <vector>

#include "base/containers/adapters.h"
#include "cc/paint/paint_export.h"
#include "third_party/skia/include/core/SkBlendMode.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkPoint.h"
#include "third_party/skia/include/core/SkRefCnt.h"

class SkPaint;

namespace cc {

// Optional collection of modifiers to paint/canvas to facilitate drawing
// a given primitive multiple times. Often this is used for shadows.
class CC_PAINT_EXPORT DrawLooper : public SkRefCnt {
 public:
  enum Flags {
    // If set, apply layer's offset after the canvas' transformation matrix.
    // If clear, pre-translate with layer's offset
    kPostTransformFlag = 1 << 0,

    // If set, set the paint's alpha to opaque
    kOverrideAlphaFlag = 1 << 1,

    // If set, ignore all modifiers but still translate using layer's offset
    kDontModifyPaintFlag = 1 << 2,
  };

  ~DrawLooper() override;

  //  The callback will be invoked for each "layer" in the looper, each time
  //  with a modified canvas and paint (depending on what the looper wanted
  //  to change). These can each be drawn directly, as the looper will callback
  //  logically bottom to top visually.
  template <typename DrawProc>
  void Apply(SkCanvas* canvas, const SkPaint& paint, DrawProc proc) const {
    // Our array is stored top to bottom
    //  e.g. layers_[0] is the top (will be drawn last)
    //       layers_[N-1] is on bottom, and will be drawn first
    //
    //  Hence, since we must draw in painter's order (bottom to top), we
    //  walk the array in reverse.
    //
    //  Each time through the loop, we make a copy of the draw's paint, modify
    //  it as indicated by the layer info, modify the canvas' translate, and
    //  then call back to issue the actual draw.
    for (const Layer& layer : base::Reversed(layers_)) {
      SkAutoCanvasRestore acr(canvas, true);
      SkPaint p(paint);
      layer.Apply(canvas, &p);
      proc(canvas, p);
    }
  }

  bool EqualsForTesting(const DrawLooper& other) const;

 private:
  // Keep this in sync with the fields in Flags
  // Used to mask out illegal bits when constructing Layer
  enum {
    kAllFlagsMask =
        kPostTransformFlag | kOverrideAlphaFlag | kDontModifyPaintFlag,
  };

  struct Layer {
    SkPoint offset;
    float blur_sigma;
    SkColor4f color;
    uint32_t flags;

    bool operator==(const Layer& other) const = default;

    void Apply(SkCanvas* canvas, SkPaint* paint) const;
  };
  std::vector<Layer> layers_;

  explicit DrawLooper(std::vector<Layer> l);

  void UpdateForLayer(const Layer& layer,
                      SkCanvas* canvas,
                      SkPaint* paint) const;

  friend class DrawLooperBuilder;
  friend class PaintOpReader;
  friend class PaintOpWriter;
};

class CC_PAINT_EXPORT DrawLooperBuilder {
 public:
  DrawLooperBuilder();
  ~DrawLooperBuilder();

  void AddUnmodifiedContent(bool add_on_top = false);
  void AddShadow(SkPoint offset,
                 float blur_sigma,
                 SkColor4f color,
                 uint32_t flags,
                 bool add_on_top = false);
  sk_sp<DrawLooper> Detach();

 private:
  std::vector<DrawLooper::Layer> layers_;
};

}  // namespace cc

#endif  // CC_PAINT_DRAW_LOOPER_H_