diff options
Diffstat (limited to 'libs/hwui/ClipArea.cpp')
| -rw-r--r-- | libs/hwui/ClipArea.cpp | 534 | 
1 files changed, 0 insertions, 534 deletions
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp deleted file mode 100644 index 27d93cfa0391..000000000000 --- a/libs/hwui/ClipArea.cpp +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ -#include "ClipArea.h" - -#include "utils/LinearAllocator.h" - -#include <SkPath.h> -#include <limits> -#include <type_traits> - -namespace android { -namespace uirenderer { - -static void handlePoint(Rect& transformedBounds, const Matrix4& transform, float x, float y) { -    Vertex v = {x, y}; -    transform.mapPoint(v.x, v.y); -    transformedBounds.expandToCover(v.x, v.y); -} - -Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform) { -    const float kMinFloat = std::numeric_limits<float>::lowest(); -    const float kMaxFloat = std::numeric_limits<float>::max(); -    Rect transformedBounds = {kMaxFloat, kMaxFloat, kMinFloat, kMinFloat}; -    handlePoint(transformedBounds, transform, r.left, r.top); -    handlePoint(transformedBounds, transform, r.right, r.top); -    handlePoint(transformedBounds, transform, r.left, r.bottom); -    handlePoint(transformedBounds, transform, r.right, r.bottom); -    return transformedBounds; -} - -void ClipBase::dump() const { -    ALOGD("mode %d" RECT_STRING, mode, RECT_ARGS(rect)); -} - -/* - * TransformedRectangle - */ - -TransformedRectangle::TransformedRectangle() {} - -TransformedRectangle::TransformedRectangle(const Rect& bounds, const Matrix4& transform) -        : mBounds(bounds), mTransform(transform) {} - -bool TransformedRectangle::canSimplyIntersectWith(const TransformedRectangle& other) const { -    return mTransform == other.mTransform; -} - -void TransformedRectangle::intersectWith(const TransformedRectangle& other) { -    mBounds.doIntersect(other.mBounds); -} - -bool TransformedRectangle::isEmpty() const { -    return mBounds.isEmpty(); -} - -/* - * RectangleList - */ - -RectangleList::RectangleList() : mTransformedRectanglesCount(0) {} - -bool RectangleList::isEmpty() const { -    if (mTransformedRectanglesCount < 1) { -        return true; -    } - -    for (int i = 0; i < mTransformedRectanglesCount; i++) { -        if (mTransformedRectangles[i].isEmpty()) { -            return true; -        } -    } -    return false; -} - -int RectangleList::getTransformedRectanglesCount() const { -    return mTransformedRectanglesCount; -} - -const TransformedRectangle& RectangleList::getTransformedRectangle(int i) const { -    return mTransformedRectangles[i]; -} - -void RectangleList::setEmpty() { -    mTransformedRectanglesCount = 0; -} - -void RectangleList::set(const Rect& bounds, const Matrix4& transform) { -    mTransformedRectanglesCount = 1; -    mTransformedRectangles[0] = TransformedRectangle(bounds, transform); -} - -bool RectangleList::intersectWith(const Rect& bounds, const Matrix4& transform) { -    TransformedRectangle newRectangle(bounds, transform); - -    // Try to find a rectangle with a compatible transformation -    int index = 0; -    for (; index < mTransformedRectanglesCount; index++) { -        TransformedRectangle& tr(mTransformedRectangles[index]); -        if (tr.canSimplyIntersectWith(newRectangle)) { -            tr.intersectWith(newRectangle); -            return true; -        } -    } - -    // Add it to the list if there is room -    if (index < kMaxTransformedRectangles) { -        mTransformedRectangles[index] = newRectangle; -        mTransformedRectanglesCount += 1; -        return true; -    } - -    // This rectangle list is full -    return false; -} - -Rect RectangleList::calculateBounds() const { -    Rect bounds; -    for (int index = 0; index < mTransformedRectanglesCount; index++) { -        const TransformedRectangle& tr(mTransformedRectangles[index]); -        if (index == 0) { -            bounds = tr.transformedBounds(); -        } else { -            bounds.doIntersect(tr.transformedBounds()); -        } -    } -    return bounds; -} - -static SkPath pathFromTransformedRectangle(const Rect& bounds, const Matrix4& transform) { -    SkPath rectPath; -    SkPath rectPathTransformed; -    rectPath.addRect(bounds.left, bounds.top, bounds.right, bounds.bottom); -    SkMatrix skTransform; -    transform.copyTo(skTransform); -    rectPath.transform(skTransform, &rectPathTransformed); -    return rectPathTransformed; -} - -SkRegion RectangleList::convertToRegion(const SkRegion& clip) const { -    SkRegion rectangleListAsRegion; -    for (int index = 0; index < mTransformedRectanglesCount; index++) { -        const TransformedRectangle& tr(mTransformedRectangles[index]); -        SkPath rectPathTransformed = -                pathFromTransformedRectangle(tr.getBounds(), tr.getTransform()); -        if (index == 0) { -            rectangleListAsRegion.setPath(rectPathTransformed, clip); -        } else { -            SkRegion rectRegion; -            rectRegion.setPath(rectPathTransformed, clip); -            rectangleListAsRegion.op(rectRegion, SkRegion::kIntersect_Op); -        } -    } -    return rectangleListAsRegion; -} - -void RectangleList::transform(const Matrix4& transform) { -    for (int index = 0; index < mTransformedRectanglesCount; index++) { -        mTransformedRectangles[index].transform(transform); -    } -} - -/* - * ClipArea - */ - -ClipArea::ClipArea() : mMode(ClipMode::Rectangle) {} - -/* - * Interface - */ - -void ClipArea::setViewportDimensions(int width, int height) { -    mPostViewportClipObserved = false; -    mViewportBounds.set(0, 0, width, height); -    mClipRect = mViewportBounds; -} - -void ClipArea::setEmpty() { -    onClipUpdated(); -    mMode = ClipMode::Rectangle; -    mClipRect.setEmpty(); -    mClipRegion.setEmpty(); -    mRectangleList.setEmpty(); -} - -void ClipArea::setClip(float left, float top, float right, float bottom) { -    onClipUpdated(); -    mMode = ClipMode::Rectangle; -    mClipRect.set(left, top, right, bottom); -    mClipRegion.setEmpty(); -} - -void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op) { -    if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true; -    if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op; -    onClipUpdated(); -    switch (mMode) { -        case ClipMode::Rectangle: -            rectangleModeClipRectWithTransform(r, transform, op); -            break; -        case ClipMode::RectangleList: -            rectangleListModeClipRectWithTransform(r, transform, op); -            break; -        case ClipMode::Region: -            regionModeClipRectWithTransform(r, transform, op); -            break; -    } -} - -void ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) { -    if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true; -    if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op; -    onClipUpdated(); -    enterRegionMode(); -    mClipRegion.op(region, op); -    onClipRegionUpdated(); -} - -void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform, SkRegion::Op op) { -    if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true; -    if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op; -    onClipUpdated(); -    SkMatrix skTransform; -    transform->copyTo(skTransform); -    SkPath transformed; -    path.transform(skTransform, &transformed); -    SkRegion region; -    regionFromPath(transformed, region); -    enterRegionMode(); -    mClipRegion.op(region, op); -    onClipRegionUpdated(); -} - -/* - * Rectangle mode - */ - -void ClipArea::enterRectangleMode() { -    // Entering rectangle mode discards any -    // existing clipping information from the other modes. -    // The only way this occurs is by a clip setting operation. -    mMode = ClipMode::Rectangle; -} - -void ClipArea::rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, -                                                  SkRegion::Op op) { -    if (op == SkRegion::kReplace_Op && transform->rectToRect()) { -        mClipRect = r; -        transform->mapRect(mClipRect); -        return; -    } else if (op != SkRegion::kIntersect_Op) { -        enterRegionMode(); -        regionModeClipRectWithTransform(r, transform, op); -        return; -    } - -    if (transform->rectToRect()) { -        Rect transformed(r); -        transform->mapRect(transformed); -        mClipRect.doIntersect(transformed); -        return; -    } - -    enterRectangleListMode(); -    rectangleListModeClipRectWithTransform(r, transform, op); -} - -/* - * RectangleList mode implementation - */ - -void ClipArea::enterRectangleListMode() { -    // Is is only legal to enter rectangle list mode from -    // rectangle mode, since rectangle list mode cannot represent -    // all clip areas that can be represented by a region. -    ALOG_ASSERT(mMode == ClipMode::Rectangle); -    mMode = ClipMode::RectangleList; -    mRectangleList.set(mClipRect, Matrix4::identity()); -} - -void ClipArea::rectangleListModeClipRectWithTransform(const Rect& r, const mat4* transform, -                                                      SkRegion::Op op) { -    if (op != SkRegion::kIntersect_Op || !mRectangleList.intersectWith(r, *transform)) { -        enterRegionMode(); -        regionModeClipRectWithTransform(r, transform, op); -    } -} - -/* - * Region mode implementation - */ - -void ClipArea::enterRegionMode() { -    ClipMode oldMode = mMode; -    mMode = ClipMode::Region; -    if (oldMode != ClipMode::Region) { -        if (oldMode == ClipMode::Rectangle) { -            mClipRegion.setRect(mClipRect.toSkIRect()); -        } else { -            mClipRegion = mRectangleList.convertToRegion(createViewportRegion()); -            onClipRegionUpdated(); -        } -    } -} - -void ClipArea::regionModeClipRectWithTransform(const Rect& r, const mat4* transform, -                                               SkRegion::Op op) { -    SkPath transformedRect = pathFromTransformedRectangle(r, *transform); -    SkRegion transformedRectRegion; -    regionFromPath(transformedRect, transformedRectRegion); -    mClipRegion.op(transformedRectRegion, op); -    onClipRegionUpdated(); -} - -void ClipArea::onClipRegionUpdated() { -    if (!mClipRegion.isEmpty()) { -        mClipRect.set(mClipRegion.getBounds()); - -        if (mClipRegion.isRect()) { -            mClipRegion.setEmpty(); -            enterRectangleMode(); -        } -    } else { -        mClipRect.setEmpty(); -    } -} - -/** - * Clip serialization - */ - -const ClipBase* ClipArea::serializeClip(LinearAllocator& allocator) { -    if (!mPostViewportClipObserved) { -        // Only initial clip-to-viewport observed, so no serialization of clip necessary -        return nullptr; -    } - -    static_assert(std::is_trivially_destructible<Rect>::value, -                  "expect Rect to be trivially destructible"); -    static_assert(std::is_trivially_destructible<RectangleList>::value, -                  "expect RectangleList to be trivially destructible"); - -    if (mLastSerialization == nullptr) { -        ClipBase* serialization = nullptr; -        switch (mMode) { -            case ClipMode::Rectangle: -                serialization = allocator.create<ClipRect>(mClipRect); -                break; -            case ClipMode::RectangleList: -                serialization = allocator.create<ClipRectList>(mRectangleList); -                serialization->rect = mRectangleList.calculateBounds(); -                break; -            case ClipMode::Region: -                serialization = allocator.create<ClipRegion>(mClipRegion); -                serialization->rect.set(mClipRegion.getBounds()); -                break; -        } -        serialization->intersectWithRoot = mReplaceOpObserved; -        // TODO: this is only done for draw time, should eventually avoid for record time -        serialization->rect.snapToPixelBoundaries(); -        mLastSerialization = serialization; -    } -    return mLastSerialization; -} - -inline static const RectangleList& getRectList(const ClipBase* scb) { -    return reinterpret_cast<const ClipRectList*>(scb)->rectList; -} - -inline static const SkRegion& getRegion(const ClipBase* scb) { -    return reinterpret_cast<const ClipRegion*>(scb)->region; -} - -// Conservative check for too many rectangles to fit in rectangle list. -// For simplicity, doesn't account for rect merging -static bool cannotFitInRectangleList(const ClipArea& clipArea, const ClipBase* scb) { -    int currentRectCount = clipArea.isRectangleList() -                                   ? clipArea.getRectangleList().getTransformedRectanglesCount() -                                   : 1; -    int recordedRectCount = (scb->mode == ClipMode::RectangleList) -                                    ? getRectList(scb).getTransformedRectanglesCount() -                                    : 1; -    return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles; -} - -static const ClipRect sEmptyClipRect(Rect(0, 0)); - -const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator, -                                                   const ClipBase* recordedClip, -                                                   const Matrix4& recordedClipTransform) { -    // if no recordedClip passed, just serialize current state -    if (!recordedClip) return serializeClip(allocator); - -    // if either is empty, clip is empty -    if (CC_UNLIKELY(recordedClip->rect.isEmpty()) || mClipRect.isEmpty()) return &sEmptyClipRect; - -    if (!mLastResolutionResult || recordedClip != mLastResolutionClip || -        recordedClipTransform != mLastResolutionTransform) { -        mLastResolutionClip = recordedClip; -        mLastResolutionTransform = recordedClipTransform; - -        if (CC_LIKELY(mMode == ClipMode::Rectangle && recordedClip->mode == ClipMode::Rectangle && -                      recordedClipTransform.rectToRect())) { -            // common case - result is a single rectangle -            auto rectClip = allocator.create<ClipRect>(recordedClip->rect); -            recordedClipTransform.mapRect(rectClip->rect); -            rectClip->rect.doIntersect(mClipRect); -            rectClip->rect.snapToPixelBoundaries(); -            mLastResolutionResult = rectClip; -        } else if (CC_UNLIKELY(mMode == ClipMode::Region || -                               recordedClip->mode == ClipMode::Region || -                               cannotFitInRectangleList(*this, recordedClip))) { -            // region case -            SkRegion other; -            switch (recordedClip->mode) { -                case ClipMode::Rectangle: -                    if (CC_LIKELY(recordedClipTransform.rectToRect())) { -                        // simple transform, skip creating SkPath -                        Rect resultClip(recordedClip->rect); -                        recordedClipTransform.mapRect(resultClip); -                        other.setRect(resultClip.toSkIRect()); -                    } else { -                        SkPath transformedRect = pathFromTransformedRectangle( -                                recordedClip->rect, recordedClipTransform); -                        other.setPath(transformedRect, createViewportRegion()); -                    } -                    break; -                case ClipMode::RectangleList: { -                    RectangleList transformedList(getRectList(recordedClip)); -                    transformedList.transform(recordedClipTransform); -                    other = transformedList.convertToRegion(createViewportRegion()); -                    break; -                } -                case ClipMode::Region: -                    other = getRegion(recordedClip); -                    applyTransformToRegion(recordedClipTransform, &other); -            } - -            ClipRegion* regionClip = allocator.create<ClipRegion>(); -            switch (mMode) { -                case ClipMode::Rectangle: -                    regionClip->region.op(mClipRect.toSkIRect(), other, SkRegion::kIntersect_Op); -                    break; -                case ClipMode::RectangleList: -                    regionClip->region.op(mRectangleList.convertToRegion(createViewportRegion()), -                                          other, SkRegion::kIntersect_Op); -                    break; -                case ClipMode::Region: -                    regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op); -                    break; -            } -            // Don't need to snap, since region's in int bounds -            regionClip->rect.set(regionClip->region.getBounds()); -            mLastResolutionResult = regionClip; -        } else { -            auto rectListClip = allocator.create<ClipRectList>(mRectangleList); -            auto&& rectList = rectListClip->rectList; -            if (mMode == ClipMode::Rectangle) { -                rectList.set(mClipRect, Matrix4::identity()); -            } - -            if (recordedClip->mode == ClipMode::Rectangle) { -                rectList.intersectWith(recordedClip->rect, recordedClipTransform); -            } else { -                const RectangleList& other = getRectList(recordedClip); -                for (int i = 0; i < other.getTransformedRectanglesCount(); i++) { -                    auto&& tr = other.getTransformedRectangle(i); -                    Matrix4 totalTransform(recordedClipTransform); -                    totalTransform.multiply(tr.getTransform()); -                    rectList.intersectWith(tr.getBounds(), totalTransform); -                } -            } -            rectListClip->rect = rectList.calculateBounds(); -            rectListClip->rect.snapToPixelBoundaries(); -            mLastResolutionResult = rectListClip; -        } -    } -    return mLastResolutionResult; -} - -void ClipArea::applyClip(const ClipBase* clip, const Matrix4& transform) { -    if (!clip) return;  // nothing to do - -    if (CC_LIKELY(clip->mode == ClipMode::Rectangle)) { -        clipRectWithTransform(clip->rect, &transform, SkRegion::kIntersect_Op); -    } else if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) { -        auto&& rectList = getRectList(clip); -        for (int i = 0; i < rectList.getTransformedRectanglesCount(); i++) { -            auto&& tr = rectList.getTransformedRectangle(i); -            Matrix4 totalTransform(transform); -            totalTransform.multiply(tr.getTransform()); -            clipRectWithTransform(tr.getBounds(), &totalTransform, SkRegion::kIntersect_Op); -        } -    } else { -        SkRegion region(getRegion(clip)); -        applyTransformToRegion(transform, ®ion); -        clipRegion(region, SkRegion::kIntersect_Op); -    } -} - -void ClipArea::applyTransformToRegion(const Matrix4& transform, SkRegion* region) { -    if (transform.rectToRect() && !transform.isPureTranslate()) { -        // handle matrices with scale manually by mapping each rect -        SkRegion other; -        SkRegion::Iterator it(*region); -        while (!it.done()) { -            Rect rect(it.rect()); -            transform.mapRect(rect); -            rect.snapGeometryToPixelBoundaries(true); -            other.op(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kUnion_Op); -            it.next(); -        } -        region->swap(other); -    } else { -        // TODO: handle non-translate transforms properly! -        region->translate(transform.getTranslateX(), transform.getTranslateY()); -    } -} - -} /* namespace uirenderer */ -} /* namespace android */  |