Region.kt

/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

@file:Suppress("NOTHING_TO_INLINE")

package androidx.core.graphics

import android.graphics.Point
import android.graphics.Rect
import android.graphics.Region
import android.graphics.RegionIterator

/**
 * Return true if the region contains the specified [Point].
 */
public inline operator fun Region.contains(p: Point): Boolean = contains(p.x, p.y)

/**
 * Return the union of this region and the specified [Rect] as a new region.
 */
public inline operator fun Region.plus(r: Rect): Region {
    return Region(this).apply {
        union(r)
    }
}

/**
 * Return the union of this region and the specified region as a new region.
 */
public inline operator fun Region.plus(r: Region): Region {
    return Region(this).apply {
        op(r, Region.Op.UNION)
    }
}

/**
 * Return the difference of this region and the specified [Rect] as a new region.
 */
public inline operator fun Region.minus(r: Rect): Region {
    return Region(this).apply {
        op(r, Region.Op.DIFFERENCE)
    }
}

/**
 * Return the difference of this region and the specified region as a new region.
 */
public inline operator fun Region.minus(r: Region): Region {
    return Region(this).apply {
        op(r, Region.Op.DIFFERENCE)
    }
}

/**
 * Returns the negation of this region as a new region.
 */
public inline operator fun Region.unaryMinus(): Region {
    return Region(bounds).apply {
        op(this@unaryMinus, Region.Op.DIFFERENCE)
    }
}

/**
 * Returns the negation of this region as a new region.
 */
public inline operator fun Region.not(): Region = -this

/**
 * Return the union of this region and the specified [Rect] as a new region.
 */
public inline infix fun Region.or(r: Rect): Region = this + r

/**
 * Return the union of this region and the specified region as a new region.
 */
public inline infix fun Region.or(r: Region): Region = this + r

/**
 * Return the intersection of this region and the specified [Rect] as a new region.
 */
public inline infix fun Region.and(r: Rect): Region {
    return Region(this).apply {
        op(r, Region.Op.INTERSECT)
    }
}

/**
 * Return the intersection of this region and the specified region as a new region.
 */
public inline infix fun Region.and(r: Region): Region {
    return Region(this).apply {
        op(r, Region.Op.INTERSECT)
    }
}

/**
 * Return the union minus the intersection of this region and the specified [Rect]
 * as a new region.
 */
public inline infix fun Region.xor(r: Rect): Region {
    return Region(this).apply {
        op(r, Region.Op.XOR)
    }
}

/**
 * Return the union minus the intersection of this region and the specified region
 * as a new region.
 */
public inline infix fun Region.xor(r: Region): Region {
    return Region(this).apply {
        op(r, Region.Op.XOR)
    }
}

/** Performs the given action on each rect in this region. */
public inline fun Region.forEach(action: (rect: Rect) -> Unit) {
    val iterator = RegionIterator(this)
    while (true) {
        val r = Rect()
        if (!iterator.next(r)) {
            break
        }
        action(r)
    }
}

/** Returns an [Iterator] over the rects in this region. */
public operator fun Region.iterator(): Iterator<Rect> = object : Iterator<Rect> {
    private val iterator = RegionIterator(this@iterator)
    private val rect = Rect()
    private var hasMore = iterator.next(rect)

    override fun hasNext() = hasMore

    override fun next(): Rect {
        if (hasMore) {
            val r = Rect(rect)
            hasMore = iterator.next(rect)
            return r
        }
        throw IndexOutOfBoundsException()
    }
}