tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TestSurfaceCache.cpp (5905B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "gtest/gtest.h"
      7 
      8 #include "Common.h"
      9 #include "imgIContainer.h"
     10 #include "ImageFactory.h"
     11 #include "mozilla/gfx/2D.h"
     12 #include "mozilla/RefPtr.h"
     13 #include "mozilla/StaticPrefs_image.h"
     14 #include "nsIInputStream.h"
     15 #include "nsString.h"
     16 #include "ProgressTracker.h"
     17 
     18 using namespace mozilla;
     19 using namespace mozilla::gfx;
     20 using namespace mozilla::image;
     21 
     22 class ImageSurfaceCache : public ::testing::Test {
     23 protected:
     24  AutoInitializeImageLib mInit;
     25 };
     26 
     27 TEST_F(ImageSurfaceCache, Factor2) {
     28  ImageTestCase testCase = GreenPNGTestCase();
     29 
     30  // Create an image.
     31  RefPtr<Image> image = ImageFactory::CreateAnonymousImage(
     32      nsDependentCString(testCase.mMimeType));
     33  ASSERT_TRUE(!image->HasError());
     34 
     35  nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath);
     36  ASSERT_TRUE(inputStream);
     37 
     38  // Figure out how much data we have.
     39  uint64_t length;
     40  nsresult rv = inputStream->Available(&length);
     41  ASSERT_NS_SUCCEEDED(rv);
     42 
     43  // Ensures we meet the threshold for FLAG_SYNC_DECODE_IF_FAST to do sync
     44  // decoding without the implications of FLAG_SYNC_DECODE.
     45  ASSERT_LT(length,
     46            static_cast<uint64_t>(
     47                StaticPrefs::image_mem_decode_bytes_at_a_time_AtStartup()));
     48 
     49  // Write the data into the image.
     50  rv = image->OnImageDataAvailable(nullptr, inputStream, 0,
     51                                   static_cast<uint32_t>(length));
     52  ASSERT_NS_SUCCEEDED(rv);
     53 
     54  // Let the image know we've sent all the data.
     55  rv = image->OnImageDataComplete(nullptr, NS_OK, true);
     56  ASSERT_NS_SUCCEEDED(rv);
     57 
     58  RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
     59  tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
     60 
     61  const uint32_t whichFrame = imgIContainer::FRAME_CURRENT;
     62 
     63  // FLAG_SYNC_DECODE will make RasterImage::LookupFrame use
     64  // SurfaceCache::Lookup to force an exact match lookup (and potential decode).
     65  const uint32_t exactFlags = imgIContainer::FLAG_HIGH_QUALITY_SCALING |
     66                              imgIContainer::FLAG_SYNC_DECODE;
     67 
     68  // If the data stream is small enough, as we assert above,
     69  // FLAG_SYNC_DECODE_IF_FAST will allow us to decode sync, but avoid forcing
     70  // SurfaceCache::Lookup. Instead it will use SurfaceCache::LookupBestMatch.
     71  const uint32_t bestMatchFlags = imgIContainer::FLAG_HIGH_QUALITY_SCALING |
     72                                  imgIContainer::FLAG_SYNC_DECODE_IF_FAST;
     73 
     74  // We need the default threshold to be enabled (otherwise we should disable
     75  // this test).
     76  int32_t threshold = StaticPrefs::image_cache_factor2_threshold_surfaces();
     77  ASSERT_TRUE(threshold >= 0);
     78 
     79  // We need to know what the native sizes are, otherwise factor of 2 mode will
     80  // be disabled.
     81  size_t nativeSizes = image->GetNativeSizesLength();
     82  ASSERT_EQ(nativeSizes, 1u);
     83 
     84  // Threshold is the native size count and the pref threshold added together.
     85  // Make sure the image is big enough that we can simply decrement and divide
     86  // off the size as we please and not hit unexpected duplicates.
     87  int32_t totalThreshold = static_cast<int32_t>(nativeSizes) + threshold;
     88  ASSERT_TRUE(testCase.mSize.width > totalThreshold * 4);
     89 
     90  // Request a bunch of slightly different sizes. We won't trip factor of 2 mode
     91  // in this loop.
     92  IntSize size = testCase.mSize;
     93  for (int32_t i = 0; i <= totalThreshold; ++i) {
     94    RefPtr<SourceSurface> surf =
     95        image->GetFrameAtSize(size, whichFrame, bestMatchFlags);
     96    ASSERT_TRUE(surf);
     97    EXPECT_EQ(surf->GetSize(), size);
     98 
     99    size.width -= 1;
    100    size.height -= 1;
    101  }
    102 
    103  // Now let's ask for a new size. Despite this being sync, it will return
    104  // the closest factor of 2 size we have and not the requested size.
    105  RefPtr<SourceSurface> surf =
    106      image->GetFrameAtSize(size, whichFrame, bestMatchFlags);
    107  ASSERT_TRUE(surf);
    108 
    109  EXPECT_EQ(surf->GetSize(), testCase.mSize);
    110 
    111  // Now we should be in factor of 2 mode but unless we trigger a decode no
    112  // pruning of the old sized surfaces should happen.
    113  size = testCase.mSize;
    114  for (int32_t i = 0; i < totalThreshold; ++i) {
    115    RefPtr<SourceSurface> surf =
    116        image->GetFrameAtSize(size, whichFrame, bestMatchFlags);
    117    ASSERT_TRUE(surf);
    118    EXPECT_EQ(surf->GetSize(), size);
    119 
    120    size.width -= 1;
    121    size.height -= 1;
    122  }
    123 
    124  // Now force an existing surface to be marked as explicit so that it
    125  // won't get freed upon pruning (gets marked in the Lookup).
    126  size.width += 1;
    127  size.height += 1;
    128  surf = image->GetFrameAtSize(size, whichFrame, exactFlags);
    129  ASSERT_TRUE(surf);
    130  EXPECT_EQ(surf->GetSize(), size);
    131 
    132  // Now force a new decode to happen by getting a new factor of 2 size.
    133  size.width = testCase.mSize.width / 2 - 1;
    134  size.height = testCase.mSize.height / 2 - 1;
    135  surf = image->GetFrameAtSize(size, whichFrame, bestMatchFlags);
    136  ASSERT_TRUE(surf);
    137  EXPECT_EQ(surf->GetSize().width, testCase.mSize.width / 2);
    138  EXPECT_EQ(surf->GetSize().height, testCase.mSize.height / 2);
    139 
    140  // The decode above would have forced a pruning to happen, so now if
    141  // we request all of the sizes we used to have decoded, only the explicit
    142  // size should have been kept.
    143  size = testCase.mSize;
    144  for (int32_t i = 0; i < totalThreshold - 1; ++i) {
    145    RefPtr<SourceSurface> surf =
    146        image->GetFrameAtSize(size, whichFrame, bestMatchFlags);
    147    ASSERT_TRUE(surf);
    148    EXPECT_EQ(surf->GetSize(), testCase.mSize);
    149 
    150    size.width -= 1;
    151    size.height -= 1;
    152  }
    153 
    154  // This lookup finds the surface that already existed that we later marked
    155  // as explicit. It should still exist after pruning.
    156  surf = image->GetFrameAtSize(size, whichFrame, bestMatchFlags);
    157  ASSERT_TRUE(surf);
    158  EXPECT_EQ(surf->GetSize(), size);
    159 }