diff options
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/androidfw/Asset.cpp | 92 | ||||
| -rw-r--r-- | libs/androidfw/AssetManager.cpp | 2 | ||||
| -rw-r--r-- | libs/androidfw/LocaleData.cpp | 31 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/Asset.h | 15 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/AssetManager.h | 6 | ||||
| -rw-r--r-- | libs/androidfw/tests/Android.mk | 1 | ||||
| -rw-r--r-- | libs/androidfw/tests/Asset_test.cpp | 37 | ||||
| -rw-r--r-- | libs/androidfw/tests/ConfigLocale_test.cpp | 67 | ||||
| -rw-r--r-- | libs/hwui/FrameBuilder.cpp | 2 | ||||
| -rw-r--r-- | libs/hwui/Interpolator.cpp | 3 | ||||
| -rw-r--r-- | libs/hwui/VectorDrawable.cpp | 2 | ||||
| -rw-r--r-- | libs/hwui/VectorDrawable.h | 13 | ||||
| -rw-r--r-- | libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp | 68 | ||||
| -rw-r--r-- | libs/hwui/tests/unit/FrameBuilderTests.cpp | 29 |
14 files changed, 247 insertions, 121 deletions
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp index 2cfa6666e9ab..8e8c6a2e25a2 100644 --- a/libs/androidfw/Asset.cpp +++ b/libs/androidfw/Asset.cpp @@ -52,6 +52,47 @@ static int32_t gCount = 0; static Asset* gHead = NULL; static Asset* gTail = NULL; +void Asset::registerAsset(Asset* asset) +{ + AutoMutex _l(gAssetLock); + gCount++; + asset->mNext = asset->mPrev = NULL; + if (gTail == NULL) { + gHead = gTail = asset; + } else { + asset->mPrev = gTail; + gTail->mNext = asset; + gTail = asset; + } + + if (kIsDebug) { + ALOGI("Creating Asset %p #%d\n", asset, gCount); + } +} + +void Asset::unregisterAsset(Asset* asset) +{ + AutoMutex _l(gAssetLock); + gCount--; + if (gHead == asset) { + gHead = asset->mNext; + } + if (gTail == asset) { + gTail = asset->mPrev; + } + if (asset->mNext != NULL) { + asset->mNext->mPrev = asset->mPrev; + } + if (asset->mPrev != NULL) { + asset->mPrev->mNext = asset->mNext; + } + asset->mNext = asset->mPrev = NULL; + + if (kIsDebug) { + ALOGI("Destroying Asset in %p #%d\n", asset, gCount); + } +} + int32_t Asset::getGlobalCount() { AutoMutex _l(gAssetLock); @@ -79,43 +120,8 @@ String8 Asset::getAssetAllocations() } Asset::Asset(void) - : mAccessMode(ACCESS_UNKNOWN) + : mAccessMode(ACCESS_UNKNOWN), mNext(NULL), mPrev(NULL) { - AutoMutex _l(gAssetLock); - gCount++; - mNext = mPrev = NULL; - if (gTail == NULL) { - gHead = gTail = this; - } else { - mPrev = gTail; - gTail->mNext = this; - gTail = this; - } - if (kIsDebug) { - ALOGI("Creating Asset %p #%d\n", this, gCount); - } -} - -Asset::~Asset(void) -{ - AutoMutex _l(gAssetLock); - gCount--; - if (gHead == this) { - gHead = mNext; - } - if (gTail == this) { - gTail = mPrev; - } - if (mNext != NULL) { - mNext->mPrev = mPrev; - } - if (mPrev != NULL) { - mPrev->mNext = mNext; - } - mNext = mPrev = NULL; - if (kIsDebug) { - ALOGI("Destroying Asset in %p #%d\n", this, gCount); - } } /* @@ -361,6 +367,9 @@ off64_t Asset::handleSeek(off64_t offset, int whence, off64_t curPosn, off64_t m _FileAsset::_FileAsset(void) : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mMap(NULL), mBuf(NULL) { + // Register the Asset with the global list here after it is fully constructed and its + // vtable pointer points to this concrete type. b/31113965 + registerAsset(this); } /* @@ -369,6 +378,10 @@ _FileAsset::_FileAsset(void) _FileAsset::~_FileAsset(void) { close(); + + // Unregister the Asset from the global list here before it is destructed and while its vtable + // pointer still points to this concrete type. b/31113965 + unregisterAsset(this); } /* @@ -685,6 +698,9 @@ _CompressedAsset::_CompressedAsset(void) : mStart(0), mCompressedLen(0), mUncompressedLen(0), mOffset(0), mMap(NULL), mFd(-1), mZipInflater(NULL), mBuf(NULL) { + // Register the Asset with the global list here after it is fully constructed and its + // vtable pointer points to this concrete type. b/31113965 + registerAsset(this); } /* @@ -693,6 +709,10 @@ _CompressedAsset::_CompressedAsset(void) _CompressedAsset::~_CompressedAsset(void) { close(); + + // Unregister the Asset from the global list here before it is destructed and while its vtable + // pointer still points to this concrete type. b/31113965 + unregisterAsset(this); } /* diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 81e91a80783b..80968e51d48c 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -79,7 +79,7 @@ static volatile int32_t gCount = 0; const char* AssetManager::RESOURCES_FILENAME = "resources.arsc"; const char* AssetManager::IDMAP_BIN = "/system/bin/idmap"; const char* AssetManager::OVERLAY_DIR = "/vendor/overlay"; -const char* AssetManager::OVERLAY_SKU_DIR_PROPERTY = "ro.boot.vendor.overlay.sku"; +const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme"; const char* AssetManager::TARGET_PACKAGE_NAME = "android"; const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk"; const char* AssetManager::IDMAP_DIR = "/data/resource-cache"; diff --git a/libs/androidfw/LocaleData.cpp b/libs/androidfw/LocaleData.cpp index 038ef5839fe2..889d166d853b 100644 --- a/libs/androidfw/LocaleData.cpp +++ b/libs/androidfw/LocaleData.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <array> #include <cstdint> #include <cstdlib> #include <cstring> @@ -121,6 +122,16 @@ inline bool isRepresentative(uint32_t language_and_region, const char* script) { return (REPRESENTATIVE_LOCALES.count(packed_locale) != 0); } +const uint32_t US_SPANISH = 0x65735553lu; // es-US +const uint32_t MEXICAN_SPANISH = 0x65734D58lu; // es-MX +const uint32_t LATIN_AMERICAN_SPANISH = 0x6573A424lu; // es-419 + +// The two locales es-US and es-MX are treated as special fallbacks for es-419. +// If there is no es-419, they are considered its equivalent. +inline bool isSpecialSpanish(uint32_t language_and_region) { + return (language_and_region == US_SPANISH || language_and_region == MEXICAN_SPANISH); +} + int localeDataCompareRegions( const char* left_region, const char* right_region, const char* requested_language, const char* requested_script, @@ -129,18 +140,30 @@ int localeDataCompareRegions( if (left_region[0] == right_region[0] && left_region[1] == right_region[1]) { return 0; } - const uint32_t left = packLocale(requested_language, left_region); - const uint32_t right = packLocale(requested_language, right_region); + uint32_t left = packLocale(requested_language, left_region); + uint32_t right = packLocale(requested_language, right_region); const uint32_t request = packLocale(requested_language, requested_region); + // If one and only one of the two locales is a special Spanish locale, we + // replace it with es-419. We don't do the replacement if the other locale + // is already es-419, or both locales are special Spanish locales (when + // es-US is being compared to es-MX). + const bool leftIsSpecialSpanish = isSpecialSpanish(left); + const bool rightIsSpecialSpanish = isSpecialSpanish(right); + if (leftIsSpecialSpanish && !rightIsSpecialSpanish && right != LATIN_AMERICAN_SPANISH) { + left = LATIN_AMERICAN_SPANISH; + } else if (rightIsSpecialSpanish && !leftIsSpecialSpanish && left != LATIN_AMERICAN_SPANISH) { + right = LATIN_AMERICAN_SPANISH; + } + uint32_t request_ancestors[MAX_PARENT_DEPTH+1]; ssize_t left_right_index; // Find the parents of the request, but stop as soon as we saw left or right - const uint32_t left_and_right[] = {left, right}; + const std::array<uint32_t, 2> left_and_right = {{left, right}}; const size_t ancestor_count = findAncestors( request_ancestors, &left_right_index, request, requested_script, - left_and_right, sizeof(left_and_right)/sizeof(left_and_right[0])); + left_and_right.data(), left_and_right.size()); if (left_right_index == 0) { // We saw left earlier return 1; } diff --git a/libs/androidfw/include/androidfw/Asset.h b/libs/androidfw/include/androidfw/Asset.h index 36efbe5a48e9..2cd8c0bf3c78 100644 --- a/libs/androidfw/include/androidfw/Asset.h +++ b/libs/androidfw/include/androidfw/Asset.h @@ -44,7 +44,7 @@ namespace android { */ class Asset { public: - virtual ~Asset(void); + virtual ~Asset(void) = default; static int32_t getGlobalCount(); static String8 getAssetAllocations(); @@ -119,6 +119,19 @@ public: const char* getAssetSource(void) const { return mAssetSource.string(); } protected: + /* + * Adds this Asset to the global Asset list for debugging and + * accounting. + * Concrete subclasses must call this in their constructor. + */ + static void registerAsset(Asset* asset); + + /* + * Removes this Asset from the global Asset list. + * Concrete subclasses must call this in their destructor. + */ + static void unregisterAsset(Asset* asset); + Asset(void); // constructor; only invoked indirectly /* handle common seek() housekeeping */ diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h index b39dccf44a8b..594dba5049dd 100644 --- a/libs/androidfw/include/androidfw/AssetManager.h +++ b/libs/androidfw/include/androidfw/AssetManager.h @@ -64,11 +64,11 @@ public: static const char* IDMAP_BIN; static const char* OVERLAY_DIR; /* - * If OVERLAY_SKU_DIR_PROPERTY is set, search for runtime resource overlay - * APKs in OVERLAY_DIR/<value of OVERLAY_SKU_DIR_PROPERTY> rather than in + * If OVERLAY_THEME_DIR_PROPERTY is set, search for runtime resource overlay + * APKs in OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to * OVERLAY_DIR. */ - static const char* OVERLAY_SKU_DIR_PROPERTY; + static const char* OVERLAY_THEME_DIR_PROPERTY; static const char* TARGET_PACKAGE_NAME; static const char* TARGET_APK_PATH; static const char* IDMAP_DIR; diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk index 2bc026b79ca2..1fe1773578fa 100644 --- a/libs/androidfw/tests/Android.mk +++ b/libs/androidfw/tests/Android.mk @@ -22,6 +22,7 @@ LOCAL_PATH:= $(call my-dir) testFiles := \ AppAsLib_test.cpp \ + Asset_test.cpp \ AttributeFinder_test.cpp \ ByteBucketArray_test.cpp \ Config_test.cpp \ diff --git a/libs/androidfw/tests/Asset_test.cpp b/libs/androidfw/tests/Asset_test.cpp new file mode 100644 index 000000000000..45c8cef92918 --- /dev/null +++ b/libs/androidfw/tests/Asset_test.cpp @@ -0,0 +1,37 @@ +/* + * 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 <androidfw/Asset.h> + +#include <gtest/gtest.h> + +using namespace android; + +TEST(AssetTest, FileAssetRegistersItself) { + const int32_t count = Asset::getGlobalCount(); + Asset* asset = new _FileAsset(); + EXPECT_EQ(count + 1, Asset::getGlobalCount()); + delete asset; + EXPECT_EQ(count, Asset::getGlobalCount()); +} + +TEST(AssetTest, CompressedAssetRegistersItself) { + const int32_t count = Asset::getGlobalCount(); + Asset* asset = new _CompressedAsset(); + EXPECT_EQ(count + 1, Asset::getGlobalCount()); + delete asset; + EXPECT_EQ(count, Asset::getGlobalCount()); +} diff --git a/libs/androidfw/tests/ConfigLocale_test.cpp b/libs/androidfw/tests/ConfigLocale_test.cpp index 2bf9b12b6ce5..10f4d46058ec 100644 --- a/libs/androidfw/tests/ConfigLocale_test.cpp +++ b/libs/androidfw/tests/ConfigLocale_test.cpp @@ -470,15 +470,80 @@ TEST(ConfigLocaleTest, isLocaleBetterThan_regionComparison) { EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "AR", NULL, NULL, &request); + fillIn("es", "US", NULL, NULL, &config1); + fillIn("es", NULL, NULL, NULL, &config2); + // Special case for Latin American Spanish: es-MX and es-US are + // pseudo-parents of all Latin Ameircan Spanish locales. + EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); + EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); + + fillIn("es", "MX", NULL, NULL, &request); + fillIn("es", "US", NULL, NULL, &config1); + fillIn("es", NULL, NULL, NULL, &config2); + // Special case for Latin American Spanish: es-MX and es-US are + // pseudo-parents of all Latin Ameircan Spanish locales. + EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); + EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); + + fillIn("es", "AR", NULL, NULL, &request); + fillIn("es", "MX", NULL, NULL, &config1); + fillIn("es", NULL, NULL, NULL, &config2); + // Special case for Latin American Spanish: es-MX and es-US are + // pseudo-parents of all Latin Ameircan Spanish locales. + EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); + EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); + + fillIn("es", "US", NULL, NULL, &request); + fillIn("es", "MX", NULL, NULL, &config1); + fillIn("es", NULL, NULL, NULL, &config2); + // Special case for Latin American Spanish: es-MX and es-US are + // pseudo-parents of all Latin Ameircan Spanish locales. + EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); + EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); + + fillIn("es", "AR", NULL, NULL, &request); + fillIn("es", "419", NULL, NULL, &config1); + fillIn("es", "MX", NULL, NULL, &config2); + // Even though es-MX and es-US are pseudo-parents of all Latin Ameircan + // Spanish locales, es-419 is a closer parent. + EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); + EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); + + fillIn("es", "US", NULL, NULL, &request); + fillIn("es", "419", NULL, NULL, &config1); + fillIn("es", "MX", NULL, NULL, &config2); + // Even though es-MX and es-US are pseudo-parents of all Latin Ameircan + // Spanish locales, es-419 is a closer parent. + EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); + EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); + + fillIn("es", "MX", NULL, NULL, &request); + fillIn("es", "419", NULL, NULL, &config1); + fillIn("es", "US", NULL, NULL, &config2); + // Even though es-MX and es-US are pseudo-parents of all Latin Ameircan + // Spanish locales, es-419 is a closer parent. + EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); + EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); + + fillIn("es", "AR", NULL, NULL, &request); fillIn("es", "MX", NULL, NULL, &config1); fillIn("es", "BO", NULL, NULL, &config2); - // A representative locale is better if they are equidistant. + // Special case for Latin American Spanish: es-MX and es-US are + // pseudo-parents of all Latin Ameircan Spanish locales. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "AR", NULL, NULL, &request); fillIn("es", "US", NULL, NULL, &config1); fillIn("es", "BO", NULL, NULL, &config2); + // Special case for Latin American Spanish: es-MX and es-US are + // pseudo-parents of all Latin Ameircan Spanish locales. + EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); + EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); + + fillIn("es", "IC", NULL, NULL, &request); + fillIn("es", "ES", NULL, NULL, &config1); + fillIn("es", "GQ", NULL, NULL, &config2); // A representative locale is better if they are equidistant. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp index 37d9d0e749e6..7524ba0dcea6 100644 --- a/libs/hwui/FrameBuilder.cpp +++ b/libs/hwui/FrameBuilder.cpp @@ -591,7 +591,7 @@ void FrameBuilder::deferArcOp(const ArcOp& op) { } static bool hasMergeableClip(const BakedOpState& state) { - return state.computedState.clipState + return !state.computedState.clipState || state.computedState.clipState->mode == ClipMode::Rectangle; } diff --git a/libs/hwui/Interpolator.cpp b/libs/hwui/Interpolator.cpp index 9af8eeba14a0..b5a33afccdc7 100644 --- a/libs/hwui/Interpolator.cpp +++ b/libs/hwui/Interpolator.cpp @@ -98,7 +98,8 @@ LUTInterpolator::~LUTInterpolator() { } float LUTInterpolator::interpolate(float input) { - float lutpos = input * mSize; + // lut position should only be at the end of the table when input is 1f. + float lutpos = input * (mSize - 1); if (lutpos >= (mSize - 1)) { return mValues[mSize - 1]; } diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp index aeee66106fb3..223605fa34ed 100644 --- a/libs/hwui/VectorDrawable.cpp +++ b/libs/hwui/VectorDrawable.cpp @@ -576,7 +576,7 @@ bool Tree::allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height) { } bool Tree::canReuseBitmap(const SkBitmap& bitmap, int width, int height) { - return width == bitmap.width() && height == bitmap.height(); + return width <= bitmap.width() && height <= bitmap.height(); } void Tree::onPropertyChanged(TreeProperties* prop) { diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h index 6c1815fe1301..b867dbc59714 100644 --- a/libs/hwui/VectorDrawable.h +++ b/libs/hwui/VectorDrawable.h @@ -622,10 +622,15 @@ public: } void setScaledSize(int width, int height) { - if (mNonAnimatableProperties.scaledWidth != width - || mNonAnimatableProperties.scaledHeight != height) { - mNonAnimatableProperties.scaledWidth = width; - mNonAnimatableProperties.scaledHeight = height; + // If the requested size is bigger than what the bitmap was, then + // we increase the bitmap size to match. The width and height + // are bound by MAX_CACHED_BITMAP_SIZE. + if (mNonAnimatableProperties.scaledWidth < width + || mNonAnimatableProperties.scaledHeight < height) { + mNonAnimatableProperties.scaledWidth = std::max(width, + mNonAnimatableProperties.scaledWidth); + mNonAnimatableProperties.scaledHeight = std::max(height, + mNonAnimatableProperties.scaledHeight); mNonAnimatablePropertiesDirty = true; mTree->onPropertyChanged(this); } diff --git a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp deleted file mode 100644 index a438afd5c889..000000000000 --- a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "TestSceneBase.h" - -class ShadowShaderAnimation; - -static TestScene::Registrar _ShadowShader(TestScene::Info{ - "shadowshader", - "A set of overlapping shadowed areas with simple tessellation useful for" - " benchmarking shadow shader performance.", - TestScene::simpleCreateScene<ShadowShaderAnimation> -}); - -class ShadowShaderAnimation : public TestScene { -public: - std::vector< sp<RenderNode> > cards; - void createContent(int width, int height, TestCanvas& canvas) override { - canvas.drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode); - canvas.insertReorderBarrier(true); - - int outset = 50; - for (int i = 0; i < 10; i++) { - sp<RenderNode> card = createCard(outset, outset, - width - (outset * 2), height - (outset * 2)); - canvas.drawRenderNode(card.get()); - cards.push_back(card); - } - - canvas.insertReorderBarrier(false); - } - void doFrame(int frameNr) override { - int curFrame = frameNr % 10; - for (size_t ci = 0; ci < cards.size(); ci++) { - cards[ci]->mutateStagingProperties().setTranslationX(curFrame); - cards[ci]->mutateStagingProperties().setTranslationY(curFrame); - cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); - } - } -private: - sp<RenderNode> createCard(int x, int y, int width, int height) { - return TestUtils::createNode(x, y, x + width, y + height, - [width, height](RenderProperties& props, TestCanvas& canvas) { - props.setElevation(1000); - - // Set 0 radius, no clipping, so shadow is easy to compute. Slightly transparent outline - // to signal contents aren't opaque (not necessary though, as elevation is so high, no - // inner content to cut out) - props.mutableOutline().setRoundRect(0, 0, width, height, 0, 0.99f); - props.mutableOutline().setShouldClip(false); - - // don't draw anything to card's canvas - we just want the shadow - }); - } -}; diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp index 53dbede2f8e1..e2dc3a0a2c66 100644 --- a/libs/hwui/tests/unit/FrameBuilderTests.cpp +++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp @@ -477,6 +477,35 @@ RENDERTHREAD_TEST(FrameBuilder, clippedMerging) { EXPECT_EQ(4, renderer.getIndex()); } +RENDERTHREAD_TEST(FrameBuilder, regionClipStopsMerge) { + class RegionClipStopsMergeTestRenderer : public TestRendererBase { + public: + void onTextOp(const TextOp& op, const BakedOpState& state) override { mIndex++; } + }; + auto node = TestUtils::createNode(0, 0, 400, 400, + [](RenderProperties& props, TestCanvas& canvas) { + SkPath path; + path.addCircle(200, 200, 200, SkPath::kCW_Direction); + canvas.save(SaveFlags::MatrixClip); + canvas.clipPath(&path, SkRegion::kIntersect_Op); + SkPaint paint; + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + paint.setAntiAlias(true); + paint.setTextSize(50); + TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); + TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 200); + canvas.restore(); + }); + + FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400, + sLightGeometry, Caches::getInstance()); + frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); + + RegionClipStopsMergeTestRenderer renderer; + frameBuilder.replayBakedOps<TestDispatcher>(renderer); + EXPECT_EQ(2, renderer.getIndex()); +} + RENDERTHREAD_TEST(FrameBuilder, textMerging) { class TextMergingTestRenderer : public TestRendererBase { public: |