diff options
author | 2018-09-20 14:56:27 -0400 | |
---|---|---|
committer | 2018-10-03 14:30:21 -0400 | |
commit | 72903272aee873b02ac73469f4ffb8c727e71e0a (patch) | |
tree | 032b69a22baddf5fc45df55dee11ed6955ce9c23 | |
parent | 9bf8ba3c699d0e4d3a2f74e636b20a6d62176966 (diff) |
Remove unused classes from HWUI.
Test: compiles and hwui_unit_tests
Change-Id: I42e279a497ea17ad06a857c9914d5aca5df9f6df
-rw-r--r-- | core/jni/android/graphics/NinePatch.cpp | 9 | ||||
-rw-r--r-- | libs/hwui/Android.bp | 7 | ||||
-rw-r--r-- | libs/hwui/CanvasState.cpp | 284 | ||||
-rw-r--r-- | libs/hwui/CanvasState.h | 195 | ||||
-rw-r--r-- | libs/hwui/ClipArea.cpp | 534 | ||||
-rw-r--r-- | libs/hwui/ClipArea.h | 212 | ||||
-rw-r--r-- | libs/hwui/FloatColor.h | 71 | ||||
-rw-r--r-- | libs/hwui/ResourceCache.cpp | 145 | ||||
-rw-r--r-- | libs/hwui/ResourceCache.h | 103 | ||||
-rw-r--r-- | libs/hwui/Snapshot.cpp | 209 | ||||
-rw-r--r-- | libs/hwui/Snapshot.h | 279 | ||||
-rw-r--r-- | libs/hwui/Vertex.h | 1 | ||||
-rw-r--r-- | libs/hwui/tests/common/TestUtils.h | 9 | ||||
-rw-r--r-- | libs/hwui/tests/microbench/DisplayListCanvasBench.cpp | 47 | ||||
-rw-r--r-- | libs/hwui/tests/unit/CanvasStateTests.cpp | 160 | ||||
-rw-r--r-- | libs/hwui/tests/unit/ClipAreaTests.cpp | 353 | ||||
-rw-r--r-- | libs/hwui/tests/unit/RenderNodeDrawableTests.cpp | 1 | ||||
-rw-r--r-- | libs/hwui/tests/unit/SnapshotTests.cpp | 74 |
18 files changed, 2 insertions, 2691 deletions
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp index 261910727db9..bb291e74ce0d 100644 --- a/core/jni/android/graphics/NinePatch.cpp +++ b/core/jni/android/graphics/NinePatch.cpp @@ -23,8 +23,6 @@ #include <hwui/Paint.h> #include <utils/Log.h> -#include <ResourceCache.h> - #include "SkCanvas.h" #include "SkLatticeIter.h" #include "SkRegion.h" @@ -83,12 +81,7 @@ public: static void finalize(JNIEnv* env, jobject, jlong patchHandle) { int8_t* patch = reinterpret_cast<int8_t*>(patchHandle); - if (android::uirenderer::ResourceCache::hasInstance()) { - Res_png_9patch* p = (Res_png_9patch*) patch; - android::uirenderer::ResourceCache::getInstance().destructor(p); - } else { - delete[] patch; - } + delete[] patch; } static jlong getTransparentRegion(JNIEnv* env, jobject, jobject jbitmap, diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 494e5135d5bb..449e587ae007 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -201,9 +201,7 @@ cc_defaults { "AnimationContext.cpp", "Animator.cpp", "AnimatorManager.cpp", - "CanvasState.cpp", "CanvasTransform.cpp", - "ClipArea.cpp", "DamageAccumulator.cpp", "DeferredLayerUpdater.cpp", "DeviceInfo.cpp", @@ -226,9 +224,7 @@ cc_defaults { "RecordingCanvas.cpp", "RenderNode.cpp", "RenderProperties.cpp", - "ResourceCache.cpp", "SkiaCanvas.cpp", - "Snapshot.cpp", "TreeInfo.cpp", "VectorDrawable.cpp", "protos/graphicsstats.proto", @@ -307,8 +303,6 @@ cc_test { "tests/unit/main.cpp", "tests/unit/CacheManagerTests.cpp", "tests/unit/CanvasContextTests.cpp", - "tests/unit/CanvasStateTests.cpp", - "tests/unit/ClipAreaTests.cpp", "tests/unit/DamageAccumulatorTests.cpp", "tests/unit/DeferredLayerUpdaterTests.cpp", "tests/unit/FatVectorTests.cpp", @@ -327,7 +321,6 @@ cc_test { "tests/unit/SkiaPipelineTests.cpp", "tests/unit/SkiaRenderPropertiesTests.cpp", "tests/unit/SkiaCanvasTests.cpp", - "tests/unit/SnapshotTests.cpp", "tests/unit/StringUtilsTests.cpp", "tests/unit/TestUtilsTests.cpp", "tests/unit/ThreadBaseTests.cpp", diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp deleted file mode 100644 index d18c4abde7f2..000000000000 --- a/libs/hwui/CanvasState.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (C) 2014 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 "CanvasState.h" -#include "hwui/Canvas.h" -#include "utils/MathUtils.h" - -namespace android { -namespace uirenderer { - -CanvasState::CanvasState(CanvasStateClient& renderer) - : mWidth(-1), mHeight(-1), mSaveCount(1), mCanvas(renderer), mSnapshot(&mFirstSnapshot) {} - -CanvasState::~CanvasState() { - // First call freeSnapshot on all but mFirstSnapshot - // to invoke all the dtors - freeAllSnapshots(); - - // Now actually release the memory - while (mSnapshotPool) { - void* temp = mSnapshotPool; - mSnapshotPool = mSnapshotPool->previous; - free(temp); - } -} - -void CanvasState::initializeRecordingSaveStack(int viewportWidth, int viewportHeight) { - if (mWidth != viewportWidth || mHeight != viewportHeight) { - mWidth = viewportWidth; - mHeight = viewportHeight; - mFirstSnapshot.initializeViewport(viewportWidth, viewportHeight); - mCanvas.onViewportInitialized(); - } - - freeAllSnapshots(); - mSnapshot = allocSnapshot(&mFirstSnapshot, SaveFlags::MatrixClip); - mSnapshot->setRelativeLightCenter(Vector3()); - mSaveCount = 1; -} - -void CanvasState::initializeSaveStack(int viewportWidth, int viewportHeight, float clipLeft, - float clipTop, float clipRight, float clipBottom, - const Vector3& lightCenter) { - if (mWidth != viewportWidth || mHeight != viewportHeight) { - mWidth = viewportWidth; - mHeight = viewportHeight; - mFirstSnapshot.initializeViewport(viewportWidth, viewportHeight); - mCanvas.onViewportInitialized(); - } - - freeAllSnapshots(); - mSnapshot = allocSnapshot(&mFirstSnapshot, SaveFlags::MatrixClip); - mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom); - mSnapshot->fbo = mCanvas.getTargetFbo(); - mSnapshot->setRelativeLightCenter(lightCenter); - mSaveCount = 1; -} - -Snapshot* CanvasState::allocSnapshot(Snapshot* previous, int savecount) { - void* memory; - if (mSnapshotPool) { - memory = mSnapshotPool; - mSnapshotPool = mSnapshotPool->previous; - mSnapshotPoolCount--; - } else { - memory = malloc(sizeof(Snapshot)); - } - return new (memory) Snapshot(previous, savecount); -} - -void CanvasState::freeSnapshot(Snapshot* snapshot) { - snapshot->~Snapshot(); - // Arbitrary number, just don't let this grown unbounded - if (mSnapshotPoolCount > 10) { - free((void*)snapshot); - } else { - snapshot->previous = mSnapshotPool; - mSnapshotPool = snapshot; - mSnapshotPoolCount++; - } -} - -void CanvasState::freeAllSnapshots() { - while (mSnapshot != &mFirstSnapshot) { - Snapshot* temp = mSnapshot; - mSnapshot = mSnapshot->previous; - freeSnapshot(temp); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Save (layer) -/////////////////////////////////////////////////////////////////////////////// - -/** - * Guaranteed to save without side-effects - * - * This approach, here and in restoreSnapshot(), allows subclasses to directly manipulate the save - * stack, and ensures restoreToCount() doesn't call back into subclass overrides. - */ -int CanvasState::saveSnapshot(int flags) { - mSnapshot = allocSnapshot(mSnapshot, flags); - return mSaveCount++; -} - -int CanvasState::save(int flags) { - return saveSnapshot(flags); -} - -/** - * Guaranteed to restore without side-effects. - */ -void CanvasState::restoreSnapshot() { - Snapshot* toRemove = mSnapshot; - Snapshot* toRestore = mSnapshot->previous; - - mSaveCount--; - mSnapshot = toRestore; - - // subclass handles restore implementation - mCanvas.onSnapshotRestored(*toRemove, *toRestore); - - freeSnapshot(toRemove); -} - -void CanvasState::restore() { - if (mSaveCount > 1) { - restoreSnapshot(); - } -} - -void CanvasState::restoreToCount(int saveCount) { - if (saveCount < 1) saveCount = 1; - - while (mSaveCount > saveCount) { - restoreSnapshot(); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Matrix -/////////////////////////////////////////////////////////////////////////////// - -void CanvasState::getMatrix(SkMatrix* matrix) const { - mSnapshot->transform->copyTo(*matrix); -} - -void CanvasState::translate(float dx, float dy, float dz) { - mSnapshot->transform->translate(dx, dy, dz); -} - -void CanvasState::rotate(float degrees) { - mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f); -} - -void CanvasState::scale(float sx, float sy) { - mSnapshot->transform->scale(sx, sy, 1.0f); -} - -void CanvasState::skew(float sx, float sy) { - mSnapshot->transform->skew(sx, sy); -} - -void CanvasState::setMatrix(const SkMatrix& matrix) { - mSnapshot->transform->load(matrix); -} - -void CanvasState::setMatrix(const Matrix4& matrix) { - *(mSnapshot->transform) = matrix; -} - -void CanvasState::concatMatrix(const SkMatrix& matrix) { - mat4 transform(matrix); - mSnapshot->transform->multiply(transform); -} - -void CanvasState::concatMatrix(const Matrix4& matrix) { - mSnapshot->transform->multiply(matrix); -} - -/////////////////////////////////////////////////////////////////////////////// -// Clip -/////////////////////////////////////////////////////////////////////////////// - -bool CanvasState::clipRect(float left, float top, float right, float bottom, SkClipOp op) { - mSnapshot->clip(Rect(left, top, right, bottom), op); - return !mSnapshot->clipIsEmpty(); -} - -bool CanvasState::clipPath(const SkPath* path, SkClipOp op) { - mSnapshot->clipPath(*path, op); - return !mSnapshot->clipIsEmpty(); -} - -void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline* outline) { - Rect bounds; - float radius; - if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported - - bool outlineIsRounded = MathUtils::isPositive(radius); - if (!outlineIsRounded || currentTransform()->isSimple()) { - // TODO: consider storing this rect separately, so that this can't be replaced with clip ops - clipRect(bounds.left, bounds.top, bounds.right, bounds.bottom, SkClipOp::kIntersect); - } - if (outlineIsRounded) { - setClippingRoundRect(allocator, bounds, radius, false); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Quick Rejection -/////////////////////////////////////////////////////////////////////////////// - -/** - * Calculates whether content drawn within the passed bounds would be outside of, or intersect with - * the clipRect. Does not modify the scissor. - * - * @param clipRequired if not null, will be set to true if element intersects clip - * (and wasn't rejected) - * - * @param snapOut if set, the geometry will be treated as having an AA ramp. - * See Rect::snapGeometryToPixelBoundaries() - */ -bool CanvasState::calculateQuickRejectForScissor(float left, float top, float right, float bottom, - bool* clipRequired, bool* roundRectClipRequired, - bool snapOut) const { - if (bottom <= top || right <= left) { - return true; - } - - Rect r(left, top, right, bottom); - currentTransform()->mapRect(r); - r.snapGeometryToPixelBoundaries(snapOut); - - Rect clipRect(currentRenderTargetClip()); - clipRect.snapToPixelBoundaries(); - - if (!clipRect.intersects(r)) return true; - - // clip is required if geometry intersects clip rect - if (clipRequired) { - *clipRequired = !clipRect.contains(r); - } - - // round rect clip is required if RR clip exists, and geometry intersects its corners - if (roundRectClipRequired) { - *roundRectClipRequired = mSnapshot->roundRectClipState != nullptr && - mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r); - } - return false; -} - -bool CanvasState::quickRejectConservative(float left, float top, float right, float bottom) const { - if (bottom <= top || right <= left) { - return true; - } - - Rect r(left, top, right, bottom); - currentTransform()->mapRect(r); - r.roundOut(); // rounded out to be conservative - - Rect clipRect(currentRenderTargetClip()); - clipRect.snapToPixelBoundaries(); - - if (!clipRect.intersects(r)) return true; - - return false; -} - -} // namespace uirenderer -} // namespace android diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h deleted file mode 100644 index 9ac35ff47dab..000000000000 --- a/libs/hwui/CanvasState.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -#pragma once - -#include "Snapshot.h" - -#include <SkClipOp.h> -#include <SkMatrix.h> -#include <SkPath.h> -#include <SkRegion.h> - -namespace android { -namespace uirenderer { - -/** - * Abstract base class for any class containing CanvasState. - * Defines three mandatory callbacks. - */ -class CanvasStateClient { -public: - CanvasStateClient() {} - virtual ~CanvasStateClient() {} - - /** - * Callback allowing embedder to take actions in the middle of a - * setViewport() call. - */ - virtual void onViewportInitialized() = 0; - - /** - * Callback allowing embedder to take actions in the middle of a - * restore() call. May be called several times sequentially. - */ - virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) = 0; - - /** - * Allows subclasses to control what value is stored in snapshot's - * fbo field in * initializeSaveStack. - */ - virtual GLuint getTargetFbo() const = 0; - -}; // class CanvasStateClient - -/** - * Implements Canvas state methods on behalf of Renderers. - * - * Manages the Snapshot stack, implementing matrix, save/restore, and clipping methods in the - * Renderer interface. Drawing and recording classes that include a CanvasState will have - * different use cases: - * - * Drawing code maintaining canvas state (e.g. FrameBuilder) can query attributes (such as - * transform) or hook into changes (e.g. save/restore) with minimal surface area for manipulating - * the stack itself. - * - * Recording code maintaining canvas state (e.g. RecordingCanvas) can both record and pass - * through state operations to CanvasState, so that not only will querying operations work - * (getClip/Matrix), but so that quickRejection can also be used. - */ - -class CanvasState { -public: - explicit CanvasState(CanvasStateClient& renderer); - ~CanvasState(); - - /** - * Initializes the first snapshot, computing the projection matrix, - * and stores the dimensions of the render target. - */ - void initializeRecordingSaveStack(int viewportWidth, int viewportHeight); - - /** - * Initializes the first snapshot, computing the projection matrix, - * and stores the dimensions of the render target. - */ - void initializeSaveStack(int viewportWidth, int viewportHeight, float clipLeft, float clipTop, - float clipRight, float clipBottom, const Vector3& lightCenter); - - bool hasRectToRectTransform() const { return CC_LIKELY(currentTransform()->rectToRect()); } - - // Save (layer) - int getSaveCount() const { return mSaveCount; } - int save(int flags); - void restore(); - void restoreToCount(int saveCount); - - // Save/Restore without side-effects - int saveSnapshot(int flags); - void restoreSnapshot(); - - // Matrix - void getMatrix(SkMatrix* outMatrix) const; - void translate(float dx, float dy, float dz = 0.0f); - void rotate(float degrees); - void scale(float sx, float sy); - void skew(float sx, float sy); - - void setMatrix(const SkMatrix& matrix); - void setMatrix(const Matrix4& matrix); // internal only convenience method - void concatMatrix(const SkMatrix& matrix); - void concatMatrix(const Matrix4& matrix); // internal only convenience method - - // Clip - const Rect& getLocalClipBounds() const { return mSnapshot->getLocalClip(); } - const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); } - - bool quickRejectConservative(float left, float top, float right, float bottom) const; - - bool clipRect(float left, float top, float right, float bottom, SkClipOp op); - bool clipPath(const SkPath* path, SkClipOp op); - - /** - * Sets a "clipping outline", which is independent from the regular clip. - * Currently only supports rectangles or rounded rectangles; passing in a - * more complicated outline fails silently. Replaces any previous clipping - * outline. - */ - void setClippingOutline(LinearAllocator& allocator, const Outline* outline); - void setClippingRoundRect(LinearAllocator& allocator, const Rect& rect, float radius, - bool highPriority = true) { - mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority); - } - void setProjectionPathMask(const SkPath* path) { mSnapshot->setProjectionPathMask(path); } - - /** - * Returns true if drawing in the rectangle (left, top, right, bottom) - * will be clipped out. Is conservative: might return false when subpixel- - * perfect tests would return true. - */ - bool calculateQuickRejectForScissor(float left, float top, float right, float bottom, - bool* clipRequired, bool* roundRectClipRequired, - bool snapOut) const; - - void scaleAlpha(float alpha) { mSnapshot->alpha *= alpha; } - - inline const mat4* currentTransform() const { return currentSnapshot()->transform; } - inline const Rect& currentRenderTargetClip() const { - return currentSnapshot()->getRenderTargetClip(); - } - inline int currentFlags() const { return currentSnapshot()->flags; } - const Vector3& currentLightCenter() const { - return currentSnapshot()->getRelativeLightCenter(); - } - int getViewportWidth() const { return currentSnapshot()->getViewportWidth(); } - int getViewportHeight() const { return currentSnapshot()->getViewportHeight(); } - int getWidth() const { return mWidth; } - int getHeight() const { return mHeight; } - bool clipIsSimple() const { return currentSnapshot()->clipIsSimple(); } - - inline const Snapshot* currentSnapshot() const { return mSnapshot; } - inline Snapshot* writableSnapshot() { return mSnapshot; } - inline const Snapshot* firstSnapshot() const { return &mFirstSnapshot; } - -private: - Snapshot* allocSnapshot(Snapshot* previous, int savecount); - void freeSnapshot(Snapshot* snapshot); - void freeAllSnapshots(); - - /// Dimensions of the drawing surface - int mWidth, mHeight; - - /// Number of saved states - int mSaveCount; - - /// Base state - Snapshot mFirstSnapshot; - - /// Host providing callbacks - CanvasStateClient& mCanvas; - - /// Current state - Snapshot* mSnapshot; - - // Pool of allocated snapshots to re-use - // NOTE: The dtors have already been invoked! - Snapshot* mSnapshotPool = nullptr; - int mSnapshotPoolCount = 0; - -}; // class CanvasState - -}; // namespace uirenderer -}; // namespace android 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 */ diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h deleted file mode 100644 index a7a11801cfe2..000000000000 --- a/libs/hwui/ClipArea.h +++ /dev/null @@ -1,212 +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. - */ -#ifndef CLIPAREA_H -#define CLIPAREA_H - -#include "Matrix.h" -#include "Rect.h" -#include "utils/Pair.h" - -#include <SkRegion.h> - -namespace android { -namespace uirenderer { - -class LinearAllocator; - -Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform); - -class TransformedRectangle { -public: - TransformedRectangle(); - TransformedRectangle(const Rect& bounds, const Matrix4& transform); - - bool canSimplyIntersectWith(const TransformedRectangle& other) const; - void intersectWith(const TransformedRectangle& other); - - bool isEmpty() const; - - const Rect& getBounds() const { return mBounds; } - - Rect transformedBounds() const { - Rect transformedBounds(transformAndCalculateBounds(mBounds, mTransform)); - return transformedBounds; - } - - const Matrix4& getTransform() const { return mTransform; } - - void transform(const Matrix4& transform) { - Matrix4 t; - t.loadMultiply(transform, mTransform); - mTransform = t; - } - -private: - Rect mBounds; - Matrix4 mTransform; -}; - -class RectangleList { -public: - RectangleList(); - - bool isEmpty() const; - int getTransformedRectanglesCount() const; - const TransformedRectangle& getTransformedRectangle(int i) const; - - void setEmpty(); - void set(const Rect& bounds, const Matrix4& transform); - bool intersectWith(const Rect& bounds, const Matrix4& transform); - void transform(const Matrix4& transform); - - SkRegion convertToRegion(const SkRegion& clip) const; - Rect calculateBounds() const; - - enum { kMaxTransformedRectangles = 5 }; - -private: - int mTransformedRectanglesCount; - TransformedRectangle mTransformedRectangles[kMaxTransformedRectangles]; -}; - -enum class ClipMode { - Rectangle, - RectangleList, - - // region and path - intersected. if either is empty, don't use - Region -}; - -struct ClipBase { - explicit ClipBase(ClipMode mode) : mode(mode) {} - explicit ClipBase(const Rect& rect) : mode(ClipMode::Rectangle), rect(rect) {} - const ClipMode mode; - bool intersectWithRoot = false; - // Bounds of the clipping area, used to define the scissor, and define which - // portion of the stencil is updated/used - Rect rect; - - void dump() const; -}; - -struct ClipRect : ClipBase { - explicit ClipRect(const Rect& rect) : ClipBase(rect) {} -}; - -struct ClipRectList : ClipBase { - explicit ClipRectList(const RectangleList& rectList) - : ClipBase(ClipMode::RectangleList), rectList(rectList) {} - RectangleList rectList; -}; - -struct ClipRegion : ClipBase { - explicit ClipRegion(const SkRegion& region) : ClipBase(ClipMode::Region), region(region) {} - ClipRegion() : ClipBase(ClipMode::Region) {} - SkRegion region; -}; - -class ClipArea { -public: - ClipArea(); - - void setViewportDimensions(int width, int height); - - bool isEmpty() const { return mClipRect.isEmpty(); } - - void setEmpty(); - void setClip(float left, float top, float right, float bottom); - void clipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op); - void clipPathWithTransform(const SkPath& path, const mat4* transform, SkRegion::Op op); - - const Rect& getClipRect() const { return mClipRect; } - - const SkRegion& getClipRegion() const { return mClipRegion; } - - const RectangleList& getRectangleList() const { return mRectangleList; } - - bool isRegion() const { return ClipMode::Region == mMode; } - - bool isSimple() const { return mMode == ClipMode::Rectangle; } - - bool isRectangleList() const { return mMode == ClipMode::RectangleList; } - - WARN_UNUSED_RESULT const ClipBase* serializeClip(LinearAllocator& allocator); - WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip( - LinearAllocator& allocator, const ClipBase* recordedClip, - const Matrix4& recordedClipTransform); - void applyClip(const ClipBase* recordedClip, const Matrix4& recordedClipTransform); - - static void applyTransformToRegion(const Matrix4& transform, SkRegion* region); - -private: - void enterRectangleMode(); - void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op); - - void enterRectangleListMode(); - void rectangleListModeClipRectWithTransform(const Rect& r, const mat4* transform, - SkRegion::Op op); - - void enterRegionModeFromRectangleMode(); - void enterRegionModeFromRectangleListMode(); - void enterRegionMode(); - void regionModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op); - - void clipRegion(const SkRegion& region, SkRegion::Op op); - void ensureClipRegion(); - void onClipRegionUpdated(); - - // Called by every state modifying public method. - void onClipUpdated() { - mPostViewportClipObserved = true; - mLastSerialization = nullptr; - mLastResolutionResult = nullptr; - } - - SkRegion createViewportRegion() { return SkRegion(mViewportBounds.toSkIRect()); } - - void regionFromPath(const SkPath& path, SkRegion& pathAsRegion) { - // TODO: this should not mask every path to the viewport - this makes it impossible to use - // paths to clip to larger areas (which is valid e.g. with SkRegion::kReplace_Op) - pathAsRegion.setPath(path, createViewportRegion()); - } - - ClipMode mMode; - bool mPostViewportClipObserved = false; - bool mReplaceOpObserved = false; - - /** - * If mLastSerialization is non-null, it represents an already serialized copy - * of the current clip state. If null, it has not been computed. - */ - const ClipBase* mLastSerialization = nullptr; - - /** - * This pair of pointers is a single entry cache of most recently seen - */ - const ClipBase* mLastResolutionResult = nullptr; - const ClipBase* mLastResolutionClip = nullptr; - Matrix4 mLastResolutionTransform; - - Rect mViewportBounds; - Rect mClipRect; - SkRegion mClipRegion; - RectangleList mRectangleList; -}; - -} /* namespace uirenderer */ -} /* namespace android */ - -#endif /* CLIPAREA_H_ */ diff --git a/libs/hwui/FloatColor.h b/libs/hwui/FloatColor.h deleted file mode 100644 index b424f97a5004..000000000000 --- a/libs/hwui/FloatColor.h +++ /dev/null @@ -1,71 +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. - */ -#ifndef FLOATCOLOR_H -#define FLOATCOLOR_H - -#include "utils/Color.h" -#include "utils/Macros.h" -#include "utils/MathUtils.h" - -#include <stdint.h> - -namespace android { -namespace uirenderer { - -struct FloatColor { - // "color" is a gamma-encoded sRGB color - // After calling this method, the color is stored as a pre-multiplied linear color - // if linear blending is enabled. Otherwise, the color is stored as a pre-multiplied - // gamma-encoded sRGB color - void set(uint32_t color) { - a = ((color >> 24) & 0xff) / 255.0f; - r = a * EOCF(((color >> 16) & 0xff) / 255.0f); - g = a * EOCF(((color >> 8) & 0xff) / 255.0f); - b = a * EOCF(((color)&0xff) / 255.0f); - } - - // "color" is a gamma-encoded sRGB color - // After calling this method, the color is stored as a un-premultiplied linear color - // if linear blending is enabled. Otherwise, the color is stored as a un-premultiplied - // gamma-encoded sRGB color - void setUnPreMultiplied(uint32_t color) { - a = ((color >> 24) & 0xff) / 255.0f; - r = EOCF(((color >> 16) & 0xff) / 255.0f); - g = EOCF(((color >> 8) & 0xff) / 255.0f); - b = EOCF(((color)&0xff) / 255.0f); - } - - bool isNotBlack() { return a < 1.0f || r > 0.0f || g > 0.0f || b > 0.0f; } - - bool operator==(const FloatColor& other) const { - return MathUtils::areEqual(r, other.r) && MathUtils::areEqual(g, other.g) && - MathUtils::areEqual(b, other.b) && MathUtils::areEqual(a, other.a); - } - - bool operator!=(const FloatColor& other) const { return !(*this == other); } - - float r; - float g; - float b; - float a; -}; - -REQUIRE_COMPATIBLE_LAYOUT(FloatColor); - -} /* namespace uirenderer */ -} /* namespace android */ - -#endif /* FLOATCOLOR_H */ diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp deleted file mode 100644 index 65bee476f14d..000000000000 --- a/libs/hwui/ResourceCache.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2010 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 "ResourceCache.h" - -namespace android { - -using namespace uirenderer; -ANDROID_SINGLETON_STATIC_INSTANCE(ResourceCache); - -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Resource cache -/////////////////////////////////////////////////////////////////////////////// - -void ResourceCache::logCache() { - ALOGD("ResourceCache: cacheReport:"); - for (size_t i = 0; i < mCache->size(); ++i) { - ResourceReference* ref = mCache->valueAt(i); - ALOGD(" ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p", i, mCache->keyAt(i), - mCache->valueAt(i)); - ALOGD(" ResourceCache: mCache(%zu): refCount, destroyed, type = %d, %d, %d", i, - ref->refCount, ref->destroyed, ref->resourceType); - } -} - -ResourceCache::ResourceCache() { - Mutex::Autolock _l(mLock); - mCache = new KeyedVector<const void*, ResourceReference*>(); -} - -ResourceCache::~ResourceCache() { - Mutex::Autolock _l(mLock); - delete mCache; -} - -void ResourceCache::lock() { - mLock.lock(); -} - -void ResourceCache::unlock() { - mLock.unlock(); -} - -void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) { - Mutex::Autolock _l(mLock); - incrementRefcountLocked(resource, resourceType); -} - -void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) { - incrementRefcount((void*)patchResource, kNinePatch); -} - -void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) { - ssize_t index = mCache->indexOfKey(resource); - ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr; - if (ref == nullptr || mCache->size() == 0) { - ref = new ResourceReference(resourceType); - mCache->add(resource, ref); - } - ref->refCount++; -} - -void ResourceCache::decrementRefcount(void* resource) { - Mutex::Autolock _l(mLock); - decrementRefcountLocked(resource); -} - -void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) { - decrementRefcount((void*)patchResource); -} - -void ResourceCache::decrementRefcountLocked(void* resource) { - ssize_t index = mCache->indexOfKey(resource); - ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr; - if (ref == nullptr) { - // Should not get here - shouldn't get a call to decrement if we're not yet tracking it - return; - } - ref->refCount--; - if (ref->refCount == 0) { - deleteResourceReferenceLocked(resource, ref); - } -} - -void ResourceCache::decrementRefcountLocked(const Res_png_9patch* patchResource) { - decrementRefcountLocked((void*)patchResource); -} - -void ResourceCache::destructor(Res_png_9patch* resource) { - Mutex::Autolock _l(mLock); - destructorLocked(resource); -} - -void ResourceCache::destructorLocked(Res_png_9patch* resource) { - ssize_t index = mCache->indexOfKey(resource); - ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr; - if (ref == nullptr) { - // If we're not tracking this resource, just delete it - // A Res_png_9patch is actually an array of byte that's larger - // than sizeof(Res_png_9patch). It must be freed as an array. - delete[](int8_t*) resource; - return; - } - ref->destroyed = true; - if (ref->refCount == 0) { - deleteResourceReferenceLocked(resource, ref); - } -} - -/** - * This method should only be called while the mLock mutex is held (that mutex is grabbed - * by the various destructor() and recycle() methods which call this method). - */ -void ResourceCache::deleteResourceReferenceLocked(const void* resource, ResourceReference* ref) { - if (ref->destroyed) { - switch (ref->resourceType) { - case kNinePatch: { - // A Res_png_9patch is actually an array of byte that's larger - // than sizeof(Res_png_9patch). It must be freed as an array. - int8_t* patch = (int8_t*)resource; - delete[] patch; - } break; - } - } - mCache->removeItem(resource); - delete ref; -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h deleted file mode 100644 index fd3f9fd05d58..000000000000 --- a/libs/hwui/ResourceCache.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef ANDROID_HWUI_RESOURCE_CACHE_H -#define ANDROID_HWUI_RESOURCE_CACHE_H - -#include <cutils/compiler.h> - -#include <SkBitmap.h> -#include <SkPixelRef.h> - -#include <utils/KeyedVector.h> -#include <utils/Singleton.h> - -#include <androidfw/ResourceTypes.h> - -namespace android { -namespace uirenderer { - -class Layer; - -/** - * Type of Resource being cached - */ -enum ResourceType { - kNinePatch, -}; - -class ResourceReference { -public: - explicit ResourceReference(ResourceType type) { - refCount = 0; - destroyed = false; - resourceType = type; - } - - int refCount; - bool destroyed; - ResourceType resourceType; -}; - -class ANDROID_API ResourceCache : public Singleton<ResourceCache> { - ResourceCache(); - ~ResourceCache(); - - friend class Singleton<ResourceCache>; - -public: - /** - * When using these two methods, make sure to only invoke the *Locked() - * variants of increment/decrementRefcount(), recyle() and destructor() - */ - void lock(); - void unlock(); - - void incrementRefcount(const Res_png_9patch* resource); - - void decrementRefcount(const Res_png_9patch* resource); - - void decrementRefcountLocked(const Res_png_9patch* resource); - - void destructor(Res_png_9patch* resource); - - void destructorLocked(Res_png_9patch* resource); - -private: - void deleteResourceReferenceLocked(const void* resource, ResourceReference* ref); - - void incrementRefcount(void* resource, ResourceType resourceType); - void incrementRefcountLocked(void* resource, ResourceType resourceType); - - void decrementRefcount(void* resource); - void decrementRefcountLocked(void* resource); - - void logCache(); - - /** - * Used to increment, decrement, and destroy. Incrementing is generally accessed on the UI - * thread, but destroying resources may be called from the GC thread, the finalizer thread, - * or a reference queue finalization thread. - */ - mutable Mutex mLock; - - KeyedVector<const void*, ResourceReference*>* mCache; -}; - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_RESOURCE_CACHE_H diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp deleted file mode 100644 index f1a1bef7c94e..000000000000 --- a/libs/hwui/Snapshot.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (C) 2012 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 "Snapshot.h" - -#include "hwui/Canvas.h" - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Constructors -/////////////////////////////////////////////////////////////////////////////// - -Snapshot::Snapshot() - : flags(0) - , previous(nullptr) - , layer(nullptr) - , fbo(0) - , alpha(1.0f) - , roundRectClipState(nullptr) - , projectionPathMask(nullptr) - , mClipArea(&mClipAreaRoot) { - transform = &mTransformRoot; - mRelativeLightCenter.x = mRelativeLightCenter.y = mRelativeLightCenter.z = 0; -} - -/** - * Copies the specified snapshot/ The specified snapshot is stored as - * the previous snapshot. - */ -Snapshot::Snapshot(Snapshot* s, int saveFlags) - : flags(0) - , previous(s) - , layer(s->layer) - , fbo(s->fbo) - , alpha(s->alpha) - , roundRectClipState(s->roundRectClipState) - , projectionPathMask(s->projectionPathMask) - , mClipArea(nullptr) - , mViewportData(s->mViewportData) - , mRelativeLightCenter(s->mRelativeLightCenter) { - if (saveFlags & SaveFlags::Matrix) { - mTransformRoot = *s->transform; - transform = &mTransformRoot; - } else { - transform = s->transform; - } - - if (saveFlags & SaveFlags::Clip) { - mClipAreaRoot = s->getClipArea(); - mClipArea = &mClipAreaRoot; - } else { - mClipArea = s->mClipArea; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Clipping -/////////////////////////////////////////////////////////////////////////////// - -void Snapshot::clip(const Rect& localClip, SkClipOp op) { - flags |= Snapshot::kFlagClipSet; - mClipArea->clipRectWithTransform(localClip, transform, static_cast<SkRegion::Op>(op)); -} - -void Snapshot::clipPath(const SkPath& path, SkClipOp op) { - flags |= Snapshot::kFlagClipSet; - mClipArea->clipPathWithTransform(path, transform, static_cast<SkRegion::Op>(op)); -} - -void Snapshot::setClip(float left, float top, float right, float bottom) { - flags |= Snapshot::kFlagClipSet; - mClipArea->setClip(left, top, right, bottom); -} - -bool Snapshot::hasPerspectiveTransform() const { - return transform->isPerspective(); -} - -const Rect& Snapshot::getLocalClip() { - mat4 inverse; - inverse.loadInverse(*transform); - - mLocalClip.set(mClipArea->getClipRect()); - inverse.mapRect(mLocalClip); - - return mLocalClip; -} - -void Snapshot::resetClip(float left, float top, float right, float bottom) { - // TODO: This is incorrect, when we start rendering into a new layer, - // we may have to modify the previous snapshot's clip rect and clip - // region if the previous restore() call did not restore the clip - mClipArea = &mClipAreaRoot; - setClip(left, top, right, bottom); -} - -/////////////////////////////////////////////////////////////////////////////// -// Clipping round rect -/////////////////////////////////////////////////////////////////////////////// - -void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, float radius, - bool highPriority) { - if (bounds.isEmpty()) { - mClipArea->setEmpty(); - return; - } - - if (roundRectClipState && roundRectClipState->highPriority) { - // ignore, don't replace, already have a high priority clip - return; - } - - RoundRectClipState* state = new (allocator) RoundRectClipState; - - state->highPriority = highPriority; - - // store the inverse drawing matrix - Matrix4 roundRectDrawingMatrix = getOrthoMatrix(); - roundRectDrawingMatrix.multiply(*transform); - state->matrix.loadInverse(roundRectDrawingMatrix); - - // compute area under rounded corners - only draws overlapping these rects need to be clipped - for (int i = 0; i < 4; i++) { - state->dangerRects[i] = bounds; - } - state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius; - state->dangerRects[0].right = state->dangerRects[2].right = bounds.left + radius; - state->dangerRects[1].left = state->dangerRects[3].left = bounds.right - radius; - state->dangerRects[2].top = state->dangerRects[3].top = bounds.bottom - radius; - for (int i = 0; i < 4; i++) { - transform->mapRect(state->dangerRects[i]); - - // round danger rects out as though they are AA geometry (since they essentially are) - state->dangerRects[i].snapGeometryToPixelBoundaries(true); - } - - // store RR area - state->innerRect = bounds; - state->innerRect.inset(radius); - state->radius = radius; - - // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info - roundRectClipState = state; -} - -void Snapshot::setProjectionPathMask(const SkPath* path) { - projectionPathMask = path; -} - -static Snapshot* getClipRoot(Snapshot* target) { - while (target->previous && target->previous->previous) { - target = target->previous; - } - return target; -} - -const ClipBase* Snapshot::serializeIntersectedClip(LinearAllocator& allocator, - const ClipBase* recordedClip, - const Matrix4& recordedClipTransform) { - auto target = this; - if (CC_UNLIKELY(recordedClip && recordedClip->intersectWithRoot)) { - // Clip must be intersected with root, instead of current clip. - target = getClipRoot(this); - } - - return target->mClipArea->serializeIntersectedClip(allocator, recordedClip, - recordedClipTransform); -} - -void Snapshot::applyClip(const ClipBase* recordedClip, const Matrix4& transform) { - if (CC_UNLIKELY(recordedClip && recordedClip->intersectWithRoot)) { - // current clip is being replaced, but must intersect with clip root - *mClipArea = *(getClipRoot(this)->mClipArea); - } - mClipArea->applyClip(recordedClip, transform); -} - -/////////////////////////////////////////////////////////////////////////////// -// Queries -/////////////////////////////////////////////////////////////////////////////// - -void Snapshot::dump() const { - ALOGD("Snapshot %p, flags %x, prev %p, height %d, hasComplexClip %d", this, flags, previous, - getViewportHeight(), !mClipArea->isSimple()); - const Rect& clipRect(mClipArea->getClipRect()); - ALOGD(" ClipRect %.1f %.1f %.1f %.1f, clip simple %d", clipRect.left, clipRect.top, - clipRect.right, clipRect.bottom, mClipArea->isSimple()); - - ALOGD(" Transform (at %p):", transform); - transform->dump(); -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h deleted file mode 100644 index 655f819ca41b..000000000000 --- a/libs/hwui/Snapshot.h +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#pragma once - -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> - -#include <ui/Region.h> -#include <utils/LinearAllocator.h> -#include <utils/RefBase.h> - -#include <SkClipOp.h> -#include <SkRegion.h> - -#include "ClipArea.h" -#include "Layer.h" -#include "Matrix.h" -#include "Outline.h" -#include "Rect.h" -#include "utils/Macros.h" - -namespace android { -namespace uirenderer { - -/** - * Temporary structure holding information for a single outline clip. - * - * These structures are treated as immutable once created, and only exist for a single frame, which - * is why they may only be allocated with a LinearAllocator. - */ -class RoundRectClipState { -public: - static void* operator new(size_t size) = delete; - static void* operator new(size_t size, LinearAllocator& allocator) { - return allocator.alloc<RoundRectClipState>(size); - } - - bool areaRequiresRoundRectClip(const Rect& rect) const { - return rect.intersects(dangerRects[0]) || rect.intersects(dangerRects[1]) || - rect.intersects(dangerRects[2]) || rect.intersects(dangerRects[3]); - } - - bool highPriority; - Matrix4 matrix; - Rect dangerRects[4]; - Rect innerRect; - float radius; -}; - -/** - * A snapshot holds information about the current state of the rendering - * surface. A snapshot is usually created whenever the user calls save() - * and discarded when the user calls restore(). Once a snapshot is created, - * it can hold information for deferred rendering. - * - * Each snapshot has a link to a previous snapshot, indicating the previous - * state of the renderer. - */ -class Snapshot { -public: - Snapshot(); - Snapshot(Snapshot* s, int saveFlags); - - /** - * Various flags set on ::flags. - */ - enum Flags { - /** - * Indicates that the clip region was modified. When this - * snapshot is restored so must the clip. - */ - kFlagClipSet = 0x1, - /** - * Indicates that this snapshot was created when saving - * a new layer. - */ - kFlagIsLayer = 0x2, - /** - * Indicates that this snapshot is a special type of layer - * backed by an FBO. This flag only makes sense when the - * flag kFlagIsLayer is also set. - * - * Viewport has been modified to fit the new Fbo, and must be - * restored when this snapshot is restored. - */ - kFlagIsFboLayer = 0x4, - }; - - /** - * Modifies the current clip with the new clip rectangle and - * the specified operation. The specified rectangle is transformed - * by this snapshot's trasnformation. - */ - void clip(const Rect& localClip, SkClipOp op); - - /** - * Modifies the current clip with the new clip rectangle and - * the specified operation. The specified rectangle is considered - * already transformed. - */ - void clipTransformed(const Rect& r, SkClipOp op = SkClipOp::kIntersect); - - /** - * Modifies the current clip with the specified path and operation. - */ - void clipPath(const SkPath& path, SkClipOp op); - - /** - * Sets the current clip. - */ - void setClip(float left, float top, float right, float bottom); - - /** - * Returns the current clip in local coordinates. The clip rect is - * transformed by the inverse transform matrix. - */ - ANDROID_API const Rect& getLocalClip(); - - /** - * Returns the current clip in render target coordinates. - */ - const Rect& getRenderTargetClip() const { return mClipArea->getClipRect(); } - - /* - * Accessor functions so that the clip area can stay private - */ - bool clipIsEmpty() const { return mClipArea->isEmpty(); } - const SkRegion& getClipRegion() const { return mClipArea->getClipRegion(); } - bool clipIsSimple() const { return mClipArea->isSimple(); } - const ClipArea& getClipArea() const { return *mClipArea; } - ClipArea& mutateClipArea() { return *mClipArea; } - - WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip( - LinearAllocator& allocator, const ClipBase* recordedClip, - const Matrix4& recordedClipTransform); - void applyClip(const ClipBase* clip, const Matrix4& transform); - - /** - * Resets the clip to the specified rect. - */ - void resetClip(float left, float top, float right, float bottom); - - void initializeViewport(int width, int height) { - mViewportData.initialize(width, height); - mClipAreaRoot.setViewportDimensions(width, height); - } - - int getViewportWidth() const { return mViewportData.mWidth; } - int getViewportHeight() const { return mViewportData.mHeight; } - const Matrix4& getOrthoMatrix() const { return mViewportData.mOrthoMatrix; } - - const Vector3& getRelativeLightCenter() const { return mRelativeLightCenter; } - void setRelativeLightCenter(const Vector3& lightCenter) { mRelativeLightCenter = lightCenter; } - - /** - * Sets (and replaces) the current clipping outline - * - * If the current round rect clip is high priority, the incoming clip is ignored. - */ - void setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, float radius, - bool highPriority); - - /** - * Sets (and replaces) the current projection mask - */ - void setProjectionPathMask(const SkPath* path); - - /** - * Indicates whether the current transform has perspective components. - */ - bool hasPerspectiveTransform() const; - - /** - * Dirty flags. - */ - int flags; - - /** - * Previous snapshot. - */ - Snapshot* previous; - - /** - * A pointer to the currently active layer. - * - * This snapshot does not own the layer, this pointer must not be freed. - */ - Layer* layer; - - /** - * Target FBO used for rendering. Set to 0 when rendering directly - * into the framebuffer. - */ - GLuint fbo; - - /** - * Local transformation. Holds the current translation, scale and - * rotation values. - * - * This is a reference to a matrix owned by this snapshot or another - * snapshot. This pointer must not be freed. See ::mTransformRoot. - */ - mat4* transform; - - /** - * Current alpha value. This value is 1 by default, but may be set by a DisplayList which - * has translucent rendering in a non-overlapping View. This value will be used by - * the renderer to set the alpha in the current color being used for ensuing drawing - * operations. The value is inherited by child snapshots because the same value should - * be applied to descendants of the current DisplayList (for example, a TextView contains - * the base alpha value which should be applied to the child DisplayLists used for drawing - * the actual text). - */ - float alpha; - - /** - * Current clipping round rect. - * - * Points to data not owned by the snapshot, and may only be replaced by subsequent RR clips, - * never modified. - */ - const RoundRectClipState* roundRectClipState; - - /** - * Current projection masking path - used exclusively to mask projected, tessellated circles. - */ - const SkPath* projectionPathMask; - - void dump() const; - -private: - struct ViewportData { - ViewportData() : mWidth(0), mHeight(0) {} - void initialize(int width, int height) { - mWidth = width; - mHeight = height; - mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1); - } - - /* - * Width and height of current viewport. - * - * The viewport is always defined to be (0, 0, width, height). - */ - int mWidth; - int mHeight; - /** - * Contains the current orthographic, projection matrix. - */ - mat4 mOrthoMatrix; - }; - - mat4 mTransformRoot; - - ClipArea mClipAreaRoot; - ClipArea* mClipArea; - Rect mLocalClip; - - ViewportData mViewportData; - Vector3 mRelativeLightCenter; - -}; // class Snapshot - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h index a6aae55b2ee8..f0912777e3d8 100644 --- a/libs/hwui/Vertex.h +++ b/libs/hwui/Vertex.h @@ -19,7 +19,6 @@ #include "Vector.h" -#include "FloatColor.h" #include "utils/Macros.h" namespace android { diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index a00b8db3c617..c5db861d4f48 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -21,7 +21,6 @@ #include <Properties.h> #include <Rect.h> #include <RenderNode.h> -#include <Snapshot.h> #include <hwui/Bitmap.h> #include <pipeline/skia/SkiaRecordingCanvas.h> #include <private/hwui/DrawGlInfo.h> @@ -141,14 +140,6 @@ public: return true; } - static std::unique_ptr<Snapshot> makeSnapshot(const Matrix4& transform, const Rect& clip) { - std::unique_ptr<Snapshot> snapshot(new Snapshot()); - // store clip first, so it isn't transformed - snapshot->setClip(clip.left, clip.top, clip.right, clip.bottom); - *(snapshot->transform) = transform; - return snapshot; - } - static sk_sp<Bitmap> createBitmap(int width, int height, SkColorType colorType = kN32_SkColorType) { SkImageInfo info = SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType); diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp index 9388c2062736..70423a70157b 100644 --- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp +++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp @@ -16,7 +16,6 @@ #include <benchmark/benchmark.h> -#include "CanvasState.h" #include "DisplayList.h" #include "hwui/Canvas.h" #include "pipeline/skia/SkiaDisplayList.h" @@ -116,52 +115,6 @@ void BM_DisplayListCanvas_record_simpleBitmapView(benchmark::State& benchState) } BENCHMARK(BM_DisplayListCanvas_record_simpleBitmapView); -class NullClient : public CanvasStateClient { - void onViewportInitialized() override {} - void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {} - GLuint getTargetFbo() const override { return 0; } -}; - -void BM_CanvasState_saverestore(benchmark::State& benchState) { - NullClient client; - CanvasState state(client); - state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3()); - - while (benchState.KeepRunning()) { - state.save(SaveFlags::MatrixClip); - state.save(SaveFlags::MatrixClip); - benchmark::DoNotOptimize(&state); - state.restore(); - state.restore(); - } -} -BENCHMARK(BM_CanvasState_saverestore); - -void BM_CanvasState_init(benchmark::State& benchState) { - NullClient client; - CanvasState state(client); - state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3()); - - while (benchState.KeepRunning()) { - state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3()); - benchmark::DoNotOptimize(&state); - } -} -BENCHMARK(BM_CanvasState_init); - -void BM_CanvasState_translate(benchmark::State& benchState) { - NullClient client; - CanvasState state(client); - state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3()); - - while (benchState.KeepRunning()) { - state.translate(5, 5, 0); - benchmark::DoNotOptimize(&state); - state.translate(-5, -5, 0); - } -} -BENCHMARK(BM_CanvasState_translate); - void BM_DisplayListCanvas_basicViewGroupDraw(benchmark::State& benchState) { sp<RenderNode> child = TestUtils::createNode(50, 50, 100, 100, [](auto& props, auto& canvas) { canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); diff --git a/libs/hwui/tests/unit/CanvasStateTests.cpp b/libs/hwui/tests/unit/CanvasStateTests.cpp deleted file mode 100644 index 4c03811b0c96..000000000000 --- a/libs/hwui/tests/unit/CanvasStateTests.cpp +++ /dev/null @@ -1,160 +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 "CanvasState.h" - -#include "Matrix.h" -#include "Rect.h" -#include "hwui/Canvas.h" -#include "utils/LinearAllocator.h" - -#include <SkClipOp.h> -#include <SkPath.h> -#include <gtest/gtest.h> - -namespace android { -namespace uirenderer { - -class NullClient : public CanvasStateClient { - void onViewportInitialized() override {} - void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {} - GLuint getTargetFbo() const override { return 0; } -}; - -static NullClient sNullClient; - -static bool approxEqual(const Matrix4& a, const Matrix4& b) { - for (int i = 0; i < 16; i++) { - if (!MathUtils::areEqual(a[i], b[i])) { - return false; - } - } - return true; -} - -TEST(CanvasState, gettersAndSetters) { - CanvasState state(sNullClient); - state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3()); - - ASSERT_EQ(state.getWidth(), 200); - ASSERT_EQ(state.getHeight(), 200); - - Matrix4 simpleTranslate; - simpleTranslate.loadTranslate(10, 20, 0); - state.setMatrix(simpleTranslate); - - ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200)); - ASSERT_EQ(state.getLocalClipBounds(), Rect(-10, -20, 190, 180)); - EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate)); - EXPECT_TRUE(state.clipIsSimple()); -} - -TEST(CanvasState, simpleClipping) { - CanvasState state(sNullClient); - state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3()); - - state.clipRect(0, 0, 100, 100, SkClipOp::kIntersect); - ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(100, 100)); - - state.clipRect(10, 10, 200, 200, SkClipOp::kIntersect); - ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10, 100, 100)); - - state.clipRect(50, 50, 150, 150, SkClipOp::kReplace_deprecated); - ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(50, 50, 150, 150)); -} - -TEST(CanvasState, complexClipping) { - CanvasState state(sNullClient); - state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3()); - - state.save(SaveFlags::MatrixClip); - { - // rotated clip causes complex clip - state.rotate(10); - EXPECT_TRUE(state.clipIsSimple()); - state.clipRect(0, 0, 200, 200, SkClipOp::kIntersect); - EXPECT_FALSE(state.clipIsSimple()); - } - state.restore(); - - state.save(SaveFlags::MatrixClip); - { - // subtracted clip causes complex clip - EXPECT_TRUE(state.clipIsSimple()); - state.clipRect(50, 50, 150, 150, SkClipOp::kDifference); - EXPECT_FALSE(state.clipIsSimple()); - } - state.restore(); - - state.save(SaveFlags::MatrixClip); - { - // complex path causes complex clip - SkPath path; - path.addOval(SkRect::MakeWH(200, 200)); - EXPECT_TRUE(state.clipIsSimple()); - state.clipPath(&path, SkClipOp::kDifference); - EXPECT_FALSE(state.clipIsSimple()); - } - state.restore(); -} - -TEST(CanvasState, saveAndRestore) { - CanvasState state(sNullClient); - state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3()); - - state.save(SaveFlags::Clip); - { - state.clipRect(0, 0, 10, 10, SkClipOp::kIntersect); - ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10)); - } - state.restore(); - ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200)); // verify restore - - Matrix4 simpleTranslate; - simpleTranslate.loadTranslate(10, 10, 0); - state.save(SaveFlags::Matrix); - { - state.translate(10, 10, 0); - EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate)); - } - state.restore(); - EXPECT_FALSE(approxEqual(*state.currentTransform(), simpleTranslate)); -} - -TEST(CanvasState, saveAndRestoreButNotTooMuch) { - CanvasState state(sNullClient); - state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3()); - - state.save(SaveFlags::Matrix); // NOTE: clip not saved - { - state.clipRect(0, 0, 10, 10, SkClipOp::kIntersect); - ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10)); - } - state.restore(); - ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10)); // verify not restored - - Matrix4 simpleTranslate; - simpleTranslate.loadTranslate(10, 10, 0); - state.save(SaveFlags::Clip); // NOTE: matrix not saved - { - state.translate(10, 10, 0); - EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate)); - } - state.restore(); - EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate)); // verify not restored -} -} -} diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp deleted file mode 100644 index 450bb679a45f..000000000000 --- a/libs/hwui/tests/unit/ClipAreaTests.cpp +++ /dev/null @@ -1,353 +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 <SkPath.h> -#include <SkRegion.h> -#include <gtest/gtest.h> - -#include "ClipArea.h" - -#include "Matrix.h" -#include "Rect.h" -#include "utils/LinearAllocator.h" - -namespace android { -namespace uirenderer { - -static Rect kViewportBounds(2048, 2048); - -static ClipArea createClipArea() { - ClipArea area; - area.setViewportDimensions(kViewportBounds.getWidth(), kViewportBounds.getHeight()); - return area; -} - -TEST(TransformedRectangle, basics) { - Rect r(0, 0, 100, 100); - Matrix4 minus90; - minus90.loadRotate(-90); - minus90.mapRect(r); - Rect r2(20, 40, 120, 60); - - Matrix4 m90; - m90.loadRotate(90); - TransformedRectangle tr(r, m90); - EXPECT_TRUE(tr.canSimplyIntersectWith(tr)); - - Matrix4 m0; - TransformedRectangle tr0(r2, m0); - EXPECT_FALSE(tr.canSimplyIntersectWith(tr0)); - - Matrix4 m45; - m45.loadRotate(45); - TransformedRectangle tr2(r, m45); - EXPECT_FALSE(tr2.canSimplyIntersectWith(tr)); -} - -TEST(RectangleList, basics) { - RectangleList list; - EXPECT_TRUE(list.isEmpty()); - - Rect r(0, 0, 100, 100); - Matrix4 m45; - m45.loadRotate(45); - list.set(r, m45); - EXPECT_FALSE(list.isEmpty()); - - Rect r2(20, 20, 200, 200); - list.intersectWith(r2, m45); - EXPECT_FALSE(list.isEmpty()); - EXPECT_EQ(1, list.getTransformedRectanglesCount()); - - Rect r3(20, 20, 200, 200); - Matrix4 m30; - m30.loadRotate(30); - list.intersectWith(r2, m30); - EXPECT_FALSE(list.isEmpty()); - EXPECT_EQ(2, list.getTransformedRectanglesCount()); - - SkRegion clip; - clip.setRect(0, 0, 2000, 2000); - SkRegion rgn(list.convertToRegion(clip)); - EXPECT_FALSE(rgn.isEmpty()); -} - -TEST(ClipArea, basics) { - ClipArea area(createClipArea()); - EXPECT_FALSE(area.isEmpty()); -} - -TEST(ClipArea, paths) { - ClipArea area(createClipArea()); - SkPath path; - SkScalar r = 100; - path.addCircle(r, r, r); - area.clipPathWithTransform(path, &Matrix4::identity(), SkRegion::kIntersect_Op); - EXPECT_FALSE(area.isEmpty()); - EXPECT_FALSE(area.isSimple()); - EXPECT_FALSE(area.isRectangleList()); - - Rect clipRect(area.getClipRect()); - Rect expected(0, 0, r * 2, r * 2); - EXPECT_EQ(expected, clipRect); - SkRegion clipRegion(area.getClipRegion()); - auto skRect(clipRegion.getBounds()); - Rect regionBounds; - regionBounds.set(skRect); - EXPECT_EQ(expected, regionBounds); -} - -TEST(ClipArea, replaceNegative) { - ClipArea area(createClipArea()); - area.setClip(0, 0, 100, 100); - - Rect expected(-50, -50, 50, 50); - area.clipRectWithTransform(expected, &Matrix4::identity(), SkRegion::kReplace_Op); - EXPECT_EQ(expected, area.getClipRect()); -} - -TEST(ClipArea, serializeClip) { - ClipArea area(createClipArea()); - LinearAllocator allocator; - - // unset clip - EXPECT_EQ(nullptr, area.serializeClip(allocator)); - - // rect clip - area.setClip(0, 0, 200, 200); - { - auto serializedClip = area.serializeClip(allocator); - ASSERT_NE(nullptr, serializedClip); - ASSERT_EQ(ClipMode::Rectangle, serializedClip->mode); - ASSERT_FALSE(serializedClip->intersectWithRoot) << "No replace, so no intersectWithRoot"; - EXPECT_EQ(Rect(200, 200), serializedClip->rect); - EXPECT_EQ(serializedClip, area.serializeClip(allocator)) - << "Requery of clip on unmodified ClipArea must return same pointer."; - } - - // rect list - Matrix4 rotate; - rotate.loadRotate(5.0f); - area.clipRectWithTransform(Rect(50, 50, 150, 150), &rotate, SkRegion::kIntersect_Op); - { - auto serializedClip = area.serializeClip(allocator); - ASSERT_NE(nullptr, serializedClip); - ASSERT_EQ(ClipMode::RectangleList, serializedClip->mode); - ASSERT_FALSE(serializedClip->intersectWithRoot) << "No replace, so no intersectWithRoot"; - auto clipRectList = reinterpret_cast<const ClipRectList*>(serializedClip); - EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount()); - EXPECT_EQ(Rect(37, 54, 145, 163), clipRectList->rect); - EXPECT_EQ(serializedClip, area.serializeClip(allocator)) - << "Requery of clip on unmodified ClipArea must return same pointer."; - } - - // region - SkPath circlePath; - circlePath.addCircle(100, 100, 100); - area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kReplace_Op); - { - auto serializedClip = area.serializeClip(allocator); - ASSERT_NE(nullptr, serializedClip); - ASSERT_EQ(ClipMode::Region, serializedClip->mode); - ASSERT_TRUE(serializedClip->intersectWithRoot) << "Replace op, so expect intersectWithRoot"; - auto clipRegion = reinterpret_cast<const ClipRegion*>(serializedClip); - EXPECT_EQ(SkIRect::MakeWH(200, 200), clipRegion->region.getBounds()) - << "Clip region should be 200x200"; - EXPECT_EQ(Rect(200, 200), clipRegion->rect); - EXPECT_EQ(serializedClip, area.serializeClip(allocator)) - << "Requery of clip on unmodified ClipArea must return same pointer."; - } -} - -TEST(ClipArea, serializeClip_pathIntersectWithRoot) { - ClipArea area(createClipArea()); - LinearAllocator allocator; - SkPath circlePath; - circlePath.addCircle(100, 100, 100); - area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kIntersect_Op); - - auto serializedClip = area.serializeClip(allocator); - ASSERT_NE(nullptr, serializedClip); - EXPECT_FALSE(serializedClip->intersectWithRoot) << "No replace, so no intersectWithRoot"; -} - -TEST(ClipArea, serializeIntersectedClip) { - ClipArea area(createClipArea()); - LinearAllocator allocator; - - // simple state; - EXPECT_EQ(nullptr, area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity())); - area.setClip(0, 0, 200, 200); - { - auto origRectClip = area.serializeClip(allocator); - ASSERT_NE(nullptr, origRectClip); - EXPECT_EQ(origRectClip, - area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity())); - } - - // rect - { - ClipRect recordedClip(Rect(100, 100)); - Matrix4 translateScale; - translateScale.loadTranslate(100, 100, 0); - translateScale.scale(2, 3, 1); - auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale); - ASSERT_NE(nullptr, resolvedClip); - ASSERT_EQ(ClipMode::Rectangle, resolvedClip->mode); - EXPECT_EQ(Rect(100, 100, 200, 200), resolvedClip->rect); - - EXPECT_EQ(resolvedClip, - area.serializeIntersectedClip(allocator, &recordedClip, translateScale)) - << "Must return previous serialization, since input is same"; - - ClipRect recordedClip2(Rect(100, 100)); - EXPECT_NE(resolvedClip, - area.serializeIntersectedClip(allocator, &recordedClip2, translateScale)) - << "Shouldn't return previous serialization, since matrix location is different"; - } - - // rect list - Matrix4 rotate; - rotate.loadRotate(2.0f); - area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op); - { - ClipRect recordedClip(Rect(100, 100)); - auto resolvedClip = - area.serializeIntersectedClip(allocator, &recordedClip, Matrix4::identity()); - ASSERT_NE(nullptr, resolvedClip); - ASSERT_EQ(ClipMode::RectangleList, resolvedClip->mode); - auto clipRectList = reinterpret_cast<const ClipRectList*>(resolvedClip); - EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount()); - } - - // region - SkPath circlePath; - circlePath.addCircle(100, 100, 100); - area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kReplace_Op); - { - SkPath ovalPath; - ovalPath.addOval(SkRect::MakeLTRB(50, 0, 150, 200)); - - ClipRegion recordedClip; - recordedClip.region.setPath(ovalPath, SkRegion(SkIRect::MakeWH(200, 200))); - recordedClip.rect = Rect(200, 200); - - Matrix4 translate10x20; - translate10x20.loadTranslate(10, 20, 0); - auto resolvedClip = area.serializeIntersectedClip( - allocator, &recordedClip, - translate10x20); // Note: only translate for now, others not handled correctly - ASSERT_NE(nullptr, resolvedClip); - ASSERT_EQ(ClipMode::Region, resolvedClip->mode); - auto clipRegion = reinterpret_cast<const ClipRegion*>(resolvedClip); - EXPECT_EQ(SkIRect::MakeLTRB(60, 20, 160, 200), clipRegion->region.getBounds()); - } -} - -TEST(ClipArea, serializeIntersectedClip_snap) { - ClipArea area(createClipArea()); - area.setClip(100.2, 100.4, 500.6, 500.8); - LinearAllocator allocator; - - { - // no recorded clip case - auto resolvedClip = area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()); - EXPECT_EQ(Rect(100, 100, 501, 501), resolvedClip->rect); - } - { - // recorded clip case - ClipRect recordedClip(Rect(100.12, 100.74)); - Matrix4 translateScale; - translateScale.loadTranslate(100, 100, 0); - translateScale.scale(2, 3, - 1); // recorded clip will have non-int coords, even after transform - auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale); - ASSERT_NE(nullptr, resolvedClip); - EXPECT_EQ(ClipMode::Rectangle, resolvedClip->mode); - EXPECT_EQ(Rect(100, 100, 300, 402), resolvedClip->rect); - } -} - -TEST(ClipArea, serializeIntersectedClip_scale) { - ClipArea area(createClipArea()); - area.setClip(0, 0, 400, 400); - LinearAllocator allocator; - - SkPath circlePath; - circlePath.addCircle(50, 50, 50); - - ClipRegion recordedClip; - recordedClip.region.setPath(circlePath, SkRegion(SkIRect::MakeWH(100, 100))); - recordedClip.rect = Rect(100, 100); - - Matrix4 translateScale; - translateScale.loadTranslate(100, 100, 0); - translateScale.scale(2, 2, 1); - auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale); - - ASSERT_NE(nullptr, resolvedClip); - EXPECT_EQ(ClipMode::Region, resolvedClip->mode); - EXPECT_EQ(Rect(100, 100, 300, 300), resolvedClip->rect); - auto clipRegion = reinterpret_cast<const ClipRegion*>(resolvedClip); - EXPECT_EQ(SkIRect::MakeLTRB(100, 100, 300, 300), clipRegion->region.getBounds()); -} - -TEST(ClipArea, applyTransformToRegion_identity) { - SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4)); - ClipArea::applyTransformToRegion(Matrix4::identity(), ®ion); - EXPECT_TRUE(region.isRect()); - EXPECT_EQ(SkIRect::MakeLTRB(1, 2, 3, 4), region.getBounds()); -} - -TEST(ClipArea, applyTransformToRegion_translate) { - SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4)); - Matrix4 transform; - transform.loadTranslate(10, 20, 0); - ClipArea::applyTransformToRegion(transform, ®ion); - EXPECT_TRUE(region.isRect()); - EXPECT_EQ(SkIRect::MakeLTRB(11, 22, 13, 24), region.getBounds()); -} - -TEST(ClipArea, applyTransformToRegion_scale) { - SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4)); - Matrix4 transform; - transform.loadScale(2, 3, 1); - ClipArea::applyTransformToRegion(transform, ®ion); - EXPECT_TRUE(region.isRect()); - EXPECT_EQ(SkIRect::MakeLTRB(2, 6, 6, 12), region.getBounds()); -} - -TEST(ClipArea, applyTransformToRegion_translateScale) { - SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4)); - Matrix4 transform; - transform.translate(10, 20); - transform.scale(2, 3, 1); - ClipArea::applyTransformToRegion(transform, ®ion); - EXPECT_TRUE(region.isRect()); - EXPECT_EQ(SkIRect::MakeLTRB(12, 26, 16, 32), region.getBounds()); -} - -TEST(ClipArea, applyTransformToRegion_rotate90) { - SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4)); - Matrix4 transform; - transform.loadRotate(90); - ClipArea::applyTransformToRegion(transform, ®ion); - EXPECT_TRUE(region.isRect()); - EXPECT_EQ(SkIRect::MakeLTRB(-4, 1, -2, 3), region.getBounds()); -} - -} // namespace uirenderer -} // namespace android diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp index 2926ef3a2d95..2c73940b9b9c 100644 --- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp @@ -32,6 +32,7 @@ #include "pipeline/skia/SkiaRecordingCanvas.h" #include "renderthread/CanvasContext.h" #include "tests/common/TestUtils.h" +#include "utils/Color.h" using namespace android; using namespace android::uirenderer; diff --git a/libs/hwui/tests/unit/SnapshotTests.cpp b/libs/hwui/tests/unit/SnapshotTests.cpp deleted file mode 100644 index 9d673c82d4d0..000000000000 --- a/libs/hwui/tests/unit/SnapshotTests.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2016 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 <gtest/gtest.h> - -#include <Snapshot.h> - -#include <tests/common/TestUtils.h> - -using namespace android::uirenderer; - -TEST(Snapshot, serializeIntersectedClip) { - auto actualRoot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(0, 0, 100, 100)); - auto root = TestUtils::makeSnapshot(Matrix4::identity(), Rect(10, 10, 90, 90)); - auto child = TestUtils::makeSnapshot(Matrix4::identity(), Rect(50, 50, 90, 90)); - root->previous = actualRoot.get(); - child->previous = root.get(); - - LinearAllocator allocator; - ClipRect rect(Rect(0, 0, 75, 75)); - { - auto intersectWithChild = - child->serializeIntersectedClip(allocator, &rect, Matrix4::identity()); - ASSERT_NE(nullptr, intersectWithChild); - EXPECT_EQ(Rect(50, 50, 75, 75), intersectWithChild->rect) << "Expect intersect with child"; - } - - rect.intersectWithRoot = true; - { - auto intersectWithRoot = - child->serializeIntersectedClip(allocator, &rect, Matrix4::identity()); - ASSERT_NE(nullptr, intersectWithRoot); - EXPECT_EQ(Rect(10, 10, 75, 75), intersectWithRoot->rect) << "Expect intersect with root"; - } -} - -TEST(Snapshot, applyClip) { - auto actualRoot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(0, 0, 100, 100)); - auto root = TestUtils::makeSnapshot(Matrix4::identity(), Rect(10, 10, 90, 90)); - root->previous = actualRoot.get(); - - ClipRect rect(Rect(0, 0, 75, 75)); - { - auto child = TestUtils::makeSnapshot(Matrix4::identity(), Rect(50, 50, 90, 90)); - child->previous = root.get(); - child->applyClip(&rect, Matrix4::identity()); - - EXPECT_TRUE(child->getClipArea().isSimple()); - EXPECT_EQ(Rect(50, 50, 75, 75), child->getRenderTargetClip()); - } - - { - rect.intersectWithRoot = true; - auto child = TestUtils::makeSnapshot(Matrix4::identity(), Rect(50, 50, 90, 90)); - child->previous = root.get(); - child->applyClip(&rect, Matrix4::identity()); - - EXPECT_TRUE(child->getClipArea().isSimple()); - EXPECT_EQ(Rect(10, 10, 75, 75), child->getRenderTargetClip()); - } -} |