| /* |
| * Copyright 2013 Google Inc. |
| * |
| * 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. |
| */ |
| |
| // Author: Huibao Lin |
| |
| #include "pagespeed/kernel/base/basictypes.h" |
| #include "pagespeed/kernel/base/gtest.h" |
| #include "pagespeed/kernel/base/mock_message_handler.h" |
| #include "pagespeed/kernel/base/null_mutex.h" |
| #include "pagespeed/kernel/base/scoped_ptr.h" |
| #include "pagespeed/kernel/base/string.h" |
| #include "pagespeed/kernel/image/pixel_format_optimizer.h" |
| #include "pagespeed/kernel/image/png_optimizer.h" |
| #include "pagespeed/kernel/image/test_utils.h" |
| |
| namespace { |
| |
| using net_instaweb::MessageHandler; |
| using net_instaweb::MockMessageHandler; |
| using net_instaweb::NullMutex; |
| using pagespeed::image_compression::PngScanlineReaderRaw; |
| using pagespeed::image_compression::ReadTestFileWithExt; |
| using pagespeed::image_compression::kMessagePatternUnexpectedEOF; |
| using pagespeed::image_compression::kWebpTestDir; |
| using pagespeed::image_compression::PixelFormatOptimizer; |
| |
| const char kOpaqueAlphaImage[] = "completely_opaque_32x20.png"; |
| const char kNoAlphaImage[] = "opaque_32x20.png"; |
| |
| const char* kUnoptimizableImages[] = { |
| "pagespeed_32x32_gray.png", // no alpha, gray scale |
| "opaque_32x20.png", // no alpha, RGB |
| "alpha_32x32.png", // alpha, first few pixels are transparent |
| "partially_opaque_32x20.png", // alpha, only last pixel is transparent |
| }; |
| const size_t kUnoptimizableImageCount = arraysize(kUnoptimizableImages); |
| |
| // Message to ignore. |
| const char kMessagePatternScanline[] = "*scanline*"; |
| const char kMessagePatternLongJmp[] = "*longjmp()*"; |
| |
| class PixelFormatOptimizerTest : public testing::Test { |
| public: |
| PixelFormatOptimizerTest() : |
| message_handler_(new NullMutex), |
| optimizer_(&message_handler_), |
| gold_reader_(&message_handler_) { |
| } |
| |
| bool InitializeOptimizer(const char* file_name) { |
| if (!ReadTestFileWithExt(kWebpTestDir, file_name, &input_image_)) { |
| return false; |
| } |
| |
| net_instaweb::scoped_ptr<PngScanlineReaderRaw> input_reader( |
| new PngScanlineReaderRaw(&message_handler_)); |
| |
| if (!input_reader->Initialize(input_image_.data(), input_image_.length())) { |
| return false; |
| } |
| return optimizer_.Initialize(input_reader.release()).Success(); |
| } |
| |
| bool InitializeGoldReader(const char* file_name) { |
| if (!ReadTestFileWithExt(kWebpTestDir, file_name, &gold_image_)) { |
| return false; |
| } |
| return gold_reader_.Initialize(gold_image_.data(), gold_image_.length()); |
| } |
| |
| protected: |
| MockMessageHandler message_handler_; |
| PixelFormatOptimizer optimizer_; |
| PngScanlineReaderRaw gold_reader_; |
| GoogleString input_image_; |
| GoogleString gold_image_; |
| void* scanline_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(PixelFormatOptimizerTest); |
| }; |
| |
| // The optimizable image will be converted to a new image. |
| TEST_F(PixelFormatOptimizerTest, Optimizable) { |
| ASSERT_TRUE(InitializeOptimizer(kOpaqueAlphaImage)); |
| ASSERT_TRUE(InitializeGoldReader(kNoAlphaImage)); |
| CompareImageReaders(&gold_reader_, &optimizer_); |
| } |
| |
| // The un-optimizable images will stay the same after conversion. |
| TEST_F(PixelFormatOptimizerTest, Unoptimizable) { |
| for (size_t i = 0; i < kUnoptimizableImageCount; ++i) { |
| const char* file_name = kUnoptimizableImages[i]; |
| ASSERT_TRUE(InitializeOptimizer(file_name)); |
| ASSERT_TRUE(InitializeGoldReader(file_name)); |
| CompareImageReaders(&gold_reader_, &optimizer_); |
| } |
| } |
| |
| // Test that we don't have memory leakage if the object is initialized |
| // but no scanline is read. |
| TEST_F(PixelFormatOptimizerTest, InitializeWithoutRead) { |
| ASSERT_TRUE(InitializeOptimizer(kOpaqueAlphaImage)); |
| } |
| |
| // Test that we don't have memory leakage if we don't read all of the |
| // scanlines. |
| TEST_F(PixelFormatOptimizerTest, ReadOneRow) { |
| ASSERT_TRUE(InitializeOptimizer(kOpaqueAlphaImage)); |
| ASSERT_TRUE(optimizer_.ReadNextScanline(&scanline_)); |
| } |
| |
| TEST_F(PixelFormatOptimizerTest, ReinitializeAfterOneRow) { |
| ASSERT_TRUE(InitializeOptimizer(kOpaqueAlphaImage)); |
| ASSERT_TRUE(optimizer_.ReadNextScanline(&scanline_)); |
| ASSERT_TRUE(InitializeOptimizer(kOpaqueAlphaImage)); |
| ASSERT_TRUE(InitializeGoldReader(kNoAlphaImage)); |
| CompareImageReaders(&gold_reader_, &optimizer_); |
| } |
| |
| TEST_F(PixelFormatOptimizerTest, ReInitializeAfterLastRow) { |
| message_handler_.AddPatternToSkipPrinting(kMessagePatternScanline); |
| ASSERT_TRUE(InitializeOptimizer(kOpaqueAlphaImage)); |
| while (optimizer_.HasMoreScanLines()) { |
| ASSERT_TRUE(optimizer_.ReadNextScanline(&scanline_)); |
| } |
| ASSERT_FALSE(optimizer_.ReadNextScanline(&scanline_)); |
| // Initalize and use the object again. |
| ASSERT_TRUE(InitializeOptimizer(kOpaqueAlphaImage)); |
| ASSERT_TRUE(InitializeGoldReader(kNoAlphaImage)); |
| CompareImageReaders(&gold_reader_, &optimizer_); |
| } |
| |
| // The truncated image leads to a bad reader, which consequently causes |
| // the optimizer fail to initialize. |
| TEST_F(PixelFormatOptimizerTest, TruncatedImage) { |
| message_handler_.AddPatternToSkipPrinting(kMessagePatternLongJmp); |
| message_handler_.AddPatternToSkipPrinting(kMessagePatternScanline); |
| message_handler_.AddPatternToSkipPrinting(kMessagePatternUnexpectedEOF); |
| |
| ASSERT_TRUE(ReadTestFileWithExt(kWebpTestDir, kOpaqueAlphaImage, |
| &input_image_)); |
| int truncated_length = input_image_.length() * 0.8; |
| |
| net_instaweb::scoped_ptr<PngScanlineReaderRaw> input_reader( |
| new PngScanlineReaderRaw(&message_handler_)); |
| ASSERT_TRUE(input_reader->Initialize(input_image_.data(), truncated_length)); |
| ASSERT_FALSE(optimizer_.Initialize(input_reader.release()).Success()); |
| } |
| |
| } // namespace |