Home | History | Annotate | Download | only in pdf
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/pdf/pdf_browsertest_base.h"
      6 
      7 #include <algorithm>
      8 #include <vector>
      9 
     10 #include "base/path_service.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "chrome/browser/chrome_notification_types.h"
     14 #include "chrome/browser/ui/browser.h"
     15 #include "chrome/browser/ui/browser_window.h"
     16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     17 #include "chrome/common/chrome_paths.h"
     18 #include "chrome/test/base/ui_test_utils.h"
     19 #include "content/public/browser/render_view_host.h"
     20 #include "content/public/browser/web_contents.h"
     21 #include "third_party/skia/include/core/SkBitmap.h"
     22 #include "ui/gfx/codec/png_codec.h"
     23 #include "ui/gfx/screen.h"
     24 
     25 #if defined(OS_LINUX)
     26 #include "base/command_line.h"
     27 #include "content/public/common/content_switches.h"
     28 #endif
     29 
     30 #if defined(OS_CHROMEOS)
     31 #include "ui/compositor/compositor_switches.h"
     32 #endif
     33 
     34 namespace {
     35 
     36 // Include things like browser frame and scrollbar and make sure we're bigger
     37 // than the test pdf document.
     38 const int kBrowserWidth = 1000;
     39 const int kBrowserHeight = 600;
     40 
     41 }  // namespace
     42 
     43 PDFBrowserTest::PDFBrowserTest()
     44     : snapshot_different_(true),
     45       next_dummy_search_value_(0),
     46       load_stop_notification_count_(0) {
     47   base::FilePath src_dir;
     48   EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir));
     49   pdf_test_server_.ServeFilesFromDirectory(src_dir.AppendASCII(
     50       "chrome/test/data/pdf_private"));
     51 }
     52 
     53 PDFBrowserTest::~PDFBrowserTest() {
     54 }
     55 
     56 void PDFBrowserTest::Load() {
     57   // Make sure to set the window size before rendering, as otherwise rendering
     58   // to a smaller window and then expanding leads to slight anti-aliasing
     59   // differences of the text and the pixel comparison fails.
     60   gfx::Rect bounds(gfx::Rect(0, 0, kBrowserWidth, kBrowserHeight));
     61   gfx::Rect screen_bounds =
     62       gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().bounds();
     63   ASSERT_GT(screen_bounds.width(), kBrowserWidth);
     64   ASSERT_GT(screen_bounds.height(), kBrowserHeight);
     65   browser()->window()->SetBounds(bounds);
     66 
     67   GURL url(ui_test_utils::GetTestUrl(
     68       base::FilePath(FILE_PATH_LITERAL("pdf_private")),
     69       base::FilePath(FILE_PATH_LITERAL("pdf_browsertest.pdf"))));
     70   ui_test_utils::NavigateToURL(browser(), url);
     71 }
     72 
     73 void PDFBrowserTest::WaitForResponse() {
     74   // Even if the plugin has loaded the data or scrolled, because of how
     75   // pepper painting works, we might not have the data.  One way to force this
     76   // to be flushed is to do a find operation, since on this two-page test
     77   // document, it'll wait for us to flush the renderer message loop twice and
     78   // also the browser's once, at which point we're guaranteed to have updated
     79   // the backingstore.  Hacky, but it works.
     80   // Note that we need to change the text each time, because if we don't the
     81   // renderer code will think the second message is to go to next result, but
     82   // there are none so the plugin will assert.
     83 
     84   base::string16 query = base::UTF8ToUTF16(
     85       std::string("xyzxyz" + base::IntToString(next_dummy_search_value_++)));
     86   ASSERT_EQ(0, ui_test_utils::FindInPage(
     87       browser()->tab_strip_model()->GetActiveWebContents(),
     88       query, true, false, NULL, NULL));
     89 }
     90 
     91 bool PDFBrowserTest::VerifySnapshot(const std::string& expected_filename) {
     92   snapshot_different_ = true;
     93   expected_filename_ = expected_filename;
     94   content::WebContents* web_contents =
     95       browser()->tab_strip_model()->GetActiveWebContents();
     96   DCHECK(web_contents);
     97 
     98   content::RenderWidgetHost* rwh = web_contents->GetRenderViewHost();
     99   rwh->CopyFromBackingStore(
    100       gfx::Rect(),
    101       gfx::Size(),
    102       base::Bind(&PDFBrowserTest::CopyFromBackingStoreCallback, this),
    103       kN32_SkColorType);
    104 
    105   content::RunMessageLoop();
    106 
    107   if (snapshot_different_) {
    108     LOG(INFO) << "Rendering didn't match, see result "
    109               << snapshot_filename_.value();
    110   }
    111   return !snapshot_different_;
    112 }
    113 
    114 void PDFBrowserTest::CopyFromBackingStoreCallback(bool success,
    115                                                   const SkBitmap& bitmap) {
    116   base::MessageLoopForUI::current()->Quit();
    117   ASSERT_EQ(success, true);
    118   base::FilePath reference = ui_test_utils::GetTestFilePath(
    119       base::FilePath(FILE_PATH_LITERAL("pdf_private")),
    120       base::FilePath().AppendASCII(expected_filename_));
    121   base::File::Info info;
    122   ASSERT_TRUE(base::GetFileInfo(reference, &info));
    123   int size = static_cast<size_t>(info.size);
    124   scoped_ptr<char[]> data(new char[size]);
    125   ASSERT_EQ(size, base::ReadFile(reference, data.get(), size));
    126 
    127   int w, h;
    128   std::vector<unsigned char> decoded;
    129   ASSERT_TRUE(gfx::PNGCodec::Decode(
    130       reinterpret_cast<unsigned char*>(data.get()), size,
    131       gfx::PNGCodec::FORMAT_BGRA, &decoded, &w, &h));
    132   int32* ref_pixels = reinterpret_cast<int32*>(&decoded[0]);
    133 
    134   int32* pixels = static_cast<int32*>(bitmap.getPixels());
    135 
    136   // Get the background color, and use it to figure out the x-offsets in
    137   // each image.  The reason is that depending on the theme in the OS, the
    138   // same browser width can lead to slightly different plugin sizes, so the
    139   // pdf content will start at different x offsets.
    140   // Also note that the images we saved are cut off before the scrollbar, as
    141   // that'll change depending on the theme, and also cut off vertically so
    142   // that the ui controls don't show up, as those fade-in and so the timing
    143   // will affect their transparency.
    144   int32 bg_color = ref_pixels[0];
    145   int ref_x_offset, snapshot_x_offset;
    146   for (ref_x_offset = 0; ref_x_offset < w; ++ref_x_offset) {
    147     if (ref_pixels[ref_x_offset] != bg_color)
    148       break;
    149   }
    150 
    151   for (snapshot_x_offset = 0; snapshot_x_offset < bitmap.width();
    152        ++snapshot_x_offset) {
    153     if (pixels[snapshot_x_offset] != bg_color)
    154       break;
    155   }
    156 
    157   int x_max = std::min(w - ref_x_offset, bitmap.width() - snapshot_x_offset);
    158   int y_max = std::min(h, bitmap.height());
    159   int stride = bitmap.rowBytes();
    160   snapshot_different_ = false;
    161   for (int y = 0; y < y_max && !snapshot_different_; ++y) {
    162     for (int x = 0; x < x_max && !snapshot_different_; ++x) {
    163       if (pixels[y * stride / sizeof(int32) + x + snapshot_x_offset] !=
    164           ref_pixels[y * w + x + ref_x_offset])
    165         snapshot_different_ = true;
    166     }
    167   }
    168 
    169   if (snapshot_different_) {
    170     std::vector<unsigned char> png_data;
    171     gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &png_data);
    172     if (base::CreateTemporaryFile(&snapshot_filename_)) {
    173       base::WriteFile(snapshot_filename_,
    174                       reinterpret_cast<char*>(&png_data[0]), png_data.size());
    175     }
    176   }
    177 }
    178 
    179 void PDFBrowserTest::Observe(int type,
    180                              const content::NotificationSource& source,
    181                              const content::NotificationDetails& details) {
    182   DCHECK_EQ(content::NOTIFICATION_LOAD_STOP, type);
    183   load_stop_notification_count_++;
    184 }
    185 
    186 void PDFBrowserTest::SetUpCommandLine(base::CommandLine* command_line) {
    187 #if defined(OS_LINUX)
    188   // Calling RenderWidgetHost::CopyFromBackingStore() with the GPU enabled
    189   // fails on Linux.
    190   command_line->AppendSwitch(switches::kDisableGpu);
    191 #endif
    192 
    193 #if defined(OS_CHROMEOS)
    194   // Also need on CrOS in addition to disabling the GPU above.
    195   command_line->AppendSwitch(switches::kUIDisableThreadedCompositing);
    196 #endif
    197 }
    198