blob: 170a67cbffa926082f8681ea7c5def0ca7ee1da3 [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.
#ifndef FLUTTER_DISPLAY_LIST_GEOMETRY_DL_REGION_H_
#define FLUTTER_DISPLAY_LIST_GEOMETRY_DL_REGION_H_
#include "third_party/skia/include/core/SkRect.h"
#include <memory>
#include <vector>
namespace flutter {
/// Represents a region as a collection of non-overlapping rectangles.
/// Implements a subset of SkRegion functionality optimized for quickly
/// converting set of overlapping rectangles to non-overlapping rectangles.
class DlRegion {
public:
/// Creates an empty region.
DlRegion() = default;
/// Creates region by bulk adding the rectangles.
/// Matches SkRegion::op(rect, SkRegion::kUnion_Op) behavior.
explicit DlRegion(const std::vector<SkIRect>& rects);
/// Creates region covering area of a rectangle.
explicit DlRegion(const SkIRect& rect);
DlRegion(const DlRegion&) = default;
DlRegion(DlRegion&&) = default;
DlRegion& operator=(const DlRegion&) = default;
DlRegion& operator=(DlRegion&&) = default;
/// Creates union region of region a and b.
/// Matches SkRegion a; a.op(b, SkRegion::kUnion_Op) behavior.
static DlRegion MakeUnion(const DlRegion& a, const DlRegion& b);
/// Creates intersection region of region a and b.
/// Matches SkRegion a; a.op(b, SkRegion::kIntersect_Op) behavior.
static DlRegion MakeIntersection(const DlRegion& a, const DlRegion& b);
/// Returns list of non-overlapping rectangles that cover current region.
/// If |deband| is false, each span line will result in separate rectangles,
/// closely matching SkRegion::Iterator behavior.
/// If |deband| is true, matching rectangles from adjacent span lines will be
/// merged into single rectangle.
std::vector<SkIRect> getRects(bool deband = true) const;
/// Returns maximum and minimum axis values of rectangles in this region.
/// If region is empty returns SKIRect::MakeEmpty().
const SkIRect& bounds() const { return bounds_; }
/// Returns whether this region intersects with a rectangle.
bool intersects(const SkIRect& rect) const;
/// Returns whether this region intersects with another region.
bool intersects(const DlRegion& region) const;
/// Returns true if region is empty (contains no rectangles).
bool isEmpty() const { return lines_.empty(); }
/// Returns true if region is not empty and contains more than one rectangle.
bool isComplex() const;
/// Returns true if region can be represented by single rectangle or is
/// empty.
bool isSimple() const { return !isComplex(); }
private:
typedef std::uint32_t SpanChunkHandle;
struct Span {
int32_t left;
int32_t right;
Span() = default;
Span(int32_t left, int32_t right) : left(left), right(right) {}
};
/// Holds spans for the region. Having custom allocated memory that doesn't
/// do zero initialization every time the buffer gets resized improves
/// performance measurably.
class SpanBuffer {
public:
SpanBuffer() = default;
SpanBuffer(const SpanBuffer&);
SpanBuffer(SpanBuffer&& m);
SpanBuffer& operator=(const SpanBuffer&);
SpanBuffer& operator=(SpanBuffer&& m);
void reserve(size_t capacity);
size_t capacity() const { return capacity_; }
SpanChunkHandle storeChunk(const Span* begin, const Span* end);
size_t getChunkSize(SpanChunkHandle handle) const;
void getSpans(SpanChunkHandle handle,
const DlRegion::Span*& begin,
const DlRegion::Span*& end) const;
~SpanBuffer();
private:
void setChunkSize(SpanChunkHandle handle, size_t size);
size_t capacity_ = 0;
size_t size_ = 0;
// Spans for the region chunks. First span in each chunk contains the
// chunk size.
Span* spans_ = nullptr;
};
struct SpanLine {
int32_t top;
int32_t bottom;
SpanChunkHandle chunk_handle;
};
void setRects(const std::vector<SkIRect>& rects);
void appendLine(int32_t top,
int32_t bottom,
const Span* begin,
const Span* end);
void appendLine(int32_t top,
int32_t bottom,
const SpanBuffer& buffer,
SpanChunkHandle handle) {
const Span *begin, *end;
buffer.getSpans(handle, begin, end);
appendLine(top, bottom, begin, end);
}
typedef std::vector<Span> SpanVec;
SpanLine makeLine(int32_t top, int32_t bottom, const SpanVec&);
SpanLine makeLine(int32_t top,
int32_t bottom,
const Span* begin,
const Span* end);
static size_t unionLineSpans(std::vector<Span>& res,
const SpanBuffer& a_buffer,
SpanChunkHandle a_handle,
const SpanBuffer& b_buffer,
SpanChunkHandle b_handle);
static size_t intersectLineSpans(std::vector<Span>& res,
const SpanBuffer& a_buffer,
SpanChunkHandle a_handle,
const SpanBuffer& b_buffer,
SpanChunkHandle b_handle);
bool spansEqual(SpanLine& line, const Span* begin, const Span* end) const;
static bool spansIntersect(const Span* begin1,
const Span* end1,
const Span* begin2,
const Span* end2);
static void getIntersectionIterators(
const std::vector<SpanLine>& a_lines,
const std::vector<SpanLine>& b_lines,
std::vector<SpanLine>::const_iterator& a_it,
std::vector<SpanLine>::const_iterator& b_it);
std::vector<SpanLine> lines_;
SkIRect bounds_ = SkIRect::MakeEmpty();
SpanBuffer span_buffer_;
};
} // namespace flutter
#endif // FLUTTER_DISPLAY_LIST_GEOMETRY_DL_REGION_H_