| /* |
| * 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 <VectorDrawable.h> |
| #include <gtest/gtest.h> |
| |
| #include <SkCanvas.h> |
| #include <SkClipStack.h> |
| #include <SkSurface_Base.h> |
| #include <string.h> |
| #include "AnimationContext.h" |
| #include "DamageAccumulator.h" |
| #include "FatalTestCanvas.h" |
| #include "IContextFactory.h" |
| #include "hwui/Paint.h" |
| #include "SkiaCanvas.h" |
| #include "pipeline/skia/SkiaDisplayList.h" |
| #include "pipeline/skia/SkiaPipeline.h" |
| #include "pipeline/skia/SkiaRecordingCanvas.h" |
| #include "renderthread/CanvasContext.h" |
| #include "tests/common/TestUtils.h" |
| |
| using namespace android; |
| using namespace android::uirenderer; |
| using namespace android::uirenderer::renderthread; |
| using namespace android::uirenderer::skiapipeline; |
| |
| namespace { |
| |
| static void testProperty(std::function<void(RenderProperties&)> propSetupCallback, |
| std::function<void(const SkCanvas&)> opValidateCallback) { |
| static const int CANVAS_WIDTH = 100; |
| static const int CANVAS_HEIGHT = 100; |
| class PropertyTestCanvas : public TestCanvasBase { |
| public: |
| explicit PropertyTestCanvas(std::function<void(const SkCanvas&)> callback) |
| : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT), mCallback(callback) {} |
| void onDrawRect(const SkRect& rect, const SkPaint& paint) override { |
| EXPECT_EQ(mDrawCounter++, 0); |
| mCallback(*this); |
| } |
| void onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle style) { |
| SkCanvas::onClipRRect(rrect, op, style); |
| } |
| std::function<void(const SkCanvas&)> mCallback; |
| }; |
| |
| auto node = TestUtils::createSkiaNode( |
| 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, |
| [propSetupCallback](RenderProperties& props, SkiaRecordingCanvas& canvas) { |
| propSetupCallback(props); |
| Paint paint; |
| paint.setColor(SK_ColorWHITE); |
| canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint); |
| }); |
| |
| PropertyTestCanvas canvas(opValidateCallback); |
| RenderNodeDrawable drawable(node.get(), &canvas, true); |
| canvas.drawDrawable(&drawable); |
| EXPECT_EQ(1, canvas.mDrawCounter); |
| } |
| } |
| |
| TEST(RenderNodeDrawable, renderPropClipping) { |
| testProperty( |
| [](RenderProperties& properties) { |
| properties.setClipToBounds(true); |
| properties.setClipBounds(android::uirenderer::Rect(10, 20, 300, 400)); |
| }, |
| [](const SkCanvas& canvas) { |
| EXPECT_EQ(SkRect::MakeLTRB(10, 20, 100, 100), TestUtils::getClipBounds(&canvas)) |
| << "Clip rect should be intersection of node bounds and clip bounds"; |
| }); |
| } |
| |
| TEST(RenderNodeDrawable, renderPropRevealClip) { |
| testProperty( |
| [](RenderProperties& properties) { |
| properties.mutableRevealClip().set(true, 50, 50, 25); |
| }, |
| [](const SkCanvas& canvas) { |
| EXPECT_EQ(SkRect::MakeLTRB(25, 25, 75, 75), TestUtils::getClipBounds(&canvas)); |
| }); |
| } |
| |
| TEST(RenderNodeDrawable, renderPropOutlineClip) { |
| testProperty( |
| [](RenderProperties& properties) { |
| properties.mutableOutline().setShouldClip(true); |
| properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f); |
| }, |
| [](const SkCanvas& canvas) { |
| EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(&canvas)); |
| }); |
| } |
| |
| TEST(RenderNodeDrawable, renderPropTransform) { |
| testProperty( |
| [](RenderProperties& properties) { |
| properties.setLeftTopRightBottom(10, 10, 110, 110); |
| |
| SkMatrix staticMatrix = SkMatrix::Scale(1.2f, 1.2f); |
| properties.setStaticMatrix(&staticMatrix); |
| |
| // ignored, since static overrides animation |
| SkMatrix animationMatrix = SkMatrix::Translate(15, 15); |
| properties.setAnimationMatrix(&animationMatrix); |
| |
| properties.setTranslationX(10); |
| properties.setTranslationY(20); |
| properties.setScaleX(0.5f); |
| properties.setScaleY(0.7f); |
| }, |
| [](const SkCanvas& canvas) { |
| Matrix4 matrix; |
| matrix.loadTranslate(10, 10, 0); // left, top |
| matrix.scale(1.2f, 1.2f, 1); // static matrix |
| // ignore animation matrix, since static overrides it |
| |
| // translation xy |
| matrix.translate(10, 20); |
| |
| // scale xy (from default pivot - center) |
| matrix.translate(50, 50); |
| matrix.scale(0.5f, 0.7f, 1); |
| matrix.translate(-50, -50); |
| Matrix4 actual(canvas.getTotalMatrix()); |
| EXPECT_MATRIX_APPROX_EQ(matrix, actual) << "Op draw matrix must match expected " |
| "combination of transformation " |
| "properties"; |
| }); |
| } |