f2d90659ff
Sksg::Merge needs to preserve the fill type of the first path appended in the stack. Theoretically, one could append multiple paths with different fill types using sksg::Merge, but in practice Skottie should never do that (append mode with invertible shape only used for the very first mask in a stack). TBR= Change-Id: Ie9ac9187cc1c8baaae2bef439313a7700407f04a Reviewed-on: https://skia-review.googlesource.com/c/skia/+/303582 Reviewed-by: Florin Malita <fmalita@google.com> Commit-Queue: Florin Malita <fmalita@google.com>
112 lines
2.5 KiB
C++
112 lines
2.5 KiB
C++
/*
|
|
* Copyright 2017 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "modules/sksg/include/SkSGMerge.h"
|
|
|
|
#include "include/core/SkCanvas.h"
|
|
#include "include/pathops/SkPathOps.h"
|
|
|
|
namespace sksg {
|
|
|
|
Merge::Merge(std::vector<Rec>&& recs)
|
|
: fRecs(std::move(recs)) {
|
|
for (const auto& rec : fRecs) {
|
|
this->observeInval(rec.fGeo);
|
|
}
|
|
}
|
|
|
|
Merge::~Merge() {
|
|
for (const auto& rec : fRecs) {
|
|
this->unobserveInval(rec.fGeo);
|
|
}
|
|
}
|
|
|
|
void Merge::onClip(SkCanvas* canvas, bool antiAlias) const {
|
|
canvas->clipPath(fMerged, SkClipOp::kIntersect, antiAlias);
|
|
}
|
|
|
|
void Merge::onDraw(SkCanvas* canvas, const SkPaint& paint) const {
|
|
canvas->drawPath(fMerged, paint);
|
|
}
|
|
|
|
bool Merge::onContains(const SkPoint& p) const {
|
|
return fMerged.contains(p.x(), p.y());
|
|
}
|
|
|
|
SkPath Merge::onAsPath() const {
|
|
return fMerged;
|
|
}
|
|
|
|
static SkPathOp mode_to_op(Merge::Mode mode) {
|
|
switch (mode) {
|
|
case Merge::Mode::kUnion:
|
|
return kUnion_SkPathOp;
|
|
case Merge::Mode::kIntersect:
|
|
return kIntersect_SkPathOp;
|
|
case Merge::Mode::kDifference:
|
|
return kDifference_SkPathOp;
|
|
case Merge::Mode::kReverseDifference:
|
|
return kReverseDifference_SkPathOp;
|
|
case Merge::Mode::kXOR:
|
|
return kXOR_SkPathOp;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return kUnion_SkPathOp;
|
|
}
|
|
|
|
SkRect Merge::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
|
|
SkASSERT(this->hasInval());
|
|
|
|
SkOpBuilder builder;
|
|
|
|
fMerged.reset();
|
|
bool in_builder = false;
|
|
|
|
auto append = [&](const SkPath& path) {
|
|
if (in_builder) {
|
|
builder.resolve(&fMerged);
|
|
in_builder = false;
|
|
}
|
|
|
|
if (fMerged.isEmpty()) {
|
|
// First merge path determines the fill type.
|
|
fMerged = path;
|
|
} else {
|
|
fMerged.addPath(path);
|
|
}
|
|
};
|
|
|
|
for (const auto& rec : fRecs) {
|
|
rec.fGeo->revalidate(ic, ctm);
|
|
|
|
if (rec.fMode == Mode::kMerge) {
|
|
// Merge (append) is not supported by SkOpBuidler.
|
|
append(rec.fGeo->asPath());
|
|
continue;
|
|
}
|
|
|
|
if (!in_builder) {
|
|
builder.add(fMerged, kUnion_SkPathOp);
|
|
in_builder = true;
|
|
}
|
|
|
|
builder.add(rec.fGeo->asPath(), mode_to_op(rec.fMode));
|
|
}
|
|
|
|
if (in_builder) {
|
|
builder.resolve(&fMerged);
|
|
}
|
|
|
|
fMerged.shrinkToFit();
|
|
|
|
return fMerged.computeTightBounds();
|
|
}
|
|
|
|
} // namespace sksg
|