Skip to content

Commit

Permalink
Add custom loopers for shadows
Browse files Browse the repository at this point in the history
SkDrawLooper is unused and untested in Skia, so moving the functionality
into Chrome.

Bug: skia:8672
Change-Id: I412ff1f2fe51c87cbe3b173efb0fc6e56df4dabb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2679292
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
Reviewed-by: vmpstr <vmpstr@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Reviewed-by: Aaron Krajeski <aaronhk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#853590}
  • Loading branch information
reed-at-google authored and Chromium LUCI CQ committed Feb 12, 2021
1 parent 122ea27 commit efacd53
Show file tree
Hide file tree
Showing 39 changed files with 398 additions and 169 deletions.
1 change: 0 additions & 1 deletion ash/magnifier/magnifier_glass.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

#include "ash/shell.h"
#include "base/check_op.h"
#include "third_party/skia/include/core/SkDrawLooper.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/paint_recorder.h"
#include "ui/gfx/shadow_value.h"
Expand Down
1 change: 0 additions & 1 deletion ash/system/tray/tray_detailed_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include "ash/system/tray/tri_view.h"
#include "base/containers/adapters.h"
#include "base/strings/string_number_conversions.h"
#include "third_party/skia/include/core/SkDrawLooper.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/compositor/clip_recorder.h"
Expand Down
2 changes: 2 additions & 0 deletions cc/paint/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ cc_component("paint") {
"display_item_list.h",
"draw_image.cc",
"draw_image.h",
"draw_looper.cc",
"draw_looper.h",
"element_id.cc",
"element_id.h",
"filter_operation.cc",
Expand Down
90 changes: 90 additions & 0 deletions cc/paint/draw_looper.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <utility>

#include "cc/paint/draw_looper.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/core/SkMaskFilter.h"
#include "third_party/skia/include/core/SkPaint.h"

namespace cc {

bool DrawLooper::DrawLooper::Layer::operator==(const Layer& other) const {
return offset == other.offset && blurSigma == other.blurSigma &&
color == other.color && flags == other.flags;
}

DrawLooper::DrawLooper(std::vector<Layer> l) : layers_(std::move(l)) {}
DrawLooper::~DrawLooper() = default;

void DrawLooper::Layer::Apply(SkCanvas* canvas, SkPaint* paint) const {
if (!(flags & kDontModifyPaintFlag)) {
if (flags & kOverrideAlphaFlag)
paint->setAlpha(0xFF);

if (blurSigma > 0)
paint->setMaskFilter(SkMaskFilter::MakeBlur(
kNormal_SkBlurStyle, blurSigma, !(flags & kPostTransformFlag)));

paint->setColorFilter(SkColorFilters::Blend(color, SkBlendMode::kSrcIn));
}

if (flags & kPostTransformFlag)
canvas->setMatrix(
canvas->getLocalToDevice().postTranslate(offset.fX, offset.fY));
else
canvas->translate(offset.fX, offset.fY);
}

bool DrawLooper::operator==(const DrawLooper& other) const {
return layers_ == other.layers_;
}

// static
size_t DrawLooper::GetSerializedSize(const DrawLooper* looper) {
size_t size = sizeof(bool);
if (!looper)
return size;

size_t count = looper->layers_.size();
size += sizeof(count);
if (count == 0)
return size;

auto layer = looper->layers_.begin();

size_t layer_size = sizeof(layer->offset.fX) + sizeof(layer->offset.fY) +
sizeof(layer->blurSigma) + sizeof(layer->color) +
sizeof(layer->flags);

return size + count * layer_size;
}

DrawLooperBuilder::DrawLooperBuilder() = default;
DrawLooperBuilder::~DrawLooperBuilder() = default;

void DrawLooperBuilder::AddUnmodifiedContent(bool addOnTop) {
AddShadow({0, 0}, 0, 0, DrawLooper::kDontModifyPaintFlag, addOnTop);
}

void DrawLooperBuilder::AddShadow(SkPoint offset,
float blurSigma,
SkColor color,
uint32_t flags,
bool addOnTop) {
const DrawLooper::Layer layer = {offset, blurSigma, color,
flags & DrawLooper::kAllFlagsMask};
if (addOnTop)
layers_.insert(layers_.begin(), layer);
else
layers_.push_back(layer);
}

sk_sp<DrawLooper> DrawLooperBuilder::Detach() {
return sk_sp<DrawLooper>(new DrawLooper(std::move(layers_)));
}

} // namespace cc
125 changes: 125 additions & 0 deletions cc/paint/draw_looper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Copyright 2021 The Chromium Authors. All rights reserved.
// 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/optional.h"
#include "base/stl_util.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 SkCanvas;
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 the layer's alpha
// If clear, 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 (auto it = layers_.rbegin(); it != layers_.rend(); ++it) {
SkAutoCanvasRestore acr(canvas, true);
SkPaint p(paint);
it->Apply(canvas, &p);
proc(canvas, p);
}
}

bool operator==(const DrawLooper& other) const;
bool operator!=(const DrawLooper& other) const { return !(*this == other); }

static size_t GetSerializedSize(const DrawLooper* looper);

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 blurSigma;
SkColor color;
uint32_t flags;

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

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 addOnTop = false);
void AddShadow(SkPoint offset,
float blurSigma,
SkColor color,
uint32_t flags,
bool addOnTop = false);
sk_sp<DrawLooper> Detach();

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

} // namespace cc

#endif // CC_PAINT_DRAW_LOOPER_H_
22 changes: 12 additions & 10 deletions cc/paint/paint_flags.cc
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ bool PaintFlags::IsValid() const {
return PaintOp::IsValidPaintFlagsSkBlendMode(getBlendMode());
}

template <typename T>
bool AreEqual(const T* a, const T* b) {
return (a && b) ? *a == *b : a == b;
}

bool PaintFlags::operator==(const PaintFlags& other) const {
// Can't just ToSkPaint and operator== here as SkPaint does pointer
// comparisons on all the ref'd skia objects on the SkPaint, which
Expand Down Expand Up @@ -181,20 +186,17 @@ bool PaintFlags::operator==(const PaintFlags& other) const {
other.getColorFilter().get())) {
return false;
}
if (!PaintOp::AreSkFlattenablesEqual(getLooper().get(),
other.getLooper().get())) {

if (!AreEqual(getLooper().get(), other.getLooper().get())) {
return false;
}

if (!getImageFilter() != !other.getImageFilter())
if (!AreEqual(getImageFilter().get(), other.getImageFilter().get())) {
return false;
if (getImageFilter() && *getImageFilter() != *other.getImageFilter())
}
if (!AreEqual(getShader(), other.getShader())) {
return false;
}

if (!getShader() != !other.getShader())
return false;
if (getShader() && *getShader() != *other.getShader())
return false;
return true;
}

Expand All @@ -212,7 +214,7 @@ size_t PaintFlags::GetSerializedSize() const {
PaintOpWriter::Alignment() +
PaintOpWriter::GetFlattenableSize(color_filter_.get()) +
PaintOpWriter::Alignment() +
PaintOpWriter::GetFlattenableSize(draw_looper_.get()) +
DrawLooper::GetSerializedSize(draw_looper_.get()) +
PaintFilter::GetFilterSize(image_filter_.get()) +
PaintShader::GetSerializedSize(shader_.get());
}
Expand Down
12 changes: 6 additions & 6 deletions cc/paint/paint_flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
#define CC_PAINT_PAINT_FLAGS_H_

#include "base/compiler_specific.h"
#include "cc/paint/draw_looper.h"
#include "cc/paint/paint_export.h"
#include "cc/paint/paint_shader.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/core/SkDrawLooper.h"
#include "third_party/skia/include/core/SkImageFilter.h"
#include "third_party/skia/include/core/SkMaskFilter.h"
#include "third_party/skia/include/core/SkPaint.h"
Expand Down Expand Up @@ -139,10 +139,10 @@ class CC_PAINT_EXPORT PaintFlags {
}
void setImageFilter(sk_sp<PaintFilter> filter);

ALWAYS_INLINE const sk_sp<SkDrawLooper>& getLooper() const {
ALWAYS_INLINE const sk_sp<DrawLooper>& getLooper() const {
return draw_looper_;
}
ALWAYS_INLINE void setLooper(sk_sp<SkDrawLooper> looper) {
ALWAYS_INLINE void setLooper(sk_sp<DrawLooper> looper) {
draw_looper_ = std::move(looper);
}

Expand All @@ -162,8 +162,8 @@ class CC_PAINT_EXPORT PaintFlags {
template <typename Proc>
void DrawToSk(SkCanvas* canvas, Proc proc) const {
SkPaint paint = ToSkPaint();
if (const sk_sp<SkDrawLooper>& looper = getLooper())
looper->apply(canvas, paint, proc);
if (const sk_sp<DrawLooper>& looper = getLooper())
looper->Apply(canvas, paint, proc);
else
proc(canvas, paint);
}
Expand All @@ -184,7 +184,7 @@ class CC_PAINT_EXPORT PaintFlags {
sk_sp<PaintShader> shader_;
sk_sp<SkMaskFilter> mask_filter_;
sk_sp<SkColorFilter> color_filter_;
sk_sp<SkDrawLooper> draw_looper_;
sk_sp<DrawLooper> draw_looper_;
sk_sp<PaintFilter> image_filter_;

// Match(ish) SkPaint defaults. SkPaintDefaults is not public, so this
Expand Down
Loading

0 comments on commit efacd53

Please sign in to comment.