Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / pdf / pdf_unsupported_feature.cc
1 // Copyright (c) 2012 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_unsupported_feature.h"
6
7 #include "base/bind.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "base/version.h"
13 #include "chrome/browser/lifetime/application_lifetime.h"
14 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
15 #include "chrome/browser/plugins/plugin_finder.h"
16 #include "chrome/browser/plugins/plugin_metadata.h"
17 #include "chrome/browser/plugins/plugin_prefs.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/renderer_preferences_util.h"
20 #include "chrome/browser/tab_contents/tab_util.h"
21 #include "chrome/browser/ui/pdf/open_pdf_in_reader_prompt_delegate.h"
22 #include "chrome/browser/ui/pdf/pdf_tab_helper.h"
23 #include "chrome/common/chrome_content_client.h"
24 #include "chrome/common/pref_names.h"
25 #include "content/public/browser/interstitial_page.h"
26 #include "content/public/browser/interstitial_page_delegate.h"
27 #include "content/public/browser/navigation_details.h"
28 #include "content/public/browser/navigation_entry.h"
29 #include "content/public/browser/plugin_service.h"
30 #include "content/public/browser/render_frame_host.h"
31 #include "content/public/browser/render_process_host.h"
32 #include "content/public/browser/render_view_host.h"
33 #include "content/public/browser/user_metrics.h"
34 #include "content/public/browser/web_contents.h"
35 #include "content/public/common/page_transition_types.h"
36 #include "grit/browser_resources.h"
37 #include "grit/generated_resources.h"
38 #include "grit/theme_resources.h"
39 #include "ui/base/l10n/l10n_util.h"
40 #include "ui/base/resource/resource_bundle.h"
41 #include "ui/base/webui/jstemplate_builder.h"
42 #include "ui/gfx/image/image.h"
43
44 #if defined(OS_WIN)
45 #include "base/win/metro.h"
46 #endif
47
48 using base::UserMetricsAction;
49 using content::InterstitialPage;
50 using content::OpenURLParams;
51 using content::PluginService;
52 using content::Referrer;
53 using content::WebContents;
54 using content::WebPluginInfo;
55
56 namespace {
57
58 const char kAdobeReaderUpdateUrl[] = "http://www.adobe.com/go/getreader_chrome";
59
60 #if defined(OS_WIN) && defined(ENABLE_PLUGIN_INSTALLATION)
61 const char kAdobeReaderIdentifier[] = "adobe-reader";
62 #endif
63
64 // The prompt delegate used to ask the user if they want to use Adobe Reader
65 // by default.
66 class PDFEnableAdobeReaderPromptDelegate
67     : public OpenPDFInReaderPromptDelegate {
68  public:
69   explicit PDFEnableAdobeReaderPromptDelegate(Profile* profile);
70   virtual ~PDFEnableAdobeReaderPromptDelegate();
71
72   // OpenPDFInReaderPromptDelegate
73   virtual base::string16 GetMessageText() const OVERRIDE;
74   virtual base::string16 GetAcceptButtonText() const OVERRIDE;
75   virtual base::string16 GetCancelButtonText() const OVERRIDE;
76   virtual bool ShouldExpire(
77       const content::LoadCommittedDetails& details) const OVERRIDE;
78   virtual void Accept() OVERRIDE;
79   virtual void Cancel() OVERRIDE;
80
81  private:
82   void OnYes();
83   void OnNo();
84
85   Profile* profile_;
86
87   DISALLOW_IMPLICIT_CONSTRUCTORS(PDFEnableAdobeReaderPromptDelegate);
88 };
89
90 PDFEnableAdobeReaderPromptDelegate::PDFEnableAdobeReaderPromptDelegate(
91     Profile* profile)
92     : profile_(profile) {
93   content::RecordAction(UserMetricsAction("PDF_EnableReaderInfoBarShown"));
94 }
95
96 PDFEnableAdobeReaderPromptDelegate::~PDFEnableAdobeReaderPromptDelegate() {
97 }
98
99 bool PDFEnableAdobeReaderPromptDelegate::ShouldExpire(
100     const content::LoadCommittedDetails& details) const {
101   content::PageTransition transition =
102       content::PageTransitionStripQualifier(details.entry->GetTransitionType());
103   // We don't want to expire on a reload, because that is how we open the PDF in
104   // Reader.
105   return !details.is_in_page && transition != content::PAGE_TRANSITION_RELOAD;
106 }
107
108 void PDFEnableAdobeReaderPromptDelegate::Accept() {
109   content::RecordAction(UserMetricsAction("PDF_EnableReaderInfoBarOK"));
110   PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile_).get();
111   plugin_prefs->EnablePluginGroup(
112       true, base::ASCIIToUTF16(PluginMetadata::kAdobeReaderGroupName));
113   plugin_prefs->EnablePluginGroup(
114       false, base::ASCIIToUTF16(ChromeContentClient::kPDFPluginName));
115 }
116
117 void PDFEnableAdobeReaderPromptDelegate::Cancel() {
118   content::RecordAction(UserMetricsAction("PDF_EnableReaderInfoBarCancel"));
119 }
120
121 base::string16 PDFEnableAdobeReaderPromptDelegate::GetAcceptButtonText() const {
122   return l10n_util::GetStringUTF16(IDS_PDF_INFOBAR_ALWAYS_USE_READER_BUTTON);
123 }
124
125 base::string16 PDFEnableAdobeReaderPromptDelegate::GetCancelButtonText() const {
126   return l10n_util::GetStringUTF16(IDS_DONE);
127 }
128
129 base::string16 PDFEnableAdobeReaderPromptDelegate::GetMessageText() const {
130   return l10n_util::GetStringUTF16(IDS_PDF_INFOBAR_QUESTION_ALWAYS_USE_READER);
131 }
132
133 // Launch the url to get the latest Adbobe Reader installer.
134 void OpenReaderUpdateURL(WebContents* web_contents) {
135   OpenURLParams params(
136       GURL(kAdobeReaderUpdateUrl), Referrer(), NEW_FOREGROUND_TAB,
137       content::PAGE_TRANSITION_LINK, false);
138   web_contents->OpenURL(params);
139 }
140
141 // Opens the PDF using Adobe Reader.
142 void OpenUsingReader(WebContents* web_contents,
143                      const WebPluginInfo& reader_plugin,
144                      OpenPDFInReaderPromptDelegate* delegate) {
145   ChromePluginServiceFilter::GetInstance()->OverridePluginForFrame(
146       web_contents->GetRenderProcessHost()->GetID(),
147       web_contents->GetMainFrame()->GetRoutingID(),
148       web_contents->GetURL(),
149       reader_plugin);
150   web_contents->GetRenderViewHost()->ReloadFrame();
151
152   PDFTabHelper* pdf_tab_helper = PDFTabHelper::FromWebContents(web_contents);
153   if (delegate)
154     pdf_tab_helper->ShowOpenInReaderPrompt(make_scoped_ptr(delegate));
155 }
156
157 // An interstitial to be used when the user chooses to open a PDF using Adobe
158 // Reader, but it is out of date.
159 class PDFUnsupportedFeatureInterstitial
160     : public content::InterstitialPageDelegate {
161  public:
162   PDFUnsupportedFeatureInterstitial(
163       WebContents* web_contents,
164       const WebPluginInfo& reader_webplugininfo)
165       : web_contents_(web_contents),
166         reader_webplugininfo_(reader_webplugininfo) {
167     content::RecordAction(UserMetricsAction("PDF_ReaderInterstitialShown"));
168     interstitial_page_ = InterstitialPage::Create(
169         web_contents, false, web_contents->GetURL(), this);
170     interstitial_page_->Show();
171   }
172
173  protected:
174   // InterstitialPageDelegate implementation.
175   virtual std::string GetHTMLContents() OVERRIDE {
176     base::DictionaryValue strings;
177     strings.SetString(
178         "title",
179         l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_TITLE));
180     strings.SetString(
181         "headLine",
182         l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_BODY));
183     strings.SetString(
184         "update",
185         l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_UPDATE));
186     strings.SetString(
187         "open_with_reader",
188         l10n_util::GetStringUTF16(
189             IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_PROCEED));
190     strings.SetString(
191         "ok",
192         l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_OK));
193     strings.SetString(
194         "cancel",
195         l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_CANCEL));
196
197     base::StringPiece html(ResourceBundle::GetSharedInstance().
198                            GetRawDataResource(IDR_READER_OUT_OF_DATE_HTML));
199
200     return webui::GetI18nTemplateHtml(html, &strings);
201   }
202
203   virtual void CommandReceived(const std::string& command) OVERRIDE {
204     if (command == "0") {
205       content::RecordAction(
206           UserMetricsAction("PDF_ReaderInterstitialCancel"));
207       interstitial_page_->DontProceed();
208       return;
209     }
210
211     if (command == "1") {
212       content::RecordAction(
213           UserMetricsAction("PDF_ReaderInterstitialUpdate"));
214       OpenReaderUpdateURL(web_contents_);
215     } else if (command == "2") {
216       content::RecordAction(
217           UserMetricsAction("PDF_ReaderInterstitialIgnore"));
218       // Pretend that the plug-in is up-to-date so that we don't block it.
219       reader_webplugininfo_.version = base::ASCIIToUTF16("11.0.0.0");
220       OpenUsingReader(web_contents_, reader_webplugininfo_, NULL);
221     } else {
222       NOTREACHED();
223     }
224     interstitial_page_->Proceed();
225   }
226
227   virtual void OverrideRendererPrefs(
228       content::RendererPreferences* prefs) OVERRIDE {
229     Profile* profile =
230         Profile::FromBrowserContext(web_contents_->GetBrowserContext());
231     renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
232   }
233
234  private:
235   WebContents* web_contents_;
236   WebPluginInfo reader_webplugininfo_;
237   InterstitialPage* interstitial_page_;  // Owns us.
238
239   DISALLOW_COPY_AND_ASSIGN(PDFUnsupportedFeatureInterstitial);
240 };
241
242 // The delegate for the bubble used to inform the user that we don't support a
243 // feature in the PDF.
244 class PDFUnsupportedFeaturePromptDelegate
245     : public OpenPDFInReaderPromptDelegate {
246  public:
247   // |reader| is NULL if Adobe Reader isn't installed.
248   PDFUnsupportedFeaturePromptDelegate(WebContents* web_contents,
249                                       const content::WebPluginInfo* reader,
250                                       PluginFinder* plugin_finder);
251   virtual ~PDFUnsupportedFeaturePromptDelegate();
252
253   // OpenPDFInReaderPromptDelegate:
254   virtual base::string16 GetMessageText() const OVERRIDE;
255   virtual base::string16 GetAcceptButtonText() const OVERRIDE;
256   virtual base::string16 GetCancelButtonText() const OVERRIDE;
257   virtual bool ShouldExpire(
258       const content::LoadCommittedDetails& details) const OVERRIDE;
259   virtual void Accept() OVERRIDE;
260   virtual void Cancel() OVERRIDE;
261
262  private:
263   WebContents* web_contents_;
264   bool reader_installed_;
265   bool reader_vulnerable_;
266   WebPluginInfo reader_webplugininfo_;
267
268   DISALLOW_IMPLICIT_CONSTRUCTORS(PDFUnsupportedFeaturePromptDelegate);
269 };
270
271 PDFUnsupportedFeaturePromptDelegate::PDFUnsupportedFeaturePromptDelegate(
272     WebContents* web_contents,
273     const content::WebPluginInfo* reader,
274     PluginFinder* plugin_finder)
275     : web_contents_(web_contents),
276       reader_installed_(!!reader),
277       reader_vulnerable_(false) {
278   if (!reader_installed_) {
279     content::RecordAction(
280         UserMetricsAction("PDF_InstallReaderInfoBarShown"));
281     return;
282   }
283
284   content::RecordAction(UserMetricsAction("PDF_UseReaderInfoBarShown"));
285   reader_webplugininfo_ = *reader;
286
287 #if defined(ENABLE_PLUGIN_INSTALLATION)
288   scoped_ptr<PluginMetadata> plugin_metadata(
289       plugin_finder->GetPluginMetadata(reader_webplugininfo_));
290
291   reader_vulnerable_ = plugin_metadata->GetSecurityStatus(*reader) !=
292                        PluginMetadata::SECURITY_STATUS_UP_TO_DATE;
293 #else
294   NOTREACHED();
295 #endif
296 }
297
298 PDFUnsupportedFeaturePromptDelegate::~PDFUnsupportedFeaturePromptDelegate() {
299 }
300
301 base::string16 PDFUnsupportedFeaturePromptDelegate::GetMessageText() const {
302   return l10n_util::GetStringUTF16(IDS_PDF_BUBBLE_MESSAGE);
303 }
304
305 base::string16 PDFUnsupportedFeaturePromptDelegate::GetAcceptButtonText()
306     const {
307 #if defined(OS_WIN)
308   if (base::win::IsMetroProcess())
309     return l10n_util::GetStringUTF16(IDS_PDF_BUBBLE_METRO_MODE_LINK);
310 #endif
311
312   if (reader_installed_)
313     return l10n_util::GetStringUTF16(IDS_PDF_BUBBLE_OPEN_IN_READER_LINK);
314
315   return l10n_util::GetStringUTF16(IDS_PDF_BUBBLE_INSTALL_READER_LINK);
316 }
317
318 base::string16 PDFUnsupportedFeaturePromptDelegate::GetCancelButtonText()
319     const {
320   return l10n_util::GetStringUTF16(IDS_DONE);
321 }
322
323 bool PDFUnsupportedFeaturePromptDelegate::ShouldExpire(
324     const content::LoadCommittedDetails& details) const {
325   return !details.is_in_page;
326 }
327
328 void PDFUnsupportedFeaturePromptDelegate::Accept() {
329 #if defined(OS_WIN)
330   if (base::win::IsMetroProcess()) {
331     chrome::AttemptRestartWithModeSwitch();
332     return;
333   }
334 #endif
335
336   if (!reader_installed_) {
337     content::RecordAction(UserMetricsAction("PDF_InstallReaderInfoBarOK"));
338     OpenReaderUpdateURL(web_contents_);
339     return;
340   }
341
342   content::RecordAction(UserMetricsAction("PDF_UseReaderInfoBarOK"));
343
344   if (reader_vulnerable_) {
345     new PDFUnsupportedFeatureInterstitial(web_contents_, reader_webplugininfo_);
346     return;
347   }
348
349   Profile* profile =
350       Profile::FromBrowserContext(web_contents_->GetBrowserContext());
351   OpenPDFInReaderPromptDelegate* delegate =
352       new PDFEnableAdobeReaderPromptDelegate(profile);
353
354   OpenUsingReader(web_contents_, reader_webplugininfo_, delegate);
355 }
356
357 void PDFUnsupportedFeaturePromptDelegate::Cancel() {
358   content::RecordAction(reader_installed_ ?
359                         UserMetricsAction("PDF_UseReaderInfoBarCancel") :
360                         UserMetricsAction("PDF_InstallReaderInfoBarCancel"));
361 }
362
363 #if defined(OS_WIN) && defined(ENABLE_PLUGIN_INSTALLATION)
364 void GotPluginsCallback(int process_id,
365                         int routing_id,
366                         const std::vector<content::WebPluginInfo>& plugins) {
367   WebContents* web_contents =
368       tab_util::GetWebContentsByID(process_id, routing_id);
369   if (!web_contents)
370     return;
371
372   const content::WebPluginInfo* reader = NULL;
373   PluginFinder* plugin_finder = PluginFinder::GetInstance();
374   for (size_t i = 0; i < plugins.size(); ++i) {
375     scoped_ptr<PluginMetadata> plugin_metadata(
376         plugin_finder->GetPluginMetadata(plugins[i]));
377     if (plugin_metadata->identifier() != kAdobeReaderIdentifier)
378       continue;
379
380     DCHECK(!reader);
381     reader = &plugins[i];
382     // If the Reader plugin is disabled by policy, don't prompt them.
383     Profile* profile =
384         Profile::FromBrowserContext(web_contents->GetBrowserContext());
385     PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile);
386     if (plugin_prefs->PolicyStatusForPlugin(plugin_metadata->name()) ==
387         PluginPrefs::POLICY_DISABLED) {
388       return;
389     }
390     break;
391   }
392
393   scoped_ptr<OpenPDFInReaderPromptDelegate> prompt(
394       new PDFUnsupportedFeaturePromptDelegate(
395           web_contents, reader, plugin_finder));
396   PDFTabHelper* pdf_tab_helper = PDFTabHelper::FromWebContents(web_contents);
397   pdf_tab_helper->ShowOpenInReaderPrompt(prompt.Pass());
398 }
399 #endif  // defined(OS_WIN) && defined(ENABLE_PLUGIN_INSTALLATION)
400
401 }  // namespace
402
403 void PDFHasUnsupportedFeature(content::WebContents* web_contents) {
404 #if defined(OS_WIN) && defined(ENABLE_PLUGIN_INSTALLATION)
405   // Only works for Windows for now.  For Mac, we'll have to launch the file
406   // externally since Adobe Reader doesn't work inside Chrome.
407   PluginService::GetInstance()->GetPlugins(base::Bind(&GotPluginsCallback,
408       web_contents->GetRenderProcessHost()->GetID(),
409       web_contents->GetRenderViewHost()->GetRoutingID()));
410 #endif
411 }