blob: e13f640dca2d0103aae08faf6ac4452577700780 [file] [log] [blame]
// Copyright 2013 The Flutter 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 "flutter/display_list/display_list_utils.h"
#include <math.h>
#include <optional>
#include <type_traits>
#include "flutter/display_list/display_list_blend_mode.h"
#include "flutter/display_list/display_list_canvas_dispatcher.h"
#include "flutter/fml/logging.h"
#include "third_party/skia/include/core/SkMaskFilter.h"
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkRSXform.h"
#include "third_party/skia/include/core/SkTextBlob.h"
#include "third_party/skia/include/utils/SkShadowUtils.h"
namespace flutter {
// clang-format off
constexpr float kInvertColorMatrix[20] = {
-1.0, 0, 0, 1.0, 0,
0, -1.0, 0, 1.0, 0,
0, 0, -1.0, 1.0, 0,
1.0, 1.0, 1.0, 1.0, 0
};
// clang-format on
void SkPaintDispatchHelper::save_opacity(SkScalar child_opacity) {
save_stack_.emplace_back(opacity_);
set_opacity(child_opacity);
}
void SkPaintDispatchHelper::restore_opacity() {
if (save_stack_.empty()) {
return;
}
set_opacity(save_stack_.back().opacity);
save_stack_.pop_back();
}
void SkPaintDispatchHelper::setAntiAlias(bool aa) {
paint_.setAntiAlias(aa);
}
void SkPaintDispatchHelper::setDither(bool dither) {
paint_.setDither(dither);
}
void SkPaintDispatchHelper::setInvertColors(bool invert) {
invert_colors_ = invert;
paint_.setColorFilter(makeColorFilter());
}
void SkPaintDispatchHelper::setStrokeCap(DlStrokeCap cap) {
paint_.setStrokeCap(ToSk(cap));
}
void SkPaintDispatchHelper::setStrokeJoin(DlStrokeJoin join) {
paint_.setStrokeJoin(ToSk(join));
}
void SkPaintDispatchHelper::setStyle(DlDrawStyle style) {
paint_.setStyle(ToSk(style));
}
void SkPaintDispatchHelper::setStrokeWidth(SkScalar width) {
paint_.setStrokeWidth(width);
}
void SkPaintDispatchHelper::setStrokeMiter(SkScalar limit) {
paint_.setStrokeMiter(limit);
}
void SkPaintDispatchHelper::setColor(DlColor color) {
current_color_ = color;
paint_.setColor(color);
if (has_opacity()) {
paint_.setAlphaf(paint_.getAlphaf() * opacity());
}
}
void SkPaintDispatchHelper::setBlendMode(DlBlendMode mode) {
paint_.setBlendMode(ToSk(mode));
}
void SkPaintDispatchHelper::setBlender(sk_sp<SkBlender> blender) {
paint_.setBlender(blender);
}
void SkPaintDispatchHelper::setColorSource(const DlColorSource* source) {
paint_.setShader(source ? source->skia_object() : nullptr);
}
void SkPaintDispatchHelper::setImageFilter(const DlImageFilter* filter) {
paint_.setImageFilter(filter ? filter->skia_object() : nullptr);
}
void SkPaintDispatchHelper::setColorFilter(const DlColorFilter* filter) {
color_filter_ = filter ? filter->shared() : nullptr;
paint_.setColorFilter(makeColorFilter());
}
void SkPaintDispatchHelper::setPathEffect(const DlPathEffect* effect) {
paint_.setPathEffect(effect ? effect->skia_object() : nullptr);
}
void SkPaintDispatchHelper::setMaskFilter(const DlMaskFilter* filter) {
paint_.setMaskFilter(filter ? filter->skia_object() : nullptr);
}
sk_sp<SkColorFilter> SkPaintDispatchHelper::makeColorFilter() const {
if (!invert_colors_) {
return color_filter_ ? color_filter_->skia_object() : nullptr;
}
sk_sp<SkColorFilter> invert_filter =
SkColorFilters::Matrix(kInvertColorMatrix);
if (color_filter_) {
invert_filter = invert_filter->makeComposed(color_filter_->skia_object());
}
return invert_filter;
}
void RectBoundsAccumulator::accumulate(const SkRect& r, int index) {
if (r.fLeft < r.fRight && r.fTop < r.fBottom) {
rect_.accumulate(r.fLeft, r.fTop);
rect_.accumulate(r.fRight, r.fBottom);
}
}
void RectBoundsAccumulator::save() {
saved_rects_.emplace_back(rect_);
rect_ = AccumulationRect();
}
void RectBoundsAccumulator::restore() {
if (!saved_rects_.empty()) {
SkRect layer_bounds = rect_.bounds();
pop_and_accumulate(layer_bounds, nullptr);
}
}
bool RectBoundsAccumulator::restore(
std::function<bool(const SkRect&, SkRect&)> mapper,
const SkRect* clip) {
bool success = true;
if (!saved_rects_.empty()) {
SkRect layer_bounds = rect_.bounds();
success = mapper(layer_bounds, layer_bounds);
pop_and_accumulate(layer_bounds, clip);
}
return success;
}
void RectBoundsAccumulator::pop_and_accumulate(SkRect& layer_bounds,
const SkRect* clip) {
FML_DCHECK(!saved_rects_.empty());
rect_ = saved_rects_.back();
saved_rects_.pop_back();
if (clip == nullptr || layer_bounds.intersect(*clip)) {
accumulate(layer_bounds, -1);
}
}
RectBoundsAccumulator::AccumulationRect::AccumulationRect() {
min_x_ = std::numeric_limits<SkScalar>::infinity();
min_y_ = std::numeric_limits<SkScalar>::infinity();
max_x_ = -std::numeric_limits<SkScalar>::infinity();
max_y_ = -std::numeric_limits<SkScalar>::infinity();
}
void RectBoundsAccumulator::AccumulationRect::accumulate(SkScalar x,
SkScalar y) {
if (min_x_ > x) {
min_x_ = x;
}
if (min_y_ > y) {
min_y_ = y;
}
if (max_x_ < x) {
max_x_ = x;
}
if (max_y_ < y) {
max_y_ = y;
}
}
SkRect RectBoundsAccumulator::AccumulationRect::bounds() const {
return (max_x_ >= min_x_ && max_y_ >= min_y_)
? SkRect::MakeLTRB(min_x_, min_y_, max_x_, max_y_)
: SkRect::MakeEmpty();
}
void RTreeBoundsAccumulator::accumulate(const SkRect& r, int index) {
if (r.fLeft < r.fRight && r.fTop < r.fBottom) {
rects_.push_back(r);
rect_indices_.push_back(index);
}
}
void RTreeBoundsAccumulator::save() {
saved_offsets_.push_back(rects_.size());
}
void RTreeBoundsAccumulator::restore() {
if (saved_offsets_.empty()) {
return;
}
saved_offsets_.pop_back();
}
bool RTreeBoundsAccumulator::restore(
std::function<bool(const SkRect& original, SkRect& modified)> map,
const SkRect* clip) {
if (saved_offsets_.empty()) {
return true;
}
size_t previous_size = saved_offsets_.back();
saved_offsets_.pop_back();
bool success = true;
for (size_t i = previous_size; i < rects_.size(); i++) {
SkRect original = rects_[i];
if (!map(original, original)) {
success = false;
}
if (clip == nullptr || original.intersect(*clip)) {
rect_indices_[previous_size] = rect_indices_[i];
rects_[previous_size] = original;
previous_size++;
}
}
rects_.resize(previous_size);
rect_indices_.resize(previous_size);
return success;
}
SkRect RTreeBoundsAccumulator::bounds() const {
FML_DCHECK(saved_offsets_.empty());
RectBoundsAccumulator accumulator;
for (auto& rect : rects_) {
accumulator.accumulate(rect, 0);
}
return accumulator.bounds();
}
sk_sp<DlRTree> RTreeBoundsAccumulator::rtree() const {
FML_DCHECK(saved_offsets_.empty());
return sk_make_sp<DlRTree>(rects_.data(), rects_.size(), rect_indices_.data(),
[](int id) { return id >= 0; });
}
} // namespace flutter