Home | History | Annotate | Download | only in file_manager
      1 // Copyright 2013 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/chromeos/file_manager/open_with_browser.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/command_line.h"
      9 #include "base/logging.h"
     10 #include "base/path_service.h"
     11 #include "base/threading/sequenced_worker_pool.h"
     12 #include "chrome/browser/browser_process.h"
     13 #include "chrome/browser/chromeos/drive/file_system_util.h"
     14 #include "chrome/browser/plugins/plugin_prefs.h"
     15 #include "chrome/browser/profiles/profile_manager.h"
     16 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
     17 #include "chrome/browser/ui/browser.h"
     18 #include "chrome/browser/ui/browser_tabstrip.h"
     19 #include "chrome/browser/ui/browser_window.h"
     20 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
     21 #include "chrome/common/chrome_paths.h"
     22 #include "chrome/common/chrome_switches.h"
     23 #include "content/public/browser/browser_thread.h"
     24 #include "content/public/browser/plugin_service.h"
     25 #include "content/public/common/pepper_plugin_info.h"
     26 #include "net/base/filename_util.h"
     27 
     28 using content::BrowserThread;
     29 using content::PluginService;
     30 
     31 namespace file_manager {
     32 namespace util {
     33 namespace {
     34 
     35 const base::FilePath::CharType kPdfExtension[] = FILE_PATH_LITERAL(".pdf");
     36 const base::FilePath::CharType kSwfExtension[] = FILE_PATH_LITERAL(".swf");
     37 
     38 // List of file extensions viewable in the browser.
     39 const base::FilePath::CharType* kFileExtensionsViewableInBrowser[] = {
     40   FILE_PATH_LITERAL(".bmp"),
     41   FILE_PATH_LITERAL(".ico"),
     42   FILE_PATH_LITERAL(".jpg"),
     43   FILE_PATH_LITERAL(".jpeg"),
     44   FILE_PATH_LITERAL(".png"),
     45   FILE_PATH_LITERAL(".webp"),
     46   FILE_PATH_LITERAL(".gif"),
     47   FILE_PATH_LITERAL(".txt"),
     48   FILE_PATH_LITERAL(".html"),
     49   FILE_PATH_LITERAL(".htm"),
     50   FILE_PATH_LITERAL(".mhtml"),
     51   FILE_PATH_LITERAL(".mht"),
     52   FILE_PATH_LITERAL(".svg"),
     53 };
     54 
     55 // Returns true if |file_path| is viewable in the browser (ex. HTML file).
     56 bool IsViewableInBrowser(const base::FilePath& file_path) {
     57   for (size_t i = 0; i < arraysize(kFileExtensionsViewableInBrowser); i++) {
     58     if (file_path.MatchesExtension(kFileExtensionsViewableInBrowser[i]))
     59       return true;
     60   }
     61   return false;
     62 }
     63 
     64 bool IsPepperPluginEnabled(Profile* profile,
     65                            const base::FilePath& plugin_path) {
     66   DCHECK(profile);
     67 
     68   content::PepperPluginInfo* pepper_info =
     69       PluginService::GetInstance()->GetRegisteredPpapiPluginInfo(plugin_path);
     70   if (!pepper_info)
     71     return false;
     72 
     73   scoped_refptr<PluginPrefs> plugin_prefs = PluginPrefs::GetForProfile(profile);
     74   if (!plugin_prefs.get())
     75     return false;
     76 
     77   return plugin_prefs->IsPluginEnabled(pepper_info->ToWebPluginInfo());
     78 }
     79 
     80 bool IsPdfPluginEnabled(Profile* profile) {
     81   DCHECK(profile);
     82 
     83   base::FilePath plugin_path;
     84   PathService::Get(chrome::FILE_PDF_PLUGIN, &plugin_path);
     85   return IsPepperPluginEnabled(profile, plugin_path);
     86 }
     87 
     88 bool IsFlashPluginEnabled(Profile* profile) {
     89   DCHECK(profile);
     90 
     91   base::FilePath plugin_path(
     92       CommandLine::ForCurrentProcess()->GetSwitchValueNative(
     93           switches::kPpapiFlashPath));
     94   if (plugin_path.empty())
     95     PathService::Get(chrome::FILE_PEPPER_FLASH_PLUGIN, &plugin_path);
     96   return IsPepperPluginEnabled(profile, plugin_path);
     97 }
     98 
     99 void OpenNewTab(Profile* profile, const GURL& url) {
    100   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    101 
    102   // Check the validity of the pointer so that the closure from
    103   // base::Bind(&OpenNewTab, profile) can be passed between threads.
    104   if (!g_browser_process->profile_manager()->IsValidProfile(profile))
    105     return;
    106 
    107   chrome::ScopedTabbedBrowserDisplayer displayer(
    108       profile, chrome::HOST_DESKTOP_TYPE_ASH);
    109   chrome::AddSelectedTabWithURL(displayer.browser(), url,
    110       content::PAGE_TRANSITION_LINK);
    111 
    112   // Since the ScopedTabbedBrowserDisplayer does not guarantee that the
    113   // browser will be shown on the active desktop, we ensure the visibility.
    114   multi_user_util::MoveWindowToCurrentDesktop(
    115       displayer.browser()->window()->GetNativeWindow());
    116 }
    117 
    118 // Reads the alternate URL from a GDoc file. When it fails, returns a file URL
    119 // for |file_path| as fallback.
    120 // Note that an alternate url is a URL to open a hosted document.
    121 GURL ReadUrlFromGDocOnBlockingPool(const base::FilePath& file_path) {
    122   GURL url = drive::util::ReadUrlFromGDocFile(file_path);
    123   if (url.is_empty())
    124     url = net::FilePathToFileURL(file_path);
    125   return url;
    126 }
    127 
    128 }  // namespace
    129 
    130 bool OpenFileWithBrowser(Profile* profile, const base::FilePath& file_path) {
    131   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    132   DCHECK(profile);
    133 
    134   // For things supported natively by the browser, we should open it
    135   // in a tab.
    136   if (IsViewableInBrowser(file_path) ||
    137       ShouldBeOpenedWithPlugin(profile, file_path.Extension())) {
    138     GURL page_url = net::FilePathToFileURL(file_path);
    139     // Override drive resource to point to internal handler instead of file URL.
    140     if (drive::util::IsUnderDriveMountPoint(file_path)) {
    141       page_url = drive::util::FilePathToDriveURL(
    142           drive::util::ExtractDrivePath(file_path));
    143     }
    144     OpenNewTab(profile, page_url);
    145     return true;
    146   }
    147 
    148   if (drive::util::HasGDocFileExtension(file_path)) {
    149     if (drive::util::IsUnderDriveMountPoint(file_path)) {
    150       // The file is on Google Docs. Open with drive URL.
    151       GURL url = drive::util::FilePathToDriveURL(
    152           drive::util::ExtractDrivePath(file_path));
    153       OpenNewTab(profile, url);
    154     } else {
    155       // The file is local (downloaded from an attachment or otherwise copied).
    156       // Parse the file to extract the Docs url and open this url.
    157       base::PostTaskAndReplyWithResult(
    158           BrowserThread::GetBlockingPool(),
    159           FROM_HERE,
    160           base::Bind(&ReadUrlFromGDocOnBlockingPool, file_path),
    161           base::Bind(&OpenNewTab, profile));
    162     }
    163     return true;
    164   }
    165 
    166   // Failed to open the file of unknown type.
    167   LOG(WARNING) << "Unknown file type: " << file_path.value();
    168   return false;
    169 }
    170 
    171 // If a bundled plugin is enabled, we should open pdf/swf files in a tab.
    172 bool ShouldBeOpenedWithPlugin(
    173     Profile* profile,
    174     const base::FilePath::StringType& file_extension) {
    175   DCHECK(profile);
    176 
    177   const base::FilePath file_path =
    178       base::FilePath::FromUTF8Unsafe("dummy").AddExtension(file_extension);
    179   if (file_path.MatchesExtension(kPdfExtension))
    180     return IsPdfPluginEnabled(profile);
    181   if (file_path.MatchesExtension(kSwfExtension))
    182     return IsFlashPluginEnabled(profile);
    183   return false;
    184 }
    185 
    186 }  // namespace util
    187 }  // namespace file_manager
    188